tabby-agentdeck 1.1.3 → 1.2.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/CHANGELOG.md +24 -1
- package/README.ko.md +26 -574
- package/README.md +25 -545
- package/dist/agents.d.ts +15 -0
- package/dist/codexHooks.d.ts +23 -0
- package/dist/codexMeta.d.ts +87 -0
- package/dist/config.d.ts +120 -2
- package/dist/cursorVisibility.d.ts +33 -1
- package/dist/deck.service.d.ts +182 -19
- package/dist/devReload.service.d.ts +48 -0
- package/dist/devReload.stub.d.ts +19 -0
- package/dist/dock.d.ts +15 -0
- package/dist/i18n/af.d.ts +83 -0
- package/dist/i18n/bg.d.ts +83 -0
- package/dist/i18n/cs.d.ts +83 -0
- package/dist/i18n/da.d.ts +83 -0
- package/dist/i18n/de.d.ts +83 -0
- package/dist/i18n/en.d.ts +83 -0
- package/dist/i18n/es.d.ts +83 -0
- package/dist/i18n/fr.d.ts +83 -0
- package/dist/i18n/hr.d.ts +83 -0
- package/dist/i18n/id.d.ts +83 -0
- package/dist/i18n/it.d.ts +83 -0
- package/dist/i18n/ja.d.ts +83 -0
- package/dist/i18n/ko.d.ts +83 -0
- package/dist/i18n/pl.d.ts +83 -0
- package/dist/i18n/pt.d.ts +83 -0
- package/dist/i18n/ru.d.ts +83 -0
- package/dist/i18n/sr.d.ts +83 -0
- package/dist/i18n/sv.d.ts +83 -0
- package/dist/i18n/tr.d.ts +83 -0
- package/dist/i18n/uk.d.ts +83 -0
- package/dist/i18n/zh-CN.d.ts +83 -0
- package/dist/i18n/zh-TW.d.ts +83 -0
- package/dist/i18n.d.ts +3618 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -2
- package/dist/keybind.d.ts +121 -0
- package/dist/meta.d.ts +83 -0
- package/dist/nav.d.ts +29 -0
- package/dist/notify.service.d.ts +149 -1
- package/dist/project-root.d.ts +1 -1
- package/dist/reload.service.d.ts +57 -0
- package/dist/sessionLedger.d.ts +11 -6
- package/dist/settings.component.d.ts +133 -8
- package/dist/status.service.d.ts +30 -2
- package/dist/statusLine.d.ts +27 -0
- package/dist/update.d.ts +19 -5
- package/dist/update.service.d.ts +29 -20
- package/dist/viewPanel.d.ts +13 -3
- package/hooks/agentdeck-codex-notify.ps1 +5 -2
- package/hooks/agentdeck-label.js +1 -1
- package/hooks/agentdeck-notify.ps1 +32 -12
- package/hooks/agentdeck-statusline.mjs +351 -0
- package/package.json +4 -2
- package/updater/agentdeck-update.ps1 +50 -27
- package/dist/index.js.map +0 -1
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","mappings":"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","sources":["webpack://tabby-agentdeck/webpack/universalModuleDefinition","webpack://tabby-agentdeck/./src/styles.scss","webpack://tabby-agentdeck/./node_modules/css-loader/dist/runtime/api.js","webpack://tabby-agentdeck/./node_modules/css-loader/dist/runtime/sourceMaps.js","webpack://tabby-agentdeck/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js","webpack://tabby-agentdeck/./node_modules/style-loader/dist/runtime/insertBySelector.js","webpack://tabby-agentdeck/./node_modules/style-loader/dist/runtime/insertStyleElement.js","webpack://tabby-agentdeck/./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js","webpack://tabby-agentdeck/./node_modules/style-loader/dist/runtime/styleDomAPI.js","webpack://tabby-agentdeck/./node_modules/style-loader/dist/runtime/styleTagTransform.js","webpack://tabby-agentdeck/./src/styles.scss?a609","webpack://tabby-agentdeck/./src/agents.ts","webpack://tabby-agentdeck/./src/alert.service.ts","webpack://tabby-agentdeck/./src/api.ts","webpack://tabby-agentdeck/./src/bind.ts","webpack://tabby-agentdeck/./src/claudeHooks.ts","webpack://tabby-agentdeck/./src/codexHooks.ts","webpack://tabby-agentdeck/./src/codexWheel.ts","webpack://tabby-agentdeck/./src/config.ts","webpack://tabby-agentdeck/./src/cursorVisibility.ts","webpack://tabby-agentdeck/./src/deck.service.ts","webpack://tabby-agentdeck/./src/decorator.ts","webpack://tabby-agentdeck/./src/detect.ts","webpack://tabby-agentdeck/./src/diag.ts","webpack://tabby-agentdeck/./src/dock.ts","webpack://tabby-agentdeck/./src/gitCommit.ts","webpack://tabby-agentdeck/./src/gitDiff.ts","webpack://tabby-agentdeck/./src/group.ts","webpack://tabby-agentdeck/./src/hotkeys.ts","webpack://tabby-agentdeck/./src/ime.ts","webpack://tabby-agentdeck/./src/index.ts","webpack://tabby-agentdeck/./src/markdown.ts","webpack://tabby-agentdeck/./src/nav.ts","webpack://tabby-agentdeck/./src/notify.service.ts","webpack://tabby-agentdeck/./src/order.ts","webpack://tabby-agentdeck/./src/profile.service.ts","webpack://tabby-agentdeck/./src/project-root.ts","webpack://tabby-agentdeck/./src/prompt.ts","webpack://tabby-agentdeck/./src/reason.ts","webpack://tabby-agentdeck/./src/recovery.service.ts","webpack://tabby-agentdeck/./src/screen.ts","webpack://tabby-agentdeck/./src/screenAgent.ts","webpack://tabby-agentdeck/./src/sessionLedger.service.ts","webpack://tabby-agentdeck/./src/sessionLedger.ts","webpack://tabby-agentdeck/./src/settings.component.ts","webpack://tabby-agentdeck/./src/settings.ts","webpack://tabby-agentdeck/./src/status.service.ts","webpack://tabby-agentdeck/./src/subagents.ts","webpack://tabby-agentdeck/./src/synchronizedOutput.ts","webpack://tabby-agentdeck/./src/tabenv.ts","webpack://tabby-agentdeck/./src/terminalInput.ts","webpack://tabby-agentdeck/./src/update.service.ts","webpack://tabby-agentdeck/./src/update.ts","webpack://tabby-agentdeck/./src/viewPanel.ts","webpack://tabby-agentdeck/./src/viewer.ts","webpack://tabby-agentdeck/external node-commonjs \"child_process\"","webpack://tabby-agentdeck/external node-commonjs \"electron\"","webpack://tabby-agentdeck/external node-commonjs \"fs\"","webpack://tabby-agentdeck/external node-commonjs \"http\"","webpack://tabby-agentdeck/external node-commonjs \"https\"","webpack://tabby-agentdeck/external node-commonjs \"net\"","webpack://tabby-agentdeck/external node-commonjs \"os\"","webpack://tabby-agentdeck/external node-commonjs \"path\"","webpack://tabby-agentdeck/external node-commonjs \"string_decoder\"","webpack://tabby-agentdeck/external umd \"@angular/common\"","webpack://tabby-agentdeck/external umd \"@angular/core\"","webpack://tabby-agentdeck/external umd \"@angular/forms\"","webpack://tabby-agentdeck/external umd \"rxjs\"","webpack://tabby-agentdeck/external umd \"tabby-core\"","webpack://tabby-agentdeck/external umd \"tabby-settings\"","webpack://tabby-agentdeck/external umd \"tabby-terminal\"","webpack://tabby-agentdeck/webpack/bootstrap","webpack://tabby-agentdeck/webpack/runtime/compat get default export","webpack://tabby-agentdeck/webpack/runtime/concatenation wrap","webpack://tabby-agentdeck/webpack/runtime/define property getters","webpack://tabby-agentdeck/webpack/runtime/hasOwnProperty shorthand","webpack://tabby-agentdeck/webpack/runtime/nonce","webpack://tabby-agentdeck/webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"@angular/common\"), require(\"@angular/core\"), require(\"@angular/forms\"), require(\"rxjs\"), require(\"tabby-core\"), require(\"tabby-settings\"), require(\"tabby-terminal\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"@angular/common\", \"@angular/core\", \"@angular/forms\", \"rxjs\", \"tabby-core\", \"tabby-settings\", \"tabby-terminal\"], factory);\n\telse {\n\t\tvar a = typeof exports === 'object' ? factory(require(\"@angular/common\"), require(\"@angular/core\"), require(\"@angular/forms\"), require(\"rxjs\"), require(\"tabby-core\"), require(\"tabby-settings\"), require(\"tabby-terminal\")) : factory(root[\"@angular/common\"], root[\"@angular/core\"], root[\"@angular/forms\"], root[\"rxjs\"], root[\"tabby-core\"], root[\"tabby-settings\"], root[\"tabby-terminal\"]);\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(global, (__WEBPACK_EXTERNAL_MODULE__4358__, __WEBPACK_EXTERNAL_MODULE__860__, __WEBPACK_EXTERNAL_MODULE__7182__, __WEBPACK_EXTERNAL_MODULE__3961__, __WEBPACK_EXTERNAL_MODULE__7650__, __WEBPACK_EXTERNAL_MODULE__3700__, __WEBPACK_EXTERNAL_MODULE__8349__) => {\nreturn ","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `body.agentdeck-active.ad-bg-clip .content-tab-active::before{left:var(--ad-bg-left) !important;top:var(--ad-bg-top) !important;right:auto !important;bottom:auto !important;width:var(--ad-bg-width) !important;height:var(--ad-bg-height) !important}#agentdeck-sidebar{display:flex;flex-direction:column;z-index:5;overflow:hidden;background:var(--ad-panel-bg, var(--bs-body-bg, #1e2127));font-size:12px;user-select:none;-webkit-app-region:no-drag}#agentdeck-sidebar.ad-dock-right{border-left:1px solid rgba(255,255,255,.08)}#agentdeck-sidebar.ad-dock-left{border-right:1px solid rgba(255,255,255,.08)}#agentdeck-sidebar.ad-dock-top{border-bottom:1px solid rgba(255,255,255,.08)}#agentdeck-sidebar.ad-dock-bottom{border-top:1px solid rgba(255,255,255,.08)}#agentdeck-sidebar.ad-dock-top .ad-list,#agentdeck-sidebar.ad-dock-bottom .ad-list{display:flex;flex-wrap:wrap;align-content:flex-start;gap:0 6px;overflow-y:auto}#agentdeck-sidebar.ad-dock-top .ad-tab,#agentdeck-sidebar.ad-dock-bottom .ad-tab{flex:0 0 220px;min-width:0}#agentdeck-sidebar.ad-dock-top .ad-group-head,#agentdeck-sidebar.ad-dock-bottom .ad-group-head{flex:0 0 100%;margin-top:2px}#agentdeck-sidebar .ad-head{display:flex;align-items:center;justify-content:space-between;padding:10px 12px 8px;letter-spacing:.12em;font-size:10px;font-weight:700;color:rgba(255,255,255,.4);-webkit-app-region:no-drag;cursor:grab}#agentdeck-sidebar .ad-head:active{cursor:grabbing}#agentdeck-sidebar .ad-resize{position:absolute;z-index:6;background:rgba(0,0,0,0);transition:background .12s ease}#agentdeck-sidebar .ad-resize:hover,body.ad-resizing #agentdeck-sidebar .ad-resize{background:rgba(97,175,239,.5)}#agentdeck-sidebar .ad-resize-right,#agentdeck-sidebar .ad-resize-left{top:0;bottom:0;width:6px;cursor:col-resize}#agentdeck-sidebar .ad-resize-right{left:0}#agentdeck-sidebar .ad-resize-left{right:0}#agentdeck-sidebar .ad-resize-top,#agentdeck-sidebar .ad-resize-bottom{left:0;right:0;height:6px;cursor:row-resize}#agentdeck-sidebar .ad-resize-bottom{top:0}#agentdeck-sidebar .ad-resize-top{bottom:0}#agentdeck-sidebar .ad-head-count{-webkit-app-region:no-drag;display:flex;align-items:center;gap:6px;flex:0 0 auto;white-space:nowrap;letter-spacing:0;color:rgba(255,255,255,.55)}#agentdeck-sidebar .ad-cnt{padding:1px 6px;border-radius:8px;background:rgba(255,255,255,.08);color:var(--ad-color, rgba(255, 255, 255, 0.55));font-size:10px;line-height:1.3;font-variant-numeric:tabular-nums}#agentdeck-sidebar .ad-list{flex:1 1 auto;overflow-y:auto;overflow-x:hidden;padding:2px 6px 8px;scroll-behavior:auto}#agentdeck-sidebar .ad-list::-webkit-scrollbar{width:8px}#agentdeck-sidebar .ad-list::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:4px}#agentdeck-sidebar .ad-list::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.24)}#agentdeck-sidebar .ad-group-head{display:flex;align-items:center;gap:5px;margin:7px 0 2px;padding:2px 4px;border-radius:4px;color:rgba(255,255,255,.42);font-size:10px;font-weight:700;letter-spacing:.06em;cursor:pointer;transition:background .1s ease,color .1s ease}#agentdeck-sidebar .ad-group-head:first-child{margin-top:1px}#agentdeck-sidebar .ad-group-head:hover{background:rgba(255,255,255,.05);color:rgba(255,255,255,.7)}#agentdeck-sidebar .ad-group-head.collapsed .ad-group-count{background:rgba(255,255,255,.14);color:rgba(255,255,255,.75)}#agentdeck-sidebar .ad-group-caret{flex:0 0 auto;width:9px;font-size:9px;line-height:1;opacity:.75}#agentdeck-sidebar .ad-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#agentdeck-sidebar .ad-group-head.filter-open .ad-group-caret{opacity:.45}#agentdeck-sidebar .ad-group-count{flex:0 0 auto;padding:0 5px;border-radius:8px;background:rgba(255,255,255,.08);color:rgba(255,255,255,.55);font-size:9.5px;line-height:1.5;letter-spacing:0;font-variant-numeric:tabular-nums}#agentdeck-sidebar .ad-tab{position:relative;display:flex;align-items:stretch;gap:8px;margin-bottom:3px;padding:7px 6px 7px 0;border-radius:5px;cursor:pointer;transition:background .1s ease}#agentdeck-sidebar .ad-tab:hover{background:rgba(255,255,255,.05)}#agentdeck-sidebar .ad-tab:hover .ad-close{opacity:.65}#agentdeck-sidebar .ad-tab.active{background:rgba(255,255,255,.1)}#agentdeck-sidebar .ad-tab.active .ad-title{color:#fff}#agentdeck-sidebar .ad-bar{flex:0 0 3px;border-radius:2px;background:var(--ad-color, #6b727d)}#agentdeck-sidebar .ad-body{flex:1 1 auto;min-width:0}#agentdeck-sidebar .ad-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:rgba(255,255,255,.82);font-size:12.5px;line-height:1.35}#agentdeck-sidebar .ad-meta{display:flex;align-items:center;gap:6px;margin-top:2px;font-size:10.5px;line-height:1.4;color:rgba(255,255,255,.45)}#agentdeck-sidebar .ad-badge{flex:0 1 auto;min-width:0;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ad-color, #6b727d);font-weight:600}#agentdeck-sidebar .ad-badge.pinned{text-decoration:underline dotted;text-underline-offset:2px}#agentdeck-sidebar .ad-subagents{flex:0 0 auto;padding:0 4px;border-radius:7px;background:rgba(86,182,194,.18);color:#56b6c2;font-weight:600;font-variant-numeric:tabular-nums}#agentdeck-sidebar .ad-prompt{display:flex;align-items:center;margin-top:2px;min-width:0;font-size:11px;line-height:1.4}#agentdeck-sidebar .ad-label{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:rgba(255,255,255,.6)}#agentdeck-sidebar .ad-label.empty{color:rgba(255,255,255,.25)}#agentdeck-sidebar .ad-elapsed{flex:0 0 auto;margin-left:auto;font-variant-numeric:tabular-nums;opacity:.55}#agentdeck-sidebar .ad-resume-head{display:flex;align-items:center;gap:5px;margin:5px 0 2px;padding:2px 4px 2px 11px;border-radius:4px;color:rgba(255,255,255,.34);font-size:10px;font-weight:700;letter-spacing:.06em;cursor:pointer;transition:background .1s ease,color .1s ease}#agentdeck-sidebar .ad-resume-head:hover{background:rgba(255,255,255,.05);color:rgba(255,255,255,.6)}#agentdeck-sidebar .ad-resume-head .ad-group-count{background:rgba(255,255,255,.06);color:rgba(255,255,255,.45)}#agentdeck-sidebar .ad-resume-head .ad-group-caret{margin-left:auto}#agentdeck-sidebar .ad-resume{display:flex;align-items:stretch;gap:8px;margin:0 0 3px 11px;padding:5px 6px 5px 0;border-radius:5px;cursor:pointer;opacity:.66;transition:background .1s ease,opacity .1s ease}#agentdeck-sidebar .ad-resume:hover{background:rgba(255,255,255,.05);opacity:1}#agentdeck-sidebar .ad-resume .ad-bar{background:#3a404b;background-image:linear-gradient(var(--ad-panel-bg, var(--bs-body-bg, #1e2127)) 50%, transparent 0);background-size:100% 5px}#agentdeck-sidebar .ad-resume .ad-title{font-size:12px;color:rgba(255,255,255,.72)}#agentdeck-sidebar .ad-resume .ad-meta{gap:5px;margin-top:1px;font-size:10px;color:rgba(255,255,255,.36)}#agentdeck-sidebar .re-was{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}#agentdeck-sidebar .re-was.s-done{color:rgba(152,195,121,.62)}#agentdeck-sidebar .re-was.s-error{color:rgba(224,108,117,.68)}#agentdeck-sidebar .re-was.s-limited{color:rgba(198,120,221,.62)}#agentdeck-sidebar .re-was.s-waiting{color:rgba(97,175,239,.62)}#agentdeck-sidebar .re-was.s-running{color:rgba(229,192,123,.62)}#agentdeck-sidebar .re-was.s-idle{color:rgba(255,255,255,.3)}#agentdeck-sidebar .re-was.live{padding:0 4px;border-radius:7px;background:rgba(229,192,123,.16);color:#e5c07b}#agentdeck-sidebar .re-when{flex:0 0 auto;margin-left:auto;padding-left:6px;font-variant-numeric:tabular-nums}#agentdeck-sidebar .ad-resume.open{opacity:.9}#agentdeck-sidebar .ad-resume.open .ad-bar{background:#e5c07b;background-image:none}#agentdeck-sidebar .ad-label-input{flex:1 1 auto;min-width:0;padding:0 4px;border:1px solid rgba(255,255,255,.25);border-radius:3px;background:rgba(0,0,0,.35);color:#fff;font-size:10.5px;outline:none}#agentdeck-sidebar .ad-label-input:focus{border-color:var(--ad-color, #61afef)}#agentdeck-sidebar .ad-close{flex:0 0 auto;align-self:center;width:18px;height:18px;padding:0;border:0;border-radius:3px;opacity:0;background:rgba(0,0,0,0);color:rgba(255,255,255,.8);font-size:15px;line-height:1;cursor:pointer;transition:opacity .1s ease,background .1s ease}#agentdeck-sidebar .ad-close:hover{opacity:1 !important;background:rgba(255,80,80,.35)}#agentdeck-sidebar .ad-foot{display:flex;gap:6px;padding:8px;border-top:1px solid rgba(255,255,255,.07)}#agentdeck-sidebar .ad-btn{flex:1 1 auto;padding:5px 8px;border:1px solid rgba(255,255,255,.12);border-radius:4px;background:rgba(0,0,0,0);color:rgba(255,255,255,.6);font-size:11px;cursor:pointer}#agentdeck-sidebar .ad-btn:hover{background:rgba(255,255,255,.08);color:#fff}#agentdeck-sidebar .ad-repair,#agentdeck-sidebar .ad-viewtoggle{flex:0 0 auto;min-width:28px;font-size:13px;line-height:1}#agentdeck-sidebar .ad-search{display:flex;flex:0 0 auto;gap:4px;align-items:center;padding:0 8px 6px;-webkit-app-region:no-drag}#agentdeck-sidebar .ad-search-input{flex:1 1 auto;min-width:0;padding:3px 6px;border:1px solid rgba(255,255,255,.14);border-radius:4px;outline:none;background:rgba(0,0,0,.28);color:rgba(255,255,255,.85);font-size:11px;line-height:1.4}#agentdeck-sidebar .ad-search-input::placeholder{color:rgba(255,255,255,.3)}#agentdeck-sidebar .ad-search-input:focus{border-color:rgba(97,175,239,.7);color:#fff}#agentdeck-sidebar .ad-search-clear{display:none;flex:0 0 auto;width:18px;height:18px;padding:0;border:0;border-radius:3px;background:rgba(0,0,0,0);color:rgba(255,255,255,.45);font-size:14px;line-height:1;cursor:pointer}#agentdeck-sidebar .ad-search-clear:hover{background:rgba(255,255,255,.12);color:#fff}#agentdeck-sidebar .ad-search.has-query .ad-search-clear{display:block}#agentdeck-sidebar .ad-cnt{cursor:pointer;user-select:none;transition:background .1s ease,color .1s ease}#agentdeck-sidebar .ad-cnt:hover{background:rgba(255,255,255,.16)}#agentdeck-sidebar .ad-cnt.active{box-shadow:inset 0 0 0 1px var(--ad-color, #61afef);background:rgba(255,255,255,.2);color:var(--ad-color, #fff)}#agentdeck-sidebar .ad-empty{padding:10px 8px;color:rgba(255,255,255,.42);text-align:center;word-break:break-all;font-size:11px;line-height:1.5}#agentdeck-sidebar .ad-tab.ad-nav-focus,#agentdeck-sidebar .ad-group-head.ad-nav-focus{box-shadow:inset 0 0 0 1px rgba(97,175,239,.85);background:rgba(97,175,239,.1)}#agentdeck-sidebar .ad-tab.active.ad-nav-focus{background:rgba(255,255,255,.14)}#agentdeck-sidebar .ad-list:focus,#agentdeck-sidebar .ad-list:focus-visible{outline:none}#agentdeck-sidebar .ad-tab.ad-dragging{opacity:.45;background:rgba(255,255,255,.06);outline:1px dashed rgba(255,255,255,.28);outline-offset:-1px}#agentdeck-sidebar .ad-reorder-note{position:absolute;left:8px;right:8px;bottom:34px;z-index:3;padding:7px 9px;border:1px solid rgba(255,255,255,.12);border-radius:5px;background:rgba(38,42,49,.96);box-shadow:0 4px 14px rgba(0,0,0,.45);color:rgba(255,255,255,.78);font-size:11px;line-height:1.45;pointer-events:none}#agentdeck-sidebar.ad-dock-top .ad-search,#agentdeck-sidebar.ad-dock-bottom .ad-search{padding:0 8px 4px}#agentdeck-sidebar.ad-dock-top .ad-list .ad-empty,#agentdeck-sidebar.ad-dock-bottom .ad-list .ad-empty{flex:0 0 100%}#agentdeck-view{display:flex;flex-direction:column;z-index:5;overflow:hidden;background:var(--ad-panel-bg, var(--bs-body-bg, #1e2127));font-size:12px;-webkit-app-region:no-drag}#agentdeck-view.ad-view-right{border-left:1px solid rgba(255,255,255,.08)}#agentdeck-view.ad-view-left{border-right:1px solid rgba(255,255,255,.08)}#agentdeck-view.ad-view-dropping{outline:1px dashed rgba(97,175,239,.8);outline-offset:-3px}#agentdeck-view .ad-view-head{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:8px 8px 6px 12px;border-bottom:1px solid rgba(255,255,255,.06);user-select:none}#agentdeck-view .ad-view-title{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:rgba(255,255,255,.82);font-weight:600}#agentdeck-view .ad-view-tools{display:flex;flex:0 0 auto;gap:2px}#agentdeck-view .ad-view-btn{min-width:24px;padding:2px 5px;border:0;border-radius:4px;background:rgba(0,0,0,0);color:rgba(255,255,255,.5);font-size:12px;line-height:1.2;cursor:pointer}#agentdeck-view .ad-view-btn:hover{background:rgba(255,255,255,.1);color:#fff}#agentdeck-view .ad-view-btn.ad-view-btn-on{background:rgba(97,175,239,.22);color:#9ecbff}#agentdeck-view .ad-view-path{display:flex;flex-wrap:wrap;gap:4px;padding:6px 8px;border-bottom:1px solid rgba(255,255,255,.06)}#agentdeck-view .ad-view-path input{width:100%;padding:4px 6px;border:1px solid rgba(255,255,255,.14);border-radius:4px;background:rgba(0,0,0,.25);color:#e6e6e6;font-family:monospace;font-size:11px}#agentdeck-view .ad-view-path input:focus{outline:0;border-color:rgba(97,175,239,.7)}#agentdeck-view .ad-view-path-note{width:100%;overflow:hidden;color:rgba(229,192,123,.9);font-size:11px;text-overflow:ellipsis;white-space:nowrap}#agentdeck-view .ad-view-path-note:empty{display:none}#agentdeck-view .ad-view-find{display:flex;align-items:center;gap:4px;padding:6px 8px;border-bottom:1px solid rgba(255,255,255,.06)}#agentdeck-view .ad-view-find input{flex:1 1 auto;min-width:0;padding:4px 6px;border:1px solid rgba(255,255,255,.14);border-radius:4px;background:rgba(0,0,0,.25);color:#e6e6e6;font-family:monospace;font-size:11px}#agentdeck-view .ad-view-find input:focus{outline:0;border-color:rgba(97,175,239,.7)}#agentdeck-view .ad-view-find-count{flex:0 0 auto;min-width:44px;color:rgba(255,255,255,.45);font-size:11px;text-align:right}#agentdeck-view mark.ad-find-hit{border-radius:2px;background:rgba(229,192,123,.35);color:inherit}#agentdeck-view mark.ad-find-cur{background:rgba(229,192,123,.85);color:#1a1a1a}#agentdeck-view .ad-view-editbar{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:5px 8px;border-top:1px solid rgba(255,255,255,.06);background:rgba(0,0,0,.18)}#agentdeck-view .ad-view-edit-note{overflow:hidden;color:rgba(255,255,255,.5);font-size:11px;text-overflow:ellipsis;white-space:nowrap}#agentdeck-view .ad-view-edit-btns{display:flex;flex:0 0 auto;gap:4px}#agentdeck-view .ad-view-edit-save,#agentdeck-view .ad-view-edit-cancel{padding:2px 10px;border:1px solid rgba(255,255,255,.14);border-radius:4px;background:rgba(0,0,0,0);color:rgba(255,255,255,.75);font-size:11px;cursor:pointer}#agentdeck-view .ad-view-edit-save:hover:not(:disabled),#agentdeck-view .ad-view-edit-cancel:hover:not(:disabled){border-color:rgba(255,255,255,.3);background:rgba(255,255,255,.08);color:#fff}#agentdeck-view .ad-view-edit-save:disabled,#agentdeck-view .ad-view-edit-cancel:disabled{opacity:.35;cursor:default}#agentdeck-view .ad-view-edit-save{border-color:rgba(97,175,239,.5);color:#9ecbff}#agentdeck-view textarea.ad-view-edit{display:block;box-sizing:border-box;width:100%;height:100%;min-height:200px;padding:6px 8px;border:0;background:rgba(0,0,0,.22);color:#e6e6e6;font-family:monospace;font-size:12px;line-height:1.5;resize:none;tab-size:4}#agentdeck-view textarea.ad-view-edit:focus{outline:0}#agentdeck-view .ad-view-tabs{display:flex;flex-wrap:wrap;gap:4px;padding:6px 8px;border-bottom:1px solid rgba(255,255,255,.06);user-select:none}#agentdeck-view .ad-view-tab{max-width:100%;overflow:hidden;padding:2px 7px;border:1px solid rgba(255,255,255,.1);border-radius:10px;background:rgba(0,0,0,0);color:rgba(255,255,255,.55);white-space:nowrap;text-overflow:ellipsis;font-size:11px;cursor:pointer}#agentdeck-view .ad-view-tab:hover{color:#fff;border-color:rgba(255,255,255,.25)}#agentdeck-view .ad-view-tab.ad-view-tab-on{border-color:rgba(97,175,239,.6);background:rgba(97,175,239,.14);color:#cfe6ff}#agentdeck-view .ad-view-body{flex:1 1 auto;overflow:auto;padding:10px 12px 16px;color:rgba(255,255,255,.85);user-select:text}#agentdeck-view .ad-view-foot{flex:0 0 auto;overflow:hidden;padding:5px 10px;border-top:1px solid rgba(255,255,255,.06);color:rgba(255,255,255,.35);white-space:nowrap;text-overflow:ellipsis;font-size:10px}#agentdeck-view .ad-view-resize{position:absolute;top:0;bottom:0;width:6px;cursor:col-resize;z-index:6}#agentdeck-view.ad-view-right .ad-view-resize{left:-2px}#agentdeck-view.ad-view-left .ad-view-resize{right:-2px}#agentdeck-view .ad-view-empty{padding:8px 2px;color:rgba(255,255,255,.55);line-height:1.7}#agentdeck-view .ad-view-empty ul{padding-left:18px;margin:6px 0 0}#agentdeck-view .ad-view-empty li{margin:2px 0}#agentdeck-view .ad-view-dim{color:rgba(255,255,255,.35);font-size:11px}#agentdeck-view .ad-view-image{display:flex;align-items:flex-start;justify-content:center}#agentdeck-view .ad-view-image img{max-width:100%;height:auto;background:rgba(255,255,255,.04)}#agentdeck-view .ad-view-code{display:flex;gap:8px;font-family:monospace;font-size:11px;line-height:1.5}#agentdeck-view .ad-view-code pre{margin:0;white-space:pre}#agentdeck-view .ad-view-code .ad-view-gutter{flex:0 0 auto;color:rgba(255,255,255,.25);text-align:right;user-select:none}#agentdeck-view .ad-view-code .ad-view-src{flex:1 1 auto;overflow-x:auto;color:rgba(255,255,255,.85)}#agentdeck-view .ad-view-table{overflow-x:auto}#agentdeck-view .ad-view-table table{border-collapse:collapse;font-size:11px}#agentdeck-view .ad-view-table th,#agentdeck-view .ad-view-table td{max-width:260px;overflow:hidden;padding:3px 6px;border:1px solid rgba(255,255,255,.08);white-space:nowrap;text-overflow:ellipsis}#agentdeck-view .ad-view-table th{position:sticky;top:0;background:#262a31;color:rgba(255,255,255,.7)}#agentdeck-view .ad-view-table .ad-view-rownum{color:rgba(255,255,255,.3);text-align:right}#agentdeck-view .ad-view-md{line-height:1.65;word-break:break-word}#agentdeck-view .ad-view-md h1,#agentdeck-view .ad-view-md h2,#agentdeck-view .ad-view-md h3,#agentdeck-view .ad-view-md h4,#agentdeck-view .ad-view-md h5,#agentdeck-view .ad-view-md h6{margin:1.1em 0 .5em;color:#fff;line-height:1.3}#agentdeck-view .ad-view-md h1{font-size:18px}#agentdeck-view .ad-view-md h2{font-size:16px;padding-bottom:3px;border-bottom:1px solid rgba(255,255,255,.1)}#agentdeck-view .ad-view-md h3{font-size:14px}#agentdeck-view .ad-view-md h4,#agentdeck-view .ad-view-md h5,#agentdeck-view .ad-view-md h6{font-size:13px}#agentdeck-view .ad-view-md p{margin:.6em 0}#agentdeck-view .ad-view-md a{color:#61afef;text-decoration:none;cursor:pointer}#agentdeck-view .ad-view-md a:hover{text-decoration:underline}#agentdeck-view .ad-view-md code{padding:1px 4px;border-radius:3px;background:rgba(255,255,255,.08);font-family:monospace;font-size:11px}#agentdeck-view .ad-view-md pre{overflow-x:auto;margin:.7em 0;padding:8px 10px;border:1px solid rgba(255,255,255,.07);border-radius:5px;background:rgba(0,0,0,.28)}#agentdeck-view .ad-view-md pre code{padding:0;background:rgba(0,0,0,0);line-height:1.5}#agentdeck-view .ad-view-md ul,#agentdeck-view .ad-view-md ol{padding-left:20px;margin:.5em 0}#agentdeck-view .ad-view-md li{margin:.15em 0}#agentdeck-view .ad-view-md .ad-md-task{list-style:none;margin-left:-14px}#agentdeck-view .ad-view-md .ad-md-check{color:rgba(255,255,255,.6)}#agentdeck-view .ad-view-md blockquote{margin:.7em 0;padding:2px 0 2px 10px;border-left:3px solid rgba(255,255,255,.18);color:rgba(255,255,255,.6)}#agentdeck-view .ad-view-md hr{margin:1.2em 0;border:0;border-top:1px solid rgba(255,255,255,.12)}#agentdeck-view .ad-view-md table{display:block;overflow-x:auto;border-collapse:collapse;margin:.7em 0;font-size:11px}#agentdeck-view .ad-view-md th,#agentdeck-view .ad-view-md td{padding:4px 8px;border:1px solid rgba(255,255,255,.1);text-align:left}#agentdeck-view .ad-view-md th{background:rgba(255,255,255,.05);color:#fff}#agentdeck-view .ad-view-md img{max-width:100%;border-radius:4px}#agentdeck-view .ad-view-md .ad-md-noimg{padding:1px 5px;border-radius:3px;background:rgba(255,255,255,.06);color:rgba(255,255,255,.45);font-size:11px}#agentdeck-view .ad-view-modes{display:flex;flex:0 0 auto;gap:4px;padding:6px 8px;border-bottom:1px solid rgba(255,255,255,.06);user-select:none}#agentdeck-view .ad-view-mode{flex:0 0 auto;padding:3px 12px;border:1px solid rgba(255,255,255,.1);border-radius:4px;background:rgba(0,0,0,0);color:rgba(255,255,255,.55);font-size:11px;cursor:pointer}#agentdeck-view .ad-view-mode:hover{border-color:rgba(255,255,255,.25);color:#fff}#agentdeck-view .ad-view-mode.ad-view-mode-on{border-color:rgba(97,175,239,.6);background:rgba(97,175,239,.14);color:#cfe6ff}#agentdeck-view .ad-view-scope{flex:0 0 auto;margin-left:auto;padding:3px 10px;border:1px dashed rgba(255,255,255,.18);border-radius:4px;background:rgba(0,0,0,0);color:rgba(255,255,255,.55);font-size:11px;cursor:pointer}#agentdeck-view .ad-view-scope:hover{border-color:rgba(255,255,255,.35);color:#fff}#agentdeck-view .ad-view-scope.ad-view-scope-all{border-style:solid;border-color:rgba(229,192,123,.5);color:#e5c07b}#agentdeck-view .ad-view-diff .ad-plus{color:#98c379}#agentdeck-view .ad-view-diff .ad-minus{color:#e06c75}#agentdeck-view .ad-view-diff-sum{padding-bottom:6px;color:rgba(255,255,255,.8);font-weight:600}#agentdeck-view .ad-view-diff-list{margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid rgba(255,255,255,.08)}#agentdeck-view .ad-view-diff-item{display:flex;align-items:center;gap:6px;width:100%;padding:2px 4px;border:0;border-radius:3px;background:rgba(0,0,0,0);color:rgba(255,255,255,.7);text-align:left;font-size:11px;cursor:pointer}#agentdeck-view .ad-view-diff-item:hover{background:rgba(255,255,255,.07)}#agentdeck-view .ad-view-diff-item .ad-view-diff-st{flex:0 0 auto;min-width:40px;color:rgba(255,255,255,.4);text-align:center;font-size:10px}#agentdeck-view .ad-view-diff-item .ad-view-diff-st-added{color:#98c379}#agentdeck-view .ad-view-diff-item .ad-view-diff-st-deleted{color:#e06c75}#agentdeck-view .ad-view-diff-item .ad-view-diff-st-renamed{color:#61afef}#agentdeck-view .ad-view-diff-item .ad-view-diff-name{flex:1 1 auto;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-family:monospace}#agentdeck-view .ad-view-diff-item .ad-view-diff-num{flex:0 0 auto}#agentdeck-view .ad-view-diff-item .ad-view-diff-num b{margin-left:5px;font-weight:500}#agentdeck-view .ad-view-diff-sub{margin:4px 0;color:rgba(255,255,255,.4);font-size:11px}#agentdeck-view .ad-view-diff-untracked{margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid rgba(255,255,255,.08)}#agentdeck-view .ad-view-diff-untracked .ad-view-diff-u{overflow:hidden;padding:1px 4px;color:rgba(255,255,255,.5);white-space:nowrap;text-overflow:ellipsis;font-family:monospace;font-size:11px}#agentdeck-view .ad-view-diff-untracked .ad-view-diff-u[data-ad-open]{cursor:pointer}#agentdeck-view .ad-view-diff-untracked .ad-view-diff-u[data-ad-open]:hover{background:rgba(255,255,255,.07);color:#fff}#agentdeck-view .ad-view-diff-file{margin-bottom:14px}#agentdeck-view .ad-view-diff-fhead{position:sticky;top:0;z-index:1;overflow:hidden;padding:4px 6px;border:1px solid rgba(255,255,255,.08);border-radius:4px 4px 0 0;background:#262a31;color:rgba(255,255,255,.8);white-space:nowrap;text-overflow:ellipsis;font-family:monospace;font-size:11px;cursor:pointer}#agentdeck-view .ad-view-diff-fhead:hover{color:#fff}#agentdeck-view .ad-view-diff-note{padding:4px 6px;border:1px solid rgba(255,255,255,.08);border-top:0;color:rgba(255,255,255,.35);font-size:11px}#agentdeck-view .ad-view-diff-lines{overflow-x:auto;border:1px solid rgba(255,255,255,.08);border-top:0;font-family:monospace;font-size:11px;line-height:1.5}#agentdeck-view .ad-dl{display:flex;min-width:100%;min-height:17px;white-space:pre}#agentdeck-view .ad-dl .ad-dl-no{flex:0 0 auto;width:38px;padding-right:6px;color:rgba(255,255,255,.25);text-align:right;user-select:none}#agentdeck-view .ad-dl .ad-dl-tx{flex:1 0 auto;padding-right:8px;color:rgba(255,255,255,.8)}#agentdeck-view .ad-dl-add{background:rgba(152,195,121,.12)}#agentdeck-view .ad-dl-add .ad-dl-tx{color:#b7d99b}#agentdeck-view .ad-dl-del{background:rgba(224,108,117,.12)}#agentdeck-view .ad-dl-del .ad-dl-tx{color:#eda3a9}#agentdeck-view .ad-dl-hunk{background:rgba(97,175,239,.1)}#agentdeck-view .ad-dl-hunk .ad-dl-tx{color:rgba(97,175,239,.85)}#agentdeck-view .ad-view-stage{flex:0 0 auto;min-width:44px;padding:0 4px;border:1px solid rgba(255,255,255,.14);border-radius:3px;color:rgba(255,255,255,.45);text-align:center;font-size:10px;cursor:pointer}#agentdeck-view .ad-view-stage:hover{border-color:rgba(255,255,255,.4);color:#fff}#agentdeck-view .ad-view-stage-staged{border-color:rgba(152,195,121,.5);background:rgba(152,195,121,.14);color:#b7d99b}#agentdeck-view .ad-view-stage-both{border-color:rgba(229,192,123,.5);background:rgba(229,192,123,.12);color:#e5c07b}#agentdeck-view .ad-view-stage-conflict{border-color:rgba(224,108,117,.6);background:rgba(224,108,117,.14);color:#eda3a9}#agentdeck-view .ad-dl[data-ad-ref-line],#agentdeck-view .ad-dl[data-ad-ref-del],#agentdeck-view .ad-cl[data-ad-ref-line]{cursor:pointer}#agentdeck-view .ad-dl[data-ad-ref-line]:hover,#agentdeck-view .ad-cl[data-ad-ref-line]:hover{box-shadow:inset 2px 0 0 rgba(97,175,239,.55)}#agentdeck-view .ad-dl.ad-ref-sel,#agentdeck-view .ad-cl.ad-ref-sel{box-shadow:inset 2px 0 0 #61afef;background:rgba(97,175,239,.22)}#agentdeck-view .ad-dl.ad-ref-sel .ad-dl-no,#agentdeck-view .ad-dl.ad-ref-sel .ad-cl-no,#agentdeck-view .ad-cl.ad-ref-sel .ad-dl-no,#agentdeck-view .ad-cl.ad-ref-sel .ad-cl-no{color:rgba(255,255,255,.6)}#agentdeck-view .ad-dl.ad-ref-sel .ad-dl-tx,#agentdeck-view .ad-dl.ad-ref-sel .ad-cl-tx,#agentdeck-view .ad-cl.ad-ref-sel .ad-dl-tx,#agentdeck-view .ad-cl.ad-ref-sel .ad-cl-tx{color:#fff}#agentdeck-view .ad-view-code.ad-view-code-rows{display:block;overflow-x:auto}#agentdeck-view .ad-cl{display:flex;min-width:100%;min-height:17px;white-space:pre}#agentdeck-view .ad-cl .ad-cl-no{flex:0 0 auto;width:44px;padding-right:8px;color:rgba(255,255,255,.25);text-align:right;user-select:none}#agentdeck-view .ad-cl .ad-cl-tx{flex:1 0 auto;padding-right:8px;color:rgba(255,255,255,.85)}#agentdeck-view .ad-view-ref{flex:0 0 auto;overflow:hidden;padding:4px 10px;border-top:1px solid rgba(255,255,255,.06);color:rgba(255,255,255,.5);white-space:nowrap;text-overflow:ellipsis;font-size:10px}#agentdeck-view .ad-view-ref-on{background:rgba(97,175,239,.14);color:#cfe6ff}#agentdeck-view .ad-view-commit{flex:0 0 auto;padding:6px 8px;border-top:1px solid rgba(255,255,255,.06)}#agentdeck-view .ad-view-commit-sum{margin-bottom:4px;color:rgba(255,255,255,.55);font-size:11px}#agentdeck-view .ad-view-commit-row{display:flex;gap:6px;align-items:center}#agentdeck-view .ad-view-commit-msg{flex:1 1 auto;min-width:0;padding:4px 6px;border:1px solid rgba(255,255,255,.14);border-radius:4px;background:rgba(0,0,0,.25);color:#e6e6e6;font-family:monospace;font-size:11px}#agentdeck-view .ad-view-commit-msg:focus{border-color:rgba(97,175,239,.6);outline:0}#agentdeck-view .ad-view-commit-go{flex:0 0 auto;padding:4px 10px;border:1px solid rgba(255,255,255,.14);border-radius:4px;background:rgba(0,0,0,0);color:rgba(255,255,255,.7);font-size:11px;cursor:pointer}#agentdeck-view .ad-view-commit-go:hover:not(:disabled){border-color:rgba(255,255,255,.35);color:#fff}#agentdeck-view .ad-view-commit-go:disabled{opacity:.45;cursor:default}#agentdeck-view .ad-view-commit-go.ad-view-commit-armed{border-color:rgba(224,108,117,.7);background:rgba(224,108,117,.18);color:#ffd7da}#agentdeck-view .ad-view-commit-note{margin-top:4px;overflow:hidden;color:rgba(255,255,255,.4);white-space:nowrap;text-overflow:ellipsis;font-size:11px}.ad-menu{position:fixed;z-index:10000;min-width:130px;padding:4px;border:1px solid rgba(255,255,255,.12);border-radius:6px;background:#262a31;box-shadow:0 6px 24px rgba(0,0,0,.5);font-size:12px;user-select:none}.ad-menu .ad-menu-item{padding:6px 10px;border-radius:4px;color:rgba(255,255,255,.75);cursor:pointer}.ad-menu .ad-menu-item:hover{background:rgba(255,255,255,.1);color:#fff}.ad-dock-overlay{position:fixed;inset:0;z-index:9998;pointer-events:none}.ad-dock-preview{position:fixed;display:none;border:1px solid rgba(97,175,239,.9);background:rgba(97,175,239,.22);box-shadow:0 0 0 9999px rgba(0,0,0,.18);transition:left .08s ease,top .08s ease,width .08s ease,height .08s ease}.ad-dock-zone{position:fixed;width:46px;height:46px;margin:-23px 0 0 -23px;border:1px solid rgba(255,255,255,.35);border-radius:6px;background:rgba(38,42,49,.92);box-shadow:0 4px 16px rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center}.ad-dock-zone .ad-dock-mark{width:26px;height:26px;border:1px solid rgba(255,255,255,.45);border-radius:3px}.ad-dock-zone.active{border-color:rgba(97,175,239,.95);background:rgba(97,175,239,.35)}.ad-dock-zone.ad-dock-zone-left .ad-dock-mark{border-left:4px solid rgba(97,175,239,.95)}.ad-dock-zone.ad-dock-zone-right .ad-dock-mark{border-right:4px solid rgba(97,175,239,.95)}.ad-dock-zone.ad-dock-zone-top .ad-dock-mark{border-top:4px solid rgba(97,175,239,.95)}.ad-dock-zone.ad-dock-zone-bottom .ad-dock-mark{border-bottom:4px solid rgba(97,175,239,.95)}.ad-reorder-line{position:fixed;z-index:9997;border-radius:1px;background:rgba(97,175,239,.95);box-shadow:0 0 5px rgba(97,175,239,.6);pointer-events:none}body.ad-reordering{cursor:grabbing}body.ad-reordering #agentdeck-sidebar,body.ad-reordering #agentdeck-sidebar *{cursor:grabbing !important}body.ad-reordering .content.main{pointer-events:none}body.ad-resizing{cursor:inherit}body.ad-resizing .content.main{pointer-events:none}body.agentdeck-active .content.main>.tab-bar{display:none !important}body.agentdeck-active .window{display:flex;flex-direction:row;position:relative;background:var(--ad-panel-bg, var(--bs-body-bg, #1e2127))}.ad-drop-ask{position:fixed;right:16px;bottom:16px;z-index:10000;min-width:260px;max-width:420px;padding:10px 12px;border:1px solid rgba(255,255,255,.16);border-radius:6px;background:rgba(24,26,30,.97);box-shadow:0 6px 24px rgba(0,0,0,.45);color:#e6e6e6;font-size:12px}.ad-drop-ask .ad-drop-ask-msg{overflow:hidden;margin-bottom:8px;white-space:nowrap;text-overflow:ellipsis;font-weight:600}.ad-drop-ask .ad-drop-ask-row{display:flex;gap:6px;align-items:center}.ad-drop-ask button{flex:1 1 auto;padding:5px 8px;border:1px solid rgba(255,255,255,.16);border-radius:4px;background:rgba(0,0,0,0);color:rgba(255,255,255,.85);font-size:12px;cursor:pointer}.ad-drop-ask button:hover{border-color:rgba(97,175,239,.6);background:rgba(97,175,239,.14);color:#fff}.ad-drop-ask .ad-drop-ask-close{flex:0 0 auto;min-width:26px;padding:5px 6px;color:rgba(255,255,255,.45)}.ad-drop-ask .ad-drop-ask-again{display:flex;gap:5px;align-items:center;margin-top:8px;margin-bottom:0;color:rgba(255,255,255,.5);font-size:11px;cursor:pointer}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles.scss\"],\"names\":[],\"mappings\":\"AAMA,6DACI,iCAAA,CACA,+BAAA,CACA,qBAAA,CACA,sBAAA,CACA,mCAAA,CACA,qCAAA,CAGJ,mBACI,YAAA,CACA,qBAAA,CAEA,SAAA,CACA,eAAA,CAEA,yDAAA,CACA,cAAA,CACA,gBAAA,CACA,0BAAA,CAGA,iCAAA,2CAAA,CACA,gCAAA,4CAAA,CACA,+BAAA,6CAAA,CACA,kCAAA,0CAAA,CAKI,mFACI,YAAA,CACA,cAAA,CACA,wBAAA,CACA,SAAA,CACA,eAAA,CAYJ,iFACI,cAAA,CACA,WAAA,CAKJ,+FACI,aAAA,CACA,cAAA,CAIR,4BACI,YAAA,CACA,kBAAA,CACA,6BAAA,CACA,qBAAA,CACA,oBAAA,CACA,cAAA,CACA,eAAA,CACA,0BAAA,CAEA,0BAAA,CACA,WAAA,CAEA,mCACI,eAAA,CAKR,8BACI,iBAAA,CACA,SAAA,CACA,wBAAA,CACA,+BAAA,CAEA,mFAEI,8BAAA,CAIR,uEAEI,KAAA,CACA,QAAA,CACA,SAAA,CACA,iBAAA,CAGJ,oCAAA,MAAA,CACA,mCAAA,OAAA,CAEA,uEAEI,MAAA,CACA,OAAA,CACA,UAAA,CACA,iBAAA,CAGJ,qCAAA,KAAA,CACA,kCAAA,QAAA,CAGA,kCACI,0BAAA,CACA,YAAA,CACA,kBAAA,CACA,OAAA,CACA,aAAA,CACA,kBAAA,CACA,gBAAA,CACA,2BAAA,CAGJ,2BACI,eAAA,CACA,iBAAA,CACA,gCAAA,CACA,gDAAA,CACA,cAAA,CACA,eAAA,CACA,iCAAA,CAIJ,4BACI,aAAA,CACA,eAAA,CACA,iBAAA,CACA,mBAAA,CAMA,oBAAA,CAEA,+CACI,SAAA,CAGJ,qDACI,gCAAA,CACA,iBAAA,CAEA,2DACI,gCAAA,CAOZ,kCACI,YAAA,CACA,kBAAA,CACA,OAAA,CACA,gBAAA,CACA,eAAA,CACA,iBAAA,CACA,2BAAA,CACA,cAAA,CACA,eAAA,CACA,oBAAA,CACA,cAAA,CACA,6CAAA,CAGA,8CACI,cAAA,CAGJ,wCACI,gCAAA,CACA,0BAAA,CAIJ,4DACI,gCAAA,CACA,2BAAA,CAIR,mCACI,aAAA,CACA,SAAA,CACA,aAAA,CACA,aAAA,CACA,WAAA,CAGJ,mCAEI,aAAA,CACA,WAAA,CACA,eAAA,CACA,sBAAA,CACA,kBAAA,CAOJ,8DACI,WAAA,CAGJ,mCACI,aAAA,CACA,aAAA,CACA,iBAAA,CACA,gCAAA,CACA,2BAAA,CACA,eAAA,CACA,eAAA,CACA,gBAAA,CACA,iCAAA,CAGJ,2BACI,iBAAA,CACA,YAAA,CACA,mBAAA,CACA,OAAA,CACA,iBAAA,CACA,qBAAA,CACA,iBAAA,CACA,cAAA,CACA,8BAAA,CAEA,iCACI,gCAAA,CAEA,2CACI,WAAA,CAIR,kCACI,+BAAA,CAEA,4CACI,UAAA,CAMZ,2BACI,YAAA,CACA,iBAAA,CACA,mCAAA,CAGJ,4BACI,aAAA,CACA,WAAA,CAGJ,6BACI,eAAA,CACA,sBAAA,CACA,kBAAA,CACA,2BAAA,CACA,gBAAA,CACA,gBAAA,CAGJ,4BACI,YAAA,CACA,kBAAA,CACA,OAAA,CACA,cAAA,CACA,gBAAA,CACA,eAAA,CACA,2BAAA,CAGJ,6BAEI,aAAA,CACA,WAAA,CACA,cAAA,CACA,eAAA,CACA,sBAAA,CACA,kBAAA,CACA,8BAAA,CACA,eAAA,CAGA,oCACI,gCAAA,CACA,yBAAA,CAKR,iCAEI,aAAA,CACA,aAAA,CACA,iBAAA,CAGA,+BAAA,CACA,aAAA,CACA,eAAA,CACA,iCAAA,CAIJ,8BACI,YAAA,CACA,kBAAA,CACA,cAAA,CACA,WAAA,CACA,cAAA,CACA,eAAA,CAGJ,6BACI,aAAA,CACA,eAAA,CACA,sBAAA,CACA,kBAAA,CACA,0BAAA,CAGA,mCACI,2BAAA,CAIR,+BACI,aAAA,CACA,gBAAA,CACA,iCAAA,CACA,WAAA,CAQJ,mCACI,YAAA,CACA,kBAAA,CACA,OAAA,CACA,gBAAA,CACA,wBAAA,CACA,iBAAA,CAEA,2BAAA,CACA,cAAA,CACA,eAAA,CACA,oBAAA,CACA,cAAA,CACA,6CAAA,CAEA,yCACI,gCAAA,CACA,0BAAA,CAGJ,mDACI,gCAAA,CACA,2BAAA,CAKJ,mDACI,gBAAA,CAIR,8BACI,YAAA,CACA,mBAAA,CACA,OAAA,CACA,mBAAA,CACA,qBAAA,CACA,iBAAA,CACA,cAAA,CAGA,WAAA,CACA,+CAAA,CAEA,oCACI,gCAAA,CACA,SAAA,CAIJ,sCACI,kBAAA,CACA,mGAAA,CACA,wBAAA,CAGJ,wCACI,cAAA,CACA,2BAAA,CAGJ,uCACI,OAAA,CACA,cAAA,CACA,cAAA,CACA,2BAAA,CAKR,2BACI,aAAA,CACA,WAAA,CACA,eAAA,CACA,sBAAA,CACA,kBAAA,CACA,eAAA,CAEA,kCAAA,2BAAA,CACA,mCAAA,2BAAA,CACA,qCAAA,2BAAA,CACA,qCAAA,0BAAA,CACA,qCAAA,2BAAA,CACA,kCAAA,0BAAA,CAGA,gCACI,aAAA,CACA,iBAAA,CACA,gCAAA,CACA,aAAA,CAIR,4BACI,aAAA,CACA,gBAAA,CACA,gBAAA,CACA,iCAAA,CAIJ,mCACI,UAAA,CAEA,2CACI,kBAAA,CACA,qBAAA,CAIR,mCACI,aAAA,CACA,WAAA,CACA,aAAA,CACA,sCAAA,CACA,iBAAA,CACA,0BAAA,CACA,UAAA,CACA,gBAAA,CACA,YAAA,CAEA,yCACI,qCAAA,CAIR,6BACI,aAAA,CACA,iBAAA,CACA,UAAA,CACA,WAAA,CACA,SAAA,CACA,QAAA,CACA,iBAAA,CACA,SAAA,CACA,wBAAA,CACA,0BAAA,CACA,cAAA,CACA,aAAA,CACA,cAAA,CACA,+CAAA,CAEA,mCACI,oBAAA,CACA,8BAAA,CAIR,4BACI,YAAA,CACA,OAAA,CACA,WAAA,CACA,0CAAA,CAGJ,2BACI,aAAA,CACA,eAAA,CACA,sCAAA,CACA,iBAAA,CACA,wBAAA,CACA,0BAAA,CACA,cAAA,CACA,cAAA,CAEA,iCACI,gCAAA,CACA,UAAA,CAKR,gEAEI,aAAA,CACA,cAAA,CACA,cAAA,CACA,aAAA,CAOJ,8BACI,YAAA,CACA,aAAA,CACA,OAAA,CACA,kBAAA,CACA,iBAAA,CACA,0BAAA,CAGJ,oCAEI,aAAA,CACA,WAAA,CACA,eAAA,CACA,sCAAA,CACA,iBAAA,CACA,YAAA,CACA,0BAAA,CACA,2BAAA,CACA,cAAA,CACA,eAAA,CAEA,iDACI,0BAAA,CAGJ,0CACI,gCAAA,CACA,UAAA,CAMR,oCACI,YAAA,CACA,aAAA,CACA,UAAA,CACA,WAAA,CACA,SAAA,CACA,QAAA,CACA,iBAAA,CACA,wBAAA,CACA,2BAAA,CACA,cAAA,CACA,aAAA,CACA,cAAA,CAEA,0CACI,gCAAA,CACA,UAAA,CAIR,yDACI,aAAA,CAKJ,2BACI,cAAA,CAEA,gBAAA,CACA,6CAAA,CAEA,iCACI,gCAAA,CAKJ,kCACI,mDAAA,CACA,+BAAA,CACA,2BAAA,CAMR,6BACI,gBAAA,CACA,2BAAA,CACA,iBAAA,CACA,oBAAA,CACA,cAAA,CACA,eAAA,CAYJ,uFAEI,+CAAA,CACA,8BAAA,CAKJ,+CACI,gCAAA,CAKJ,4EAEI,YAAA,CAMJ,uCACI,WAAA,CACA,gCAAA,CACA,wCAAA,CACA,mBAAA,CAKJ,oCACI,iBAAA,CACA,QAAA,CACA,SAAA,CACA,WAAA,CACA,SAAA,CACA,eAAA,CACA,sCAAA,CACA,iBAAA,CACA,6BAAA,CACA,qCAAA,CACA,2BAAA,CACA,cAAA,CACA,gBAAA,CAEA,mBAAA,CAKJ,uFAEI,iBAAA,CAGJ,uGAEI,aAAA,CAMR,gBACI,YAAA,CACA,qBAAA,CACA,SAAA,CACA,eAAA,CACA,yDAAA,CACA,cAAA,CACA,0BAAA,CAGA,8BAAA,2CAAA,CACA,6BAAA,4CAAA,CAEA,iCACI,sCAAA,CACA,mBAAA,CAGJ,8BACI,YAAA,CACA,kBAAA,CACA,6BAAA,CACA,OAAA,CACA,wBAAA,CACA,6CAAA,CACA,gBAAA,CAGJ,+BACI,eAAA,CACA,kBAAA,CACA,sBAAA,CACA,2BAAA,CACA,eAAA,CAGJ,+BACI,YAAA,CACA,aAAA,CACA,OAAA,CAGJ,6BACI,cAAA,CACA,eAAA,CACA,QAAA,CACA,iBAAA,CACA,wBAAA,CACA,0BAAA,CACA,cAAA,CACA,eAAA,CACA,cAAA,CAEA,mCACI,+BAAA,CACA,UAAA,CAIJ,4CACI,+BAAA,CACA,aAAA,CAIR,8BACI,YAAA,CACA,cAAA,CACA,OAAA,CACA,eAAA,CACA,6CAAA,CAEA,oCACI,UAAA,CACA,eAAA,CACA,sCAAA,CACA,iBAAA,CACA,0BAAA,CACA,aAAA,CACA,qBAAA,CACA,cAAA,CAEA,0CACI,SAAA,CACA,gCAAA,CAMZ,mCACI,UAAA,CACA,eAAA,CACA,0BAAA,CACA,cAAA,CACA,sBAAA,CACA,kBAAA,CAEA,yCACI,YAAA,CAKR,8BACI,YAAA,CACA,kBAAA,CACA,OAAA,CACA,eAAA,CACA,6CAAA,CAEA,oCACI,aAAA,CACA,WAAA,CACA,eAAA,CACA,sCAAA,CACA,iBAAA,CACA,0BAAA,CACA,aAAA,CACA,qBAAA,CACA,cAAA,CAEA,0CACI,SAAA,CACA,gCAAA,CAKZ,oCACI,aAAA,CACA,cAAA,CACA,2BAAA,CACA,cAAA,CACA,gBAAA,CAIJ,iCACI,iBAAA,CACA,gCAAA,CACA,aAAA,CAGJ,iCACI,gCAAA,CACA,aAAA,CAIJ,iCACI,YAAA,CACA,kBAAA,CACA,6BAAA,CACA,OAAA,CACA,eAAA,CACA,0CAAA,CACA,0BAAA,CAGJ,mCACI,eAAA,CACA,0BAAA,CACA,cAAA,CACA,sBAAA,CACA,kBAAA,CAGJ,mCACI,YAAA,CACA,aAAA,CACA,OAAA,CAGJ,wEAEI,gBAAA,CACA,sCAAA,CACA,iBAAA,CACA,wBAAA,CACA,2BAAA,CACA,cAAA,CACA,cAAA,CAEA,kHACI,iCAAA,CACA,gCAAA,CACA,UAAA,CAGJ,0FACI,WAAA,CACA,cAAA,CAIR,mCACI,gCAAA,CACA,aAAA,CAKJ,sCACI,aAAA,CACA,qBAAA,CACA,UAAA,CACA,WAAA,CACA,gBAAA,CACA,eAAA,CACA,QAAA,CACA,0BAAA,CACA,aAAA,CACA,qBAAA,CACA,cAAA,CACA,eAAA,CACA,WAAA,CACA,UAAA,CAEA,4CACI,SAAA,CAKR,8BACI,YAAA,CACA,cAAA,CACA,OAAA,CACA,eAAA,CACA,6CAAA,CACA,gBAAA,CAGJ,6BACI,cAAA,CACA,eAAA,CACA,eAAA,CACA,qCAAA,CACA,kBAAA,CACA,wBAAA,CACA,2BAAA,CACA,kBAAA,CACA,sBAAA,CACA,cAAA,CACA,cAAA,CAEA,mCACI,UAAA,CACA,kCAAA,CAGJ,4CACI,gCAAA,CACA,+BAAA,CACA,aAAA,CAIR,8BACI,aAAA,CACA,aAAA,CACA,sBAAA,CACA,2BAAA,CAEA,gBAAA,CAGJ,8BACI,aAAA,CACA,eAAA,CACA,gBAAA,CACA,0CAAA,CACA,2BAAA,CACA,kBAAA,CACA,sBAAA,CACA,cAAA,CAIJ,gCACI,iBAAA,CACA,KAAA,CACA,QAAA,CACA,SAAA,CACA,iBAAA,CACA,SAAA,CAGJ,8CAAA,SAAA,CACA,6CAAA,UAAA,CAEA,+BACI,eAAA,CACA,2BAAA,CACA,eAAA,CAEA,kCAAA,iBAAA,CAAA,cAAA,CACA,kCAAA,YAAA,CAGJ,6BACI,2BAAA,CACA,cAAA,CAKJ,+BACI,YAAA,CACA,sBAAA,CACA,sBAAA,CAEA,mCACI,cAAA,CAEA,WAAA,CACA,gCAAA,CAIR,8BACI,YAAA,CACA,OAAA,CACA,qBAAA,CACA,cAAA,CACA,eAAA,CAEA,kCACI,QAAA,CACA,eAAA,CAGJ,8CACI,aAAA,CACA,2BAAA,CACA,gBAAA,CACA,gBAAA,CAGJ,2CACI,aAAA,CACA,eAAA,CACA,2BAAA,CAIR,+BACI,eAAA,CAEA,qCACI,wBAAA,CACA,cAAA,CAGJ,oEACI,eAAA,CACA,eAAA,CACA,eAAA,CACA,sCAAA,CACA,kBAAA,CACA,sBAAA,CAGJ,kCACI,eAAA,CACA,KAAA,CACA,kBAAA,CACA,0BAAA,CAGJ,+CACI,0BAAA,CACA,gBAAA,CAKR,4BACI,gBAAA,CACA,qBAAA,CAEA,0LACI,mBAAA,CACA,UAAA,CACA,eAAA,CAEJ,+BAAA,cAAA,CACA,+BAAA,cAAA,CAAA,kBAAA,CAAA,4CAAA,CACA,+BAAA,cAAA,CACA,6FAAA,cAAA,CAEA,8BAAA,aAAA,CAEA,8BACI,aAAA,CACA,oBAAA,CACA,cAAA,CAEA,oCAAA,yBAAA,CAGJ,iCACI,eAAA,CACA,iBAAA,CACA,gCAAA,CACA,qBAAA,CACA,cAAA,CAGJ,gCACI,eAAA,CACA,aAAA,CACA,gBAAA,CACA,sCAAA,CACA,iBAAA,CACA,0BAAA,CAEA,qCACI,SAAA,CACA,wBAAA,CACA,eAAA,CAIR,8DAAA,iBAAA,CAAA,aAAA,CACA,+BAAA,cAAA,CAEA,wCAAA,eAAA,CAAA,iBAAA,CACA,yCAAA,0BAAA,CAEA,uCACI,aAAA,CACA,sBAAA,CACA,2CAAA,CACA,0BAAA,CAGJ,+BACI,cAAA,CACA,QAAA,CACA,0CAAA,CAGJ,kCACI,aAAA,CACA,eAAA,CACA,wBAAA,CACA,aAAA,CACA,cAAA,CAGJ,8DACI,eAAA,CACA,qCAAA,CACA,eAAA,CAGJ,+BAAA,gCAAA,CAAA,UAAA,CAEA,gCACI,cAAA,CACA,iBAAA,CAGJ,yCACI,eAAA,CACA,iBAAA,CACA,gCAAA,CACA,2BAAA,CACA,cAAA,CAMR,+BACI,YAAA,CACA,aAAA,CACA,OAAA,CACA,eAAA,CACA,6CAAA,CACA,gBAAA,CAGJ,8BACI,aAAA,CACA,gBAAA,CACA,qCAAA,CACA,iBAAA,CACA,wBAAA,CACA,2BAAA,CACA,cAAA,CACA,cAAA,CAEA,oCACI,kCAAA,CACA,UAAA,CAGJ,8CACI,gCAAA,CACA,+BAAA,CACA,aAAA,CAOR,+BACI,aAAA,CACA,gBAAA,CACA,gBAAA,CACA,uCAAA,CACA,iBAAA,CACA,wBAAA,CACA,2BAAA,CACA,cAAA,CACA,cAAA,CAEA,qCACI,kCAAA,CACA,UAAA,CAIJ,iDACI,kBAAA,CACA,iCAAA,CACA,aAAA,CAKJ,uCAAA,aAAA,CACA,wCAAA,aAAA,CAIJ,kCACI,kBAAA,CACA,0BAAA,CACA,eAAA,CAGJ,mCACI,kBAAA,CACA,kBAAA,CACA,6CAAA,CAGJ,mCACI,YAAA,CACA,kBAAA,CACA,OAAA,CACA,UAAA,CACA,eAAA,CACA,QAAA,CACA,iBAAA,CACA,wBAAA,CACA,0BAAA,CACA,eAAA,CACA,cAAA,CACA,cAAA,CAEA,yCAAA,gCAAA,CAEA,oDACI,aAAA,CACA,cAAA,CACA,0BAAA,CACA,iBAAA,CACA,cAAA,CAGJ,0DAAA,aAAA,CACA,4DAAA,aAAA,CACA,4DAAA,aAAA,CAEA,sDACI,aAAA,CACA,eAAA,CACA,kBAAA,CACA,sBAAA,CAEA,qBAAA,CAGJ,qDACI,aAAA,CAEA,uDACI,eAAA,CACA,eAAA,CAKZ,kCACI,YAAA,CACA,0BAAA,CACA,cAAA,CAGJ,wCACI,kBAAA,CACA,kBAAA,CACA,6CAAA,CAEA,wDACI,eAAA,CACA,eAAA,CACA,0BAAA,CACA,kBAAA,CACA,sBAAA,CACA,qBAAA,CACA,cAAA,CAEA,sEACI,cAAA,CAEA,4EAAA,gCAAA,CAAA,UAAA,CAKZ,mCACI,kBAAA,CAIJ,oCACI,eAAA,CACA,KAAA,CACA,SAAA,CACA,eAAA,CACA,eAAA,CACA,sCAAA,CACA,yBAAA,CACA,kBAAA,CACA,0BAAA,CACA,kBAAA,CACA,sBAAA,CACA,qBAAA,CACA,cAAA,CACA,cAAA,CAEA,0CAAA,UAAA,CAGJ,mCACI,eAAA,CACA,sCAAA,CACA,YAAA,CACA,2BAAA,CACA,cAAA,CAGJ,oCACI,eAAA,CACA,sCAAA,CACA,YAAA,CACA,qBAAA,CACA,cAAA,CACA,eAAA,CAIJ,uBACI,YAAA,CAEA,cAAA,CACA,eAAA,CACA,eAAA,CAEA,iCACI,aAAA,CACA,UAAA,CACA,iBAAA,CACA,2BAAA,CACA,gBAAA,CACA,gBAAA,CAGJ,iCACI,aAAA,CACA,iBAAA,CACA,0BAAA,CAIR,2BACI,gCAAA,CAEA,qCAAA,aAAA,CAGJ,2BACI,gCAAA,CAEA,qCAAA,aAAA,CAGJ,4BACI,8BAAA,CAEA,sCAAA,0BAAA,CAMJ,+BACI,aAAA,CACA,cAAA,CACA,aAAA,CACA,sCAAA,CACA,iBAAA,CACA,2BAAA,CACA,iBAAA,CACA,cAAA,CACA,cAAA,CAEA,qCACI,iCAAA,CACA,UAAA,CAIR,sCACI,iCAAA,CACA,gCAAA,CACA,aAAA,CAGJ,oCACI,iCAAA,CACA,gCAAA,CACA,aAAA,CAGJ,wCACI,iCAAA,CACA,gCAAA,CACA,aAAA,CAQJ,0HAGI,cAAA,CAGJ,8FAEI,6CAAA,CAIJ,oEAEI,gCAAA,CACA,+BAAA,CAEA,gLAEI,0BAAA,CAGJ,gLAEI,UAAA,CAOR,gDACI,aAAA,CACA,eAAA,CAGJ,uBACI,YAAA,CAEA,cAAA,CACA,eAAA,CACA,eAAA,CAEA,iCACI,aAAA,CACA,UAAA,CACA,iBAAA,CACA,2BAAA,CACA,gBAAA,CACA,gBAAA,CAGJ,iCACI,aAAA,CACA,iBAAA,CACA,2BAAA,CAKR,6BACI,aAAA,CACA,eAAA,CACA,gBAAA,CACA,0CAAA,CACA,0BAAA,CACA,kBAAA,CACA,sBAAA,CACA,cAAA,CAIJ,gCACI,+BAAA,CACA,aAAA,CAIJ,gCACI,aAAA,CACA,eAAA,CACA,0CAAA,CAGJ,oCACI,iBAAA,CACA,2BAAA,CACA,cAAA,CAGJ,oCACI,YAAA,CACA,OAAA,CACA,kBAAA,CAGJ,oCACI,aAAA,CACA,WAAA,CACA,eAAA,CACA,sCAAA,CACA,iBAAA,CACA,0BAAA,CACA,aAAA,CACA,qBAAA,CACA,cAAA,CAEA,0CACI,gCAAA,CACA,SAAA,CAIR,mCACI,aAAA,CACA,gBAAA,CACA,sCAAA,CACA,iBAAA,CACA,wBAAA,CACA,0BAAA,CACA,cAAA,CACA,cAAA,CAEA,wDACI,kCAAA,CACA,UAAA,CAIJ,4CACI,WAAA,CACA,cAAA,CAIJ,wDACI,iCAAA,CACA,gCAAA,CACA,aAAA,CAIR,qCACI,cAAA,CACA,eAAA,CACA,0BAAA,CACA,kBAAA,CACA,sBAAA,CACA,cAAA,CAKR,SACI,cAAA,CACA,aAAA,CACA,eAAA,CACA,WAAA,CACA,sCAAA,CACA,iBAAA,CACA,kBAAA,CACA,oCAAA,CACA,cAAA,CACA,gBAAA,CAEA,uBACI,gBAAA,CACA,iBAAA,CACA,2BAAA,CACA,cAAA,CAEA,6BACI,+BAAA,CACA,UAAA,CAMZ,iBACI,cAAA,CACA,OAAA,CACA,YAAA,CAEA,mBAAA,CAIJ,iBACI,cAAA,CACA,YAAA,CACA,oCAAA,CACA,+BAAA,CACA,uCAAA,CACA,wEAAA,CAIJ,cACI,cAAA,CACA,UAAA,CACA,WAAA,CACA,sBAAA,CACA,sCAAA,CACA,iBAAA,CACA,6BAAA,CACA,qCAAA,CACA,YAAA,CACA,kBAAA,CACA,sBAAA,CAEA,4BACI,UAAA,CACA,WAAA,CACA,sCAAA,CACA,iBAAA,CAGJ,qBACI,iCAAA,CACA,+BAAA,CAIJ,8CAAA,0CAAA,CACA,+CAAA,2CAAA,CACA,6CAAA,yCAAA,CACA,gDAAA,4CAAA,CAOJ,iBACI,cAAA,CACA,YAAA,CACA,iBAAA,CACA,+BAAA,CACA,sCAAA,CAEA,mBAAA,CAIJ,mBACI,eAAA,CAIA,8EAEI,0BAAA,CAGJ,iCACI,mBAAA,CAKR,iBACI,cAAA,CAEA,+BACI,mBAAA,CAMJ,6CACI,uBAAA,CAGJ,8BACI,YAAA,CACA,kBAAA,CAEA,iBAAA,CAGA,yDAAA,CAQR,aACI,cAAA,CACA,UAAA,CACA,WAAA,CACA,aAAA,CACA,eAAA,CACA,eAAA,CACA,iBAAA,CACA,sCAAA,CACA,iBAAA,CACA,6BAAA,CACA,qCAAA,CACA,aAAA,CACA,cAAA,CAEA,8BACI,eAAA,CACA,iBAAA,CACA,kBAAA,CACA,sBAAA,CACA,eAAA,CAGJ,8BACI,YAAA,CACA,OAAA,CACA,kBAAA,CAGJ,oBACI,aAAA,CACA,eAAA,CACA,sCAAA,CACA,iBAAA,CACA,wBAAA,CACA,2BAAA,CACA,cAAA,CACA,cAAA,CAEA,0BACI,gCAAA,CACA,+BAAA,CACA,UAAA,CAKR,gCACI,aAAA,CACA,cAAA,CACA,eAAA,CACA,2BAAA,CAGJ,gCACI,YAAA,CACA,OAAA,CACA,kBAAA,CACA,cAAA,CACA,eAAA,CACA,0BAAA,CACA,cAAA,CACA,cAAA\",\"sourcesContent\":[\"// AgentDeck 사이드바 스타일\\r\\n// Tabby 테마 변수(--bs-*)를 우선 쓰되, 없을 때를 대비해 폴백 색을 함께 준다.\\r\\n\\r\\n// tabby-background 의 배경 이미지 레이어(.content-tab-active::before)를 터미널 영역으로 자른다.\\r\\n// 좌표 변수(--ad-bg-*)는 deck.service 의 syncBackgroundClip 이 relayout 마다 내려준다.\\r\\n// 그 플러그인은 런타임에 <style> 을 만들어 head 뒤쪽에 붙이므로 순서로는 못 이긴다 — !important 필수.\\r\\nbody.agentdeck-active.ad-bg-clip .content-tab-active::before {\\r\\n left: var(--ad-bg-left) !important;\\r\\n top: var(--ad-bg-top) !important;\\r\\n right: auto !important;\\r\\n bottom: auto !important;\\r\\n width: var(--ad-bg-width) !important;\\r\\n height: var(--ad-bg-height) !important;\\r\\n}\\r\\n\\r\\n#agentdeck-sidebar {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n // 실제 위치와 크기는 deck.service 의 relayout 이 인라인으로 준다 (도킹 방향에 따라 달라짐)\\r\\n z-index: 5;\\r\\n overflow: hidden;\\r\\n // --ad-panel-bg 는 agentdeck 이 sidebarOpacity 로 내려준다 (배경 이미지가 비치게)\\r\\n background: var(--ad-panel-bg, var(--bs-body-bg, #1e2127));\\r\\n font-size: 12px;\\r\\n user-select: none;\\r\\n -webkit-app-region: no-drag;\\r\\n\\r\\n // 붙어 있는 쪽 반대편에만 경계선을 그린다\\r\\n &.ad-dock-right { border-left: 1px solid rgba(255, 255, 255, 0.08); }\\r\\n &.ad-dock-left { border-right: 1px solid rgba(255, 255, 255, 0.08); }\\r\\n &.ad-dock-top { border-bottom: 1px solid rgba(255, 255, 255, 0.08); }\\r\\n &.ad-dock-bottom { border-top: 1px solid rgba(255, 255, 255, 0.08); }\\r\\n\\r\\n // 상/하 도킹은 세로가 짧으므로 목록을 가로로 흘린다\\r\\n &.ad-dock-top,\\r\\n &.ad-dock-bottom {\\r\\n .ad-list {\\r\\n display: flex;\\r\\n flex-wrap: wrap;\\r\\n align-content: flex-start;\\r\\n gap: 0 6px;\\r\\n overflow-y: auto;\\r\\n }\\r\\n\\r\\n // 한 줄에 여러 탭이 나란히 서므로 폭을 220px 로 못박는다 — 제목 길이에 따라\\r\\n // 들쭉날쭉하면 어느 칸이 어느 세션인지 눈으로 못 따라가고, 제목이 바뀔 때마다 자리가 밀린다.\\r\\n //\\r\\n // **`min-width: 0` 이 있어야 `flex-basis` 가 살아남는다.** flex 아이템은\\r\\n // `min-width: auto`(초깃값) + `overflow: visible` 이면 **자동 최소 크기**가 걸려\\r\\n // 최소내용폭(min-content) 밑으로는 줄지 않는다. 그래서 제목이 긴 탭은 220 을 밀어올렸다\\r\\n // (2026-09-09 CDP 실측: 1700 창·탭 6개에서 220 지정인데 384.7px, 한 줄에 4개 +\\r\\n // 둘째 줄이 반쯤 잘림). 폭을 못박아도 제목은 읽힌다 — `.ad-title` 이 이미 말줄임을\\r\\n // 갖고 있고, 220 은 좌/우 도킹의 평소 줄 폭(사이드바 기본 200px)보다 오히려 넓다.\\r\\n .ad-tab {\\r\\n flex: 0 0 220px;\\r\\n min-width: 0;\\r\\n }\\r\\n\\r\\n // 그룹 헤더는 한 줄을 다 차지해 가로 흘림을 끊는다 — 그래야 헤더 아래 줄부터 그 그룹의\\r\\n // 탭이 흐른다. 헤더를 div 로 감싸는 대신 형제로 두는 이유가 이것이다(deck.service renderGroupHead)\\r\\n .ad-group-head {\\r\\n flex: 0 0 100%;\\r\\n margin-top: 2px;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-head {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n padding: 10px 12px 8px;\\r\\n letter-spacing: 0.12em;\\r\\n font-size: 10px;\\r\\n font-weight: 700;\\r\\n color: rgba(255, 255, 255, 0.4);\\r\\n // 헤더를 잡아 끌면 도킹 방향을 바꾼다 (OS 창 이동에 뺏기면 안 되므로 no-drag)\\r\\n -webkit-app-region: no-drag;\\r\\n cursor: grab;\\r\\n\\r\\n &:active {\\r\\n cursor: grabbing;\\r\\n }\\r\\n }\\r\\n\\r\\n // 경계선 — 잡아 끌면 크기가 바뀐다. 붙어 있는 쪽 반대편 가장자리에 놓는다\\r\\n .ad-resize {\\r\\n position: absolute;\\r\\n z-index: 6;\\r\\n background: transparent;\\r\\n transition: background 0.12s ease;\\r\\n\\r\\n &:hover,\\r\\n body.ad-resizing & {\\r\\n background: rgba(97, 175, 239, 0.5);\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-resize-right,\\r\\n .ad-resize-left {\\r\\n top: 0;\\r\\n bottom: 0;\\r\\n width: 6px;\\r\\n cursor: col-resize;\\r\\n }\\r\\n\\r\\n .ad-resize-right { left: 0; }\\r\\n .ad-resize-left { right: 0; }\\r\\n\\r\\n .ad-resize-top,\\r\\n .ad-resize-bottom {\\r\\n left: 0;\\r\\n right: 0;\\r\\n height: 6px;\\r\\n cursor: row-resize;\\r\\n }\\r\\n\\r\\n .ad-resize-bottom { top: 0; }\\r\\n .ad-resize-top { bottom: 0; }\\r\\n\\r\\n // 상태별 집계 칩 한 줄 — `⏸ 2 ● 3 ○ 1`. 헤더 높이는 총 개수만 있던 때와 같게 유지한다\\r\\n .ad-head-count {\\r\\n -webkit-app-region: no-drag;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n flex: 0 0 auto;\\r\\n white-space: nowrap;\\r\\n letter-spacing: 0;\\r\\n color: rgba(255, 255, 255, 0.55);\\r\\n }\\r\\n\\r\\n .ad-cnt {\\r\\n padding: 1px 6px;\\r\\n border-radius: 8px;\\r\\n background: rgba(255, 255, 255, 0.08);\\r\\n color: var(--ad-color, rgba(255, 255, 255, 0.55));\\r\\n font-size: 10px;\\r\\n line-height: 1.3;\\r\\n font-variant-numeric: tabular-nums;\\r\\n }\\r\\n\\r\\n // 요구 2-1: 탭이 많아지면 이 영역만 스크롤된다\\r\\n .ad-list {\\r\\n flex: 1 1 auto;\\r\\n overflow-y: auto;\\r\\n overflow-x: hidden;\\r\\n padding: 2px 6px 8px;\\r\\n // **못박아 둔다** — 드래그 자동 스크롤(deck.service `dragScrollTick`)이 매 프레임\\r\\n // `scrollTop` 에 몇 px 를 더하는 식으로 목록을 흘린다. 여기가 `smooth` 면 그 대입마다\\r\\n // 새 애니메이션이 시작돼 서로를 덮어써서 목록이 기어가거나 아예 멈춘다.\\r\\n // 지금 이 값을 `smooth` 로 켜는 곳은 없지만(전역 검색 0건), 나중에 누가 켜면\\r\\n // 그 기능이 **조용히** 못 쓰게 되는 자리라 의도를 여기 남긴다.\\r\\n scroll-behavior: auto;\\r\\n\\r\\n &::-webkit-scrollbar {\\r\\n width: 8px;\\r\\n }\\r\\n\\r\\n &::-webkit-scrollbar-thumb {\\r\\n background: rgba(255, 255, 255, 0.14);\\r\\n border-radius: 4px;\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.24);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // 프로젝트(작업 폴더) 그룹 헤더 — `▾ tabby-agentdeck 3`. 그룹이 둘 이상일 때만 그린다.\\r\\n // 헤더 자체는 탭보다 작고 어둡게 둔다 — 세션 목록이 주인공이고 이건 칸막이다.\\r\\n .ad-group-head {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 5px;\\r\\n margin: 7px 0 2px;\\r\\n padding: 2px 4px;\\r\\n border-radius: 4px;\\r\\n color: rgba(255, 255, 255, 0.42);\\r\\n font-size: 10px;\\r\\n font-weight: 700;\\r\\n letter-spacing: 0.06em;\\r\\n cursor: pointer;\\r\\n transition: background 0.1s ease, color 0.1s ease;\\r\\n\\r\\n // 첫 그룹은 목록 맨 위에 붙어야 자연스럽다 (.ad-list 가 이미 위쪽 여백을 준다)\\r\\n &:first-child {\\r\\n margin-top: 1px;\\r\\n }\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.05);\\r\\n color: rgba(255, 255, 255, 0.7);\\r\\n }\\r\\n\\r\\n // 접힌 그룹은 \\\"여기 뭔가 숨어 있다\\\" 가 보여야 한다 — 개수 칩을 살짝 밝게\\r\\n &.collapsed .ad-group-count {\\r\\n background: rgba(255, 255, 255, 0.14);\\r\\n color: rgba(255, 255, 255, 0.75);\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-group-caret {\\r\\n flex: 0 0 auto;\\r\\n width: 9px;\\r\\n font-size: 9px;\\r\\n line-height: 1;\\r\\n opacity: 0.75;\\r\\n }\\r\\n\\r\\n .ad-group-label {\\r\\n // 폴더 이름은 길 수 있다(사이드바는 200~560px) — 개수 칩을 밀어내지 않게 줄이고 말줄임\\r\\n flex: 0 1 auto;\\r\\n min-width: 0;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n }\\r\\n\\r\\n // 검색 때문에 임시로 펴 둔 그룹 — 캐럿만 흐리게 해서 \\\"내가 접어 둔 그룹인데 지금은\\r\\n // 검색 때문에 보이는 중\\\" 임을 알린다. 이유 전문은 헤더 title 에 있다(renderGroupHead).\\r\\n // 줄 배경이나 라벨 색을 바꾸지 않는 이유: 검색 결과 자체가 이미 강조된 화면이라\\r\\n // 여기서 또 강조하면 무엇이 걸린 줄인지가 흐려진다.\\r\\n .ad-group-head.filter-open .ad-group-caret {\\r\\n opacity: 0.45;\\r\\n }\\r\\n\\r\\n .ad-group-count {\\r\\n flex: 0 0 auto;\\r\\n padding: 0 5px;\\r\\n border-radius: 8px;\\r\\n background: rgba(255, 255, 255, 0.08);\\r\\n color: rgba(255, 255, 255, 0.55);\\r\\n font-size: 9.5px;\\r\\n line-height: 1.5;\\r\\n letter-spacing: 0;\\r\\n font-variant-numeric: tabular-nums;\\r\\n }\\r\\n\\r\\n .ad-tab {\\r\\n position: relative;\\r\\n display: flex;\\r\\n align-items: stretch;\\r\\n gap: 8px;\\r\\n margin-bottom: 3px;\\r\\n padding: 7px 6px 7px 0;\\r\\n border-radius: 5px;\\r\\n cursor: pointer;\\r\\n transition: background 0.1s ease;\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.05);\\r\\n\\r\\n .ad-close {\\r\\n opacity: 0.65;\\r\\n }\\r\\n }\\r\\n\\r\\n &.active {\\r\\n background: rgba(255, 255, 255, 0.1);\\r\\n\\r\\n .ad-title {\\r\\n color: #fff;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // 상태색 표시 바\\r\\n .ad-bar {\\r\\n flex: 0 0 3px;\\r\\n border-radius: 2px;\\r\\n background: var(--ad-color, #6b727d);\\r\\n }\\r\\n\\r\\n .ad-body {\\r\\n flex: 1 1 auto;\\r\\n min-width: 0;\\r\\n }\\r\\n\\r\\n .ad-title {\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n color: rgba(255, 255, 255, 0.82);\\r\\n font-size: 12.5px;\\r\\n line-height: 1.35;\\r\\n }\\r\\n\\r\\n .ad-meta {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n margin-top: 2px;\\r\\n font-size: 10.5px;\\r\\n line-height: 1.4;\\r\\n color: rgba(255, 255, 255, 0.45);\\r\\n }\\r\\n\\r\\n .ad-badge {\\r\\n // 이유가 붙으면(승인대기 · Bash 권한) 길어질 수 있다 — 경과시간을 밀어내지 않게 줄이고 말줄임\\r\\n flex: 0 1 auto;\\r\\n min-width: 0;\\r\\n max-width: 100%;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n color: var(--ad-color, #6b727d);\\r\\n font-weight: 600;\\r\\n\\r\\n // 수동/훅으로 고정된 상태는 밑줄로 구분\\r\\n &.pinned {\\r\\n text-decoration: underline dotted;\\r\\n text-underline-offset: 2px;\\r\\n }\\r\\n }\\r\\n\\r\\n // 도는 서브에이전트 개수 (`❖3`) — 상태 배지 바로 뒤. 자리 선정 이유는 deck.service `renderTab` 주석\\r\\n .ad-subagents {\\r\\n // 배지가 길어져도 이건 줄이지 않는다 — 개수는 한두 글자고, 줄어들면 읽을 수가 없다\\r\\n flex: 0 0 auto;\\r\\n padding: 0 4px;\\r\\n border-radius: 7px;\\r\\n // 상태색(`--ad-color`)을 쓰지 않는다 — 상태와 다른 축의 정보라 같은 색이면 배지의\\r\\n // 일부로 읽힌다. 배경까지 넣어 숫자가 상태 문구에 섞이지 않게 칩으로 떼어 둔다\\r\\n background: rgba(86, 182, 194, 0.18);\\r\\n color: #56b6c2;\\r\\n font-weight: 600;\\r\\n font-variant-numeric: tabular-nums;\\r\\n }\\r\\n\\r\\n // 두 번째 줄 — 마지막으로 보낸 프롬프트\\r\\n .ad-prompt {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n margin-top: 2px;\\r\\n min-width: 0;\\r\\n font-size: 11px;\\r\\n line-height: 1.4;\\r\\n }\\r\\n\\r\\n .ad-label {\\r\\n flex: 1 1 auto;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n color: rgba(255, 255, 255, 0.6);\\r\\n\\r\\n // 아직 프롬프트가 없는 탭 — 자리는 지키되 눈에 덜 걸리게\\r\\n &.empty {\\r\\n color: rgba(255, 255, 255, 0.25);\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-elapsed {\\r\\n flex: 0 0 auto;\\r\\n margin-left: auto;\\r\\n font-variant-numeric: tabular-nums;\\r\\n opacity: 0.55;\\r\\n }\\r\\n\\r\\n // ── 지난 세션 (닫힌 Claude Code 세션 이어받기) ─────────────────────────\\r\\n //\\r\\n // 그룹의 **서랍**이다 — 살아 있는 탭 뒤에 오고 기본은 접혀 있다.\\r\\n // 들여쓰기(11px)로 그룹 헤더보다 한 단계 안쪽임을 보인다: 이 줄들은 그룹에 속한\\r\\n // 목록이지 또 하나의 그룹이 아니다.\\r\\n .ad-resume-head {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 5px;\\r\\n margin: 5px 0 2px;\\r\\n padding: 2px 4px 2px 11px;\\r\\n border-radius: 4px;\\r\\n // 그룹 헤더(0.42)보다 더 죽인다 — 살아 있는 목록이 먼저 읽혀야 한다\\r\\n color: rgba(255, 255, 255, 0.34);\\r\\n font-size: 10px;\\r\\n font-weight: 700;\\r\\n letter-spacing: 0.06em;\\r\\n cursor: pointer;\\r\\n transition: background 0.1s ease, color 0.1s ease;\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.05);\\r\\n color: rgba(255, 255, 255, 0.6);\\r\\n }\\r\\n\\r\\n .ad-group-count {\\r\\n background: rgba(255, 255, 255, 0.06);\\r\\n color: rgba(255, 255, 255, 0.45);\\r\\n }\\r\\n\\r\\n // 캐럿은 오른쪽 끝으로 — 그룹 헤더는 캐럿이 앞에 있는데, 이 줄은 그룹의 하위라\\r\\n // 같은 자리에 두면 두 헤더가 같은 층으로 읽힌다\\r\\n .ad-group-caret {\\r\\n margin-left: auto;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-resume {\\r\\n display: flex;\\r\\n align-items: stretch;\\r\\n gap: 8px;\\r\\n margin: 0 0 3px 11px;\\r\\n padding: 5px 6px 5px 0;\\r\\n border-radius: 5px;\\r\\n cursor: pointer;\\r\\n // 죽은 세션은 **색이 아니라 형태**로 구분한다. 상태 6색(api.ts STATUS_STYLES)이 이미\\r\\n // 꽉 차 있어 일곱 번째 색을 들이면 배지가 뜻하는 바가 흐려진다\\r\\n opacity: 0.66;\\r\\n transition: background 0.1s ease, opacity 0.1s ease;\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.05);\\r\\n opacity: 1;\\r\\n }\\r\\n\\r\\n // 좌측 바를 점선으로 끊는다 — 살아 있는 줄의 실선 상태바와 한눈에 갈린다\\r\\n .ad-bar {\\r\\n background: #3a404b;\\r\\n background-image: linear-gradient(var(--ad-panel-bg, var(--bs-body-bg, #1e2127)) 50%, transparent 0);\\r\\n background-size: 100% 5px;\\r\\n }\\r\\n\\r\\n .ad-title {\\r\\n font-size: 12px;\\r\\n color: rgba(255, 255, 255, 0.72);\\r\\n }\\r\\n\\r\\n .ad-meta {\\r\\n gap: 5px;\\r\\n margin-top: 1px;\\r\\n font-size: 10px;\\r\\n color: rgba(255, 255, 255, 0.36);\\r\\n }\\r\\n }\\r\\n\\r\\n // 끝난 상태의 흔적 — 살아 있는 배지와 같은 세기로 칠하지 않는다(그러면 도는 줄로 읽힌다)\\r\\n .re-was {\\r\\n flex: 0 1 auto;\\r\\n min-width: 0;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n font-weight: 600;\\r\\n\\r\\n &.s-done { color: rgba(152, 195, 121, 0.62); }\\r\\n &.s-error { color: rgba(224, 108, 117, 0.68); }\\r\\n &.s-limited { color: rgba(198, 120, 221, 0.62); }\\r\\n &.s-waiting { color: rgba(97, 175, 239, 0.62); }\\r\\n &.s-running { color: rgba(229, 192, 123, 0.62); }\\r\\n &.s-idle { color: rgba(255, 255, 255, 0.3); }\\r\\n\\r\\n // 이미 열려 있는 세션 — 이건 죽지 않았으므로 상태색을 그대로 쓴다\\r\\n &.live {\\r\\n padding: 0 4px;\\r\\n border-radius: 7px;\\r\\n background: rgba(229, 192, 123, 0.16);\\r\\n color: #e5c07b;\\r\\n }\\r\\n }\\r\\n\\r\\n .re-when {\\r\\n flex: 0 0 auto;\\r\\n margin-left: auto;\\r\\n padding-left: 6px;\\r\\n font-variant-numeric: tabular-nums;\\r\\n }\\r\\n\\r\\n // 열려 있는 세션은 흐리게 두지 않는다 — 지금 도는 작업이라 목록에서도 살아 보여야 한다\\r\\n .ad-resume.open {\\r\\n opacity: 0.9;\\r\\n\\r\\n .ad-bar {\\r\\n background: #e5c07b;\\r\\n background-image: none;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-label-input {\\r\\n flex: 1 1 auto;\\r\\n min-width: 0;\\r\\n padding: 0 4px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.25);\\r\\n border-radius: 3px;\\r\\n background: rgba(0, 0, 0, 0.35);\\r\\n color: #fff;\\r\\n font-size: 10.5px;\\r\\n outline: none;\\r\\n\\r\\n &:focus {\\r\\n border-color: var(--ad-color, #61afef);\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-close {\\r\\n flex: 0 0 auto;\\r\\n align-self: center;\\r\\n width: 18px;\\r\\n height: 18px;\\r\\n padding: 0;\\r\\n border: 0;\\r\\n border-radius: 3px;\\r\\n opacity: 0;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.8);\\r\\n font-size: 15px;\\r\\n line-height: 1;\\r\\n cursor: pointer;\\r\\n transition: opacity 0.1s ease, background 0.1s ease;\\r\\n\\r\\n &:hover {\\r\\n opacity: 1 !important;\\r\\n background: rgba(255, 80, 80, 0.35);\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-foot {\\r\\n display: flex;\\r\\n gap: 6px;\\r\\n padding: 8px;\\r\\n border-top: 1px solid rgba(255, 255, 255, 0.07);\\r\\n }\\r\\n\\r\\n .ad-btn {\\r\\n flex: 1 1 auto;\\r\\n padding: 5px 8px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.12);\\r\\n border-radius: 4px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.6);\\r\\n font-size: 11px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.08);\\r\\n color: #fff;\\r\\n }\\r\\n }\\r\\n\\r\\n // 글자가 한 자뿐인 버튼들은 나머지와 같은 비율로 늘어나면 허전하다\\r\\n .ad-repair,\\r\\n .ad-viewtoggle {\\r\\n flex: 0 0 auto;\\r\\n min-width: 28px;\\r\\n font-size: 13px;\\r\\n line-height: 1;\\r\\n }\\r\\n // ---------- 세션 검색 / 상태 필터 (deck.service buildSidebar · wireSearch) ----------\\r\\n // 유닛 T 가 넘긴 CSS — 그 유닛은 이 파일을 소유하지 않아 배리어에서 메인이 넣는다.\\r\\n //\\r\\n // 검색 줄은 헤더와 목록 사이의 별도 flex 아이템이다. `.ad-list` 안에 두면 `render()` 의\\r\\n // innerHTML 초기화에 입력창이 매 글자마다 새로 만들어져 포커스·IME 조합이 날아간다.\\r\\n .ad-search {\\r\\n display: flex;\\r\\n flex: 0 0 auto;\\r\\n gap: 4px;\\r\\n align-items: center;\\r\\n padding: 0 8px 6px;\\r\\n -webkit-app-region: no-drag;\\r\\n }\\r\\n\\r\\n .ad-search-input {\\r\\n // 사이드바는 200~560px — 입력창이 남는 폭을 다 쓰되 줄어들 때 버튼을 밀지 않게\\r\\n flex: 1 1 auto;\\r\\n min-width: 0;\\r\\n padding: 3px 6px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.14);\\r\\n border-radius: 4px;\\r\\n outline: none;\\r\\n background: rgba(0, 0, 0, 0.28);\\r\\n color: rgba(255, 255, 255, 0.85);\\r\\n font-size: 11px;\\r\\n line-height: 1.4;\\r\\n\\r\\n &::placeholder {\\r\\n color: rgba(255, 255, 255, 0.3);\\r\\n }\\r\\n\\r\\n &:focus {\\r\\n border-color: rgba(97, 175, 239, 0.7);\\r\\n color: #fff;\\r\\n }\\r\\n }\\r\\n\\r\\n // 지우기 버튼은 **걸린 필터가 있을 때만** 보인다 (deck.service syncSearchUi 가 `.has-query`).\\r\\n // 늘 자리를 잡으면 입력창이 그만큼 좁아지고, 빈 칸 옆의 ✕ 는 무엇을 지우는지 알 수 없다.\\r\\n .ad-search-clear {\\r\\n display: none;\\r\\n flex: 0 0 auto;\\r\\n width: 18px;\\r\\n height: 18px;\\r\\n padding: 0;\\r\\n border: 0;\\r\\n border-radius: 3px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.45);\\r\\n font-size: 14px;\\r\\n line-height: 1;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.12);\\r\\n color: #fff;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-search.has-query .ad-search-clear {\\r\\n display: block;\\r\\n }\\r\\n\\r\\n // 집계 칩은 상태 필터의 조작부다 (renderHeadCount → toggleStatusFilter).\\r\\n // 위쪽 `.ad-cnt` 규칙에 \\\"누를 수 있다\\\" 와 \\\"지금 걸려 있다\\\" 만 덧붙인다.\\r\\n .ad-cnt {\\r\\n cursor: pointer;\\r\\n // 헤더는 도킹 드래그 핸들이라 글자가 잡히면 드래그가 지저분해진다\\r\\n user-select: none;\\r\\n transition: background 0.1s ease, color 0.1s ease;\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.16);\\r\\n }\\r\\n\\r\\n // 걸려 있는 필터 — 배경 알파는 SCSS 가 var() 를 계산할 수 없으니\\r\\n // 상태색은 안쪽 테두리와 글자색으로만 쓴다\\r\\n &.active {\\r\\n box-shadow: inset 0 0 0 1px var(--ad-color, #61afef);\\r\\n background: rgba(255, 255, 255, 0.2);\\r\\n color: var(--ad-color, #fff);\\r\\n }\\r\\n }\\r\\n\\r\\n // 필터에 아무것도 안 걸렸을 때의 한 줄 (deck.service renderEmpty).\\r\\n // 빈 목록만 남기면 \\\"탭이 다 닫혔다\\\" 로 읽히므로 이유를 글로 남긴다.\\r\\n .ad-empty {\\r\\n padding: 10px 8px;\\r\\n color: rgba(255, 255, 255, 0.42);\\r\\n text-align: center;\\r\\n word-break: break-all;\\r\\n font-size: 11px;\\r\\n line-height: 1.5;\\r\\n }\\r\\n\\r\\n // 키보드 포커스 링 (deck.service `isNavFocused`) — **활성 탭 표시와 다른 것이어야 한다.**\\r\\n // 활성(선택)은 배경으로, 키보드 포커스는 테두리로 말한다. 둘을 같은 모양으로 그리면\\r\\n // \\\"지금 보고 있는 줄\\\" 과 \\\"지금 쓰고 있는 탭\\\" 이 화면에서 구별되지 않고, 그 구별이 이\\r\\n // 기능의 전부다(이동만으로는 탭이 바뀌지 않는다, `navFocus` 주석).\\r\\n //\\r\\n // outline 대신 inset box-shadow 를 쓰는 이유 둘 — outline 은 `.ad-list` 의\\r\\n // `overflow-y: auto` 경계에서 잘리고, border 는 줄 높이를 1px 밀어 포커스가 지나갈 때마다\\r\\n // 목록 전체가 흔들린다. 상태색(`--ad-color`)을 쓰지 않는 것도 일부러다: 포커스는 세션 상태와\\r\\n // 무관한 \\\"내 손이 어디 있나\\\" 라서, 상태색으로 그리면 배지 색과 섞여 읽힌다.\\r\\n .ad-tab.ad-nav-focus,\\r\\n .ad-group-head.ad-nav-focus {\\r\\n box-shadow: inset 0 0 0 1px rgba(97, 175, 239, 0.85);\\r\\n background: rgba(97, 175, 239, 0.1);\\r\\n }\\r\\n\\r\\n // 포커스가 활성 탭 위에 있을 때 — 배경은 활성 쪽(밝은 회색)을 유지하고 테두리만 얹는다.\\r\\n // 그래야 \\\"이 줄이 지금 쓰는 탭이고, 포커스도 여기 있다\\\" 가 한 줄에서 다 읽힌다\\r\\n .ad-tab.active.ad-nav-focus {\\r\\n background: rgba(255, 255, 255, 0.14);\\r\\n }\\r\\n\\r\\n // 목록 자체가 포커스를 받는다(tabindex=-1) — 브라우저 기본 outline 은 지운다.\\r\\n // 사각형이 목록 전체에 둘러쳐지면 어느 **줄**에 있는지가 오히려 안 보인다\\r\\n .ad-list:focus,\\r\\n .ad-list:focus-visible {\\r\\n outline: none;\\r\\n }\\r\\n\\r\\n // 끌고 있는 줄 — 원래 자리에 흐릿하게 남긴다. 줄을 실제로 옮겨 그리지 않는 이유는\\r\\n // deck.service `render` 의 드래그 가드에 있다(목록을 다시 만들면 끌던 DOM 이 사라진다).\\r\\n // \\\"무엇을 들고 있나\\\" 는 이 흐릿한 줄이, \\\"어디에 놓이나\\\" 는 삽입선(.ad-reorder-line)이 말한다.\\r\\n .ad-tab.ad-dragging {\\r\\n opacity: 0.45;\\r\\n background: rgba(255, 255, 255, 0.06);\\r\\n outline: 1px dashed rgba(255, 255, 255, 0.28);\\r\\n outline-offset: -1px;\\r\\n }\\r\\n\\r\\n // 순서를 바꿀 수 없는 상태에서 끌었을 때의 한 줄 (deck.service noteReorderBlocked).\\r\\n // 목록 위에 겹쳐 띄운다 — flex 자식으로 흐르면 줄들이 밀려 드래그하던 자리가 움직인다.\\r\\n .ad-reorder-note {\\r\\n position: absolute;\\r\\n left: 8px;\\r\\n right: 8px;\\r\\n bottom: 34px;\\r\\n z-index: 3;\\r\\n padding: 7px 9px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.12);\\r\\n border-radius: 5px;\\r\\n background: rgba(38, 42, 49, 0.96);\\r\\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);\\r\\n color: rgba(255, 255, 255, 0.78);\\r\\n font-size: 11px;\\r\\n line-height: 1.45;\\r\\n // 안내를 누르려는 손짓이 아래 줄의 클릭(탭 선택)으로 가지 않게\\r\\n pointer-events: none;\\r\\n }\\r\\n\\r\\n // 상/하 도킹 — 세로가 짧다(기본 sidebarHeight 200px). 검색 줄 높이를 줄이고,\\r\\n // 가로로 흐르는 목록에서 안내 한 줄은 폭을 다 차지하게 한다 (`.ad-group-head` 와 같은 이유)\\r\\n &.ad-dock-top .ad-search,\\r\\n &.ad-dock-bottom .ad-search {\\r\\n padding: 0 8px 4px;\\r\\n }\\r\\n\\r\\n &.ad-dock-top .ad-list .ad-empty,\\r\\n &.ad-dock-bottom .ad-list .ad-empty {\\r\\n flex: 0 0 100%;\\r\\n }\\r\\n}\\r\\n\\r\\n// ---------- 결과물 미리보기 패널 (viewPanel.ts) ----------\\r\\n// 사이드바와 같은 규칙을 따른다 — 위치·폭은 deck.service 의 relayout 이 인라인으로 준다.\\r\\n#agentdeck-view {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n z-index: 5;\\r\\n overflow: hidden;\\r\\n background: var(--ad-panel-bg, var(--bs-body-bg, #1e2127));\\r\\n font-size: 12px;\\r\\n -webkit-app-region: no-drag;\\r\\n\\r\\n // 터미널과 닿는 쪽에만 경계선\\r\\n &.ad-view-right { border-left: 1px solid rgba(255, 255, 255, 0.08); }\\r\\n &.ad-view-left { border-right: 1px solid rgba(255, 255, 255, 0.08); }\\r\\n\\r\\n &.ad-view-dropping {\\r\\n outline: 1px dashed rgba(97, 175, 239, 0.8);\\r\\n outline-offset: -3px;\\r\\n }\\r\\n\\r\\n .ad-view-head {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n gap: 6px;\\r\\n padding: 8px 8px 6px 12px;\\r\\n border-bottom: 1px solid rgba(255, 255, 255, 0.06);\\r\\n user-select: none;\\r\\n }\\r\\n\\r\\n .ad-view-title {\\r\\n overflow: hidden;\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n color: rgba(255, 255, 255, 0.82);\\r\\n font-weight: 600;\\r\\n }\\r\\n\\r\\n .ad-view-tools {\\r\\n display: flex;\\r\\n flex: 0 0 auto;\\r\\n gap: 2px;\\r\\n }\\r\\n\\r\\n .ad-view-btn {\\r\\n min-width: 24px;\\r\\n padding: 2px 5px;\\r\\n border: 0;\\r\\n border-radius: 4px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.5);\\r\\n font-size: 12px;\\r\\n line-height: 1.2;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.1);\\r\\n color: #fff;\\r\\n }\\r\\n\\r\\n // 켜져 있는 도구(편집 중의 ✎) — 지금 어떤 상태인지 버튼만 보고 알 수 있어야 한다\\r\\n &.ad-view-btn-on {\\r\\n background: rgba(97, 175, 239, 0.22);\\r\\n color: #9ecbff;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-path {\\r\\n display: flex;\\r\\n flex-wrap: wrap;\\r\\n gap: 4px;\\r\\n padding: 6px 8px;\\r\\n border-bottom: 1px solid rgba(255, 255, 255, 0.06);\\r\\n\\r\\n input {\\r\\n width: 100%;\\r\\n padding: 4px 6px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.14);\\r\\n border-radius: 4px;\\r\\n background: rgba(0, 0, 0, 0.25);\\r\\n color: #e6e6e6;\\r\\n font-family: monospace;\\r\\n font-size: 11px;\\r\\n\\r\\n &:focus {\\r\\n outline: 0;\\r\\n border-color: rgba(97, 175, 239, 0.7);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // 경로 줄 안내 — \\\"없는 파일이다, 한 번 더 Enter\\\" 같은 말이 여기 뜬다\\r\\n .ad-view-path-note {\\r\\n width: 100%;\\r\\n overflow: hidden;\\r\\n color: rgba(229, 192, 123, 0.9);\\r\\n font-size: 11px;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n\\r\\n &:empty {\\r\\n display: none;\\r\\n }\\r\\n }\\r\\n\\r\\n // 찾기 줄 (Ctrl+F). 경로 줄과 같은 자리·같은 옷을 입힌다 — 둘 다 헤더 아래 한 줄짜리 도구다\\r\\n .ad-view-find {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n padding: 6px 8px;\\r\\n border-bottom: 1px solid rgba(255, 255, 255, 0.06);\\r\\n\\r\\n input {\\r\\n flex: 1 1 auto;\\r\\n min-width: 0;\\r\\n padding: 4px 6px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.14);\\r\\n border-radius: 4px;\\r\\n background: rgba(0, 0, 0, 0.25);\\r\\n color: #e6e6e6;\\r\\n font-family: monospace;\\r\\n font-size: 11px;\\r\\n\\r\\n &:focus {\\r\\n outline: 0;\\r\\n border-color: rgba(97, 175, 239, 0.7);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-find-count {\\r\\n flex: 0 0 auto;\\r\\n min-width: 44px;\\r\\n color: rgba(255, 255, 255, 0.45);\\r\\n font-size: 11px;\\r\\n text-align: right;\\r\\n }\\r\\n\\r\\n // 일치 표시. 지금 보고 있는 것 하나만 진하게 — 개수가 많아도 어디에 있는지 눈에 든다\\r\\n mark.ad-find-hit {\\r\\n border-radius: 2px;\\r\\n background: rgba(229, 192, 123, 0.35);\\r\\n color: inherit;\\r\\n }\\r\\n\\r\\n mark.ad-find-cur {\\r\\n background: rgba(229, 192, 123, 0.85);\\r\\n color: #1a1a1a;\\r\\n }\\r\\n\\r\\n // 편집 줄 — 저장/취소는 본문 밖에 둔다 (본문은 갱신마다 다시 그려진다)\\r\\n .ad-view-editbar {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n gap: 8px;\\r\\n padding: 5px 8px;\\r\\n border-top: 1px solid rgba(255, 255, 255, 0.06);\\r\\n background: rgba(0, 0, 0, 0.18);\\r\\n }\\r\\n\\r\\n .ad-view-edit-note {\\r\\n overflow: hidden;\\r\\n color: rgba(255, 255, 255, 0.5);\\r\\n font-size: 11px;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n }\\r\\n\\r\\n .ad-view-edit-btns {\\r\\n display: flex;\\r\\n flex: 0 0 auto;\\r\\n gap: 4px;\\r\\n }\\r\\n\\r\\n .ad-view-edit-save,\\r\\n .ad-view-edit-cancel {\\r\\n padding: 2px 10px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.14);\\r\\n border-radius: 4px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.75);\\r\\n font-size: 11px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n border-color: rgba(255, 255, 255, 0.3);\\r\\n background: rgba(255, 255, 255, 0.08);\\r\\n color: #fff;\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.35;\\r\\n cursor: default;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-edit-save {\\r\\n border-color: rgba(97, 175, 239, 0.5);\\r\\n color: #9ecbff;\\r\\n }\\r\\n\\r\\n // 편집기 — 본문 자리를 그대로 채운다. 글꼴·줄간격을 코드 보기와 맞춰야 편집 전후로\\r\\n // 글자가 튀지 않는다\\r\\n textarea.ad-view-edit {\\r\\n display: block;\\r\\n box-sizing: border-box;\\r\\n width: 100%;\\r\\n height: 100%;\\r\\n min-height: 200px;\\r\\n padding: 6px 8px;\\r\\n border: 0;\\r\\n background: rgba(0, 0, 0, 0.22);\\r\\n color: #e6e6e6;\\r\\n font-family: monospace;\\r\\n font-size: 12px;\\r\\n line-height: 1.5;\\r\\n resize: none;\\r\\n tab-size: 4;\\r\\n\\r\\n &:focus {\\r\\n outline: 0;\\r\\n }\\r\\n }\\r\\n\\r\\n // 최근 파일 칩 — Codex 앱의 결과물 탭 자리\\r\\n .ad-view-tabs {\\r\\n display: flex;\\r\\n flex-wrap: wrap;\\r\\n gap: 4px;\\r\\n padding: 6px 8px;\\r\\n border-bottom: 1px solid rgba(255, 255, 255, 0.06);\\r\\n user-select: none;\\r\\n }\\r\\n\\r\\n .ad-view-tab {\\r\\n max-width: 100%;\\r\\n overflow: hidden;\\r\\n padding: 2px 7px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.1);\\r\\n border-radius: 10px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.55);\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n font-size: 11px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n color: #fff;\\r\\n border-color: rgba(255, 255, 255, 0.25);\\r\\n }\\r\\n\\r\\n &.ad-view-tab-on {\\r\\n border-color: rgba(97, 175, 239, 0.6);\\r\\n background: rgba(97, 175, 239, 0.14);\\r\\n color: #cfe6ff;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-body {\\r\\n flex: 1 1 auto;\\r\\n overflow: auto;\\r\\n padding: 10px 12px 16px;\\r\\n color: rgba(255, 255, 255, 0.85);\\r\\n // 문서를 읽는 자리라 글자 선택은 열어 둔다 (사이드바는 막아 둔다)\\r\\n user-select: text;\\r\\n }\\r\\n\\r\\n .ad-view-foot {\\r\\n flex: 0 0 auto;\\r\\n overflow: hidden;\\r\\n padding: 5px 10px;\\r\\n border-top: 1px solid rgba(255, 255, 255, 0.06);\\r\\n color: rgba(255, 255, 255, 0.35);\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n font-size: 10px;\\r\\n }\\r\\n\\r\\n // 폭 조절 손잡이 — 터미널과 닿는 쪽 경계선\\r\\n .ad-view-resize {\\r\\n position: absolute;\\r\\n top: 0;\\r\\n bottom: 0;\\r\\n width: 6px;\\r\\n cursor: col-resize;\\r\\n z-index: 6;\\r\\n }\\r\\n\\r\\n &.ad-view-right .ad-view-resize { left: -2px; }\\r\\n &.ad-view-left .ad-view-resize { right: -2px; }\\r\\n\\r\\n .ad-view-empty {\\r\\n padding: 8px 2px;\\r\\n color: rgba(255, 255, 255, 0.55);\\r\\n line-height: 1.7;\\r\\n\\r\\n ul { padding-left: 18px; margin: 6px 0 0; }\\r\\n li { margin: 2px 0; }\\r\\n }\\r\\n\\r\\n .ad-view-dim {\\r\\n color: rgba(255, 255, 255, 0.35);\\r\\n font-size: 11px;\\r\\n }\\r\\n\\r\\n // ---------- 종류별 본문 ----------\\r\\n\\r\\n .ad-view-image {\\r\\n display: flex;\\r\\n align-items: flex-start;\\r\\n justify-content: center;\\r\\n\\r\\n img {\\r\\n max-width: 100%;\\r\\n // 원본보다 키우지 않는다 — 확대하면 스크린샷 글자가 뭉개진다\\r\\n height: auto;\\r\\n background: rgba(255, 255, 255, 0.04);\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-code {\\r\\n display: flex;\\r\\n gap: 8px;\\r\\n font-family: monospace;\\r\\n font-size: 11px;\\r\\n line-height: 1.5;\\r\\n\\r\\n pre {\\r\\n margin: 0;\\r\\n white-space: pre;\\r\\n }\\r\\n\\r\\n .ad-view-gutter {\\r\\n flex: 0 0 auto;\\r\\n color: rgba(255, 255, 255, 0.25);\\r\\n text-align: right;\\r\\n user-select: none;\\r\\n }\\r\\n\\r\\n .ad-view-src {\\r\\n flex: 1 1 auto;\\r\\n overflow-x: auto;\\r\\n color: rgba(255, 255, 255, 0.85);\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-table {\\r\\n overflow-x: auto;\\r\\n\\r\\n table {\\r\\n border-collapse: collapse;\\r\\n font-size: 11px;\\r\\n }\\r\\n\\r\\n th, td {\\r\\n max-width: 260px;\\r\\n overflow: hidden;\\r\\n padding: 3px 6px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.08);\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n }\\r\\n\\r\\n th {\\r\\n position: sticky;\\r\\n top: 0;\\r\\n background: #262a31;\\r\\n color: rgba(255, 255, 255, 0.7);\\r\\n }\\r\\n\\r\\n .ad-view-rownum {\\r\\n color: rgba(255, 255, 255, 0.3);\\r\\n text-align: right;\\r\\n }\\r\\n }\\r\\n\\r\\n // ---------- 마크다운 ----------\\r\\n .ad-view-md {\\r\\n line-height: 1.65;\\r\\n word-break: break-word;\\r\\n\\r\\n h1, h2, h3, h4, h5, h6 {\\r\\n margin: 1.1em 0 0.5em;\\r\\n color: #fff;\\r\\n line-height: 1.3;\\r\\n }\\r\\n h1 { font-size: 18px; }\\r\\n h2 { font-size: 16px; padding-bottom: 3px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); }\\r\\n h3 { font-size: 14px; }\\r\\n h4, h5, h6 { font-size: 13px; }\\r\\n\\r\\n p { margin: 0.6em 0; }\\r\\n\\r\\n a {\\r\\n color: #61afef;\\r\\n text-decoration: none;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover { text-decoration: underline; }\\r\\n }\\r\\n\\r\\n code {\\r\\n padding: 1px 4px;\\r\\n border-radius: 3px;\\r\\n background: rgba(255, 255, 255, 0.08);\\r\\n font-family: monospace;\\r\\n font-size: 11px;\\r\\n }\\r\\n\\r\\n pre {\\r\\n overflow-x: auto;\\r\\n margin: 0.7em 0;\\r\\n padding: 8px 10px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.07);\\r\\n border-radius: 5px;\\r\\n background: rgba(0, 0, 0, 0.28);\\r\\n\\r\\n code {\\r\\n padding: 0;\\r\\n background: transparent;\\r\\n line-height: 1.5;\\r\\n }\\r\\n }\\r\\n\\r\\n ul, ol { padding-left: 20px; margin: 0.5em 0; }\\r\\n li { margin: 0.15em 0; }\\r\\n\\r\\n .ad-md-task { list-style: none; margin-left: -14px; }\\r\\n .ad-md-check { color: rgba(255, 255, 255, 0.6); }\\r\\n\\r\\n blockquote {\\r\\n margin: 0.7em 0;\\r\\n padding: 2px 0 2px 10px;\\r\\n border-left: 3px solid rgba(255, 255, 255, 0.18);\\r\\n color: rgba(255, 255, 255, 0.6);\\r\\n }\\r\\n\\r\\n hr {\\r\\n margin: 1.2em 0;\\r\\n border: 0;\\r\\n border-top: 1px solid rgba(255, 255, 255, 0.12);\\r\\n }\\r\\n\\r\\n table {\\r\\n display: block;\\r\\n overflow-x: auto;\\r\\n border-collapse: collapse;\\r\\n margin: 0.7em 0;\\r\\n font-size: 11px;\\r\\n }\\r\\n\\r\\n th, td {\\r\\n padding: 4px 8px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.1);\\r\\n text-align: left;\\r\\n }\\r\\n\\r\\n th { background: rgba(255, 255, 255, 0.05); color: #fff; }\\r\\n\\r\\n img {\\r\\n max-width: 100%;\\r\\n border-radius: 4px;\\r\\n }\\r\\n\\r\\n .ad-md-noimg {\\r\\n padding: 1px 5px;\\r\\n border-radius: 3px;\\r\\n background: rgba(255, 255, 255, 0.06);\\r\\n color: rgba(255, 255, 255, 0.45);\\r\\n font-size: 11px;\\r\\n }\\r\\n }\\r\\n\\r\\n // ---------- 변경 탭 (파일/변경 스위치 + git diff) ----------\\r\\n // 최근 파일 칩과 같은 모양을 쓴다 — 같은 자리에서 같은 방식으로 고르는 것이라서.\\r\\n .ad-view-modes {\\r\\n display: flex;\\r\\n flex: 0 0 auto;\\r\\n gap: 4px;\\r\\n padding: 6px 8px;\\r\\n border-bottom: 1px solid rgba(255, 255, 255, 0.06);\\r\\n user-select: none;\\r\\n }\\r\\n\\r\\n .ad-view-mode {\\r\\n flex: 0 0 auto;\\r\\n padding: 3px 12px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.1);\\r\\n border-radius: 4px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.55);\\r\\n font-size: 11px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n border-color: rgba(255, 255, 255, 0.25);\\r\\n color: #fff;\\r\\n }\\r\\n\\r\\n &.ad-view-mode-on {\\r\\n border-color: rgba(97, 175, 239, 0.6);\\r\\n background: rgba(97, 175, 239, 0.14);\\r\\n color: #cfe6ff;\\r\\n }\\r\\n }\\r\\n\\r\\n // `변경` 목록의 범위 스위치 (세션 / 전체).\\r\\n // 모드 버튼과 **다른 모양**이어야 한다 — 같은 줄에 있지만 고르는 대상이 다르다\\r\\n // (모드는 무엇을 보나, 이건 얼마나 보나). 그래서 오른쪽 끝으로 밀고 테두리를 점선으로 둔다\\r\\n .ad-view-scope {\\r\\n flex: 0 0 auto;\\r\\n margin-left: auto;\\r\\n padding: 3px 10px;\\r\\n border: 1px dashed rgba(255, 255, 255, 0.18);\\r\\n border-radius: 4px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.55);\\r\\n font-size: 11px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n border-color: rgba(255, 255, 255, 0.35);\\r\\n color: #fff;\\r\\n }\\r\\n\\r\\n // '전체' = 저장소의 커밋 안 된 전부. 기본(세션)에서 벗어난 상태라는 것이 보여야 한다\\r\\n &.ad-view-scope-all {\\r\\n border-style: solid;\\r\\n border-color: rgba(229, 192, 123, 0.5);\\r\\n color: #e5c07b;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-diff {\\r\\n .ad-plus { color: #98c379; }\\r\\n .ad-minus { color: #e06c75; }\\r\\n }\\r\\n\\r\\n // `2 files changed +9 -6` 자리\\r\\n .ad-view-diff-sum {\\r\\n padding-bottom: 6px;\\r\\n color: rgba(255, 255, 255, 0.8);\\r\\n font-weight: 600;\\r\\n }\\r\\n\\r\\n .ad-view-diff-list {\\r\\n margin-bottom: 10px;\\r\\n padding-bottom: 6px;\\r\\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\\r\\n }\\r\\n\\r\\n .ad-view-diff-item {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n width: 100%;\\r\\n padding: 2px 4px;\\r\\n border: 0;\\r\\n border-radius: 3px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.7);\\r\\n text-align: left;\\r\\n font-size: 11px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover { background: rgba(255, 255, 255, 0.07); }\\r\\n\\r\\n .ad-view-diff-st {\\r\\n flex: 0 0 auto;\\r\\n min-width: 40px;\\r\\n color: rgba(255, 255, 255, 0.4);\\r\\n text-align: center;\\r\\n font-size: 10px;\\r\\n }\\r\\n\\r\\n .ad-view-diff-st-added { color: #98c379; }\\r\\n .ad-view-diff-st-deleted { color: #e06c75; }\\r\\n .ad-view-diff-st-renamed { color: #61afef; }\\r\\n\\r\\n .ad-view-diff-name {\\r\\n flex: 1 1 auto;\\r\\n overflow: hidden;\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n // 경로는 등폭이 읽기 쉽다 — 같은 폴더가 세로로 줄을 맞춘다\\r\\n font-family: monospace;\\r\\n }\\r\\n\\r\\n .ad-view-diff-num {\\r\\n flex: 0 0 auto;\\r\\n\\r\\n b {\\r\\n margin-left: 5px;\\r\\n font-weight: 500;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-diff-sub {\\r\\n margin: 4px 0;\\r\\n color: rgba(255, 255, 255, 0.4);\\r\\n font-size: 11px;\\r\\n }\\r\\n\\r\\n .ad-view-diff-untracked {\\r\\n margin-bottom: 10px;\\r\\n padding-bottom: 6px;\\r\\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\\r\\n\\r\\n .ad-view-diff-u {\\r\\n overflow: hidden;\\r\\n padding: 1px 4px;\\r\\n color: rgba(255, 255, 255, 0.5);\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n font-family: monospace;\\r\\n font-size: 11px;\\r\\n\\r\\n &[data-ad-open] {\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover { background: rgba(255, 255, 255, 0.07); color: #fff; }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-diff-file {\\r\\n margin-bottom: 14px;\\r\\n }\\r\\n\\r\\n // 파일명은 스크롤해도 남아 있어야 한다 — 긴 diff 를 내려가다 보면 어느 파일인지 잊는다\\r\\n .ad-view-diff-fhead {\\r\\n position: sticky;\\r\\n top: 0;\\r\\n z-index: 1;\\r\\n overflow: hidden;\\r\\n padding: 4px 6px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.08);\\r\\n border-radius: 4px 4px 0 0;\\r\\n background: #262a31;\\r\\n color: rgba(255, 255, 255, 0.8);\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n font-family: monospace;\\r\\n font-size: 11px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover { color: #fff; }\\r\\n }\\r\\n\\r\\n .ad-view-diff-note {\\r\\n padding: 4px 6px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.08);\\r\\n border-top: 0;\\r\\n color: rgba(255, 255, 255, 0.35);\\r\\n font-size: 11px;\\r\\n }\\r\\n\\r\\n .ad-view-diff-lines {\\r\\n overflow-x: auto;\\r\\n border: 1px solid rgba(255, 255, 255, 0.08);\\r\\n border-top: 0;\\r\\n font-family: monospace;\\r\\n font-size: 11px;\\r\\n line-height: 1.5;\\r\\n }\\r\\n\\r\\n // 한 줄 = 구 번호 · 신 번호 · 본문. 배경이 줄 전체를 덮어야 추가/삭제가 눈에 띈다\\r\\n .ad-dl {\\r\\n display: flex;\\r\\n // 가로 스크롤 안에서도 배경이 끊기지 않게 (본문이 넘치면 줄이 넓어진다)\\r\\n min-width: 100%;\\r\\n min-height: 17px;\\r\\n white-space: pre;\\r\\n\\r\\n .ad-dl-no {\\r\\n flex: 0 0 auto;\\r\\n width: 38px;\\r\\n padding-right: 6px;\\r\\n color: rgba(255, 255, 255, 0.25);\\r\\n text-align: right;\\r\\n user-select: none;\\r\\n }\\r\\n\\r\\n .ad-dl-tx {\\r\\n flex: 1 0 auto;\\r\\n padding-right: 8px;\\r\\n color: rgba(255, 255, 255, 0.8);\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-dl-add {\\r\\n background: rgba(152, 195, 121, 0.12);\\r\\n\\r\\n .ad-dl-tx { color: #b7d99b; }\\r\\n }\\r\\n\\r\\n .ad-dl-del {\\r\\n background: rgba(224, 108, 117, 0.12);\\r\\n\\r\\n .ad-dl-tx { color: #eda3a9; }\\r\\n }\\r\\n\\r\\n .ad-dl-hunk {\\r\\n background: rgba(97, 175, 239, 0.1);\\r\\n\\r\\n .ad-dl-tx { color: rgba(97, 175, 239, 0.85); }\\r\\n }\\r\\n\\r\\n // ---------- 스테이지 딱지 (파일 목록 / 추적 안 됨 줄) ----------\\r\\n // 유닛 L 이 넘긴 CSS — 그 유닛은 이 파일을 소유하지 않아 배리어에서 메인이 넣는다.\\r\\n // 상태 색은 `.ad-view-diff-st-*` 와 같은 팔레트를 쓴다 (같은 줄에서 두 딱지가 싸우지 않게).\\r\\n .ad-view-stage {\\r\\n flex: 0 0 auto;\\r\\n min-width: 44px;\\r\\n padding: 0 4px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.14);\\r\\n border-radius: 3px;\\r\\n color: rgba(255, 255, 255, 0.45);\\r\\n text-align: center;\\r\\n font-size: 10px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n border-color: rgba(255, 255, 255, 0.4);\\r\\n color: #fff;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-stage-staged {\\r\\n border-color: rgba(152, 195, 121, 0.5);\\r\\n background: rgba(152, 195, 121, 0.14);\\r\\n color: #b7d99b;\\r\\n }\\r\\n\\r\\n .ad-view-stage-both {\\r\\n border-color: rgba(229, 192, 123, 0.5);\\r\\n background: rgba(229, 192, 123, 0.12);\\r\\n color: #e5c07b;\\r\\n }\\r\\n\\r\\n .ad-view-stage-conflict {\\r\\n border-color: rgba(224, 108, 117, 0.6);\\r\\n background: rgba(224, 108, 117, 0.14);\\r\\n color: #eda3a9;\\r\\n }\\r\\n\\r\\n // ---------- `파일:라인` 참조 ----------\\r\\n // 유닛 U 가 넘긴 CSS — 그 유닛은 이 파일을 소유하지 않아 배리어에서 메인이 넣는다.\\r\\n //\\r\\n // 누를 수 있는 줄은 커서와 왼쪽 선으로 알린다. 줄번호 칸은 `user-select: none` 이라\\r\\n // 거기를 눌러도 글자 선택이 시작되지 않는다 (본문 복사와 싸우지 않게)\\r\\n .ad-dl[data-ad-ref-line],\\r\\n .ad-dl[data-ad-ref-del],\\r\\n .ad-cl[data-ad-ref-line] {\\r\\n cursor: pointer;\\r\\n }\\r\\n\\r\\n .ad-dl[data-ad-ref-line]:hover,\\r\\n .ad-cl[data-ad-ref-line]:hover {\\r\\n box-shadow: inset 2px 0 0 rgba(97, 175, 239, 0.55);\\r\\n }\\r\\n\\r\\n // 고른 줄. 추가/삭제 배경(`.ad-dl-add`/`.ad-dl-del`)을 덮어야 하므로 두 클래스로 특정한다\\r\\n .ad-dl.ad-ref-sel,\\r\\n .ad-cl.ad-ref-sel {\\r\\n box-shadow: inset 2px 0 0 #61afef;\\r\\n background: rgba(97, 175, 239, 0.22);\\r\\n\\r\\n .ad-dl-no,\\r\\n .ad-cl-no {\\r\\n color: rgba(255, 255, 255, 0.6);\\r\\n }\\r\\n\\r\\n .ad-dl-tx,\\r\\n .ad-cl-tx {\\r\\n color: #fff;\\r\\n }\\r\\n }\\r\\n\\r\\n // ---------- `파일` 모드 코드 보기: 줄마다 한 칸 ----------\\r\\n // 원래는 `<pre>` 두 장을 좌우로 놓는 flex 였다. 줄 단위로 그리게 되면서(어느 줄을 눌렀는지\\r\\n // 알아야 한다) 세로로 쌓아야 하므로 배치만 되돌린다 — 글꼴·크기·줄높이는 그대로 쓴다\\r\\n .ad-view-code.ad-view-code-rows {\\r\\n display: block;\\r\\n overflow-x: auto;\\r\\n }\\r\\n\\r\\n .ad-cl {\\r\\n display: flex;\\r\\n // 가로 스크롤 안에서도 강조 배경이 끊기지 않게 (`.ad-dl` 과 같은 사정)\\r\\n min-width: 100%;\\r\\n min-height: 17px;\\r\\n white-space: pre;\\r\\n\\r\\n .ad-cl-no {\\r\\n flex: 0 0 auto;\\r\\n width: 44px;\\r\\n padding-right: 8px;\\r\\n color: rgba(255, 255, 255, 0.25);\\r\\n text-align: right;\\r\\n user-select: none;\\r\\n }\\r\\n\\r\\n .ad-cl-tx {\\r\\n flex: 1 0 auto;\\r\\n padding-right: 8px;\\r\\n color: rgba(255, 255, 255, 0.85);\\r\\n }\\r\\n }\\r\\n\\r\\n // ---------- 참조 안내줄 (본문 밖 — 자동 갱신에 지워지지 않는 자리) ----------\\r\\n .ad-view-ref {\\r\\n flex: 0 0 auto;\\r\\n overflow: hidden;\\r\\n padding: 4px 10px;\\r\\n border-top: 1px solid rgba(255, 255, 255, 0.06);\\r\\n color: rgba(255, 255, 255, 0.5);\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n font-size: 10px;\\r\\n }\\r\\n\\r\\n // 방금 넣었다 — REF_FLASH_MS(2.5초)만 켜진다\\r\\n .ad-view-ref-on {\\r\\n background: rgba(97, 175, 239, 0.14);\\r\\n color: #cfe6ff;\\r\\n }\\r\\n\\r\\n // ---------- 커밋 줄 (본문 밖 — 자동 갱신에 지워지지 않는 자리) ----------\\r\\n .ad-view-commit {\\r\\n flex: 0 0 auto;\\r\\n padding: 6px 8px;\\r\\n border-top: 1px solid rgba(255, 255, 255, 0.06);\\r\\n }\\r\\n\\r\\n .ad-view-commit-sum {\\r\\n margin-bottom: 4px;\\r\\n color: rgba(255, 255, 255, 0.55);\\r\\n font-size: 11px;\\r\\n }\\r\\n\\r\\n .ad-view-commit-row {\\r\\n display: flex;\\r\\n gap: 6px;\\r\\n align-items: center;\\r\\n }\\r\\n\\r\\n .ad-view-commit-msg {\\r\\n flex: 1 1 auto;\\r\\n min-width: 0;\\r\\n padding: 4px 6px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.14);\\r\\n border-radius: 4px;\\r\\n background: rgba(0, 0, 0, 0.25);\\r\\n color: #e6e6e6;\\r\\n font-family: monospace;\\r\\n font-size: 11px;\\r\\n\\r\\n &:focus {\\r\\n border-color: rgba(97, 175, 239, 0.6);\\r\\n outline: 0;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-commit-go {\\r\\n flex: 0 0 auto;\\r\\n padding: 4px 10px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.14);\\r\\n border-radius: 4px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.7);\\r\\n font-size: 11px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n border-color: rgba(255, 255, 255, 0.35);\\r\\n color: #fff;\\r\\n }\\r\\n\\r\\n // 메시지가 비면 잠긴다 — 잠긴 것이 눈에 보여야 \\\"왜 안 눌리나\\\" 를 묻지 않는다\\r\\n &:disabled {\\r\\n opacity: 0.45;\\r\\n cursor: default;\\r\\n }\\r\\n\\r\\n // 확인 대기: 다음 누름이 실제 커밋이라는 것을 색으로 경고한다\\r\\n &.ad-view-commit-armed {\\r\\n border-color: rgba(224, 108, 117, 0.7);\\r\\n background: rgba(224, 108, 117, 0.18);\\r\\n color: #ffd7da;\\r\\n }\\r\\n }\\r\\n\\r\\n .ad-view-commit-note {\\r\\n margin-top: 4px;\\r\\n overflow: hidden;\\r\\n color: rgba(255, 255, 255, 0.4);\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n font-size: 11px;\\r\\n }\\r\\n}\\r\\n\\r\\n// 우클릭 상태 메뉴\\r\\n.ad-menu {\\r\\n position: fixed;\\r\\n z-index: 10000;\\r\\n min-width: 130px;\\r\\n padding: 4px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.12);\\r\\n border-radius: 6px;\\r\\n background: #262a31;\\r\\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);\\r\\n font-size: 12px;\\r\\n user-select: none;\\r\\n\\r\\n .ad-menu-item {\\r\\n padding: 6px 10px;\\r\\n border-radius: 4px;\\r\\n color: rgba(255, 255, 255, 0.75);\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n background: rgba(255, 255, 255, 0.1);\\r\\n color: #fff;\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n// 도킹 가이드 — 헤더를 끌고 있는 동안만 창 위에 뜬다\\r\\n.ad-dock-overlay {\\r\\n position: fixed;\\r\\n inset: 0;\\r\\n z-index: 9998;\\r\\n // 커서 판정은 좌표로 직접 하므로 오버레이가 이벤트를 가로채면 안 된다\\r\\n pointer-events: none;\\r\\n}\\r\\n\\r\\n// 놓으면 사이드바가 자리잡을 영역\\r\\n.ad-dock-preview {\\r\\n position: fixed;\\r\\n display: none;\\r\\n border: 1px solid rgba(97, 175, 239, 0.9);\\r\\n background: rgba(97, 175, 239, 0.22);\\r\\n box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.18);\\r\\n transition: left 0.08s ease, top 0.08s ease, width 0.08s ease, height 0.08s ease;\\r\\n}\\r\\n\\r\\n// 네 가장자리에 뜨는 도킹 표적\\r\\n.ad-dock-zone {\\r\\n position: fixed;\\r\\n width: 46px;\\r\\n height: 46px;\\r\\n margin: -23px 0 0 -23px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.35);\\r\\n border-radius: 6px;\\r\\n background: rgba(38, 42, 49, 0.92);\\r\\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n\\r\\n .ad-dock-mark {\\r\\n width: 26px;\\r\\n height: 26px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.45);\\r\\n border-radius: 3px;\\r\\n }\\r\\n\\r\\n &.active {\\r\\n border-color: rgba(97, 175, 239, 0.95);\\r\\n background: rgba(97, 175, 239, 0.35);\\r\\n }\\r\\n\\r\\n // 표적 안의 작은 사각형이 \\\"어느 쪽 절반에 붙는지\\\" 를 그대로 보여준다\\r\\n &.ad-dock-zone-left .ad-dock-mark { border-left: 4px solid rgba(97, 175, 239, 0.95); }\\r\\n &.ad-dock-zone-right .ad-dock-mark { border-right: 4px solid rgba(97, 175, 239, 0.95); }\\r\\n &.ad-dock-zone-top .ad-dock-mark { border-top: 4px solid rgba(97, 175, 239, 0.95); }\\r\\n &.ad-dock-zone-bottom .ad-dock-mark { border-bottom: 4px solid rgba(97, 175, 239, 0.95); }\\r\\n}\\r\\n\\r\\n// 놓일 자리를 가리키는 삽입선 — 줄을 끌고 있는 동안만 뜬다 (deck.service drawReorderLine).\\r\\n// 좌표는 인라인으로 준다(가로 도킹은 세로선, 상/하 도킹은 가로선). `.ad-list` 안이 아니라\\r\\n// body 에 붙는 이유는 그 함수 주석에 있다 — 목록을 다시 그릴 때 날아가지 않게, 그리고\\r\\n// 회귀 프로브가 목록의 자식만 훑어 그룹을 읽으므로 낯선 노드를 끼워 넣지 않게.\\r\\n.ad-reorder-line {\\r\\n position: fixed;\\r\\n z-index: 9997;\\r\\n border-radius: 1px;\\r\\n background: rgba(97, 175, 239, 0.95);\\r\\n box-shadow: 0 0 5px rgba(97, 175, 239, 0.6);\\r\\n // 좌표 판정은 elementFromPoint 로 한다 — 선이 이벤트를 가로채면 자기 자신을 짚는다\\r\\n pointer-events: none;\\r\\n}\\r\\n\\r\\n// 줄을 끄는 동안 — 커서를 옮기기 모양으로 두고, 커서가 터미널 위로 넘어가도 모양이 유지되게\\r\\nbody.ad-reordering {\\r\\n cursor: grabbing;\\r\\n\\r\\n // 줄 자신은 `cursor: pointer`(클릭=탭 선택)라 body 것으로는 덮이지 않는다.\\r\\n // 끌고 있는 동안만 사이드바 안쪽을 통째로 덮어써 손 모양이 도중에 바뀌지 않게 한다.\\r\\n #agentdeck-sidebar,\\r\\n #agentdeck-sidebar * {\\r\\n cursor: grabbing !important;\\r\\n }\\r\\n\\r\\n .content.main {\\r\\n pointer-events: none;\\r\\n }\\r\\n}\\r\\n\\r\\n// 경계선을 끄는 동안에는 터미널이 커서를 뺏지 않게 한다\\r\\nbody.ad-resizing {\\r\\n cursor: inherit;\\r\\n\\r\\n .content.main {\\r\\n pointer-events: none;\\r\\n }\\r\\n}\\r\\n\\r\\n// AgentDeck 이 켜져 있을 때만 순정 탭바를 감춘다 (사이드바가 그 역할을 대신함)\\r\\nbody.agentdeck-active {\\r\\n .content.main > .tab-bar {\\r\\n display: none !important;\\r\\n }\\r\\n\\r\\n .window {\\r\\n display: flex;\\r\\n flex-direction: row;\\r\\n // 사이드바를 창 안에 절대 배치하므로 기준점이 필요하다\\r\\n position: relative;\\r\\n // 터미널 옆에 남는 여백이 밝은 기본 배경으로 튀지 않게 한다\\r\\n // (--ad-panel-bg 가 있으면 배경 이미지가 이 여백으로도 비친다)\\r\\n background: var(--ad-panel-bg, var(--bs-body-bg, #1e2127));\\r\\n }\\r\\n}\\r\\n\\r\\n// ---------- 드롭 확인 배너 (터미널 위에 파일을 끌어다 놓았을 때) ----------\\r\\n// OS 모달이 아니라 인라인 카드다 — 모달은 터미널 흐름을 끊고 CDP 로 검증할 수 없다.\\r\\n// 화면 오른쪽 아래에 띄운다: 입력창(아래 중앙)과 사이드바(좌/우 가장자리)를 둘 다 피하려면\\r\\n// 그 모서리가 가장 덜 겹친다. `z-index` 는 사이드바(#agentdeck-sidebar)보다 위여야 한다.\\r\\n.ad-drop-ask {\\r\\n position: fixed;\\r\\n right: 16px;\\r\\n bottom: 16px;\\r\\n z-index: 10000;\\r\\n min-width: 260px;\\r\\n max-width: 420px;\\r\\n padding: 10px 12px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.16);\\r\\n border-radius: 6px;\\r\\n background: rgba(24, 26, 30, 0.97);\\r\\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);\\r\\n color: #e6e6e6;\\r\\n font-size: 12px;\\r\\n\\r\\n .ad-drop-ask-msg {\\r\\n overflow: hidden;\\r\\n margin-bottom: 8px;\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n font-weight: 600;\\r\\n }\\r\\n\\r\\n .ad-drop-ask-row {\\r\\n display: flex;\\r\\n gap: 6px;\\r\\n align-items: center;\\r\\n }\\r\\n\\r\\n button {\\r\\n flex: 1 1 auto;\\r\\n padding: 5px 8px;\\r\\n border: 1px solid rgba(255, 255, 255, 0.16);\\r\\n border-radius: 4px;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.85);\\r\\n font-size: 12px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n border-color: rgba(97, 175, 239, 0.6);\\r\\n background: rgba(97, 175, 239, 0.14);\\r\\n color: #fff;\\r\\n }\\r\\n }\\r\\n\\r\\n // 닫기는 강조하지 않는다 — 기본 선택이 아니다\\r\\n .ad-drop-ask-close {\\r\\n flex: 0 0 auto;\\r\\n min-width: 26px;\\r\\n padding: 5px 6px;\\r\\n color: rgba(255, 255, 255, 0.45);\\r\\n }\\r\\n\\r\\n .ad-drop-ask-again {\\r\\n display: flex;\\r\\n gap: 5px;\\r\\n align-items: center;\\r\\n margin-top: 8px;\\r\\n margin-bottom: 0;\\r\\n color: rgba(255, 255, 255, 0.5);\\r\\n font-size: 11px;\\r\\n cursor: pointer;\\r\\n }\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","\"use strict\";\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};","\"use strict\";\n\nmodule.exports = function (item) {\n var content = item[1];\n var cssMapping = item[3];\n if (!cssMapping) {\n return content;\n }\n if (typeof btoa === \"function\") {\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(cssMapping))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n var sourceMapping = \"/*# \".concat(data, \" */\");\n return [content].concat([sourceMapping]).join(\"\\n\");\n }\n return [content].join(\"\\n\");\n};","\"use strict\";\n\nvar stylesInDOM = [];\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n for (var i = 0; i < stylesInDOM.length; i++) {\n if (stylesInDOM[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n return result;\n}\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var indexByIdentifier = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3],\n supports: item[4],\n layer: item[5]\n };\n if (indexByIdentifier !== -1) {\n stylesInDOM[indexByIdentifier].references++;\n stylesInDOM[indexByIdentifier].updater(obj);\n } else {\n var updater = addElementStyle(obj, options);\n options.byIndex = i;\n stylesInDOM.splice(i, 0, {\n identifier: identifier,\n updater: updater,\n references: 1\n });\n }\n identifiers.push(identifier);\n }\n return identifiers;\n}\nfunction addElementStyle(obj, options) {\n var api = options.domAPI(options);\n api.update(obj);\n var updater = function updater(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\n return;\n }\n api.update(obj = newObj);\n } else {\n api.remove();\n }\n };\n return updater;\n}\nmodule.exports = function (list, options) {\n options = options || {};\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDOM[index].references--;\n }\n var newLastIdentifiers = modulesToDom(newList, options);\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n var _index = getIndexByIdentifier(_identifier);\n if (stylesInDOM[_index].references === 0) {\n stylesInDOM[_index].updater();\n stylesInDOM.splice(_index, 1);\n }\n }\n lastIdentifiers = newLastIdentifiers;\n };\n};","\"use strict\";\n\nvar memo = {};\n\n/* istanbul ignore next */\nfunction getTarget(target) {\n if (typeof memo[target] === \"undefined\") {\n var styleTarget = document.querySelector(target);\n\n // Special case to return head of iframe instead of iframe itself\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n memo[target] = styleTarget;\n }\n return memo[target];\n}\n\n/* istanbul ignore next */\nfunction insertBySelector(insert, style) {\n var target = getTarget(insert);\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n target.appendChild(style);\n}\nmodule.exports = insertBySelector;","\"use strict\";\n\n/* istanbul ignore next */\nfunction insertStyleElement(options) {\n var element = document.createElement(\"style\");\n options.setAttributes(element, options.attributes);\n options.insert(element, options.options);\n return element;\n}\nmodule.exports = insertStyleElement;","\"use strict\";\n\n/* istanbul ignore next */\nfunction setAttributesWithoutAttributes(styleElement) {\n var nonce = typeof __webpack_nonce__ !== \"undefined\" ? __webpack_nonce__ : null;\n if (nonce) {\n styleElement.setAttribute(\"nonce\", nonce);\n }\n}\nmodule.exports = setAttributesWithoutAttributes;","\"use strict\";\n\n/* istanbul ignore next */\nfunction apply(styleElement, options, obj) {\n var css = \"\";\n if (obj.supports) {\n css += \"@supports (\".concat(obj.supports, \") {\");\n }\n if (obj.media) {\n css += \"@media \".concat(obj.media, \" {\");\n }\n var needLayer = typeof obj.layer !== \"undefined\";\n if (needLayer) {\n css += \"@layer\".concat(obj.layer.length > 0 ? \" \".concat(obj.layer) : \"\", \" {\");\n }\n css += obj.css;\n if (needLayer) {\n css += \"}\";\n }\n if (obj.media) {\n css += \"}\";\n }\n if (obj.supports) {\n css += \"}\";\n }\n var sourceMap = obj.sourceMap;\n if (sourceMap && typeof btoa !== \"undefined\") {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n }\n\n // For old IE\n /* istanbul ignore if */\n options.styleTagTransform(css, styleElement, options.options);\n}\nfunction removeStyleElement(styleElement) {\n // istanbul ignore if\n if (styleElement.parentNode === null) {\n return false;\n }\n styleElement.parentNode.removeChild(styleElement);\n}\n\n/* istanbul ignore next */\nfunction domAPI(options) {\n if (typeof document === \"undefined\") {\n return {\n update: function update() {},\n remove: function remove() {}\n };\n }\n var styleElement = options.insertStyleElement(options);\n return {\n update: function update(obj) {\n apply(styleElement, options, obj);\n },\n remove: function remove() {\n removeStyleElement(styleElement);\n }\n };\n}\nmodule.exports = domAPI;","\"use strict\";\n\n/* istanbul ignore next */\nfunction styleTagTransform(css, styleElement) {\n if (styleElement.styleSheet) {\n styleElement.styleSheet.cssText = css;\n } else {\n while (styleElement.firstChild) {\n styleElement.removeChild(styleElement.firstChild);\n }\n styleElement.appendChild(document.createTextNode(css));\n }\n}\nmodule.exports = styleTagTransform;","\n import API from \"!../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../node_modules/css-loader/dist/cjs.js!../node_modules/sass-loader/dist/cjs.js!./styles.scss\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\n\n options.insert = insertFn.bind(null, \"head\");\n \noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../node_modules/css-loader/dist/cjs.js!../node_modules/sass-loader/dist/cjs.js!./styles.scss\";\n export default content && content.locals ? content.locals : undefined;\n","\"use strict\";\r\n/**\r\n * 에이전트 프로필 — \"클로드든 코덱스든 제미나이든 같은 포맷으로 쓴다\" 를 위한 단일 출처.\r\n *\r\n * 상태 감지(detect.ts)·이미지 붙여넣기 키(deck.service.ts)·입력창 머리글자(prompt.ts)가\r\n * 원래 각자 Claude Code 를 전제로 하드코딩돼 있었다. 새 CLI 를 하나 지원하려면 세 파일을\r\n * 따로 고쳐야 했고, 어떤 값이 실측이고 어떤 값이 짐작인지도 코드에서 구분되지 않았다.\r\n * 그래서 \"무엇을 어떻게 알아보나\" 를 프로필 한 덩이로 모았다 — 새 CLI 는 아래 배열에\r\n * 항목 하나를 더하는 것으로 끝난다.\r\n *\r\n * **이 파일은 순수하다** — DOM·fs·tabby 를 건드리지 않는다. 그래야 노드에서 바로 테스트된다.\r\n *\r\n * 값의 출처 표기 규칙: 실측된 값에는 근거(날짜·파일)를 적고, 관측이 없는 값에는\r\n * `근거 미확인` 을 적는다. 짐작을 실측처럼 적어두면 다음 사람이 그것을 근거로 또 짐작한다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.identifyAgent = exports.detectProfileFor = exports.profileFor = exports.unionProfile = exports.UNKNOWN_PROFILE = exports.AGENT_PROFILES = void 0;\r\n// ---------- 여러 에이전트가 함께 쓰는 조각 ----------\r\n//\r\n// 같은 정규식 객체를 공유한다. 합집합(unionProfile)이 이걸 중복 없이 합칠 수 있어야\r\n// \"프로필 없이 부르면 0.5.0 과 같은 동작\" 이 유지되기 때문이다.\r\n/** 터미널 앱을 가리지 않는 예/아니오 확인 — 셸 스크립트·CLI 가 다 쓴다 */\r\nconst CONFIRM_YN = /\\(y\\/n\\)/i;\r\nconst CONFIRM_YN_CAP = /\\[y\\/N\\]/i;\r\nconst PRESS_ENTER = /Press Enter to continue/i;\r\n/** 작업을 붙잡고 있는 동안에만 뜨는 취소 안내 — Claude 외의 TUI 도 흔히 쓴다 */\r\nconst CTRL_C_INTERRUPT = /ctrl\\+c to (?:interrupt|cancel|stop)/i;\r\n/**\r\n * 입력창 머리글자 — `prompt.ts` 의 `PROMPT_HEAD_RE`(정규식 `^[>❯›❭➜]\\s*`) 와 같은 목록이다.\r\n *\r\n * 이 목록은 지금까지 에이전트를 가리지 않고 쓰였고 그대로 동작해 왔다. 그래서 codex/gemini\r\n * 프로필에도 같은 목록을 준다 — 그 두 앱의 화면을 따로 실측한 것은 아니지만(근거 미확인),\r\n * \"지금 동작\" 을 그대로 옮기는 쪽이 빈 목록을 주어 라벨 읽기를 죽이는 것보다 낫다.\r\n */\r\nconst GENERIC_PROMPT_HEADS = ['>', '❯', '›', '❭', '➜'];\r\n/**\r\n * Claude Code 프로필.\r\n *\r\n * 모든 값이 `detect.ts`/`deck.service.ts` 에 있던 실측값 그대로다 — 옮기기만 했고 바꾸지 않았다.\r\n */\r\nconst CLAUDE = {\r\n id: 'claude',\r\n label: 'Claude Code',\r\n // `claude` 문자열은 경로(`~/.claude/...`)에도 섞여 나오므로 판정 순서를 뒤로 둔다 (MATCH_ORDER 주석)\r\n processHints: ['claude'],\r\n titleHints: ['claude'],\r\n waitingPatterns: [\r\n /Do you want to\\b/i,\r\n /❯\\s*1\\.\\s*Yes/,\r\n CONFIRM_YN,\r\n CONFIRM_YN_CAP,\r\n PRESS_ENTER,\r\n ],\r\n /**\r\n * 작업 중일 때만 화면에 내보내는 문구. 상태줄 갱신 같은 평시 출력과 구분하는 근거다 —\r\n * 이 문구는 일을 붙잡고 있는 동안에만 뜨고 끝나면 사라지므로, 사라진 시점부터 시간을 재면\r\n * 진행중에서 정확히 내려올 수 있다.\r\n */\r\n busyPatterns: [\r\n /esc to interrupt/i,\r\n CTRL_C_INTERRUPT,\r\n /\\btokens?\\b.{0,20}\\besc\\b/i,\r\n ],\r\n /**\r\n * **비운다 — 화면 원문이 채집된 바 없다.**\r\n *\r\n * 이 에이전트의 한도는 훅으로 온다(`claudeHooks.ts` `StopFailure` → 스크립트가\r\n * `error=rate_limit` 이면 `limited` 로 바꿔 보낸다). 훅이 실은 문구\r\n * (`You've hit your session limit · resets 12pm (Asia/Seoul)`)는 `last_assistant_message`\r\n * 이고 **PTY 출력 조각으로 관측한 것이 아니다** — 그것을 화면 패턴으로 옮겨 적으면\r\n * 실측이 아닌 값을 실측처럼 쓰는 것이다. 훅 경로가 이미 이 상태를 만들어 주므로 갭도 없다.\r\n * 화면 원문을 실제로 채집하면(`docs/AGENT-OBSERVATION.md` 절차) 그때 여기 넣는다.\r\n */\r\n limitedPatterns: [],\r\n /**\r\n * 작업 중일 때 콘솔 제목에 넣는 표식.\r\n * 별 모양과 원형 스피너 두 계열을 모두 쓴다 (2026-08-28 실측: \"◐ WindowTitle 설정\").\r\n */\r\n busyTitleMarks: ['✳', '✻', '✽', '✶', '✢', '◐', '◓', '◑', '◒'],\r\n /**\r\n * ESC v 만 받는다. 리터럴 0x16 은 5회 보내도 이미지가 들어가지 않았다\r\n * (2026-08-28 실측, `.agentdeck-diag.log` 09:33:47~48). claude.exe 안의\r\n * `ctrl+v ... paste images` 문구는 자기가 키 이벤트를 직접 볼 때의 안내였다.\r\n */\r\n imagePasteKey: 'alt-v',\r\n /** ASCII `>` 가 아니라 `❯`(U+276F) 를 쓴다 — 2026-09-01 화면 캡처로 확인 (prompt.ts 주석) */\r\n promptHeads: ['❯', '>'],\r\n // promptShape / screenShape 는 일부러 비운다 — prompt.ts·screen.ts 의 기본값이 곧 이\r\n // 에이전트의 실측값이라(그 화면을 보고 만든 규칙이다) 여기 옮겨 적으면 같은 값이 두 곳에\r\n // 생긴다. 화면 모양이 다른 에이전트가 나오면 그때 그 프로필에만 적는다.\r\n // 화면 문구 전부가 이 리포에서 실제로 관찰된 것이다 (위 개별 주석의 날짜)\r\n patternsProven: true,\r\n};\r\n/**\r\n * Codex CLI 프로필.\r\n *\r\n * 실측된 것 —\r\n * - 이미지 붙여넣기: 0x16(ctrl-v) 를 자기 붙여넣기로 받고 ESC v 는 모른다 (2026-08-28 실측)\r\n * - 입력창 머리글자는 `›`(U+203A) 다 — `› Ask Codex to do anything` (2026-09-08, 국면① 채집).\r\n * 기본 `promptHeads` 에 이미 있는 문자라 `promptShape` 가 필요 없다.\r\n * - 배너 테두리는 박스 문자(`╭─╮│╰╯`)지만 **입력창에는 테두리가 없다** — 그래서\r\n * `screenShape` 도 넣지 않는다 (없는 테두리를 찾게 만들면 상시 \"깨짐\" 이 된다).\r\n * - 프로세스 **이름**으로는 안 잡힌다(자식이 `node.exe` 뿐). 제목도 `junggon` 이라 근거가 없다.\r\n * 잡히는 자리는 pid 의 명령줄이고, `deck.service.ts` 의 `commandLinesOf` 폴백이 읽어 준다.\r\n *\r\n * 화면 문구(대기·작업중)는 **여전히 관측하지 못했다.** 2026-09-08 시도가 국면②③ 을 못 만든\r\n * 이유는 두 단계였다 —\r\n * ① 기본 모델 `gpt-5.4` 가 이 계정에서 거부됐다\r\n * (`invalid_request_error … not supported when using Codex with a ChatGPT account`)\r\n * ② `/model` 로 `gpt-6-astra low` 로 바꿔 그 벽은 넘었는데, 그 다음이 계정 사용량 한도였다\r\n * (`■ Usage limit reached. You've reached your usage limit.`)\r\n * 둘 다 우리 코드와 무관한 계정 상태다. 그래서 `patternsProven` 은 false 를 유지한다 —\r\n * 합집합이 받쳐 주므로 프로필을 주지 않으면 예전과 똑같이 판정된다.\r\n *\r\n * 덧붙여 그 실패 화면이 **한도 도달 문구**를 하나 실측으로 남겼다(위 ②). 그 값은 이제\r\n * `limitedPatterns` 에 들어 있다 — 화면 문구로 `limited` 를 판정하는 경로가 생겼기 때문이다\r\n * (`detect.ts`). 대기·작업중이 여전히 미관측이라 `patternsProven` 은 false 그대로지만,\r\n * 합집합이 이 한도 문구를 품으므로(`buildUnion`) codex 탭도 그 문구로 판정된다.\r\n */\r\nconst CODEX = {\r\n id: 'codex',\r\n label: 'Codex CLI',\r\n processHints: ['codex'],\r\n titleHints: ['codex'],\r\n // 근거 미확인 — 터미널 앱 일반의 확인 문구만. codex 고유 문구는 실사용 관측 필요\r\n waitingPatterns: [CONFIRM_YN, CONFIRM_YN_CAP, PRESS_ENTER],\r\n // 근거 미확인 — codex 가 실제로 무엇을 찍는지 관측 필요\r\n busyPatterns: [CTRL_C_INTERRUPT],\r\n /**\r\n * 한도 도달 화면 원문 (2026-09-08 실측, 위 ② · `docs/AGENT-OBSERVATION.md` Codex 표) —\r\n * `■ Usage limit reached. You've reached your usage limit. Increase your limits to continue using codex.`\r\n *\r\n * 같은 뜻이 한 줄에 두 번 나오므로 둘 다 잡는다 — `applyOutput` 은 누적 버퍼가 아니라\r\n * **출력 조각 하나**에 `test` 하므로(`detect.ts`), 청크가 문장 사이에서 갈려도 하나는 살아남는다.\r\n * 오탐을 피해 **넣지 않은 것**:\r\n * - `Increase your limits`(안내 문구) — 한도 국면이 아닌 요금제 안내에도 쓸 수 있는 말이고,\r\n * 청크 뒷토막만 왔을 때 판정이 서면 안 된다.\r\n * - `■` 접두(codex 의 오류 표식) — 모델 거부 오류(위 ①)에도 붙는다. 국면 구분력이 없다.\r\n * - `limit`/`usage` 단독 — 사용자가 그 단어를 화면에 띄우는 일이 흔하다.\r\n */\r\n limitedPatterns: [/usage limit reached/i, /reached your usage limit/i],\r\n // 근거 미확인 — 제목에 스피너를 넣는지 관측된 바 없다\r\n busyTitleMarks: [],\r\n imagePasteKey: 'ctrl-v',\r\n promptHeads: GENERIC_PROMPT_HEADS,\r\n // 화면 문구는 관찰된 바 없다 — 판정은 합집합을 쓴다 (patternsProven 주석)\r\n patternsProven: false,\r\n};\r\n/**\r\n * Gemini CLI 프로필.\r\n *\r\n * **2026-09-08 에 실제로 띄워 3국면(유휴·승인대기·작업중)을 채집했다** (Gemini CLI v0.58.0,\r\n * vertex-ai 인증, 격리 인스턴스 80x33). 절차와 원문은 `docs/AGENT-OBSERVATION.md` 의 채집 표.\r\n *\r\n * 이 CLI 의 특징은 **상태를 콘솔 제목으로 말한다**는 것이다 —\r\n * 유휴 `◇ Ready (work)` / 승인대기 `✋ Action Required (work)` / 작업중 `✦ Working… (work)`\r\n * 그래서 `busyTitleMarks` 에 `✦` 하나만 넣는다. `◇`(유휴)·`✋`(대기)를 넣으면 상시 진행중이\r\n * 되거나 대기를 진행중으로 덮어쓴다.\r\n *\r\n * 아직 못 채운 것: `imagePasteKey`(격리 환경에서 클립보드 이미지를 만들 수 없다 — R6·IN6 선례)\r\n * 라서 `'config'`(사용자 설정값) 폴백을 유지한다.\r\n */\r\nconst GEMINI = {\r\n id: 'gemini',\r\n label: 'Gemini CLI',\r\n /**\r\n * 프로세스 **이름**으로는 안 잡힌다 — npm 전역 래퍼라 자식이 `node.exe` 하나뿐이다\r\n * (2026-09-08 실측: `{ pid, command: 'node.exe' }`). 잡히는 자리는 그 pid 의 명령줄\r\n * (`…/npm/node_modules/@google/gemini-cli/bundle/gemini.js`)이고,\r\n * `deck.service.ts` 의 `commandLinesOf` 폴백이 그것을 읽어 이 힌트에 걸어 준다.\r\n */\r\n processHints: ['gemini'],\r\n /**\r\n * 제목에는 `gemini` 라는 글자가 없다(`◇ Ready (work)`). 그래도 힌트를 남기는 이유는\r\n * 사용자가 탭 이름을 직접 `gemini` 로 바꿔 두는 경우가 실제로 있어서다 — 해가 없다.\r\n */\r\n titleHints: ['gemini'],\r\n /**\r\n * 승인 대화상자 원문 (국면③, `gemini-3-waiting.json`) —\r\n * `│ Allow execution of [Shell]? │`\r\n * `│ ● 1. Allow once │`\r\n * `[Shell]` 자리는 도구 이름마다 바뀌므로 `Allow execution of` 까지만 잡는다.\r\n * 선택지 줄은 커서(`●`)와 번호를 묶어서 본다 — `Allow` 만 보면 설명문에도 걸린다.\r\n */\r\n waitingPatterns: [\r\n /Allow execution of\\b/i,\r\n /●\\s*\\d+\\.\\s*Allow once/,\r\n ],\r\n /**\r\n * 작업 중에만 뜨는 상태줄 (국면②, `gemini-2-busy.json`) —\r\n * ` ⠇ Thinking... (esc to cancel, 6s)`\r\n * Claude 의 `esc to interrupt` 와 문구가 다르다(`cancel`). 끝나면 사라지는 줄이라\r\n * `busyPatterns` 의 요건(`detect.ts`: 사라지는 문구여야 한다)을 만족한다.\r\n * 브라유 스피너(`⠇`/`⠦`)는 표본마다 바뀌지만 **화면** 문자라 여기 넣지 않는다 —\r\n * `busyTitleMarks` 는 제목만 본다.\r\n */\r\n busyPatterns: [/esc to cancel/i],\r\n /**\r\n * **미관측 — 비운다.** 2026-09-08 채집은 3국면(유휴·작업중·승인대기)뿐이고 한도 국면은\r\n * 만들지 못했다. gemini 가 한도를 어떤 문구로 말하는지 본 적이 없으므로 짐작해 넣지 않는다.\r\n *\r\n * 이 프로필은 `patternsProven: true` 라 판정에 자기 값이 쓰인다 — 즉 codex 에서 실측된\r\n * 문구가 여기로 새어 들어오지 않는다. 그게 이 리포의 규칙(\"실측이 있을 때만 좁힌다\")의\r\n * 반대편 대가다: gemini 탭은 한도 문구가 채집될 때까지 화면으로는 `limited` 가 되지 않는다.\r\n */\r\n limitedPatterns: [],\r\n /**\r\n * 작업 중 제목 마크 (국면② 10표본 전부 `✦ Working… (work)`).\r\n * 국면①은 `◇`, 국면③은 `✋` 였으므로 이 하나만 진행중의 근거다.\r\n */\r\n busyTitleMarks: ['✦'],\r\n // 판정 불가 — 격리 환경에서 클립보드 이미지를 만들 수 없다 (docs/AGENT-OBSERVATION.md)\r\n imagePasteKey: 'config',\r\n /** 입력창 머리는 ASCII `>` 다 (`> Type your message or @path/to/file`) — 기본값에 이미 있다 */\r\n promptHeads: GENERIC_PROMPT_HEADS,\r\n /**\r\n * 입력창 테두리가 **반블록**이다 — 위 `▄`(U+2584), 아래 `▀`(U+2580), 둘 다 폭을 꽉 채운다.\r\n * 기본 테두리 문자(`─`/`━`/`═`)로는 이 입력창을 못 찾으므로 여기서 넓혀 준다.\r\n * 화면 판정(`screenShape`)에도 같은 문자를 주되 ASCII `-` 는 넣지 않는다 —\r\n * 코드·마크다운의 `-----` 이 테두리로 세어져 오탐이 쏟아진다(`src/screen.ts` 주석).\r\n */\r\n promptShape: { ruleChars: ['\\u2584', '\\u2580', '\\u2500', '\\u2501', '\\u2550', '-'] },\r\n screenShape: { ruleChars: ['\\u2584', '\\u2580', '\\u2500', '\\u2501', '\\u2550'] },\r\n // 위 값 전부가 2026-09-08 실측이다 (docs/AGENT-OBSERVATION.md 채집 표에 원문)\r\n patternsProven: true,\r\n};\r\n/** 지원하는 에이전트 목록 — 새 CLI 는 여기에 한 덩이 추가하면 된다 */\r\nexports.AGENT_PROFILES = [CLAUDE, CODEX, GEMINI];\r\n/**\r\n * 식별 순서 — **claude 를 맨 뒤에 둔다.**\r\n *\r\n * `claude` 라는 문자열은 경로에 섞여 나온다(`~/.claude/...`, `claude_workflow/`). codex 를\r\n * 먼저 보지 않으면 codex 세션이 claude 로 잡힐 수 있다. 옛 `detectAgentApp` 이 codex 를\r\n * claude 보다 먼저 본 이유가 이것이고, 그 성질을 그대로 유지한다.\r\n */\r\nconst MATCH_ORDER = ['codex', 'gemini', 'claude'];\r\n/** 같은 정규식이 두 번 들어가지 않게 — 합집합을 만들 때 쓴다 */\r\nfunction dedupeRe(list) {\r\n const seen = new Set();\r\n const out = [];\r\n for (const re of list) {\r\n const key = `${re.source}\\u0000${re.flags}`;\r\n if (!seen.has(key)) {\r\n seen.add(key);\r\n out.push(re);\r\n }\r\n }\r\n return out;\r\n}\r\nfunction dedupeStr(list) {\r\n return [...new Set(list)];\r\n}\r\n/**\r\n * 어느 에이전트인지 못 알아냈을 때 쓰는 프로필 = **모든 프로필의 합집합.**\r\n *\r\n * 0.5.0 까지의 동작이 정확히 이것이었다 — detect.ts 가 Claude 기준 패턴 하나로 모든 탭을\r\n * 판정했고, codex/gemini 에 우리가 추가로 넣은 패턴은 Claude 것의 부분집합이므로\r\n * 합집합은 그때의 목록과 같다. 그래서 프로필 없이 detect 를 부르면 예전과 결과가 같다\r\n * (test/detect.test.js 의 기존 17종이 그것을 고정한다).\r\n *\r\n * 이미지 키만은 합집합을 만들 수 없다(키는 하나만 보낼 수 있다) — `config` 로 두어\r\n * 예전처럼 사용자 설정값으로 떨어지게 한다.\r\n */\r\nfunction buildUnion() {\r\n return {\r\n id: 'unknown',\r\n label: '알 수 없음',\r\n processHints: dedupeStr(exports.AGENT_PROFILES.flatMap(p => p.processHints)),\r\n titleHints: dedupeStr(exports.AGENT_PROFILES.flatMap(p => p.titleHints)),\r\n waitingPatterns: dedupeRe(exports.AGENT_PROFILES.flatMap(p => p.waitingPatterns)),\r\n busyPatterns: dedupeRe(exports.AGENT_PROFILES.flatMap(p => p.busyPatterns)),\r\n // 한도 문구도 여기서 모인다 — 이 한 줄이 \"codex 는 patternsProven=false 인데 어떻게\r\n // 실측된 한도 문구로 판정되나\" 의 답이다. detectProfileFor 가 그 프로필의 화면 문구를\r\n // 합집합으로 갈아 끼우고, 합집합에는 codex 자신이 실측한 문구가 들어 있다\r\n limitedPatterns: dedupeRe(exports.AGENT_PROFILES.flatMap(p => p.limitedPatterns)),\r\n busyTitleMarks: dedupeStr(exports.AGENT_PROFILES.flatMap(p => p.busyTitleMarks)),\r\n imagePasteKey: 'config',\r\n promptHeads: dedupeStr([...GENERIC_PROMPT_HEADS, ...exports.AGENT_PROFILES.flatMap(p => p.promptHeads)]),\r\n // 합집합 자신은 \"실측된 것을 다 모은 것\" 이라 더 넓힐 대상이 없다 —\r\n // 이 값이 false 면 detectProfileFor 가 자기 자신을 다시 펼치려 든다\r\n patternsProven: true,\r\n };\r\n}\r\nexports.UNKNOWN_PROFILE = buildUnion();\r\n/** 프로필을 모르는 상황(감지 전/실패)에서 쓰는 합집합 — 0.5.0 까지의 동작과 같다 */\r\nfunction unionProfile() {\r\n return exports.UNKNOWN_PROFILE;\r\n}\r\nexports.unionProfile = unionProfile;\r\n/** 아이디로 프로필을 집는다 — 모르는 아이디면 합집합을 준다(호출부에 null 검사를 강요하지 않는다) */\r\nfunction profileFor(id) {\r\n var _a;\r\n return (_a = exports.AGENT_PROFILES.find(p => p.id === id)) !== null && _a !== void 0 ? _a : exports.UNKNOWN_PROFILE;\r\n}\r\nexports.profileFor = profileFor;\r\n/**\r\n * **상태 판정(detect.ts)에 넘길** 프로필. 화면 문구가 실측되지 않은 에이전트는 그 세 필드만\r\n * 합집합으로 갈아 준다 — 나머지 필드(이미지 키·머리글자·라벨)는 프로필 것을 그대로 쓴다.\r\n *\r\n * 왜 이 함수가 따로 있나 — 프로필을 붙이는 것만으로 판정이 좁아지면 관측이 없는 에이전트에서는\r\n * **퇴행**이다. 0.5.0 은 합집합 하나로 모든 탭을 판정했으므로, 예컨대 Codex 가 실제로\r\n * `esc to interrupt` 를 찍고 있었다면 그때는 잡혔는데 프로필을 붙인 뒤로는 놓치게 된다\r\n * (유닛 C 가 그 리스크를 보고했고, 그래서 배리어에서 이 갈래를 넣었다).\r\n *\r\n * 즉 **좁히는 것은 실측이 있을 때만** 한다. Codex/Gemini 화면 문구가 관측되면 그 프로필의\r\n * `patternsProven` 을 true 로 올리면 이 함수가 자동으로 프로필 값을 쓴다.\r\n */\r\nfunction detectProfileFor(id) {\r\n const profile = profileFor(id);\r\n if (profile.patternsProven) {\r\n return profile;\r\n }\r\n const union = exports.UNKNOWN_PROFILE;\r\n return {\r\n ...profile,\r\n waitingPatterns: union.waitingPatterns,\r\n busyPatterns: union.busyPatterns,\r\n // 한도 문구도 같은 취급 — 합집합은 항상 프로필의 상위집합이라(모든 프로필을 flatMap)\r\n // 이 교체로 잃는 것이 없다. codex 는 이 줄 때문에 자기 실측 한도 문구를 계속 쓴다\r\n limitedPatterns: union.limitedPatterns,\r\n busyTitleMarks: union.busyTitleMarks,\r\n // 화면 모양도 같은 원칙이다 — 실측이 없으면 좁히지 않는다. shape 를 빼면 읽는 쪽이\r\n // 자기 기본값(= 지금까지의 동작)을 쓴다. 지금은 codex/gemini 가 shape 를 아예 안 들고\r\n // 있어 무의미해 보이지만, 나중에 누가 짐작으로 채워 넣어도 여기서 막힌다\r\n promptShape: undefined,\r\n screenShape: undefined,\r\n };\r\n}\r\nexports.detectProfileFor = detectProfileFor;\r\n/**\r\n * 이 탭에서 도는 에이전트가 뭔지 — 프로세스 이름/명령줄을 먼저 보고, 없으면 탭 제목으로 본다.\r\n *\r\n * 프로세스를 먼저 보는 이유: npm 전역 래퍼를 거치면 명령줄이 node/pwsh 로만 보일 수 있어\r\n * 제목이 보조 근거가 되지만, 제목은 셸이 아무 문자열이나 넣을 수 있어 신뢰도가 낮다.\r\n * 두 근거 안에서의 에이전트 판정 순서는 `MATCH_ORDER` — claude 가 맨 뒤다.\r\n *\r\n * @param processNames 프로세스 트리에서 모은 `command name` 을 이어붙인 문자열\r\n * @param title 탭 제목(+ 사용자 지정 제목)\r\n */\r\nfunction identifyAgent(processNames, title) {\r\n const procs = (processNames !== null && processNames !== void 0 ? processNames : '').toLowerCase();\r\n for (const id of MATCH_ORDER) {\r\n if (profileFor(id).processHints.some(h => procs.includes(h))) {\r\n return id;\r\n }\r\n }\r\n const t = (title !== null && title !== void 0 ? title : '').toLowerCase();\r\n for (const id of MATCH_ORDER) {\r\n if (profileFor(id).titleHints.some(h => t.includes(h))) {\r\n return id;\r\n }\r\n }\r\n return 'unknown';\r\n}\r\nexports.identifyAgent = identifyAgent;\r\n","\"use strict\";\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckAlertService = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\nconst status_service_1 = require(\"./status.service\");\r\nconst api_1 = require(\"./api\");\r\nconst diag_1 = require(\"./diag\");\r\n/** 창 밖으로 알려야 하는 상태 — 사람이 손을 대야 진행되는 것들 */\r\n/** 창이 뒤에 있을 때 알릴 상태 — 사람이 봐야 하는 것: 승인 / 오류 / 한도에 걸려 멈춤 */\r\nconst ALERT_STATUSES = ['waiting', 'error', 'limited'];\r\n/**\r\n * 창이 뒤로 가 있을 때의 OS 알림.\r\n *\r\n * 사이드바는 창이 보일 때만 의미가 있다. 에이전트 탭을 여섯 개쯤 굴리면서 Slack·VS 를 보고\r\n * 있으면 어느 탭이 `승인대기` 로 멈춰 있어도 알 길이 없어서, 돌아와 보면 몇 분씩 놀고 있던\r\n * 일이 잦았다. 그래서 상태가 **`waiting` / `error` 로 넘어가는 순간** 창이 포커스를 잃은\r\n * 상태면 OS 쪽에 세 가지로 알린다.\r\n *\r\n * 1. **작업표시줄 깜빡임** (`flashFrame`) — 창이 포커스를 받으면 끈다. `alertFlash`\r\n * 2. **작업표시줄 뱃지** — 지금 `waiting`+`error` 인 탭 수를 아이콘 위에 얹는다. Windows 에는\r\n * `setBadgeCount` 가 없어서 `setOverlayIcon` 에 캔버스로 그린 원+숫자를 넣는다.\r\n * 전이 순간만이 아니라 상태가 바뀔 때마다 갱신해 실제 개수를 따라간다. `alertBadge`\r\n * 3. **OS 토스트** (`Notification`) — 기본은 끔. 누르면 창을 앞으로 가져오고 그 탭을 고른다. `alertToast`\r\n *\r\n * 창이 앞에 있을 때는 아무것도 하지 않는다 — 사이드바가 이미 보이고 있다.\r\n * Electron 을 만지는 모든 곳은 try/catch 로 감싼다. 알림이 안 되는 것은 불편이지만\r\n * 예외가 새어 나가 다른 배선을 죽이는 것은 사고다.\r\n */\r\nlet AgentDeckAlertService = class AgentDeckAlertService {\r\n constructor(app, config, zone, status) {\r\n this.app = app;\r\n this.config = config;\r\n this.zone = zone;\r\n this.status = status;\r\n /** 탭별로 마지막에 본 상태 — \"전이\" 를 판정하려고 들고 있는다 */\r\n this.last = new WeakMap();\r\n /** flashFrame(true) 를 걸어 둔 상태인가 — 포커스가 오면 끈다 */\r\n this.flashing = false;\r\n /** 마지막으로 그린 뱃지 숫자 (0 = 안 그림). 같은 숫자면 다시 그리지 않는다 */\r\n this.badgeShown = 0;\r\n /** 뱃지 그림 캐시 — key 는 `${count}:${color}` */\r\n this.badgeCache = new Map();\r\n /**\r\n * 진단/검증용 카운터 — CDP 에서 `__agentdeck.alert` 로 읽는다.\r\n * `forceUnfocused` 를 true 로 두면 포커스 판정을 건너뛰고 \"창이 뒤에 있다\" 로 친다\r\n * (테스트 인스턴스가 앞에 떠 있는 상태에서 알림 경로를 밟아 보려고)\r\n */\r\n this.debug = {\r\n flashes: 0,\r\n badgeCount: 0,\r\n badgeDraws: 0,\r\n toasts: 0,\r\n transitions: 0,\r\n lastFocused: null,\r\n forceUnfocused: false,\r\n };\r\n }\r\n init() {\r\n this.app.ready$.subscribe(() => {\r\n var _a;\r\n try {\r\n this.setup();\r\n }\r\n catch (e) {\r\n this.diag(`alert setup ERROR ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`);\r\n }\r\n });\r\n }\r\n setup() {\r\n var _a;\r\n // 기동 시점의 상태를 기준선으로 삼는다 — 이미 waiting 인 탭은 \"전이\" 가 아니다\r\n for (const tab of this.app.tabs) {\r\n this.last.set(tab, this.status.get(tab).status);\r\n }\r\n this.status.changed$.subscribe(() => {\r\n var _a;\r\n try {\r\n this.onChanged();\r\n }\r\n catch (e) {\r\n this.diag(`alert onChanged ERROR ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`);\r\n }\r\n });\r\n // 닫힌 탭은 개수에서 빠져야 한다 — status.changed$ 는 탭 닫힘에 안 울린다\r\n this.app.tabClosed$.subscribe(tab => {\r\n var _a;\r\n this.last.delete(tab);\r\n try {\r\n this.updateBadge(this.countAlerting());\r\n }\r\n catch (e) {\r\n this.diag(`alert tabClosed ERROR ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`);\r\n }\r\n });\r\n // 사람이 돌아왔다 — 깜빡임은 여기서 끝난다. 뱃지는 상태가 풀릴 때 따로 지워진다\r\n window.addEventListener('focus', () => this.stopFlash());\r\n // 개발/진단용 — deck.service 가 만든 __agentdeck 에 붙는다 (없으면 만든다)\r\n const g = window;\r\n g.__agentdeck = (_a = g.__agentdeck) !== null && _a !== void 0 ? _a : {};\r\n g.__agentdeck.alert = this.debug;\r\n this.diag(`alert ready tabs=${this.app.tabs.length}`);\r\n }\r\n /**\r\n * 상태가 바뀔 때마다 — 뱃지는 항상 실제 개수로 맞추고,\r\n * 알림 상태로 **새로 들어온** 탭이 있고 창이 뒤에 있으면 깜빡임/토스트를 낸다\r\n */\r\n onChanged() {\r\n const entered = [];\r\n let count = 0;\r\n for (const tab of this.app.tabs) {\r\n const now = this.status.get(tab).status;\r\n const prev = this.last.get(tab);\r\n this.last.set(tab, now);\r\n if (!ALERT_STATUSES.includes(now)) {\r\n continue;\r\n }\r\n count++;\r\n // waiting -> error 도 전이로 친다 — 성격이 다른 일이 새로 생긴 것이다\r\n if (prev !== now) {\r\n entered.push(tab);\r\n }\r\n }\r\n this.updateBadge(count);\r\n if (entered.length === 0) {\r\n return;\r\n }\r\n this.debug.transitions += entered.length;\r\n const focused = this.isFocused();\r\n this.debug.lastFocused = focused;\r\n if (focused) {\r\n return;\r\n }\r\n this.diag(`alert enter=${entered.length} count=${count} focused=${focused}`);\r\n if (this.config.store.agentDeck.alertFlash) {\r\n this.flash();\r\n }\r\n if (this.config.store.agentDeck.alertToast) {\r\n for (const tab of entered) {\r\n this.toast(tab);\r\n }\r\n }\r\n }\r\n countAlerting() {\r\n let n = 0;\r\n for (const tab of this.app.tabs) {\r\n if (ALERT_STATUSES.includes(this.status.get(tab).status)) {\r\n n++;\r\n }\r\n }\r\n return n;\r\n }\r\n // ---------- Electron 접근 ----------\r\n /** `@electron/remote` 의 현재 창. 못 잡으면 null — 호출부는 전부 null 을 감안한다 */\r\n win() {\r\n var _a, _b, _c, _d;\r\n try {\r\n const req = (_a = window.require) !== null && _a !== void 0 ? _a : globalThis.require;\r\n return (_d = (_c = (_b = req === null || req === void 0 ? void 0 : req('@electron/remote')) === null || _b === void 0 ? void 0 : _b.getCurrentWindow) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : null;\r\n }\r\n catch {\r\n return null;\r\n }\r\n }\r\n nativeImage() {\r\n var _a, _b, _c;\r\n try {\r\n const req = (_a = window.require) !== null && _a !== void 0 ? _a : globalThis.require;\r\n return (_c = (_b = req === null || req === void 0 ? void 0 : req('electron')) === null || _b === void 0 ? void 0 : _b.nativeImage) !== null && _c !== void 0 ? _c : null;\r\n }\r\n catch {\r\n return null;\r\n }\r\n }\r\n /**\r\n * 창이 앞에 있나. Electron 의 판정을 우선하고(devtools 를 따로 띄워도 본창 기준으로 본다),\r\n * remote 를 못 잡으면 DOM 의 `document.hasFocus()` 로 대신한다\r\n */\r\n isFocused() {\r\n if (this.debug.forceUnfocused) {\r\n return false;\r\n }\r\n try {\r\n const win = this.win();\r\n if (win === null || win === void 0 ? void 0 : win.isFocused) {\r\n return !!win.isFocused();\r\n }\r\n }\r\n catch {\r\n // 아래 DOM 판정으로\r\n }\r\n return document.hasFocus();\r\n }\r\n // ---------- 깜빡임 ----------\r\n flash() {\r\n var _a;\r\n try {\r\n const win = this.win();\r\n if (!(win === null || win === void 0 ? void 0 : win.flashFrame)) {\r\n return;\r\n }\r\n win.flashFrame(true);\r\n this.flashing = true;\r\n this.debug.flashes++;\r\n }\r\n catch (e) {\r\n this.diag(`alert flash ERROR ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`);\r\n }\r\n }\r\n stopFlash() {\r\n var _a, _b;\r\n if (!this.flashing) {\r\n return;\r\n }\r\n this.flashing = false;\r\n try {\r\n (_b = (_a = this.win()) === null || _a === void 0 ? void 0 : _a.flashFrame) === null || _b === void 0 ? void 0 : _b.call(_a, false);\r\n }\r\n catch {\r\n // 포커스가 오면 Windows 가 알아서 멈추므로 실패해도 남는 건 없다\r\n }\r\n }\r\n // ---------- 뱃지 ----------\r\n /**\r\n * 작업표시줄 아이콘 위의 숫자를 지금 개수로 맞춘다. 0 이면 지운다.\r\n * `alertBadge` 가 꺼져 있으면 그려 둔 것이 있을 때만 지우고 끝낸다\r\n */\r\n updateBadge(count) {\r\n var _a;\r\n this.debug.badgeCount = count;\r\n const enabled = !!this.config.store.agentDeck.alertBadge;\r\n const want = enabled ? count : 0;\r\n if (want === this.badgeShown) {\r\n return;\r\n }\r\n try {\r\n const win = this.win();\r\n if (!(win === null || win === void 0 ? void 0 : win.setOverlayIcon)) {\r\n return;\r\n }\r\n if (want === 0) {\r\n win.setOverlayIcon(null, '');\r\n this.badgeShown = 0;\r\n // 개수가 0 으로 내려왔으면 깜빡일 이유도 사라졌다\r\n this.stopFlash();\r\n return;\r\n }\r\n const img = this.badgeImage(want);\r\n if (!img) {\r\n return;\r\n }\r\n win.setOverlayIcon(img, `승인대기/오류 ${want}개`);\r\n this.badgeShown = want;\r\n this.debug.badgeDraws++;\r\n }\r\n catch (e) {\r\n this.diag(`alert badge ERROR ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`);\r\n }\r\n }\r\n /**\r\n * 원 위에 숫자를 얹은 오버레이 이미지. 오류 탭이 하나라도 있으면 오류색, 아니면 승인대기색.\r\n * Windows 오버레이는 16px 기준이라 16@1x + 32@2x 두 표현을 넣는다 (고배율에서 흐려지지 않게).\r\n * `addRepresentation` 을 못 쓰는 빌드면 32px 하나로 물러난다\r\n */\r\n badgeImage(count) {\r\n var _a;\r\n const hasError = this.app.tabs.some(t => this.status.get(t).status === 'error');\r\n const color = hasError ? api_1.STATUS_STYLES.error.color : api_1.STATUS_STYLES.waiting.color;\r\n const key = `${count}:${color}`;\r\n const cached = this.badgeCache.get(key);\r\n if (cached) {\r\n return cached;\r\n }\r\n const nativeImage = this.nativeImage();\r\n if (!nativeImage) {\r\n return null;\r\n }\r\n const text = count > 9 ? '9+' : String(count);\r\n let img;\r\n try {\r\n img = nativeImage.createEmpty();\r\n img.addRepresentation({ scaleFactor: 1, width: 16, height: 16, dataURL: this.drawBadge(16, text, color) });\r\n img.addRepresentation({ scaleFactor: 2, width: 32, height: 32, dataURL: this.drawBadge(32, text, color) });\r\n if ((_a = img.isEmpty) === null || _a === void 0 ? void 0 : _a.call(img)) {\r\n throw new Error('empty after addRepresentation');\r\n }\r\n }\r\n catch {\r\n img = nativeImage.createFromDataURL(this.drawBadge(32, text, color));\r\n }\r\n this.badgeCache.set(key, img);\r\n return img;\r\n }\r\n /** 오프스크린 canvas 에 원+숫자를 그려 data URL 로 돌려준다 */\r\n drawBadge(size, text, color) {\r\n const canvas = document.createElement('canvas');\r\n canvas.width = size;\r\n canvas.height = size;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) {\r\n throw new Error('canvas 2d 미지원');\r\n }\r\n const r = size / 2;\r\n ctx.clearRect(0, 0, size, size);\r\n ctx.beginPath();\r\n ctx.arc(r, r, r - 0.5, 0, Math.PI * 2);\r\n ctx.fillStyle = color;\r\n ctx.fill();\r\n // 어두운 작업표시줄 위에서 원 테두리가 살게 얇은 흰 선\r\n ctx.lineWidth = Math.max(1, size / 16);\r\n ctx.strokeStyle = 'rgba(255,255,255,0.85)';\r\n ctx.stroke();\r\n ctx.fillStyle = '#ffffff';\r\n ctx.font = `bold ${Math.round(size * (text.length > 1 ? 0.55 : 0.7))}px \"Segoe UI\", sans-serif`;\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'middle';\r\n // 글리프의 시각적 중심이 살짝 위로 치우쳐서 조금 내린다\r\n ctx.fillText(text, r, r + size * 0.04);\r\n return canvas.toDataURL('image/png');\r\n }\r\n // ---------- 토스트 ----------\r\n /** OS 토스트. 누르면 창을 앞으로 가져오고 그 탭을 고른다 */\r\n toast(tab) {\r\n var _a;\r\n try {\r\n if (typeof Notification === 'undefined') {\r\n return;\r\n }\r\n const s = this.status.get(tab);\r\n const name = s.label || tab.title || '(제목 없음)';\r\n const style = api_1.STATUS_STYLES[s.status];\r\n const n = new Notification('AgentDeck', {\r\n body: `${name} — ${style.label}`,\r\n // 같은 탭의 토스트는 하나로 겹친다 (waiting -> error 가 잇달아 와도 두 장이 쌓이지 않게)\r\n tag: `agentdeck-${this.tabKey(tab)}`,\r\n });\r\n this.debug.toasts++;\r\n n.onclick = () => {\r\n var _a, _b;\r\n try {\r\n const win = this.win();\r\n (_a = win === null || win === void 0 ? void 0 : win.show) === null || _a === void 0 ? void 0 : _a.call(win);\r\n (_b = win === null || win === void 0 ? void 0 : win.focus) === null || _b === void 0 ? void 0 : _b.call(win);\r\n }\r\n catch {\r\n // 창을 못 올려도 탭 선택은 해 둔다\r\n }\r\n this.zone.run(() => {\r\n if (this.app.tabs.includes(tab)) {\r\n this.app.selectTab(tab);\r\n }\r\n });\r\n n.close();\r\n };\r\n }\r\n catch (e) {\r\n this.diag(`alert toast ERROR ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`);\r\n }\r\n }\r\n /** 토스트 tag 용 탭 식별자 — 객체 자체는 문자열이 안 되니 인덱스로 대신한다 */\r\n tabKey(tab) {\r\n const i = this.app.tabs.indexOf(tab);\r\n return i >= 0 ? String(i) : 'x';\r\n }\r\n // ---------- 진단 ----------\r\n /** deck.service 와 같은 파일(`~/.agentdeck-diag.log`)에 남긴다 — 회전·시각 표기는 `diag.ts` 가 한다 */\r\n diag(line) {\r\n (0, diag_1.diag)(line);\r\n }\r\n};\r\nAgentDeckAlertService = __decorate([\r\n (0, core_1.Injectable)({ providedIn: 'root' }),\r\n __metadata(\"design:paramtypes\", [tabby_core_1.AppService,\r\n tabby_core_1.ConfigService,\r\n core_1.NgZone,\r\n status_service_1.WorkStatusService])\r\n], AgentDeckAlertService);\r\nexports.AgentDeckAlertService = AgentDeckAlertService;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.STATUS_STYLES = void 0;\r\n/** 상태별 표시 규칙 — 사이드바 배지와 좌측 컬러바에 함께 쓰인다 */\r\nexports.STATUS_STYLES = {\r\n running: { icon: '●', label: '진행중', color: '#e5c07b' },\r\n waiting: { icon: '⏸', label: '승인대기', color: '#61afef' },\r\n limited: { icon: '⛔', label: '한도 도달', color: '#c678dd' },\r\n done: { icon: '✔', label: '완료', color: '#98c379' },\r\n error: { icon: '✖', label: '오류', color: '#e06c75' },\r\n idle: { icon: '○', label: '대기', color: '#6b727d' },\r\n};\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.pickTabByPids = void 0;\r\nfunction pickTabByPids(pids, tabPids) {\r\n const wanted = (pids !== null && pids !== void 0 ? pids : []).filter(n => Number.isInteger(n) && n > 0);\r\n let anyInfo = false;\r\n for (const list of tabPids.values()) {\r\n if (list.length) {\r\n anyInfo = true;\r\n break;\r\n }\r\n }\r\n if (!wanted.length || !anyInfo) {\r\n return { tab: null, mode: 'legacy' };\r\n }\r\n const set = new Set(wanted);\r\n for (const [tab, list] of tabPids) {\r\n if (list.some(p => set.has(p))) {\r\n return { tab, mode: 'pid' };\r\n }\r\n }\r\n return { tab: null, mode: 'pid-miss' };\r\n}\r\nexports.pickTabByPids = pickTabByPids;\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.uninstallHooks = exports.installHooks = exports.hooksInstalled = exports.stripHooks = exports.mergeHooks = exports.isMerged = exports.hooksSupported = exports.notifyScriptPath = exports.claudeSettingsPath = void 0;\r\nconst fs = __importStar(require(\"fs\"));\r\nconst os = __importStar(require(\"os\"));\r\nconst path = __importStar(require(\"path\"));\r\n/**\r\n * Claude Code 상태 통보 훅을 사용자의 Claude 설정에 등록/해제한다.\r\n *\r\n * 왜 플러그인이 남의 설정 파일을 만지나 — 훅은 Claude Code 쪽 설정(`~/.claude/settings.json`)에\r\n * 있어야 하고, npm 으로 배포되는 Tabby 플러그인은 그 파일에 손댈 방법이 달리 없다.\r\n * 그래서 \"설치할지\" 를 사용자가 설정 창에서 직접 고르게 하고, 고른 순간에만 쓴다.\r\n * 쓰기 전에 항상 백업을 남기고, 남의 훅은 건드리지 않는다.\r\n *\r\n * 훅이 있으면 상태 판정이 정확해진다. 에이전트가 \"지시를 받았다 / 승인을 기다린다 / 끝났다\" 를\r\n * 직접 알려주기 때문이다. 훅이 없으면 화면에 그려진 글자로 추측하는 폴백(detect.ts)이 도는데,\r\n * 그건 TUI 가 화면을 어떻게 그리는지에 기대는 만큼 흔들린다.\r\n */\r\n/** 우리 훅인지 알아보는 표식 — 파일 이름이 그대로 명령줄에 들어간다 */\r\nconst MARK = 'agentdeck-notify';\r\n/**\r\n * 어떤 순간에 무엇을 보고할지.\r\n *\r\n * **상태만 보낸다 — 작업 이름은 여기서 보내지 않는다.** 라벨은 플러그인이 Enter 시점에\r\n * 입력창을 읽어 매번 갱신하는 경로(`claimEnterLabel`)가 전담한다. 예전에는 여기에\r\n * `-PromptAsLabel` 이 붙어 있었는데, 훅이 상태 파일의 직전 라벨을 도로 써 넣는 바람에\r\n * 플러그인이 방금 넣은 최신 프롬프트를 옛 값으로 되돌렸다 (2026-09-01 실측).\r\n */\r\nconst PLAN = [\r\n // 지시를 받았다\r\n { event: 'UserPromptSubmit', args: '-Status running' },\r\n // 승인을 기다린다\r\n { event: 'Notification', args: '-Status waiting' },\r\n // 승인 뒤 도구가 돌았다 / 실패했다 / 사람이 거부했다 — 어느 쪽이든 에이전트는 다시 일하는 중이다.\r\n // 이 셋이 없으면 승인대기에서 내려올 훅이 Stop 밖에 없어 승인을 해 줘도 사이드바가 승인대기에\r\n // 박혀 있었다 (2026-09-07 실측). 스크립트는 이미 running 이면 아무것도 쓰지 않아 도구마다 도는 비용이 없다\r\n { event: 'PostToolUse', args: '-Status running' },\r\n { event: 'PostToolUseFailure', args: '-Status running' },\r\n { event: 'PermissionDenied', args: '-Status running' },\r\n // 서브에이전트가 뜨고 졌다 — **개수는 이 두 줄이 진실이다.**\r\n // 예전에는 대화기록(JSONL)을 2초마다 훑어 세었는데(subagents.ts), 그건 파일에 기록이 닿은\r\n // 뒤에야 보이고 종료 알림의 JSON 모양이 세 가지라 놓치기 쉬웠다 — 화면에 5개가 떠 있는데\r\n // 배지가 4로 남는 어긋남이 실제로 났다 (2026-09-11 유저 스크린샷).\r\n // 이 두 이벤트에는 `agent_id` 가 실려 오므로(실측 payload) 켜짐/꺼짐을 id 로 정확히 맞출 수 있다.\r\n { event: 'SubagentStart', args: '-Subagent start' },\r\n { event: 'SubagentStop', args: '-Subagent stop' },\r\n // 답이 끝났다\r\n { event: 'Stop', args: '-Status done' },\r\n // 턴이 실패로 끝났다 — 스크립트가 `error` 를 보고 rate_limit(사용량 한도)이면 limited 로 바꿔 보낸다\r\n { event: 'StopFailure', args: '-Status error' },\r\n];\r\nfunction claudeSettingsPath() {\r\n return path.join(os.homedir(), '.claude', 'settings.json');\r\n}\r\nexports.claudeSettingsPath = claudeSettingsPath;\r\n/** 훅 스크립트의 실제 경로. dist/index.js 기준으로 한 단계 위가 패키지 뿌리다 */\r\nfunction notifyScriptPath() {\r\n return path.join(__dirname, '..', 'hooks', 'agentdeck-notify.ps1');\r\n}\r\nexports.notifyScriptPath = notifyScriptPath;\r\n/** 이 환경에서 훅을 걸 수 있나 — 통보 스크립트가 PowerShell 이라 Windows 전용이다 */\r\nfunction hooksSupported() {\r\n return process.platform === 'win32' && fs.existsSync(notifyScriptPath());\r\n}\r\nexports.hooksSupported = hooksSupported;\r\nfunction readSettings() {\r\n try {\r\n const raw = fs.readFileSync(claudeSettingsPath(), 'utf8');\r\n return raw.trim() ? JSON.parse(raw) : {};\r\n }\r\n catch {\r\n // 파일이 없거나 아직 JSON 이 아니다 — 새로 만드는 것으로 본다\r\n return {};\r\n }\r\n}\r\n/** 이 이벤트에 걸린 훅 중 우리 것이 아닌 것만 남긴다 */\r\nfunction withoutOurs(entries) {\r\n return (Array.isArray(entries) ? entries : [])\r\n .filter(e => !JSON.stringify(e !== null && e !== void 0 ? e : '').includes(MARK));\r\n}\r\n/**\r\n * 우리 훅이 PLAN 의 모든 이벤트에 걸려 있나 — 파일을 읽지 않는 순수 판정.\r\n * 이벤트가 늘어난 버전으로 올라오면 옛 설치는 \"설치 안 됨\" 으로 보인다 — 설정 창에서 설치를 다시 누르면 된다.\r\n * 파일 접근과 분리해 둔 이유는 이 판단을 테스트로 묶어 두기 위해서다.\r\n */\r\nfunction isMerged(settings) {\r\n var _a;\r\n const hooks = (_a = settings === null || settings === void 0 ? void 0 : settings.hooks) !== null && _a !== void 0 ? _a : {};\r\n return PLAN.every(p => {\r\n const entries = Array.isArray(hooks[p.event]) ? hooks[p.event] : [];\r\n return entries.some((e) => JSON.stringify(e !== null && e !== void 0 ? e : '').includes(MARK));\r\n });\r\n}\r\nexports.isMerged = isMerged;\r\n/**\r\n * 설정 객체에 우리 훅을 더한 새 객체를 돌려준다 (원본은 건드리지 않는다).\r\n * 이미 우리 것이 있으면 명령줄만 지금 경로로 갈아끼우고, 남이 걸어 둔 훅은 그대로 둔다.\r\n */\r\nfunction mergeHooks(settings, script) {\r\n var _a;\r\n const next = { ...(settings !== null && settings !== void 0 ? settings : {}) };\r\n next.hooks = { ...((_a = next.hooks) !== null && _a !== void 0 ? _a : {}) };\r\n for (const p of PLAN) {\r\n const command = `powershell -NoProfile -ExecutionPolicy Bypass -File \"${script}\" ${p.args}`;\r\n next.hooks[p.event] = [\r\n ...withoutOurs(next.hooks[p.event]),\r\n { matcher: '*', hooks: [{ type: 'command', command, timeout: 5 }] },\r\n ];\r\n }\r\n return next;\r\n}\r\nexports.mergeHooks = mergeHooks;\r\n/** 우리 훅만 걷어낸 새 객체. 비어 버린 이벤트 키는 지워서 설정을 깨끗하게 남긴다 */\r\nfunction stripHooks(settings) {\r\n const next = { ...(settings !== null && settings !== void 0 ? settings : {}) };\r\n if (!next.hooks) {\r\n return next;\r\n }\r\n next.hooks = { ...next.hooks };\r\n for (const p of PLAN) {\r\n const kept = withoutOurs(next.hooks[p.event]);\r\n if (kept.length) {\r\n next.hooks[p.event] = kept;\r\n }\r\n else {\r\n delete next.hooks[p.event];\r\n }\r\n }\r\n return next;\r\n}\r\nexports.stripHooks = stripHooks;\r\nfunction hooksInstalled() {\r\n return isMerged(readSettings());\r\n}\r\nexports.hooksInstalled = hooksInstalled;\r\n/** 훅을 등록한다 */\r\nfunction installHooks() {\r\n const script = notifyScriptPath();\r\n if (!fs.existsSync(script)) {\r\n throw new Error(`훅 스크립트를 찾지 못했다: ${script}`);\r\n }\r\n writeSettings(mergeHooks(readSettings(), script));\r\n}\r\nexports.installHooks = installHooks;\r\n/** 훅을 뗀다 */\r\nfunction uninstallHooks() {\r\n writeSettings(stripHooks(readSettings()));\r\n}\r\nexports.uninstallHooks = uninstallHooks;\r\nfunction writeSettings(settings) {\r\n const file = claudeSettingsPath();\r\n fs.mkdirSync(path.dirname(file), { recursive: true });\r\n // 남의 설정을 고치는 일이라 되돌릴 수 있게 한 벌 남긴다\r\n if (fs.existsSync(file)) {\r\n fs.copyFileSync(file, file + '.agentdeck-backup');\r\n }\r\n fs.writeFileSync(file, JSON.stringify(settings, null, 2) + '\\n', 'utf8');\r\n}\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.setCodexHooks = exports.codexHooksInstalled = exports.mergeCodexHooks = exports.stripCodexHooks = exports.codexHooksPath = exports.CODEX_EVENTS = void 0;\r\nconst fs = __importStar(require(\"fs\"));\r\nconst os = __importStar(require(\"os\"));\r\nconst path = __importStar(require(\"path\"));\r\nconst MARK = 'agentdeck-codex-notify.ps1';\r\n// https://learn.chatgpt.com/docs/hooks — no Claude-only Notification/StopFailure events.\r\nexports.CODEX_EVENTS = ['UserPromptSubmit', 'PreToolUse', 'PermissionRequest', 'PostToolUse', 'Stop', 'Interrupt', 'SessionEnd'];\r\nfunction codexHooksPath() {\r\n return path.join(process.env.CODEX_HOME || path.join(os.homedir(), '.codex'), 'hooks.json');\r\n}\r\nexports.codexHooksPath = codexHooksPath;\r\nfunction ours(handler) {\r\n return typeof (handler === null || handler === void 0 ? void 0 : handler.command) === 'string' && handler.command.includes(MARK);\r\n}\r\nfunction stripCodexHooks(settings) {\r\n var _a;\r\n const hooks = { ...((_a = settings === null || settings === void 0 ? void 0 : settings.hooks) !== null && _a !== void 0 ? _a : {}) };\r\n for (const event of Object.keys(hooks)) {\r\n if (!Array.isArray(hooks[event])) {\r\n throw new Error(`Invalid hooks.${event}: expected an array`);\r\n }\r\n hooks[event] = hooks[event].map((group) => {\r\n if (!Array.isArray(group === null || group === void 0 ? void 0 : group.hooks)) {\r\n throw new Error(`Invalid hooks.${event} group`);\r\n }\r\n return { ...group, hooks: group.hooks.filter((handler) => !ours(handler)) };\r\n }).filter((group) => group.hooks.length);\r\n if (!hooks[event].length) {\r\n delete hooks[event];\r\n }\r\n }\r\n return { ...settings, hooks };\r\n}\r\nexports.stripCodexHooks = stripCodexHooks;\r\nfunction mergeCodexHooks(settings, script) {\r\n var _a;\r\n const next = stripCodexHooks(settings);\r\n const command = `powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File \"${script}\"`;\r\n for (const event of exports.CODEX_EVENTS) {\r\n next.hooks[event] = [...((_a = next.hooks[event]) !== null && _a !== void 0 ? _a : []), {\r\n hooks: [{ type: 'command', command, timeout: 3 }],\r\n }];\r\n }\r\n return next;\r\n}\r\nexports.mergeCodexHooks = mergeCodexHooks;\r\nfunction codexHooksInstalled() {\r\n const settings = readCodexHooks();\r\n return exports.CODEX_EVENTS.every(event => { var _a, _b; return (_b = (_a = settings.hooks) === null || _a === void 0 ? void 0 : _a[event]) === null || _b === void 0 ? void 0 : _b.some((group) => { var _a; return (_a = group.hooks) === null || _a === void 0 ? void 0 : _a.some(ours); }); });\r\n}\r\nexports.codexHooksInstalled = codexHooksInstalled;\r\nfunction readCodexHooks() {\r\n const file = codexHooksPath();\r\n if (!fs.existsSync(file)) {\r\n return {};\r\n }\r\n const value = JSON.parse(fs.readFileSync(file, 'utf8').replace(/^\\uFEFF/, ''));\r\n if (!value || typeof value !== 'object' || Array.isArray(value)\r\n || (value.hooks != null && (typeof value.hooks !== 'object' || Array.isArray(value.hooks)))) {\r\n throw new Error('Invalid Codex hooks.json; existing configuration was not changed');\r\n }\r\n return value;\r\n}\r\nfunction setCodexHooks(enabled) {\r\n const file = codexHooksPath();\r\n const script = path.join(__dirname, '..', 'hooks', MARK);\r\n if (enabled && !fs.existsSync(script)) {\r\n throw new Error(`Missing hook: ${script}`);\r\n }\r\n const current = readCodexHooks();\r\n const next = enabled ? mergeCodexHooks(current, script) : stripCodexHooks(current);\r\n fs.mkdirSync(path.dirname(file), { recursive: true });\r\n if (fs.existsSync(file)) {\r\n fs.copyFileSync(file, `${file}.agentdeck-backup-${Date.now()}`);\r\n }\r\n fs.writeFileSync(file, JSON.stringify(next, null, 2) + '\\n', 'utf8');\r\n}\r\nexports.setCodexHooks = setCodexHooks;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.installCodexWheel = exports.isCodexTranscript = void 0;\r\n/** Windows Codex redraws one viewport instead of accumulating native history.\r\n * Use its transcript pager only when there is no native scrollback to browse.\r\n * Never send navigation keys until the pager is visibly confirmed.\r\n */\r\nfunction isCodexTranscript(lines) {\r\n var _a;\r\n return /^\\s*\\/ T R A N S C R I P T\\b/.test((_a = lines[0]) !== null && _a !== void 0 ? _a : '')\r\n && lines.slice(-4).some(line => /q close/.test(line));\r\n}\r\nexports.isCodexTranscript = isCodexTranscript;\r\nfunction installCodexWheel(frontend, enabled, send) {\r\n const x = frontend === null || frontend === void 0 ? void 0 : frontend.xterm;\r\n const element = x === null || x === void 0 ? void 0 : x.element;\r\n if (!element || frontend.__adCodexWheel) {\r\n return;\r\n }\r\n frontend.__adCodexWheel = true;\r\n let opening = false;\r\n let queued = 0;\r\n const lines = () => {\r\n const b = x.buffer.active;\r\n return Array.from({ length: x.rows }, (_, i) => { var _a, _b; return (_b = (_a = b.getLine(b.baseY + i)) === null || _a === void 0 ? void 0 : _a.translateToString(true)) !== null && _b !== void 0 ? _b : ''; });\r\n };\r\n const navigate = (amount) => {\r\n if (amount) {\r\n send((amount < 0 ? '\\x1b[A' : '\\x1b[B').repeat(Math.min(12, Math.abs(amount))));\r\n }\r\n };\r\n element.addEventListener('wheel', event => {\r\n if (!enabled() || event.ctrlKey || event.altKey || event.shiftKey || event.metaKey\r\n || !event.deltaY || Math.abs(event.deltaX) > Math.abs(event.deltaY)) {\r\n return;\r\n }\r\n const screen = lines();\r\n const transcript = isCodexTranscript(screen);\r\n const b = x.buffer.active;\r\n // A live composer footer is required, so approvals, menus, shells and\r\n // alternate-screen tools cannot receive an unsolicited Ctrl+T.\r\n const contentEnd = screen.reduce((end, line, i) => line.trim() ? i + 1 : end, 0);\r\n const composer = screen.slice(Math.max(0, contentEnd - 4), contentEnd)\r\n .some(line => /Context \\d+% left/.test(line));\r\n if (!transcript && !opening && (b.type !== 'normal' || b.baseY > 0 || !composer || event.deltaY > 0)) {\r\n return;\r\n }\r\n event.preventDefault();\r\n event.stopImmediatePropagation();\r\n const amount = Math.sign(event.deltaY) * Math.max(1, Math.min(12, Math.ceil(Math.abs(event.deltaY) / (event.deltaMode === 1 ? 1 : 40))));\r\n if (transcript) {\r\n navigate(amount);\r\n return;\r\n }\r\n queued = Math.max(-12, Math.min(12, queued + amount));\r\n if (opening) {\r\n return;\r\n }\r\n opening = true;\r\n send('\\x14');\r\n let attempts = 0;\r\n const check = () => {\r\n if (!enabled() || ++attempts > 20) {\r\n opening = false;\r\n queued = 0;\r\n return;\r\n }\r\n if (isCodexTranscript(lines())) {\r\n opening = false;\r\n navigate(queued);\r\n queued = 0;\r\n }\r\n else {\r\n setTimeout(check, 50);\r\n }\r\n };\r\n setTimeout(check, 50);\r\n }, { capture: true, passive: false });\r\n}\r\nexports.installCodexWheel = installCodexWheel;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckConfigProvider = exports.LAYOUT_DEFAULTS = void 0;\r\nconst tabby_core_1 = require(\"tabby-core\");\r\n/**\r\n * 마우스로 만진 배치만 따로 모아 둔다 — 설정 탭의 \"배치 초기화\" 가 이 값으로 되돌린다.\r\n * 기본값 정의와 초기화 대상이 어긋나지 않도록 아래 defaults 도 이걸 펼쳐 쓴다.\r\n */\r\nexports.LAYOUT_DEFAULTS = {\r\n /**\r\n * 사이드바가 붙는 방향. 헤더를 잡고 창 가장자리로 끌어다 놓으면 바뀐다.\r\n * 'left' | 'right' | 'top' | 'bottom'\r\n */\r\n sidebarDock: 'right',\r\n /**\r\n * 좌/우 도킹일 때의 사이드바 폭 (px). 0 이면 자동 —\r\n * 화면비(aspectW:aspectH)로 터미널 폭을 역산하고 남는 만큼을 사이드바가 갖는다.\r\n * 경계선을 드래그하는 순간 그 폭이 여기 박히고, 그 뒤로는 자동 계산을 쓰지 않는다.\r\n */\r\n sidebarWidth: 0,\r\n /** 상/하 도킹일 때의 사이드바 높이 (px). 경계선 드래그로 바뀐다 */\r\n sidebarHeight: 200,\r\n /**\r\n * 미리보기 패널이 붙는 방향 — 'right' | 'left'.\r\n * 사이드바와 같은 쪽이면 사이드바가 창 가장자리(바깥), 패널이 터미널 쪽(안)에 앉는다.\r\n */\r\n viewerDock: 'right',\r\n /** 미리보기 패널 폭 (px). 경계선 드래그로 바뀐다 */\r\n viewerWidth: 420,\r\n};\r\n/** @hidden */\r\nclass AgentDeckConfigProvider extends tabby_core_1.ConfigProvider {\r\n constructor() {\r\n super(...arguments);\r\n this.defaults = {\r\n agentDeck: {\r\n /** 레이아웃/사이드바 전체 on-off */\r\n enabled: true,\r\n /** 터미널 뷰포트 가로:세로 비율 */\r\n aspectW: 4,\r\n aspectH: 3,\r\n /**\r\n * 사이드바 폭 제한 (px).\r\n * sidebarMax 를 키우면 사이드바가 그만큼 넓어지고, 그래도 남는 폭은 터미널이 흡수한다\r\n * (4:3 보다 \"창을 꽉 채운다\" 가 우선). config.yaml 의 agentDeck 아래에서 조절한다.\r\n */\r\n sidebarMin: 200,\r\n sidebarMax: 560,\r\n // 마우스로 만지는 배치 (도킹 방향 / 폭 / 높이) — 정의는 LAYOUT_DEFAULTS 에 있다\r\n ...exports.LAYOUT_DEFAULTS,\r\n /**\r\n * 결과물 미리보기 패널(viewPanel.ts)이 지금 열려 있나.\r\n *\r\n * 사이드바 `▤` 버튼이나 `agentdeck-view` 핫키로 토글하면 이 값이 바뀌고,\r\n * 다음 기동 때 그대로 복원한다 — 문서를 띄워 놓고 쓰는 사람에게는 그게 기본 화면이다.\r\n */\r\n viewerOpen: false,\r\n /**\r\n * 화면에 찍힌 파일 경로를 주워 최근 목록에 쌓는다.\r\n *\r\n * 에이전트를 가리지 않는 유일한 경로다 — Claude Code 처럼 훅이 있는 CLI 만 되는 게\r\n * 아니라 Codex·Gemini 도 만진 파일을 화면에 찍기 때문이다(viewer.ts 주석).\r\n * 비용은 탭당 400ms 마다 정규식 한 번이고, 끄면 수동으로 열 때만 쓰게 된다.\r\n */\r\n viewerScrape: true,\r\n /**\r\n * 에이전트가 만진 파일을 **패널에 미리 얹어 둔다** (닫혀 있어도).\r\n *\r\n * 기본 켬. 패널이 닫혀 있는 동안에도 최근 목록과 \"다음에 열면 보여줄 파일\" 을\r\n * 계속 갈아 두므로, 작업이 한창일 때 `▤` 를 누르면 **그때까지 만진 파일들이\r\n * 칩으로 쌓여 있고 본문은 가장 최근 파일**이다 (`변경` 모드였으면 그 자리에서\r\n * diff 를 다시 읽는다). 끄면 아무것도 자동으로 하지 않는다 — 경로 수집만 남고\r\n * 무엇을 볼지는 사람이 칩·`+`·드롭으로 고른다.\r\n *\r\n * 이 값이 `false` 면 `viewerAutoOpen` 은 의미가 없다 (읽어두지 않으니 열 것도 없다).\r\n */\r\n viewerPreload: true,\r\n /**\r\n * 새 파일을 주우면 **닫힌 패널을 스스로 연다.**\r\n *\r\n * **기본 끔** (2026-09-10 유저 결정). 여닫기는 사람 몫이라는 뜻이다 — 작업 중에\r\n * 패널이 저절로 열리면 터미널이 좁아지고 읽던 화면이 밀린다. 대신 위 `viewerPreload`\r\n * 가 내용을 계속 채워 두므로, 열고 싶을 때 열면 이미 최신이다.\r\n * 켜면 결과물이 나오는 순간 패널이 열리면서 그 파일을 띄운다.\r\n */\r\n viewerAutoOpen: false,\r\n /**\r\n * @deprecated 0.18.0 부터 `viewerPreload` + `viewerAutoOpen` 두 토글로 갈랐다.\r\n *\r\n * 목록(`open`/`show`/`manual`) 하나로는 \"읽어두기\" 와 \"자동으로 열기\" 가 한 축에\r\n * 얹혀 있어서, 사람이 고를 때 두 결정을 한꺼번에 해야 했다. 남겨 두는 이유는\r\n * 이미 값을 적어 둔 설정 파일 때문이고, 기동 때 한 번 두 토글로 옮긴 뒤 비운다\r\n * (`migrateFollow`, deck.service 의 `migrateFollowConfig`).\r\n */\r\n viewerFollowMode: '',\r\n /**\r\n * @deprecated 0.17.0 부터 `viewerFollowMode` 로, 0.18.0 부터 위 두 토글로 옮겼다.\r\n *\r\n * boolean 하나가 \"자동으로 열기\" 와 \"새 파일로 바꾸기\" 를 같이 쥐고 있어서,\r\n * **\"패널은 내가 열고 닫되 열어 둔 동안에는 따라와라\"** 를 표현할 수 없었다.\r\n * 마이그레이션이 `false` 를 읽고 나면 기본값(`true`)으로 되돌려 다시 읽지 않는다.\r\n */\r\n viewerFollow: true,\r\n /**\r\n * 패널 **밖**(터미널 위)에 파일을 끌어다 놓았을 때 무엇을 할지.\r\n *\r\n * 순정 Tabby 는 그 경로를 터미널에 붙여넣는다(그래서 `cat <경로>` 가 쉽다). 그 동작은\r\n * 그대로 두고, **미리보기로 열지를 물어본다** — 자동으로 화면을 바꾸면 붙여넣기만\r\n * 원했던 사람의 화면을 빼앗는다 (2026-09-09 유저: \"한번 물어보긴 해야 할 듯\").\r\n *\r\n * - `ask` : 확인 배너를 띄워 `패널에 띄우기` / `경로 붙여넣기` 를 고르게 한다 (기본)\r\n * - `always` : 묻지 않고 패널에 띄운다\r\n * - `paste` : 묻지 않고 경로만 터미널에 붙여넣는다\r\n * - `never` : 우리가 개입하지 않는다 — 순정 Tabby 동작 그대로\r\n *\r\n * 배너의 `다시 묻지 않기` 를 체크하고 버튼을 누르면 그 선택이 `always`/`paste` 로\r\n * 저장된다. 되돌리려면 설정 창에서 `물어본다` 로 바꾼다.\r\n */\r\n viewerDropOpen: 'ask',\r\n /** 최근 목록(패널 위쪽 칩)에 남겨 두는 파일 수 */\r\n viewerRecentMax: 12,\r\n /**\r\n * 훅이 상태를 밀어 넣는 TCP 채널의 포트 (127.0.0.1 전용).\r\n *\r\n * Windows 임시 포트 범위(49152~65535) 아래로 잡는다 — 그 위 번호는 OS 가\r\n * 다른 프로세스에 먼저 내줄 수 있어 기동 순서에 따라 충돌한다.\r\n * 이 번호가 물려 있으면 0(임의 포트)으로 물러나고, 실제 번호는 어느 쪽이든\r\n * `%LOCALAPPDATA%\\tabby-agentdeck\\port` 에 적히므로 훅은 그 파일만 보면 된다.\r\n */\r\n notifyPort: 47500,\r\n /**\r\n * 외부 통보 채널(TCP + 상태 파일 폴링)을 열지.\r\n *\r\n * 기본으로 켠다. 에이전트 훅이 보내 주는 상태가 가장 정확한 원천이기 때문이다 —\r\n * 출력 패턴으로 추측하는 경로(detect.ts)는 훅이 없는 환경을 위한 폴백일 뿐이고,\r\n * TUI 가 화면을 어떻게 그리는지에 기대는 만큼 판정이 흔들린다\r\n * (2026-09-01: Claude Code 가 놀 때도 상태줄을 매초 갱신해 진행중이 안 풀렸다).\r\n * 훅을 안 쓰더라도 비용은 유휴 포트 하나와 400ms 폴링뿐이다.\r\n */\r\n notifyChannel: true,\r\n /**\r\n * 훅 설치 안내를 다시 띄우지 않는다.\r\n *\r\n * 기동할 때 훅이 안 걸려 있으면 한 번 물어보는데, \"다시 묻지 않기\" 를 고르면 켜진다.\r\n * 설정 창의 설치 버튼은 이 값과 무관하게 언제든 쓸 수 있다.\r\n */\r\n hookPromptDismissed: false,\r\n /**\r\n * 기동 시 지난 탭을 복원하지 않는다 (Tabby `recoverTabs` 를 false 로 강제).\r\n *\r\n * 복원되는 건 셸뿐이고 그 안의 Claude Code 세션은 이미 죽어 있어 의미가 없다.\r\n * 켜면 항상 빈 상태(기본 프로필 새 탭)로 시작하고, 끄면 Tabby 순정 동작으로 돌아간다.\r\n * 설정 창에서 토글한다 (recovery.service.ts).\r\n */\r\n noTabRecovery: false,\r\n /**\r\n * 기동할 때 npm 레지스트리를 보고 **새 버전을 받아 둔다** (적용은 다음 기동).\r\n *\r\n * Tabby 는 플러그인을 기동할 때 한 번 읽으므로 돌고 있는 것을 갈아끼울 수 없다 —\r\n * 그래서 받아만 두고 한 번 알린다. 기동 20초 뒤에 한 번, 그 뒤로는 아래 간격마다.\r\n *\r\n * **개발 설치(소스 트리 junction)에는 설치하지 않는다.** 거기에 `npm install` 이 돌면\r\n * 작업 중인 소스를 덮어쓴다 — 새 버전이 있다는 것만 알리고 손대지 않는다\r\n * (판정은 `update.ts` 의 `canSelfUpdate`).\r\n */\r\n autoUpdate: true,\r\n /** 확인 간격 (시간). 기동마다 묻지 않는다 */\r\n updateCheckIntervalHours: 6,\r\n /** 마지막으로 레지스트리에 물어본 시각 (epoch ms) — 설정이 아니라 상태다 */\r\n lastUpdateCheck: 0,\r\n /** 레지스트리 주소. 사내 미러를 쓰면 여기를 바꾼다 */\r\n updateRegistry: 'https://registry.npmjs.org',\r\n /** PTY 출력이 이 시간(ms) 이상 없으면 running -> idle */\r\n idleAfterMs: 2500,\r\n /** 출력 패턴으로 상태를 자동 추론할지 */\r\n autoDetect: true,\r\n /** 사이드바에 경과 시간 표시 */\r\n showElapsed: true,\r\n /**\r\n * 세션이 지금 돌리고 있는 **백그라운드 서브에이전트 개수**를 줄에 보인다\r\n * (`❖ 3`, 툴팁에 무엇을 시켜 놨는지 + 가장 오래된 것의 경과 시간).\r\n *\r\n * 기본으로 켠다 — 얻는 것이 \"저 탭이 사람 없이도 일이 도는 중인지\" 이고 그것을 볼\r\n * 다른 수단이 없다(훅은 세션 **하나**의 상태만 알려 준다, `subagents.ts` 주석).\r\n * 0 개면 아무것도 그리지 않으므로(deck.service `renderTab`) 서브에이전트를 안 쓰는\r\n * 사람의 화면은 0.12.0 까지와 똑같다 — 켜 둬서 잃는 것이 없다.\r\n *\r\n * 비용은 세션당 **2초에 `stat` 한 번**이고, 파일이 자란 만큼만 비동기로 읽는다\r\n * (실측 대화기록 13MB — 동기로 읽으면 UI 가 멈춘다).\r\n * 끄면 읽기도 표시도 멈춘다: 끈 기능이 대화기록 파일을 계속 여는 일은 없다\r\n * (`notify.service` `scanSubagents`).\r\n */\r\n subagentCount: true,\r\n /**\r\n * 사이드바 탭을 상태 우선순위(waiting → error → running → done → idle)로 정렬한다.\r\n * 같은 상태끼리는 탭 순서를 지킨다. 기본은 끔 — 순정 탭바와 같은 탭 순서로 보인다.\r\n * 헤더의 상태별 집계는 이 값과 무관하게 항상 보인다.\r\n */\r\n sortByStatus: false,\r\n /**\r\n * 사이드바 헤더 아래에 **세션 검색 줄**을 둔다 (제목 · 작업이름 · 작업 폴더로 좁히기,\r\n * 헤더의 상태 칩을 눌러 그 상태만 보기).\r\n *\r\n * 기본으로 켠다 — 탭이 몇 개뿐일 때도 잃는 것은 26px 한 줄이고, 탭이 많아지는 순간\r\n * 목록을 눈으로 훑는 비용이 그보다 훨씬 크다. 세로가 짧은 상/하 도킹에서 그 한 줄이\r\n * 아까운 사람만 끄면 된다.\r\n *\r\n * **여기 저장하는 것은 기능 on/off 뿐이다.** 검색어와 상태 필터는 설정에 남기지 않는다\r\n * (deck.service `searchQuery` 주석) — 다음 기동에 필터가 살아 있으면 목록이 좁혀진\r\n * 채로 떠서 \"탭이 사라졌다\" 로 읽힌다. 그 오해는 이 기능이 주는 이득보다 비싸고,\r\n * 되살릴 값어치도 없다(검색은 \"지금 이것을 찾는다\" 는 한순간의 행위다).\r\n * 이 값을 끄면 걸려 있던 필터도 같이 지운다 — 감춰진 필터가 남는 것이 가장 위험하다.\r\n */\r\n searchBox: true,\r\n /**\r\n * 사이드바를 **키보드로** 다룬다 — 핫키(`agentdeck-focus-list`, 기본 `Ctrl-Shift-L`)로\r\n * 목록에 들어가 ↑↓ 로 훑고, Enter 로 그 탭으로 전환, Esc 로 터미널에 돌아온다.\r\n * 검색창에서 ↓ 를 누르면 결과 목록으로 내려가고, 첫 줄에서 ↑ 면 검색창으로 돌아온다.\r\n * 그룹 헤더도 지나가며 Enter 로 접었다 펼 수 있다.\r\n *\r\n * **이동만으로는 탭이 바뀌지 않는다** (포커스 ≠ 선택). 여섯 개쯤 띄워 두고 훑을 때\r\n * 줄마다 활성 탭이 바뀌면 터미널 화면이 계속 튀어 훑기 자체가 불가능하다\r\n * (`deck.service.ts` `navFocus` 주석).\r\n *\r\n * 기본으로 켠다 — **포커스가 사이드바에 없는 동안은 키를 한 개도 가로채지 않는다.**\r\n * 리스너가 document 가 아니라 목록 엘리먼트(`.ad-list`)에 걸려 있어서, 핫키를 누르거나\r\n * 검색창에 들어가지 않으면 이벤트가 아예 오지 않는다(`wireListKeys` 주석).\r\n * 끄면 핫키·검색창 ↓ 가 모두 no-op 이 되고 링도 그리지 않는다.\r\n */\r\n keyboardNav: true,\r\n /**\r\n * 목록 끝에서 ↑↓ 를 한 번 더 누르면 반대쪽 끝으로 감싼다.\r\n *\r\n * 기본은 끔 — 감싸면 \"맨 아래에 왔다\" 는 신호가 사라지고, 목록이 한 번에 위로 튀어\r\n * 화면이 다시 그려진 것처럼 보인다. 끝에서 끝으로 갈 일은 Home/End 가 받는다.\r\n *\r\n * 켜도 **맨 위의 ↑ 는 검색창으로 나간다**(검색 줄이 보일 때). 그 경계를 감싸기에\r\n * 내주면 목록에서 검색창으로 돌아갈 키가 없어진다 — 검색↔목록 왕복이 이 기능의\r\n * 요구사항이라 감싸기보다 앞에 둔다 (`deck.service.ts` `moveNav`).\r\n */\r\n keyboardNavWrap: false,\r\n /**\r\n * `Ctrl+W` 로 지금 탭을 닫는다 (터미널에서 누르면 활성 탭, 목록이 키보드를 갖고\r\n * 있으면 포커스 줄의 탭 — `nav.ts` `pickCloseTarget`).\r\n *\r\n * **`keyboardNav` 에 매달아 둔다** — 키보드로 목록을 훑다가 버릴 탭을 만나는 것이\r\n * 이 키의 쓰임새이고, 키보드 조작을 끈 사람에게 터미널 키를 빼앗을 이유가 없다.\r\n * 그래서 `keyboardNav` 가 꺼져 있으면 이 값이 `true` 여도 아무 일도 하지 않는다\r\n * (설정 창에서도 줄이 사라진다 — `keyboardNavWrap` 과 같은 방식).\r\n *\r\n * 끄고 싶을 만한 이유가 분명히 있다: 셸·에이전트 CLI 에서 `Ctrl+W` 는 **앞 단어\r\n * 지우기**(0x17)다. 그걸 그대로 쓰려면 이 값만 끄면 되고, 목록 키보드 조작은 남는다.\r\n * 켠 상태에서도 우리가 키를 먹는 것은 **닫을 탭이 실제로 정해졌을 때뿐**이다 —\r\n * 그룹 헤더에 포커스가 있거나 설정 화면 입력창이면 키를 그대로 흘린다.\r\n * 닫기는 사이드바 `✕` 와 같은 경로라(`closeTab(tab, true)`) 돌아가는 프로세스가\r\n * 있으면 Tabby 가 평소처럼 한 번 물어본다.\r\n */\r\n keyboardCloseTab: true,\r\n /**\r\n * 줄을 끌어 순서를 바꾸는 동안 커서를 **목록 끝에 대면 목록이 따라 스크롤된다.**\r\n *\r\n * 기본으로 켠다 — 없으면 탭이 많아 목록이 넘치는 순간 \"화면 밖으로 옮기기\" 가\r\n * 아예 불가능해진다(손을 떼고 스크롤한 뒤 다시 끄는 왕복이 필요하다). 그게\r\n * 0.12.0 의 드래그 재정렬에 남아 있던 구멍이다.\r\n *\r\n * 끄면 0.12.0 과 똑같이 동작한다 — 목록은 가만히 있고, 보이는 줄 사이에서만\r\n * 옮긴다. 자동 스크롤을 꺼서 얻는 것이 있다: 가장자리 띠 안에서 화면이 흐르지\r\n * 않으므로 **맨 끝 줄의 뒤에 놓는** 조작이 절대 미끄러지지 않는다. 띠를 줄 하나\r\n * 두께로 좁혀 두긴 했지만(deck.service `DRAG_SCROLL_BAND_PX`) 그 조작을 자주\r\n * 하는 사람에게는 이 스위치가 답이다.\r\n *\r\n * 속도·띠 두께는 설정으로 내지 않았다 — px/s 는 사람이 판단할 수 있는 숫자가\r\n * 아니고, 띠 두께는 줄 높이에서 나온 값인데 줄 높이가 설정이 아니다.\r\n * 이 값은 **드래그 중에만** 읽는다: 끌지 않을 때는 커서가 목록 끝에 얹혀 있어도\r\n * 아무 일도 일어나지 않는다(hover 리스너를 두지 않았다).\r\n */\r\n dragAutoScroll: true,\r\n // 세션 그룹에는 설정이 없다 — **항상 켜져 있고 경계도 자동으로 잡는다.**\r\n //\r\n // 스위치(`groupByProject`)를 없앤 근거: 그룹이 하나뿐이면 헤더를 아예 그리지 않고\r\n // 순서도 건드리지 않으므로(deck.service `renderPlan`), 한 프로젝트만 쓰는 사람에게는\r\n // 켜 둔 화면과 끈 화면이 **같다.** 끌 이유가 없는 스위치는 설정 창에서 고를 것만 늘린다.\r\n // 경계를 적는 값(`groupRoot`)도 없앴다 — `project-root.ts` 가 저장소 루트(`.git` 등)를\r\n // 직접 찾는다. 사람이 상위 폴더를 적는 방식은 프로젝트들이 한 폴더에 나란히 있을 때만\r\n // 맞고, 깊이가 다르면 어떤 값을 적어도 한쪽이 틀렸다.\r\n // 묶는 기준은 **탭이 태어난 cwd** 다 — 셸에서 `cd` 를 해도 따라오지 않으므로\r\n // (docs/DEVELOPMENT.md 0.5.0 실측) 세션이 사는 동안 그룹이 흔들리지 않는다.\r\n /**\r\n * 접어 둔 그룹 키 목록. 그룹 헤더를 클릭할 때마다 갱신되고 다음 기동에 복원된다.\r\n *\r\n * 키는 `group.ts` 가 정규화한 경로를 **소문자로 접은** 값이다(`foldGroupKey`) —\r\n * 셸이 알려주는 경로의 대소문자·구분자가 기동마다 달라도 접힘이 유지돼야 하기 때문이다.\r\n */\r\n collapsedGroups: [],\r\n /**\r\n * 그룹 안에 **지난 세션**(죽은 Claude Code 세션) 줄을 그린다.\r\n *\r\n * 이 기능이 있는 이유는 `recovery.service.ts` 주석에 있다 — agentdeck 은 Tabby 의 순정\r\n * 탭 복원을 껐다(셸만 살아나고 세션은 죽어 있어 \"주인 없는 탭\" 이 남는다).\r\n * `claude --resume` 이 그 자리에 들어갈 진짜 복원이고, 사람이 막히는 곳은 명령이 아니라\r\n * UUID 목록에서 자기 작업을 찾는 것이라 **라벨을 붙여 보여주는 것** 이 이 기능의 전부다.\r\n */\r\n resumeList: true,\r\n /** 그룹당 몇 줄까지 보여줄지. 0 이면 제한 없음 (목록이 길어지면 살아 있는 탭이 밀린다) */\r\n resumeListLimit: 5,\r\n /**\r\n * 며칠치까지. 기간 밖 세션은 **화면에서만** 빠지고 원장·기록은 그대로다.\r\n * stat 단계에서 잘라내므로 이 값이 작을수록 펼치는 순간이 싸다.\r\n */\r\n resumeListDays: 7,\r\n /** 지난 세션 줄을 펼쳐 둔 그룹 키 (`collapsedGroups` 와 반대로 **펼침**을 적는다 — 기본이 접힘이라서) */\r\n resumeExpanded: [],\r\n /** 사람이 목록에서 숨긴 세션 id */\r\n resumeHidden: [],\r\n /**\r\n * 창이 가려져 있어도 사이드바를 계속 갱신한다 (Electron backgroundThrottling 해제).\r\n *\r\n * 끄면 Chromium 기본 동작으로 돌아간다 — 창이 hidden 이면 rAF 가 멈추고 타이머가\r\n * 1초, 5분 이상 가려지면 분당 1회까지 느려져서 훅이 보낸 done 이 화면에 늦게 뜬다.\r\n * 켜 두면 훅 보고가 바로 보이는 대신 가려진 동안에도 렌더 비용이 조금 든다\r\n * (사이드바 DOM 갱신뿐이라 미미하다).\r\n */\r\n keepRenderingWhenHidden: true,\r\n // labelAsTitle 은 없앴다 — 사이드바가 제목/프롬프트/상태를 각자 줄에 보여주게 되면서\r\n // (deck.service renderTab) 둘 중 하나를 고를 이유가 사라졌다.\r\n /**\r\n * Enter 로 프롬프트를 보낼 때 그 원문을 작업 라벨로 삼는다 (claimEnterLabel 주석 참고).\r\n * 훅도 콘솔 제목도 못 믿는 배포 환경에서 라벨을 최신으로 유지하는 유일한 경로다.\r\n * Shift+Enter / Ctrl+Enter(줄바꿈)는 잡지 않는다.\r\n */\r\n enterAsLabel: true,\r\n /**\r\n * Ctrl+V 를 agentdeck 이 직접 받는다 (document 캡처 단계에서 한 번만).\r\n *\r\n * 핫키(`agentdeck-paste`)로 받던 시절에는 Tabby 가 같은 keydown 을 두 경로로\r\n * HotkeysService 에 밀어 넣어 한 번 눌러 두 번 붙는 일이 남아 있었다\r\n * (deck.service.ts `ensurePasteHotkey` 주석에 원인). 캡처로 옮기고 전파를 끊으면서\r\n * 경로가 하나로 정리됐다.\r\n *\r\n * false 로 두면 터미널 앱에 리터럴 Ctrl+V(0x16, quoted-insert)를 보낼 수 있다\r\n */\r\n claimCtrlV: true,\r\n /**\r\n * Shift+Enter / Ctrl+Enter 를 캡처 단계에서 직접 줄바꿈으로 처리한다.\r\n *\r\n * 핫키(agentdeck-newline)에만 맡기면 한글 조합 중에 눌렀을 때 Shift 가 실리지\r\n * 않은 Enter 로 도착해 전송돼 버린다 (deck.service.ts `claimShiftEnterKey` 주석).\r\n * false 로 두면 예전처럼 핫키 경로만 쓴다.\r\n */\r\n claimShiftEnter: true,\r\n /**\r\n * Home / End 를 Tabby 핫키에서 걷어내 xterm 순정 경로로 돌려준다.\r\n *\r\n * 핫키로 두면 한글 조합 중에 눌렀을 때 조합 음절이 커서를 따라간다\r\n * (deck.service.ts `releaseHomeEndHotkey` 주석에 원인). 방향키가 멀쩡한 이유도 같다 —\r\n * 방향키는 핫키가 아니라서 xterm 이 조합을 먼저 확정하고 키를 보낸다.\r\n */\r\n releaseHomeEnd: true,\r\n /**\r\n * pty 에 바이트를 쓰기 전에 조합 중인 한글 음절을 먼저 확정시킨다.\r\n *\r\n * 핫키를 놓아주는 것(`releaseHomeEnd`)만으로는 부족했다 — 실사용 config.yaml 이\r\n * 이미 `home: []` / `end: []` 인데도 조합 중 음절이 커서를 따라가는 증상이 재발했다\r\n * (2026-09-08 사용자 재보고). 원인은 핫키가 아니라 **xterm 을 거치지 않는 pty 직접\r\n * 쓰기**여서, 이 옵션은 그 쓰기 지점 전부를 한 진입점으로 모아 순서를 맞춘다\r\n * (deck.service.ts `sendToPane` / `guardHomeEndComposition`, 기전은 `ime.ts`).\r\n *\r\n * false 로 두면 0.4.0 까지의 동작 그대로 — 조합 상태를 보지 않고 바로 쓴다.\r\n */\r\n imeOrderGuard: true,\r\n /**\r\n * 클립보드에 이미지만 있으면 Ctrl+V 로도 이미지가 들어가게 한다.\r\n *\r\n * 터미널 붙여넣기는 \"클립보드 텍스트를 PTY 에 써넣는\" 동작이라 이미지는 지나갈 수가 없다.\r\n * 대신 에이전트 CLI 는 자기가 OS 클립보드를 직접 읽는 키를 따로 두므로,\r\n * 이미지일 때만 그 키를 흘려보낸다 (어떤 키인지는 `imagePasteKey`).\r\n */\r\n pasteImageWithCtrlV: true,\r\n /**\r\n * 이미지 전용 클립보드일 때 흘려보낼 키의 **기본값**. `'alt-v'`(ESC v) | `'ctrl-v'`(0x16).\r\n *\r\n * 평소에는 이 값이 쓰이지 않는다 — 탭에서 도는 앱을 보고 자동으로 갈라 보내기 때문이다\r\n * (Claude Code = ESC v / Codex = 0x16, `deck.service.ts` `sendImagePasteKey` 주석에 실측).\r\n * 앱을 못 알아낼 때(SSH 세션 등)의 폴백으로만 쓴다.\r\n *\r\n * Claude Code 는 PTY 로 들어온 0x16 에 반응하지 않는 것이 실측됐으므로\r\n * (`.agentdeck-diag.log` 2026-08-28T09:33:47~48 에 `paste image (ctrl-v)` 5줄, 이미지 미삽입)\r\n * 폴백은 더 널리 먹히는 ESC v 로 둔다.\r\n */\r\n imagePasteKey: 'alt-v',\r\n /**\r\n * 우클릭(붙여넣기 / 선택 시 복사)을 agentdeck 이 직접 처리한다.\r\n * Tabby 자체 처리를 끄고(terminal.rightClick = 'off') 캡처 단계에서 한 번만\r\n * 처리하므로, 핸들러가 두 번 걸려 붙여넣기가 2중으로 들어가던 문제가 사라진다.\r\n * false 로 두면 Tabby 순정 동작으로 되돌아간다\r\n */\r\n claimRightClick: true,\r\n /** 우클릭을 이 시간(ms) 이상 누르고 있으면 붙여넣기 대신 컨텍스트 메뉴 */\r\n rightClickMenuMs: 250,\r\n /**\r\n * 터미널 배경 불투명도 (%). 100 이면 순정(완전 불투명).\r\n *\r\n * tabby-background 플러그인은 배경 이미지를 `.content-tab-active::before`\r\n * (position:fixed, z-index:-1) 로 **모든 내용 뒤에** 깐다. 그런데 xterm 은\r\n * 컬러스킴의 `background` 색으로 셀을 직접 칠하므로, 그 색에 알파가 없으면\r\n * 이미지는 터미널 영역에서 100% 가려진다 — \"배경 이미지를 넣었는데 아무 데도 안 보인다\"\r\n * 의 정체가 이것이다(2026-08-28 실측: colorScheme.background = '#171717' 불투명).\r\n * Tabby 는 xterm 을 `allowTransparency: true` 로 만들기 때문에 알파만 넣어주면 비친다.\r\n *\r\n * 그래서 agentdeck 이 기동 시 `terminal.colorScheme.background` 를 8자리 hex 로 바꿔준다.\r\n * 100 으로 되돌리면 알파를 떼어 원래 색으로 복구한다 (되돌리기 가능).\r\n */\r\n terminalOpacity: 75,\r\n /** 사이드바 배경 불투명도 (%). 터미널과 같은 이유로 배경 이미지가 비치게 한다 */\r\n sidebarOpacity: 75,\r\n /**\r\n * tabby-background 의 배경 이미지를 **터미널 영역(`.content.main`) 안에만** 그린다.\r\n *\r\n * 그 플러그인은 이미지를 `.content-tab-active::before` 에 `position:fixed; 100%x100%`\r\n * 로 깔아 창 전체를 덮으므로, 사이드바가 반투명이면 이미지가 사이드바 밑까지 비친다\r\n * (2026-09-02 유저 지적: \"배경이 agentdeck 사이드바를 침범한다\").\r\n * true 면 relayout 때마다 터미널 영역 좌표를 CSS 변수(`--ad-bg-*`)로 내려\r\n * 그 레이어의 위치·크기를 터미널 영역으로 잘라 붙인다. false 면 순정(창 전체).\r\n */\r\n clipBackgroundToTerminal: true,\r\n // 크기 보정 설정(`sizeWatchMs` / `sizeWatchIntervalMs` / `redrawKickMs` /\r\n // `startupWindowKickMs`)은 그 장치들과 함께 폐지했다 (2026-09-02).\r\n // 줄맞춤은 Tabby 순정이 한다 — xterm `ResizeObserver` → `fitAddon.fit()` →\r\n // `session.resize()`. agentdeck 은 폭만 정해 `.content.main` 에 적는다.\r\n // 자세한 경위는 `deck.service.ts` 의 relayout 주석 참고.\r\n /**\r\n * 화면 복구(사이드바 `↻` / `agentdeck-repair` 핫키)가 **스크롤백까지 지우고**\r\n * 터미널 상태를 초기화한다(`xterm.reset()`).\r\n *\r\n * true 인 이유: 깨진 화면에는 옛 폭으로 그려진 잔상이 셀에 남아 있는데, 앱이 다시\r\n * 그려도 자기가 쓰는 자리만 덮으므로 그 바깥은 지워지지 않는다. 지난 대화를 남기고\r\n * 싶으면 false — 그때는 크기 정합 + 흔들기까지만 한다(그것만으로는 안 고쳐지는\r\n * 경우가 있다, 2026-09-01 확인).\r\n */\r\n /**\r\n * 화면이 깨졌는지 **주기적으로 직접 보고**, 깨졌으면 조용히 복구한다.\r\n *\r\n * 이게 필요한 이유 — 크기 감시(`sizeWatchMs`)는 \"우리가 pty 에 보낸 값\" 과\r\n * \"xterm 이 가진 값\" 을 비교한다. 그런데 세션이 막 열린 직후의 `session.resize()` 는\r\n * **pty 에 도달하지 못하고 유실된다**(2026-09-01 실측: 진단 로그에\r\n * `pty resize 254x78 -> 280x78` 을 찍고 `pane.size` 도 280 으로 남겼는데,\r\n * 같은 탭에서 셸에 물어보니 `PTYW=254 xtermCols=280`). 보낸 값을 낙관적으로\r\n * 기록하기 때문에 감시는 \"이제 맞다\" 고 보고 손을 뗀다. 그 뒤에 뜨는 TUI 는\r\n * 254 폭으로 그리고, 오른쪽 26칸에는 옛 프레임(`Try \"how do I …\"` 힌트)이 남는다.\r\n *\r\n * 그래서 판정 기준을 **화면 자체**로 바꾼다. 입력창 테두리 길이가 화면 폭과 다르거나,\r\n * 가로선과 입력 텍스트가 한 줄에 섞였거나, 입력창 머리가 둘 보이면 깨진 것이다\r\n * (`screen.ts` 의 `judgeScreen` — 정상/깨짐 실측 케이스로 유닛 테스트가 걸려 있다).\r\n * 원인이 무엇이든 결과를 보고 고치므로, 원인 하나를 쫓다 다른 것이 깨지는 일이 없다.\r\n */\r\n /**\r\n * **다시 켬 (2026-09-02).** 껐던 근거가 오진이었다.\r\n *\r\n * 껐을 때의 이유는 \"Claude Code 는 테두리를 `cols - 1` 로 그리는데 판정이\r\n * `== cols` 를 정상으로 봐서 멀쩡한 화면을 깨짐으로 친다\" 였다. **그 전제가 틀렸다.**\r\n * 격리 인스턴스에서 실물 claude 를 띄워 xterm 버퍼를 직접 덤프해 보니\r\n * (2026-09-02, cols=271):\r\n *\r\n * 71 len=271 wrap=0 \"────…\" ← 테두리는 cols 를 꽉 채운다\r\n * 72 len=2 wrap=1 \"❯ \" ← 꽉 찼기 때문에 autowrap 으로 넘어온 행이다\r\n * 73 len=271 wrap=0 \"────…\"\r\n *\r\n * 즉 `len == cols` 가 정상이고, `len == cols - 1` 은 **앱이 폭을 1 작게 알고 있는**\r\n * 진짜 깨짐이다. 그때는 테두리가 폭을 못 채워 autowrap 이 안 걸리므로 `❯` 가\r\n * 윗줄에 붙어버리고 **입력행이 통째로 사라진다**(항목 25 의 ④ 증상이 이것이다).\r\n * 껐던 탓에 실사용에서 깨져도 아무도 고치지 않고 방치됐다.\r\n *\r\n * 예전 자동복구가 화면을 흔들어 놓은 진짜 이유는 판정이 아니라 **조건이 없어서**였다.\r\n * 프레임을 그리는 도중을 한 번 잡아도 바로 복구를 때렸다. 그래서 이번에는\r\n * `autoRepairMinStreak` 로 \"몇 초 넘게 깨진 채로 있을 때만\" 손대게 한다.\r\n */\r\n /**\r\n * **다시 끔 (2026-09-02, 실사용 실측 4/4 실패).** 위 판정 근거는 여전히 맞지만\r\n * **복구 수단이 이 유형에 안 듣는다.** 실사용 로그 06:02:27~06:03:12 —\r\n * `redraw nudge 277x78` → `pty resize 276x78 -> 277x78` → `Ctrl+L` 을 다 보내고도\r\n * 네 번 모두 `auto-after 아직 깨짐 rule@73 len=276 != cols=277`.\r\n * 그동안 10초마다 화면이 흔들려 유저 체감만 나빠졌다(\"최대화됐다 다시 깨지네\").\r\n *\r\n * 격리에서 한 번에 복구됐던 건 `session.resize(cols-1)` 로 **pty 를 직접 좁혀** 만든\r\n * 표본이라, 흔들기가 되돌릴 대상이 실제로 있었다. 실사용은 pty 가 이미 277 로 맞고\r\n * **앱만 276** 이라 되돌릴 것이 없다 — 항목 27 이 이 유형을 정확히 짚었던 것이고,\r\n * 항목 28 의 반전은 그 표본에는 해당하지 않았다.\r\n * 되살리려면 \"앱이 pty 폭을 다시 읽게 만드는\" 수단부터 찾을 것. 감지·채증(`screenWatch`)은 계속 돈다.\r\n */\r\n /**\r\n * **다시 켬 (2026-09-09).** 위 두 주석의 판단 근거가 오늘 채증으로 갈렸다.\r\n *\r\n * 껐던 이유는 \"복구 수단이 이 유형에 안 듣는다\" 였는데, 그 유형이 무엇이었는지가\r\n * 오늘 실사용 8건으로 확정됐다 — **`xterm.cols != pty` 인 리사이즈 중간 프레임**이다\r\n * (4건 전부, 0~3초 만에 스스로 복구, 화면 덤프는 앱 기준 정상). 거기에 `fit`+`nudge`\r\n * 를 때렸으니 고쳐질 리가 없고 화면만 흔들렸다.\r\n *\r\n * 크기가 맞는데 깨진 나머지 4건(02:07:45~02:08:01, 자식 프로세스 stdout 이 TUI 를\r\n * 덮어씀)은 26초를 버텼고, 이 유형은 `clearInputArea` + `Ctrl+L` 로 실제로 고쳐진다\r\n * (회귀 PR8·PR9 가 격리 인스턴스에서 100~160ms 해소를 잰다).\r\n *\r\n * 그래서 **손댈 유형만 손대도록** `checkScreen` 에 크기 가드를 넣고 기본값을 켠다.\r\n * 자동 경로가 하는 일은 사이드바 `↻` 한 번과 같다(잔상 지우기 + Ctrl+L, **흔들기 없음**).\r\n *\r\n * 켜기 직전에 \"켜면 격리 인스턴스가 죽는다\" 로 한 번 막혔는데, **그 죽음은 우리 코드가\r\n * 아니었다** (2026-09-09 확정). `tools/test-instance.ps1 -Kill` 이 커맨드라인에\r\n * `tabby-agentdeck-test` 가 든 Tabby 를 **전부** 죽이고 기동은 그 `ud` 폴더를 지운다 —\r\n * 같은 저장소에서 두 세션이 동시에 회귀를 돌리면 서로의 인스턴스를 죽인다. 그때 CDP 는\r\n * ECONNRESET 으로 끊기고 진단로그에 상대의 `setup start tabs=0` 이 이어 붙어 크래시처럼\r\n * 보인다. 판별법 — **Crashpad 리포트가 비어 있으면 크래시가 아니라 누가 죽인 것이다**\r\n * (`<ud>\\Crashpad\\reports`). 이름이 겹치지 않는 전용 인스턴스에서 다시 재니\r\n * 기본 `true` 로 `probe-profile` 3회 연속 8 PASS / 0 FAIL 이었다.\r\n *\r\n * 끄고 싶으면 `%APPDATA%\\tabby\\config.yaml` 의 `agentDeck.autoRepairScreen: false`\r\n * 한 줄이면 되고, 감지·채증(`screenWatch`)은 어느 쪽이든 돈다.\r\n */\r\n autoRepairScreen: true,\r\n /**\r\n * 화면을 **보고 기록만** 한다 (복구는 하지 않는다).\r\n *\r\n * `autoRepairScreen` 을 끄면서 감지·채증까지 같이 꺼진 게 문제였다 —\r\n * 실사용에서 깨져도 `~/.agentdeck-screen.log` 에 한 줄도 안 남아,\r\n * \"고쳤다고 했는데 또 깨진다\" 를 확인할 증거가 없었다\r\n * (2026-09-02 실측: Tabby 재시작 11:21 이후 기록 0줄, 그 사이 화면은 깨져 있었다).\r\n * 그래서 **관측과 조치를 분리한다.** 이 값이 켜져 있으면 깨짐을 판정해\r\n * 화면 원문을 남기기만 하고 키는 쏘지 않는다 — 부작용이 없으니 기본으로 켠다.\r\n */\r\n screenWatch: true,\r\n /** 자동 복구를 한 번 한 뒤 이만큼은 다시 하지 않는다 (ms) */\r\n autoRepairCooldownMs: 10000,\r\n /**\r\n * 깨짐이 이만큼 **연속으로** 보여야 복구한다 (화면 검사는 2초 그물이므로 2 면 2초 이상).\r\n * TUI 는 한 프레임을 여러 번의 write 로 그리므로 그 도중을 읽으면 멀쩡한 화면도\r\n * 한 번은 깨져 보인다 — 그 중간 프레임에 키를 쏘지 않기 위한 조건이다.\r\n */\r\n autoRepairMinStreak: 2,\r\n /**\r\n * 한 탭에서 자동 복구를 최대 몇 번까지 할지. 판정이 오탐이거나 앱이 정말\r\n * 그렇게 그리는 경우에 무한히 흔드는 것을 막는 안전장치다. 0 이면 무제한.\r\n */\r\n autoRepairMaxPerTab: 3,\r\n /**\r\n * 복구 때 `xterm.reset()` 까지 한다 — **스크롤백(지난 대화)이 날아간다.**\r\n * 기본은 끔. 잔상은 `clearInputArea`(화면만 비우고 스크롤백은 보존)로 지우므로\r\n * 여기까지 갈 일이 거의 없다. 그걸로도 안 풀리는 화면을 만나면 그때 켠다.\r\n */\r\n repairHard: false,\r\n /**\r\n * 복구 마지막에 `Ctrl+L`(0x0C)을 보낸다.\r\n *\r\n * **기본 끔 (2026-09-11 전환).** 0x0C 를 \"전부 다시 그려라\" 로 받는 앱을 전제했는데,\r\n * **Claude Code 는 \"화면을 지워라\" 로 받는다** — 채증으로 확정했다.\r\n * `↻` 를 누른 뒤 스냅샷(`.agentdeck-screen.log` 06:04:52→54)에서 78행 중 **0~72행이\r\n * 통째로 비고** 입력창(73~77행)만 남았고, 진단 로그의 순서가 원인을 못 박는다:\r\n * `clear input area row=73/78`(73~77행만 지움) → `repair redraw-key ctrl-l` → 화면 전멸.\r\n * 사용자에게는 \"새로고침하면 출력이 한참 위로 올라가 버린다\" 로 보인다(유저 지적).\r\n *\r\n * 끄고도 복구는 된다 — 실제로 고치는 것은 잔상 지우기(`clearInputArea`)와\r\n * 크기 정합·흔들기(SIGWINCH)이고, 0x0C 는 그 위에 얹은 \"확실히 해두기\" 였다.\r\n * 지운 자리의 입력창은 앱이 자기 렌더 주기에 다시 그린다(Claude Code 는 상태줄을\r\n * 매초 갱신하므로 즉시 돌아온다). 수동 복구는 흔들기까지 하므로 그 자리에서 돌아온다.\r\n *\r\n * 켜는 경우 — Ctrl+L 이 실제로 재렌더인 앱만 쓰거나, 셸에서 화면이 지워져도\r\n * 상관없을 때. 켜면 자동복구에도 적용되므로 오탐 한 번에 보고 있던 화면이 밀린다.\r\n */\r\n repairSendRedrawKey: false,\r\n /**\r\n * 작업 루트 전용 프로필을 만들고 기본 프로필로 삼는다.\r\n *\r\n * 에이전트 CLI 는 \"어느 폴더에서 떴는가\" 가 곧 작업 대상이라 새 탭마다 cd 하게 되는데,\r\n * 그걸 없애려는 기능이다. 기본은 꺼져 있다 — 남의 PC 에 설치되자마자 프로필을 만들고\r\n * 기본값을 가로채면 곤란하므로, 쓰려는 사람이 `rootProfileCwd` 를 채우고 켜야 한다.\r\n */\r\n rootProfile: false,\r\n rootProfileName: 'Agent Root',\r\n // 백슬래시 이스케이프 함정을 피하려고 슬래시로 적는다 (Windows 도 그대로 받는다)\r\n // 빈 값이면 프로필을 만들지 않는다\r\n rootProfileCwd: '',\r\n rootProfileCommand: 'powershell.exe',\r\n /**\r\n * -ExecutionPolicy Bypass 가 필요한 이유: npm 전역 명령(claude 등)은 .ps1 래퍼인데\r\n * 기본 실행 정책(Restricted)에서는 로드가 막힌다. 이 인자는 해당 세션에만 적용되고\r\n * 시스템/사용자 정책은 건드리지 않는다.\r\n */\r\n rootProfileArgs: ['-NoLogo', '-ExecutionPolicy', 'Bypass'],\r\n /**\r\n * 탭에 주입할 환경변수. Claude Code 등 TUI 는 이 값들이 없으면 색 지원을 낮게 잡아\r\n * 흑백에 가깝게 렌더된다 (Windows 는 TERM 이 기본으로 비어 있다).\r\n */\r\n rootProfileEnv: {\r\n TERM: 'xterm-256color',\r\n COLORTERM: 'truecolor',\r\n FORCE_COLOR: '3',\r\n },\r\n /** 기본 프로필 지정을 이미 했는지 — 사용자 선택을 매번 덮어쓰지 않기 위한 플래그 */\r\n rootProfileClaimed: false,\r\n /**\r\n * 창이 뒤에 있을 때(포커스 없음) 탭이 `승인대기`/`오류` 로 넘어가면 OS 쪽에 알린다.\r\n * 창이 앞에 있으면 세 항목 모두 아무 일도 하지 않는다 — 사이드바가 이미 보이고 있다.\r\n * 작업표시줄 아이콘을 깜빡인다(`flashFrame`). 창이 포커스를 받으면 멈춘다\r\n */\r\n alertFlash: true,\r\n /**\r\n * 작업표시줄 아이콘 위에 `승인대기`+`오류` 탭 개수를 뱃지로 얹는다.\r\n * Windows 는 `setBadgeCount` 가 없어 오버레이 아이콘(원+숫자)으로 그린다.\r\n * 이 값은 전이 순간이 아니라 상태가 바뀔 때마다 실제 개수로 갱신되고, 0 이면 지운다\r\n */\r\n alertBadge: true,\r\n /**\r\n * OS 토스트(`Notification`)까지 띄운다. 기본은 끔 — 탭이 여럿이면 시끄럽다.\r\n * 토스트를 누르면 창을 앞으로 가져오고 그 탭을 고른다\r\n */\r\n alertToast: false,\r\n },\r\n hotkeys: {\r\n 'agentdeck-toggle': [],\r\n /**\r\n * Claude Code 는 0x0A(Ctrl+J)를 줄바꿈으로 받는다. Tabby 로 옮겨 왔으니\r\n * Ctrl+Enter / Shift+Enter 로도 같은 바이트를 보낸다\r\n */\r\n 'agentdeck-newline': ['Ctrl-Enter', 'Shift-Enter'],\r\n /**\r\n * Tabby 순정 `paste` 대신 이걸 쓴다 — 클립보드가 이미지인지 텍스트인지 보고\r\n * 갈라야 하는데 순정 paste 는 텍스트만 알기 때문\r\n */\r\n 'agentdeck-paste': ['Ctrl-V'],\r\n /**\r\n * 사이드바 목록에 키보드 포커스 (다시 누르면 터미널로 복귀).\r\n *\r\n * 기본값을 비워 두지 않은 이유 — 이것이 사이드바를 마우스 없이 만지는 **유일한\r\n * 진입점**이라(목록은 tabindex=-1, `wireListKeys`) 안 묶여 있으면 기능이 없는 것과\r\n * 같다. `Ctrl-Shift-L` 은 Tabby 순정 기본 핫키와 겹치지 않는다 — core·terminal·\r\n * local·settings 네 패키지의 기본 조합을 훑어 확인했다(2026-09-09):\r\n * 그쪽이 쓰는 것은 `Ctrl-Shift-{A,C,D,E,F,I,P,R,S,T,V,W,Z}`·방향키·Tab·PageUp/Down·\r\n * Backspace·`-` 이다. 다른 플러그인과 부딪히면 설정 창에서 바꾼다.\r\n */\r\n 'agentdeck-focus-list': ['Ctrl-Shift-L'],\r\n },\r\n };\r\n }\r\n}\r\nexports.AgentDeckConfigProvider = AgentDeckConfigProvider;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.installCursorVisibilityFix = exports.CursorVisibilityStream = void 0;\r\n/** Codex 0.154.0 + Windows ConPTY emits CSI 25 l (without the DEC '?').\r\n * xterm only implements DECTCEM as CSI ? 25 l/h. Preserve chunk boundaries\r\n * so a split hide sequence is repaired as well as a complete one.\r\n */\r\nconst synchronizedOutput_1 = require(\"./synchronizedOutput\");\r\nclass CursorVisibilityStream {\r\n constructor() {\r\n this.pending = '';\r\n this.corrections = 0;\r\n }\r\n write(data, enabled) {\r\n let input = this.pending + data;\r\n this.pending = '';\r\n if (!enabled) {\r\n return input;\r\n }\r\n const marker = '\\x1b[25';\r\n for (let length = marker.length; length > 0; length--) {\r\n if (input.endsWith(marker.slice(0, length))) {\r\n this.pending = input.slice(-length);\r\n input = input.slice(0, -length);\r\n break;\r\n }\r\n }\r\n return input.replace(/\\x1b\\[25([lh])/g, (_match, mode) => {\r\n this.corrections++;\r\n return `\\x1b[?25${mode}`;\r\n });\r\n }\r\n}\r\nexports.CursorVisibilityStream = CursorVisibilityStream;\r\n/** Install at the frontend's write boundary; do not inject into xterm's\r\n * asynchronously parsed stream or touch the application's saved cursor slot.\r\n */\r\nfunction installCursorVisibilityFix(frontend, enabled, onCorrection) {\r\n if (!frontend || typeof frontend.write !== 'function' || frontend.__adCursorVisibilityFix) {\r\n return;\r\n }\r\n const original = frontend.write.bind(frontend);\r\n const stream = new CursorVisibilityStream();\r\n const frames = new synchronizedOutput_1.SynchronizedOutputStream();\r\n let timer;\r\n frontend.__adCursorVisibilityFix = true;\r\n frontend.write = (data) => {\r\n const before = stream.corrections;\r\n const active = enabled(data);\r\n const output = frames.write(stream.write(data, active), active);\r\n if (timer) {\r\n clearTimeout(timer);\r\n timer = undefined;\r\n }\r\n if (frames.waiting) {\r\n // Broken/interrupted producers must not freeze output indefinitely.\r\n timer = setTimeout(() => {\r\n timer = undefined;\r\n const tail = frames.flush();\r\n if (tail) {\r\n void Promise.resolve(original(tail)).catch(() => { });\r\n }\r\n }, 200);\r\n }\r\n if (!before && stream.corrections) {\r\n onCorrection();\r\n }\r\n return output ? original(output) : Promise.resolve();\r\n };\r\n}\r\nexports.installCursorVisibilityFix = installCursorVisibilityFix;\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckService = exports.matchesSearchTokens = exports.searchTokens = exports.foldSearchText = void 0;\r\nconst fs = __importStar(require(\"fs\"));\r\nconst core_1 = require(\"@angular/core\");\r\nconst terminalInput_1 = require(\"./terminalInput\");\r\nconst cursorVisibility_1 = require(\"./cursorVisibility\");\r\nconst screenAgent_1 = require(\"./screenAgent\");\r\nconst codexWheel_1 = require(\"./codexWheel\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\nconst tabby_settings_1 = require(\"tabby-settings\");\r\nconst status_service_1 = require(\"./status.service\");\r\nconst notify_service_1 = require(\"./notify.service\");\r\nconst detect_1 = require(\"./detect\");\r\nconst agents_1 = require(\"./agents\");\r\nconst api_1 = require(\"./api\");\r\nconst prompt_1 = require(\"./prompt\");\r\nconst screen_1 = require(\"./screen\");\r\nconst ime_1 = require(\"./ime\");\r\nconst dock_1 = require(\"./dock\");\r\nconst order_1 = require(\"./order\");\r\nconst group_1 = require(\"./group\");\r\nconst project_root_1 = require(\"./project-root\");\r\nconst nav_1 = require(\"./nav\");\r\nconst sessionLedger_service_1 = require(\"./sessionLedger.service\");\r\nconst sessionLedger_1 = require(\"./sessionLedger\");\r\nconst viewPanel_1 = require(\"./viewPanel\");\r\nconst viewer_1 = require(\"./viewer\");\r\nconst diag_1 = require(\"./diag\");\r\nconst SIDEBAR_ID = 'agentdeck-sidebar';\r\nconst BODY_CLASS = 'agentdeck-active';\r\n/** 배경 이미지 레이어를 터미널 영역으로 자르는 중일 때 body 에 붙는 클래스 (styles.scss 참조) */\r\nconst BG_CLIP_CLASS = 'ad-bg-clip';\r\n/** 터미널이 이보다 좁아지거나 낮아지지 않게 막는다 — 드래그로 사이드바를 끝까지 밀어도 */\r\nconst MIN_TERM_W = 320;\r\nconst MIN_TERM_H = 160;\r\n/** 사이드바가 이보다 작아지면 목록을 읽을 수 없다 — 드래그로도 이 밑으로는 안 내려간다 */\r\nconst MIN_SIDEBAR_W = 140;\r\nconst MIN_SIDEBAR_H = 90;\r\n/**\r\n * 줄을 잡아 끈 것으로 인정하는 최소 이동 거리 (px).\r\n *\r\n * `dock.ts` 의 `DRAG_THRESHOLD` 와 같은 값으로 둔다 — 같은 사이드바에서 헤더는 도킹 드래그,\r\n * 줄은 순서 드래그인데 문턱이 다르면 어느 쪽은 손이 떨려도 발화하고 어느 쪽은 안 한다.\r\n * 이 문턱이 곧 \"클릭으로 탭 선택\" 과 \"끌어서 옮기기\" 를 가르는 선이다.\r\n */\r\nconst ROW_DRAG_THRESHOLD = 5;\r\n/** 삽입선 두께 (px) — 줄 사이 여백(styles.scss `.ad-tab` margin-bottom 3px)보다 얇지 않게 */\r\nconst REORDER_LINE_PX = 2;\r\n/** \"지금은 순서를 못 바꾼다\" 안내가 떠 있는 시간 (ms) — 읽고 이해할 만큼만 */\r\nconst REORDER_NOTE_MS = 2600;\r\n/**\r\n * 드래그 중 자동 스크롤이 걸리는 목록 가장자리 띠의 두께 (px).\r\n *\r\n * 줄 하나(약 34px — `.ad-tab` 의 padding 14 + 제목 17 + margin 3)와 비슷하게 둔다.\r\n * 띠가 줄보다 좁으면 \"목록 끝에 갖다 대기\" 가 픽셀 사냥이 되고, 넓으면 목록 가운데\r\n * 근처에서도 화면이 흐르기 시작해 **보이는 줄에 놓는 평범한 드롭**을 방해한다.\r\n * 짧은 목록에서 앞·뒤 띠가 겹쳐 어디에 놓아도 스크롤되는 일을 막으려고 실제로는 목록\r\n * 길이의 1/3 로 한 번 더 깎는다 (`dragScrollSpeed`).\r\n *\r\n * **설정으로 빼지 않았다** — 이 값은 줄 높이에서 나온 것이고 줄 높이는 설정이 아니다.\r\n * 사람이 정하고 싶은 것은 \"이 동작을 쓸지\" 이고 그것만 `dragAutoScroll` 로 열어 뒀다.\r\n */\r\nconst DRAG_SCROLL_BAND_PX = 32;\r\n/**\r\n * 자동 스크롤 속도 (px/s) — 띠의 **안쪽 경계**에서 MIN, 가장자리에 완전히 붙였을 때 MAX.\r\n *\r\n * 왜 한 값이 아니라 비례인가 — 한 값만 쓰면 \"한두 줄만 더 보기\" 와 \"목록 끝까지 가기\" 중\r\n * 하나는 반드시 불편하다(느리면 답답하고 빠르면 지나친다). 띠 안으로 커서를 얼마나\r\n * 밀어넣었는지가 곧 속도가 되면 두 조작이 같은 손짓 하나에 들어온다.\r\n * 줄 높이 ~34px 기준 MIN 은 초당 4줄쯤(눈으로 따라갈 수 있다), MAX 는 초당 24줄쯤이라\r\n * 탭 40개 목록을 2초 안에 끝에서 끝까지 훑는다.\r\n */\r\nconst DRAG_SCROLL_MIN_PPS = 150;\r\nconst DRAG_SCROLL_MAX_PPS = 800;\r\n/**\r\n * 한 tick 이 인정하는 최대 경과시간 (ms) — 3프레임쯤.\r\n *\r\n * 속도를 **프레임이 아니라 시간으로** 곱하는 이유는 120Hz 모니터에서 두 배로 빨라지지 않게\r\n * 하는 것인데(px/프레임 으로 두면 그렇게 된다), 그러면 반대 위험이 생긴다: 창이 잠깐 멈췄다\r\n * 돌아오면(GC·다른 창으로 전환) rAF 간격이 수백 ms 가 되고 그것을 그대로 곱하면 목록이\r\n * 한 번에 튀어 사용자가 짚어 둔 자리를 지나쳐 버린다. 느려지는 것보다 튀는 것이 나쁘다.\r\n */\r\nconst DRAG_SCROLL_MAX_DT_MS = 50;\r\n/** Ctrl+V 를 눌렀을 때 xterm 의 네이티브 paste 가 오는지 기다려보는 시간 */\r\nconst PASTE_NATIVE_WAIT_MS = 60;\r\n/**\r\n * 같은 한 번의 붙여넣기가 여러 경로로 들어왔을 때 뒤엣것을 버리는 창(ms).\r\n *\r\n * 사람이 Ctrl+V 를 연타해도 이보다 빠를 수 없다(실측된 중복은 1ms 간격이었다).\r\n * claimCtrlVKey 로 경로를 하나로 모았어도, 그게 안 먹는 상황(포커스가 xterm 밖 등)을\r\n * 대비한 마지막 보험이다.\r\n */\r\nconst PASTE_DEDUPE_MS = 80;\r\n/** 붙여넣기 계측 창 — 두 번째 write 가 늦게 와도 놓치지 않게 넉넉히 둔다 */\r\nconst PASTE_PROBE_MS = 5000;\r\n/** 입력창을 찾으려고 화면 아래에서 훑어 올라갈 줄 수 — 여러 줄 프롬프트를 덮을 만큼만 */\r\nconst PROMPT_SCAN_ROWS = 14;\r\n/**\r\n * 복구할 때 Ctrl+L 을 보내기까지 기다리는 시간.\r\n * 앞선 흔들기(`nudgePtyRedraw`)가 60ms 뒤에 폭을 되돌리므로, 앱이 그 두 번째 SIGWINCH 로\r\n * 새 폭을 받아들인 다음에 \"다시 그려라\" 가 도착해야 한다. 순서가 뒤집히면 옛 폭으로 다시 그린다.\r\n */\r\nconst REPAIR_REDRAW_DELAY_MS = 180;\r\n/** 복구 뒤 화면을 다시 재는 시각 — 앱이 새 프레임을 다 그릴 만큼은 기다린다 */\r\nconst SNAP_AFTER_MS = 1500;\r\n/** 진단 로그 — devtools 를 못 여는 상황에서도 밖에서 읽을 수 있게 파일로 남긴다 */\r\n/**\r\n * 화면 깨짐 검사를 출력이 멈춘 뒤 이만큼 기다렸다 한다.\r\n * TUI 가 한 프레임을 여러 번의 write 로 그리므로, 그리는 도중에 읽으면 멀쩡한 화면도 깨져 보인다.\r\n */\r\nconst SCREEN_CHECK_DEBOUNCE_MS = 700;\r\n/**\r\n * pty 크기를 고친 뒤 같은 값을 다시 보내는 시점 (ms).\r\n * 세션 초기화 직후의 resize 는 유실되므로(syncPtySize 주석) 시간을 벌려 몇 번 더 던진다.\r\n */\r\nconst PTY_RESIZE_RETRY_MS = [150, 400, 900, 1800, 3000];\r\n/**\r\n * 탭이 열린 뒤 \"지금 xterm 이 쓰는 크기\" 를 pty 에 알려 주는 시점 (ms).\r\n *\r\n * 순정이 못 메우는 구멍이 딱 하나 남아 있다 — **새 탭.** Tabby 는 프론트엔드의 첫 `resize$`\r\n * 값으로 세션을 스폰하므로(tabby-local `initializeSession(this.size…)`), 그 스냅샷이\r\n * 레이아웃 확정보다 이르면 pty 만 좁게 태어난다. 그 뒤 xterm 이 넓어져도 **크기 변화\r\n * 이벤트가 나지 않으므로** ResizeObserver 도 fit() 도 아무것도 보내지 않는다(fit 은 열/행이\r\n * 이미 맞으면 no-op). 아무도 pty 에 알려주지 않아 그대로 굳는다.\r\n *\r\n * 실측(2026-09-02, 격리 인스턴스): 평범하게 연 새 탭 3개가 전부 `xterm=88 / pane.size=88`\r\n * 인데 pty 는 72 였고, TUI 는 72 폭으로 그려 테두리 두 줄이 73·88 로 어긋났다.\r\n * 같은 값(`session.resize(88, 39)`)을 **한 번** 보내자 즉시 정상으로 돌아왔다.\r\n *\r\n * 그래서 되살린 개입은 이것 하나뿐이다 — \"현재 크기를 몇 번 알려준다\". 흔들기(cols-1 ↔ cols)도,\r\n * 250ms 감시 루프도, fit 강제도 아니다. 값이 이미 맞으면 SIGWINCH 가 나지 않아 무해하고,\r\n * xterm 을 건드리지 않으므로 그리는 중인 프레임과 경쟁하지도 않는다.\r\n */\r\nconst TAB_OPEN_ANNOUNCE_MS = [250, 800, 1800];\r\n/** 화면 깨짐 주기 검사 간격 (ms) — 출력 구독이 없는 탭도 잡기 위한 그물 */\r\nconst SCREEN_SWEEP_MS = 2000;\r\n/**\r\n * 조합이 끝나기를 기다려 주는 시간 (ms).\r\n *\r\n * 이 시간이 지나면 동기 확정을 시키고 쓴다 — IME 가 `compositionend` 를 안 내는 경우\r\n * (창 포커스가 빠지는 등)에 입력이 영영 안 나가는 것을 막는 안전장치다. 사람이 조합을\r\n * 끝내는 데 걸리는 시간보다 넉넉해야 하지만, 개행이 눈에 띄게 늦어서도 안 된다.\r\n */\r\nconst IME_WAIT_MS = 400;\r\n/**\r\n * 잔상을 지울 때 마지막 테두리에서 위로 몇 행까지 같은 입력창 블록으로 볼지.\r\n *\r\n * 4 였을 때는 **Ctrl+Enter 로 여러 줄이 된 입력창**의 위 테두리에 닿지 못해\r\n * 시작행이 아래 테두리로 잡히고 입력창 **아래**를 지웠다 — 잔상은 그대로 남는다\r\n * (2026-09-09 실사용 스샷: 위 테두리 + 입력 3줄 + 아래 테두리).\r\n */\r\nconst INPUT_BLOCK_ROWS = 12;\r\n/**\r\n * 자동복구 예산(`autoRepairMaxPerTab`)을 되돌리기까지 화면이 온전해야 하는 시간.\r\n *\r\n * 예산은 \"같은 깨짐에 무한히 손대지 않는다\" 는 안전장치인데, 카운터를 한 번도 되돌리지\r\n * 않아 **탭이 살아 있는 동안 영구히** 소진됐다 — 며칠씩 켜 두는 탭에서는 뒤에 온 진짜\r\n * 깨짐이 통째로 방치된다. 그렇다고 온전해지자마자 되돌리면 깨짐↔복구가 번갈아 오는\r\n * 화면에서 예산이 무한이 되어 안전장치가 사라진다. 그래서 **오래 온전할 때만** 되돌린다.\r\n */\r\nconst AUTO_REPAIR_REFILL_MS = 60000;\r\n/** 탭 cwd 캐시를 다시 물어보는 간격 (ms) */\r\nconst CWD_TTL_MS = 3000;\r\n/**\r\n * cwd 를 아직 못 알아낸 탭을 다시 묻기까지의 최소 간격.\r\n *\r\n * 0 이면(=TTL 을 통째로 건너뛰면) 출력 조각마다 OS 호출이 된다 — 2026-09-09 실측으로\r\n * 조각 24개에 34회였다(PF6). 반대로 `CWD_TTL_MS` 를 그대로 쓰면 조용한 탭이 오래\r\n * `기타` 그룹에 남는다. 400ms 는 사람이 그룹이 바뀌는 것을 눈치채지 못하는 범위이면서\r\n * 초당 호출을 2~3회로 묶는다.\r\n */\r\nconst CWD_MISS_MS = 400;\r\n/**\r\n * cwd 를 못 알아낸 탭을 **출력 없이도** 몇 번까지 더 물어볼지.\r\n *\r\n * `touchCwd` 는 출력이 흐를 때 불린다. 그래서 아무것도 찍지 않는 탭은 재시도 기회가\r\n * 없는데, 세션이 붙는 중이던 첫 조회가 빈손이면 그대로 `기타` 그룹에 남고 미리보기의\r\n * `변경` 탭도 \"작업 폴더를 모른다\" 로 끝난다 (2026-09-09 실측: 새 탭이 조용하면 재현).\r\n * 그래서 1초 tick 이 미상 탭만 이 횟수까지 다시 묻는다 — 20회면 약 20초 안에 잡히고,\r\n * 끝내 cwd 를 안 주는 셸(SSH 등)에서는 그 뒤 조용해진다(출력이 올 때만 다시 시도).\r\n */\r\nconst CWD_MISS_MAX = 20;\r\n/**\r\n * 이 경로가 **폴더**인가. 없거나 파일이면 false.\r\n *\r\n * cwd 후보를 받아들이기 전 관문이다 — Tabby 의 윈도우 cwd 는 출력에서 주운 추정이고\r\n * 폴더인지 확인하지 않는다(`touchCwd` 주석). 동기 호출인 이유: 판정 결과로 캐시에 넣을지가\r\n * 갈리는데 그 사이 다른 보고가 끼어들면 순서가 뒤집힌다. TTL 뒤에만 불리는 자리라 비용도 없다.\r\n */\r\nfunction isDirectory(target) {\r\n try {\r\n return fs.statSync(target).isDirectory();\r\n }\r\n catch {\r\n // 사라진 폴더·권한 없음 — 어느 쪽이든 cwd 로 쓸 수 없다\r\n return false;\r\n }\r\n}\r\n/**\r\n * cwd 를 모르는 탭들의 그룹을 설정(`collapsedGroups`)에 적을 때 쓰는 키.\r\n *\r\n * 실제 그룹 키는 정규화된 경로(`D:/project/a`)뿐이라 괄호로 시작하는 이 토큰과는 겹칠 수 없다.\r\n */\r\n/**\r\n * 탭에서 도는 에이전트를 다시 물어보는 간격 (ms).\r\n *\r\n * `session.getChildProcesses()` 는 OS 호출이다 — 출력 조각마다 부르면 안 된다.\r\n * 그래서 세션이 붙을 때와 제목이 바뀔 때만, 그것도 이 간격을 두고 묻는다.\r\n * 셸에서 `claude` 를 나중에 직접 띄우는 경우가 있으니 한 번 unknown 이어도 다시 본다.\r\n */\r\nconst AGENT_PROBE_TTL_MS = 10000;\r\n/** 자식이 아직 없는 래퍼 탭을 다시 훑는 간격과 횟수 */\r\nconst EMPTY_TAB_RETRY_MS = 400;\r\nconst EMPTY_TAB_RETRY_MAX = 20;\r\nlet cachedClipboard;\r\n/**\r\n * Electron 의 clipboard 를 런타임에 가져온다.\r\n *\r\n * `import { clipboard } from 'electron'` 을 쓰면 타입 때문에 electron 패키지(200MB+)를\r\n * devDependency 로 받아야 한다. Tabby 렌더러는 nodeIntegration 이 켜져 있어(`fs` 를 그냥 import 한다)\r\n * window.require 로 바로 집을 수 있으므로 그쪽을 쓴다.\r\n */\r\nfunction getClipboard() {\r\n var _a, _b, _c, _d, _e;\r\n if (cachedClipboard !== undefined) {\r\n return cachedClipboard;\r\n }\r\n // webpack externals 에 'electron' 이 있어(webpack.config.js) 이 require 는 번들되지 않고\r\n // 런타임에 Tabby 가 그대로 넘겨준다 — 다른 모듈에서 `fs` 를 그냥 import 하는 것과 같은 경로다.\r\n // window.require 는 contextIsolation 이 켜지면 사라지므로 폴백으로만 둔다.\r\n try {\r\n cachedClipboard = (_b = (_a = require('electron')) === null || _a === void 0 ? void 0 : _a.clipboard) !== null && _b !== void 0 ? _b : null;\r\n }\r\n catch (e) {\r\n cachedClipboard = null;\r\n (0, diag_1.diagCatch)('clipboard require(electron)', e);\r\n }\r\n if (!cachedClipboard) {\r\n try {\r\n const req = (_c = window.require) !== null && _c !== void 0 ? _c : globalThis.require;\r\n cachedClipboard = (_e = (_d = req === null || req === void 0 ? void 0 : req('electron')) === null || _d === void 0 ? void 0 : _d.clipboard) !== null && _e !== void 0 ? _e : null;\r\n }\r\n catch (e) {\r\n cachedClipboard = null;\r\n (0, diag_1.diagCatch)('clipboard window.require', e);\r\n }\r\n }\r\n if (!cachedClipboard) {\r\n // 이미지 붙여넣기가 통째로 안 되는 상태다. 사유 없이는 \"붙여넣기가 안 된다\" 제보를 가를 수 없다\r\n (0, diag_1.diagOnce)('clipboard-missing', 'clipboard 없음 — 이미지 붙여넣기 불가');\r\n }\r\n return cachedClipboard;\r\n}\r\nfunction clampPct(value) {\r\n const n = typeof value === 'number' && isFinite(value) ? value : 100;\r\n return Math.min(100, Math.max(0, Math.round(n)));\r\n}\r\n/**\r\n * `#RRGGBB` / `#RRGGBBAA` 에 불투명도(%)를 입힌다.\r\n * 100% 면 알파를 떼어 원래 6자리로 되돌린다 — 설정을 되돌리면 원상복구되게 하려는 것.\r\n * 해석할 수 없는 형식(rgb(), 색이름 등)은 건드리지 않고 그대로 돌려준다.\r\n */\r\nfunction withAlpha(color, pct) {\r\n const m = /^#([0-9a-fA-F]{6})(?:[0-9a-fA-F]{2})?$/.exec(color.trim());\r\n if (!m) {\r\n return color;\r\n }\r\n const rgb = '#' + m[1];\r\n if (pct >= 100) {\r\n return rgb;\r\n }\r\n const alpha = Math.round(pct * 255 / 100).toString(16).padStart(2, '0');\r\n return rgb + alpha;\r\n}\r\n/**\r\n * 검색어와 후보 필드를 비교 가능한 꼴로 접는다.\r\n *\r\n * 세 가지를 한꺼번에 처리한다 —\r\n * 1) 대소문자 무시.\r\n * 2) 경로 구분자 통일(`\\` -> `/`). 후보에는 cwd 원문이 들어오고 Windows 셸은 `\\` 를 주는데,\r\n * 사용자는 `d:\\project` 로도 `d:/project` 로도 친다. 접지 않으면 어느 한쪽이 항상 0건이다.\r\n * 3) 유니코드 정규화(NFC). 한글은 같은 글자를 두 가지로 적을 수 있고(macOS 가 주는 경로는 NFD),\r\n * Windows IME 가 주는 입력은 NFC 다 — 눈에 같아 보이는 글자가 안 맞는 사고를 막는다.\r\n */\r\nfunction foldSearchText(raw) {\r\n if (typeof raw !== 'string' || !raw) {\r\n return '';\r\n }\r\n let s = raw;\r\n try {\r\n s = s.normalize('NFC');\r\n }\r\n catch {\r\n // normalize 가 없는 런타임 — 정규화만 못 하고 나머지 접기는 그대로 돈다\r\n }\r\n return s.toLowerCase().replace(/\\\\/g, '/');\r\n}\r\nexports.foldSearchText = foldSearchText;\r\n/**\r\n * 검색어를 토큰으로 쪼갠다 — 공백으로 끊고 빈 조각을 버린다.\r\n *\r\n * 왜 통째로 안 찾고 쪼개나 — `root api` 처럼 **여러 조각의 AND** 가 사람이 기대하는 동작이다.\r\n * 폴더가 `Root` 이고 제목에 `api` 가 든 세션을 좁히려면 조각마다 따로 봐야 한다.\r\n * 통째로 부분문자열을 찾으면 그런 조합은 영원히 0건이 된다.\r\n */\r\nfunction searchTokens(query) {\r\n return foldSearchText(query).split(/\\s+/).filter(t => t.length > 0);\r\n}\r\nexports.searchTokens = searchTokens;\r\n/**\r\n * 후보 필드들이 검색 토큰을 전부 만족하나 — 토큰끼리는 AND, 필드끼리는 OR.\r\n *\r\n * 토큰이 없으면(검색어가 비었거나 공백뿐) **항상 참**이다. 필터가 없는 상태와 화면이 같아야 한다.\r\n */\r\nfunction matchesSearchTokens(fields, tokens) {\r\n if (!tokens.length) {\r\n return true;\r\n }\r\n const folded = [];\r\n for (const f of fields) {\r\n const s = foldSearchText(f);\r\n if (s) {\r\n folded.push(s);\r\n }\r\n }\r\n return tokens.every(t => folded.some(f => f.includes(t)));\r\n}\r\nexports.matchesSearchTokens = matchesSearchTokens;\r\n/**\r\n * AgentDeck 본체.\r\n *\r\n * 하는 일 두 가지 —\r\n * 1) 터미널 뷰포트(.content.main)를 창 높이 기준 4:3 폭으로 고정하고\r\n * 2) 그때 남는 왼쪽 공간에 탭 목록 + 작업 상태 사이드바를 그린다.\r\n *\r\n * Tabby 순정 탭바는 CSS 로 감추고 이 사이드바가 탭 관리를 대신한다.\r\n * Angular 컴포넌트 대신 순수 DOM 을 쓰는 이유는 appRoot 템플릿에 컴포넌트를\r\n * 꽂는 공식 확장점이 없기 때문 — DOM 직접 조작이 Tabby 버전 변화에 더 견딘다.\r\n */\r\nlet AgentDeckService = class AgentDeckService {\r\n constructor(app, config, status, hotkeys, profiles, hostWindow, platform, \r\n // 서브에이전트 개수를 물어보는 창구(`subagentsOf`). 순환 의존이 아니다 —\r\n // notify 쪽은 deck 을 모른다(상태는 `status.service` 를 거쳐 만난다)\r\n notify, \r\n // 지난 세션 원장. deck 이 라벨·cwd 를 아는 유일한 자리라 적는 쪽도 여기다\r\n ledger, zone) {\r\n this.app = app;\r\n this.config = config;\r\n this.status = status;\r\n this.hotkeys = hotkeys;\r\n this.profiles = profiles;\r\n this.hostWindow = hostWindow;\r\n this.platform = platform;\r\n this.notify = notify;\r\n this.ledger = ledger;\r\n this.zone = zone;\r\n this.sidebar = null;\r\n this.listEl = null;\r\n this.windowEl = null;\r\n this.mainEl = null;\r\n this.observer = null;\r\n this.editing = null;\r\n /**\r\n * 줄을 끌어 순서를 바꾸는 중일 때의 상태 (null 이면 드래그 중이 아니다).\r\n *\r\n * `moved` 가 false 인 구간은 **아직 클릭일 수도 있는** 무장 상태다 — 그 사이에는 화면도\r\n * 멈추지 않고 삽입선도 그리지 않는다. dock.ts 의 `dragArmed`/`dragging` 와 같은 두 단계다.\r\n */\r\n this.drag = null;\r\n /**\r\n * 드래그로 끝난 pointerup 뒤에 따라오는 click 을 한 번 삼킨다.\r\n *\r\n * 줄의 click 은 탭 선택이다(`renderTab`). 순서를 옮기고 손을 뗀 것까지 선택으로 읽으면\r\n * 옮길 때마다 활성 탭이 바뀌어 터미널 화면이 튄다 — 사용자는 순서만 만졌다고 생각한다.\r\n *\r\n * **낡은 가드가 남을 수 있다** — 목록 밖에서 손을 떼면 click 이 아예 오지 않으므로 켜 둔\r\n * 가드를 아무도 안 쓴다. 그러면 그 다음의 정당한 클릭이 삼켜진다. 그래서 소비뿐 아니라\r\n * **모든 pointerdown 첫 줄에서 끈다**(`armRowDrag`) — click 은 언제나 같은 줄의\r\n * pointerdown 뒤에 오므로, 이렇게 두면 시간에 기대지 않고도 항상 새 값이 된다.\r\n */\r\n this.dragClickGuard = false;\r\n /**\r\n * 마지막 드래그가 어떻게 끝났나 — 회귀가 **의도한 이유로** 취소됐는지 보게 남긴다.\r\n *\r\n * 결과(순서 불변)만으로는 부족하다: 낡은 `data-ad-index` 로 대상을 못 찾아 취소된 것과\r\n * 사용자가 Esc 를 눌러 취소된 것이 결과가 같아서, 판정이 초록인 채로 규칙이 썩는다.\r\n */\r\n this.lastDragEnd = null;\r\n /** `dropTargetAt` 이 방금 자리를 거부한 이유 (성공이면 null) */\r\n this.dropReject = null;\r\n /**\r\n * 검색 입력창. **`.ad-list` 밖**에 산다 — `render()` 가 목록의 innerHTML 을 비우므로\r\n * 안에 두면 한 글자 칠 때마다 입력창이 새로 만들어져 포커스와 IME 조합이 날아간다.\r\n */\r\n this.searchEl = null;\r\n /**\r\n * 지금 걸린 검색어. **설정에 저장하지 않는다.**\r\n * 다음 기동에 남아 있으면 목록이 좁혀진 채로 떠서 \"탭이 사라졌다\" 로 읽힌다 —\r\n * 이 기능에서 가장 위험한 실패 모양이다. 필터는 지금 이 순간의 도구다.\r\n */\r\n this.searchQuery = '';\r\n /** 지금 걸린 상태 필터(헤더 칩 클릭). 검색어와 같은 이유로 저장하지 않는다 */\r\n this.statusFilter = null;\r\n /** 검색창에서 IME 조합이 도는 중인가 — 조합 중의 Esc 는 조합 취소이므로 검색을 지우면 안 된다 */\r\n this.searchComposing = false;\r\n /**\r\n * 키보드로 짚어 둔 줄 (null 이면 아무 줄도 안 짚었다).\r\n *\r\n * **선택(활성 탭)과 다른 값이다.** ↑↓ 는 이 값만 움직이고 `app.selectTab` 은 부르지 않는다 —\r\n * 이동만으로 탭이 바뀌면 세션을 여섯 개쯤 띄워 둔 사람이 목록을 훑을 수 없다. 줄을 지날 때마다\r\n * 활성 탭이 바뀌고, 그때마다 터미널이 다시 그려지고(폭 적용·refit) 화면이 튀며, 돌고 있는\r\n * 탭을 지나가면 그 출력이 화면을 채운다. 그래서 \"보고 있는 줄\" 과 \"쓰고 있는 탭\" 을 갈랐고,\r\n * 둘을 합치는 지점은 Enter 하나다 (`activateNav`).\r\n *\r\n * **DOM 이 아니라 여기에 둔다.** `render()` 는 목록을 통째로 다시 만들므로(`innerHTML = ''`)\r\n * 줄에 얹은 상태는 매 렌더에 날아간다 — 라벨 편집이 `editing` 에, 드래그가 `drag.tab` 에\r\n * 대상을 객체로 들고 있는 것과 같은 이유다. 인덱스가 아니라 **탭 객체 / 그룹 키**로 들고 있는\r\n * 근거는 `NavRow` 주석에 있다(인덱스는 탭이 하나 닫히면 다른 줄을 가리킨다).\r\n */\r\n this.navFocus = null;\r\n this.renderQueued = false;\r\n /** Shift 물리 키가 눌려 있나 — IME 조합을 거친 Enter 는 shiftKey 가 지워져 온다 */\r\n this.shiftDownAt = 0;\r\n /** rAF 가 멈춘 상황(창 가려짐)을 대비한 렌더 폴백 타이머 */\r\n this.renderTimer = null;\r\n /** 직전에 적용한 폭 — 같은 값이면 DOM 을 다시 건드리지 않는다 */\r\n this.lastTermW = -1;\r\n this.lastSidebarW = -1;\r\n /** 직전에 적용한 도킹 방향 — 크기가 같아도 방향이 바뀌면 다시 그려야 한다 */\r\n this.lastDock = null;\r\n /** 경계선 드래그(크기)와 헤더 드래그(도킹 방향)를 맡는다 */\r\n this.dock = null;\r\n this.refitQueued = false;\r\n /** 결과물 미리보기 패널 (viewPanel.ts) — 사이드바 반대편에 앉는다 */\r\n this.view = null;\r\n this.lastViewW = -1;\r\n this.lastViewSide = null;\r\n /**\r\n * 탭별 작업 디렉토리 캐시.\r\n *\r\n * 미리보기 패널이 화면에서 주운 상대경로(`src/a.ts`)를 풀 때 필요하다. `getWorkingDirectory()`\r\n * 는 비동기이고 OS 호출이라 출력 조각마다 부를 수 없어서, 필요할 때 한 번 받아 두고\r\n * `CWD_TTL_MS` 동안 재사용한다 (cd 로 옮겨 다녀도 그 정도면 따라간다).\r\n */\r\n this.cwdCache = new WeakMap();\r\n /**\r\n * 지난 세션 목록에서 \"이미 열림\" 으로 그린 줄이 가리키는 탭 — `세션id -> 탭`.\r\n * 매 렌더마다 `liveSessionIds()` 가 다시 채운다(탭이 닫히면 그 줄은 이어받기로 돌아간다).\r\n */\r\n this.resumeTabs = new Map();\r\n /**\r\n * 이 서비스의 출력 구독이 실제로 몇 번 돌았나 (진단용).\r\n *\r\n * decorator(`decorator.ts`)도 같은 `output$` 를 구독하므로, 상태 감지가 정상으로 보여도\r\n * **이쪽 구독은 안 돌고 있을 수 있다.** 그 둘을 가릴 수단이 없어서 검증 중에 막혔다\r\n * (2026-09-08). `__agentdeck.debug()` 로 읽는다.\r\n */\r\n this.outputHits = 0;\r\n /**\r\n * 탭별로 판정한 에이전트 (`agents.ts`).\r\n *\r\n * 상태 감지 패턴·이미지 붙여넣기 키가 에이전트마다 다르므로, 출력마다 프로세스 트리를\r\n * 묻지 않으려면 한 번 알아낸 것을 여기 기억해 둬야 한다. 채우는 시점은 세션이 붙을 때와\r\n * 제목이 바뀔 때 (`probeAgent`, TTL = `AGENT_PROBE_TTL_MS`).\r\n */\r\n this.tabAgents = new WeakMap();\r\n this.paneAgents = new WeakMap();\r\n /** 마지막으로 프로세스 트리를 물어본 시각 — OS 호출이라 TTL 로 묶는다 */\r\n this.agentProbedAt = new WeakMap();\r\n /** 이미 감시를 건 래퍼 탭 / pane — 중복 구독 방지 */\r\n this.watched = new WeakSet();\r\n this.watchedPanes = new WeakSet();\r\n /** 화면 깨짐 검사 예약 타이머 — pane 당 하나만 돈다 */\r\n this.screenCheckTimers = new WeakMap();\r\n /** 빈 래퍼 탭을 다시 훑은 횟수 */\r\n this.emptyTabRetries = new WeakMap();\r\n /** 마지막 화면 판정 결과 — 상태가 바뀔 때만 채증하려고 들고 있는다 */\r\n this.screenObs = new WeakMap();\r\n /** 마지막 자동 복구 시각 — 쿨다운 판정용 */\r\n this.autoRepairAt = new WeakMap();\r\n /** 자동 복구 횟수 — 오탐으로 무한히 흔드는 것을 막는다 */\r\n this.autoRepairCount = new WeakMap();\r\n /** 이 탭 화면이 온전해진 시각 — 예산 회복 판정에만 쓴다 (`AUTO_REPAIR_REFILL_MS`) */\r\n this.autoRepairHealthySince = new WeakMap();\r\n /** 우클릭 누른 시각 — 길게 누르면 컨텍스트 메뉴로 분기 */\r\n this.rightDownAt = 0;\r\n /** 직전 우클릭 처리 시각 — 같은 클릭이 두 번 들어오는 걸 막는다 */\r\n this.lastRightHandledAt = 0;\r\n /** xterm 이 네이티브 paste 로 붙여넣은 마지막 시각 — Ctrl+V 이중 입력 방지 */\r\n this.nativePasteAt = 0;\r\n /** 직전에 붙여넣기를 처리한 시각 — 같은 클릭/키가 여러 경로로 들어와도 한 번만 붙인다 */\r\n this.lastPasteAt = 0;\r\n /** 이 시각까지는 PTY 로 나가는 입력을 진단 로그에 남긴다 (붙여넣기가 두 번 들어가는지 보려고) */\r\n this.pasteProbeUntil = 0;\r\n }\r\n init() {\r\n this.app.ready$.subscribe(() => this.zone.runOutsideAngular(() => {\r\n var _a, _b, _c, _d, _e;\r\n // 진단 로그는 setup 보다 먼저 연다 — `.window` 를 못 찾아 배치를 포기하는 경로도\r\n // 로그에 남아야 하고, 세션 스탬프(버전·환경)는 그 판정보다 앞에 찍혀야 한다\r\n (0, diag_1.startDiagSession)({\r\n tabby: (_b = (_a = this.platform).getAppVersion) === null || _b === void 0 ? void 0 : _b.call(_a),\r\n osRelease: (_d = (_c = this.platform).getOSRelease) === null || _d === void 0 ? void 0 : _d.call(_c),\r\n config: this.diagConfig(),\r\n });\r\n (0, diag_1.installErrorCapture)();\r\n // 원장 스캔이 끝나면 다시 그린다 — 스캔은 비동기라 첫 렌더에는 목록이 비어 있다\r\n this.ledger.onChange = () => this.scheduleRender();\r\n // setup 도중 예외가 나면 그 뒤 배선(탭 감시, 흔들기 예약)이 통째로 죽는데\r\n // 콘솔을 안 보면 알 길이 없다. 진단 파일에 남겨 밖에서 읽을 수 있게 한다\r\n try {\r\n this.setup();\r\n }\r\n catch (e) {\r\n this.diag(`setup ERROR ${(_e = e === null || e === void 0 ? void 0 : e.message) !== null && _e !== void 0 ? _e : e}`);\r\n throw e;\r\n }\r\n }));\r\n }\r\n /**\r\n * 같은 키로는 한 번만 남기는 진단.\r\n * relayout 처럼 초당 여러 번 불리는 자리에서 조기 return 사유를 남길 때 쓴다\r\n */\r\n diagOnce(key, line) {\r\n (0, diag_1.diagOnce)(key, line);\r\n }\r\n /** 진단 한 줄 — 회전·시각 표기·메모리 보관은 `diag.ts` 가 한다 */\r\n diag(line) {\r\n (0, diag_1.diag)(line);\r\n }\r\n /** 세션 머리말에 넣을 설정 — 고르는 기준은 `diag.ts` 의 `configStamp` 에 적혀 있다 */\r\n diagConfig() {\r\n return (0, diag_1.configStamp)(this.config.store);\r\n }\r\n setup() {\r\n var _a;\r\n this.windowEl = document.querySelector('.window');\r\n this.mainEl = document.querySelector('.content.main');\r\n if (!this.windowEl) {\r\n console.warn('[agentdeck] .window 를 찾지 못해 레이아웃을 적용하지 않는다');\r\n return;\r\n }\r\n this.diag(`setup start tabs=${this.app.tabs.length}`);\r\n this.migrateFollowConfig();\r\n this.buildSidebar();\r\n this.buildView();\r\n this.applyEnabled();\r\n this.applyOpacity();\r\n this.disableBackgroundThrottling();\r\n this.ensurePasteHotkey();\r\n this.ensureNewlineHotkey();\r\n this.releaseHomeEndHotkey();\r\n this.guardHomeEndComposition();\r\n this.claimCtrlVKey();\r\n this.claimCtrlWKey();\r\n this.claimShiftEnterKey();\r\n this.claimEnterLabel();\r\n this.claimRightClick();\r\n this.claimFileDrop();\r\n // xterm 의 네이티브 paste 를 관측만 한다 (doPaste 의 이중 입력 방지용).\r\n // 캡처 단계라 xterm 핸들러의 stopPropagation 보다 먼저 돈다.\r\n document.addEventListener('paste', () => {\r\n this.nativePasteAt = Date.now();\r\n this.diag(`native-paste`);\r\n }, true);\r\n // 탭 변화 -> 사이드바 다시 그림\r\n // 탭 복원은 ready$ 보다 늦게 끝나므로 목록이 바뀔 때마다 감시 대상을 다시 훑는다\r\n // (watched WeakSet 이 중복 구독을 막는다)\r\n this.app.tabsChanged$.subscribe(() => {\r\n for (const tab of this.app.tabs) {\r\n this.watchTab(tab);\r\n }\r\n this.scheduleRender();\r\n });\r\n // 탭을 바꾸면 그 탭은 숨어 있던 동안 폭 0 이라 refit 을 건너뛰었다 — 지금 맞춰준다\r\n this.app.activeTabChange$.subscribe(() => {\r\n var _a, _b;\r\n // 미리보기의 최근 목록은 탭마다 따로다 — 보고 있는 탭 것으로 바꿔 준다\r\n (_a = this.view) === null || _a === void 0 ? void 0 : _a.setActiveTab((_b = this.app.activeTab) !== null && _b !== void 0 ? _b : null);\r\n this.scheduleRender();\r\n this.scheduleRefit();\r\n });\r\n this.app.tabOpened$.subscribe(tab => {\r\n this.watchTab(tab);\r\n // 새 탭은 xterm 은 맞는 폭으로 열리는데 pty 만 옛 폭으로 남는 일이 있다 (syncPtySize 주석)\r\n this.scheduleRefit();\r\n this.scheduleRender();\r\n });\r\n this.app.tabClosed$.subscribe(() => {\r\n // 닫힌 탭의 상태를 버린다. `decorator.detach` 만으로는 새는 경로가 있다\r\n // (분할 탭의 자식이 detach 될 때 부모가 아직 목록에 있으면 그냥 지나간다 —\r\n // `status.service` 의 `sweep` 주석에 실측값). 여기서 목록을 기준으로 한 번 훑는다.\r\n this.status.sweep(this.app.tabs);\r\n this.scheduleRender();\r\n });\r\n // 세션이 이미 열린 채 복원된 탭들도 감시 대상에 넣는다\r\n for (const tab of this.app.tabs) {\r\n this.watchTab(tab);\r\n }\r\n this.status.changed$.subscribe(() => this.scheduleRender());\r\n this.config.changed$.subscribe(() => {\r\n var _a;\r\n this.applyEnabled();\r\n this.applyOpacity();\r\n // 검색 줄 on/off 는 설정 창에서 바뀐다 (끄면 걸려 있던 필터도 같이 지운다)\r\n this.applySearchBox();\r\n // 설정 창에서 패널을 여닫았을 수도 있다 — 값이 같으면 아무 일도 하지 않는다.\r\n // remember=false: 방금 설정에서 온 값을 되쓰지 않는다(무한 왕복 방지)\r\n (_a = this.view) === null || _a === void 0 ? void 0 : _a.setOpen(!!this.config.store.agentDeck.viewerOpen, false);\r\n this.relayout();\r\n this.scheduleRender();\r\n });\r\n // 화면 깨짐 주기 검사. 출력 구독(scheduleScreenCheck)이 더 정밀하지만, 구독이 붙지\r\n // 못한 탭에서는 아무도 보지 않게 되므로 그물을 하나 더 둔다. 활성 탭만 본다 —\r\n // 숨은 탭은 폭이 0 이라 판정할 근거가 없다.\r\n setInterval(() => this.sweepScreens(), SCREEN_SWEEP_MS);\r\n // 창 크기 변화 -> 4:3 폭 재계산\r\n this.observer = new ResizeObserver(() => this.relayout());\r\n this.observer.observe(this.windowEl);\r\n window.addEventListener('resize', () => this.relayout());\r\n // 핫키 처리는 여기서 — provider 쪽에서 하면 HotkeysService 와 순환 의존이 된다\r\n this.hotkeys.hotkey$.subscribe(hotkey => {\r\n var _a, _b;\r\n if (hotkey === 'agentdeck-toggle') {\r\n this.config.store.agentDeck.enabled = !this.config.store.agentDeck.enabled;\r\n this.config.save();\r\n }\r\n if (hotkey === 'agentdeck-newline') {\r\n this.sendNewline();\r\n }\r\n if (hotkey === 'agentdeck-paste') {\r\n this.doPaste('hotkey');\r\n }\r\n if (hotkey === 'agentdeck-repair') {\r\n this.repair('all');\r\n }\r\n if (hotkey === 'agentdeck-view') {\r\n (_a = this.view) === null || _a === void 0 ? void 0 : _a.toggle();\r\n }\r\n // 처리를 여기서 하는 이유는 위와 같다 — provider 에서 HotkeysService 를 주입하면\r\n // 순환 의존이다(`hotkeys.ts` 주석). 선언만 그쪽에 있고 동작은 전부 이 파일이다\r\n if (hotkey === 'agentdeck-focus-list') {\r\n this.toggleKeyboardNav();\r\n }\r\n // 유닛 L 이 `hotkeys.ts` 에 선언만 하고 넘긴 것 — 처리는 여기서만 할 수 있다\r\n // (provider 에서 HotkeysService 를 주입하면 순환 의존이 된다, `hotkeys.ts` 주석)\r\n if (hotkey === 'agentdeck-view-mode') {\r\n (_b = this.view) === null || _b === void 0 ? void 0 : _b.toggleMode();\r\n }\r\n });\r\n // 경과 시간 갱신 + running -> idle 자동 복귀\r\n setInterval(() => this.tick(), 1000);\r\n this.relayout();\r\n this.render();\r\n this.diag(`setup done tabs=${this.app.tabs.length} enabled=${this.enabled} mainEl=${!!this.mainEl}`);\r\n // 개발/진단용 — devtools 나 CDP 에서 내부 상태를 들여다볼 수 있게 노출한다.\r\n //\r\n // **덮지 말고 합친다.** 다른 서비스도 여기에 자기 진단구를 붙이는데(`alert.service` 의\r\n // `alert`, `notify.service` 의 `tabIds`), 통째로 재할당하면 **우리보다 먼저 붙인 것이\r\n // 조용히 사라진다**. 실측(2026-09-08): notify 는 `init()` 즉시 붙고 이 코드는 `ready$`\r\n // 뒤에 도므로 `tabIds` 가 지워져 R18 이 \"진단구가 없다\" 로 판정됐다. alert 는 자기도\r\n // `ready$` 안에서 붙어 우연히 살아남았을 뿐이다.\r\n const g = window;\r\n g.__agentdeck = Object.assign((_a = g.__agentdeck) !== null && _a !== void 0 ? _a : {}, {\r\n app: this.app,\r\n config: this.config,\r\n status: this.status,\r\n relayout: () => this.relayout(),\r\n render: () => this.render(),\r\n /**\r\n * 검색·상태 필터를 코드에서 걸어 본다 (회귀용).\r\n *\r\n * 사람 손으로는 입력창에 치는 것이 유일한 경로인데, 프로브는 포커스·IME 조합을\r\n * 재현할 수 없어 화면 결과만 재려면 이 문이 필요하다. 입력창 값도 같이 맞춰 준다 —\r\n * 화면과 내부 상태가 어긋난 채로 판정하면 그 판정을 못 믿는다.\r\n */\r\n setFilter: (query, status) => {\r\n this.searchQuery = typeof query === 'string' ? query : '';\r\n this.statusFilter = status !== null && status !== void 0 ? status : null;\r\n if (this.searchEl) {\r\n this.searchEl.value = this.searchQuery;\r\n }\r\n this.syncSearchUi();\r\n this.render();\r\n return { query: this.searchQuery, status: this.statusFilter };\r\n },\r\n repair: (scope = 'all') => this.repair(scope),\r\n /**\r\n * 순서 재배열을 좌표 없이 시켜 본다 (회귀용) — **드롭과 같은 경로**(`applyReorder`)를 탄다.\r\n *\r\n * 드래그 자체는 합성 포인터로도 흉내낼 수 있다(document 리스너를 쓰고\r\n * `setPointerCapture` 를 쓰지 않는다 — tools/README 의 함정 목록 참고). 그래도 이 문을\r\n * 여는 이유는 **결과 검증**이다: 옮긴 뒤 `app.tabs` 가 어떻게 됐는지를 프로브가\r\n * 자기 사본으로 계산하지 않고 제품에게 물어야 한다.\r\n */\r\n reorder: (from, to, place = 'before') => {\r\n const before = [...this.app.tabs];\r\n const a = before[from];\r\n const b = before[to];\r\n if (!a || !b) {\r\n return { ok: false, reason: '없는 탭 인덱스', order: before.map((_, i) => i) };\r\n }\r\n // `place` 는 런타임에 아무 문자열이나 올 수 있다(프로브가 부르는 문이다). 검사하지\r\n // 않으면 `'atfer'` 같은 오타가 조용히 `before` 로 처리되어 **프로브가 재는 것과\r\n // 제품이 한 일이 어긋난다** — 회귀가 초록인데 규칙은 안 검증된 상태가 된다.\r\n if (place !== 'before' && place !== 'after') {\r\n return { ok: false, reason: `place 가 before/after 가 아니다: ${String(place)}`, order: before.map((_, i) => i) };\r\n }\r\n // **드래그가 막히는 조건은 여기서도 막아야 한다.** 이 진단구는 드래그를 좌표 없이\r\n // 재현하는 용도라, 게이트를 안 지나면 \"화면에서는 막히는데 진단구로는 된다\" 가 되어\r\n // 회귀가 게이트를 검증할 수 없다 (2026-09-09 실측: `sortByStatus` 를 켠 채로도\r\n // `ok: true` 가 나왔다). 상태순 정렬 중에는 옮겨도 다음 렌더에 제자리로 돌아간다.\r\n if (this.config.store.agentDeck.sortByStatus) {\r\n return {\r\n ok: false,\r\n reason: '상태순 정렬이 켜져 있어 순서를 바꿀 수 없다',\r\n order: before.map((_, i) => i),\r\n };\r\n }\r\n const ok = this.applyReorder(a, b, place);\r\n this.render();\r\n // 새 순서를 **옛 인덱스로** 적어 돌려준다 — `[1,0,2]` 면 0번과 1번이 자리를 바꿨다는 뜻\r\n return { ok, order: this.app.tabs.map(t => before.indexOf(t)) };\r\n },\r\n /**\r\n * **마지막** 드래그가 어떻게 끝났나 + 목록이 흐르는 축.\r\n *\r\n * `reorderDrag()` 와 따로 둔 이유 — 그쪽은 드래그가 끝나면 `null` 이 되고 회귀가 그\r\n * `null` 로 \"드래그 상태가 남지 않았다\" 를 판정한다(RO4). 끝난 뒤의 사유를 거기 얹으면\r\n * 그 계약이 깨진다.\r\n *\r\n * `flowsSideways` 를 여는 까닭은 프로브가 `sidebarDock` 으로 축을 **다시 계산**하지\r\n * 않게 하는 것이다 — 규칙 사본은 제품이 규칙을 바꿔도 옛 규칙으로 계속 초록이 된다.\r\n */\r\n lastDrag: () => ({\r\n end: this.lastDragEnd,\r\n flowsSideways: this.listFlowsSideways(),\r\n dock: this.dockSide,\r\n clickGuard: this.dragClickGuard,\r\n /**\r\n * 지금 목록이 스크롤되는 축 (null = 넘치지 않는다). 드래그 중이 아닐 때도 답한다 —\r\n * 회귀가 \"스크롤할 화면이 아니다\" 를 **실패가 아니라 판정 불가**로 적으려면\r\n * 그 사실을 제품에게 물어야 한다. 프로브가 도킹으로 다시 계산하면 규칙 사본이 된다.\r\n */\r\n scrollAxis: this.listScrollAxis(),\r\n autoScroll: this.config.store.agentDeck.dragAutoScroll,\r\n }),\r\n /** 지금 드래그 상태 — 삽입선이 어디를 가리키는지·취소가 먹었는지를 프로브가 되읽는다 */\r\n reorderDrag: () => {\r\n const d = this.drag;\r\n if (!d) {\r\n return null;\r\n }\r\n const axis = this.listScrollAxis();\r\n return {\r\n moved: d.moved,\r\n from: this.app.tabs.indexOf(d.tab),\r\n target: d.target ? { index: this.app.tabs.indexOf(d.target.tab), place: d.target.place } : null,\r\n line: !!d.line,\r\n /**\r\n * 자동 스크롤 상태. `axis` 는 제품이 고른 스크롤 축, `speed` 는 **지금 좌표에서**\r\n * 나오는 속도(0 = 스크롤할 이유 없음)다 — 회귀가 띠 판정·정지 조건을 제품 규칙으로\r\n * 되읽게 하려고 여는 것이다(임계 폭·속도표를 프로브가 베끼면 사본이 낡는다).\r\n * `active` 는 루프가 실제로 돌고 있나 = 타이머 잔여 판정의 근거.\r\n */\r\n scroll: {\r\n axis,\r\n active: !!d.scroll,\r\n speed: axis ? Math.round(this.dragScrollSpeed(axis)) : 0,\r\n px: Math.round(d.scrolled.px),\r\n at: { x: d.at.x, y: d.at.y },\r\n },\r\n };\r\n },\r\n /**\r\n * 키보드 내비게이션 상태를 **좌표 없이** 되읽는다 (회귀용).\r\n *\r\n * 이동 규칙은 여기서 다시 적지 않는다 — 키는 합성 이벤트로 실제 경로에 태울 수 있다:\r\n * `document.querySelector('.ad-list').dispatchEvent(new KeyboardEvent('keydown',`\r\n * ` { key: 'ArrowDown', bubbles: true }))`. 리스너가 그 엘리먼트에 걸려 있으므로\r\n * 사람이 누른 것과 같은 코드가 돈다. 그래서 이 문이 여는 것은 ① 지금 상태\r\n * ② 진입/해제(포커스는 CDP 로 주기 번거롭다) 두 가지뿐이다 — `groups()`·`judge()` 를\r\n * 연 것과 같은 이유로 규칙의 사본을 만들지 않는다.\r\n *\r\n * `activeTabIndex` 를 같이 주는 까닭 — **포커스와 선택이 갈렸는지**는\r\n * \"`index` 는 움직였는데 `activeTabIndex` 는 그대로\" 로만 확인할 수 있다.\r\n * `owner` 는 지금 키를 받는 주인이다: `list`/`search` 가 아니면 우리는 아무것도\r\n * 가로채지 않는다는 뜻이고, 그것이 \"터미널로 새지 않는다\" 의 반쪽 증거다.\r\n */\r\n focusNav: (op) => {\r\n var _a, _b;\r\n if (op === 'list') {\r\n this.focusList('keep');\r\n }\r\n if (op === 'search') {\r\n this.focusSearch();\r\n }\r\n if (op === 'off') {\r\n this.releaseKeyboard();\r\n }\r\n const all = this.app.tabs;\r\n const { rows, index } = this.navPlan();\r\n const desc = (r) => r.kind === 'head'\r\n ? { kind: 'head', key: r.key, tabIndex: -1 }\r\n : { kind: 'tab', key: null, tabIndex: all.indexOf(r.tab) };\r\n const active = document.activeElement;\r\n const ring = (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.querySelector('.ad-nav-focus');\r\n return {\r\n mode: this.navMode,\r\n index,\r\n count: rows.length,\r\n focused: this.navFocus ? desc(this.navFocus) : null,\r\n /** 화면에 보이는 순서 그대로 — 프로브가 `renderPlan` 을 재계산하지 않게 */\r\n rows: rows.map(desc),\r\n /** 지금 활성 탭 (= 선택). 이동으로 이 값이 움직이면 포커스 분리가 깨진 것이다 */\r\n activeTabIndex: this.app.activeTab ? all.indexOf(this.app.activeTab) : -1,\r\n /** 링이 실제로 그려진 줄 — DOM 이 상태를 따라왔는지 좌표 없이 본다 */\r\n ring: ring\r\n ? { tab: ring.classList.contains('ad-tab'), adIndex: (_b = ring.dataset.adIndex) !== null && _b !== void 0 ? _b : null }\r\n : null,\r\n owner: active === this.listEl ? 'list'\r\n : active === this.searchEl ? 'search'\r\n : (active === null || active === void 0 ? void 0 : active.className) || 'other',\r\n searchVisible: this.navSearchVisible(),\r\n wrap: !!this.config.store.agentDeck.keyboardNavWrap,\r\n enabled: this.config.store.agentDeck.keyboardNav !== false,\r\n };\r\n },\r\n view: () => this.view,\r\n openFile: (file) => { var _a; return (_a = this.view) === null || _a === void 0 ? void 0 : _a.openFile(file); },\r\n /**\r\n * 기동 때 하는 핫키 정리를 **다시 한 번** 돌린다.\r\n *\r\n * `ensurePasteHotkey` 는 `ready$` 안에서 딱 한 번 도는데, 그 안의 `claimCtrlV`\r\n * 게이트는 설정에 따라 갈리므로 회귀에서 양쪽 갈래를 재려면 재실행이 필요하다.\r\n * 하는 일이 \"핫키 테이블에서 Ctrl-V 를 빼는 것\" 뿐이라 여러 번 불러도 결과가 같다.\r\n */\r\n rescanPasteHotkey: () => this.ensurePasteHotkey(),\r\n /**\r\n * 지금 화면의 그룹 구성을 **제품 계산 그대로** 돌려준다 (`groupsFor` + `foldGroupKey`).\r\n *\r\n * 왜 여는가 — 검증 도구가 그룹 규칙(라벨 사전순·`기타` 를 맨 뒤·키 폴딩)을 사본으로\r\n * 들고 있으면 그 사본이 낡는다. `judge()`·`profiles()` 를 연 것과 같은 이유다.\r\n * `cwd` 를 같이 주는 이유는 따로 있다 — 그룹이 안 갈릴 때 원인이 \"캐시가 비었다\" 인지\r\n * \"폴딩이 합쳤다\" 인지 이것 없이는 가를 수 없다 (2026-09-08 GR6~GR14 가 그래서\r\n * `판정 불가` 로 9개 한꺼번에 빠졌다).\r\n */\r\n groups: () => {\r\n const all = this.app.tabs;\r\n // **화면과 같은 계산을 쓴다** — `render()` 와 공유하는 `renderPlan()`.\r\n // 여기서 규칙을 다시 적으면 그 사본이 낡는다(프로브가 헤더 생략 조건을\r\n // 재계산하던 것이 마지막 사본이었고, 그것을 없애려고 이 값을 연다).\r\n const rp = this.renderPlan();\r\n const idx = (g) => g.tabs.map(t => all.indexOf(t));\r\n return {\r\n cwdCache: all.map((t, i) => {\r\n var _a, _b, _c, _d, _e, _f, _g;\r\n return ({\r\n index: i,\r\n title: String((_a = t.title) !== null && _a !== void 0 ? _a : '').slice(0, 40),\r\n dir: (_c = (_b = this.cwdCache.get(t)) === null || _b === void 0 ? void 0 : _b.dir) !== null && _c !== void 0 ? _c : null,\r\n at: (_e = (_d = this.cwdCache.get(t)) === null || _d === void 0 ? void 0 : _d.at) !== null && _e !== void 0 ? _e : null,\r\n // 이 탭의 cwd 에서 찾아낸 프로젝트 루트 (`null` = 못 찾음 → cwd 자체가 키)\r\n projectRoot: (0, project_root_1.projectRootOf)((_g = (_f = this.cwdCache.get(t)) === null || _f === void 0 ? void 0 : _f.dir) !== null && _g !== void 0 ? _g : null),\r\n });\r\n }),\r\n // 지금까지 탐지해 둔 폴더→루트 — 그룹이 안 갈릴 때 \"탐지가 아직\" 인지\r\n // \"루트가 같아서\" 인지 이것 없이는 가를 수 없다 (cwd 를 같이 여는 것과 같은 이유)\r\n projectRoots: (0, project_root_1.projectRootCacheSnapshot)(),\r\n /**\r\n * 그룹 계산 결과 (헤더 생략과 무관하게 `groupsFor` 가 낸 것).\r\n *\r\n * `collapsed` 는 **설정에 저장된 값**이고 `collapsedEffective` 는 화면에\r\n * 실제로 접히는지다. 둘을 가른 이유 — 검색 중에는 매칭이 있는 접힌 그룹을\r\n * 임시로 펴 보이는데(`collapseReason: 'filter-open'`), `collapsed` 를 그\r\n * 유효값으로 바꿔 버리면 회귀 GR8·GR9(\"제품이 **저장값으로** 접힘이라\r\n * 판정하는가\")의 의미가 흔들린다.\r\n */\r\n list: rp.groups.map(g => ({\r\n key: g.key,\r\n label: g.label,\r\n collapsed: this.isGroupCollapsed(g.key),\r\n collapsedEffective: rp.collapseOf(g).collapsed,\r\n collapseReason: rp.collapseOf(g).reason,\r\n tabIndexes: idx(g),\r\n })),\r\n /** 헤더를 실제로 그리는가 — 이 조건을 프로브가 재계산하지 않게 연다 */\r\n withHeads: rp.withHeads,\r\n /** 실제 렌더 계획 (헤더 생략 시 평면 한 덩이). 화면 순서의 정답이다 */\r\n plan: rp.plan.map(g => ({\r\n key: g.key,\r\n label: g.label,\r\n // 화면 그대로 — 헤더를 안 그리면 접힘을 적용하지 않는다\r\n collapsed: rp.withHeads && rp.collapseOf(g).collapsed,\r\n collapseReason: rp.collapseOf(g).reason,\r\n tabIndexes: idx(g),\r\n })),\r\n /**\r\n * `render()` 가 실제로 줄을 그린 탭들의 `app.tabs` 인덱스\r\n * (`sortByStatus` 적용 후 + 검색·상태 필터 통과분).\r\n * 이게 없으면 검증 도구가 정렬을 끄고서만 그룹핑을 잴 수 있다 —\r\n * \"정렬 + 그룹핑\" 조합 화면이 회귀 대상에서 빠진다.\r\n */\r\n tabsUsedByRender: rp.visible.map(t => all.indexOf(t)),\r\n /** 집계 칩이 센 모집단 — 필터가 걸려도 전체다 (`render` 주석의 근거) */\r\n tabsForCounts: rp.tabs.map(t => all.indexOf(t)),\r\n /** 지금 걸린 검색·상태 필터 — 화면이 좁혀진 이유를 프로브가 되읽을 수 있게 */\r\n filter: { query: this.searchQuery, status: this.statusFilter, active: rp.filtering },\r\n sortByStatus: !!this.config.store.agentDeck.sortByStatus,\r\n fold: (k) => (0, group_1.foldGroupKey)(k),\r\n };\r\n },\r\n /**\r\n * 지난 세션 목록을 **제품 계산 그대로** 돌려준다 (`resumeRowsFor` + 원장 상태).\r\n *\r\n * `groups()` 와 같은 이유로 연다 — 검증 도구가 \"어느 세션이 어느 그룹에 붙나\" 를\r\n * 사본으로 재계산하면 그 사본이 낡는다. 화면에 그려졌는지는 프로브가 DOM\r\n * (`.ad-resume`)과 대조해 판정한다.\r\n */\r\n sessions: () => {\r\n const cfg = this.config.store.agentDeck;\r\n const rp = this.renderPlan();\r\n const live = this.liveSessionIds();\r\n const records = this.ledger.records();\r\n return {\r\n ledger: this.ledger.snapshot(),\r\n /** 원장+디스크를 합친 전체 (그룹 필터 전) */\r\n records: records.map(r => ({ ...r })),\r\n /** 지금 탭이 들고 있는 세션 */\r\n live: [...live.keys()],\r\n enabled: cfg.resumeList !== false,\r\n /** 그룹별로 실제 그릴 줄 — 화면 순서의 정답이다 */\r\n byGroup: rp.plan.map(g => ({\r\n key: g.key,\r\n label: g.label,\r\n expanded: this.isResumeExpanded(g.key),\r\n rows: (0, sessionLedger_1.resumeRowsFor)(records, {\r\n groupKeys: this.resumeKeysOf(g),\r\n keyOf: cwd => (0, group_1.groupKeyOf)(cwd, project_root_1.projectRootOf),\r\n fold: group_1.foldGroupKey,\r\n live,\r\n days: Number(cfg.resumeListDays) || 0,\r\n limit: Number(cfg.resumeListLimit) || 0,\r\n hidden: new Set(Array.isArray(cfg.resumeHidden) ? cfg.resumeHidden : []),\r\n now: Date.now(),\r\n }).map(r => ({ sessionId: r.sessionId, label: r.label, cwd: r.cwd,\r\n lastStatus: r.lastStatus, openTabId: r.openTabId })),\r\n })),\r\n };\r\n },\r\n /** 원장 스캔을 지금 한 번 돌린다 (프로브가 기다릴 수 있게 Promise 를 준다) */\r\n rescanSessions: () => this.ledger.refresh(true),\r\n // 에이전트 판정 상태 — 진단 로그는 값이 바뀔 때만 찍히므로 \"조회가 돌았는지\" 를\r\n // 로그만으로는 가를 수 없다 (2026-09-08 검증 중 실제로 막혔다)\r\n debug: () => ({ outputHits: this.outputHits, decorator: this.status.debug }),\r\n /**\r\n * 화면 판정을 **제품과 같은 규칙으로** 돌려준다 (`judgeScreen`).\r\n *\r\n * 검증 도구가 규칙을 복사해 가지면 그 사본이 낡는다 — `tools/verdict.js` 가 이미\r\n * 그래서 \"규칙을 고치면 양쪽을 같이 고칠 것\" 이라는 주석을 달고 있다. 프로브는\r\n * 복사 대신 이걸 부른다(2026-09-08: 단순화한 사본이 fakebox 화면을 깨진 것으로\r\n * 잘못 읽어 R2·R14 가 거짓 실패했다).\r\n */\r\n /**\r\n * 에이전트 프로필을 **제품 모듈 그대로** 돌려준다.\r\n *\r\n * 왜 필요한가 — 검증 도구가 프로필을 보려면 방법이 두 가지뿐이었다: 값을 복사해 갖거나\r\n * `.tmp/agents.js`(= `npm test` 컴파일 산출물)를 require 하거나. 전자는 사본이 낡고\r\n * (`tools/verdict.js` 가 이미 그 문제를 주석으로 달고 있다), 후자는 `npm test` 를 한 번도\r\n * 안 돌렸으면 파일이 없고 돌렸어도 `src` 보다 낡을 수 있다 — 관측 도구가 낡은 값을 보고\r\n * \"프로필이 이렇다\" 고 말하는 것이 가장 나쁜 결과다 (2026-09-08 유닛 M 지적).\r\n *\r\n * 정규식은 JSON 으로 나가지 않으므로 `source`/`flags` 로 펼쳐서 준다.\r\n */\r\n profiles: () => {\r\n const dump = (p) => {\r\n var _a, _b;\r\n return ({\r\n id: p.id,\r\n label: p.label,\r\n processHints: p.processHints,\r\n titleHints: p.titleHints,\r\n waitingPatterns: p.waitingPatterns.map(r => ({ source: r.source, flags: r.flags })),\r\n busyPatterns: p.busyPatterns.map(r => ({ source: r.source, flags: r.flags })),\r\n busyTitleMarks: p.busyTitleMarks,\r\n imagePasteKey: p.imagePasteKey,\r\n promptHeads: p.promptHeads,\r\n promptShape: (_a = p.promptShape) !== null && _a !== void 0 ? _a : null,\r\n screenShape: (_b = p.screenShape) !== null && _b !== void 0 ? _b : null,\r\n patternsProven: p.patternsProven,\r\n });\r\n };\r\n return {\r\n list: agents_1.AGENT_PROFILES.map(dump),\r\n union: dump((0, agents_1.unionProfile)()),\r\n // 판정에 실제로 쓰이는 형태 — 실측 없는 프로필은 문구가 합집합으로 떨어진다\r\n effective: agents_1.AGENT_PROFILES.map(p => dump((0, agents_1.detectProfileFor)(p.id))),\r\n // 식별도 **제품 함수 그대로** 부를 수 있게 열어 둔다 — 관측 도구가 판정 순서\r\n // (claude 를 맨 뒤에 두는 규칙)를 복사해 갖지 않도록\r\n identify: (processNames, title) => (0, agents_1.identifyAgent)(processNames, title),\r\n /**\r\n * 실측 없는 프로필의 안전장치가 실제로 작동하는지 — **판정을 여기서 한다.**\r\n *\r\n * 그 판정의 기준은 \"합집합과 **같은 배열 객체**(`===`)\" 인데, 진단구는 정규식을\r\n * JSON 으로 펼쳐 주므로 밖에서는 동일성을 볼 수 없다. 관측 도구가 내용 비교로\r\n * 대신하면 \"우연히 같은 내용\" 과 \"실제로 같은 객체\" 를 못 가른다 —\r\n * 그래서 제품 안에서 확인한 결과만 boolean 으로 넘긴다 (2026-09-08).\r\n */\r\n fallback: agents_1.AGENT_PROFILES.map(p => {\r\n const eff = (0, agents_1.detectProfileFor)(p.id);\r\n const u = (0, agents_1.unionProfile)();\r\n return {\r\n id: p.id,\r\n patternsProven: p.patternsProven,\r\n // 실측 없는 프로필: 화면 문구 셋이 합집합 **그 객체** 여야 한다\r\n usesUnionPatterns: eff.waitingPatterns === u.waitingPatterns\r\n && eff.busyPatterns === u.busyPatterns\r\n && eff.busyTitleMarks === u.busyTitleMarks,\r\n // 실측 있는 프로필: 자기 배열을 그대로 써야 한다\r\n usesOwnPatterns: eff.waitingPatterns === p.waitingPatterns\r\n && eff.busyPatterns === p.busyPatterns\r\n && eff.busyTitleMarks === p.busyTitleMarks,\r\n shapesDropped: !eff.promptShape && !eff.screenShape,\r\n // 좁히지 않는 것은 화면 문구뿐 — 실측된 값은 프로필 것을 유지한다\r\n imagePasteKeyKept: eff.imagePasteKey === p.imagePasteKey,\r\n catchesClaudeBusy: eff.busyPatterns.some(r => r.test('esc to interrupt')),\r\n };\r\n }),\r\n };\r\n },\r\n judge: (pane) => {\r\n var _a;\r\n const target = pane !== null && pane !== void 0 ? pane : this.focusedPane();\r\n const read = target ? this.readScreen(target) : null;\r\n if (!read) {\r\n return null;\r\n }\r\n return {\r\n ...(0, screen_1.judgeScreen)(read.lines, read.cols, (_a = this.profileForPane(target)) === null || _a === void 0 ? void 0 : _a.screenShape),\r\n cols: read.cols,\r\n };\r\n },\r\n agentOf: (tab) => {\r\n var _a, _b, _c, _d, _e;\r\n const root = tab !== null && tab !== void 0 ? tab : this.app.activeTab;\r\n const pane = root ? this.firstPane(root) : undefined;\r\n const observed = pane ? this.paneAgents.get(pane) : undefined;\r\n return root\r\n ? {\r\n id: (_a = this.tabAgents.get(root)) !== null && _a !== void 0 ? _a : null,\r\n effectiveId: pane ? (_c = (_b = this.profileForPane(pane)) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : 'unknown' : 'unknown',\r\n streamId: (observed === null || observed === void 0 ? void 0 : observed.session) === (pane === null || pane === void 0 ? void 0 : pane.session) ? (_d = observed === null || observed === void 0 ? void 0 : observed.tracker.id) !== null && _d !== void 0 ? _d : null : null,\r\n probedAt: (_e = this.agentProbedAt.get(root)) !== null && _e !== void 0 ? _e : 0,\r\n }\r\n : null;\r\n },\r\n probeAgent: (tab) => {\r\n const root = tab !== null && tab !== void 0 ? tab : this.app.activeTab;\r\n if (root) {\r\n this.agentProbedAt.delete(root);\r\n void this.probeAgent(root, 'manual');\r\n }\r\n },\r\n kickLog: (0, diag_1.diagMemory)(),\r\n /**\r\n * 진단 묶음을 만들고 경로를 돌려준다 — 설정 창의 \"진단 로그 모으기\" 와 같은 동작.\r\n * 콘솔에서 쓰는 경로도 남겨 두는 이유: 설정 창을 열 수 없을 만큼 깨진 상태에서도 채증이 돼야 한다\r\n */\r\n /**\r\n * 진단 로그가 **지금 어디에 쓰이는지** 알려준다.\r\n *\r\n * 검증 도구가 `os.homedir()` 로 경로를 만들어 두면, 격리 인스턴스가 자기 폴더에\r\n * 쓰기 시작한 순간(`AGENTDECK_DIAG_DIR`, `diag.ts` 의 `logDir`) 남의 파일을 읽고\r\n * \"아무 줄도 안 남았다\" 로 거짓 실패한다 — 2026-09-09 에 IN9·PR4·PR5 가 그렇게\r\n * 한꺼번에 뒤집혔다. 경로는 제품에게 물어야 한다.\r\n */\r\n diagPaths: () => ({ diag: diag_1.DIAG_PATH, prev: diag_1.DIAG_PREV_PATH, screen: diag_1.SCREEN_PATH }),\r\n collectDiag: (includeScreen = false) => {\r\n var _a, _b, _c, _d;\r\n return (0, diag_1.collectDiagBundle)({\r\n includeScreen,\r\n stamp: {\r\n tabby: (_b = (_a = this.platform).getAppVersion) === null || _b === void 0 ? void 0 : _b.call(_a),\r\n osRelease: (_d = (_c = this.platform).getOSRelease) === null || _d === void 0 ? void 0 : _d.call(_c),\r\n config: (0, diag_1.configStamp)(this.config.store),\r\n },\r\n });\r\n },\r\n });\r\n }\r\n // ---------- 화면 복구 ----------\r\n /**\r\n * 깨진 화면을 사람이 직접 되살린다 — 창을 복원→최대화로 흔드는 것을 코드로 대신한다.\r\n *\r\n * 자동 경로(`watchSize`)는 \"xterm 과 pty 의 크기가 어긋났다\" 를 보고 고치는데, 그 감시는\r\n * 탭이 열리고 `sizeWatchMs`(기본 6초) 동안만 돈다. 그 뒤에 깨지는 경우가 남는다 —\r\n * 두 크기는 서로 맞는데 **TUI 가 들고 있는 프레임만** 옛것인 상황이다. 크기가 이미 같으니\r\n * 커널은 SIGWINCH 를 내지 않고, 앱은 다시 그릴 이유를 영영 못 받는다. 증상은\r\n * \"statusline 이 사라지고 입력창 구분선이 중간에서 끊긴다\" (2026-09-01 실측).\r\n *\r\n * 그래서 복구는 크기를 맞추는 것으로 끝내지 않고 **항상 한 번 흔든다**(`nudgePtyRedraw`).\r\n * 어긋남이 없어도 무해하다 — 폭이 한 칸 줄었다 돌아올 뿐이고 xterm 은 건드리지 않는다.\r\n *\r\n * @param scope `active` = 지금 보고 있는 탭만, `all` = 열려 있는 모든 탭\r\n */\r\n repair(scope = 'all') {\r\n const targets = scope === 'active' && this.app.activeTab\r\n ? [this.app.activeTab]\r\n : this.app.tabs;\r\n this.diag(`repair scope=${scope} tabs=${targets.length}`);\r\n // 1) 사이드바 폭부터 다시 잰다 — 어긋남의 출발점이 대개 여기다\r\n this.relayout();\r\n // 2) 레이아웃이 실제로 반영된 다음에 재야 한다 (scheduleRefit 과 같은 이유로 두 프레임)\r\n requestAnimationFrame(() => requestAnimationFrame(() => {\r\n for (const tab of targets) {\r\n const anyTab = tab;\r\n const panes = typeof anyTab.getAllTabs === 'function'\r\n ? anyTab.getAllTabs()\r\n : [tab];\r\n for (const pane of panes) {\r\n this.repairPane(pane);\r\n }\r\n }\r\n }));\r\n }\r\n /**\r\n * 복구 한 pane 분 — **화면을 지우고 앱에게 처음부터 다시 그리게 한다.**\r\n *\r\n * 흔들기(`nudgePtyRedraw`)만으로는 안 고쳐지는 경우가 실제로 있다(2026-09-01 유저 확인).\r\n * 이유는 흔들기가 고치는 대상이 하나뿐이라서다 — 그건 \"앱이 폭을 잘못 알고 있다\" 를 푼다.\r\n * 그런데 깨진 화면에는 그 말고도 두 가지가 더 얹혀 있다.\r\n *\r\n * - **xterm 쪽 잔상**: 옛 폭으로 그려진 글자가 셀에 그대로 남아 있다. 앱이 다시 그려도\r\n * 앱은 자기가 쓴 자리만 덮으므로, 그 바깥(옛 프레임의 오른쪽·아래)은 영영 안 지워진다.\r\n * - **터미널 상태**: 스크롤 영역(DECSTBM)·줄바꿈 모드·속성이 옛 크기 기준으로 잡혀 있으면\r\n * 새로 그린 것까지 어긋난 자리에 들어간다.\r\n *\r\n * 그래서 순서가 있다 — ① 크기를 맞추고 ② `reset()` 으로 터미널 상태와 화면을 비우고\r\n * ③ 그래도 앱은 자기가 이미 그렸다고 믿고 있으니 흔들어 SIGWINCH 를 주고\r\n * ④ 마지막으로 `Ctrl+L`(0x0C) 을 보내 \"전부 다시 그려라\" 를 명시로 시킨다.\r\n * ③ 만으로 부족했던 이유가 ①②④ 가 빠져서였다.\r\n *\r\n * `reset()` 은 스크롤백을 함께 지운다. 지난 대화를 남기고 싶으면 `repairHard: false` —\r\n * 그때는 예전처럼 크기 정합 + 흔들기까지만 한다.\r\n */\r\n repairPane(pane) {\r\n var _a, _b, _c, _d, _e, _f, _g;\r\n const cfg = this.config.store.agentDeck;\r\n const anyPane = pane;\r\n const frontend = anyPane.frontend;\r\n const xterm = frontend === null || frontend === void 0 ? void 0 : frontend.xterm;\r\n // 숨겨진 탭은 컨테이너 폭이 0 이라 fit 하면 1열로 줄어든다 — 크기는 건드리지 않고\r\n // 다시 선택될 때 Tabby 가 재측정하게 둔다\r\n const host = (_a = xterm === null || xterm === void 0 ? void 0 : xterm.element) === null || _a === void 0 ? void 0 : _a.parentElement;\r\n if (!(host === null || host === void 0 ? void 0 : host.clientWidth) || !(host === null || host === void 0 ? void 0 : host.clientHeight)) {\r\n return;\r\n }\r\n const before = this.readScreen(pane);\r\n const beforeVerdict = before ? (0, screen_1.judgeScreen)(before.lines, before.cols, (_b = this.profileForPane(pane)) === null || _b === void 0 ? void 0 : _b.screenShape) : null;\r\n this.snapshot(pane, `manual-before ${beforeVerdict\r\n ? (beforeVerdict.broken ? beforeVerdict.reasons.join(' / ') : '판정=정상')\r\n : '읽을 수 없음'}`);\r\n // ① 크기 정합 — 여기가 어긋나 있으면 뒤 단계가 전부 헛돈다\r\n try {\r\n (_d = (_c = frontend === null || frontend === void 0 ? void 0 : frontend.fitAddon) === null || _c === void 0 ? void 0 : _c.fit) === null || _d === void 0 ? void 0 : _d.call(_c);\r\n }\r\n catch {\r\n // 아직 붙는 중이다 — 아래 단계만이라도 태운다\r\n }\r\n this.syncPtySize(pane, frontend);\r\n // ② 잔상 지우기 — 입력창 영역만 비운다 (대화는 남는다)\r\n if (before) {\r\n this.clearInputArea(pane, before);\r\n }\r\n // ②-b 그래도 안 되면 터미널 상태까지 초기화 (스크롤백이 날아가므로 기본은 끔)\r\n if (cfg.repairHard === true) {\r\n try {\r\n (_e = xterm === null || xterm === void 0 ? void 0 : xterm.reset) === null || _e === void 0 ? void 0 : _e.call(xterm);\r\n }\r\n catch {\r\n // 프론트엔드가 막 떨어졌다\r\n }\r\n }\r\n try {\r\n (_f = xterm === null || xterm === void 0 ? void 0 : xterm.refresh) === null || _f === void 0 ? void 0 : _f.call(xterm, 0, ((_g = xterm.rows) !== null && _g !== void 0 ? _g : 1) - 1);\r\n }\r\n catch { }\r\n // ③ 크기가 이미 맞아도 무조건 흔든다 — 이 함수를 부르는 이유 자체가 \"맞는데 깨졌다\" 다\r\n this.nudgePtyRedraw(pane);\r\n // ④ `Ctrl+L` — **기본으로 보내지 않는다** (`repairSendRedrawKey` 기본 끔).\r\n // Claude Code 가 이걸 \"화면 지우기\" 로 받아 보고 있던 대화를 스크롤백으로 밀어내는 것을\r\n // 2026-09-11 채증으로 확정했다(`sendRedrawKey` 주석). ①~③ 이 이미 고치므로 없어도 된다.\r\n // 켜 둔 경우에만 보내고, 흔들기가 도착한 뒤여야 하므로 nudge 되돌리기(60ms)보다 뒤에 둔다.\r\n if (cfg.repairSendRedrawKey === true) {\r\n setTimeout(() => this.sendRedrawKey(pane), REPAIR_REDRAW_DELAY_MS);\r\n }\r\n // ⑤ 채증 — \"↻ 를 눌렀는데 안 고쳐진다\" 를 감이 아니라 파일로 가른다.\r\n // 누른 직후와 다시 그려진 뒤를 짝으로 남긴다.\r\n setTimeout(() => {\r\n var _a;\r\n const after = this.readScreen(pane);\r\n const still = after ? (0, screen_1.judgeScreen)(after.lines, after.cols, (_a = this.profileForPane(pane)) === null || _a === void 0 ? void 0 : _a.screenShape) : null;\r\n this.snapshot(pane, `manual-after ${still ? (still.broken ? '아직 깨짐: ' + still.reasons.join(' / ') : '복구됨') : '읽을 수 없음'}`);\r\n }, SNAP_AFTER_MS);\r\n }\r\n /**\r\n * `Ctrl+L`(0x0C) 을 보낸다 — **기본 경로가 아니다** (`repairSendRedrawKey`, 기본 끔).\r\n *\r\n * **\"거의 모든 TUI 가 이걸 전체 재렌더로 받는다\" 는 틀린 전제였다** (2026-09-11 채증으로 확정).\r\n * Claude Code 는 이걸 **화면 지우기**로 받는다 — 지운 뒤 자기 입력창만 다시 그리므로\r\n * 보고 있던 대화가 통째로 스크롤백으로 밀려난다. `.agentdeck-screen.log` 06:04:52→54 의\r\n * `manual-before`(0~77행 전부 내용) → `manual-after`(73~77행만 남음) 가 그 증거이고,\r\n * `clear input area row=73/78` 이 73행 아래만 지웠음을 진단 로그가 확인해 준다.\r\n * 즉 0~72행을 날린 것은 우리 지우기가 아니라 이 키다.\r\n *\r\n * 그래서 복구의 기본 수단은 이 키가 아니라 **잔상 지우기 + 크기 정합/흔들기**다.\r\n * 자세한 근거와 켜는 기준은 `config.ts` 의 `repairSendRedrawKey` 주석에 있다.\r\n */\r\n sendRedrawKey(pane) {\r\n var _a;\r\n const anyPane = pane;\r\n if (typeof anyPane.sendInput !== 'function' || !((_a = anyPane.session) === null || _a === void 0 ? void 0 : _a.open)) {\r\n return;\r\n }\r\n this.diag(`repair redraw-key ctrl-l`);\r\n // 사람이 ↻ 를 누른 경로라 조합 중일 일은 사실상 없지만, pty 직접 쓰기는 예외 없이\r\n // 한 진입점을 지나게 둔다 — 세션이 막 닫혔을 때의 예외도 sendToPane 이 삼킨다.\r\n this.sendToPane(anyPane, 'redraw-key', () => anyPane.sendInput('\\x0c'));\r\n }\r\n /**\r\n * 입력창 영역에 남은 **옛 프레임 잔상만** 지운다 (대화 = 스크롤백은 그대로 둔다).\r\n *\r\n * 복구가 계속 실패하던 진짜 이유가 여기 있었다 (2026-09-02 실측).\r\n * `nudge` 도 `Ctrl+L` 도 하는 일은 \"앱아 다시 그려라\" 뿐인데, **앱은 자기가 쓰는 자리만 덮는다.**\r\n * 그래서 옛 폭으로 그려진 줄이 `❯` 자리를 차지하고 있으면 아무도 그걸 못 지운다 —\r\n * 채증 원문이 그 모양이었다 (`.agentdeck-screen.log` 06:02:27):\r\n *\r\n * 72 len=275 \" \" ← 위 테두리가 있어야 할 자리, 공백\r\n * 73 len=276 \"────…\" ← ❯ 자리에 옛 프레임(276) 잔상\r\n * 74 len=277 \"────…\" ← 앱이 새로 그린 아래 테두리(277, 정상)\r\n *\r\n * 앱은 이미 277 로 제대로 그리고 있는데 73 행 잔상 때문에 계속 깨짐으로 남았다.\r\n * `auto-after 아직 깨짐` 이 두 번 연속 찍힌 게 이것이다.\r\n *\r\n * 그래서 **터미널 쪽에서 직접 지운다** — 입력창 첫 테두리 행으로 커서를 옮기고\r\n * `ESC[J`(커서부터 화면 끝까지)로 비운다. 이건 화면만 비우고 스크롤백은 건드리지 않으므로\r\n * `xterm.reset()`(스크롤백까지 날아감)과 다르다. 커서는 `ESC7`/`ESC8` 로 저장·복원해\r\n * 앱이 들고 있는 커서 위치와 어긋나지 않게 한다. 지운 뒤 `Ctrl+L` 을 보내면 앱이\r\n * 자기 UI 를 그 빈 자리에 다시 그린다.\r\n */\r\n clearInputArea(pane, read) {\r\n var _a, _b, _c;\r\n if (!(0, terminalInput_1.canRepairComposer)((_a = this.profileForPane(pane)) === null || _a === void 0 ? void 0 : _a.id)) {\r\n return false;\r\n }\r\n const xterm = (_b = pane.frontend) === null || _b === void 0 ? void 0 : _b.xterm;\r\n if (!xterm || typeof xterm.write !== 'function') {\r\n return false;\r\n }\r\n const lines = read.lines;\r\n const shape = (_c = this.profileForPane(pane)) === null || _c === void 0 ? void 0 : _c.screenShape;\r\n // 하단 INPUT_TAIL 행 안에서만 본다 — 대화 이력에 남아 있는 옛 입력창까지 지우면 안 된다\r\n const from = Math.max(0, lines.length - screen_1.INPUT_TAIL);\r\n // **잔상이 얹힌 테두리도 테두리로 친다.** 2026-09-09 실사용 스샷의 위 테두리가 바로\r\n // 그 모양이었는데(가로선 사이에 전각 글자 3개), 순수 가로선만 찾던 옛 코드는 이 행을\r\n // 못 보고 시작행을 아래 테두리로 잡아 **입력창 아래**를 지웠다 — 잔상은 그대로 남는다.\r\n const border = (i) => (0, screen_1.isRuleRow)(lines[i].text, shape) || (0, screen_1.isGhostRuleRow)(lines[i].text, read.cols, shape);\r\n let last = -1;\r\n for (let i = lines.length - 1; i >= from; i--) {\r\n if (border(i)) {\r\n last = i;\r\n break;\r\n }\r\n }\r\n if (last < 0) {\r\n return false;\r\n }\r\n // 마지막 테두리에서 위로 INPUT_BLOCK_ROWS 행까지 같은 입력창 블록으로 본다\r\n let start = last;\r\n for (let i = last - 1; i >= Math.max(from, last - INPUT_BLOCK_ROWS); i--) {\r\n if (border(i)) {\r\n start = i;\r\n }\r\n }\r\n const row = start + 1;\r\n this.diag(`clear input area row=${row}/${lines.length}`);\r\n try {\r\n xterm.write(`\u001b7\u001b[${row};1H\u001b[J\u001b8`);\r\n }\r\n catch {\r\n return false;\r\n }\r\n return true;\r\n }\r\n // ---------- 화면 깨짐 자동 감지 ----------\r\n /**\r\n * 출력이 잠잠해지면 화면이 온전한지 본다.\r\n *\r\n * TUI 는 한 프레임을 여러 번의 write 로 그리므로, 그리는 도중에 읽으면 멀쩡한 화면도\r\n * 깨져 보인다. 그래서 마지막 출력에서 `SCREEN_CHECK_DEBOUNCE_MS` 만큼 조용해진 뒤에만 본다.\r\n */\r\n scheduleScreenCheck(pane) {\r\n // 감지·채증은 복구와 분리한다 — `autoRepairScreen` 이 꺼져 있어도 관측은 계속한다.\r\n // (2026-09-02: 이 게이트가 채증까지 막아 실사용 재현이 통째로 증거 없이 지나갔다)\r\n if (!this.screenObservingEnabled()) {\r\n return;\r\n }\r\n const prev = this.screenCheckTimers.get(pane);\r\n if (prev) {\r\n clearTimeout(prev);\r\n }\r\n this.screenCheckTimers.set(pane, setTimeout(() => {\r\n this.screenCheckTimers.delete(pane);\r\n this.checkScreen(pane);\r\n }, SCREEN_CHECK_DEBOUNCE_MS));\r\n }\r\n /** 감지·채증이 켜져 있나 — 복구(`autoRepairScreen`)와는 별개다 */\r\n screenObservingEnabled() {\r\n const cfg = this.config.store.agentDeck;\r\n return cfg.screenWatch !== false || !!cfg.autoRepairScreen;\r\n }\r\n /** 화면을 판정해 채증하고, 복구가 켜져 있으면 조용히 고친다 */\r\n checkScreen(pane) {\r\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;\r\n // 2026-09-13: real logs misclassified Codex's \"─ Worked for 1m 29s ─\"\r\n // as a damaged Claude border and ran auto-repair. Do not diagnose or\r\n // mutate another agent's screen using Claude's composer geometry.\r\n if (!(0, terminalInput_1.canRepairComposer)((_a = this.profileForPane(pane)) === null || _a === void 0 ? void 0 : _a.id)) {\r\n return;\r\n }\r\n const cfg = this.config.store.agentDeck;\r\n const read = this.readScreen(pane);\r\n if (!read) {\r\n return;\r\n }\r\n const verdict = (0, screen_1.judgeScreen)(read.lines, read.cols, (_b = this.profileForPane(pane)) === null || _b === void 0 ? void 0 : _b.screenShape);\r\n // ---- 관측 (복구와 무관하게 항상) ----\r\n // 상태가 바뀔 때만 남긴다 — 2초마다 도는 그물이라 매번 찍으면 파일이 같은 줄로 찬다.\r\n const prevObs = this.screenObs.get(pane);\r\n const reason = verdict.reasons.join(' / ');\r\n // 같은 깨짐이 몇 번 연속으로 보였나 — TUI 가 한 프레임을 여러 write 로 그리는 도중을\r\n // 잡으면 멀쩡한 화면도 한 번은 깨져 보인다. 그 중간 프레임에 손대지 않으려고 센다.\r\n const streak = verdict.broken ? (((prevObs === null || prevObs === void 0 ? void 0 : prevObs.broken) ? ((_c = prevObs.streak) !== null && _c !== void 0 ? _c : 0) : 0) + 1) : 0;\r\n const changed = !prevObs || prevObs.broken !== verdict.broken || prevObs.reason !== reason;\r\n this.screenObs.set(pane, { broken: verdict.broken, reason, streak });\r\n if (changed) {\r\n if (verdict.broken) {\r\n this.snapshot(pane, `detect 깨짐 ${reason}`);\r\n }\r\n else if (prevObs === null || prevObs === void 0 ? void 0 : prevObs.broken) {\r\n // 우리가 아무것도 안 했는데 스스로 돌아왔다 — 트리거를 가르는 중요한 단서다\r\n this.snapshot(pane, 'detect 스스로 복구됨');\r\n }\r\n }\r\n if (!verdict.broken) {\r\n this.refillAutoRepairBudget(pane);\r\n return;\r\n }\r\n // 깨진 동안은 온전 시계를 접어 둔다 — 깨짐↔복구가 번갈아 오는 화면에서\r\n // 옛 시각이 남아 있으면 다음 온전 샘플 한 번에 예산이 되살아난다\r\n this.autoRepairHealthySince.delete(pane);\r\n if (!cfg.autoRepairScreen) {\r\n return;\r\n }\r\n // 한 번 스친 중간 프레임은 건드리지 않는다 — 2초 그물이므로 기본값 2 는 \"2초 넘게\r\n // 깨진 채로 있다\" 는 뜻이다. 예전에 자동복구가 타이핑 중에 튀어나와 체감을 망친 것이\r\n // 이 조건이 없어서였다 (2026-09-02 항목 27).\r\n if (streak < ((_d = cfg.autoRepairMinStreak) !== null && _d !== void 0 ? _d : 2)) {\r\n return;\r\n }\r\n const anyPane = pane;\r\n const now = Date.now();\r\n const last = (_e = this.autoRepairAt.get(pane)) !== null && _e !== void 0 ? _e : 0;\r\n const count = (_f = this.autoRepairCount.get(pane)) !== null && _f !== void 0 ? _f : 0;\r\n const max = (_g = cfg.autoRepairMaxPerTab) !== null && _g !== void 0 ? _g : 5;\r\n const cooldown = (_h = cfg.autoRepairCooldownMs) !== null && _h !== void 0 ? _h : 4000;\r\n // 쿨다운/한도에 걸려 아무것도 하지 않을 때는 로그도 남기지 않는다 —\r\n // 주기 검사가 2초마다 돌므로 판정이 오탐이면 진단 파일이 같은 줄로 가득 찬다\r\n if (now - last < cooldown) {\r\n return;\r\n }\r\n if (max > 0 && count >= max) {\r\n this.diagOnce(`auto-repair-cap`, `screen auto-repair 한도 도달 (${count}/${max}) — 더 고치지 않는다.`\r\n + ` 사이드바 ↻ 로 직접 복구할 것. 마지막 판정: ${verdict.reasons.join(' / ')}`);\r\n return;\r\n }\r\n // **크기가 어긋난 동안에는 손대지 않는다.**\r\n //\r\n // 오늘(2026-09-09) 실사용 채증 8건을 갈라 보니 정확히 둘로 나뉜다 —\r\n // ⓐ `xterm.cols != pty(sent)` 인 4건(00:46:54 280/283 · 01:13:20 281/279 ·\r\n // 01:59:08 221/281 · 02:34:21 282/280)은 전부 **리사이즈 중간 프레임**이었다.\r\n // 화면 덤프는 앱 기준으로 완전히 정상이고(`──(283)/❯/──(283)`) 0~3초 만에\r\n // **스스로** 돌아왔다 — Tabby 순정이 pty 까지 맞춘다.\r\n // ⓑ 크기가 맞는(281==281) 4건(02:07:45~02:08:01)은 그 탭에서 띄운 자식 프로세스의\r\n // stdout(`(node:…) DeprecationWarning`, `Unable to find latest version on Keygen`)이\r\n // TUI 프레임을 덮어쓴 **진짜 깨짐**이고 26초를 버텼다. 이쪽만 잔상 지우기로 고쳐진다.\r\n //\r\n // 2026-09-02 에 자동복구를 껐던 이유(`fit`+`nudge` 로 실사용 4/4 실패, 화면만 흔들림)가\r\n // 바로 ⓐ 에 손을 댄 것이었다. 그래서 그 유형은 아예 건드리지 않는다 — 감지·채증은 계속한다.\r\n const xterm = (_j = anyPane.frontend) === null || _j === void 0 ? void 0 : _j.xterm;\r\n const xcols = xterm === null || xterm === void 0 ? void 0 : xterm.cols;\r\n const xrows = xterm === null || xterm === void 0 ? void 0 : xterm.rows;\r\n if (!(0, screen_1.sizeInSync)(xcols, xrows, (_k = anyPane.size) === null || _k === void 0 ? void 0 : _k.columns, (_l = anyPane.size) === null || _l === void 0 ? void 0 : _l.rows)) {\r\n this.diagOnce('auto-repair-resizing', `screen 자동복구 보류 — 크기가 어긋나 있다 (xterm ${xcols}x${xrows}`\r\n + ` vs pty ${(_m = anyPane.size) === null || _m === void 0 ? void 0 : _m.columns}x${(_o = anyPane.size) === null || _o === void 0 ? void 0 : _o.rows}). 리사이즈 중간 프레임은`\r\n + ` 순정이 곧 맞춘다 — 이 줄은 처음 한 번만 남긴다`);\r\n return;\r\n }\r\n this.diag(`screen BROKEN cols=${read.cols}`\r\n + ` sent=${(_p = anyPane.size) === null || _p === void 0 ? void 0 : _p.columns}x${(_q = anyPane.size) === null || _q === void 0 ? void 0 : _q.rows} ${verdict.reasons.join(' / ')}`);\r\n // 고치기 **전에** 화면 원문을 남긴다 — 복구가 덮어쓰면 증거가 사라진다\r\n this.snapshot(pane, `auto-before ${verdict.reasons.join(' / ')}`);\r\n this.autoRepairAt.set(pane, now);\r\n this.autoRepairCount.set(pane, count + 1);\r\n this.diag(`screen auto-repair #${count + 1}`);\r\n // 자동 경로가 하는 일은 **사이드바 ↻ 를 한 번 눌러 주는 것**뿐이다 —\r\n // 잔상 지우기(`clearInputArea`) → `Ctrl+L`. 크기는 위 가드에서 이미 맞다고 확인했으니\r\n // `fit`·`syncPtySize`·`nudgePtyRedraw` 는 태우지 않는다. 그 셋이 화면을 흔들어\r\n // 체감을 망친 범인이었다(\"최대화됐다 다시 깨지네\", 2026-09-02).\r\n // 스크롤백을 지우는 hard 복구도 하지 않는다 — 자동 경로에서 오탐 한 번에 지난 대화가\r\n // 날아가면 손해가 크다(`repairHard` 는 사람이 켤 때만).\r\n //\r\n // 잔상을 지우면 앱이 **자기 렌더 주기에** 그 자리를 다시 그린다 — 앱은 자기가 쓰는\r\n // 자리만 덮으므로, 지우지 않으면 옛 줄이 `❯` 자리를 계속 차지한다.\r\n // `Ctrl+L` 로 재렌더를 재촉하던 것은 기본에서 뺐다 — Claude Code 가 그걸 화면 지우기로\r\n // 받아 대화를 밀어냈다(`sendRedrawKey` 주석). 자동 경로에서 그게 터지면 더 나쁘다.\r\n this.clearInputArea(pane, read);\r\n if (cfg.repairSendRedrawKey === true) {\r\n setTimeout(() => this.sendRedrawKey(pane), REPAIR_REDRAW_DELAY_MS);\r\n }\r\n // 복구가 실제로 먹혔는지 같은 파일에 이어 남긴다 — 앱이 다시 그릴 시간을 준다\r\n setTimeout(() => {\r\n var _a;\r\n const after = this.readScreen(pane);\r\n const still = after ? (0, screen_1.judgeScreen)(after.lines, after.cols, (_a = this.profileForPane(pane)) === null || _a === void 0 ? void 0 : _a.screenShape) : null;\r\n this.snapshot(pane, `auto-after ${still ? (still.broken ? '아직 깨짐: ' + still.reasons.join(' / ') : '복구됨') : '읽을 수 없음'}`);\r\n }, SNAP_AFTER_MS);\r\n }\r\n /**\r\n * 화면이 `AUTO_REPAIR_REFILL_MS` 넘게 온전하면 이 탭의 자동복구 예산을 되돌린다.\r\n *\r\n * 되돌리는 곳이 아예 없던 것이 결함이었다 — `autoRepairCount` 는 pane 이 살아 있는 동안\r\n * 단조증가만 해서, 며칠 켜 두는 탭은 `autoRepairMaxPerTab`(기본 3)회를 쓰고 나면 그 뒤의\r\n * 모든 깨짐을 방치했다. 반대로 온전해지자마자 되돌리면 예산이 사실상 무한이 되므로\r\n * (깨짐 → 복구 → 온전 → 깨짐 … 이 그대로 반복된다) **오래 온전할 때만** 되돌린다.\r\n */\r\n refillAutoRepairBudget(pane) {\r\n if (!this.autoRepairCount.get(pane)) {\r\n this.autoRepairHealthySince.delete(pane);\r\n return;\r\n }\r\n const now = Date.now();\r\n const since = this.autoRepairHealthySince.get(pane);\r\n if (!since) {\r\n this.autoRepairHealthySince.set(pane, now);\r\n return;\r\n }\r\n if (now - since < AUTO_REPAIR_REFILL_MS) {\r\n return;\r\n }\r\n this.autoRepairCount.delete(pane);\r\n this.autoRepairHealthySince.delete(pane);\r\n (0, diag_1.resetDiagOnce)('auto-repair-cap');\r\n this.diag(`screen auto-repair 예산 회복`\r\n + ` (화면이 ${Math.round((now - since) / 1000)}초 동안 온전했다)`);\r\n }\r\n /** 활성 탭의 pane 들을 한 번씩 본다 (주기 그물) */\r\n sweepScreens() {\r\n if (!this.enabled || !this.screenObservingEnabled()) {\r\n return;\r\n }\r\n const tab = this.app.activeTab;\r\n if (!tab) {\r\n return;\r\n }\r\n const anyTab = tab;\r\n const panes = typeof anyTab.getAllTabs === 'function'\r\n ? anyTab.getAllTabs()\r\n : [tab];\r\n for (const pane of panes) {\r\n this.checkScreen(pane);\r\n }\r\n }\r\n /** 판정에 넣을 화면 줄과 폭 — 숨겨진 탭이나 아직 안 붙은 프론트엔드는 건너뛴다 */\r\n readScreen(pane) {\r\n var _a, _b, _c, _d;\r\n const anyPane = pane;\r\n const xterm = (_a = anyPane.frontend) === null || _a === void 0 ? void 0 : _a.xterm;\r\n const buf = (_b = xterm === null || xterm === void 0 ? void 0 : xterm.buffer) === null || _b === void 0 ? void 0 : _b.active;\r\n if (!buf || typeof buf.getLine !== 'function' || !(xterm.cols > 1)) {\r\n return null;\r\n }\r\n // 숨겨진 탭은 컨테이너 폭이 0 이라 xterm 이 1열로 줄어 있다 — 판정 대상이 아니다\r\n const host = (_c = xterm.element) === null || _c === void 0 ? void 0 : _c.parentElement;\r\n if (!(host === null || host === void 0 ? void 0 : host.clientWidth)) {\r\n return null;\r\n }\r\n const lines = [];\r\n // 읽는 도중에 버퍼가 갈릴 수 있다 — `xterm.reset()`(repairHard)·프론트엔드 교체가 그렇다.\r\n // 이 함수는 2초 그물에서 불리므로 예외가 새면 그 인터벌이 통째로 죽는다.\r\n // 못 읽었으면 판정을 건너뛰는 것이 맞다.\r\n try {\r\n for (let y = buf.baseY; y <= buf.baseY + xterm.rows - 1; y++) {\r\n const line = buf.getLine(y);\r\n lines.push({\r\n text: (_d = line === null || line === void 0 ? void 0 : line.translateToString(false)) !== null && _d !== void 0 ? _d : '',\r\n wrapped: !!(line === null || line === void 0 ? void 0 : line.isWrapped),\r\n });\r\n }\r\n }\r\n catch {\r\n return null;\r\n }\r\n return { lines, cols: xterm.cols };\r\n }\r\n /**\r\n * 화면 원문을 통째로 남긴다 — 깨짐 채증용.\r\n *\r\n * 판정 이유만 남기면 다음에 또 \"왜 그렇게 됐는지\" 를 추측하게 된다. 행 번호·wrap 플래그·\r\n * 길이까지 그대로 적어 두면 `❯` 가 어느 행에 있었는지, 테두리가 몇 칸이었는지가 확정된다.\r\n * before/after 를 짝으로 남기므로 복구가 실제로 먹혔는지도 이 파일에서 바로 갈린다.\r\n */\r\n snapshot(pane, tag) {\r\n var _a, _b, _c, _d;\r\n const read = this.readScreen(pane);\r\n if (!read) {\r\n return;\r\n }\r\n const anyPane = pane;\r\n const xterm = (_a = anyPane.frontend) === null || _a === void 0 ? void 0 : _a.xterm;\r\n const head = `\\n===== ${new Date().toISOString()} ${tag}`\r\n + ` cols=${read.cols} rows=${xterm === null || xterm === void 0 ? void 0 : xterm.rows} sent=${(_b = anyPane.size) === null || _b === void 0 ? void 0 : _b.columns}x${(_c = anyPane.size) === null || _c === void 0 ? void 0 : _c.rows}`\r\n + ` title=${JSON.stringify((_d = pane.title) !== null && _d !== void 0 ? _d : '')} =====`;\r\n const body = read.lines\r\n .map((l, i) => ({ i, t: l.text.replace(/\\s+$/, ''), w: l.wrapped }))\r\n .filter(l => l.t)\r\n .map(l => `${String(l.i).padStart(3)} w=${l.w ? 1 : 0} len=${l.t.length} ${JSON.stringify(l.t)}`);\r\n (0, diag_1.appendScreenLog)([head, ...body, ''].join('\\n'));\r\n }\r\n // ---------- 세션 감시 ----------\r\n /**\r\n * 탭(그리고 그 안의 모든 pane)의 PTY 출력을 구독한다.\r\n *\r\n * TerminalDecorator 는 프론트엔드 첫 리사이즈 시점에만 붙어서 복원된 탭 등을\r\n * 놓치는 경우가 있다. 이쪽은 탭이 목록에 들어오는 즉시 붙으므로 그 빈틈을 메운다.\r\n * 같은 출력을 decorator 와 둘 다 먹어도 상태 설정이 멱등이라 결과는 같다.\r\n */\r\n watchTab(root) {\r\n var _a;\r\n const anyRoot = root;\r\n if (!this.watched.has(root)) {\r\n this.watched.add(root);\r\n // 제목은 래퍼 탭이 자식 것을 위임받으므로 여기서 받는 게 가장 확실하다\r\n if (anyRoot.titleChange$) {\r\n anyRoot.titleChange$.subscribe((title) => {\r\n // 제목이 바뀌는 순간은 \"셸에서 방금 에이전트를 띄웠다\" 일 수 있다 — 그때 한 번 더 본다\r\n // (TTL 로 묶여 있어 제목이 자주 바뀌어도 프로세스 트리를 매번 묻지는 않는다)\r\n void this.probeAgent(root, 'title-change');\r\n (0, detect_1.applyTitle)(this.status, root, title, this.config.store.agentDeck.autoDetect, this.profileForTab(root));\r\n });\r\n }\r\n if (anyRoot.title) {\r\n (0, detect_1.applyTitle)(this.status, root, anyRoot.title, this.config.store.agentDeck.autoDetect, this.profileForTab(root));\r\n }\r\n // 나중에 분할로 추가되는 pane 도 따라간다\r\n if (anyRoot.tabAdded$) {\r\n anyRoot.tabAdded$.subscribe((pane) => this.watchPane(root, pane));\r\n }\r\n }\r\n // pane 은 래퍼보다 늦게 붙는 경우가 있으므로 호출될 때마다 다시 훑는다\r\n // (래퍼만 보고 한 번에 끝내면 목록에 먼저 들어온 빈 SplitTab 을 잡고 끝나버린다)\r\n const panes = typeof anyRoot.getAllTabs === 'function'\r\n ? anyRoot.getAllTabs()\r\n : [root];\r\n this.diag(`watchTab panes=${panes.length}`);\r\n for (const pane of panes) {\r\n this.watchPane(root, pane);\r\n }\r\n // 래퍼(SplitTabComponent)가 자식보다 먼저 목록에 들어오는 경우가 있다. 그때 여기서\r\n // panes=0 을 보고 물러나면, 자식이 붙어도 다시 훑을 계기가 없어 그 탭은 영영\r\n // 감시 밖에 남는다 — 상태 감지·Enter 라벨·화면 검사가 전부 안 돈다\r\n // (2026-09-01 실측: 기동 직후 첫 탭에서 `watchTab panes=0` 만 두 번 찍히고\r\n // `session bind` 가 한 번도 없었다). 그래서 비어 있으면 잠시 뒤 다시 본다.\r\n if (!panes.length) {\r\n const tries = ((_a = this.emptyTabRetries.get(root)) !== null && _a !== void 0 ? _a : 0) + 1;\r\n this.emptyTabRetries.set(root, tries);\r\n if (tries <= EMPTY_TAB_RETRY_MAX) {\r\n setTimeout(() => {\r\n if (this.app.tabs.includes(root)) {\r\n this.watchTab(root);\r\n }\r\n }, EMPTY_TAB_RETRY_MS);\r\n }\r\n }\r\n }\r\n watchPane(root, pane) {\r\n var _a;\r\n if (this.watchedPanes.has(pane)) {\r\n return;\r\n }\r\n this.watchedPanes.add(pane);\r\n this.diag(`watchPane ${(_a = pane.constructor) === null || _a === void 0 ? void 0 : _a.name}`);\r\n const anyPane = pane;\r\n const bind = (session) => {\r\n var _a, _b, _c, _d, _e, _f;\r\n this.installCodexCursorFix(pane);\r\n if (!session || !session.output$) {\r\n return;\r\n }\r\n // pty 가 어떤 폭으로 태어났는지 남긴다. Tabby 는 프론트엔드의 **첫** resize$ 값으로\r\n // 세션을 스폰하므로(tabby-local: initializeSession(this.size...) -> spawn cols),\r\n // 그 스냅샷이 우리 레이아웃보다 이르면 pty 만 옛 폭으로 굳는다 — 그 순간이 여기 찍힌다.\r\n this.diag(`session bind`\r\n + ` xterm=${(_b = (_a = anyPane.frontend) === null || _a === void 0 ? void 0 : _a.xterm) === null || _b === void 0 ? void 0 : _b.cols}x${(_d = (_c = anyPane.frontend) === null || _c === void 0 ? void 0 : _c.xterm) === null || _d === void 0 ? void 0 : _d.rows}`\r\n + ` paneSize=${(_e = anyPane.size) === null || _e === void 0 ? void 0 : _e.columns}x${(_f = anyPane.size) === null || _f === void 0 ? void 0 : _f.rows}`);\r\n // 어떤 에이전트가 도는 탭인지 여기서 한 번 알아낸다 — 출력마다 물어볼 수 없는 값이다\r\n // (getChildProcesses 는 OS 호출). 아직 셸만 떠 있으면 unknown 이고, 그때는\r\n // 합집합 패턴으로 판정하다가 제목이 바뀌는 시점에 다시 본다.\r\n void this.probeAgent(root, 'session-bind');\r\n session.output$.subscribe((data) => {\r\n var _a;\r\n // 아직 못 알아낸 탭만 다시 물어본다 — **셸을 먼저 열고 나중에 `claude` 를 치는 흐름**이\r\n // 가장 흔한데, 그때 제목이 안 바뀌면 session-bind 때의 unknown 이 영영 굳는다\r\n // (2026-09-08 실측: 자식 프로세스가 codex.exe 인데 진단은 `id=unknown` 그대로).\r\n // TTL(AGENT_PROBE_TTL_MS)이 조회 빈도를 막고, 한 번 알아낸 탭은 이 갈래를 타지 않는다\r\n this.outputHits++;\r\n const observed = this.paneAgents.get(pane);\r\n if (((_a = this.tabAgents.get(root)) !== null && _a !== void 0 ? _a : 'unknown') === 'unknown'\r\n || ((observed === null || observed === void 0 ? void 0 : observed.session) === anyPane.session && (observed === null || observed === void 0 ? void 0 : observed.tracker.id) === 'unknown')) {\r\n void this.probeAgent(root, 'output');\r\n }\r\n (0, detect_1.applyOutput)(this.status, root, pane, data, this.config.store.agentDeck.autoDetect, this.profileForTab(root));\r\n // 화면에 찍힌 파일 경로를 주워 미리보기 패널의 최근 목록에 쌓는다.\r\n // 에이전트를 가리지 않는 경로다 — Claude·Codex·Gemini 가 모두 만진 파일을 찍는다.\r\n // 조각마다 정규식을 돌리지 않는다 (패널이 모아서 400ms 마다 한 번 훑는다)\r\n if (this.view && this.config.store.agentDeck.viewerScrape) {\r\n this.view.noteOutput(root, data);\r\n }\r\n // cwd 캐시는 미리보기 패널 설정(viewerScrape) 안에 있으면 안 된다 — 사이드바\r\n // 프로젝트 그룹(group.ts)도 이 캐시를 원천으로 쓰므로, 패널 옵션을 끈 사람은\r\n // 모든 탭이 `기타` 그룹으로 떨어진다. TTL(CWD_TTL_MS=3초)이 조회 빈도를 막으니\r\n // 출력 조각마다 불려도 비용은 WeakMap 조회 한 번이다.\r\n this.touchCwd(root, pane);\r\n // 출력이 멈춘 뒤 화면이 온전한지 본다 (그리는 도중에 읽으면 멀쩡한 화면도 깨져 보인다)\r\n this.scheduleScreenCheck(pane);\r\n });\r\n };\r\n bind(anyPane.session);\r\n if (anyPane.sessionChanged$) {\r\n anyPane.sessionChanged$.subscribe((session) => bind(session));\r\n }\r\n // 프론트엔드가 붙는 도중에 우리가 폭을 바꿨으면 그 변경은 유실될 수 있다\r\n // (Tabby 는 attach() 맨 끝에서야 ResizeObserver 를 건다) — 준비되면 fit 한 번으로 깨워 준다.\r\n // 여기서 하는 건 `fitAddon.fit()` 뿐이다. 그 뒤는 순정 경로가 이어받는다\r\n // (fit → xterm onResize → Tabby 가 session.resize). 우리가 pty 에 직접 쏘지 않는다.\r\n if (anyPane.frontendReady$) {\r\n anyPane.frontendReady$.subscribe(() => {\r\n this.installCodexCursorFix(pane);\r\n this.scheduleRefit();\r\n this.announceSizeOnOpen(pane);\r\n // 작업 폴더는 **태어날 때 한 번** 물어 둔다. 출력 구독에만 맡기면 아무것도\r\n // 찍지 않는 탭(열어 두고 안 쓰는 셸)이 영영 `기타` 그룹에 남는다.\r\n this.touchCwd(root, pane);\r\n });\r\n }\r\n // frontendReady 는 replay 가 없는 맨 Subject 라, 복원된 탭의 프론트엔드가 우리보다\r\n // 먼저 붙어버리면 위 구독은 영영 못 받는다. 이벤트와 무관하게 한 번 더 예약한다 —\r\n // 같은 크기를 두 번 알려도 SIGWINCH 가 안 나므로 무해하다.\r\n this.announceSizeOnOpen(pane);\r\n }\r\n installCodexCursorFix(pane) {\r\n (0, codexWheel_1.installCodexWheel)(pane.frontend, () => { var _a; return process.platform === 'win32' && ((_a = this.profileForPane(pane)) === null || _a === void 0 ? void 0 : _a.id) === 'codex'; }, data => pane.sendInput(data));\r\n (0, cursorVisibility_1.installCursorVisibilityFix)(pane.frontend, data => {\r\n var _a;\r\n this.observePaneAgent(pane, data);\r\n return process.platform === 'win32' && ((_a = this.profileForPane(pane)) === null || _a === void 0 ? void 0 : _a.id) === 'codex';\r\n }, () => this.diag('codex cursor: repaired non-private CSI 25 visibility sequence'));\r\n }\r\n observePaneAgent(pane, data) {\r\n let state = this.paneAgents.get(pane);\r\n if (!state || state.session !== pane.session) {\r\n state = { session: pane.session, tracker: new screenAgent_1.TerminalAgentTracker() };\r\n this.paneAgents.set(pane, state);\r\n }\r\n state.tracker.write(data);\r\n }\r\n /**\r\n * 탭이 열린 뒤 몇 차례, **지금 xterm 이 쓰는 크기를 pty 에 알려준다.**\r\n *\r\n * 순정이 유일하게 못 메우는 구멍(새 탭에서 pty 만 좁게 태어남)을 메우는 최소 개입이다.\r\n * 자세한 근거와 실측은 `TAB_OPEN_ANNOUNCE_MS` 주석에 있다.\r\n *\r\n * 하지 않는 것 — xterm 은 건드리지 않고(fit 도 resize 도), 폭을 흔들지 않으며,\r\n * 감시 루프도 돌지 않는다. 그 셋이 예전에 화면을 깨뜨린 장본인이다.\r\n */\r\n announceSizeOnOpen(pane) {\r\n const anyPane = pane;\r\n for (const delay of TAB_OPEN_ANNOUNCE_MS) {\r\n setTimeout(() => {\r\n var _a;\r\n const x = (_a = anyPane.frontend) === null || _a === void 0 ? void 0 : _a.xterm;\r\n const session = anyPane.session;\r\n if (!(session === null || session === void 0 ? void 0 : session.open) || typeof session.resize !== 'function' || !((x === null || x === void 0 ? void 0 : x.cols) > 1)) {\r\n return;\r\n }\r\n const prev = anyPane.size;\r\n if ((prev === null || prev === void 0 ? void 0 : prev.columns) !== x.cols || (prev === null || prev === void 0 ? void 0 : prev.rows) !== x.rows) {\r\n this.diag(`announce size ${prev === null || prev === void 0 ? void 0 : prev.columns}x${prev === null || prev === void 0 ? void 0 : prev.rows}`\r\n + ` -> ${x.cols}x${x.rows} (+${delay}ms)`);\r\n }\r\n try {\r\n session.resize(x.cols, x.rows);\r\n anyPane.size = { columns: x.cols, rows: x.rows };\r\n }\r\n catch (e) {\r\n // 세션이 막 닫혔다 — 흔한 사유지만 그 밖의 실패도 여기로 오므로 남긴다\r\n (0, diag_1.diagCatch)('announce-size resize', e);\r\n }\r\n }, delay);\r\n }\r\n }\r\n // 흔들기 장치는 전부 폐지했다 (2026-09-02).\r\n //\r\n // 여기에 있던 것들 — `scheduleWindowKick`(기동 시 창 복원→최대화), `scheduleRedrawKick`,\r\n // `kickPtySize`(탭당 한 번 cols-1 ↔ cols) — 는 모두 \"순정이 크기를 못 맞춘다\" 는 전제에서\r\n // 나온 우회책이었다. 전제가 틀렸다: Tabby 는 xterm `ResizeObserver` → `fitAddon.fit()` →\r\n // `session.resize()` 로 스스로 맞춘다. 우리가 폭만 정해 주면 된다.\r\n // 이 흔들기들은 순정 수렴과 경쟁하며 프레임을 반쯤 그린 상태를 남겨 화면을 깨뜨렸다.\r\n // 수동 복구(`repairPane`)는 여전히 흔든다 — 거기는 사용자가 명시로 요청한 경로다.\r\n /**\r\n * Ctrl+V 를 **핫키 테이블에서 걷어낸다** (실제 처리는 claimCtrlVKey 가 한다).\r\n *\r\n * 예전에는 여기서 `agentdeck-paste` 에 Ctrl-V 를 등록했는데, 그러면 한 번 눌러 두 번 붙는\r\n * 경우가 남았다. Tabby 는 같은 keydown 을 **두 경로**로 HotkeysService 에 밀어 넣기 때문이다 —\r\n * xterm 의 커스텀 키 핸들러(`tabby-terminal/dist/index.js:40789` keyboardEventHandler →\r\n * `hotkeysService.pushKeyEvent`)와, document 에 걸린 core 리스너(`tabby-core:21425`).\r\n * `pushKeyEvent` 앞에 `timeStamp` 중복 가드가 있지만(`tabby-core:21451`) 그건 **같은**\r\n * 이벤트 객체일 때만 먹고, 두 경로가 서로 다른 이벤트(keydown/keyup 등)로 들어오면\r\n * `emitHotkeyOn` 이 두 번 나간다(실측: hotkey-paste 가 1ms 간격 2회, `.agentdeck-diag.log`).\r\n *\r\n * 그래서 핫키에 기대지 않고 캡처 단계에서 직접 한 번만 처리한다 — 우클릭을 claimRightClick\r\n * 으로 가져온 것과 같은 이유·같은 방식이다. 순정 `paste` 쪽에 Ctrl-V 가 남아 있어도 캡처가\r\n * 먼저 먹고 전파를 끊으므로 발화하지 않지만, 설정 화면이 헷갈리지 않게 양쪽 모두에서 뺀다.\r\n *\r\n * 대가: 터미널 앱에 리터럴 Ctrl+V(0x16, quoted-insert)를 보낼 수 없다.\r\n * 그게 필요하면 `agentDeck.claimCtrlV: false`. 그때도 **핫키 회수는 그대로 한다** —\r\n * 이유는 본문 주석(핫키에 남기면 붙여넣기가 먼저 발화해 0x16 이 PTY 에 닿지 못한다).\r\n */\r\n ensurePasteHotkey() {\r\n const hotkeys = this.config.store.hotkeys;\r\n if (!hotkeys) {\r\n return;\r\n }\r\n let changed = false;\r\n // 옛 이름(workdeck-*)으로 저장된 핫키가 config.yaml 에 남아 있으면 Ctrl-V 가 그쪽에\r\n // 먼저 매칭돼 우리 핸들러가 통째로 죽는다 — HotkeysService.matchActiveHotkey 는\r\n // 길이가 같은 후보 중 config 삽입 순서로 앞선 것 하나만 고르고, 옛 항목이 먼저 저장돼 있다\r\n // (tabby-core/dist/index.js:21558 matches.sort → matches[0].id).\r\n for (const legacy of ['workdeck-paste', 'workdeck-newline', 'workdeck-toggle']) {\r\n if (legacy in hotkeys) {\r\n delete hotkeys[legacy];\r\n changed = true;\r\n }\r\n }\r\n // 지난 버전이 넣어둔 Ctrl-V 를 회수한다. 남겨두면 캡처 경로와 겹쳐 다시 2중이 될 수 있다.\r\n //\r\n // **여기에 `claimCtrlV` 게이트를 두면 안 된다** — 2026-09-08 에 \"설정을 꺼도 회수가 도니까\r\n // 갭이다\" 로 보고 게이트를 넣어봤다가 되돌렸다. 그 설정의 목적은 *리터럴* Ctrl+V(0x16,\r\n // quoted-insert)를 터미널 앱에 흘리는 것이고, 순정 `hotkeys.paste` 에 Ctrl-V 가 남아 있으면\r\n // HotkeysService 가 붙여넣기를 먼저 발화해 **0x16 이 PTY 에 영영 닿지 않는다**. 즉 게이트를\r\n // 넣는 순간 그 설정이 아무 일도 못 하게 된다. 꺼둔 상태에서 붙여넣기는 순정\r\n // `Ctrl+Shift+V`·`Shift+Insert` 나 우클릭으로 한다 (README `키` 절에 그대로 적혀 있다).\r\n //\r\n // 되돌려도 잃는 것이 없다 — `claimCtrlV` 를 다시 켜면 붙여넣기는 캡처 경로가 처리하므로\r\n // 핫키 테이블이 비어 있어도 Ctrl+V 가 그대로 동작한다.\r\n for (const id of ['agentdeck-paste', 'paste']) {\r\n const keys = Array.isArray(hotkeys[id]) ? hotkeys[id] : [];\r\n if (keys.includes('Ctrl-V')) {\r\n hotkeys[id] = keys.filter(k => k !== 'Ctrl-V');\r\n changed = true;\r\n }\r\n }\r\n if (changed) {\r\n this.config.save();\r\n }\r\n this.diag(`hotkeys paste=${JSON.stringify(hotkeys.paste)} `\r\n + `agentdeck-paste=${JSON.stringify(hotkeys['agentdeck-paste'])} `\r\n + `legacy=${Object.keys(hotkeys).filter(k => k.startsWith('workdeck')).join(',') || 'none'}`);\r\n }\r\n /**\r\n * Ctrl+V 를 document **캡처 단계**에서 한 번만 처리한다.\r\n *\r\n * 캡처는 xterm 의 textarea 리스너보다도 먼저 돌기 때문에, 여기서 전파를 끊으면\r\n * 그 뒤에 있는 경로(xterm 커스텀 키 핸들러 → pushKeyEvent, core 의 document 리스너,\r\n * xterm 이 Ctrl+V 를 0x16 으로 바꿔 PTY 에 흘리는 기본 동작, 브라우저 네이티브 paste)가\r\n * 통째로 죽는다. 몇 개가 겹쳐 걸려 있든 붙여넣기는 정확히 한 번이 된다 —\r\n * 핫키로 받던 시절 남아 있던 2중 입력의 해법이다(ensurePasteHotkey 주석에 원인).\r\n *\r\n * 단, 설정 화면 같은 **평범한 입력 필드**에서는 손대지 않는다. 거기서는 Ctrl+V 가\r\n * 브라우저 기본 붙여넣기여야 하고, 우리가 가로채면 아예 못 붙여넣게 된다.\r\n */\r\n claimCtrlVKey() {\r\n document.addEventListener('keydown', (event) => {\r\n if (!this.config.store.agentDeck.claimCtrlV) {\r\n return;\r\n }\r\n if (!event.ctrlKey || event.shiftKey || event.altKey || event.metaKey) {\r\n return;\r\n }\r\n // 한글 입력 상태에서는 key 가 'ㅍ' 로 오기도 한다 — 물리 키(code)를 같이 본다\r\n if ((event.key || '').toLowerCase() !== 'v' && event.code !== 'KeyV') {\r\n return;\r\n }\r\n if (this.isPlainInput(event.target) || this.isDeckUiKey(event.target)) {\r\n return;\r\n }\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.zone.runOutsideAngular(() => this.doPaste('ctrl-v'));\r\n }, true);\r\n }\r\n /**\r\n * `Ctrl+W` — 지금 탭을 닫는다. **`keyboardNav` 에 매달려 있다**(`keyboardCloseTab` 주석).\r\n *\r\n * 핫키(`hotkeys` 테이블)로 두지 않은 이유가 이 기능의 핵심이다. Tabby 핫키는 **등록되어\r\n * 있는 것만으로 키를 먹는다** — 우리 처리부에서 설정을 보고 no-op 하더라도 키는 이미\r\n * 터미널에 닿지 못한다. 그런데 셸·에이전트 CLI 에서 `Ctrl+W` 는 **앞 단어 지우기**(0x17)로\r\n * 늘 쓰는 키다. 즉 \"설정을 껐는데 Ctrl+W 가 죽어 있다\" 가 되는데, 그건 이 기능을 끈 사람에게\r\n * 가장 나쁜 결과다. 캡처 리스너로 두면 **우리가 안 잡을 때 키가 아무 손상 없이 흐른다**.\r\n * (`claimCtrlVKey` 가 캡처로 간 이유는 달랐다 — 핫키 경로의 2중 발화. 결론만 같다.)\r\n *\r\n * 그래서 `preventDefault` 는 **닫을 탭이 실제로 정해졌을 때만** 한다. 고르는 규칙은\r\n * `nav.ts` 의 `pickCloseTarget` 이고(목록이 키보드를 가졌으면 포커스 줄, 아니면 활성 탭),\r\n * 그 함수가 `null` 을 주는 경우 — 그룹 헤더 포커스, 이미 닫힌 탭 — 에는 키를 흘린다.\r\n *\r\n * 설정 화면 같은 보통 입력 필드(`isPlainInput`)에서도 비켜 준다. 사이드바 안에서 난 키는\r\n * **목록이 키보드를 가진 때만** 받는다(`isDeckUiKey`) — 검색창은 `isPlainInput` 이 먼저\r\n * 걸러내고, 나머지(버튼 등)에서 온 `Ctrl+W` 는 우리 것이 아니다.\r\n *\r\n * 닫기는 사이드바 `✕` 와 **같은 경로**다 — `closeTab(tab, true)` 이므로 돌아가는 프로세스가\r\n * 있으면 Tabby 가 평소처럼 확인을 띄운다. 여기서 그 확인을 건너뛰면 키 하나로 세션이\r\n * 사라진다(에이전트가 일하는 중일 수도 있다).\r\n */\r\n claimCtrlWKey() {\r\n document.addEventListener('keydown', (event) => {\r\n var _a, _b, _c;\r\n const cfg = this.config.store.agentDeck;\r\n if (!this.enabled || cfg.keyboardNav === false || cfg.keyboardCloseTab === false) {\r\n return;\r\n }\r\n if (!event.ctrlKey || event.shiftKey || event.altKey || event.metaKey) {\r\n return;\r\n }\r\n // 한글 입력 상태에서는 key 가 'ㅈ' 로 온다 — 물리 키(code)를 같이 본다 (claimCtrlVKey 와 같은 이유)\r\n if ((event.key || '').toLowerCase() !== 'w' && event.code !== 'KeyW') {\r\n return;\r\n }\r\n if (this.isPlainInput(event.target)) {\r\n return;\r\n }\r\n const inList = this.navMode === 'list';\r\n if (!inList && this.isDeckUiKey(event.target)) {\r\n return;\r\n }\r\n const tab = (0, nav_1.pickCloseTarget)({\r\n inList,\r\n focus: this.navFocus,\r\n active: (_a = this.app.activeTab) !== null && _a !== void 0 ? _a : null,\r\n tabs: this.app.tabs,\r\n });\r\n if (!tab) {\r\n this.diag(`ctrl-w skip inList=${inList} focus=${(_c = (_b = this.navFocus) === null || _b === void 0 ? void 0 : _b.kind) !== null && _c !== void 0 ? _c : 'none'}`);\r\n return;\r\n }\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.diag(`ctrl-w close inList=${inList} tabs=${this.app.tabs.length}`);\r\n this.zone.run(() => { void this.app.closeTab(tab, true); });\r\n }, true);\r\n }\r\n /**\r\n * Home / End 를 Tabby 핫키 테이블에서 걷어내 xterm 순정 경로로 돌려준다.\r\n *\r\n * 증상: 한글 마지막 음절이 조합 중일 때 Home/End 를 누르면 그 음절이 **커서를 따라간다**\r\n * (2026-09-08 사용자 보고). 방향키는 멀쩡하다 — 그 차이가 곧 원인이다.\r\n *\r\n * 방향키는 핫키가 아니라서 xterm 의 키 경로를 그대로 탄다. 거기서는 조합 중에 아무 키나\r\n * 들어오면 `CompositionHelper.keydown` 이 `_finalizeComposition(false)` 로 조합을\r\n * **동기 전송**하고(`tabby-terminal/dist/index.js:44098`, `:44120` triggerDataEvent) 그다음\r\n * 방향키를 보낸다 — 글자 먼저, 이동 나중이라 순서가 맞는다.\r\n *\r\n * Home/End 는 그 경로를 못 탄다. Tabby 가 `hotkeys.home` / `hotkeys.end` 로 선점해서\r\n * `tabby-local/dist/index.js:613` 이 `sendInput('\u001b[H')` 를 **즉시** 쏘기 때문이다.\r\n * xterm 을 거치지 않으니 조합 확정은 `compositionend` 경로로 밀리는데, 그쪽\r\n * `_finalizeComposition(true)` 는 `setTimeout(..., 0)` 로 **비동기 전송**이다\r\n * (`tabby-terminal/dist/index.js:44110`). 결국 커서 이동이 먼저 나가고 음절이 한 틱 뒤에\r\n * 도착한다 — 앱은 옮겨간 자리에 글자를 찍는다.\r\n *\r\n * 그래서 고치는 방법은 핸들러를 더 얹는 게 아니라 **핫키를 놓아주는 것**이다. 비워두면\r\n * xterm 이 Home/End 를 방향키와 똑같이 처리한다(조합 확정 → 키 전송). 되돌리려면\r\n * `agentDeck.releaseHomeEnd: false` 후 설정에서 다시 지정하면 된다.\r\n */\r\n releaseHomeEndHotkey() {\r\n if (!this.config.store.agentDeck.releaseHomeEnd) {\r\n return;\r\n }\r\n const hotkeys = this.config.store.hotkeys;\r\n if (!hotkeys) {\r\n return;\r\n }\r\n let changed = false;\r\n for (const id of ['home', 'end']) {\r\n const keys = Array.isArray(hotkeys[id]) ? hotkeys[id] : [];\r\n const kept = keys.filter(k => k !== 'Home' && k !== 'End');\r\n if (kept.length !== keys.length) {\r\n hotkeys[id] = kept;\r\n changed = true;\r\n }\r\n }\r\n if (changed) {\r\n this.config.save();\r\n }\r\n this.diag(`hotkeys home=${JSON.stringify(hotkeys.home)} `\r\n + `end=${JSON.stringify(hotkeys.end)}`);\r\n }\r\n /**\r\n * Home / End 를 눌렀을 때 조합 중인 음절을 **먼저 확정**시킨다 (막지는 않는다).\r\n *\r\n * 왜 `releaseHomeEndHotkey` 위에 한 겹을 더 얹는가 — 핫키를 놓아주는 것만으로는 부족했다.\r\n * 실사용 `%APPDATA%\\tabby\\config.yaml:71-72` 가 이미 `home: []` / `end: []` 인데도 같은\r\n * 증상이 재발했다 (2026-09-08 사용자 재보고). 즉 그 키를 pty 에 직접 쓰는 경로가 Tabby\r\n * 핫키 말고도 남아 있다는 뜻이다. 누가 쓰든 우리가 **먼저** 확정을 끝내 두면 순서가 맞는다.\r\n *\r\n * 그래서 이 리스너는 캡처 단계에 걸되 **아무것도 막지 않는다**(preventDefault 금지).\r\n * 캡처는 Tabby 핫키·xterm 키 핸들러보다 먼저 돌기 때문에, 이 시점에 동기 확정을 끝내면\r\n * 그다음 누가 `\\x1b[H` 를 쏘든 음절이 이미 나가 있다.\r\n *\r\n * `releaseHomeEndHotkey` 는 그대로 둔다 — 방향키와 같은 경로로 돌려주는 것이 여전히 옳고\r\n * (xterm 이 확정과 키 전송의 순서를 스스로 지킨다), 이건 그 경로가 다시 선점당했을 때를 위한\r\n * 두 번째 겹이다. 둘 다 켜져 있어도 확정이 두 번 나가지는 않는다 — 첫 확정 뒤에는\r\n * `isComposing === false` 라 `readCompositionState` 가 `idle` 로 읽어 아무 일도 하지 않는다.\r\n *\r\n * 판정은 이벤트 필드가 아니라 **헬퍼의 살아있는 상태**로 한다. 한글 IME 를 거친 이벤트는\r\n * `isComposing`·수식키가 지워진 채 도착하는 것이 실측됐다 (`claimShiftEnterKey` 주석).\r\n */\r\n guardHomeEndComposition() {\r\n document.addEventListener('keydown', (event) => {\r\n if (!this.config.store.agentDeck.imeOrderGuard) {\r\n return;\r\n }\r\n const key = event.key;\r\n if (key !== 'Home' && key !== 'End' && event.code !== 'Home' && event.code !== 'End') {\r\n return;\r\n }\r\n if (this.isPlainInput(event.target) || this.isDeckUiKey(event.target)) {\r\n return; // 우리 패널의 보통 입력창 — 터미널이 아니다\r\n }\r\n const pane = this.focusedPane();\r\n const helper = this.compositionHelper(pane);\r\n const state = (0, ime_1.readCompositionState)(helper);\r\n const plan = (0, ime_1.planSend)(state);\r\n // **여기서는 확정을 재촉하지 않는다.** 조합 중에 우리가 동기 확정시키면 IME 가 뒤이어\r\n // `compositionend` 를 쏘고 xterm 이 음절을 한 번 더 보내, 그 두 번째가 커서 이동 뒤에\r\n // 나가 음절이 따라가 보인다 (Shift+Enter 에서 실측한 것과 같은 기전 — `ime.ts` planSend).\r\n //\r\n // Home/End 는 이미 핫키에서 놓아줬으므로(`releaseHomeEndHotkey`) xterm 이 방향키와\r\n // 똑같이 처리한다 — 즉 xterm 의 `keydown` 이 **자기 경로에서 동기 확정을 먼저** 한다.\r\n // 우리가 할 일은 그 경로를 방해하지 않는 것뿐이고, 남길 것은 진단 한 줄이다.\r\n // (그 경로가 다시 선점당해 증상이 재발하면 이 줄이 어느 분기였는지 알려준다.)\r\n this.diag(`ime home-end key=${key} keyCode=${event.keyCode} `\r\n + `${this.describeComposition(helper)} evComposing=${event.isComposing} `\r\n + `state=${state} plan=${plan}`);\r\n }, true);\r\n }\r\n /**\r\n * pty 에 바이트를 쓰는 **공통 진입점** — 조합 중인 음절보다 먼저 나가지 않게 순서를 맞춘다.\r\n *\r\n * xterm 을 거치지 않고 `sendInput`/`paste` 로 직접 쓰는 경로는 조합 동기 확정을 트리거하지\r\n * 않는다 (기전은 `ime.ts` 머리주석에 xterm 원문과 함께). 그래서 쓰기 직전에 조합 상태를 보고\r\n * - 조합 중이면 동기 확정을 시킨 뒤 쓴다 (방향키가 하는 일을 그대로)\r\n * - 확정 전송이 예약돼 있으면 우리가 한 틱 뒤로 물러난다 (같은 `setTimeout(…,0)` 큐의 뒤)\r\n * - 그 외에는 그냥 쓴다\r\n * 로 갈라 준다. 상태를 못 읽으면(`unknown`) 그냥 쓴다 — 이 훅이 정상 입력을 막는 일은\r\n * 없어야 한다. `imeOrderGuard: false` 로 끄면 0.4.0 까지의 동작 그대로다.\r\n */\r\n sendToPane(pane, tag, write) {\r\n const run = () => {\r\n try {\r\n write();\r\n }\r\n catch {\r\n // 세션이 막 닫혔다 (defer 로 한 틱 늦게 쓸 때 특히) — 조용히 넘긴다\r\n }\r\n };\r\n if (!this.config.store.agentDeck.imeOrderGuard) {\r\n run();\r\n return;\r\n }\r\n const helper = this.compositionHelper(pane);\r\n const state = (0, ime_1.readCompositionState)(helper);\r\n const plan = (0, ime_1.planSend)(state);\r\n this.diag(`ime send=${tag} ${this.describeComposition(helper)} `\r\n + `state=${state} plan=${plan}`);\r\n if (plan === 'defer') {\r\n setTimeout(run, 0);\r\n return;\r\n }\r\n if (plan === 'after-composition') {\r\n this.writeAfterComposition(pane, tag, run);\r\n return;\r\n }\r\n run();\r\n }\r\n /**\r\n * 조합이 끝난 **뒤에** 우리 바이트를 쓴다.\r\n *\r\n * 왜 확정을 재촉하지 않나 — 우리가 동기 확정시켜도 IME 는 자기 일정대로 `compositionend` 를\r\n * 또 쏘고, xterm 이 그때 음절을 한 번 더 보낸다. 그 두 번째 전송이 우리 개행 뒤에 나가면\r\n * **음절이 새 줄로 내려간다**(사용자가 신고한 증상, `ime.ts` planSend 주석에 실측).\r\n * 그래서 IME 의 생애주기를 건드리지 않고 그것이 끝나기를 기다린다.\r\n *\r\n * `compositionend` 가 온 그 순간이 아니라 **그 안에서 예약된 전송이 나간 뒤**에 써야 하므로\r\n * 한 틱(`setTimeout 0`)을 더 준다 — xterm 의 `_finalizeComposition(true)` 가 같은 큐를 쓴다.\r\n *\r\n * 조합이 끝나지 않는 경우(IME 가 이벤트를 안 내거나 창 포커스가 빠짐)를 대비해\r\n * `IME_WAIT_MS` 뒤에는 동기 확정을 시키고 쓴다 — 입력이 영영 안 나가는 것이 최악이다.\r\n */\r\n writeAfterComposition(pane, tag, run) {\r\n const ta = (() => {\r\n var _a, _b, _c;\r\n try {\r\n return (_c = (_b = (_a = pane === null || pane === void 0 ? void 0 : pane.frontend) === null || _a === void 0 ? void 0 : _a.xterm) === null || _b === void 0 ? void 0 : _b.textarea) !== null && _c !== void 0 ? _c : null;\r\n }\r\n catch {\r\n return null;\r\n }\r\n })();\r\n if (!ta) {\r\n // 기다릴 곳이 없다 — 예전처럼 동기 확정 후 쓴다\r\n const flushed = (0, ime_1.flushComposition)(this.compositionHelper(pane), this.compositionTextLength(pane));\r\n this.diag(`ime send=${tag} no-textarea flushed=${flushed}`);\r\n run();\r\n return;\r\n }\r\n let done = false;\r\n const fire = (why) => {\r\n if (done) {\r\n return;\r\n }\r\n done = true;\r\n ta.removeEventListener('compositionend', onEnd);\r\n clearTimeout(timer);\r\n this.diag(`ime send=${tag} wrote-after=${why}`);\r\n // 조합 확정 전송(setTimeout 0)이 먼저 나가게 한 틱 양보한다\r\n setTimeout(run, 0);\r\n };\r\n const onEnd = () => fire('compositionend');\r\n const timer = setTimeout(() => {\r\n // 조합이 끝나지 않았다 — 더 기다리면 입력이 사라진 것처럼 보인다\r\n const flushed = (0, ime_1.flushComposition)(this.compositionHelper(pane), this.compositionTextLength(pane));\r\n this.diag(`ime send=${tag} timeout flushed=${flushed}`);\r\n fire('timeout');\r\n }, IME_WAIT_MS);\r\n ta.addEventListener('compositionend', onEnd, { once: true });\r\n }\r\n /**\r\n * pane 의 xterm 에서 조합 헬퍼를 집는다.\r\n *\r\n * `_core._compositionHelper` 는 xterm 내부다(`tabby-terminal/dist/index.js:50042` 에서 생성).\r\n * 언제 사라져도 이상하지 않으므로 못 찾으면 null 을 주고, 판정은 `unknown`(= 기존 동작)으로\r\n * 떨어진다. 예외를 밖으로 내보내면 입력 자체가 막히므로 절대 던지지 않는다.\r\n */\r\n compositionHelper(pane) {\r\n var _a, _b, _c, _d;\r\n try {\r\n return (_d = (_c = (_b = (_a = pane === null || pane === void 0 ? void 0 : pane.frontend) === null || _a === void 0 ? void 0 : _a.xterm) === null || _b === void 0 ? void 0 : _b._core) === null || _c === void 0 ? void 0 : _c._compositionHelper) !== null && _d !== void 0 ? _d : null;\r\n }\r\n catch {\r\n return null;\r\n }\r\n }\r\n /** 동기 확정이 읽을 textarea 길이 — 낡은 `_compositionPosition.end` 를 메우는 값 (ime.ts 참조) */\r\n compositionTextLength(pane) {\r\n var _a, _b, _c;\r\n try {\r\n const value = (_c = (_b = (_a = pane === null || pane === void 0 ? void 0 : pane.frontend) === null || _a === void 0 ? void 0 : _a.xterm) === null || _b === void 0 ? void 0 : _b.textarea) === null || _c === void 0 ? void 0 : _c.value;\r\n return typeof value === 'string' ? value.length : 0;\r\n }\r\n catch {\r\n return 0;\r\n }\r\n }\r\n /** 진단 한 줄에 넣을 헬퍼 원본값 — 판정(state)만 남기면 오판을 가릴 수 없다 */\r\n describeComposition(helper) {\r\n if (!helper) {\r\n return 'helper=none';\r\n }\r\n try {\r\n return `isComposing=${helper.isComposing} sending=${helper._isSendingComposition}`;\r\n }\r\n catch {\r\n return 'helper=unreadable';\r\n }\r\n }\r\n /**\r\n * Shift+Enter / Ctrl+Enter 를 document **캡처 단계**에서 직접 줄바꿈으로 바꾼다.\r\n *\r\n * 핫키(`agentdeck-newline`)에만 맡겼더니 한글을 치다 누르면 절반쯤 줄바꿈이 아니라\r\n * **전송**이 됐다 (2026-09-08 사용자 보고: \"50% 정도는 그냥 enter 로 들어간다\").\r\n * 진단로그에 증거가 남아 있다 — 오발신 순간 `enter-label` 이 발화했는데\r\n * (`.agentdeck-diag.log` 00:54:59 `enter-label text=\"지금도 그랬\"`), 그 핸들러는\r\n * 수식키가 하나라도 눌려 있으면 맨 앞에서 빠져나간다. 즉 그 Enter 는 **shiftKey 가\r\n * 지워진 채** 도착했다. 한글 IME 가 조합을 확정하며 Enter 를 한 번 삼키고, 뒤이어\r\n * 내보내는 이벤트에는 Shift 상태를 싣지 않는 것이다. Shift 가 없으니 `Shift-Enter`\r\n * 핫키에 매칭될 리 없고, xterm 은 평범한 Enter 로 0x0D 를 PTY 에 흘린다 —\r\n * 쓰다 만 문장이 그대로 전송된다.\r\n *\r\n * 그래서 이벤트가 알려주는 수식키를 믿지 않고 **Shift 눌림을 우리가 따로 센다**.\r\n * Shift 자체의 keydown/keyup 은 조합과 무관하게 그대로 오므로 IME 를 타지 않는다.\r\n * 세어 둔 값이 썩는 것(키업 유실)을 막으려고 창 포커스가 나가거나, Shift 없이 평범한\r\n * 글자가 들어오거나, 오래 묵으면(STALE_MS) 스스로 잊는다.\r\n *\r\n * 조합 중(`isComposing`/keyCode 229)인 Enter 는 손대지 않는다. 그건 \"이 음절을\r\n * 확정해라\" 는 신호고 여기서 막으면 마지막 글자가 확정되지 못한 채 줄만 넘어간다.\r\n * 확정이 끝나면 Enter 가 한 번 더 오니 그때 잡으면 글자 순서도 어긋나지 않는다.\r\n *\r\n * 캡처에서 전파를 끊는 이유는 claimCtrlVKey 와 같다 — 뒤에 걸린 경로(xterm 커스텀 키\r\n * 핸들러 → pushKeyEvent, core 의 document 리스너, xterm 이 Enter 를 0x0D 로 흘리는\r\n * 기본 동작)를 통째로 죽여야 줄바꿈이 정확히 한 번이 된다.\r\n */\r\n claimShiftEnterKey() {\r\n const STALE_MS = 5000;\r\n const forget = () => {\r\n this.shiftDownAt = 0;\r\n };\r\n const isShiftKey = (event) => event.key === 'Shift' || (event.code || '').startsWith('Shift');\r\n window.addEventListener('blur', forget);\r\n document.addEventListener('keyup', (event) => {\r\n if (isShiftKey(event)) {\r\n forget();\r\n }\r\n }, true);\r\n document.addEventListener('keydown', (event) => {\r\n if (isShiftKey(event)) {\r\n this.shiftDownAt = Date.now();\r\n return;\r\n }\r\n if (!this.config.store.agentDeck.claimShiftEnter) {\r\n return;\r\n }\r\n const isEnter = event.key === 'Enter' || event.code === 'Enter' || event.code === 'NumpadEnter';\r\n // Shift 없이 평범한 글자가 들어왔다 = Shift 는 확실히 떼어져 있다 (키업 유실 자가복구)\r\n if (!isEnter && !event.shiftKey && !event.getModifierState('Shift')) {\r\n forget();\r\n return;\r\n }\r\n if (!isEnter || event.altKey || event.metaKey) {\r\n return;\r\n }\r\n if (event.isComposing || event.keyCode === 229) {\r\n return; // 조합 확정용 Enter — 확정된 뒤에 한 번 더 온다\r\n }\r\n const tracked = this.shiftDownAt > 0 && Date.now() - this.shiftDownAt < STALE_MS;\r\n const shift = event.shiftKey || event.getModifierState('Shift') || tracked;\r\n if (!shift && !event.ctrlKey) {\r\n return; // 맨 Enter 는 전송이다 — 건드리지 않는다\r\n }\r\n if (this.isPlainInput(event.target) || this.isDeckUiKey(event.target)) {\r\n return;\r\n }\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.diag(`newline (capture) shiftKey=${event.shiftKey} `\r\n + `modState=${event.getModifierState('Shift')} tracked=${tracked} ctrl=${event.ctrlKey}`);\r\n this.sendNewline();\r\n }, true);\r\n }\r\n /**\r\n * Enter 를 눌러 프롬프트를 보낼 때, 그 프롬프트 원문을 작업 라벨로 삼는다.\r\n *\r\n * 왜 이게 필요한가 — 라벨을 채우는 다른 경로(훅·콘솔 제목)는 둘 다 배포판에서 못 믿는다.\r\n * 훅은 사용자가 `~/.claude/settings.json` 을 손봐야 돌고, 플러그인이 그걸 대신 깔아줄 수도 없다.\r\n * 콘솔 제목은 Claude Code 가 세션 첫 작업을 요약해 한 번 박고 그 뒤로 갱신하지 않는다\r\n * (2026-08-28 실측: 작업이 네 번 바뀌는 동안 `◑ sendInput 한 줄 vs 두 줄 원인 파악` 그대로).\r\n * 그래서 설정이 하나도 없는 상태에서 라벨을 최신으로 유지할 수 있는 건 이 경로뿐이다.\r\n *\r\n * **Enter 만 잡는다.** Shift+Enter / Ctrl+Enter 는 줄바꿈이라(agentdeck-newline) 아직 전송이\r\n * 아니고, 그때 라벨을 바꾸면 쓰다 만 문장이 박힌다. 수식키가 하나라도 눌려 있으면 그냥 흘린다.\r\n * IME 조합 중의 Enter(한글 확정)도 전송이 아니므로 제외한다.\r\n *\r\n * 관측만 하고 이벤트는 절대 막지 않는다 — 여기서 preventDefault 하면 프롬프트가 안 보내진다.\r\n */\r\n claimEnterLabel() {\r\n document.addEventListener('keydown', (event) => {\r\n var _a, _b;\r\n if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey) {\r\n return; // 줄바꿈이지 전송이 아니다\r\n }\r\n if (event.key !== 'Enter' && event.code !== 'Enter' && event.code !== 'NumpadEnter') {\r\n return;\r\n }\r\n if (event.isComposing || event.keyCode === 229) {\r\n return; // 한글 조합 확정용 Enter\r\n }\r\n if (this.isPlainInput(event.target) || this.isDeckUiKey(event.target)) {\r\n return;\r\n }\r\n // **한도 도달은 여기서 풀린다.** 사용자가 새 지시를 보냈다는 것이 \"다시 쓸 수 있게\r\n // 됐다\" 의 가장 이른 신호다. 화면 출력으로는 풀지 않는다 — 한도 화면도 상태줄을 계속\r\n // 다시 그려서 \"출력이 있다 = 진행중\" 으로 풀면 배지가 한 조각만 떴다 사라진다\r\n // (`detect.ts` 의 sticky 가드). `limited` 가 아니거나 사용자가 직접 지정한(pinned)\r\n // 상태면 no-op 이라 Enter 마다 불려도 안전하다.\r\n //\r\n // **`enterAsLabel` 가드보다 위에 있어야 한다.** 아래로 내려가면 라벨 기능을 끈\r\n // 사용자에게는 이 해제 경로가 통째로 죽는다 (한도는 라벨과 무관한 기능이다).\r\n const limitedTab = this.app.activeTab;\r\n if (limitedTab) {\r\n (0, detect_1.releaseLimited)(this.status, limitedTab);\r\n }\r\n if (!this.config.store.agentDeck.enterAsLabel) {\r\n return;\r\n }\r\n const pane = this.focusedPane();\r\n if (!pane) {\r\n this.diag(`enter-label skipped (no pane)`);\r\n return;\r\n }\r\n // 화면은 아직 프롬프트가 지워지기 전이다 — 캡처 단계라 앱이 Enter 를 보기 전에 읽는다\r\n const text = this.readPromptLine(pane);\r\n // 상태는 루트 탭 단위로 관리한다 (watchTab 이 app.tabs 로 감시하는 것과 같은 단위)\r\n const tab = this.app.activeTab;\r\n // 어느 프로필로 읽었는지 같이 남긴다 — 이 줄이 라벨 회귀를 가르는 유일한 근거라,\r\n // shape 를 주입하기 시작한 뒤로는 \"어떤 규칙으로 읽었나\" 까지 있어야 원인을 좁힐 수 있다\r\n this.diag(`enter-label text=\"${text}\" tab=${tab ? 'yes' : 'no'}`\r\n + ` profile=${(_b = (_a = this.profileForPane(pane)) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'default'}`);\r\n if (!text || !tab) {\r\n return;\r\n }\r\n this.status.setLabel(tab, text);\r\n }, true);\r\n }\r\n /**\r\n * xterm 화면 버퍼에서 지금 입력창에 쓰여 있는 프롬프트를 읽는다 (판정은 extractPrompt).\r\n *\r\n * 화면 맨 아래가 아니라 **커서 줄**을 기준점으로 잡는다. Claude Code 는 대화가 짧으면\r\n * 입력창을 화면 위쪽에 두고 그 아래를 전부 빈 줄로 남기는데(2026-08-28 실측), 아래 14줄만\r\n * 읽으면 빈 줄만 걸려 프롬프트를 영영 못 찾는다 — 라벨이 안 바뀌던 원인이 이것이다.\r\n * 커서는 항상 입력 중인 줄에 있고, 여러 줄 프롬프트면 마지막 줄에 있으니 거기서 위로 훑으면\r\n * `> ` 머리를 만난다. 커서 아래는 힌트 줄이라 애초에 읽지 않는 편이 정확하다.\r\n */\r\n readPromptLine(pane) {\r\n var _a, _b, _c, _d;\r\n const xterm = (_a = pane.frontend) === null || _a === void 0 ? void 0 : _a.xterm;\r\n const buf = (_b = xterm === null || xterm === void 0 ? void 0 : xterm.buffer) === null || _b === void 0 ? void 0 : _b.active;\r\n if (!buf || typeof buf.getLine !== 'function') {\r\n this.diag(`enter-label no-buffer frontend=${pane.frontend ? 'yes' : 'no'} xterm=${xterm ? 'yes' : 'no'}`);\r\n return '';\r\n }\r\n const read = (from, to) => {\r\n var _a, _b;\r\n const lines = [];\r\n for (let y = Math.max(0, from); y <= to; y++) {\r\n lines.push((_b = (_a = buf.getLine(y)) === null || _a === void 0 ? void 0 : _a.translateToString(true)) !== null && _b !== void 0 ? _b : '');\r\n }\r\n return lines;\r\n };\r\n const cursor = buf.baseY + ((_c = buf.cursorY) !== null && _c !== void 0 ? _c : 0);\r\n const nearCursor = read(cursor - PROMPT_SCAN_ROWS, cursor);\r\n const shape = (_d = this.profileForPane(pane)) === null || _d === void 0 ? void 0 : _d.promptShape;\r\n const byCursor = (0, prompt_1.extractPrompt)(nearCursor, shape);\r\n if (byCursor) {\r\n return byCursor;\r\n }\r\n // 커서가 입력창 밖에 있을 때의 폴백 — 화면 전체를 아래에서 위로 훑는다\r\n const byScreen = (0, prompt_1.extractPrompt)(read(buf.baseY, buf.baseY + xterm.rows - 1), shape);\r\n if (!byScreen) {\r\n // 두 경로가 다 빈손이면 화면이 어떻게 생겼는지 남긴다.\r\n // 이게 없어서 \"입력창 못 찾음\" 과 \"버퍼를 못 읽음\" 을 못 갈랐다 (2026-09-01).\r\n const dump = nearCursor.slice(-4)\r\n .map(l => JSON.stringify(l.slice(0, 60)))\r\n .join(' | ');\r\n this.diag(`enter-label miss baseY=${buf.baseY} cursorY=${buf.cursorY} rows=${xterm.rows} tail=${dump}`);\r\n }\r\n return byScreen;\r\n }\r\n /** 터미널이 아닌 보통 입력 필드(설정 화면 등)인지 — 거기서는 Ctrl+V 를 건드리지 않는다 */\r\n isPlainInput(target) {\r\n var _a;\r\n const el = target;\r\n if (!el || typeof el.closest !== 'function') {\r\n return false;\r\n }\r\n // xterm 이 키 입력을 받는 숨은 textarea 는 터미널이지 입력 필드가 아니다\r\n if (((_a = el.classList) === null || _a === void 0 ? void 0 : _a.contains('xterm-helper-textarea')) || el.closest('.xterm')) {\r\n return false;\r\n }\r\n return el.isContentEditable || ['INPUT', 'TEXTAREA'].includes(el.tagName);\r\n }\r\n /**\r\n * 이 키가 **우리 사이드바 안에서** 났나 — 그렇다면 터미널 몫이 아니다.\r\n *\r\n * `isPlainInput` 과 나란히 쓰는 두 번째 가드다. 그 함수는 \"보통 입력 필드냐\" 를 보므로\r\n * 검색창(`<input>`)은 이미 걸러 주지만, 키보드 내비게이션은 목록(`.ad-list`, DIV)이\r\n * 포커스를 갖는다 — 태그로는 터미널과 구별되지 않는다. 그대로 두면 목록에서 누른 Enter 가\r\n * 캡처 단계의 `claimEnterLabel` 에 먼저 걸려 **엉뚱한 탭의 화면을 읽어 라벨로 박고**,\r\n * Shift+Enter 는 `claimShiftEnterKey` 가 0x0A 를 pty 로 보낸다. 우리 리스너는 target\r\n * 단계라 캡처보다 늦게 돌아 끊을 수 없으니, 비켜 주는 쪽이 캡처여야 한다.\r\n *\r\n * 기존 동작은 바뀌지 않는다 — 이 판정이 참이 되는 상황은 **사이드바가 포커스를 가진 때**뿐이고,\r\n * 그런 상태는 이 기능이 생기기 전에는 검색창(이미 `isPlainInput` 이 비켜 줬다) 외에 없었다.\r\n */\r\n isDeckUiKey(target) {\r\n const el = target;\r\n if (!el || typeof el.closest !== 'function') {\r\n return false;\r\n }\r\n return !!el.closest('#' + SIDEBAR_ID);\r\n }\r\n /**\r\n * Ctrl+V 붙여넣기 — 클립보드가 이미지면 Alt+V 로 넘긴다.\r\n *\r\n * 터미널 붙여넣기는 \"클립보드 텍스트를 키 입력처럼 PTY 에 써넣는\" 동작이다\r\n * (`tabby-terminal/dist/index.js:41842` paste() → readClipboard() → sendInput).\r\n * PTY 는 바이트 스트림이라 이미지가 지나갈 방법 자체가 없고, 클립보드는 OS 자원이라\r\n * 터미널 안에서 도는 앱은 손댈 수 없다 — 그래서 이미지는 조용히 사라진다.\r\n *\r\n * Claude Code 는 이걸 자기가 OS 클립보드를 직접 읽어서 푼다. Alt+V(= ESC v)가 그\r\n * \"지금 클립보드를 읽어라\" 신호다. 즉 Ctrl+V 와 Alt+V 는 붙여넣는 주체가 다르다\r\n * (Ctrl+V = 터미널이 넣어줌 / Alt+V = 앱이 직접 읽음). 사용자가 그걸 구분할 이유는 없으니\r\n * 클립보드에 이미지만 있을 때 Ctrl+V 가 알아서 ESC v 를 대신 보낸다.\r\n *\r\n * 텍스트가 같이 들어 있으면(엑셀·워드 복사 등) 텍스트 붙여넣기를 유지한다 — 그쪽이 의도이므로.\r\n */\r\n doPaste(source) {\r\n // 한 번의 Ctrl+V / 우클릭이 여러 경로로 들어오는 일이 있다 (ensurePasteHotkey 주석 참고).\r\n // 어느 경로가 먼저 오든 처음 것만 살린다 — 사람 연타는 이 창보다 느리다.\r\n const now = Date.now();\r\n if (now - this.lastPasteAt < PASTE_DEDUPE_MS) {\r\n this.diag(`paste ignored (dup ${now - this.lastPasteAt}ms, ${source})`);\r\n return;\r\n }\r\n this.lastPasteAt = now;\r\n const pane = this.focusedPane();\r\n if (!pane) {\r\n return;\r\n }\r\n const imageOnly = this.clipboardHasImageOnly();\r\n this.diag(`paste probe enabled=${this.config.store.agentDeck.pasteImageWithCtrlV} imageOnly=${imageOnly} sendInput=${typeof pane.sendInput}`);\r\n if (this.config.store.agentDeck.pasteImageWithCtrlV\r\n && imageOnly\r\n && typeof pane.sendInput === 'function') {\r\n // 이미지 전용 클립보드 — 텍스트 붙여넣기는 어차피 아무것도 못 넣으므로\r\n // \"네가 직접 클립보드를 읽어라\" 키를 흘려보낸다 (sendImagePasteKey 주석 참고)\r\n void this.sendImagePasteKey(pane);\r\n return;\r\n }\r\n if (typeof pane.paste !== 'function') {\r\n return;\r\n }\r\n // 붙여넣기 한 번이 PTY 에 몇 번 써지는지 본다 (우클릭 2중 입력 추적용).\r\n // 창을 열어둔 동안의 입력만 남긴다 — 상시 켜두면 사람이 타이핑한 것까지 다 찍힌다.\r\n this.pasteProbeUntil = Date.now() + PASTE_PROBE_MS;\r\n this.probeSendInput(pane);\r\n this.probeWrite(pane);\r\n // 텍스트 붙여넣기는 xterm 이 네이티브 paste 이벤트로 이미 처리한다\r\n // (tabby-terminal/dist/index.js:5383 에서 textarea/element 에 handlePasteEvent 등록).\r\n // 그런데도 우리가 무조건 paste() 를 부르면 한 번 눌러 두 번 붙는다.\r\n // 그래서 네이티브가 오는지 잠깐 보고, 안 오면(터미널 textarea 가 포커스를 못 잡은 경우 등)\r\n // 그제야 우리가 붙인다 — 어느 쪽이든 정확히 한 번이 된다.\r\n this.diag(`paste (${source})`);\r\n if (source === 'ctrl-v') {\r\n // 캡처 단계에서 이미 preventDefault 했으므로 네이티브 paste 는 오지 않는다 — 기다릴 것 없이 바로 붙인다\r\n this.sendToPane(pane, 'paste-ctrl-v', () => void pane.paste());\r\n return;\r\n }\r\n const startedAt = Date.now();\r\n setTimeout(() => {\r\n if (this.nativePasteAt >= startedAt) {\r\n this.diag(`paste skipped (native handled)`);\r\n return;\r\n }\r\n this.diag(`paste fallback`);\r\n this.sendToPane(pane, 'paste-fallback', () => void pane.paste());\r\n }, PASTE_NATIVE_WAIT_MS);\r\n }\r\n /**\r\n * 이미지 전용 클립보드일 때 터미널 앱에 \"네가 클립보드를 직접 읽어라\" 키를 흘려보낸다.\r\n *\r\n * 어떤 키인지는 앱마다 다르다 (2026-08-28 실측):\r\n * - Claude Code: ESC v 만 받는다. 리터럴 0x16 은 5회 보내도 이미지가 들어가지 않았다\r\n * (`.agentdeck-diag.log` 09:33:47~48 `paste image (ctrl-v)` 5줄, 화면에는 아무 변화 없음).\r\n * claude.exe 안의 `ctrl+v ... paste images` 문구는 자기가 키 이벤트를 직접 볼 때의 안내였고,\r\n * PTY 로 들어온 0x16 에는 반응하지 않는다.\r\n * - Codex: 0x16 을 자기 붙여넣기로 받고, ESC v 는 모른다.\r\n * 그래서 탭에서 도는 앱을 보고 갈라 보내고, 못 알아내면 설정값(`imagePasteKey`)을 쓴다.\r\n */\r\n async sendImagePasteKey(pane) {\r\n const found = await this.detectAgentApp(pane);\r\n const profile = (0, agents_1.profileFor)(found.id);\r\n const configured = this.config.store.agentDeck.imagePasteKey;\r\n // 프로필의 `config` 는 \"이 에이전트가 무엇을 받는지 관측된 바 없다\" 는 뜻 —\r\n // 그때만 사용자 설정값으로 떨어진다 (claude=alt-v, codex=ctrl-v 는 실측값이다)\r\n const mode = profile.imagePasteKey === 'config' ? configured : profile.imagePasteKey;\r\n const key = mode === 'ctrl-v' ? '\u0016' : '\u001bv';\r\n this.diag(`paste image app=${found.id} via=${found.via} mode=${mode} `\r\n + `bytes=${[...key].map(c => c.charCodeAt(0)).join(',')}`);\r\n // doPaste 쪽이 아니라 여기서 진입점을 지난다 — 위 detectAgentApp 을 await 하는 동안\r\n // 조합 상태가 바뀌므로, 실제로 쓰는 시점에 다시 읽는 편이 정확하다.\r\n this.sendToPane(pane, 'paste-image', () => pane.sendInput(key));\r\n }\r\n /**\r\n * 터미널 위에 **파일을 끌어다 놓았을 때** 무엇을 할지 물어본다.\r\n *\r\n * 순정 Tabby 는 그 경로를 터미널에 붙여넣는다(`cat <경로>` 를 쉽게 만드는 유용한 동작이다).\r\n * 그런데 미리보기 패널이 생긴 뒤로는 \"그 파일을 보고 싶어서\" 끌어놓는 경우가 더 많은데,\r\n * 패널이 닫혀 있으면 경로만 붙고 아무것도 안 열린다(2026-09-09 유저 지적).\r\n *\r\n * 그래서 캡처 단계에서 드롭을 가로채고 **둘 중 하나를 고르게** 한다 —\r\n * `패널에 띄우기` / `경로 붙여넣기`. 자동으로 화면을 바꾸지 않는 이유는 붙여넣기만 원했던\r\n * 사람의 화면을 빼앗지 않기 위해서다(유저: \"한번 물어보긴 해야 할 듯\").\r\n *\r\n * `viewerDropOpen` 이 `always`/`paste` 면 묻지 않고 그 선택을 하고, `never` 면 아예\r\n * 개입하지 않아 순정 동작이 그대로 돈다.\r\n */\r\n claimFileDrop() {\r\n const overPanel = (target) => {\r\n var _a;\r\n const el = target;\r\n return !!((_a = el === null || el === void 0 ? void 0 : el.closest) === null || _a === void 0 ? void 0 : _a.call(el, '#agentdeck-view, #agentdeck-sidebar'));\r\n };\r\n // dragover 에서 preventDefault 를 하지 않으면 브라우저가 drop 을 아예 안 만든다\r\n document.addEventListener('dragover', (e) => {\r\n var _a, _b;\r\n if (this.config.store.agentDeck.viewerDropOpen === 'never' || overPanel(e.target)) {\r\n return;\r\n }\r\n if (!Array.from((_b = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes('Files')) {\r\n return;\r\n }\r\n e.preventDefault();\r\n }, true);\r\n document.addEventListener('drop', (e) => {\r\n var _a, _b, _c;\r\n const mode = this.config.store.agentDeck.viewerDropOpen;\r\n // 패널·사이드바 위 드롭은 그쪽 핸들러가 처리한다 (viewPanel.installDrop)\r\n if (mode === 'never' || overPanel(e.target)) {\r\n return;\r\n }\r\n const file = (_b = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0];\r\n const raw = (file === null || file === void 0 ? void 0 : file.path) || ((_c = e.dataTransfer) === null || _c === void 0 ? void 0 : _c.getData('text/plain')) || '';\r\n const target = String(raw).trim().replace(/^\"|\"$/g, '');\r\n if (!target) {\r\n return;\r\n }\r\n // 여기서 막지 않으면 순정 붙여넣기가 같이 일어나 \"붙여넣기\" 버튼이 무의미해진다\r\n e.preventDefault();\r\n e.stopPropagation();\r\n if (mode === 'always') {\r\n this.openDroppedInPanel(target);\r\n return;\r\n }\r\n if (mode === 'paste') {\r\n this.pasteDroppedPath(target);\r\n return;\r\n }\r\n this.askFileDrop(target);\r\n }, true);\r\n }\r\n /** 끌어다 놓은 파일을 미리보기 패널에서 연다 (패널이 닫혀 있으면 열면서) */\r\n openDroppedInPanel(file) {\r\n var _a, _b;\r\n (_a = this.view) === null || _a === void 0 ? void 0 : _a.setOpen(true, false);\r\n (_b = this.view) === null || _b === void 0 ? void 0 : _b.openFile(file);\r\n }\r\n /**\r\n * 끌어다 놓은 경로를 터미널에 넣는다 — 순정 Tabby 가 하던 그 일이다.\r\n *\r\n * 공백이 든 경로는 따옴표로 감싼다. 그러지 않으면 셸이 두 인자로 쪼개 읽는다.\r\n * **개행은 붙이지 않는다** — 사용자가 앞에 `cat` 을 붙일 여지를 남긴다.\r\n */\r\n pasteDroppedPath(file) {\r\n const pane = this.firstPane(this.app.activeTab);\r\n if (!pane) {\r\n return;\r\n }\r\n const text = /\\s/.test(file) ? `\"${file}\"` : file;\r\n this.sendToPane(pane, 'drop-paste', () => pane.sendInput(text));\r\n }\r\n /**\r\n * 드롭 확인 배너. **OS 모달이 아니라 인라인 카드**다 —\r\n * 모달은 터미널 흐름을 끊고, CDP 로 자동 검증할 수 없다(`showMessageBox` 는 프로브가\r\n * 응답할 방법이 없어 회귀가 그 자리에서 멈춘다).\r\n */\r\n askFileDrop(file) {\r\n var _a, _b, _c, _d;\r\n (_a = document.getElementById('agentdeck-drop-ask')) === null || _a === void 0 ? void 0 : _a.remove();\r\n const name = file.split(/[\\\\/]/).pop() || file;\r\n const card = document.createElement('div');\r\n card.id = 'agentdeck-drop-ask';\r\n card.className = 'ad-drop-ask';\r\n card.innerHTML = [\r\n '<div class=\"ad-drop-ask-msg\"></div>',\r\n '<div class=\"ad-drop-ask-row\">',\r\n ' <button class=\"ad-drop-ask-view\">패널에 띄우기</button>',\r\n ' <button class=\"ad-drop-ask-paste\">경로 붙여넣기</button>',\r\n ' <button class=\"ad-drop-ask-close\" title=\"아무것도 하지 않는다\">✕</button>',\r\n '</div>',\r\n '<label class=\"ad-drop-ask-again\">',\r\n ' <input type=\"checkbox\" class=\"ad-drop-ask-again-box\"> 다시 묻지 않기',\r\n '</label>',\r\n ].join('');\r\n const msg = card.querySelector('.ad-drop-ask-msg');\r\n // 파일명은 사용자 데이터다 — innerHTML 로 넣지 않는다\r\n msg.textContent = `${name} 을 어떻게 할까요?`;\r\n msg.title = file;\r\n const again = () => { var _a; return ((_a = card.querySelector('.ad-drop-ask-again-box')) === null || _a === void 0 ? void 0 : _a.checked) === true; };\r\n const remember = (mode) => {\r\n if (again()) {\r\n this.config.store.agentDeck.viewerDropOpen = mode;\r\n this.config.save();\r\n }\r\n };\r\n const close = () => card.remove();\r\n (_b = card.querySelector('.ad-drop-ask-view')) === null || _b === void 0 ? void 0 : _b.addEventListener('click', () => {\r\n remember('always');\r\n this.openDroppedInPanel(file);\r\n close();\r\n });\r\n (_c = card.querySelector('.ad-drop-ask-paste')) === null || _c === void 0 ? void 0 : _c.addEventListener('click', () => {\r\n remember('paste');\r\n this.pasteDroppedPath(file);\r\n close();\r\n });\r\n (_d = card.querySelector('.ad-drop-ask-close')) === null || _d === void 0 ? void 0 : _d.addEventListener('click', close);\r\n document.body.appendChild(card);\r\n // 방치하면 화면에 남는다 — 사용자가 아무것도 고르지 않은 것도 하나의 선택이다\r\n setTimeout(() => {\r\n if (document.getElementById('agentdeck-drop-ask') === card) {\r\n close();\r\n }\r\n }, 15000);\r\n }\r\n /**\r\n * 이 탭에서 도는 에이전트 CLI 가 뭔지 — 상태 감지 패턴과 이미지 붙여넣기 키가 앱마다 다르다.\r\n *\r\n * 프로세스 트리를 먼저 본다 (`session.getChildProcesses()`). npm 전역 래퍼를 거치면\r\n * 커맨드가 node/pwsh 로만 보일 수 있어서, 그때는 탭 제목으로 한 번 더 본다.\r\n * 어느 조각을 어떤 순서로 보는지는 `agents.ts` 의 프로필이 정한다 — 이 함수에 남은 일은\r\n * pane 에서 근거(프로세스 이름·제목)를 모으는 것뿐이다.\r\n *\r\n * `via` 를 함께 돌려주는 이유: 나중에 \"왜 codex 로 잡혔나\" 를 가르려면 프로세스에서\r\n * 나온 판정인지 제목(신뢰도가 낮다)에서 나온 판정인지가 유일한 단서다.\r\n */\r\n async detectAgentApp(pane) {\r\n var _a, _b, _c, _d, _e;\r\n let pids = [];\r\n try {\r\n const procs = (_c = await ((_b = (_a = pane.session) === null || _a === void 0 ? void 0 : _a.getChildProcesses) === null || _b === void 0 ? void 0 : _b.call(_a))) !== null && _c !== void 0 ? _c : [];\r\n const names = procs.map(x => { var _a, _b; return `${(_a = x === null || x === void 0 ? void 0 : x.command) !== null && _a !== void 0 ? _a : ''} ${(_b = x === null || x === void 0 ? void 0 : x.name) !== null && _b !== void 0 ? _b : ''}`; }).join(' ');\r\n const byProc = (0, agents_1.identifyAgent)(names, '');\r\n if (byProc !== 'unknown') {\r\n return { id: byProc, via: 'proc' };\r\n }\r\n pids = procs.map(x => Number(x === null || x === void 0 ? void 0 : x.pid)).filter(n => Number.isInteger(n) && n > 0);\r\n }\r\n catch {\r\n // 프로세스 트리를 못 읽는 세션(SSH 등) — 아래 제목으로 떨어진다\r\n }\r\n // **npm 전역 래퍼로 띄운 CLI 는 이름만으로는 영영 unknown 이다.**\r\n // 2026-09-08 실측: gemini 를 띄운 탭의 자식 프로세스는 `{ pid, command: 'node.exe' }`\r\n // 하나뿐이고 제목도 `◇ Ready (work)` 라 `gemini` 라는 글자가 어디에도 없다. 그런데\r\n // 그 pid 의 **명령줄**에는 그대로 들어 있다 —\r\n // \"…/node.exe\" C:/Users/…/npm/node_modules/@google/gemini-cli/bundle/gemini.js\r\n // 그래서 이름으로 못 가렸을 때만 pid 로 명령줄을 한 번 묻는다. 이름으로 잡히는\r\n // 경우(claude 처럼 자기 실행 파일로 뜨는 앱)에는 이 경로가 아예 돌지 않는다.\r\n const cmdline = await this.commandLinesOf(pids);\r\n if (cmdline) {\r\n const byCmd = (0, agents_1.identifyAgent)(cmdline, '');\r\n if (byCmd !== 'unknown') {\r\n return { id: byCmd, via: 'cmdline' };\r\n }\r\n }\r\n const title = `${(_d = pane.title) !== null && _d !== void 0 ? _d : ''} ${(_e = pane.customTitle) !== null && _e !== void 0 ? _e : ''}`;\r\n const byTitle = (0, agents_1.identifyAgent)('', title);\r\n return { id: byTitle, via: byTitle === 'unknown' ? 'none' : 'title' };\r\n }\r\n /**\r\n * 그 pid 들의 명령줄을 한 줄로 이어 돌려준다 (식별 폴백 전용).\r\n *\r\n * 비용이 있는 호출이라 **이름·제목으로 못 가렸을 때만** 부른다. 호출 빈도는 `probeAgent`\r\n * 의 TTL(`AGENT_PROBE_TTL_MS`)이 잡아 준다 — 출력 조각마다 도는 경로가 아니다.\r\n *\r\n * pid 는 **숫자만** 통과시킨다. 값을 명령에 이어 붙이는 자리라, 여기서 걸러내지 않으면\r\n * 그대로 셸에 넘어간다.\r\n */\r\n async commandLinesOf(pids) {\r\n const clean = pids.filter(n => Number.isInteger(n) && n > 0).slice(0, 8);\r\n if (!clean.length) {\r\n return null;\r\n }\r\n try {\r\n // eslint-disable-next-line\r\n const { execFile } = require('child_process');\r\n const isWin = process.platform === 'win32';\r\n const file = isWin ? 'powershell' : 'ps';\r\n const args = isWin\r\n // Win32_Process 의 CommandLine 이 우리가 원하는 그 문자열이다.\r\n // wmic 은 Windows 11 에서 폐기 대상이라 쓰지 않는다.\r\n ? ['-NoProfile', '-NonInteractive', '-Command',\r\n `Get-CimInstance Win32_Process -Filter \"${clean.map(n => `ProcessId=${n}`).join(' or ')}\"`\r\n + ' | Select-Object -ExpandProperty CommandLine']\r\n : ['-o', 'args=', '-p', clean.join(',')];\r\n return await new Promise(resolve => {\r\n const child = execFile(file, args, { timeout: 4000, windowsHide: true }, (err, stdout) => resolve(err && !stdout ? null : String(stdout !== null && stdout !== void 0 ? stdout : '')));\r\n child.on('error', () => resolve(null));\r\n });\r\n }\r\n catch {\r\n return null;\r\n }\r\n }\r\n /**\r\n * 이 탭의 에이전트를 알아내 기억한다 — 출력 경로에서 프로세스 트리를 묻지 않기 위한 캐시.\r\n *\r\n * TTL(`AGENT_PROBE_TTL_MS`)로 묶는다. 세션이 붙는 시점에는 셸만 떠 있고 사용자가 그 뒤\r\n * `claude` 를 직접 띄우는 경우가 흔해서, 한 번 unknown 이어도 제목이 바뀔 때 다시 본다.\r\n * 반대로 이미 알아낸 탭이 일시적으로 unknown 으로 읽히면(프로세스 트리 조회 실패 등)\r\n * 기억을 지우지 않는다 — 지웠다가 합집합으로 되돌아가면 판정이 왔다갔다 한다.\r\n */\r\n async probeAgent(root, why) {\r\n var _a, _b;\r\n const now = Date.now();\r\n if (now - ((_a = this.agentProbedAt.get(root)) !== null && _a !== void 0 ? _a : 0) < AGENT_PROBE_TTL_MS) {\r\n return;\r\n }\r\n this.agentProbedAt.set(root, now);\r\n const pane = this.firstPane(root);\r\n if (!pane) {\r\n return;\r\n }\r\n const session = pane.session;\r\n const observed = this.paneAgents.get(pane);\r\n const found = await this.detectAgentApp(pane);\r\n if (pane.session !== session) {\r\n return;\r\n }\r\n // A fresh process result can recover a stream identity invalidated by\r\n // a console title. The tab cache may belong to an exited application.\r\n if (found.id !== 'unknown' && (found.via === 'proc' || found.via === 'cmdline')\r\n && observed && this.paneAgents.get(pane) === observed && observed.session === session\r\n && observed.tracker.id === 'unknown') {\r\n observed.tracker.id = found.id;\r\n this.diag(`agent stream recovered id=${found.id} via=${found.via}`);\r\n }\r\n const prev = this.tabAgents.get(root);\r\n if (found.id === 'unknown' && prev && prev !== 'unknown') {\r\n return;\r\n }\r\n this.tabAgents.set(root, found.id);\r\n if (found.id !== prev) {\r\n this.diag(`agent tab=${JSON.stringify((_b = root.title) !== null && _b !== void 0 ? _b : '')}`\r\n + ` id=${found.id} via=${found.via} (${why})`);\r\n }\r\n }\r\n /** 그 탭의 첫 pane — 프로세스 트리를 물어볼 대상. 래퍼 탭(SplitTab)이면 자식 중 첫 번째 */\r\n firstPane(root) {\r\n var _a;\r\n const anyRoot = root;\r\n const panes = typeof anyRoot.getAllTabs === 'function'\r\n ? anyRoot.getAllTabs()\r\n : [root];\r\n return (_a = panes[0]) !== null && _a !== void 0 ? _a : null;\r\n }\r\n /**\r\n * 상태 감지에 넘길 프로필 — **아직 모르면 넘기지 않는다.**\r\n *\r\n * `undefined` 를 주면 detect 쪽 기본값(합집합)이 쓰이고, 그게 0.5.0 까지의 판정과 같다.\r\n * 판정 전이나 판정 실패(보통 셸)에 특정 에이전트 프로필을 씌우면, 그 에이전트에 없는\r\n * 문구를 못 잡아 예전보다 못해진다.\r\n */\r\n /**\r\n * pane 으로 들어오는 경로(화면 읽기·깨짐 판정)에서 쓰는 프로필.\r\n *\r\n * 상태는 root 탭 단위로 들고 있으므로(SplitTab 래퍼) pane 을 부모로 올려서 찾는다 —\r\n * `decorator.ts` 의 `rootOf` 와 같은 규칙이다. 정규화하지 않으면 자식에 쓰고 부모를 읽어\r\n * 영영 매칭되지 않는다.\r\n */\r\n profileForPane(pane) {\r\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;\r\n try {\r\n const root = ((_c = (_b = (_a = this.app).getParentTab) === null || _b === void 0 ? void 0 : _b.call(_a, pane)) !== null && _c !== void 0 ? _c : pane);\r\n const state = (_d = this.paneAgents) === null || _d === void 0 ? void 0 : _d.get(pane);\r\n const x = (_e = pane === null || pane === void 0 ? void 0 : pane.frontend) === null || _e === void 0 ? void 0 : _e.xterm;\r\n const buffer = (_f = x === null || x === void 0 ? void 0 : x.buffer) === null || _f === void 0 ? void 0 : _f.active;\r\n const current = (state === null || state === void 0 ? void 0 : state.session) === pane.session ? state : undefined;\r\n // Rendering, keyboard, wheel and the periodic screen check all use\r\n // this path. Recover from the live UI even if process/title probes\r\n // failed; never reuse a previous PTY's visible terminal contents.\r\n if (buffer && (!state || current) && (!(current === null || current === void 0 ? void 0 : current.tracker.id) || current.tracker.id === 'unknown')) {\r\n const visible = Array.from({ length: x.rows }, (_, i) => { var _a, _b; return (_b = (_a = buffer.getLine(buffer.baseY + i)) === null || _a === void 0 ? void 0 : _a.translateToString(true)) !== null && _b !== void 0 ? _b : ''; });\r\n if ((0, screenAgent_1.isLiveCodexScreen)(visible)) {\r\n const tracker = (_g = current === null || current === void 0 ? void 0 : current.tracker) !== null && _g !== void 0 ? _g : new screenAgent_1.TerminalAgentTracker();\r\n tracker.id = 'codex';\r\n (_h = this.paneAgents) === null || _h === void 0 ? void 0 : _h.set(pane, { session: pane.session, tracker });\r\n (_j = this.tabAgents) === null || _j === void 0 ? void 0 : _j.set(root, 'codex');\r\n (_k = this.diag) === null || _k === void 0 ? void 0 : _k.call(this, 'agent stream recovered id=codex via=live-screen');\r\n return (0, agents_1.detectProfileFor)('codex');\r\n }\r\n }\r\n if ((state === null || state === void 0 ? void 0 : state.session) === pane.session && (state === null || state === void 0 ? void 0 : state.tracker.id) !== undefined) {\r\n return state.tracker.id === 'unknown' ? undefined : (0, agents_1.detectProfileFor)(state.tracker.id);\r\n }\r\n const known = this.profileForTab(root);\r\n // Claude always keeps its existing input/rendering path. A cached\r\n // Codex identity may outlive that process when a shell is reused.\r\n if (known && known.id !== 'codex') {\r\n return known;\r\n }\r\n if (!buffer) {\r\n return known;\r\n }\r\n const from = Math.max(0, buffer.baseY - 60);\r\n const lines = [];\r\n for (let i = from; i < buffer.baseY + x.rows; i++) {\r\n lines.push((_m = (_l = buffer.getLine(i)) === null || _l === void 0 ? void 0 : _l.translateToString(true)) !== null && _m !== void 0 ? _m : '');\r\n }\r\n const id = (0, screenAgent_1.identifyScreenAgent)(lines);\r\n if (id === 'claude') {\r\n return (0, agents_1.detectProfileFor)('claude');\r\n }\r\n if (known) {\r\n return known;\r\n }\r\n return id === 'unknown' ? undefined : (0, agents_1.detectProfileFor)(id);\r\n }\r\n catch {\r\n return undefined;\r\n }\r\n }\r\n profileForTab(root) {\r\n const id = this.tabAgents.get(root);\r\n // `detectProfileFor` — 화면 문구가 실측되지 않은 에이전트(codex/gemini)는 판정 패턴만\r\n // 합집합으로 떨어진다. 프로필을 붙였다는 이유로 판정이 0.5.0 보다 나빠지면 안 된다\r\n return id && id !== 'unknown' ? (0, agents_1.detectProfileFor)(id) : undefined;\r\n }\r\n /**\r\n * pane.sendInput 을 한 번 감싸 PTY 로 나간 입력을 진단 로그에 남긴다.\r\n *\r\n * 붙여넣기 한 번에 텍스트가 두 번 들어가는 증상은 \"우리가 두 번 불렀는지\" 와\r\n * \"한 번 불렀는데 PTY 에 두 번 써졌는지\" 를 갈라야 원인이 잡힌다. 이 계측이 그 경계다.\r\n * `pasteProbeUntil` 창 안에서만 기록하므로 평소 타이핑은 남지 않는다.\r\n */\r\n probeSendInput(pane) {\r\n if (!pane || pane.__adSendInputProbe || typeof pane.sendInput !== 'function') {\r\n return;\r\n }\r\n const orig = pane.sendInput.bind(pane);\r\n pane.__adSendInputProbe = true;\r\n pane.sendInput = (data, ...rest) => {\r\n if (Date.now() < this.pasteProbeUntil) {\r\n const text = typeof data === 'string' ? data : String(data);\r\n this.diag(`sendInput len=${text.length} `\r\n + `head=${JSON.stringify(text.slice(0, 24))} from=${this.callSite()}`);\r\n }\r\n return orig(data, ...rest);\r\n };\r\n }\r\n /**\r\n * PTY 로 나가는 최종 관문(session.write)을 랩핑한다.\r\n *\r\n * pane.sendInput 만 보면 그걸 거치지 않는 경로를 놓친다 — 실측(2026-08-28 09:44:03)에서\r\n * 우클릭 한 번에 sendInput 은 154바이트 1회뿐인데 화면에는 두 번 들어갔다. 즉 두 번째는\r\n * 우리 계측 밖의 경로다. session.write 는 어느 경로든 마지막에 지나가므로 여기서 잡힌다.\r\n */\r\n probeWrite(pane) {\r\n const session = pane === null || pane === void 0 ? void 0 : pane.session;\r\n if (!session || session.__adWriteProbe || typeof session.write !== 'function') {\r\n return;\r\n }\r\n const orig = session.write.bind(session);\r\n session.__adWriteProbe = true;\r\n session.write = (data, ...rest) => {\r\n if (Date.now() < this.pasteProbeUntil) {\r\n const text = typeof data === 'string' ? data : String(data);\r\n this.diag(`write len=${text.length} `\r\n + `head=${JSON.stringify(text.slice(0, 24))} from=${this.callSite()}`);\r\n }\r\n return orig(data, ...rest);\r\n };\r\n }\r\n /** 호출 지점 몇 프레임 — 두 번째 붙여넣기를 누가 넣는지 보려고 */\r\n callSite() {\r\n var _a;\r\n return ((_a = new Error().stack) !== null && _a !== void 0 ? _a : '').split(String.fromCharCode(10)).slice(3, 7)\r\n .map(l => l.trim().replace(/^at\\s+/, '')).join(' <- ');\r\n }\r\n /** 클립보드에 이미지가 있고 텍스트는 비어 있는지 */\r\n clipboardHasImageOnly() {\r\n const cb = getClipboard();\r\n if (!cb) {\r\n // Electron clipboard 를 못 쓰는 환경(웹 빌드 등) — 텍스트 붙여넣기로 떨어진다\r\n this.diag(`clipboard unavailable`);\r\n return false;\r\n }\r\n try {\r\n const hasImage = !cb.readImage().isEmpty();\r\n const text = cb.readText();\r\n this.diag(`clipboard hasImage=${hasImage} textLen=${text.length}`);\r\n return hasImage && text.trim() === '';\r\n }\r\n catch (err) {\r\n this.diag(`clipboard read failed: ${err}`);\r\n return false;\r\n }\r\n }\r\n /** 분할된 탭이면 래퍼가 아니라 실제 포커스된 pane 을 돌려준다 */\r\n focusedPane() {\r\n var _a;\r\n const active = this.app.activeTab;\r\n if (!active) {\r\n return null;\r\n }\r\n return typeof active.getFocusedTab === 'function'\r\n ? ((_a = active.getFocusedTab()) !== null && _a !== void 0 ? _a : active)\r\n : active;\r\n }\r\n /**\r\n * 줄바꿈 핫키에 Shift+Enter 를 보정해 넣는다.\r\n *\r\n * config.yaml 에 이미 `agentdeck-newline` 이 저장돼 있으면 ConfigProvider 의 defaults 는\r\n * 무시되므로(저장값이 이긴다) 기동 시 코드로 채워 넣어야 한다 — ensurePasteHotkey 와 같은 이유.\r\n */\r\n ensureNewlineHotkey() {\r\n const hotkeys = this.config.store.hotkeys;\r\n if (!hotkeys || !Array.isArray(hotkeys['agentdeck-newline'])) {\r\n return;\r\n }\r\n const list = hotkeys['agentdeck-newline'];\r\n if (list.includes('Shift-Enter')) {\r\n return;\r\n }\r\n hotkeys['agentdeck-newline'] = [...list, 'Shift-Enter'];\r\n this.config.save();\r\n }\r\n // ---------- 우클릭 ----------\r\n /**\r\n * 우클릭 처리를 agentdeck 이 가져온다.\r\n *\r\n * 증상: 우클릭 한 번에 클립보드가 두 번 들어갔다.\r\n * 원인: Tabby 의 우클릭 처리는 터미널 host 엘리먼트에 건 버블 단계 mouseup 리스너인데\r\n * (`tabby-terminal/dist/index.js:40972` 에서 등록, `detach()` 는 이 리스너를 떼지 않는다)\r\n * 프론트엔드가 같은 host 에 다시 attach 되면 리스너가 겹쳐 붙어 mouseEvent$ 가 한 클릭에\r\n * 두 번 발화한다. 그러면 `handleRightMouseUp` 이 두 번 돌아 paste() 도 두 번 나간다.\r\n *\r\n * 해결: Tabby 쪽 처리를 끄고(terminal.rightClick = 'off') document 캡처 단계에서\r\n * 우리가 한 번만 처리한다. 캡처는 host 리스너보다 먼저 돌기 때문에 몇 개가 겹쳐 붙어 있든\r\n * stopPropagation 으로 전부 차단된다. 동작 자체는 Tabby 의 'clipboard' 모드와 동일하게 —\r\n * 선택이 있으면 복사, 없으면 붙여넣기, 길게 누르면 컨텍스트 메뉴 — 유지한다.\r\n */\r\n claimRightClick() {\r\n if (!this.config.store.agentDeck.claimRightClick) {\r\n return;\r\n }\r\n // Tabby 자체 처리를 꺼서 리스너가 겹쳐도 아무 일이 없게 만든다 (이중 안전장치)\r\n if (this.config.store.terminal && this.config.store.terminal.rightClick !== 'off') {\r\n this.config.store.terminal.rightClick = 'off';\r\n this.config.save();\r\n }\r\n document.addEventListener('mousedown', ev => {\r\n if (ev.button !== 2 || !this.inTerminalArea(ev)) {\r\n return;\r\n }\r\n this.rightDownAt = Date.now();\r\n // mouseup 만 막으면 mousedown 이 xterm 까지 내려가 마우스 리포트가 PTY 로 나간다.\r\n // Claude Code 처럼 마우스 트래킹을 켠 앱은 그 우클릭 리포트(ESC [ < 2 ; x ; y M)를\r\n // 자기 붙여넣기 신호로 받아 스스로 클립보드를 읽는다 — 우리 paste 와 합쳐 두 번 붙는다\r\n // (2026-08-28 실측: .agentdeck-diag.log 09:49:08.616 에 \"\u001b[<2;172;35M\" 전송,\r\n // 플러그인 write 는 클릭당 1회뿐인데 화면에는 2회 들어감).\r\n ev.preventDefault();\r\n ev.stopPropagation();\r\n }, { capture: true });\r\n // 우클릭에 딸려오는 contextmenu 도 캡처에서 끊는다 (메뉴는 길게 누를 때 우리가 직접 띄운다)\r\n document.addEventListener('contextmenu', ev => {\r\n if (this.inTerminalArea(ev)) {\r\n ev.preventDefault();\r\n ev.stopPropagation();\r\n }\r\n }, { capture: true });\r\n document.addEventListener('mouseup', ev => {\r\n if (ev.button !== 2 || !this.inTerminalArea(ev)) {\r\n return;\r\n }\r\n ev.preventDefault();\r\n ev.stopPropagation();\r\n // 같은 물리 클릭이 두 번 들어오면(리스너 중복) 뒤엣것은 버린다\r\n const now = Date.now();\r\n if (now - this.lastRightHandledAt < 150) {\r\n return;\r\n }\r\n this.lastRightHandledAt = now;\r\n const held = now - this.rightDownAt;\r\n void this.handleRightClick(ev, held);\r\n }, { capture: true });\r\n }\r\n /** 사이드바가 아니라 터미널 뷰포트 안에서 일어난 이벤트인지 */\r\n inTerminalArea(ev) {\r\n const target = ev.target;\r\n if (!target || typeof target.closest !== 'function') {\r\n return false;\r\n }\r\n return !!target.closest('.content.main') && !target.closest(`#${SIDEBAR_ID}`);\r\n }\r\n async handleRightClick(ev, heldMs) {\r\n var _a, _b;\r\n const pane = this.focusedPane();\r\n if (!pane) {\r\n return;\r\n }\r\n const menuMs = (_a = this.config.store.agentDeck.rightClickMenuMs) !== null && _a !== void 0 ? _a : 250;\r\n if (heldMs >= menuMs) {\r\n if (typeof pane.buildContextMenu === 'function' && pane.platform) {\r\n pane.platform.popupContextMenu(await pane.buildContextMenu(), ev);\r\n }\r\n return;\r\n }\r\n const selection = typeof ((_b = pane.frontend) === null || _b === void 0 ? void 0 : _b.getSelection) === 'function'\r\n ? pane.frontend.getSelection()\r\n : '';\r\n if (selection) {\r\n pane.frontend.copySelection();\r\n pane.frontend.clearSelection();\r\n }\r\n else {\r\n // 우클릭 붙여넣기도 Ctrl+V 와 같은 경로를 타게 한다 (이미지면 Alt+V 위임)\r\n this.doPaste('rightclick');\r\n }\r\n }\r\n /**\r\n * 포커스된 pane 에 0x0A(LF) 를 보낸다 — Ctrl+J 가 보내는 것과 같은 바이트다.\r\n * Claude Code 는 이걸 줄바꿈으로 받고, Enter(0x0D) 는 전송으로 받는다.\r\n * Enter 를 눌러 줄을 넘기지 않으려는 것이므로 CR 을 섞으면 안 된다.\r\n */\r\n sendNewline() {\r\n var _a, _b, _c;\r\n const pane = this.focusedPane();\r\n if (!pane) {\r\n return;\r\n }\r\n if (typeof pane.sendInput === 'function') {\r\n // 조합 중인 음절이 이 LF 보다 먼저 나가게 순서를 맞춘다 (sendToPane 주석).\r\n // Shift+Enter 로 조합 중인 음절이 새 줄로 따라가던 원인이 바로 이 직접 쓰기다\r\n // (2026-09-08 사용자 재보고) — 여기는 xterm 을 거치지 않으므로 동기 확정이 걸리지 않는다.\r\n const sequence = (0, terminalInput_1.newlineSequence)((_a = this.profileForPane(pane)) === null || _a === void 0 ? void 0 : _a.id);\r\n this.diag(`newline agent=${(_c = (_b = this.profileForPane(pane)) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : 'unknown'} sequence=${JSON.stringify(sequence)}`);\r\n this.sendToPane(pane, 'newline', () => pane.sendInput(sequence));\r\n }\r\n }\r\n // ---------- 레이아웃 ----------\r\n get enabled() {\r\n return this.config.store.agentDeck.enabled;\r\n }\r\n applyEnabled() {\r\n var _a;\r\n document.body.classList.toggle(BODY_CLASS, this.enabled);\r\n if (this.sidebar) {\r\n this.sidebar.style.display = this.enabled ? '' : 'none';\r\n }\r\n // 레이아웃을 끄면 미리보기도 같이 숨는다 (열림 상태는 설정에 그대로 남긴다)\r\n (_a = this.view) === null || _a === void 0 ? void 0 : _a.setVisible(this.enabled);\r\n if (!this.enabled && this.mainEl) {\r\n for (const prop of ['flex', 'width', 'max-width', 'height',\r\n 'margin-left', 'margin-right', 'margin-top', 'margin-bottom']) {\r\n this.mainEl.style.removeProperty(prop);\r\n }\r\n // 폭을 되돌렸으니 메모도 무효화하고 터미널에 새 폭을 알린다\r\n this.lastTermW = -1;\r\n this.lastSidebarW = -1;\r\n this.lastViewW = -1;\r\n this.lastViewSide = null;\r\n this.lastDock = null;\r\n this.scheduleRefit();\r\n }\r\n this.syncBackgroundClip();\r\n }\r\n /**\r\n * tabby-background 의 이미지 레이어를 터미널 영역(`.content.main`)에 맞춰 자른다.\r\n *\r\n * 그 레이어는 `position: fixed` 라 viewport 좌표를 쓰므로 `getBoundingClientRect()` 값을\r\n * 그대로 CSS 변수로 내리면 된다 (styles.scss 가 `!important` 로 덮어쓴다).\r\n * relayout 직후에는 인라인 폭이 아직 레이아웃에 반영되지 않았을 수 있어 rAF 한 번 뒤에 잰다.\r\n * 꺼져 있으면(또는 agentdeck 비활성) 클래스와 변수를 걷어 순정(창 전체)으로 되돌린다.\r\n */\r\n syncBackgroundClip() {\r\n const root = document.documentElement;\r\n const clear = () => {\r\n document.body.classList.remove(BG_CLIP_CLASS);\r\n for (const v of ['--ad-bg-left', '--ad-bg-top', '--ad-bg-width', '--ad-bg-height']) {\r\n root.style.removeProperty(v);\r\n }\r\n };\r\n if (!this.enabled || !this.config.store.agentDeck.clipBackgroundToTerminal || !this.mainEl) {\r\n clear();\r\n return;\r\n }\r\n requestAnimationFrame(() => {\r\n if (!this.enabled || !this.mainEl) {\r\n clear();\r\n return;\r\n }\r\n const r = this.mainEl.getBoundingClientRect();\r\n if (r.width <= 0 || r.height <= 0) {\r\n return;\r\n }\r\n root.style.setProperty('--ad-bg-left', Math.round(r.left) + 'px');\r\n root.style.setProperty('--ad-bg-top', Math.round(r.top) + 'px');\r\n root.style.setProperty('--ad-bg-width', Math.round(r.width) + 'px');\r\n root.style.setProperty('--ad-bg-height', Math.round(r.height) + 'px');\r\n document.body.classList.add(BG_CLIP_CLASS);\r\n });\r\n }\r\n /**\r\n * 터미널/사이드바 배경에 알파를 넣어 tabby-background 의 배경 이미지가 비치게 한다.\r\n *\r\n * 배경 이미지는 `.content-tab-active::before` 로 **모든 내용 뒤에** 깔린다. 그래서\r\n * 그 위를 덮는 두 면이 불투명하면 이미지는 어디에도 보이지 않는다 —\r\n * (1) 터미널: xterm 이 컬러스킴 background 색으로 셀을 직접 칠한다 (CSS 로는 못 뚫는다)\r\n * (2) 사이드바 / .window: 우리가 넣은 불투명 배경\r\n * (1) 은 Tabby 가 xterm 을 `allowTransparency: true` 로 만들기 때문에 색에 알파만 넣으면 된다.\r\n * config.yaml 을 손으로 고쳐도 Tabby 가 종료할 때 메모리 값으로 덮어써 되돌아가므로,\r\n * ensurePasteHotkey 와 같은 이유로 여기서 코드로 보정한다.\r\n */\r\n applyOpacity() {\r\n var _a;\r\n const cfg = this.config.store.agentDeck;\r\n const termPct = clampPct(cfg.terminalOpacity);\r\n const sidePct = clampPct(cfg.sidebarOpacity);\r\n // 사이드바 / 창 여백 — CSS 변수로 내려보낸다 (styles.scss 가 폴백을 들고 있다)\r\n const root = document.documentElement;\r\n if (sidePct >= 100) {\r\n root.style.removeProperty('--ad-panel-bg');\r\n }\r\n else {\r\n root.style.setProperty('--ad-panel-bg', `rgba(30, 33, 39, ${sidePct / 100})`);\r\n }\r\n // 터미널 — 컬러스킴 배경색에 알파를 붙인다\r\n const scheme = (_a = this.config.store.terminal) === null || _a === void 0 ? void 0 : _a.colorScheme;\r\n if (!(scheme === null || scheme === void 0 ? void 0 : scheme.background)) {\r\n return;\r\n }\r\n const next = withAlpha(scheme.background, termPct);\r\n // 컬러스킴 기반 배경을 쓰도록 못 박는다 — 테마 배경으로 떨어지면 알파가 무시된다\r\n const wantMode = termPct < 100 ? 'colorScheme' : this.config.store.terminal.background;\r\n if (next === scheme.background && wantMode === this.config.store.terminal.background) {\r\n // 이미 적용돼 있다. 여기서 save 를 부르면 changed$ 가 다시 우리를 부른다\r\n return;\r\n }\r\n scheme.background = next;\r\n this.config.store.terminal.background = wantMode;\r\n this.config.save();\r\n }\r\n /** 지금 사이드바가 붙어 있는 방향 (설정값이 망가져 있으면 오른쪽으로 본다) */\r\n get dockSide() {\r\n const v = this.config.store.agentDeck.sidebarDock;\r\n return (0, dock_1.isDockSide)(v) ? v : 'right';\r\n }\r\n /**\r\n * 사이드바가 차지할 크기를 px 로 정한다 — 좌/우면 폭, 상/하면 높이.\r\n *\r\n * 사용자가 경계선을 한 번이라도 끌었으면 그 값(`sidebarWidth`/`sidebarHeight`)이 진실이다.\r\n * 아직 안 끌었다면(폭이 0) 예전처럼 화면비로 터미널 폭을 역산해 남는 만큼을 사이드바가 갖는다.\r\n */\r\n sidebarExtent(availW, availH, winH) {\r\n const cfg = this.config.store.agentDeck;\r\n if ((0, dock_1.isHorizontalDock)(this.dockSide)) {\r\n const minSidebar = cfg.sidebarMin || 200;\r\n const maxSidebar = Math.max(cfg.sidebarMax || 560, minSidebar);\r\n let want = cfg.sidebarWidth || 0;\r\n if (!want) {\r\n // 화면비를 지킨다는 가정에서 터미널 폭을 높이로 역산하고 남는 폭을 사이드바에 준다\r\n const ratio = (cfg.aspectW || 4) / (cfg.aspectH || 3);\r\n let termW = Math.round(availH * ratio);\r\n termW = Math.min(termW, availW - minSidebar);\r\n termW = Math.max(termW, MIN_TERM_W);\r\n want = availW - termW;\r\n }\r\n // 손으로 끈 값은 설정의 min/max 를 넘어설 수 있다 — 마우스가 우선이므로\r\n // 목록이 읽히는 최소 폭과 터미널이 남을 최대 폭까지만 막는다\r\n const hardMin = cfg.sidebarWidth ? MIN_SIDEBAR_W : minSidebar;\r\n const hardMax = Math.max(availW - MIN_TERM_W, hardMin);\r\n const softMax = cfg.sidebarWidth ? Math.max(maxSidebar, cfg.sidebarWidth) : maxSidebar;\r\n return Math.min(Math.max(want, hardMin), softMax, hardMax);\r\n }\r\n // 세로 도킹은 창 높이를 기준으로 잡는다 — 터미널 높이(availH)는 사이드바를 뺀 값이라\r\n // 그걸로 클램프하면 잴 때마다 값이 줄어드는 되먹임이 생긴다\r\n const want = cfg.sidebarHeight || 200;\r\n return Math.min(Math.max(want, MIN_SIDEBAR_H), Math.max(winH - MIN_TERM_H, MIN_SIDEBAR_H));\r\n }\r\n /** 사이드바를 창 한쪽에 붙이고, 남는 자리를 `.content.main` 이 갖게 한다 */\r\n relayout() {\r\n var _a, _b, _c, _d;\r\n if (!this.enabled || !this.windowEl) {\r\n this.diagOnce('relayout-skip-enabled', `relayout skipped enabled=${this.enabled} windowEl=${!!this.windowEl}`);\r\n return;\r\n }\r\n // appRoot 가 늦게 렌더되는 경우가 있어 매번 다시 찾는다\r\n if (!this.mainEl) {\r\n this.mainEl = document.querySelector('.content.main');\r\n }\r\n if (!this.mainEl) {\r\n this.diagOnce('relayout-skip-mainel', 'relayout skipped mainEl=null');\r\n return;\r\n }\r\n const availW = this.windowEl.clientWidth;\r\n // 화면비로 폭을 역산할 때 쓰는 높이는 터미널이 실제로 쓰는 높이여야 한다.\r\n // 창 높이를 쓰면 탭바 등을 뺀 만큼 폭이 과대 계산돼 사이드바가 좁아진다\r\n const availH = this.mainEl.clientHeight || this.windowEl.clientHeight;\r\n if (!availW || !availH) {\r\n return;\r\n }\r\n const side = this.dockSide;\r\n const horizontal = (0, dock_1.isHorizontalDock)(side);\r\n // 미리보기 패널이 먼저 자기 폭을 갖고, 사이드바는 그 나머지 안에서 화면비를 계산한다.\r\n // **여기서 4:3 이 완화된다** — 패널을 열면 터미널이 그만큼 좁아진다(사이드바는 안 줄어든다).\r\n // 반대로 하면(터미널 4:3 고정) 창이 좁을 때 패널이 열릴 자리가 없다 (2026-09-08 결정).\r\n const viewSide = this.viewSide;\r\n // 패널이 써도 되는 폭 = 창폭 − 터미널 최소 − 사이드바 최소.\r\n // 이 계산이 없으면 좁은 창에서 패널이 터미널 자리까지 먹는다\r\n const viewRoom = availW - MIN_TERM_W - (horizontal ? MIN_SIDEBAR_W : 0);\r\n const viewW = Math.round((_b = (_a = this.view) === null || _a === void 0 ? void 0 : _a.extent(viewRoom)) !== null && _b !== void 0 ? _b : 0);\r\n const layoutW = Math.max(availW - viewW, MIN_TERM_W);\r\n let extent = Math.round(this.sidebarExtent(layoutW, availH, this.windowEl.clientHeight));\r\n // 사이드바/패널이 가로로 먹는 몫을 빼고 남는 것이 터미널 폭이다\r\n const sideW = horizontal ? extent : 0;\r\n const leftPad = (side === 'left' ? sideW : 0) + (viewSide === 'left' ? viewW : 0);\r\n const rightPad = (side === 'right' ? sideW : 0) + (viewSide === 'right' ? viewW : 0);\r\n let termW = availW - leftPad - rightPad;\r\n // 터미널 폭을 문자 셀의 정수배로 깎는다.\r\n //\r\n // 셀 폭으로 나누어떨어지지 않으면 오른쪽에 셀 하나가 안 되는 자투리가 남는데,\r\n // fit() 은 그 자투리를 두고 창이 몇 px 만 흔들려도 열 수가 오르내린다. 열 수가 바뀔 때마다\r\n // pty 에 새 크기가 나가고 TUI 는 전체를 다시 그린다 — 화면이 깜빡이고 어긋날 틈이 생긴다.\r\n // 정수배로 맞춰 두면 자투리가 사라져 열 수가 흔들리지 않는다. 깎아 낸 픽셀은 사이드바가 갖는다.\r\n // 한때 이 자리에서 터미널 폭을 문자 셀의 정수배로 깎았다. 자투리 픽셀을 없애려던 건데\r\n // 오히려 화면이 계속 밀리는 원인이 됐다 — 셀 폭은 폰트가 자리를 잡는 동안 조금씩 다르게\r\n // 잡히고(2026-09-01 실측: 같은 창에서 termW 가 1977 -> 1970 -> 1974 로 진동),\r\n // 폭이 바뀔 때마다 pty 를 다시 맞추고 TUI 를 다시 그리게 만들었다.\r\n // 폭은 사용자가 정한 사이드바 크기에서 곧장 나오는 값 하나로 고정하는 편이 안정적이다.\r\n // 남는 자투리는 어차피 배경색이라 눈에 띄지 않는다.\r\n extent = Math.round(extent);\r\n termW = Math.round(termW);\r\n // 값이 그대로면 DOM 을 건드리지 않는다 — relayout 은 탭/상태가 바뀔 때마다 불리므로\r\n // 매번 스타일을 다시 쓰면 xterm 이 불필요하게 재측정한다\r\n // 미리보기 패널의 방향도 메모에 넣어야 한다 — 폭이 그대로인 채 좌↔우만 바뀌는 경우가\r\n // 있고(설정 변경), 그때 여기서 되돌아가면 패널이 옛 자리에 남는다 (2026-09-08 실측)\r\n if (termW === this.lastTermW && extent === this.lastSidebarW && side === this.lastDock\r\n && viewW === this.lastViewW && viewSide === this.lastViewSide) {\r\n return;\r\n }\r\n const prevTermW = this.lastTermW;\r\n this.lastTermW = termW;\r\n this.lastSidebarW = extent;\r\n this.lastDock = side;\r\n this.lastViewW = viewW;\r\n this.lastViewSide = viewSide;\r\n // 기동 직후 흔들기(rearm kick)는 폐지했다 — 아래 relayout 주석 참고.\r\n // 사이드바는 창 위에 절대 배치한다. flex 자식으로 두면 도킹 방향을 바꿀 때마다\r\n // `.window` 의 flex-direction 을 뒤집어야 하고, 그러면 같은 줄에 있는 profile-tree 까지\r\n // 따라 움직인다. 절대 배치면 우리 것만 옮기면 된다.\r\n if (this.sidebar) {\r\n const s = this.sidebar.style;\r\n s.position = 'absolute';\r\n s.left = side === 'right' ? 'auto' : '0';\r\n s.right = side === 'left' ? 'auto' : '0';\r\n s.top = side === 'bottom' ? 'auto' : '0';\r\n s.bottom = side === 'top' ? 'auto' : '0';\r\n s.width = horizontal ? extent + 'px' : 'auto';\r\n s.height = horizontal ? 'auto' : extent + 'px';\r\n for (const d of dock_1.DOCK_SIDES) {\r\n this.sidebar.classList.toggle('ad-dock-' + d, d === side);\r\n }\r\n }\r\n // 터미널이 차지할 자리.\r\n //\r\n // 가로 도킹에서는 폭을 px 로 못 박는다. margin 만 주고 flex 에게 남는 폭을 맡겨 봤더니\r\n // (2026-09-01) xterm 이 fit 할 때 잡는 폭과 TUI 가 아는 폭이 어긋나 입력창이 깨졌다 —\r\n // 가로선과 입력 텍스트가 한 줄에 섞여 wrap 되는 그 증상이다. 폭을 직접 주면 xterm host 가\r\n // 재는 값이 곧 우리가 정한 값이라 어긋날 여지가 없다.\r\n // 세로 도킹은 폭을 건드릴 필요가 없고, `h-100`(height:100%) 때문에 margin 만으로는\r\n // 그만큼 창 밖으로 넘치므로 높이를 대신 깎는다.\r\n // 미리보기 패널도 사이드바와 같은 자리를 나눠 쓴다 — 같은 쪽에 붙었으면 사이드바가\r\n // 창 가장자리(바깥), 패널이 터미널 쪽(안)이다\r\n (_c = this.view) === null || _c === void 0 ? void 0 : _c.layout(viewSide, viewW, side === viewSide ? sideW : 0);\r\n const m = this.mainEl.style;\r\n // 폭을 못 박아야 하는 경우: 가로 도킹이거나, 세로 도킹이어도 미리보기 패널이 폭을 먹을 때\r\n if (horizontal || viewW > 0) {\r\n m.flex = '0 0 ' + termW + 'px';\r\n m.width = termW + 'px';\r\n m.maxWidth = termW + 'px';\r\n // 왼쪽에 붙은 것(사이드바/패널)만큼 앞자리를 비운다.\r\n // 오른쪽 것들은 고정폭만으로 자리가 남는다 (둘 다 절대 배치라서)\r\n m.marginLeft = leftPad + 'px';\r\n m.marginRight = '0';\r\n }\r\n else {\r\n m.removeProperty('flex');\r\n m.removeProperty('width');\r\n m.removeProperty('max-width');\r\n m.marginLeft = '0';\r\n m.marginRight = '0';\r\n }\r\n if (horizontal) {\r\n m.removeProperty('height');\r\n m.marginTop = '0';\r\n m.marginBottom = '0';\r\n }\r\n else {\r\n m.marginTop = side === 'top' ? extent + 'px' : '0';\r\n m.marginBottom = side === 'bottom' ? extent + 'px' : '0';\r\n // **`important` 가 필요하다.** `.content.main` 에는 부트스트랩 `h-100` 클래스가 붙어\r\n // 있고 그 규칙이 `height: 100% !important` 라, 평범한 인라인 스타일은 진다.\r\n // 그래서 상하 도킹에서 터미널 높이가 전혀 줄지 않았다 — bottom 이면 아래쪽이\r\n // 사이드바에 가리고, top 이면 그만큼 창 밖으로 넘쳤다\r\n // (2026-09-02 실측, 창 1100x700 / 사이드바 200: 인라인은 `calc(100% - 200px)` 인데\r\n // computed 는 `700px`, host 는 top 에서 `1070x670@y=215` 로 하단 185px 가 잘렸다).\r\n m.setProperty('height', 'calc(100% - ' + extent + 'px)', 'important');\r\n }\r\n (_d = this.dock) === null || _d === void 0 ? void 0 : _d.syncHandle();\r\n this.syncBackgroundClip();\r\n // 우리가 하는 일은 여기까지다 — **폭을 정해 `.content.main` 에 적고 fit 한 번.**\r\n //\r\n // 2026-09-02 방향 전환(유저 지적): \"Tabby 는 창 크기가 어떻든 알아서 줄맞춤 되잖아?\" 맞다.\r\n // 순정 경로는 xterm `ResizeObserver` → `fitAddon.fit()` → `session.resize()` 이고,\r\n // 우리가 폭만 정해 주면 그 뒤는 Tabby 가 스스로 계산한다.\r\n // 예전에는 \"순정이 우리 CSS 변경을 못 따라온다\"고 보고 보정을 4겹 쌓았다 —\r\n // relayout 시 fit / `watchSize`(250ms 마다 fit+resize, 6초) / `syncPtySize` 재전송 사슬 /\r\n // `nudgePtyRedraw`(cols-1↔cols 흔들기). 그 겹침이 순정 수렴과 경쟁하면서\r\n // 프레임을 반쯤 그린 상태를 남겼고, 그게 실사용 깨짐의 정체였다(항목 24~28 은 전부 그 부작용).\r\n // 전제도 로그로 반박됐다 — 폭은 탭이 생기기 전에 이미 확정돼 있는데도\r\n // (`rearm kick termW -1->2000 panes=0`) 새 탭 xterm 이 254 로 뜬다. 그건 레이아웃 확정 전의\r\n // 초기 측정값일 뿐이고 순정 옵저버가 어차피 수렴시킨다.\r\n // 그래서 자동 보정은 전부 걷어냈다. 남은 건 이 fit 하나(순정 경로를 깨우는 용도)다.\r\n this.scheduleRefit();\r\n // 폭이 어긋나는 사고를 다시 만나면 이 줄이 실제 값을 알려 준다 —\r\n // 우리가 정한 값(termW)과 브라우저가 실제로 준 폭(clientWidth)이 다르면 그게 원인이다\r\n this.diag(`relayout dock=${side} avail=${availW}x${availH}`\r\n + ` extent=${extent} termW=${termW} mainW=${this.mainEl.clientWidth}`);\r\n }\r\n /**\r\n * 폭을 바꿨으면 터미널에 반드시 알려야 한다.\r\n *\r\n * Tabby 의 xterm 프론트엔드는 창(OS 창) 리사이즈에 맞춰 재측정하지만,\r\n * 우리처럼 CSS 로만 `.content.main` 폭을 바꾸면 그 경로를 타지 않는다.\r\n * 그러면 xterm 의 열 수는 넓어졌는데 pty 는 옛 폭 그대로라, Claude Code 같은\r\n * 전체화면 TUI 가 화면보다 좁게 그리고 오른쪽에 지워지지 않은 잔상이 남는다\r\n * (2026-08-28 실측: 입력창 구분선이 화면 중간에서 끊기고 옛 statusline 이 우측에 박혀 있었다.\r\n * 창을 복원→최대화로 흔들면 OS 리사이즈 경로를 타서 즉시 정상 복구됐다).\r\n *\r\n * fitAddon.fit() 이 xterm 의 onResize 를 발화시키고, Tabby 가 그걸 받아\r\n * session.resize() 로 pty 까지 내려보낸다. 값이 같으면 xterm 이 이벤트를 내지 않으므로\r\n * 여분 호출은 무해하다.\r\n */\r\n scheduleRefit() {\r\n if (this.refitQueued) {\r\n return;\r\n }\r\n this.refitQueued = true;\r\n // 레이아웃이 실제로 반영된 뒤에 재야 한다 — 한 프레임으로는 아직 옛 폭이 잡힌다\r\n requestAnimationFrame(() => requestAnimationFrame(() => {\r\n this.refitQueued = false;\r\n this.refitTerminals();\r\n }));\r\n // attach() 가 아직 진행 중이면 위 fit 이 무시될 수 있다. fit 은 크기가 같으면\r\n // 아무 일도 안 하므로 한 번 더 늦게 때려도 무해하다\r\n setTimeout(() => this.refitTerminals(), 500);\r\n }\r\n refitTerminals() {\r\n var _a, _b;\r\n for (const tab of this.app.tabs) {\r\n const anyTab = tab;\r\n const panes = typeof anyTab.getAllTabs === 'function'\r\n ? anyTab.getAllTabs()\r\n : [tab];\r\n for (const pane of panes) {\r\n const frontend = pane.frontend;\r\n const fitAddon = frontend === null || frontend === void 0 ? void 0 : frontend.fitAddon;\r\n if (!fitAddon || typeof fitAddon.fit !== 'function') {\r\n continue;\r\n }\r\n // 숨겨진 탭은 컨테이너 폭이 0 이라 fit 하면 1열짜리로 줄어든다 — 건너뛴다.\r\n // 그 탭은 다시 선택될 때 Tabby 가 알아서 재측정한다\r\n const host = (_b = (_a = frontend.xterm) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.parentElement;\r\n if (!host || !host.clientWidth || !host.clientHeight) {\r\n continue;\r\n }\r\n try {\r\n fitAddon.fit();\r\n }\r\n catch {\r\n // 아직 붙지 않은 프론트엔드 — 다음 relayout 때 다시 잡힌다\r\n }\r\n // 여기서 끝낸다. 예전에는 뒤이어 `syncPtySize` 로 pty 에 직접 크기를 쐈는데,\r\n // fit() 이 이미 순정 경로(onResize → session.resize)를 태우므로 중복이고,\r\n // 그 중복이 순정 수렴과 경쟁해 화면을 깨뜨렸다 (2026-09-02).\r\n }\r\n }\r\n }\r\n /**\r\n * pty 크기를 xterm 이 실제로 그리고 있는 크기에 강제로 맞춘다.\r\n *\r\n * `fitAddon.fit()` 은 xterm 의 열/행이 이미 맞으면 onResize 를 내지 않는다. 그런데 새 탭은\r\n * xterm 은 우리가 줄여 놓은 폭으로 제대로 열리는데 **세션(pty)만** 생성 시점의 옛 폭으로 남는\r\n * 경우가 있다. 이때 fit() 은 no-op 이라 pty 가 영영 안 고쳐지고, TUI 가 처음 화면을 다시\r\n * 그리는 순간(줄바꿈 등) 오른쪽에 옛 폭 잔상이 남는다 — 창 복원→최대화로 흔들면 OS 리사이즈\r\n * 경로를 타서 그제야 맞는다(2026-08-28 실측, 새 탭에서 재현).\r\n *\r\n * 그래서 fit() 뒤에 pty 로 직접 한 번 더 내려보낸다. 같은 값이면 pty 쪽에서 무시되므로 무해하다.\r\n */\r\n syncPtySize(pane, frontend) {\r\n var _a, _b;\r\n const cols = (_a = frontend === null || frontend === void 0 ? void 0 : frontend.xterm) === null || _a === void 0 ? void 0 : _a.cols;\r\n const rows = (_b = frontend === null || frontend === void 0 ? void 0 : frontend.xterm) === null || _b === void 0 ? void 0 : _b.rows;\r\n if (!cols || !rows) {\r\n return;\r\n }\r\n const anyPane = pane;\r\n const session = anyPane.session;\r\n if (!session || !session.open || typeof session.resize !== 'function') {\r\n return;\r\n }\r\n // 이 경로는 지금까지 조용했다. 그래서 \"언제 pty 폭이 바뀌었나\" 가 로그에 안 남아\r\n // 어긋남 사고를 만나도 발생 지점을 못 짚었다 (watchSize 의 `size fix` 만 남았다).\r\n // 값이 실제로 달라질 때만 남긴다 — 같은 값 재전송은 매 refit 마다 일어나므로 시끄럽다.\r\n const prev = anyPane.size;\r\n if ((prev === null || prev === void 0 ? void 0 : prev.columns) !== cols || (prev === null || prev === void 0 ? void 0 : prev.rows) !== rows) {\r\n this.diag(`pty resize ${prev === null || prev === void 0 ? void 0 : prev.columns}x${prev === null || prev === void 0 ? void 0 : prev.rows}`\r\n + ` -> ${cols}x${rows}`);\r\n }\r\n try {\r\n session.resize(cols, rows);\r\n anyPane.size = { columns: cols, rows };\r\n }\r\n catch (e) {\r\n // 세션이 막 닫혔다 — 다음 refit 때 다시 잡힌다\r\n (0, diag_1.diagCatch)('pty resize', e);\r\n return;\r\n }\r\n // **보냈다고 도착한 것이 아니다.**\r\n //\r\n // 세션이 막 열린 직후의 `session.resize()` 는 pty 에 닿지 못하고 유실된다\r\n // (2026-09-01 실측: `size fix 254x78 -> 280x78` + `pty resize` + `redraw nudge` 가\r\n // 모두 돌고 `pane.size` 도 280 으로 남았는데, 같은 탭 셸에 물어보니 `PTYW=254`.\r\n // 같은 호출을 몇 초 뒤에 CDP 로 하면 그때는 정상 반영된다 — 초기화 경합이다).\r\n // 그런데 `pane.size` 에 낙관적으로 280 을 적어 두므로, 크기 감시(watchSize)는\r\n // \"이제 맞다\" 고 보고 손을 뗀다. 그 뒤에 뜨는 TUI 는 254 폭으로 첫 화면을 그린다.\r\n //\r\n // 그래서 값이 실제로 바뀐 경우에만 같은 크기를 몇 번 더 보낸다. pty 크기가 이미\r\n // 그 값이면 아무 일도 일어나지 않으므로(SIGWINCH 도 안 난다) 재전송은 무해하다.\r\n if ((prev === null || prev === void 0 ? void 0 : prev.columns) !== cols || (prev === null || prev === void 0 ? void 0 : prev.rows) !== rows) {\r\n for (const delay of PTY_RESIZE_RETRY_MS) {\r\n setTimeout(() => {\r\n var _a, _b;\r\n const now = (_a = anyPane.frontend) === null || _a === void 0 ? void 0 : _a.xterm;\r\n // 그동안 폭이 또 바뀌었으면 그쪽 경로가 새 값을 보낸다 — 옛 값을 덮어쓰지 않는다\r\n if (!((_b = anyPane.session) === null || _b === void 0 ? void 0 : _b.open) || (now === null || now === void 0 ? void 0 : now.cols) !== cols || (now === null || now === void 0 ? void 0 : now.rows) !== rows) {\r\n return;\r\n }\r\n try {\r\n anyPane.session.resize(cols, rows);\r\n }\r\n catch (e) {\r\n // 세션이 닫혔다\r\n (0, diag_1.diagCatch)('pty resize retry', e);\r\n }\r\n }, delay);\r\n }\r\n }\r\n }\r\n /**\r\n * pty 크기만 한 칸 줄였다 되돌려 TUI 가 화면을 다시 그리게 한다. **수동 복구 전용.**\r\n *\r\n * 자동 경로에서는 전부 걷어냈다 — 이 흔들기가 순정 수렴과 경쟁하며 깨진 화면을\r\n * 만들어 왔다(2026-09-02). 남겨 둔 이유는 `repairPane`(사이드바 `↻` / `agentdeck-repair`)\r\n * 때문이다. 거기서는 사용자가 \"지금 깨졌으니 고쳐라\" 를 명시로 눌렀고, 크기를 맞추는\r\n * 것만으로는 앱이 다시 그리지 않는 경우가 실제로 있다 — 폭이 **실제로 바뀌어야**\r\n * SIGWINCH 가 나가므로 한 칸 흔들어 두 번 내보낸다. 뒤이어 `Ctrl+L` 이 따라간다.\r\n *\r\n * 좁힌 값을 `pane.size` 에 그대로 적는다. 되돌리기가 유실됐는데 낙관적으로 `cols` 를\r\n * 적어 두면 아무도 어긋남을 못 보고 한 열 좁은 채로 굳는다(옛 버그).\r\n */\r\n nudgePtyRedraw(pane) {\r\n var _a, _b, _c, _d;\r\n const anyPane = pane;\r\n const session = anyPane.session;\r\n const cols = (_b = (_a = anyPane.frontend) === null || _a === void 0 ? void 0 : _a.xterm) === null || _b === void 0 ? void 0 : _b.cols;\r\n const rows = (_d = (_c = anyPane.frontend) === null || _c === void 0 ? void 0 : _c.xterm) === null || _d === void 0 ? void 0 : _d.rows;\r\n if (!(session === null || session === void 0 ? void 0 : session.open) || typeof session.resize !== 'function' || !(cols > 1) || !(rows > 1)) {\r\n return;\r\n }\r\n this.diag(`redraw nudge ${cols}x${rows}`);\r\n try {\r\n session.resize(cols - 1, rows);\r\n anyPane.size = { columns: cols - 1, rows };\r\n setTimeout(() => {\r\n var _a;\r\n if (!((_a = anyPane.session) === null || _a === void 0 ? void 0 : _a.open)) {\r\n return;\r\n }\r\n // 되돌릴 값은 \"지금\" 의 xterm 폭이다 — 흔드는 사이 사이드바가 움직였을 수 있다\r\n this.syncPtySize(pane, anyPane.frontend);\r\n }, 60);\r\n }\r\n catch {\r\n // 세션이 막 닫혔다\r\n }\r\n }\r\n // 크기 감시(`watchSize` / `watchAllSizes`)도 폐지했다 (2026-09-02).\r\n //\r\n // 250ms 마다 `fitAddon.fit()` + `session.resize()` 를 6초간 쏘던 장치다. 목적은\r\n // \"xterm 은 넓어졌는데 pty 는 옛 폭\" 을 잡는 것이었는데, 그 어긋남은 순정\r\n // ResizeObserver 가 이미 수렴시킨다. 우리 감시는 그 수렴 도중의 중간값을 보고\r\n // 계속 끼어들었고, 끝에 `nudgePtyRedraw` 흔들기까지 붙여 화면을 깨뜨렸다.\r\n // 순정이 정말 못 맞추는 경우가 나오면 `screenWatch` 채증에 남는다 — 그때 근거를 갖고 되켠다.\r\n // ---------- 사이드바 DOM ----------\r\n buildSidebar() {\r\n const el = document.createElement('div');\r\n el.id = SIDEBAR_ID;\r\n el.innerHTML = [\r\n '<div class=\"ad-head\">',\r\n ' <span class=\"ad-head-title\">AGENT DECK</span>',\r\n ' <span class=\"ad-head-count\"></span>',\r\n '</div>',\r\n // 검색 줄은 헤더와 목록 **사이**에 둔다. 목록 안에 넣으면 render() 가 지우고,\r\n // 헤더 안에 넣으면 200px 사이드바에서 제목·집계 칩과 자리를 다툰다.\r\n '<div class=\"ad-search\">',\r\n ' <input class=\"ad-search-input\" type=\"text\" spellcheck=\"false\"',\r\n ' placeholder=\"세션 검색 (제목 · 작업이름 · 폴더)\">',\r\n ' <button class=\"ad-search-clear\" type=\"button\" title=\"검색·필터 지우기 (Esc)\">×</button>',\r\n '</div>',\r\n '<div class=\"ad-list\"></div>',\r\n '<div class=\"ad-foot\">',\r\n ' <button class=\"ad-btn ad-new\" title=\"새 탭\">+ 새 탭</button>',\r\n ' <button class=\"ad-btn ad-settings\" title=\"설정\">설정</button>',\r\n // 화면이 깨졌을 때 누르는 자리 — 창을 복원→최대화로 흔들던 것을 대신한다.\r\n // 자주 쓰는 두 버튼(새 탭·설정) 뒤에 둔다 (2026-09-01 유저 요청)\r\n ' <button class=\"ad-btn ad-repair\" title=\"화면 복구 (모든 탭 다시 그리기)\">↻</button>',\r\n ' <button class=\"ad-btn ad-viewtoggle\" title=\"미리보기 패널 (md · 이미지 · 표)\">▤</button>',\r\n '</div>',\r\n ].join('\\n');\r\n // 순정 탭바보다 뒤(오른쪽)에 놓는다 — 왼쪽에 두면 세로로 길어 허전하다는 피드백(2026-08-28)\r\n this.windowEl.appendChild(el);\r\n this.sidebar = el;\r\n this.listEl = el.querySelector('.ad-list');\r\n this.wireSearch(el);\r\n this.wireListKeys(this.listEl);\r\n el.querySelector('.ad-new').addEventListener('click', () => {\r\n this.zone.run(() => { void this.openNewTab(); });\r\n });\r\n el.querySelector('.ad-repair').addEventListener('click', () => {\r\n this.zone.run(() => this.repair('all'));\r\n });\r\n el.querySelector('.ad-settings').addEventListener('click', () => {\r\n this.zone.run(() => this.openSettings());\r\n });\r\n el.querySelector('.ad-viewtoggle').addEventListener('click', () => {\r\n this.zone.run(() => { var _a; return (_a = this.view) === null || _a === void 0 ? void 0 : _a.toggle(); });\r\n });\r\n // 크기/도킹은 설정 창이 아니라 마우스로 맞춘다.\r\n // 드래그 중에는 relayout 이 초당 수십 번 불리므로 config.save() 는 손을 뗄 때만 부른다.\r\n this.dock = new dock_1.DockController({\r\n sidebar: el,\r\n windowEl: this.windowEl,\r\n getDock: () => this.dockSide,\r\n setDock: side => {\r\n this.config.store.agentDeck.sidebarDock = side;\r\n },\r\n getSize: side => {\r\n const cfg = this.config.store.agentDeck;\r\n if (!(0, dock_1.isHorizontalDock)(side)) {\r\n return cfg.sidebarHeight || 0;\r\n }\r\n // 지금 좌/우로 붙어 있다면 화면에 실제로 적용된 폭이 가장 정확하다\r\n // (자동 계산 상태면 sidebarWidth 가 0 이라 물어봐야 소용이 없다)\r\n return (0, dock_1.isHorizontalDock)(this.dockSide) && this.lastSidebarW > 0\r\n ? this.lastSidebarW\r\n : (cfg.sidebarWidth || 0);\r\n },\r\n setSize: px => {\r\n const cfg = this.config.store.agentDeck;\r\n if ((0, dock_1.isHorizontalDock)(this.dockSide)) {\r\n cfg.sidebarWidth = px;\r\n }\r\n else {\r\n cfg.sidebarHeight = px;\r\n }\r\n },\r\n commit: () => this.zone.run(() => this.config.save()),\r\n relayout: () => this.relayout(),\r\n });\r\n this.dock.install();\r\n }\r\n /**\r\n * 검색창 배선.\r\n *\r\n * 키 이벤트를 여기서 끊는 이유는 `startLabelEdit` 와 같다 — 안 끊으면 터미널로 새어 나간다.\r\n * 캡처 단계 리스너들(Ctrl+V·Shift+Enter·Enter 라벨)은 `isPlainInput` 이 이 입력창을\r\n * \"터미널이 아닌 보통 입력 필드\" 로 판정해 이미 비켜 준다(INPUT 태그 + .xterm 밖).\r\n */\r\n wireSearch(root) {\r\n const input = root.querySelector('.ad-search-input');\r\n const clear = root.querySelector('.ad-search-clear');\r\n if (!input) {\r\n return;\r\n }\r\n this.searchEl = input;\r\n // **`input` 이벤트만 본다.** keydown 으로 값을 읽으면 IME 조합 중에는 아직 반영되지 않은\r\n // 값을 보게 되어 한글이 한 박자 늦고, 붙여넣기·마우스로 지우기도 놓친다.\r\n // 조합 중에도 `input` 은 조합 중인 글자를 담아 오므로 좁혀지는 것이 바로 보인다.\r\n input.addEventListener('input', () => {\r\n this.searchQuery = input.value;\r\n this.syncSearchUi();\r\n this.render();\r\n });\r\n input.addEventListener('compositionstart', () => {\r\n this.searchComposing = true;\r\n });\r\n input.addEventListener('compositionend', () => {\r\n this.searchComposing = false;\r\n });\r\n input.addEventListener('keydown', ev => {\r\n ev.stopPropagation();\r\n // ↓ = 결과 목록으로 내려간다. `<input>` 에서 ↑↓ 의 브라우저 기본 동작은 한 줄 입력이라\r\n // 커서를 맨 앞/맨 뒤로 보내는 것뿐인데, ↓(맨 뒤)는 End 와 겹쳐 잃는 것이 없다.\r\n // **↑ 는 넘기지 않는다** — 검색창 위에는 아무것도 없고, 치던 검색어를 고치려면 커서를\r\n // 앞으로 보내는 그 기본 동작이 필요하다. 목록에서 검색창으로 돌아오는 길은 첫 줄에서의\r\n // ↑ 다(`moveNav`) — 화면상 검색창이 목록 **위**에 있으니 방향이 그대로 맞는다.\r\n if (ev.key === 'ArrowDown' || ev.code === 'ArrowDown') {\r\n // 조합 중의 방향키는 IME 것이다(후보 고르기) — 건드리지 않는다\r\n if (this.searchComposing || ev.isComposing || !this.navReady) {\r\n return;\r\n }\r\n ev.preventDefault();\r\n // **항상 첫 줄로 들어간다.** 검색어를 방금 고친 사람이 원하는 것은 첫 결과이고,\r\n // 지난 포커스는 이미 필터 밖일 수도 있다.\r\n this.focusList('first');\r\n return;\r\n }\r\n if (ev.key !== 'Escape' && ev.code !== 'Escape') {\r\n return;\r\n }\r\n // **조합 중의 Esc 는 IME 의 조합 취소다.** 그때 검색을 지우면 한글을 쓰다 만 사람이\r\n // 쓴 것을 통째로 잃는다 — 조합만 취소되도록 흘려보낸다.\r\n if (this.searchComposing || ev.isComposing) {\r\n return;\r\n }\r\n ev.preventDefault();\r\n // 지우기와 나가기의 순서는 `navEscape` 한 곳에서 정한다 (목록의 Esc 와 같아야 한다)\r\n this.navEscape();\r\n });\r\n clear === null || clear === void 0 ? void 0 : clear.addEventListener('click', () => {\r\n var _a;\r\n this.clearFilters();\r\n // 지우고 나면 계속 칠 차례다 — 포커스를 입력창에 남긴다\r\n (_a = this.searchEl) === null || _a === void 0 ? void 0 : _a.focus();\r\n });\r\n this.applySearchBox();\r\n }\r\n /** 검색어와 상태 필터를 한 번에 지운다 — Esc 와 `✕` 가 같은 곳으로 온다(\"전체 목록으로\") */\r\n clearFilters() {\r\n this.searchQuery = '';\r\n this.statusFilter = null;\r\n if (this.searchEl) {\r\n this.searchEl.value = '';\r\n }\r\n this.syncSearchUi();\r\n this.render();\r\n }\r\n /** 검색어가 있을 때만 `✕` 를 보여준다 — 빈 칸 옆의 지우기 버튼은 무엇을 지우는지 알 수 없다 */\r\n syncSearchUi() {\r\n var _a;\r\n const row = (_a = this.sidebar) === null || _a === void 0 ? void 0 : _a.querySelector('.ad-search');\r\n row === null || row === void 0 ? void 0 : row.classList.toggle('has-query', !!this.searchQuery.trim() || !!this.statusFilter);\r\n }\r\n /**\r\n * 검색 줄을 보일지 (`searchBox` 설정).\r\n *\r\n * **끌 때 필터도 같이 지운다.** 입력창만 감추고 검색어를 남기면 목록이 좁혀진 이유가\r\n * 화면에서 사라진다 — 사용자에게는 탭이 사라진 것과 구분되지 않는다.\r\n */\r\n applySearchBox() {\r\n var _a;\r\n const row = (_a = this.sidebar) === null || _a === void 0 ? void 0 : _a.querySelector('.ad-search');\r\n const on = this.config.store.agentDeck.searchBox !== false;\r\n if (row) {\r\n row.style.display = on ? '' : 'none';\r\n }\r\n if (!on && (this.searchQuery || this.statusFilter)) {\r\n this.clearFilters();\r\n }\r\n }\r\n /**\r\n * 상태 칩 클릭 = 그 상태만 보기, 한 번 더 누르면 해제.\r\n *\r\n * 왜 새 UI 대신 칩인가 — 칩은 이미 헤더에 있고, 이미 상태별 개수를 급한 순서로 보여준다\r\n * (`order.ts` STATUS_ORDER). 사용자가 `⏸ 2` 를 보고 \"그 둘이 어디 있나\" 를 찾는 순간이\r\n * 곧 필터가 필요한 순간이라, 누를 자리와 알고 싶은 것이 같은 픽셀에 있다.\r\n * 드롭다운을 새로 두면 같은 정보를 두 군데서 말하게 되고, 200px 짜리 사이드바\r\n * (`sidebarMin`)에서 검색창 옆에 그것을 놓을 자리도 없다.\r\n */\r\n toggleStatusFilter(status) {\r\n this.statusFilter = this.statusFilter === status ? null : status;\r\n this.syncSearchUi();\r\n this.render();\r\n }\r\n /**\r\n * 이 탭이 지금 걸린 필터를 통과하나.\r\n *\r\n * 매칭 후보는 **사용자가 그 줄에서 눈으로 보는 것 + 그 줄이 속한 그룹**이다 —\r\n * 제목(`customTitle` 우선, `[AD:...]` 표식은 뗀 것), 작업 이름(라벨), 작업 폴더 경로.\r\n * 그룹 라벨은 폴더 경로의 뒷조각이라(`group.ts` `groupLabelOf`) 경로를 후보에 넣으면\r\n * 라벨로 검색한 것도 같이 걸린다. cwd 를 아직 모르는 탭은 `기타` 그룹으로 묶이므로\r\n * 그 이름도 후보에 넣는다 — 화면에 그렇게 적혀 있으니 그것으로 찾을 수 있어야 한다.\r\n */\r\n tabMatchesFilter(tab, tokens, status) {\r\n var _a, _b;\r\n if (this.statusFilter && status !== this.statusFilter) {\r\n return false;\r\n }\r\n if (!tokens.length) {\r\n return true;\r\n }\r\n const dir = (_b = (_a = this.cwdCache.get(tab)) === null || _a === void 0 ? void 0 : _a.dir) !== null && _b !== void 0 ? _b : null;\r\n return matchesSearchTokens([\r\n (0, detect_1.stripTitleMarker)(tab.customTitle || tab.title || ''),\r\n this.status.get(tab).label,\r\n dir,\r\n dir ? null : group_1.UNGROUPED_LABEL,\r\n ], tokens);\r\n }\r\n /**\r\n * 옛 미리보기 설정(`viewerFollowMode` 목록 / 그보다 옛 `viewerFollow` boolean)을\r\n * 토글 두 개(`viewerPreload`/`viewerAutoOpen`)로 옮긴다 — **기동 때 한 번.**\r\n *\r\n * 읽는 시점에 옛 값을 보는 방식으로 두지 않은 이유: 토글은 boolean 이라 \"아직 안 골랐다\" 를\r\n * 담을 자리가 없다. 빈 값을 그대로 두면 화면에는 꺼져 보이는데 동작은 켜져 있게 된다.\r\n * 그래서 한 번 적고 **옛 키를 기본값으로 비운다** — 안 비우면 다음 기동에 또 옮기면서\r\n * 사람이 방금 바꾼 토글을 덮는다.\r\n */\r\n migrateFollowConfig() {\r\n const cfg = this.config.store.agentDeck;\r\n const moved = (0, viewer_1.migrateFollow)(cfg.viewerFollowMode, cfg.viewerFollow);\r\n if (!moved) {\r\n return;\r\n }\r\n cfg.viewerPreload = moved.preload;\r\n cfg.viewerAutoOpen = moved.autoOpen;\r\n cfg.viewerFollowMode = '';\r\n cfg.viewerFollow = true;\r\n this.config.save();\r\n this.diag(`migrate follow -> preload=${moved.preload} autoOpen=${moved.autoOpen}`);\r\n }\r\n /**\r\n * 결과물 미리보기 패널을 만든다 (viewPanel.ts).\r\n *\r\n * 사이드바와 같은 방식으로 `.window` 위에 절대 배치하고, 위치·폭은 relayout 이 정한다.\r\n * 열림 상태는 설정(`viewerOpen`)에 남겨 다음 기동에 그대로 복원한다 — 문서를 띄워 놓고\r\n * 쓰는 사람에게는 그게 기본 화면이기 때문이다.\r\n */\r\n buildView() {\r\n var _a;\r\n if (!this.windowEl) {\r\n return;\r\n }\r\n const cfg = () => this.config.store.agentDeck;\r\n this.view = new viewPanel_1.ViewPanel({\r\n windowEl: this.windowEl,\r\n getSide: () => this.viewSide,\r\n getWidth: () => cfg().viewerWidth || 420,\r\n setWidth: px => {\r\n cfg().viewerWidth = px;\r\n },\r\n getRecentMax: () => cfg().viewerRecentMax || 12,\r\n // 토글 두 개(`viewerPreload`/`viewerAutoOpen`)를 모드로 접는다.\r\n // 옛 목록값은 기동 때 `migrateFollowConfig` 가 이 둘로 옮기고 비운다\r\n getFollowMode: () => (0, viewer_1.followModeOf)(cfg().viewerPreload, cfg().viewerAutoOpen),\r\n // 상대경로는 그 탭의 cwd 로 푼다. 아직 못 물어봤으면 작업 루트라도 써 본다.\r\n // 훅이 말해 준 값(`cwdOf`)이 있으면 그게 1순위다 — 캐시는 출력이 흘러야 채워지므로\r\n // 조용한 탭에서는 훅 값이 먼저 와 있다 (그리고 추정보다 정확하다)\r\n cwdFor: tab => {\r\n var _a;\r\n return this.notify.cwdOf(tab)\r\n || ((_a = this.cwdCache.get(tab)) === null || _a === void 0 ? void 0 : _a.dir)\r\n || cfg().rootProfileCwd\r\n || null;\r\n },\r\n // `변경` 탭의 '세션' 목록 — 훅이 보고한 \"이번 세션이 고친 파일\". 훅이 없는 탭은 빈 배열\r\n touchedFor: tab => this.notify.touchedOf(tab),\r\n commit: () => this.zone.run(() => this.config.save()),\r\n relayout: () => this.relayout(),\r\n setOpen: open => this.zone.run(() => {\r\n cfg().viewerOpen = open;\r\n this.config.save();\r\n }),\r\n openExternal: url => this.platform.openExternal(url),\r\n // 미리보기 패널에서 고른 줄의 `파일:라인` 을 활성 탭 터미널에 넣는다.\r\n // 쓰기는 `sendToPane` 을 거친다(조합 중이면 확정을 기다리고, 진단 로그를 남긴다).\r\n // **개행은 붙이지 않는다** — 사용자가 앞뒤에 말을 붙일 자리를 남긴다\r\n // (끌어다 놓은 경로를 넣는 `pasteDroppedPath` 와 같은 규칙).\r\n sendText: (text) => {\r\n const tab = this.app.activeTab;\r\n const pane = tab ? this.firstPane(tab) : null;\r\n if (!pane || !text) {\r\n return false;\r\n }\r\n this.sendToPane(pane, 'ref-paste', () => pane.sendInput(text));\r\n return true;\r\n },\r\n });\r\n this.view.install();\r\n this.view.setActiveTab((_a = this.app.activeTab) !== null && _a !== void 0 ? _a : null);\r\n if (cfg().viewerOpen) {\r\n // 지난 세션의 열림 상태 복원 — 설정에 되쓰지 않는다(remember=false)\r\n this.view.setOpen(true, false);\r\n }\r\n }\r\n /** 미리보기 패널이 붙는 방향 (설정값이 망가져 있으면 오른쪽) */\r\n get viewSide() {\r\n return this.config.store.agentDeck.viewerDock === 'left' ? 'left' : 'right';\r\n }\r\n /**\r\n * 이 탭의 작업 디렉토리를 캐시에 채운다.\r\n *\r\n * 미리보기 패널이 화면에서 주운 상대경로를 풀 때 쓴다. `getWorkingDirectory()` 는 비동기\r\n * OS 호출이라 출력 조각마다 부를 수 없으므로 `CWD_TTL_MS` 주기로만 갱신한다.\r\n */\r\n touchCwd(root, pane) {\r\n var _a, _b;\r\n const now = Date.now();\r\n const hit = this.cwdCache.get(root);\r\n // **훅이 말해 준 값이 있으면 그것으로 끝낸다 — Tabby 의 추정은 보지도 않는다.**\r\n //\r\n // 윈도우의 `getWorkingDirectory()` 는 사실상 추정이다: PTY 출력에서 `X:\\…` 로 보이는 첫\r\n // 토큰을 cwd 로 삼고(tabby-local dist/index.js:1316 `guessWindowsCWD`), 그것이 폴더인지는\r\n // 확인하지 않는다(:1306, `fs.access` 만 본다). 그래서 에이전트가 화면에 찍은 파일 경로가\r\n // 그대로 cwd 가 되어 `변경` 탭이 `git -C …\\inject_prompts.py` 를 돌렸다 (2026-09-11 실측).\r\n // 훅 경로(notify.service `cwdOf`)는 에이전트가 자기 cwd 를 직접 말해 주는 것이라 추정이 아니다.\r\n const hooked = this.notify.cwdOf(root);\r\n if (hooked) {\r\n if ((hit === null || hit === void 0 ? void 0 : hit.dir) !== hooked) {\r\n this.cwdCache.set(root, { dir: hooked, at: now, misses: 0 });\r\n this.scheduleRender();\r\n }\r\n return;\r\n }\r\n // **아직 한 번도 못 알아낸 탭은 짧은 간격으로 다시 묻는다.**\r\n //\r\n // TTL(3초)은 \"이미 아는 값을 너무 자주 다시 묻지 않기\" 위한 것이다. 그런데 첫 조회가\r\n // 빈손이면(세션이 붙는 중이거나 셸이 프롬프트를 아직 안 찍었을 때) 그 빈 값에도 TTL 이\r\n // 걸려, 다음 출력이 3초 안에 오는 탭은 계속 막히고 **조용한 탭은 영영 `기타` 에 남았다**\r\n // (2026-09-08 실측: 탭 둘을 연달아 열면 먼저 연 쪽이 25초 뒤에도 `dir: null`, 그 때문에\r\n // 다중 그룹 회귀 9종이 판정 불가로 빠졌다).\r\n //\r\n // 그래서 미상 탭은 TTL 을 건너뛰게 했는데, 그 대가가 2026-09-09 에 숫자로 나왔다 —\r\n // **조각 24개를 흘리는 동안 `getWorkingDirectory()` 가 34회**(PF6). cwd 를 끝내 못\r\n // 알려주는 셸(SSH 등)에서는 출력 조각마다 OS 호출이고 탭 수에 곱해진다.\r\n // 지금은 미상 탭에 **짧은 백오프**(`CWD_MISS_MS`)를 둔다: 조용한 탭도 곧 다시 묻고\r\n // (수백 ms 안에 제 그룹으로 옮겨온다), 시끄러운 탭에서 조각마다 묻는 일은 사라진다.\r\n const ttl = (hit === null || hit === void 0 ? void 0 : hit.dir) ? CWD_TTL_MS : CWD_MISS_MS;\r\n if (hit && now - hit.at < ttl) {\r\n return;\r\n }\r\n // 미상인 동안은 조회 횟수를 센다 — 1초 tick 이 이 값으로 재시도를 멈출 시점을 안다\r\n const misses = (hit === null || hit === void 0 ? void 0 : hit.dir) ? 0 : ((_a = hit === null || hit === void 0 ? void 0 : hit.misses) !== null && _a !== void 0 ? _a : 0) + 1;\r\n this.cwdCache.set(root, { dir: (_b = hit === null || hit === void 0 ? void 0 : hit.dir) !== null && _b !== void 0 ? _b : null, at: now, misses });\r\n const session = pane.session;\r\n if (!(session === null || session === void 0 ? void 0 : session.getWorkingDirectory)) {\r\n return;\r\n }\r\n Promise.resolve(session.getWorkingDirectory())\r\n .then((dir) => {\r\n // **폴더가 맞는지 여기서 거른다.** 윈도우에서 이 값은 출력에서 주운 추정이고\r\n // (`guessWindowsCWD`), Tabby 는 존재 여부만 확인하므로 **파일 경로가 그대로 나온다.**\r\n // 그대로 받으면 `git -C <파일>` 이 `Invalid argument` 로 죽고, 상대경로 풀기도\r\n // 전부 어긋난다. 거른 값 대신 **직전에 알던 폴더를 그대로 둔다** — 파일의 상위\r\n // 폴더로 바꾸지 않는다. 그 상위 폴더(예: 스크래치패드)는 탭의 작업 폴더가 아니라\r\n // 그저 화면에 지나간 경로라, 그걸 받아들이면 틀린 값을 조용히 확정하게 된다.\r\n if (dir && isDirectory(dir)) {\r\n this.cwdCache.set(root, { dir, at: Date.now(), misses: 0 });\r\n // 그룹이 방금 정해졌으면 화면도 그것을 반영해야 한다 — 캐시만 바꾸면\r\n // 다음 상태 변화 때까지 사이드바가 옛 그룹을 보여준다 (`render` 는 tick 에서만)\r\n this.scheduleRender();\r\n }\r\n })\r\n .catch(() => {\r\n // 셸이 알려주지 않는 환경 — 절대경로만 주워도 쓸 만하다\r\n });\r\n }\r\n /** 설정에 지정된 기본 프로필(기본값 agentdeck:root)로 새 탭을 연다 */\r\n async openNewTab() {\r\n var _a;\r\n const wanted = this.config.store.terminal.profile;\r\n const profiles = await this.profiles.getProfiles();\r\n const profile = (_a = profiles.find(p => p.id === wanted)) !== null && _a !== void 0 ? _a : profiles[0];\r\n if (profile) {\r\n await this.profiles.openNewTabForProfile(profile);\r\n }\r\n }\r\n openSettings() {\r\n this.app.openNewTabRaw({ type: tabby_settings_1.SettingsTabComponent });\r\n }\r\n /**\r\n * 사이드바 다시 그리기를 한 번으로 모은다.\r\n *\r\n * rAF 만 쓰면 **창이 가려졌을 때 상태가 늦게 반영된다.** Chromium 은 창이 hidden\r\n * (최소화·완전 가려짐) 이 되면 rAF 를 아예 멈추고 타이머도 스로틀한다. 그러면\r\n * 훅이 보낸 done 은 메모리에 즉시 반영됐는데 화면만 옛 상태로 남아 있다가,\r\n * 1초 tick(그것도 스로틀되면 더 늦게)이 와야 그려진다 — \"작업중이 한참 뒤에야 완료로 바뀐다\"\r\n * 의 정체가 이것이다(2026-08-28). 시작 쪽이 빨라 보이는 건 그때는 사용자가 방금\r\n * 창에 입력해서 창이 떠 있기 때문일 뿐이다.\r\n *\r\n * 그래서 rAF 와 짧은 타이머를 같이 걸고 **먼저 오는 쪽이 그린다**. 창이 떠 있으면\r\n * 지금까지와 똑같이 다음 프레임에, 가려져 있으면 타이머가 대신 그린다.\r\n */\r\n scheduleRender() {\r\n if (this.renderQueued) {\r\n return;\r\n }\r\n this.renderQueued = true;\r\n const run = () => {\r\n if (!this.renderQueued) {\r\n return;\r\n }\r\n this.renderQueued = false;\r\n if (this.renderTimer) {\r\n clearTimeout(this.renderTimer);\r\n this.renderTimer = null;\r\n }\r\n this.render();\r\n this.relayout();\r\n };\r\n requestAnimationFrame(run);\r\n this.renderTimer = setTimeout(run, 50);\r\n }\r\n /**\r\n * 창이 가려져 있어도 타이머·rAF 가 계속 돌게 한다.\r\n *\r\n * 위 scheduleRender 의 타이머 폴백은 \"타이머가 제때 돈다\" 를 전제로 하는데,\r\n * Chromium 은 hidden 페이지의 타이머를 1초로 묶고 5분 넘게 가려져 있으면\r\n * **분당 1회**까지 떨어뜨린다. 그 상태에서는 폴백조차 늦다.\r\n * Electron 의 backgroundThrottling 을 꺼서 이 계층을 통째로 없앤다.\r\n */\r\n disableBackgroundThrottling() {\r\n var _a, _b, _c, _d, _e;\r\n if (!this.config.store.agentDeck.keepRenderingWhenHidden) {\r\n return;\r\n }\r\n try {\r\n const req = (_a = window.require) !== null && _a !== void 0 ? _a : globalThis.require;\r\n const win = (_c = (_b = req === null || req === void 0 ? void 0 : req('@electron/remote')) === null || _b === void 0 ? void 0 : _b.getCurrentWindow) === null || _c === void 0 ? void 0 : _c.call(_b);\r\n (_e = (_d = win === null || win === void 0 ? void 0 : win.webContents) === null || _d === void 0 ? void 0 : _d.setBackgroundThrottling) === null || _e === void 0 ? void 0 : _e.call(_d, false);\r\n }\r\n catch {\r\n // remote 를 못 잡아도 위 타이머 폴백은 살아 있다 (조금 늦을 뿐)\r\n }\r\n }\r\n tick() {\r\n var _a, _b;\r\n if (!this.enabled) {\r\n return;\r\n }\r\n let dirty = false;\r\n const idleAfter = this.config.store.agentDeck.idleAfterMs || 2500;\r\n for (const tab of this.app.tabs) {\r\n if (this.status.tickIdle(tab, idleAfter)) {\r\n dirty = true;\r\n }\r\n // **작업 폴더를 아직 못 알아낸 탭은 출력이 없어도 다시 묻는다 — 단 활성 탭만.**\r\n //\r\n // `touchCwd` 는 출력 구독에서만 불리므로, 아무것도 찍지 않는 탭은 재시도 기회가\r\n // 없다 — 세션이 붙는 중이던 첫 조회가 빈손이면 영영 `기타` 그룹이고 `변경` 탭도\r\n // \"작업 폴더를 모른다\" 로 끝난다(2026-09-09 실측).\r\n //\r\n // **활성 탭으로 한정하는 이유**: 처음에는 전 탭을 매초 물었는데, 그러면 닫히는\r\n // 중인 탭의 `session.getWorkingDirectory()` 를 건드려 프로세스가 조용히 사라지는\r\n // 판이 생겼다(회귀 러너에서 탭을 만들고 닫는 프로브 구간마다 재현. `try/catch` 로는\r\n // 못 막는다 — 네이티브 pty 핸들 쪽이다). 활성 탭은 파괴 중일 가능성이 낮고,\r\n // 미리보기가 보는 것도 활성 탭의 cwd 다. 배경 탭은 출력이 흐를 때나 활성으로\r\n // 바뀔 때 잡히므로 그룹도 곧 정리된다.\r\n // 훅이 알려 준 폴더는 **출력을 기다리지 않고** 캐시에 반영한다.\r\n // `touchCwd` 는 출력 구독에서만 불리는데, 에이전트가 폴더를 옮긴 직후에 아무것도\r\n // 찍지 않으면 사이드바 그룹과 `변경` 탭이 옛 폴더에 머문다. WeakMap 조회 한 번이라\r\n // 매초 전 탭을 훑어도 비용이 없고, 위의 `getWorkingDirectory()` 와 달리 OS 를\r\n // 건드리지 않으므로 배경 탭·파괴 중인 탭에 물어도 안전하다\r\n const hooked = this.notify.cwdOf(tab);\r\n if (hooked && ((_a = this.cwdCache.get(tab)) === null || _a === void 0 ? void 0 : _a.dir) !== hooked) {\r\n this.cwdCache.set(tab, { dir: hooked, at: Date.now(), misses: 0 });\r\n dirty = true;\r\n }\r\n if (tab === this.app.activeTab) {\r\n try {\r\n const hit = this.cwdCache.get(tab);\r\n if (!(hit === null || hit === void 0 ? void 0 : hit.dir) && ((_b = hit === null || hit === void 0 ? void 0 : hit.misses) !== null && _b !== void 0 ? _b : 0) < CWD_MISS_MAX) {\r\n const pane = this.firstPane(tab);\r\n if (pane) {\r\n this.touchCwd(tab, pane);\r\n }\r\n }\r\n }\r\n catch {\r\n // 파괴 중인 탭 — 다음 tick 에 다시 본다\r\n }\r\n }\r\n }\r\n this.syncLedger();\r\n // 서브에이전트 개수는 `notify.service` 의 2초 스캔이 갱신하는데 렌더를 부르는 경로가\r\n // 없다 — 경과시간을 끈 사람에게도 숫자가 흐르게 여기서 같이 그린다. 비용은 이미\r\n // 기본값(`showElapsed: true`)으로 매초 그리던 것과 같다\r\n if (dirty || this.config.store.agentDeck.showElapsed || this.config.store.agentDeck.subagentCount !== false) {\r\n this.render();\r\n }\r\n }\r\n /**\r\n * 살아 있는 세션의 라벨·cwd·상태를 원장에 적는다 (매초).\r\n *\r\n * **여기가 적는 유일한 자리다.** 세 조각이 각각 다른 곳에 있기 때문이다 —\r\n * 세션↔탭은 `notify`, 라벨·상태는 `status.service`, cwd 는 이 서비스의 `cwdCache`.\r\n * 한 곳에서 모아 적지 않으면 셋이 어긋난 원장이 남는다.\r\n *\r\n * 매초 파일을 쓰지는 않는다 — `note` 가 값이 그대로면 저장을 예약하지 않고, 예약도 2초로 모은다.\r\n */\r\n syncLedger() {\r\n var _a, _b;\r\n if (this.config.store.agentDeck.resumeList === false) {\r\n return;\r\n }\r\n let live;\r\n try {\r\n live = this.notify.liveSessions();\r\n }\r\n catch {\r\n return;\r\n }\r\n for (const [sid, tab] of live) {\r\n if (!this.app.tabs.includes(tab)) {\r\n continue;\r\n }\r\n const st = this.status.get(tab);\r\n this.ledger.note(sid, {\r\n cwd: (_b = (_a = this.cwdCache.get(tab)) === null || _a === void 0 ? void 0 : _a.dir) !== null && _b !== void 0 ? _b : null,\r\n label: st.label,\r\n status: st.status,\r\n });\r\n }\r\n }\r\n /**\r\n * 사이드바를 **무엇을 어떤 순서로** 그릴지 한 번에 계산한다 (그리지는 않는다).\r\n *\r\n * `render()` 와 진단구(`__agentdeck.groups()`)가 **같은 계산을 공유하기 위해** 뽑았다.\r\n * 예전에는 이 규칙이 `render()` 안에만 있어서, 검증 도구가 헤더 생략 조건을\r\n * `list.filter(key!==null).length > 1` 로 **다시 적어야** 했다. 그런 사본은 낡는다 —\r\n * 이 저장소가 `judge()`·`profiles()`·`groups()` 를 연 이유가 전부 그것이다.\r\n */\r\n renderPlan() {\r\n const statusOf = (tab) => this.status.get(tab).status;\r\n // 정렬은 복사본에만 — app.tabs 의 순서(순정 탭바)는 그대로 둔다\r\n const tabs = this.config.store.agentDeck.sortByStatus\r\n ? (0, order_1.sortTabsByStatus)(this.app.tabs, statusOf)\r\n : this.app.tabs;\r\n // **필터는 여기서 먹인다** — 그룹핑·헤더 생략·plan 이 전부 이 결과를 딛는다.\r\n // `render()` 안에서만 걸러내면 진단구(`__agentdeck.groups()`)가 화면과 어긋나고,\r\n // 그러면 회귀 프로브가 \"제품이 배정한 탭 집합 != 화면의 줄 집합\"(GR2)을 거짓 실패로 읽는다.\r\n // 이 함수를 뽑은 이유 자체가 그 사본 문제였다.\r\n //\r\n // 필터가 없으면 배열을 복사하지 않고 `tabs` 를 그대로 넘긴다 — 렌더는 초당 여러 번 돈다.\r\n const tokens = searchTokens(this.searchQuery);\r\n const filtering = tokens.length > 0 || !!this.statusFilter;\r\n const visible = filtering\r\n ? tabs.filter(tab => this.tabMatchesFilter(tab, tokens, statusOf(tab)))\r\n : tabs;\r\n const groups = this.groupsFor(visible);\r\n // 그룹이 하나뿐이면 헤더를 그리지 않는다 — 단일 프로젝트에서는 아무것도 가르지 못하면서\r\n // 세로 공간만 먹는다 — 그룹을 항상 계산해도 한 프로젝트만 쓰는 화면이 예전과 같은 이유다.\r\n //\r\n // **세는 것은 \"작업 폴더를 아는 그룹\" 뿐이다.** cwd 를 모르는 탭(Welcome 탭, 조회 실패)은\r\n // `기타` 그룹으로 모이는데, 그것까지 세면 Welcome 탭 하나 때문에 항상 2그룹이 되어\r\n // 단일 프로젝트에서도 헤더가 뜬다 — 생략 규칙이 사실상 무력화된다\r\n // (2026-09-08 배리어 실측: 같은 cwd 인데 헤더가 2개였다).\r\n const withHeads = groups.filter(g => g.key !== null).length > 1;\r\n // **헤더를 안 그리기로 했으면 순서도 건드리지 않는다.**\r\n // `groupTabs` 는 그룹을 라벨순으로 정렬하고 `기타`(작업 폴더를 모르는 탭)를 맨 뒤로 붙인다\r\n // (group.ts:228-230). 헤더가 있으면 그게 보기 좋지만, 헤더가 없는 화면에서는 구분선이\r\n // 없으니 \"그룹으로 묶여서 옮겨졌다\" 는 것을 알 방법이 없다 — Welcome 탭이 이유 없이\r\n // 맨 아래로 내려간 것처럼만 보이고, 순정 탭바와의 순서 대응도 깨진다.\r\n // (2026-09-08 실측: 이 재배열 때문에 사이드바 첫 줄이 `app.tabs[0]` 이 아니게 되어\r\n // R16·R19 가 다른 탭의 배지를 읽었다.)\r\n //\r\n // 평면으로 떨어질 때 담는 것은 **`visible`** 이다. `tabs`(전체)를 담으면 필터로 그룹이\r\n // 하나만 남는 순간 걸러낸 탭들이 통째로 되살아난다 — 헤더 생략 규칙과 필터가 부딪치는\r\n // 유일한 지점이라 여기만 조심하면 된다.\r\n const plan = withHeads\r\n ? groups\r\n : [{ key: null, label: group_1.UNGROUPED_LABEL, tabs: [...visible] }];\r\n // 접힘 판정은 순수 규칙에 맡긴다 — 검색 중 매칭이 있는 접힌 그룹은 **임시로** 펴 보이고,\r\n // 저장된 `collapsedGroups` 는 건드리지 않는다(검색을 지우면 같은 입력이 되어 복귀한다).\r\n const collapseOf = (group) => (0, group_1.resolveGroupCollapseFor)(group, this.config.store.agentDeck.collapsedGroups, filtering);\r\n return { tabs, visible, groups, withHeads, plan, statusOf, filtering, collapseOf };\r\n }\r\n render() {\r\n var _a;\r\n // 드래그가 진행 중이면 그리지 않는다. 목록을 다시 만들면 **끌고 있던 줄의 DOM 이 사라져**\r\n // 삽입선이 가리킬 대상도, 되돌아갈 자리도 없어진다 (라벨 편집 중에 안 그리는 것과 같은 이유).\r\n // 상태 갱신이 드래그가 끝날 때까지(수 초) 밀리는 것은 그 대가로 받아들인다 —\r\n // `endRowDrag` 가 끝에 반드시 한 번 그린다.\r\n if (!this.listEl || !this.enabled || this.editing || ((_a = this.drag) === null || _a === void 0 ? void 0 : _a.moved)) {\r\n return;\r\n }\r\n // 닫힌 탭을 가리키는 키보드 포커스를 먼저 버린다 (`pruneNavFocus` 주석)\r\n this.pruneNavFocus();\r\n const { tabs, visible, withHeads, plan, statusOf, filtering, collapseOf } = this.renderPlan();\r\n // **집계 칩은 전체(`tabs`) 기준이다.** 근거 둘 —\r\n // 1) 칩이 곧 상태 필터의 조작부다. 필터 기준으로 세면 `⏸` 을 누른 순간 다른 상태의 칩이\r\n // 사라져 다른 상태로 갈아탈 수도, 무엇을 놓치고 있는지 볼 수도 없다.\r\n // 2) 화면에서 줄이 사라졌는데 총계까지 줄면 \"탭이 닫혔나\" 로 읽힌다. 이 저장소는 이미\r\n // 같은 판단을 한 번 했다 — 그룹을 접어 줄이 사라져도 헤더 총계는 그대로 유지한다\r\n // (그 성질을 회귀가 `headCountTitle` 로 고정해 두고 있다).\r\n this.renderHeadCount(tabs, statusOf);\r\n this.listEl.innerHTML = '';\r\n if (filtering && !visible.length) {\r\n // 빈 목록만 남기면 \"탭이 다 닫혔다\" 로 읽힌다 — 무엇도 걸리지 않았음을 한 줄로 말한다\r\n this.listEl.appendChild(this.renderEmpty(tabs.length));\r\n return;\r\n }\r\n for (const group of plan) {\r\n // **화면에 접히는지**는 순수 규칙이 정한다 — 검색 중 매칭이 있는 접힌 그룹은\r\n // 임시로 펴진다(group.ts `resolveGroupCollapse`). 헤더를 안 그리는 화면에서는\r\n // 접힘을 적용하지 않는다(그 규칙은 예전부터 여기 있었다).\r\n const state = withHeads\r\n ? collapseOf(group)\r\n : { collapsed: false, reason: 'open' };\r\n const collapsed = state.collapsed;\r\n if (withHeads) {\r\n this.listEl.appendChild(this.renderGroupHead(group, state));\r\n }\r\n if (collapsed) {\r\n continue;\r\n }\r\n for (const tab of group.tabs) {\r\n this.listEl.appendChild(this.renderTab(tab));\r\n }\r\n this.renderResume(group, filtering);\r\n }\r\n }\r\n /**\r\n * 그룹 끝에 **지난 세션** 줄을 붙인다 — `⟲ 지난 세션 5` 한 줄(기본 접힘)과, 펴면 그 목록.\r\n *\r\n * 살아 있는 탭 뒤에 오는 이유: 사이드바의 주인공은 지금 도는 작업이고 이건 그 밑의 서랍이다.\r\n * 검색·상태필터가 걸려 있을 때는 아예 그리지 않는다 — 그 둘은 **탭**을 좁히는 장치라\r\n * (`tabMatchesFilter`) 죽은 세션에는 적용되지 않는데, 걸러진 화면에 안 걸러진 줄이 섞이면\r\n * \"검색 결과\" 라는 말이 깨진다.\r\n */\r\n renderResume(group, filtering) {\r\n const cfg = this.config.store.agentDeck;\r\n if (cfg.resumeList === false || !this.listEl || filtering) {\r\n return;\r\n }\r\n // 목록은 캐시에서 즉시 나온다. 스캔은 비동기로 돌고 끝나면 `onChange` 가 다시 그린다\r\n void this.ledger.refresh();\r\n const rows = (0, sessionLedger_1.resumeRowsFor)(this.ledger.records(), {\r\n groupKeys: this.resumeKeysOf(group),\r\n keyOf: cwd => (0, group_1.groupKeyOf)(cwd, project_root_1.projectRootOf),\r\n fold: group_1.foldGroupKey,\r\n live: this.liveSessionIds(),\r\n days: Number(cfg.resumeListDays) || 0,\r\n limit: Number(cfg.resumeListLimit) || 0,\r\n hidden: new Set(Array.isArray(cfg.resumeHidden) ? cfg.resumeHidden : []),\r\n now: Date.now(),\r\n });\r\n if (!rows.length) {\r\n // 지난 세션이 없는 그룹에는 줄 자체를 그리지 않는다 — Claude Code 가 아닌 탭\r\n // (Codex·Gemini)만 있는 그룹에서는 이 서랍이 늘 비어 있는데, 빈 서랍이 매번\r\n // 보이면 사이드바에 읽을 것 없는 줄이 하나 더 생길 뿐이다\r\n return;\r\n }\r\n const expanded = this.isResumeExpanded(group.key);\r\n this.listEl.appendChild(this.renderResumeHead(group, rows.length, expanded));\r\n if (!expanded) {\r\n return;\r\n }\r\n for (const row of rows) {\r\n this.listEl.appendChild(this.renderResumeRow(row));\r\n }\r\n }\r\n /**\r\n * 이 줄 묶음이 덮는 그룹 키들.\r\n *\r\n * 헤더를 그리는 화면에서는 `group.key` 하나지만, **그룹이 하나뿐이면 사이드바는 헤더를\r\n * 안 그리고 목록을 평면 한 덩이로 만든다**(`renderPlan`) — 그때 `group.key` 는 `null`(기타)이\r\n * 되어 어떤 세션도 안 걸린다. 프로젝트를 하나만 열어 둔 화면이 가장 흔하므로 그대로 두면\r\n * 기능이 평소에 안 보인다. 그래서 **그 덩이에 실제로 들어 있는 탭들의 키**를 모아 쓴다.\r\n */\r\n resumeKeysOf(group) {\r\n var _a, _b;\r\n if (group.key !== null) {\r\n return [group.key];\r\n }\r\n const keys = new Set();\r\n for (const tab of group.tabs) {\r\n keys.add((0, group_1.groupKeyOf)((_b = (_a = this.cwdCache.get(tab)) === null || _a === void 0 ? void 0 : _a.dir) !== null && _b !== void 0 ? _b : null, project_root_1.projectRootOf));\r\n }\r\n // 탭이 하나도 없으면(있을 수 없지만) 빈 목록 — `null` 을 넣으면 cwd 를 모르는 세션이 딸려 온다\r\n return [...keys];\r\n }\r\n /** 지금 탭이 들고 있는 세션 — `세션id -> 탭 식별용 문자열`. 되돌아올 탭은 `resumeTabs` 가 들고 있다 */\r\n liveSessionIds() {\r\n this.resumeTabs.clear();\r\n const out = new Map();\r\n let live;\r\n try {\r\n live = this.notify.liveSessions();\r\n }\r\n catch {\r\n return out;\r\n }\r\n for (const [sid, tab] of live) {\r\n if (!this.app.tabs.includes(tab)) {\r\n continue;\r\n }\r\n out.set(sid, sid);\r\n this.resumeTabs.set(sid, tab);\r\n }\r\n return out;\r\n }\r\n /** 지난 세션 서랍이 펴져 있나. `collapsedGroups` 와 **반대로 펼침을 적는다** — 기본이 접힘이라서 */\r\n isResumeExpanded(key) {\r\n const stored = this.config.store.agentDeck.resumeExpanded;\r\n if (!Array.isArray(stored)) {\r\n return false;\r\n }\r\n const id = (0, group_1.collapseIdOf)(key);\r\n return stored.some((k) => typeof k === 'string' && (0, group_1.foldGroupKey)(k) === (0, group_1.foldGroupKey)(id));\r\n }\r\n toggleResumeExpanded(key) {\r\n const cfg = this.config.store.agentDeck;\r\n const id = (0, group_1.collapseIdOf)(key);\r\n const stored = Array.isArray(cfg.resumeExpanded)\r\n ? cfg.resumeExpanded.filter((k) => typeof k === 'string')\r\n : [];\r\n const kept = stored.filter(k => (0, group_1.foldGroupKey)(k) !== (0, group_1.foldGroupKey)(id));\r\n cfg.resumeExpanded = kept.length === stored.length ? [...stored, id] : kept;\r\n this.config.save();\r\n this.render();\r\n }\r\n renderResumeHead(group, count, expanded) {\r\n const head = document.createElement('div');\r\n head.className = 'ad-resume-head' + (expanded ? '' : ' collapsed');\r\n head.innerHTML = [\r\n '<span class=\"ad-resume-glyph\">⟲</span>',\r\n '<span class=\"ad-group-label\"></span>',\r\n '<span class=\"ad-group-count\"></span>',\r\n '<span class=\"ad-group-caret\"></span>',\r\n ].join('');\r\n head.querySelector('.ad-group-label').textContent = '지난 세션';\r\n head.querySelector('.ad-group-count').textContent = String(count);\r\n head.querySelector('.ad-group-caret').textContent = expanded ? '▾' : '▸';\r\n head.title = '닫힌 Claude Code 세션 — 누르면 그 대화를 이어받는다';\r\n head.addEventListener('click', e => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.toggleResumeExpanded(group.key);\r\n });\r\n return head;\r\n }\r\n renderResumeRow(row) {\r\n const el = document.createElement('div');\r\n el.className = 'ad-resume' + (row.openTabId ? ' open' : '');\r\n el.innerHTML = [\r\n '<div class=\"ad-bar\"></div>',\r\n '<div class=\"ad-body\">',\r\n ' <div class=\"ad-title\"></div>',\r\n ' <div class=\"ad-meta\">',\r\n ' <span class=\"re-was\"></span>',\r\n ' <span class=\"re-when\"></span>',\r\n ' </div>',\r\n '</div>',\r\n ].join('\\n');\r\n // 라벨이 비면 세션 id 앞자리로 대신한다 — 줄을 지우면 \"이어받을 게 있는데 안 보인다\" 가 된다\r\n const title = row.label || `세션 ${row.sessionId.slice(0, 8)}`;\r\n el.querySelector('.ad-title').textContent = title;\r\n const was = el.querySelector('.re-was');\r\n if (row.openTabId) {\r\n was.textContent = '● 열림';\r\n was.className = 're-was live';\r\n }\r\n else {\r\n const style = api_1.STATUS_STYLES[row.lastStatus];\r\n // 끝난 상태는 **흔적으로만** 남긴다 — 살아 있는 배지와 같은 세기로 칠하면\r\n // 죽은 줄이 도는 줄처럼 읽힌다. 색 대신 형태(점선 바 + 흐림)가 죽음을 말한다\r\n was.textContent = style ? style.label : '';\r\n was.className = 're-was' + (row.lastStatus ? ' s-' + row.lastStatus : '');\r\n }\r\n was.textContent = `${row.agent === 'codex' ? 'Codex' : 'Claude'} · ${was.textContent || '지난 세션'}`;\r\n el.querySelector('.re-when').textContent = (0, sessionLedger_1.formatWhen)(row.lastSeen, Date.now());\r\n el.title = row.openTabId\r\n ? `${title}\\n이미 열려 있다 — 누르면 그 탭으로 이동`\r\n : `${title}\\n누르면 새 탭에서 이어받는다 (${row.sessionId})`\r\n + '\\n작업 폴더: ' + (row.cwd || '모름')\r\n + '\\n※ 대화만 돌아온다 — 그때 띄워 둔 서버·백그라운드 프로세스는 되살아나지 않는다';\r\n el.addEventListener('click', e => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.zone.run(() => { void this.activateResume(row, false); });\r\n });\r\n el.addEventListener('contextmenu', e => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.zone.run(() => this.showResumeMenu(row, e));\r\n });\r\n return el;\r\n }\r\n /**\r\n * 필터에 걸린 것이 하나도 없을 때의 한 줄.\r\n *\r\n * **필터가 걸려 있을 때만** 그린다 — 탭이 정말 0개인 화면(기동 직후)에까지 이 문구를 넣으면\r\n * 필터와 무관한 상태를 필터 탓으로 읽게 된다. 전체 개수를 같이 적는 이유도 그것이다:\r\n * \"탭은 그대로 있고 내 검색어가 안 걸렸을 뿐\" 이 한 줄로 보여야 한다.\r\n */\r\n renderEmpty(total) {\r\n const el = document.createElement('div');\r\n el.className = 'ad-empty';\r\n const parts = [];\r\n const q = this.searchQuery.trim();\r\n if (q) {\r\n parts.push('\"' + q + '\"');\r\n }\r\n if (this.statusFilter) {\r\n parts.push(api_1.STATUS_STYLES[this.statusFilter].label);\r\n }\r\n // 검색어는 사용자 입력이다 — textContent 로만 넣는다 (innerHTML 금지)\r\n el.textContent = parts.join(' · ') + '에 걸리는 세션이 없다 (전체 ' + total + '개)';\r\n el.title = 'Esc 또는 ✕ 로 전체 목록으로 돌아간다';\r\n return el;\r\n }\r\n /**\r\n * 탭을 프로젝트(작업 폴더) 그룹으로 나눈다. 규칙은 전부 `group.ts` 에 있다.\r\n *\r\n * cwd 는 **이미 채워져 있는 `cwdCache`** 만 본다 — 여기서 `getWorkingDirectory()` 를\r\n * 새로 부르면 렌더(초당 여러 번, `scheduleRender`)마다 OS 호출이 탭 수만큼 늘어난다.\r\n * 아직 캐시가 빈 탭은 `기타` 에 있다가, 출력이 흐를 때 `touchCwd` 가 채우면 제 그룹으로 옮겨온다.\r\n * 프로젝트 루트(`projectRootOf`)도 같은 성질이다 — 처음 보는 폴더는 그 순간엔 cwd 자체가\r\n * 키였다가, 탐지가 끝나면 저장소 루트로 합쳐진다.\r\n *\r\n * 비용은 탭 수만큼의 맵 조작 + 그룹 수²의 라벨 대조뿐이라(group.ts `groupTabs` 주석)\r\n * 캐시를 두지 않는다 — 캐시 무효화용 시그니처를 만드는 비용이 계산 비용과 같기 때문이다.\r\n */\r\n groupsFor(tabs) {\r\n // 프로젝트 경계는 **자동으로** 찾는다 (`project-root.ts`) — 조회는 캐시라 렌더를 막지\r\n // 않고, 처음 보는 폴더는 백그라운드 탐지가 끝나면 다시 그린다.\r\n return (0, group_1.groupTabs)(tabs, tab => { var _a, _b; return (_b = (_a = this.cwdCache.get(tab)) === null || _a === void 0 ? void 0 : _a.dir) !== null && _b !== void 0 ? _b : null; }, cwd => (0, project_root_1.projectRootOf)(cwd, () => this.scheduleRender()));\r\n }\r\n /** 설정에 남아 있는 접힌 그룹 키들 — 저장·비교는 항상 폴딩한 값으로 (group.ts `collapseIdOf`) */\r\n collapsedKeys() {\r\n const raw = this.config.store.agentDeck.collapsedGroups;\r\n return Array.isArray(raw) ? raw.map(k => (0, group_1.foldGroupKey)(String(k))) : [];\r\n }\r\n /**\r\n * **설정에 저장된** 접힘 여부. 화면에 실제로 접히는지는 `renderPlan().collapseOf` 가 정한다\r\n * — 검색 중에는 매칭이 있는 그룹을 임시로 펴 보이기 때문이다(group.ts `resolveGroupCollapse`).\r\n *\r\n * 이 함수의 의미를 \"유효 접힘\" 으로 바꾸면 안 된다. 진단구 `groups().list[].collapsed` 와\r\n * 회귀 GR8·GR9 가 \"제품이 **저장값으로** 접힘이라 판정하는가\" 를 보고 있어서,\r\n * 그 값이 필터에 따라 흔들리면 두 항목의 의미가 무너진다.\r\n */\r\n isGroupCollapsed(key) {\r\n return (0, group_1.isStoredCollapsed)(key, this.config.store.agentDeck.collapsedGroups);\r\n }\r\n /**\r\n * 그룹 접기/펴기. 상태를 설정에 남겨 다음 기동에도 유지한다 —\r\n * 안 쓰는 프로젝트를 접어 두는 것이 목적인데 매번 다시 접어야 하면 의미가 없다.\r\n */\r\n toggleGroup(key) {\r\n const id = (0, group_1.collapseIdOf)(key);\r\n const keys = this.collapsedKeys();\r\n const next = keys.filter(k => k !== id);\r\n if (next.length === keys.length) {\r\n next.push(id);\r\n }\r\n this.zone.run(() => {\r\n this.config.store.agentDeck.collapsedGroups = next;\r\n this.config.save();\r\n });\r\n this.render();\r\n }\r\n /**\r\n * 그룹 헤더 한 줄 — `▾ tabby-agentdeck 3`. 클릭하면 접힌다.\r\n *\r\n * 탭 줄들과 **형제로** 넣는다(그룹마다 감싸는 div 를 두지 않는다). 상/하 도킹은 목록을\r\n * 가로로 흘리는데(styles.scss `.ad-dock-top .ad-list`), 감싸면 그 flex 흐름이 그룹마다\r\n * 끊겨 탭이 세로로 쌓인다. 대신 헤더가 CSS 에서 한 줄을 다 차지해(`flex: 0 0 100%`) 줄을 가른다.\r\n */\r\n renderGroupHead(group, state) {\r\n const collapsed = state.collapsed;\r\n const head = document.createElement('div');\r\n // `filter-open` = 저장된 접힘인데 검색에 걸린 세션이 있어 **임시로** 펴 둔 상태.\r\n // 사용자에게는 \"왜 접어 뒀는데 펴져 있나\" 가 보여야 하고, 검색을 지우면 다시 접힌다.\r\n head.className = collapsed\r\n ? 'ad-group-head collapsed'\r\n : (state.reason === 'filter-open' ? 'ad-group-head filter-open' : 'ad-group-head');\r\n head.innerHTML = [\r\n '<span class=\"ad-group-caret\"></span>',\r\n '<span class=\"ad-group-label\"></span>',\r\n '<span class=\"ad-group-count\"></span>',\r\n ].join('');\r\n const caret = head.querySelector('.ad-group-caret');\r\n const label = head.querySelector('.ad-group-label');\r\n const count = head.querySelector('.ad-group-count');\r\n caret.textContent = collapsed ? '▸' : '▾';\r\n // textContent 로만 넣는다 — 폴더 이름에 어떤 문자가 와도 마크업으로 해석되지 않게\r\n label.textContent = group.label;\r\n // 개수는 접었을 때 특히 필요하다 — 접힌 그룹에 세션이 몇 개 숨어 있는지 보여야 한다\r\n count.textContent = String(group.tabs.length);\r\n // 임시로 펴 둔 이유를 꼬리말로 — 이 한 줄이 없으면 \"접어 뒀는데 왜 보이나\" 가 된다\r\n const why = state.reason === 'filter-open'\r\n ? ' · 검색에 걸린 세션이 있어 임시로 펴 둠 (검색을 지우면 다시 접힌다)'\r\n : '';\r\n head.title = (group.key\r\n ? `${group.key} (탭 ${group.tabs.length}개) — 클릭하면 접기/펴기`\r\n : `작업 폴더를 아직 모르는 탭 ${group.tabs.length}개 — 클릭하면 접기/펴기`) + why;\r\n // 헤더도 키보드로 짚을 수 있다 — 거기서 Enter 는 접기/펴기다 (`activateNav`)\r\n if (this.isNavFocused({ kind: 'head', key: group.key })) {\r\n head.classList.add('ad-nav-focus');\r\n }\r\n head.addEventListener('click', () => this.toggleGroup(group.key));\r\n return head;\r\n }\r\n /**\r\n * 헤더 오른쪽의 상태별 집계 — `⏸ 2 ● 3 ○ 1` 처럼 급한 순서로 놓는다.\r\n * 총 개수만 보이던 자리다. 세션을 여럿 띄우면 \"몇 개가 나를 기다리나\" 가 먼저 보여야 한다.\r\n *\r\n * 칩은 **상태 필터의 조작부도 겸한다** — 누르면 그 상태만 남고, 한 번 더 누르면 풀린다\r\n * (그 UI 를 고른 이유는 `toggleStatusFilter` 주석). 그래서 집계는 **항상 전체 탭 기준**이다:\r\n * 필터 기준으로 세면 다른 상태로 갈아타거나 필터를 풀 수단이 화면에서 사라진다(`render` 주석).\r\n * 0 인 상태는 그리지 않지만, **지금 걸어 둔 필터의 칩만은 0 이어도 남긴다.**\r\n * 동적 텍스트는 textContent 로만 넣는다 (innerHTML 금지).\r\n */\r\n renderHeadCount(tabs, statusOf) {\r\n const countEl = this.sidebar.querySelector('.ad-head-count');\r\n if (!countEl) {\r\n return;\r\n }\r\n countEl.innerHTML = '';\r\n countEl.title = `탭 ${tabs.length}개`;\r\n const active = this.statusFilter;\r\n const counts = (0, order_1.countByStatus)(tabs, statusOf);\r\n // 걸어 둔 필터의 칩은 **개수가 0 이 되어도 남긴다.** `countByStatus` 는 0 인 상태를\r\n // 빼는데(order.ts), 그 상태의 마지막 탭이 상태를 바꾸면 칩이 사라져 필터를 끌 수단이\r\n // 화면에서 없어진다 — 목록은 비었고 이유는 안 보이는 최악의 조합이 된다.\r\n if (active && !counts.some(c => c.status === active)) {\r\n counts.push({ status: active, count: 0 });\r\n counts.sort((a, b) => (0, order_1.statusRank)(a.status) - (0, order_1.statusRank)(b.status));\r\n }\r\n for (const { status, count } of counts) {\r\n const style = api_1.STATUS_STYLES[status];\r\n const chip = document.createElement('span');\r\n chip.className = status === active ? 'ad-cnt active' : 'ad-cnt';\r\n chip.style.setProperty('--ad-color', style.color);\r\n chip.title = status === active\r\n ? `${style.label} ${count} — 클릭하면 필터 해제`\r\n : `${style.label} ${count} — 클릭하면 이 상태만`;\r\n chip.textContent = `${style.icon} ${count}`;\r\n // `.ad-head` 는 도킹 방향을 바꾸는 드래그 핸들이다(dock.ts `installDockDrag`).\r\n // 거기서 pointerdown 이 시작되면 헤더가 포인터 캡처를 잡아 우리 click 이 헤더로\r\n // 되배달될 수 있다. dock.ts 는 `button, input` 만 예외로 두는데 칩은 span 이라\r\n // 그 예외에 안 걸리므로, 전파를 끊어 드래그가 아예 무장되지 않게 한다.\r\n chip.addEventListener('pointerdown', ev => ev.stopPropagation());\r\n chip.addEventListener('click', ev => {\r\n ev.stopPropagation();\r\n this.toggleStatusFilter(status);\r\n });\r\n countEl.appendChild(chip);\r\n }\r\n if (!tabs.length) {\r\n countEl.textContent = '0';\r\n }\r\n }\r\n renderTab(tab) {\r\n const st = this.status.get(tab);\r\n const style = api_1.STATUS_STYLES[st.status];\r\n const active = tab === this.app.activeTab;\r\n const row = document.createElement('div');\r\n row.className = active ? 'ad-tab active' : 'ad-tab';\r\n row.style.setProperty('--ad-color', style.color);\r\n // 이 줄이 `app.tabs` 의 몇 번째 탭인지 남긴다. 화면 순서는 정렬(`sortByStatus`)·그룹핑으로\r\n // 얼마든지 바뀔 수 있어서, \"n 번째 줄 = n 번째 탭\" 이라는 가정을 두면 안 되기 때문이다\r\n // (회귀 프로브가 그 가정으로 다른 탭의 배지를 읽은 적이 있다). 없는 탭이면 -1.\r\n row.dataset.adIndex = String(this.app.tabs.indexOf(tab));\r\n // 키보드 포커스 링. **`data-ad-index` 에 얹지 않는다** — 그 속성의 뜻은 `app.tabs`\r\n // 인덱스 하나뿐이고 회귀 R41·R16·R19·GR2 가 그것으로 대상 줄을 찾는다. 포커스는\r\n // 클래스로만 말한다(`.ad-nav-focus`, styles.scss)\r\n if (this.isNavFocused({ kind: 'tab', tab })) {\r\n row.classList.add('ad-nav-focus');\r\n }\r\n // [AD:...] 표식은 상태로 이미 반영했으니 제목에서는 지운다\r\n const tabTitle = (0, detect_1.stripTitleMarker)(tab.customTitle || tab.title || '');\r\n // 세 줄은 서로 다른 것을 말한다 —\r\n // 1) 제목: 에이전트가 세션에 붙인 이름. 세션이 사는 동안 거의 안 바뀐다\r\n // (Claude Code 는 시작 때 붙인 콘솔 제목을 계속 들고 있다, 2026-08-28 실측)\r\n // 2) 프롬프트: 마지막으로 보낸 지시. 작업이 넘어갈 때마다 바뀐다\r\n // 3) 상태: 지금 돌고 있는지 / 얼마나 됐는지\r\n // 예전에는 1과 2를 한 줄에 겹쳐 놓느라 둘 중 하나를 못 봤다.\r\n const title = tabTitle || '(제목 없음)';\r\n const elapsed = this.config.store.agentDeck.showElapsed\r\n ? this.formatElapsed(Date.now() - st.since)\r\n : '';\r\n row.innerHTML = [\r\n '<div class=\"ad-bar\"></div>',\r\n '<div class=\"ad-body\">',\r\n ' <div class=\"ad-title\"></div>',\r\n // 라벨은 더블클릭하면 입력창으로 바뀐다(startLabelEdit) — 그때 줄이 무너지지 않게\r\n // 감싸는 줄을 따로 둔다\r\n ' <div class=\"ad-prompt\"><span class=\"ad-label\"></span></div>',\r\n ' <div class=\"ad-meta\">',\r\n ' <span class=\"ad-badge\"></span>',\r\n ' <span class=\"ad-elapsed\"></span>',\r\n ' </div>',\r\n '</div>',\r\n '<button class=\"ad-close\" title=\"탭 닫기\">×</button>',\r\n ].join('\\n');\r\n // textContent 로만 넣는다 — 탭 제목에 어떤 문자가 와도 마크업으로 해석되지 않게\r\n row.querySelector('.ad-title').textContent = title;\r\n const labelEl = row.querySelector('.ad-label');\r\n // 아직 프롬프트가 없어도 줄은 남겨 둔다 — 줄 수가 들쭉날쭉하면 목록이 어지럽고,\r\n // 더블클릭으로 이름을 붙일 자리도 사라진다\r\n labelEl.textContent = st.label || '—';\r\n labelEl.classList.toggle('empty', !st.label);\r\n row.querySelector('.ad-elapsed').textContent = elapsed;\r\n const badge = row.querySelector('.ad-badge');\r\n // 승인대기 이유가 있으면 뒤에 붙인다 — \"⏸ 승인대기 · Bash 권한\". 여러 세션을 띄워 둔 사람이\r\n // 사이드바만 보고 지금 가서 승인할지 정할 수 있게. 원문은 title 로 마우스를 올리면 보인다\r\n badge.textContent = style.icon + ' ' + style.label + (st.reason ? ' · ' + st.reason : '');\r\n badge.title = st.reason;\r\n if (st.pinned) {\r\n badge.classList.add('pinned');\r\n }\r\n // 도는 서브에이전트 개수 — **상태 배지 바로 뒤, 경과시간 앞**에 끼운다.\r\n //\r\n // 왜 그 자리인가. 이 줄(`.ad-meta`)에는 이미 상태 배지(승인 이유·한도 문구까지 붙어\r\n // 길어질 수 있다)와 경과시간이 있고 경과시간은 `margin-left: auto` 로 오른쪽 끝에\r\n // 붙어 있다(styles.scss). ① \"지금 몇 개가 도는가\" 는 상태의 부연이라 배지 옆이 읽는\r\n // 순서에 맞다. ② 배지는 줄어들 수 있게(`flex: 0 1 auto` + 말줄임) 두고 이 칩만\r\n // `flex: 0 0 auto` 로 두면 이유 문구가 길어져도 **개수가 먼저 밀려나지 않는다**.\r\n // ③ 제목·프롬프트 줄에 얹으면 그 두 줄의 말줄임 폭을 먹어 제목이 잘린다.\r\n // 줄의 **직계 자식 구성은 그대로** 다 — 새 노드는 `.ad-meta` 안에만 들어가고\r\n // `data-ad-index` 의 뜻도 건드리지 않는다(회귀 R41·RO2·GR2 가 그것으로 줄을 찾는다).\r\n //\r\n // **0 개면 아무것도 그리지 않는다** — 모든 줄에 `0` 이 붙으면 그냥 노이즈다.\r\n // 표시/스캔의 on-off 게이트(`agentDeck.subagentCount`)는 `subagentsOf` 안에 하나만 있다.\r\n const sub = this.notify.subagentsOf(tab);\r\n if (sub) {\r\n const chip = document.createElement('span');\r\n chip.className = 'ad-subagents';\r\n chip.textContent = `❖${sub.running}`;\r\n // 개수만으로는 무엇을 시켜 놨는지 모른다 — 목록과 경과 시간은 툴팁이 말한다.\r\n // 빈 문자열이면 `title` 을 아예 붙이지 않는다(빈 툴팁이 떠서 커서를 가리지 않게)\r\n if (sub.tooltip) {\r\n chip.title = sub.tooltip;\r\n }\r\n badge.insertAdjacentElement('afterend', chip);\r\n }\r\n // 순서 드래그의 시작점 — 임계치를 넘기기 전에는 아무 일도 하지 않으므로 클릭을 가리지 않는다\r\n row.addEventListener('pointerdown', ev => this.armRowDrag(ev, tab, row));\r\n row.addEventListener('click', ev => {\r\n if (ev.target.closest('.ad-close')) {\r\n return;\r\n }\r\n // 방금 끝난 것이 드래그였으면 이 click 은 그 부산물이다 (dragClickGuard 주석)\r\n if (this.dragClickGuard) {\r\n this.dragClickGuard = false;\r\n return;\r\n }\r\n // 마우스로 짚은 줄에서 키보드가 이어지게 — 핫키를 누르면 여기서 시작한다.\r\n // 링은 목록이 포커스를 가질 때만 그리므로(`isNavFocused`) 지금 화면은 바뀌지 않는다\r\n this.navFocus = { kind: 'tab', tab };\r\n this.zone.run(() => this.app.selectTab(tab));\r\n });\r\n row.addEventListener('dblclick', ev => {\r\n ev.preventDefault();\r\n this.startLabelEdit(row, tab);\r\n });\r\n row.addEventListener('contextmenu', ev => {\r\n ev.preventDefault();\r\n this.showStatusMenu(ev, tab);\r\n });\r\n row.querySelector('.ad-close').addEventListener('click', ev => {\r\n ev.stopPropagation();\r\n this.zone.run(() => { void this.app.closeTab(tab, true); });\r\n });\r\n return row;\r\n }\r\n // ---------- 키보드 내비게이션 ----------\r\n /**\r\n * 키보드가 지금 어디를 갖고 있나 — **`document.activeElement` 가 유일한 출처다.**\r\n *\r\n * 플래그로 들고 있지 않는 이유: \"우리가 키를 받는가\" 는 곧 브라우저 포커스가 어디 있나이고,\r\n * 그 둘이 어긋나는 순간(다른 코드가 터미널을 다시 포커스하는 일은 흔하다 —\r\n * `selectTab` → `emitFocused` → `frontend.focus()`) 플래그를 믿은 쪽이 **터미널 입력을\r\n * 먹는다.** 파생값으로 두면 어긋날 수가 없다.\r\n */\r\n get navMode() {\r\n const el = document.activeElement;\r\n if (el && el === this.searchEl) {\r\n return 'search';\r\n }\r\n if (el && el === this.listEl) {\r\n return 'list';\r\n }\r\n return 'off';\r\n }\r\n /** 키보드 조작을 받을 상태인가 — 끄면(`keyboardNav: false`) 진입 자체를 하지 않는다 */\r\n get navReady() {\r\n return !!this.listEl && this.enabled && this.config.store.agentDeck.keyboardNav !== false;\r\n }\r\n /** 검색창이 화면에 있나 (`applySearchBox` 와 같은 조건) — 위쪽 경계에서 나갈 곳이 있는지 */\r\n navSearchVisible() {\r\n return !!this.searchEl && this.enabled && this.config.store.agentDeck.searchBox !== false;\r\n }\r\n /**\r\n * 지금 화면의 이동 순서와 그 안에서의 포커스 위치. **매번 `renderPlan()` 에서 새로 받는다.**\r\n *\r\n * 사본을 들고 있지 않는 이유 — 정렬(`sortByStatus`)·검색·상태 필터·그룹 접힘이 전부 이\r\n * 계산에 걸려 있어서, 한 번 만들어 둔 목록은 다음 상태 변화에 곧 낡는다. 줄 수는 탭 수\r\n * 규모(수십)라 매 키마다 다시 계산해도 비용이 렌더 한 번보다 싸다.\r\n */\r\n navPlan() {\r\n const { withHeads, plan, collapseOf } = this.renderPlan();\r\n const rows = (0, nav_1.navRowsOf)(plan.map(group => ({\r\n key: group.key,\r\n tabs: group.tabs,\r\n head: withHeads,\r\n // 헤더를 안 그리는 화면에서는 접힘을 적용하지 않는다 — `render()` 와 같은 규칙\r\n collapsed: withHeads && collapseOf(group).collapsed,\r\n })));\r\n return { rows, index: this.navIndexIn(rows) };\r\n }\r\n /** 같은 줄을 가리키나 — 탭은 객체 동일성, 그룹은 폴딩한 키로 본다(`group.ts collapseIdOf`) */\r\n sameNavRow(a, b) {\r\n if (a.kind === 'tab' && b.kind === 'tab') {\r\n return a.tab === b.tab;\r\n }\r\n if (a.kind === 'head' && b.kind === 'head') {\r\n return (0, group_1.collapseIdOf)(a.key) === (0, group_1.collapseIdOf)(b.key);\r\n }\r\n return false;\r\n }\r\n /** 지금 포커스가 이 줄 목록의 몇 번째인가 — 없거나 화면에서 사라졌으면 -1 */\r\n navIndexIn(rows) {\r\n const focus = this.navFocus;\r\n if (!focus) {\r\n return -1;\r\n }\r\n for (let i = 0; i < rows.length; i++) {\r\n if (this.sameNavRow(rows[i], focus)) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n }\r\n /** 이 줄에 포커스 링을 그려야 하나 — **목록이 키보드를 갖고 있을 때만** 그린다 */\r\n isNavFocused(row) {\r\n return this.navMode === 'list' && !!this.navFocus && this.sameNavRow(row, this.navFocus);\r\n }\r\n /**\r\n * 닫힌 탭을 가리키는 포커스를 버린다 (`render()` 가 매번 부른다).\r\n *\r\n * **필터로 숨은 줄은 버리지 않는다** — 검색을 지우면 같은 줄로 돌아와야 한다. 그래서 판정\r\n * 기준은 `app.tabs` 에 남아 있는지 하나뿐이다(닫힌 탭은 영영 돌아오지 않는다). 이 정리가\r\n * 없으면 닫힌 탭 하나를 계속 붙들고 있게 되고, ↑↓ 를 눌러도 \"없는 줄\" 에서 시작한다.\r\n */\r\n pruneNavFocus() {\r\n const focus = this.navFocus;\r\n if (focus && focus.kind === 'tab' && !this.app.tabs.includes(focus.tab)) {\r\n this.navFocus = null;\r\n }\r\n }\r\n /**\r\n * 목록에 키보드 포커스를 준다 (핫키 · 검색창 ↓).\r\n *\r\n * 포커스를 **`.ad-list` 엘리먼트에** 준다. 이 엘리먼트는 `render()` 가 innerHTML 만 비우고\r\n * 자신은 새로 만들지 않으므로(`buildSidebar` 에서 한 번 만든다) 렌더를 몇 번 왕복해도\r\n * 포커스가 살아남는다 — 줄(`.ad-tab`)에 포커스를 주면 매 렌더에 날아간다. 어느 줄인지는\r\n * DOM 이 아니라 `navFocus`(탭 객체 / 그룹 키)가 들고 있어서 역시 렌더에 지워지지 않는다.\r\n * 라벨 편집(`this.editing`)·드래그(`this.drag`)가 대상을 객체로 들고 있는 것과 같은 방식이다.\r\n */\r\n focusList(where = 'keep') {\r\n if (!this.navReady) {\r\n return false;\r\n }\r\n const { rows, index } = this.navPlan();\r\n if (!rows.length) {\r\n return false;\r\n }\r\n if (where === 'last') {\r\n this.navFocus = rows[rows.length - 1];\r\n }\r\n else if (where === 'first' || index < 0) {\r\n this.navFocus = rows[0];\r\n }\r\n // **여기서 tabindex 를 준다** (배선 때가 아니라). tabindex 가 붙은 엘리먼트는 그 안을\r\n // 클릭해도 포커스를 받으므로, 배선 때 붙여 두면 이 기능을 끈 사람(`keyboardNav: false`)이\r\n // 목록 빈 자리를 클릭했을 때 키가 사이드바에 갇힌다 — 꺼 둔 기능이 만든 죽은 상태다.\r\n // -1 인 이유: Tab 순서에 넣지 않는다. 터미널에서 Tab 을 누른 사람이 사이드바로 튀면\r\n // 입력이 사라지고, 에이전트 CLI 는 Tab 을 자기 것으로 쓴다.\r\n this.listEl.tabIndex = -1;\r\n // preventScroll: 포커스를 주는 것만으로 목록이 튀지 않게 — 어디로 스크롤할지는\r\n // `scrollNavIntoView` 가 포커스 줄 기준으로 정한다\r\n this.listEl.focus({ preventScroll: true });\r\n this.render();\r\n this.scrollNavIntoView();\r\n return true;\r\n }\r\n /** 검색창으로 (목록 첫 줄에서 ↑ · 목록에서 Tab · 핫키인데 줄이 하나도 없을 때) */\r\n focusSearch() {\r\n if (!this.navSearchVisible()) {\r\n return false;\r\n }\r\n this.searchEl.focus();\r\n // 커서는 글 끝에 둔다 — 이어서 치는 것이 자연스럽다(select 하면 다음 글자가 다 지운다)\r\n try {\r\n const n = this.searchEl.value.length;\r\n this.searchEl.setSelectionRange(n, n);\r\n }\r\n catch {\r\n // 일부 입력 타입은 선택 범위를 못 받는다 — 포커스만으로 충분하다\r\n }\r\n // 링을 지운다 — 포커스가 검색창으로 갔으니 `navMode` 는 이제 'search' 다\r\n this.render();\r\n return true;\r\n }\r\n /**\r\n * 키보드를 터미널에 돌려준다 (Esc · Enter 로 탭을 고른 뒤).\r\n *\r\n * **먼저 우리 것을 blur 한다.** `frontend.focus()` 는 `setTimeout` 안에서 xterm 을 포커스하므로\r\n * (`tabby-terminal/dist/index.js:3415`) 그것만 부르면 이 함수가 끝난 시점에는 아직 포커스가\r\n * 우리에게 있고, 곧바로 그리는 화면에 링이 남는다. blur 는 동기라 `navMode` 가 즉시 'off' 가 된다.\r\n * blur 만 하고 끝내지 않는 이유도 분명하다 — 포커스가 `<body>` 에 앉으면 사이드바도 터미널도\r\n * 키를 못 받아 키보드가 죽은 것처럼 보인다.\r\n */\r\n releaseKeyboard() {\r\n var _a, _b, _c;\r\n const el = document.activeElement;\r\n if (el === this.listEl || el === this.searchEl) {\r\n el.blur();\r\n }\r\n const pane = this.focusedPane();\r\n if (typeof ((_a = pane === null || pane === void 0 ? void 0 : pane.frontend) === null || _a === void 0 ? void 0 : _a.focus) === 'function') {\r\n pane.frontend.focus();\r\n }\r\n else {\r\n // 터미널이 아닌 탭(설정 화면 등) — 순정이 포커스를 배달하는 경로에 맡긴다\r\n (_c = (_b = this.app.activeTab) === null || _b === void 0 ? void 0 : _b.emitFocused) === null || _c === void 0 ? void 0 : _c.call(_b);\r\n }\r\n this.render();\r\n }\r\n /**\r\n * ↑↓ · Home · End.\r\n *\r\n * 경계 규칙은 순수 함수(`stepNavIndex`)가 정하고, 여기서는 **검색창으로 나가는 경계**만\r\n * 따로 본다: 검색 줄이 보이는 상태에서 첫 줄의 ↑ 는 항상 검색창이다. 감싸기(`keyboardNavWrap`)\r\n * 보다 이쪽을 앞에 두는 이유 — 검색↔목록 왕복이 이 기능의 요구사항이고, 감싸기를 켠 사람에게\r\n * 그 길이 사라지면 검색창으로 되돌아갈 키가 아예 없어진다(Tab 이 남지만 그건 우회로다).\r\n */\r\n moveNav(step, to) {\r\n if (!this.navReady) {\r\n return;\r\n }\r\n const { rows, index } = this.navPlan();\r\n if (!rows.length) {\r\n this.navFocus = null;\r\n return;\r\n }\r\n if (!to && step < 0 && index === 0 && this.navSearchVisible()) {\r\n this.focusSearch();\r\n return;\r\n }\r\n const wrap = !!this.config.store.agentDeck.keyboardNavWrap;\r\n const next = to === 'first'\r\n ? 0\r\n : to === 'last'\r\n ? rows.length - 1\r\n : (0, nav_1.stepNavIndex)(rows.length, index, step, wrap);\r\n if (next < 0) {\r\n return;\r\n }\r\n this.navFocus = rows[next];\r\n this.render();\r\n this.scrollNavIntoView();\r\n }\r\n /**\r\n * Enter — 탭 줄이면 그 탭으로 전환, 그룹 헤더면 접기/펴기.\r\n *\r\n * **여기가 포커스와 선택이 만나는 유일한 지점이다.** ↑↓ 로는 활성 탭이 바뀌지 않고\r\n * (그래야 훑어볼 수 있다, `navFocus` 주석), 사람이 \"이거\" 라고 말하는 순간이 Enter 다.\r\n * 탭을 골랐으면 이어서 할 일은 그 터미널에 치는 것이므로 키보드도 같이 넘긴다.\r\n * 헤더에서는 넘기지 않는다 — 접었다 펴 보는 것은 아직 목록을 훑는 중이다.\r\n */\r\n activateNav() {\r\n const focus = this.navFocus;\r\n if (!focus) {\r\n return;\r\n }\r\n if (focus.kind === 'head') {\r\n this.toggleGroup(focus.key);\r\n this.scrollNavIntoView();\r\n return;\r\n }\r\n if (!this.app.tabs.includes(focus.tab)) {\r\n return;\r\n }\r\n this.zone.run(() => this.app.selectTab(focus.tab));\r\n this.releaseKeyboard();\r\n }\r\n /**\r\n * Esc — **보이는 것부터 되돌린다.** 걸린 검색어·상태 필터가 있으면 그것을 먼저 지우고\r\n * 포커스는 사이드바에 남기고, 지울 것이 없을 때 비로소 터미널로 나간다.\r\n *\r\n * 순서를 이렇게 정한 근거는 이 기능 밖에 있다 — `✕` 버튼의 title 이 이미\r\n * `검색·필터 지우기 (Esc)` 이고 빈 목록 안내도 `Esc 또는 ✕ 로 전체 목록으로 돌아간다` 라고\r\n * 적혀 있다(`renderEmpty`). 회귀 R52 도 그 계약을 본다. Esc 를 먼저 \"나가기\" 로 바꾸면\r\n * 화면에 적힌 말과 어긋나고, 좁혀진 목록을 남긴 채 포커스만 빠져 필터가 감춰진다 —\r\n * 이 저장소가 가장 위험하다고 적어 둔 실패 모양이다(`searchQuery` 주석).\r\n *\r\n * 검색창의 Esc 도 이 함수로 온다 — 규칙이 두 군데 있으면 갈린다.\r\n */\r\n navEscape() {\r\n if (this.searchQuery.trim() || this.statusFilter) {\r\n this.clearFilters();\r\n return;\r\n }\r\n this.releaseKeyboard();\r\n }\r\n /**\r\n * 핫키(`agentdeck-focus-list`) — 같은 키로 들어가고 나온다.\r\n *\r\n * 목록으로 들어간다(검색창이 아니라). 이 키를 누르는 목적은 \"지금 뜬 세션 중에서 고르는 것\"\r\n * 이고, 검색은 첫 줄에서 ↑ 한 번이면 닿는다. 반대로 검색창을 진입점으로 삼으면 세션이\r\n * 세 개뿐인 사람도 매번 빈 입력창을 지나가야 한다. 줄이 하나도 없으면(탭 0개 · 필터에\r\n * 아무것도 안 걸림) 검색창으로 보낸다 — 그때 사람이 할 수 있는 일은 검색어를 고치는 것뿐이다.\r\n */\r\n toggleKeyboardNav() {\r\n if (!this.navReady) {\r\n return;\r\n }\r\n if (this.navMode !== 'off') {\r\n this.releaseKeyboard();\r\n return;\r\n }\r\n if (!this.focusList('keep')) {\r\n this.focusSearch();\r\n }\r\n }\r\n /**\r\n * 포커스 줄이 목록 밖으로 나갔으면 스크롤해 보여준다.\r\n *\r\n * **키로 옮겼을 때만** 부른다. 매 렌더(경과시간 tick 이 1초마다 돈다)마다 부르면 마우스로\r\n * 목록을 스크롤해 둔 사람의 화면을 계속 되돌린다. `block: 'nearest'` 라 이미 보이는 줄에는\r\n * 아무 일도 하지 않으므로, 목록이 길어져도 필요한 만큼만 움직인다\r\n * (탭이 많으면 화면 밖으로 못 나가던 것이 cycle 10 에서 남은 것으로 적혀 있었다).\r\n */\r\n scrollNavIntoView() {\r\n var _a;\r\n const el = (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.querySelector('.ad-nav-focus');\r\n el === null || el === void 0 ? void 0 : el.scrollIntoView({ block: 'nearest', inline: 'nearest' });\r\n }\r\n /**\r\n * 목록의 키보드 조작을 배선한다.\r\n *\r\n * 리스너를 **`.ad-list` 엘리먼트에** 건다 — 그것이 곧 \"포커스가 없을 때는 아무것도\r\n * 가로채지 않는다\" 의 보증이다. document 리스너 + 플래그로 하면 플래그가 어긋나는 순간\r\n * 터미널 입력을 먹는데, 이 파일은 이미 그 대가를 알고 있다(`claimCtrlVKey` 계열은 그래서\r\n * `isPlainInput` 가드를 달고 있다). 엘리먼트에 걸면 포커스가 여기 없는 동안 이벤트가\r\n * **아예 오지 않는다.**\r\n *\r\n * 처리한 키는 `preventDefault` + `stopPropagation` 으로 끊는다. 끊으면 Tabby core 의\r\n * document **버블** 리스너(`tabby-core/dist/index.js:6329` keydown → `pushKeyEvent`)까지\r\n * 죽으므로 핫키도 발화하지 않는다 — 우리 리스너는 target(`.ad-list`)에 걸려 있어 그보다\r\n * 먼저 돈다. 반대로 **캡처 단계**에 걸린 우리 리스너들(Ctrl+V · Shift+Enter · Enter 라벨 ·\r\n * Home/End IME)은 이보다 먼저 돌아 끊을 수 없으므로, 그쪽이 `isDeckUiKey` 로 사이드바에서\r\n * 난 키를 비켜 준다.\r\n *\r\n * 수식키(Ctrl·Alt·Meta)가 붙은 조합은 손대지 않는다 — 그건 Tabby 핫키의 몫이다\r\n * (Shift 는 예외: Shift+Tab 이 Tab 과 같은 뜻이어야 한다).\r\n */\r\n wireListKeys(list) {\r\n // 여기서는 리스너만 건다 — 목록을 포커스 받을 수 있게 만드는 것(`tabIndex`)은\r\n // 진입 함수 `focusList` 가 한다(이유는 그쪽 주석).\r\n list.addEventListener('keydown', (ev) => {\r\n if (!this.navReady) {\r\n return;\r\n }\r\n if (ev.ctrlKey || ev.altKey || ev.metaKey) {\r\n return;\r\n }\r\n const key = ev.key;\r\n const code = ev.code;\r\n const stop = () => {\r\n ev.preventDefault();\r\n ev.stopPropagation();\r\n };\r\n if (key === 'ArrowDown' || code === 'ArrowDown') {\r\n stop();\r\n this.moveNav(1);\r\n return;\r\n }\r\n if (key === 'ArrowUp' || code === 'ArrowUp') {\r\n stop();\r\n this.moveNav(-1);\r\n return;\r\n }\r\n if (key === 'Home' || code === 'Home') {\r\n stop();\r\n this.moveNav(0, 'first');\r\n return;\r\n }\r\n if (key === 'End' || code === 'End') {\r\n stop();\r\n this.moveNav(0, 'last');\r\n return;\r\n }\r\n if (key === 'Enter' || code === 'Enter' || code === 'NumpadEnter') {\r\n // 조합 확정용 Enter 는 우리 것이 아니다 (`claimEnterLabel` 과 같은 판정)\r\n if (ev.isComposing || ev.keyCode === 229) {\r\n return;\r\n }\r\n stop();\r\n this.activateNav();\r\n return;\r\n }\r\n if (key === 'Escape' || code === 'Escape') {\r\n stop();\r\n this.navEscape();\r\n return;\r\n }\r\n if (key === 'Tab' || code === 'Tab') {\r\n // 기본 동작으로 새면 사이드바도 터미널도 아닌 곳(툴바 버튼 등)에 포커스가 앉아\r\n // 키보드가 죽는다. 검색창이 있으면 거기로 보내고, 없으면 그냥 붙잡아 둔다\r\n stop();\r\n this.focusSearch();\r\n return;\r\n }\r\n });\r\n // 포커스가 오갈 때 링을 맞춘다 — `navMode` 는 activeElement 로 판정하므로 다시\r\n // 그리기만 하면 된다. 줄을 마우스로 클릭했을 때도 여기로 들어오는데, 그때는 곧바로\r\n // `selectTab` → `frontend.focus()` 가 포커스를 터미널로 되가져가고(setTimeout, ~1ms)\r\n // 그건 rAF 보다 빨라 링이 그려지기 전에 상태가 되돌아간다.\r\n list.addEventListener('focus', () => this.scheduleRender());\r\n list.addEventListener('blur', () => this.scheduleRender());\r\n }\r\n // ---------- 줄 드래그로 순서 바꾸기 ----------\r\n /**\r\n * pointerdown — 아직 드래그로 단정하지 않는다(무장까지만).\r\n *\r\n * 이 줄 위에서 일어나는 조작이 이미 넷이다: 클릭=탭 선택, 더블클릭=라벨 편집,\r\n * 우클릭=상태 지정, `✕`=닫기. 그래서 **왼쪽 버튼 + 버튼/입력창 밖 + 임계치 초과** 세\r\n * 조건을 다 만족할 때만 드래그가 된다 (`dock.ts installDockDrag` 와 같은 규약).\r\n *\r\n * 뒤 이벤트를 줄이 아니라 **document 에서 캡처 단계로** 받는 이유 둘 —\r\n * 1) `setPointerCapture` 는 합성 포인터에서 던진다(tools/README 함정 목록). 캡처에\r\n * 기대면 회귀 프로브가 이 기능을 흉내낼 수 없다. document 리스너는 캡처가 없어도\r\n * 커서가 줄 밖으로 나가도 계속 온다.\r\n * 2) Esc 를 캡처 단계에서 먼저 잡아야 터미널·검색창으로 새지 않는다.\r\n */\r\n armRowDrag(ev, tab, row) {\r\n // 새 손짓이 시작됐다 — 지난 드래그가 남긴 가드를 여기서 버린다 (dragClickGuard 주석)\r\n this.dragClickGuard = false;\r\n if (ev.button !== 0 || this.drag || this.editing) {\r\n return;\r\n }\r\n // 닫기 버튼과 라벨 입력창은 그쪽 일이다 (dock.ts 도 `button, input` 을 비켜 준다)\r\n if (ev.target.closest('button, input')) {\r\n return;\r\n }\r\n const onMove = (e) => this.dragMove(e);\r\n const onUp = (e) => this.endRowDrag(true, e);\r\n const onCancel = () => this.endRowDrag(false, undefined, 'cancel');\r\n const onKey = (e) => {\r\n if (e.key !== 'Escape' && e.code !== 'Escape') {\r\n return;\r\n }\r\n // 취소 경로 하나 — Esc. 여기서 끊지 않으면 터미널로 새고 검색 필터까지 지워진다\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.endRowDrag(false, undefined, 'esc');\r\n };\r\n document.addEventListener('pointermove', onMove, true);\r\n document.addEventListener('pointerup', onUp, true);\r\n document.addEventListener('pointercancel', onCancel, true);\r\n document.addEventListener('keydown', onKey, true);\r\n this.drag = {\r\n tab,\r\n row,\r\n from: { x: ev.clientX, y: ev.clientY },\r\n at: { x: ev.clientX, y: ev.clientY },\r\n moved: false,\r\n target: null,\r\n line: null,\r\n scrolled: { px: 0, axis: null },\r\n scroll: null,\r\n detach: () => {\r\n document.removeEventListener('pointermove', onMove, true);\r\n document.removeEventListener('pointerup', onUp, true);\r\n document.removeEventListener('pointercancel', onCancel, true);\r\n document.removeEventListener('keydown', onKey, true);\r\n },\r\n };\r\n }\r\n /** pointermove — 임계치를 넘기면 드래그로 승격하고, 그 뒤로는 놓일 자리를 계속 다시 잰다 */\r\n dragMove(ev) {\r\n const d = this.drag;\r\n if (!d) {\r\n return;\r\n }\r\n if (!d.moved) {\r\n if (Math.hypot(ev.clientX - d.from.x, ev.clientY - d.from.y) < ROW_DRAG_THRESHOLD) {\r\n return;\r\n }\r\n if (this.config.store.agentDeck.sortByStatus) {\r\n this.noteReorderBlocked();\r\n // 손짓은 드래그였다 — 뒤따라 오는 click(탭 선택)까지 먹지 않게 가드를 켠다.\r\n // 안내를 읽으려는 사람의 활성 탭이 바뀌면 터미널 화면까지 튄다.\r\n this.dragClickGuard = true;\r\n this.endRowDrag(false, undefined, 'blocked-sort');\r\n return;\r\n }\r\n d.moved = true;\r\n d.row.classList.add('ad-dragging');\r\n // 드래그 중에는 커서를 옮기기 모양으로 — 줄마다 주는 것보다 한 곳에서 켜고 끄는 편이 안전하다\r\n document.body.classList.add('ad-reordering');\r\n }\r\n // 드래그 중의 텍스트 선택·브라우저 기본 자동 스크롤 같은 동작을 막는다\r\n // (목록 스크롤은 우리가 `dragScrollTick` 에서 직접 한다 — 브라우저 것은 축·속도·\r\n // 삽입선 갱신을 우리 규칙과 맞출 수 없다)\r\n ev.preventDefault();\r\n d.at = { x: ev.clientX, y: ev.clientY };\r\n this.refreshDropTarget();\r\n // 놓일 자리를 먼저 재고 **그 다음** 스크롤을 건다 — 순서가 반대면 커서를 띠에 넣는\r\n // 순간의 한 프레임 동안 삽입선이 스크롤 전 자리를 가리킨다\r\n this.armDragScroll();\r\n }\r\n /**\r\n * 지금 포인터 자리로 놓일 자리를 다시 재고 삽입선을 다시 그린다.\r\n *\r\n * 포인터가 움직였을 때(`dragMove`)와 **목록이 커서 아래에서 흘렀을 때**(`dragScrollTick`)\r\n * 둘 다 필요한 일이라 한 곳에 둔다. 스크롤 뒤 이것을 부르지 않으면 삽입선이 옛 자리에\r\n * 남아 \"어디에 떨어질지 모르는 드래그\" 가 되어, 자동 스크롤이 없애려던 문제로 돌아간다.\r\n *\r\n * 판정은 반드시 `dropTargetAt` 을 지난다 — 낡은 `data-ad-index` 검사(`stale-index`)를\r\n * 우회하는 지름길을 만들지 않는다.\r\n */\r\n refreshDropTarget() {\r\n const d = this.drag;\r\n if (!d) {\r\n return;\r\n }\r\n d.target = this.dropTargetAt(d.at.x, d.at.y);\r\n this.drawReorderLine();\r\n }\r\n /**\r\n * 목록이 실제로 스크롤되는 축 — 도킹 방향으로 정하지 않고 **넘치는 쪽을 재서** 정한다.\r\n * 넘치지 않으면 null (= 자동 스크롤이 할 일이 없는 화면).\r\n *\r\n * 흐르는 축(`listFlowsSideways`)과 **스크롤되는 축이 다르다**는 것이 실측이다:\r\n * 상/하 도킹의 목록은 줄이 가로로 흐르지만 `flex-wrap: wrap` + `overflow-x: hidden`\r\n * 이라 넘치면 **아래로 감기고 세로로** 스크롤된다(`styles.scss` 의 `.ad-dock-top .ad-list`).\r\n * 그래서 흐름축을 그대로 스크롤축으로 쓰면 상/하 도킹에서 이 기능이 **조용히 아무것도\r\n * 안 하게** 된다. 흐름축은 두 축이 다 넘칠 때의 우선순위로만 쓴다 — 그때는 사용자가\r\n * 눈으로 따라가는 방향이 흐름축이다.\r\n */\r\n listScrollAxis() {\r\n const el = this.listEl;\r\n if (!el) {\r\n return null;\r\n }\r\n // 1px 는 소수점 레이아웃에서 늘 생기는 잔차라 넘침으로 세지 않는다\r\n const canY = el.scrollHeight - el.clientHeight > 1;\r\n const canX = el.scrollWidth - el.clientWidth > 1;\r\n if (canY && canX) {\r\n return this.listFlowsSideways() ? 'x' : 'y';\r\n }\r\n if (canY) {\r\n return 'y';\r\n }\r\n return canX ? 'x' : null;\r\n }\r\n /**\r\n * 지금 포인터 자리에서의 자동 스크롤 속도 (px/s). 0 이면 스크롤할 이유가 없다.\r\n *\r\n * **여기는 DOM 을 읽는 껍데기고 판단은 `planEdgeScroll` 이 한다** — 속도 램프·띠 겹침·\r\n * 끝 도달 같은 규칙이 rect 읽기와 한 함수에 있으면 그것을 검사할 방법이 없다.\r\n * 옮긴 뒤 `test/order.test.js` 가 전수로 잰다(`planTabMove`·`stepNavIndex` 와 같은 방식).\r\n */\r\n dragScrollSpeed(axis) {\r\n const el = this.listEl;\r\n const d = this.drag;\r\n if (!el || !d) {\r\n return 0;\r\n }\r\n const r = el.getBoundingClientRect();\r\n const vertical = axis === 'y';\r\n return (0, order_1.planEdgeScroll)({\r\n pos: vertical ? d.at.y : d.at.x,\r\n near: vertical ? r.top : r.left,\r\n far: vertical ? r.bottom : r.right,\r\n cur: vertical ? el.scrollTop : el.scrollLeft,\r\n maxScroll: vertical\r\n ? el.scrollHeight - el.clientHeight\r\n : el.scrollWidth - el.clientWidth,\r\n bandPx: DRAG_SCROLL_BAND_PX,\r\n minPps: DRAG_SCROLL_MIN_PPS,\r\n maxPps: DRAG_SCROLL_MAX_PPS,\r\n });\r\n }\r\n /**\r\n * 포인터가 목록 가장자리 띠에 있으면 자동 스크롤 루프를 건다 (이미 돌고 있으면 그대로 둔다).\r\n *\r\n * **끌고 있을 때만 부른다** — `dragMove` 가 임계치를 넘긴 뒤의 유일한 호출자다.\r\n * 마우스가 목록 끝에 얹혀 있어도 드래그가 아니면 이 함수에 닿는 길이 없다(hover 리스너를\r\n * 두지 않은 이유가 그것이다).\r\n */\r\n armDragScroll() {\r\n const d = this.drag;\r\n if (!d || !d.moved) {\r\n return;\r\n }\r\n // 끈 사람의 화면은 0.12.0 과 똑같아야 한다 (config `dragAutoScroll`)\r\n if (!this.config.store.agentDeck.dragAutoScroll) {\r\n return;\r\n }\r\n const axis = this.listScrollAxis();\r\n if (!axis || (d.scroll && d.scroll.axis !== axis)) {\r\n // 축이 바뀌었으면(도킹 변경·목록 재구성) 옛 축의 루프는 버린다\r\n this.stopDragScroll(d);\r\n if (!axis) {\r\n return;\r\n }\r\n }\r\n if (!this.dragScrollSpeed(axis)) {\r\n // 띠를 벗어났거나 끝에 닿았다 — 돌고 있던 루프를 여기서 끊는다\r\n this.stopDragScroll(d);\r\n return;\r\n }\r\n if (d.scroll) {\r\n return;\r\n }\r\n const s = { raf: 0, prev: performance.now(), axis };\r\n d.scroll = s;\r\n d.scrolled.axis = axis;\r\n s.raf = requestAnimationFrame(now => this.dragScrollTick(now));\r\n }\r\n /**\r\n * 자동 스크롤 한 프레임 — 목록을 조금 흘리고 **놓일 자리를 다시 잰다**.\r\n *\r\n * `render()` 를 부르지 않는다(부르면 끌고 있던 줄의 DOM 이 사라진다 — `render` 의 드래그\r\n * 가드). 여기서 만지는 것은 목록의 `scrollTop`/`scrollLeft` 와 삽입선뿐이다.\r\n * `scrollNavIntoView` 도 부르지 않는다 — 그건 키 이동의 몫이고, 여기서 부르면 방금\r\n * 흘린 화면을 포커스 줄 기준으로 되돌린다.\r\n */\r\n dragScrollTick(now) {\r\n const d = this.drag;\r\n const el = this.listEl;\r\n // 드래그가 끝났거나 다른 드래그로 바뀌었으면 루프도 여기서 끝난다 (누수 이중 안전망)\r\n if (!d || !d.scroll || !d.moved || !el) {\r\n return;\r\n }\r\n const s = d.scroll;\r\n const speed = this.dragScrollSpeed(s.axis);\r\n if (!speed) {\r\n this.stopDragScroll(d);\r\n return;\r\n }\r\n const dt = Math.min(DRAG_SCROLL_MAX_DT_MS, Math.max(0, now - s.prev));\r\n s.prev = now;\r\n const step = speed * dt / 1000;\r\n const before = s.axis === 'y' ? el.scrollTop : el.scrollLeft;\r\n if (s.axis === 'y') {\r\n el.scrollTop = before + step;\r\n }\r\n else {\r\n el.scrollLeft = before + step;\r\n }\r\n // **실제로 움직인 만큼**만 센다 — 끝에 닿으면 브라우저가 값을 깎으므로 요청값과 다르다\r\n d.scrolled.px += Math.abs((s.axis === 'y' ? el.scrollTop : el.scrollLeft) - before);\r\n // 줄이 커서 아래를 지나갔다 — 같은 좌표로 다시 판정해야 삽입선이 옛 자리에 남지 않는다\r\n this.refreshDropTarget();\r\n s.raf = requestAnimationFrame(t => this.dragScrollTick(t));\r\n }\r\n /** 자동 스크롤 루프를 끊는다 — 취소 없이 두면 드래그가 끝나도 프레임마다 계속 돈다 */\r\n stopDragScroll(d) {\r\n if (!d.scroll) {\r\n return;\r\n }\r\n cancelAnimationFrame(d.scroll.raf);\r\n d.scroll = null;\r\n }\r\n /**\r\n * 이 좌표에 놓으면 어디로 가나 — 놓을 자리가 없으면 null(= 놓아도 아무 일 없음).\r\n *\r\n * **후보 집합을 `renderPlan()` 에서 받는다.** 화면 순서를 정하는 계산이 한 곳뿐이어야\r\n * 진단구(`__agentdeck.groups()`)와 화면이 어긋나지 않는다 — 이 파일에서 순서 규칙의\r\n * 사본을 만들지 않는 것이 그 함수를 뽑은 이유다.\r\n *\r\n * 후보는 **끌고 있는 탭이 속한 `plan` 그룹의 탭들**이다. 두 화면이 한 규칙으로 덮인다 —\r\n * - 헤더가 없는 화면: `plan` 이 평면 한 덩이라(renderPlan) 후보 = 보이는 줄 전부.\r\n * - 헤더가 있는 화면: 후보 = **같은 그룹 안**. 그룹 키는 작업 폴더(cwd)라 순서를 바꿔도\r\n * 그룹이 바뀌지 않으므로, 다른 그룹의 줄에 놓아 주면 그 줄은 사용자가 놓은 자리가 아니라\r\n * 자기 그룹 안으로 되돌아가 앉는다. \"놓은 곳에 안 간다\" 가 가장 나쁜 결과라, 다른 그룹\r\n * 위에서는 삽입선을 아예 그리지 않고 놓아도 취소로 끝낸다(무시).\r\n *\r\n * 필터가 걸려 줄이 숨은 화면에서는 숨은 탭이 사이에 남는다 — 그래도 **보이는 줄들의\r\n * 상대 순서**는 사용자가 놓은 그대로가 된다. 눈에 보이지 않는 탭의 자리를 짐작해 옮기는\r\n * 것보다 이쪽이 예측 가능하다.\r\n */\r\n dropTargetAt(x, y) {\r\n const reject = (why) => {\r\n this.dropReject = why;\r\n return null;\r\n };\r\n const d = this.drag;\r\n if (!d || !this.listEl) {\r\n return reject('gone');\r\n }\r\n const list = this.listEl.getBoundingClientRect();\r\n // 취소 경로 둘 — 목록 밖에 놓기\r\n if (x < list.left || x > list.right || y < list.top || y > list.bottom) {\r\n return reject('outside-list');\r\n }\r\n const { withHeads, plan } = this.renderPlan();\r\n const group = plan.find(g => g.tabs.includes(d.tab));\r\n if (!group || !this.app.tabs.includes(d.tab)) {\r\n // 끌던 탭이 화면에서 빠졌거나(필터) 닫혔다 — 놓을 자리를 정할 근거가 없다\r\n return reject('gone');\r\n }\r\n const el = document.elementFromPoint(x, y);\r\n const rowEl = el === null || el === void 0 ? void 0 : el.closest('.ad-tab');\r\n if (!rowEl) {\r\n // 줄이 아닌 빈 자리. 헤더가 없는 화면에서만 \"맨 끝\" 으로 본다 —\r\n // 헤더가 있으면 그 빈 자리가 어느 그룹의 끝인지 화면상 정해지지 않는다\r\n if (withHeads || (el === null || el === void 0 ? void 0 : el.closest('.ad-list')) !== this.listEl) {\r\n return reject('no-row');\r\n }\r\n const last = group.tabs[group.tabs.length - 1];\r\n if (!last || last === d.tab) {\r\n return reject('self');\r\n }\r\n this.dropReject = null;\r\n return { tab: last, place: 'after' };\r\n }\r\n // 대상 탭은 줄에 남아 있는 `data-ad-index`(= `app.tabs` 인덱스) 로 되찾는다.\r\n // 그 값의 뜻을 바꾸지 않는 이유는 `renderTab` 주석에 있다 (회귀가 그것으로 줄을 찾는다).\r\n const tab = this.app.tabs[Number(rowEl.dataset.adIndex)];\r\n if (!tab) {\r\n return reject('gone');\r\n }\r\n if (tab === d.tab) {\r\n return reject('self');\r\n }\r\n if (!group.tabs.includes(tab)) {\r\n return reject('other-group');\r\n }\r\n // **낡은 식별자를 걸러낸다.** 드래그 중에는 화면을 다시 그리지 않으므로(`render` 가드),\r\n // 그 사이 탭이 하나 닫히면 뒤쪽 줄들의 `data-ad-index` 가 한 칸씩 밀려 **다른 탭을**\r\n // 가리킨다 — 그대로 쓰면 사용자가 짚지 않은 탭을 옮긴다. 지금 인덱스로 되찾은 줄이\r\n // 방금 짚은 줄과 같은지 확인해 어긋나면 놓을 자리로 보지 않는다 (다음 렌더에 회복된다).\r\n if (this.rowElOf(tab) !== rowEl) {\r\n return reject('stale-index');\r\n }\r\n const r = rowEl.getBoundingClientRect();\r\n // 상/하 도킹은 목록이 가로로 흐른다(styles.scss `.ad-dock-top .ad-list`) — 축이 바뀐다\r\n const past = this.listFlowsSideways()\r\n ? x > (r.left + r.right) / 2\r\n : y > (r.top + r.bottom) / 2;\r\n this.dropReject = null;\r\n return { tab, place: past ? 'after' : 'before' };\r\n }\r\n /** 목록이 가로로 흐르나 (상/하 도킹) — 삽입선의 방향과 중점 판정 축이 여기서 갈린다 */\r\n listFlowsSideways() {\r\n return !(0, dock_1.isHorizontalDock)(this.dockSide);\r\n }\r\n /**\r\n * 놓일 자리를 삽입선으로 보여준다 (요구: 어디에 떨어질지 모르는 드래그는 쓸 수 없다).\r\n *\r\n * **`.ad-list` 안에 넣지 않는다.** 목록의 자식으로 두면 (1) `render()` 가 innerHTML 을\r\n * 비울 때 같이 날아가고, (2) 회귀 프로브가 목록의 자식을 순서대로 훑어 그룹 구성을 읽는데\r\n * (probe-group `sections`) 그 사이에 낯선 노드가 끼어든다. dock.ts 의 드롭 가이드와 같이\r\n * body 에 붙이고 `position: fixed` 로 화면 좌표에 그린다 — 사이드바의 `overflow: hidden`\r\n * 에도 잘리지 않는다.\r\n */\r\n drawReorderLine() {\r\n var _a;\r\n const d = this.drag;\r\n if (!d || !this.listEl) {\r\n return;\r\n }\r\n if (!d.target) {\r\n // 놓을 자리가 없으면 선을 지운다 — 선이 남아 있으면 \"놓으면 저기로 간다\" 는 거짓말이 된다\r\n (_a = d.line) === null || _a === void 0 ? void 0 : _a.remove();\r\n d.line = null;\r\n return;\r\n }\r\n const rowEl = this.rowElOf(d.target.tab);\r\n if (!rowEl) {\r\n return;\r\n }\r\n if (!d.line) {\r\n const line = document.createElement('div');\r\n line.className = 'ad-reorder-line';\r\n document.body.appendChild(line);\r\n d.line = line;\r\n }\r\n const r = rowEl.getBoundingClientRect();\r\n const list = this.listEl.getBoundingClientRect();\r\n const s = d.line.style;\r\n const half = REORDER_LINE_PX / 2;\r\n // **가로지르는 축도 가둔다.** 자동 스크롤이 들어온 뒤로는 목록 경계에 반쯤 걸린 줄을\r\n // 가리키는 일이 흔해졌는데(가장자리에 커서를 대고 있으면 그 자리의 줄이 늘 반쯤 잘려\r\n // 있다), 줄의 rect 를 그대로 쓰면 선이 사이드바 밖 터미널 위까지 뻗는다 —\r\n // 삽입선은 `position: fixed` 라 목록의 `overflow` 가 잘라 주지 않는다.\r\n const clampTo = (v, lo, hi) => Math.min(Math.max(v, lo), hi);\r\n if (this.listFlowsSideways()) {\r\n const x = d.target.place === 'after' ? r.right : r.left;\r\n // 목록 밖으로 삐져나가지 않게 가둔다 — 맨 끝 줄의 뒤를 가리킬 때 특히\r\n s.left = Math.round(clampTo(x, list.left, list.right) - half) + 'px';\r\n const top = clampTo(r.top, list.top, list.bottom);\r\n const bottom = clampTo(r.bottom, list.top, list.bottom);\r\n s.top = Math.round(top) + 'px';\r\n s.width = REORDER_LINE_PX + 'px';\r\n // 줄이 통째로 밖에 있으면 0 이 되는데, 그러면 \"어디에 놓이나\" 가 화면에서 사라진다.\r\n // 그 좌표는 `dropTargetAt` 이 이미 후보로 인정한 자리라 1px 이라도 그려야 한다\r\n s.height = Math.max(1, Math.round(bottom - top)) + 'px';\r\n }\r\n else {\r\n const y = d.target.place === 'after' ? r.bottom : r.top;\r\n const left = clampTo(r.left, list.left, list.right);\r\n const right = clampTo(r.right, list.left, list.right);\r\n s.left = Math.round(left) + 'px';\r\n s.top = Math.round(clampTo(y, list.top, list.bottom) - half) + 'px';\r\n s.width = Math.max(1, Math.round(right - left)) + 'px';\r\n s.height = REORDER_LINE_PX + 'px';\r\n }\r\n }\r\n /** 그 탭의 줄 엘리먼트 — 줄은 `data-ad-index`(= `app.tabs` 인덱스) 로만 찾는다 */\r\n rowElOf(tab) {\r\n const i = this.app.tabs.indexOf(tab);\r\n if (i < 0 || !this.listEl) {\r\n return null;\r\n }\r\n return this.listEl.querySelector(`.ad-tab[data-ad-index=\"${i}\"]`);\r\n }\r\n /**\r\n * 드래그 종료 — `commit` 이 false 면 취소(원래 순서 그대로).\r\n *\r\n * 취소로 들어오는 길은 셋이다: Esc, `pointercancel`, 그리고 놓을 자리가 없는 곳에서\r\n * 손을 뗀 것(목록 밖 · 다른 그룹 위). 셋 다 `app.tabs` 를 건드리지 않고 화면만 되돌린다.\r\n */\r\n endRowDrag(commit, ev, why) {\r\n var _a;\r\n const d = this.drag;\r\n if (!d) {\r\n return;\r\n }\r\n this.dropReject = null;\r\n if (commit && d.moved && ev) {\r\n // 놓은 좌표로 한 번 더 판정한다 — 마지막 pointermove 와 pointerup 사이에도 커서는 움직인다\r\n d.target = this.dropTargetAt(ev.clientX, ev.clientY);\r\n }\r\n const moved = d.moved;\r\n const target = commit && moved ? d.target : null;\r\n this.drag = null;\r\n // 자동 스크롤을 **가장 먼저** 끊는다. 손을 떼거나 취소된 뒤에도 목록이 흐르면\r\n // 사용자가 방금 놓은 자리가 화면에서 미끄러진다 (`this.drag` 를 이미 비웠으므로\r\n // tick 은 다음 프레임에 스스로 멈추지만, 그 한 프레임도 그리지 않는다)\r\n this.stopDragScroll(d);\r\n d.detach();\r\n (_a = d.line) === null || _a === void 0 ? void 0 : _a.remove();\r\n d.row.classList.remove('ad-dragging');\r\n document.body.classList.remove('ad-reordering');\r\n // 사유는 **부르는 쪽이 아는 것**(Esc·pointercancel·게이트)을 우선하고, 나머지는 결과로 정한다\r\n const note = (reason) => {\r\n this.lastDragEnd = {\r\n reason,\r\n drop: this.dropReject,\r\n committed: reason === 'moved',\r\n at: Date.now(),\r\n scrolled: { px: Math.round(d.scrolled.px), axis: d.scrolled.axis },\r\n };\r\n };\r\n if (!moved) {\r\n // 임계치를 못 넘긴 것 = 그냥 클릭이었다. 선택 동작을 방해하지 않는다\r\n note(why !== null && why !== void 0 ? why : 'below-threshold');\r\n return;\r\n }\r\n this.dragClickGuard = true;\r\n note(why !== null && why !== void 0 ? why : (target ? 'moved' : 'no-target'));\r\n if (target) {\r\n this.applyReorder(d.tab, target.tab, target.place);\r\n }\r\n // 드래그 중 멈춰 뒀던 화면을 반드시 여기서 한 번 되살린다 (`render` 의 드래그 가드)\r\n this.render();\r\n }\r\n /**\r\n * `app.tabs` 를 실제로 재배열한다 — **순정과 같은 방법**이다.\r\n *\r\n * 근거: Tabby 의 탭바도 드롭을 받으면 그 배열을 제자리에서 흔들고 변경을 알린다 —\r\n * `moveItemInArray(this.app.tabs, event.previousIndex, event.currentIndex); this.app.emitTabsChanged()`\r\n * (`node_modules/tabby-core/dist/index.js` 의 `onTabsReordered`). 탭바 템플릿도\r\n * `*ngFor=\"let tab of app.tabs; let idx = index\"` 로 그 배열을 그대로 읽고 trackBy 가 없어서,\r\n * 제자리 재배열 + 변경 감지가 곧 순정 탭바의 순서 변경이다.\r\n *\r\n * `AppService` 의 순서 API 는 이 조작에 못 쓴다 — `swapTabs(a, b)` 는 두 탭을 맞바꾸기만 해서\r\n * \"사이에 끼워넣기\" 를 표현할 수 없고(중간 탭들이 밀리지 않는다), `moveSelectedTabLeft/Right`\r\n * 는 활성 탭만 한 칸씩 옮긴다. 그래서 순정 탭바가 자기 드롭에 쓰는 경로를 그대로 쓴다.\r\n *\r\n * 배열 객체를 새것으로 갈아 끼우지 않는 이유도 같다 — 이미 `app.tabs` 를 들고 있는 곳이\r\n * 있어도 같은 배열을 보게 해야 한다(순정도 제자리에서 흔든다).\r\n * 포인터 이벤트는 Angular 밖이라 `zone.run` 안에서 바꿔 변경 감지를 태운다.\r\n */\r\n applyReorder(tab, to, place) {\r\n const tabs = this.app.tabs;\r\n const from = tabs.indexOf(tab);\r\n const at = tabs.indexOf(to);\r\n const order = (0, order_1.planTabMove)(tabs.length, from, at, place);\r\n if (!order) {\r\n // 제자리 드롭이거나 이미 닫힌 탭 — 순정 탭바를 다시 그릴 이유가 없다\r\n return false;\r\n }\r\n const next = order.map(i => tabs[i]);\r\n this.zone.run(() => {\r\n for (let i = 0; i < next.length; i++) {\r\n tabs[i] = next[i];\r\n }\r\n this.app.emitTabsChanged();\r\n });\r\n this.diag(`reorder ${from} -> ${at} ${place} order=${order.join(',')}`);\r\n return true;\r\n }\r\n /**\r\n * \"지금은 순서를 바꿀 수 없다\" 를 그 자리에서 한 줄로 알린다.\r\n *\r\n * `sortByStatus` 가 켜져 있으면 화면 순서를 상태가 정한다(`renderPlan`) — 옮겨 놓아도\r\n * 다음 렌더에 제자리로 돌아가므로 드래그가 무의미하다. 그래서 **막는다.**\r\n * 드래그를 계기로 그 설정을 대신 꺼 주지는 않는다: 사용자가 저장해 둔 설정을 곁동작으로\r\n * 뒤집는 것은 예측할 수 없고(다음 기동까지 남는다), 무엇이 바뀌었는지 화면에 단서도 없다.\r\n * 대신 막은 이유와 푸는 방법을 적어 보여준다.\r\n */\r\n noteReorderBlocked() {\r\n var _a;\r\n if (!this.sidebar) {\r\n return;\r\n }\r\n (_a = this.sidebar.querySelector('.ad-reorder-note')) === null || _a === void 0 ? void 0 : _a.remove();\r\n const el = document.createElement('div');\r\n el.className = 'ad-reorder-note';\r\n // 고정 문구여도 textContent 로 넣는다 (이 파일의 규약 — innerHTML 에 본문 금지)\r\n el.textContent = '상태순 정렬이 켜져 있어 순서를 바꿀 수 없다 — 설정에서 끄면 끌어서 옮길 수 있다';\r\n this.sidebar.appendChild(el);\r\n setTimeout(() => el.remove(), REORDER_NOTE_MS);\r\n }\r\n /** 더블클릭 -> 작업 이름 인라인 편집 */\r\n startLabelEdit(row, tab) {\r\n this.editing = tab;\r\n const holder = row.querySelector('.ad-label');\r\n const input = document.createElement('input');\r\n input.className = 'ad-label-input';\r\n input.value = this.status.get(tab).label;\r\n input.placeholder = '작업 이름';\r\n holder.replaceWith(input);\r\n input.focus();\r\n input.select();\r\n const finish = (commit) => {\r\n if (this.editing !== tab) {\r\n return;\r\n }\r\n this.editing = null;\r\n if (commit) {\r\n this.status.setLabel(tab, input.value.trim());\r\n }\r\n this.render();\r\n };\r\n // 터미널로 키가 새지 않도록 이벤트를 여기서 끊는다\r\n input.addEventListener('keydown', ev => {\r\n ev.stopPropagation();\r\n if (ev.key === 'Enter') {\r\n finish(true);\r\n }\r\n if (ev.key === 'Escape') {\r\n finish(false);\r\n }\r\n });\r\n input.addEventListener('blur', () => finish(true));\r\n }\r\n /**\r\n * 지난 세션 한 줄을 누른 결과 — **이미 열려 있으면 이어받지 않고 그 탭으로 보낸다.**\r\n *\r\n * 같은 세션을 두 탭에서 `--resume` 하면 두 프로세스가 같은 기록 파일에 덧쓴다.\r\n * 세션↔탭 매핑은 `notify` 가 이미 들고 있어 판정에 드는 비용이 없으니 막는다.\r\n */\r\n async activateResume(row, fork) {\r\n if (row.openTabId) {\r\n const tab = this.resumeTabs.get(row.openTabId);\r\n if (tab && this.app.tabs.includes(tab)) {\r\n this.app.selectTab(tab);\r\n return;\r\n }\r\n // 그 사이 닫혔다 — 이어받기로 흘려보낸다\r\n }\r\n const command = (0, sessionLedger_1.resumeCommand)(row.sessionId, fork, row.agent);\r\n if (!command) {\r\n this.diag(`resume 거부 sid=${row.sessionId}`);\r\n return;\r\n }\r\n await this.openResumeTab(row, command);\r\n }\r\n /**\r\n * 이어받기용 새 탭.\r\n *\r\n * **프로필의 `command` 를 갈아끼우지 않고, 평소 프로필로 셸을 띄운 뒤 명령을 써 넣는다.**\r\n * 이유는 `sessionLedger.ts` 의 `resumeCommand` 주석에 있다 — 기존 `agentdeck:root` 프로필의\r\n * 인자(`-ExecutionPolicy Bypass`)가 npm 전역 `.ps1` 래퍼 문제를 이미 풀어 두었고,\r\n * claude 가 끝나도 셸이 남아 사람이 이어서 쓸 수 있다.\r\n *\r\n * **cwd 는 그 세션의 것으로 덮는다.** `--resume` 은 cwd 로 세션을 묶기 때문에(같은 세션도\r\n * 다른 폴더에서 띄우면 목록에 없다) 여기를 틀리면 이어받기 자체가 실패한다.\r\n */\r\n async openResumeTab(row, command) {\r\n var _a, _b, _c, _d;\r\n try {\r\n const wanted = this.config.store.terminal.profile;\r\n const all = await this.profiles.getProfiles();\r\n const base = (_a = all.find(p => p.id === wanted)) !== null && _a !== void 0 ? _a : all[0];\r\n if (!base) {\r\n this.diag('resume 프로필 없음');\r\n return;\r\n }\r\n // 원본 프로필을 건드리지 않는다 — 설정에 저장되는 객체라 cwd 를 박으면 그 뒤\r\n // 새 탭이 전부 그 폴더에서 열린다\r\n const profile = {\r\n ...base,\r\n options: { ...base.options, cwd: row.cwd || ((_b = base.options) === null || _b === void 0 ? void 0 : _b.cwd) },\r\n };\r\n const tab = await this.profiles.openNewTabForProfile(profile);\r\n this.diag(`resume 탭 sid=${row.sessionId.slice(0, 8)} cwd=${(_d = (_c = profile.options) === null || _c === void 0 ? void 0 : _c.cwd) !== null && _d !== void 0 ? _d : '?'} tab=${tab ? 'yes' : 'null'}`);\r\n if (!tab) {\r\n return;\r\n }\r\n // 라벨을 미리 물려준다 — 셸이 뜨고 claude 가 붙기까지 몇 초 동안 줄이 `—` 로 비어\r\n // 있으면 방금 무엇을 눌렀는지 사라진다. 사람이 Enter 를 치면 그때 덮인다\r\n if (row.label) {\r\n this.status.setLabel(tab, row.label);\r\n }\r\n this.sendResumeCommand(tab, command);\r\n }\r\n catch (e) {\r\n (0, diag_1.diagCatch)('resume 탭 열기', e);\r\n }\r\n }\r\n /**\r\n * 갓 뜬 셸에 명령을 써 넣는다.\r\n *\r\n * **바로 쏘면 삼켜진다** — pty 는 열렸는데 셸이 아직 프롬프트를 안 그린 상태에서 쓴 바이트는\r\n * 어디에도 안 남는다(같은 이유로 `sendInput` 을 쓰는 다른 경로들도 프론트엔드 준비를 기다린다).\r\n * 그래서 출력이 한 번이라도 흐른 뒤에 보내고, 끝내 안 오면 정해진 시각에 한 번은 보낸다 —\r\n * 아무것도 안 보내고 조용히 끝나는 것이 제일 나쁜 결과다.\r\n */\r\n sendResumeCommand(tab, command) {\r\n /** 첫 출력(=셸이 프롬프트를 그렸다)을 보고 나서 더 기다리는 시간 */\r\n const RESUME_SETTLE_MS = 700;\r\n /** 출력이 끝내 안 와도 여기서는 한 번 쏜다 — 아무것도 안 보내고 조용히 끝나는 게 제일 나쁘다 */\r\n const RESUME_GIVEUP_MS = 6000;\r\n /** 세션이 붙기를 기다리는 간격 */\r\n const RESUME_POLL_MS = 200;\r\n let sent = false;\r\n let sub = null;\r\n const fire = () => {\r\n var _a;\r\n if (sent) {\r\n return;\r\n }\r\n const anyPane = this.firstPane(tab);\r\n if (!anyPane || typeof anyPane.sendInput !== 'function') {\r\n return;\r\n }\r\n sent = true;\r\n (_a = sub === null || sub === void 0 ? void 0 : sub.unsubscribe) === null || _a === void 0 ? void 0 : _a.call(sub);\r\n this.sendToPane(anyPane, 'resume', () => anyPane.sendInput(command + '\\r'));\r\n this.diag('resume 명령 전송');\r\n };\r\n /**\r\n * **세션은 탭이 만들어진 직후엔 아직 없다** (2026-09-11 실측: `openNewTabForProfile` 이\r\n * 돌아온 시점에 `pane.session` 이 `undefined`). 그때 한 번만 보고 포기하면 구독이 영영\r\n * 안 걸려 매번 6초를 꽉 채우고서야 명령이 나간다. 그래서 붙을 때까지 짧게 되물어본다.\r\n */\r\n const t0 = Date.now();\r\n const arm = () => {\r\n var _a, _b, _c;\r\n if (sent || sub) {\r\n return;\r\n }\r\n let pane = null;\r\n try {\r\n pane = this.firstPane(tab);\r\n sub = (_c = (_b = (_a = pane === null || pane === void 0 ? void 0 : pane.session) === null || _a === void 0 ? void 0 : _a.output$) === null || _b === void 0 ? void 0 : _b.subscribe) === null || _c === void 0 ? void 0 : _c.call(_b, () => setTimeout(fire, RESUME_SETTLE_MS));\r\n }\r\n catch (e) {\r\n (0, diag_1.diagCatch)('resume 출력 구독', e);\r\n return;\r\n }\r\n if (sub) {\r\n this.diag(`resume 구독 armed after=${Date.now() - t0}ms`);\r\n return;\r\n }\r\n if (Date.now() - t0 < RESUME_GIVEUP_MS) {\r\n setTimeout(arm, RESUME_POLL_MS);\r\n }\r\n };\r\n arm();\r\n setTimeout(fire, RESUME_GIVEUP_MS);\r\n }\r\n /** 지난 세션 줄 우클릭 */\r\n showResumeMenu(row, ev) {\r\n const old = document.querySelector('.ad-menu');\r\n if (old) {\r\n old.remove();\r\n }\r\n const menu = document.createElement('div');\r\n menu.className = 'ad-menu';\r\n const items = [];\r\n if (row.openTabId) {\r\n items.push(['이 탭으로 이동', () => { void this.activateResume(row, false); }]);\r\n }\r\n else {\r\n items.push(['새 탭에서 이어받기', () => { void this.activateResume(row, false); }]);\r\n // 분기는 기록을 복제한다 — 기본 동작으로 두면 목록이 비슷한 이름으로 불어난다\r\n items.push(['분기해서 이어받기', () => { void this.activateResume(row, true); }]);\r\n }\r\n items.push(['세션 ID 복사', () => {\r\n var _a, _b;\r\n try {\r\n (_b = (_a = this.platform).setClipboard) === null || _b === void 0 ? void 0 : _b.call(_a, { text: row.sessionId });\r\n }\r\n catch (e) {\r\n (0, diag_1.diagCatch)('세션 ID 복사', e);\r\n }\r\n }]);\r\n items.push(['목록에서 숨기기', () => this.hideResumeRow(row.sessionId)]);\r\n for (const [label, action] of items) {\r\n const item = document.createElement('div');\r\n item.className = 'ad-menu-item';\r\n item.textContent = label;\r\n item.addEventListener('click', () => {\r\n action();\r\n menu.remove();\r\n });\r\n menu.appendChild(item);\r\n }\r\n document.body.appendChild(menu);\r\n menu.style.left = ev.clientX + 'px';\r\n menu.style.top = Math.min(ev.clientY, window.innerHeight - menu.offsetHeight - 8) + 'px';\r\n const close = (e) => {\r\n if (!menu.contains(e.target)) {\r\n menu.remove();\r\n document.removeEventListener('mousedown', close);\r\n }\r\n };\r\n setTimeout(() => document.addEventListener('mousedown', close), 0);\r\n }\r\n /** 목록에서만 감춘다 — 기록 파일은 건드리지 않는다(그건 사람이 지울 일이다) */\r\n hideResumeRow(sessionId) {\r\n const cfg = this.config.store.agentDeck;\r\n const stored = Array.isArray(cfg.resumeHidden)\r\n ? cfg.resumeHidden.filter((k) => typeof k === 'string')\r\n : [];\r\n if (!stored.includes(sessionId)) {\r\n cfg.resumeHidden = [...stored, sessionId];\r\n this.config.save();\r\n }\r\n this.render();\r\n }\r\n /** 우클릭 -> 상태 직접 지정 */\r\n showStatusMenu(ev, tab) {\r\n const old = document.querySelector('.ad-menu');\r\n if (old) {\r\n old.remove();\r\n }\r\n const menu = document.createElement('div');\r\n menu.className = 'ad-menu';\r\n const statuses = ['running', 'waiting', 'limited', 'done', 'error', 'idle'];\r\n const items = statuses.map(s => {\r\n const label = api_1.STATUS_STYLES[s].icon + ' ' + api_1.STATUS_STYLES[s].label;\r\n const action = () => this.status.setManual(tab, s);\r\n return [label, action];\r\n });\r\n items.push(['↺ 자동 감지로', () => this.status.unpin(tab)]);\r\n // 이 탭만 다시 그리기 — 사이드바 아래 ↻ 는 모든 탭이 대상이라 무거울 때가 있다\r\n items.push(['↻ 화면 복구', () => {\r\n this.app.selectTab(tab);\r\n this.repair('active');\r\n }]);\r\n for (const [label, action] of items) {\r\n const item = document.createElement('div');\r\n item.className = 'ad-menu-item';\r\n item.textContent = label;\r\n item.addEventListener('click', () => {\r\n action();\r\n menu.remove();\r\n });\r\n menu.appendChild(item);\r\n }\r\n document.body.appendChild(menu);\r\n menu.style.left = ev.clientX + 'px';\r\n menu.style.top = Math.min(ev.clientY, window.innerHeight - menu.offsetHeight - 8) + 'px';\r\n const close = (e) => {\r\n if (!menu.contains(e.target)) {\r\n menu.remove();\r\n document.removeEventListener('mousedown', close);\r\n }\r\n };\r\n setTimeout(() => document.addEventListener('mousedown', close), 0);\r\n }\r\n formatElapsed(ms) {\r\n const s = Math.floor(ms / 1000);\r\n if (s < 60) {\r\n return s + '초';\r\n }\r\n const m = Math.floor(s / 60);\r\n if (m < 60) {\r\n return m + '분';\r\n }\r\n return Math.floor(m / 60) + '시간 ' + (m % 60) + '분';\r\n }\r\n};\r\nAgentDeckService = __decorate([\r\n (0, core_1.Injectable)({ providedIn: 'root' }),\r\n __metadata(\"design:paramtypes\", [tabby_core_1.AppService,\r\n tabby_core_1.ConfigService,\r\n status_service_1.WorkStatusService,\r\n tabby_core_1.HotkeysService,\r\n tabby_core_1.ProfilesService,\r\n tabby_core_1.HostWindowService,\r\n tabby_core_1.PlatformService,\r\n notify_service_1.WorkNotifyService,\r\n sessionLedger_service_1.SessionLedgerService,\r\n core_1.NgZone])\r\n], AgentDeckService);\r\nexports.AgentDeckService = AgentDeckService;\r\n","\"use strict\";\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckDecorator = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\nconst tabby_terminal_1 = require(\"tabby-terminal\");\r\nconst status_service_1 = require(\"./status.service\");\r\nconst detect_1 = require(\"./detect\");\r\n/**\r\n * PTY 출력을 훔쳐보며 탭 상태를 추론한다.\r\n *\r\n * Tabby 는 프론트엔드(xterm)가 첫 리사이즈를 보고할 때 decorator 를 붙이므로\r\n * (tabby-terminal/src/api/baseTerminalTab.component.ts:386) 그 시점을 놓친 탭은\r\n * 여기로 들어오지 않는다. 그 빈틈은 AgentDeckService 의 세션 워처가 메운다.\r\n */\r\nlet AgentDeckDecorator = class AgentDeckDecorator extends tabby_terminal_1.TerminalDecorator {\r\n constructor(status, config, app) {\r\n super();\r\n this.status = status;\r\n this.config = config;\r\n this.app = app;\r\n }\r\n /**\r\n * 상태를 기록할 키를 사이드바가 보는 것과 같은 탭으로 맞춘다.\r\n *\r\n * Tabby 는 모든 탭을 SplitTabComponent 로 감싸므로 app.tabs 에 들어있는 것은\r\n * 그 래퍼이고, decorator 가 받는 것은 그 안의 터미널 탭이다. 정규화하지 않으면\r\n * 상태를 자식에 쓰고 사이드바는 부모를 읽어 영영 매칭되지 않는다.\r\n * 분할된 pane 여러 개는 하나의 탭 상태를 공유한다.\r\n */\r\n rootOf(tab) {\r\n var _a;\r\n return (_a = this.app.getParentTab(tab)) !== null && _a !== void 0 ? _a : tab;\r\n }\r\n attach(tab) {\r\n this.status.debug.attached++;\r\n if (tab.session) {\r\n this.attachToSession(tab, tab.session);\r\n }\r\n this.subscribeUntilDetached(tab, tab.sessionChanged$.subscribe(session => {\r\n if (session) {\r\n this.attachToSession(tab, session);\r\n }\r\n }));\r\n }\r\n detach(tab) {\r\n const root = this.rootOf(tab);\r\n super.detach(tab);\r\n (0, detect_1.forgetOutputBuffer)(tab);\r\n // 분할 pane 중 하나만 닫힌 경우라면 탭 상태는 남겨둔다\r\n if (root === tab || !this.app.tabs.includes(root)) {\r\n this.status.forget(root);\r\n }\r\n }\r\n attachToSession(tab, session) {\r\n this.subscribeUntilDetached(tab, session.output$.subscribe(data => {\r\n (0, detect_1.applyOutput)(this.status, this.rootOf(tab), tab, data, this.config.store.agentDeck.autoDetect);\r\n }));\r\n }\r\n};\r\nAgentDeckDecorator = __decorate([\r\n (0, core_1.Injectable)(),\r\n __metadata(\"design:paramtypes\", [status_service_1.WorkStatusService,\r\n tabby_core_1.ConfigService,\r\n tabby_core_1.AppService])\r\n], AgentDeckDecorator);\r\nexports.AgentDeckDecorator = AgentDeckDecorator;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.applyTitle = exports.stripTitleMarker = exports.forgetOutputBuffer = exports.applyOutput = exports.releaseLimited = void 0;\r\nconst agents_1 = require(\"./agents\");\r\nconst reason_1 = require(\"./reason\");\r\n/** 훅이 상태를 직접 통보하는 커스텀 OSC — ESC ] 1337 ; AgentDeck=<status>;<label> BEL */\r\nconst OSC_RE = /\\x1b\\]1337;AgentDeck=([a-z]+)(?:;([^\\x07\\x1b]*))?(?:\\x07|\\x1b\\\\)/gi;\r\n// 대기·작업중 판정에 쓰는 화면 문구와 제목 스피너는 **에이전트마다 다르므로** 여기 두지 않고\r\n// `agents.ts` 의 프로필에서 읽는다. 예전에는 Claude Code 기준 리터럴이 이 파일에 박혀 있었고,\r\n// 그래서 새 CLI 를 지원할 때마다 이 파일을 고쳐야 했다. 실측 근거는 값과 함께 그쪽으로 옮겼다.\r\n// OSC_RE 와 TITLE_RE 는 우리 규약이라 에이전트와 무관하다 — 그것만 이 파일에 남는다.\r\nconst VALID = ['idle', 'running', 'waiting', 'limited', 'done', 'error'];\r\n/** OSC 가 청크 경계에 걸리는 것을 막기 위한 잔여 버퍼 */\r\nconst tails = new WeakMap();\r\n/**\r\n * 조각 안에서 그 패턴에 걸린 **줄 하나**를 찾아 배지에 붙일 이유로 줄인다.\r\n *\r\n * 판정 자체는 조각 전체에 `test` 한다(아래 갈래들 — 지금까지의 동작을 그대로 둔다). 그런데\r\n * 이유는 조각 전체를 쓸 수 없다: 화면 재그리기 한 번이 수십 줄이라 그대로 넣으면 배지가\r\n * 화면 덤프가 된다. 그래서 이유만 줄 단위로 다시 찾는다.\r\n *\r\n * 빈 이유를 주는 줄은 건너뛰고 다음 줄을 본다 — 승인 대화상자는 질문 줄과 선택지 줄이 같은\r\n * 조각에 오는데(`Allow execution of …` + `● 1. Allow once`), 선택지 줄은 이유가 아니라\r\n * 빈 값으로 접히기 때문이다(`reason.ts`). 아무 줄도 안 걸리면 빈 값 = 부연 없이 상태만 바꾼다.\r\n */\r\nfunction reasonFrom(data, patterns) {\r\n for (const line of data.split(/[\\r\\n]+/)) {\r\n if (!line.trim() || !patterns.some(re => re.test(line))) {\r\n continue;\r\n }\r\n const short = (0, reason_1.reasonFromScreen)(line);\r\n if (short) {\r\n return short;\r\n }\r\n }\r\n return '';\r\n}\r\n/**\r\n * 자동 판정으로 상태를 바꾸면서 **부연(이유)도 함께** 남긴다.\r\n *\r\n * `status.setAuto` 는 상태만 바꾸고 이유를 받지 않는다 — 이유는 지금까지 훅 경로(`setManual`)에만\r\n * 있던 값이었고, 그래서 화면 판정으로 `waiting` 이 된 탭은 배지에 이유가 비어 있었다(어느 탭이\r\n * 무엇을 기다리는지 사이드바만 보고 알 수 없다). 그래서 살아있는 상태 객체(`status.get`)에\r\n * 이유를 먼저 써 두고 전이는 `setAuto` 에 맡긴다 — 전이가 일어나면 화면 갱신 통보도 그때 함께 나간다.\r\n *\r\n * **상태가 바뀔 때는 빈 이유라도 덮어쓴다.** `waiting`·`limited` 는 둘 다 이유를 가질 수 있어\r\n * (`status.service` `REASON_STATUSES`) 그냥 두면 승인 이유(\"Bash 권한\")가 한도 배지에 남고,\r\n * 그러면 지금 승인을 기다리는 것처럼 읽힌다. 반대로 **같은 상태의 재판정에서는 빈 이유로 지우지\r\n * 않는다** — 커서만 움직인 재그리기 조각에서 이유를 못 뽑았다고 앞서 잡은 이유를 버릴 일이 없다.\r\n *\r\n * pinned(훅·수동 지정) 탭은 손대지 않는다 — `setAuto` 가 어차피 무시하므로 이유만 바뀌면\r\n * 배지가 훅이 준 상태와 어긋난다.\r\n */\r\nfunction setAutoWithReason(status, root, next, reason) {\r\n const s = status.get(root);\r\n if (s.pinned) {\r\n return;\r\n }\r\n if (s.status !== next || reason) {\r\n s.reason = reason;\r\n }\r\n status.setAuto(root, next);\r\n}\r\n/**\r\n * 한도 도달을 사람의 행동으로 풀어 준다 — **사용자가 새 프롬프트를 보낸 순간**이 근거다.\r\n *\r\n * `limited` 는 화면 갱신만으로는 안 풀린다(`applyOutput` 의 마지막 갈래 주석). 그래서 풀리는\r\n * 길을 반드시 하나 더 열어 둔다 — 실패에 영구 lock 을 걸지 않는다는 이 저장소의 원칙이다.\r\n * `deck.service` 의 Enter 관측 지점(`claimEnterLabel`)에서 부르면, 사용량이 회복된 뒤 사용자가\r\n * 다시 지시를 넣는 순간 배지가 진행중으로 돌아온다.\r\n *\r\n * pinned(훅이 지정한 `limited`)는 건드리지 않는다 — 그 탭은 훅이 풀어 준다\r\n * (`UserPromptSubmit` → `running`, `claudeHooks.ts` PLAN).\r\n */\r\nfunction releaseLimited(status, root) {\r\n if (status.get(root).status === 'limited') {\r\n status.setAuto(root, 'running');\r\n }\r\n}\r\nexports.releaseLimited = releaseLimited;\r\n/**\r\n * PTY 출력 한 조각을 보고 탭 상태를 갱신한다.\r\n *\r\n * 우선순위: OSC 통보 > 대기 패턴 > 한도 패턴 > \"출력이 있다 = 진행중\".\r\n * idle 로의 복귀는 사이드바 타이머(tickIdle)가 담당한다.\r\n *\r\n * decorator 와 deck 의 세션 워처 양쪽에서 호출된다 — 같은 조각을 두 번 먹어도\r\n * 결과가 같도록 상태 설정은 모두 멱등하게 만들어 두었다.\r\n *\r\n * @param profile 이 탭에서 도는 에이전트의 프로필. **생략하면 합집합**(`unionProfile()`)이라\r\n * 0.5.0 까지의 판정과 완전히 같다 — 아직 어떤 에이전트인지 못 알아낸 탭에는 넘기지 않는다.\r\n */\r\nfunction applyOutput(status, root, owner, data, autoDetect, profile = (0, agents_1.unionProfile)()) {\r\n var _a;\r\n status.debug.outputs++;\r\n status.markOutput(root);\r\n const buf = ((_a = tails.get(owner)) !== null && _a !== void 0 ? _a : '') + data;\r\n let matched = false;\r\n let m;\r\n // 이미 처리한 OSC 가 어디까지인지 — 그 뒤만 다음 조각으로 넘긴다\r\n let consumed = 0;\r\n OSC_RE.lastIndex = 0;\r\n while ((m = OSC_RE.exec(buf)) !== null) {\r\n consumed = OSC_RE.lastIndex;\r\n const s = m[1].toLowerCase();\r\n if (VALID.includes(s)) {\r\n status.setManual(root, s, m[2]);\r\n status.debug.oscHits++;\r\n matched = true;\r\n }\r\n }\r\n // 미완성 OSC 가 남아있을 수 있으므로 꼬리만 보관한다.\r\n // 단 이미 처리한 부분은 반드시 버린다 — 완결된 OSC 가 짧으면 꼬리 안에 통째로 남고,\r\n // 그러면 다음 출력마다 같은 시퀀스가 또 매치돼 상태가 그 값에 박혀 버린다\r\n // (2026-09-01, detect 테스트에서 드러남).\r\n tails.set(owner, buf.slice(Math.max(consumed, buf.length - 256)));\r\n if (matched || !autoDetect) {\r\n return;\r\n }\r\n if (profile.waitingPatterns.some(re => re.test(data))) {\r\n // 이유를 함께 남긴다 — 여기까지는 화면 판정으로 waiting 이 된 탭의 배지가 `⏸ 승인대기` 뿐이라\r\n // 여섯 탭 중 어느 것이 무엇을 기다리는지 사이드바만 보고 정할 수 없었다 (훅이 있는 Claude 탭만\r\n // `⏸ 승인대기 · Bash 권한` 이었다). 이유의 출처는 걸린 줄 하나뿐이다 (reasonFrom)\r\n setAutoWithReason(status, root, 'waiting', reasonFrom(data, profile.waitingPatterns));\r\n return;\r\n }\r\n // 사용량 한도 — 대기 다음, 작업중보다 앞이다.\r\n //\r\n // 왜 작업중보다 앞인가: 한도에 걸린 화면에도 상태줄·힌트가 계속 그려지고, 그 조각이 먼저\r\n // \"진행중\" 으로 읽히면 정작 한도 줄이 왔을 때 배지가 이미 진행중이라 사용자는 왜 멈췄는지\r\n // 알 수 없다. 왜 대기보다 뒤인가: 대기 오탐의 비용이 가장 크다는 원칙(대기 > busy)을\r\n // 흔들지 않기 위해서다 — 한 조각에 둘이 같이 왔다면 사람이 답할 것이 있는 쪽이 먼저다.\r\n //\r\n // 문구는 프로필이 들고 있다(`agents.ts` `limitedPatterns`) — 실측이 없는 에이전트는 비어 있고,\r\n // 그 프로필의 판정에는 합집합이 쓰이므로 어느 한 곳에서 실측된 문구는 모두가 함께 쓴다.\r\n if (profile.limitedPatterns.some(re => re.test(data))) {\r\n setAutoWithReason(status, root, 'limited', reasonFrom(data, profile.limitedPatterns));\r\n return;\r\n }\r\n // 승인대기였던 탭에 작업 중 문구가 다시 보이면 사람이 승인한 것이다 — 진행중으로 올린다.\r\n // 훅은 이 순간을 알려주지 않는다: 승인 뒤 첫 훅(PostToolUse)은 도구가 끝난 뒤라, 2분짜리 빌드를\r\n // 승인하면 그동안 사이드바가 승인대기에 박혀 있다 (2026-09-07 실측 — \"승인했는데 진행중으로 안 돌아온다\").\r\n // 훅이 고정(pinned)한 탭에도 적용해야 하므로 setAuto 가 아니라 resume 을 쓴다.\r\n // 제목 스피너(busyTitleMarks)는 근거로 삼지 않는다 — 승인 대화상자가 떠 있는 동안에도 제목에 남을 수 있다\r\n if (status.get(root).status === 'waiting' && profile.busyPatterns.some(re => re.test(data))) {\r\n status.markBusy(root);\r\n status.resume(root);\r\n return;\r\n }\r\n // 에이전트가 \"지금 일하는 중\" 이라고 스스로 밝히는 표시를 찾는다\r\n if (profile.busyTitleMarks.some(mark => data.includes(mark))\r\n || profile.busyPatterns.some(re => re.test(data))) {\r\n status.markBusy(root);\r\n status.setAuto(root, 'running');\r\n return;\r\n }\r\n // 그 표시를 내는 탭(에이전트 TUI)이라면, 표시가 없는 출력은 진행중의 근거가 아니다.\r\n // Claude Code 는 놀고 있을 때도 하단 상태줄을 매초 다시 그리기 때문에, 이 갈래가 없으면\r\n // 사이드바가 영원히 \"진행중\" 에 박혀 있게 된다 (2026-09-01 실측 — 세 탭 모두 진행중).\r\n if (status.isBusyMode(root)) {\r\n return;\r\n }\r\n // 한도 도달은 \"출력이 있다 = 진행중\" 으로 풀리지 않는다.\r\n //\r\n // 한도에 걸린 CLI 도 하단 상태줄을 계속 다시 그린다. 그런데 작업중 문구를 한 번도 못 본\r\n // 탭(busyMode 가 아닌 탭 — codex 가 그렇다. 작업중 문구가 미관측이라 그 신호를 잡을 수 없다)은\r\n // 바로 아래 갈래에서 그 재그리기 한 조각에 진행중으로 올라가 버린다. 그러면 배지가 한 조각만\r\n // ⛔ 였다가 사라져 이 판정이 아무 쓸모가 없다.\r\n //\r\n // **풀리는 길은 열어 둔다** (실패에 영구 lock 을 걸지 않는다):\r\n // ① 작업중 문구·스피너가 다시 보이면 위 갈래가 running 으로 올린다 (사용량이 회복돼 실제로 도는 경우)\r\n // ② 사용자가 새 프롬프트를 Enter 로 보내면 `releaseLimited` (deck.service 의 claimEnterLabel 배선)\r\n // ③ 훅이 있는 CLI 는 다음 훅(`UserPromptSubmit` → running)이 덮는다\r\n // ④ 사이드바에서 상태를 직접 고르거나 고정을 푸는 것(setManual/unpin)\r\n if (status.get(root).status === 'limited') {\r\n return;\r\n }\r\n // 신호를 낼 줄 모르는 보통 셸 — 예전처럼 \"출력이 있다 = 진행중\" 으로 본다\r\n status.setAuto(root, 'running');\r\n}\r\nexports.applyOutput = applyOutput;\r\nfunction forgetOutputBuffer(owner) {\r\n tails.delete(owner);\r\n}\r\nexports.forgetOutputBuffer = forgetOutputBuffer;\r\n/**\r\n * 탭 제목에 실려 온 상태 표식 — `[AD:running] 결제 버그 수정` 형태.\r\n *\r\n * Windows 에서 이 경로를 쓰는 이유: ConPTY 는 자기가 모르는 OSC 를 삼켜서\r\n * 커스텀 이스케이프가 PTY 스트림까지 오지 못한다(2026-08-28 실측 — 출력에 남은 건\r\n * 입력 에코뿐이었다). 반면 콘솔 제목은 ConPTY 가 API 로 변환해 전달하므로 확실히 통과한다.\r\n */\r\nconst TITLE_RE = /\\[AD:([a-z]+)\\]\\s*(.*)$/i;\r\n// 작업중 제목 표식(Claude 의 별·원형 스피너 9종)은 `agents.ts` 의 프로필로 옮겼다 —\r\n// 실측 근거(\"2026-08-28 ◐ WindowTitle 설정\")도 값과 함께 그쪽에 있다.\r\nfunction stripTitleMarker(title) {\r\n return title.replace(/\\[AD:[a-z]+\\]\\s*/i, '');\r\n}\r\nexports.stripTitleMarker = stripTitleMarker;\r\n/**\r\n * @param profile 이 탭의 에이전트 프로필. 생략하면 합집합이라 0.5.0 과 같은 판정이다.\r\n */\r\nfunction applyTitle(status, root, title, autoDetect, profile = (0, agents_1.unionProfile)()) {\r\n const m = TITLE_RE.exec(title);\r\n if (m) {\r\n const s = m[1].toLowerCase();\r\n if (VALID.includes(s)) {\r\n status.setManual(root, s, m[2].trim());\r\n status.debug.titleHits++;\r\n return;\r\n }\r\n }\r\n // 명시 표식이 없으면 에이전트가 제목에 넣는 작업중 표식(스피너)이라도 읽는다\r\n if (autoDetect && profile.busyTitleMarks.some(mark => title.includes(mark))) {\r\n status.setAuto(root, 'running');\r\n }\r\n}\r\nexports.applyTitle = applyTitle;\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.collectDiagBundle = exports.appendScreenLog = exports.diagCatch = exports.diagException = exports.installErrorCapture = exports.startDiagSession = exports.recentDiag = exports.diagMemory = exports.resetDiagOnce = exports.diagOnce = exports.diag = exports.pluginVersion = exports.configStamp = exports.SCREEN_PREV_PATH = exports.SCREEN_PATH = exports.DIAG_PREV_PATH = exports.DIAG_PATH = void 0;\r\nconst childProcess = __importStar(require(\"child_process\"));\r\nconst fs = __importStar(require(\"fs\"));\r\nconst os = __importStar(require(\"os\"));\r\nconst path = __importStar(require(\"path\"));\r\nconst viewer_1 = require(\"./viewer\");\r\n/**\r\n * 진단 로그.\r\n *\r\n * 이 파일이 따로 있는 이유 — 이 플러그인은 npm 으로 배포되므로 버그를 겪는 사람이\r\n * 개발자가 아니다. 그 사람에게서 받을 수 있는 것은 **파일 한 개**뿐이고, 그 파일이\r\n * ① 세션이 바뀌어도 남아 있어야 하고 (옛 구현은 기동할 때마다 비웠다)\r\n * ② 어느 버전·어느 환경에서 난 일인지 스스로 말해야 하고 (스탬프)\r\n * ③ 예외를 담아야 하며 (`catch {}` 로 삼킨 것은 아무 데도 안 남는다)\r\n * ④ 무한정 커지지 않아야 한다 (사람에게 첨부를 요구하는 파일이다)\r\n * 네 가지가 전부 만족돼야 \"로그 받아서 고친다\" 가 성립한다.\r\n *\r\n * 그래서 deck / alert / notify 가 각자 `appendFileSync` 를 하던 것을 여기로 모으고,\r\n * 회전 · 세션 스탬프 · 예외 캡처 · 수집(zip)까지 한 군데서 처리한다.\r\n */\r\n/**\r\n * 로그를 둘 폴더. 기본은 홈, `AGENTDECK_DIAG_DIR` 가 있으면 그 폴더.\r\n *\r\n * **왜 갈라야 하나** — 회귀용 격리 인스턴스와 실사용 Tabby 가 같은 파일에 섞어 쓰면\r\n * 남의 줄에 묻힌다. 2026-09-09 실측: 러너에서 프로세스가 사라진 판의 마지막 줄을 보려 했는데\r\n * 실사용 쪽이 계속 쓰는 동안 그 줄이 밀려나고 `.1` 회전도 실사용 분량에 걸려 **종료 원인을\r\n * 끝내 볼 수 없었다.** 회전이 있어도 파일이 공유되면 소용이 없다.\r\n *\r\n * **왜 전용 변수인가** — 처음에는 `TABBY_CONFIG_DIRECTORY` 로 판별했는데, 그 값은 **실사용\r\n * Tabby 에도 설정돼 있을 수 있다**(이 개발기가 그런 환경이었고 `test/diag.test.js` 의\r\n * \"홈에 잡힌다\" 케이스가 그걸 잡았다). 그러면 실사용 로그까지 엉뚱한 폴더로 옮긴다.\r\n * 목적이 하나뿐인 변수를 두고 `tools/test-instance.ps1` 만 그것을 심는다.\r\n */\r\nfunction logDir() {\r\n const wanted = process.env.AGENTDECK_DIAG_DIR;\r\n if (wanted) {\r\n try {\r\n if (fs.existsSync(wanted)) {\r\n return wanted;\r\n }\r\n }\r\n catch {\r\n // 접근할 수 없으면 홈으로 — 로그 때문에 기동이 막히면 안 된다\r\n }\r\n }\r\n return os.homedir();\r\n}\r\n/** 한 줄 요약이 쌓이는 곳 */\r\nexports.DIAG_PATH = path.join(logDir(), '.agentdeck-diag.log');\r\n/** 직전 분량 — 상한을 넘으면 여기로 밀고 새로 쓴다. 지우지 않는 것이 요점이다 */\r\nexports.DIAG_PREV_PATH = exports.DIAG_PATH + '.1';\r\n/** 깨진 화면의 원문 (deck.service 의 snapshot) */\r\nexports.SCREEN_PATH = path.join(logDir(), '.agentdeck-screen.log');\r\n/** 화면 원문의 직전 분량 */\r\nexports.SCREEN_PREV_PATH = exports.SCREEN_PATH + '.1';\r\n/** 진단 로그 상한 — 넘으면 `.1` 로 밀린다. 두 개를 합쳐도 메일에 붙일 수 있는 크기로 잡았다 */\r\nconst DIAG_MAX_BYTES = 2 * 1024 * 1024;\r\n/** 화면 원문 상한. 한 스냅샷이 수십 KB 라 진단 로그보다 넉넉히 준다 */\r\nconst SCREEN_MAX_BYTES = 4 * 1024 * 1024;\r\n/** 메모리에 들고 있는 줄 수 — devtools(`__agentdeck.kickLog`)와 수집 리포트가 이걸 읽는다 */\r\nconst MEMORY_MAX_LINES = 2000;\r\n/** 한 세션에서 콘솔을 옮겨 적는 최대 건수. 폭주하는 경고가 로그를 밀어내지 않게 한다 */\r\nconst CONSOLE_MAX_ENTRIES = 300;\r\n/** 같은 콘솔 메시지를 다시 적기까지의 간격 */\r\nconst CONSOLE_DEDUPE_MS = 5000;\r\n/** 콘솔 인자 하나를 적을 최대 길이 */\r\nconst CONSOLE_ARG_CHARS = 400;\r\n/** `diagCatch` 로 남길 최대 건수 */\r\nconst CATCH_MAX_ENTRIES = 200;\r\n/** 같은 자리·같은 사유를 다시 적기까지의 간격 */\r\nconst CATCH_DEDUPE_MS = 60000;\r\n/** 이 횟수마다 파일 크기를 다시 읽는다 (다른 창이 같은 파일에 쓴 만큼을 반영) */\r\nconst STAT_REFRESH_APPENDS = 500;\r\n/** 예외 스택을 적을 최대 줄 수 */\r\nconst STACK_MAX_LINES = 12;\r\n/**\r\n * 세션 머리말·수집 리포트에 넣을 설정만 골라 담는다.\r\n *\r\n * 전체 config 를 넣지 않는 이유 — 작업 폴더 같은 사적인 경로까지 들어가는데, 정작 증상을\r\n * 가르는 데 필요한 값은 몇 개뿐이다. `terminal.useConPTY` 는 Tabby 쪽 값이지만 새 탭이 안\r\n * 열리는 증상(README 문제해결)의 원인이라 같이 본다.\r\n */\r\nfunction configStamp(store) {\r\n var _a, _b;\r\n const cfg = (_a = store === null || store === void 0 ? void 0 : store.agentDeck) !== null && _a !== void 0 ? _a : {};\r\n return {\r\n enabled: cfg.enabled,\r\n dock: cfg.sidebarDock,\r\n sidebar: cfg.sidebarWidth || cfg.sidebarHeight,\r\n aspect: `${cfg.aspectW}:${cfg.aspectH}`,\r\n viewerOpen: cfg.viewerOpen,\r\n // **해석한 값**을 적는다 — 토글 두 개(읽어두기·자동열기)가 접힌 결과가 동작을 정하므로,\r\n // 원본 둘만 보면 \"패널이 왜 저절로 열리나/안 열리나\" 를 한눈에 가리기 어렵다\r\n viewerFollow: (0, viewer_1.followModeOf)(cfg.viewerPreload, cfg.viewerAutoOpen),\r\n screenWatch: cfg.screenWatch,\r\n autoRepair: cfg.autoRepair,\r\n notifyChannel: cfg.notifyChannel,\r\n rootProfile: cfg.rootProfile,\r\n useConPTY: (_b = store === null || store === void 0 ? void 0 : store.terminal) === null || _b === void 0 ? void 0 : _b.useConPTY,\r\n };\r\n}\r\nexports.configStamp = configStamp;\r\n/** 최근 줄 — 파일이 안 써지는 환경에서도 devtools 로는 볼 수 있어야 한다 */\r\nconst memory = [];\r\n/** `diagOnce` 가 이미 남긴 키 */\r\nconst onceKeys = new Set();\r\n/** 지금 파일 크기 (append 마다 statSync 하지 않으려고 들고 센다). -1 = 아직 안 읽음 */\r\nlet diagBytes = -1;\r\n/** 마지막 재측정 이후의 append 횟수 — 창이 두 개면 같은 파일에 둘이 쓰므로 셈이 어긋난다 */\r\nlet appendsSinceStat = 0;\r\n/** 회전 직후 새 파일에 다시 적을 세션 머리말 */\r\nlet sessionHeader = '';\r\n/** 예외 캡처를 이미 걸었나 */\r\nlet captureInstalled = false;\r\n/** 콘솔에서 옮겨 적은 건수 */\r\nlet consoleCount = 0;\r\n/** 같은 콘솔 메시지의 마지막 기록 시각 */\r\nconst consoleSeen = new Map();\r\n/** `diagCatch` 로 남긴 건수 */\r\nlet catchCount = 0;\r\n/** 같은 (자리, 사유) 의 마지막 기록 시각 */\r\nconst catchSeen = new Map();\r\n/** package.json 의 버전 — 배포판은 사용자가 어느 버전을 쓰는지 모르니 로그가 스스로 말해야 한다 */\r\nlet cachedVersion = null;\r\n/**\r\n * 이 플러그인 버전.\r\n *\r\n * `dist/index.js` 기준 `../package.json` 이 npm 설치본과 개발용 junction 양쪽에서 모두 맞는다\r\n * (`claudeHooks.ts:52` 가 `hooks/` 를 찾는 방식과 같다).\r\n */\r\nfunction pluginVersion() {\r\n var _a;\r\n if (cachedVersion !== null) {\r\n return cachedVersion;\r\n }\r\n cachedVersion = 'unknown';\r\n for (const candidate of [path.join(__dirname, '..', 'package.json'), path.join(__dirname, 'package.json')]) {\r\n try {\r\n const raw = fs.readFileSync(candidate, 'utf8');\r\n const version = (_a = JSON.parse(raw)) === null || _a === void 0 ? void 0 : _a.version;\r\n if (version) {\r\n cachedVersion = String(version);\r\n break;\r\n }\r\n }\r\n catch {\r\n // 다음 후보로 넘어간다 — 버전은 있으면 좋은 값이고 없어도 로그는 남아야 한다\r\n }\r\n }\r\n return cachedVersion;\r\n}\r\nexports.pluginVersion = pluginVersion;\r\nfunction fileSize(target) {\r\n try {\r\n return fs.statSync(target).size;\r\n }\r\n catch {\r\n return 0;\r\n }\r\n}\r\n/**\r\n * 상한을 넘었으면 `.1` 로 밀어낸다.\r\n *\r\n * `rename` 은 Windows 에서도 기존 `.1` 을 덮어쓴다. 두 세대만 남기는 것은 의도다 —\r\n * 세 세대째부터는 사람이 첨부하지 않고, 디스크만 먹는다.\r\n */\r\nfunction rotate(target, prev, max) {\r\n try {\r\n if (fileSize(target) < max) {\r\n return false;\r\n }\r\n fs.renameSync(target, prev);\r\n return true;\r\n }\r\n catch {\r\n return false;\r\n }\r\n}\r\n/** 파일에 그대로 붙인다. 상한을 넘으면 회전하고 새 파일 머리에 세션 스탬프를 다시 적는다 */\r\nfunction append(chunk) {\r\n try {\r\n // 창(렌더러 프로세스)이 두 개면 같은 파일에 둘이 쓴다 — 들고 센 값만 믿으면 상한을 넘겨\r\n // 계속 자란다. 그래서 일정 횟수마다 실제 크기를 다시 읽는다 (statSync 는 그때만)\r\n if (diagBytes < 0 || ++appendsSinceStat >= STAT_REFRESH_APPENDS) {\r\n diagBytes = fileSize(exports.DIAG_PATH);\r\n appendsSinceStat = 0;\r\n }\r\n if (diagBytes >= DIAG_MAX_BYTES && rotate(exports.DIAG_PATH, exports.DIAG_PREV_PATH, DIAG_MAX_BYTES)) {\r\n diagBytes = 0;\r\n if (sessionHeader) {\r\n fs.appendFileSync(exports.DIAG_PATH, sessionHeader);\r\n diagBytes += Buffer.byteLength(sessionHeader);\r\n }\r\n }\r\n fs.appendFileSync(exports.DIAG_PATH, chunk);\r\n diagBytes += Buffer.byteLength(chunk);\r\n }\r\n catch {\r\n // 디스크가 막혀 있다 — 진단일 뿐이라 동작에는 영향이 없다\r\n }\r\n}\r\nfunction remember(line) {\r\n memory.push(line);\r\n if (memory.length > MEMORY_MAX_LINES) {\r\n memory.splice(0, memory.length - MEMORY_MAX_LINES);\r\n }\r\n}\r\n/** 진단 한 줄. 시각은 여기서 붙이므로 호출부는 내용만 넘긴다 */\r\nfunction diag(line) {\r\n const text = `${new Date().toISOString()} ${line}`;\r\n remember(text);\r\n append(text + '\\n');\r\n}\r\nexports.diag = diag;\r\n/**\r\n * 같은 키로는 한 번만 남기는 진단.\r\n * relayout 처럼 초당 여러 번 불리는 자리에서 조기 return 사유를 남길 때 쓴다\r\n */\r\nfunction diagOnce(key, line) {\r\n if (onceKeys.has(key)) {\r\n return;\r\n }\r\n onceKeys.add(key);\r\n diag(line);\r\n}\r\nexports.diagOnce = diagOnce;\r\n/** `diagOnce` 키를 푼다 — 상황이 바뀌어 다시 한 번 남겨야 할 때 */\r\nfunction resetDiagOnce(key) {\r\n onceKeys.delete(key);\r\n}\r\nexports.resetDiagOnce = resetDiagOnce;\r\n/** 메모리에 남은 진단 줄 (devtools `__agentdeck.kickLog` 가 이 배열을 그대로 참조한다) */\r\nfunction diagMemory() {\r\n return memory;\r\n}\r\nexports.diagMemory = diagMemory;\r\n/** 최근 N 줄 — 수집 리포트가 쓴다 */\r\nfunction recentDiag(limit = 200) {\r\n return memory.slice(-limit);\r\n}\r\nexports.recentDiag = recentDiag;\r\n/**\r\n * 세션 시작을 기록한다.\r\n *\r\n * 옛 구현은 여기서 파일을 **비웠다**(`writeFileSync(path, '')`). 그래서 \"어제 이렇게 깨졌어\" 를\r\n * 들고 Tabby 를 껐다 켠 사람에게서는 받을 로그가 없었다. 지금은 비우지 않고, 상한을 넘었을 때만\r\n * `.1` 로 밀어 두 세대를 남긴다.\r\n */\r\nfunction startDiagSession(stamp = {}) {\r\n var _a, _b, _c, _d, _e, _f;\r\n rotate(exports.DIAG_PATH, exports.DIAG_PREV_PATH, DIAG_MAX_BYTES);\r\n diagBytes = -1;\r\n const lines = [\r\n '',\r\n `===== agentdeck session ${new Date().toISOString()} =====`,\r\n `plugin=${pluginVersion()} tabby=${(_a = stamp.tabby) !== null && _a !== void 0 ? _a : '?'}`\r\n + ` platform=${process.platform} arch=${process.arch}`\r\n + ` node=${(_c = (_b = process.versions) === null || _b === void 0 ? void 0 : _b.node) !== null && _c !== void 0 ? _c : '?'} electron=${(_e = (_d = process.versions) === null || _d === void 0 ? void 0 : _d.electron) !== null && _e !== void 0 ? _e : '?'}`\r\n + ` os=${JSON.stringify((_f = stamp.osRelease) !== null && _f !== void 0 ? _f : os.release())}`,\r\n ];\r\n if (stamp.config) {\r\n lines.push(`config=${safeJson(stamp.config)}`);\r\n }\r\n sessionHeader = lines.join('\\n') + '\\n';\r\n for (const line of lines) {\r\n remember(line);\r\n }\r\n append(sessionHeader);\r\n}\r\nexports.startDiagSession = startDiagSession;\r\n/**\r\n * 잡히지 않은 예외를 진단 로그로 끌어온다.\r\n *\r\n * 세 갈래를 다 덮는다 —\r\n * ① `window.onerror` / `unhandledrejection`: Angular 밖에서 터지는 비동기 예외\r\n * ② `console.error` / `console.warn`: Angular 기본 `ErrorHandler` 와 Tabby 의\r\n * `platform.setErrorHandler` 가 결국 여기로 흘린다(tabby-core `AppModule`).\r\n * 그래서 `ErrorHandler` 를 우리가 갈아끼우지 않아도 잡힌다 — 코어 동작을 건드리지 않는 쪽을 골랐다.\r\n * 원래 함수는 항상 그대로 호출하므로 devtools 출력은 달라지지 않는다.\r\n */\r\nfunction installErrorCapture() {\r\n if (captureInstalled) {\r\n return;\r\n }\r\n captureInstalled = true;\r\n const anyWindow = typeof window === 'undefined' ? null : window;\r\n if (anyWindow === null || anyWindow === void 0 ? void 0 : anyWindow.addEventListener) {\r\n anyWindow.addEventListener('error', (event) => {\r\n var _a;\r\n const where = (event === null || event === void 0 ? void 0 : event.filename) ? ` at ${event.filename}:${event.lineno}:${event.colno}` : '';\r\n diagException('window.onerror' + where, (_a = event === null || event === void 0 ? void 0 : event.error) !== null && _a !== void 0 ? _a : event === null || event === void 0 ? void 0 : event.message);\r\n });\r\n anyWindow.addEventListener('unhandledrejection', (event) => {\r\n diagException('unhandledrejection', event === null || event === void 0 ? void 0 : event.reason);\r\n });\r\n }\r\n teeConsole('error');\r\n teeConsole('warn');\r\n}\r\nexports.installErrorCapture = installErrorCapture;\r\n/** 예외 한 건 — 첫 줄에 요약, 그 뒤에 스택을 붙인다 */\r\nfunction diagException(tag, error) {\r\n const message = errorMessage(error);\r\n diag(`EXCEPTION ${tag} ${message}`);\r\n const stack = typeof (error === null || error === void 0 ? void 0 : error.stack) === 'string' ? error.stack.split(/\\r?\\n/) : [];\r\n for (const line of stack.slice(1, STACK_MAX_LINES + 1)) {\r\n const trimmed = line.trim();\r\n if (trimmed) {\r\n append(` ${trimmed}\\n`);\r\n remember(` ${trimmed}`);\r\n }\r\n }\r\n}\r\nexports.diagException = diagException;\r\n/**\r\n * `catch` 에서 삼키던 실패를 한 줄로 남긴다.\r\n *\r\n * 이 프로젝트는 \"동작에는 영향 없다\" 는 이유로 빈 `catch {}` 를 많이 쓴다(그 판단 자체는 맞다 —\r\n * 세션이 막 닫히는 중의 resize 실패 같은 것들이다). 문제는 **정말 이상한 실패도 같은 자리에서\r\n * 사라진다** 는 것이다. 그래서 같은 (자리, 메시지) 조합은 창(`CATCH_DEDUPE_MS`) 안에서 한 번만,\r\n * 세션 전체로도 상한(`CATCH_MAX_ENTRIES`)까지만 남긴다 — 흔한 실패로 로그가 밀리지 않게.\r\n */\r\nfunction diagCatch(tag, error) {\r\n if (catchCount >= CATCH_MAX_ENTRIES) {\r\n return;\r\n }\r\n const message = errorMessage(error);\r\n const key = `${tag}|${message}`;\r\n const now = Date.now();\r\n const last = catchSeen.get(key);\r\n if (last !== undefined && now - last < CATCH_DEDUPE_MS) {\r\n return;\r\n }\r\n catchSeen.set(key, now);\r\n catchCount++;\r\n diag(`CATCH ${tag} ${clip(message)}`);\r\n if (catchCount >= CATCH_MAX_ENTRIES) {\r\n diag(`CATCH 캡처 상한(${CATCH_MAX_ENTRIES}) 도달 — 이 세션에서는 더 적지 않는다`);\r\n }\r\n}\r\nexports.diagCatch = diagCatch;\r\nfunction errorMessage(error) {\r\n var _a;\r\n if (error == null) {\r\n return '(no error object)';\r\n }\r\n if (typeof error === 'string') {\r\n return error;\r\n }\r\n const name = error.name ? `${error.name}: ` : '';\r\n return `${name}${(_a = error.message) !== null && _a !== void 0 ? _a : safeJson(error)}`;\r\n}\r\n/** `console[level]` 을 감싸 진단 로그로도 흘린다. 원래 함수 호출은 그대로 유지한다 */\r\nfunction teeConsole(level) {\r\n const target = typeof console === 'undefined' ? null : console;\r\n const original = target === null || target === void 0 ? void 0 : target[level];\r\n if (typeof original !== 'function') {\r\n return;\r\n }\r\n target[level] = (...args) => {\r\n try {\r\n recordConsole(level, args);\r\n }\r\n catch {\r\n // 진단이 콘솔을 망가뜨리면 안 된다\r\n }\r\n return original.apply(target, args);\r\n };\r\n}\r\nfunction recordConsole(level, args) {\r\n if (consoleCount >= CONSOLE_MAX_ENTRIES) {\r\n return;\r\n }\r\n const text = args.slice(0, 4).map(formatArg).join(' ');\r\n if (!text) {\r\n return;\r\n }\r\n const now = Date.now();\r\n const last = consoleSeen.get(text);\r\n if (last !== undefined && now - last < CONSOLE_DEDUPE_MS) {\r\n return;\r\n }\r\n consoleSeen.set(text, now);\r\n consoleCount++;\r\n diag(`CONSOLE ${level} ${text}`);\r\n if (consoleCount >= CONSOLE_MAX_ENTRIES) {\r\n diag(`CONSOLE 캡처 상한(${CONSOLE_MAX_ENTRIES}) 도달 — 이 세션에서는 더 적지 않는다`);\r\n }\r\n}\r\nfunction formatArg(arg) {\r\n var _a;\r\n if (typeof arg === 'string') {\r\n return clip(arg);\r\n }\r\n if (arg instanceof Error) {\r\n const first = typeof arg.stack === 'string' ? (_a = arg.stack.split(/\\r?\\n/)[1]) === null || _a === void 0 ? void 0 : _a.trim() : '';\r\n return clip(`${arg.name}: ${arg.message}${first ? ' | ' + first : ''}`);\r\n }\r\n return clip(safeJson(arg));\r\n}\r\nfunction clip(text) {\r\n const flat = text.replace(/\\r?\\n/g, ' ');\r\n return flat.length > CONSOLE_ARG_CHARS ? flat.slice(0, CONSOLE_ARG_CHARS) + '…' : flat;\r\n}\r\nfunction safeJson(value) {\r\n var _a;\r\n try {\r\n return (_a = JSON.stringify(value)) !== null && _a !== void 0 ? _a : String(value);\r\n }\r\n catch {\r\n return String(value);\r\n }\r\n}\r\n/** 화면 원문 한 덩이 — 상한을 넘으면 회전한다 (옛 구현은 상한이 없어 무한히 커졌다) */\r\nfunction appendScreenLog(chunk) {\r\n try {\r\n rotate(exports.SCREEN_PATH, exports.SCREEN_PREV_PATH, SCREEN_MAX_BYTES);\r\n fs.appendFileSync(exports.SCREEN_PATH, chunk);\r\n }\r\n catch {\r\n // 채증일 뿐이라 실패해도 동작에는 영향이 없다\r\n }\r\n}\r\nexports.appendScreenLog = appendScreenLog;\r\n/** 파일명에 쓸 시각 — `2026-09-09_1130` */\r\nfunction stampForName(now = new Date()) {\r\n const p = (n) => String(n).padStart(2, '0');\r\n return `${now.getFullYear()}-${p(now.getMonth() + 1)}-${p(now.getDate())}`\r\n + `_${p(now.getHours())}${p(now.getMinutes())}`;\r\n}\r\n/**\r\n * 신고용 묶음을 만든다.\r\n *\r\n * 화면 원문(`SCREEN_PATH`)은 **기본으로 넣지 않는다** — 터미널에 찍힌 코드·경로가 그대로 들어 있어서,\r\n * 넣을지는 보내는 사람이 정할 일이다. 압축이 안 되는 환경(zip 도구 없음)에서는 폴더를 그대로 돌려준다.\r\n */\r\nfunction collectDiagBundle(options = {}) {\r\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;\r\n const name = `agentdeck-diag-${stampForName()}`;\r\n const dir = path.join(os.tmpdir(), name);\r\n fs.mkdirSync(dir, { recursive: true });\r\n const files = [];\r\n const report = [\r\n `agentdeck 진단 묶음 ${new Date().toISOString()}`,\r\n `plugin=${pluginVersion()} tabby=${(_b = (_a = options.stamp) === null || _a === void 0 ? void 0 : _a.tabby) !== null && _b !== void 0 ? _b : '?'}`,\r\n `platform=${process.platform} arch=${process.arch}`\r\n + ` node=${(_d = (_c = process.versions) === null || _c === void 0 ? void 0 : _c.node) !== null && _d !== void 0 ? _d : '?'} electron=${(_f = (_e = process.versions) === null || _e === void 0 ? void 0 : _e.electron) !== null && _f !== void 0 ? _f : '?'}`,\r\n `os=${(_h = (_g = options.stamp) === null || _g === void 0 ? void 0 : _g.osRelease) !== null && _h !== void 0 ? _h : os.release()}`,\r\n `config=${safeJson((_k = (_j = options.stamp) === null || _j === void 0 ? void 0 : _j.config) !== null && _k !== void 0 ? _k : {})}`,\r\n `diag=${fileSize(exports.DIAG_PATH)}B prev=${fileSize(exports.DIAG_PREV_PATH)}B`\r\n + ` screen=${fileSize(exports.SCREEN_PATH)}B (포함=${options.includeScreen ? 'y' : 'n'})`,\r\n '',\r\n '--- 이 세션의 최근 진단 (메모리) ---',\r\n ...recentDiag(200),\r\n '',\r\n ].join('\\n');\r\n fs.writeFileSync(path.join(dir, 'report.txt'), report, 'utf8');\r\n files.push('report.txt');\r\n const sources = [exports.DIAG_PATH, exports.DIAG_PREV_PATH];\r\n if (options.includeScreen) {\r\n sources.push(exports.SCREEN_PATH, exports.SCREEN_PREV_PATH);\r\n }\r\n for (const source of sources) {\r\n try {\r\n if (fs.existsSync(source)) {\r\n const base = path.basename(source).replace(/^\\./, '');\r\n fs.copyFileSync(source, path.join(dir, base));\r\n files.push(base);\r\n }\r\n }\r\n catch {\r\n // 한 파일을 못 복사해도 나머지는 담는다\r\n }\r\n }\r\n const zip = dir + '.zip';\r\n try {\r\n fs.rmSync(zip, { force: true });\r\n }\r\n catch {\r\n // 옛 묶음이 남아 있어도 압축 단계에서 다시 판정한다\r\n }\r\n if (compress(dir, zip) && fs.existsSync(zip)) {\r\n return { path: zip, zipped: true, files };\r\n }\r\n return { path: dir, zipped: false, files };\r\n}\r\nexports.collectDiagBundle = collectDiagBundle;\r\n/**\r\n * 폴더를 zip 으로 만든다.\r\n *\r\n * 의존성을 늘리지 않으려고 OS 도구를 쓴다 — Windows 는 `Compress-Archive`, 그 외는 `zip`.\r\n * 실패하면 false 를 돌려주고 호출부가 폴더 경로를 그대로 안내한다.\r\n */\r\nfunction compress(dir, zip) {\r\n try {\r\n if (process.platform === 'win32') {\r\n childProcess.execFileSync('powershell.exe', [\r\n '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass',\r\n '-Command', `Compress-Archive -Path '${dir}\\\\*' -DestinationPath '${zip}' -Force`,\r\n ], { timeout: 30000, stdio: 'ignore' });\r\n }\r\n else {\r\n childProcess.execFileSync('zip', ['-r', '-q', zip, '.'], { cwd: dir, timeout: 30000, stdio: 'ignore' });\r\n }\r\n return true;\r\n }\r\n catch {\r\n return false;\r\n }\r\n}\r\n","\"use strict\";\r\n/**\r\n * 사이드바를 마우스로 조절하는 부분 — 경계선 드래그로 크기, 헤더 드래그로 붙는 방향.\r\n *\r\n * 설정 창에서 숫자를 넣게 하지 않고 Visual Studio 의 도킹처럼 직접 끌어서 맞추게 한다.\r\n * DOM 을 직접 만지는 코드라 deck.service 밖으로 빼 두고, 값을 읽고 쓰는 통로만\r\n * `DockHost` 로 받는다 (deck.service 가 config 와 relayout 을 쥐고 있으므로).\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.DockController = exports.isHorizontalDock = exports.isDockSide = exports.DOCK_SIDES = void 0;\r\nexports.DOCK_SIDES = ['left', 'right', 'top', 'bottom'];\r\nfunction isDockSide(v) {\r\n return exports.DOCK_SIDES.includes(v);\r\n}\r\nexports.isDockSide = isDockSide;\r\n/** 좌/우 도킹이면 폭, 상/하 도킹이면 높이를 다룬다 */\r\nfunction isHorizontalDock(side) {\r\n return side === 'left' || side === 'right';\r\n}\r\nexports.isHorizontalDock = isHorizontalDock;\r\n/** 드래그로 오해하지 않을 최소 이동 거리 (px) */\r\nconst DRAG_THRESHOLD = 5;\r\n/** 존 버튼 밖에서 놓았을 때 가장자리로 인정하는 여백 비율 */\r\nconst EDGE_RATIO = 0.25;\r\nclass DockController {\r\n constructor(host) {\r\n this.host = host;\r\n this.handle = null;\r\n this.overlay = null;\r\n this.preview = null;\r\n this.zones = new Map();\r\n this.resizing = false;\r\n this.dragging = false;\r\n this.dragArmed = false;\r\n this.dragFrom = { x: 0, y: 0 };\r\n this.hoverSide = null;\r\n }\r\n /** 사이드바가 만들어진 뒤 한 번 부른다 */\r\n install() {\r\n this.installResizeHandle();\r\n this.installDockDrag();\r\n }\r\n /** 도킹 방향이 바뀌면 핸들 위치도 반대편으로 옮겨야 한다 */\r\n syncHandle() {\r\n if (!this.handle) {\r\n return;\r\n }\r\n const side = this.host.getDock();\r\n this.handle.className = 'ad-resize ad-resize-' + side;\r\n }\r\n // ---------- 경계선 드래그 (크기) ----------\r\n installResizeHandle() {\r\n const handle = document.createElement('div');\r\n handle.className = 'ad-resize';\r\n this.host.sidebar.appendChild(handle);\r\n this.handle = handle;\r\n this.syncHandle();\r\n handle.addEventListener('pointerdown', (ev) => {\r\n // 왼쪽 버튼만\r\n if (ev.button !== 0) {\r\n return;\r\n }\r\n ev.preventDefault();\r\n ev.stopPropagation();\r\n this.resizing = true;\r\n handle.setPointerCapture(ev.pointerId);\r\n document.body.classList.add('ad-resizing');\r\n });\r\n handle.addEventListener('pointermove', (ev) => {\r\n if (!this.resizing) {\r\n return;\r\n }\r\n const side = this.host.getDock();\r\n const rect = this.host.windowEl.getBoundingClientRect();\r\n // 커서와 창 가장자리 사이의 거리가 곧 사이드바 크기다\r\n let size;\r\n if (side === 'right') {\r\n size = rect.right - ev.clientX;\r\n }\r\n else if (side === 'left') {\r\n size = ev.clientX - rect.left;\r\n }\r\n else if (side === 'bottom') {\r\n size = rect.bottom - ev.clientY;\r\n }\r\n else {\r\n size = ev.clientY - rect.top;\r\n }\r\n this.host.setSize(Math.round(size));\r\n this.host.relayout();\r\n });\r\n const end = (ev) => {\r\n if (!this.resizing) {\r\n return;\r\n }\r\n this.resizing = false;\r\n try {\r\n handle.releasePointerCapture(ev.pointerId);\r\n }\r\n catch {\r\n // 이미 놓쳤다 — 무시해도 상태는 위에서 정리됐다\r\n }\r\n document.body.classList.remove('ad-resizing');\r\n this.host.commit();\r\n };\r\n handle.addEventListener('pointerup', end);\r\n handle.addEventListener('pointercancel', end);\r\n }\r\n // ---------- 헤더 드래그 (도킹 방향) ----------\r\n installDockDrag() {\r\n const head = this.host.sidebar.querySelector('.ad-head');\r\n if (!head) {\r\n return;\r\n }\r\n head.addEventListener('pointerdown', (ev) => {\r\n if (ev.button !== 0) {\r\n return;\r\n }\r\n // 헤더 안의 버튼류를 누른 것이면 건드리지 않는다\r\n if (ev.target.closest('button, input')) {\r\n return;\r\n }\r\n this.dragArmed = true;\r\n this.dragFrom = { x: ev.clientX, y: ev.clientY };\r\n head.setPointerCapture(ev.pointerId);\r\n });\r\n head.addEventListener('pointermove', (ev) => {\r\n if (!this.dragArmed) {\r\n return;\r\n }\r\n if (!this.dragging) {\r\n const dx = ev.clientX - this.dragFrom.x;\r\n const dy = ev.clientY - this.dragFrom.y;\r\n if (Math.hypot(dx, dy) < DRAG_THRESHOLD) {\r\n return;\r\n }\r\n // 여기서부터 도킹 드래그다 — 가이드를 띄운다\r\n this.dragging = true;\r\n this.showOverlay();\r\n }\r\n this.updateHover(ev.clientX, ev.clientY);\r\n });\r\n const end = (ev) => {\r\n if (!this.dragArmed) {\r\n return;\r\n }\r\n this.dragArmed = false;\r\n try {\r\n head.releasePointerCapture(ev.pointerId);\r\n }\r\n catch {\r\n // 무시\r\n }\r\n if (!this.dragging) {\r\n return;\r\n }\r\n this.dragging = false;\r\n const side = this.hoverSide;\r\n this.hideOverlay();\r\n if (side && side !== this.host.getDock()) {\r\n this.host.setDock(side);\r\n this.host.relayout();\r\n this.syncHandle();\r\n this.host.commit();\r\n }\r\n };\r\n head.addEventListener('pointerup', end);\r\n head.addEventListener('pointercancel', end);\r\n }\r\n // ---------- 드롭 가이드 ----------\r\n showOverlay() {\r\n if (this.overlay) {\r\n return;\r\n }\r\n const overlay = document.createElement('div');\r\n overlay.className = 'ad-dock-overlay';\r\n const preview = document.createElement('div');\r\n preview.className = 'ad-dock-preview';\r\n overlay.appendChild(preview);\r\n for (const side of exports.DOCK_SIDES) {\r\n const zone = document.createElement('div');\r\n zone.className = 'ad-dock-zone ad-dock-zone-' + side;\r\n zone.innerHTML = '<span class=\"ad-dock-mark\"></span>';\r\n overlay.appendChild(zone);\r\n this.zones.set(side, zone);\r\n }\r\n document.body.appendChild(overlay);\r\n this.overlay = overlay;\r\n this.preview = preview;\r\n this.positionZones();\r\n }\r\n /** 존 버튼을 `.window` 네 가장자리 안쪽에 놓는다 (창이 전체화면이 아닐 수도 있으므로 매번 잰다) */\r\n positionZones() {\r\n const rect = this.host.windowEl.getBoundingClientRect();\r\n const cx = rect.left + rect.width / 2;\r\n const cy = rect.top + rect.height / 2;\r\n const inset = 56;\r\n const place = {\r\n left: [rect.left + inset, cy],\r\n right: [rect.right - inset, cy],\r\n top: [cx, rect.top + inset],\r\n bottom: [cx, rect.bottom - inset],\r\n };\r\n for (const side of exports.DOCK_SIDES) {\r\n const zone = this.zones.get(side);\r\n if (!zone) {\r\n continue;\r\n }\r\n const [x, y] = place[side];\r\n zone.style.left = x + 'px';\r\n zone.style.top = y + 'px';\r\n }\r\n }\r\n /** 커서 위치로 어느 쪽에 붙일지 정하고 미리보기를 그린다 */\r\n updateHover(x, y) {\r\n const side = this.hitTest(x, y);\r\n if (side !== this.hoverSide) {\r\n this.hoverSide = side;\r\n for (const [s, zone] of this.zones) {\r\n zone.classList.toggle('active', s === side);\r\n }\r\n }\r\n this.drawPreview(side);\r\n }\r\n /**\r\n * 존 버튼 위에 있으면 그쪽, 아니면 커서가 창의 어느 가장자리 띠에 들어와 있는지로 정한다.\r\n * 가운데에 있으면 null — 놓아도 아무 일이 없다.\r\n */\r\n hitTest(x, y) {\r\n for (const [side, zone] of this.zones) {\r\n const r = zone.getBoundingClientRect();\r\n if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) {\r\n return side;\r\n }\r\n }\r\n const rect = this.host.windowEl.getBoundingClientRect();\r\n const dx = (x - rect.left) / rect.width;\r\n const dy = (y - rect.top) / rect.height;\r\n if (dx < EDGE_RATIO && dx <= dy && dx <= 1 - dy) {\r\n return 'left';\r\n }\r\n if (dx > 1 - EDGE_RATIO && 1 - dx <= dy && 1 - dx <= 1 - dy) {\r\n return 'right';\r\n }\r\n if (dy < EDGE_RATIO) {\r\n return 'top';\r\n }\r\n if (dy > 1 - EDGE_RATIO) {\r\n return 'bottom';\r\n }\r\n return null;\r\n }\r\n /** 놓으면 사이드바가 어디에 얼마만큼 자리잡는지 반투명 박스로 미리 보여준다 */\r\n drawPreview(side) {\r\n if (!this.preview) {\r\n return;\r\n }\r\n if (!side) {\r\n this.preview.style.display = 'none';\r\n return;\r\n }\r\n const rect = this.host.windowEl.getBoundingClientRect();\r\n const horizontal = isHorizontalDock(side);\r\n // 방향마다 기억된 크기가 다르다 — 지금 붙어 있는 쪽이 아니라 놓으려는 쪽 값을 물어본다\r\n const current = this.host.getSize(side);\r\n const size = horizontal\r\n ? Math.min(Math.max(current || 320, 180), rect.width * 0.6)\r\n : Math.min(Math.max(current || 200, 120), rect.height * 0.6);\r\n const s = this.preview.style;\r\n s.display = 'block';\r\n s.left = (side === 'right' ? rect.right - size : rect.left) + 'px';\r\n s.top = (side === 'bottom' ? rect.bottom - size : rect.top) + 'px';\r\n s.width = (horizontal ? size : rect.width) + 'px';\r\n s.height = (horizontal ? rect.height : size) + 'px';\r\n }\r\n hideOverlay() {\r\n var _a;\r\n (_a = this.overlay) === null || _a === void 0 ? void 0 : _a.remove();\r\n this.overlay = null;\r\n this.preview = null;\r\n this.zones.clear();\r\n this.hoverSide = null;\r\n }\r\n}\r\nexports.DockController = DockController;\r\n","\"use strict\";\r\n/**\r\n * `git status` 의 스테이지 상태를 구조로 바꾸고, 스테이지·커밋에 쓸 **명령 인자만** 조립하는\r\n * 순수 모듈 — 미리보기 패널 `변경` 탭의 스테이지 토글·커밋 버튼이 쓴다.\r\n *\r\n * **여기서 git 을 실행하지 않는 이유** — 커밋은 되돌리기 번거로운 실제 부작용이다. 그래서\r\n * \"무엇을 실행할지\" 를 정하는 자리(이 파일, 테스트로 고정)와 \"실제로 실행하는 자리\"\r\n * (viewPanel.ts, 사람의 클릭에만 반응)를 갈랐다. 이 파일만 읽으면 어떤 명령이 나가는지\r\n * 인자 배열 단위로 확인할 수 있고, 반대로 이 파일을 불러도 아무 일도 일어나지 않는다.\r\n *\r\n * DOM·child_process·fs 를 건드리지 않는다 — gitDiff.ts 와 같은 결이다(테스트로 묶기 위해서).\r\n *\r\n * **셸을 거치지 않는다** — viewPanel 은 `execFile('git', args)` 로 부르므로 여기서 만드는\r\n * 인자는 인용·이스케이프가 필요 없고, 반대로 인용을 붙이면 그 따옴표가 파일명이 된다.\r\n * 경로 앞에는 항상 `--` 를 넣는다(파일명이 `-f` 나 브랜치명이어도 옵션·리비전으로 안 읽히게).\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.formatStageSummary = exports.hasStaged = exports.commitArgs = exports.validateMessage = exports.unstageFallbackArgs = exports.unstageArgs = exports.stageArgs = exports.parseStatus = exports.stageLabel = exports.stageStateOf = void 0;\r\nconst gitDiff_1 = require(\"./gitDiff\");\r\n/**\r\n * 소스에 리터럴 NUL(0x00)을 쓰면 그 파일이 \"바이너리\" 로 취급돼 diff·grep·리뷰가 통째로\r\n * 막힌다 (0.6.0 에서 agents.ts 가 실제로 그렇게 됐다 — docs/DEVELOPMENT.md 함정 목록).\r\n * `--porcelain -z` 를 다루려면 NUL 이 필요하므로 **이스케이프로만** 적는다.\r\n */\r\nconst NUL = '\\u0000';\r\n/**\r\n * 커밋 메시지 길이 상한. git 자체에는 제한이 없지만 우리는 인자로 넘기고,\r\n * Windows 의 CreateProcess 명령줄 상한이 32767 자다 — 그 앞에서 넉넉히 막아\r\n * \"왜 실패했는지 모르는 실패\" 를 안 만든다.\r\n */\r\nconst MAX_MESSAGE = 8000;\r\n/** 충돌 조합 — 한쪽이 `U` 면 무조건, 그 밖에 `DD`(양쪽 삭제)·`AA`(양쪽 추가)도 충돌이다 */\r\nfunction isConflict(x, y) {\r\n return x === 'U' || y === 'U' || (x === 'D' && y === 'D') || (x === 'A' && y === 'A');\r\n}\r\n/**\r\n * 두 글자 상태코드(XY)를 상태로 읽는다.\r\n *\r\n * 규칙은 하나다 — **X 는 스테이지, Y 는 작업트리.** 어느 쪽이 공백이 아니냐로 갈리고,\r\n * 둘 다 값이 있으면 부분 스테이지(`both`)다. 충돌을 먼저 걸러내는 이유는 `AA`·`UU` 가\r\n * \"양쪽에 값이 있다\" 조건도 만족해서 `both` 로 새기 때문이다.\r\n */\r\nfunction stageStateOf(index, work) {\r\n const x = index || ' ';\r\n const y = work || ' ';\r\n if (x === '?' || y === '?') {\r\n return 'untracked';\r\n }\r\n if (isConflict(x, y)) {\r\n return 'conflict';\r\n }\r\n const staged = x !== ' ';\r\n const dirty = y !== ' ';\r\n if (staged && dirty) {\r\n return 'both';\r\n }\r\n return staged ? 'staged' : 'unstaged';\r\n}\r\nexports.stageStateOf = stageStateOf;\r\n/** 목록에 붙일 딱지 — 지금 상태를 그대로 말한다(누르면 무엇이 되는지는 title 이 말한다) */\r\nfunction stageLabel(state) {\r\n switch (state) {\r\n case 'staged': return '올림';\r\n case 'both': return '일부';\r\n case 'untracked': return '새파일';\r\n case 'conflict': return '충돌';\r\n default: return '안올림';\r\n }\r\n}\r\nexports.stageLabel = stageLabel;\r\n/** `## main...origin/main` 같은 머리줄(`-b`)은 경로가 아니다 */\r\nfunction isHeader(rec) {\r\n return rec.startsWith('## ');\r\n}\r\n/**\r\n * `XY PATH` 를 가른다. `-z` 든 아니든 **XY 다음 한 칸은 공백**이다\r\n * (실측: `git status --porcelain -z` → `b' M docs/ORCHESTRATION.md\\x00'`).\r\n */\r\nfunction splitCode(rec) {\r\n if (rec.length < 3) {\r\n return null;\r\n }\r\n return { code: rec.slice(0, 2), rest: rec.slice(2).replace(/^ /, '') };\r\n}\r\n/** 이름변경·복사인가 — 이때만 경로가 두 개 온다 */\r\nfunction isRenameCode(code) {\r\n return code.indexOf('R') >= 0 || code.indexOf('C') >= 0;\r\n}\r\n/** 따옴표 토큰의 닫는 위치 (백슬래시 이스케이프를 건너뛴다) */\r\nfunction endOfQuoted(s) {\r\n for (let i = 1; i < s.length; i++) {\r\n if (s[i] === '\\\\') {\r\n i++;\r\n continue;\r\n }\r\n if (s[i] === '\"') {\r\n return i + 1;\r\n }\r\n }\r\n return -1;\r\n}\r\n/**\r\n * 줄 형식(`-z` 아님)의 이름변경 `ORIG -> PATH` 를 가른다.\r\n *\r\n * 따옴표로 감싼 쪽은 닫는 따옴표를 찾아 정확히 가른다. 감싸지 않은 경우는 **첫 ` -> `** 로\r\n * 가르는데, 파일명 자체에 ` -> ` 가 들어 있으면 이 줄만으로는 원리적으로 가를 수 없다\r\n * (gitDiff.splitHeadPaths 가 `diff --git` 에서 만난 것과 같은 종류의 모호함이다).\r\n */\r\nfunction splitRename(rest) {\r\n if (rest.startsWith('\"')) {\r\n const end = endOfQuoted(rest);\r\n if (end > 0) {\r\n const tail = rest.slice(end).replace(/^ -> /, '');\r\n return { orig: (0, gitDiff_1.unquotePath)(rest.slice(0, end)), next: (0, gitDiff_1.unquotePath)(tail) };\r\n }\r\n }\r\n const cut = rest.indexOf(' -> ');\r\n if (cut < 0) {\r\n return { orig: '', next: (0, gitDiff_1.unquotePath)(rest) };\r\n }\r\n return { orig: (0, gitDiff_1.unquotePath)(rest.slice(0, cut)), next: (0, gitDiff_1.unquotePath)(rest.slice(cut + 4)) };\r\n}\r\nfunction entryOf(code, path, oldPath) {\r\n var _a, _b;\r\n const index = (_a = code[0]) !== null && _a !== void 0 ? _a : ' ';\r\n const work = (_b = code[1]) !== null && _b !== void 0 ? _b : ' ';\r\n const e = { path, index, work, state: stageStateOf(index, work) };\r\n if (oldPath) {\r\n e.oldPath = oldPath;\r\n }\r\n return e;\r\n}\r\n/**\r\n * `-z` 형식. 레코드마다 NUL 이 붙고 **따옴표를 쓰지 않는다**(그래서 여기서는 따옴표를 벗기지\r\n * 않는다 — 벗기면 이름이 `\"x\"` 인 파일이 망가진다).\r\n *\r\n * 이름변경은 `-z` 에서 **순서가 뒤집힌다** — `->` 가 사라지고 `XY PATH<NUL>ORIG<NUL>` 로 온다\r\n * (git-status(1): \"the `->` is omitted from rename entries and the field order is reversed\").\r\n * 이 줄을 실측으로 확인하지 못한 이유는 스테이지된 이름변경을 만들려면 `git add` 가 필요한데\r\n * 이 라운드에서는 어떤 저장소에도 add/commit 을 하지 않기로 했기 때문이다 — 근거는 문서다.\r\n */\r\nfunction parseZ(src) {\r\n var _a;\r\n const fields = src.split(NUL);\r\n const out = [];\r\n for (let i = 0; i < fields.length; i++) {\r\n const rec = fields[i];\r\n if (!rec || isHeader(rec)) {\r\n continue;\r\n }\r\n const cut = splitCode(rec);\r\n if (!cut || cut.code === '!!' || cut.code === ' ') {\r\n continue;\r\n }\r\n if (isRenameCode(cut.code)) {\r\n const orig = (_a = fields[i + 1]) !== null && _a !== void 0 ? _a : '';\r\n i++;\r\n out.push(entryOf(cut.code, cut.rest, orig));\r\n continue;\r\n }\r\n out.push(entryOf(cut.code, cut.rest));\r\n }\r\n return out;\r\n}\r\n/**\r\n * `git status --porcelain=v1` 출력을 구조로 바꾼다. `-z` 인지는 NUL 유무로 스스로 안다 —\r\n * 부르는 쪽이 어느 형식으로 뽑았는지 두 번 말하지 않게 하기 위해서다.\r\n *\r\n * 버리는 것 두 가지: `!!`(무시된 파일 — `--ignored` 없이는 안 나오고 화면에도 안 그린다)과\r\n * `## ` 머리줄. 나머지는 상태코드를 그대로 보존해서(`index`/`work`) 판정을 되짚을 수 있게 둔다.\r\n */\r\nfunction parseStatus(text) {\r\n const src = String(text !== null && text !== void 0 ? text : '');\r\n if (!src.trim()) {\r\n return [];\r\n }\r\n if (src.indexOf(NUL) >= 0) {\r\n return parseZ(src);\r\n }\r\n const out = [];\r\n // CRLF 로 오는 경우 — 셸을 거치거나 하네스가 흘리면 붙는다\r\n for (const raw of src.replace(/\\r\\n?/g, '\\n').split('\\n')) {\r\n if (!raw.trim() || isHeader(raw)) {\r\n continue;\r\n }\r\n const cut = splitCode(raw);\r\n if (!cut || cut.code === '!!' || cut.code === ' ') {\r\n continue;\r\n }\r\n if (isRenameCode(cut.code)) {\r\n const pair = splitRename(cut.rest);\r\n out.push(entryOf(cut.code, pair.next, pair.orig));\r\n continue;\r\n }\r\n out.push(entryOf(cut.code, (0, gitDiff_1.unquotePath)(cut.rest)));\r\n }\r\n return out;\r\n}\r\nexports.parseStatus = parseStatus;\r\n/**\r\n * 인자로 넘길 경로를 다듬는다.\r\n * - 빈 경로는 버린다 (git 이 \"빈 경로 명세\" 로 거절한다)\r\n * - NUL 이 든 경로는 버린다 — `execFile` 이 인자에 NUL 을 허용하지 않아 **예외로 죽는다**\r\n * - 중복은 없앤다 (같은 파일을 두 번 넘길 이유가 없다)\r\n *\r\n * 앞뒤 공백은 **떼지 않는다** — 파일명에 공백이 들어 있을 수 있고, 다듬으면 없는 경로가 된다.\r\n */\r\nfunction cleanPaths(paths) {\r\n const seen = new Set();\r\n for (const p of paths !== null && paths !== void 0 ? paths : []) {\r\n const s = typeof p === 'string' ? p : '';\r\n if (!s || s.indexOf(NUL) >= 0) {\r\n continue;\r\n }\r\n seen.add(s);\r\n }\r\n return Array.from(seen);\r\n}\r\n/** 스테이지에 올린다. 경로가 없으면 **빈 배열** — 인자 없는 `git add` 는 저장소 전체를 건드린다 */\r\nfunction stageArgs(paths) {\r\n const list = cleanPaths(paths);\r\n return list.length ? ['add', '--', ...list] : [];\r\n}\r\nexports.stageArgs = stageArgs;\r\n/**\r\n * 스테이지에서 내린다. `git reset -q -- <경로>` = 그 경로만 index 를 HEAD 로 되돌린다\r\n * (작업트리는 건드리지 않는다 — `--hard` 는 절대 쓰지 않는다).\r\n * 경로가 없으면 빈 배열 — 인자 없는 `git reset` 은 스테이지 전체를 비운다.\r\n */\r\nfunction unstageArgs(paths) {\r\n const list = cleanPaths(paths);\r\n return list.length ? ['reset', '-q', '--', ...list] : [];\r\n}\r\nexports.unstageArgs = unstageArgs;\r\n/**\r\n * 커밋이 0개인 저장소용 대체 명령. `reset` 은 HEAD 를 풀어야 하므로 첫 커밋 전에는 실패한다\r\n * (`변경` 탭이 `diff HEAD` 대신 `diff` 로 폴백해야 했던 것과 같은 사정 — docs/DEVELOPMENT.md).\r\n * `rm --cached` 는 index 에서만 빼고 작업트리의 파일은 남긴다.\r\n */\r\nfunction unstageFallbackArgs(paths) {\r\n const list = cleanPaths(paths);\r\n return list.length ? ['rm', '--cached', '-q', '--', ...list] : [];\r\n}\r\nexports.unstageFallbackArgs = unstageFallbackArgs;\r\n/**\r\n * 커밋 메시지 검증. **거부하는 이유를 사람이 읽을 문장으로** 준다 — 버튼이 안 눌리는데\r\n * 이유가 없으면 사용자는 플러그인이 고장난 줄 안다.\r\n */\r\nfunction validateMessage(msg) {\r\n if (typeof msg !== 'string' || msg === '') {\r\n return { ok: false, reason: '커밋 메시지가 비어 있다 — 무엇을 바꿨는지 한 줄 적어야 커밋한다' };\r\n }\r\n if (msg.indexOf(NUL) >= 0) {\r\n return { ok: false, reason: '커밋 메시지에 NUL 문자가 들어 있다 — 그대로 넘기면 git 실행 자체가 실패한다' };\r\n }\r\n if (!msg.trim()) {\r\n return { ok: false, reason: '공백·줄바꿈만 있다 — git 도 빈 메시지로 보고 커밋을 거절한다' };\r\n }\r\n if (msg.length > MAX_MESSAGE) {\r\n return { ok: false, reason: '메시지가 너무 길다 (' + msg.length + '자 / 최대 ' + MAX_MESSAGE + '자)' };\r\n }\r\n return { ok: true };\r\n}\r\nexports.validateMessage = validateMessage;\r\n/**\r\n * 커밋 명령. **메시지는 `-m` 의 값으로 배열 원소 하나로 넘긴다** — 셸을 거치지 않으므로\r\n * 메시지에 `&&`·`\"`·`$(…)` 가 들어 있어도 그냥 글자다(주입 경로가 없다).\r\n *\r\n * 검증에 걸리면 **빈 배열**을 돌려준다. 부르는 쪽이 실수로 그대로 실행해도 인자가 없어\r\n * 커밋이 만들어지지 않는다 — UI 의 버튼 잠금과 별개인 두 번째 안전장치다.\r\n */\r\nfunction commitArgs(msg, opts) {\r\n if (!validateMessage(msg).ok) {\r\n return [];\r\n }\r\n const args = ['commit'];\r\n if (opts === null || opts === void 0 ? void 0 : opts.amend) {\r\n args.push('--amend');\r\n }\r\n args.push('-m', msg);\r\n return args;\r\n}\r\nexports.commitArgs = commitArgs;\r\n/** 스테이지에 올라간 것이 하나라도 있나 — 커밋 버튼이 \"올린 게 없다\" 를 미리 말하는 근거 */\r\nfunction hasStaged(entries) {\r\n for (const e of entries !== null && entries !== void 0 ? entries : []) {\r\n if (e.state === 'staged' || e.state === 'both') {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\nexports.hasStaged = hasStaged;\r\n/**\r\n * 커밋 줄에 붙일 요약. 부분 스테이지(`both`)는 **양쪽에 센다** — 그 파일은 올린 부분과\r\n * 안 올린 부분이 실제로 둘 다 있고, 한쪽만 세면 합이 파일 수와 안 맞아 더 헷갈린다.\r\n */\r\nfunction formatStageSummary(entries) {\r\n let staged = 0;\r\n let unstaged = 0;\r\n let untracked = 0;\r\n let conflict = 0;\r\n for (const e of entries !== null && entries !== void 0 ? entries : []) {\r\n switch (e === null || e === void 0 ? void 0 : e.state) {\r\n case 'staged':\r\n staged++;\r\n break;\r\n case 'unstaged':\r\n unstaged++;\r\n break;\r\n case 'both':\r\n staged++;\r\n unstaged++;\r\n break;\r\n case 'untracked':\r\n untracked++;\r\n break;\r\n case 'conflict':\r\n conflict++;\r\n break;\r\n default: break;\r\n }\r\n }\r\n const parts = [];\r\n if (staged) {\r\n parts.push(staged + '개 스테이지');\r\n }\r\n if (unstaged) {\r\n parts.push(unstaged + '개 미스테이지');\r\n }\r\n if (untracked) {\r\n parts.push(untracked + '개 추적안됨');\r\n }\r\n if (conflict) {\r\n parts.push(conflict + '개 충돌');\r\n }\r\n return parts.length ? parts.join(' · ') : '변경 없음';\r\n}\r\nexports.formatStageSummary = formatStageSummary;\r\n","\"use strict\";\r\n/**\r\n * `git diff` 유니파이드 출력을 구조로 바꾸는 순수 파서 — 미리보기 패널의 `변경` 탭이 쓴다.\r\n *\r\n * **왜 근거를 훅이 아니라 git 에 두나 —** 이 패널은 Claude·Codex·Gemini 를 가리지 않아야 한다.\r\n * \"누가 무엇을 고쳤다\" 를 에이전트에게 물으면 에이전트마다 규약이 달라지고(훅이 있는 것은\r\n * Claude Code 뿐이다 — src/claudeHooks.ts), 훅이 없는 에이전트에서는 탭이 텅 빈다.\r\n * 반면 작업트리는 누가 고쳤든 같은 자리에 같은 모양으로 남는다. 그래서 `git diff` 가 기본이다.\r\n *\r\n * DOM 도 child_process 도 건드리지 않는다 — git 실행과 화면 그리기는 viewPanel.ts 가 맡고\r\n * 여기서는 문자열을 구조로만 바꾼다. viewer.ts / markdown.ts 를 가른 것과 같은 이유(테스트)다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.parseUntracked = exports.filterTouched = exports.formatLineRef = exports.refPathFrom = exports.joinRefPath = exports.refLineNo = exports.statusLabel = exports.formatStat = exports.parseUnifiedDiff = exports.unquotePath = void 0;\r\nconst DIFF_HEAD_RE = /^diff --git (.*)$/;\r\n/**\r\n * `@@ -12,7 +12,9 @@ 함수명` — 개수는 1일 때 생략된다(`@@ -1 +1 @@`).\r\n * 꼬리(함수명)는 git 이 붙여 주는 문맥이라 그대로 보존한다 — 어느 함수 안인지가 diff 를 읽는 데\r\n * 가장 큰 단서다.\r\n */\r\nconst HUNK_RE = /^@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@(.*)$/;\r\nconst BINARY_RE = /^Binary files (.*) and (.*) differ$/;\r\n/** 바이트 배열을 UTF-8 로 읽는다 — git 이 한글 경로를 `\\355\\225\\234` 처럼 8진 이스케이프로 준다 */\r\nfunction bytesToUtf8(bytes) {\r\n if (!bytes.length) {\r\n return '';\r\n }\r\n try {\r\n return decodeURIComponent(bytes.map(b => '%' + b.toString(16).padStart(2, '0')).join(''));\r\n }\r\n catch {\r\n // UTF-8 이 아닌 파일명 — 바이트를 글자로 그대로 흘린다 (깨져 보여도 목록에서 사라지지는 않게)\r\n return bytes.map(b => String.fromCharCode(b)).join('');\r\n }\r\n}\r\nconst ESCAPES = {\r\n n: '\\n', t: '\\t', r: '\\r', '\"': '\"', '\\\\': '\\\\', b: '\\b', f: '\\f', v: '\\v', a: '\\x07',\r\n};\r\n/**\r\n * git 이 따옴표로 감싼 경로의 속을 푼다.\r\n *\r\n * `core.quotePath` 기본값이 true 라서 한글·공백·따옴표가 든 경로는 `\"a/\\355\\225\\234 \\353\\254\\270.md\"`\r\n * 처럼 온다. 8진 이스케이프는 **바이트 단위**라 한 글자가 여러 개로 쪼개져 있고, 그래서 모아 두었다가\r\n * 비-8진 문자를 만날 때 한 번에 UTF-8 로 읽는다 (한 개씩 읽으면 한글이 전부 깨진다).\r\n */\r\nfunction decodeQuoted(body) {\r\n var _a, _b;\r\n let out = '';\r\n let bytes = [];\r\n const flush = () => {\r\n if (bytes.length) {\r\n out += bytesToUtf8(bytes);\r\n bytes = [];\r\n }\r\n };\r\n for (let i = 0; i < body.length; i++) {\r\n const ch = body[i];\r\n if (ch !== '\\\\') {\r\n flush();\r\n out += ch;\r\n continue;\r\n }\r\n const next = (_a = body[i + 1]) !== null && _a !== void 0 ? _a : '';\r\n if (next >= '0' && next <= '7') {\r\n let oct = '';\r\n while (oct.length < 3 && body[i + 1] >= '0' && body[i + 1] <= '7') {\r\n oct += body[i + 1];\r\n i++;\r\n }\r\n bytes.push(parseInt(oct, 8));\r\n continue;\r\n }\r\n flush();\r\n out += (_b = ESCAPES[next]) !== null && _b !== void 0 ? _b : next;\r\n i++;\r\n }\r\n flush();\r\n return out;\r\n}\r\n/** 경로 한 토큰을 정규화한다 — 따옴표를 벗기고 탭 뒤(타임스탬프)를 버린다 */\r\nfunction unquotePath(raw) {\r\n let s = String(raw !== null && raw !== void 0 ? raw : '').replace(/\\t.*$/, '').trim();\r\n if (s.length >= 2 && s.startsWith('\"') && s.endsWith('\"')) {\r\n s = decodeQuoted(s.slice(1, -1));\r\n }\r\n return s;\r\n}\r\nexports.unquotePath = unquotePath;\r\n/** `a/` `b/` 접두를 뗀다. `--no-prefix` 로 뽑은 diff 는 접두가 없어 그대로 둔다 */\r\nfunction stripSide(p) {\r\n return /^[ab]\\//.test(p) ? p.slice(2) : p;\r\n}\r\n/** 따옴표 토큰 하나를 읽는다 (끝 위치도 같이 돌려준다 — 뒤에 두 번째 경로가 붙어 있다) */\r\nfunction readQuoted(s) {\r\n if (s[0] !== '\"') {\r\n return null;\r\n }\r\n for (let i = 1; i < s.length; i++) {\r\n if (s[i] === '\\\\') {\r\n i++;\r\n continue;\r\n }\r\n if (s[i] === '\"') {\r\n return { value: decodeQuoted(s.slice(1, i)), end: i + 1 };\r\n }\r\n }\r\n return null;\r\n}\r\n/**\r\n * `diff --git a/X b/Y` 의 두 경로를 가른다.\r\n *\r\n * 경로에 공백이 있으면 이 줄만으로는 원리적으로 가를 수 없다(구분자가 공백인데 경로에도 공백이 있다).\r\n * 그래서 **같은 경로가 두 번 오는 경우**(수정·삭제·신규 = 거의 전부)를 길이로 정확히 판정하고,\r\n * 이름이 바뀐 경우는 뒤따라오는 `rename from/to` 나 `---`/`+++` 가 덮어 준다.\r\n */\r\nfunction splitHeadPaths(rest) {\r\n const s = String(rest !== null && rest !== void 0 ? rest : '').trim();\r\n if (s.startsWith('\"')) {\r\n const first = readQuoted(s);\r\n if (first) {\r\n const tail = s.slice(first.end).trim();\r\n const second = readQuoted(tail);\r\n return { old: stripSide(first.value), next: stripSide(second ? second.value : tail) };\r\n }\r\n }\r\n // `a/P b/P` 꼴이면 길이가 `2 + L + 3 + L` 이다 — L 을 역산해 양쪽이 같은지 확인한다\r\n const half = (s.length - 5) / 2;\r\n if (Number.isInteger(half) && half > 0 && s.slice(0, 2) === 'a/'\r\n && s.slice(2 + half, 5 + half) === ' b/' && s.slice(2, 2 + half) === s.slice(5 + half)) {\r\n const p = s.slice(2, 2 + half);\r\n return { old: p, next: p };\r\n }\r\n const cut = s.indexOf(' b/');\r\n if (cut > 0) {\r\n return { old: stripSide(s.slice(0, cut)), next: stripSide(s.slice(cut + 1)) };\r\n }\r\n return { old: stripSide(s), next: stripSide(s) };\r\n}\r\nfunction blank() {\r\n return { path: '', status: 'modified', binary: false, added: 0, removed: 0, lines: [] };\r\n}\r\n/**\r\n * 유니파이드 diff 한 덩이를 파일 목록으로 바꾼다.\r\n *\r\n * 훑는 방식: `diff --git` 마다 파일을 하나 열고, `@@` 를 만나면 그 헝크가 **몇 줄인지 세면서**\r\n * 본문을 먹는다. 줄 수로 끝을 판정하는 이유 — 헝크 본문에는 `+++ b/x` 나 `--- a/x` 같은 글자가\r\n * 그대로 들어 있을 수 있다(diff 를 담은 파일의 diff). 앞머리 기호만 보고 헤더와 본문을 가르면\r\n * 그런 줄에서 파싱이 어긋난다.\r\n */\r\nfunction parseUnifiedDiff(text) {\r\n var _a;\r\n const src = String(text !== null && text !== void 0 ? text : '').replace(/\\r\\n?/g, '\\n');\r\n if (!src.trim()) {\r\n return [];\r\n }\r\n const files = [];\r\n let cur = null;\r\n let oldNo = 0;\r\n let newNo = 0;\r\n /** 지금 헝크에서 아직 안 먹은 줄 수 (둘 다 0 이면 헝크 밖) */\r\n let remOld = 0;\r\n let remNew = 0;\r\n for (const raw of src.split('\\n')) {\r\n const inHunk = cur !== null && (remOld > 0 || remNew > 0);\r\n if (inHunk) {\r\n const mark = (_a = raw[0]) !== null && _a !== void 0 ? _a : '';\r\n if (mark === '\\\\') {\r\n // `\` — 내용이 아니라 주석이라 줄로 세지 않는다.\r\n // 이걸 ctx 로 흘리면 줄번호가 한 칸씩 밀린다\r\n continue;\r\n }\r\n if (mark === '+') {\r\n cur.added++;\r\n cur.lines.push({ kind: 'add', text: raw.slice(1), newNo: newNo++ });\r\n remNew--;\r\n continue;\r\n }\r\n if (mark === '-') {\r\n cur.removed++;\r\n cur.lines.push({ kind: 'del', text: raw.slice(1), oldNo: oldNo++ });\r\n remOld--;\r\n continue;\r\n }\r\n if (mark === ' ' || raw === '') {\r\n // 빈 문맥줄은 원래 공백 한 칸이지만, 중간에 거친 도구가 뒷공백을 떼면 빈 줄로 온다\r\n cur.lines.push({ kind: 'ctx', text: raw.slice(1), oldNo: oldNo++, newNo: newNo++ });\r\n remOld--;\r\n remNew--;\r\n continue;\r\n }\r\n // 헝크가 선언한 줄 수보다 일찍 끝났다 — 헤더로 되돌아간다\r\n remOld = 0;\r\n remNew = 0;\r\n }\r\n const head = DIFF_HEAD_RE.exec(raw);\r\n if (head) {\r\n const pair = splitHeadPaths(head[1]);\r\n cur = blank();\r\n cur.path = pair.next;\r\n if (pair.old && pair.old !== pair.next) {\r\n cur.oldPath = pair.old;\r\n }\r\n files.push(cur);\r\n remOld = 0;\r\n remNew = 0;\r\n continue;\r\n }\r\n if (!cur) {\r\n // `diff --git` 앞에 붙은 것(커밋 메시지 등) — 볼 것이 없다\r\n continue;\r\n }\r\n const hunk = HUNK_RE.exec(raw);\r\n if (hunk) {\r\n oldNo = Number(hunk[1]);\r\n newNo = Number(hunk[3]);\r\n remOld = hunk[2] === undefined ? 1 : Number(hunk[2]);\r\n remNew = hunk[4] === undefined ? 1 : Number(hunk[4]);\r\n cur.lines.push({ kind: 'hunk', text: raw });\r\n continue;\r\n }\r\n if (raw.startsWith('new file mode')) {\r\n cur.status = 'added';\r\n }\r\n else if (raw.startsWith('deleted file mode')) {\r\n cur.status = 'deleted';\r\n }\r\n else if (raw.startsWith('rename from ')) {\r\n cur.status = 'renamed';\r\n cur.oldPath = unquotePath(raw.slice('rename from '.length));\r\n }\r\n else if (raw.startsWith('rename to ')) {\r\n cur.status = 'renamed';\r\n cur.path = unquotePath(raw.slice('rename to '.length));\r\n }\r\n else if (raw.startsWith('--- ')) {\r\n const p = unquotePath(raw.slice(4));\r\n if (p === '/dev/null') {\r\n cur.status = 'added';\r\n }\r\n else if (cur.status !== 'renamed') {\r\n // 이름이 바뀐 경우는 rename from/to 가 더 정확하다 (거기엔 접두가 없다)\r\n const old = stripSide(p);\r\n if (old !== cur.path) {\r\n cur.oldPath = old;\r\n }\r\n }\r\n }\r\n else if (raw.startsWith('+++ ')) {\r\n const p = unquotePath(raw.slice(4));\r\n if (p === '/dev/null') {\r\n cur.status = 'deleted';\r\n }\r\n else if (cur.status !== 'renamed') {\r\n cur.path = stripSide(p);\r\n }\r\n }\r\n else if (raw.startsWith('GIT binary patch')) {\r\n cur.binary = true;\r\n }\r\n else {\r\n const bin = BINARY_RE.exec(raw);\r\n if (bin) {\r\n cur.binary = true;\r\n // 이 줄은 경로를 공백 없이 `and` 로 갈라 줘서 공백 든 경로도 정확히 읽힌다\r\n const oldSide = unquotePath(bin[1]);\r\n const newSide = unquotePath(bin[2]);\r\n if (newSide !== '/dev/null') {\r\n cur.path = stripSide(newSide);\r\n }\r\n if (oldSide === '/dev/null') {\r\n cur.status = 'added';\r\n }\r\n else if (newSide === '/dev/null') {\r\n cur.status = 'deleted';\r\n }\r\n }\r\n }\r\n }\r\n return files;\r\n}\r\nexports.parseUnifiedDiff = parseUnifiedDiff;\r\n/**\r\n * 헤더에 쓸 한 줄 요약. 변경이 없으면 그 사실을 그대로 문장으로 돌려준다 —\r\n * 부르는 쪽에서 빈 목록을 또 갈라 보지 않게 하기 위해서다.\r\n */\r\nfunction formatStat(files) {\r\n const list = files !== null && files !== void 0 ? files : [];\r\n if (!list.length) {\r\n return '변경 없음';\r\n }\r\n let added = 0;\r\n let removed = 0;\r\n for (const f of list) {\r\n added += f.added;\r\n removed += f.removed;\r\n }\r\n return list.length + '개 파일 · +' + added + ' -' + removed;\r\n}\r\nexports.formatStat = formatStat;\r\n/** 파일 목록에 붙일 상태 딱지 */\r\nfunction statusLabel(file) {\r\n switch (file.status) {\r\n case 'added': return '신규';\r\n case 'deleted': return '삭제';\r\n case 'renamed': return '이름변경';\r\n default: return '수정';\r\n }\r\n}\r\nexports.statusLabel = statusLabel;\r\n// ---------- `파일:라인` 참조 ----------\r\n// 패널에서 줄을 골라 터미널에 넣는 기능(viewPanel.clickRefLine)이 쓰는 규칙들이다.\r\n// 번호·경로·따옴표 판정은 전부 문자열 계산이라 여기 순수 함수로 두고 테스트로 못 박는다 —\r\n// DOM 을 띄우지 않고는 확인할 수 없는 곳에 두면 회귀를 잡을 방법이 없다.\r\n/** 윈도우 드라이브 접두(`D:`) — 이게 보이면 경로 비교를 대소문자 무시로 한다 */\r\nconst WIN_DRIVE_RE = /^[A-Za-z]:/;\r\n/** 경로 구분자를 `/` 로 맞춘다 — git 은 `/` 를, Tabby 의 cwd 는 OS 것(윈도우는 `\\`)을 준다 */\r\nfunction slash(p) {\r\n return String(p !== null && p !== void 0 ? p : '').replace(/\\\\/g, '/');\r\n}\r\n/** 끝의 `/` 를 뗀다 (`D:/x/` 와 `D:/x` 가 다른 폴더로 비교되지 않게) */\r\nfunction trimTail(p) {\r\n return p.length > 1 ? p.replace(/\\/+$/, '') : p;\r\n}\r\n/**\r\n * 참조에 쓸 줄번호 — **신(新) 파일 기준**이다.\r\n *\r\n * 유니파이드 diff 에는 구/신 번호가 둘 다 있는데, 참조를 받는 에이전트는 **지금 디스크에 있는\r\n * 파일을 열어 본다.** 그 파일에서 맞는 번호는 신 번호뿐이다(구 번호는 커밋 전 원본의 좌표라\r\n * 작업트리와 어긋난다). 그래서 추가줄·문맥줄은 `newNo` 를 쓴다.\r\n *\r\n * **삭제줄은 `null` 을 돌려준다 = 참조 불가.** 삭제된 줄은 지금 파일에 없으므로 어떤 번호를\r\n * 붙여도 거짓이 된다. \"직전 신 번호\" 로 대신하면 `file:42` 가 삭제된 내용이 아니라 **엉뚱하게\r\n * 남아 있는 42번 줄**을 가리키고, 에이전트는 그 줄을 자신 있게 고친다 — 조용히 틀리는 쪽보다\r\n * 참조를 못 만들고 이유를 말하는 쪽이 낫다. 헝크 머리줄(`@@`)도 내용이 아니라 머리라 제외한다.\r\n */\r\nfunction refLineNo(line) {\r\n if (!line || line.kind === 'del' || line.kind === 'hunk') {\r\n return null;\r\n }\r\n const no = line.newNo;\r\n return typeof no === 'number' && Number.isFinite(no) && no > 0 ? Math.floor(no) : null;\r\n}\r\nexports.refLineNo = refLineNo;\r\n/**\r\n * git 이 낸 저장소 루트 기준 경로를 절대경로로 바꾼다 (`/` 형태로).\r\n *\r\n * `path.join` 을 쓰지 않는 이유 — 윈도우에서 `\\` 로 되돌아오는데, 참조 문자열은 git 이 보여 준\r\n * 모양(`src/a.ts`)과 같아야 사람이 화면과 대조할 수 있다. `/` 는 윈도우 셸·에이전트 모두 받는다.\r\n */\r\nfunction joinRefPath(root, rel) {\r\n const r = slash(rel);\r\n if (!r) {\r\n return '';\r\n }\r\n const base = trimTail(slash(root));\r\n if (!base || r.startsWith('/') || WIN_DRIVE_RE.test(r)) {\r\n return r;\r\n }\r\n return base + '/' + r;\r\n}\r\nexports.joinRefPath = joinRefPath;\r\n/**\r\n * 절대경로를 **그 탭의 cwd 기준 상대경로**로 줄인다. cwd 밖이면 절대경로를 그대로 돌려준다.\r\n *\r\n * 왜 cwd 기준인가 — 참조를 받는 에이전트는 그 탭의 cwd 에서 돌고 있어서 `src/a.ts` 가 곧바로\r\n * 열린다. 반대로 저장소 루트 기준을 그대로 넘기면 cwd 가 하위 폴더일 때 어긋난다.\r\n * cwd 밖(예: cwd 가 하위 폴더인데 파일은 상위에 있음)은 `../` 로 올라가지 않고 절대경로로 준다 —\r\n * 짧게는 되지만 에이전트가 cwd 밖 파일을 못 여는 경우가 있고, 그때 원인이 보이지 않는다.\r\n */\r\nfunction refPathFrom(abs, cwd) {\r\n const a = slash(abs);\r\n if (!a) {\r\n return '';\r\n }\r\n const c = trimTail(slash(cwd));\r\n if (!c) {\r\n return a;\r\n }\r\n // 윈도우 경로는 대소문자를 가리지 않는다 — `D:\\Proj` 와 `d:/proj` 는 같은 폴더다.\r\n // POSIX 에서는 정말 다른 폴더일 수 있으므로 드라이브 접두가 보일 때만 무시한다\r\n const win = WIN_DRIVE_RE.test(a) || WIN_DRIVE_RE.test(c);\r\n const ka = win ? a.toLowerCase() : a;\r\n const kc = win ? c.toLowerCase() : c;\r\n if (ka === kc) {\r\n return a;\r\n }\r\n return ka.startsWith(kc + '/') ? a.slice(c.length + 1) : a;\r\n}\r\nexports.refPathFrom = refPathFrom;\r\n/**\r\n * `파일:라인` 한 토큰을 만든다. 두 줄 이상이면 `파일:시작-끝`.\r\n *\r\n * **공백이 든 경로는 따옴표로 감싼다** — 그러지 않으면 셸이 두 인자로 쪼개 읽는다\r\n * (deck.service 의 `pasteDroppedPath` 와 같은 규칙, 같은 이유). 번호까지 함께 감싸서\r\n * 한 낱말로 남긴다. 경로에 따옴표 자체가 들어 있는 경우는 다루지 않는다 — 윈도우에서는\r\n * 파일명에 쓸 수 없는 글자이고, 드롭 붙여넣기도 같은 선에서 멈춰 있다.\r\n *\r\n * 번호가 없거나(0·NaN) 뒤집혀 있어도 값을 낸다 — 참조를 못 만들어 침묵하는 것보다 경로만이라도\r\n * 넣는 쪽이 사람이 이어 쓸 수 있다.\r\n */\r\nfunction formatLineRef(refPath, from, to) {\r\n const p = String(refPath !== null && refPath !== void 0 ? refPath : '');\r\n if (!p) {\r\n return '';\r\n }\r\n const a = Number(from);\r\n const b = Number(to !== null && to !== void 0 ? to : from);\r\n const okA = Number.isFinite(a) && a > 0;\r\n const okB = Number.isFinite(b) && b > 0;\r\n let ref = p;\r\n if (okA || okB) {\r\n const lo = Math.floor(Math.min(okA ? a : b, okB ? b : a));\r\n const hi = Math.floor(Math.max(okA ? a : b, okB ? b : a));\r\n ref = p + ':' + lo + (hi > lo ? '-' + hi : '');\r\n }\r\n return /\\s/.test(ref) ? '\"' + ref + '\"' : ref;\r\n}\r\nexports.formatLineRef = formatLineRef;\r\n// ---------- 이 세션이 만진 것만 ----------\r\n// 왜 필요한가 — `git diff HEAD` 는 **저장소가 커밋되지 않은 전부**를 낸다. 그게 맞는 저장소도\r\n// 있지만, P4 워크스페이스 위에 git 을 얹어 쓰는 곳에서는 마지막 커밋 이후 sync 된 것이 전부\r\n// 걸려 405개가 뜬다 (2026-09-11 실측: `D:/Project/SoloLV/Root`, HEAD 가 2026-08-26 에 멈춰 있다).\r\n// 그 목록에서 \"방금 에이전트가 뭘 고쳤나\" 를 찾는 것은 불가능하다.\r\n//\r\n// 그래서 훅이 알려 준 **이번 세션이 만진 파일**로 목록을 좁힌다. 판정은 문자열 계산뿐이라\r\n// 여기 순수 함수로 두고 테스트로 고정한다 (refLineNo·joinRefPath 를 여기 둔 것과 같은 이유).\r\n/** 경로 비교용 열쇠 — 구분자를 `/` 로 맞추고, 윈도우 경로면 대소문자를 무시한다 */\r\nfunction pathKey(p) {\r\n const s = trimTail(slash(p));\r\n return WIN_DRIVE_RE.test(s) ? s.toLowerCase() : s;\r\n}\r\n/**\r\n * 저장소 루트 기준 경로(`src/a.ts`)들 중 **만진 목록에 있는 것**만 남긴다.\r\n *\r\n * `touched` 는 훅이 준 절대경로다. 루트를 붙여 절대경로로 맞춘 뒤 비교한다 —\r\n * 반대로 touched 를 상대경로로 줄이면 루트 밖의 파일(다른 저장소·임시 폴더)이 조용히\r\n * 같은 이름에 걸린다.\r\n *\r\n * **빈 목록이면 그대로 돌려준다** = 필터를 걸 근거가 없다는 뜻(훅이 없는 에이전트, 아직 아무것도\r\n * 안 고친 세션). 이때 빈 화면을 보여 주면 \"변경이 없다\" 는 거짓말이 된다.\r\n */\r\nfunction filterTouched(items, pathOf, root, touched) {\r\n const list = items !== null && items !== void 0 ? items : [];\r\n if (!touched || !touched.length) {\r\n return [...list];\r\n }\r\n const want = new Set(touched.map(t => pathKey(t)));\r\n return list.filter(item => want.has(pathKey(joinRefPath(root, pathOf(item)))));\r\n}\r\nexports.filterTouched = filterTouched;\r\n/**\r\n * `git status --porcelain` 에서 추적되지 않는 파일(`??`)의 경로만 뽑는다.\r\n *\r\n * 내용 diff 는 하지 않는다 — 새로 만든 파일은 전부 추가줄이라 diff 를 붙여도 정보가 없고,\r\n * 에이전트가 만든 큰 산출물(로그·이미지)이 그대로 딸려 들어와 패널이 굳는다.\r\n */\r\nfunction parseUntracked(text) {\r\n const out = [];\r\n for (const raw of String(text !== null && text !== void 0 ? text : '').replace(/\\r\\n?/g, '\\n').split('\\n')) {\r\n if (!raw.startsWith('?? ')) {\r\n continue;\r\n }\r\n const p = unquotePath(raw.slice(3));\r\n if (p) {\r\n out.push(p);\r\n }\r\n }\r\n return out;\r\n}\r\nexports.parseUntracked = parseUntracked;\r\n","\"use strict\";\r\n/**\r\n * 사이드바를 프로젝트 단위로 묶는 순수 규칙 — DOM·tabby·fs 에 기대지 않아 단위 테스트가 된다.\r\n *\r\n * 탭이 열 개를 넘으면 평면 목록에서는 어느 프로젝트의 세션인지 눈으로 가릴 수 없다. 그래서\r\n * **탭이 태어난 작업 폴더(cwd)** 로 묶는다 — 에이전트 CLI 는 \"어느 폴더에서 떴는가\" 가 곧\r\n * 작업 대상이고(`config.ts` rootProfile 주석), `getWorkingDirectory()` 는 셸의 `cd` 를\r\n * 따라오지 않아 사실상 \"탭이 태어난 폴더\" 를 준다(docs/DEVELOPMENT.md 0.5.0 실측).\r\n * 즉 이 값은 세션이 사는 동안 안 바뀌는 = 그룹 키로 쓸 만한 유일한 값이다.\r\n *\r\n * 이 모듈은 **여전히 fs 를 모른다.** 프로젝트 경계(저장소 루트)를 실제로 찾는 것은\r\n * `project-root.ts` 이고, 여기는 호출부가 넘긴 `rootOf` 조회 함수를 부를 뿐이다 —\r\n * 경계를 알아내려고 여기서 `.git` 을 찾기 시작하면 렌더마다 디스크를 때리게 된다\r\n * (렌더는 초당 여러 번 불린다 — deck.service `scheduleRender`).\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.resolveGroupCollapseFor = exports.resolveGroupCollapse = exports.isStoredCollapsed = exports.collapseIdOf = exports.UNGROUPED_COLLAPSE_KEY = exports.groupTabs = exports.groupLabelOf = exports.parentPath = exports.groupKeyOf = exports.foldGroupKey = exports.normalizeCwd = exports.UNGROUPED_LABEL = void 0;\r\n/** cwd 를 모르는 탭들이 모이는 그룹의 이름 (Welcome 탭·조회 실패) */\r\nexports.UNGROUPED_LABEL = '기타';\r\n/**\r\n * 경로를 비교 가능한 꼴로 — 구분자는 `/` 하나, 중복 슬래시 축약, 끝 슬래시 제거.\r\n *\r\n * 대소문자는 **일부러 안 건드린다.** 라벨에 원문 대소문자(`Root` 를 `root` 로 만들지 않게)를\r\n * 살려야 하기 때문이고, 같은 폴더인지 볼 때만 `foldGroupKey` 를 통과시킨다.\r\n * 값이 없거나 공백뿐이면 null — 호출부에서 \"cwd 모름\" 과 같게 취급된다.\r\n */\r\nfunction normalizeCwd(cwd) {\r\n if (typeof cwd !== 'string') {\r\n return null;\r\n }\r\n let p = cwd.trim();\r\n if (!p) {\r\n return null;\r\n }\r\n p = p.replace(/\\\\/g, '/');\r\n // UNC(`//server/share`) 의 앞 두 슬래시는 의미가 있으므로 축약한 뒤 되살린다\r\n const unc = p.startsWith('//');\r\n p = p.replace(/\\/{2,}/g, '/');\r\n if (unc) {\r\n p = '/' + p;\r\n }\r\n // 끝 슬래시 제거 — 단 루트 자체(`/`, `C:/`)는 더 줄일 것이 없으므로 남긴다\r\n while (p.length > 1 && p.endsWith('/') && !/^[A-Za-z]:\\/$/.test(p)) {\r\n p = p.slice(0, -1);\r\n }\r\n return p;\r\n}\r\nexports.normalizeCwd = normalizeCwd;\r\n/**\r\n * 그룹 동일성 판정용 접기.\r\n *\r\n * Windows 는 경로 대소문자를 무시한다 — `D:\\Project` 와 `d:\\project` 는 같은 폴더다.\r\n * 이걸 안 접으면 같은 프로젝트가 두 그룹으로 갈려 기능 자체가 무의미해진다.\r\n * 설정에 저장한 접힘 목록을 맞출 때도 이걸 통과시켜야 한다 — 셸이 알려주는 경로의\r\n * 대소문자는 기동마다 다를 수 있는데 접힘은 유지돼야 하기 때문이다.\r\n */\r\nfunction foldGroupKey(key) {\r\n return (key !== null && key !== void 0 ? key : '').toLowerCase();\r\n}\r\nexports.foldGroupKey = foldGroupKey;\r\n/** 경로를 \"더 못 쪼개는 접두 + 조각들\" 로 — 접두는 `C:` / `//server/share` / POSIX 는 빈 문자열 */\r\nfunction splitPath(p) {\r\n var _a;\r\n // UNC 는 `//server/share` 까지가 한 덩어리다 (호스트만 떼면 경로가 아니다)\r\n const unc = /^\\/\\/([^/]+)\\/([^/]+)(.*)$/.exec(p);\r\n if (unc) {\r\n return { prefix: '//' + unc[1] + '/' + unc[2], abs: true, segs: segsOf(unc[3]) };\r\n }\r\n const drive = /^([A-Za-z]:)(\\/.*)?$/.exec(p);\r\n if (drive) {\r\n return { prefix: drive[1], abs: true, segs: segsOf((_a = drive[2]) !== null && _a !== void 0 ? _a : '') };\r\n }\r\n return { prefix: '', abs: p.startsWith('/'), segs: segsOf(p) };\r\n}\r\nfunction segsOf(rest) {\r\n return rest.split('/').filter(s => s.length > 0);\r\n}\r\nfunction joinPath(s, segs) {\r\n if (!segs.length) {\r\n // 루트 자체 — 드라이브는 `C:/` 로 되돌린다(`normalizeCwd` 가 남기는 꼴과 같아야\r\n // 같은 폴더가 `C:` 와 `C:/` 두 값으로 갈리지 않는다). UNC 공유 루트는 그대로, POSIX 는 `/`\r\n if (/^[A-Za-z]:$/.test(s.prefix)) {\r\n return s.prefix + '/';\r\n }\r\n return s.prefix || (s.abs ? '/' : '');\r\n }\r\n return s.prefix + (s.abs ? '/' : '') + segs.join('/');\r\n}\r\nfunction sameSegs(a, b) {\r\n return a.length === b.length && a.every((s, i) => foldGroupKey(s) === foldGroupKey(b[i]));\r\n}\r\n/** b 의 조각들로 시작하나 (대소문자 무시) */\r\nfunction startsWithSegs(segs, prefix) {\r\n return segs.length >= prefix.length && sameSegs(segs.slice(0, prefix.length), prefix);\r\n}\r\n/**\r\n * cwd 를 그룹 키로 — 없으면 null(그룹 없음).\r\n *\r\n * cwd 를 그대로 키로 쓰면 `D:\\Project\\a\\sub` 에서 띄운 탭과 `D:\\Project\\a` 에서 띄운 탭이\r\n * 다른 그룹으로 갈린다(에이전트를 서브폴더에서 띄우는 건 흔하다). 그래서 **그 폴더가 속한\r\n * 프로젝트 루트**를 키로 삼는다 — 루트는 `rootOf` 가 알려주고(보통 `.git` 이 있는 폴더),\r\n * 모르면 cwd 자체가 키다(예전 동작 그대로).\r\n *\r\n * `rootOf` 가 준 값이 cwd 의 조상이 아니면 **버린다.** 엉뚱한 값 하나가 상관없는 탭들을\r\n * 한 그룹으로 빨아들이는 것이 \"안 묶임\" 보다 훨씬 나쁘기 때문이다.\r\n */\r\nfunction groupKeyOf(cwd, rootOf) {\r\n const p = normalizeCwd(cwd);\r\n if (!p) {\r\n return null;\r\n }\r\n const root = rootOf ? normalizeCwd(rootOf(p)) : null;\r\n if (!root) {\r\n return p;\r\n }\r\n const pp = splitPath(p);\r\n const rp = splitPath(root);\r\n if (foldGroupKey(rp.prefix) === foldGroupKey(pp.prefix) && startsWithSegs(pp.segs, rp.segs)) {\r\n return root;\r\n }\r\n return p;\r\n}\r\nexports.groupKeyOf = groupKeyOf;\r\n/**\r\n * 한 단계 위 폴더 — 더 올라갈 데가 없으면 null.\r\n *\r\n * `project-root.ts` 가 마커를 찾아 올라갈 때 쓴다. 여기 두는 이유는 드라이브(`C:/`)·UNC\r\n * (`//server/share`) 경계를 아는 것이 `splitPath` 뿐이라서다 — `path.dirname` 은 UNC 공유\r\n * 루트에서 호스트만 남기는 등 경로가 아닌 값을 만든다.\r\n */\r\nfunction parentPath(p) {\r\n const norm = normalizeCwd(p);\r\n if (!norm) {\r\n return null;\r\n }\r\n const s = splitPath(norm);\r\n if (!s.segs.length) {\r\n return null;\r\n }\r\n return joinPath(s, s.segs.slice(0, -1));\r\n}\r\nexports.parentPath = parentPath;\r\n/**\r\n * 그룹에 붙일 짧은 이름 — 경로 마지막 조각. 다른 그룹과 겹치면 상위를 한 단계씩 더 붙인다.\r\n *\r\n * 사이드바는 200~560px 라(config `sidebarMin`/`sidebarMax`) 전체 경로를 그리면 말줄임으로\r\n * 뭉개진다. 그래도 `…/work/agent` 와 `…/temp/agent` 를 둘 다 `agent` 로 적으면 그룹을\r\n * 구분할 수 없으므로, 겹치는 동안만 위로 올라간다. 끝까지 겹치면 정규화한 전체 경로.\r\n */\r\nfunction groupLabelOf(key, allKeys) {\r\n const norm = normalizeCwd(key);\r\n if (!norm) {\r\n return exports.UNGROUPED_LABEL;\r\n }\r\n const segs = splitPath(norm).segs;\r\n if (!segs.length) {\r\n // 드라이브 루트(`C:/`)·UNC 공유 루트 — 더 짧게 만들 조각이 없다\r\n return norm;\r\n }\r\n const others = [];\r\n for (const k of allKeys) {\r\n const n = normalizeCwd(k);\r\n if (n && foldGroupKey(n) !== foldGroupKey(norm)) {\r\n others.push(splitPath(n).segs);\r\n }\r\n }\r\n for (let depth = 1; depth <= segs.length; depth++) {\r\n const tail = segs.slice(-depth);\r\n const collide = others.some(o => o.length >= depth && sameSegs(o.slice(-depth), tail));\r\n if (!collide) {\r\n return tail.join('/');\r\n }\r\n }\r\n return norm;\r\n}\r\nexports.groupLabelOf = groupLabelOf;\r\n/** 라벨 사전순(대소문자 무시). 같으면 키로 가른다 — 로케일에 안 기대는 코드포인트 비교라 어디서나 같은 순서다 */\r\nfunction compareGroups(a, b) {\r\n const la = a.label.toLowerCase();\r\n const lb = b.label.toLowerCase();\r\n if (la !== lb) {\r\n return la < lb ? -1 : 1;\r\n }\r\n const ka = foldGroupKey(a.key);\r\n const kb = foldGroupKey(b.key);\r\n return ka === kb ? 0 : (ka < kb ? -1 : 1);\r\n}\r\n/**\r\n * 탭을 그룹으로 묶는다.\r\n *\r\n * 두 순서를 서로 다르게 정한다 —\r\n * - **그룹 순서**: 라벨 사전순, cwd 를 모르는 그룹(`key: null`)은 맨 아래. 프로젝트 목록은\r\n * 자주 안 바뀌므로 눈이 자리를 기억하는 편이 낫고, 상태로 정렬하면 그룹이 매초 뛴다.\r\n * - **그룹 안의 탭 순서**: 넘어온 순서 그대로. 호출부가 `sortByStatus` 를 이미 적용해\r\n * 넘길 수 있기 때문이다(`order.ts` 의 `sortTabsByStatus` 도 같은 성질을 지킨다).\r\n *\r\n * 반환 길이가 1 이면 호출부는 그룹 헤더를 생략한다 — 단일 프로젝트에서 세로 공간을 낭비하지 않게.\r\n * 비용은 탭 수만큼의 맵 조작 + 그룹 수²의 라벨 대조뿐이라 렌더마다 불러도 된다.\r\n */\r\nfunction groupTabs(tabs, cwdOf, rootOf) {\r\n const order = [];\r\n const byFold = new Map();\r\n const ungrouped = [];\r\n for (const tab of tabs) {\r\n const key = groupKeyOf(cwdOf(tab), rootOf);\r\n if (!key) {\r\n ungrouped.push(tab);\r\n continue;\r\n }\r\n const fold = foldGroupKey(key);\r\n let hit = byFold.get(fold);\r\n if (!hit) {\r\n // 대소문자만 다른 경로는 같은 그룹으로 합치고, 표기는 먼저 온 탭의 것을 쓴다\r\n hit = { key, tabs: [] };\r\n byFold.set(fold, hit);\r\n order.push(fold);\r\n }\r\n hit.tabs.push(tab);\r\n }\r\n const keys = order.map(f => byFold.get(f).key);\r\n const out = order.map(f => {\r\n const hit = byFold.get(f);\r\n return { key: hit.key, label: groupLabelOf(hit.key, keys), tabs: hit.tabs };\r\n });\r\n out.sort(compareGroups);\r\n if (ungrouped.length) {\r\n out.push({ key: null, label: exports.UNGROUPED_LABEL, tabs: ungrouped });\r\n }\r\n return out;\r\n}\r\nexports.groupTabs = groupTabs;\r\n/**\r\n * 접힘 상태를 설정(`collapsedGroups`)에 적을 때 쓰는 id.\r\n *\r\n * cwd 를 모르는 그룹(`key === null`, 라벨 `기타`)도 접을 수 있어야 하는데 그 그룹에는 경로\r\n * 키가 없다. 그래서 경로일 수 없는 이 토큰을 대신 쓴다 — 실제 그룹 키는 정규화된 경로뿐이라\r\n * 괄호로 시작하는 값과는 겹칠 수 없다.\r\n *\r\n * `deck.service.ts` 의 private `UNGROUPED_KEY` 와 **같은 값이어야 한다**(deck.service.ts:134).\r\n * 이미 그 값으로 설정에 적힌 접힘이 있어서, 바꾸면 사용자가 접어 둔 그룹이 조용히 펴진다.\r\n */\r\nexports.UNGROUPED_COLLAPSE_KEY = '(ungrouped)';\r\n/**\r\n * 그룹 키 → 설정에 적는 접힘 id. **쓸 때도 읽을 때도** 이걸 통과시켜야 한다.\r\n *\r\n * 폴딩(`foldGroupKey`)을 빼먹으면 셸이 기동마다 다른 대소문자로 cwd 를 알려줄 때 접힘이\r\n * 풀린다(회귀 `GR8`·`GR9` 가 그 성질을 고정한다). `null` 은 `기타` 그룹이라 위 토큰이 된다.\r\n */\r\nfunction collapseIdOf(key) {\r\n return foldGroupKey(key !== null && key !== void 0 ? key : exports.UNGROUPED_COLLAPSE_KEY);\r\n}\r\nexports.collapseIdOf = collapseIdOf;\r\n/**\r\n * 설정에 남은 접힘 목록에 이 그룹이 있나 — **저장된 사용자 의도**를 읽는 유일한 창구.\r\n *\r\n * 저장값은 사람이 손으로 고칠 수 있는 config.yaml 이라 무엇이든 들어올 수 있다. 배열이\r\n * 아니거나 비어 있으면 \"접힌 것 없음\" 이고, 원소는 문자열로 만든 뒤 폴딩해서 비교한다\r\n * (`deck.service.ts` `collapsedKeys` 와 같은 처리).\r\n */\r\nfunction isStoredCollapsed(key, stored) {\r\n if (!Array.isArray(stored)) {\r\n return false;\r\n }\r\n const id = collapseIdOf(key);\r\n return stored.some(k => k !== null && k !== undefined && foldGroupKey(String(k)) === id);\r\n}\r\nexports.isStoredCollapsed = isStoredCollapsed;\r\n/**\r\n * 접힘의 **최종 판정** — 저장된 접힘 + 필터 상태 + 그 그룹의 매칭 수로 정한다.\r\n *\r\n * 왜 이 함수가 있나 — 그룹이 여럿이고 그중 접힌 그룹에만 검색어가 걸리면, 줄은 안 그려지고\r\n * 헤더의 개수 칩만 남는다. 사용자는 \"검색했는데 아무것도 안 나온다\" 로 읽는데 실제로는\r\n * 접힌 그룹 안에 있다. 이 규칙을 렌더에 직접 적으면 진단구(`groups()`)와 사본이 갈리므로\r\n * (그 사본 문제가 `renderPlan()` 을 뽑은 이유다) 판정은 여기 하나만 둔다.\r\n *\r\n * **세 안을 비교하고 ②를 골랐다.**\r\n * ① 검색 중에는 접힘을 통째로 무시(다 펴 보인다) — 결과는 지금 배선에서 ②와 같다\r\n * (`renderPlan` 이 그룹을 `visible` 로 만들므로 매칭 0인 그룹은 애초에 목록에 없다).\r\n * 그래도 규칙으로는 버렸다: \"매칭이 없는데도 펴진다\" 를 허용하는 문장이라, 나중에 빈\r\n * 그룹까지 헤더로 보여주는 화면이 생기면 아무 이유 없이 다 펴진다.\r\n * ② **매칭이 있는 접힌 그룹만 임시로 펴진다** ← 채택. 좁아진 이유가 화면에 보이고\r\n * (`renderEmpty` 가 0건을 한 줄로 알리는 것과 같은 계열), 저장값은 건드리지 않으므로\r\n * 필터를 지우면 저장된 접힘으로 **정확히** 돌아온다. 판정에 매칭 수가 들어가 있어\r\n * \"왜 펴졌나\" 를 `reason` 으로 되읽을 수 있다.\r\n * ③ 접힌 채 두고 헤더에 \"안에 N개 걸렸다\" 를 표시 — 버렸다. 개수 칩은 **전체 기준**이라는\r\n * 성질을 회귀 `GR11` 이 고정하고 있어서(접어도 총계가 줄지 않는다) 같은 자리에 매칭 수를\r\n * 넣으면 그 성질과 부딪히고, 칩을 하나 더 두더라도 200px 사이드바(`sidebarMin`)에\r\n * 자리가 없다. 무엇보다 사용자가 헤더를 눌러야 결과를 보게 되는데, 검색은 \"치면 바로\r\n * 보이는 것\" 이라 왕복이 하나 늘면 검색창의 의미가 준다.\r\n *\r\n * **이 함수는 설정을 바꾸지 않는다** — 임시로 펴 보이는 것과 접힘을 푸는 것은 다른 일이다.\r\n * 접힘을 실제로 푸는 길은 헤더 클릭(`toggleGroup`) 하나뿐이어야 한다. 그래서 반환값은\r\n * 매번 입력만으로 계산되고, 임시 상태를 어디에도 남기지 않는다(필터를 지우면 같은 입력이\r\n * 되어 저장된 접힘이 그대로 나온다).\r\n *\r\n * 상태 필터만 걸린 경우(검색어는 비었다)도 **같게 다룬다.** 칩 `⏸ 2` 를 눌렀는데 그 두 탭이\r\n * 접힌 그룹에 있으면 \"대기 중인 게 없다\" 로 읽히는 것은 검색어일 때와 똑같은 오독이다.\r\n * 그래서 입력은 검색어가 아니라 `filtering`(검색어 OR 상태 필터) 하나로 받는다.\r\n */\r\nfunction resolveGroupCollapse(input) {\r\n if (!input.stored) {\r\n // 저장된 접힘이 없으면 필터와 무관하게 펴진 그룹이다 (필터가 접는 일은 없다)\r\n return { collapsed: false, reason: 'open' };\r\n }\r\n const raw = input.matches;\r\n const matches = typeof raw === 'number' && isFinite(raw) && raw > 0 ? Math.floor(raw) : 0;\r\n if (input.filtering && matches > 0) {\r\n return { collapsed: false, reason: 'filter-open' };\r\n }\r\n // 필터가 없거나, 있어도 이 그룹에 걸린 것이 없으면 저장된 접힘 그대로 — 보여줄 것이 없다\r\n return { collapsed: true, reason: 'stored' };\r\n}\r\nexports.resolveGroupCollapse = resolveGroupCollapse;\r\n/**\r\n * `resolveGroupCollapse` 를 그룹 하나에 바로 먹인다 — 렌더가 매칭 수를 다시 세지 않게.\r\n *\r\n * 필터가 걸린 화면에서 `group.tabs` 는 **이미 필터를 통과한 탭들**이다\r\n * (`deck.service.ts renderPlan()` 이 `groupsFor(visible)` 로 그룹을 만든다). 그래서\r\n * `tabs.length` 가 곧 이 그룹의 매칭 수다. 필터가 없으면 그 값은 쓰이지 않는다.\r\n *\r\n * 헤더 자체를 안 그리는 화면(그룹 1개 = `withHeads === false`)에서는 접힘을 적용하지 않는다는\r\n * 규칙은 그대로 호출부에 있다 — `withHeads && collapsed` 조합을 유지할 것.\r\n */\r\nfunction resolveGroupCollapseFor(group, stored, filtering) {\r\n return resolveGroupCollapse({\r\n stored: isStoredCollapsed(group.key, stored),\r\n filtering,\r\n matches: group.tabs.length,\r\n });\r\n}\r\nexports.resolveGroupCollapseFor = resolveGroupCollapseFor;\r\n","\"use strict\";\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckHotkeyProvider = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\n/**\r\n * 핫키 \"선언\"만 한다.\r\n *\r\n * 여기서 HotkeysService 를 주입하면 안 된다 — HotkeysService 자신이\r\n * HotkeyProvider 목록을 주입받으므로(tabby-core/src/services/hotkeys.service.ts:85)\r\n * 순환 의존이 되어 부분 초기화된 인스턴스가 넘어온다.\r\n * 실제 핫키 처리는 AgentDeckService 에서 구독한다.\r\n */\r\nlet AgentDeckHotkeyProvider = class AgentDeckHotkeyProvider extends tabby_core_1.HotkeyProvider {\r\n async provide() {\r\n return [\r\n {\r\n id: 'agentdeck-toggle',\r\n name: 'AgentDeck 사이드바 / 4:3 전환',\r\n },\r\n {\r\n id: 'agentdeck-newline',\r\n name: 'AgentDeck 줄바꿈 (Ctrl+Enter / Shift+Enter, 0x0A 전송)',\r\n },\r\n {\r\n id: 'agentdeck-paste',\r\n name: 'AgentDeck 붙여넣기 (텍스트는 그대로, 이미지는 Alt+V 로 위임)',\r\n },\r\n {\r\n id: 'agentdeck-repair',\r\n name: 'AgentDeck 화면 복구 (깨진 TUI 다시 그리기)',\r\n },\r\n {\r\n id: 'agentdeck-view',\r\n name: 'AgentDeck 미리보기 패널 (md · 이미지 · 표)',\r\n },\r\n {\r\n // 처리는 AgentDeckService 의 `hotkey$` 구독에서 `view?.toggleMode()` 로 잇는다\r\n // (여기서 HotkeysService 를 주입하면 순환 의존 — 위 주석 참고)\r\n id: 'agentdeck-view-mode',\r\n name: 'AgentDeck 미리보기 파일 / 변경 전환',\r\n },\r\n {\r\n // 사이드바를 마우스 없이 다루기 위한 **유일한 진입점**이다. 목록은 tabindex=-1 이라\r\n // 터미널에서 Tab 으로 넘어올 수 없고(에이전트 CLI 가 Tab 을 자기 것으로 쓴다),\r\n // 검색창 포커스로 갈음할 수도 없다 — 검색 줄은 끌 수 있는 기능이다(`searchBox`).\r\n // 처리는 AgentDeckService 의 `hotkey$` 구독 → `toggleKeyboardNav()`.\r\n id: 'agentdeck-focus-list',\r\n name: 'AgentDeck 사이드바 목록에 포커스 (↑↓ 이동 · Enter 전환 · Esc 복귀)',\r\n },\r\n ];\r\n }\r\n};\r\nAgentDeckHotkeyProvider = __decorate([\r\n (0, core_1.Injectable)()\r\n], AgentDeckHotkeyProvider);\r\nexports.AgentDeckHotkeyProvider = AgentDeckHotkeyProvider;\r\n","\"use strict\";\r\n/**\r\n * 한글 조합 중에 우리가 PTY 로 바이트를 써도 되는 시점인지 가른다.\r\n *\r\n * 증상: 조합 중인 마지막 음절이 **커서를 따라간다.** Home/End 를 누르면 그 음절이 옮겨간\r\n * 자리에 찍히고, Shift+Enter 를 누르면 새 줄로 따라간다 (2026-09-08 사용자 재보고).\r\n * 방향키(←→)만 멀쩡한데, 그 차이가 곧 원인이다.\r\n *\r\n * xterm 의 조합 확정에는 **동기·비동기 두 경로**가 있다\r\n * (`node_modules/tabby-terminal/dist/index.js:44087~44121`, CompositionHelper):\r\n *\r\n * keydown(t) → 조합 중이면 `_finalizeComposition(false)` = **지금 바로** triggerDataEvent\r\n * compositionend() → `_finalizeComposition(true)` = `setTimeout(…, 0)` 에서 triggerDataEvent\r\n *\r\n * 방향키는 xterm 의 키 경로를 타므로 `keydown()` 이 먼저 동기 확정을 하고 그 뒤에 키를 보낸다 —\r\n * 글자 먼저, 이동 나중이라 순서가 맞는다. 반대로 **xterm 을 거치지 않고 pty 에 직접 쓰는 경로**\r\n * (Tabby 핫키의 `sendInput('\\x1b[H')`, 우리 `sendNewline()` 의 `sendInput('\\n')`)는 동기 확정을\r\n * 트리거하지 않는다. 확정이 `compositionend` 의 setTimeout 으로 밀리는 동안\r\n * (`_isSendingComposition === true`) 우리 바이트가 먼저 나가고 음절이 한 틱 뒤에 붙는다.\r\n *\r\n * 0.3.0 에서 Home/End 를 핫키에서 놓아준 것(`releaseHomeEndHotkey`)만으로는 부족했다 —\r\n * 실사용 `%APPDATA%\\tabby\\config.yaml:71-72` 가 `home: []` / `end: []` 인데도 재발했다.\r\n * 그래서 한 겹 더 내려가, **바이트를 쓰기 직전에 조합 상태를 보고 순서를 맞춘다.**\r\n *\r\n * 여기는 순수 로직만 둔다(테스트로 고정). DOM·xterm 접근은 인자로 받은 객체로만 한다 —\r\n * `screen.ts` / `prompt.ts` 와 같은 관례다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.flushComposition = exports.planSend = exports.readCompositionState = void 0;\r\n/**\r\n * 조합 헬퍼의 **살아있는 상태**를 읽는다.\r\n *\r\n * 키보드 이벤트의 `isComposing` / 수식키 필드를 믿으면 안 된다 — 한글 IME 가 조합을 확정하며\r\n * 이벤트를 한 번 삼키고 뒤이어 내보내는 이벤트에는 상태를 싣지 않는다\r\n * (2026-09-08 실측: Shift+Enter 의 Enter 가 `shiftKey=false` 로 도착, `claimShiftEnterKey` 주석).\r\n * 그래서 판정 근거는 이벤트가 아니라 헬퍼가 지금 들고 있는 값이다.\r\n */\r\nfunction readCompositionState(helper) {\r\n if (!helper || typeof helper !== 'object') {\r\n return 'unknown';\r\n }\r\n try {\r\n // `isComposing` 은 getter(`get isComposing() { return this._isComposing }`)라 읽기만 해도\r\n // 던질 수 있는 자리다 — 전체를 try 로 감싼다.\r\n if (helper.isComposing === true) {\r\n return 'composing';\r\n }\r\n // 조합은 끝났는데 확정 텍스트가 아직 setTimeout 대기 중이다 — 이 틈이 버그의 정체다\r\n if (helper._isSendingComposition === true) {\r\n return 'pending';\r\n }\r\n // 두 필드 중 하나라도 실제 boolean 으로 읽혔다면 \"조합 아님\" 을 확인한 것이다\r\n if (typeof helper.isComposing === 'boolean' || typeof helper._isSendingComposition === 'boolean') {\r\n return 'idle';\r\n }\r\n }\r\n catch {\r\n return 'unknown';\r\n }\r\n // 필드가 둘 다 없다 = xterm 내부가 바뀌었다. 아무것도 단정하지 않는다\r\n return 'unknown';\r\n}\r\nexports.readCompositionState = readCompositionState;\r\n/**\r\n * 그 상태에서 우리 바이트를 언제 보내야 하나.\r\n *\r\n * `unknown` 이 `now` 인 것이 중요하다 — 이 훅은 순서를 맞추려고 얹은 것이고, 상태를 못 읽었을 때\r\n * 정상 입력을 막아서는 절대 안 된다. 못 읽으면 0.4.0 까지의 동작 그대로 간다.\r\n */\r\nfunction planSend(state) {\r\n if (state === 'composing') {\r\n // **조합이 끝날 때까지 기다린다.**\r\n //\r\n // 0.5.0 은 여기서 `flush-then-now`(동기 확정시키고 바로 쓰기)를 했는데 그것만으로는\r\n // 부족했다 — 우리가 확정시켜도 **IME 는 자기 일정대로 `compositionend` 를 또 쏘고**,\r\n // xterm 이 그때 비동기 경로로 음절을 한 번 더 보낸다(`_finalizeComposition(true)`).\r\n // 그 두 번째 전송이 우리 개행 뒤에 나가면 **음절이 새 줄로 내려간다** — 사용자가\r\n // 신고한 그 증상이다 (2026-09-08: 하네스에서 `한` → `ESC[H` → `한` 순서로 실측).\r\n //\r\n // 그래서 확정을 재촉하지 않고 IME 의 생애주기를 그대로 둔다. 음절은 자기 경로로\r\n // 한 번만 나가고, 우리 바이트는 그 뒤에 붙는다.\r\n return 'after-composition';\r\n }\r\n if (state === 'pending') {\r\n // 예약된 전송을 앞당길 방법이 없으므로 **우리가 뒤로 물러난다.**\r\n // 같은 setTimeout(…, 0) 큐의 뒤에 붙으므로 음절이 먼저 나간다.\r\n return 'defer';\r\n }\r\n return 'now';\r\n}\r\nexports.planSend = planSend;\r\n/**\r\n * 조합을 **동기 확정**시킨다. 성공하면 true.\r\n *\r\n * 왜 `keydown()` 인가 — 실제로 확정하는 것은 `_finalizeComposition(false)` 지만 그건 private 이고\r\n * 최소화 빌드에서 이름이 바뀔 수 있다. `keydown` 은 xterm 코어가 밖에서 부르는 공개 표면이라\r\n * (`tabby-terminal/dist/index.js:50225` `this._compositionHelper.keydown(e)`) 최소화를 넘어 살아남는다.\r\n * 조합 중에 아무 키나 들어오면 동기 확정한다는 성질이 곧 방향키가 멀쩡한 이유이므로,\r\n * **방향키가 하는 일을 그대로 흉내내는 것**이 가장 안전하다.\r\n *\r\n * `keyCode: 0` 을 쓰는 이유 — 20(한/영)·229(IME)·16/17/18(Shift/Ctrl/Alt)은 헬퍼가 확정 없이\r\n * 빠져나가는 값이고, 229 는 `_handleAnyTextareaChanges()` 까지 부른다. 0 은 그 어느 것도 아니다.\r\n *\r\n * 낡은 `end` 보정 — 동기 경로는\r\n * `value.substring(_compositionPosition.start, _compositionPosition.end)` 를 보내는데, `end` 는\r\n * `compositionupdate` 의 `setTimeout(…, 0)` 에서만 갱신된다(`index.js:44092`). 첫 음절을 치고\r\n * 바로 Home 을 누르면 `end` 가 아직 0(또는 start 이하)이라 **빈 문자열이 나가 음절이 통째로\r\n * 유실된다.** 그래서 확정 직전에 `textarea.value.length` 로 메워 준다.\r\n *\r\n * @param textLength `xterm.textarea.value.length` — 낡은 `end` 를 메울 값\r\n */\r\nfunction flushComposition(helper, textLength) {\r\n if (!helper || typeof helper.keydown !== 'function') {\r\n return false;\r\n }\r\n try {\r\n const pos = helper._compositionPosition;\r\n if (pos\r\n && typeof pos.start === 'number'\r\n && typeof pos.end === 'number'\r\n && pos.end <= pos.start\r\n && typeof textLength === 'number'\r\n && isFinite(textLength)\r\n && textLength > pos.start) {\r\n pos.end = textLength;\r\n }\r\n helper.keydown({ keyCode: 0 });\r\n return true;\r\n }\r\n catch {\r\n // xterm 내부가 바뀌었다 — 확정을 못 했다고만 알리고 예외는 밖으로 내보내지 않는다\r\n return false;\r\n }\r\n}\r\nexports.flushComposition = flushComposition;\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nvar __exportStar = (this && this.__exportStar) || function(m, exports) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nconst core_1 = require(\"@angular/core\");\r\nconst common_1 = require(\"@angular/common\");\r\nconst forms_1 = require(\"@angular/forms\");\r\nconst tabby_core_1 = __importStar(require(\"tabby-core\"));\r\nconst tabby_settings_1 = require(\"tabby-settings\");\r\nconst tabby_terminal_1 = require(\"tabby-terminal\");\r\nconst config_1 = require(\"./config\");\r\nconst hotkeys_1 = require(\"./hotkeys\");\r\nconst decorator_1 = require(\"./decorator\");\r\nconst deck_service_1 = require(\"./deck.service\");\r\nconst profile_service_1 = require(\"./profile.service\");\r\nconst notify_service_1 = require(\"./notify.service\");\r\nconst alert_service_1 = require(\"./alert.service\");\r\nconst recovery_service_1 = require(\"./recovery.service\");\r\nconst update_service_1 = require(\"./update.service\");\r\nconst settings_1 = require(\"./settings\");\r\nconst settings_component_1 = require(\"./settings.component\");\r\nrequire(\"./styles.scss\");\r\n__exportStar(require(\"./api\"), exports);\r\nlet AgentDeckModule = class AgentDeckModule {\r\n constructor(deck, profiles, notify, alert, recovery, update) {\r\n // 여섯 서비스 모두 app.ready$ 를 기다렸다가 스스로 붙는다.\r\n // alert 는 deck 이 만드는 `__agentdeck` 에 붙으므로 deck 뒤에 둔다\r\n deck.init();\r\n profiles.init();\r\n notify.init();\r\n alert.init();\r\n recovery.init();\r\n // 자동 업데이트는 기동 20초 뒤에 한 번 움직인다 — 창이 뜨는 순간에 네트워크를 건드리지 않는다\r\n update.init();\r\n }\r\n};\r\nAgentDeckModule = __decorate([\r\n (0, core_1.NgModule)({\r\n imports: [\r\n common_1.CommonModule,\r\n // 설정 탭이 [(ngModel)] 로 config.store 를 직접 물고 있어서 필요하다\r\n forms_1.FormsModule,\r\n tabby_core_1.default,\r\n ],\r\n providers: [\r\n { provide: tabby_core_1.ConfigProvider, useClass: config_1.AgentDeckConfigProvider, multi: true },\r\n { provide: tabby_core_1.HotkeyProvider, useClass: hotkeys_1.AgentDeckHotkeyProvider, multi: true },\r\n { provide: tabby_terminal_1.TerminalDecorator, useClass: decorator_1.AgentDeckDecorator, multi: true },\r\n { provide: tabby_settings_1.SettingsTabProvider, useClass: settings_1.AgentDeckSettingsTabProvider, multi: true },\r\n ],\r\n declarations: [\r\n settings_component_1.AgentDeckSettingsTabComponent,\r\n ],\r\n }),\r\n __metadata(\"design:paramtypes\", [deck_service_1.AgentDeckService,\r\n profile_service_1.AgentDeckProfileService,\r\n notify_service_1.WorkNotifyService,\r\n alert_service_1.AgentDeckAlertService,\r\n recovery_service_1.AgentDeckRecoveryService,\r\n update_service_1.AgentDeckUpdateService])\r\n], AgentDeckModule);\r\nexports.default = AgentDeckModule;\r\n","\"use strict\";\r\n/**\r\n * 미리보기 패널이 쓰는 최소 마크다운 렌더러.\r\n *\r\n * 왜 라이브러리(marked 등)를 안 쓰나 — 이 플러그인은 런타임 의존성이 하나도 없다(package.json\r\n * 은 devDependencies 뿐이고 webpack 이 전부 번들한다). 그 성질을 지키는 값이 크고, 여기서 필요한\r\n * 것은 문서 미리보기 수준의 부분집합이다. 무엇보다 **HTML 을 우리가 전부 만들면 새니타이즈가\r\n * 필요 없다** — Electron 렌더러 안에서 남이 만든 문자열을 innerHTML 에 넣는 것이 이 기능의\r\n * 유일한 보안 위험인데, 원문을 먼저 이스케이프하고 태그는 이쪽에서만 붙이므로 원문에 들어 있는\r\n * `<script>` 나 `onerror=` 는 태그가 될 기회가 없다.\r\n *\r\n * 지원하는 것: 제목 · 문단 · 강조 · 코드(인라인/펜스) · 목록(중첩) · 표 · 인용 · 구분선 ·\r\n * 링크 · 이미지 · 체크박스. 지원하지 않는 것: 원문 HTML(그대로 글자로 보인다) · 참조 링크\r\n * (`[a][1]`) · 각주 · 정의목록.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.renderMarkdown = exports.safeUrl = exports.escapeHtml = void 0;\r\nfunction escapeHtml(s) {\r\n return s\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"');\r\n}\r\nexports.escapeHtml = escapeHtml;\r\n/**\r\n * 링크로 써도 되는 주소인지 본다.\r\n *\r\n * 스킴이 붙어 있으면 http/https/mailto/file 만 통과시킨다 — `javascript:` 와 `data:` 를 막는\r\n * 것이 목적이다. 스킴이 없는 것(상대경로 `./a.md`, 절대경로 `/tmp/a`, 앵커 `#절`)은 그대로 둔다.\r\n * Windows 드라이브 문자(`D:/x`)는 스킴처럼 보이므로 따로 통과시킨다.\r\n */\r\nfunction safeUrl(raw) {\r\n const url = (raw !== null && raw !== void 0 ? raw : '').trim();\r\n if (!url) {\r\n return null;\r\n }\r\n if (/^[A-Za-z]:[\\\\/]/.test(url)) {\r\n return url;\r\n }\r\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(url) && !/^(?:https?|mailto|file):/i.test(url)) {\r\n return null;\r\n }\r\n return url;\r\n}\r\nexports.safeUrl = safeUrl;\r\n/** 인라인 문법 — 블록을 다 가른 뒤 각 줄 안에서 돈다 */\r\nfunction inline(src, opts) {\r\n // 코드 스팬을 먼저 떼어 자리표시자로 바꾼다. 그 안에서는 강조·링크 규칙이 돌면 안 된다\r\n const codes = [];\r\n let text = src.replace(/(`+)([\\s\\S]+?)\\1(?!`)/g, (_m, _ticks, body) => {\r\n codes.push('<code>' + escapeHtml(String(body).replace(/^ | $/g, '')) + '</code>');\r\n return '\\u0000' + (codes.length - 1) + '\\u0000';\r\n });\r\n // 여기서 한 번 이스케이프해 두면 아래 규칙이 붙이는 태그만 태그로 남는다\r\n text = escapeHtml(text);\r\n // 이미지가 링크 문법을 품고 있으므로 이미지를 먼저 본다\r\n text = text.replace(/!\\[([^\\]]*)\\]\\(([^)\\s]+)(?:\\s+"[^&]*")?\\)/g, (_m, alt, target) => {\r\n const resolved = opts.resolveImage ? opts.resolveImage(String(target)) : safeUrl(String(target));\r\n if (!resolved) {\r\n return '<span class=\"ad-md-noimg\">🖼 ' + (alt || target) + '</span>';\r\n }\r\n return '<img src=\"' + resolved + '\" alt=\"' + alt + '\">';\r\n });\r\n text = text.replace(/\\[([^\\]]*)\\]\\(([^)\\s]+)(?:\\s+"[^&]*")?\\)/g, (m, label, target) => {\r\n const url = safeUrl(String(target));\r\n if (!url) {\r\n return String(label);\r\n }\r\n return '<a href=\"' + url + '\" data-ad-link=\"' + url + '\">' + label + '</a>';\r\n });\r\n text = text.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\r\n text = text.replace(/__([^_]+)__/g, '<strong>$1</strong>');\r\n text = text.replace(/(^|[\\s(\\[])\\*([^*\\n]+)\\*/g, '$1<em>$2</em>');\r\n text = text.replace(/(^|[\\s(\\[])_([^_\\n]+)_/g, '$1<em>$2</em>');\r\n text = text.replace(/~~([^~]+)~~/g, '<del>$1</del>');\r\n return text.replace(/\\u0000(\\d+)\\u0000/g, (_m, i) => { var _a; return (_a = codes[Number(i)]) !== null && _a !== void 0 ? _a : ''; });\r\n}\r\n/** 표 구분선인가 — `|---|:--:|` 형태 */\r\nfunction isTableRule(line) {\r\n return /^\\s*\\|?\\s*:?-{2,}:?\\s*(\\|\\s*:?-{2,}:?\\s*)*\\|?\\s*$/.test(line);\r\n}\r\nfunction splitRow(line) {\r\n return line.trim().replace(/^\\|/, '').replace(/\\|$/, '').split('|').map(c => c.trim());\r\n}\r\n/**\r\n * 마크다운 원문을 HTML 로 바꾼다.\r\n *\r\n * 한 번 훑으면서 블록을 가른다 — 상태는 \"지금 펜스 안인가 / 목록 몇 겹인가\" 두 개뿐이다.\r\n */\r\nfunction renderMarkdown(src, opts = {}) {\r\n var _a;\r\n const lines = String(src !== null && src !== void 0 ? src : '').replace(/\\r\\n?/g, '\\n').split('\\n');\r\n const out = [];\r\n const stack = [];\r\n let para = [];\r\n let fence = null;\r\n const closeLists = (toIndent = -1) => {\r\n while (stack.length && stack[stack.length - 1].indent > toIndent) {\r\n out.push(stack.pop().ordered ? '</ol>' : '</ul>');\r\n }\r\n };\r\n const flushPara = () => {\r\n if (para.length) {\r\n out.push('<p>' + inline(para.join('\\n'), opts).replace(/\\n/g, '<br>') + '</p>');\r\n para = [];\r\n }\r\n };\r\n const breakBlocks = () => {\r\n flushPara();\r\n closeLists();\r\n };\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i];\r\n // ---------- 코드 펜스 ----------\r\n if (fence) {\r\n if (new RegExp('^\\\\s*' + fence.mark + '\\\\s*$').test(line)) {\r\n const cls = fence.lang ? ' class=\"ad-md-lang-' + fence.lang.replace(/[^\\w-]/g, '') + '\"' : '';\r\n out.push('<pre' + cls + '><code>' + escapeHtml(fence.body.join('\\n')) + '</code></pre>');\r\n fence = null;\r\n }\r\n else {\r\n fence.body.push(line);\r\n }\r\n continue;\r\n }\r\n const fenceOpen = /^\\s*(```+|~~~+)\\s*([\\w+#.-]*)/.exec(line);\r\n if (fenceOpen) {\r\n breakBlocks();\r\n fence = { mark: fenceOpen[1].slice(0, 3), lang: fenceOpen[2] || '', body: [] };\r\n continue;\r\n }\r\n // ---------- 빈 줄 ----------\r\n if (!line.trim()) {\r\n flushPara();\r\n continue;\r\n }\r\n // ---------- 제목 ----------\r\n const heading = /^(#{1,6})\\s+(.*)$/.exec(line);\r\n if (heading) {\r\n breakBlocks();\r\n const level = heading[1].length;\r\n out.push('<h' + level + '>' + inline(heading[2].replace(/\\s+#+\\s*$/, ''), opts) + '</h' + level + '>');\r\n continue;\r\n }\r\n // ---------- 구분선 ----------\r\n if (/^\\s*([-*_])\\s*(\\1\\s*){2,}$/.test(line)) {\r\n breakBlocks();\r\n out.push('<hr>');\r\n continue;\r\n }\r\n // ---------- 표 ----------\r\n if (line.includes('|') && i + 1 < lines.length && isTableRule(lines[i + 1])) {\r\n breakBlocks();\r\n const head = splitRow(line);\r\n const rows = [];\r\n let j = i + 2;\r\n for (; j < lines.length && lines[j].includes('|') && lines[j].trim(); j++) {\r\n rows.push(splitRow(lines[j]));\r\n }\r\n i = j - 1;\r\n out.push('<table><thead><tr>'\r\n + head.map(c => '<th>' + inline(c, opts) + '</th>').join('')\r\n + '</tr></thead><tbody>'\r\n + rows.map(r => '<tr>' + r.map(c => '<td>' + inline(c, opts) + '</td>').join('') + '</tr>').join('')\r\n + '</tbody></table>');\r\n continue;\r\n }\r\n // ---------- 인용 ----------\r\n const quote = /^\\s*>\\s?(.*)$/.exec(line);\r\n if (quote) {\r\n breakBlocks();\r\n const body = [quote[1]];\r\n let j = i + 1;\r\n for (; j < lines.length; j++) {\r\n const more = /^\\s*>\\s?(.*)$/.exec(lines[j]);\r\n if (!more) {\r\n break;\r\n }\r\n body.push(more[1]);\r\n }\r\n i = j - 1;\r\n out.push('<blockquote>' + inline(body.join('\\n'), opts).replace(/\\n/g, '<br>') + '</blockquote>');\r\n continue;\r\n }\r\n // ---------- 목록 ----------\r\n const item = /^(\\s*)([-*+]|\\d+[.)])\\s+(.*)$/.exec(line);\r\n if (item) {\r\n flushPara();\r\n const indent = item[1].replace(/\\t/g, ' ').length;\r\n const ordered = /\\d/.test(item[2]);\r\n // 들여쓰기가 줄었으면 그만큼 닫고, 늘었으면 새로 연다\r\n while (stack.length && stack[stack.length - 1].indent > indent) {\r\n out.push(stack.pop().ordered ? '</ol>' : '</ul>');\r\n }\r\n const top = stack[stack.length - 1];\r\n if (!top || top.indent < indent) {\r\n stack.push({ ordered, indent });\r\n out.push(ordered ? '<ol>' : '<ul>');\r\n }\r\n else if (top.ordered !== ordered) {\r\n out.push(stack.pop().ordered ? '</ol>' : '</ul>');\r\n stack.push({ ordered, indent });\r\n out.push(ordered ? '<ol>' : '<ul>');\r\n }\r\n // 체크박스는 읽기 전용으로 그린다 (누를 수 있으면 파일과 어긋난다)\r\n const task = /^\\[([ xX])\\]\\s+(.*)$/.exec(item[3]);\r\n if (task) {\r\n const checked = task[1].toLowerCase() === 'x';\r\n out.push('<li class=\"ad-md-task\"><span class=\"ad-md-check\">'\r\n + (checked ? '☑' : '☐') + '</span> ' + inline(task[2], opts) + '</li>');\r\n }\r\n else {\r\n out.push('<li>' + inline(item[3], opts) + '</li>');\r\n }\r\n continue;\r\n }\r\n // ---------- 그 밖 = 문단 ----------\r\n // 목록 항목 아래에 들여쓴 줄은 그 항목의 이어짐으로 본다\r\n if (stack.length && /^\\s{2,}/.test(line) && ((_a = out[out.length - 1]) === null || _a === void 0 ? void 0 : _a.startsWith('<li'))) {\r\n out[out.length - 1] = out[out.length - 1].replace(/<\\/li>$/, '<br>' + inline(line.trim(), opts) + '</li>');\r\n continue;\r\n }\r\n closeLists();\r\n para.push(line);\r\n }\r\n if (fence) {\r\n out.push('<pre><code>' + escapeHtml(fence.body.join('\\n')) + '</code></pre>');\r\n }\r\n breakBlocks();\r\n return out.join('\\n');\r\n}\r\nexports.renderMarkdown = renderMarkdown;\r\n","\"use strict\";\r\n/**\r\n * 사이드바 **키보드 내비게이션**의 순수 규칙 — 보이는 줄 펼치기(`navRowsOf`)와 그 위의\r\n * 커서 이동(`stepNavIndex`). Angular/Tabby/DOM 에 기대지 않아 단위 테스트가 된다.\r\n *\r\n * 이 기능의 계약은 딱 하나다 — **훑는 동안 활성 탭이 바뀌지 않는다.** 지나가는 탭의 출력이\r\n * 화면을 덮으면 훑어보기 자체가 불가능해지므로, ↑↓ 는 `navFocus`(포커스 링)만 옮기고\r\n * 선택은 Enter 에서만 일어난다. 그래서 \"어느 줄로 가는가\" 는 화면을 흔들지 않고 확인할 수\r\n * 있어야 하는 값이고, 펼치기와 이동을 한 곳에 둔 이유도 그것이다 — 줄 목록의 순서와\r\n * 커서의 경계 규칙이 같은 계약(화면에 보이는 순서)을 지켜야 한다.\r\n *\r\n * **`deck.service.ts` 에서 여기로 옮겨 왔다** — 그 파일은 Angular/Tabby 를 import 해서\r\n * `package.json` 의 test 스크립트가 컴파일하는 순수 모듈 목록에 들어갈 수 없고, 그래서 이 두\r\n * 함수엔 유닛 테스트가 한 개도 없었다(사람이 손으로 떼어내 돌려보는 것이 전부였다).\r\n * `planTabMove` 를 `order.ts` 로 옮긴 것과 같은 이유·같은 방식이며, 구현은 한 줄도 바꾸지\r\n * 않았다(실경로에서 이미 도는 코드다). 옮기자마자 `test/nav.test.js` 의 전수 검사가 붙었다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.stepNavIndex = exports.pickCloseTarget = exports.navRowsOf = void 0;\r\n/**\r\n * 렌더 계획을 키보드 이동 순서로 펼친다 — `render()` 의 루프와 **같은 순서**여야 한다.\r\n *\r\n * 순서의 출처는 `renderPlan()` 하나뿐이다. 여기서 정렬·필터·그룹 규칙을 다시 적으면 그 사본이\r\n * 낡는다(`deck.service.ts` 가 `renderPlan` 을 뽑은 이유 자체가 그것이다). 그래서 이 함수는\r\n * **받은 구획을 그대로 펼치기만** 하고, 무엇이 보이는지는 판단하지 않는다.\r\n *\r\n * 접힌 그룹은 헤더만 남고 줄이 없다 — 화면과 같다. 헤더를 안 그리는 화면(`withHeads: false`)은\r\n * `head: false` 로 들어오므로 평면 목록이 된다.\r\n\r\n *\r\n * **전제 — 구획마다 `head`·`collapsed` 가 일관되어야 한다.** 지금 유일한 호출부(`navPlan`)\r\n * 는 둘을 화면 전체의 `withHeads` 에서 파생시키므로 어긋날 수 없다. 손으로 섞어 넣으면 규칙이\r\n * 이상해진다 — `head: false` + `collapsed: true` 인 구획은 **통째로 사라지고**(줄 0개), 구획마다\r\n * `head` 가 섞이면 헤더 없는 구획의 탭이 **앞 구획 헤더 밑에 붙어** 보인다.\r\n * 그 조합을 함수가 막지 않는 이유는, 막는 분기가 지금 도달 불가라 검증되지 않는 코드로 남기\r\n * 때문이다. 새 호출부를 만들 사람이 읽을 곳은 여기다. */\r\nfunction navRowsOf(sections) {\r\n const rows = [];\r\n for (const s of sections) {\r\n if (s.head) {\r\n rows.push({ kind: 'head', key: s.key });\r\n }\r\n if (s.collapsed) {\r\n continue;\r\n }\r\n for (const tab of s.tabs) {\r\n rows.push({ kind: 'tab', tab });\r\n }\r\n }\r\n return rows;\r\n}\r\nexports.navRowsOf = navRowsOf;\r\n/**\r\n * 보이는 줄이 `count` 개일 때 `index` 에서 `step` 칸 움직인 자리. 줄이 없으면 -1.\r\n *\r\n * 화면도 DOM 도 모르는 순수 규칙으로 뽑아 둔 이유는 `planTabMove` 와 같다 — 경계에서\r\n * 무엇이 일어나는지(멈추나 감싸나)를 좌표·포커스 없이 확인할 수 있어야 한다.\r\n * 규칙 세 가지 —\r\n * 1) 포커스가 없거나(-1) 목록에서 사라졌으면(닫힘·필터) **방향에 맞는 끝**에서 새로 시작한다.\r\n * 아래로 눌렀으면 첫 줄, 위로 눌렀으면 마지막 줄이다. 손이 간 방향으로 들어와야\r\n * \"아무 일도 안 일어났다\" 가 되지 않는다.\r\n * 2) `wrap` 이 false 면 끝에서 **제자리**다(기본). 감싸면 \"맨 아래에 왔다\" 는 신호가 사라진다.\r\n * 3) `wrap` 이 true 면 반대쪽 끝으로 — 음수 나머지를 쓰지 않게 두 번 접는다.\r\n *\r\n * 돌려주는 값은 **줄 인덱스일 뿐 선택이 아니다** — 호출부(`moveNav`)는 이 값으로 `navFocus`\r\n * 만 옮기고 활성 탭은 건드리지 않는다. 그리고 헤더 줄을 건너뛰지 않는다: 건너뛰면 그룹 A 의\r\n * 마지막 탭에서 B 의 첫 탭으로 점프해 \"보이는 순서대로 훑는다\" 는 계약이 깨진다.\r\n */\r\n/**\r\n * `Ctrl+W` 가 닫을 탭 — **키보드가 어디에 있느냐로 갈린다.**\r\n *\r\n * 터미널에서 눌렀으면 활성 탭이다(사람이 보고 있는 화면 = 닫으려는 것). 목록이 키보드를\r\n * 갖고 있을 때(`inList`)는 **포커스 링이 얹힌 줄**이다 — 그때 활성 탭을 닫으면 링을 옮겨\r\n * 놓고 엉뚱한 탭이 사라진다. ↑↓ 로 훑다가 \"이건 버리자\" 하는 자리가 곧 이 키의 쓰임새다.\r\n *\r\n * 두 경우에 `null`(아무것도 하지 않는다)을 돌려준다 —\r\n * 1) 목록에서 포커스가 **그룹 헤더**에 있다. 헤더는 탭이 아니고, \"이 그룹을 통째로 닫는다\"\r\n * 는 되돌릴 수 없는 조작이라 키 하나에 매달 것이 아니다.\r\n * 2) 고른 탭이 `tabs` 에 없다 — 이미 닫혔거나(포커스가 낡았다) 다른 창의 것이다.\r\n * `navFocus` 는 렌더마다 정리되지만(`pruneNavFocus`) 그 사이 키가 들어올 수 있다.\r\n *\r\n * 호출부(`claimCtrlWKey`)는 `null` 이면 **키를 막지 않고 흘린다** — 터미널의 `Ctrl+W`\r\n * (앞 단어 지우기)를 우리가 먹어 놓고 아무 일도 안 하는 것이 가장 나쁘다.\r\n */\r\nfunction pickCloseTarget(opts) {\r\n const { inList, focus, active, tabs } = opts;\r\n if (inList) {\r\n if (!focus || focus.kind !== 'tab') {\r\n return null;\r\n }\r\n return tabs.includes(focus.tab) ? focus.tab : null;\r\n }\r\n return active && tabs.includes(active) ? active : null;\r\n}\r\nexports.pickCloseTarget = pickCloseTarget;\r\nfunction stepNavIndex(count, index, step, wrap) {\r\n if (!Number.isInteger(count) || count <= 0) {\r\n return -1;\r\n }\r\n if (!Number.isInteger(index) || index < 0 || index >= count) {\r\n return step < 0 ? count - 1 : 0;\r\n }\r\n if (!Number.isInteger(step) || step === 0) {\r\n return index;\r\n }\r\n const next = index + step;\r\n if (next >= 0 && next < count) {\r\n return next;\r\n }\r\n if (!wrap) {\r\n return index;\r\n }\r\n return ((next % count) + count) % count;\r\n}\r\nexports.stepNavIndex = stepNavIndex;\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.WorkNotifyService = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\nconst fs = __importStar(require(\"fs\"));\r\nconst net = __importStar(require(\"net\"));\r\nconst os = __importStar(require(\"os\"));\r\nconst path = __importStar(require(\"path\"));\r\nconst string_decoder_1 = require(\"string_decoder\");\r\nconst status_service_1 = require(\"./status.service\");\r\nconst claudeHooks_1 = require(\"./claudeHooks\");\r\nconst bind_1 = require(\"./bind\");\r\nconst reason_1 = require(\"./reason\");\r\nconst tabenv_1 = require(\"./tabenv\");\r\nconst diag_1 = require(\"./diag\");\r\nconst subagents_1 = require(\"./subagents\");\r\n/**\r\n * 대화기록을 다시 재는 주기 — 폴링(400ms) 몇 번마다 한 번인지. 5 = 2초.\r\n *\r\n * 상태 파일 폴링(400ms)에 얹지 않는 이유: 하는 일이 \"자랐나\" 를 보는 것뿐이라 초당 두 번 반\r\n * 볼 값어치가 없고, 자란 경우에는 파일을 읽는다 — 그 비용을 400ms 마다 낼 수는 없다.\r\n * 사람이 사이드바 숫자에서 2초를 늦게 보는 것은 눈에 띄지 않는다(경과시간도 1초 단위로 흐른다).\r\n */\r\nconst SUBAGENT_SCAN_EVERY = 5;\r\n/**\r\n * 한 탭에서 기억할 \"만진 파일\" 개수 상한.\r\n *\r\n * `변경` 탭 목록의 재료라 화면에 그려지는 수(`MAX_DIFF_FILES` 300)보다 넉넉하면 충분하다.\r\n * 넘치면 오래된 것부터 버린다 — 버려도 '전체' 로 바꾸면 그 파일은 여전히 보인다.\r\n */\r\nconst TOUCHED_MAX = 400;\r\n/**\r\n * 그 주기 안에서 **몇 번째** 폴링에 볼지. `refreshPids`(0번째)와 겹치지 않게 어긋나 둔다 —\r\n * 같은 tick 에 몰면 pty 조회와 파일 읽기가 한 프레임에 같이 걸린다.\r\n */\r\nconst SUBAGENT_SCAN_PHASE = 2;\r\n/**\r\n * 대화기록 파일을 못 찾았을 때 폴더를 다시 훑기까지의 간격 (ms).\r\n *\r\n * 못 찾는 것은 정상 상태일 수 있다 — 세션 첫 줄이 아직 안 쓰였거나(파일이 없다), 훅만 붙은\r\n * 다른 CLI 다. 그런 세션 때문에 2초마다 `~/.claude/projects` 전체를 readdir 하면 안 된다.\r\n */\r\nconst TRANSCRIPT_LOOKUP_RETRY_MS = 10000;\r\n/** 경과 시간을 짧은 한국어로 (`40초` / `3분` / `2시간 5분` / `1일 3시간`) */\r\nfunction formatAge(ms) {\r\n // 음수는 시계 어긋남(파일의 timestamp 가 미래) — 0 으로 눕힌다\r\n const s = Math.max(0, Math.floor(ms / 1000));\r\n if (s < 60) {\r\n return `${s}초`;\r\n }\r\n const m = Math.floor(s / 60);\r\n if (m < 60) {\r\n return `${m}분`;\r\n }\r\n const h = Math.floor(m / 60);\r\n if (h < 24) {\r\n return h + '시간' + (m % 60 ? ` ${m % 60}분` : '');\r\n }\r\n const d = Math.floor(h / 24);\r\n return d + '일' + (h % 24 ? ` ${h % 24}시간` : '');\r\n}\r\n/**\r\n * 에이전트 훅 -> 사이드바 상태 채널. **기본으로 켜져 있다** (`notifyChannel`).\r\n *\r\n * 이쪽이 상태의 정확한 원천이다 — 에이전트가 \"지시를 받았다 / 승인을 기다린다 / 끝났다\" 를\r\n * 직접 알려준다. 출력 패턴으로 추측하는 경로(detect.ts)는 훅이 없는 환경을 위한 폴백이고,\r\n * TUI 가 화면을 어떻게 그리는지에 기대는 만큼 흔들린다 (2026-09-01: Claude Code 가 놀 때도\r\n * 상태줄을 매초 갱신해 진행중이 안 풀렸다).\r\n *\r\n * 훅은 Claude Code 쪽 설정에 있어야 해서 플러그인 설치만으로는 걸리지 않는다. 그래서\r\n * 기동할 때 한 번 물어보고(promptHooksOnce), 설정 창에도 설치 버튼을 둔다(claudeHooks.ts).\r\n *\r\n * 왜 파일인가 — 콘솔 제목 방식(`hooks/agentdeck-status.ps1`)은 **훅에서는 통하지 않는다**.\r\n * Claude Code 는 훅을 파이프 stdio 로 띄우기 때문에 그 자식 프로세스는 터미널의 콘솔에\r\n * 붙어 있지 않고, 제목을 바꿔도 pty 까지 오지 않는다 (2026-08-28 실측: 훅으로\r\n * `[AD:waiting] ...` 을 걸어도 사이드바가 그대로였다). 셸 안에서 직접 실행할 때는\r\n * 제목 방식이 여전히 유효하므로 그 경로는 남겨 둔다.\r\n *\r\n * 전달 경로는 두 가닥이다.\r\n *\r\n * 1. **TCP (기본)** — 이쪽이 `127.0.0.1` 임의 포트로 듣고, 실제 포트를\r\n * `%LOCALAPPDATA%\\tabby-agentdeck\\port` 에 적어 둔다. 훅은 그 포트로 JSON 한 줄을\r\n * 보내고 끊는다. 폴링 지연이 없고 상태 파일도 남지 않는다.\r\n * 2. **파일 (폴백)** — TCP 연결이 안 되면(Tabby 미기동, 포트 파일 없음, 방화벽)\r\n * 훅이 `...\\status\\<sessionId>.json` 에 쓰고 이쪽이 400ms 마다 읽는다.\r\n *\r\n * 두 경로 모두 `apply()` 로 모이고, `applied` 의 ts 대조가 중복 적용을 막으므로\r\n * 같은 보고가 양쪽으로 들어와도 결과는 같다.\r\n *\r\n * 세션 -> 탭 매칭: 어떤 Claude 세션이 **처음** 보고할 때의 활성 탭에 묶는다.\r\n * 사용자가 프롬프트를 넣은 탭이 곧 활성 탭이므로 이 규칙이면 탭이 여러 개여도 맞다.\r\n * 한 번 묶으면 그 뒤로는 활성 탭이 바뀌어도 같은 탭을 따라간다.\r\n */\r\nlet WorkNotifyService = class WorkNotifyService {\r\n constructor(app, config, status, platform) {\r\n this.app = app;\r\n this.config = config;\r\n this.status = status;\r\n this.platform = platform;\r\n this.root = path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), 'tabby-agentdeck');\r\n this.dir = path.join(this.root, 'status');\r\n /** 훅이 접속할 포트를 알려주는 파일 */\r\n this.portFile = path.join(this.root, 'port');\r\n this.server = null;\r\n this.sessionTab = new Map();\r\n /** 역방향 — 한 탭을 두 세션이 나눠 쓰지 못하게 막는다 */\r\n this.tabSession = new Map();\r\n /** 이미 적용한 (sessionId -> ts) — 같은 파일을 반복 적용하지 않는다 */\r\n this.applied = new Map();\r\n this.timer = null;\r\n /** 폴링을 시작한 시각 — 이보다 오래된 파일은 지난 실행의 잔재다 */\r\n this.startedAt = 0;\r\n /**\r\n * 탭(루트) -> 그 안 패널들의 셸 PID. 훅이 보낸 조상 PID 와 맞춰 어느 탭의 보고인지 확정한다.\r\n * pty 에 물어보는 비동기 작업이라 표로 들고 있고, 탭이 열릴 때와 2초마다 새로 채운다\r\n */\r\n this.tabPids = new Map();\r\n this.pidRefreshing = false;\r\n /**\r\n * 탭(루트) -> 그 안 패널 셸에 심은 `AGENTDECK_TAB` 값들(tabenv.ts). 훅이 tabId 로 보내면 여기서 바로\r\n * 확정하고, 프로세스 계보(tabPids)는 이 표에 없을 때의 폴백이다. 패널의 `profile.options.env` 를 읽어\r\n * 다시 채우므로 재시작으로 복원된 탭(복원 토큰에 profile 이 통째로 들어간다, tabby-local\r\n * dist/index.js:639-648)도 지난 실행의 id 를 그대로 되찾는다 — 살아 있는 pty 에 다시 붙든, 복원이\r\n * 실패해 같은 options 로 새 셸을 띄우든 셸 환경은 그 값이다\r\n */\r\n this.tabIds = new Map();\r\n /**\r\n * 탭(루트) -> 훅이 알려 준 작업 폴더. 상대경로 풀기·`변경` 탭의 git 기준이 된다.\r\n *\r\n * **Tabby 의 추정값보다 앞세우려고 따로 든다** (NotifyFile.cwd 주석 참고). 약참조라 탭이\r\n * 사라지면 같이 사라진다 — 탭 닫힘을 따로 청소할 필요가 없다.\r\n */\r\n this.hookCwd = new WeakMap();\r\n /**\r\n * 탭(루트) -> 이번 세션에서 에이전트가 고친 파일들 (훅이 보고한 절대경로, 최신이 앞).\r\n *\r\n * `변경` 탭이 \"저장소 전체\" 대신 \"이 세션이 만진 것\" 을 그리는 근거다 — P4 워크스페이스 위에\r\n * git 을 얹은 저장소에서는 전체 diff 가 405개씩 나와 방금 고친 것을 찾을 수 없다\r\n * (2026-09-11 유저 지적). 훅이 없는 에이전트는 이 목록이 비고, 그때는 전체를 그린다.\r\n *\r\n * 상한을 두는 이유 — 오래 도는 세션에서 무한히 자란다. 넘치면 오래된 것부터 버린다.\r\n * 버려진 파일은 '전체' 로 바꾸면 여전히 보인다.\r\n */\r\n this.touched = new WeakMap();\r\n /**\r\n * 탭(루트) -> 훅이 \"지금 돌고 있다\" 고 알려 준 서브에이전트들 (`agent_id` -> 정보).\r\n *\r\n * **이 표가 있는 탭에서는 이것이 개수의 진실이고**, 대화기록 훑기(`scans`)는 훅이 없는\r\n * 세션의 폴백으로만 쓴다. 두 원천을 섞지 않는 이유: 배지 숫자와 툴팁 목록이 서로 다른\r\n * 원천에서 나오면 \"4개라면서 5줄\" 같은 화면이 나온다 — 사용자가 어긋남을 본 바로 그 모양이다.\r\n */\r\n this.liveAgents = new WeakMap();\r\n /**\r\n * 서브에이전트 훅 보고를 **한 번이라도 받은** 탭. 이 표에 있으면 개수를 훅으로만 센다.\r\n *\r\n * \"지금 0개\" 와 \"훅이 없어서 모른다\" 를 가르는 유일한 자리다. 이게 없으면 에이전트가 전부\r\n * 끝난 순간(집합이 빔) 폴백이 되살아나 옛 기록을 세어 유령 숫자가 다시 뜬다.\r\n */\r\n this.agentHookSeen = new WeakSet();\r\n /** tabAdded$ 를 이미 구독한 분할 루트 — 루트가 사라지면 함께 사라진다 */\r\n this.watchedSplits = new WeakSet();\r\n this.pollCount = 0;\r\n /** 같은 매칭 실패를 폴링마다 diag 에 찍지 않기 위한 마지막 메시지 */\r\n this.lastBindLog = new Map();\r\n /**\r\n * 세션 id -> 대화기록 증분 스캔 상태. 탭에 묶인 세션만 들어 있다(`pruneScans`).\r\n *\r\n * 탭이 아니라 **세션** 을 키로 두는 이유: 같은 탭에서 claude 를 다시 띄우면 세션 id 가\r\n * 새로 생기는데(그게 정상이다) 탭을 키로 두면 옛 세션의 줄 수·호출 목록이 새 세션 것으로\r\n * 이어져 개수가 틀어진다.\r\n */\r\n this.scans = new Map();\r\n /**\r\n * Claude Code 대화기록이 사는 곳. 그 아래 프로젝트 폴더 이름은 **규칙을 흉내내지 않고**\r\n * 훑어서 찾는다 (`findTranscript`).\r\n */\r\n this.projectsDir = path.join(os.homedir(), '.claude', 'projects');\r\n }\r\n /**\r\n * 훅이 안 걸려 있으면 기동할 때 한 번 물어본다.\r\n *\r\n * 훅은 Claude Code 쪽 설정(`~/.claude/settings.json`)에 있어야 해서 플러그인을 설치하는 것만으로는\r\n * 걸리지 않는다. 그렇다고 말없이 남의 설정을 고칠 수는 없으니, 한 번 묻고 고른 대로 한다.\r\n * \"다시 묻지 않기\" 를 고르면 그 뒤로는 조용하고, 설정 창의 설치 버튼은 언제든 그대로 쓸 수 있다.\r\n */\r\n async promptHooksOnce() {\r\n var _a;\r\n const cfg = this.config.store.agentDeck;\r\n if (cfg.hookPromptDismissed || !(0, claudeHooks_1.hooksSupported)()) {\r\n return;\r\n }\r\n try {\r\n if ((0, claudeHooks_1.hooksInstalled)()) {\r\n return;\r\n }\r\n }\r\n catch {\r\n // 설정을 못 읽었다 — 그 상태로 남의 파일을 고치자고 권할 수는 없다\r\n return;\r\n }\r\n const r = await this.platform.showMessageBox({\r\n // 이 타입에는 'question' 이 없다 (tabby-core MessageBoxOptions) — 경고로 띄우면\r\n // 필요 이상으로 겁을 주므로 'warning' 대신 형만 맞추고 문구로 성격을 드러낸다\r\n type: 'warning',\r\n message: 'AgentDeck — Claude Code 상태 통보를 연결할까요?',\r\n detail: [\r\n '연결하면 에이전트가 \"지시를 받았다 / 승인을 기다린다 / 끝났다\" 를 사이드바에 직접 알려줍니다.',\r\n '연결하지 않아도 동작은 하지만, 화면에 그려진 글자를 보고 추측하는 방식이라 상태가 부정확할 수 있습니다.',\r\n '',\r\n `설치 위치: ${(0, claudeHooks_1.claudeSettingsPath)()}`,\r\n '기존 훅은 건드리지 않고, 쓰기 전에 같은 폴더에 백업을 남깁니다. 설정 창에서 언제든 제거할 수 있습니다.',\r\n ].join('\\n'),\r\n buttons: ['연결한다', '나중에', '다시 묻지 않기'],\r\n defaultId: 0,\r\n cancelId: 1,\r\n });\r\n if (r.response === 0) {\r\n try {\r\n (0, claudeHooks_1.installHooks)();\r\n if (!cfg.notifyChannel) {\r\n cfg.notifyChannel = true;\r\n }\r\n this.config.save();\r\n }\r\n catch (e) {\r\n await this.platform.showMessageBox({\r\n type: 'error',\r\n message: 'AgentDeck — 훅을 설치하지 못했습니다.',\r\n detail: `${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`,\r\n buttons: ['확인'],\r\n });\r\n }\r\n return;\r\n }\r\n if (r.response === 2) {\r\n cfg.hookPromptDismissed = true;\r\n this.config.save();\r\n }\r\n }\r\n init() {\r\n var _a;\r\n // 개발/진단용 — deck.service 가 만든 `__agentdeck` 에 붙는다 (alert.service 와 같은 방식).\r\n // 탭↔AGENTDECK_TAB 매핑은 훅 보고가 어느 탭에 붙을지의 근거인데, 지금까지는 진단 로그의\r\n // `tabid-map` 줄로만 볼 수 있어 검증 도구가 대조할 방법이 없었다 (2026-09-08 R18).\r\n const g = window;\r\n g.__agentdeck = (_a = g.__agentdeck) !== null && _a !== void 0 ? _a : {};\r\n g.__agentdeck.tabIds = () => [...this.tabIds].map(([tab, ids]) => {\r\n var _a;\r\n return ({\r\n title: (_a = tab.title) !== null && _a !== void 0 ? _a : '', ids,\r\n });\r\n });\r\n /**\r\n * 탭별 \"훅이 말해 준 것\" — 작업 폴더와 이번 세션이 만진 파일.\r\n *\r\n * `변경` 탭이 목록을 안 좁힐 때 **\"훅 보고가 안 왔다\" 와 \"필터가 안 걸렸다\" 를 가르는**\r\n * 유일한 자리다. 이게 없어서 회귀(CW6)가 원인을 못 짚고 한 바퀴를 돌았다 (2026-09-11).\r\n */\r\n g.__agentdeck.hookInfo = () => this.app.tabs.map((tab, index) => {\r\n var _a, _b, _c, _d, _e, _f;\r\n return ({\r\n index,\r\n title: String((_a = tab.title) !== null && _a !== void 0 ? _a : '').slice(0, 40),\r\n sessionId: (_b = this.tabSession.get(tab)) !== null && _b !== void 0 ? _b : null,\r\n cwd: (_c = this.hookCwd.get(tab)) !== null && _c !== void 0 ? _c : null,\r\n touched: (_d = this.touched.get(tab)) !== null && _d !== void 0 ? _d : [],\r\n // 서브에이전트 숫자가 이상할 때 **어느 원천을 보고 있는지**부터 가른다 —\r\n // `agentHook: false` 면 훅을 못 받아 대화기록 훑기로 센 값이다\r\n agentHook: this.agentHookSeen.has(tab),\r\n agents: [...((_f = (_e = this.liveAgents.get(tab)) === null || _e === void 0 ? void 0 : _e.values()) !== null && _f !== void 0 ? _f : [])],\r\n });\r\n });\r\n /**\r\n * 서브에이전트 개수의 **지금 상태**를 좌표 없이 되읽는다 (회귀용).\r\n *\r\n * 규칙의 사본을 만들지 않는다 — 개수는 `subagents.ts` 가 세고 여기서는 그 결과와\r\n * 스캔 배선(대화기록을 찾았나·어디까지 읽었나)만 내놓는다. 검증 도구가 \"0 개인 이유\" 를\r\n * 가르는 데 필요한 것이 정확히 그 배선이다: 파일을 못 찾은 것(`transcript: null`)과\r\n * 찾아서 다 읽었는데 도는 게 없는 것(`lastSize > 0, running: 0`)은 전혀 다른 상황이다.\r\n * `index` 는 `app.tabs` 인덱스 — 사이드바 줄의 `data-ad-index` 와 같은 뜻이라\r\n * 프로브가 줄을 찾을 때 쓴다.\r\n */\r\n g.__agentdeck.subagents = () => ({\r\n enabled: this.subagentEnabled,\r\n projectsDir: this.projectsDir,\r\n tabs: [...this.tabSession].map(([tab, sid]) => {\r\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;\r\n const scan = this.scans.get(sid);\r\n const sum = scan === null || scan === void 0 ? void 0 : scan.summary;\r\n return {\r\n index: this.app.tabs.indexOf(tab),\r\n title: String((_a = tab.title) !== null && _a !== void 0 ? _a : '').slice(0, 40),\r\n tabId: (_c = (_b = this.tabIds.get(tab)) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : null,\r\n sessionId: sid,\r\n transcript: (_d = scan === null || scan === void 0 ? void 0 : scan.path) !== null && _d !== void 0 ? _d : null,\r\n lastSize: (_e = scan === null || scan === void 0 ? void 0 : scan.lastSize) !== null && _e !== void 0 ? _e : 0,\r\n lines: (_f = scan === null || scan === void 0 ? void 0 : scan.state.lines) !== null && _f !== void 0 ? _f : 0,\r\n skipped: (_g = scan === null || scan === void 0 ? void 0 : scan.state.skipped) !== null && _g !== void 0 ? _g : 0,\r\n running: (_h = sum === null || sum === void 0 ? void 0 : sum.running) !== null && _h !== void 0 ? _h : 0,\r\n calls: (_j = sum === null || sum === void 0 ? void 0 : sum.calls) !== null && _j !== void 0 ? _j : 0,\r\n done: (_k = sum === null || sum === void 0 ? void 0 : sum.done) !== null && _k !== void 0 ? _k : 0,\r\n items: ((_l = sum === null || sum === void 0 ? void 0 : sum.items) !== null && _l !== void 0 ? _l : []).map(c => ({\r\n id: c.id, description: c.description, subagentType: c.subagentType, startedAt: c.startedAt,\r\n })),\r\n tooltip: sum ? this.subagentTooltip(sum) : '',\r\n };\r\n }),\r\n });\r\n this.app.ready$.subscribe(() => {\r\n // 이미 열려 있는 탭 중 셸이 아직 안 뜬 패널이 있으면 지금 심는다 (기동 직후의 첫 탭).\r\n // 셸이 이미 뜬 패널은 못 심고 계보 폴백으로 남는다\r\n for (const root of [...this.app.tabs]) {\r\n this.stampRoot(root);\r\n }\r\n // 훅이 안 걸려 있으면 기동할 때 한 번 물어본다. 통로만 열려 있고 보고자가 없으면\r\n // 아무 일도 일어나지 않는데, 사용자 눈에는 그냥 \"상태가 이상하다\" 로만 보인다.\r\n // 기동 직후는 화면이 정신없으니 조금 뒤에 띄운다\r\n setTimeout(() => { void this.promptHooksOnce(); }, 3000);\r\n // 채널이 닫혀 있으면 훅이 보낸 보고가 어디에도 닿지 않는다.\r\n // 기본은 열려 있고, 비용은 유휴 포트 하나와 400ms 폴링뿐이다\r\n if (!this.config.store.agentDeck.notifyChannel) {\r\n return;\r\n }\r\n this.startedAt = Date.now();\r\n this.listen();\r\n this.timer = setInterval(() => this.poll(), 400);\r\n void this.refreshPids();\r\n });\r\n this.app.tabOpened$.subscribe(tab => {\r\n // 셸은 아직 안 떴다 — `openNewTab` 은 `tabsService.create` 직후 `addTabRaw` 에서 동기로 tabOpened 를\r\n // 내고(tabby-core dist/index.js:5029), 셸은 그 뒤 프런트엔드가 준비된 다음에야 뜬다(tabby-local\r\n // dist/index.js:623-635). 여기서 profile.options.env 에 심어야 셸이 물려받는다\r\n this.stampRoot(tab);\r\n // 새 탭의 셸 PID 는 세션이 붙은 뒤에야 나온다 — 조금 뒤에 한 번 더 채운다 (2초 주기 폴링도 있다)\r\n setTimeout(() => { void this.refreshPids(); }, 1500);\r\n });\r\n // 탭이 닫히면 점유를 풀어야 그 자리를 다음 세션이 쓸 수 있다\r\n this.app.tabClosed$.subscribe(tab => {\r\n this.tabPids.delete(tab);\r\n this.tabIds.delete(tab);\r\n const sid = this.tabSession.get(tab);\r\n if (sid) {\r\n this.tabSession.delete(tab);\r\n this.sessionTab.delete(sid);\r\n // 스캔 상태(줄 수·호출 목록·decoder)도 같이 버린다 — 닫힌 탭의 세션은 다시\r\n // 그려질 일이 없고, 안 지우면 하루 켜 둔 Tabby 에서 죽은 세션이 끝없이 쌓인다.\r\n // 이 저장소에서 같은 종류의 누수(`status.states`)가 실제 결함으로 잡혔다\r\n this.scans.delete(sid);\r\n }\r\n });\r\n }\r\n /** 진단 한 줄 — deck.service 와 같은 파일(`~/.agentdeck-diag.log`)에 남긴다 */\r\n diag(line) {\r\n (0, diag_1.diag)(line);\r\n }\r\n tabName(tab) {\r\n const anyTab = tab;\r\n return JSON.stringify(String(anyTab.customTitle || anyTab.title || '').slice(0, 40));\r\n }\r\n /**\r\n * 탭별 셸 PID 표를 새로 채운다. 로컬 pty 는 `session.pty.getPID()` 로 셸 PID 를 준다\r\n * (tabby-local Session — gracefullyKillProcess 가 쓰는 그 경로). SSH 등 PID 가 없는 탭은 빈 목록.\r\n */\r\n async refreshPids() {\r\n var _a;\r\n if (this.pidRefreshing) {\r\n return;\r\n }\r\n this.pidRefreshing = true;\r\n try {\r\n for (const root of [...this.app.tabs]) {\r\n const pids = [];\r\n for (const pane of this.panesOf(root)) {\r\n const pty = (_a = pane === null || pane === void 0 ? void 0 : pane.session) === null || _a === void 0 ? void 0 : _a.pty;\r\n if (!pty || typeof pty.getPID !== 'function') {\r\n continue;\r\n }\r\n try {\r\n const pid = await pty.getPID();\r\n if (Number.isInteger(pid) && pid > 0) {\r\n pids.push(pid);\r\n }\r\n }\r\n catch {\r\n // 세션이 닫히는 중이다\r\n }\r\n }\r\n const prev = this.tabPids.get(root);\r\n if (!prev || prev.join(',') !== pids.join(',')) {\r\n this.tabPids.set(root, pids);\r\n this.diag(`pid-map tab=${this.tabName(root)} pids=[${pids.join(',')}]`);\r\n }\r\n }\r\n }\r\n finally {\r\n this.pidRefreshing = false;\r\n }\r\n }\r\n /** 루트 하나의 터미널 패널들 — 분할 래퍼(`app.tabs` 의 원소는 SplitTabComponent)면 자식들, 아니면 자기 자신 */\r\n panesOf(root) {\r\n const anyRoot = root;\r\n return typeof anyRoot.getAllTabs === 'function' ? anyRoot.getAllTabs() : [root];\r\n }\r\n isLocalProfile(profile) {\r\n return !!profile && profile.type === 'local' && !!profile.options && typeof profile.options === 'object';\r\n }\r\n /**\r\n * 새 루트 탭의 셸에 `AGENTDECK_TAB` 을 심는다 — 지금 있는 패널, 복원 토큰 안의 패널, 나중에 분할로 붙는 패널.\r\n *\r\n * 심는 자리가 맞는 근거 (tabby-local/dist/index.js, 1.0.231):\r\n * - 셸은 `onFrontendReady -> initializeSession` 이 `session.start({ ...this.profile.options, width, height })`\r\n * 로 띄운다(623-635). 자식 env 는 `mergeEnv(process.env, {TERM_PROGRAM: 'Tabby', …}, substituteEnv(options.env),\r\n * config.store.terminal.environment)` 다(1158-1162). 즉 **spawn 시점의 `pane.profile.options.env`** 가 셸 환경이다.\r\n * - `ngOnInit` 의 `this.sessionOptions = this.profile.options`(604-605) 는 같은 객체를 가리키는 참조일 뿐\r\n * spawn 에 쓰이지 않는다. profile 을 새 객체로 바꾸므로 그것도 같이 맞춰 둔다.\r\n * - `tab.profile` 은 `getNewTabParameters` 가 deep clone 한 것(898)이라 저장된 프로필과 다른 객체다. 그래도\r\n * 여기서 다시 얕게 복제해 넣는다 — 다른 경로(복원·복제 토큰)로 들어온 profile 이 공유 객체일 가능성을 막고,\r\n * 탭 하나의 id 가 설정 파일의 프로필로 새는 일이 없게 한다.\r\n *\r\n * 타이밍 (tabby-core/dist/index.js): `openNewTab`(5075) 은 `wrapAndAddTab`(5086) 에서 `splitTab.addTab(tab)` 을\r\n * 부르고 — `add()` 는 첫 await(2620 `initialized$`) 앞에서 자식을 `children` 에 넣는다(2618) — 그 다음\r\n * `addTabRaw` 가 `tabOpened.next(splitTab)` 를 낸다(5029). 그래서 tabOpened 시점에 `getAllTabs()` 에 자식이\r\n * 있고 `session` 은 아직 null 이다.\r\n */\r\n stampRoot(root) {\r\n this.stampPanes(root);\r\n const anyRoot = root;\r\n // 복제 탭(duplicateTab, 5245-5249)과 재시작 복원 탭(5003-5006)은 이 시점에 자식이 없고 복원 토큰\r\n // (`_recoveredState`)만 있다 — 자식은 ngAfterViewInit 의 recoverContainer 가 비동기로 만들고(2488-2491,\r\n // 3093 `tabsService.create(recovered)`) tabAdded 도 내지 않는다. 토큰 안의 profile 을 지금 고치면 그것이\r\n // 그대로 자식의 profile 이 된다 (recoverTab -> inputs.profile)\r\n if (anyRoot._recoveredState && typeof anyRoot._recoveredState === 'object') {\r\n this.stampRecoveryState(anyRoot._recoveredState, root);\r\n }\r\n // 나중에 분할로 붙는 패널 — tabAdded 는 onAfterTabAdded 의 setImmediate 에서 나오는데(2935-2939),\r\n // 셸은 그보다 뒤인 프런트엔드 준비 후에 뜬다. 혹시 이미 떠 있으면 stampPane 이 건너뛴다.\r\n // Subject 는 루트가 destroy 될 때 complete 되므로(2510) 구독을 따로 풀 필요가 없다\r\n if (anyRoot.tabAdded$ && typeof anyRoot.tabAdded$.subscribe === 'function' && !this.watchedSplits.has(root)) {\r\n this.watchedSplits.add(root);\r\n anyRoot.tabAdded$.subscribe(() => this.stampPanes(root));\r\n }\r\n }\r\n stampPanes(root) {\r\n for (const pane of this.panesOf(root)) {\r\n this.stampPane(pane, root);\r\n }\r\n this.refreshTabIds();\r\n }\r\n /**\r\n * 패널 하나에 심는다. **아직 셸이 안 뜬**(`session` 없음) 로컬 패널만 — 이미 뜬 셸의 환경은 바꿀 수 없다.\r\n * 복원 패널(`restoreFromPTYID`)은 살아 있는 pty 에 다시 붙으므로 건드리지 않는다 — 토큰의 profile 에\r\n * 지난 실행의 id 가 있으면 그게 곧 그 셸의 환경이고 refreshTabIds 가 읽어 간다.\r\n * 이미 id 가 있어도 다른 패널이 같은 값을 갖고 있으면(복제) 새로 뽑는다 — 같은 id 가 두 셸에 있으면 어느 쪽인지 알 수 없다.\r\n */\r\n stampPane(pane, root) {\r\n var _a;\r\n if (!pane || pane.session || !this.isLocalProfile(pane.profile) || pane.profile.options.restoreFromPTYID) {\r\n return;\r\n }\r\n const env = (_a = pane.profile.options.env) !== null && _a !== void 0 ? _a : {};\r\n const cur = typeof env[tabenv_1.TAB_ENV] === 'string' ? env[tabenv_1.TAB_ENV] : '';\r\n if (cur && !this.idTakenElsewhere(cur, pane)) {\r\n return;\r\n }\r\n const id = (0, tabenv_1.newTabId)();\r\n pane.profile = { ...pane.profile, options: { ...pane.profile.options, env: { ...env, [tabenv_1.TAB_ENV]: id } } };\r\n if (pane.sessionOptions !== undefined) {\r\n pane.sessionOptions = pane.profile.options;\r\n }\r\n this.diag(`tabid stamp tab=${this.tabName(root)} id=${id}${cur ? ` (was ${cur}: duplicate)` : ''}`);\r\n }\r\n /**\r\n * 복원 토큰 트리(`app:split-tab` 은 children, 잎은 profile 을 가진다)의 로컬 패널에 심는다.\r\n * `restoreFromPTYID` 가 있는 잎은 재시작 복원(saveTabs 가 includeState 로 만든 토큰, tabby-core 7700) —\r\n * 살아 있는 pty 의 환경은 이미 정해져 있으니 두고, 없는 잎은 새 셸이 뜰 것이므로(복제 탭 —\r\n * `tabsService.duplicate` 는 options 없이 토큰을 만들어 restoreFromPTYID 가 비어 있다, 7819-7830) 항상 새 id 를 준다.\r\n * 복제 원본의 id 가 토큰에 그대로 실려 오는데 그걸 두면 두 탭이 같은 id 를 갖게 된다\r\n */\r\n stampRecoveryState(state, root) {\r\n var _a;\r\n if (Array.isArray(state.children)) {\r\n for (const child of state.children) {\r\n if (child && typeof child === 'object') {\r\n this.stampRecoveryState(child, root);\r\n }\r\n }\r\n return;\r\n }\r\n const profile = state.profile;\r\n if (!this.isLocalProfile(profile) || profile.options.restoreFromPTYID) {\r\n return;\r\n }\r\n const id = (0, tabenv_1.newTabId)();\r\n state.profile = { ...profile, options: { ...profile.options, env: { ...((_a = profile.options.env) !== null && _a !== void 0 ? _a : {}), [tabenv_1.TAB_ENV]: id } } };\r\n this.diag(`tabid stamp tab=${this.tabName(root)} id=${id} (recovery token)`);\r\n }\r\n /** 같은 id 를 다른 패널(어느 루트든)이 이미 갖고 있나 */\r\n idTakenElsewhere(id, self) {\r\n var _a, _b, _c;\r\n for (const root of this.app.tabs) {\r\n for (const pane of this.panesOf(root)) {\r\n if (pane !== self && ((_c = (_b = (_a = pane === null || pane === void 0 ? void 0 : pane.profile) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.env) === null || _c === void 0 ? void 0 : _c[tabenv_1.TAB_ENV]) === id) {\r\n return true;\r\n }\r\n }\r\n }\r\n return false;\r\n }\r\n /**\r\n * 탭별 tabId 표를 패널의 `profile.options.env` 에서 다시 읽는다. 동기·저비용이라 폴링(400ms)마다 돈다 —\r\n * 복원 탭의 자식은 tabOpened 뒤에 비동기로 생기고(tabby-core 3093) 이벤트도 없어서 읽는 쪽이 주기적으로 봐야 한다.\r\n * 같은 id 가 두 루트에 있으면(복제 뒤 셸이 이미 뜬 경우) 어느 쪽인지 알 수 없으니 둘 다 표에서 빼고 계보 폴백에 맡긴다.\r\n */\r\n refreshTabIds() {\r\n var _a, _b, _c;\r\n const owner = new Map();\r\n const dup = new Set();\r\n const next = new Map();\r\n for (const root of [...this.app.tabs]) {\r\n const ids = [];\r\n for (const pane of this.panesOf(root)) {\r\n const v = (_c = (_b = (_a = pane === null || pane === void 0 ? void 0 : pane.profile) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.env) === null || _c === void 0 ? void 0 : _c[tabenv_1.TAB_ENV];\r\n if (typeof v !== 'string' || !v || ids.includes(v)) {\r\n continue;\r\n }\r\n ids.push(v);\r\n const prevOwner = owner.get(v);\r\n if (prevOwner && prevOwner !== root) {\r\n dup.add(v);\r\n }\r\n else {\r\n owner.set(v, root);\r\n }\r\n }\r\n next.set(root, ids);\r\n }\r\n for (const root of [...this.tabIds.keys()]) {\r\n if (!next.has(root)) {\r\n this.tabIds.delete(root);\r\n }\r\n }\r\n for (const [root, ids] of next) {\r\n const clean = ids.filter(v => !dup.has(v));\r\n const prev = this.tabIds.get(root);\r\n if (!prev || prev.join(',') !== clean.join(',')) {\r\n this.tabIds.set(root, clean);\r\n const dropped = ids.filter(v => dup.has(v));\r\n this.diag(`tabid-map tab=${this.tabName(root)} ids=[${clean.join(',')}]`\r\n + (dropped.length ? ` dup-dropped=[${dropped.join(',')}]` : ''));\r\n }\r\n }\r\n }\r\n /** 진단용 */\r\n get debugDir() { return this.dir; }\r\n /** 진단용 — 듣고 있는 포트 (0 = TCP 채널이 안 떴다) */\r\n get debugPort() {\r\n var _a;\r\n const addr = (_a = this.server) === null || _a === void 0 ? void 0 : _a.address();\r\n return addr && typeof addr === 'object' ? addr.port : 0;\r\n }\r\n /**\r\n * 훅이 상태를 바로 밀어 넣을 TCP 채널을 연다.\r\n *\r\n * 기본은 `agentDeck.notifyPort` 고정 포트다 — 번호가 늘 같아야 훅이나 진단 도구가\r\n * 바로 붙을 수 있다. Windows 임시 포트 범위(49152~65535) 아래로 잡아 두어야\r\n * OS 가 그 번호를 다른 프로세스에 먼저 내주는 일이 없다.\r\n *\r\n * 그 번호가 이미 물려 있으면(Tabby 두 개, 다른 프로그램) 0 으로 다시 시도한다 —\r\n * OS 가 빈 포트를 골라 준다. 어느 쪽이든 실제 번호는 port 파일에 적어 두므로\r\n * 훅은 고정/임의를 구분할 필요가 없다. 둘 다 실패해도 파일 폴백이 살아 있다.\r\n */\r\n listen() {\r\n const server = net.createServer(socket => {\r\n let buf = '';\r\n socket.setEncoding('utf8');\r\n socket.on('data', chunk => {\r\n buf += chunk;\r\n // 훅이 여러 건을 몰아 보낼 수도 있으니 줄 단위로 끊어 처리한다\r\n let nl;\r\n while ((nl = buf.indexOf('\\n')) >= 0) {\r\n const line = buf.slice(0, nl);\r\n buf = buf.slice(nl + 1);\r\n this.accept(line);\r\n }\r\n });\r\n // 개행 없이 끊는 훅도 받아 준다\r\n socket.on('end', () => this.accept(buf));\r\n socket.on('error', () => { });\r\n });\r\n let fellBack = false;\r\n server.on('error', (e) => {\r\n if (!fellBack) {\r\n // 고정 포트가 물려 있다 — OS 가 골라 주는 번호로 한 번 더 시도한다\r\n fellBack = true;\r\n (0, diag_1.diagCatch)('notify channel listen (고정 포트 실패, 임의 포트로 재시도)', e);\r\n server.listen(0, '127.0.0.1');\r\n return;\r\n }\r\n // 여기까지 오면 훅의 TCP 경로는 죽었다. 상태가 안 바뀐다는 제보의 1순위 원인이라 반드시 남긴다\r\n (0, diag_1.diagCatch)('notify channel listen 최종 실패', e);\r\n this.server = null;\r\n // 지난 실행의 포트 번호를 남겨 두면 훅이 그 번호로 접속을 시도한다.\r\n // 그 사이 다른 프로그램이 같은 번호를 잡았다면 엉뚱한 곳으로 JSON 을 쏘게 되므로 지운다\r\n try {\r\n fs.unlinkSync(this.portFile);\r\n }\r\n catch {\r\n // 이미 없으면 그만이다\r\n }\r\n });\r\n server.on('listening', () => {\r\n this.server = server;\r\n try {\r\n fs.mkdirSync(this.root, { recursive: true });\r\n fs.writeFileSync(this.portFile, String(this.debugPort), 'utf8');\r\n }\r\n catch (e) {\r\n // 포트를 못 알리면 훅은 파일 경로로 떨어진다 (느려지지만 동작은 한다)\r\n (0, diag_1.diagCatch)('notify port 파일 쓰기', e);\r\n }\r\n });\r\n server.listen(this.config.store.agentDeck.notifyPort || 0, '127.0.0.1');\r\n }\r\n /** TCP 로 들어온 JSON 한 줄 */\r\n accept(line) {\r\n const text = line.trim();\r\n if (!text) {\r\n return;\r\n }\r\n try {\r\n this.apply(JSON.parse(text));\r\n }\r\n catch (e) {\r\n // 깨진 줄은 버린다 — 다음 보고가 곧 온다.\r\n // 다만 훅 스크립트가 바뀌어 형식이 어긋난 경우도 여기로 오므로 사유는 남긴다\r\n (0, diag_1.diagCatch)('notify 보고 파싱', e);\r\n }\r\n }\r\n poll() {\r\n // tabId 표는 동기라 매번, 셸 PID 표는 pty 에 물어야 해서 2초마다 — 탭 안에서 셸을 다시 띄우거나 분할하면 바뀐다\r\n this.refreshTabIds();\r\n if (++this.pollCount % 5 === 0) {\r\n void this.refreshPids();\r\n }\r\n // 대화기록 증분 스캔은 2초에 한 번, pid 조회와 다른 tick 에 (상수 주석 참고)\r\n if (this.pollCount % SUBAGENT_SCAN_EVERY === SUBAGENT_SCAN_PHASE) {\r\n this.scanSubagents();\r\n }\r\n let names;\r\n try {\r\n names = fs.readdirSync(this.dir);\r\n }\r\n catch {\r\n return; // 폴더 없음 = 훅이 아직 한 번도 안 돌았다\r\n }\r\n for (const name of names) {\r\n if (!name.endsWith('.json')) {\r\n continue;\r\n }\r\n const full = path.join(this.dir, name);\r\n let data;\r\n try {\r\n data = JSON.parse(fs.readFileSync(full, 'utf8'));\r\n }\r\n catch {\r\n continue; // 훅이 쓰는 중 — 다음 폴링에서 다시 읽는다\r\n }\r\n // 지난 Tabby 실행 때 남은 파일 — 이걸 읽으면 죽은 세션들이 전부 \"지금 활성 탭\" 에\r\n // 묶여 버려서(resolveTab 규칙) 실제 세션이 엉뚱한 탭에 붙는다. 실제로 완료된 세션의\r\n // done 이 작업 중인 탭에 찍히는 증상이 이것이었다 (2026-08-28 실측). 읽지 말고 지운다\r\n if (data.ts < this.startedAt && !this.sessionTab.has(data.sessionId)) {\r\n try {\r\n fs.unlinkSync(full);\r\n }\r\n catch {\r\n // 지우기 실패해도 아래 apply 를 타지 않으므로 해는 없다\r\n }\r\n continue;\r\n }\r\n this.apply(data);\r\n }\r\n }\r\n /**\r\n * 보고 한 건을 반영한다. `status` / `label` 은 **각각 선택**이고, 빠진 쪽은 지금 값을 유지한다.\r\n *\r\n * 병합 규칙을 여기(플러그인)에 둔 이유 — 예전에는 훅 스크립트가 status 파일을 읽어\r\n * 직전 값과 합친 뒤 다시 쓰는 read-modify-write 를 했다. 그러면 진짜 상태가 파일과\r\n * 플러그인 메모리 두 곳에 살고 병합 규칙이 PowerShell 안에 숨는다. 라벨만 바꾸려 해도\r\n * 직전 status 를 채워 넣어야 했고(안 채우면 여기서 통째로 버려졌다), 파일이 밀리면\r\n * 표시가 어긋났다. 보내는 쪽은 \"자기가 아는 것만\" 보내고 합치는 건 상태를 실제로\r\n * 들고 있는 이쪽이 한다 — 그래야 어느 경로로 들어오든 결과가 같다.\r\n */\r\n apply(data) {\r\n var _a, _b, _c, _d, _e, _f;\r\n if (!data || !data.sessionId) {\r\n return;\r\n }\r\n const hasStatus = !!data.status;\r\n const hasLabel = typeof data.label === 'string' && !!data.label.trim();\r\n const hasFile = typeof data.file === 'string' && !!data.file.trim();\r\n const hasAgents = data.agents !== undefined && data.agents !== null;\r\n if (!hasStatus && !hasLabel && !hasFile && !hasAgents) {\r\n return;\r\n }\r\n if (this.applied.get(data.sessionId) === data.ts) {\r\n return;\r\n }\r\n const tab = this.resolveTab(data.sessionId, data.tabId, data.pids);\r\n if (!tab) {\r\n // tabId 도 pids 도 없는 보고(옛 훅·수동 호출)는 다시 봐도 결과가 같다. 그런데 폴링이 400ms 마다\r\n // 되풀이하면 \"활성 탭에 묶는다\" 규칙이 다음에 열리는 빈 탭을 붙잡는다 — 끝난 세션의\r\n // done 이 새 탭에 박히고, 그 탭의 진짜 세션은 주인이 있다며 거절됐다 (2026-09-02 실측).\r\n // 적용한 것으로 쳐서 멈춘다. 다음 보고(새 ts)가 오면 그때 다시 시도한다.\r\n // tabId / pids 가 있는 보고는 표가 채워지면 맞을 수 있으니 다음 폴링에 다시 본다.\r\n if (!((_a = data.pids) === null || _a === void 0 ? void 0 : _a.length) && !data.tabId) {\r\n this.applied.set(data.sessionId, data.ts);\r\n }\r\n return;\r\n }\r\n this.applied.set(data.sessionId, data.ts);\r\n // 작업 폴더는 상태·라벨과 독립이다 — 온 보고마다 최신 값으로 갈아 둔다.\r\n // (에이전트가 세션 도중 폴더를 옮기면 다음 보고가 그 값을 들고 온다)\r\n const cwd = typeof data.cwd === 'string' ? data.cwd.trim() : '';\r\n if (cwd) {\r\n this.hookCwd.set(tab, cwd);\r\n }\r\n // 만진 파일도 마찬가지다 — 같은 파일을 또 고치면 맨 앞으로 올린다(최근 순).\r\n // 목록 자체를 `변경` 탭이 읽으므로 순서가 곧 화면 순서는 아니지만(그건 git 이 정한다),\r\n // 상한을 넘길 때 **오래된 것부터** 버리려면 순서가 있어야 한다\r\n // 서브에이전트 목록 — **덧붙이지 않고 통째로 갈아 끼운다**(스냅샷, NotifyFile.agents 주석).\r\n // 빈 목록도 뜻이 있다: \"마지막 하나가 끝났다\". 그래서 `hasAgents` 는 길이가 아니라\r\n // 키의 유무로 판정한다\r\n if (hasAgents) {\r\n const raw = Array.isArray(data.agents) ? data.agents : [data.agents];\r\n const live = new Map();\r\n for (const a of raw) {\r\n const id = String((_b = a === null || a === void 0 ? void 0 : a.id) !== null && _b !== void 0 ? _b : '').trim();\r\n if (!id) {\r\n continue;\r\n }\r\n const at = Number(a === null || a === void 0 ? void 0 : a.at);\r\n live.set(id, {\r\n id,\r\n type: String((_c = a === null || a === void 0 ? void 0 : a.type) !== null && _c !== void 0 ? _c : '').trim(),\r\n // 시작 시각이 없거나 깨졌으면 **지금**으로 둔다 — 툴팁의 \"가장 오래된 것\"\r\n // 계산이 NaN 으로 새지 않게. 값을 지어내는 셈이지만 그 줄은 참고용이고,\r\n // 0 으로 두면 1970년부터 돌고 있다고 말하게 된다\r\n at: Number.isFinite(at) && at > 0 ? at : Date.now(),\r\n });\r\n }\r\n const before = (_e = (_d = this.liveAgents.get(tab)) === null || _d === void 0 ? void 0 : _d.size) !== null && _e !== void 0 ? _e : 0;\r\n this.liveAgents.set(tab, live);\r\n this.agentHookSeen.add(tab);\r\n if (before !== live.size) {\r\n this.diag(`agents sid=${data.sessionId.slice(0, 8)} ${before} -> ${live.size}`\r\n + ` [${[...live.values()].map(a => a.type || '?').join(',')}]`);\r\n }\r\n }\r\n if (hasFile) {\r\n const file = data.file.trim();\r\n const list = (_f = this.touched.get(tab)) !== null && _f !== void 0 ? _f : [];\r\n const next = [file, ...list.filter(p => p !== file)];\r\n this.touched.set(tab, next.length > TOUCHED_MAX ? next.slice(0, TOUCHED_MAX) : next);\r\n }\r\n const label = (data.label || '').trim();\r\n if (hasStatus) {\r\n // 라벨이 안 왔으면 undefined 를 넘겨 기존 라벨을 지키게 한다 (setManual 규약)\r\n // 이유는 waiting 에서만 의미가 있고 setManual 이 다른 상태에서는 비운다\r\n const reason = (0, reason_1.shortenReason)(typeof data.reason === 'string' ? data.reason : '');\r\n this.status.setManual(tab, data.status, hasLabel ? label : undefined, reason);\r\n }\r\n else {\r\n // 라벨만 온 보고 — 상태도 고정 여부도 건드리지 않는다\r\n this.status.setLabel(tab, label);\r\n }\r\n // 탭 제목(customTitle)은 건드리지 않는다.\r\n // 제목을 라벨 원천으로 쓸 수 있는지 보려고 한동안 비워 뒀고, 판정은 났다 —\r\n // Claude Code 는 세션 첫 작업을 요약해 제목에 한 번 박고 그 뒤로 갱신하지 않는다.\r\n // 그래서 라벨은 Enter 시점 입력창에서 직접 읽고(claimEnterLabel), 사이드바는\r\n // 제목과 그 라벨을 각자 줄에 나눠 그린다(renderTab). 여기서 제목을 덮어쓸 이유가 없다.\r\n }\r\n /**\r\n * 세션에 묶인 탭을 찾는다.\r\n *\r\n * 1순위는 **셸에 심어 둔 `AGENTDECK_TAB`**(tabId, tabenv.ts) — 플러그인이 탭을 열 때 심은 값을 훅이 그대로\r\n * 돌려보낸 것이라 표에 있으면 곧 그 탭이다. 2순위는 **프로세스 계보**(pids) — 훅이 보낸 조상 PID(claude.exe →\r\n * 탭 셸 → Tabby) 에 어떤 탭의 셸 PID 가 들어 있으면 그 탭이다(bind.ts). 이 버전 이전에 열린 탭·복원된 탭이\r\n * 여기로 온다. 둘 다 이미 다른 세션이 그 탭을 갖고 있어도 넘겨받는다: 같은 탭에서 claude 를 다시 띄우면\r\n * 세션 id 가 바뀌는 게 정상이고, 이전 주인은 이미 죽은 세션이다. 알던 탭과 다른 탭이 맞으면 옮긴다\r\n * (`claude --resume` 을 다른 탭에서 띄운 경우).\r\n *\r\n * tabId 나 pids 가 왔는데 맞는 탭이 없으면 **추측하지 않고** null 이다 — 표가 아직 안 채워진 것일 수\r\n * 있고(복원 탭의 자식은 늦게 생긴다), 그 경우 다음 폴링(400ms)에 다시 온다. 활성 탭으로 떨어지던 예전 규칙이\r\n * 낸 사고가 \"끝난 세션의 done 이 새 탭에 박힘\" 이었다 (2026-09-02 실측).\r\n *\r\n * 둘 다 없는 보고(옛 훅·셸에서 사람이 부른 것)만 예전 규칙을 탄다 — 처음 보는 세션이면 지금 활성 탭.\r\n * 단 그 탭을 이미 다른 세션이 점유했으면 묶지 않는다 (여러 세션이 한 탭에 겹쳐 붙어 서로의\r\n * 상태를 덮어쓰던 2026-08-28 사고의 방지책).\r\n */\r\n resolveTab(sessionId, tabId, pids) {\r\n const known = this.sessionTab.get(sessionId);\r\n const alive = known && this.app.tabs.includes(known) ? known : null;\r\n const byId = (0, tabenv_1.pickTabByTabId)(tabId, this.tabIds);\r\n if (byId) {\r\n if (byId !== alive) {\r\n this.bind(sessionId, byId, alive ? 'tabid-move' : 'tabid');\r\n }\r\n return byId;\r\n }\r\n const pick = (0, bind_1.pickTabByPids)(pids, this.tabPids);\r\n if (pick.mode === 'pid' && pick.tab) {\r\n if (pick.tab !== alive) {\r\n this.bind(sessionId, pick.tab, alive ? 'pid-move' : 'pid');\r\n }\r\n return pick.tab;\r\n }\r\n if (alive) {\r\n return alive;\r\n }\r\n if (tabId) {\r\n // 훅은 tabId 가 있으면 pids 를 보내지 않으므로 여기서 멈춘다 — 계보처럼 추측 없이 다음 폴링을 기다린다\r\n const table = [...this.tabIds.entries()]\r\n .map(([tab, list]) => `${this.tabName(tab)}:[${list.join(',')}]`)\r\n .join(' ');\r\n this.bindLog(sessionId, `unbound (tabid-miss) tabId=${tabId} tabs=${table}`);\r\n return null;\r\n }\r\n if (pick.mode === 'pid-miss') {\r\n const table = [...this.tabPids.entries()]\r\n .map(([tab, list]) => `${this.tabName(tab)}:[${list.join(',')}]`)\r\n .join(' ');\r\n this.bindLog(sessionId, `unbound (pid-miss) pids=[${(pids !== null && pids !== void 0 ? pids : []).join(',')}] tabs=${table}`);\r\n return null;\r\n }\r\n const active = this.app.activeTab;\r\n if (!active) {\r\n return null;\r\n }\r\n const owner = this.tabSession.get(active);\r\n if (owner && owner !== sessionId) {\r\n this.bindLog(sessionId, `unbound (legacy: active tab owned by ${owner.slice(0, 8)})`);\r\n return null;\r\n }\r\n this.bind(sessionId, active, 'legacy');\r\n return active;\r\n }\r\n /** 세션 <-> 탭 을 묶고, 그 탭의 이전 주인과 이 세션의 이전 탭은 풀어 준다 */\r\n bind(sessionId, tab, how) {\r\n const prevOwner = this.tabSession.get(tab);\r\n if (prevOwner && prevOwner !== sessionId) {\r\n this.sessionTab.delete(prevOwner);\r\n // 이 탭에서 다른 세션이 시작됐다 — 만진 파일 목록은 **앞 세션 것**이라 버린다.\r\n // 안 버리면 `변경` 탭의 '세션' 목록에 지난 세션이 고친 파일이 섞여 남는다\r\n this.touched.delete(tab);\r\n // 도는 중이던 서브에이전트도 앞 세션 것이다. 그 세션의 `SubagentStop` 은 이제 이\r\n // 탭으로 오지 않으므로(세션이 바뀌었다) 남겨 두면 영원히 안 지워지는 유령이 된다\r\n this.liveAgents.delete(tab);\r\n }\r\n const prevTab = this.sessionTab.get(sessionId);\r\n if (prevTab && prevTab !== tab && this.tabSession.get(prevTab) === sessionId) {\r\n this.tabSession.delete(prevTab);\r\n }\r\n this.sessionTab.set(sessionId, tab);\r\n this.tabSession.set(tab, sessionId);\r\n this.lastBindLog.delete(sessionId);\r\n this.diag(`bind sid=${sessionId.slice(0, 8)} via=${how} tab=${this.tabName(tab)}`\r\n + (prevOwner && prevOwner !== sessionId ? ` (took over from ${prevOwner.slice(0, 8)})` : ''));\r\n }\r\n /** 매칭 실패는 폴링마다 반복되므로 같은 내용은 한 번만 남긴다 */\r\n bindLog(sessionId, msg) {\r\n if (this.lastBindLog.get(sessionId) === msg) {\r\n return;\r\n }\r\n this.lastBindLog.set(sessionId, msg);\r\n this.diag(`bind sid=${sessionId.slice(0, 8)} ${msg}`);\r\n }\r\n // ---------- 서브에이전트 개수 (대화기록 증분 스캔) ----------\r\n /** 서브에이전트 개수를 세고 보일지 (`agentDeck.subagentCount`) */\r\n get subagentEnabled() {\r\n return this.config.store.agentDeck.subagentCount !== false;\r\n }\r\n /**\r\n * 이 탭에서 도는 에이전트가 알려 준 작업 폴더. 훅이 붙지 않은 탭(Codex·Gemini·맨 셸)은 null.\r\n *\r\n * 부르는 쪽(deck.service)은 이 값이 있으면 Tabby 의 추정을 쓰지 않는다 — 추정이 파일 경로를\r\n * 집어 오는 실사고가 있었다(NotifyFile.cwd 주석).\r\n */\r\n cwdOf(tab) {\r\n return (tab && this.hookCwd.get(tab)) || null;\r\n }\r\n /**\r\n * 이번 세션에서 에이전트가 고친 파일들 (절대경로, 최신 순). 훅이 없는 탭은 빈 배열.\r\n *\r\n * **빈 배열은 \"아무것도 안 고쳤다\" 가 아니라 \"모른다\" 로 읽어야 한다** — 훅이 없는\r\n * 에이전트(Codex·Gemini)와 아직 안 고친 세션이 같은 값이다. 그래서 `변경` 탭은 이게 비면\r\n * 목록을 좁히지 않고 저장소 전체를 그린다(빈 화면은 거짓말이 된다).\r\n */\r\n touchedOf(tab) {\r\n return (tab && this.touched.get(tab)) || [];\r\n }\r\n /**\r\n * 이 탭에서 도는 서브에이전트 — **사이드바가 쓰는 유일한 창구**. 없으면 null.\r\n *\r\n * 개수를 여기서 다시 세지 않는다(`subagents.ts` 가 센 것을 되읽는다). 툴팁만 부를 때마다\r\n * 만드는데, 거기에 **경과 시간**이 들어가기 때문이다 — 캐시하면 시계가 멈춘다.\r\n * 세션이 안 묶인 탭·꺼진 상태·0 개는 전부 null 로 떨어져 호출부가 조건을 따로 적을 일이 없다.\r\n */\r\n subagentsOf(tab) {\r\n var _a;\r\n if (!tab || !this.subagentEnabled) {\r\n return null;\r\n }\r\n const sid = this.tabSession.get(tab);\r\n // **훅을 받는 탭은 훅만 본다** (`agentHookSeen`). 대화기록 훑기는 그 세션의 옛 호출까지\r\n // 다시 세는 폴백이라, 훅이 \"지금 0개\" 라고 말한 뒤에 그것이 끼어들면 유령 숫자가 뜬다\r\n if (this.agentHookSeen.has(tab)) {\r\n const live = (0, subagents_1.summarizeLiveAgents)((_a = this.liveAgents.get(tab)) === null || _a === void 0 ? void 0 : _a.values());\r\n if (live.running <= 0) {\r\n return null;\r\n }\r\n const head = (0, subagents_1.formatLiveAgentTooltip)(live);\r\n return {\r\n sessionId: sid !== null && sid !== void 0 ? sid : '',\r\n running: live.running,\r\n // 목록(`items`)은 대화기록 쪽 구조라 여기서는 비운다 — 숫자와 다른 원천의 목록을\r\n // 섞으면 \"4개라면서 5줄\" 이 된다. 툴팁은 같은 원천(훅)으로만 만든다\r\n items: [],\r\n tooltip: live.oldestAt\r\n ? `${head}\\n가장 오래된 것: ${formatAge(Date.now() - live.oldestAt)} 전 시작`\r\n : head,\r\n };\r\n }\r\n const scan = sid ? this.scans.get(sid) : null;\r\n if (!scan || scan.summary.running <= 0) {\r\n return null;\r\n }\r\n return {\r\n sessionId: scan.sessionId,\r\n running: scan.summary.running,\r\n items: scan.summary.items,\r\n tooltip: this.subagentTooltip(scan.summary),\r\n };\r\n }\r\n /**\r\n * 툴팁 문장 = `formatSubagentTooltip()`(목록) + **가장 오래된 것의 경과 시간** 한 줄.\r\n *\r\n * **유령 카운트를 감추지 않는다** (2026-09-09 판단 확정). 사용자가 Esc 로 취소하거나 CLI 가\r\n * 죽으면 종료 알림이 안 남아 \"영구 1개\" 가 될 수 있는데, 임의 임계(예: 2시간 넘으면 제외)나\r\n * 세션 상태로 숨기는 처리를 넣지 않는다 —\r\n * ⓐ 백그라운드 에이전트가 도는 동안 **메인 세션 상태가 `대기` 인 것은 정상**이다. 그걸로\r\n * 숨기면 진짜로 도는 것을 지운다.\r\n * ⓑ 이 저장소의 원칙은 잘못된 상태를 조용한 폴백으로 덮지 않는 것이다. 숨겨 버리면 개수가\r\n * 맞는지 아무도 알 수 없고, 정작 사용자가 \"왜 안 보이나\" 를 물을 때 근거가 없다.\r\n * 대신 **경과 시간을 보여** 사람이 스스로 유령을 알아보게 한다 — 5분 된 3개와 이틀 된 1개는\r\n * 눈으로 갈린다. 시각의 원천은 호출 줄의 `timestamp`(`SubagentCall.startedAt`)다.\r\n */\r\n subagentTooltip(summary) {\r\n const head = (0, subagents_1.formatSubagentTooltip)(summary);\r\n if (!head) {\r\n return '';\r\n }\r\n let oldest = 0;\r\n for (const item of summary.items) {\r\n const at = item.startedAt ? Date.parse(item.startedAt) : NaN;\r\n if (Number.isFinite(at) && (!oldest || at < oldest)) {\r\n oldest = at;\r\n }\r\n }\r\n if (!oldest) {\r\n // 호출 줄에 timestamp 가 없었다 — 목록만 보여 준다 (없는 값을 만들어 내지 않는다)\r\n return head;\r\n }\r\n return `${head}\\n가장 오래된 것: ${formatAge(Date.now() - oldest)} 전 시작`\r\n + ' (종료 알림을 못 받은 것이면 이 값만 계속 늘어난다)';\r\n }\r\n /**\r\n * 지금 탭이 들고 있는 세션들 — `세션id -> 탭`.\r\n *\r\n * 사이드바의 \"지난 세션\" 목록이 이걸 본다. 살아 있는 세션은 이어받는 대신 그 탭으로 보내야\r\n * 하기 때문이다: 같은 세션을 두 탭에서 `--resume` 하면 두 프로세스가 같은 기록 파일에\r\n * 덧쓴다. 매핑은 이 서비스가 훅 보고로 이미 만들어 두었으니 판정에 드는 비용이 없다.\r\n *\r\n * 사본을 돌려준다 — 호출부가 들고 있는 동안 이쪽에서 지워도(`sessionTab.delete`) 순회가 깨지지 않게.\r\n */\r\n liveSessions() {\r\n return new Map(this.sessionTab);\r\n }\r\n /**\r\n * 탭에 묶인 세션들의 대화기록을 **자란 만큼만** 읽어 개수를 갱신한다 (2초마다).\r\n *\r\n * 매 주기에 하는 일은 `statSync().size` 비교뿐이다 — 안 자랐으면 파일을 아예 열지 않는다.\r\n * 자란 경우에만 그 구간을 스트림으로 읽고, 그 읽기는 **비동기**다: 실측 대화기록이\r\n * 13MB / 6,570줄이라 첫 스캔을 동기로 하면 그동안 Tabby UI 가 통째로 멈춘다.\r\n *\r\n * 상태 파일을 다시 읽지 않는다 — 세션 ↔ 탭 은 이 서비스가 이미 들고 있는 `sessionTab` 이\r\n * 정본이고(훅 보고로 채워진다), 같은 것을 두 곳에서 만들면 어긋난다.\r\n */\r\n scanSubagents() {\r\n if (!this.subagentEnabled) {\r\n // 끈 기능이 파일을 계속 읽고 있으면 안 된다. 들고 있던 상태도 버린다 — 꺼 둔 사이의\r\n // 호출·종료를 못 봤으므로 남겨 두면 종료 알림을 놓친 유령만 남는다. 다시 켜면 그때\r\n // 처음부터(파일 앞부터) 다시 센다\r\n if (this.scans.size) {\r\n this.scans.clear();\r\n }\r\n return;\r\n }\r\n this.pruneScans();\r\n for (const [sid, tab] of this.sessionTab) {\r\n if (!this.app.tabs.includes(tab)) {\r\n continue;\r\n }\r\n let scan = this.scans.get(sid);\r\n if (!scan) {\r\n scan = { sessionId: sid, state: (0, subagents_1.createSubagentState)(), decoder: new string_decoder_1.StringDecoder('utf8'),\r\n path: null, lastSize: 0, busy: false, lookupAt: 0, summary: (0, subagents_1.summarizeSubagents)(null) };\r\n this.scans.set(sid, scan);\r\n }\r\n if (scan.busy) {\r\n // 첫 스캔(13MB)이 아직 도는 중이다 — 겹쳐 읽으면 같은 구간을 두 번 먹인다\r\n continue;\r\n }\r\n if (!scan.path) {\r\n void this.findTranscript(scan);\r\n continue;\r\n }\r\n let size;\r\n try {\r\n size = fs.statSync(scan.path).size;\r\n }\r\n catch {\r\n // 파일이 사라졌다(세션 삭제·프로젝트 폴더 이동) — 경로부터 다시 찾는다.\r\n //\r\n // **집계도 같이 버린다.** 예전에는 경로만 비워서, 근거 파일이 없어진 뒤에도\r\n // 마지막 개수가 그대로 남아 `❖N` 칩이 영구히 붙어 있었다(파일이 다시 안 생기면\r\n // Tabby 재시작까지). 크기가 줄어드는 경로에만 리셋이 있어서 **삭제·이동은 리셋을\r\n // 못 탔다.** 근거를 잃었으면 숫자를 말하지 않는 것이 맞다 — 파일이 잠깐 안 보인\r\n // 것이었으면 다음 탐색에서 다시 찾아 처음부터 세면 되고, 그쪽이 틀린 수를\r\n // 계속 보여 주는 것보다 낫다.\r\n if (scan.lastSize > 0 || scan.summary.running > 0) {\r\n this.diag(`subagent gone sid=${sid.slice(0, 8)} running=${scan.summary.running} -> 0`);\r\n }\r\n this.resetScan(scan);\r\n scan.path = null;\r\n scan.lookupAt = 0;\r\n continue;\r\n }\r\n if (size < scan.lastSize) {\r\n // 잘렸거나 같은 이름으로 다른 파일이 왔다. 오프셋을 그대로 쓰면 파일 중간부터\r\n // 읽어 줄 경계가 어긋나고 decoder 도 엉뚱한 바이트를 이어 붙인다 — 처음부터 다시\r\n this.diag(`subagent reset sid=${sid.slice(0, 8)} size=${size} < last=${scan.lastSize}`);\r\n this.resetScan(scan);\r\n }\r\n if (size === scan.lastSize) {\r\n continue;\r\n }\r\n this.readGrowth(scan, size);\r\n }\r\n }\r\n /**\r\n * 탭이 닫히거나 세션이 다른 탭으로 넘어가면 그 스캔 상태를 버린다.\r\n *\r\n * `tabClosed$` 만 믿지 않고 매 주기에 표를 대조하는 이유 — 세션이 다른 탭에서 되살아나면\r\n * (`claude --resume`) 닫힘 이벤트 없이 `bind()` 가 이전 주인을 조용히 풀고, 그러면\r\n * `sessionTab` 에서 빠진 세션의 스캔만 남는다.\r\n */\r\n pruneScans() {\r\n for (const sid of [...this.scans.keys()]) {\r\n const tab = this.sessionTab.get(sid);\r\n if (!tab || !this.app.tabs.includes(tab)) {\r\n this.scans.delete(sid);\r\n }\r\n }\r\n }\r\n /** 상태·decoder·오프셋을 한 세트로 새로 만든다 (셋이 따로 놀면 글자가 깨지거나 개수가 틀어진다) */\r\n resetScan(scan) {\r\n scan.state = (0, subagents_1.createSubagentState)();\r\n scan.decoder = new string_decoder_1.StringDecoder('utf8');\r\n scan.lastSize = 0;\r\n scan.summary = (0, subagents_1.summarizeSubagents)(null);\r\n }\r\n /**\r\n * `~/.claude/projects/<프로젝트폴더>/<세션id>.jsonl` 을 찾는다.\r\n *\r\n * **폴더 이름 규칙을 흉내내지 않는다.** 그 이름은 작업 경로를 `-` 로 뭉갠 것인데 드라이브\r\n * 문자·대소문자·특수문자에서 어긋난다. 하위 폴더를 훑어 파일명을 세션 id 로 맞추면 폴더를\r\n * 몰라도 정확히 하나가 잡힌다 — 판정은 `subagents.ts` 의 `matchesSessionTranscript` 하나뿐이고\r\n * 여기에 사본을 두지 않는다.\r\n *\r\n * 비동기인 이유는 읽기와 같다(프로젝트가 수십 개면 readdir 도 공짜가 아니다). 못 찾으면\r\n * `TRANSCRIPT_LOOKUP_RETRY_MS` 뒤에 다시 본다 — 파일이 아직 안 생겼을 수 있다.\r\n */\r\n async findTranscript(scan) {\r\n const now = Date.now();\r\n if (now - scan.lookupAt < TRANSCRIPT_LOOKUP_RETRY_MS) {\r\n return;\r\n }\r\n scan.lookupAt = now;\r\n scan.busy = true;\r\n try {\r\n const dirs = await fs.promises.readdir(this.projectsDir, { withFileTypes: true });\r\n for (const entry of dirs) {\r\n if (!entry.isDirectory()) {\r\n continue;\r\n }\r\n const dir = path.join(this.projectsDir, entry.name);\r\n let names;\r\n try {\r\n names = await fs.promises.readdir(dir);\r\n }\r\n catch {\r\n // 권한·경합으로 못 읽는 폴더 하나 때문에 나머지를 포기하지 않는다\r\n continue;\r\n }\r\n const hit = names.find(name => (0, subagents_1.matchesSessionTranscript)(name, scan.sessionId));\r\n if (hit) {\r\n scan.path = path.join(dir, hit);\r\n this.diag(`subagent transcript sid=${scan.sessionId.slice(0, 8)} file=${scan.path}`);\r\n return;\r\n }\r\n }\r\n }\r\n catch {\r\n // `~/.claude/projects` 자체가 없다 — Claude Code 가 아닌 CLI 이거나 아직 한 번도 안 돌았다.\r\n // 개수는 0 으로 남고 사이드바에는 아무것도 안 그려진다(그게 맞는 표시다)\r\n }\r\n finally {\r\n scan.busy = false;\r\n }\r\n }\r\n /**\r\n * `lastSize` 부터 `size` 까지만 읽어 먹인다.\r\n *\r\n * 실패하면 `lastSize` 를 **올리지 않는다** — 다음 주기에 같은 구간을 다시 읽게 되는데, 같은\r\n * 줄을 두 번 먹여도 결과는 같다(`subagents.ts`: 호출은 이미 본 id 를 무시하고 종료는 Set).\r\n * 중간에 끊긴 조각이 앞에 붙어 생기는 깨진 줄은 그쪽에서 `skipped` 로 버린다.\r\n */\r\n readGrowth(scan, size) {\r\n const file = scan.path;\r\n if (!file) {\r\n return;\r\n }\r\n const from = scan.lastSize;\r\n const sid8 = scan.sessionId.slice(0, 8);\r\n scan.busy = true;\r\n let stream;\r\n try {\r\n stream = fs.createReadStream(file, { start: from, end: size - 1 });\r\n }\r\n catch (e) {\r\n // 스트림을 못 만들었다. **`busy` 를 반드시 되돌린다** — 여기서 true 로 남으면 그\r\n // 세션은 다시는 스캔되지 않고 개수가 조용히 멈춘 채로 굳는다(잘못된 상태를 조용히\r\n // 덮는 것이 이 저장소에서 가장 경계하는 실패 모양이다)\r\n scan.busy = false;\r\n (0, diag_1.diagCatch)(`subagent 스트림 생성 sid=${sid8}`, e);\r\n return;\r\n }\r\n let settled = false;\r\n const finish = (e) => {\r\n if (settled) {\r\n return;\r\n }\r\n settled = true;\r\n scan.busy = false;\r\n if (e) {\r\n (0, diag_1.diagCatch)(`subagent 대화기록 읽기 sid=${sid8}`, e);\r\n return;\r\n }\r\n scan.lastSize = size;\r\n const prev = scan.summary.running;\r\n scan.summary = (0, subagents_1.summarizeSubagents)(scan.state);\r\n if (from === 0) {\r\n // 첫 스캔은 늘 남긴다 — \"개수가 0\" 의 원인이 파일을 못 읽은 것인지 정말 없는\r\n // 것인지를 나중에 이 한 줄로 가른다\r\n this.diag(`subagent first-scan sid=${sid8} bytes=${size} lines=${scan.state.lines}`\r\n + ` calls=${scan.summary.calls} done=${scan.summary.done} running=${scan.summary.running}`);\r\n }\r\n else if (scan.summary.running !== prev) {\r\n this.diag(`subagent sid=${sid8} running=${prev} -> ${scan.summary.running} (+${size - from}B)`);\r\n }\r\n };\r\n // Buffer -> 문자열 변환은 decoder 에게 맡긴다 (멀티바이트 경계, `SubagentScan` 주석)\r\n stream.on('data', (chunk) => (0, subagents_1.feedChunk)(scan.state, scan.decoder.write(chunk)));\r\n stream.on('end', () => finish());\r\n stream.on('error', (e) => finish(e));\r\n }\r\n};\r\nWorkNotifyService = __decorate([\r\n (0, core_1.Injectable)({ providedIn: 'root' }),\r\n __metadata(\"design:paramtypes\", [tabby_core_1.AppService,\r\n tabby_core_1.ConfigService,\r\n status_service_1.WorkStatusService,\r\n tabby_core_1.PlatformService])\r\n], WorkNotifyService);\r\nexports.WorkNotifyService = WorkNotifyService;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.planEdgeScroll = exports.planTabMove = exports.sortTabsByStatus = exports.countByStatus = exports.statusRank = exports.STATUS_ORDER = void 0;\r\n/** 표시·정렬 우선순위. 앞이 더 급하다 */\r\nexports.STATUS_ORDER = ['waiting', 'error', 'limited', 'running', 'done', 'idle'];\r\n/** 우선순위 숫자 — 작을수록 앞. 모르는 값은 맨 뒤로 보낸다 */\r\nfunction statusRank(status) {\r\n const i = exports.STATUS_ORDER.indexOf(status);\r\n return i < 0 ? exports.STATUS_ORDER.length : i;\r\n}\r\nexports.statusRank = statusRank;\r\n/**\r\n * 상태별 개수. `STATUS_ORDER` 순서로, 0 인 상태는 빼고 돌려준다 — 헤더에 그대로 그리면 된다.\r\n */\r\nfunction countByStatus(tabs, statusOf) {\r\n var _a, _b;\r\n const counts = new Map();\r\n for (const tab of tabs) {\r\n const s = statusOf(tab);\r\n counts.set(s, ((_a = counts.get(s)) !== null && _a !== void 0 ? _a : 0) + 1);\r\n }\r\n const out = [];\r\n for (const s of exports.STATUS_ORDER) {\r\n const n = (_b = counts.get(s)) !== null && _b !== void 0 ? _b : 0;\r\n if (n > 0) {\r\n out.push({ status: s, count: n });\r\n }\r\n }\r\n return out;\r\n}\r\nexports.countByStatus = countByStatus;\r\n/**\r\n * 상태 우선순위로 정렬한 **복사본**. 같은 상태끼리는 원래 탭 순서를 지킨다(안정 정렬).\r\n * 원본 배열(`app.tabs`)은 건드리지 않는다 — Tabby 의 탭 순서는 사용자의 것이다.\r\n */\r\nfunction sortTabsByStatus(tabs, statusOf) {\r\n return tabs\r\n .map((tab, index) => ({ tab, index, rank: statusRank(statusOf(tab)) }))\r\n .sort((a, b) => a.rank - b.rank || a.index - b.index)\r\n .map(x => x.tab);\r\n}\r\nexports.sortTabsByStatus = sortTabsByStatus;\r\n/**\r\n * `from` 번째를 `to` 번째의 앞/뒤로 옮긴 **인덱스 순열**. 옮길 이유가 없으면 null.\r\n *\r\n * 배열도 탭도 모르는 순수 규칙으로 뽑아 둔 이유 둘 —\r\n * 1) `app.tabs` 를 흔드는 것은 되돌릴 수 없는 조작이다. \"어디로 가는가\" 를 DOM·포인터 없이\r\n * 확인할 수 있어야 한다.\r\n * 2) **제자리로 놓는 드래그를 걸러내는 곳**이 여기 하나여야 한다. 자기 바로 앞 줄의 뒤에\r\n * 놓는 것은 순열이 항등이므로 null 이 되고, 그러면 호출부가 `emitTabsChanged()` 를\r\n * 부르지 않는다 — 아무것도 안 바뀐 재배열로 순정 탭바를 다시 그리게 하지 않는다.\r\n *\r\n * **`deck.service.ts` 에서 여기로 옮겨 왔다** — 그 파일은 Angular/Tabby 를 import 해서\r\n * `package.json` 의 test 스크립트가 컴파일하는 순수 모듈 목록에 들어갈 수 없고, 그래서 이 함수엔\r\n * 유닛 테스트가 한 개도 없었다(손으로 떼어내 돌려보는 것이 전부였다). 순서를 다루는 순수 규칙이라\r\n * 정렬 규칙과 같은 자리가 맞고, 옮기자마자 위 1) 이 말한 \"DOM·포인터 없이 확인\" 이\r\n * `test/order.test.js` 의 전수 검사가 됐다. 구현은 한 줄도 바꾸지 않았다(실경로 R58 통과 상태).\r\n */\r\nfunction planTabMove(count, from, to, place) {\r\n if (!Number.isInteger(count) || count < 2) {\r\n return null;\r\n }\r\n if (!Number.isInteger(from) || !Number.isInteger(to)) {\r\n return null;\r\n }\r\n if (from < 0 || from >= count || to < 0 || to >= count || from === to) {\r\n return null;\r\n }\r\n const order = [];\r\n for (let i = 0; i < count; i++) {\r\n order.push(i);\r\n }\r\n order.splice(from, 1);\r\n // 뽑아낸 뒤의 자리를 다시 찾는다 — `to` 는 뽑기 전의 인덱스라 그대로 쓰면 한 칸 밀린다\r\n const at = order.indexOf(to) + (place === 'after' ? 1 : 0);\r\n order.splice(at, 0, from);\r\n for (let i = 0; i < count; i++) {\r\n if (order[i] !== i) {\r\n return order;\r\n }\r\n }\r\n return null;\r\n}\r\nexports.planTabMove = planTabMove;\r\n/**\r\n * 드래그 중 목록 가장자리 **자동 스크롤 속도** (px/s). 0 이면 스크롤할 이유가 없다.\r\n * 음수 = 목록 앞쪽(위/왼쪽), 양수 = 뒤쪽(아래/오른쪽).\r\n *\r\n * 0 을 주는 갈래 넷 —\r\n * 1) **목록 밖**: 목록 밖에서 손을 떼는 것은 취소 손짓이다(`dropTargetAt` 의\r\n * `outside-list`). 취소하려고 커서를 빼는 사람의 목록을 흘려 보내면 안 된다.\r\n * 2) 띠 밖(목록 가운데): 평범한 드롭을 방해하지 않는다.\r\n * 3) 그 방향으로 **더 갈 데가 없다**: 루프를 살려 두면 아무 일도 없이 매 프레임 돈다.\r\n * 4) 목록이 너무 짧아 띠가 성립하지 않는다.\r\n *\r\n * 띠를 `bandPx` 그대로 쓰지 않고 목록 길이의 1/3 로 깎는 것이 이 규칙의 핵심이다 —\r\n * 그래서 앞·뒤 띠는 **어떤 길이에서도 겹치지 않고**(각 1/3, 가운데 1/3 은 조용하다) 짧은\r\n * 목록에서 \"어디에 놓아도 화면이 흘러 놓기 자체가 불가능\" 해지는 일이 생기지 않는다.\r\n * 목록이 12px 보다 짧으면 띠가 4px 아래로 내려가 아예 성립하지 않는다(갈래 4).\r\n *\r\n * 상수(32 / 150 / 800)를 안으로 들이지 않고 **인자로 받는다** — 그 세 값의 근거는\r\n * 줄 높이(`.ad-tab`)와 모니터 주사율이라 `deck.service.ts` 의 상수 주석에 적혀 있고,\r\n * 사본을 여기 두면 둘 중 하나가 낡는다. 인자로 받으면 테스트가 띠·속도 조합을 직접\r\n * 만들어 경계 대칭·단조·상하한을 전수로 훑을 수 있다는 이득도 같이 온다.\r\n *\r\n * **`deck.service.ts` 의 `dragScrollSpeed` 에서 여기로 옮겨 왔다** — 그 파일은 Angular/Tabby\r\n * 를 import 해서 `package.json` 의 test 스크립트가 컴파일하는 순수 모듈 목록에 들어갈 수 없고,\r\n * 그래서 이 속도 램프는 실경로 프로브(RO9·RO13 의 `speed` 진단구)로만 검증됐다.\r\n * `planTabMove`·`stepNavIndex` 를 옮긴 것과 같은 이유·같은 방식이며, 구현은 이름만 인자로\r\n * 바꿨을 뿐 산술은 한 줄도 손대지 않았다(실경로 R73 통과 상태). 남은 `dragScrollSpeed` 는\r\n * rect·`scrollTop` 을 읽어 이 함수에 넘기는 껍데기다 — 경계를 그렇게 그은 이유는 DOM 을\r\n * 읽는 줄과 속도를 정하는 줄이 한 함수에 있으면 후자를 검사할 방법이 없어서다.\r\n */\r\nfunction planEdgeScroll(input) {\r\n const { pos, near, far, cur, maxScroll, bandPx, minPps, maxPps } = input;\r\n if (pos < near || pos > far) {\r\n return 0;\r\n }\r\n // 앞·뒤 띠가 겹치면 목록 어디에 커서를 두어도 화면이 흘러 **놓기 자체가 불가능**해진다\r\n const band = Math.min(bandPx, (far - near) / 3);\r\n if (band < 4) {\r\n return 0;\r\n }\r\n let dir = 0;\r\n let depth = 0;\r\n if (pos <= near + band) {\r\n dir = -1;\r\n depth = (near + band - pos) / band;\r\n }\r\n else if (pos >= far - band) {\r\n dir = 1;\r\n depth = (pos - (far - band)) / band;\r\n }\r\n else {\r\n return 0;\r\n }\r\n const left = dir < 0 ? cur : maxScroll - cur;\r\n if (left <= 0.5) {\r\n return 0;\r\n }\r\n const t = Math.min(1, Math.max(0, depth));\r\n return dir * (minPps + (maxPps - minPps) * t);\r\n}\r\nexports.planEdgeScroll = planEdgeScroll;\r\n","\"use strict\";\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckProfileService = exports.ROOT_PROFILE_ID = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\nexports.ROOT_PROFILE_ID = 'agentdeck:root';\r\n/**\r\n * 새 탭이 항상 작업 루트에서 열리게 한다.\r\n *\r\n * Tabby 프로필을 하나 만들어 config 에 심고, 사용자가 아직 기본 프로필을\r\n * 직접 고른 적이 없으면 이것을 기본으로 지정한다.\r\n * 한 번 심은 뒤에는 사용자가 설정에서 바꾼 값을 존중한다 (매 기동 덮어쓰지 않음).\r\n */\r\nlet AgentDeckProfileService = class AgentDeckProfileService {\r\n constructor(app, config) {\r\n this.app = app;\r\n this.config = config;\r\n }\r\n init() {\r\n this.app.ready$.subscribe(() => this.ensureProfile());\r\n }\r\n ensureProfile() {\r\n const cfg = this.config.store.agentDeck;\r\n // 경로를 안 정했으면 만들지 않는다 — 남의 홈 디렉토리에 엉뚱한 프로필을 심지 않기 위해\r\n if (!cfg.rootProfile || !cfg.rootProfileCwd) {\r\n return;\r\n }\r\n const profiles = this.config.store.profiles || [];\r\n const existing = profiles.find((p) => p.id === exports.ROOT_PROFILE_ID);\r\n const profile = {\r\n id: exports.ROOT_PROFILE_ID,\r\n type: 'local',\r\n name: cfg.rootProfileName || 'Agent Root',\r\n options: {\r\n command: cfg.rootProfileCommand || 'powershell.exe',\r\n args: [...(cfg.rootProfileArgs || [])],\r\n cwd: cfg.rootProfileCwd,\r\n env: { ...(cfg.rootProfileEnv || {}) },\r\n // 권한 승격은 이 플러그인이 다루지 않는다 — Tabby 를 어떤 권한으로 띄울지는 사용자의 몫이다.\r\n },\r\n };\r\n if (existing) {\r\n // 사용자가 설정 UI 에서 손댔을 수 있으므로 비어 있는 값만 보정한다\r\n if (!existing.options) {\r\n existing.options = profile.options;\r\n this.config.save();\r\n }\r\n else {\r\n let dirty = false;\r\n if (!existing.options.cwd) {\r\n existing.options.cwd = profile.options.cwd;\r\n dirty = true;\r\n }\r\n // npm 전역 .ps1 래퍼(claude 등)가 기본 실행 정책에 막히지 않도록 인자를 보정한다.\r\n // 사용자가 직접 인자를 넣어 뒀다면 건드리지 않는다.\r\n if (!existing.options.args || existing.options.args.length === 0) {\r\n existing.options.args = [...profile.options.args];\r\n dirty = true;\r\n }\r\n // 색 지원 환경변수는 사용자가 지정한 값을 덮지 않고 빠진 것만 채운다\r\n existing.options.env = existing.options.env || {};\r\n for (const [k, v] of Object.entries(profile.options.env)) {\r\n if (existing.options.env[k] === undefined) {\r\n existing.options.env[k] = v;\r\n dirty = true;\r\n }\r\n }\r\n if (dirty) {\r\n this.config.save();\r\n }\r\n }\r\n }\r\n else {\r\n profiles.push(profile);\r\n this.config.store.profiles = profiles;\r\n // 최초 1회만 기본 프로필로 지정\r\n if (!cfg.rootProfileClaimed) {\r\n this.config.store.terminal.profile = exports.ROOT_PROFILE_ID;\r\n cfg.rootProfileClaimed = true;\r\n }\r\n this.config.save();\r\n }\r\n }\r\n};\r\nAgentDeckProfileService = __decorate([\r\n (0, core_1.Injectable)({ providedIn: 'root' }),\r\n __metadata(\"design:paramtypes\", [tabby_core_1.AppService,\r\n tabby_core_1.ConfigService])\r\n], AgentDeckProfileService);\r\nexports.AgentDeckProfileService = AgentDeckProfileService;\r\n","\"use strict\";\r\n/**\r\n * cwd 가 속한 **프로젝트 루트**를 찾는다 — 사이드바 그룹 경계의 유일한 출처.\r\n *\r\n * 예전에는 사람이 설정(`groupRoot`)에 상위 폴더를 적어 두고 \"그 직하 한 단계\" 를 그룹으로\r\n * 삼았다. 그 규칙은 프로젝트들이 한 폴더에 나란히 있을 때만 맞고, `D:/Project/SoloLV/Root` 와\r\n * `D:/Project/tabby-agentdeck` 처럼 깊이가 다르면 어떤 값을 적어도 한쪽이 틀린다.\r\n * 그래서 설정을 없애고 **저장소 루트를 직접 찾는다** — 사람이 프로젝트라고 부르는 경계는\r\n * 사실상 버전관리의 경계이기 때문이다.\r\n *\r\n * 두 가지를 지킨다 —\r\n * 1. **렌더 중에 디스크를 훑지 않는다.** 조회는 캐시를 보고 즉시 돌아오고(`projectRootOf`),\r\n * 처음 보는 폴더는 백그라운드로 찾은 뒤 `onResolved` 로 다시 그리게 한다. cwd 는 탭이\r\n * 사는 동안 안 바뀌므로(group.ts 주석) 탭당 한 번이면 끝난다.\r\n * 2. **판정 규칙은 순수 함수로 둔다**(`walkUp`/`findProjectRoot`) — fs 없이 단위 테스트한다.\r\n *\r\n * 캐시는 프로세스 수명 동안 유지된다. 세션 도중 `git init` 을 한 폴더는 다음 기동에 잡힌다 —\r\n * 그걸 따라가려면 폴더를 계속 다시 물어야 하는데, 얻는 것에 비해 비용이 크다.\r\n */\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.projectRootCacheSnapshot = exports.clearProjectRootCache = exports.projectRootOf = exports.findProjectRoot = exports.walkUp = exports.homeBoundary = exports.PROJECT_MARKERS = void 0;\r\nconst fs = __importStar(require(\"fs\"));\r\nconst os = __importStar(require(\"os\"));\r\nconst group_1 = require(\"./group\");\r\n/**\r\n * 프로젝트 루트임을 알리는 표식. 위로 올라가며 **가장 먼저** 만나는 것이 루트다\r\n * (중첩 저장소·서브모듈에서는 가까운 쪽이 그 탭의 프로젝트다).\r\n *\r\n * `.git` 은 폴더가 아닐 수도 있다 — worktree·서브모듈에서는 파일이다. 그래서 존재만 본다.\r\n * `package.json` 류는 넣지 않았다: 모노레포·하위 패키지마다 있어서 프로젝트를 잘게 쪼갠다.\r\n */\r\nexports.PROJECT_MARKERS = ['.git', '.hg', '.svn', '.p4config'];\r\n/** 위로 올라가는 최대 단계 — 경로가 이상하게 길어도 여기서 멈춘다 */\r\nconst MAX_UP = 64;\r\n/**\r\n * **홈 디렉토리는 프로젝트가 아니다 — 거기서 멈춘다.**\r\n *\r\n * dotfiles 를 git 으로 관리하면 `~/.git` 이 있고(이 PC 가 그렇다), 그러면 홈 아래에서 띄운\r\n * 모든 탭 — `%LOCALAPPDATA%` 임시 폴더까지 — 이 `junggon` 이라는 한 그룹으로 빨려 들어간다.\r\n * 2026-09-11 실측: 한글 경로 검증용으로 연 탭이 그 폴더 대신 홈 그룹에 들어갔다.\r\n * 홈 위(`C:/Users`, `C:/`)도 같은 이유로 볼 필요가 없다.\r\n */\r\nfunction homeBoundary() {\r\n try {\r\n return (0, group_1.normalizeCwd)(os.homedir());\r\n }\r\n catch {\r\n return null;\r\n }\r\n}\r\nexports.homeBoundary = homeBoundary;\r\n/**\r\n * cwd 자신부터 루트까지 — `['D:/a/b', 'D:/a', 'D:/']`.\r\n *\r\n * `stopAt`(보통 홈)에 닿으면 **그 폴더를 빼고** 멈춘다 — 거기 있는 마커는 프로젝트 경계가 아니다.\r\n */\r\nfunction walkUp(cwd, stopAt) {\r\n let dir = (0, group_1.normalizeCwd)(cwd);\r\n const stop = (0, group_1.normalizeCwd)(stopAt);\r\n const out = [];\r\n for (let i = 0; dir && i < MAX_UP; i++) {\r\n if (stop && (0, group_1.foldGroupKey)(dir) === (0, group_1.foldGroupKey)(stop)) {\r\n break;\r\n }\r\n out.push(dir);\r\n const up = (0, group_1.parentPath)(dir);\r\n if (!up || (0, group_1.foldGroupKey)(up) === (0, group_1.foldGroupKey)(dir)) {\r\n break;\r\n }\r\n dir = up;\r\n }\r\n return out;\r\n}\r\nexports.walkUp = walkUp;\r\n/**\r\n * 표식을 가진 가장 가까운 조상 — 없으면 null(그때는 cwd 자체가 그룹이다).\r\n *\r\n * `hasMarker` 를 주입받는 이유는 테스트 때문만이 아니다 — 실제 조회는 비동기라\r\n * (`detect`) 이 함수는 \"어느 순서로 무엇을 묻는가\" 만 정하고 묻는 방법은 모른다.\r\n */\r\nfunction findProjectRoot(cwd, hasMarker, stopAt) {\r\n for (const dir of walkUp(cwd, stopAt)) {\r\n if (hasMarker(dir)) {\r\n return dir;\r\n }\r\n }\r\n return null;\r\n}\r\nexports.findProjectRoot = findProjectRoot;\r\n/** 폴딩한 cwd → 루트(없으면 null). `undefined` 는 \"아직 안 찾아봤다\" 와 구별하려고 안 넣는다 */\r\nconst cache = new Map();\r\n/** 지금 찾고 있는 폴더 — 같은 cwd 로 탭이 여럿이어도 한 번만 훑는다 */\r\nconst pending = new Set();\r\n/** 마커 하나가 있나 — 접근 실패(권한·끊긴 네트워크)는 \"없다\" 로 본다 */\r\nasync function hasMarkerAsync(dir) {\r\n for (const marker of exports.PROJECT_MARKERS) {\r\n try {\r\n await fs.promises.access(dir + '/' + marker);\r\n return true;\r\n }\r\n catch {\r\n // 다음 마커로\r\n }\r\n }\r\n return false;\r\n}\r\nasync function detect(cwd) {\r\n for (const dir of walkUp(cwd, homeBoundary())) {\r\n if (await hasMarkerAsync(dir)) {\r\n return dir;\r\n }\r\n }\r\n return null;\r\n}\r\n/**\r\n * 그룹 키 계산용 조회 — **절대 막히지 않는다.**\r\n *\r\n * 캐시에 있으면 그 값, 없으면 null 을 돌려주고 탐지를 백그라운드로 건다. 탐지가 끝나서\r\n * 그룹이 달라질 때만(`root` 를 찾았을 때만) `onResolved` 를 부른다 — 못 찾은 경우는\r\n * 키가 cwd 그대로라 화면이 바뀌지 않으므로 다시 그릴 이유가 없다.\r\n */\r\nfunction projectRootOf(cwd, onResolved) {\r\n const p = (0, group_1.normalizeCwd)(cwd);\r\n if (!p) {\r\n return null;\r\n }\r\n const id = (0, group_1.foldGroupKey)(p);\r\n const hit = cache.get(id);\r\n if (hit !== undefined) {\r\n return hit;\r\n }\r\n if (!pending.has(id)) {\r\n pending.add(id);\r\n detect(p).then(root => {\r\n cache.set(id, root);\r\n pending.delete(id);\r\n if (root) {\r\n onResolved === null || onResolved === void 0 ? void 0 : onResolved();\r\n }\r\n }).catch(() => {\r\n // 못 찾은 것으로 굳힌다 — 실패한 경로를 매 렌더마다 다시 훑지 않게\r\n cache.set(id, null);\r\n pending.delete(id);\r\n });\r\n }\r\n return null;\r\n}\r\nexports.projectRootOf = projectRootOf;\r\n/** 테스트·진단용 — 캐시를 비운다 (다음 조회가 다시 훑는다) */\r\nfunction clearProjectRootCache() {\r\n cache.clear();\r\n pending.clear();\r\n}\r\nexports.clearProjectRootCache = clearProjectRootCache;\r\n/** 진단용 — 지금까지 찾아 둔 것 (`__agentdeck.groups()` 가 보여준다) */\r\nfunction projectRootCacheSnapshot() {\r\n return [...cache.entries()].map(([cwd, root]) => ({ cwd, root }));\r\n}\r\nexports.projectRootCacheSnapshot = projectRootCacheSnapshot;\r\n","\"use strict\";\r\n/**\r\n * 터미널 화면에 그려진 입력창에서 지금 쓰여 있는 프롬프트를 뽑아낸다.\r\n *\r\n * 타이핑을 따로 세지 않고 화면을 읽는 이유 — 붙여넣기·↑ 히스토리·자동완성·IME 로 들어온 글자는\r\n * 키 이벤트로 안 오거나 원문과 다르다. 화면에 실제로 그려진 것이 곧 보낼 내용이다.\r\n *\r\n * 입력창 모양은 앱·버전마다 다르다. 옛 Claude Code / Codex 는 테두리 상자였고\r\n * ╭────────────────────╮\r\n * │ > 프롬프트 내용 │\r\n * ╰────────────────────╯\r\n * Claude Code 2.1.x 는 상자를 버리고 위아래 가로선 사이에 한 줄만 그린다.\r\n * ────────────────────────\r\n * ❯ 프롬프트 내용\r\n * ────────────────────────\r\n * ? for shortcuts\r\n * 머리글자도 ASCII `>` 가 아니라 `❯`(U+276F) 다 — 2026-09-01 화면 캡처로 확인.\r\n * `>` 만 찾던 정규식이 이걸 못 잡아 라벨이 한 번도 안 바뀌었다.\r\n *\r\n * 머리를 못 찾으면 빈 문자열을 준다 — 일반 셸이나 y/n 확인 같은 데서 엉뚱한 라벨이 박히느니\r\n * 라벨을 그대로 두는 편이 낫다.\r\n *\r\n * 화면 버퍼를 직접 받지 않고 줄 배열만 받는 순수 함수로 둔다 (xterm 없이 검증할 수 있게).\r\n *\r\n * **모양은 밖에서 주입한다** (`PromptShape`). 위 실측은 전부 Claude Code 화면이고,\r\n * Codex·Gemini 는 머리글자도 테두리도 다를 수 있다. 상수를 파일에 박아 두면 에이전트가\r\n * 늘 때마다 이 순수 함수를 고쳐야 한다 — 대신 글자 묶음을 인자로 받아 두면 에이전트별\r\n * 프로필이 그 자리에 값을 꽂는다. 인자를 안 주면 `DEFAULT_PROMPT_SHAPE`(= 여태 쓰던 값)다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.extractPrompt = exports.MAX_LABEL_LEN = exports.DEFAULT_PROMPT_SHAPE = void 0;\r\n/**\r\n * 여태 쓰던 값 그대로 — Claude Code 2.1.x 실측 기준 (2026-09-01 화면 캡처).\r\n *\r\n * - `heads`: ASCII `>` 와 꺾쇠 계열(❯ › ❭ ➜). Claude Code 2.1.x 는 `❯`(U+276F).\r\n * - `choiceWords`: 같은 꺾쇠를 선택지 커서로도 쓴다 (`❯ 1. Yes`). 번호 목록은 아래\r\n * 조립부에서 항상 배제하고, `Yes`/`No` 같은 무번호 선택지는 이 단어 목록으로 배제한다.\r\n * - `ruleChars`: 입력창 아래 테두리에 쓰이는 가로선 문자. ASCII `-` 도 넣어 둔다 —\r\n * 상자형 입력창을 ASCII 로 그리는 앱(`+------+`)이 있다.\r\n */\r\nexports.DEFAULT_PROMPT_SHAPE = {\r\n heads: ['>', '❯', '›', '❭', '➜'],\r\n choiceWords: ['Yes', 'No'],\r\n ruleChars: ['─', '━', '═', '-'],\r\n};\r\n/** 이보다 짧으면 라벨로 쓰지 않는다 (y/n 응답 등) */\r\nconst MIN_PROMPT_LEN = 2;\r\n/** 사이드바에 들어가는 라벨 길이 */\r\nexports.MAX_LABEL_LEN = 40;\r\n/**\r\n * 입력창 테두리로 보고 떼어낼 글자 (`stripBox`). 앞과 뒤가 조금 다르다 — 원래 값 그대로다.\r\n *\r\n * shape 로 빼지 않은 이유 — 유니코드 박스드로잉은 앱이 달라도 같은 글자를 쓰고(실측: 옛\r\n * Claude Code·Codex 둘 다 `╭─╮`), 여백을 과하게 떼어내도 프롬프트 내용이 상하지 않는다.\r\n * 다만 **shape 가 머리라고 선언한 글자는 여기서 뺀다** — `|` 는 테두리이기도 하고\r\n * 셸 스타일 입력창의 머리이기도 해서, 안 빼면 머리를 테두리로 알고 떼어내 버린다\r\n * (그러면 `head` 정규식이 못 맞아 프롬프트를 통째로 놓친다).\r\n */\r\nconst BOX_LEAD = '│┃|╭╰┌└─╮╯┐┘';\r\nconst BOX_TAIL = '│┃|╮╯┐┘─';\r\n/** 세로 테두리만 — 아래 테두리 줄(`│ ─── │`)의 좌우를 봐줄 때 쓴다 */\r\nconst BOX_VERT = '│┃|';\r\n/**\r\n * 정규식 본문에 리터럴로 박아도 안전하게.\r\n * 프로필이 `-`·`]`·`\\` 같은 글자를 머리로 줘도 조립이 깨지지 않아야 한다.\r\n */\r\nfunction reEscape(s) {\r\n return s.replace(/[\\\\^$.*+?()[\\]{}|/]/g, '\\\\$&');\r\n}\r\n/** 문자클래스 안에 박을 때 — 여기서 사고를 내는 건 `\\`·`]`·`^`·`-` 넷이다 */\r\nfunction classEscape(chars) {\r\n return chars.join('').replace(/[\\\\\\]^-]/g, '\\\\$&');\r\n}\r\n/**\r\n * 후보들을 교대(`a|b|c`)로 조립한다. **긴 것을 먼저** 놓는다 —\r\n * `['>', '>>']` 를 순서대로 두면 `>` 가 `>>` 를 가로채 한 글자만 먹는다.\r\n */\r\nfunction altOf(items) {\r\n return [...items].sort((a, b) => b.length - a.length).map(reEscape).join('|');\r\n}\r\n/** 빈 배열·타입 이상값은 조용히 기본값으로 떨어뜨린다 (프로필 일부만 준 경우) */\r\nfunction pick(given, fallback) {\r\n if (!Array.isArray(given)) {\r\n return fallback;\r\n }\r\n const kept = given.filter(s => typeof s === 'string' && s.length > 0);\r\n return kept.length ? kept : fallback;\r\n}\r\n/**\r\n * 조립 결과 캐시. `extractPrompt` 는 Enter 마다 도니까 정규식 다섯 개를 매번 새로 만들지 않는다.\r\n *\r\n * 키를 shape **객체 신원**이 아니라 **내용**으로 잡는 이유 — 호출부가 객체 리터럴을\r\n * 그때그때 만들어 넘겨도(테스트가 그렇게 한다) 캐시가 맞는다. 키 계산(JSON 문자열 몇십 자)은\r\n * `new RegExp` 다섯 번보다 훨씬 싸다. 서로 다른 프로필 수만큼만 늘어나므로 상한도 사실상 있다.\r\n */\r\nconst promptCache = new Map();\r\nfunction resolveShape(shape) {\r\n const heads = pick(shape ? shape.heads : undefined, exports.DEFAULT_PROMPT_SHAPE.heads);\r\n const choiceWords = pick(shape ? shape.choiceWords : undefined, exports.DEFAULT_PROMPT_SHAPE.choiceWords);\r\n const ruleChars = pick(shape ? shape.ruleChars : undefined, exports.DEFAULT_PROMPT_SHAPE.ruleChars);\r\n const key = JSON.stringify([heads, choiceWords, ruleChars]);\r\n const hit = promptCache.get(key);\r\n if (hit) {\r\n return hit;\r\n }\r\n const head = altOf(heads);\r\n const rule = classEscape(ruleChars);\r\n // 머리로 쓰이는 글자는 테두리 목록에서 빼낸다 (위 BOX_LEAD 주석 참조)\r\n const headChars = new Set(heads.join(''));\r\n const lead = classEscape([...BOX_LEAD].filter(c => !headChars.has(c)));\r\n const tail = classEscape([...BOX_TAIL].filter(c => !headChars.has(c)));\r\n const vert = classEscape([...BOX_VERT].filter(c => !headChars.has(c)));\r\n const made = {\r\n head: new RegExp(`^(?:${head})\\\\s*`),\r\n // 번호 목록(`1.` `2)`)은 어느 앱에서나 선택지라 shape 와 무관하게 항상 배제하고,\r\n // 무번호 선택지는 `choiceWords` 로 배제한다.\r\n //\r\n // 단어 끝을 `\\b` 가 아니라 `(?!\\w)` 로 잠그는 이유 — 한글 선택지(`예`/`아니오`)는\r\n // 마지막 글자가 `\\w` 가 아니어서 뒤에 `\\b` 가 생기지 않는다. `\\b` 로 조립하면\r\n // 한글 단어는 영영 안 맞는다. 영문 단어(`Yes`/`No`)에는 `\\b` 와 결과가 같다.\r\n choice: new RegExp(`^(?:${head})\\\\s*(?:\\\\d+[.)]\\\\s|(?:${altOf(choiceWords)})(?!\\\\w))`, 'i'),\r\n bottom: new RegExp(`^[\\\\s${vert}]*[${rule}]{3,}[\\\\s${vert}]*$|[╰└]`),\r\n stripLead: new RegExp(`^[\\\\s${lead}]+`),\r\n stripTail: new RegExp(`[\\\\s${tail}]+$`),\r\n };\r\n promptCache.set(key, made);\r\n return made;\r\n}\r\n/** 입력창 테두리(│ ┃ 등)와 좌우 여백을 떼어낸 알맹이 */\r\nfunction stripBox(line, re) {\r\n return line.replace(re.stripLead, '').replace(re.stripTail, '').trim();\r\n}\r\n/**\r\n * @param lines 화면에 그려진 줄 배열 (위에서 아래로)\r\n * @param shape 입력창 모양. 생략하면 `DEFAULT_PROMPT_SHAPE`(Claude Code 2.1.x 실측)\r\n */\r\nfunction extractPrompt(lines, shape) {\r\n const re = resolveShape(shape);\r\n // 아래에서 위로 머리 줄을 찾는다 (마지막 입력창이 곧 지금 입력창)\r\n let head = -1;\r\n for (let i = lines.length - 1; i >= 0; i--) {\r\n const body = stripBox(lines[i], re);\r\n if (!re.head.test(body)) {\r\n continue;\r\n }\r\n if (re.choice.test(body)) {\r\n return ''; // 선택지 커서 — 여기서 위로 더 올라가면 옛 프롬프트를 주워온다\r\n }\r\n head = i;\r\n break;\r\n }\r\n if (head < 0) {\r\n return '';\r\n }\r\n const parts = [stripBox(lines[head], re).replace(re.head, '')];\r\n for (let i = head + 1; i < lines.length; i++) {\r\n if (re.bottom.test(lines[i])) {\r\n break; // 입력창 끝 — 그 아래는 힌트 줄이라 프롬프트가 아니다\r\n }\r\n const body = stripBox(lines[i], re);\r\n if (body) {\r\n parts.push(body);\r\n }\r\n }\r\n const text = parts.join(' ').replace(/\\s+/g, ' ').trim();\r\n if (text.length < MIN_PROMPT_LEN) {\r\n return ''; // y/n 같은 한 글자 응답 — 라벨로 쓸 것이 못 된다\r\n }\r\n return text.length > exports.MAX_LABEL_LEN ? text.slice(0, exports.MAX_LABEL_LEN).trimEnd() + '...' : text;\r\n}\r\nexports.extractPrompt = extractPrompt;\r\n","\"use strict\";\r\n/**\r\n * 승인대기 이유 줄이기 — Notification 훅의 message 원문을 배지에 붙일 짧은 한국어로 바꾼다.\r\n *\r\n * 훅(hooks/agentdeck-notify.ps1)은 원문을 그대로 보내고, 줄이는 규칙은 여기 한 곳에만 둔다.\r\n * Claude Code 가 문구를 바꾸면 이 파일만 고치면 되고, 훅을 다시 설치할 필요가 없다.\r\n *\r\n * **훅이 없는 CLI 는 화면에서 온다** — `reasonFromScreen` 이 그 입구다(ANSI·테두리를 벗기고\r\n * 같은 축약 표를 태운다). 규칙을 두 곳에 두면 한쪽만 고쳐지므로 사본을 만들지 않는다.\r\n *\r\n * 알려진 문구 (2026-09 기준):\r\n * \"Claude needs your permission to use Bash\" -> \"Bash 권한\"\r\n * \"Claude is waiting for your input\" -> \"입력 대기\"\r\n * \"Allow execution of [Shell]?\" (Gemini CLI 화면) -> \"Shell 권한\"\r\n * 플랜 승인 / 질문 응답도 같은 요령으로 잡는다.\r\n * 한도 도달(StopFailure error=rate_limit 의 last_assistant_message):\r\n * \"You've hit your session limit · resets 12pm (Asia/Seoul)\" -> \"12pm 리셋\"\r\n * 리셋 시각이 없으면 빈 값 — 배지가 이미 `⛔ 한도 도달` 이라 같은 말을 되풀이하지 않는다.\r\n * 모르는 문구는 앞 24자만 남긴다 — 배지 한 줄을 넘기지 않기 위해서다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.reasonFromScreen = exports.shortenReason = void 0;\r\n/** 모르는 문구를 잘라 낼 길이 */\r\nconst UNKNOWN_MAX = 24;\r\nfunction shortenReason(msg) {\r\n const m = (msg || '').replace(/\\s+/g, ' ').trim();\r\n if (!m) {\r\n return '';\r\n }\r\n // 선택지 줄은 이유가 아니다 — `❯ 1. Yes`(claude) / `● 1. Allow once`(gemini 국면③ 원문).\r\n // 화면 경로에서는 커서만 움직인 재그리기 조각에 **이 줄만** 담겨 오는 일이 있는데, 그것을\r\n // 이유로 삼으면 배지에 `1. Yes` 가 박힌다. 빈 값을 주면 화면 판정 쪽이 앞서 잡은 이유를\r\n // 그대로 남긴다(`detect.ts` 는 빈 이유로 덮지 않는다)\r\n if (/^[^\\w가-힣]*\\d+\\.\\s/.test(m)) {\r\n return '';\r\n }\r\n // 도구 승인 — 도구 이름만 남긴다 (Bash, Edit, Write, mcp__vs-mcp__Xxx …). MCP 이름의 '-' 도 포함\r\n const tool = /permission to use ([\\w-]+)/i.exec(m);\r\n if (tool) {\r\n return tool[1] + ' 권한';\r\n }\r\n // Gemini CLI 의 승인 대화상자 — 도구 이름만 남긴다.\r\n // 원문 `│ Allow execution of [Shell]? │` (2026-09-08 국면③ 채집, docs/AGENT-OBSERVATION.md).\r\n // 대괄호는 화면 장식이라 벗기고, 이름 문자만 받는다 — `?` 나 테두리가 이름에 붙지 않게\r\n const allow = /Allow execution of\\s*\\[?([\\w.:-]+)/i.exec(m);\r\n if (allow) {\r\n return allow[1] + ' 권한';\r\n }\r\n if (/waiting for your input/i.test(m)) {\r\n return '입력 대기';\r\n }\r\n // 한도 도달 — 리셋 시각만 남긴다. 실측 문구 3형:\r\n // \"You've hit your session limit · resets 12pm (Asia/Seoul)\"\r\n // \"You've reached your weekly limit · resets Monday 9am\"\r\n // \"Claude usage limit reached. Your limit will reset at 7pm (Asia/Seoul).\"\r\n if (/\\b(?:hit|reached|exceeded)\\b.*\\blimit\\b|usage limit|limit reached|limit will reset/i.test(m)) {\r\n const reset = /\\breset(?:s)?\\s+(?:at\\s+)?(.+?)\\s*(?:\\(|\\.\\s*$|$)/i.exec(m);\r\n return reset ? reset[1].trim() + ' 리셋' : '';\r\n }\r\n if (/plan/i.test(m)) {\r\n return '플랜 승인';\r\n }\r\n if (/question|answer/i.test(m)) {\r\n return '질문 응답';\r\n }\r\n return m.slice(0, UNKNOWN_MAX).trimEnd();\r\n}\r\nexports.shortenReason = shortenReason;\r\n/**\r\n * **화면에서 뽑은 줄**을 배지에 붙일 이유로 바꾼다 — 훅 문구용 `shortenReason` 을 그대로 태우고,\r\n * 화면에만 있는 잡음(ANSI 제어열 · TUI 테두리)을 먼저 벗기는 것만 다르다.\r\n *\r\n * 왜 여기 두나 — 축약 규칙의 사본을 만들면 한쪽만 고쳐진다. 훅이 있는 탭과 없는 탭의 배지 문구가\r\n * 같아야 사이드바를 훑어 어느 세션을 먼저 볼지 정할 수 있다(그게 이유를 붙이는 목적이다).\r\n *\r\n * 벗기는 것: CSI(색·커서 이동) · OSC/DCS · 남은 ESC 한 글자 · 박스드로잉(U+2500~257F)과\r\n * 블록(U+2580~259F) 테두리. **`●`(U+25CF)·`■`(U+25A0)·`❯`(U+276F) 는 남긴다** — 선택지 커서와\r\n * 오류 표식이라 위 규칙들이 그것을 보고 판정한다(선택지 줄 → 빈 이유).\r\n */\r\nfunction reasonFromScreen(line) {\r\n const clean = (line || '')\r\n // CSI (색·커서 이동) — TUI 한 줄에 이게 여러 개 섞여 있다\r\n .replace(/\\u001b\\[[0-9;?]*[ -/]*[@-~]/g, '')\r\n // OSC / DCS — 종결자는 BEL 또는 ESC \\\r\n .replace(/\\u001b[\\]P][^\\u0007\\u001b]*(?:\\u0007|\\u001b\\\\)?/g, '')\r\n // 청크 경계에 걸쳐 와 종결자가 없는 조각에 남은 ESC 한 글자\r\n .replace(/\\u001b/g, ' ')\r\n // 박스드로잉(│ 등) · 반블록(▄ ▀) 테두리 — 글자가 아니라 상자다\r\n .replace(/[\\u2500-\\u259f]/g, ' ')\r\n .replace(/\\s+/g, ' ')\r\n .trim();\r\n return shortenReason(clean);\r\n}\r\nexports.reasonFromScreen = reasonFromScreen;\r\n","\"use strict\";\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckRecoveryService = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\n/**\r\n * \"기동 시 탭 복원 끄기\" — Tabby 의 `recoverTabs` 를 강제로 false 에 묶는다.\r\n *\r\n * 왜 따로 있나: Tabby 는 종료 때 열려 있던 탭을 `localStorage.tabsRecovery` 에 저장하고\r\n * 다음 기동에서 `config.store.recoverTabs` 가 참이면 되살린다(tabby-core/dist/index.js:5003).\r\n * 그런데 복원되는 것은 **셸만**이다 — 그 안에서 돌던 Claude Code 세션은 이미 죽어 있어\r\n * 되살아난 탭은 빈 프롬프트일 뿐이고, 사이드바에는 주인 없는 탭이 줄줄이 남는다.\r\n * 그래서 사용자가 고르면 \"무조건 빈 상태로 시작\" 을 보장한다.\r\n *\r\n * 두 상태만 있다:\r\n * - `agentDeck.noTabRecovery = false` : 순정. Tabby 의 `recoverTabs` 값을 건드리지 않는다.\r\n * - `agentDeck.noTabRecovery = true` : 무조건 끔. Tabby 설정 창에서 `recoverTabs` 를 다시 켜도\r\n * 기동 때와 설정이 바뀔 때마다 false 로 되돌린다(`enforce`).\r\n *\r\n * 기동 분기(5003)는 `config.ready$` 직후라 플러그인보다 먼저 지나간다 — 그래서 값은 토글 순간에\r\n * config.yaml 에 써 두고, 여기서는 그 뒤로 누가 뒤집어 놓는 경우만 막는다.\r\n */\r\nlet AgentDeckRecoveryService = class AgentDeckRecoveryService {\r\n constructor(app, config) {\r\n this.app = app;\r\n this.config = config;\r\n }\r\n init() {\r\n this.app.ready$.subscribe(() => this.enforce());\r\n this.config.changed$.subscribe(() => this.enforce());\r\n }\r\n /**\r\n * 토글 진입점. 켜면 `recoverTabs=false` + 이미 저장된 복원 목록도 지운다 —\r\n * 남겨 두면 나중에 순정으로 되돌렸을 때 그때의 낡은 탭들이 되살아난다.\r\n * 끄면 Tabby 기본값(true)으로 되돌린다.\r\n */\r\n setNoTabRecovery(on) {\r\n this.config.store.agentDeck.noTabRecovery = on;\r\n this.config.store.recoverTabs = !on;\r\n if (on) {\r\n try {\r\n delete window.localStorage.tabsRecovery;\r\n }\r\n catch { /* 격리/비브라우저 환경 — 없으면 지울 것도 없다 */ }\r\n }\r\n this.config.save();\r\n }\r\n /** noTabRecovery 가 켜져 있는데 recoverTabs 가 참으로 돌아와 있으면 다시 끈다. 필요할 때만 저장한다 */\r\n enforce() {\r\n var _a;\r\n if (!((_a = this.config.store.agentDeck) === null || _a === void 0 ? void 0 : _a.noTabRecovery) || this.config.store.recoverTabs === false) {\r\n return;\r\n }\r\n this.config.store.recoverTabs = false;\r\n this.config.save();\r\n }\r\n};\r\nAgentDeckRecoveryService = __decorate([\r\n (0, core_1.Injectable)({ providedIn: 'root' }),\r\n __metadata(\"design:paramtypes\", [tabby_core_1.AppService,\r\n tabby_core_1.ConfigService])\r\n], AgentDeckRecoveryService);\r\nexports.AgentDeckRecoveryService = AgentDeckRecoveryService;\r\n","\"use strict\";\r\n/**\r\n * 터미널 화면이 깨졌는지 판정한다.\r\n *\r\n * \"깨졌다\" 의 정체는 하나다 — **TUI 가 아는 폭과 xterm 이 가진 폭이 다르다.**\r\n * 그러면 TUI 가 그린 한 행이 xterm 에서 두 행으로 접히거나(폭이 더 크다),\r\n * 행 오른쪽에 옛 프레임이 남는다(폭이 더 작다). 눈으로는 \"입력창 구분선이 중간에서 끊긴다\",\r\n * \"가로선과 입력 텍스트가 한 줄에 섞인다\" 로 보인다.\r\n *\r\n * 정상 화면의 모양은 실측해서 확정했다 (2026-09-01, Claude Code 2.1.x, CDP 로 xterm 버퍼 원문).\r\n * 사이드바를 켠 창(cols=280)과 순정 창(cols=360) 양쪽에서 완전히 같은 구조가 나왔다.\r\n *\r\n * 71 wrapped=0 len=278 \" … ● high · /effort\" ← 오른쪽 정렬 힌트\r\n * 72 wrapped=0 len=280 \"──────────────────────────────────────────────────\" ← len == cols\r\n * 73 wrapped=1 len= 1 \"❯\" ← wrapped=1 이 정상\r\n * 74 wrapped=0 len=280 \"──────────────────────────────────────────────────\" ← len == cols\r\n * 75 wrapped=0 len=155 \" ⚠ Transcript saving is off — …\"\r\n * 76 wrapped=0 len= 58 \" ⏱ 1s 컨텍스트 사용량: …\"\r\n * 77 wrapped=0 len= 38 \" ⏵⏵ auto mode on (shift+tab to cycle)\"\r\n *\r\n * 여기서 놓치기 쉬운 세 가지 —\r\n * - 가로선은 **cols 를 정확히 꽉 채운다**. 그래서 그 다음 줄에 `wrapped=1` 이 붙는 것은\r\n * xterm 의 pending-wrap 이고 **정상이다**. `wrapped` 만 보고 깨졌다고 판정하면 안 된다.\r\n * - 프롬프트 오른쪽에 오는 힌트(`● high · /effort`, `Try \"how does …\"`)는 **별도 줄**이다.\r\n * 프롬프트 줄과 같은 줄에 두 개의 머리(`❯`/`>`)가 보이면 그것이 깨진 화면이다.\r\n * - **폭이 다 맞아도 깨진 화면이 있다.** 테두리 두 줄이 맞붙어 `❯` 가 들어갈 행이\r\n * 사라지는 모양인데, 두 테두리 모두 cols 를 꽉 채우므로 폭 기준 판정은 전부 통과한다\r\n * (2026-09-02: 사람 눈으로도 이 도구로도 \"정상\" 이라고 오판했다). 그래서 폭만이 아니라\r\n * **입력할 자리가 있는가**(테두리 사이 간격 ≥ 2)를 같이 본다.\r\n *\r\n * xterm 없이 검증할 수 있도록 줄 배열만 받는 순수 함수로 둔다.\r\n *\r\n * **글자 묶음은 밖에서 주입한다** (`ScreenShape`). 위 실측은 전부 Claude Code 화면이라\r\n * 테두리 문자·머리글자를 파일에 박아 두면 다른 에이전트가 늘 때 이 순수 함수를 고쳐야 한다.\r\n * 인자를 안 주면 `DEFAULT_SCREEN_SHAPE`(= 여태 쓰던 값)로 지금과 똑같이 판정한다.\r\n * **판정 규칙 자체(테두리가 cols 를 꽉 채운다, 테두리 사이 간격 ≥ 2)는 shape 로 빼지 않았다** —\r\n * 그건 글자 모양이 아니라 \"가로선 2줄 + 입력줄 1줄\" 이라는 배치 가정이고, 실측 근거가\r\n * Claude Code 화면 하나뿐이다. 다른 앱 실측이 생기면 그때 규칙을 손댈 자리다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.judgeScreen = exports.isGhostRuleRow = exports.isRuleRow = exports.sizeInSync = exports.INPUT_TAIL = exports.DEFAULT_SCREEN_SHAPE = void 0;\r\n/**\r\n * 여태 쓰던 값 그대로 — Claude Code 2.1.x 실측 기준.\r\n *\r\n * `ruleChars` 에 ASCII `-` 가 없는 것은 의도다(원래 값 그대로 옮겼다). 이 판정은 화면\r\n * 전체를 훑기 때문에, `-` 를 넣으면 코드·마크다운 출력의 `-----` 줄이 입력창 테두리로\r\n * 세어지고 \"폭이 안 맞는 테두리\" 오탐이 쏟아진다. 실측 골든의 테두리는 전부 U+2500 계열이다.\r\n *\r\n * `choiceWords` 의 `Yes`/`No` 는 Claude Code 확인창 문구다 — 다른 에이전트·다른 언어에서는\r\n * 다른 단어이므로 상수로 박아 두지 않고 여기 기본값으로만 둔다.\r\n */\r\nexports.DEFAULT_SCREEN_SHAPE = {\r\n ruleChars: ['─', '━', '═'],\r\n heads: ['>', '❯', '›', '❭', '➜'],\r\n choiceWords: ['Yes', 'No'],\r\n};\r\n// 아래 세 헬퍼는 `prompt.ts` 에도 같은 것이 있다. 공유 파일로 빼지 않은 이유 —\r\n// 두 모듈은 순수 함수 단위로 따로 컴파일해 따로 테스트하고(`npm test` 가 파일 목록을\r\n// 직접 나열한다), 서로를 import 하지 않는 것이 이 파일들의 규약이다. 열 줄을 아끼려고\r\n// 의존을 만들 자리가 아니다.\r\n/** 정규식 본문에 리터럴로 박아도 안전하게 (`-`·`]`·`\\` 가 들어와도 안 깨지게) */\r\nfunction reEscape(s) {\r\n return s.replace(/[\\\\^$.*+?()[\\]{}|/]/g, '\\\\$&');\r\n}\r\n/** 문자클래스 안에 박을 때 — 사고를 내는 건 `\\`·`]`·`^`·`-` 넷이다 */\r\nfunction classEscape(chars) {\r\n return chars.join('').replace(/[\\\\\\]^-]/g, '\\\\$&');\r\n}\r\n/** 후보들을 교대(`a|b|c`)로. **긴 것을 먼저** — `>` 가 `>>` 를 가로채지 않게 */\r\nfunction altOf(items) {\r\n return [...items].sort((a, b) => b.length - a.length).map(reEscape).join('|');\r\n}\r\n/** 빈 배열·타입 이상값은 조용히 기본값으로 (프로필 일부만 준 경우) */\r\nfunction pick(given, fallback) {\r\n if (!Array.isArray(given)) {\r\n return fallback;\r\n }\r\n const kept = given.filter(s => typeof s === 'string' && s.length > 0);\r\n return kept.length ? kept : fallback;\r\n}\r\n/**\r\n * 조립 결과 캐시. `judgeScreen` 은 2초마다 **전 탭**에 도니까 정규식 다섯 개를\r\n * 매번 새로 만들지 않는다. 키를 객체 신원이 아니라 내용으로 잡는 이유는 `prompt.ts` 와 같다.\r\n */\r\nconst screenCache = new Map();\r\nfunction resolveShape(shape) {\r\n const ruleChars = pick(shape ? shape.ruleChars : undefined, exports.DEFAULT_SCREEN_SHAPE.ruleChars);\r\n const heads = pick(shape ? shape.heads : undefined, exports.DEFAULT_SCREEN_SHAPE.heads);\r\n const choiceWords = pick(shape ? shape.choiceWords : undefined, exports.DEFAULT_SCREEN_SHAPE.choiceWords);\r\n const key = JSON.stringify([ruleChars, heads, choiceWords]);\r\n const hit = screenCache.get(key);\r\n if (hit) {\r\n return hit;\r\n }\r\n const rule = classEscape(ruleChars);\r\n const head = altOf(heads);\r\n const made = {\r\n rule: new RegExp(`^[${rule}]{2,}$`),\r\n head: new RegExp(`^(?:${head})(?:\\\\s|$)`),\r\n headAnywhere: new RegExp(`(?:${head})(?:\\\\s|$)`),\r\n // 번호 목록은 앱과 무관하게 늘 선택지라 항상 배제한다. 무번호 선택지는 단어 목록으로.\r\n // 단어 끝을 `\\b` 대신 `(?!\\w)` 로 잠그는 이유 — 한글 선택지(`예`/`아니오`)는 마지막\r\n // 글자가 `\\w` 가 아니어서 `\\b` 가 생기지 않는다. 영문 단어에는 `\\b` 와 결과가 같다.\r\n choice: new RegExp(`^(?:${head})\\\\s*(?:\\\\d+[.)]\\\\s|(?:${altOf(choiceWords)})(?!\\\\w))`, 'i'),\r\n ruleChar: new RegExp(`[${rule}]`),\r\n ruleCharAll: new RegExp(`[${rule}]`, 'g'),\r\n };\r\n screenCache.set(key, made);\r\n return made;\r\n}\r\n/**\r\n * 입력창이 있는 구간 — 화면 맨 아래 이만큼만 본다.\r\n *\r\n * 입력창은 언제나 화면 맨 아래에 있고, 대화 이력에 남은 옛 입력창까지 같은 규칙으로 보면\r\n * 오탐이 쏟아진다. `deck.service.ts` 의 `clearInputArea` 가 잔상을 지울 때 쓰는 창과 같은 값이다.\r\n */\r\nexports.INPUT_TAIL = 16;\r\n/**\r\n * xterm 이 가진 크기와 pty 에 알려 둔 크기가 **맞나**.\r\n *\r\n * 자동복구를 켤 수 있느냐가 이 하나에 달려 있다. 2026-09-09 실사용 채증 8건이 정확히 둘로 갈렸다 —\r\n *\r\n * xterm != pty : 00:46:54 (280/283) · 01:13:20 (281/279) · 01:59:08 (221/281) · 02:34:21 (282/280)\r\n * → 전부 **리사이즈 중간 프레임**. 화면 덤프는 앱 기준 정상이고 0~3초 만에\r\n * 스스로 돌아왔다. Tabby 순정이 pty 까지 맞춘다 — 우리가 손대면 화면만 흔들린다.\r\n * xterm == pty : 02:07:45 ~ 02:08:01 (281/281, 4샘플)\r\n * → 자식 프로세스 stdout 이 TUI 를 덮어쓴 **진짜 깨짐**. 26초를 버텼고\r\n * `clearInputArea` + `Ctrl+L` 로 고쳐진다.\r\n *\r\n * 2026-09-02 에 자동복구를 껐던 \"실사용 4/4 실패\" 가 앞 유형에 손댄 것이었다.\r\n * 그래서 판정은 `judgeScreen`(화면 모양)과 **따로** 둔다 — 깨진 것은 맞는데 우리 일이 아닌 경우다.\r\n *\r\n * pty 크기를 아직 못 읽은 경우(`undefined`)는 **맞다고 본다** — 모르는 것을 이유로 복구를\r\n * 막으면 크기 정보가 없는 프론트엔드에서 기능이 통째로 죽는다.\r\n */\r\nfunction sizeInSync(xcols, xrows, sentCols, sentRows) {\r\n if (!(typeof xcols === 'number' && xcols > 1)) {\r\n return true;\r\n }\r\n if (typeof sentCols !== 'number' || typeof sentRows !== 'number') {\r\n return true;\r\n }\r\n return sentCols === xcols && sentRows === xrows;\r\n}\r\nexports.sizeInSync = sizeInSync;\r\n/** 가로선 문자만으로 된 줄인가 (입력창 위/아래 테두리) */\r\nfunction isRuleRow(text, shape) {\r\n return resolveShape(shape).rule.test(text.trim());\r\n}\r\nexports.isRuleRow = isRuleRow;\r\n/**\r\n * 테두리 행이 \"거의 다 가로선\" 이라고 볼 최소 비율.\r\n *\r\n * 문자열 길이로 `== cols` 를 볼 수 없어서 비율로 잰다 — xterm 의 `translateToString` 은\r\n * **전각 글자를 한 글자로** 돌려주므로(둘째 칸은 빈 셀) 한글이 섞인 행은 문자열 길이가\r\n * cols 보다 짧다 (실측 채증: cols=281 화면의 한글 행이 `len=134`).\r\n * 잔상은 몇 글자짜리라 가로선이 압도적으로 많다.\r\n */\r\nconst GHOST_RULE_RATIO = 0.6;\r\n/**\r\n * 잔상이 얹힌 테두리 행인가 — 양끝은 가로선인데 가운데에 옛 프레임 글자가 남았다.\r\n *\r\n * `judgeScreen` 의 같은 규칙을 밖에서도 쓰려고 뺐다. 복구(`clearInputArea`)가 입력창의\r\n * 시작 행을 찾을 때 이 행을 **테두리로 쳐 줘야** 잔상 위에서부터 지우기가 시작된다 —\r\n * 순수 가로선만 찾으면 이 행을 못 보고 입력창 아래를 지워 아무것도 안 고쳐진다.\r\n *\r\n * **양끝이 가로선인 줄만** 본다 — 상자형 입력창(`╭──╮`)은 모서리로 시작·끝나므로 안 걸린다.\r\n * 대화 출력의 짧은 구분선(`── 요약 ──`)은 가로선 비율에서 걸러진다.\r\n */\r\nfunction isGhostRuleRow(text, cols, shape) {\r\n const re = resolveShape(shape);\r\n const body = text.replace(/\\s+$/, '');\r\n if (!(cols > 1) || body.length < 2 || re.rule.test(body)) {\r\n return false;\r\n }\r\n if (!re.ruleChar.test(body[0]) || !re.ruleChar.test(body[body.length - 1])) {\r\n return false;\r\n }\r\n const ruleCount = (body.match(re.ruleCharAll) || []).length;\r\n return ruleCount >= cols * GHOST_RULE_RATIO;\r\n}\r\nexports.isGhostRuleRow = isGhostRuleRow;\r\n/**\r\n * @param lines 화면에 그려진 줄 배열 (위에서 아래로)\r\n * @param cols xterm 이 가진 화면 폭\r\n * @param shape 입력창 글자 묶음. 생략하면 `DEFAULT_SCREEN_SHAPE`(Claude Code 2.1.x 실측)\r\n */\r\nfunction judgeScreen(lines, cols, shape) {\r\n const re = resolveShape(shape);\r\n const reasons = [];\r\n if (!(cols > 1) || !lines.length) {\r\n return { broken: false, reasons: [] };\r\n }\r\n const rules = [];\r\n const heads = [];\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i];\r\n const body = line.text.replace(/\\s+$/, '');\r\n if (!body) {\r\n continue;\r\n }\r\n if (re.rule.test(body)) {\r\n rules.push(i);\r\n // 테두리는 화면 폭을 꽉 채운다. 짧으면 TUI 가 더 좁은 폭으로 그린 것이고,\r\n // 그보다 짧은 자투리 줄이면 넘쳐 접힌 꼬리다 — 어느 쪽이든 폭이 어긋났다.\r\n //\r\n // 2026-09-02: `cols - 1` 도 정상으로 봐주도록 한 번 완화했다가 되돌렸다.\r\n // 근거로 삼은 `len=279` 스냅샷이 **전부 깨짐으로 판정된 화면**이었고,\r\n // 같은 로그의 정상 표본(`auto-after 복구됨`)은 `len == cols == 280` 이었다.\r\n // 병상 표본을 정상 기준으로 삼으면 안 된다.\r\n if (body.length !== cols) {\r\n reasons.push(`rule@${i} len=${body.length} != cols=${cols}`);\r\n }\r\n continue;\r\n }\r\n // **테두리 행 한가운데에 옛 프레임 글자가 남았다** (2026-09-09 실사용 스샷 픽셀 복원).\r\n //\r\n // Ctrl+Enter 로 입력창이 여러 줄로 자라면 화면이 한 줄 밀리는데, 앱은 자기가 아는\r\n // 자리에 테두리를 다시 그린다. 그 행에 있던 옛 글자는 앱이 덮지 않는 칸에 그대로 남는다.\r\n // 채증(387x157 스샷, 셀폭 7px·행높이 17px)의 테두리 행 잉크 구간이 그 증거다 —\r\n // `19-46`(가로선) `49-57 63-71 77-85`(전각 글자 3개) `89-385`(가로선)\r\n //\r\n // 이 모양은 여태 **정상으로 통과했다.** 테두리 행이 순수 가로선이 아니라 `rules` 에\r\n // 안 들어가고, 머리글자가 없어 `mixed` 도 아니고, 그래서 `아래 테두리가 없다`·`lens 섞임`\r\n // 까지 전부 비껴간다. 판정의 구멍이었다 (재현 케이스는 test/screen.test.js 에 고정).\r\n //\r\n // 판정은 `isGhostRuleRow` 하나로 모아 뒀다 — 복구(`clearInputArea`)가 입력창의 시작\r\n // 행을 찾을 때 **같은 규칙**을 써야 \"깨졌다고 하면서 그 자리를 못 지운다\" 가 안 생긴다.\r\n // 화면 하단 구간(`INPUT_TAIL`)으로 좁히는 것은 여기서만 한다 — 대화 이력에 스크롤되어\r\n // 남은 옛 화면까지 깨짐으로 세면 오탐이 쏟아진다.\r\n if (i >= lines.length - exports.INPUT_TAIL && isGhostRuleRow(body, cols, shape)) {\r\n reasons.push(`테두리 행에 옛 글자가 남았다@${i} ${JSON.stringify(body.slice(0, 40))}`);\r\n }\r\n // 가로선과 다른 글자가 한 줄에 섞였다.\r\n // 상자형 입력창(`╭──╮` / `│ > … │`)을 쓰는 앱도 있으므로, 머리글자가 같은 줄에\r\n // 함께 있을 때만 깨진 것으로 본다 — 그것이 \"가로선과 입력 텍스트가 섞인\" 그 증상이다.\r\n if (re.ruleChar.test(body) && re.headAnywhere.test(body)) {\r\n reasons.push(`mixed@${i} ${JSON.stringify(body.slice(0, 40))}`);\r\n }\r\n if (re.head.test(body) && !re.choice.test(body)) {\r\n heads.push(i);\r\n }\r\n }\r\n // 입력창 **안에** 머리가 두 개 이상 보인다 = 옛 프레임이 지워지지 않았다.\r\n //\r\n // 화면 전체의 머리 수를 세면 안 된다 — Claude Code 는 지난 사용자 프롬프트를\r\n // `❯ 내가 보낸 말` 로 대화 이력에 남기고, 큐에 쌓인 메시지도 같은 모양으로 나열한다.\r\n // 그래서 정상 화면에도 머리가 예사로 일곱 개 보인다 (2026-09-01 실측: `heads=7` 오탐으로\r\n // 자동 복구가 2초마다 헛돌았다). 판정은 입력창 테두리(가로선) 사이 구간에서만 한다.\r\n //\r\n // 판정은 **맨 아래 두 테두리** 사이에서만 한다. 위쪽 테두리를 `rules[0]` 으로 잡으면\r\n // 대화 이력에 스크롤되어 남은 옛 입력창의 테두리를 물어, 그 사이의 지난 프롬프트가\r\n // 전부 머리로 세어진다. 입력창은 언제나 화면 맨 아래에 있다.\r\n // 자투리 테두리(폭이 안 맞는 줄)는 위치 기준이 못 되므로 **화면 폭을 꽉 채운 것**만 쓴다.\r\n const fullRules = rules.filter(i => lines[i].text.replace(/\\s+$/, '').length === cols);\r\n if (fullRules.length >= 2) {\r\n const bottom = fullRules[fullRules.length - 1];\r\n const top = fullRules[fullRules.length - 2];\r\n // **입력할 자리가 없다** — 테두리 두 줄이 맞붙어 `❯` 가 들어갈 행이 사라졌다.\r\n //\r\n // 이것이 2026-09-02 에 사람 눈으로도 도구로도 놓친 그 증상이다. 폭은 멀쩡해서\r\n // (테두리 둘 다 cols 를 꽉 채운다) 폭 기준 판정은 전부 통과해 버린다. 실측 픽셀:\r\n // 가로선 y=59 와 y=76 이 행높이(17px) 1행 간격, 그 사이 커서 글리프가 아래 선을 관통.\r\n // 정상이라면 두 테두리는 최소 한 행(입력줄)을 사이에 두므로 간격이 2 이상이다.\r\n if (bottom - top < 2) {\r\n reasons.push(`입력창에 자리가 없다 (테두리 ${top}·${bottom} 이 맞붙었다)`);\r\n }\r\n else {\r\n const inside = heads.filter(i => i > top && i < bottom).length;\r\n // 머리가 0 개인 것은 깨짐으로 보지 않는다 — 선택지 커서(`❯ 1. Yes`)만 있는\r\n // 정상 화면이 그렇게 보인다 (choice 로 빼고 나면 머리가 0 이 된다).\r\n if (inside > 1) {\r\n reasons.push(`입력창 안 머리=${inside} (기대 1)`);\r\n }\r\n }\r\n }\r\n // **아래 테두리가 통째로 사라졌다.**\r\n //\r\n // 2026-09-02 실사용 실측(창 캡처 픽셀 스캔, 행높이 17px): 가로선이 `y=1295` 하나뿐이고\r\n // 프롬프트 글리프(y≈1304~1320) 아래 `y≈1329` 에 있어야 할 두 번째 가로선이 없었다.\r\n // 이 모양은 위 규칙들이 전부 통과한다 — 남은 테두리 하나는 폭을 꽉 채우고(폭 규칙 통과),\r\n // 테두리가 하나뿐이라 `fullRules.length >= 2` 가 거짓이라 자리 규칙도 건너뛰고,\r\n // `rules.length > 1` 도 거짓이라 섞임 규칙도 안 본다. 판정의 구멍이었다.\r\n //\r\n // 머리 **바로 위** 가 폭을 꽉 채운 테두리일 때만 본다. 그래야 3줄 입력창(`──/❯/──`)을\r\n // 쓰는 화면에만 적용되고, 테두리가 없는 일반 셸이나 상자형 입력창은 건드리지 않는다.\r\n // 대화 이력에 남은 옛 `❯ 내가 보낸 말` 도 안전하다 — 그 아래에는 현재 입력창의\r\n // 테두리가 있으므로 \"아래에 테두리가 없다\" 조건에 걸리지 않는다.\r\n if (heads.length && fullRules.length) {\r\n const head = heads[heads.length - 1];\r\n const topAttached = fullRules.includes(head - 1);\r\n const belowHead = fullRules.some(i => i > head);\r\n if (topAttached && !belowHead) {\r\n reasons.push(`입력창 아래 테두리가 없다 (머리@${head}, 위 테두리@${head - 1})`);\r\n }\r\n }\r\n // 테두리 길이가 서로 다르면 두 폭이 화면에 공존한다\r\n if (rules.length > 1) {\r\n const lens = new Set(rules.map(i => lines[i].text.replace(/\\s+$/, '').length));\r\n if (lens.size > 1) {\r\n reasons.push(`rule lens=${[...lens].join(',')} (섞임)`);\r\n }\r\n }\r\n return { broken: reasons.length > 0, reasons };\r\n}\r\nexports.judgeScreen = judgeScreen;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.TerminalAgentTracker = exports.identifyScreenAgent = exports.isLiveCodexScreen = void 0;\r\n/** Match the current UI, never a banner left in scrollback. Both the composer\r\n * and its model/context footer are required; a shell prompt below it rejects\r\n * an old Codex screen after exit. Trailing empty terminal rows are harmless.\r\n */\r\nfunction isLiveCodexScreen(lines) {\r\n var _a;\r\n const end = lines.reduce((last, line, i) => line.trim() ? i + 1 : last, 0);\r\n const visible = lines.slice(0, end);\r\n if (/^\\s*\\/ T R A N S C R I P T\\b/.test((_a = visible[0]) !== null && _a !== void 0 ? _a : '')\r\n && visible.slice(-4).some(line => /\\bq close\\b/.test(line))) {\r\n return true;\r\n }\r\n const footer = visible.findIndex(line => /^\\s*(?:gpt-[\\w.-]+|o\\d[\\w.-]*)\\b.*\\bContext \\d+% left\\b/.test(line));\r\n if (footer < 0 || footer < end - 3) {\r\n return false;\r\n }\r\n if (visible.slice(footer + 1).some(line => /^(?:PS )?[A-Za-z]:[\\\\/][^>]*>/.test(line.trim()))) {\r\n return false;\r\n }\r\n return visible.slice(0, footer).some(line => /^\\s*›/.test(line));\r\n}\r\nexports.isLiveCodexScreen = isLiveCodexScreen;\r\nfunction identifyShellLaunch(command) {\r\n var _a, _b, _c, _d;\r\n const args = ((_a = command.match(/\"[^\"]*\"|\\S+/g)) !== null && _a !== void 0 ? _a : []).map(arg => arg.replace(/^\"|\"$/g, ''));\r\n const exe = (_c = ((_b = args[0]) !== null && _b !== void 0 ? _b : '').split(/[\\\\/]/).pop()) === null || _c === void 0 ? void 0 : _c.replace(/\\.(exe|cmd|bat)$/i, '').toLowerCase();\r\n if (exe === 'codex' || exe === 'claude' || exe === 'gemini') {\r\n return exe;\r\n }\r\n if (exe === 'node') {\r\n const script = ((_d = args[1]) !== null && _d !== void 0 ? _d : '').replace(/\\\\/g, '/');\r\n if (/\\/@openai\\/codex\\/bin\\/codex\\.js$/i.test(script)) {\r\n return 'codex';\r\n }\r\n if (/\\/@anthropic-ai\\/claude-code\\/cli\\.js$/i.test(script)) {\r\n return 'claude';\r\n }\r\n if (/\\/@google\\/gemini-cli\\/(?:bundle\\/gemini|dist\\/index)\\.js$/i.test(script)) {\r\n return 'gemini';\r\n }\r\n }\r\n return 'unknown';\r\n}\r\n/** Synchronous fallback while the OS process probe is pending or unavailable.\r\n * Only application version banners count, not mentions in ordinary output.\r\n * A newer shell prompt or a Claude banner supersedes an old Codex banner.\r\n */\r\nfunction identifyScreenAgent(lines) {\r\n let id = 'unknown';\r\n for (const line of lines) {\r\n if (/^\\s*│\\s*>_\\s+OpenAI Codex\\s+\\(v\\d+\\./.test(line)) {\r\n id = 'codex';\r\n }\r\n else if (/^[\\s*\\u2500-\\u259f]*Claude Code v\\d+\\./.test(line)) {\r\n id = 'claude';\r\n }\r\n else if (/^(?:PS )?[A-Za-z]:[\\\\/][^>]*>/.test(line)) {\r\n id = 'unknown';\r\n }\r\n }\r\n return id;\r\n}\r\nexports.identifyScreenAgent = identifyScreenAgent;\r\n/** Observe banners before xterm renders them, and retain the identity when a\r\n * resumed transcript replaces the banner. Bound parser state even for corrupt\r\n * or split CSI/OSC sequences. Child processes can also change the console\r\n * title, so require a shell prompt before treating a shell title as an exit.\r\n */\r\nclass TerminalAgentTracker {\r\n constructor() {\r\n this.line = '';\r\n this.control = '';\r\n this.shellTitle = false;\r\n this.mode = 'text';\r\n }\r\n write(data) {\r\n for (const ch of data) {\r\n if (this.mode === 'osc' || this.mode === 'osc-escape') {\r\n if (ch === '\\x07' || (this.mode === 'osc-escape' && ch === '\\\\')) {\r\n const title = this.control.replace(/^[02];/, '');\r\n if (/^[02];/.test(this.control) && /(?:^|:\\s+)(?:[a-z]:[\\\\/][^\\r\\n]*[\\\\/])?(?:cmd|powershell|pwsh)(?:\\.exe)?\\s*$/i.test(title)) {\r\n this.shellTitle = true;\r\n }\r\n const launch = /^[02];/.test(this.control) && title.match(/(?:^|:\\s+)(?:[a-z]:[\\\\/][^\\r\\n]*[\\\\/])?(?:cmd|powershell|pwsh)(?:\\.exe)?\\s+-\\s+(.+)$/i);\r\n if (launch) {\r\n const launched = identifyShellLaunch(launch[1]);\r\n this.shellTitle = launched === 'unknown';\r\n if (launched !== 'unknown' || !this.id) {\r\n this.id = launched;\r\n }\r\n }\r\n this.mode = 'text';\r\n this.control = '';\r\n this.line = '';\r\n }\r\n else {\r\n this.mode = ch === '\\x1b' ? 'osc-escape' : 'osc';\r\n if (this.control.length < 4096 && ch !== '\\x1b') {\r\n this.control += ch;\r\n }\r\n }\r\n continue;\r\n }\r\n if (this.mode === 'escape') {\r\n this.mode = ch === '[' ? 'csi' : ch === ']' ? 'osc' : 'text';\r\n this.control = '';\r\n continue;\r\n }\r\n if (this.mode === 'csi') {\r\n if (ch >= '@' && ch <= '~') {\r\n this.mode = 'text';\r\n // Cursor positioning begins a new on-screen line. SGR does not.\r\n if ('HfG'.includes(ch)) {\r\n this.line = '';\r\n }\r\n }\r\n continue;\r\n }\r\n if (ch === '\\x1b') {\r\n this.mode = 'escape';\r\n continue;\r\n }\r\n if (ch === '\\r' || ch === '\\n') {\r\n this.line = '';\r\n continue;\r\n }\r\n if (ch < ' ') {\r\n continue;\r\n }\r\n this.line = (this.line + ch).slice(-512);\r\n if (ch === '>' && this.shellTitle && /^(?:PS )?[A-Za-z]:[\\\\/][^>]*>$/.test(this.line.trim())) {\r\n this.id = 'unknown';\r\n this.shellTitle = false;\r\n }\r\n // Check only the short version prefix, not ordinary mentions in text.\r\n if (ch === '.') {\r\n const id = identifyScreenAgent([this.line]);\r\n // A conversation can quote a different application's banner.\r\n // Only a new shell/launch boundary can replace an active identity.\r\n if (id !== 'unknown' && (!this.id || this.id === 'unknown')) {\r\n this.id = id;\r\n }\r\n }\r\n }\r\n }\r\n}\r\nexports.TerminalAgentTracker = TerminalAgentTracker;\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.SessionLedgerService = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\nconst fs = __importStar(require(\"fs\"));\r\nconst os = __importStar(require(\"os\"));\r\nconst path = __importStar(require(\"path\"));\r\nconst diag_1 = require(\"./diag\");\r\nconst sessionLedger_1 = require(\"./sessionLedger\");\r\n/**\r\n * 지난 세션 원장의 **파일 담당** — 읽고, 쓰고, 기록 폴더를 훑는다.\r\n * 무엇을 보여줄지 정하는 규칙은 전부 `sessionLedger.ts` 에 있다(fs 없이 테스트되는 쪽).\r\n *\r\n * 저장 위치는 `%LOCALAPPDATA%\\tabby-agentdeck\\sessions.json` — 훅 상태 파일 폴더 옆이다.\r\n * **Tabby 설정(`config.yaml`)에 넣지 않는다.** 세션은 계속 쌓이는데 거기 넣으면 남의 설정 파일이\r\n * 수백 줄 불어나고, 라벨이 바뀔 때마다 `config.save()` 가 돌아 관계없는 설정까지 다시 쓴다.\r\n */\r\nlet SessionLedgerService = class SessionLedgerService {\r\n constructor(config) {\r\n this.config = config;\r\n this.root = path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), 'tabby-agentdeck');\r\n this.file = path.join(this.root, 'sessions.json');\r\n /** Claude Code 대화기록이 사는 곳 (`notify.service` 와 같은 자리) */\r\n this.projectsDir = path.join(os.homedir(), '.claude', 'projects');\r\n /** 세션 id -> 원장 한 줄. 사람이 친 라벨이 여기 남는다 */\r\n this.ledger = new Map();\r\n /** 디스크 스캔 결과 (기록 파일에서 읽은 것) */\r\n this.scanned = [];\r\n /**\r\n * 기록 앞부분 파싱 캐시 — `세션id:mtime` 키. 파일이 자라도 **앞부분은 안 바뀐다**.\r\n * 그래도 mtime 을 키에 넣는 이유는 세션이 이어받기로 되살아나 새 줄이 앞에 붙는 경우가\r\n * 아니라, 파일이 통째로 갈렸을 때(삭제 후 재생성) 옛 값을 물고 있지 않기 위해서다.\r\n */\r\n this.headCache = new Map();\r\n this.loaded = false;\r\n this.saveTimer = null;\r\n this.scanning = null;\r\n this.lastScan = 0;\r\n /** 목록이 바뀌었을 때 호출부(사이드바)가 다시 그리도록 */\r\n this.onChange = null;\r\n }\r\n // ── 원장 ────────────────────────────────────────────────────────────────\r\n load() {\r\n if (this.loaded) {\r\n return;\r\n }\r\n this.loaded = true;\r\n try {\r\n const raw = fs.readFileSync(this.file, 'utf8');\r\n const parsed = JSON.parse(raw);\r\n const rows = Array.isArray(parsed === null || parsed === void 0 ? void 0 : parsed.records) ? parsed.records : [];\r\n for (const r of rows) {\r\n if (r && typeof r.sessionId === 'string' && r.sessionId) {\r\n this.ledger.set(r.sessionId, {\r\n sessionId: r.sessionId,\r\n cwd: typeof r.cwd === 'string' ? r.cwd : null,\r\n label: (0, sessionLedger_1.clampLabel)(r.label),\r\n lastStatus: typeof r.lastStatus === 'string' ? r.lastStatus : null,\r\n lastSeen: Number(r.lastSeen) || 0,\r\n from: r.from === 'head' ? 'head' : 'live',\r\n });\r\n }\r\n }\r\n }\r\n catch {\r\n // 아직 없다 / 깨졌다 — 빈 원장으로 시작한다. 디스크 스캔만으로도 목록은 선다\r\n }\r\n }\r\n /**\r\n * 저장을 한 번으로 모은다. 라벨은 사람이 Enter 를 칠 때마다 갱신되므로\r\n * 그때마다 파일을 쓰면 타자 속도로 디스크를 때린다.\r\n */\r\n scheduleSave() {\r\n if (this.saveTimer) {\r\n return;\r\n }\r\n this.saveTimer = setTimeout(() => {\r\n this.saveTimer = null;\r\n this.save();\r\n }, 2000);\r\n }\r\n save() {\r\n try {\r\n fs.mkdirSync(this.root, { recursive: true });\r\n const records = [...this.ledger.values()];\r\n fs.writeFileSync(this.file, JSON.stringify({ version: 1, records }, null, 1) + '\\n', 'utf8');\r\n }\r\n catch (e) {\r\n (0, diag_1.diagCatch)('세션 원장 저장', e);\r\n }\r\n }\r\n /**\r\n * 세션 하나의 지금을 원장에 적는다.\r\n *\r\n * 라벨은 **비어 있지 않을 때만** 덮는다 — 탭이 막 열려 아직 프롬프트가 없을 때 빈 문자열로\r\n * 덮으면 지난 실행에서 적어 둔 좋은 라벨을 지우게 된다.\r\n */\r\n note(sessionId, patch) {\r\n var _a, _b, _c;\r\n if (!sessionId) {\r\n return;\r\n }\r\n this.load();\r\n const prev = this.ledger.get(sessionId);\r\n const label = (0, sessionLedger_1.clampLabel)(patch.label);\r\n const next = {\r\n sessionId,\r\n cwd: patch.cwd || (prev === null || prev === void 0 ? void 0 : prev.cwd) || null,\r\n label: label || (prev === null || prev === void 0 ? void 0 : prev.label) || '',\r\n lastStatus: (_b = (_a = patch.status) !== null && _a !== void 0 ? _a : prev === null || prev === void 0 ? void 0 : prev.lastStatus) !== null && _b !== void 0 ? _b : null,\r\n lastSeen: Date.now(),\r\n from: label ? 'live' : ((_c = prev === null || prev === void 0 ? void 0 : prev.from) !== null && _c !== void 0 ? _c : 'live'),\r\n };\r\n const same = prev\r\n && prev.cwd === next.cwd\r\n && prev.label === next.label\r\n && prev.lastStatus === next.lastStatus;\r\n this.ledger.set(sessionId, next);\r\n // 값이 그대로면 저장만 미룬다 — `lastSeen` 하나 때문에 2초마다 쓰지 않게\r\n if (!same) {\r\n this.scheduleSave();\r\n }\r\n }\r\n // ── 디스크 스캔 ─────────────────────────────────────────────────────────\r\n /**\r\n * 기록 폴더를 훑어 세션 목록을 다시 만든다.\r\n *\r\n * **폴링하지 않는다.** `notify.service.ts:64` 가 적어 둔 대로 `~/.claude/projects` 전체를\r\n * 2초마다 readdir 하면 안 된다. 목록을 펼칠 때와 탭이 닫힐 때만 부른다.\r\n */\r\n async refresh(force = false) {\r\n const now = Date.now();\r\n if (!force && now - this.lastScan < 15000) {\r\n return;\r\n }\r\n if (this.scanning) {\r\n return this.scanning;\r\n }\r\n this.scanning = this.scan().finally(() => {\r\n this.scanning = null;\r\n this.lastScan = Date.now();\r\n });\r\n return this.scanning;\r\n }\r\n async scan() {\r\n var _a;\r\n this.load();\r\n const cfg = this.config.store.agentDeck;\r\n const days = Number(cfg.resumeListDays) || 0;\r\n const cutoff = days > 0 ? Date.now() - days * 86400000 : 0;\r\n const found = [];\r\n /**\r\n * 기간과 **무관하게** 디스크에 파일이 있는 세션 전부. 원장 청소는 이걸로 판정한다 —\r\n * `found` 는 기간 필터를 통과한 것만이라 그걸로 지우면 오래된(그러나 멀쩡한) 기록의\r\n * 라벨이 통째로 날아간다. 기간은 \"화면에 안 보인다\" 이지 \"없다\" 가 아니다.\r\n */\r\n const onDisk = new Set();\r\n try {\r\n const dirs = await fs.promises.readdir(this.projectsDir, { withFileTypes: true });\r\n for (const entry of dirs) {\r\n if (!entry.isDirectory()) {\r\n continue;\r\n }\r\n const dir = path.join(this.projectsDir, entry.name);\r\n let names;\r\n try {\r\n names = await fs.promises.readdir(dir);\r\n }\r\n catch {\r\n // 권한·경합으로 못 읽는 폴더 하나 때문에 나머지를 포기하지 않는다\r\n continue;\r\n }\r\n for (const name of names) {\r\n const sid = (0, sessionLedger_1.sessionIdFromFile)(name);\r\n if (!sid) {\r\n continue;\r\n }\r\n const full = path.join(dir, name);\r\n onDisk.add(sid);\r\n try {\r\n const st = await fs.promises.stat(full);\r\n // 기간 밖은 **앞부분을 읽기 전에** 버린다 — 파싱이 아니라 stat 이 필터다\r\n if (cutoff && st.mtimeMs < cutoff) {\r\n continue;\r\n }\r\n found.push({ sessionId: sid, file: full, mtime: st.mtimeMs });\r\n }\r\n catch {\r\n // 방금 지워졌다 — 다음 스캔에서 사라진다\r\n }\r\n }\r\n }\r\n }\r\n catch {\r\n // `~/.claude/projects` 자체가 없다 — Claude Code 를 안 쓰는 환경. 목록은 비고 화면엔 아무것도 안 그려진다\r\n // Codex history is independent of the Claude installation.\r\n }\r\n const scanCodex = async (dir, depth) => {\r\n let entries;\r\n try {\r\n entries = await fs.promises.readdir(dir, { withFileTypes: true });\r\n }\r\n catch {\r\n return;\r\n }\r\n for (const entry of entries) {\r\n const full = path.join(dir, entry.name);\r\n if (entry.isDirectory() && depth < 3) {\r\n await scanCodex(full, depth + 1);\r\n continue;\r\n }\r\n const match = /^rollout-.*-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\.jsonl$/i.exec(entry.name);\r\n if (!entry.isFile() || !match) {\r\n continue;\r\n }\r\n onDisk.add(match[1]);\r\n try {\r\n const st = await fs.promises.stat(full);\r\n if (!cutoff || st.mtimeMs >= cutoff) {\r\n found.push({ sessionId: match[1], file: full, mtime: st.mtimeMs, agent: 'codex' });\r\n }\r\n }\r\n catch { /* File removed during scan. */ }\r\n }\r\n };\r\n await scanCodex(path.join(process.env.CODEX_HOME || path.join(os.homedir(), '.codex'), 'sessions'), 0);\r\n found.sort((a, b) => b.mtime - a.mtime);\r\n // 앞부분 읽기에 상한을 둔다 — 기록이 수백 개인 사람에게도 펼치는 순간이 멈추지 않게.\r\n // 그룹당 몇 줄만 그리므로 최신 200개면 화면에 닿는 것은 다 들어온다\r\n const HEAD_SCAN_MAX = 200;\r\n const slice = found.slice(0, HEAD_SCAN_MAX);\r\n const out = [];\r\n for (const f of slice) {\r\n const key = `${f.sessionId}:${Math.round(f.mtime)}`;\r\n let head = this.headCache.get(key);\r\n if (!head) {\r\n head = await this.readHeadOf(f.file);\r\n this.headCache.set(key, head);\r\n }\r\n if (head.isSubagent) {\r\n continue;\r\n }\r\n out.push({\r\n agent: f.agent || 'claude',\r\n sessionId: f.sessionId,\r\n cwd: head.cwd,\r\n label: head.label,\r\n lastStatus: null,\r\n lastSeen: f.mtime,\r\n from: 'head',\r\n });\r\n }\r\n this.scanned = out;\r\n // 기록이 사라진 세션은 원장에서 지운다 — 이어받아도 복원할 것이 없다\r\n const before = this.ledger.size;\r\n const kept = (0, sessionLedger_1.pruneLedger)([...this.ledger.values()], onDisk);\r\n if (kept.length !== before) {\r\n this.ledger = new Map(kept.map(r => [r.sessionId, r]));\r\n this.scheduleSave();\r\n }\r\n (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this);\r\n }\r\n /**\r\n * 기록 파일 앞부분만 읽는다 — 전체를 읽지 않는 이유는 `HEAD_LINE_LIMIT` 주석에 있다.\r\n * 마지막 조각은 줄이 잘려 있을 수 있으니 버린다(파싱 실패로 조용히 넘어가긴 하지만,\r\n * 버리는 편이 \"왜 라벨이 가끔 이상한가\" 를 애초에 만들지 않는다).\r\n */\r\n async readHeadOf(file) {\r\n let fh = null;\r\n try {\r\n fh = await fs.promises.open(file, 'r');\r\n const buf = Buffer.alloc(sessionLedger_1.HEAD_BYTE_LIMIT);\r\n const { bytesRead } = await fh.read(buf, 0, sessionLedger_1.HEAD_BYTE_LIMIT, 0);\r\n const text = buf.slice(0, bytesRead).toString('utf8');\r\n const lines = text.split('\\n');\r\n if (bytesRead === sessionLedger_1.HEAD_BYTE_LIMIT) {\r\n lines.pop();\r\n }\r\n return (0, sessionLedger_1.readHead)(lines.slice(0, sessionLedger_1.HEAD_LINE_LIMIT));\r\n }\r\n catch (e) {\r\n (0, diag_1.diagCatch)(`세션 기록 앞부분 읽기 ${path.basename(file)}`, e);\r\n return { cwd: null, label: '', startedAt: null };\r\n }\r\n finally {\r\n await (fh === null || fh === void 0 ? void 0 : fh.close().catch(() => { }));\r\n }\r\n }\r\n // ── 조회 ────────────────────────────────────────────────────────────────\r\n /** 원장 + 디스크를 합친 전체 목록. 렌더 중에 불러도 막히지 않는다(캐시만 본다) */\r\n records() {\r\n this.load();\r\n return (0, sessionLedger_1.mergeSessions)([...this.ledger.values()], this.scanned);\r\n }\r\n /** 진단용 — `__agentdeck.sessions()` 가 보여준다 */\r\n snapshot() {\r\n return {\r\n ledger: this.ledger.size,\r\n scanned: this.scanned.length,\r\n file: this.file,\r\n lastScan: this.lastScan,\r\n };\r\n }\r\n};\r\nSessionLedgerService = __decorate([\r\n (0, core_1.Injectable)({ providedIn: 'root' }),\r\n __metadata(\"design:paramtypes\", [tabby_core_1.ConfigService])\r\n], SessionLedgerService);\r\nexports.SessionLedgerService = SessionLedgerService;\r\n","\"use strict\";\r\n/**\r\n * **지난 세션 원장** — 죽은 Claude Code 세션을 다시 찾아낼 수 있게 하는 순수 규칙.\r\n *\r\n * 왜 필요한가 — `recovery.service.ts` 가 적어 둔 대로 agentdeck 은 Tabby 의 순정 탭 복원을\r\n * 의도적으로 껐다. 되살아나는 것은 셸뿐이고 그 안의 세션은 이미 죽어 있어 \"주인 없는 탭\" 만\r\n * 남기 때문이다. 그 자리에 들어갈 진짜 복원이 `claude --resume <세션id>` 인데, 사람이 막히는\r\n * 지점은 명령이 아니라 **UUID 목록에서 내 작업을 못 찾는 것** 이다.\r\n *\r\n * agentdeck 은 그 답을 이미 갖고 있다 — Enter 시점에 입력창에서 주운 프롬프트 원문(라벨).\r\n * 문제는 그게 **메모리에만 있다는 것** 이다(`status.service` 의 `TabState.label`). 탭이 닫히면\r\n * 같이 증발한다. 그래서 이 모듈이 라벨·상태·cwd 를 세션 id 에 묶어 남기고, 목록을 만든다.\r\n *\r\n * fs·타이머는 여기 없다 — `group.ts`·`subagents.ts` 와 같은 이유다. 파일을 읽고 주기를\r\n * 관리하는 것은 호출부(서비스)의 일이고, 이 파일은 **무엇을 어떤 순서로 보여줄지** 만 정한다.\r\n * 그래야 `npm test` 에서 돌릴 수 있다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.resumeCommand = exports.sessionIdFromFile = exports.formatWhen = exports.resumeRowsFor = exports.pruneLedger = exports.mergeSessions = exports.readHead = exports.clampLabel = exports.LABEL_MAX = exports.promptFromRecord = exports.isHumanPrompt = exports.HEAD_BYTE_LIMIT = exports.HEAD_LINE_LIMIT = void 0;\r\n/**\r\n * 기록 파일 앞부분을 얼마나 읽을지.\r\n *\r\n * 전부 파싱하면 안 된다 — 실측 세션이 2.6MB(1,021줄)·5.5MB 고, 목록 한 번에 수십 개를 훑는다.\r\n * 필요한 것은 `cwd` 와 **첫 사람 프롬프트** 둘뿐인데 실측에서 `cwd` 는 5번째 줄,\r\n * 프롬프트는 65번째 줄에 나왔다(2026-09-11, `f54b20b9`). 앞의 60여 줄은 훅 주입·모드·첨부라\r\n * 여유를 크게 잡아도 이 정도면 닿는다. 못 찾으면 라벨 없이 두지, 파일을 더 파고들지 않는다.\r\n */\r\nexports.HEAD_LINE_LIMIT = 400;\r\n/** 줄 수와 별개로 이 바이트를 넘기면 멈춘다 — 한 줄이 통째로 거대한 기록(대용량 첨부)이 있다 */\r\nexports.HEAD_BYTE_LIMIT = 512 * 1024;\r\n/**\r\n * 첫 프롬프트로 치지 않는 것들.\r\n *\r\n * 기록의 `type:\"user\"` 줄에는 사람이 친 것만 오지 않는다 — 훅이 주입한 컨텍스트, 한도 리셋\r\n * 안내, 서브에이전트 종료 알림, 슬래시 명령의 출력이 같은 모양으로 들어온다(실측: `9e0c954f`\r\n * 의 마지막 user 줄 8개가 전부 `Your claude.ai usage limit has reset…` 이었다).\r\n * 그걸 라벨로 올리면 목록의 모든 줄이 같은 문장이 되어 아무것도 구별하지 못한다.\r\n */\r\nconst NOISE_PREFIXES = [\r\n '<',\r\n 'Caveat:',\r\n '[Request interrupted',\r\n 'Your claude.ai usage limit',\r\n];\r\n/** 사람이 친 프롬프트로 볼 수 있는 문자열인가 */\r\nfunction isHumanPrompt(text) {\r\n if (typeof text !== 'string') {\r\n return false;\r\n }\r\n const t = text.trim();\r\n if (!t) {\r\n return false;\r\n }\r\n return !NOISE_PREFIXES.some(p => t.startsWith(p));\r\n}\r\nexports.isHumanPrompt = isHumanPrompt;\r\n/**\r\n * 기록 줄(파싱된 JSON) 하나에서 사람이 친 프롬프트를 꺼낸다 — 아니면 null.\r\n *\r\n * `message.content` 는 문자열일 때도 있고 블록 배열일 때도 있다. 배열이면 `text` 블록만 잇는다\r\n * (`tool_result` 가 섞여 들어오면 라벨이 도구 출력으로 오염된다).\r\n */\r\nfunction promptFromRecord(rec) {\r\n var _a, _b, _c;\r\n if ((rec === null || rec === void 0 ? void 0 : rec.type) === 'event_msg' && ((_a = rec.payload) === null || _a === void 0 ? void 0 : _a.type) === 'user_message') {\r\n return isHumanPrompt(rec.payload.message) ? rec.payload.message.trim() : null;\r\n }\r\n if ((rec === null || rec === void 0 ? void 0 : rec.type) === 'response_item' && ((_b = rec.payload) === null || _b === void 0 ? void 0 : _b.role) === 'user') {\r\n const text = (Array.isArray(rec.payload.content) ? rec.payload.content : [])\r\n .filter((b) => (b === null || b === void 0 ? void 0 : b.type) === 'input_text' && typeof b.text === 'string')\r\n .map((b) => b.text).join(' ');\r\n return isHumanPrompt(text) ? text.trim() : null;\r\n }\r\n if (!rec || rec.type !== 'user' || rec.isMeta === true) {\r\n return null;\r\n }\r\n const content = (_c = rec.message) === null || _c === void 0 ? void 0 : _c.content;\r\n let text = null;\r\n if (typeof content === 'string') {\r\n text = content;\r\n }\r\n else if (Array.isArray(content)) {\r\n const parts = content\r\n .filter((b) => b && b.type === 'text' && typeof b.text === 'string')\r\n .map((b) => b.text);\r\n text = parts.length ? parts.join(' ') : null;\r\n }\r\n return isHumanPrompt(text) ? text.trim() : null;\r\n}\r\nexports.promptFromRecord = promptFromRecord;\r\n/** 라벨로 쓸 길이로 줄인다 — 사이드바 한 줄은 말줄임이 있지만 원장에 소설을 담을 이유는 없다 */\r\nexports.LABEL_MAX = 140;\r\nfunction clampLabel(text) {\r\n if (!text) {\r\n return '';\r\n }\r\n // 줄바꿈이 들어오면 한 줄로 — 여러 줄 프롬프트가 그대로 오면 목록 높이가 튄다\r\n const one = text.replace(/\\s+/g, ' ').trim();\r\n return one.length > exports.LABEL_MAX ? one.slice(0, exports.LABEL_MAX - 1) + '…' : one;\r\n}\r\nexports.clampLabel = clampLabel;\r\n/**\r\n * 기록 앞부분의 줄들에서 cwd·첫 프롬프트를 뽑는다.\r\n *\r\n * **폴더 이름 규칙을 흉내내지 않는다.** `~/.claude/projects/<폴더>` 의 이름은 작업 경로를 `-` 로\r\n * 뭉갠 것이라 드라이브 문자·한글·특수문자에서 되돌릴 수 없다(`notify.service.ts:1006` 이 같은\r\n * 이유로 폴더 이름 대신 파일명 매칭을 쓴다). 기록 안에 `cwd` 가 그대로 들어 있으니 그걸 읽는다.\r\n */\r\nfunction readHead(lines) {\r\n var _a, _b, _c;\r\n let cwd = null;\r\n let label = '';\r\n let startedAt = null;\r\n for (const line of lines) {\r\n if (!line) {\r\n continue;\r\n }\r\n let rec;\r\n try {\r\n rec = JSON.parse(line);\r\n }\r\n catch {\r\n // 잘린 줄 하나 때문에 나머지를 포기하지 않는다 (증분 읽기와 같은 태도)\r\n continue;\r\n }\r\n if ((rec === null || rec === void 0 ? void 0 : rec.type) === 'session_meta') {\r\n if ((_b = (_a = rec.payload) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.subagent) {\r\n return { cwd: null, label: '', startedAt: null, isSubagent: true };\r\n }\r\n if (!cwd && typeof ((_c = rec.payload) === null || _c === void 0 ? void 0 : _c.cwd) === 'string') {\r\n cwd = rec.payload.cwd;\r\n }\r\n }\r\n if (!cwd && typeof (rec === null || rec === void 0 ? void 0 : rec.cwd) === 'string' && rec.cwd) {\r\n cwd = rec.cwd;\r\n }\r\n if (startedAt === null && typeof (rec === null || rec === void 0 ? void 0 : rec.timestamp) === 'string') {\r\n const t = Date.parse(rec.timestamp);\r\n if (!Number.isNaN(t)) {\r\n startedAt = t;\r\n }\r\n }\r\n if (!label) {\r\n const p = promptFromRecord(rec);\r\n if (p) {\r\n label = clampLabel(p);\r\n }\r\n }\r\n if (cwd && label && startedAt !== null) {\r\n break;\r\n }\r\n }\r\n return { cwd, label, startedAt };\r\n}\r\nexports.readHead = readHead;\r\n/**\r\n * 원장과 디스크 스캔을 합친다 — **세션 id 가 키, 원장이 우선.**\r\n *\r\n * 두 경로가 다 필요하다. 원장에만 기대면 agentdeck 설치 이전 세션과 다른 터미널에서 띄운\r\n * 세션이 통째로 안 보이고, 디스크에만 기대면 사람이 친 라벨(가장 좋은 단서)을 잃는다.\r\n *\r\n * 원장이 이기는 것은 **라벨과 상태** 뿐이다. `lastSeen` 은 둘 중 큰 값을 쓴다 — 원장은 탭이\r\n * 닫힐 때 멈추는데 그 뒤 다른 터미널에서 같은 세션을 이어받았을 수 있고, 그때는 디스크가 맞다.\r\n */\r\nfunction mergeSessions(ledger, scanned) {\r\n var _a;\r\n const out = new Map();\r\n for (const rec of scanned) {\r\n if (rec.sessionId) {\r\n out.set(rec.sessionId, { ...rec });\r\n }\r\n }\r\n for (const rec of ledger) {\r\n if (!rec.sessionId) {\r\n continue;\r\n }\r\n const disk = out.get(rec.sessionId);\r\n if (!disk) {\r\n // 기록 파일이 사라진 세션. **목록에 넣지 않는다** — 이어받아도 복원할 것이 없다.\r\n // 원장 청소(`pruneLedger`)가 같은 판정으로 지운다\r\n continue;\r\n }\r\n out.set(rec.sessionId, {\r\n ...disk,\r\n label: rec.label || disk.label,\r\n from: rec.label ? rec.from : disk.from,\r\n lastStatus: (_a = rec.lastStatus) !== null && _a !== void 0 ? _a : disk.lastStatus,\r\n cwd: disk.cwd || rec.cwd,\r\n lastSeen: Math.max(rec.lastSeen || 0, disk.lastSeen || 0),\r\n });\r\n }\r\n return [...out.values()];\r\n}\r\nexports.mergeSessions = mergeSessions;\r\n/**\r\n * 기록 파일이 남아 있는 세션만 남긴다 — 원장이 무한히 부풀지 않게.\r\n *\r\n * 디스크를 진실로 삼는 이유: 사람이 `~/.claude/projects` 를 지우면 그 세션은 이어받을 수 없고,\r\n * 그걸 원장이 계속 보여주면 눌렀을 때 빈 세션이 뜬다.\r\n */\r\nfunction pruneLedger(ledger, aliveIds) {\r\n return ledger.filter(r => r.sessionId && aliveIds.has(r.sessionId));\r\n}\r\nexports.pruneLedger = pruneLedger;\r\n/**\r\n * 한 그룹에 그릴 지난 세션 줄.\r\n *\r\n * **살아 있는 세션을 빼지 않는다** — `openTabId` 를 달아 그대로 둔다. 지우면 \"내가 방금 보던\r\n * 그 작업이 목록에 없다\" 가 되어 사람이 같은 세션을 다시 찾아 헤맨다. 대신 눌렀을 때\r\n * 이어받지 않고 그 탭으로 보낸다(같은 세션을 두 번 이어받으면 두 프로세스가 한 기록에 덧쓴다).\r\n *\r\n * 정렬은 **마지막 활동 내림차순** 하나뿐이다. 상태별로 묶고 싶어질 수 있는데, 지난 세션에서\r\n * 사람이 찾는 것은 \"방금 하던 것\" 이지 \"완료된 것\" 이 아니다.\r\n */\r\nfunction resumeRowsFor(records, opts) {\r\n var _a;\r\n const want = new Set(opts.groupKeys.map(k => opts.fold(k)));\r\n const cutoff = opts.days > 0 ? opts.now - opts.days * 86400000 : null;\r\n const rows = [];\r\n for (const rec of records) {\r\n if (!rec.sessionId || opts.hidden.has(rec.sessionId)) {\r\n continue;\r\n }\r\n if (!want.has(opts.fold(opts.keyOf(rec.cwd)))) {\r\n continue;\r\n }\r\n if (cutoff !== null && rec.lastSeen < cutoff) {\r\n continue;\r\n }\r\n rows.push({ ...rec, openTabId: (_a = opts.live.get(rec.sessionId)) !== null && _a !== void 0 ? _a : null });\r\n }\r\n rows.sort((a, b) => b.lastSeen - a.lastSeen || a.sessionId.localeCompare(b.sessionId));\r\n return opts.limit > 0 ? rows.slice(0, opts.limit) : rows;\r\n}\r\nexports.resumeRowsFor = resumeRowsFor;\r\n/**\r\n * 마지막 활동 시각을 사람이 읽는 짧은 꼴로.\r\n *\r\n * 오늘이면 시각(`14:12`), 어제면 `어제`, 그보다 오래면 `9/10`. 사이드바 줄의 오른쪽 끝에\r\n * 들어가므로 길면 제목 폭을 먹는다 — 연도는 넣지 않는다(제한 기간이 기본 7일이라 못 만난다).\r\n */\r\nfunction formatWhen(ts, now) {\r\n if (!ts || !Number.isFinite(ts)) {\r\n return '';\r\n }\r\n const d = new Date(ts);\r\n const n = new Date(now);\r\n const sameDay = d.getFullYear() === n.getFullYear()\r\n && d.getMonth() === n.getMonth()\r\n && d.getDate() === n.getDate();\r\n if (sameDay) {\r\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;\r\n }\r\n const y = new Date(now);\r\n y.setDate(y.getDate() - 1);\r\n if (d.getFullYear() === y.getFullYear() && d.getMonth() === y.getMonth() && d.getDate() === y.getDate()) {\r\n return '어제';\r\n }\r\n return `${d.getMonth() + 1}/${d.getDate()}`;\r\n}\r\nexports.formatWhen = formatWhen;\r\n/** 세션 id 처럼 생겼나 — 기록 폴더에는 우리 것이 아닌 파일도 있을 수 있다 */\r\nconst SESSION_FILE_RE = /^([0-9a-fA-F-]{8,64})\\.jsonl$/;\r\n/** 파일 이름에서 세션 id 를 꺼낸다 (아니면 null) */\r\nfunction sessionIdFromFile(name) {\r\n const m = SESSION_FILE_RE.exec(name || '');\r\n return m ? m[1] : null;\r\n}\r\nexports.sessionIdFromFile = sessionIdFromFile;\r\n/**\r\n * 셸에 보낼 이어받기 명령.\r\n *\r\n * **프로필의 `command` 를 갈아끼우지 않고 셸에 문자열로 보낸다.** 이유 둘 —\r\n * ① 기존 `agentdeck:root` 프로필(`-NoLogo -ExecutionPolicy Bypass`, COLORTERM/FORCE_COLOR)을\r\n * 그대로 쓴다. npm 전역 `.ps1` 래퍼가 실행정책에 막히는 문제를 그 인자가 이미 풀어 둔다\r\n * (`profile.service.ts:58`).\r\n * ② claude 가 끝나도 셸이 남아 사람이 이어서 쓸 수 있다. `command` 로 박으면\r\n * `behaviorOnSessionEnd` 에 따라 탭이 닫힌다.\r\n *\r\n * 세션 id 는 우리가 파일 이름에서 읽은 값이고 `SESSION_FILE_RE` 를 통과한 것만 여기 온다 —\r\n * 그래도 명령을 만드는 자리이므로 한 번 더 막는다. 통과 못 하면 빈 문자열이고 호출부가 아무것도 보내지 않는다.\r\n */\r\nfunction resumeCommand(sessionId, fork, agent = 'claude') {\r\n if (!/^[0-9a-fA-F-]{8,64}$/.test(sessionId || '')) {\r\n return '';\r\n }\r\n return agent === 'codex'\r\n ? `codex ${fork ? 'fork' : 'resume'} ${sessionId}`\r\n : `claude --resume ${sessionId}${fork ? ' --fork-session' : ''}`;\r\n}\r\nexports.resumeCommand = resumeCommand;\r\n","\"use strict\";\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckSettingsTabComponent = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\nconst config_1 = require(\"./config\");\r\nconst claudeHooks_1 = require(\"./claudeHooks\");\r\nconst codexHooks_1 = require(\"./codexHooks\");\r\nconst recovery_service_1 = require(\"./recovery.service\");\r\nconst update_service_1 = require(\"./update.service\");\r\nconst diag_1 = require(\"./diag\");\r\n/** 확인 결과를 사람 말로 — 설정 창의 한 줄 안내 */\r\nconst UPDATE_OUTCOME_TEXT = {\r\n 'disabled': '자동 업데이트가 꺼져 있다',\r\n 'too-soon': '방금 확인했다',\r\n 'dev-install': '새 버전이 있지만 개발 설치라 건드리지 않는다',\r\n 'unknown': 'npm 에 물어보지 못했다 (네트워크·프록시)',\r\n 'up-to-date': '최신이다',\r\n 'update-ready': '새 버전이 있다',\r\n 'skipped': '이 버전은 건너뛰기로 했다',\r\n 'postponed': '나중에 하기로 했다',\r\n 'installing': '설치를 시작했다 — Tabby 가 곧 닫혔다가 다시 켜진다',\r\n 'failed': '업데이트를 시작하지 못했다',\r\n};\r\nconst DOCK_LABELS = {\r\n left: '왼쪽',\r\n right: '오른쪽',\r\n top: '위쪽',\r\n bottom: '아래쪽',\r\n};\r\n/**\r\n * 설정 > AgentDeck 탭.\r\n *\r\n * 사용자가 실제로 바꿀 일이 있는 것만 노출한다 — 레이아웃 on/off, 기동 시 탭 복원 끄기,\r\n * 사이드바 목록(키보드 조작 · 서브에이전트 개수), 세션 그룹, 미리보기 패널, 작업 루트 프로필.\r\n * 나머지(화면비, 사이드바 폭, 투명도, 상태 감지, 붙여넣기/줄바꿈 가로채기, 렌더 보정)는\r\n * 손댈 이유가 거의 없고 잘못 만지면 화면이 깨지는 값이라 `config.ts` 의 기본값으로 고정하고\r\n * 설정 창에서는 뺐다. 정말 필요하면 설정 파일의 `agentDeck.*` 를 직접 고친다.\r\n *\r\n * `enabled` 는 deck.service 가 `config.changed$` 를 구독해 즉시 반영한다(deck.service.ts:256).\r\n * 루트 프로필은 기동 시 한 번만 읽으므로 재시작이 필요하다고 적어 둔다.\r\n *\r\n * `사이드바 목록` 절을 `세션 그룹` **앞**에 둔 이유 — 그룹도 결국 이 목록의 세부 규칙이라\r\n * 목록 전체에 걸리는 것(키보드 조작 · 줄에 무엇을 보일지)을 먼저 읽는 편이 순서가 맞는다.\r\n * 0.14.0 의 `dragAutoScroll` 도 같은 절에 뒀다 — 정하는 것이 \"목록을 다루는 방법\" 이라\r\n * 키보드 조작과 성질이 같고, 따로 절을 만들면 항목 하나뿐인 절이 생긴다.\r\n * 0.13.0 에서 생긴 세 값(`keyboardNav` / `keyboardNavWrap` / `subagentCount`)은\r\n * 설정 창에 자리가 없어 `config.yaml` 을 손으로 고쳐야만 바꿀 수 있었다.\r\n *\r\n * `keyboardNavWrap` 과 `keyboardCloseTab`(0.19.0) 은 `keyboardNav` 를 끄면 아무 뜻이 없으므로 그때는 줄을 아예 감춘다 —\r\n * 꺼진 값을 회색으로 남겨 두는 것보다 \"지금 만질 수 있는 것\" 이 짧아진다.\r\n * 세션 그룹 절에 값이 하나도 없는 것(0.20.0)도 같은 기준이다 — 끌 이유가 없는 스위치와\r\n * 자동으로 알아낼 수 있는 경로는 설정이 아니라 동작이어야 한다.\r\n * 이 세 값은 deck.service/notify.service 가 쓸 때마다 store 를 다시 읽으므로\r\n * (deck.service.ts `navCanFocus`/`moveNav`, notify.service `subagentEnabled`)\r\n * 토글하면 바로 듣는다 — 그래서 재시작 안내를 붙이지 않았다.\r\n */\r\nlet AgentDeckSettingsTabComponent = class AgentDeckSettingsTabComponent {\r\n constructor(config, recovery, update, platform) {\r\n this.config = config;\r\n this.recovery = recovery;\r\n this.update = update;\r\n this.platform = platform;\r\n /** 이 환경에서 훅을 걸 수 있나 (통보 스크립트가 PowerShell 이라 Windows 전용) */\r\n this.hooksSupported = (0, claudeHooks_1.hooksSupported)();\r\n /** 지금 걸려 있나 — 파일을 매번 읽지 않도록 화면용으로 들고 있는다 */\r\n this.hooksOn = false;\r\n this.codexHooksOn = false;\r\n this.codexHookError = '';\r\n /** 훅을 쓰다 실패한 이유 — 조용히 삼키면 사용자는 버튼이 먹통인 줄 안다 */\r\n this.hookError = '';\r\n /** 신고 안내에 그대로 보여줄 진단 로그 경로 */\r\n this.diagPath = diag_1.DIAG_PATH;\r\n /** 신고 본문에 적을 버전 — 사용자가 어느 버전을 쓰는지 스스로 알 방법이 없었다 */\r\n this.diagVersion = (0, diag_1.pluginVersion)();\r\n /** 묶음에 화면 원문까지 넣나 (기본 제외 — 터미널에 찍힌 내용이 그대로 들어간다) */\r\n this.diagIncludeScreen = false;\r\n /** 마지막으로 만든 묶음 경로 */\r\n this.diagBundlePath = '';\r\n /** 묶음을 만들다 실패한 이유 */\r\n this.diagError = '';\r\n /** `지금 확인` 이 도는 동안 버튼을 잠근다 (레지스트리 응답까지 몇 초) */\r\n this.updateBusy = false;\r\n /** 마지막 확인 결과 한 줄 */\r\n this.updateMsg = '';\r\n this.refreshHooks();\r\n }\r\n /**\r\n * 사람이 직접 누른 확인. `force` 라 간격과 `다시 묻지 않기` 를 건너뛴다 —\r\n * 눌렀다는 것 자체가 \"지금 알고 싶다\" 는 뜻이다.\r\n */\r\n async checkUpdate() {\r\n var _a, _b;\r\n this.updateBusy = true;\r\n this.updateMsg = '';\r\n try {\r\n this.updateMsg = (_a = UPDATE_OUTCOME_TEXT[await this.update.run('settings', true)]) !== null && _a !== void 0 ? _a : '';\r\n }\r\n catch (e) {\r\n this.updateMsg = `확인하지 못했다: ${(_b = e === null || e === void 0 ? void 0 : e.message) !== null && _b !== void 0 ? _b : e}`;\r\n }\r\n finally {\r\n this.updateBusy = false;\r\n }\r\n }\r\n refreshHooks() {\r\n var _a, _b;\r\n try {\r\n this.codexHooksOn = this.hooksSupported && (0, codexHooks_1.codexHooksInstalled)();\r\n }\r\n catch (e) {\r\n this.codexHooksOn = false;\r\n this.codexHookError = `설정을 읽지 못했다: ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`;\r\n }\r\n try {\r\n this.hooksOn = this.hooksSupported && (0, claudeHooks_1.hooksInstalled)();\r\n }\r\n catch (e) {\r\n this.hooksOn = false;\r\n this.hookError = `설정을 읽지 못했다: ${(_b = e === null || e === void 0 ? void 0 : e.message) !== null && _b !== void 0 ? _b : e}`;\r\n }\r\n }\r\n /**\r\n * 훅을 걸거나 뗀다.\r\n *\r\n * 걸 때는 통보 채널도 같이 켠다 — 훅만 걸고 채널이 닫혀 있으면 보고가 어디에도 닿지 않는데,\r\n * 사용자 입장에서는 \"설치했는데 아무 일도 안 일어난다\" 로만 보인다.\r\n */\r\n toggleHooks() {\r\n var _a;\r\n this.hookError = '';\r\n try {\r\n if (this.hooksOn) {\r\n (0, claudeHooks_1.uninstallHooks)();\r\n }\r\n else {\r\n (0, claudeHooks_1.installHooks)();\r\n if (!this.config.store.agentDeck.notifyChannel) {\r\n this.config.store.agentDeck.notifyChannel = true;\r\n this.config.save();\r\n }\r\n }\r\n }\r\n catch (e) {\r\n this.hookError = `${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`;\r\n }\r\n this.refreshHooks();\r\n }\r\n toggleCodexHooks() {\r\n var _a;\r\n this.codexHookError = '';\r\n try {\r\n (0, codexHooks_1.setCodexHooks)(!this.codexHooksOn);\r\n if (!this.codexHooksOn && !this.config.store.agentDeck.notifyChannel) {\r\n this.config.store.agentDeck.notifyChannel = true;\r\n this.config.save();\r\n }\r\n }\r\n catch (e) {\r\n this.codexHookError = `${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`;\r\n }\r\n this.refreshHooks();\r\n }\r\n /**\r\n * OS 폴더 선택 창을 띄워 작업 폴더를 고른다.\r\n *\r\n * `pickDirectory` 는 취소하면 null/undefined 를 주므로 그때는 기존 값을 건드리지 않는다.\r\n * 다이얼로그 제목은 Tabby 버전에 따라 인자를 받기도 하고 안 받기도 해서 any 로 넘긴다 —\r\n * 안 받는 쪽은 그냥 무시하므로 어느 쪽에서도 깨지지 않는다.\r\n * 돌려받은 경로는 백슬래시를 슬래시로 바꿔 저장한다. 설정 파일에 그대로 적히는 값이라\r\n * 손으로 고칠 때 이스케이프 사고가 나지 않게 하려는 것이고, Windows 도 슬래시 경로를 받는다.\r\n */\r\n /**\r\n * 진단 묶음을 만들고 그 파일이 있는 폴더를 연다.\r\n *\r\n * 폴더를 여는 것까지가 한 동작인 이유 — 경로만 알려 주면 \"그 폴더가 어디냐\" 가 다시 질문으로\r\n * 돌아온다. 압축이 안 되는 환경에서는 폴더 경로가 나오므로 그대로 열어 주면 된다.\r\n */\r\n collectDiag() {\r\n var _a, _b, _c, _d, _e;\r\n this.diagError = '';\r\n this.diagBundlePath = '';\r\n try {\r\n const bundle = (0, diag_1.collectDiagBundle)({\r\n includeScreen: this.diagIncludeScreen,\r\n stamp: {\r\n tabby: (_b = (_a = this.platform).getAppVersion) === null || _b === void 0 ? void 0 : _b.call(_a),\r\n osRelease: (_d = (_c = this.platform).getOSRelease) === null || _d === void 0 ? void 0 : _d.call(_c),\r\n config: (0, diag_1.configStamp)(this.config.store),\r\n },\r\n });\r\n this.diagBundlePath = bundle.path;\r\n this.platform.showItemInFolder(bundle.path);\r\n }\r\n catch (e) {\r\n this.diagError = `모으지 못했다: ${(_e = e === null || e === void 0 ? void 0 : e.message) !== null && _e !== void 0 ? _e : e}`;\r\n }\r\n }\r\n /** 배치가 기본값에서 벗어나 있나 — 벗어나 있을 때만 초기화 버튼이 살아 있다 */\r\n layoutChanged() {\r\n const cfg = this.config.store.agentDeck;\r\n return Object.keys(config_1.LAYOUT_DEFAULTS).some(k => cfg[k] !== config_1.LAYOUT_DEFAULTS[k]);\r\n }\r\n dockLabel() {\r\n var _a;\r\n return (_a = DOCK_LABELS[this.config.store.agentDeck.sidebarDock]) !== null && _a !== void 0 ? _a : '오른쪽';\r\n }\r\n sizeLabel() {\r\n const cfg = this.config.store.agentDeck;\r\n if (cfg.sidebarDock === 'top' || cfg.sidebarDock === 'bottom') {\r\n return '높이 ' + cfg.sidebarHeight + 'px';\r\n }\r\n return cfg.sidebarWidth ? '폭 ' + cfg.sidebarWidth + 'px' : '폭 자동';\r\n }\r\n /**\r\n * 도킹 방향과 크기만 기본값으로 되돌린다.\r\n *\r\n * 되돌리기 쉬운 조작이라 확인 창은 두지 않는다. `config.save()` 가 `changed$` 를 발화시키고\r\n * deck.service 가 그걸 받아 곧바로 다시 배치하므로(deck.service.ts:256) 재시작도 필요 없다.\r\n */\r\n resetLayout() {\r\n Object.assign(this.config.store.agentDeck, config_1.LAYOUT_DEFAULTS);\r\n this.config.save();\r\n }\r\n /** 접혀 있는 그룹 수 — 버튼을 살릴지와 안내 문장에 쓴다 */\r\n collapsedCount() {\r\n const list = this.config.store.agentDeck.collapsedGroups;\r\n return Array.isArray(list) ? list.length : 0;\r\n }\r\n /**\r\n * 접어 둔 그룹을 모두 펼친다.\r\n *\r\n * 왜 버튼이 필요한가 — 접힌 그룹의 탭을 다 닫아도 키는 남는다(그 프로젝트를 다시 열었을 때\r\n * 접힘이 유지되는 것이 의도다). 그래서 \"예전에 접었는데 지금은 그 그룹이 안 보이는\" 상태가\r\n * 쌓일 수 있고, 그때 되돌릴 방법이 config 파일 편집뿐이었다.\r\n */\r\n expandGroups() {\r\n this.config.store.agentDeck.collapsedGroups = [];\r\n this.config.save();\r\n }\r\n async pickCwd() {\r\n const picked = await this.platform.pickDirectory('작업 폴더 선택');\r\n if (!picked) {\r\n return;\r\n }\r\n this.config.store.agentDeck.rootProfileCwd = String(picked).replace(/\\\\/g, '/');\r\n this.config.save();\r\n }\r\n};\r\nAgentDeckSettingsTabComponent = __decorate([\r\n (0, core_1.Component)({\r\n selector: 'agentdeck-settings-tab',\r\n template: `\n<h3 class=\"mb-3\">AgentDeck</h3>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">레이아웃 사용</div>\n <div class=\"description\">끄면 사이드바와 고정폭 레이아웃이 사라지고 Tabby 순정 화면으로 돌아간다.</div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.enabled\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">UI 배치 초기화</div>\n <div class=\"description\">\n 마우스로 바꾼 사이드바 위치와 크기를 처음 상태로 되돌린다 —\n 오른쪽 도킹 + 화면비로 자동 계산한 폭.\n <span *ngIf=\"layoutChanged()\">지금: {{dockLabel()}} 도킹, {{sizeLabel()}}.</span>\n <span *ngIf=\"!layoutChanged()\">지금은 기본 상태다.</span>\n </div>\n </div>\n <button class=\"btn btn-secondary\" type=\"button\" [disabled]=\"!layoutChanged()\" (click)=\"resetLayout()\">\n <i class=\"fas fa-undo me-2\"></i>초기화\n </button>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">기동 시 탭 복원 끄기</div>\n <div class=\"description\">\n 켜면 Tabby 를 다시 열 때 지난 탭을 되살리지 않고 빈 상태로 시작한다 —\n 복원되는 건 셸뿐이고 그 안의 Claude 세션은 이미 끝나 있어 의미가 없다.\n 끄면 Tabby 순정 동작(<code>recoverTabs</code>)으로 돌아간다. 다음 기동부터 적용.\n </div>\n </div>\n <toggle [ngModel]=\"config.store.agentDeck.noTabRecovery\" (ngModelChange)=\"recovery.setNoTabRecovery($event)\"></toggle>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">자동 업데이트</div>\n <div class=\"description\">\n 기동할 때 npm 을 보고 새 버전이 있으면 <b>물어본 뒤</b> 업데이트한다.\n 승낙하면 Tabby 가 닫히고 → 설치하고 → <b>스스로 다시 켜진다</b> (사람이 할 일은 없다).\n 돌고 있는 플러그인은 갈아끼울 수 없어서 이 방법뿐이다.\n 끊긴 Claude Code·Codex 대화는 <code>⟲ 지난 세션</code> 에서 이어받으면 된다.\n <b>개발 설치(소스 링크)에는 설치하지 않는다</b> — 작업 중인 소스를 덮어쓰기 때문이다.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.autoUpdate\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\" *ngIf=\"config.store.agentDeck.autoUpdate\">\n <div class=\"header\">\n <div class=\"title\">지금 확인</div>\n <div class=\"description\">\n 간격({{config.store.agentDeck.updateCheckIntervalHours}}시간)과 <code>다시 묻지 않기</code> 를 무시하고 한 번 확인한다.\n <span *ngIf=\"updateMsg\">— {{updateMsg}}</span>\n </div>\n </div>\n <button class=\"btn btn-secondary\" type=\"button\" [disabled]=\"updateBusy\" (click)=\"checkUpdate()\">\n <i class=\"fas fa-rotate me-2\"></i>{{updateBusy ? '확인 중…' : '확인'}}\n </button>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">지난 세션 이어받기</div>\n <div class=\"description\">\n 그룹 끝에 <code>⟲ 지난 세션</code> 서랍을 둔다 (기본 접힘). 펴면 <b>닫힌 Claude Code·Codex 세션</b>이\n 그때 친 프롬프트로 보이고, 누르면 그 세션의 작업 폴더에서 <code>claude --resume</code> 또는 <code>codex resume</code> 으로\n 대화가 되살아난다. 위의 <b>탭 복원 끄기</b> 와 한 쌍이다 — 순정 복원은 셸만 되살리지만\n 이건 대화를 되살린다. <b>다만 그때 띄워 둔 서버·백그라운드 프로세스는 돌아오지 않는다.</b>\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.resumeList\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\" *ngIf=\"config.store.agentDeck.resumeList\">\n <div class=\"header\">\n <div class=\"title\">몇 줄까지 · 며칠치</div>\n <div class=\"description\">\n 그룹마다 최근 <b>{{config.store.agentDeck.resumeListLimit}}줄</b>까지,\n 최근 <b>{{config.store.agentDeck.resumeListDays}}일</b> 안의 세션만 보여준다.\n 길게 잡으면 살아 있는 탭이 아래로 밀린다. 숨긴 세션은 줄 우클릭으로 되돌릴 수 없고\n <code>config.yaml</code> 의 <code>resumeHidden</code> 을 비우면 다시 나온다.\n </div>\n </div>\n <div class=\"d-flex align-items-center\">\n <input class=\"form-control text-end me-2\" style=\"width: 5rem\" type=\"number\" min=\"0\" max=\"50\"\n [(ngModel)]=\"config.store.agentDeck.resumeListLimit\" (ngModelChange)=\"config.save()\">\n <input class=\"form-control text-end\" style=\"width: 5rem\" type=\"number\" min=\"0\" max=\"365\"\n [(ngModel)]=\"config.store.agentDeck.resumeListDays\" (ngModelChange)=\"config.save()\">\n </div>\n</div>\n\n<h3 class=\"mt-4 mb-3\">사이드바 목록</h3>\n<div class=\"text-muted mb-3\">\n 세션 목록을 마우스 없이 다루는 방법과, 줄에 무엇까지 보일지를 정한다. 바꾸면 곧바로 적용된다.\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">키보드로 다루기</div>\n <div class=\"description\">\n <code>Ctrl+Shift+L</code> 로 목록에 들어가 <code>↑↓</code> 로 훑고 Enter 로 그 탭으로 옮긴다\n (<code>Esc</code> 로 터미널로 돌아온다). <b>훑는 동안 활성 탭은 바뀌지 않는다</b> —\n 줄마다 탭이 바뀌면 그 탭의 출력이 화면을 덮어 훑어보는 것 자체가 안 된다.\n 포커스가 사이드바에 없는 동안은 키를 한 개도 가로채지 않으므로 켜 둬서 잃는 것이 없다.\n 끄면 목록이 포커스를 받지 않는다.\n 키 배정은 <b>단축키</b> 탭의 <code>agentdeck-focus-list</code> 에서 바꾼다.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.keyboardNav\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\" *ngIf=\"config.store.agentDeck.keyboardNav\">\n <div class=\"header\">\n <div class=\"title\">끝에서 반대쪽으로 감싸기</div>\n <div class=\"description\">\n 맨 아래에서 <code>↓</code> 를 한 번 더 누르면 맨 위로 넘어간다.\n 기본은 꺼짐 — 끝에서 멈춰야 \"맨 아래에 왔다\" 가 보이고 목록이 통째로 튀지 않는다.\n 끝에서 끝으로 갈 일은 <code>Home</code> · <code>End</code> 가 받는다.\n 켜도 <b>맨 위의 ↑ 는 검색창으로 나간다</b> — 그 경계까지 감싸기에 내주면\n 목록에서 검색창으로 돌아갈 키가 없어진다.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.keyboardNavWrap\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\" *ngIf=\"config.store.agentDeck.keyboardNav\">\n <div class=\"header\">\n <div class=\"title\"><code>Ctrl+W</code> 로 탭 닫기</div>\n <div class=\"description\">\n 터미널에서 누르면 <b>지금 보고 있는 탭</b>, 목록이 키보드를 갖고 있으면\n <b>포커스 줄의 탭</b>을 닫는다 (그룹 헤더에서는 아무 일도 하지 않는다).\n 사이드바 <code>✕</code> 와 같은 경로라 돌아가는 프로세스가 있으면 평소처럼 한 번 물어본다.\n <b>끄면 <code>Ctrl+W</code> 가 터미널로 그대로 간다</b> — 셸·에이전트 CLI 에서\n 그 키는 <b>앞 단어 지우기</b>이고, 우리는 닫을 탭이 정해졌을 때만 키를 가로챈다.\n <code>키보드로 다루기</code> 를 끄면 이 항목도 함께 꺼진다.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.keyboardCloseTab\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">서브에이전트 개수 보이기</div>\n <div class=\"description\">\n 그 세션이 백그라운드로 돌리고 있는 에이전트 수를 줄에 <b>❖3</b> 으로 보인다\n (툴팁에 무엇을 시켜 놨는지와 가장 오래된 것의 경과 시간).\n 0 개면 아무것도 그리지 않으므로 켜 둬서 잃는 것이 없다.\n 끄면 표시도 멈추고 대화 기록을 <b>읽지도 않는다</b>.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.subagentCount\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">끌 때 목록 끝에서 저절로 흐르기</div>\n <div class=\"description\">\n 줄을 끌어 순서를 바꿀 때 목록의 위·아래 끝에 커서를 대고 있으면\n <b>커서를 더 움직이지 않아도</b> 목록이 그 방향으로 흘러간다.\n 그래서 탭이 많아 화면에 안 보이는 자리로도 한 손짓에 옮길 수 있다.\n 끄면 손을 뗀 뒤 스크롤하고 다시 끌어야 하지만, 그 대신\n <b>맨 끝 줄 뒤에 놓는 조작이 미끄러지지 않는다</b>.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.dragAutoScroll\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<h3 class=\"mt-4 mb-3\">세션 그룹</h3>\n<div class=\"text-muted mb-3\">\n 사이드바의 세션을 <b>프로젝트 단위</b>로 묶고 헤더를 눌러 접는다. 끄고 켜는 값이 없다 —\n 그룹이 하나뿐이면 헤더도 순서도 건드리지 않으므로, 한 프로젝트만 쓸 때는 묶지 않은 화면과 같다.\n <br>\n 묶는 기준은 <b>탭이 태어난 작업 폴더</b>다 — 셸에서 <code>cd</code> 를 해도 따라오지 않으므로\n 세션이 사는 동안 그룹이 흔들리지 않는다. 그룹 안의 순서는 상태 정렬을 그대로 따른다.\n 경계는 <b>저장소 루트</b>(<code>.git</code> 등)를 위로 훑어 자동으로 잡으므로 하위 폴더에서 띄운\n 세션도 같은 프로젝트로 들어오고, 저장소가 아닌 폴더는 그 폴더 자체가 그룹이다.\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">접어 둔 그룹 펼치기</div>\n <div class=\"description\">\n 헤더를 눌러 접은 그룹은 다음 기동에도 접힌 채로 뜬다.\n <span *ngIf=\"collapsedCount()\">지금 {{collapsedCount()}}개가 접혀 있다.</span>\n <span *ngIf=\"!collapsedCount()\">지금 접힌 그룹은 없다.</span>\n </div>\n </div>\n <button class=\"btn btn-secondary\" type=\"button\" [disabled]=\"!collapsedCount()\" (click)=\"expandGroups()\">\n <i class=\"fas fa-angles-down me-2\"></i>모두 펼치기\n </button>\n</div>\n\n<h3 class=\"mt-4 mb-3\">미리보기 패널</h3>\n<div class=\"text-muted mb-3\">\n 터미널 옆에서 에이전트가 만든 md · 이미지 · 표 · 코드를 그대로 본다.\n 글자 파일은 <b>✎</b> 로 고쳐 저장하고(<code>Ctrl+S</code>), <b>🔍</b> 나 <code>Ctrl+F</code> 로 찾는다.\n 여닫기는 사이드바의 <b>▤</b> 버튼(또는 단축키 <code>agentdeck-view</code>)이다.\n 특정 CLI 에 매이지 않는다 — 화면에 찍힌 경로를 주우므로 Claude Code · Codex · Gemini 모두 같이 동작한다.\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">패널 열기</div>\n <div class=\"description\">\n 지금 여닫는다. 이 상태는 다음 기동에도 그대로 복원된다.\n 사이드바의 <b>▤</b> 버튼·단축키 <code>agentdeck-view</code> 와 같은 값이다 —\n 아래 <b>새 파일을 주우면</b> 을 <b>사람이 열 때만</b> 으로 두면 이 값은\n <b>사람이 바꿀 때만</b> 바뀐다.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.viewerOpen\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">경로 자동 수집</div>\n <div class=\"description\">\n 에이전트가 화면에 찍은 파일 경로를 주워 패널 위쪽 최근 목록에 쌓는다.\n 끄면 파일을 끌어다 놓거나 <b>+</b> 로 경로를 넣을 때만 열린다.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.viewerScrape\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">문서 패널에 읽어두기</div>\n <div class=\"description\">\n 에이전트가 만진 파일을 <b>닫혀 있는 동안에도</b> 패널에 얹어 둔다 —\n 나중에 <b>▤</b> 를 누르면 그때까지 건드린 파일이 칩으로 쌓여 있고 본문은 가장 최근 파일이다\n (<b>변경</b> 을 보고 있었으면 여는 김에 diff 를 다시 읽는다).\n 끄면 아무것도 자동으로 하지 않는다 — 무엇을 볼지 칩·<b>+</b>·드롭으로 직접 고른다.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.viewerPreload\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">패널 자동으로 열기</div>\n <div class=\"description\">\n 새 파일을 주우면 닫힌 패널을 스스로 연다. <b>기본은 꺼짐</b> — 여닫기는 사람 몫이다\n (작업 중에 저절로 열리면 터미널이 좁아진다). 위 <b>읽어두기</b> 가 내용을 채워 두므로\n 열고 싶을 때 열면 이미 최신이다. <b>읽어두기</b> 를 끄면 이 값은 의미가 없다.\n </div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.viewerAutoOpen\"\n [disabled]=\"!config.store.agentDeck.viewerPreload\"\n (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">터미널에 파일을 끌어다 놓으면</div>\n <div class=\"description\">\n 순정 Tabby 는 경로를 터미널에 붙여넣는다. 패널이 닫혀 있으면 그래서 아무것도 안 열린다 —\n 기본은 <b>물어본다</b> — 패널에 띄우기 / 경로 붙여넣기 중에서 고른다. 배너에서 \"다시 묻지 않기\" 를\n 체크하고 누르면 그 선택이 여기 저장된다.\n </div>\n </div>\n <select class=\"form-control w-auto\"\n [(ngModel)]=\"config.store.agentDeck.viewerDropOpen\"\n (ngModelChange)=\"config.save()\">\n <option value=\"ask\">물어본다 (기본)</option>\n <option value=\"always\">패널에 띄운다</option>\n <option value=\"paste\">경로를 붙여넣는다</option>\n <option value=\"never\">개입하지 않는다 (순정)</option>\n </select>\n</div>\n\n<h3 class=\"mt-4 mb-3\">에이전트 상태 연동</h3>\n<div class=\"text-muted mb-3\">\n 에이전트가 \"지시를 받았다 / 승인을 기다린다 / 끝났다\" 를 직접 알려주게 한다.\n 이게 사이드바 상태의 가장 정확한 원천이다 — 걸지 않으면 화면에 그려진 글자를 보고\n 추측하는 방식으로 동작하고, 그만큼 판정이 흔들린다.\n</div>\n\n<div class=\"form-line\" *ngIf=\"!hooksSupported\">\n <div class=\"header\">\n <div class=\"title\">이 환경에서는 걸 수 없다</div>\n <div class=\"description\">통보 스크립트가 PowerShell 이라 Windows 에서만 동작한다. 상태는 출력 패턴으로 추측한다.</div>\n </div>\n</div>\n\n<div class=\"form-line\" *ngIf=\"hooksSupported\">\n <div class=\"header\">\n <div class=\"title\">Claude Code 상태 통보 훅</div>\n <div class=\"description\">\n {{hooksOn ? '설치됨' : '설치 안 됨'}} — <code>~/.claude/settings.json</code> 의\n UserPromptSubmit / Notification / PostToolUse / PostToolUseFailure / PermissionDenied / Stop / StopFailure 에 걸린다.\n 다른 훅은 건드리지 않고, 쓰기 전에 같은 폴더에 백업을 남긴다.\n <span *ngIf=\"hookError\" class=\"text-danger d-block mt-1\">{{hookError}}</span>\n </div>\n </div>\n <button class=\"btn\" type=\"button\"\n [class.btn-secondary]=\"!hooksOn\" [class.btn-outline-danger]=\"hooksOn\"\n (click)=\"toggleHooks()\">\n <i class=\"fas me-2\" [class.fa-plug]=\"!hooksOn\" [class.fa-trash]=\"hooksOn\"></i>\n {{hooksOn ? '제거' : '설치'}}\n </button>\n</div>\n\n<div class=\"form-line\" *ngIf=\"hooksSupported\">\n <div class=\"header\">\n <div class=\"title\">Codex 상태 통보 훅</div>\n <div class=\"description\">\n {{codexHooksOn ? '설치됨' : '설치 안 됨'}} — 진행 중, 승인 대기, 완료, 중단 상태를 전달한다.\n 설치 후 Codex를 다시 열고 <code>/hooks</code>에서 AgentDeck 훅을 검토하고 신뢰해야 동작한다.\n <span *ngIf=\"codexHookError\" class=\"text-danger d-block mt-1\">{{codexHookError}}</span>\n </div>\n </div>\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"toggleCodexHooks()\">\n {{codexHooksOn ? '제거' : '설치'}}\n </button>\n</div>\n\n<div class=\"form-line\" *ngIf=\"hooksSupported && (hooksOn || codexHooksOn)\">\n <div class=\"header\">\n <div class=\"title\">통보 채널</div>\n <div class=\"description\">훅이 보낸 상태를 받는 통로. 꺼져 있으면 훅을 걸어도 전달되지 않는다. 변경은 Tabby 재시작 후 적용된다.</div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.notifyChannel\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<h3 class=\"mt-4 mb-3\">작업 루트 프로필</h3>\n<div class=\"text-muted mb-3\">새 탭이 항상 같은 작업 폴더에서 뜨도록 전용 프로필을 만든다. 변경은 Tabby 재시작 후 적용된다.</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">루트 프로필 사용</div>\n <div class=\"description\">켜고 작업 폴더를 채우면 해당 프로필을 만들어 기본 프로필로 삼는다.</div>\n </div>\n <toggle [(ngModel)]=\"config.store.agentDeck.rootProfile\" (ngModelChange)=\"config.save()\"></toggle>\n</div>\n\n<ng-container *ngIf=\"config.store.agentDeck.rootProfile\">\n <div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">프로필 이름</div>\n </div>\n <input class=\"form-control w-50\" type=\"text\"\n [(ngModel)]=\"config.store.agentDeck.rootProfileName\" (change)=\"config.save()\">\n </div>\n\n <div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">작업 폴더</div>\n <div class=\"description\">비우면 프로필을 만들지 않는다. 직접 적을 때는 백슬래시 이스케이프 함정을 피하려고 슬래시로 적는다 (예: D:/Project).</div>\n </div>\n <div class=\"input-group w-50\">\n <input class=\"form-control\" type=\"text\" placeholder=\"D:/Project\"\n [(ngModel)]=\"config.store.agentDeck.rootProfileCwd\" (change)=\"config.save()\">\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"pickCwd()\">\n <i class=\"fas fa-folder-open me-2\"></i>찾아보기\n </button>\n </div>\n </div>\n\n <div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">실행 명령</div>\n </div>\n <input class=\"form-control w-50\" type=\"text\"\n [(ngModel)]=\"config.store.agentDeck.rootProfileCommand\" (change)=\"config.save()\">\n </div>\n\n</ng-container>\n\n<h3 class=\"mt-4 mb-3\">문제 신고</h3>\n<div class=\"text-muted mb-3\">\n 버그를 만났을 때 <b>진단 로그를 모아 zip 하나로 만든다</b> — 만든 뒤 그 파일이 있는 폴더가 열린다.\n 담기는 것: 플러그인/Tabby 버전·OS, 위에 있는 설정 값, 그리고 <code>{{diagPath}}</code> 의 최근 두 세대.\n 로그에는 <b>탭 제목과 열어 본 파일 경로</b>가 들어간다 — 보내기 전에 열어 확인해도 된다.\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">화면 원문까지 넣기</div>\n <div class=\"description\">\n 화면이 깨지는 문제라면 켠다. 깨진 순간의 터미널 화면이 글자 그대로 들어가므로\n (작업 내용·코드가 보인다) 기본은 꺼져 있다.\n </div>\n </div>\n <toggle [(ngModel)]=\"diagIncludeScreen\"></toggle>\n</div>\n\n<div class=\"form-line\">\n <div class=\"header\">\n <div class=\"title\">진단 로그 모으기</div>\n <div class=\"description\">\n 플러그인 v{{diagVersion}}.\n <span *ngIf=\"diagBundlePath\" class=\"d-block mt-1\">만들었다: <code>{{diagBundlePath}}</code></span>\n <span *ngIf=\"diagError\" class=\"text-danger d-block mt-1\">{{diagError}}</span>\n </div>\n </div>\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"collectDiag()\">\n <i class=\"fas fa-folder-open me-2\"></i>모으기\n </button>\n</div>\n\n<div class=\"text-muted mt-4\">\n 화면비·사이드바 폭·투명도·상태 감지·입력 처리 등 나머지 값은 기본값으로 고정돼 있다.\n 바꿔야 한다면 설정 파일의 <code>agentDeck.*</code> 를 직접 고친다.\n 단축키는 <b>단축키</b> 탭의 <code>agentdeck-*</code> 항목에서 바꾼다.\n</div>\n`,\r\n }),\r\n __metadata(\"design:paramtypes\", [tabby_core_1.ConfigService,\r\n recovery_service_1.AgentDeckRecoveryService,\r\n update_service_1.AgentDeckUpdateService,\r\n tabby_core_1.PlatformService])\r\n], AgentDeckSettingsTabComponent);\r\nexports.AgentDeckSettingsTabComponent = AgentDeckSettingsTabComponent;\r\n","\"use strict\";\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckSettingsTabProvider = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_settings_1 = require(\"tabby-settings\");\r\nconst settings_component_1 = require(\"./settings.component\");\r\n/**\r\n * 설정 창 왼쪽 목록에 AgentDeck 탭을 끼워 넣는다.\r\n * `weight` 를 주지 않으면 등록 순서 뒤쪽에 붙는다 — 순정 탭들 아래로 가도록 그대로 둔다.\r\n */\r\nlet AgentDeckSettingsTabProvider = class AgentDeckSettingsTabProvider extends tabby_settings_1.SettingsTabProvider {\r\n constructor() {\r\n super(...arguments);\r\n this.id = 'agentdeck';\r\n this.icon = 'layer-group';\r\n this.title = 'AgentDeck';\r\n }\r\n getComponentType() {\r\n return settings_component_1.AgentDeckSettingsTabComponent;\r\n }\r\n};\r\nAgentDeckSettingsTabProvider = __decorate([\r\n (0, core_1.Injectable)()\r\n], AgentDeckSettingsTabProvider);\r\nexports.AgentDeckSettingsTabProvider = AgentDeckSettingsTabProvider;\r\n","\"use strict\";\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.WorkStatusService = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst rxjs_1 = require(\"rxjs\");\r\n/**\r\n * 부연(reason)을 들고 있을 수 있는 상태. 나머지 상태로 바뀌면 무조건 비운다 —\r\n * 끝난 뒤에도 \"Bash 권한\" 이 남아 있으면 지금 승인을 기다리는 것처럼 읽히기 때문이다\r\n */\r\nconst REASON_STATUSES = ['waiting', 'limited', 'error'];\r\n/**\r\n * 탭별 작업 상태 보관소.\r\n * 상태의 출처는 3가지 — 자동 감지(decorator), OSC 시퀀스(Claude Code 훅), 사이드바에서의 수동 지정.\r\n * pinned 가 true 면 자동 감지가 값을 덮어쓰지 않는다.\r\n */\r\nlet WorkStatusService = class WorkStatusService {\r\n constructor() {\r\n this.states = new Map();\r\n this.changed = new rxjs_1.Subject();\r\n /** 진단용 카운터 — decorator 가 실제로 붙었는지, 출력이 흘러오는지 확인한다 */\r\n this.debug = {\r\n attached: 0,\r\n outputs: 0,\r\n oscHits: 0,\r\n titleHits: 0,\r\n };\r\n }\r\n get changed$() { return this.changed; }\r\n get(tab) {\r\n let s = this.states.get(tab);\r\n if (!s) {\r\n s = {\r\n status: 'idle', label: '', reason: '', since: Date.now(), pinned: false,\r\n lastOutput: 0, busyMode: false, lastBusy: 0,\r\n };\r\n this.states.set(tab, s);\r\n }\r\n return s;\r\n }\r\n /** 자동 감지용 — pinned 상태는 건드리지 않는다 */\r\n setAuto(tab, status) {\r\n const s = this.get(tab);\r\n if (s.pinned || s.status === status) {\r\n return;\r\n }\r\n s.status = status;\r\n s.since = Date.now();\r\n this.clearReasonUnlessWaiting(s);\r\n this.changed.next();\r\n }\r\n /**\r\n * 수동/훅 지정 — 이후 자동 감지보다 우선한다.\r\n * `reason` 은 상태의 부연(승인 이유 / 한도 리셋 시각 / 오류 코드) — REASON_STATUSES 일 때만 담는다\r\n */\r\n setManual(tab, status, label, reason) {\r\n const s = this.get(tab);\r\n s.status = status;\r\n s.since = Date.now();\r\n s.pinned = true;\r\n if (label !== undefined) {\r\n s.label = label;\r\n }\r\n s.reason = REASON_STATUSES.includes(status) ? (reason !== null && reason !== void 0 ? reason : '') : '';\r\n this.changed.next();\r\n }\r\n /**\r\n * 승인대기 → 진행중. 사람이 승인한 순간을 훅은 알려주지 않는다 — 다음 훅(PostToolUse)은\r\n * 도구가 **끝난 뒤**라 긴 빌드 동안 사이드바가 승인대기에 박혀 있다. 그래서 화면에 \"esc to interrupt\"\r\n * 같은 작업 중 표시가 다시 보이면 여기로 올린다 (detect.ts). pinned·label 은 그대로 둔다 —\r\n * 훅이 고정한 탭도 이 전이만은 허용해야 하기 때문이다. waiting 이 아니면 아무것도 하지 않는다\r\n */\r\n resume(tab) {\r\n const s = this.get(tab);\r\n if (s.status !== 'waiting') {\r\n return;\r\n }\r\n s.status = 'running';\r\n s.since = Date.now();\r\n s.reason = '';\r\n this.changed.next();\r\n }\r\n setLabel(tab, label) {\r\n this.get(tab).label = label;\r\n this.changed.next();\r\n }\r\n /** 수동 고정을 풀고 자동 감지로 되돌린다 */\r\n unpin(tab) {\r\n const s = this.get(tab);\r\n s.pinned = false;\r\n s.status = 'idle';\r\n s.since = Date.now();\r\n this.clearReasonUnlessWaiting(s);\r\n this.changed.next();\r\n }\r\n /** 부연을 가질 수 없는 상태에는 이유가 남아 있을 수 없다 */\r\n clearReasonUnlessWaiting(s) {\r\n if (!REASON_STATUSES.includes(s.status)) {\r\n s.reason = '';\r\n }\r\n }\r\n markOutput(tab) {\r\n this.get(tab).lastOutput = Date.now();\r\n }\r\n /**\r\n * 에이전트가 \"작업 중\" 이라고 스스로 밝힌 순간 — 스피너나 \"esc to interrupt\" 같은 표시.\r\n *\r\n * 이 신호를 한 번이라도 본 탭은 그 뒤로 신호만 보고 판단한다(busyMode).\r\n * 상태줄을 매초 다시 그리는 TUI 를 \"계속 일하는 중\" 으로 오해하지 않기 위해서다.\r\n */\r\n markBusy(tab) {\r\n const s = this.get(tab);\r\n s.busyMode = true;\r\n s.lastBusy = Date.now();\r\n }\r\n /** 이 탭을 에이전트 TUI 로 볼지 — 아니면 예전처럼 출력 유무로 판단한다 */\r\n isBusyMode(tab) {\r\n return this.get(tab).busyMode;\r\n }\r\n forget(tab) {\r\n this.states.delete(tab);\r\n this.changed.next();\r\n }\r\n /**\r\n * 살아있는 탭만 남긴다 — **닫힌 탭이 `states` 에 쌓이는 것을 막는 유일한 경로다.**\r\n *\r\n * `states` 는 WeakMap 이 아니라 Map 이라(틱마다 전 탭을 훑어야 해서 열거가 필요하다)\r\n * 참조를 우리가 직접 지워야 한다. 지우는 곳은 원래 `decorator.detach` 하나뿐이었는데,\r\n * 거기 조건이 `root === tab || !app.tabs.includes(root)` 라서 **닫히는 순서에 걸린다** —\r\n * 분할 탭(`SplitTabComponent`)의 자식 터미널이 detach 될 때 부모가 아직 `app.tabs` 에\r\n * 남아 있으면 그냥 지나가고, 그 뒤 부모가 사라지면 아무도 지우지 않는다.\r\n * 2026-09-09 실측(PF9): 탭 11개를 닫았는데 `states` 가 37→37 로 그대로였다.\r\n *\r\n * 그래서 탭 목록이 바뀔 때마다 여기서 한 번 훑는다. 비용은 Map 크기만큼의 `includes` 이고,\r\n * 탭 목록 변화는 사람이 만드는 빈도(초당 몇 번이 최대)라 문제가 되지 않는다.\r\n */\r\n sweep(alive) {\r\n let removed = 0;\r\n for (const tab of [...this.states.keys()]) {\r\n if (!alive.includes(tab)) {\r\n this.states.delete(tab);\r\n removed++;\r\n }\r\n }\r\n if (removed > 0) {\r\n this.changed.next();\r\n }\r\n return removed;\r\n }\r\n /** 사이드바가 매 틱 호출 — idle 전환만 담당하고 화면 갱신 필요 여부를 돌려준다 */\r\n tickIdle(tab, idleAfterMs) {\r\n const s = this.get(tab);\r\n if (s.pinned || s.status !== 'running') {\r\n return false;\r\n }\r\n // 에이전트 탭은 \"작업 중\" 신호가 끊긴 시점부터 잰다.\r\n // 일반 셸은 예전대로 출력이 끊긴 시점부터 잰다 (신호를 낼 줄 모르므로)\r\n const from = s.busyMode ? s.lastBusy : s.lastOutput;\r\n if (from && Date.now() - from > idleAfterMs) {\r\n s.status = 'idle';\r\n s.since = Date.now();\r\n this.clearReasonUnlessWaiting(s);\r\n return true;\r\n }\r\n return false;\r\n }\r\n};\r\nWorkStatusService = __decorate([\r\n (0, core_1.Injectable)({ providedIn: 'root' })\r\n], WorkStatusService);\r\nexports.WorkStatusService = WorkStatusService;\r\n","\"use strict\";\r\n/**\r\n * 세션이 지금 **서브에이전트를 몇 개 돌리고 있나** — Claude Code 대화기록(JSONL) 줄만 보고 세는 순수 로직.\r\n *\r\n * 왜 대화기록인가 — 훅(`hooks/agentdeck-notify.ps1`)이 알려 주는 것은 세션 하나의 상태\r\n * (`running`/`waiting`/…)뿐이다. 그 안에서 백그라운드 Agent 가 몇 개 도는지는 훅에 없고,\r\n * 대화기록에만 남는다. 그리고 탭 ↔ 세션 연결은 이미 `notify.service.ts` 가 갖고 있으므로\r\n * (status 파일의 `sessionId`·`tabId`) 세션 id 로 대화기록을 찾아 세면 사이드바에 붙일 수 있다.\r\n *\r\n * **개수는 id 대조로 나온다** (실측 2026-09-09, 6,395줄/13MB 세션에서 호출 28 · 도는 중 1 = 실제와 일치):\r\n * - 호출 = `type:\"assistant\"` 줄의 `message.content[]` 안 `{type:\"tool_use\", name:\"Agent\", id:\"toolu_…\"}`\r\n * - 종료 = 어딘가의 문자열에 실린 `<task-notification>` 블록의 `<tool-use-id>`\r\n * - 도는 중 = 호출된 id 중 종료 알림에 안 나온 것\r\n *\r\n * **`tool_result` 를 종료로 보면 안 된다.** 백그라운드 Agent 의 `tool_result` 는 호출 **바로 다음 줄**에\r\n * `Async agent launched successfully.` 로 온다(실측: 28건 전부 호출줄 +1). 이걸 완료로 세면 항상 0개가 된다.\r\n *\r\n * **종료 알림은 JSON 모양이 한 가지가 아니다.** 같은 알림이 실측에서 세 모양으로 나왔다 —\r\n * ① `type:\"user\"` 줄의 `message.content` (문자열 그대로)\r\n * ② `type:\"queue-operation\"` 줄의 최상위 `content`\r\n * ③ `type:\"attachment\"` 줄의 `attachment.prompt`\r\n * 그래서 알림은 **줄 원문에서 태그를 직접 긁는다.** JSON 모양을 따라가면 셋 중 하나만 잡게 되는데,\r\n * 처음에 ①만 봤을 때 28건 중 16건을 놓쳤다(도는 중 16 = 오답). 태그는 순수 ASCII 라 JSON 이스케이프가\r\n * 끼어도(`\\n`) 그대로 읽힌다.\r\n *\r\n * 파일을 읽거나 경로를 뒤지지 않는다 — 줄(또는 청크)을 받아 상태를 갱신하는 것만 한다.\r\n * `group.ts`·`gitDiff.ts` 와 같은 이유다: fs·타이머가 들어오면 `npm test` 에서 돌릴 수 없고,\r\n * 폴링 주기·증분 오프셋 관리는 호출부(서비스)의 일이다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.matchesSessionTranscript = exports.formatLiveAgentTooltip = exports.summarizeLiveAgents = exports.formatSubagentTooltip = exports.summarizeSubagents = exports.feedChunk = exports.feedLines = exports.createSubagentState = exports.AGENT_TOOL_NAMES = void 0;\r\n/**\r\n * 서브에이전트를 띄우는 도구 이름. `Task` 는 옛 이름(구버전 CLI)이라 같이 받는다 —\r\n * 최근 기록에는 `Agent` 만 나오지만, 플러그인은 사용자가 깔아 둔 아무 버전과도 붙는다.\r\n */\r\nexports.AGENT_TOOL_NAMES = ['Agent', 'Task'];\r\nconst NOTIFY_OPEN = '<task-notification>';\r\nconst NOTIFY_CLOSE = '</task-notification>';\r\nconst TOOL_USE_ID_RE = /<tool-use-id>([^<]*)<\\/tool-use-id>/;\r\nconst STATUS_RE = /<status>([^<]*)<\\/status>/;\r\n/**\r\n * 알림에 실려 오는 id 의 생김새. 이걸 통과하지 못하면 버린다.\r\n *\r\n * 왜 필요한가 — 대화기록에는 **알림 형식을 설명하는 산문**도 들어 있다(이 모듈의 작업 지시문이\r\n * 그랬다). 거기서 `<tool-use-id>` 를 긁으면 `0-9]+)` 같은 정규식 조각이 딸려 온다(실측).\r\n * 실제 호출 id 와 겹치지 않는 쓰레기라 개수를 틀리게 만들지는 않지만, 상태 집합에 쌓이지 않게 막는다.\r\n */\r\nconst ID_RE = /^[A-Za-z0-9_-]{4,200}$/;\r\n/**\r\n * \"아직 도는 중\" 을 뜻하는 알림 상태들. 이 값이면 종료로 세지 않는다.\r\n *\r\n * 지금 실측에 나오는 값은 `completed`(66) 와 `failed`(5) 둘뿐이고 **둘 다 종료**다. 그래서 판정은\r\n * 화이트리스트(`completed` 만 종료)가 아니라 **블랙리스트**로 뒀다 — 새 종료 상태(`cancelled` 등)가\r\n * 생겨도 자동으로 종료로 잡히는 쪽이 안전하다. 화이트리스트면 모르는 상태가 영원히 \"도는 중\" 으로 남는다.\r\n * `<status>` 자체가 없는 알림도 종료로 본다(진행 중 알림은 관측되지 않았다).\r\n */\r\nconst RUNNING_STATUSES = ['running', 'pending', 'in_progress', 'in-progress', 'started', 'queued'];\r\n/**\r\n * 개행 없이 남은 꼬리를 얼마까지 들고 있을지. 넘으면 버린다(`dropped`).\r\n *\r\n * 꼬리는 \"아직 다 안 쓰인 줄\" 이라 다음 청크에 이어 붙여야 하는데, 파일이 이상해져서 개행이 영원히\r\n * 안 오면 메모리가 계속 늘어난다. 실측 줄 길이는 평균 2KB 지만 큰 `tool_result` 가 실린 줄은\r\n * 수백 KB 가 되므로 넉넉히 잡는다.\r\n */\r\nconst MAX_PENDING = 4 * 1024 * 1024;\r\nfunction createSubagentState() {\r\n return { calls: new Map(), done: new Set(), pending: '', lines: 0, skipped: 0, dropped: 0 };\r\n}\r\nexports.createSubagentState = createSubagentState;\r\n/** 알림 블록에서 종료 id 를 긁어 `done` 에 넣는다 (한 줄에 여러 블록이 실려 오기도 한다) */\r\nfunction readNotifications(state, line) {\r\n let at = 0;\r\n for (;;) {\r\n const open = line.indexOf(NOTIFY_OPEN, at);\r\n if (open < 0) {\r\n return;\r\n }\r\n const from = open + NOTIFY_OPEN.length;\r\n const close = line.indexOf(NOTIFY_CLOSE, from);\r\n // 닫는 태그가 없어도 앞쪽의 id 는 읽는다 — 태그 순서가 `task-id` → `tool-use-id` → 나머지라\r\n // 블록이 잘려 있어도 열쇠는 이미 지나갔다\r\n const block = close < 0 ? line.slice(from) : line.slice(from, close);\r\n at = close < 0 ? line.length : close + NOTIFY_CLOSE.length;\r\n const hit = TOOL_USE_ID_RE.exec(block);\r\n if (!hit) {\r\n continue;\r\n }\r\n const id = hit[1].trim();\r\n if (!ID_RE.test(id)) {\r\n continue;\r\n }\r\n const st = STATUS_RE.exec(block);\r\n if (st && RUNNING_STATUSES.indexOf(st[1].trim().toLowerCase()) >= 0) {\r\n continue;\r\n }\r\n state.done.add(id);\r\n }\r\n}\r\n/** 이 줄에 Agent 호출이 들어 있을 가능성이 있나 — JSON.parse 를 아끼는 값싼 체 */\r\nfunction mayHaveCall(line) {\r\n if (line.indexOf('tool_use') < 0) {\r\n return false;\r\n }\r\n for (const name of exports.AGENT_TOOL_NAMES) {\r\n if (line.indexOf(name) >= 0) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n/** `message.content[]` 에서 Agent 호출을 뽑아 `calls` 에 넣는다 */\r\nfunction readCalls(state, line) {\r\n var _a, _b;\r\n let obj;\r\n try {\r\n obj = JSON.parse(line);\r\n }\r\n catch {\r\n // 완성된 줄인데 JSON 이 아니다 — 버린다. 근거는 `feedLines` 주석\r\n state.skipped++;\r\n return;\r\n }\r\n if (!obj || typeof obj !== 'object' || obj.isSidechain === true) {\r\n // 사이드체인 = 서브에이전트 자신의 줄. 그 안에서 또 Agent 를 부른 것까지 세면 사이드바 숫자가\r\n // \"이 세션이 띄운 개수\" 가 아니게 된다. (실측 파일에는 사이드체인 줄이 없었지만, 다른 버전에서\r\n // 같은 파일에 섞여 들어오더라도 숫자가 흔들리지 않게 막아 둔다)\r\n return;\r\n }\r\n const content = (_a = obj.message) === null || _a === void 0 ? void 0 : _a.content;\r\n if (!Array.isArray(content)) {\r\n return;\r\n }\r\n for (const block of content) {\r\n if (!block || typeof block !== 'object') {\r\n continue;\r\n }\r\n if (block.type !== 'tool_use' || exports.AGENT_TOOL_NAMES.indexOf(String(block.name)) < 0) {\r\n continue;\r\n }\r\n const id = String((_b = block.id) !== null && _b !== void 0 ? _b : '').trim();\r\n if (!ID_RE.test(id) || state.calls.has(id)) {\r\n // 같은 id 가 두 번 오면 먼저 본 것을 지킨다 — 세션을 이어받으면 같은 줄이 다시 적히는 일이 있다\r\n continue;\r\n }\r\n const input = block.input && typeof block.input === 'object' ? block.input : {};\r\n // `input.prompt` 는 폴백으로도 쓰지 않는다 — 지시문 전문이라 툴팁에 넣을 것이 아니고(길다),\r\n // 사용자 대화 내용이 사이드바 title 로 새는 길을 만들지 않는다. 라벨은 description 이 정본이다\r\n const desc = typeof input.description === 'string' ? input.description.trim() : '';\r\n const type = typeof input.subagent_type === 'string' && input.subagent_type.trim()\r\n ? input.subagent_type.trim() : null;\r\n const ts = typeof obj.timestamp === 'string' && obj.timestamp ? obj.timestamp : null;\r\n state.calls.set(id, { id, description: desc, subagentType: type, startedAt: ts });\r\n }\r\n}\r\n/**\r\n * **완성된 줄들**을 먹인다. 상태를 그 자리에서 고치고 같은 객체를 돌려준다\r\n * (세션당 상태 하나를 계속 들고 도는 쓰임새라 사본을 만들 이유가 없다).\r\n *\r\n * **깨진 줄은 버린다.** 개행이 왔다는 것은 그 줄이 다 쓰였다는 뜻이라, 다시 읽어도 결과가 같다.\r\n * \"다음에 다시 보자\" 로 남기면 매 폴링마다 같은 줄을 파싱하는 무한 재시도가 된다.\r\n * 반대로 **개행 없는 꼬리는 남긴다** — 그건 \"깨진 것\" 이 아니라 \"아직 안 온 것\" 이고,\r\n * 게다가 꼬리에 있는 이벤트는 거의 항상 **가장 최신**(방금 띄운 Agent / 방금 온 종료 알림)이라\r\n * 버리면 증분 구조에서는 되찾을 기회가 없다(파일을 처음부터 다시 읽지 않는다). 그 구분은\r\n * `feedChunk` 가 개행으로 판정한다.\r\n */\r\nfunction feedLines(state, lines) {\r\n for (const raw of lines !== null && lines !== void 0 ? lines : []) {\r\n if (typeof raw !== 'string') {\r\n continue;\r\n }\r\n state.lines++;\r\n // CRLF 로 적힌 기록도 있다 — 꼬리 `\\r` 를 떼지 않으면 태그·JSON 끝이 어긋난다\r\n const line = raw.charCodeAt(raw.length - 1) === 13 ? raw.slice(0, -1) : raw;\r\n if (!line) {\r\n continue;\r\n }\r\n if (line.indexOf(NOTIFY_OPEN) >= 0) {\r\n // 알림은 JSON 모양이 세 가지라 원문에서 긁는다 (모듈 주석 참고).\r\n // 사이드체인 여부를 보지 않는 것은 의도다 — `done` 은 `calls` 와 교차될 때만 뜻이 있고\r\n // `calls` 쪽에서 이미 걸렀다\r\n readNotifications(state, line);\r\n }\r\n if (mayHaveCall(line)) {\r\n readCalls(state, line);\r\n }\r\n }\r\n return state;\r\n}\r\nexports.feedLines = feedLines;\r\n/**\r\n * 파일에서 읽은 **청크**를 먹인다. 개행으로 끝나지 않은 마지막 조각은 다음 호출까지 들고 있는다.\r\n *\r\n * 호출부는 \"지난 크기 이후만 읽기\" 만 하면 되고 줄 경계는 여기서 맞춘다 — 그 경계 처리를 호출부마다\r\n * 다시 쓰면(서비스·진단구) 사본이 갈린다. 빈 청크(파일이 안 자랐다)는 아무 일도 하지 않는다.\r\n */\r\nfunction feedChunk(state, chunk) {\r\n var _a;\r\n const text = typeof chunk === 'string' ? chunk : '';\r\n if (!text) {\r\n return state;\r\n }\r\n const buf = state.pending + text;\r\n const parts = buf.split('\\n');\r\n // 마지막 조각은 개행이 없었다는 뜻 = 아직 쓰이는 중. 청크가 개행으로 끝났으면 빈 문자열이 된다\r\n state.pending = (_a = parts.pop()) !== null && _a !== void 0 ? _a : '';\r\n if (state.pending.length > MAX_PENDING) {\r\n state.dropped++;\r\n state.pending = '';\r\n }\r\n return feedLines(state, parts);\r\n}\r\nexports.feedChunk = feedChunk;\r\n/** 도는 중인 것 = 호출된 것 중 종료 알림에 안 나온 것. 호출 순서를 지킨다 */\r\nfunction summarizeSubagents(state) {\r\n const s = state;\r\n if (!s || !(s.calls instanceof Map)) {\r\n return { running: 0, items: [], calls: 0, done: 0 };\r\n }\r\n const items = [];\r\n for (const call of s.calls.values()) {\r\n if (!s.done.has(call.id)) {\r\n items.push(call);\r\n }\r\n }\r\n return { running: items.length, items, calls: s.calls.size, done: s.done.size };\r\n}\r\nexports.summarizeSubagents = summarizeSubagents;\r\n/** 설명이 없는 호출에 붙일 이름 — 타입이라도 있으면 그걸 쓴다 */\r\nfunction callLabel(call) {\r\n return call.description || call.subagentType || '(설명 없음)';\r\n}\r\n/**\r\n * 사이드바 title(툴팁)에 넣을 문장. **도는 것이 없으면 빈 문자열** — 호출부가 title 을 아예 안 붙이게.\r\n *\r\n * 개수만으로는 \"무엇을 시켜 놨는지\" 를 모른다(그게 이 기능의 목적이다). 그래서 설명을 줄줄이 붙이는데,\r\n * 200px 사이드바(config `sidebarMin`)의 툴팁이 화면을 덮지 않게 `max` 개까지만 적고 나머지는 수로 줄인다.\r\n */\r\nfunction formatSubagentTooltip(summary, max = 8) {\r\n var _a;\r\n const items = (_a = summary === null || summary === void 0 ? void 0 : summary.items) !== null && _a !== void 0 ? _a : [];\r\n if (!items.length) {\r\n return '';\r\n }\r\n const cap = Number.isFinite(max) && max > 0 ? Math.floor(max) : items.length;\r\n const head = '서브에이전트 ' + items.length + '개 진행중';\r\n const shown = items.slice(0, cap).map(c => '· ' + callLabel(c));\r\n if (items.length > cap) {\r\n shown.push('· … 외 ' + (items.length - cap) + '개');\r\n }\r\n return [head, ...shown].join('\\n');\r\n}\r\nexports.formatSubagentTooltip = formatSubagentTooltip;\r\n/**\r\n * 훅으로 받은 목록을 화면이 쓸 모양으로 줄인다.\r\n *\r\n * 정렬을 못 박는 이유 — 툴팁은 매초 다시 그려진다. `Map` 순서(삽입순)를 그대로 쓰면 에이전트\r\n * 하나가 끝날 때마다 줄 순서가 바뀌어 읽는 중에 흔들린다.\r\n */\r\nfunction summarizeLiveAgents(list) {\r\n var _a;\r\n const counts = new Map();\r\n let running = 0;\r\n let oldestAt = 0;\r\n for (const a of list !== null && list !== void 0 ? list : []) {\r\n if (!a || !a.id) {\r\n continue;\r\n }\r\n running++;\r\n const type = a.type || '이름 없음';\r\n counts.set(type, ((_a = counts.get(type)) !== null && _a !== void 0 ? _a : 0) + 1);\r\n if (Number.isFinite(a.at) && a.at > 0 && (!oldestAt || a.at < oldestAt)) {\r\n oldestAt = a.at;\r\n }\r\n }\r\n const byType = [...counts].map(([type, count]) => ({ type, count }))\r\n .sort((x, y) => y.count - x.count || x.type.localeCompare(y.type));\r\n return { running, byType, oldestAt };\r\n}\r\nexports.summarizeLiveAgents = summarizeLiveAgents;\r\n/**\r\n * 훅 집계로 만드는 툴팁 머리. 대화기록 쪽(`formatSubagentTooltip`)과 **문구를 맞춘다** —\r\n * 같은 자리에 뜨는 글이 원천에 따라 달라 보이면 사용자는 그것을 버그로 읽는다.\r\n */\r\nfunction formatLiveAgentTooltip(summary) {\r\n const s = summary;\r\n if (!s || s.running <= 0) {\r\n return '';\r\n }\r\n const head = '서브에이전트 ' + s.running + '개 진행중';\r\n return [head, ...s.byType.map(t => '· ' + t.type + ' ' + t.count + '개')].join('\\n');\r\n}\r\nexports.formatLiveAgentTooltip = formatLiveAgentTooltip;\r\n/**\r\n * 이 파일명이 그 세션의 대화기록인가 — 호출부가 `~/.claude/projects` 의 각 프로젝트 폴더를 훑을 때 쓰는 판정.\r\n *\r\n * 프로젝트 폴더 이름 규칙(경로를 `-` 로 뭉갠 이름)에 기대지 않으려고 폴더를 훑는 방식을 쓴다.\r\n * 규칙을 흉내내면 드라이브·대소문자·특수문자에서 어긋나는데, 세션 id 로 파일명을 맞추면 폴더를\r\n * 몰라도 정확히 하나가 잡힌다(실측). 대소문자를 무시하는 것은 윈도우 파일명이라서다.\r\n */\r\nfunction matchesSessionTranscript(fileName, sessionId) {\r\n const name = String(fileName !== null && fileName !== void 0 ? fileName : '').trim().toLowerCase();\r\n const sid = String(sessionId !== null && sessionId !== void 0 ? sessionId : '').trim().toLowerCase();\r\n if (!name || !sid || !ID_RE.test(sid)) {\r\n return false;\r\n }\r\n return name === sid + '.jsonl';\r\n}\r\nexports.matchesSessionTranscript = matchesSessionTranscript;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.SynchronizedOutputStream = void 0;\r\n/** Older xterm builds ignore synchronized-output mode (DEC 2026).\r\n * ConPTY exposes a temporary cursor between the begin/end packets. Buffer the\r\n * complete frame before handing it to xterm. The caller bounds missing ends.\r\n */\r\nclass SynchronizedOutputStream {\r\n constructor() {\r\n this.pending = '';\r\n }\r\n write(data, enabled) {\r\n this.pending += data;\r\n if (!enabled || this.pending.length > 1024 * 1024) {\r\n return this.flush();\r\n }\r\n const begin = '\\x1b[?2026h';\r\n const end = '\\x1b[?2026l';\r\n if (this.pending.lastIndexOf(begin) > this.pending.lastIndexOf(end)) {\r\n return '';\r\n }\r\n for (let n = 1; n < begin.length; n++) {\r\n if (this.pending.endsWith(begin.slice(0, n))) {\r\n return '';\r\n }\r\n }\r\n return this.flush();\r\n }\r\n get waiting() { return !!this.pending; }\r\n flush() { const data = this.pending; this.pending = ''; return data; }\r\n}\r\nexports.SynchronizedOutputStream = SynchronizedOutputStream;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.pickTabByTabId = exports.newTabId = exports.TAB_ENV = void 0;\r\n/**\r\n * 훅 보고를 탭에 직결하는 열쇠 — 탭 셸에 심는 환경변수와 그것으로 탭을 고르는 순수 규칙.\r\n * Angular/Tabby 에 기대지 않아 단위 테스트가 된다 (test/tabenv.test.js).\r\n *\r\n * 왜 환경변수인가 — 0.2.1 의 프로세스 계보(bind.ts)는 훅이 매 세션 `Win32_Process` 전체를\r\n * 훑어(~450ms) 조상 PID 를 보내고 플러그인이 탭별 셸 PID 와 맞추는 방식이다. 맞기는 하지만\r\n * 훅이 느리고, 셸 PID 를 pty 에 비동기로 물어야 해서 표가 늦게 채워지는 창이 있다.\r\n * 플러그인이 탭을 열 때 셸 환경에 `AGENTDECK_TAB=<id>` 를 심어 두면 그 셸에서 뜬 claude 와\r\n * 그 훅은 환경을 그대로 물려받으므로, 훅은 `$env:AGENTDECK_TAB` 을 읽어 보내기만 하면 되고\r\n * 플러그인은 표에서 바로 찾는다. 계보 조회가 통째로 빠진다.\r\n *\r\n * 계보는 폴백으로 남는다 — 이 버전 이전에 열린 탭, 재시작으로 복원된 탭(셸이 이미 떠 있어\r\n * 새 값을 심을 수 없다), 사람이 셸 밖에서 부른 훅은 환경변수가 없다.\r\n */\r\nexports.TAB_ENV = 'AGENTDECK_TAB';\r\n/**\r\n * 탭 하나를 가리키는 짧은 무작위 id — 12 hex 자리(48비트). 같은 Tabby 안에서만 유일하면 되므로\r\n * 이 길이로 충분하고, 셸 프롬프트나 진단 로그에 찍혀도 거슬리지 않는다.\r\n * Electron 렌더러와 Node 20 은 `globalThis.crypto.getRandomValues` 를 둘 다 갖고 있다.\r\n */\r\nfunction newTabId() {\r\n const bytes = new Uint8Array(6);\r\n const c = globalThis.crypto;\r\n if (c && typeof c.getRandomValues === 'function') {\r\n c.getRandomValues(bytes);\r\n }\r\n else {\r\n for (let i = 0; i < bytes.length; i++) {\r\n bytes[i] = Math.floor(Math.random() * 256);\r\n }\r\n }\r\n return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');\r\n}\r\nexports.newTabId = newTabId;\r\n/**\r\n * 훅이 보낸 tabId 를 가진 탭(루트)을 찾는다. 분할 탭은 패널마다 id 가 다르므로 루트 하나에\r\n * 여러 id 가 달린다. 없으면 null — 추측하지 않는다 (호출자가 계보/폴백으로 넘어간다).\r\n */\r\nfunction pickTabByTabId(tabId, tabIds) {\r\n const want = typeof tabId === 'string' ? tabId.trim() : '';\r\n if (!want) {\r\n return null;\r\n }\r\n for (const [tab, ids] of tabIds) {\r\n if (ids.includes(want)) {\r\n return tab;\r\n }\r\n }\r\n return null;\r\n}\r\nexports.pickTabByTabId = pickTabByTabId;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.canRepairComposer = exports.newlineSequence = void 0;\r\n/** Windows ConPTY drops CSI-u. Alt+Enter survives as a native modified Enter.\r\n * Confirmed against Codex 0.154.0's empty composer on 2026-09-13: row 11 -> 12.\r\n */\r\nfunction newlineSequence(agent) {\r\n return agent === 'codex' ? '\\x1b\\r' : '\\n';\r\n}\r\nexports.newlineSequence = newlineSequence;\r\n/** Only Claude's bordered composer has a measured repair layout. */\r\nfunction canRepairComposer(agent) {\r\n return agent === 'claude';\r\n}\r\nexports.canRepairComposer = canRepairComposer;\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n};\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nvar __metadata = (this && this.__metadata) || function (k, v) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.AgentDeckUpdateService = void 0;\r\nconst core_1 = require(\"@angular/core\");\r\nconst tabby_core_1 = require(\"tabby-core\");\r\nconst child_process_1 = require(\"child_process\");\r\nconst fs = __importStar(require(\"fs\"));\r\nconst http = __importStar(require(\"http\"));\r\nconst https = __importStar(require(\"https\"));\r\nconst os = __importStar(require(\"os\"));\r\nconst path = __importStar(require(\"path\"));\r\nconst diag_1 = require(\"./diag\");\r\nconst update_1 = require(\"./update\");\r\n/** 레지스트리 응답을 기다리는 시간 — 기동 직후라 오래 붙들면 안 된다 */\r\nconst FETCH_TIMEOUT_MS = 6000;\r\n/** 기동하고 이만큼 뒤에 확인한다 — 창이 뜨는 순간에 네트워크를 건드리지 않는다 */\r\nconst STARTUP_DELAY_MS = 8000;\r\n/** 응답 본문 상한 — 레지스트리가 아닌 무언가가 답할 때 메모리를 먹지 않게 */\r\nconst MAX_BODY_BYTES = 512 * 1024;\r\n/**\r\n * npm 레지스트리를 보고 **Tabby 를 껐다 켜면서** 새 버전을 깐다.\r\n *\r\n * 흐름은 넷이다 —\r\n * ① 기동하고 잠시 뒤 레지스트리에 묻는다\r\n * ② 새 버전이 있으면 **물어본다** (`지금 업데이트` / `나중에` / `다시 묻지 않기`)\r\n * ③ 승낙하면 설치 스크립트를 **밖으로 띄우고** Tabby 를 닫는다\r\n * ④ 스크립트가 Tabby 종료를 기다렸다가 설치하고 다시 띄운다\r\n *\r\n * **왜 밖에서 까나.** 돌고 있는 플러그인은 자기를 갈아끼울 수 없다 — Tabby 는 기동할 때\r\n * `dist/index.js` 를 한 번 읽어 메모리에 올리므로 디스크를 바꿔도 돌던 코드는 옛것이다.\r\n * 게다가 Windows 는 로드된 파일을 잡고 있어서, 떠 있는 동안 npm 이 그 폴더를 지우려 들면\r\n * 반쯤 지운 채 실패할 수 있다 — 플러그인이 깨진 채 남는 것이 가장 나쁜 결과다.\r\n *\r\n * **개발 설치에는 설치하지 않는다.** 플러그인 폴더의 `tabby-agentdeck` 은 개발 중에는 소스\r\n * 트리를 가리키는 링크이고(`plugins/package.json` 에 `file:D:/Project/tabby-agentdeck` 로 적힌다),\r\n * 거기에 `npm install` 이 돌면 작업 중인 트리를 덮어쓴다. 판정은 `update.ts` 의 `canSelfUpdate`.\r\n */\r\nlet AgentDeckUpdateService = class AgentDeckUpdateService {\r\n constructor(app, config, platform, notifications) {\r\n this.app = app;\r\n this.config = config;\r\n this.platform = platform;\r\n this.notifications = notifications;\r\n }\r\n init() {\r\n this.app.ready$.subscribe(() => {\r\n var _a;\r\n // 개발/검증용 — deck.service 가 만든 `__agentdeck` 에 붙는다 (없으면 만든다).\r\n // `run` 은 **설치까지 간다**(승낙하면 Tabby 가 닫힌다) — 회귀에서 부를 때는\r\n // 개발 설치라 `dev-install` 에서 멈추는 것을 전제로 한다\r\n const g = globalThis;\r\n g.__agentdeck = (_a = g.__agentdeck) !== null && _a !== void 0 ? _a : {};\r\n g.__agentdeck.update = {\r\n run: (force = true) => this.run('diag', force),\r\n marks: () => this.installMarks(),\r\n canSelfUpdate: () => (0, update_1.canSelfUpdate)(this.installMarks()),\r\n pluginsDir: () => this.pluginsDir(),\r\n version: () => (0, diag_1.pluginVersion)(),\r\n };\r\n setTimeout(() => { void this.run('startup'); }, STARTUP_DELAY_MS);\r\n });\r\n }\r\n /**\r\n * 한 번 확인하고, 새 버전이면 물어본 뒤 설치를 건다.\r\n *\r\n * `force` 는 설정 창의 `지금 확인` 용 — 간격 제한과 `다시 묻지 않기` 를 건너뛴다\r\n * (사람이 직접 눌렀으니 그 순간만큼은 묻는 게 맞다). 기능 자체를 끈 것은 존중한다.\r\n */\r\n async run(reason, force = false) {\r\n const cfg = this.config.store.agentDeck;\r\n const current = (0, diag_1.pluginVersion)();\r\n const marks = this.installMarks();\r\n const devInstall = !(0, update_1.canSelfUpdate)(marks);\r\n if (cfg.autoUpdate === false) {\r\n (0, diag_1.diag)(`update skip=disabled reason=${reason}`);\r\n return 'disabled';\r\n }\r\n if (!force && !(0, update_1.shouldCheck)(cfg.lastUpdateCheck, Date.now(), Number(cfg.updateCheckIntervalHours) || update_1.DEFAULT_INTERVAL_HOURS)) {\r\n (0, diag_1.diag)(`update skip=too-soon reason=${reason}`);\r\n return 'too-soon';\r\n }\r\n let latest = null;\r\n try {\r\n latest = (0, update_1.parseLatestVersion)(await this.fetch((0, update_1.latestUrl)(cfg.updateRegistry)));\r\n }\r\n catch (e) {\r\n // 오프라인·사내망·프록시 — 흔한 일이고 사람에게 알릴 것이 아니다\r\n (0, diag_1.diagCatch)('update 레지스트리 조회', e);\r\n }\r\n // 물어본 것 자체를 기록한다(성공이든 아니든) — 실패할 때마다 기동마다 다시 묻지 않게\r\n cfg.lastUpdateCheck = Date.now();\r\n this.config.save();\r\n const outcome = (0, update_1.decide)({\r\n enabled: true,\r\n lastCheckAt: 0,\r\n now: Date.now(),\r\n intervalHours: 0,\r\n devInstall,\r\n current,\r\n latest,\r\n });\r\n (0, diag_1.diag)(`update check=${reason} current=${current} latest=${latest !== null && latest !== void 0 ? latest : '?'} outcome=${outcome}`\r\n + ` dev=${devInstall} marks=${JSON.stringify(marks)}`);\r\n if (outcome === 'dev-install') {\r\n // 개발 중인 사람에게는 알려 줄 값이 있다 — 다만 손대지 않는다\r\n this.notifications.info(`AgentDeck ${latest} 가 나왔다 (지금 ${current})`, '개발 설치(소스 링크)라 자동으로 갈아끼우지 않는다. 소스에서 직접 올릴 것.');\r\n return outcome;\r\n }\r\n if (outcome !== 'update-ready') {\r\n return outcome;\r\n }\r\n // 이 버전은 건너뛰기로 한 적이 있나 — `다시 묻지 않기` 는 **그 버전에만** 건다.\r\n // 영구히 끄는 것은 설정의 `autoUpdate` 쪽이고, 여기서 영구히 막으면 다음 버전도 못 받는다\r\n if (!force && cfg.updateSkipVersion === latest) {\r\n (0, diag_1.diag)(`update skip=asked-not-to version=${latest}`);\r\n return 'skipped';\r\n }\r\n return this.confirmAndInstall(current, latest);\r\n }\r\n /** ② 물어보고 ③ 설치 스크립트를 띄운 뒤 Tabby 를 닫는다 */\r\n async confirmAndInstall(current, latest) {\r\n var _a;\r\n const r = await this.platform.showMessageBox({\r\n type: 'warning',\r\n message: `AgentDeck ${latest} 로 업데이트할까요? (지금 ${current})`,\r\n detail: [\r\n '업데이트하려면 Tabby 를 닫아야 합니다 — 돌고 있는 플러그인은 갈아끼울 수 없습니다.',\r\n '',\r\n '누르면 이렇게 됩니다:',\r\n ' 1. Tabby 가 닫힙니다 (열린 탭과 돌고 있는 세션이 끊깁니다)',\r\n ' 2. 백그라운드에서 새 버전을 내려받아 설치합니다',\r\n ' 3. Tabby 가 다시 켜집니다',\r\n '',\r\n '끊긴 Claude Code 대화는 사이드바의 `⟲ 지난 세션` 에서 이어받을 수 있습니다.',\r\n ].join('\\n'),\r\n buttons: ['지금 업데이트', '나중에', '다시 묻지 않기'],\r\n defaultId: 1,\r\n cancelId: 1,\r\n });\r\n if (r.response === 2) {\r\n // 이 버전만 건너뛴다 — 다음 버전이 나오면 다시 묻는다\r\n this.config.store.agentDeck.updateSkipVersion = latest;\r\n this.config.save();\r\n (0, diag_1.diag)(`update skip-version=${latest}`);\r\n return 'skipped';\r\n }\r\n if (r.response !== 0) {\r\n return 'postponed';\r\n }\r\n try {\r\n this.launchUpdater(latest);\r\n }\r\n catch (e) {\r\n (0, diag_1.diagCatch)('update 설치 스크립트 기동', e);\r\n this.notifications.error('업데이트를 시작하지 못했다', `${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e} — 설정 → 플러그인 에서 직접 업데이트할 수 있다.`);\r\n return 'failed';\r\n }\r\n // 스크립트가 우리 종료를 기다리고 있다. 여기서 닫아 줘야 설치가 시작된다\r\n (0, diag_1.diag)(`update quit for install ${current} -> ${latest}`);\r\n setTimeout(() => this.platform.quit(), 300);\r\n return 'installing';\r\n }\r\n /**\r\n * 설치 스크립트를 **패키지 밖에서** 떼어 띄운다.\r\n *\r\n * 임시 폴더로 복사하는 이유: 이 스크립트는 곧 npm 이 통째로 갈아엎을 폴더 안에 산다.\r\n * 제자리에서 돌리면 자기 발밑이 사라진다.\r\n *\r\n * `detached` + `unref` 라야 Tabby 가 죽어도 살아남는다 — 부모가 죽을 때 같이 끌려가면\r\n * 설치는커녕 Tabby 를 다시 띄우지도 못한다.\r\n */\r\n launchUpdater(version) {\r\n const src = path.join(__dirname, '..', 'updater', 'agentdeck-update.ps1');\r\n if (!fs.existsSync(src)) {\r\n throw new Error(`설치 스크립트를 찾지 못했다: ${src}`);\r\n }\r\n const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'agentdeck-up-'));\r\n const script = path.join(dir, 'agentdeck-update.ps1');\r\n fs.copyFileSync(src, script);\r\n const pluginsDir = this.pluginsDir();\r\n if (!pluginsDir) {\r\n throw new Error('Tabby 플러그인 폴더를 찾지 못했다');\r\n }\r\n const child = (0, child_process_1.spawn)('powershell.exe', [\r\n '-NoProfile', '-ExecutionPolicy', 'Bypass', '-WindowStyle', 'Hidden',\r\n '-File', script,\r\n '-Version', version,\r\n '-PluginsDir', pluginsDir,\r\n // Electron 에서 `process.execPath` 가 곧 Tabby.exe 다 — 경로를 짐작하지 않는다\r\n '-TabbyExe', process.execPath,\r\n // **우리 인스턴스의 메인 PID.** 플러그인은 렌더러에서 도므로 `ppid` 가 메인이다\r\n // (2026-09-11 실측: renderer pid=35432 / ppid=10028 = OS 가 보여준 main 과 일치).\r\n // 이름으로 전부 기다리면 **다른 Tabby 창 하나 때문에 업데이트가 영영 안 된다**\r\n '-TabbyPid', String(this.mainProcessPid()),\r\n ], { detached: true, stdio: 'ignore' });\r\n child.unref();\r\n (0, diag_1.diag)(`update updater spawned pid=${child.pid} script=${script}`);\r\n }\r\n /**\r\n * 이 Tabby 인스턴스의 **메인 프로세스 PID**.\r\n *\r\n * 플러그인은 렌더러에서 돌고, Electron 렌더러의 부모가 메인이다. 메인이 죽으면 렌더러·gpu 도\r\n * 함께 내려가므로 \"이 인스턴스가 완전히 꺼졌나\" 를 재는 기준점으로 이것이 맞다.\r\n * `ppid` 를 못 읽는 환경(테스트 하네스 등)에서는 0 을 주고, 스크립트가 옛 방식으로 물러난다.\r\n */\r\n mainProcessPid() {\r\n const ppid = Number(process.ppid);\r\n return Number.isFinite(ppid) && ppid > 0 ? ppid : 0;\r\n }\r\n /** `<Tabby 설정폴더>/plugins` — npm 이 `--prefix` 로 받을 경로 */\r\n pluginsDir() {\r\n var _a, _b;\r\n try {\r\n const configPath = (_b = (_a = this.platform).getConfigPath) === null || _b === void 0 ? void 0 : _b.call(_a);\r\n return configPath ? path.join(path.dirname(configPath), 'plugins') : null;\r\n }\r\n catch {\r\n return null;\r\n }\r\n }\r\n /**\r\n * 이 설치본이 개발 설치인지 가리는 표식.\r\n *\r\n * 배포본에는 `dist`·`hooks`·`updater`·`install.ps1` 만 들어간다(`package.json` 의 `files`).\r\n * `src/`·`webpack.config.js`·`.git` 중 하나라도 있으면 소스 트리이고, 플러그인 폴더의\r\n * 항목이 링크면 junction 설치다 — 어느 쪽이든 건드리면 안 된다.\r\n */\r\n installMarks() {\r\n // `__dirname` 은 `<플러그인>/dist` 다. junction 으로 깔려 있으면 node 가 실경로로 풀어 주므로\r\n // 이 값 자체가 이미 소스 트리를 가리킨다 — 그래서 아래 파일 표식이 곧바로 걸린다\r\n const root = path.join(__dirname, '..');\r\n const has = (rel) => {\r\n try {\r\n return fs.existsSync(path.join(root, rel));\r\n }\r\n catch {\r\n return false;\r\n }\r\n };\r\n return {\r\n hasSrc: has('src'),\r\n hasGit: has('.git'),\r\n hasWebpackConfig: has('webpack.config.js'),\r\n isLink: this.pluginEntryIsLink(),\r\n };\r\n }\r\n /** Tabby 플러그인 폴더의 우리 항목이 링크인가 — junction 설치의 가장 직접적인 증거 */\r\n pluginEntryIsLink() {\r\n try {\r\n const dir = this.pluginsDir();\r\n if (!dir) {\r\n return false;\r\n }\r\n return fs.lstatSync(path.join(dir, 'node_modules', update_1.PACKAGE_NAME)).isSymbolicLink();\r\n }\r\n catch {\r\n // 경로를 못 찾거나 항목이 없다 — 링크라고 단정하지 않는다(파일 표식이 따로 본다)\r\n return false;\r\n }\r\n }\r\n /** GET 한 번. 리다이렉트는 따라가지 않는다 — 레지스트리 `/latest` 는 200 으로 답한다 */\r\n fetch(url) {\r\n return new Promise((resolve, reject) => {\r\n const mod = url.startsWith('http://') ? http : https;\r\n const req = mod.get(url, { headers: { accept: 'application/json' } }, (res) => {\r\n if (res.statusCode !== 200) {\r\n res.resume();\r\n reject(new Error(`HTTP ${res.statusCode}`));\r\n return;\r\n }\r\n let body = '';\r\n res.setEncoding('utf8');\r\n res.on('data', (chunk) => {\r\n body += chunk;\r\n if (body.length > MAX_BODY_BYTES) {\r\n req.destroy(new Error('응답이 너무 크다'));\r\n }\r\n });\r\n res.on('end', () => resolve(body));\r\n });\r\n req.setTimeout(FETCH_TIMEOUT_MS, () => req.destroy(new Error('시간 초과')));\r\n req.on('error', reject);\r\n });\r\n }\r\n};\r\nAgentDeckUpdateService = __decorate([\r\n (0, core_1.Injectable)({ providedIn: 'root' }),\r\n __metadata(\"design:paramtypes\", [tabby_core_1.AppService,\r\n tabby_core_1.ConfigService,\r\n tabby_core_1.PlatformService,\r\n tabby_core_1.NotificationsService])\r\n], AgentDeckUpdateService);\r\nexports.AgentDeckUpdateService = AgentDeckUpdateService;\r\n","\"use strict\";\r\n/**\r\n * **자동 업데이트의 판단 규칙** — 언제 확인할지, 새 버전인지, 업데이트해도 되는지.\r\n *\r\n * 네트워크·fs·타이머는 여기 없다 (`group.ts`·`sessionLedger.ts` 와 같은 이유). 이 파일은\r\n * \"무엇을 근거로 결정하는가\" 만 정하고, 실제로 묻고 설치하는 것은 `update.service.ts` 다.\r\n *\r\n * ## 왜 \"받아 두고 다음 기동에 적용\" 인가\r\n *\r\n * Tabby 는 플러그인을 **기동할 때 한 번** 읽는다. 돌고 있는 플러그인을 갈아끼울 방법이 없으므로\r\n * 어떤 방식으로 업데이트하든 재시작이 필요하다. 그래서 이 기능은 조용히 받아만 두고\r\n * \"재시작하면 적용된다\" 고 한 번 알린다 — 사람의 작업을 끊지 않는 유일한 모양이다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.decide = exports.canSelfUpdate = exports.shouldCheck = exports.latestUrl = exports.parseLatestVersion = exports.isNewer = exports.compareVersions = exports.parseVersion = exports.DEFAULT_INTERVAL_HOURS = exports.PACKAGE_NAME = exports.DEFAULT_REGISTRY = void 0;\r\n/** npm 레지스트리 기본값. 사내 미러를 쓰는 사람은 설정으로 바꾼다 */\r\nexports.DEFAULT_REGISTRY = 'https://registry.npmjs.org';\r\n/** 이 패키지 이름 — 레지스트리에 물어볼 대상이자 `installPlugin` 에 넘길 이름 */\r\nexports.PACKAGE_NAME = 'tabby-agentdeck';\r\n/** 확인 간격 기본값 (시간). 기동마다 묻지 않는다 — 레지스트리에도 사람 네트워크에도 예의가 아니다 */\r\nexports.DEFAULT_INTERVAL_HOURS = 6;\r\n/**\r\n * 버전 문자열을 숫자 3개 + 프리릴리스로 가른다.\r\n * semver 가 아니면 `null` — 그런 값이 오면 비교하지 않고 \"모른다\" 로 둔다(업데이트를 강행하지 않는다).\r\n */\r\nfunction parseVersion(v) {\r\n var _a;\r\n if (typeof v !== 'string') {\r\n return null;\r\n }\r\n const m = /^\\s*v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+[0-9A-Za-z.-]+)?\\s*$/.exec(v);\r\n if (!m) {\r\n return null;\r\n }\r\n return { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: (_a = m[4]) !== null && _a !== void 0 ? _a : null };\r\n}\r\nexports.parseVersion = parseVersion;\r\n/**\r\n * semver 비교 — `a < b` 면 -1, 같으면 0, `a > b` 면 1. 못 읽으면 `null`.\r\n *\r\n * 프리릴리스는 같은 숫자의 정식판보다 **낮다**(`1.1.0-beta` < `1.1.0`). 프리릴리스끼리는\r\n * 점으로 끊어 숫자는 수로, 그 외는 문자열로 비교한다 (semver 규칙 그대로).\r\n */\r\nfunction compareVersions(a, b) {\r\n const pa = parseVersion(a);\r\n const pb = parseVersion(b);\r\n if (!pa || !pb) {\r\n return null;\r\n }\r\n for (let i = 0; i < 3; i++) {\r\n if (pa.nums[i] !== pb.nums[i]) {\r\n return pa.nums[i] < pb.nums[i] ? -1 : 1;\r\n }\r\n }\r\n if (pa.pre === pb.pre) {\r\n return 0;\r\n }\r\n // 한쪽만 프리릴리스면 그쪽이 낮다\r\n if (pa.pre === null) {\r\n return 1;\r\n }\r\n if (pb.pre === null) {\r\n return -1;\r\n }\r\n const xa = pa.pre.split('.');\r\n const xb = pb.pre.split('.');\r\n for (let i = 0; i < Math.max(xa.length, xb.length); i++) {\r\n const ta = xa[i];\r\n const tb = xb[i];\r\n if (ta === undefined) {\r\n return -1;\r\n }\r\n if (tb === undefined) {\r\n return 1;\r\n }\r\n const na = /^\\d+$/.test(ta);\r\n const nb = /^\\d+$/.test(tb);\r\n if (na && nb) {\r\n if (Number(ta) !== Number(tb)) {\r\n return Number(ta) < Number(tb) ? -1 : 1;\r\n }\r\n }\r\n else if (ta !== tb) {\r\n return ta < tb ? -1 : 1;\r\n }\r\n }\r\n return 0;\r\n}\r\nexports.compareVersions = compareVersions;\r\n/** 레지스트리의 것이 지금 것보다 새로운가. 못 읽으면 `false` — 모르면 건드리지 않는다 */\r\nfunction isNewer(current, latest) {\r\n return compareVersions(current, latest) === -1;\r\n}\r\nexports.isNewer = isNewer;\r\n/** 레지스트리 응답(JSON 문자열)에서 버전을 꺼낸다 — `<registry>/<pkg>/latest` 의 모양 */\r\nfunction parseLatestVersion(body) {\r\n var _a;\r\n try {\r\n const v = (_a = JSON.parse(body)) === null || _a === void 0 ? void 0 : _a.version;\r\n return parseVersion(v) ? String(v).trim() : null;\r\n }\r\n catch {\r\n // HTML 오류 페이지·프록시 응답 — 버전을 모르는 것으로 본다\r\n return null;\r\n }\r\n}\r\nexports.parseLatestVersion = parseLatestVersion;\r\n/** 물어볼 주소. 레지스트리 끝의 `/` 가 있든 없든 같은 주소가 나오게 한다 */\r\nfunction latestUrl(registry, pkg = exports.PACKAGE_NAME) {\r\n const base = (registry || exports.DEFAULT_REGISTRY).replace(/\\/+$/, '');\r\n return `${base}/${encodeURIComponent(pkg)}/latest`;\r\n}\r\nexports.latestUrl = latestUrl;\r\n/** 지금 확인할 때가 됐나. `lastCheckAt` 이 미래면(시계가 뒤로 갔다) 확인한다 */\r\nfunction shouldCheck(lastCheckAt, now, intervalHours) {\r\n const last = Number(lastCheckAt) || 0;\r\n if (last > now) {\r\n return true;\r\n }\r\n const interval = Math.max(0, Number(intervalHours) || 0) * 3600000;\r\n return now - last >= interval;\r\n}\r\nexports.shouldCheck = shouldCheck;\r\n/**\r\n * 이 설치본을 자동으로 갈아끼워도 되나.\r\n *\r\n * **개발 설치(소스 트리로의 junction)에는 절대 하면 안 된다.** Tabby 플러그인 폴더의\r\n * `tabby-agentdeck` 은 개발 중에는 `D:\\Project\\tabby-agentdeck` 을 가리키는 링크이고\r\n * (`install.ps1`), 거기에 `npm install` 이 돌면 **작업 중인 소스 트리를 덮어쓴다.**\r\n *\r\n * 판정은 두 가지를 본다 — 둘 다 배포본에는 없는 것들이다\r\n * (`package.json` 의 `files` 는 `dist`·`hooks`·`install.ps1` 뿐이다):\r\n * - `src/` 나 `webpack.config.js` 가 있다 = 소스 트리\r\n * - `.git` 이 있다 = 저장소\r\n * 하나라도 걸리면 확인만 하고 설치는 하지 않는다.\r\n */\r\nfunction canSelfUpdate(marks) {\r\n return !(marks.hasSrc || marks.hasGit || marks.hasWebpackConfig || marks.isLink);\r\n}\r\nexports.canSelfUpdate = canSelfUpdate;\r\n/**\r\n * 확인 결과로 무엇을 할지 — 순수 결정.\r\n *\r\n * 설치 성공/실패는 이 함수가 모르므로(`installPlugin` 이 비동기다) 여기서는\r\n * `update-ready` 직전까지만 정하고, 실제 설치는 서비스가 하고 실패하면 `failed` 로 덮는다.\r\n */\r\nfunction decide(input) {\r\n if (!input.enabled) {\r\n return 'disabled';\r\n }\r\n if (!shouldCheck(input.lastCheckAt, input.now, input.intervalHours)) {\r\n return 'too-soon';\r\n }\r\n if (input.latest === null) {\r\n return 'unknown';\r\n }\r\n if (!isNewer(input.current, input.latest)) {\r\n return 'up-to-date';\r\n }\r\n // 새 버전이 있는데 개발 설치다 — 알려만 주고 손대지 않는다\r\n return input.devInstall ? 'dev-install' : 'update-ready';\r\n}\r\nexports.decide = decide;\r\n","\"use strict\";\r\n/**\r\n * 결과물 미리보기 패널 — 터미널 옆에서 md·이미지·표·텍스트를 그대로 본다.\r\n *\r\n * 왜 필요한가: 에이전트가 만든 것이 문서(md)나 그림이면 터미널 안에서는 확인이 안 된다.\r\n * 지금까지는 탐색기로 나가서 열었고, 그 왕복이 \"작업 결과를 안 보고 넘어가는\" 이유였다.\r\n * Codex 앱의 오른쪽 패널이 하는 일과 같은 자리다.\r\n *\r\n * **어느 에이전트에도 매이지 않는다** — 보여줄 파일을 고르는 근거가 세 갈래인데 셋 다\r\n * 특정 CLI 의 기능이 아니다. ① 화면에 찍힌 경로를 줍는다(Claude·Codex·Gemini 가 모두 찍는다)\r\n * ② 사람이 경로를 넣거나 파일을 끌어다 놓는다 ③ 최근 목록에서 고른다.\r\n *\r\n * 이 파일이 하는 일은 DOM 과 파일 접근이다. 판정 로직(종류 분류·경로 줍기·최근 목록)은\r\n * viewer.ts 에, 마크다운 렌더는 markdown.ts 에 순수 함수로 있다 — dock.ts 를 deck.service 에서\r\n * 가른 것과 같은 이유(테스트로 묶기 위해서)다.\r\n */\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.ViewPanel = exports.MIN_VIEW_W = exports.VIEW_ID = void 0;\r\nconst child_process_1 = require(\"child_process\");\r\nconst fs = __importStar(require(\"fs\"));\r\nconst path = __importStar(require(\"path\"));\r\nconst markdown_1 = require(\"./markdown\");\r\nconst viewer_1 = require(\"./viewer\");\r\nconst gitDiff_1 = require(\"./gitDiff\");\r\nconst gitCommit_1 = require(\"./gitCommit\");\r\nexports.VIEW_ID = 'agentdeck-view';\r\n/** 패널이 이보다 좁으면 문서를 읽을 수 없다 */\r\nexports.MIN_VIEW_W = 260;\r\n/** 한 번에 읽어 들이는 글자 파일의 상한 — 이보다 크면 앞부분만 보여준다 */\r\nconst MAX_TEXT_BYTES = 1500000;\r\n/** 글자 파일에서 그리는 최대 줄 수 */\r\nconst MAX_TEXT_LINES = 4000;\r\n/** 표에서 그리는 최대 행/열 */\r\nconst MAX_TABLE_ROWS = 400;\r\nconst MAX_TABLE_COLS = 60;\r\n/** data URL 로 만들 이미지의 상한 — 이보다 크면 안 읽는다 (렌더러 메모리에 그대로 올라간다) */\r\nconst MAX_IMAGE_BYTES = 25000000;\r\n/** 마크다운 안의 이미지를 data URL 로 바꿔 줄 상한 */\r\nconst MAX_INLINE_IMAGE_BYTES = 4000000;\r\n/** PTY 출력을 모아 두고 경로를 훑는 주기 (ms) — 조각마다 정규식을 돌리지 않기 위한 것 */\r\nconst SCRAPE_DEBOUNCE_MS = 400;\r\n/**\r\n * 편집 모드로 열 수 있는 글자 파일의 상한.\r\n *\r\n * 보기 상한(`MAX_TEXT_BYTES`)과 같은 값을 쓰되 **뜻이 다르다** — 보기는 앞부분만 읽어도 되지만\r\n * 편집은 저장할 때 파일 전체를 다시 쓰므로, 앞부분만 들고 저장하면 **뒷부분이 사라진다.**\r\n * 그래서 편집은 전체를 읽을 수 있을 때만 연다(`readTextAll` 이 잘렸다고 하면 보기 전용).\r\n */\r\nconst MAX_EDIT_BYTES = MAX_TEXT_BYTES;\r\n/** 검색에서 한 번에 표시하는 최대 일치 수 — 이보다 많으면 앞에서부터 이만큼만 오간다 */\r\nconst MAX_FIND_HITS = 2000;\r\n/** 그 사이 모아 두는 출력의 상한 (글자) */\r\nconst SCRAPE_BUFFER_MAX = 16384;\r\n/** 열어 둔 파일이 바뀌었는지 보는 주기 (ms) */\r\nconst WATCH_INTERVAL_MS = 1000;\r\n// ---------- `변경` 탭 (git) ----------\r\n// 설정키를 새로 만들지 않고 모듈 상수로 둔다 — 이 수치들은 \"패널이 굳지 않는 선\" 이고\r\n// 사용자가 고를 이유가 없다.\r\n/** git 한 번에 기다려 주는 시간 (ms). 이보다 걸리면 저장소가 아니거나 잠겨 있는 것으로 본다 */\r\nconst GIT_TIMEOUT_MS = 5000;\r\n/** git 출력 상한 — package-lock 한 장만 바뀌어도 기본값 1MB 를 넘는다 */\r\nconst GIT_MAX_BUFFER = 32 * 1024 * 1024;\r\n/** 목록에 그리는 파일 수 상한 */\r\nconst MAX_DIFF_FILES = 200;\r\n/** 본문에 그리는 총 줄 수 상한 — DOM 노드가 이 수에 비례한다 */\r\nconst MAX_DIFF_LINES = 20000;\r\n/** 한 파일이 본문 예산을 다 먹지 않게 하는 파일별 상한 */\r\nconst MAX_DIFF_FILE_LINES = 4000;\r\n/** 추적되지 않는 파일 목록의 상한 */\r\nconst MAX_UNTRACKED = 100;\r\n/**\r\n * 자동 갱신 최소 간격 (ms). 에이전트가 파일을 연달아 고치면 훑기(400ms)마다 신호가 오는데,\r\n * 그때마다 git 을 돌리면 프로세스가 겹친다.\r\n */\r\nconst DIFF_AUTO_MS = 1500;\r\n// ---------- `파일:라인` 참조 ----------\r\n/**\r\n * 참조를 넣은 뒤 안내줄이 켜진 채로 있는 시간 (ms).\r\n * 켜 둔 채로 놔두면 다음에 무엇이 새로 일어났는지 구별이 안 된다.\r\n */\r\nconst REF_FLASH_MS = 2500;\r\n/**\r\n * 직전에 넣은 참조에 **이어 붙일 수 있다고 보는 시간** (ms).\r\n *\r\n * 이보다 오래 지났으면 사람이 그 사이에 문장을 쳤다고 보고 참조를 처음부터 다시 넣는다 —\r\n * 프롬프트 내용을 우리가 읽을 수 없으므로 시간이 유일한 단서다.\r\n */\r\nconst REF_CHAIN_MS = 15000;\r\nconst MIME = {\r\n png: 'image/png',\r\n jpg: 'image/jpeg',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n webp: 'image/webp',\r\n bmp: 'image/bmp',\r\n ico: 'image/x-icon',\r\n avif: 'image/avif',\r\n svg: 'image/svg+xml',\r\n};\r\n/**\r\n * 여러 줄 git 출력에서 사람에게 보여줄 첫 줄만 뽑는다 — 패널의 알림줄은 한 줄이고,\r\n * git 은 실패 이유를 여러 줄(+빈 줄)로 쓴다.\r\n */\r\nfunction firstLine(s) {\r\n var _a;\r\n const t = (_a = String(s !== null && s !== void 0 ? s : '').split('\\n').map(v => v.trim()).filter(v => v)[0]) !== null && _a !== void 0 ? _a : '';\r\n return t.length > 200 ? t.slice(0, 200) + '…' : t;\r\n}\r\n/**\r\n * 파일 한 줄에 붙일 꼬리말 — `12.3 KB · 22:41`. 사라졌으면 그 사실을 말한다.\r\n *\r\n * git 없이 그리는 목록(`noGit`)에서 쓴다. diff 를 못 만드는 자리라 **언제 얼마나** 가\r\n * 사람에게 남는 유일한 단서다. 시각은 날짜를 빼고 시:분만 — 이 목록은 지금 도는 세션의\r\n * 것이라 오늘 안이고, 폭이 좁은 패널에서 날짜까지 넣으면 경로가 밀린다.\r\n */\r\nfunction fileNote(target) {\r\n try {\r\n const st = fs.statSync(target);\r\n if (st.isDirectory()) {\r\n return '폴더';\r\n }\r\n const t = new Date(st.mtimeMs);\r\n const hh = String(t.getHours()).padStart(2, '0');\r\n const mm = String(t.getMinutes()).padStart(2, '0');\r\n return (0, viewer_1.formatBytes)(st.size) + ' · ' + hh + ':' + mm;\r\n }\r\n catch {\r\n // 만졌지만 지금은 없다 — 에이전트가 지웠거나 옮겼다. 목록에서 빼지 않는다:\r\n // \"사라졌다\" 는 것 자체가 사람이 알아야 할 변화다\r\n return '지금은 없다';\r\n }\r\n}\r\n/** git 을 돌릴 자리인가 — 없거나 파일이면 false */\r\nfunction isDir(target) {\r\n try {\r\n return fs.statSync(target).isDirectory();\r\n }\r\n catch {\r\n return false;\r\n }\r\n}\r\nfunction mimeOf(file) {\r\n var _a;\r\n return (_a = MIME[path.extname(file).slice(1).toLowerCase()]) !== null && _a !== void 0 ? _a : 'application/octet-stream';\r\n}\r\nfunction dataUrl(file, limit) {\r\n try {\r\n const st = fs.statSync(file);\r\n if (!st.isFile() || st.size > limit) {\r\n return null;\r\n }\r\n return 'data:' + mimeOf(file) + ';base64,' + fs.readFileSync(file).toString('base64');\r\n }\r\n catch {\r\n return null;\r\n }\r\n}\r\n/** BOM 을 떼고 읽는다 — 이 프로젝트의 .cs / .md 는 BOM 이 붙어 있는 것이 많다 */\r\nfunction readTextHead(file, limit) {\r\n const buf = fs.readFileSync(file);\r\n const cut = buf.length > limit;\r\n let text = buf.slice(0, cut ? limit : buf.length).toString('utf8');\r\n if (text.charCodeAt(0) === 0xfeff) {\r\n text = text.slice(1);\r\n }\r\n return { text, truncated: cut };\r\n}\r\n/**\r\n * 이 파일에 쓸 수 있나. **편집을 열기 전에** 본다 — 다 쳐 놓고 저장할 때야 알면 그 타이핑이\r\n * 통째로 헛일이 된다.\r\n *\r\n * 이 리포를 쓰는 환경에서 읽기 전용의 가장 흔한 정체는 **P4 에서 체크아웃하지 않은 파일**이다\r\n * (`p4 sync` 가 읽기 전용으로 내려 준다). 그래서 안내 문구가 `p4 edit` 를 같이 말한다.\r\n */\r\nfunction isWritable(file) {\r\n try {\r\n fs.accessSync(file, fs.constants.W_OK);\r\n return true;\r\n }\r\n catch {\r\n return false;\r\n }\r\n}\r\n/**\r\n * 편집용으로 파일 **전체**를 읽는다. 보기와 달리 앞부분만 읽어서는 안 된다 — 저장이 파일을\r\n * 통째로 다시 쓰기 때문이다. 한도를 넘으면 `truncated: true` 로만 알리고 편집을 열지 않는다.\r\n *\r\n * 원본의 **BOM 과 개행**을 같이 돌려주는 이유: 이 프로젝트의 `.cs`·`.md` 는 BOM 이 붙은 것이\r\n * 많고, 리포에 따라 CRLF 인 파일도 있다. textarea 는 값을 읽을 때 개행을 LF 로 정규화하므로,\r\n * 저장할 때 원래대로 되돌리지 않으면 **파일 전체가 바뀐 것으로 보인다**(P4/git diff 가 전 줄\r\n * 변경으로 뜬다).\r\n */\r\nfunction readTextAll(file, limit) {\r\n const buf = fs.readFileSync(file);\r\n if (buf.length > limit) {\r\n return { text: '', truncated: true, bom: false, crlf: false };\r\n }\r\n let text = buf.toString('utf8');\r\n const bom = text.charCodeAt(0) === 0xfeff;\r\n if (bom) {\r\n text = text.slice(1);\r\n }\r\n // 섞여 있으면 CRLF 로 본다 — 다수결이 아니라 \"하나라도 CRLF 면 그 리포의 규칙\" 이라는 뜻\r\n const crlf = text.indexOf('\\r\\n') >= 0;\r\n return { text: crlf ? text.replace(/\\r\\n/g, '\\n') : text, truncated: false, bom, crlf };\r\n}\r\nclass ViewPanel {\r\n constructor(host) {\r\n this.host = host;\r\n this.el = null;\r\n this.bodyEl = null;\r\n this.tabsEl = null;\r\n this.titleEl = null;\r\n this.footEl = null;\r\n this.pathRow = null;\r\n this.pathInput = null;\r\n this.modesEl = null;\r\n this.scopeBtn = null;\r\n /**\r\n * `변경` 목록의 범위. `session` = 이번 세션이 만진 파일만, `all` = 저장소의 커밋 안 된 전부.\r\n *\r\n * **기본이 `session` 인 이유** — `git diff HEAD` 는 저장소 사정에 따라 수백 개가 나온다\r\n * (P4 워크스페이스 위의 git 오버레이에서 405개 실측, 2026-09-11). 그 안에서 방금 에이전트가\r\n * 고친 것을 찾을 수는 없다. 설정에 저장하지 않는다 — 모드(`file`/`diff`)와 같은 이유로\r\n * 기동 때는 늘 기본값에서 시작한다.\r\n */\r\n this.diffScope = 'session';\r\n /** 마지막 `변경` 갱신에서 범위 때문에 접힌 파일 수 — 안내줄이 쓴다 */\r\n this.diffHidden = 0;\r\n /** 마지막 좁히기의 입력·결과 (진단용, `__agentdeck.view().diffDebug`) */\r\n this.diffDebug = null;\r\n this.commitEl = null;\r\n this.commitInput = null;\r\n this.commitBtn = null;\r\n this.commitSumEl = null;\r\n this.commitNoteEl = null;\r\n this.refNoteEl = null;\r\n // ---------- `파일:라인` 참조 ----------\r\n /**\r\n * 지금 고른 줄 (`파일` 은 절대경로, `변경` 은 저장소 루트 기준 경로 — DOM 의\r\n * `data-ad-ref-file` 값과 같은 문자열이다).\r\n *\r\n * **본문이 아니라 클래스 필드에 둔다.** `변경` 본문은 자동 갱신(DIFF_AUTO_MS)마다\r\n * innerHTML 을 다시 쓰므로 화면에 붙여 둔 강조(`ad-ref-sel`)는 그때 통째로 사라진다.\r\n * 여기에 두면 렌더 끝에 `applyRefSel()` 이 같은 줄에 클래스를 다시 붙일 수 있다 —\r\n * 커밋·찾기 줄을 본문 밖에 둔 것과 같은 사정이다.\r\n */\r\n this.refSel = null;\r\n /**\r\n * 마지막으로 터미널에 넣은 참조와 그 시각. 다음 참조가 이것의 접두면 **늘어난 꼬리만**\r\n * 보내 프롬프트에 `a.ts:12a.ts:12-20` 이 쌓이는 것을 막는다 (sendRef 참조).\r\n */\r\n this.refLastSent = null;\r\n /** 안내줄의 강조를 떼는 타이머 (REF_FLASH_MS) */\r\n this.refFlashTimer = null;\r\n this.mode = 'file';\r\n /**\r\n * 지금 기다리는 git 호출의 번호. 응답이 돌아왔을 때 이 값이 바뀌어 있으면 버린다 —\r\n * 탭을 옮기거나 ⟳ 를 연달아 누르면 늦게 온 응답이 새 화면을 덮는다.\r\n */\r\n this.diffSeq = 0;\r\n /** 마지막 자동 갱신 시각 (ms) — DIFF_AUTO_MS 간격 제한용 */\r\n this.diffAutoAt = 0;\r\n /** `변경` 본문의 경로를 눌렀을 때 쓸 저장소 루트 (git 이 내는 경로가 이 기준이다) */\r\n this.diffRoot = null;\r\n /** 마지막으로 읽은 `git status` — 커밋 줄의 요약과 \"올린 게 없다\" 판정의 근거 */\r\n this.statusEntries = [];\r\n /** 위 목록의 경로 색인 — 파일 목록 한 줄마다 딱지를 붙일 때 찾는다 */\r\n this.statusByPath = new Map();\r\n /**\r\n * 커밋 버튼이 \"확인 대기\" 인가. **첫 누름은 확인만, 두 번째 누름이 실제 커밋이다** —\r\n * 커밋은 되돌리기 번거로운 부작용이라 한 번의 오클릭(또는 자동화의 맹목적 click)으로\r\n * 만들어지면 안 된다. 메시지를 고치거나 모드를 옮기면 풀린다.\r\n */\r\n this.commitArmed = false;\r\n /** git 이 도는 중 — 스테이지 딱지를 연달아 누르면 add/reset 이 겹쳐 순서가 뒤집힌다 */\r\n this.gitBusy = false;\r\n this.opened = false;\r\n /** 레이아웃 자체가 꺼져 있으면(agentDeck.enabled=false) 열려 있어도 그리지 않는다 */\r\n this.visible = true;\r\n /** 지금 보고 있는 파일 (절대경로) */\r\n this.current = null;\r\n /** 파일 감시 중인 경로 — 바꿀 때 반드시 해제한다 */\r\n this.watching = null;\r\n /** 탭별 최근 파일. 탭이 닫히면 같이 사라지도록 WeakMap */\r\n this.recent = new WeakMap();\r\n /**\r\n * 탭별로 **마지막에 보던 파일**. 최근 목록의 맨 앞과 다를 수 있다 — 사람이 칩에서 옛 파일을\r\n * 고르면 보고 있는 것은 그 파일이고 목록 맨 앞은 다른 것이다. 탭을 옮겼다 돌아왔을 때\r\n * 되돌아갈 자리는 \"보던 것\" 이지 \"가장 최근에 만져진 것\" 이 아니다.\r\n */\r\n this.lastViewed = new WeakMap();\r\n this.activeTab = null;\r\n /** 탭별 출력 버퍼와 훑기 타이머 */\r\n // ---------- 편집 ----------\r\n /**\r\n * 편집 중인가. 켜져 있으면 **화면을 남이 건드리지 못한다** — 파일 감시의 자동 재읽기,\r\n * 새 파일 따라가기(follow), 모드 전환이 모두 비켜 간다. 사람이 친 글자를 지우는 것보다\r\n * 화면이 잠깐 낡아 보이는 편이 낫다.\r\n */\r\n this.editing = false;\r\n this.editArea = null;\r\n this.editBarEl = null;\r\n this.editNoteEl = null;\r\n this.editSaveBtn = null;\r\n /** 편집을 연 시점의 원본 — 저장할 때 BOM·개행을 이대로 되돌리고, mtime 으로 외부 변경을 본다 */\r\n this.editOrigin = null;\r\n /** 읽기 전용 속성을 풀고 저장할지 확인 대기 — 덮어쓰기 확인과 같은 2단 규칙 */\r\n this.editForceArmed = false;\r\n /** `+` 에 없는 경로를 넣었을 때, 만들지 확인 대기 중인 절대경로 */\r\n this.pathCreateArmed = null;\r\n /** 편집하는 동안 파일이 밖에서 바뀌었다 — 저장 버튼이 한 번 더 확인을 받는다 */\r\n this.editStale = false;\r\n /** 덮어쓰기 확인 대기 (커밋 버튼의 2단 확인과 같은 규칙) */\r\n this.editOverwriteArmed = false;\r\n // ---------- 찾기 ----------\r\n this.findRow = null;\r\n this.findInput = null;\r\n this.findCountEl = null;\r\n /** 지금 표시 중인 일치 `<mark>` 들. 본문을 다시 그리면 통째로 버린다 */\r\n this.findHits = [];\r\n this.findIndex = -1;\r\n this.buffers = new WeakMap();\r\n this.scrapeTimers = new WeakMap();\r\n this.resizing = false;\r\n }\r\n // ---------- 열고 닫기 ----------\r\n get isOpen() {\r\n return this.opened;\r\n }\r\n /**\r\n * 지금 화면에 그려질 폭 (닫혀 있거나 숨어 있으면 0).\r\n * @param room 패널이 써도 되는 폭 — deck 이 터미널·사이드바의 최소치를 뺀 값을 넘겨준다\r\n */\r\n extent(room) {\r\n if (!this.opened || !this.visible) {\r\n return 0;\r\n }\r\n const want = this.host.getWidth() || 420;\r\n return Math.min(Math.max(want, exports.MIN_VIEW_W), Math.max(room, exports.MIN_VIEW_W));\r\n }\r\n setOpen(open, remember = true) {\r\n if (this.opened === open) {\r\n return;\r\n }\r\n this.opened = open;\r\n this.syncDisplay();\r\n if (remember) {\r\n this.host.setOpen(open);\r\n }\r\n if (open) {\r\n this.renderTabs();\r\n if (this.mode === 'diff') {\r\n this.refreshDiff();\r\n }\r\n else if (!this.applyTabFile()) {\r\n // 닫혀 있는 동안 탭을 옮겼거나 에이전트가 새 파일을 만졌으면 위에서 그렸다.\r\n // 여기까지 왔으면 대상이 그대로였다는 뜻인데, **그래도 다시 읽는다** —\r\n // 닫힌 동안에는 감시(`watch`)가 꺼져 있어 같은 파일이 고쳐진 것도 모르므로,\r\n // 안 읽으면 열었을 때 옛 내용이 그대로 남는다\r\n if (this.current) {\r\n this.watch(this.current);\r\n this.renderCurrent();\r\n }\r\n else {\r\n this.renderEmpty();\r\n }\r\n }\r\n }\r\n else {\r\n this.unwatch();\r\n // 닫아 두고 다시 열었을 때 첫 누름이 곧바로 커밋이 되지 않게\r\n this.disarmCommit();\r\n }\r\n this.host.relayout();\r\n }\r\n toggle() {\r\n this.setOpen(!this.opened);\r\n }\r\n /** 레이아웃 on/off 를 따라간다 — 열림 상태는 건드리지 않는다 */\r\n setVisible(visible) {\r\n if (this.visible === visible) {\r\n return;\r\n }\r\n this.visible = visible;\r\n this.syncDisplay();\r\n if (!visible) {\r\n this.unwatch();\r\n }\r\n }\r\n syncDisplay() {\r\n if (this.el) {\r\n this.el.style.display = this.opened && this.visible ? 'flex' : 'none';\r\n }\r\n }\r\n // ---------- DOM ----------\r\n install() {\r\n const el = document.createElement('div');\r\n el.id = exports.VIEW_ID;\r\n el.style.display = this.opened ? 'flex' : 'none';\r\n el.innerHTML = [\r\n '<div class=\"ad-view-head\">',\r\n ' <span class=\"ad-view-title\">미리보기</span>',\r\n ' <span class=\"ad-view-tools\">',\r\n ' <button class=\"ad-view-btn ad-view-findbtn\" title=\"찾기 (Ctrl+F)\">🔍</button>',\r\n ' <button class=\"ad-view-btn ad-view-editbtn\" title=\"편집 (저장 Ctrl+S)\">✎</button>',\r\n ' <button class=\"ad-view-btn ad-view-pathbtn\" title=\"경로로 열기\">+</button>',\r\n ' <button class=\"ad-view-btn ad-view-reload\" title=\"다시 읽기\">⟳</button>',\r\n ' <button class=\"ad-view-btn ad-view-close\" title=\"패널 닫기\">✕</button>',\r\n ' </span>',\r\n '</div>',\r\n '<div class=\"ad-view-path\" style=\"display:none\">',\r\n ' <input type=\"text\" spellcheck=\"false\" placeholder=\"D:/Project/... 또는 상대경로\">',\r\n ' <span class=\"ad-view-path-note\"></span>',\r\n '</div>',\r\n // 모드 스위치는 제목줄(+ ⟳ ✕)을 건드리지 않고 따로 한 줄 쓴다 — 좁은 폭에서\r\n // 버튼이 접히면 ✕ 가 밀려나 패널을 닫을 수 없게 된다\r\n '<div class=\"ad-view-modes\">',\r\n ' <button class=\"ad-view-mode ad-view-mode-on\" data-ad-mode=\"file\">파일</button>',\r\n ' <button class=\"ad-view-mode\" data-ad-mode=\"diff\">변경</button>',\r\n // `변경` 을 볼 때만 보이는 범위 스위치. 기본은 **이 세션이 만진 것만** —\r\n // 저장소 전체는 P4 위에 git 을 얹은 곳에서 수백 개가 나와 방금 고친 것을 못 찾는다\r\n ' <button class=\"ad-view-scope\" style=\"display:none\" title=\"변경 목록의 범위\">세션</button>',\r\n '</div>',\r\n // 찾기 줄. 본문 밖에 두는 이유는 커밋 줄과 같다 — 본문은 갱신마다 다시 쓰므로\r\n // 안에 두면 입력하던 검색어가 지워진다\r\n '<div class=\"ad-view-find\" style=\"display:none\">',\r\n ' <input type=\"text\" class=\"ad-view-find-input\" spellcheck=\"false\" placeholder=\"찾기\">',\r\n ' <span class=\"ad-view-find-count\"></span>',\r\n ' <button class=\"ad-view-btn ad-view-find-prev\" title=\"이전 (Shift+Enter)\">‹</button>',\r\n ' <button class=\"ad-view-btn ad-view-find-next\" title=\"다음 (Enter)\">›</button>',\r\n ' <button class=\"ad-view-btn ad-view-find-close\" title=\"닫기 (Esc)\">✕</button>',\r\n '</div>',\r\n '<div class=\"ad-view-tabs\"></div>',\r\n // tabindex 를 주는 이유 — Ctrl+F 를 패널 안에서만 잡으려면 본문이 **포커스를 받을 수\r\n // 있어야** 한다. 본문을 한 번 누르면 그때부터 찾기 키가 통한다\r\n '<div class=\"ad-view-body\" tabindex=\"0\"></div>',\r\n // 편집 줄도 **본문 밖**이다 — 저장/취소 버튼이 본문 갱신에 지워지면 안 된다\r\n '<div class=\"ad-view-editbar\" style=\"display:none\">',\r\n ' <span class=\"ad-view-edit-note\"></span>',\r\n ' <span class=\"ad-view-edit-btns\">',\r\n ' <button class=\"ad-view-edit-save\">저장</button>',\r\n ' <button class=\"ad-view-edit-cancel\">취소</button>',\r\n ' </span>',\r\n '</div>',\r\n // 참조 안내줄도 **본문 밖**이다 — 자동 갱신이 본문을 다시 쓰는 동안에도 방금 넣은\r\n // 참조(\"넣었다 · src/a.ts:12\")나 못 넣은 이유가 남아 있어야 한다\r\n '<div class=\"ad-view-ref\" style=\"display:none\"></div>',\r\n // 커밋 줄은 **본문 밖**에 둔다 — 본문은 갱신마다 innerHTML 을 다시 쓰므로(renderDiff)\r\n // 안에 두면 자동 갱신 한 번에 입력하던 메시지가 지워지고 리스너도 매번 다시 붙는다\r\n '<div class=\"ad-view-commit\" style=\"display:none\">',\r\n ' <div class=\"ad-view-commit-sum\"></div>',\r\n ' <div class=\"ad-view-commit-row\">',\r\n ' <input type=\"text\" class=\"ad-view-commit-msg\" spellcheck=\"false\" placeholder=\"커밋 메시지\">',\r\n ' <button class=\"ad-view-commit-go\" disabled>커밋</button>',\r\n ' </div>',\r\n ' <div class=\"ad-view-commit-note\"></div>',\r\n '</div>',\r\n '<div class=\"ad-view-foot\"></div>',\r\n '<div class=\"ad-view-resize\"></div>',\r\n ].join('\\n');\r\n this.host.windowEl.appendChild(el);\r\n this.el = el;\r\n this.bodyEl = el.querySelector('.ad-view-body');\r\n this.tabsEl = el.querySelector('.ad-view-tabs');\r\n this.titleEl = el.querySelector('.ad-view-title');\r\n this.footEl = el.querySelector('.ad-view-foot');\r\n this.pathRow = el.querySelector('.ad-view-path');\r\n this.pathInput = el.querySelector('.ad-view-path input');\r\n this.modesEl = el.querySelector('.ad-view-modes');\r\n this.commitEl = el.querySelector('.ad-view-commit');\r\n this.commitInput = el.querySelector('.ad-view-commit-msg');\r\n this.commitBtn = el.querySelector('.ad-view-commit-go');\r\n this.commitSumEl = el.querySelector('.ad-view-commit-sum');\r\n this.commitNoteEl = el.querySelector('.ad-view-commit-note');\r\n this.refNoteEl = el.querySelector('.ad-view-ref');\r\n this.editBarEl = el.querySelector('.ad-view-editbar');\r\n this.editNoteEl = el.querySelector('.ad-view-edit-note');\r\n this.editSaveBtn = el.querySelector('.ad-view-edit-save');\r\n this.findRow = el.querySelector('.ad-view-find');\r\n this.findInput = el.querySelector('.ad-view-find-input');\r\n this.findCountEl = el.querySelector('.ad-view-find-count');\r\n this.scopeBtn = el.querySelector('.ad-view-scope');\r\n this.modesEl.addEventListener('click', (e) => {\r\n var _a, _b;\r\n const btn = (_b = (_a = e.target) === null || _a === void 0 ? void 0 : _a.closest) === null || _b === void 0 ? void 0 : _b.call(_a, '[data-ad-mode]');\r\n if (btn) {\r\n this.setMode(btn.getAttribute('data-ad-mode') === 'diff' ? 'diff' : 'file');\r\n }\r\n });\r\n this.scopeBtn.addEventListener('click', () => this.toggleScope());\r\n this.applyScopeLabel();\r\n el.querySelector('.ad-view-close').addEventListener('click', () => this.setOpen(false));\r\n el.querySelector('.ad-view-reload').addEventListener('click', () => this.reload());\r\n el.querySelector('.ad-view-pathbtn').addEventListener('click', () => this.togglePathRow());\r\n el.querySelector('.ad-view-editbtn').addEventListener('click', () => this.toggleEdit());\r\n el.querySelector('.ad-view-findbtn').addEventListener('click', () => this.openFind());\r\n el.querySelector('.ad-view-edit-save').addEventListener('click', () => this.saveEdit());\r\n el.querySelector('.ad-view-edit-cancel').addEventListener('click', () => this.cancelEdit());\r\n el.querySelector('.ad-view-find-next').addEventListener('click', () => this.stepFind(1));\r\n el.querySelector('.ad-view-find-prev').addEventListener('click', () => this.stepFind(-1));\r\n el.querySelector('.ad-view-find-close').addEventListener('click', () => this.closeFind());\r\n this.findInput.addEventListener('input', () => this.runFind());\r\n this.findInput.addEventListener('keydown', (e) => {\r\n // 패널 입력창이다 — 터미널 핫키에 뺏기지 않게 여기서 끊는다 (경로 입력창과 같은 규칙)\r\n e.stopPropagation();\r\n if (e.key === 'Enter') {\r\n e.preventDefault();\r\n this.stepFind(e.shiftKey ? -1 : 1);\r\n }\r\n else if (e.key === 'Escape') {\r\n e.preventDefault();\r\n this.closeFind();\r\n }\r\n });\r\n /**\r\n * 패널 안에서만 Ctrl+F / Ctrl+S 를 잡는다.\r\n *\r\n * **터미널의 같은 키를 뺏지 않는다** — Ctrl+F 는 less·vim·에디터가 쓰는 키이고,\r\n * Tabby 핫키로 올리면 어느 탭에서 눌러도 패널이 열려 버린다. 패널 DOM 안에서\r\n * 일어난 키만 보므로, 본문을 한 번 누르거나 검색창·편집기에 있을 때만 동작한다.\r\n */\r\n el.addEventListener('keydown', (e) => {\r\n const ctrl = e.ctrlKey || e.metaKey;\r\n if (ctrl && (e.key === 'f' || e.key === 'F')) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.openFind();\r\n }\r\n else if (ctrl && (e.key === 's' || e.key === 'S')) {\r\n if (this.editing) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.saveEdit();\r\n }\r\n }\r\n else if (e.key === 'Escape' && this.editing && e.target === this.editArea) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.cancelEdit();\r\n }\r\n });\r\n this.pathInput.addEventListener('keydown', (e) => {\r\n // 터미널 핫키에 뺏기지 않게 여기서 끊는다 (입력창은 우리 DOM 이다)\r\n e.stopPropagation();\r\n if (e.key === 'Enter') {\r\n const v = this.pathInput.value.trim();\r\n if (v) {\r\n this.openOrCreate(v);\r\n }\r\n }\r\n else if (e.key === 'Escape') {\r\n this.togglePathRow(false);\r\n }\r\n });\r\n this.commitInput.addEventListener('keydown', (e) => {\r\n // 터미널 핫키에 뺏기지 않게 여기서 끊는다 (경로 입력창과 같은 이유)\r\n e.stopPropagation();\r\n if (e.key === 'Enter') {\r\n this.pressCommit();\r\n }\r\n else if (e.key === 'Escape') {\r\n this.disarmCommit();\r\n this.setCommitNote('');\r\n }\r\n });\r\n this.commitInput.addEventListener('input', () => {\r\n // 메시지를 고치면 확인 대기를 푼다 — \"확인\" 을 눌러 둔 뒤 글자를 바꿨는데 확인이\r\n // 살아 있으면 사람이 읽지 않은 메시지로 커밋된다\r\n this.disarmCommit();\r\n });\r\n this.commitBtn.addEventListener('click', () => this.pressCommit());\r\n // 본문 안의 링크 — 웹은 브라우저로, 로컬 파일은 이 패널에서 연다\r\n this.bodyEl.addEventListener('click', (e) => {\r\n var _a, _b, _c;\r\n const a = (_b = (_a = e.target) === null || _a === void 0 ? void 0 : _a.closest) === null || _b === void 0 ? void 0 : _b.call(_a, '[data-ad-link]');\r\n if (!a) {\r\n return;\r\n }\r\n e.preventDefault();\r\n const url = (_c = a.getAttribute('data-ad-link')) !== null && _c !== void 0 ? _c : '';\r\n if (/^https?:/i.test(url)) {\r\n this.host.openExternal(url);\r\n }\r\n else {\r\n this.openFile(url.replace(/^file:\\/\\//, ''));\r\n }\r\n });\r\n // `변경` 본문의 두 가지 누르기 — 파일 목록은 그 파일 diff 로 스크롤, 경로는 파일 모드로 열기\r\n this.bodyEl.addEventListener('click', (e) => {\r\n var _a, _b, _c, _d, _e, _f;\r\n const t = e.target;\r\n // 스테이지 딱지를 **먼저** 본다 — 딱지는 점프 버튼(`[data-ad-diff]`) 안에 들어 있어서\r\n // 순서를 바꾸면 딱지를 눌렀는데 스크롤만 하고 끝난다\r\n const stage = (_a = t === null || t === void 0 ? void 0 : t.closest) === null || _a === void 0 ? void 0 : _a.call(t, '[data-ad-stage]');\r\n if (stage) {\r\n e.preventDefault();\r\n this.toggleStage((_b = stage.getAttribute('data-ad-stage')) !== null && _b !== void 0 ? _b : '', stage.getAttribute('data-ad-stage-act') === 'reset' ? 'reset' : 'add');\r\n return;\r\n }\r\n const jump = (_c = t === null || t === void 0 ? void 0 : t.closest) === null || _c === void 0 ? void 0 : _c.call(t, '[data-ad-diff]');\r\n if (jump) {\r\n e.preventDefault();\r\n // id 는 우리가 `ad-diff-<번호>` 로 만들므로 선택자 이스케이프가 필요 없다\r\n const target = document.getElementById((_d = jump.getAttribute('data-ad-diff')) !== null && _d !== void 0 ? _d : '');\r\n target === null || target === void 0 ? void 0 : target.scrollIntoView(true);\r\n return;\r\n }\r\n const open = (_e = t === null || t === void 0 ? void 0 : t.closest) === null || _e === void 0 ? void 0 : _e.call(t, '[data-ad-open]');\r\n if (open) {\r\n e.preventDefault();\r\n const file = (_f = open.getAttribute('data-ad-open')) !== null && _f !== void 0 ? _f : '';\r\n if (file) {\r\n this.openFile(file);\r\n }\r\n }\r\n });\r\n /**\r\n * 줄을 눌러 `파일:라인` 참조를 터미널에 넣는다 (`변경` diff 줄 · `파일` 코드 줄 공통).\r\n *\r\n * **이미 뜻이 있는 누르기를 가리지 않는다** — 파일명은 그 파일 diff 로 스크롤,\r\n * 스테이지 딱지는 `git add`/`reset`, 링크는 열기다. 그 중 하나에 걸렸으면 여기서\r\n * 손을 뗀다. 우발 `git add` 가 특히 위험해서 판정을 참조보다 먼저 둔다.\r\n */\r\n this.bodyEl.addEventListener('click', (e) => {\r\n const t = e.target;\r\n if (!(t === null || t === void 0 ? void 0 : t.closest)) {\r\n return;\r\n }\r\n if (t.closest('[data-ad-stage],[data-ad-diff],[data-ad-open],[data-ad-link]')) {\r\n return;\r\n }\r\n const row = t.closest('[data-ad-ref-line],[data-ad-ref-del]');\r\n if (row) {\r\n this.clickRefLine(row, e.shiftKey);\r\n }\r\n });\r\n this.installDrop(el);\r\n this.installResize(el.querySelector('.ad-view-resize'));\r\n this.renderEmpty();\r\n }\r\n /** 파일을 끌어다 놓으면 그걸 연다 — 탐색기·VS Code 탭 어느 쪽에서 끌어도 된다 */\r\n installDrop(el) {\r\n el.addEventListener('dragover', (e) => {\r\n e.preventDefault();\r\n el.classList.add('ad-view-dropping');\r\n });\r\n el.addEventListener('dragleave', () => el.classList.remove('ad-view-dropping'));\r\n el.addEventListener('drop', (e) => {\r\n var _a, _b, _c;\r\n e.preventDefault();\r\n el.classList.remove('ad-view-dropping');\r\n const file = (_b = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0];\r\n const text = (_c = e.dataTransfer) === null || _c === void 0 ? void 0 : _c.getData('text/plain');\r\n const target = (file === null || file === void 0 ? void 0 : file.path) || text;\r\n if (target) {\r\n this.openFile(String(target).trim().replace(/^\"|\"$/g, ''));\r\n }\r\n });\r\n }\r\n /**\r\n * 터미널과 닿는 쪽 경계선을 끌어 폭을 바꾼다.\r\n *\r\n * **폭은 \"잡은 순간의 폭 + 끈 거리\" 로 잰다 — 창 가장자리부터 재면 안 된다.**\r\n * 사이드바와 패널이 같은 쪽에 붙으면 패널은 창 가장자리에서 사이드바 폭만큼 안쪽에 앉는데\r\n * (`deck.service.ts` relayout 의 `outerOffset`), `rect.right - clientX` 는 그 몫까지\r\n * 폭으로 세어 버린다. 그래서 잡자마자 사이드바 폭(200~560px)만큼 한 번 커지고, 사용자는\r\n * 그걸 도로 줄이는 것으로 조작을 시작하게 된다 (2026-09-11 유저 지적).\r\n * 델타 방식은 그 몫도, 손잡이 안에서 어디를 잡았는지도 상쇄되어 **튐이 아예 없다.**\r\n * (사이드바 `dock.ts` 가 절대 거리로 재는 것은 거기서만 맞다 — 사이드바는 창에 딱 붙는다.)\r\n */\r\n installResize(handle) {\r\n handle.addEventListener('mousedown', (e) => {\r\n var _a;\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.resizing = true;\r\n document.body.classList.add('ad-resizing');\r\n const startX = e.clientX;\r\n // 기준은 **화면에 실제로 그려져 있는 폭**이다. 설정값(`getWidth`)을 쓰면 좁은 창에서\r\n // 또 튄다 — `extent()` 가 `room` 으로 깎아 그리는데 설정에는 안 깎인 값이 남아 있어서다.\r\n const startW = ((_a = this.el) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width) || this.host.getWidth();\r\n const move = (ev) => {\r\n if (!this.resizing) {\r\n return;\r\n }\r\n // 오른쪽 패널은 커서가 왼쪽으로 갈수록 넓어지고, 왼쪽 패널은 그 반대다\r\n const delta = this.host.getSide() === 'right'\r\n ? startX - ev.clientX\r\n : ev.clientX - startX;\r\n this.host.setWidth(Math.max(exports.MIN_VIEW_W, Math.round(startW + delta)));\r\n this.host.relayout();\r\n };\r\n const up = () => {\r\n this.resizing = false;\r\n document.body.classList.remove('ad-resizing');\r\n window.removeEventListener('mousemove', move);\r\n window.removeEventListener('mouseup', up);\r\n this.host.commit();\r\n };\r\n window.addEventListener('mousemove', move);\r\n window.addEventListener('mouseup', up);\r\n });\r\n }\r\n /** deck 의 relayout 이 정해 준 자리에 앉는다 (사이드바와 같은 방식으로 절대 배치) */\r\n layout(side, width, outerOffset) {\r\n if (!this.el) {\r\n return;\r\n }\r\n const s = this.el.style;\r\n s.position = 'absolute';\r\n s.top = '0';\r\n s.bottom = '0';\r\n s.width = width + 'px';\r\n s.left = side === 'left' ? outerOffset + 'px' : 'auto';\r\n s.right = side === 'right' ? outerOffset + 'px' : 'auto';\r\n this.el.classList.toggle('ad-view-left', side === 'left');\r\n this.el.classList.toggle('ad-view-right', side === 'right');\r\n }\r\n togglePathRow(force) {\r\n var _a;\r\n if (!this.pathRow) {\r\n return;\r\n }\r\n const show = force !== null && force !== void 0 ? force : this.pathRow.style.display === 'none';\r\n this.pathRow.style.display = show ? 'flex' : 'none';\r\n this.pathCreateArmed = null;\r\n this.setPathNote('');\r\n if (show) {\r\n this.pathInput.value = (_a = this.current) !== null && _a !== void 0 ? _a : '';\r\n this.pathInput.focus();\r\n this.pathInput.select();\r\n }\r\n }\r\n setPathNote(text) {\r\n var _a;\r\n const note = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelector('.ad-view-path-note');\r\n if (note) {\r\n note.textContent = text;\r\n note.title = text;\r\n }\r\n }\r\n /**\r\n * `+` 에 넣은 경로를 연다. **없는 파일이면 만들어 준다** — 메모 한 장을 시작하려고\r\n * 탐색기로 나가는 것이 이 패널이 없애려던 왕복이다.\r\n *\r\n * 만들기는 **두 번째 Enter 에서만** 한다(커밋·덮어쓰기와 같은 2단 규칙). 오타로 친 경로에\r\n * 빈 파일이 조용히 생기면, 다음에 그 오타를 찾는 데 드는 시간이 아낀 시간보다 크다.\r\n * 만든 뒤에는 곧바로 편집으로 들어간다 — 빈 파일을 보여 줄 이유가 없다.\r\n */\r\n openOrCreate(raw) {\r\n var _a, _b, _c, _d;\r\n const base = this.current ? path.dirname(this.current) : null;\r\n const cwd = (_b = this.host.cwdFor((_a = this.activeTab) !== null && _a !== void 0 ? _a : {})) !== null && _b !== void 0 ? _b : base;\r\n const found = (_c = this.resolve(raw, cwd, false)) !== null && _c !== void 0 ? _c : this.resolve(raw, base, false);\r\n if (found) {\r\n this.pathCreateArmed = null;\r\n this.setPathNote('');\r\n this.openFile(found);\r\n return;\r\n }\r\n const absolute = path.isAbsolute(raw) || /^[A-Za-z]:[\\\\/]/.test(raw);\r\n if (!absolute && !cwd) {\r\n this.setPathNote('상대경로를 풀 작업 폴더를 모른다 — 절대경로로 넣는다');\r\n return;\r\n }\r\n const target = path.normalize(absolute ? raw : path.join(cwd, raw));\r\n // 폴더를 파일로 만들려는 것은 막는다 (경로 끝의 구분자나 실제 폴더)\r\n if (/[\\\\/]$/.test(raw)) {\r\n this.setPathNote('폴더 경로다 — 파일 이름까지 넣는다');\r\n return;\r\n }\r\n try {\r\n if (fs.statSync(target).isDirectory()) {\r\n this.setPathNote('폴더다 — 파일 이름까지 넣는다');\r\n return;\r\n }\r\n }\r\n catch {\r\n // 없는 경로다 — 아래에서 만든다\r\n }\r\n if (this.pathCreateArmed !== target) {\r\n this.pathCreateArmed = target;\r\n this.setPathNote('없는 파일이다 — Enter 를 한 번 더 치면 새로 만든다');\r\n return;\r\n }\r\n try {\r\n fs.mkdirSync(path.dirname(target), { recursive: true });\r\n fs.writeFileSync(target, '', { encoding: 'utf8', flag: 'wx' });\r\n }\r\n catch (err) {\r\n this.setPathNote('만들지 못했다: ' + String((_d = err === null || err === void 0 ? void 0 : err.message) !== null && _d !== void 0 ? _d : err));\r\n return;\r\n }\r\n this.pathCreateArmed = null;\r\n this.setPathNote('');\r\n this.openFile(target);\r\n // 빈 파일이다 — 보여 줄 것이 없으니 바로 칠 수 있게 한다\r\n this.startEdit();\r\n }\r\n // ---------- 모드 (파일 / 변경) ----------\r\n get viewMode() {\r\n return this.mode;\r\n }\r\n /** 스위치 모양만 맞춘다 — 그리기는 부르는 쪽이 한다 (두 번 그리지 않기 위해서) */\r\n applyMode(mode) {\r\n this.mode = mode;\r\n if (this.modesEl) {\r\n for (const btn of Array.from(this.modesEl.querySelectorAll('[data-ad-mode]'))) {\r\n btn.classList.toggle('ad-view-mode-on', btn.getAttribute('data-ad-mode') === mode);\r\n }\r\n }\r\n if (mode === 'diff') {\r\n this.togglePathRow(false);\r\n }\r\n else {\r\n // `파일` 로 옮기면 커밋 줄을 감추고 확인 대기도 푼다 — 안 보이는 버튼이 armed 로\r\n // 남아 있으면 나중에 `변경` 으로 돌아온 첫 누름이 곧바로 커밋이 된다\r\n this.disarmCommit();\r\n }\r\n if (this.commitEl) {\r\n this.commitEl.style.display = mode === 'diff' ? 'block' : 'none';\r\n }\r\n if (this.scopeBtn) {\r\n this.scopeBtn.style.display = mode === 'diff' ? '' : 'none';\r\n }\r\n this.renderTabs();\r\n }\r\n /**\r\n * `변경` 목록의 범위를 바꾼다 (세션 ↔ 전체).\r\n *\r\n * git 을 다시 돌리지 않고 **이미 읽어 둔 결과를 다시 거르기만** 할 수도 있지만, 그러려면\r\n * 마지막 diff 원문을 들고 있어야 하고 그 사이에 파일이 또 바뀌면 화면이 과거를 보여준다.\r\n * git 한 번은 싸다(로컬 저장소 5초 상한) — 다시 읽는다.\r\n */\r\n toggleScope() {\r\n this.diffScope = this.diffScope === 'session' ? 'all' : 'session';\r\n this.applyScopeLabel();\r\n if (this.mode === 'diff' && this.opened) {\r\n this.refreshDiff();\r\n }\r\n }\r\n applyScopeLabel() {\r\n if (!this.scopeBtn) {\r\n return;\r\n }\r\n const session = this.diffScope === 'session';\r\n this.scopeBtn.textContent = session ? '세션' : '전체';\r\n this.scopeBtn.classList.toggle('ad-view-scope-all', !session);\r\n this.scopeBtn.title = session\r\n ? '이 세션이 만진 파일만 보고 있다 — 누르면 저장소 전체'\r\n : '저장소의 커밋 안 된 변경 전부를 보고 있다 — 누르면 이 세션이 만진 것만';\r\n }\r\n setMode(mode) {\r\n if (this.mode === mode) {\r\n return;\r\n }\r\n // 편집 중 모드 전환도 파일 전환과 같은 규칙이다 (openFile 주석 참조)\r\n if (this.editing) {\r\n if (this.editArea && this.editOrigin && this.editArea.value !== this.editOrigin.text) {\r\n this.setEditNote('저장하지 않은 편집이 있다 — 저장하거나 취소한 뒤에 모드를 옮긴다');\r\n return;\r\n }\r\n this.cancelEdit();\r\n }\r\n this.applyMode(mode);\r\n const wasOpen = this.opened;\r\n if (!wasOpen) {\r\n // 닫혀 있었으면 setOpen 이 모드에 맞게 한 번 그린다 (diff 면 refreshDiff 까지)\r\n this.setOpen(true);\r\n }\r\n if (mode === 'diff') {\r\n if (wasOpen) {\r\n this.refreshDiff();\r\n }\r\n }\r\n else if (this.current) {\r\n // `변경` 을 보는 동안 파일이 바뀌었어도 감시 콜백은 그리지 않았다 — 여기서 최신을 읽는다\r\n this.renderCurrent();\r\n }\r\n else {\r\n this.renderEmpty();\r\n }\r\n }\r\n /**\r\n * `파일` ↔ `변경` 전환. 핫키(`agentdeck-view-mode`) 배선이 한 줄로 끝나게 public 으로 둔다 —\r\n * 핫키 처리는 deck.service 가 하고(HotkeysService 순환 의존 때문에 provider 에서는 못 한다),\r\n * 여기서 상태를 들고 있으므로 그쪽은 이 메서드만 부르면 된다.\r\n */\r\n toggleMode() {\r\n this.setMode(this.mode === 'diff' ? 'file' : 'diff');\r\n }\r\n // ---------- PTY 출력에서 경로 줍기 ----------\r\n /**\r\n * 출력 한 조각을 받아 둔다. 조각마다 정규식을 돌리지 않고 모았다가 400ms 마다 한 번 훑는다 —\r\n * 에이전트 TUI 는 상태줄을 매초 다시 그려서 조각이 초당 수십 개씩 온다.\r\n */\r\n noteOutput(tab, data) {\r\n var _a;\r\n const buf = (((_a = this.buffers.get(tab)) !== null && _a !== void 0 ? _a : '') + data).slice(-SCRAPE_BUFFER_MAX);\r\n this.buffers.set(tab, buf);\r\n if (this.scrapeTimers.get(tab)) {\r\n return;\r\n }\r\n this.scrapeTimers.set(tab, setTimeout(() => {\r\n this.scrapeTimers.delete(tab);\r\n this.scrape(tab);\r\n }, SCRAPE_DEBOUNCE_MS));\r\n }\r\n scrape(tab) {\r\n var _a, _b;\r\n const buf = (_a = this.buffers.get(tab)) !== null && _a !== void 0 ? _a : '';\r\n // 다음 조각으로 넘길 것은 **마지막 줄의 미완성 부분뿐이다.**\r\n // 경로는 줄바꿈을 넘지 못하므로 그 앞은 이미 다 본 것이고, 그걸 남겨 두면\r\n // 다음 훑기에서 같은 경로가 또 잡혀 최근 목록의 순서가 흔들린다\r\n // (2026-09-08 실측: 따라가기가 새 파일 대신 직전 파일을 다시 띄웠다)\r\n this.buffers.set(tab, buf.slice(buf.lastIndexOf('\\n') + 1).slice(-256));\r\n if (!buf) {\r\n return;\r\n }\r\n const cwd = this.host.cwdFor(tab);\r\n /** 처음 본 파일 — 따라가기(viewerFollow)가 띄울 대상 */\r\n let added = null;\r\n /** 목록이 조금이라도 바뀌었나 — 순서만 바뀌어도 칩을 다시 그려야 한다 */\r\n let changed = false;\r\n for (const token of (0, viewer_1.extractPaths)(buf)) {\r\n const abs = this.resolve(token, cwd);\r\n if (!abs) {\r\n continue;\r\n }\r\n const list = (_b = this.recent.get(tab)) !== null && _b !== void 0 ? _b : [];\r\n if (list[0] === abs) {\r\n continue;\r\n }\r\n // 이미 아는 파일이면 순서만 올린다 — **따라가기의 대상은 처음 본 파일뿐이다.**\r\n // 화면이 다시 그려질 때 옛 경로가 또 잡히는데, 그걸 열면 방금 만든 파일을 덮는다\r\n const known = list.includes(abs);\r\n this.recent.set(tab, (0, viewer_1.pushRecent)(list, abs, this.host.getRecentMax()));\r\n changed = true;\r\n // 칩에는 무엇이든 쌓되, **스스로 띄울 대상에서는 설정 파일을 뺀다**\r\n // (`isAutoFollowable`, viewer.ts) — 에이전트가 기동하면서 찍는 설정 경로 때문에\r\n // 세션을 열자마자 화면이 `settings.json` 으로 갈리던 문제\r\n if (!known && (0, viewer_1.isAutoFollowable)(abs)) {\r\n added = abs;\r\n }\r\n }\r\n if (!changed || tab !== this.activeTab) {\r\n return;\r\n }\r\n this.renderTabs();\r\n // 여기서 **스스로 열어도 되는지**를 가른다 (`planFollow`, viewer.ts).\r\n // - `open` : 닫혀 있어도 연다 — 결과물이 나왔는데 사람이 `▤` 를 눌러야 보인다면\r\n // 그 왕복 때문에 결과물을 안 보고 넘어간다\r\n // - `show` : 열어 둔 동안에만 화면을 바꾼다. **자동으로 열지 않는다**\r\n // - `stage` : 닫혀 있다 — 그리지 않고 다음에 열 때 보일 대상만 갈아 둔다\r\n // - `manual` : 아무것도 하지 않는다 — 경로는 위 칩에 이미 쌓였다\r\n // 편집 중이면 모드와 무관하게 따라가지 않는다 (사람이 치던 것을 밀어내지 않는다).\r\n const plan = (0, viewer_1.planFollow)(this.host.getFollowMode(), this.opened, this.editing);\r\n if (plan === 'none') {\r\n return;\r\n }\r\n if (plan === 'stage') {\r\n // 닫힌 패널의 \"읽어두기\" — 그리는 일은 `setOpen(true)` 가 한다.\r\n // `lastViewed` 를 갈아 두는 것이 핵심이다: 이걸 안 하면 사람이 나중에 패널을 열었을 때\r\n // **아까 보던 옛 파일**이 뜬다(`applyTabFile` 이 lastViewed 를 먼저 본다).\r\n // `변경` 모드로 열려 있었다면 여는 순간 `setOpen` 이 `refreshDiff()` 를 부른다 —\r\n // 닫힌 채로 git 을 돌릴 이유가 없다. 그래도 대상은 적어 둔다(`파일` 로 돌아올 때 쓴다).\r\n if (added) {\r\n this.lastViewed.set(tab, added);\r\n }\r\n return;\r\n }\r\n if (this.mode === 'diff') {\r\n // 파일이 바뀌었다는 신호이므로 변경 목록을 다시 뽑는다. **모드는 바꾸지 않는다** —\r\n // 사람이 `변경` 을 골라 둔 상태에서 화면이 파일로 튀면 그게 회귀다.\r\n // 닫혀 있었다면 고른 모드 그대로 연다\r\n if (plan === 'open') {\r\n this.setOpen(true);\r\n }\r\n this.maybeAutoDiff();\r\n }\r\n else if (added) {\r\n // openFile 이 안에서 setOpen(true) 를 부른다 — 이미 열려 있으면 그건 no-op 이다\r\n this.openFile(added);\r\n }\r\n }\r\n /** 후보 토큰을 실제로 있는 파일의 절대경로로 만든다 (없으면 null) */\r\n resolve(token, cwd, requireKnownExt = true) {\r\n // 확장자 게이트는 **화면에서 주울 때만** 필요하다 — TUI 가 찍은 글자 중 경로처럼 보이는\r\n // 것을 거르는 장치다. 사람이 명시로 여는 경로(칩·드롭·+·본문 링크)에 같은 게이트를\r\n // 걸면, 실제로 있는 파일을 열었는데 \"파일을 찾지 못했다\" 고 말한다 — 거짓 안내이고\r\n // `renderBinary`(\"미리보기를 지원하지 않는 형식\")는 도달할 수 없는 죽은 코드가 된다\r\n // (2026-09-08 회귀 TC 작성 중 발견: 존재하는 `.zip` 을 열면 \"못 찾았다\" 로 끝났다).\r\n if (requireKnownExt && !(0, viewer_1.isKnownExt)(token)) {\r\n return null;\r\n }\r\n const tries = [];\r\n if (path.isAbsolute(token) || /^[A-Za-z]:[\\\\/]/.test(token)) {\r\n tries.push(token);\r\n }\r\n else if (cwd) {\r\n tries.push(path.join(cwd, token));\r\n }\r\n for (const t of tries) {\r\n try {\r\n const st = fs.statSync(t);\r\n if (st.isFile()) {\r\n return path.normalize(t);\r\n }\r\n }\r\n catch {\r\n // 없는 파일 — 화면 글자가 경로처럼 보였을 뿐이다\r\n }\r\n }\r\n return null;\r\n }\r\n /** 활성 탭이 바뀌면 최근 목록도 그 탭 것으로 바꾼다 */\r\n setActiveTab(tab) {\r\n if (this.activeTab === tab) {\r\n return;\r\n }\r\n this.activeTab = tab;\r\n this.pathCreateArmed = null;\r\n // 참조는 **활성 탭** 터미널로 나간다 — 탭을 옮겼으면 직전에 넣은 참조는 저쪽 프롬프트에\r\n // 있다. 기억을 남겨 두면 다음 누름이 \"꼬리만\"(`-20`) 을 엉뚱한 터미널에 넣는다\r\n this.refLastSent = null;\r\n // 탭이 바뀌면 **다른 저장소**일 수 있다. 화면에 남은 목록과 딱지가 이전 탭 것이면\r\n // 딱지를 누른 경로가 지금 보고 있는 저장소의 것이 아니게 되므로 상태를 비우고 다시 읽는다\r\n this.disarmCommit();\r\n if (this.opened) {\r\n this.renderTabs();\r\n if (this.mode === 'diff') {\r\n this.setStatus([]);\r\n this.refreshDiff();\r\n }\r\n }\r\n // 본문도 그 탭 것으로 바꾼다 — 세션을 옮겼는데 옆에 남의 문서가 떠 있으면\r\n // 그 파일이 지금 탭의 것이라고 착각한다 (칩·`변경` 은 이미 탭별인데 본문만 안 그랬다)\r\n this.applyTabFile();\r\n }\r\n /**\r\n * 활성 탭이 마지막으로 보던 파일로 본문을 맞춘다.\r\n *\r\n * **열려 있을 때만 그린다.** 닫혀 있으면 `current` 만 바꿔 두고, `setOpen(true)` 가 다시 불러\r\n * 그때 그린다 — 탭을 옮긴 것만으로 패널이 열리면 안 되기 때문이다(패널이 저절로 열리는\r\n * 경우는 \"새 결과물을 주웠을 때\" 하나로 족하다).\r\n *\r\n * 돌려주는 값은 **\"그렸는가\"** — 부르는 쪽이 두 번 그리지 않으려고 본다 (`setOpen`).\r\n */\r\n applyTabFile() {\r\n var _a, _b, _c;\r\n if (this.mode !== 'file') {\r\n return false;\r\n }\r\n if (this.editing) {\r\n // 편집 중에는 본문을 건드리지 않는다 — 저장/취소 뒤에 따라온다\r\n this.setEditNote('다른 탭으로 옮겼다 — 저장하거나 취소하면 그 탭 파일로 넘어간다');\r\n return true;\r\n }\r\n const tab = this.activeTab;\r\n const want = tab\r\n ? (_c = (_a = this.lastViewed.get(tab)) !== null && _a !== void 0 ? _a : ((_b = this.recent.get(tab)) !== null && _b !== void 0 ? _b : [])[0]) !== null && _c !== void 0 ? _c : null\r\n : null;\r\n if (want === this.current) {\r\n return false;\r\n }\r\n this.current = want;\r\n this.closeFind();\r\n if (!this.opened) {\r\n return false;\r\n }\r\n if (!want) {\r\n this.unwatch();\r\n this.renderEmpty();\r\n return true;\r\n }\r\n this.watch(want);\r\n this.renderCurrent();\r\n return true;\r\n }\r\n /** 사람이/훅이 알려 준 파일을 최근 목록에 얹는다 (열지는 않는다) */\r\n noteFile(tab, file) {\r\n var _a;\r\n const abs = this.resolve(file, this.host.cwdFor(tab));\r\n if (!abs) {\r\n return;\r\n }\r\n this.recent.set(tab, (0, viewer_1.pushRecent)((_a = this.recent.get(tab)) !== null && _a !== void 0 ? _a : [], abs, this.host.getRecentMax()));\r\n if (tab === this.activeTab && this.opened) {\r\n this.renderTabs();\r\n }\r\n }\r\n // ---------- 파일 열기 / 그리기 ----------\r\n openFile(file) {\r\n var _a, _b, _c, _d;\r\n const raw = String(file !== null && file !== void 0 ? file : '').trim();\r\n if (!raw) {\r\n return;\r\n }\r\n // 저장하지 않은 편집이 있으면 다른 파일로 넘어가지 않는다 — 조용히 버리면 사람이 친\r\n // 글자가 소리 없이 사라진다. 고친 것이 없으면 그냥 편집을 접고 넘어간다\r\n if (this.editing) {\r\n if (this.editArea && this.editOrigin && this.editArea.value !== this.editOrigin.text) {\r\n this.setEditNote('저장하지 않은 편집이 있다 — 저장하거나 취소한 뒤에 다른 파일을 연다');\r\n return;\r\n }\r\n this.cancelEdit();\r\n }\r\n const base = this.current ? path.dirname(this.current) : null;\r\n // 사람이 지시한 경로다 — 확장자를 모르더라도 **파일이 있으면 연다**(위 resolve 주석).\r\n // 미리보기를 못 그리는 형식이면 `renderBinary` 가 \"지원하지 않는 형식\" 이라고 말한다\r\n const cwd = (_b = this.host.cwdFor((_a = this.activeTab) !== null && _a !== void 0 ? _a : {})) !== null && _b !== void 0 ? _b : base;\r\n const abs = (_c = this.resolve(raw, cwd, false)) !== null && _c !== void 0 ? _c : this.resolve(raw, base, false);\r\n // 파일을 열라는 지시는 모드 전환을 포함한다 — 칩·드롭·+·본문 링크·`변경` 의 경로가\r\n // 모두 여기로 들어오는데, `변경` 을 보던 중이라면 그 자리에 파일을 그릴 수가 없다.\r\n // 그리기는 아래에서 하므로 여기서는 UI 만 맞춘다\r\n this.applyMode('file');\r\n if (!abs) {\r\n this.setOpen(true);\r\n this.renderMessage('파일을 찾지 못했다', raw);\r\n return;\r\n }\r\n this.current = abs;\r\n if (this.activeTab) {\r\n this.recent.set(this.activeTab, (0, viewer_1.pushRecent)((_d = this.recent.get(this.activeTab)) !== null && _d !== void 0 ? _d : [], abs, this.host.getRecentMax()));\r\n // 탭을 옮겼다 돌아오면 이 파일로 되돌아간다 (applyTabFile)\r\n this.lastViewed.set(this.activeTab, abs);\r\n }\r\n this.setOpen(true);\r\n this.togglePathRow(false);\r\n this.watch(abs);\r\n this.renderTabs();\r\n this.renderCurrent();\r\n }\r\n reload() {\r\n if (this.mode === 'diff') {\r\n this.refreshDiff();\r\n }\r\n else if (this.current) {\r\n this.renderCurrent();\r\n }\r\n else {\r\n this.renderEmpty();\r\n }\r\n }\r\n /** 파일이 바뀌면 다시 그린다 — 에이전트가 문서를 고치는 동안 옆에서 따라간다 */\r\n watch(file) {\r\n if (this.watching === file) {\r\n return;\r\n }\r\n this.unwatch();\r\n this.watching = file;\r\n try {\r\n fs.watchFile(file, { interval: WATCH_INTERVAL_MS }, (cur, prev) => {\r\n // `변경` 모드에서는 그리지 않는다 — 감시는 살려 두고(모드를 되돌릴 때 최신을\r\n // 다시 그린다) 화면만 건드리지 않는 것이다. 안 막으면 diff 본문을 덮어쓴다\r\n if (this.mode === 'file' && this.watching === file && cur.mtimeMs !== prev.mtimeMs) {\r\n this.renderCurrent();\r\n }\r\n });\r\n }\r\n catch {\r\n // 감시가 안 되는 파일시스템 — ⟳ 로 다시 읽으면 된다\r\n }\r\n }\r\n unwatch() {\r\n if (this.watching) {\r\n try {\r\n fs.unwatchFile(this.watching);\r\n }\r\n catch {\r\n // 이미 해제됨\r\n }\r\n this.watching = null;\r\n }\r\n }\r\n renderTabs() {\r\n var _a;\r\n if (!this.tabsEl) {\r\n return;\r\n }\r\n const list = this.activeTab ? (_a = this.recent.get(this.activeTab)) !== null && _a !== void 0 ? _a : [] : [];\r\n this.tabsEl.innerHTML = '';\r\n for (const file of list) {\r\n const chip = document.createElement('button');\r\n chip.className = 'ad-view-tab' + (file === this.current ? ' ad-view-tab-on' : '');\r\n chip.textContent = path.basename(file);\r\n chip.title = file;\r\n chip.addEventListener('click', () => this.openFile(file));\r\n this.tabsEl.appendChild(chip);\r\n }\r\n // 최근 파일 칩은 `파일` 모드의 것이다 — `변경` 에서는 자리만 차지한다\r\n this.tabsEl.style.display = list.length && this.mode === 'file' ? 'flex' : 'none';\r\n }\r\n renderEmpty() {\r\n if (!this.bodyEl) {\r\n return;\r\n }\r\n this.setTitle('미리보기', '');\r\n this.bodyEl.innerHTML = [\r\n '<div class=\"ad-view-empty\">',\r\n ' <p>에이전트가 만진 파일이 여기 쌓인다.</p>',\r\n ' <ul>',\r\n ' <li>화면에 찍힌 경로를 자동으로 줍는다 (md · 이미지 · 표 · 코드)</li>',\r\n ' <li>파일을 이 자리에 끌어다 놓아도 된다</li>',\r\n ' <li><b>+</b> 를 눌러 경로를 직접 넣을 수 있다</li>',\r\n ' </ul>',\r\n '</div>',\r\n ].join('');\r\n this.setFoot('');\r\n }\r\n renderMessage(title, detail) {\r\n if (!this.bodyEl) {\r\n return;\r\n }\r\n this.setTitle(title, detail);\r\n this.bodyEl.innerHTML = '<div class=\"ad-view-empty\"><p>' + (0, markdown_1.escapeHtml)(title) + '</p><p class=\"ad-view-dim\">'\r\n + (0, markdown_1.escapeHtml)(detail) + '</p></div>';\r\n this.setFoot('');\r\n }\r\n setTitle(title, tip) {\r\n if (this.titleEl) {\r\n this.titleEl.textContent = title;\r\n this.titleEl.title = tip;\r\n }\r\n }\r\n setFoot(text) {\r\n if (this.footEl) {\r\n this.footEl.textContent = text;\r\n this.footEl.title = text;\r\n }\r\n }\r\n /**\r\n * 발밑 줄 **앞에** 한 마디를 붙인다 (예: `저장했다 · 1.2KB · …`).\r\n * 저장 직후처럼 \"방금 무슨 일이 있었는지\" 를 크기·시각과 같이 보여줄 때 쓴다 —\r\n * 다음 `renderCurrent` 가 발밑 줄을 다시 쓰면 저절로 사라진다.\r\n */\r\n setFootNote(note) {\r\n var _a;\r\n if (this.footEl) {\r\n const now = (_a = this.footEl.textContent) !== null && _a !== void 0 ? _a : '';\r\n this.setFoot(now ? note + ' · ' + now : note);\r\n }\r\n }\r\n renderCurrent() {\r\n var _a;\r\n const file = this.current;\r\n if (!file || !this.bodyEl) {\r\n return;\r\n }\r\n // 편집 중에는 **누구도 본문을 덮지 못한다** — 파일 감시가 부른 것이면 \"밖에서 바뀜\" 으로\r\n // 알리기만 하고 사람이 친 글자는 그대로 둔다. 덮어쓸지는 저장할 때 묻는다\r\n if (this.editing) {\r\n this.editStale = true;\r\n this.refreshEditNote();\r\n return;\r\n }\r\n // 본문을 다시 그리면 검색 표시는 통째로 버려진다 — 참조만 비우고, 찾기 줄이 열려 있으면\r\n // 새 본문에서 다시 찾는다\r\n this.findHits = [];\r\n this.findIndex = -1;\r\n let st;\r\n try {\r\n st = fs.statSync(file);\r\n }\r\n catch {\r\n this.renderMessage('파일이 사라졌다', file);\r\n return;\r\n }\r\n this.setTitle(path.basename(file), file);\r\n this.setFoot((0, viewer_1.formatBytes)(st.size) + ' · ' + new Date(st.mtimeMs).toLocaleString() + ' · ' + file);\r\n try {\r\n switch ((0, viewer_1.classify)(file)) {\r\n case 'image':\r\n this.renderImage(file, st);\r\n break;\r\n case 'markdown':\r\n this.renderMarkdownFile(file);\r\n break;\r\n case 'table':\r\n this.renderTable(file);\r\n break;\r\n case 'text':\r\n this.renderText(file);\r\n break;\r\n default:\r\n this.renderBinary(file, st);\r\n }\r\n }\r\n catch (err) {\r\n this.renderMessage('읽지 못했다', String((_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err));\r\n }\r\n this.bodyEl.scrollTop = 0;\r\n this.syncEditButton();\r\n if (this.findRow && this.findRow.style.display !== 'none') {\r\n this.runFind();\r\n }\r\n }\r\n renderImage(file, st) {\r\n const url = dataUrl(file, MAX_IMAGE_BYTES);\r\n if (!url) {\r\n this.renderMessage('이미지가 너무 크다', (0, viewer_1.formatBytes)(st.size) + ' — ' + file);\r\n return;\r\n }\r\n this.bodyEl.innerHTML = '<div class=\"ad-view-image\"><img src=\"' + url + '\" alt=\"\"></div>';\r\n }\r\n renderMarkdownFile(file) {\r\n const { text, truncated } = readTextHead(file, MAX_TEXT_BYTES);\r\n const dir = path.dirname(file);\r\n const html = (0, markdown_1.renderMarkdown)(text, {\r\n resolveImage: src => {\r\n if (/^https?:/i.test(src)) {\r\n // 원격 이미지는 렌더러가 직접 가져오게 둔다 (CSP 가 막으면 대체 텍스트가 보인다)\r\n return src;\r\n }\r\n const target = path.isAbsolute(src) || /^[A-Za-z]:[\\\\/]/.test(src) ? src : path.join(dir, src);\r\n return dataUrl(target, MAX_INLINE_IMAGE_BYTES);\r\n },\r\n });\r\n this.bodyEl.innerHTML = '<div class=\"ad-view-md\">' + html\r\n + (truncated ? '<p class=\"ad-view-dim\">… 앞부분만 보여준다 (' + (0, viewer_1.formatBytes)(MAX_TEXT_BYTES) + ')</p>' : '')\r\n + '</div>';\r\n }\r\n renderTable(file) {\r\n const { text, truncated } = readTextHead(file, MAX_TEXT_BYTES);\r\n const rows = (0, viewer_1.parseDelimited)(text, (0, viewer_1.delimiterFor)(file));\r\n if (!rows.length) {\r\n this.renderMessage('빈 파일', file);\r\n return;\r\n }\r\n const head = rows[0].slice(0, MAX_TABLE_COLS);\r\n const body = rows.slice(1, MAX_TABLE_ROWS + 1);\r\n const cell = (v) => '<td>' + (0, markdown_1.escapeHtml)(v !== null && v !== void 0 ? v : '') + '</td>';\r\n this.bodyEl.innerHTML = '<div class=\"ad-view-table\"><table><thead><tr><th class=\"ad-view-rownum\">#</th>'\r\n + head.map(h => '<th>' + (0, markdown_1.escapeHtml)(h) + '</th>').join('')\r\n + '</tr></thead><tbody>'\r\n + body.map((r, i) => '<tr><td class=\"ad-view-rownum\">' + (i + 1) + '</td>'\r\n + head.map((_h, c) => cell(r[c])).join('') + '</tr>').join('')\r\n + '</tbody></table>'\r\n + (rows.length > MAX_TABLE_ROWS + 1 || truncated\r\n ? '<p class=\"ad-view-dim\">' + MAX_TABLE_ROWS + '행까지만 보여준다 (전체 ' + (rows.length - 1) + '행)</p>'\r\n : '')\r\n + '</div>';\r\n }\r\n renderText(file) {\r\n const { text, truncated } = readTextHead(file, MAX_TEXT_BYTES);\r\n const lines = text.split('\\n');\r\n const shown = lines.slice(0, MAX_TEXT_LINES);\r\n const cut = truncated || lines.length > MAX_TEXT_LINES;\r\n // 줄 번호를 같이 보여준다 — 코드 리뷰 때 `파일:라인` 을 확인하는 자리가 된다.\r\n //\r\n // **`<pre>` 두 장이 아니라 줄마다 한 칸(`.ad-cl`)으로 그린다** — 어느 줄을 눌렀는지\r\n // 알아야 참조를 만들 수 있고, 좌우로 놓은 `<pre>` 안에서는 클릭 지점을 줄로 되돌릴\r\n // 방법이 없다(글꼴 높이를 재서 나누는 것은 줄바꿈·확대에서 곧 어긋난다).\r\n // 마크다운·표는 대상이 아니다 — md 는 렌더된 문서라 줄 좌표가 없고, 표는 헤더 때문에\r\n // 표 행번호와 파일 줄번호가 어긋난다.\r\n const rows = ['<div class=\"ad-view-code ad-view-code-rows\" data-ad-ref-file=\"'\r\n + (0, markdown_1.escapeHtml)(file) + '\">'];\r\n shown.forEach((text, i) => {\r\n const no = i + 1;\r\n rows.push('<div class=\"ad-cl\" data-ad-ref-line=\"' + no + '\">'\r\n + '<span class=\"ad-cl-no\">' + no + '</span>'\r\n + '<span class=\"ad-cl-tx\">' + (0, markdown_1.escapeHtml)(text) + '</span></div>');\r\n });\r\n rows.push('</div>');\r\n this.bodyEl.innerHTML = rows.join('')\r\n + (cut ? '<p class=\"ad-view-dim\">… ' + MAX_TEXT_LINES + '줄까지만 보여준다 (전체 ' + lines.length + '줄)</p>' : '');\r\n // 다시 그렸으니 고른 줄의 강조를 되돌린다 (파일 감시가 부른 재렌더에서도 선택이 산다)\r\n this.applyRefSel();\r\n }\r\n renderBinary(file, st) {\r\n this.bodyEl.innerHTML = '<div class=\"ad-view-empty\"><p>' + (0, markdown_1.escapeHtml)(path.basename(file)) + '</p>'\r\n + '<p class=\"ad-view-dim\">미리보기를 지원하지 않는 형식 · ' + (0, viewer_1.formatBytes)(st.size) + '</p></div>';\r\n }\r\n // ---------- 편집 ----------\r\n //\r\n // 패널에서 고쳐 저장한다. 읽기만 되면 오타 하나에도 에디터를 따로 열어야 하고, 그 왕복이\r\n // 미리보기가 없애려던 것과 같은 종류의 낭비다.\r\n //\r\n // **보기 상한과 편집 상한이 다른 이유**는 `readTextAll` 머리주석에 있다 — 저장은 파일을\r\n // 통째로 다시 쓰므로 앞부분만 들고 열면 뒷부분이 사라진다. 그래서 전체를 읽을 수 있을\r\n // 때만 편집을 연다.\r\n /** 지금 보고 있는 것이 편집할 수 있는 글자 파일인가 (이미지·바이너리·`변경` 탭 제외) */\r\n canEdit() {\r\n if (this.mode !== 'file' || !this.current) {\r\n return false;\r\n }\r\n const kind = (0, viewer_1.classify)(this.current);\r\n return kind === 'text' || kind === 'markdown' || kind === 'table';\r\n }\r\n /** 편집 버튼의 표시 상태를 지금 화면에 맞춘다 */\r\n syncEditButton() {\r\n var _a;\r\n const btn = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelector('.ad-view-editbtn');\r\n if (!btn) {\r\n return;\r\n }\r\n const usable = this.canEdit();\r\n btn.classList.toggle('ad-view-btn-on', this.editing);\r\n btn.style.opacity = usable || this.editing ? '' : '0.35';\r\n btn.title = this.editing ? '보기로 (Esc)' : usable ? '편집 (저장 Ctrl+S)' : '편집할 수 없는 형식이다';\r\n }\r\n toggleEdit() {\r\n if (this.editing) {\r\n this.cancelEdit();\r\n }\r\n else {\r\n this.startEdit();\r\n }\r\n }\r\n startEdit() {\r\n var _a;\r\n if (this.editing || !this.bodyEl) {\r\n return;\r\n }\r\n const file = this.current;\r\n if (!file || !this.canEdit()) {\r\n this.setEditNote('이 형식은 편집할 수 없다');\r\n return;\r\n }\r\n let read;\r\n let st;\r\n try {\r\n st = fs.statSync(file);\r\n read = readTextAll(file, MAX_EDIT_BYTES);\r\n }\r\n catch (err) {\r\n this.setEditNote('읽지 못했다: ' + String((_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err));\r\n return;\r\n }\r\n if (read.truncated) {\r\n // 앞부분만 들고 저장하면 뒤가 날아간다 — 열지 않는 것이 유일하게 안전한 답이다\r\n this.setEditNote('너무 커서 편집할 수 없다 (' + (0, viewer_1.formatBytes)(MAX_EDIT_BYTES) + ' 넘음) — 보기 전용');\r\n this.showEditBar(true);\r\n return;\r\n }\r\n this.closeFind();\r\n this.editing = true;\r\n this.editStale = false;\r\n this.editOverwriteArmed = false;\r\n this.editForceArmed = false;\r\n this.editOrigin = {\r\n file, text: read.text, bom: read.bom, crlf: read.crlf, mtimeMs: st.mtimeMs,\r\n readOnly: !isWritable(file),\r\n };\r\n const ta = document.createElement('textarea');\r\n ta.className = 'ad-view-edit';\r\n ta.spellcheck = false;\r\n ta.value = read.text;\r\n // 편집 중 타이핑이 터미널로 새면 안 된다. 위쪽 패널 리스너(Ctrl+S·Esc)는 캡처가 아니라\r\n // 버블이라 여기서 멈춰도 먼저 도달한다\r\n ta.addEventListener('keydown', (e) => {\r\n const ctrl = e.ctrlKey || e.metaKey;\r\n if (!(ctrl && (e.key === 's' || e.key === 'S' || e.key === 'f' || e.key === 'F')) && e.key !== 'Escape') {\r\n e.stopPropagation();\r\n }\r\n });\r\n ta.addEventListener('input', () => this.refreshEditNote());\r\n this.bodyEl.innerHTML = '';\r\n this.bodyEl.appendChild(ta);\r\n this.editArea = ta;\r\n ta.focus();\r\n this.showEditBar(true);\r\n this.refreshEditNote();\r\n this.syncEditButton();\r\n }\r\n cancelEdit() {\r\n if (!this.editing) {\r\n this.showEditBar(false);\r\n return;\r\n }\r\n this.editing = false;\r\n this.editArea = null;\r\n this.editOrigin = null;\r\n this.editStale = false;\r\n this.editOverwriteArmed = false;\r\n this.editForceArmed = false;\r\n this.showEditBar(false);\r\n this.syncEditButton();\r\n this.renderCurrent();\r\n }\r\n saveEdit() {\r\n var _a, _b, _c;\r\n if (!this.editing || !this.editArea || !this.editOrigin) {\r\n return;\r\n }\r\n const origin = this.editOrigin;\r\n const next = this.editArea.value;\r\n if (next === origin.text && !this.editStale) {\r\n this.setEditNote('바뀐 것이 없다');\r\n return;\r\n }\r\n // 편집하는 동안 밖에서 바뀌었나 — 마지막에 한 번 더 본다(감시가 못 잡는 경우도 있다).\r\n // 커밋 버튼과 같은 2단 확인: 첫 누름은 경고, 두 번째 누름이 실제로 덮어쓴다\r\n let outside = this.editStale;\r\n try {\r\n outside = outside || fs.statSync(origin.file).mtimeMs !== origin.mtimeMs;\r\n }\r\n catch {\r\n // 사라졌으면 아래 쓰기에서 잡힌다 (새로 만들어진다)\r\n }\r\n if (outside && !this.editOverwriteArmed) {\r\n this.editOverwriteArmed = true;\r\n this.setEditNote('밖에서 바뀐 파일이다 — 다시 누르면 덮어쓴다');\r\n return;\r\n }\r\n const body = origin.crlf ? next.replace(/\\n/g, '\\r\\n') : next;\r\n const write = () => fs.writeFileSync(origin.file, (origin.bom ? '' : '') + body, 'utf8');\r\n try {\r\n write();\r\n }\r\n catch (err) {\r\n const code = String((_a = err === null || err === void 0 ? void 0 : err.code) !== null && _a !== void 0 ? _a : '');\r\n const denied = code === 'EPERM' || code === 'EACCES' || code === 'EROFS';\r\n if (!denied) {\r\n this.setEditNote('저장하지 못했다: ' + String((_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err));\r\n return;\r\n }\r\n // 읽기 전용이다. **말없이 속성을 풀지 않는다** — 이 환경에서 그 정체는 대개 P4 에서\r\n // 체크아웃하지 않은 파일이고, 체크아웃 없이 쓴 내용은 다음 `p4 sync` 에 조용히\r\n // 덮인다(`comment_writer.py` 가 같은 이유로 `p4 edit` 를 먼저 시도한다).\r\n // 그래서 사실을 말하고, 그래도 쓰겠다면 두 번째 누름에서만 속성을 푼다\r\n if (!this.editForceArmed) {\r\n this.editForceArmed = true;\r\n this.setEditNote('읽기 전용이다 (P4 면 p4 edit 먼저) — 다시 누르면 속성을 풀고 저장한다');\r\n return;\r\n }\r\n try {\r\n fs.chmodSync(origin.file, 0o666);\r\n write();\r\n }\r\n catch (err2) {\r\n this.setEditNote('저장하지 못했다: ' + String((_c = err2 === null || err2 === void 0 ? void 0 : err2.message) !== null && _c !== void 0 ? _c : err2));\r\n return;\r\n }\r\n }\r\n this.editing = false;\r\n this.editArea = null;\r\n this.editOrigin = null;\r\n this.editStale = false;\r\n this.editOverwriteArmed = false;\r\n this.editForceArmed = false;\r\n this.showEditBar(false);\r\n this.setEditNote('');\r\n this.syncEditButton();\r\n this.renderCurrent();\r\n this.setFootNote('저장했다');\r\n }\r\n showEditBar(on) {\r\n var _a;\r\n if (this.editBarEl) {\r\n this.editBarEl.style.display = on ? 'flex' : 'none';\r\n }\r\n const btns = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelector('.ad-view-edit-btns');\r\n if (btns) {\r\n // 편집이 아니라 안내만 띄운 경우(너무 큰 파일)에는 저장/취소를 숨긴다\r\n btns.style.display = this.editing ? '' : 'none';\r\n }\r\n }\r\n setEditNote(text) {\r\n if (this.editNoteEl) {\r\n this.editNoteEl.textContent = text;\r\n }\r\n if (!this.editing && this.editBarEl && text) {\r\n this.editBarEl.style.display = 'flex';\r\n }\r\n }\r\n /** 편집 중 안내줄 — 바뀐 줄 수와 외부 변경을 알린다 */\r\n refreshEditNote() {\r\n if (!this.editing || !this.editArea || !this.editOrigin) {\r\n return;\r\n }\r\n const dirty = this.editArea.value !== this.editOrigin.text;\r\n if (this.editSaveBtn) {\r\n this.editSaveBtn.disabled = !dirty && !this.editStale;\r\n }\r\n // 글자를 고치면 확인 대기는 풀린다 (커밋 줄과 같은 규칙)\r\n this.editOverwriteArmed = false;\r\n this.editForceArmed = false;\r\n const marks = [];\r\n marks.push(path.basename(this.editOrigin.file));\r\n if (this.editOrigin.bom) {\r\n marks.push('BOM');\r\n }\r\n marks.push(this.editOrigin.crlf ? 'CRLF' : 'LF');\r\n // 읽기 전용은 **열자마자** 말한다 — 저장할 때 알면 그때까지 친 것이 헛일이 된다\r\n if (this.editOrigin.readOnly) {\r\n marks.push('읽기 전용');\r\n }\r\n marks.push(dirty ? '고침' : '그대로');\r\n if (this.editStale) {\r\n marks.push('밖에서 바뀜');\r\n }\r\n this.setEditNote(marks.join(' · '));\r\n }\r\n // ---------- 찾기 ----------\r\n //\r\n // 본문에서 글자를 찾아 표시하고 오간다. 편집 중이면 textarea 안을 찾는다 — 같은 Ctrl+F 로\r\n // 두 상태를 다 덮어야 \"패널 안에서는 이 키\" 라는 규칙이 성립한다.\r\n openFind() {\r\n if (!this.findRow || !this.findInput) {\r\n return;\r\n }\r\n this.findRow.style.display = 'flex';\r\n this.findInput.focus();\r\n this.findInput.select();\r\n this.runFind();\r\n }\r\n closeFind() {\r\n if (this.findRow) {\r\n this.findRow.style.display = 'none';\r\n }\r\n this.clearFindMarks();\r\n if (this.findCountEl) {\r\n this.findCountEl.textContent = '';\r\n }\r\n }\r\n /** 검색어가 바뀔 때마다 다시 찾는다 */\r\n runFind() {\r\n var _a, _b;\r\n const term = (_b = (_a = this.findInput) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';\r\n this.clearFindMarks();\r\n if (!term) {\r\n if (this.findCountEl) {\r\n this.findCountEl.textContent = '';\r\n }\r\n return;\r\n }\r\n if (this.editing && this.editArea) {\r\n this.findInTextarea(term, 0);\r\n return;\r\n }\r\n this.markMatches(term);\r\n this.findIndex = this.findHits.length ? 0 : -1;\r\n this.showFindHit();\r\n }\r\n /** 다음/이전 일치로 이동 */\r\n stepFind(dir) {\r\n var _a, _b;\r\n const term = (_b = (_a = this.findInput) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';\r\n if (!term) {\r\n return;\r\n }\r\n if (this.editing && this.editArea) {\r\n this.findInTextarea(term, dir);\r\n return;\r\n }\r\n if (!this.findHits.length) {\r\n this.markMatches(term);\r\n this.findIndex = this.findHits.length ? 0 : -1;\r\n }\r\n else {\r\n this.findIndex = (this.findIndex + dir + this.findHits.length) % this.findHits.length;\r\n }\r\n this.showFindHit();\r\n }\r\n /**\r\n * textarea 안 찾기 — 커서 위치부터 다음 일치를 골라 **선택**한다.\r\n * 본문 찾기와 달리 DOM 을 건드리지 않으므로 편집 내용이 흔들리지 않는다.\r\n */\r\n findInTextarea(term, dir) {\r\n const ta = this.editArea;\r\n const hay = ta.value.toLowerCase();\r\n const needle = term.toLowerCase();\r\n const total = needle ? hay.split(needle).length - 1 : 0;\r\n if (!total) {\r\n this.setFindCount(0, 0);\r\n return;\r\n }\r\n let at;\r\n if (dir < 0) {\r\n const before = ta.selectionStart - 1;\r\n at = hay.lastIndexOf(needle, Math.max(before - 1, 0));\r\n if (at < 0) {\r\n at = hay.lastIndexOf(needle);\r\n }\r\n }\r\n else {\r\n const from = dir > 0 ? ta.selectionStart + 1 : ta.selectionStart;\r\n at = hay.indexOf(needle, from);\r\n if (at < 0) {\r\n at = hay.indexOf(needle);\r\n }\r\n }\r\n if (at < 0) {\r\n this.setFindCount(0, 0);\r\n return;\r\n }\r\n ta.focus();\r\n ta.setSelectionRange(at, at + term.length);\r\n // 선택한 자리가 보이도록 대략적인 줄 위치로 스크롤한다 (textarea 는 scrollIntoView 가 없다)\r\n const line = ta.value.slice(0, at).split('\\n').length - 1;\r\n const lineH = Math.max(1, Math.round(ta.scrollHeight / Math.max(1, ta.value.split('\\n').length)));\r\n ta.scrollTop = Math.max(0, line * lineH - ta.clientHeight / 2);\r\n const nth = hay.slice(0, at).split(needle).length;\r\n this.setFindCount(nth, total);\r\n }\r\n /**\r\n * 본문 텍스트 노드를 훑어 일치마다 `<mark>` 를 넣는다.\r\n *\r\n * 본문을 다시 그리지 않고 감싸기만 하는 이유 — 줄 참조(`.ad-cl`)·표·마크다운이 저마다\r\n * 다른 구조라, 그리는 쪽을 고치면 네 군데를 같이 고쳐야 한다. 텍스트 노드만 건드리면\r\n * 어떤 구조에서도 성립하고, 지울 때는 `normalize()` 로 원래대로 돌아간다.\r\n */\r\n markMatches(term) {\r\n var _a;\r\n const root = this.bodyEl;\r\n if (!root || !term) {\r\n return;\r\n }\r\n const needle = term.toLowerCase();\r\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\r\n const targets = [];\r\n let node;\r\n while ((node = walker.nextNode())) {\r\n const t = node;\r\n if (t.data && t.data.toLowerCase().indexOf(needle) >= 0) {\r\n targets.push(t);\r\n }\r\n }\r\n for (const text of targets) {\r\n if (this.findHits.length >= MAX_FIND_HITS) {\r\n break;\r\n }\r\n const parts = [];\r\n let rest = text.data;\r\n let guard = 0;\r\n while (guard++ < 500) {\r\n const at = rest.toLowerCase().indexOf(needle);\r\n if (at < 0) {\r\n break;\r\n }\r\n if (at > 0) {\r\n parts.push(document.createTextNode(rest.slice(0, at)));\r\n }\r\n const mark = document.createElement('mark');\r\n mark.className = 'ad-find-hit';\r\n mark.textContent = rest.slice(at, at + term.length);\r\n parts.push(mark);\r\n this.findHits.push(mark);\r\n rest = rest.slice(at + term.length);\r\n if (this.findHits.length >= MAX_FIND_HITS) {\r\n break;\r\n }\r\n }\r\n if (!parts.length) {\r\n continue;\r\n }\r\n if (rest) {\r\n parts.push(document.createTextNode(rest));\r\n }\r\n const frag = document.createDocumentFragment();\r\n parts.forEach(p => frag.appendChild(p));\r\n (_a = text.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(frag, text);\r\n }\r\n }\r\n /** `<mark>` 를 걷어내고 원래 텍스트로 되돌린다 */\r\n clearFindMarks() {\r\n var _a;\r\n for (const mark of this.findHits) {\r\n const parent = mark.parentNode;\r\n if (!parent) {\r\n continue;\r\n }\r\n parent.replaceChild(document.createTextNode((_a = mark.textContent) !== null && _a !== void 0 ? _a : ''), mark);\r\n parent.normalize();\r\n }\r\n this.findHits = [];\r\n this.findIndex = -1;\r\n }\r\n showFindHit() {\r\n this.findHits.forEach((m, i) => m.classList.toggle('ad-find-cur', i === this.findIndex));\r\n const cur = this.findHits[this.findIndex];\r\n if (cur) {\r\n cur.scrollIntoView({ block: 'center' });\r\n }\r\n this.setFindCount(this.findIndex + 1, this.findHits.length);\r\n }\r\n setFindCount(nth, total) {\r\n if (this.findCountEl) {\r\n this.findCountEl.textContent = total ? nth + '/' + total : '없음';\r\n }\r\n }\r\n // ---------- `변경` 탭 ----------\r\n /**\r\n * git 한 번. 실패도 값으로 돌려준다 — 저장소가 아니거나 git 이 없는 것은 흔한 상태이고\r\n * 예외로 던지면 패널이 빈 화면으로 남는다.\r\n */\r\n runGit(dir, args) {\r\n return new Promise(resolve => {\r\n var _a;\r\n try {\r\n (0, child_process_1.execFile)('git', ['--no-pager', '-C', dir, ...args], {\r\n encoding: 'utf8',\r\n maxBuffer: GIT_MAX_BUFFER,\r\n timeout: GIT_TIMEOUT_MS,\r\n windowsHide: true,\r\n }, (err, stdout, stderr) => {\r\n resolve({\r\n ok: !err,\r\n out: String(stdout !== null && stdout !== void 0 ? stdout : ''),\r\n err: String(stderr || (err === null || err === void 0 ? void 0 : err.message) || ''),\r\n });\r\n });\r\n }\r\n catch (e) {\r\n // spawn 자체가 못 뜨는 경우 (git 이 PATH 에 없다)\r\n resolve({ ok: false, out: '', err: String((_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e) });\r\n }\r\n });\r\n }\r\n /** 자동 갱신 — 간격 제한을 지킨다 (에이전트가 연달아 고치면 신호가 초당 몇 번씩 온다) */\r\n maybeAutoDiff() {\r\n const now = Date.now();\r\n if (now - this.diffAutoAt < DIFF_AUTO_MS) {\r\n return;\r\n }\r\n this.diffAutoAt = now;\r\n this.refreshDiff();\r\n }\r\n /**\r\n * 작업트리의 변경을 다시 읽어 그린다.\r\n *\r\n * **`diff HEAD` 를 쓰는 이유** — 스테이지에 올렸는지 여부는 \"무엇이 바뀌었나\" 와 상관이 없다.\r\n * 에이전트가 `git add` 를 했든 안 했든 사람이 보려는 것은 같은 것이고, 그냥 `git diff` 는\r\n * 스테이지에 올라간 변경을 감춰 버린다.\r\n */\r\n refreshDiff() {\r\n var _a;\r\n if (!this.bodyEl) {\r\n return;\r\n }\r\n const dir = this.host.cwdFor((_a = this.activeTab) !== null && _a !== void 0 ? _a : {});\r\n this.setTitle('변경', dir !== null && dir !== void 0 ? dir : '');\r\n if (!dir) {\r\n this.setStatus([]);\r\n this.renderDiffNote('작업 폴더를 모른다', '이 탭의 cwd 를 아직 잡지 못했다 — 터미널에서 명령을 한 번 실행하면 잡힌다');\r\n return;\r\n }\r\n if (!isDir(dir)) {\r\n // `git -C <파일>` 은 `fatal: cannot change to …: Invalid argument` 로 끝난다 —\r\n // 그 원문을 그대로 보여 주면 무슨 일인지 알 수 없다. cwd 가 어떻게 파일이 되는지는\r\n // deck.service `touchCwd` 주석 참고 (Tabby 의 윈도우 cwd 추정)\r\n this.setStatus([]);\r\n this.renderDiffNote('작업 폴더가 폴더가 아니다', dir);\r\n return;\r\n }\r\n const seq = ++this.diffSeq;\r\n this.diffAutoAt = Date.now();\r\n if (!this.bodyEl.querySelector('.ad-view-diff')) {\r\n // 첫 진입에만 안내를 띄운다 — 갱신마다 화면을 비우면 스크롤이 튄다\r\n this.renderDiffNote('변경을 읽고 있다', dir);\r\n }\r\n Promise.all([\r\n this.runGit(dir, ['diff', 'HEAD', '--no-color']),\r\n this.runGit(dir, ['status', '--porcelain']),\r\n this.runGit(dir, ['rev-parse', '--show-toplevel']),\r\n ]).then(async ([diff, status, root]) => {\r\n let text = diff.out;\r\n if (!diff.ok) {\r\n const msg = diff.err;\r\n if (/not a git repository/i.test(msg)) {\r\n this.noGit(seq, 'git 저장소가 아니다', dir, '이 폴더는 git 으로 관리되지 않는다 — 무엇이 바뀌었는지(diff)는 비교할 기준이 없다');\r\n return;\r\n }\r\n if (/ENOENT|not recognized|command not found/i.test(msg)) {\r\n this.noGit(seq, 'git 을 찾지 못했다', 'PATH 에 git 이 있어야 변경 내용을 비교할 수 있다', 'git 이 없어 diff 는 만들 수 없다');\r\n return;\r\n }\r\n if (/ambiguous argument .?HEAD|unknown revision|bad revision/i.test(msg)) {\r\n // 커밋이 하나도 없는 새 저장소 — HEAD 가 없으니 기준 없이 뽑는다\r\n const first = await this.runGit(dir, ['diff', '--no-color']);\r\n text = first.out;\r\n if (!first.ok && !text) {\r\n this.failDiff(seq, '변경을 읽지 못했다', first.err);\r\n return;\r\n }\r\n }\r\n else if (!text) {\r\n this.failDiff(seq, '변경을 읽지 못했다', msg);\r\n return;\r\n }\r\n }\r\n const allFiles = (0, gitDiff_1.parseUnifiedDiff)(text);\r\n const allUntracked = status.ok ? (0, gitDiff_1.parseUntracked)(status.out) : [];\r\n this.diffRoot = root.ok ? root.out.trim() || dir : dir;\r\n // **범위를 여기서 좁힌다** — git 명령에 경로를 넘기지 않는 이유: 세션이 만진 파일이\r\n // 수백 개면 명령줄 길이 상한에 걸리고, 그 목록이 저장소 밖 파일을 담고 있으면\r\n // git 이 통째로 실패한다(`fatal: ... outside repository`). 걸러 내는 쪽이 안전하다.\r\n const touched = this.diffScope === 'session' ? this.touchedNow() : [];\r\n const files = (0, gitDiff_1.filterTouched)(allFiles, f => f.path, this.diffRoot, touched);\r\n const untracked = (0, gitDiff_1.filterTouched)(allUntracked, p => p, this.diffRoot, touched);\r\n this.diffHidden = (allFiles.length - files.length) + (allUntracked.length - untracked.length);\r\n // 좁히기가 예상과 다를 때 **\"보고가 안 왔다\" 와 \"경로가 안 맞는다\" 를 가르는** 자리.\r\n // 화면에는 숨긴 개수만 나오는데, 그것만으로는 목록이 비었는지 경로 모양이 어긋났는지\r\n // 알 수 없다 (2026-09-11 회귀에서 이것 없이 한 바퀴 돌았다). `__agentdeck.view().diffDebug`\r\n this.diffDebug = {\r\n root: this.diffRoot, scope: this.diffScope,\r\n touched: touched.slice(0, 5), all: allFiles.length, kept: files.length,\r\n sample: allFiles.slice(0, 5).map(f => f.path),\r\n };\r\n this.finishDiff(seq, () => {\r\n // 같은 `status --porcelain` 출력을 두 파서가 나눠 읽는다 — 추적안됨 목록(옛 동작)과\r\n // 스테이지 상태. git 을 한 번 더 부르면 두 결과가 서로 다른 시점을 보게 된다\r\n this.setStatus(status.ok ? (0, gitCommit_1.parseStatus)(status.out) : []);\r\n this.renderDiff(files, untracked, dir);\r\n });\r\n }).catch((err) => {\r\n var _a;\r\n // 파싱까지 포함해 어디서 터져도 패널은 문장을 남긴다\r\n this.failDiff(seq, '변경을 읽지 못했다', String((_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err));\r\n });\r\n }\r\n /** 지금 탭에서 에이전트가 만진 파일 (없거나 배선이 없으면 빈 배열 = 좁히지 않는다) */\r\n touchedNow() {\r\n var _a, _b, _c, _d;\r\n return (_d = (_b = (_a = this.host).touchedFor) === null || _b === void 0 ? void 0 : _b.call(_a, (_c = this.activeTab) !== null && _c !== void 0 ? _c : {})) !== null && _d !== void 0 ? _d : [];\r\n }\r\n /** 늦게 온 응답이 새 화면을 덮지 않게 — 번호와 모드가 그대로일 때만 그린다 */\r\n finishDiff(seq, draw) {\r\n if (seq === this.diffSeq && this.mode === 'diff' && this.bodyEl) {\r\n draw();\r\n }\r\n }\r\n /**\r\n * 실패 문장을 그리고 **스테이지 상태를 비운다.**\r\n * 상태를 남겨 두면 저장소를 못 읽는 화면에서 딱지·요약이 이전 저장소 것으로 남고,\r\n * 그 딱지를 누르면 지금 보고 있지 않은 저장소에 `git add` 가 나간다.\r\n */\r\n failDiff(seq, title, detail) {\r\n this.finishDiff(seq, () => {\r\n this.setStatus([]);\r\n this.renderDiffNote(title, detail);\r\n });\r\n }\r\n /**\r\n * git 이 없거나 저장소가 아닐 때 — **그래도 이 세션이 만진 파일은 보여준다.**\r\n *\r\n * 왜 필요한가: 이 패널의 목적은 \"에이전트가 방금 무엇을 건드렸나\" 이고, 그 답은 훅이 이미\r\n * 알고 있다(`touchedFor`). git 은 거기에 **무엇이 어떻게 바뀌었는지**를 더해 주는 도구일 뿐이다.\r\n * 그런데 예전에는 git 이 없으면 안내 한 줄만 띄우고 끝나서, git 을 안 쓰는 폴더(스크립트 모음·\r\n * 기획 문서 폴더·임시 작업 폴더)에서 탭이 통째로 죽은 기능이 됐다 (2026-09-11 유저 지적).\r\n *\r\n * **줄 내용(diff)은 만들지 않는다** — 기준(HEAD)이 없으니 \"무엇이 바뀌었다\" 를 말할 근거가\r\n * 없고, 없는 근거를 지어내는 것보다 목록과 파일 크기·시각까지만 말하는 편이 정직하다.\r\n * 클릭하면 `파일` 탭에서 내용을 본다(추적 안 됨 목록과 같은 `data-ad-open` 경로).\r\n *\r\n * 훅이 없는 에이전트(Codex·Gemini)는 만진 목록이 비어 있으므로 예전처럼 안내만 남는다 —\r\n * 그 경우엔 정말로 보여줄 근거가 하나도 없다.\r\n */\r\n noGit(seq, title, detail, why) {\r\n var _a;\r\n const touched = this.touchedNow();\r\n if (!touched.length) {\r\n this.failDiff(seq, title, detail);\r\n return;\r\n }\r\n const cwd = this.host.cwdFor((_a = this.activeTab) !== null && _a !== void 0 ? _a : {});\r\n this.diffRoot = null;\r\n this.diffHidden = 0;\r\n this.finishDiff(seq, () => {\r\n // 스테이지 상태·커밋 줄은 git 이 있어야 뜻이 있다 — 여기서는 통째로 감춘다\r\n this.setStatus([]);\r\n this.setCommitVisible(false);\r\n const out = ['<div class=\"ad-view-diff\">'];\r\n out.push('<div class=\"ad-view-diff-sum\">'\r\n + (0, markdown_1.escapeHtml)('이 세션이 만진 파일 ' + touched.length + '개') + '</div>');\r\n out.push('<p class=\"ad-view-dim\">' + (0, markdown_1.escapeHtml)(title + ' — ' + why) + '</p>');\r\n out.push('<div class=\"ad-view-diff-list\">');\r\n for (const abs of touched.slice(0, MAX_DIFF_FILES)) {\r\n const shown = (0, gitDiff_1.refPathFrom)(abs, cwd);\r\n out.push('<div class=\"ad-view-diff-u\" data-ad-open=\"' + (0, markdown_1.escapeHtml)(abs) + '\">'\r\n + (0, markdown_1.escapeHtml)(shown) + ' <span class=\"ad-view-dim\">'\r\n + (0, markdown_1.escapeHtml)(fileNote(abs)) + '</span></div>');\r\n }\r\n if (touched.length > MAX_DIFF_FILES) {\r\n out.push('<p class=\"ad-view-dim\">… 이후 생략</p>');\r\n }\r\n out.push('</div></div>');\r\n this.bodyEl.innerHTML = out.join('');\r\n this.setFoot(detail);\r\n });\r\n }\r\n /** 커밋 줄은 git 이 있을 때만 뜻이 있다 — 모드와 별개로 여닫는다 */\r\n setCommitVisible(show) {\r\n if (this.commitEl) {\r\n this.commitEl.style.display = show && this.mode === 'diff' ? 'block' : 'none';\r\n }\r\n }\r\n renderDiffNote(title, detail) {\r\n if (!this.bodyEl) {\r\n return;\r\n }\r\n this.bodyEl.innerHTML = '<div class=\"ad-view-diff\"><div class=\"ad-view-empty\"><p>'\r\n + (0, markdown_1.escapeHtml)(title) + '</p><p class=\"ad-view-dim\">' + (0, markdown_1.escapeHtml)(detail) + '</p></div></div>';\r\n this.setFoot(detail);\r\n }\r\n renderDiff(files, untracked, dir) {\r\n // git 이 답한 자리다 — `noGit` 이 감춰 둔 커밋 줄을 되돌린다\r\n this.setCommitVisible(true);\r\n const shownFiles = files.slice(0, MAX_DIFF_FILES);\r\n const out = ['<div class=\"ad-view-diff\">'];\r\n // 요약줄에 **지금 보고 있는 범위**를 함께 적는다 — 숫자만 있으면 \"이게 전부인가\" 를\r\n // 알 수 없다. 좁혀서 가려진 게 있을 때만 그 수를 말한다(0 이면 군더더기다)\r\n const scopeNote = this.diffScope === 'session' && this.diffHidden > 0\r\n ? ' · 이 세션이 만진 것만 (' + this.diffHidden + '개 숨김)'\r\n : '';\r\n out.push('<div class=\"ad-view-diff-sum\">' + (0, markdown_1.escapeHtml)((0, gitDiff_1.formatStat)(files) + scopeNote) + '</div>');\r\n if (shownFiles.length) {\r\n out.push('<div class=\"ad-view-diff-list\">');\r\n shownFiles.forEach((f, i) => {\r\n out.push('<button class=\"ad-view-diff-item\" data-ad-diff=\"ad-diff-' + i + '\">'\r\n + '<span class=\"ad-view-diff-st ad-view-diff-st-' + f.status + '\">'\r\n + (0, markdown_1.escapeHtml)((0, gitDiff_1.statusLabel)(f)) + '</span>'\r\n + this.stageChipHtml(f.path)\r\n + '<span class=\"ad-view-diff-name\">' + (0, markdown_1.escapeHtml)(f.path) + '</span>'\r\n + '<span class=\"ad-view-diff-num\"><b class=\"ad-plus\">+' + f.added + '</b>'\r\n + '<b class=\"ad-minus\">-' + f.removed + '</b></span></button>');\r\n });\r\n if (files.length > shownFiles.length) {\r\n out.push('<p class=\"ad-view-dim\">… 이후 생략 (전체 ' + files.length + '개 파일)</p>');\r\n }\r\n out.push('</div>');\r\n }\r\n if (untracked.length) {\r\n // 내용은 붙이지 않는다 (gitDiff.parseUntracked 주석 참고) — 이름만 알려 준다\r\n const list = untracked.slice(0, MAX_UNTRACKED);\r\n out.push('<div class=\"ad-view-diff-untracked\"><div class=\"ad-view-diff-sub\">추적 안 됨 · '\r\n + untracked.length + '개</div>');\r\n for (const p of list) {\r\n // `?? dir/` 은 폴더 하나로 묶여서 온다 — 폴더는 열 수 없으니 이름만 보여준다\r\n const open = p.endsWith('/') ? '' : ' data-ad-open=\"' + (0, markdown_1.escapeHtml)(this.absOf(p)) + '\"';\r\n // 폴더(`dir/`)도 딱지는 붙인다 — `git add -- dir/` 는 폴더째 올리는 정상 동작이고,\r\n // 새로 만든 산출물 폴더를 한 번에 올리는 것이 실제로 가장 흔한 조작이다\r\n // 딱지와 경로 사이의 공백은 **글자로** 넣는다 — 이 줄은 flex 가 아니라서\r\n // 스타일이 아직 없거나 좁아 접힐 때 `새파일docs/x.md` 로 붙어 읽힌다\r\n out.push('<div class=\"ad-view-diff-u\"' + open + '>' + this.stageChipHtml(p)\r\n + ' ' + (0, markdown_1.escapeHtml)(p) + '</div>');\r\n }\r\n if (untracked.length > list.length) {\r\n out.push('<p class=\"ad-view-dim\">… 이후 생략</p>');\r\n }\r\n out.push('</div>');\r\n }\r\n if (!shownFiles.length && !untracked.length) {\r\n // **\"변경 없음\" 과 \"범위가 좁아서 안 보인다\" 는 다른 상황이다.** 후자를 같은 문장으로\r\n // 말하면 저장소에 변경이 없다는 거짓말이 되고, 사람은 `전체` 버튼을 누를 생각을 못 한다\r\n const narrowed = this.diffScope === 'session' && this.diffHidden > 0;\r\n out.push('<div class=\"ad-view-empty\"><p>'\r\n + (narrowed ? '이 세션이 만진 파일은 아직 없다' : '변경 없음') + '</p>'\r\n + '<p class=\"ad-view-dim\">' + (0, markdown_1.escapeHtml)(narrowed\r\n ? '저장소에는 ' + this.diffHidden + '개의 변경이 있다 — `전체` 로 보면 나온다'\r\n : dir) + '</p></div>');\r\n }\r\n /** 본문 줄 예산 — 파일 하나가 다 먹지 않게 파일별 상한도 같이 본다 */\r\n let budget = MAX_DIFF_LINES;\r\n shownFiles.forEach((f, i) => {\r\n out.push('<div class=\"ad-view-diff-file\" id=\"ad-diff-' + i + '\">');\r\n const title = f.oldPath ? f.oldPath + ' → ' + f.path : f.path;\r\n out.push('<div class=\"ad-view-diff-fhead\" data-ad-open=\"' + (0, markdown_1.escapeHtml)(this.absOf(f.path))\r\n + '\" title=\"' + (0, markdown_1.escapeHtml)(title) + '\">' + (0, markdown_1.escapeHtml)(title) + '</div>');\r\n if (f.binary) {\r\n out.push('<div class=\"ad-view-diff-note\">바이너리 · 내용 비교 없음</div>');\r\n }\r\n else if (!f.lines.length) {\r\n out.push('<div class=\"ad-view-diff-note\">내용 변경 없음</div>');\r\n }\r\n else {\r\n const cap = Math.min(f.lines.length, MAX_DIFF_FILE_LINES, Math.max(budget, 0));\r\n // 줄 참조가 어느 파일의 줄인지는 이 상자가 말한다 — git 이 낸 **저장소 루트 기준**\r\n // 경로 그대로 심고, 절대화·cwd 상대화는 sendRef 가 순수 함수로 한다\r\n out.push('<div class=\"ad-view-diff-lines\" data-ad-ref-file=\"'\r\n + (0, markdown_1.escapeHtml)(f.path) + '\">');\r\n for (let n = 0; n < cap; n++) {\r\n out.push(this.diffLineHtml(f.lines[n]));\r\n }\r\n out.push('</div>');\r\n budget -= cap;\r\n if (cap < f.lines.length) {\r\n out.push('<div class=\"ad-view-diff-note\">… 이후 생략 (전체 ' + f.lines.length + '줄)</div>');\r\n }\r\n }\r\n out.push('</div>');\r\n });\r\n out.push('</div>');\r\n this.bodyEl.innerHTML = out.join('');\r\n // **자동 갱신이 방금 본문을 통째로 덮었다** — 고른 줄의 강조를 여기서 되돌린다.\r\n // 선택은 클래스 필드(refSel)에 있으므로 갱신을 몇 번 거쳐도 살아 있다\r\n this.applyRefSel();\r\n this.setFoot((0, gitDiff_1.formatStat)(files) + ' · ' + new Date().toLocaleTimeString() + ' 기준 · ' + dir);\r\n }\r\n /**\r\n * diff 한 줄. **원문은 반드시 이스케이프한 뒤 우리 태그만 붙인다** — 소스코드 안의\r\n * `<script>` 나 `onerror=` 가 태그가 되면 안 된다 (markdown.ts 와 같은 규칙).\r\n */\r\n diffLineHtml(line) {\r\n var _a, _b;\r\n const mark = line.kind === 'add' ? '+' : line.kind === 'del' ? '-' : ' ';\r\n const body = line.kind === 'hunk' ? line.text : mark + line.text;\r\n // 참조에 쓸 번호는 **신 파일 기준**이다 (gitDiff.refLineNo 주석).\r\n // 번호가 없는 줄(삭제줄·헝크 머리줄)에는 번호를 심지 않고 `data-ad-ref-del` 만 붙인다 —\r\n // 눌러도 아무것도 보내지 않고 이유만 말한다. 직전 신 번호로 때우면 `file:42` 가\r\n // 삭제된 내용이 아니라 엉뚱하게 남아 있는 42번 줄을 가리키고, 에이전트는 그 줄을\r\n // 자신 있게 고친다. 조용히 틀리는 쪽보다 못 만들고 이유를 말하는 쪽이 낫다\r\n const no = (0, gitDiff_1.refLineNo)(line);\r\n const ref = no === null\r\n ? ' data-ad-ref-del=\"' + (line.kind === 'hunk' ? 'hunk' : 'del') + '\"'\r\n : ' data-ad-ref-line=\"' + no + '\"';\r\n return '<div class=\"ad-dl ad-dl-' + line.kind + '\"' + ref + '>'\r\n + '<span class=\"ad-dl-no\">' + ((_a = line.oldNo) !== null && _a !== void 0 ? _a : '') + '</span>'\r\n + '<span class=\"ad-dl-no\">' + ((_b = line.newNo) !== null && _b !== void 0 ? _b : '') + '</span>'\r\n + '<span class=\"ad-dl-tx\">' + (0, markdown_1.escapeHtml)(body) + '</span></div>';\r\n }\r\n /** git 이 내는 경로는 **저장소 루트 기준**이다 — 탭 cwd 로 풀면 하위 폴더에서 어긋난다 */\r\n absOf(rel) {\r\n const root = this.diffRoot;\r\n return root ? path.join(root, rel) : rel;\r\n }\r\n // ---------- `파일:라인` 참조 ----------\r\n //\r\n // 화면에서 고른 줄을 `src/a.ts:12` 한 낱말로 만들어 **활성 탭 터미널에 넣는다.**\r\n // 에이전트에게 자리를 알려 주려고 파일명을 다시 치고 줄번호를 세는 왕복이 이 패널이\r\n // 없애려던 것과 같은 종류의 낭비다.\r\n //\r\n // 번호·경로·따옴표 판정은 전부 `gitDiff.ts` 의 순수 함수(refLineNo · joinRefPath ·\r\n // refPathFrom · formatLineRef)가 한다 — 여기서 규칙을 다시 쓰지 않는다. 여기 있는 것은\r\n // DOM 에서 \"무엇을 눌렀나\" 를 읽고 그 함수들에 넘기는 배선뿐이다.\r\n //\r\n // **패널이 터미널에 직접 쓰지 않는다** — 쓰기는 host.sendText(deck.service 의 sendToPane)가\r\n // 맡는다. 거기에 한글 조합 중 입력 순서 보정과 진단 로그가 있다.\r\n /**\r\n * 줄을 눌렀다. Shift 면 직전에 고른 줄부터의 **범위**가 된다.\r\n *\r\n * 본문을 다시 그리지 않고 클래스만 갈아 끼운다 — 다시 그리면 스크롤이 튀고(긴 diff 에서\r\n * 방금 보던 자리를 잃는다) `변경` 은 git 을 한 번 더 돌린다.\r\n */\r\n clickRefLine(row, extend) {\r\n var _a;\r\n // **드래그로 글자를 긁은 직후에도 click 이 한 번 온다.** 그때 참조를 넣으면 복사하려던\r\n // 조작이 터미널에 글자를 뿌린다 — 본문은 `user-select: text` 로 열어 둔 자리이고\r\n // 긁어 복사하는 것은 의도된 기능이다. 그래서 선택이 남아 있으면 아무것도 하지 않는다.\r\n // 범위 선택(Shift)은 브라우저가 글자 선택을 같이 늘리므로 이 규칙에서 빼고,\r\n // 늘어난 선택만 걷어낸다 (그대로 두면 파란 띠가 줄 강조와 겹쳐 읽기 어렵다)\r\n const sel = typeof window.getSelection === 'function' ? window.getSelection() : null;\r\n if (!extend) {\r\n if (sel && !sel.isCollapsed && String(sel)) {\r\n return;\r\n }\r\n }\r\n else if (sel && !sel.isCollapsed) {\r\n try {\r\n sel.removeAllRanges();\r\n }\r\n catch {\r\n // 선택을 못 지우는 경우 — 강조가 겹쳐 보일 뿐이라 그냥 넘어간다\r\n }\r\n }\r\n // 참조를 만들 수 없는 줄이다. **직전 신 번호로 때우지 않는다** (diffLineHtml 주석)\r\n const del = row.getAttribute('data-ad-ref-del');\r\n if (del !== null) {\r\n this.setRefNote(del === 'hunk'\r\n ? '헝크 머리줄은 내용이 아니다 — 아래 줄을 고르면 그 자리를 가리킨다'\r\n : '삭제된 줄은 지금 파일에 없다 — 옆 문맥줄을 고르면 그 자리를 가리킨다');\r\n return;\r\n }\r\n const no = Number(row.getAttribute('data-ad-ref-line'));\r\n if (!Number.isFinite(no) || no <= 0) {\r\n return;\r\n }\r\n const box = row.closest('[data-ad-ref-file]');\r\n const key = (_a = box === null || box === void 0 ? void 0 : box.getAttribute('data-ad-ref-file')) !== null && _a !== void 0 ? _a : '';\r\n if (!key) {\r\n this.setRefNote('어느 파일의 줄인지 몰라 참조를 만들지 못했다');\r\n return;\r\n }\r\n // Shift 는 **직전 선택의 시작**에서 늘린다 — 12 를 고른 뒤 20 을 Shift 로 누르면 12-20,\r\n // 이어 15 를 누르면 12-15 다. 다른 파일이면 늘릴 자리가 없으니 그 줄 하나로 시작한다\r\n const prev = this.refSel;\r\n const anchor = extend && prev && prev.file === key ? prev.from : no;\r\n const from = Math.min(anchor, no);\r\n const to = Math.max(anchor, no);\r\n this.refSel = { file: key, from, to };\r\n this.applyRefSel();\r\n this.sendRef(key, from, to);\r\n }\r\n /**\r\n * 고른 줄에 `ad-ref-sel` 을 다시 붙인다. 본문을 그린 뒤마다 불린다 —\r\n * 상태는 `refSel`(클래스 필드)에 있어서 자동 갱신이 본문을 덮어도 선택이 산다.\r\n *\r\n * 경로를 CSS 선택자에 넣지 않고 값을 읽어 비교한다 — 경로에는 선택자 특수문자가\r\n * 들어올 수 있고(공백·괄호·`#`), 이스케이프를 우리가 다시 구현할 이유가 없다.\r\n */\r\n applyRefSel() {\r\n if (!this.bodyEl) {\r\n return;\r\n }\r\n for (const on of Array.from(this.bodyEl.querySelectorAll('.ad-ref-sel'))) {\r\n on.classList.remove('ad-ref-sel');\r\n }\r\n const sel = this.refSel;\r\n if (!sel) {\r\n return;\r\n }\r\n for (const box of Array.from(this.bodyEl.querySelectorAll('[data-ad-ref-file]'))) {\r\n if (box.getAttribute('data-ad-ref-file') !== sel.file) {\r\n continue;\r\n }\r\n for (const row of Array.from(box.querySelectorAll('[data-ad-ref-line]'))) {\r\n const no = Number(row.getAttribute('data-ad-ref-line'));\r\n if (Number.isFinite(no) && no >= sel.from && no <= sel.to) {\r\n row.classList.add('ad-ref-sel');\r\n }\r\n }\r\n }\r\n }\r\n /**\r\n * 참조 한 낱말을 만들어 터미널에 넣는다.\r\n *\r\n * `변경` 은 저장소 루트 기준 경로를, `파일` 은 절대경로를 상자에 심어 둔다 —\r\n * `joinRefPath` 가 이미 절대경로면 그대로 돌려주므로 두 갈래를 한 줄로 다룰 수 있다.\r\n * 그 다음 `refPathFrom` 이 **그 탭 cwd 기준**으로 줄이고, `formatLineRef` 가 번호와\r\n * 따옴표를 맡는다.\r\n */\r\n sendRef(key, from, to) {\r\n var _a, _b;\r\n const cwd = this.host.cwdFor((_a = this.activeTab) !== null && _a !== void 0 ? _a : {});\r\n const text = (0, gitDiff_1.formatLineRef)((0, gitDiff_1.refPathFrom)((0, gitDiff_1.joinRefPath)(this.diffRoot, key), cwd), from, to);\r\n if (!text) {\r\n this.setRefNote('참조를 만들지 못했다 — 경로가 비어 있다');\r\n return;\r\n }\r\n if (!this.host.sendText) {\r\n // 배선이 없어도 패널은 동작한다(ViewHost.sendText 가 optional 인 이유) — 다만\r\n // 사람이 눌렀는데 아무 일도 안 일어나면 안 되므로 사실을 문장으로 말한다\r\n this.setRefNote('터미널에 넣지 못했다 — 넣을 자리가 배선되지 않았다 · ' + text);\r\n return;\r\n }\r\n // 직전에 넣은 것이 지금 참조의 **접두**면 늘어난 꼬리만 보낸다 (`a.ts:12` → `-20`).\r\n // 그러지 않으면 프롬프트에 `a.ts:12a.ts:12-20` 이 쌓이고, 그 줄을 사람이 손으로\r\n // 지워야 한다. REF_CHAIN_MS 가 지나면 그 사이에 문장을 쳤다고 보고 처음부터 넣는다.\r\n // 공백이 든 경로는 따옴표로 감싸이므로(formatLineRef) 꼬리를 이어 붙일 수 없다 —\r\n // `\"a b.ts:12\"` 뒤에 `-20\"` 를 붙이면 따옴표가 어긋난다. 그때는 통째로 보낸다\r\n const now = Date.now();\r\n const prev = this.refLastSent;\r\n const chain = !!prev && now - prev.at < REF_CHAIN_MS\r\n && text.length > prev.text.length && text.startsWith(prev.text)\r\n && prev.text[0] !== '\"' && text[0] !== '\"';\r\n const payload = chain ? text.slice(prev.text.length) : text;\r\n let ok = false;\r\n try {\r\n ok = !!this.host.sendText(payload);\r\n }\r\n catch (err) {\r\n this.setRefNote('터미널에 넣지 못했다 · ' + String((_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err));\r\n return;\r\n }\r\n if (!ok) {\r\n // 보낼 팬이 없다(탭이 없거나 터미널이 아니다) — 넣은 것으로 기억하지 않는다.\r\n // 기억해 두면 다음 누름이 \"꼬리만\" 을 보내 프롬프트에 `-20` 만 남는다\r\n this.setRefNote('터미널에 넣지 못했다 — 넣을 터미널이 없다 · ' + text);\r\n return;\r\n }\r\n // 터미널에 지금 남아 있는 것은 (꼬리만 보냈어도) 참조 전체다\r\n this.refLastSent = { text, at: now };\r\n this.setRefNote('넣었다 · ' + text + (chain ? ' (꼬리만)' : ''), true);\r\n }\r\n /**\r\n * 참조 안내줄. 방금 일어난 일일 때만(`flash`) 강조를 얹고 REF_FLASH_MS 뒤에 뗀다 —\r\n * 계속 켜져 있으면 다음에 무엇이 새로 일어났는지 구별이 안 된다.\r\n */\r\n setRefNote(text, flash = false) {\r\n const el = this.refNoteEl;\r\n if (!el) {\r\n return;\r\n }\r\n el.textContent = text;\r\n el.title = text;\r\n el.style.display = text ? 'block' : 'none';\r\n if (this.refFlashTimer) {\r\n clearTimeout(this.refFlashTimer);\r\n this.refFlashTimer = null;\r\n }\r\n el.classList.toggle('ad-view-ref-on', !!text && flash);\r\n if (!text || !flash) {\r\n return;\r\n }\r\n this.refFlashTimer = setTimeout(() => {\r\n this.refFlashTimer = null;\r\n el.classList.remove('ad-view-ref-on');\r\n }, REF_FLASH_MS);\r\n }\r\n // ---------- 스테이지 · 커밋 ----------\r\n /**\r\n * 파일 한 줄에 붙는 스테이지 딱지.\r\n *\r\n * 글자는 **지금 상태**를, `title` 은 누르면 무엇이 되는지를 말한다 — 딱지가 동작을 가리키면\r\n * \"올림\" 이 \"올렸다\" 인지 \"올린다\" 인지 읽는 사람이 알 수 없다.\r\n * status 에 없는 경로면 **아무것도 붙이지 않는다.** 상태를 모르는 채로 누를 것을 주면\r\n * 사람이 의도하지 않은 것이 올라간다.\r\n */\r\n stageChipHtml(rel) {\r\n const entry = this.statusByPath.get(rel);\r\n if (!entry) {\r\n return '';\r\n }\r\n const act = entry.state === 'staged' ? 'reset' : 'add';\r\n let tip;\r\n if (act === 'reset') {\r\n tip = '누르면 스테이지에서 내린다 — git reset -q -- ' + rel;\r\n }\r\n else if (entry.state === 'conflict') {\r\n tip = '누르면 충돌 해결로 표시한다 — git add -- ' + rel;\r\n }\r\n else {\r\n tip = '누르면 스테이지에 올린다 — git add -- ' + rel;\r\n }\r\n return '<span class=\"ad-view-stage ad-view-stage-' + entry.state + '\"'\r\n + ' data-ad-stage=\"' + (0, markdown_1.escapeHtml)(rel) + '\" data-ad-stage-act=\"' + act + '\"'\r\n + ' title=\"' + (0, markdown_1.escapeHtml)(tip) + '\">' + (0, markdown_1.escapeHtml)((0, gitCommit_1.stageLabel)(entry.state)) + '</span>';\r\n }\r\n /**\r\n * 읽어 온 status 를 기억하고 커밋 줄의 요약·버튼 잠금을 맞춘다.\r\n * **알림 문장(note)은 건드리지 않는다** — 자동 갱신이 1.5초마다 도는데 여기서 note 를 쓰면\r\n * 방금 한 조작의 결과(\"커밋했다\" 등)가 곧바로 지워진다.\r\n */\r\n setStatus(entries) {\r\n this.statusEntries = entries;\r\n this.statusByPath = new Map();\r\n for (const e of entries) {\r\n this.statusByPath.set(e.path, e);\r\n }\r\n if (this.commitSumEl) {\r\n this.commitSumEl.textContent = (0, gitCommit_1.formatStageSummary)(entries);\r\n }\r\n this.syncCommitButton();\r\n }\r\n /** 버튼의 잠금·라벨을 상태에서 다시 계산한다 (상태를 바꾸는 곳마다 이걸 부른다) */\r\n syncCommitButton() {\r\n var _a, _b;\r\n const btn = this.commitBtn;\r\n if (!btn) {\r\n return;\r\n }\r\n // **메시지가 비면 아예 못 누른다** — 우발 커밋을 막는 첫 잠금이다 (둘째는 확인 대기,\r\n // 셋째는 gitCommit.commitArgs 가 빈 배열을 내는 것)\r\n btn.disabled = !(0, gitCommit_1.validateMessage)((_b = (_a = this.commitInput) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '').ok || this.gitBusy;\r\n btn.textContent = this.commitArmed ? '커밋 확인' : '커밋';\r\n btn.classList.toggle('ad-view-commit-armed', this.commitArmed);\r\n btn.title = this.commitArmed\r\n ? '한 번 더 누르면 실제로 커밋한다 (Esc 취소)'\r\n : '메시지를 넣고 두 번 눌러야 커밋된다 — git commit -m';\r\n }\r\n setCommitNote(text) {\r\n if (this.commitNoteEl) {\r\n this.commitNoteEl.textContent = text;\r\n this.commitNoteEl.title = text;\r\n }\r\n }\r\n disarmCommit() {\r\n this.commitArmed = false;\r\n this.syncCommitButton();\r\n }\r\n /**\r\n * 스테이지 토글. **사람이 딱지를 누른 경로에서만 불린다** — 자동 갱신(viewerFollow·파일 감시·\r\n * maybeAutoDiff)은 이 함수를 부르지 않는다.\r\n *\r\n * git 은 **저장소 루트**에서 돌린다. status/diff 가 내는 경로가 루트 기준이라 탭 cwd 에서\r\n * 돌리면 하위 폴더에서 \"pathspec 이 없다\" 가 된다 (absOf 와 같은 사정).\r\n */\r\n async toggleStage(rel, act) {\r\n var _a, _b, _c;\r\n if (!rel || this.gitBusy) {\r\n return;\r\n }\r\n const dir = (_a = this.diffRoot) !== null && _a !== void 0 ? _a : this.host.cwdFor((_b = this.activeTab) !== null && _b !== void 0 ? _b : {});\r\n if (!dir) {\r\n this.setCommitNote('작업 폴더를 몰라 스테이지를 바꾸지 못한다');\r\n return;\r\n }\r\n const args = act === 'add' ? (0, gitCommit_1.stageArgs)([rel]) : (0, gitCommit_1.unstageArgs)([rel]);\r\n if (!args.length) {\r\n return;\r\n }\r\n this.gitBusy = true;\r\n this.disarmCommit();\r\n try {\r\n let r = await this.runGit(dir, args);\r\n if (!r.ok && act === 'reset'\r\n && /ambiguous argument .?HEAD|unknown revision|bad revision|HEAD/i.test(r.err)) {\r\n // 커밋이 0개인 저장소 — reset 이 HEAD 를 못 푼다 (`변경` 탭이 `diff HEAD` 대신\r\n // `diff` 로 폴백해야 하는 것과 같은 사정). index 에서만 뺀다\r\n r = await this.runGit(dir, (0, gitCommit_1.unstageFallbackArgs)([rel]));\r\n }\r\n this.setCommitNote(r.ok\r\n ? (act === 'add' ? '스테이지에 올렸다 · ' : '스테이지에서 내렸다 · ') + rel\r\n : '스테이지를 바꾸지 못했다 · ' + (firstLine(r.err) || firstLine(r.out)));\r\n }\r\n catch (err) {\r\n // 예외로 죽지 않는다 — 실패도 문장으로 끝난다 (runGit 과 같은 규칙)\r\n this.setCommitNote('스테이지를 바꾸지 못했다 · ' + String((_c = err === null || err === void 0 ? void 0 : err.message) !== null && _c !== void 0 ? _c : err));\r\n }\r\n finally {\r\n this.gitBusy = false;\r\n this.syncCommitButton();\r\n }\r\n this.refreshDiff();\r\n }\r\n /**\r\n * 커밋 버튼 / 입력창 Enter. **두 번 눌러야 커밋된다** — 첫 누름은 확인 대기(arm),\r\n * 두 번째 누름이 실행이다. 검증에 걸리면 첫 누름에서 이유만 말하고 끝난다.\r\n */\r\n pressCommit() {\r\n var _a, _b, _c;\r\n if (this.gitBusy) {\r\n return;\r\n }\r\n const msg = (_b = (_a = this.commitInput) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';\r\n const v = (0, gitCommit_1.validateMessage)(msg);\r\n if (!v.ok) {\r\n this.disarmCommit();\r\n this.setCommitNote((_c = v.reason) !== null && _c !== void 0 ? _c : '커밋 메시지를 확인해야 한다');\r\n return;\r\n }\r\n if (!(0, gitCommit_1.hasStaged)(this.statusEntries)) {\r\n // git 도 거절하지만 이유를 여기서 먼저 말한다 — \"커밋했다\" 를 기다리다 실패 문장을\r\n // 보는 것보다, 무엇을 해야 하는지(딱지를 눌러 올려라)를 듣는 것이 낫다\r\n this.disarmCommit();\r\n this.setCommitNote('스테이지에 올린 것이 없다 — 파일 목록의 딱지를 눌러 올려라');\r\n return;\r\n }\r\n if (!this.commitArmed) {\r\n this.commitArmed = true;\r\n this.syncCommitButton();\r\n this.setCommitNote('다시 누르면 커밋한다 (Esc 취소) · ' + (0, gitCommit_1.formatStageSummary)(this.statusEntries));\r\n return;\r\n }\r\n this.runCommit(msg);\r\n }\r\n /** 실제 커밋. pressCommit 의 확인 단계를 지난 뒤에만 불린다 */\r\n async runCommit(msg) {\r\n var _a, _b, _c;\r\n const args = (0, gitCommit_1.commitArgs)(msg);\r\n if (!args.length) {\r\n // 세 번째 잠금 — 여기까지 잘못 들어와도 인자가 없어 커밋이 만들어지지 않는다\r\n this.disarmCommit();\r\n this.setCommitNote('커밋 메시지를 확인해야 한다');\r\n return;\r\n }\r\n const dir = (_a = this.diffRoot) !== null && _a !== void 0 ? _a : this.host.cwdFor((_b = this.activeTab) !== null && _b !== void 0 ? _b : {});\r\n if (!dir) {\r\n this.disarmCommit();\r\n this.setCommitNote('작업 폴더를 몰라 커밋하지 못한다');\r\n return;\r\n }\r\n this.gitBusy = true;\r\n this.syncCommitButton();\r\n try {\r\n const r = await this.runGit(dir, args);\r\n if (r.ok) {\r\n // 성공하면 입력창을 비운다 — 같은 메시지가 남아 있으면 두 번 커밋되는 사고가 난다\r\n if (this.commitInput) {\r\n this.commitInput.value = '';\r\n }\r\n this.setCommitNote('커밋했다 · ' + (firstLine(r.out) || firstLine(r.err)));\r\n }\r\n else {\r\n // 훅 거부·user.name 없음·스테이지 비었음 — git 은 이유를 stdout 에 쓰는 경우가 있다\r\n this.setCommitNote('커밋하지 못했다 · ' + (firstLine(r.err) || firstLine(r.out)));\r\n }\r\n }\r\n catch (err) {\r\n this.setCommitNote('커밋하지 못했다 · ' + String((_c = err === null || err === void 0 ? void 0 : err.message) !== null && _c !== void 0 ? _c : err));\r\n }\r\n finally {\r\n this.gitBusy = false;\r\n this.commitArmed = false;\r\n this.syncCommitButton();\r\n }\r\n this.refreshDiff();\r\n }\r\n dispose() {\r\n var _a;\r\n this.unwatch();\r\n // 안내줄 강조 타이머는 DOM 이 사라진 뒤에 깨어난다 — 남겨 두면 지운 노드를 건드린다\r\n if (this.refFlashTimer) {\r\n clearTimeout(this.refFlashTimer);\r\n this.refFlashTimer = null;\r\n }\r\n (_a = this.el) === null || _a === void 0 ? void 0 : _a.remove();\r\n this.el = null;\r\n this.refNoteEl = null;\r\n }\r\n}\r\nexports.ViewPanel = ViewPanel;\r\n","\"use strict\";\r\n/**\r\n * 미리보기 패널의 순수 로직 — 파일 종류 판정, PTY 출력에서 경로 줍기, 최근 목록 관리.\r\n *\r\n * DOM 도 fs 도 건드리지 않는다. 이 파일만 테스트로 묶어 두고(test/viewer.test.js),\r\n * 화면·파일 접근은 viewPanel.ts 가 맡는다 — dock.ts / deck.service.ts 를 가른 것과 같은 방식이다.\r\n *\r\n * **왜 에이전트 훅이 아니라 화면 출력에서 경로를 줍나 —** 훅이 있는 것은 Claude Code 뿐이다\r\n * (src/claudeHooks.ts). Codex·Gemini 도 같은 패널을 쓰게 하려면 셋이 공통으로 하는 일에\r\n * 기대야 하고, 그건 \"만진 파일 경로를 화면에 찍는다\" 다. 그래서 이 경로가 기본이고\r\n * 훅은 나중에 정확도를 더하는 보강일 뿐이다.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.planFollow = exports.migrateFollow = exports.followModeOf = exports.formatBytes = exports.delimiterFor = exports.parseDelimited = exports.pushRecent = exports.isAutoFollowable = exports.extractPaths = exports.stripAnsi = exports.isKnownExt = exports.classify = exports.extensionOf = void 0;\r\n/** 확장자로 판정한다 — 내용을 열어 보는 것은 패널이 하는 일이고 여기서는 분류만 한다 */\r\nconst IMAGE_EXT = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'svg', 'ico', 'avif'];\r\nconst MARKDOWN_EXT = ['md', 'markdown', 'mdx'];\r\nconst TABLE_EXT = ['csv', 'tsv'];\r\n/** 글자로 열어도 되는 것 — 여기 없는 확장자는 열지 않고 크기만 알려준다 */\r\nconst TEXT_EXT = [\r\n 'txt', 'log', 'json', 'jsonc', 'yml', 'yaml', 'toml', 'ini', 'cfg', 'conf', 'env',\r\n 'ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'cs', 'py', 'rb', 'go', 'rs', 'java', 'kt',\r\n 'c', 'h', 'cpp', 'hpp', 'cc', 'php', 'lua', 'sql', 'sh', 'bash', 'zsh', 'ps1', 'psm1',\r\n 'bat', 'cmd', 'html', 'htm', 'xml', 'svelte', 'vue', 'css', 'scss', 'sass', 'less',\r\n 'diff', 'patch', 'gitignore', 'editorconfig', 'dockerfile', 'makefile', 'gradle', 'proto',\r\n];\r\n/** 최근 목록에 올릴 만한 확장자 — 위 목록 전부 + 눌러서 열 수 있는 것들 */\r\nconst KNOWN_EXT = new Set([...IMAGE_EXT, ...MARKDOWN_EXT, ...TABLE_EXT, ...TEXT_EXT]);\r\nfunction extensionOf(file) {\r\n var _a;\r\n const base = (_a = String(file !== null && file !== void 0 ? file : '').replace(/[\\\\/]+$/, '').split(/[\\\\/]/).pop()) !== null && _a !== void 0 ? _a : '';\r\n const dot = base.lastIndexOf('.');\r\n if (dot <= 0) {\r\n // 확장자가 없는 관용 파일들 (Dockerfile, Makefile …)\r\n return base.toLowerCase();\r\n }\r\n return base.slice(dot + 1).toLowerCase();\r\n}\r\nexports.extensionOf = extensionOf;\r\nfunction classify(file) {\r\n const ext = extensionOf(file);\r\n if (IMAGE_EXT.includes(ext)) {\r\n return 'image';\r\n }\r\n if (MARKDOWN_EXT.includes(ext)) {\r\n return 'markdown';\r\n }\r\n if (TABLE_EXT.includes(ext)) {\r\n return 'table';\r\n }\r\n if (TEXT_EXT.includes(ext)) {\r\n return 'text';\r\n }\r\n return 'binary';\r\n}\r\nexports.classify = classify;\r\n/** 미리보기로 열어 볼 가치가 있는 확장자인가 — PTY 에서 주운 경로를 거르는 데 쓴다 */\r\nfunction isKnownExt(file) {\r\n return KNOWN_EXT.has(extensionOf(file));\r\n}\r\nexports.isKnownExt = isKnownExt;\r\n/**\r\n * ANSI 제어 시퀀스와 TUI 가 그리는 테두리 문자를 걷어낸다.\r\n *\r\n * 경로를 주우려면 필요하다 — 에이전트 TUI 는 `│ Edited src/a.ts │` 처럼 테두리 안에 글자를\r\n * 그리고, 색을 붙이려고 경로 중간에 SGR 을 끼워 넣기도 한다.\r\n */\r\nfunction stripAnsi(data) {\r\n return String(data !== null && data !== void 0 ? data : '')\r\n // CSI (색·커서 이동 등) / OSC (제목 등) / 단독 ESC 시퀀스\r\n .replace(/\\x1b\\[[0-9;?]*[ -/]*[@-~]/g, '')\r\n .replace(/\\x1b\\][^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)/g, '')\r\n .replace(/\\x1b[@-Z\\\\-_]/g, '')\r\n .replace(/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/g, '')\r\n // 박스 드로잉·블록 문자는 공백으로 (경로에 붙어 있으면 토큰이 깨진다)\r\n .replace(/[\\u2500-\\u257f\\u2580-\\u259f]/g, ' ');\r\n}\r\nexports.stripAnsi = stripAnsi;\r\n/**\r\n * 경로처럼 보이는 토큰.\r\n *\r\n * 세 갈래를 본다 — Windows 절대경로(`D:\\a\\b.md`), POSIX 절대/상대경로(`/a/b.md`, `src/a.ts`),\r\n * 그리고 구분자 없는 파일명(`hero.tsx`). 마지막 갈래가 필요한 이유는 에이전트가 `Edited hero.tsx`\r\n * 처럼 파일명만 찍는 경우가 많아서다 (스크린샷의 Codex 도 그렇다).\r\n */\r\n/**\r\n * 경로 글자에 `À-` 를 넣는 이유 — 한글 파일명(`docs/소개.md`)을 놓치지 않기 위해서다.\r\n * `\\w` 는 u 플래그 없이는 ASCII 만 본다. 대신 그 범위에 딸려 오는 기호(`…`, `→`, 전각 괄호)는\r\n * 아래 PUNCT 로 걸러낸다.\r\n */\r\nconst PATH_CHAR = '[\\\\w\\\\u00c0-\\\\uffff.@+~-]';\r\nconst PATH_RE = new RegExp('(?:[A-Za-z]:[\\\\\\\\/]|\\\\.{0,2}[\\\\\\\\/])?'\r\n + '(?:' + PATH_CHAR + '+[\\\\\\\\/])*' + PATH_CHAR + '+\\\\.[A-Za-z0-9]{1,8}', 'g');\r\n/** 경로에 들어갈 수 없는 기호 — 하나라도 있으면 경로가 아니다 (잘림 표시 `…`, 화살표, 전각 문자) */\r\nconst PUNCT = /[\\u2000-\\u206f\\u2190-\\u2bff\\u3000-\\u303f\\uff00-\\uffef]/;\r\n/** 경로 뒤에 붙어 오는 문장부호 — 잘라낸다 */\r\nconst TRAILING = /[),.;:'\"`\\]}]+$/;\r\n/**\r\n * 출력 한 조각에서 파일 경로 후보를 뽑는다.\r\n *\r\n * 여기서는 **후보까지만** 낸다 — 실제로 있는 파일인지, 상대경로를 어느 cwd 로 푸는지는\r\n * 패널이 fs 로 확인한다. 순수 함수로 남겨 두면 규칙을 테스트로 고정할 수 있다.\r\n *\r\n * 걸러내는 것: 확장자를 모르는 것 / 잘려서 `…` 이 들어간 것 / URL / 버전 번호처럼 보이는 것.\r\n */\r\nfunction extractPaths(data) {\r\n var _a;\r\n const clean = stripAnsi(data);\r\n const out = [];\r\n const seen = new Set();\r\n let m;\r\n PATH_RE.lastIndex = 0;\r\n while ((m = PATH_RE.exec(clean)) !== null) {\r\n let token = m[0].replace(TRAILING, '');\r\n if (!token || PUNCT.test(token)) {\r\n continue;\r\n }\r\n // URL 의 일부(`example.com/a.png`)는 로컬 파일이 아니다\r\n const before = clean.slice(Math.max(0, m.index - 3), m.index);\r\n if (/:\\/\\/?$/.test(before) || /^https?$/i.test((_a = token.split(/[\\\\/]/)[0]) !== null && _a !== void 0 ? _a : '')) {\r\n continue;\r\n }\r\n if (!isKnownExt(token)) {\r\n continue;\r\n }\r\n // `1.2.3` / `v0.3.0` 같은 버전 문자열이 확장자 규칙에 걸리는 것을 막는다\r\n if (/^[vV]?[\\d.]+$/.test(token)) {\r\n continue;\r\n }\r\n token = token.replace(/^\\.[\\\\/]/, '');\r\n if (!seen.has(token)) {\r\n seen.add(token);\r\n out.push(token);\r\n }\r\n }\r\n return out;\r\n}\r\nexports.extractPaths = extractPaths;\r\n/**\r\n * 자동으로 **띄우지는 않을** 파일 — 에이전트·에디터의 설정 파일들.\r\n *\r\n * 왜 거르나 — 에이전트는 기동할 때 자기 설정 파일 경로를 화면에 찍는 일이 잦다(훅 경고, 권한\r\n * 안내 등). 그러면 세션을 열자마자 미리보기가 `settings.json` 으로 갈린다. 사람이 그때 보려던\r\n * 것은 방금 만든 작업 파일이지 설정이 아니다 (2026-09-11 유저 지적: \"무조건 열어줄 이유는 없어\").\r\n *\r\n * **목록(칩)에서는 빼지 않는다.** 설정 파일을 진짜로 손볼 때는 칩을 눌러 열면 되고, 그때는\r\n * 사람이 명시로 고른 것이라 이 규칙과 어긋나지 않는다. 거르는 것은 \"스스로 띄우기\"뿐이다.\r\n *\r\n * 이름만 보는 이유 — 같은 파일이 `~/.claude/`, 프로젝트 `.claude/`, `.vscode/` 어디에나 있고\r\n * 폴더까지 조건에 넣으면 한 곳이 늘 빠진다. 반대로 이름이 이 꼴인 **작업 대상** 파일을 자동으로\r\n * 안 띄우는 손해는 칩 한 번 누르는 것으로 끝난다.\r\n */\r\nconst AUTO_FOLLOW_SKIP_RE = /^(?:\\.?claude\\.json|settings(?:\\.[\\w-]+)?\\.json)$/i;\r\n/**\r\n * 이 파일을 **스스로 띄워도 되는가** (`false` = 칩에만 쌓고 화면은 그대로 둔다).\r\n */\r\nfunction isAutoFollowable(file) {\r\n var _a;\r\n const base = (_a = String(file !== null && file !== void 0 ? file : '').replace(/[\\\\/]+$/, '').split(/[\\\\/]/).pop()) !== null && _a !== void 0 ? _a : '';\r\n return !!base && !AUTO_FOLLOW_SKIP_RE.test(base);\r\n}\r\nexports.isAutoFollowable = isAutoFollowable;\r\n/**\r\n * 최근 목록에 하나를 얹는다 (같은 것은 위로 올리고, 최대 개수를 넘으면 뒤를 버린다).\r\n * 원본을 바꾸지 않고 새 배열을 돌려준다 — 렌더가 이전 배열과 비교할 수 있어야 한다.\r\n */\r\nfunction pushRecent(list, file, max) {\r\n const next = [file, ...list.filter(f => f !== file)];\r\n return next.slice(0, Math.max(1, max));\r\n}\r\nexports.pushRecent = pushRecent;\r\n/**\r\n * CSV/TSV 한 장을 표로 가른다.\r\n *\r\n * 따옴표로 감싼 칸(`\"a,b\"`)과 그 안의 이스케이프(`\"\"`)까지만 본다 — 기획데이터를 편집하는\r\n * 도구가 아니라 눈으로 확인하는 미리보기라서 그 이상은 필요하지 않다.\r\n */\r\nfunction parseDelimited(text, delimiter = ',') {\r\n const rows = [];\r\n let row = [];\r\n let cell = '';\r\n let quoted = false;\r\n const src = String(text !== null && text !== void 0 ? text : '').replace(/\\r\\n?/g, '\\n');\r\n for (let i = 0; i < src.length; i++) {\r\n const ch = src[i];\r\n if (quoted) {\r\n if (ch === '\"') {\r\n if (src[i + 1] === '\"') {\r\n cell += '\"';\r\n i++;\r\n }\r\n else {\r\n quoted = false;\r\n }\r\n }\r\n else {\r\n cell += ch;\r\n }\r\n continue;\r\n }\r\n if (ch === '\"') {\r\n quoted = true;\r\n }\r\n else if (ch === delimiter) {\r\n row.push(cell);\r\n cell = '';\r\n }\r\n else if (ch === '\\n') {\r\n row.push(cell);\r\n rows.push(row);\r\n row = [];\r\n cell = '';\r\n }\r\n else {\r\n cell += ch;\r\n }\r\n }\r\n if (cell || row.length) {\r\n row.push(cell);\r\n rows.push(row);\r\n }\r\n return rows;\r\n}\r\nexports.parseDelimited = parseDelimited;\r\n/** 확장자로 구분자를 고른다 */\r\nfunction delimiterFor(file) {\r\n return extensionOf(file) === 'tsv' ? '\\t' : ',';\r\n}\r\nexports.delimiterFor = delimiterFor;\r\nfunction formatBytes(bytes) {\r\n const n = Number(bytes);\r\n if (!isFinite(n) || n < 0) {\r\n return '?';\r\n }\r\n if (n < 1024) {\r\n return n + ' B';\r\n }\r\n if (n < 1024 * 1024) {\r\n return (n / 1024).toFixed(1) + ' KB';\r\n }\r\n return (n / 1024 / 1024).toFixed(1) + ' MB';\r\n}\r\nexports.formatBytes = formatBytes;\r\nconst FOLLOW_MODES = ['open', 'show', 'manual'];\r\n/**\r\n * 토글 두 개를 모드로 접는다.\r\n *\r\n * - 읽어두기 끔 → `manual` (자동으로 열기는 의미가 없어진다)\r\n * - 읽어두기 + 자동으로 열기 → `open`\r\n * - 읽어두기만 → `show` (기본)\r\n *\r\n * 두 축으로 가른 이유 — 목록 하나로는 \"내용을 채워 둘까\" 와 \"화면을 빼앗아도 될까\" 를 한 번에\r\n * 골라야 했다. 사람이 실제로 정하고 싶은 것은 그 둘이 따로다 (2026-09-10 유저 결정:\r\n * \"읽어두기는 켜고, 자동으로 열기는 꺼라 — 내가 열면 그때까지 만진 게 보이면 된다\").\r\n */\r\nfunction followModeOf(preload, autoOpen) {\r\n if (preload === false) {\r\n return 'manual';\r\n }\r\n return autoOpen === true ? 'open' : 'show';\r\n}\r\nexports.followModeOf = followModeOf;\r\n/**\r\n * 옛 설정을 토글 두 개로 옮긴다 — 기동 때 **한 번만** 돈다 (`migrateFollowConfig`).\r\n *\r\n * 고른 적이 없으면 `null` 을 주고, 그러면 새 기본값(읽어두기 ON / 자동열기 OFF)이 그대로 쓰인다.\r\n * 읽는 시점에 옛 값을 보는 방식(0.17.0 의 `followMode(raw, legacy)`)을 버린 이유는, 토글은\r\n * boolean 이라 \"아직 안 골랐다\" 를 표현할 자리가 없어서다 — 빈 값을 두면 토글이 꺼져 보이는데\r\n * 실제 동작은 켜져 있는 상태가 된다. 그래서 한 번 적고 옛 값을 비운다.\r\n */\r\nfunction migrateFollow(raw, legacy) {\r\n const chosen = typeof raw === 'string' && FOLLOW_MODES.includes(raw)\r\n ? raw\r\n : legacy === false ? 'manual' : null;\r\n if (!chosen) {\r\n return null;\r\n }\r\n return { preload: chosen !== 'manual', autoOpen: chosen === 'open' };\r\n}\r\nexports.migrateFollow = migrateFollow;\r\n/**\r\n * 새 파일을 주웠다 — 지금 무엇을 할까.\r\n *\r\n * - `none` : 아무것도 하지 않는다 (칩만 쌓인다)\r\n * - `show` : 이미 열려 있으니 그 자리에 띄운다\r\n * - `open` : 닫혀 있으니 열면서 띄운다\r\n * - `stage` : 닫혀 있다 — 그리지 않고 **대상만 갈아 둔다.** 사람이 여는 순간 이 파일이 보인다\r\n *\r\n * `stage` 를 둔 이유 — 예전에는 이 자리가 `none` 이라, 닫아 두고 일하다 패널을 열면 **아까\r\n * 보던 옛 파일**이 떠 있었다(`lastViewed` 가 그때 멈춰 있었다). \"작업 막 진행하다가 패널을\r\n * 열면 지금까지 건드린 것이 보여야 한다\" 가 이 패널의 요점이므로, 열지는 않되 읽어는 둔다.\r\n *\r\n * **편집 중에는 무조건 `none`** 이다 — 자동으로 화면을 바꾸면 사람이 치던 것을 밀어낸다.\r\n * 모드보다 이 규칙이 앞선다.\r\n */\r\nfunction planFollow(mode, opened, editing) {\r\n if (editing || mode === 'manual') {\r\n return 'none';\r\n }\r\n if (opened) {\r\n return 'show';\r\n }\r\n return mode === 'open' ? 'open' : 'stage';\r\n}\r\nexports.planFollow = planFollow;\r\n","module.exports = require(\"child_process\");","module.exports = require(\"electron\");","module.exports = require(\"fs\");","module.exports = require(\"http\");","module.exports = require(\"https\");","module.exports = require(\"net\");","module.exports = require(\"os\");","module.exports = require(\"path\");","module.exports = require(\"string_decoder\");","module.exports = __WEBPACK_EXTERNAL_MODULE__4358__;","module.exports = __WEBPACK_EXTERNAL_MODULE__860__;","module.exports = __WEBPACK_EXTERNAL_MODULE__7182__;","module.exports = __WEBPACK_EXTERNAL_MODULE__3961__;","module.exports = __WEBPACK_EXTERNAL_MODULE__7650__;","module.exports = __WEBPACK_EXTERNAL_MODULE__3700__;","module.exports = __WEBPACK_EXTERNAL_MODULE__8349__;","// The module cache\nconst __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tconst cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tconst module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tconst getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// wrap a concatenated module body as a lazy, memoized accessor; mod is\n// set before the body runs so re-entrant calls (require cycles) observe\n// the partial exports like Node.js\n__webpack_require__.cw = (body) => {\n\tvar mod;\n\treturn () => {\n\t\tif (body) {\n\t\t\tvar fn = body;\n\t\t\tbody = 0;\n\t\t\tmod = { exports: {} };\n\t\t\tfn.call(mod.exports, mod, mod.exports);\n\t\t}\n\t\treturn mod.exports;\n\t};\n};","// define getter/value functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tif(Array.isArray(definition)) {\n\t\tvar i = 0;\n\t\twhile(i < definition.length) {\n\t\t\tvar key = definition[i++];\n\t\t\tvar binding = definition[i++];\n\t\t\tvar descriptor = binding === 0 ? { enumerable: true, value: definition[i++] } : { enumerable: true, get: binding };\n\t\t\tif(!__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, descriptor);\n\t\t}\n\t} else {\n\t\tfor(var key in definition) {\n\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t\t}\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop));","__webpack_require__.nc = undefined;","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nlet __webpack_exports__ = __webpack_require__(8156);\n"],"names":["root","factory","exports","module","require","define","amd","a","i","global","__WEBPACK_EXTERNAL_MODULE__4358__","__WEBPACK_EXTERNAL_MODULE__860__","__WEBPACK_EXTERNAL_MODULE__7182__","__WEBPACK_EXTERNAL_MODULE__3961__","__WEBPACK_EXTERNAL_MODULE__7650__","__WEBPACK_EXTERNAL_MODULE__3700__","__WEBPACK_EXTERNAL_MODULE__8349__","___CSS_LOADER_EXPORT___","_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default","_node_modules_css_loader_dist_runtime_sourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default","push","id","version","sources","names","mappings","sourcesContent","sourceRoot","__WEBPACK_DEFAULT_EXPORT__","cssWithMappingToString","list","toString","this","map","item","content","needLayer","concat","length","join","modules","media","dedupe","supports","layer","undefined","alreadyImportedModules","k","_k","cssMapping","btoa","base64","unescape","encodeURIComponent","JSON","stringify","data","sourceMapping","stylesInDOM","getIndexByIdentifier","identifier","result","modulesToDom","options","idCountMap","identifiers","base","count","indexByIdentifier","obj","css","sourceMap","references","updater","addElementStyle","byIndex","splice","api","domAPI","update","newObj","remove","lastIdentifiers","newList","index","newLastIdentifiers","_i","_index","memo","insert","style","target","styleTarget","document","querySelector","window","HTMLIFrameElement","contentDocument","head","e","getTarget","Error","appendChild","element","createElement","setAttributes","attributes","styleElement","nonce","__webpack_require__","nc","setAttribute","insertStyleElement","styleTagTransform","apply","parentNode","removeChild","removeStyleElement","styleSheet","cssText","firstChild","createTextNode","styles_options","styleTagTransform_default","setAttributesWithoutAttributes_default","insertBySelector_default","styleDomAPI_default","insertStyleElement_default","injectStylesIntoStyleTag_default","styles","A","locals","identifyAgent","detectProfileFor","profileFor","unionProfile","d","AGENT_PROFILES","CONFIRM_YN","CONFIRM_YN_CAP","PRESS_ENTER","CTRL_C_INTERRUPT","GENERIC_PROMPT_HEADS","CLAUDE","label","processHints","titleHints","waitingPatterns","busyPatterns","limitedPatterns","busyTitleMarks","imagePasteKey","promptHeads","patternsProven","CODEX","GEMINI","promptShape","ruleChars","screenShape","MATCH_ORDER","dedupeRe","seen","Set","out","re","key","source","flags","has","add","dedupeStr","_a","find","p","flatMap","profile","union","processNames","title","procs","toLowerCase","some","h","includes","t","__decorate","decorators","desc","c","arguments","r","Object","getOwnPropertyDescriptor","Reflect","decorate","defineProperty","__metadata","v","metadata","value","AgentDeckAlertService","core_1","tabby_core_1","status_service_1","api_1","diag_1","ALERT_STATUSES","constructor","app","config","zone","status","last","WeakMap","flashing","badgeShown","badgeCache","Map","debug","flashes","badgeCount","badgeDraws","toasts","transitions","lastFocused","forceUnfocused","init","ready$","subscribe","setup","diag","message","tab","tabs","set","get","changed$","onChanged","tabClosed$","delete","updateBadge","countAlerting","addEventListener","stopFlash","g","__agentdeck","alert","entered","now","prev","focused","isFocused","store","agentDeck","alertFlash","flash","alertToast","toast","n","win","_b","_c","_d","req","globalThis","getCurrentWindow","call","nativeImage","hasFocus","flashFrame","want","alertBadge","setOverlayIcon","img","badgeImage","color","STATUS_STYLES","error","waiting","cached","text","String","createEmpty","addRepresentation","scaleFactor","width","height","dataURL","drawBadge","isEmpty","createFromDataURL","size","canvas","ctx","getContext","clearRect","beginPath","arc","Math","PI","fillStyle","fill","lineWidth","max","strokeStyle","stroke","font","round","textAlign","textBaseline","fillText","toDataURL","Notification","s","name","body","tag","tabKey","onclick","show","focus","run","selectTab","close","indexOf","line","Injectable","providedIn","AppService","ConfigService","NgZone","WorkStatusService","running","icon","limited","done","idle","pickTabByPids","pids","tabPids","wanted","filter","Number","isInteger","anyInfo","values","mode","__createBinding","create","o","m","k2","__esModule","writable","configurable","enumerable","__setModuleDefault","__importStar","mod","prototype","hasOwnProperty","uninstallHooks","installHooks","hooksInstalled","stripHooks","mergeHooks","isMerged","hooksSupported","notifyScriptPath","claudeSettingsPath","fs","os","path","MARK","PLAN","event","args","homedir","__dirname","readSettings","raw","readFileSync","trim","parse","withoutOurs","entries","Array","isArray","settings","hooks","every","script","next","command","matcher","type","timeout","kept","writeSettings","file","mkdirSync","dirname","recursive","existsSync","copyFileSync","writeFileSync","process","platform","setCodexHooks","codexHooksInstalled","mergeCodexHooks","stripCodexHooks","codexHooksPath","CODEX_EVENTS","env","CODEX_HOME","ours","handler","keys","group","readCodexHooks","replace","enabled","current","Date","isCodexTranscript","lines","test","slice","installCodexWheel","frontend","send","x","xterm","__adCodexWheel","opening","queued","b","buffer","active","from","rows","_","getLine","baseY","translateToString","navigate","amount","repeat","min","abs","ctrlKey","altKey","shiftKey","metaKey","deltaY","deltaX","screen","transcript","contentEnd","reduce","end","composer","preventDefault","stopImmediatePropagation","sign","ceil","deltaMode","attempts","check","setTimeout","capture","passive","AgentDeckConfigProvider","LAYOUT_DEFAULTS","sidebarDock","sidebarWidth","sidebarHeight","viewerDock","viewerWidth","ConfigProvider","super","defaults","aspectW","aspectH","sidebarMin","sidebarMax","viewerOpen","viewerScrape","viewerPreload","viewerAutoOpen","viewerFollowMode","viewerFollow","viewerDropOpen","viewerRecentMax","notifyPort","notifyChannel","hookPromptDismissed","noTabRecovery","autoUpdate","updateCheckIntervalHours","lastUpdateCheck","updateRegistry","idleAfterMs","autoDetect","showElapsed","subagentCount","sortByStatus","searchBox","keyboardNav","keyboardNavWrap","keyboardCloseTab","dragAutoScroll","collapsedGroups","resumeList","resumeListLimit","resumeListDays","resumeExpanded","resumeHidden","keepRenderingWhenHidden","enterAsLabel","claimCtrlV","claimShiftEnter","releaseHomeEnd","imeOrderGuard","pasteImageWithCtrlV","claimRightClick","rightClickMenuMs","terminalOpacity","sidebarOpacity","clipBackgroundToTerminal","autoRepairScreen","screenWatch","autoRepairCooldownMs","autoRepairMinStreak","autoRepairMaxPerTab","repairHard","repairSendRedrawKey","rootProfile","rootProfileName","rootProfileCwd","rootProfileCommand","rootProfileArgs","rootProfileEnv","TERM","COLORTERM","FORCE_COLOR","rootProfileClaimed","hotkeys","installCursorVisibilityFix","synchronizedOutput_1","CursorVisibilityStream","pending","corrections","write","input","marker","endsWith","_match","onCorrection","__adCursorVisibilityFix","original","bind","stream","frames","SynchronizedOutputStream","timer","before","output","clearTimeout","tail","flush","Promise","resolve","catch","AgentDeckService","matchesSearchTokens","searchTokens","foldSearchText","terminalInput_1","cursorVisibility_1","screenAgent_1","codexWheel_1","tabby_settings_1","notify_service_1","detect_1","agents_1","prompt_1","screen_1","ime_1","dock_1","order_1","group_1","project_root_1","nav_1","sessionLedger_service_1","sessionLedger_1","viewPanel_1","viewer_1","SIDEBAR_ID","BG_CLIP_CLASS","MIN_TERM_W","PTY_RESIZE_RETRY_MS","TAB_OPEN_ANNOUNCE_MS","cachedClipboard","clampPct","isFinite","normalize","query","split","fields","tokens","folded","f","profiles","hostWindow","notify","ledger","sidebar","listEl","windowEl","mainEl","observer","editing","drag","dragClickGuard","lastDragEnd","dropReject","searchEl","searchQuery","statusFilter","searchComposing","navFocus","renderQueued","shiftDownAt","renderTimer","lastTermW","lastSidebarW","lastDock","dock","refitQueued","view","lastViewW","lastViewSide","cwdCache","resumeTabs","outputHits","tabAgents","paneAgents","agentProbedAt","watched","WeakSet","watchedPanes","screenCheckTimers","emptyTabRetries","screenObs","autoRepairAt","autoRepairCount","autoRepairHealthySince","rightDownAt","lastRightHandledAt","nativePasteAt","lastPasteAt","pasteProbeUntil","runOutsideAngular","_e","startDiagSession","tabby","getAppVersion","osRelease","getOSRelease","diagConfig","installErrorCapture","onChange","scheduleRender","diagOnce","configStamp","console","warn","migrateFollowConfig","buildSidebar","buildView","applyEnabled","applyOpacity","disableBackgroundThrottling","ensurePasteHotkey","ensureNewlineHotkey","releaseHomeEndHotkey","guardHomeEndComposition","claimCtrlVKey","claimCtrlWKey","claimShiftEnterKey","claimEnterLabel","claimFileDrop","tabsChanged$","watchTab","activeTabChange$","setActiveTab","activeTab","scheduleRefit","tabOpened$","sweep","applySearchBox","setOpen","relayout","setInterval","sweepScreens","ResizeObserver","observe","hotkey$","hotkey","save","sendNewline","doPaste","repair","toggle","toggleKeyboardNav","toggleMode","tick","render","assign","setFilter","syncSearchUi","scope","reorder","to","place","ok","reason","order","applyReorder","lastDrag","flowsSideways","listFlowsSideways","dockSide","clickGuard","scrollAxis","listScrollAxis","autoScroll","reorderDrag","axis","moved","scroll","speed","dragScrollSpeed","px","scrolled","at","y","focusNav","op","focusList","focusSearch","releaseKeyboard","all","navPlan","kind","tabIndex","activeElement","ring","navMode","activeTabIndex","classList","contains","adIndex","dataset","owner","className","searchVisible","navSearchVisible","wrap","openFile","rescanPasteHotkey","groups","rp","renderPlan","idx","_f","_g","dir","projectRoot","projectRootOf","projectRoots","projectRootCacheSnapshot","collapsed","isGroupCollapsed","collapsedEffective","collapseOf","collapseReason","tabIndexes","withHeads","plan","tabsUsedByRender","visible","tabsForCounts","filtering","fold","foldGroupKey","sessions","cfg","live","liveSessionIds","records","snapshot","byGroup","expanded","isResumeExpanded","resumeRowsFor","groupKeys","resumeKeysOf","keyOf","cwd","groupKeyOf","days","limit","hidden","sessionId","lastStatus","openTabId","rescanSessions","refresh","decorator","dump","effective","identify","fallback","eff","u","usesUnionPatterns","usesOwnPatterns","shapesDropped","imagePasteKeyKept","catchesClaudeBusy","judge","pane","focusedPane","read","readScreen","judgeScreen","cols","profileForPane","agentOf","firstPane","observed","effectiveId","streamId","session","tracker","probedAt","probeAgent","kickLog","diagMemory","diagPaths","DIAG_PATH","DIAG_PREV_PATH","SCREEN_PATH","collectDiag","includeScreen","collectDiagBundle","stamp","targets","requestAnimationFrame","anyTab","panes","getAllTabs","repairPane","host","parentElement","clientWidth","clientHeight","beforeVerdict","broken","reasons","fitAddon","fit","syncPtySize","clearInputArea","reset","nudgePtyRedraw","sendRedrawKey","after","still","anyPane","sendInput","open","sendToPane","canRepairComposer","shape","INPUT_TAIL","border","isRuleRow","isGhostRuleRow","start","row","scheduleScreenCheck","screenObservingEnabled","checkScreen","_h","_j","_l","_m","_o","_p","_q","verdict","prevObs","streak","changed","refillAutoRepairBudget","xcols","xrows","sizeInSync","columns","since","resetDiagOnce","buf","wrapped","isWrapped","toISOString","l","w","padStart","appendScreenLog","anyRoot","titleChange$","applyTitle","profileForTab","tabAdded$","watchPane","tries","installCodexCursorFix","output$","applyOutput","noteOutput","touchCwd","sessionChanged$","frontendReady$","announceSizeOnOpen","observePaneAgent","state","TerminalAgentTracker","delay","resize","diagCatch","legacy","paste","startsWith","code","isPlainInput","isDeckUiKey","stopPropagation","inList","pickCloseTarget","closeTab","home","helper","compositionHelper","readCompositionState","planSend","keyCode","describeComposition","isComposing","writeAfterComposition","ta","textarea","flushed","flushComposition","compositionTextLength","fire","why","removeEventListener","onEnd","once","_core","_compositionHelper","_isSendingComposition","forget","isShiftKey","isEnter","getModifierState","tracked","limitedTab","releaseLimited","readPromptLine","setLabel","cursor","cursorY","nearCursor","byCursor","extractPrompt","byScreen","el","closest","isContentEditable","tagName","imageOnly","clipboardHasImageOnly","sendImagePasteKey","probeSendInput","probeWrite","startedAt","found","detectAgentApp","configured","via","charCodeAt","overPanel","dataTransfer","types","files","getData","askFileDrop","pasteDroppedPath","openDroppedInPanel","getElementById","pop","card","innerHTML","msg","textContent","remember","checked","again","getChildProcesses","byProc","pid","cmdline","commandLinesOf","byCmd","customTitle","byTitle","clean","execFile","isWin","windowsHide","err","stdout","on","getParentTab","isLiveCodexScreen","known","identifyScreenAgent","__adSendInputProbe","orig","rest","callSite","__adWriteProbe","stack","fromCharCode","cb","clipboard","getClipboard","hasImage","readImage","readText","getFocusedTab","terminal","rightClick","ev","button","inTerminalArea","held","handleRightClick","heldMs","buildContextMenu","popupContextMenu","getSelection","copySelection","clearSelection","sequence","newlineSequence","display","setVisible","prop","removeProperty","syncBackgroundClip","documentElement","clear","getBoundingClientRect","setProperty","left","top","termPct","sidePct","scheme","colorScheme","background","pct","exec","rgb","withAlpha","wantMode","isDockSide","sidebarExtent","availW","availH","winH","isHorizontalDock","minSidebar","maxSidebar","ratio","termW","hardMin","hardMax","softMax","side","horizontal","viewSide","viewRoom","viewW","extent","layoutW","sideW","leftPad","position","right","bottom","DOCK_SIDES","layout","flex","maxWidth","marginLeft","marginRight","marginTop","marginBottom","syncHandle","refitTerminals","wireSearch","wireListKeys","openNewTab","openSettings","DockController","getDock","setDock","getSize","setSize","commit","install","navReady","navEscape","clearFilters","toggleStatusFilter","tabMatchesFilter","stripTitleMarker","UNGROUPED_LABEL","migrateFollow","preload","autoOpen","ViewPanel","getSide","getWidth","setWidth","getRecentMax","getFollowMode","followModeOf","cwdFor","cwdOf","touchedFor","touchedOf","openExternal","url","sendText","hit","hooked","misses","ttl","getWorkingDirectory","then","statSync","isDirectory","getProfiles","openNewTabForProfile","openNewTabRaw","SettingsTabComponent","webContents","setBackgroundThrottling","dirty","idleAfter","tickIdle","syncLedger","liveSessions","sid","st","note","statusOf","sortTabsByStatus","groupsFor","resolveGroupCollapseFor","pruneNavFocus","renderHeadCount","renderGroupHead","renderTab","renderResume","renderEmpty","renderResumeHead","renderResumeRow","stored","collapseIdOf","toggleResumeExpanded","was","agent","formatWhen","lastSeen","activateResume","showResumeMenu","total","parts","q","groupTabs","collapsedKeys","isStoredCollapsed","toggleGroup","caret","isNavFocused","countEl","counts","countByStatus","sort","statusRank","chip","elapsed","formatElapsed","labelEl","badge","pinned","sub","subagentsOf","tooltip","insertAdjacentElement","armRowDrag","startLabelEdit","showStatusMenu","navRowsOf","navIndexIn","sameNavRow","where","preventScroll","scrollNavIntoView","setSelectionRange","blur","emitFocused","moveNav","step","stepNavIndex","activateNav","scrollIntoView","block","inline","stop","onMove","dragMove","onUp","endRowDrag","onCancel","onKey","clientX","clientY","detach","hypot","noteReorderBlocked","refreshDropTarget","armDragScroll","dropTargetAt","drawReorderLine","canY","scrollHeight","canX","scrollWidth","vertical","planEdgeScroll","pos","near","far","cur","scrollTop","scrollLeft","maxScroll","bandPx","minPps","maxPps","stopDragScroll","raf","performance","dragScrollTick","dt","cancelAnimationFrame","reject","elementFromPoint","rowEl","rowElOf","past","clampTo","lo","hi","REORDER_LINE_PX","drop","committed","planTabMove","emitTabsChanged","holder","placeholder","replaceWith","select","finish","fork","resumeCommand","openResumeTab","sendResumeCommand","sent","unsubscribe","t0","arm","old","menu","items","setClipboard","hideResumeRow","action","innerHeight","offsetHeight","setManual","unpin","ms","floor","HotkeysService","ProfilesService","HostWindowService","PlatformService","WorkNotifyService","SessionLedgerService","AgentDeckDecorator","tabby_terminal_1","TerminalDecorator","rootOf","attach","attached","attachToSession","subscribeUntilDetached","forgetOutputBuffer","reason_1","OSC_RE","VALID","tails","reasonFrom","patterns","short","reasonFromScreen","setAutoWithReason","setAuto","outputs","markOutput","matched","consumed","lastIndex","oscHits","markBusy","resume","mark","isBusyMode","TITLE_RE","titleHits","diagException","recentDiag","pluginVersion","SCREEN_PREV_PATH","childProcess","logDir","AGENTDECK_DIAG_DIR","DIAG_MAX_BYTES","aspect","autoRepair","useConPTY","memory","onceKeys","diagBytes","appendsSinceStat","sessionHeader","captureInstalled","consoleCount","consoleSeen","catchCount","catchSeen","cachedVersion","candidate","fileSize","rotate","renameSync","append","chunk","appendFileSync","Buffer","byteLength","errorMessage","STACK_MAX_LINES","trimmed","safeJson","teeConsole","level","formatArg","recordConsole","arg","clip","first","flat","arch","versions","node","electron","release","anyWindow","filename","lineno","colno","getFullYear","getMonth","getDate","getHours","getMinutes","stampForName","tmpdir","report","basename","zip","rmSync","force","execFileSync","stdio","compress","zipped","handle","overlay","preview","zones","resizing","dragging","dragArmed","dragFrom","hoverSide","installResizeHandle","installDockDrag","setPointerCapture","pointerId","rect","releasePointerCapture","dx","dy","showOverlay","updateHover","hideOverlay","positionZones","cx","cy","hitTest","drawPreview","formatStageSummary","hasStaged","commitArgs","validateMessage","unstageFallbackArgs","unstageArgs","stageArgs","parseStatus","stageLabel","gitDiff_1","NUL","stageStateOf","work","isConflict","staged","isHeader","rec","splitCode","isRenameCode","splitRename","endOfQuoted","unquotePath","cut","entryOf","oldPath","cleanPaths","paths","src","parseZ","pair","opts","amend","unstaged","untracked","conflict","parseUntracked","filterTouched","formatLineRef","refPathFrom","joinRefPath","refLineNo","statusLabel","formatStat","parseUnifiedDiff","DIFF_HEAD_RE","HUNK_RE","BINARY_RE","ESCAPES","decodeQuoted","bytes","decodeURIComponent","bytesToUtf8","ch","oct","parseInt","stripSide","readQuoted","splitHeadPaths","second","half","blank","binary","added","removed","oldNo","newNo","remOld","remNew","hunk","bin","oldSide","newSide","WIN_DRIVE_RE","slash","trimTail","rel","pathKey","no","ka","kc","refPath","okA","okB","ref","pathOf","touched","normalizeCwd","unc","splitPath","prefix","segs","segsOf","drive","sameSegs","pp","groupLabelOf","allKeys","norm","others","depth","compareGroups","la","lb","kb","QC","parentPath","joinPath","byFold","ungrouped","matches","resolveGroupCollapse","AgentDeckHotkeyProvider","HotkeyProvider","provide","textLength","keydown","_compositionPosition","__exportStar","common_1","forms_1","config_1","hotkeys_1","decorator_1","deck_service_1","profile_service_1","alert_service_1","recovery_service_1","update_service_1","settings_1","settings_component_1","AgentDeckModule","deck","recovery","NgModule","imports","CommonModule","FormsModule","default","providers","useClass","multi","SettingsTabProvider","AgentDeckSettingsTabProvider","declarations","AgentDeckSettingsTabComponent","AgentDeckProfileService","AgentDeckRecoveryService","AgentDeckUpdateService","escapeHtml","safeUrl","codes","_ticks","alt","resolved","resolveImage","isTableRule","splitRow","renderMarkdown","para","fence","closeLists","toIndent","indent","ordered","flushPara","breakBlocks","RegExp","cls","lang","fenceOpen","heading","j","quote","more","task","sections","net","string_decoder_1","claudeHooks_1","bind_1","tabenv_1","subagents_1","formatAge","LOCALAPPDATA","portFile","server","sessionTab","tabSession","applied","pidRefreshing","tabIds","hookCwd","liveAgents","agentHookSeen","watchedSplits","pollCount","lastBindLog","scans","projectsDir","promptHooksOnce","showMessageBox","detail","buttons","defaultId","cancelId","response","ids","hookInfo","agentHook","agents","subagents","subagentEnabled","scan","sum","summary","tabId","lastSize","skipped","calls","description","subagentType","subagentTooltip","stampRoot","listen","poll","refreshPids","tabName","panesOf","pty","getPID","isLocalProfile","stampPanes","_recoveredState","stampRecoveryState","stampPane","refreshTabIds","restoreFromPTYID","TAB_ENV","idTakenElsewhere","newTabId","sessionOptions","children","child","self","dup","prevOwner","dropped","debugDir","debugPort","addr","address","port","createServer","socket","setEncoding","nl","accept","fellBack","unlinkSync","scanSubagents","readdirSync","full","ts","hasStatus","hasLabel","hasFile","hasAgents","resolveTab","shortenReason","alive","byId","pickTabByTabId","pick","table","bindLog","how","prevTab","summarizeLiveAgents","formatLiveAgentTooltip","oldestAt","formatSubagentTooltip","oldest","NaN","pruneScans","createSubagentState","decoder","StringDecoder","busy","lookupAt","summarizeSubagents","resetScan","readGrowth","findTranscript","dirs","promises","readdir","withFileTypes","entry","matchesSessionTranscript","sid8","createReadStream","settled","feedChunk","Q","rank","band","ROOT_PROFILE_ID","ensureProfile","existing","clearProjectRootCache","findProjectRoot","walkUp","homeBoundary","PROJECT_MARKERS","stopAt","up","hasMarker","cache","async","hasMarkerAsync","access","onResolved","detect","reEscape","classEscape","chars","altOf","given","yY","D0","heads","choiceWords","promptCache","stripBox","stripLead","stripTail","rule","headChars","lead","vert","made","choice","resolveShape","trimEnd","tool","allow","enforce","setNoTabRecovery","recoverTabs","localStorage","tabsRecovery","screenCache","headAnywhere","ruleChar","ruleCharAll","match","sentCols","sentRows","rules","fullRules","inside","topAttached","belowHead","lens","identifyShellLaunch","exe","footer","findIndex","control","shellTitle","launch","launched","scanned","headCache","loaded","saveTimer","scanning","lastScan","load","parsed","clampLabel","scheduleSave","patch","same","finally","cutoff","onDisk","sessionIdFromFile","stat","mtimeMs","mtime","scanCodex","isFile","readHeadOf","isSubagent","pruneLedger","fh","alloc","HEAD_BYTE_LIMIT","bytesRead","readHead","HEAD_LINE_LIMIT","mergeSessions","wd","NOISE_PREFIXES","isHumanPrompt","promptFromRecord","payload","role","isMeta","one","subagent","timestamp","isNaN","disk","aliveIds","localeCompare","setDate","SESSION_FILE_RE","codexHooks_1","UPDATE_OUTCOME_TEXT","disabled","unknown","postponed","installing","failed","DOCK_LABELS","hooksOn","codexHooksOn","codexHookError","hookError","diagPath","diagVersion","diagIncludeScreen","diagBundlePath","diagError","updateBusy","updateMsg","refreshHooks","checkUpdate","toggleHooks","toggleCodexHooks","bundle","showItemInFolder","layoutChanged","dockLabel","sizeLabel","resetLayout","collapsedCount","expandGroups","pickCwd","picked","pickDirectory","Component","selector","template","getComponentType","rxjs_1","REASON_STATUSES","states","Subject","lastOutput","busyMode","lastBusy","clearReasonUnlessWaiting","oq","NOTIFY_OPEN","TOOL_USE_ID_RE","STATUS_RE","ID_RE","RUNNING_STATUSES","readNotifications","NOTIFY_CLOSE","mayHaveCall","readCalls","isSidechain","subagent_type","feedLines","cap","shown","byType","fileName","begin","lastIndexOf","Uint8Array","crypto","getRandomValues","random","child_process_1","http","https","update_1","notifications","marks","installMarks","canSelfUpdate","pluginsDir","devInstall","shouldCheck","DEFAULT_INTERVAL_HOURS","latest","parseLatestVersion","fetch","latestUrl","outcome","decide","lastCheckAt","intervalHours","info","updateSkipVersion","confirmAndInstall","launchUpdater","quit","mkdtempSync","spawn","execPath","mainProcessPid","detached","unref","ppid","configPath","getConfigPath","hasSrc","hasGit","hasWebpackConfig","isLink","pluginEntryIsLink","lstatSync","PACKAGE_NAME","isSymbolicLink","headers","res","statusCode","destroy","NotificationsService","parseVersion","nums","pre","isNewer","pa","pb","xa","xb","tb","na","nb","compareVersions","sx","registry","pkg","MIN_VIEW_W","VIEW_ID","markdown_1","gitCommit_1","MAX_TEXT_BYTES","MAX_EDIT_BYTES","MIME","png","jpg","jpeg","gif","webp","bmp","ico","avif","svg","firstLine","fileNote","hh","mm","formatBytes","dataUrl","extname","mimeOf","readTextHead","truncated","isWritable","accessSync","constants","W_OK","bodyEl","tabsEl","titleEl","footEl","pathRow","pathInput","modesEl","scopeBtn","diffScope","diffHidden","diffDebug","commitEl","commitInput","commitBtn","commitSumEl","commitNoteEl","refNoteEl","refSel","refLastSent","refFlashTimer","diffSeq","diffAutoAt","diffRoot","statusEntries","statusByPath","commitArmed","gitBusy","opened","watching","recent","lastViewed","editArea","editBarEl","editNoteEl","editSaveBtn","editOrigin","editForceArmed","pathCreateArmed","editStale","editOverwriteArmed","findRow","findInput","findCountEl","findHits","buffers","scrapeTimers","isOpen","room","syncDisplay","renderTabs","refreshDiff","applyTabFile","watch","renderCurrent","unwatch","disarmCommit","btn","setMode","getAttribute","toggleScope","applyScopeLabel","reload","togglePathRow","toggleEdit","openFind","saveEdit","cancelEdit","stepFind","closeFind","runFind","ctrl","openOrCreate","pressCommit","setCommitNote","stage","toggleStage","jump","clickRefLine","installDrop","installResize","startX","startW","move","delta","outerOffset","setPathNote","absolute","isAbsolute","encoding","flag","startEdit","viewMode","applyMode","querySelectorAll","setEditNote","wasOpen","scrape","token","extractPaths","pushRecent","isAutoFollowable","planFollow","maybeAutoDiff","requireKnownExt","isKnownExt","setStatus","noteFile","renderMessage","watchFile","interval","unwatchFile","setTitle","setFoot","tip","setFootNote","refreshEditNote","toLocaleString","classify","renderImage","renderMarkdownFile","renderTable","renderText","renderBinary","syncEditButton","html","parseDelimited","delimiterFor","MAX_TABLE_ROWS","cell","forEach","applyRefSel","canEdit","usable","opacity","bom","crlf","readTextAll","showEditBar","readOnly","spellcheck","origin","outside","chmodSync","err2","btns","clearFindMarks","term","findInTextarea","markMatches","showFindHit","hay","needle","setFindCount","selectionStart","lineH","nth","walker","createTreeWalker","NodeFilter","SHOW_TEXT","nextNode","guard","frag","createDocumentFragment","replaceChild","parent","runGit","maxBuffer","stderr","renderDiffNote","isDir","seq","diff","noGit","failDiff","allFiles","allUntracked","touchedNow","sample","finishDiff","renderDiff","draw","setCommitVisible","shownFiles","scopeNote","stageChipHtml","absOf","narrowed","budget","diffLineHtml","toLocaleTimeString","extend","sel","isCollapsed","removeAllRanges","del","setRefNote","box","anchor","sendRef","chain","act","syncCommitButton","runCommit","dispose","IMAGE_EXT","MARKDOWN_EXT","TABLE_EXT","TEXT_EXT","KNOWN_EXT","extensionOf","dot","ext","PATH_CHAR","PATH_RE","PUNCT","TRAILING","stripAnsi","AUTO_FOLLOW_SKIP_RE","delimiter","quoted","toFixed","FOLLOW_MODES","chosen","__webpack_module_cache__","moduleId","cachedModule","__webpack_modules__","getter","cw","fn","definition","binding","descriptor"],"sourceRoot":""}
|