tabby-agentdeck 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +178 -240
- package/dist/api.d.ts +10 -0
- package/dist/bind.d.ts +23 -0
- package/dist/claudeHooks.d.ts +22 -0
- package/dist/config.d.ts +156 -34
- package/dist/deck.service.d.ts +140 -29
- package/dist/dock.d.ts +62 -0
- package/dist/index.js +2480 -311
- package/dist/index.js.map +1 -1
- package/dist/notify.service.d.ts +53 -11
- package/dist/screen.d.ts +42 -0
- package/dist/settings.component.d.ts +52 -0
- package/dist/settings.d.ts +11 -0
- package/dist/status.service.d.ts +9 -0
- package/hooks/agentdeck-notify.ps1 +83 -23
- package/install.ps1 +60 -2
- package/package.json +50 -50
package/README.md
CHANGED
|
@@ -1,240 +1,178 @@
|
|
|
1
|
-
# tabby-agentdeck
|
|
2
|
-
|
|
3
|
-
Tabby 터미널 플러그인. **Claude Code · Codex 같은 AI 에이전트 CLI 를 여러 탭에 띄워 놓고 쓰는 사람**을 위한 것이다.
|
|
4
|
-
|
|
5
|
-
터미널 뷰포트를 **4:3 으로 고정**하고 남는 공간에 **세션 목록 + 작업 상태 사이드바**를 그린다.
|
|
6
|
-
어느 에이전트가 돌고 있고 어느 쪽이 내 입력을 기다리는지 탭을 옮겨 다니지 않고 한눈에 본다.
|
|
7
|
-
거기에 에이전트 CLI 가 터미널에서 겪는 문제들(이미지 붙여넣기, 줄바꿈 키, pty 폭 어긋남)을 같이 손봐 둔다.
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
┌──────────────────────────────┬──────────────────┐
|
|
11
|
-
│ │ AGENT DECK 4 │
|
|
12
|
-
│ 터미널 (창 높이 × 4/3) ├──────────────────┤
|
|
13
|
-
│ │ ● 진행중 리팩터링 │
|
|
14
|
-
│ Tabby 순정 탭바는 숨김 │ ⏸ 승인대기 재빌드 │
|
|
15
|
-
│ │ ✔ 완료 테스트 │
|
|
16
|
-
│ │ ○ 대기 │
|
|
17
|
-
│ ├──────────────────┤
|
|
18
|
-
│ │ + 새 탭 │ 설정 │
|
|
19
|
-
└──────────────────────────────┴──────────────────┘
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
|
27
|
-
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
`
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
|
124
|
-
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
|
|
147
|
-
`
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
###
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
useConPTY: false
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### npm 전역 명령(`claude` 등)이 실행 정책에 막힘
|
|
183
|
-
|
|
184
|
-
`claude` 는 `.ps1` 래퍼라 기본 실행 정책(Restricted)에서 로드되지 않는다.
|
|
185
|
-
`rootProfileArgs` 의 `-ExecutionPolicy Bypass` 가 이를 해결한다 — **해당 세션에만** 적용되고 시스템 정책은 건드리지 않는다.
|
|
186
|
-
|
|
187
|
-
## 개발
|
|
188
|
-
|
|
189
|
-
```powershell
|
|
190
|
-
npm run watch # 소스 감시 빌드
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
Tabby 를 `--remote-debugging-port=9222` 로 띄우면 CDP 로 내부 상태를 들여다볼 수 있다.
|
|
194
|
-
플러그인이 `window.__agentdeck` 에 `app` / `config` / `status` / `relayout()` / `render()` 를 노출한다.
|
|
195
|
-
|
|
196
|
-
```js
|
|
197
|
-
window.__agentdeck.status.debug // { attached, outputs, oscHits, titleHits }
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## 구조
|
|
201
|
-
|
|
202
|
-
| 파일 | 역할 |
|
|
203
|
-
|---|---|
|
|
204
|
-
| `src/index.ts` | NgModule — provider 등록, 서비스 기동 |
|
|
205
|
-
| `src/deck.service.ts` | 사이드바 DOM, 4:3 레이아웃, 세션·제목 감시 |
|
|
206
|
-
| `src/detect.ts` | 출력·제목에서 상태를 읽어내는 규칙 |
|
|
207
|
-
| `src/status.service.ts` | 탭별 상태 보관 |
|
|
208
|
-
| `src/decorator.ts` | Tabby 공식 확장점(TerminalDecorator) 경유 출력 구독 |
|
|
209
|
-
| `src/profile.service.ts` | 작업 루트 프로필 등록 |
|
|
210
|
-
| `src/notify.service.ts` | Claude Code 훅이 남긴 상태 파일을 읽어 탭에 반영 |
|
|
211
|
-
| `src/config.ts` | 기본 설정값 |
|
|
212
|
-
| `src/hotkeys.ts` | 핫키 선언 |
|
|
213
|
-
|
|
214
|
-
### 구현하며 부딪힌 것들
|
|
215
|
-
|
|
216
|
-
- **탭은 래퍼에 싸여 있다.** `app.tabs` 의 원소는 `SplitTabComponent` 이고 터미널은 그 자식이다.
|
|
217
|
-
상태 키를 정규화하지 않으면 자식에 쓰고 부모를 읽어 영영 매칭되지 않는다.
|
|
218
|
-
- **래퍼가 자식보다 먼저 목록에 들어온다.** 한 번 훑고 "감시 완료" 로 표시하면 빈 래퍼만 잡고 끝난다.
|
|
219
|
-
pane 은 호출될 때마다 다시 훑는다.
|
|
220
|
-
- **`HotkeysService` 는 `HotkeyProvider` 들을 주입받는다.** provider 생성자에서 그것을 다시 주입하면
|
|
221
|
-
순환 의존으로 부분 초기화된 인스턴스가 넘어온다(`Cannot read properties of undefined`). 핫키 구독은 다른 서비스에서.
|
|
222
|
-
- **CSS 로만 폭을 바꾸면 pty 가 따라오지 않을 수 있다.** Tabby 의 xterm 은 `attach()` **맨 끝**에서야
|
|
223
|
-
`ResizeObserver` 를 건다(`tabby-terminal/dist/index.js:40979`). 그 앞에는 `await` 가 여러 개 있어서,
|
|
224
|
-
탭이 붙는 도중(`tabOpened$`/`tabsChanged$`)에 `.content.main` 폭을 바꾸면 그 변경이 아무에게도 관측되지 않고
|
|
225
|
-
유실된다. 결과: xterm 은 넓은데 pty 는 옛 폭 그대로 → Claude Code 같은 전체화면 TUI 가 화면보다 좁게 그리고
|
|
226
|
-
오른쪽에 지워지지 않은 옛 프레임이 박혀 있다. 창을 복원→최대화로 흔들면 OS 리사이즈 경로를 타서 즉시 복구된다
|
|
227
|
-
(2026-08-28 실측). 그래서 `relayout()` 은 폭이 바뀔 때마다, 그리고 `frontendReady$` 때
|
|
228
|
-
`frontend.fitAddon.fit()` 을 직접 호출한다. 숨겨진 탭은 컨테이너 폭이 0 이라 건너뛴다.
|
|
229
|
-
|
|
230
|
-
- **입력창 머리글자를 `>` 로 가정한 것이 라벨이 안 바뀌던 진짜 원인이다.** 앞서 "화면 아래 14줄만
|
|
231
|
-
읽어서" 로 진단해 스캔 기준을 커서 줄로 옮겼는데도 증상이 그대로였다. 실제 원인은 정규식 —
|
|
232
|
-
Claude Code 2.1.252 의 입력창은 `❯`(U+276F) 로 시작해서 `/^>\s*/` 에 절대 걸리지 않았다.
|
|
233
|
-
CDP 로 읽은 xterm 버퍼 원문이 증거다(2026-09-01):
|
|
234
|
-
`"────────…"`, `"❯ "`, `"────────…"`, `" ⏵⏵ auto mode on (shift+tab to cycle)"`.
|
|
235
|
-
같은 실수를 반복하지 않으려면 `readPromptLine` 이 빈손일 때 남기는
|
|
236
|
-
`enter-label miss ... tail=` 진단 라인(커서 주변 4줄 원문)을 먼저 볼 것 —
|
|
237
|
-
"버퍼를 못 읽음" 과 "머리를 못 찾음" 을 이 줄 하나로 가른다.
|
|
238
|
-
|
|
239
|
-
- **`package.json` 에 `author` 가 없으면 플러그인이 조용히 로드되지 않는다.**
|
|
240
|
-
Tabby 의 `parsePluginInfo` 가 `author.name` 을 읽다가 예외를 삼킨다.
|
|
1
|
+
# tabby-agentdeck
|
|
2
|
+
|
|
3
|
+
Tabby 터미널 플러그인. **Claude Code · Codex 같은 AI 에이전트 CLI 를 여러 탭에 띄워 놓고 쓰는 사람**을 위한 것이다.
|
|
4
|
+
|
|
5
|
+
터미널 뷰포트를 **4:3 으로 고정**하고 남는 공간에 **세션 목록 + 작업 상태 사이드바**를 그린다.
|
|
6
|
+
어느 에이전트가 돌고 있고 어느 쪽이 내 입력을 기다리는지 탭을 옮겨 다니지 않고 한눈에 본다.
|
|
7
|
+
거기에 에이전트 CLI 가 터미널에서 겪는 문제들(이미지 붙여넣기, 줄바꿈 키, pty 폭 어긋남)을 같이 손봐 둔다.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌──────────────────────────────┬──────────────────┐
|
|
11
|
+
│ │ AGENT DECK 4 │
|
|
12
|
+
│ 터미널 (창 높이 × 4/3) ├──────────────────┤
|
|
13
|
+
│ │ ● 진행중 리팩터링 │
|
|
14
|
+
│ Tabby 순정 탭바는 숨김 │ ⏸ 승인대기 재빌드 │
|
|
15
|
+
│ │ ✔ 완료 테스트 │
|
|
16
|
+
│ │ ○ 대기 │
|
|
17
|
+
│ ├──────────────────┤
|
|
18
|
+
│ │ + 새 탭 │ 설정 │
|
|
19
|
+
└──────────────────────────────┴──────────────────┘
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Windows 에서 만들고 검증했다. 상태 통보 훅은 PowerShell 스크립트라 Windows 전용이고, 그 외 기능은 플랫폼을 가리지 않는다.
|
|
23
|
+
|
|
24
|
+
## 기능
|
|
25
|
+
|
|
26
|
+
| | 동작 |
|
|
27
|
+
|---|---|
|
|
28
|
+
| **4:3 기준 폭 계산** | 창 높이에서 폭을 역산해 터미널을 고정폭으로 만든다. 남는 폭은 사이드바가 갖고, 그러고도 남으면 터미널이 흡수한다 |
|
|
29
|
+
| **사이드바 탭 관리** | 클릭=선택, `×`=닫기, 더블클릭=작업 이름 편집, 우클릭=상태 직접 지정 |
|
|
30
|
+
| **마우스 도킹** | 헤더를 끌어 좌/우/상/하 어느 가장자리에나 붙이고, 경계선을 끌어 크기를 바꾼다 |
|
|
31
|
+
| **작업 상태** | 진행중 / 승인대기 / 완료 / 오류 / 대기 를 색·배지·경과시간으로 표시 |
|
|
32
|
+
| **작업 이름** | Enter 로 프롬프트를 보내는 순간 입력창 원문을 읽어 라벨로 삼는다 |
|
|
33
|
+
| **Claude Code 훅 연동** | 설정 창에서 한 번 설치하면 에이전트가 상태를 직접 알려준다 (선택) |
|
|
34
|
+
| **기본 프로필** | 새 탭을 항상 지정한 작업 루트에서 연다 |
|
|
35
|
+
| **입력 보정** | `Ctrl+V` 이미지 붙여넣기, `Ctrl+Enter`/`Shift+Enter` 줄바꿈, 우클릭 복사/붙여넣기 |
|
|
36
|
+
| **화면 복구** | 깨진 TUI 를 지우고 다시 그리게 한다. 사이드바 `↻` / 탭 우클릭 / `agentdeck-repair` 핫키 |
|
|
37
|
+
|
|
38
|
+
## 설치
|
|
39
|
+
|
|
40
|
+
**Tabby 안에서**: 설정 → 플러그인 → `agentdeck` 검색 → 설치 → Tabby 재시작.
|
|
41
|
+
|
|
42
|
+
**소스에서**:
|
|
43
|
+
|
|
44
|
+
```powershell
|
|
45
|
+
npm install
|
|
46
|
+
npm run build
|
|
47
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`install.ps1` 은 Tabby 플러그인 디렉토리(`%APPDATA%\tabby\plugins\node_modules\tabby-agentdeck`)에
|
|
51
|
+
이 폴더를 가리키는 junction 을 건다. 소스를 고치고 `npm run build` 하면 Tabby 재시작으로 반영된다.
|
|
52
|
+
|
|
53
|
+
## 작업 이름과 상태
|
|
54
|
+
|
|
55
|
+
사이드바 한 줄은 **작업 이름(라벨)** 과 **상태 배지** 로 이루어진다.
|
|
56
|
+
둘 다 **설정 없이 플러그인만으로 돈다.** 더 정확하게 하려면 Claude Code 훅을 건다.
|
|
57
|
+
|
|
58
|
+
### 작업 이름
|
|
59
|
+
|
|
60
|
+
Enter 로 프롬프트를 보내는 그 순간, 화면에 그려져 있는 입력창(`❯ ...`, `> ...`)을 읽어 40자로 잘라 라벨에 넣는다.
|
|
61
|
+
붙여넣기·↑ 히스토리·IME 로 들어온 글자도 화면에 그려진 대로 잡힌다.
|
|
62
|
+
Shift+Enter / Ctrl+Enter 는 줄바꿈이라 라벨을 바꾸지 않고, 입력창 머리를 못 찾으면(일반 셸, y/n 확인 등) 라벨을 그대로 둔다.
|
|
63
|
+
|
|
64
|
+
### 상태
|
|
65
|
+
|
|
66
|
+
- **자동 감지(기본)**: PTY 출력이 흐르면 `진행중`, `idleAfterMs`(기본 2.5초) 동안 조용하면 `대기`.
|
|
67
|
+
`Do you want to`, `❯ 1. Yes`, `(y/n)` 같은 패턴이 보이면 `승인대기`. Claude Code 가 제목에 넣는 스피너도 진행중으로 읽는다.
|
|
68
|
+
- **Claude Code 훅(권장)**: 설정 → AgentDeck → "상태 통보 훅" 설치. `~/.claude/settings.json` 의
|
|
69
|
+
UserPromptSubmit / Notification / Stop 에 통보 스크립트를 건다. 다른 훅은 건드리지 않고 쓰기 전에 백업을 남긴다.
|
|
70
|
+
에이전트가 "지시를 받았다 / 승인을 기다린다 / 끝났다" 를 직접 알려주므로 판정이 흔들리지 않는다. 설정 창의 "제거" 로 되돌린다.
|
|
71
|
+
|
|
72
|
+
### 직접 지정
|
|
73
|
+
|
|
74
|
+
- 사이드바에서 **우클릭 → 상태 고르기**, **더블클릭 → 이름 편집**.
|
|
75
|
+
- 셸 스크립트 안에서라면 콘솔 제목을 `[AD:<status>] <라벨>` 로 바꾼다. 접두사는 표시에서 지워진다.
|
|
76
|
+
|
|
77
|
+
```powershell
|
|
78
|
+
$host.UI.RawUI.WindowTitle = "[AD:waiting] 배포 승인 대기"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
status 는 `running` / `waiting` / `done` / `error` / `idle`.
|
|
82
|
+
직접 지정한 상태는 **고정**되어 자동 감지가 덮어쓰지 않는다(배지에 점선 밑줄). 우클릭 → `↺ 자동 감지로` 로 해제한다.
|
|
83
|
+
이 경로는 셸 안에서 직접 실행할 때만 통한다 — 에이전트 훅에서는 콘솔 제목이 터미널까지 오지 않는다.
|
|
84
|
+
|
|
85
|
+
## 키
|
|
86
|
+
|
|
87
|
+
| 키 | 동작 |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `Ctrl+Enter` / `Shift+Enter` | 줄바꿈 (`0x0A` 전송). `agentdeck-newline` |
|
|
90
|
+
| `Ctrl+V` | 붙여넣기. 클립보드에 **이미지만** 있으면 텍스트 대신 이미지 붙여넣기 키를 앱에 넘긴다 — Claude Code·Codex 가 클립보드를 직접 읽는다. `agentdeck-paste` |
|
|
91
|
+
| 우클릭 | 선택이 있으면 복사, 없으면 붙여넣기. 길게(기본 250ms) 누르면 컨텍스트 메뉴 |
|
|
92
|
+
| (미배정) | `agentdeck-toggle` — 사이드바/4:3 즉시 on-off |
|
|
93
|
+
| (미배정) | `agentdeck-repair` — 화면 복구 |
|
|
94
|
+
|
|
95
|
+
키 배정은 Tabby 설정 → 단축키의 `agentdeck-*` 항목에서 바꾼다.
|
|
96
|
+
`Ctrl+V` 는 플러그인이 기동할 때 `agentdeck-paste` 에 넣고 순정 `hotkeys.paste` 에서는 뺀다(둘 다 있으면 두 번 붙는다).
|
|
97
|
+
터미널 앱에 리터럴 `Ctrl+V`(0x16)를 보내야 하면 `claimCtrlV: false`.
|
|
98
|
+
|
|
99
|
+
### 화면 복구 (`↻`)
|
|
100
|
+
|
|
101
|
+
statusline 이 사라지거나 입력창 구분선이 화면 중간에서 끊기는 등 화면이 깨졌을 때 누른다.
|
|
102
|
+
폭 재계산 → pty 크기 동기화 → 터미널 상태 초기화 → 앱에 전체 재렌더 요청(`Ctrl+L`) 순으로 진행한다.
|
|
103
|
+
기본값은 스크롤백을 보존한다(`repairHard: false`). 잔상까지 지우려면 `repairHard: true`.
|
|
104
|
+
|
|
105
|
+
## 설정
|
|
106
|
+
|
|
107
|
+
**설정 창(설정 → AgentDeck)** 에는 실제로 바꿀 일이 있는 것만 있다 — 레이아웃 on/off, 마우스로 바꾼 배치 초기화,
|
|
108
|
+
Claude Code 훅 설치/제거, 작업 루트 프로필. 나머지는 Tabby 설정 파일(`%APPDATA%\tabby\config.yaml`)의
|
|
109
|
+
`agentDeck` 아래에서 조절한다.
|
|
110
|
+
|
|
111
|
+
| 키 | 기본값 | 설명 |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `enabled` | `true` | 사이드바 + 4:3 레이아웃 on/off |
|
|
114
|
+
| `aspectW` / `aspectH` | `4` / `3` | 터미널 뷰포트 비율 |
|
|
115
|
+
| `sidebarDock` | `right` | 사이드바 위치 `left` / `right` / `top` / `bottom`. 헤더 드래그로도 바뀐다 |
|
|
116
|
+
| `sidebarWidth` | `0` | 좌/우 도킹 시 폭(px). 0 = 화면비로 자동 계산 |
|
|
117
|
+
| `sidebarHeight` | `200` | 상/하 도킹 시 높이(px) |
|
|
118
|
+
| `sidebarMin` / `sidebarMax` | `200` / `560` | 자동 계산 폭의 범위(px). 넓은 모니터에서 정확히 4:3 을 원하면 `sidebarMax` 를 `창 너비 − 창 높이 × 4/3` 으로 |
|
|
119
|
+
| `idleAfterMs` | `2500` | 이 시간 동안 출력이 없으면 `대기` 로 |
|
|
120
|
+
| `autoDetect` | `true` | 출력·제목 패턴으로 상태 추론 |
|
|
121
|
+
| `showElapsed` | `true` | 경과 시간 표시 |
|
|
122
|
+
| `keepRenderingWhenHidden` | `true` | 창이 가려져 있어도 사이드바를 갱신한다. 끄면 상태 변화가 최대 1분까지 늦게 보일 수 있다 |
|
|
123
|
+
| `enterAsLabel` | `true` | Enter 로 프롬프트를 보낼 때 입력창 원문을 작업 라벨로 삼는다 |
|
|
124
|
+
| `labelAsTitle` | `true` | 사이드바 제목 줄에 탭 제목 대신 작업 라벨을 쓴다. Tabby 의 탭 제목 자체는 건드리지 않는다 |
|
|
125
|
+
| `notifyChannel` | `true` | 훅이 보낸 상태를 받는 통로(로컬 TCP + 상태 파일). 훅을 설치하면 자동으로 켜진다 |
|
|
126
|
+
| `notifyPort` | `47500` | 그 TCP 포트(127.0.0.1 전용). 물려 있으면 임의 포트로 물러나고 실제 번호는 `%LOCALAPPDATA%\tabby-agentdeck\port` 에 적힌다 |
|
|
127
|
+
| `hookPromptDismissed` | `false` | 기동 시 뜨는 훅 설치 안내를 다시 띄우지 않는다 |
|
|
128
|
+
| `claimCtrlV` | `true` | 기동 시 `agentdeck-paste` 에 `Ctrl-V` 를 넣고 순정 `hotkeys.paste` 에서는 뺀다 |
|
|
129
|
+
| `pasteImageWithCtrlV` | `true` | 클립보드에 이미지만 있으면 텍스트 붙여넣기 대신 이미지 붙여넣기 키를 보낸다 |
|
|
130
|
+
| `imagePasteKey` | `alt-v` | 그때 보낼 키. `ctrl-v`(0x16) 는 Claude Code·Codex 둘 다, `alt-v`(ESC v) 는 Claude Code 전용 |
|
|
131
|
+
| `claimRightClick` | `true` | 우클릭을 플러그인이 처리한다 (Tabby 의 `terminal.rightClick` 은 `off` 로) |
|
|
132
|
+
| `rightClickMenuMs` | `250` | 이 시간 이상 누르면 붙여넣기 대신 컨텍스트 메뉴 |
|
|
133
|
+
| `terminalOpacity` | `75` | 터미널 배경 불투명도(%). 100 미만이면 `tabby-background` 의 배경 이미지가 비친다. 100 = 순정 |
|
|
134
|
+
| `sidebarOpacity` | `75` | 사이드바 / 창 여백 불투명도(%) |
|
|
135
|
+
| `clipBackgroundToTerminal` | `true` | `tabby-background` 이미지를 터미널 영역으로 잘라 사이드바 밑까지 비치지 않게 한다 |
|
|
136
|
+
| `screenWatch` | `true` | 2초마다 화면이 깨졌는지 판정해 `~/.agentdeck-screen.log` 에 기록만 한다 (복구는 하지 않음) |
|
|
137
|
+
| `autoRepairScreen` | `false` | 깨졌다고 판정되면 조용히 화면 복구까지 한다 |
|
|
138
|
+
| `autoRepairMinStreak` | `2` | 깨짐이 이만큼 연속으로 보여야 복구한다 (그리는 도중의 중간 프레임 오탐 방지) |
|
|
139
|
+
| `autoRepairCooldownMs` | `10000` | 자동 복구 후 이만큼은 다시 하지 않는다 |
|
|
140
|
+
| `autoRepairMaxPerTab` | `3` | 한 탭에서 자동 복구 최대 횟수. 0 = 무제한 |
|
|
141
|
+
| `repairHard` | `false` | 화면 복구가 `xterm.reset()` 까지 한다 (스크롤백도 지워진다) |
|
|
142
|
+
| `repairSendRedrawKey` | `true` | 화면 복구 마지막에 `Ctrl+L` 을 보내 전체 재렌더를 시킨다 |
|
|
143
|
+
| `rootProfile` | `false` | 작업 루트 프로필을 만들어 기본 프로필로 삼는다 (설정 창에서 켠다) |
|
|
144
|
+
| `rootProfileName` | `Agent Root` | 그 프로필 이름 |
|
|
145
|
+
| `rootProfileCwd` | `''` | 새 탭이 열릴 경로. 비우면 프로필을 만들지 않는다. 슬래시로 적는다 (예: `D:/Project`) |
|
|
146
|
+
| `rootProfileCommand` | `powershell.exe` | 셸 |
|
|
147
|
+
| `rootProfileArgs` | `-NoLogo -ExecutionPolicy Bypass` | 셸 인자. `Bypass` 는 npm 전역 `.ps1` 래퍼(`claude` 등)가 실행 정책에 막히지 않게 한다 — 그 세션에만 적용 |
|
|
148
|
+
| `rootProfileEnv` | `TERM=xterm-256color`, `COLORTERM=truecolor` | 셸 환경변수 (빠진 것만 채운다) |
|
|
149
|
+
|
|
150
|
+
## 알려진 문제
|
|
151
|
+
|
|
152
|
+
### Tabby 1.0.235 에서 새 탭이 열리지 않음
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
Error: ENOENT, node_modules\node-pty\lib\conpty_console_list_agent not found in ...\resources\app.asar
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Tabby 설치본의 패키징 버그로 플러그인과 무관하다. ConPTY 를 끄면 이 경로를 타지 않는다.
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
# %APPDATA%\tabby\config.yaml
|
|
162
|
+
terminal:
|
|
163
|
+
useConPTY: false
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 관리자 권한 프로필(`runAsAdministrator: true`)에서 입력창이 깨짐
|
|
167
|
+
|
|
168
|
+
프로필에 `runAsAdministrator` 가 켜져 있으면 Tabby 가 셸을 `UAC.exe` 릴레이로 감싸고, 그 릴레이가 폭을 1칸 잃어
|
|
169
|
+
Claude Code 입력창 테두리가 짧게 그려진다. 플러그인이 고칠 수 있는 자리가 아니다.
|
|
170
|
+
|
|
171
|
+
- 프로필의 `runAsAdministrator` 를 끈다. **이미 열려 있던 탭은 닫고 새로 열어야 한다** (탭 복원 토큰에 릴레이가 남는다).
|
|
172
|
+
- 관리자 권한이 필요하면 Tabby 자체를 관리자로 띄운다. 그 안의 탭은 권한을 물려받는다.
|
|
173
|
+
|
|
174
|
+
## 라이선스
|
|
175
|
+
|
|
176
|
+
MIT
|
|
177
|
+
|
|
178
|
+
개발 절차·구조·설계 근거·실측 함정은 리포의 `docs/DEVELOPMENT.md`, 회귀 체크리스트는 `docs/REGRESSION.md` 에 있다.
|
package/dist/api.d.ts
CHANGED
|
@@ -18,4 +18,14 @@ export interface TabState {
|
|
|
18
18
|
pinned: boolean;
|
|
19
19
|
/** 마지막 PTY 출력 시각 */
|
|
20
20
|
lastOutput: number;
|
|
21
|
+
/**
|
|
22
|
+
* 이 탭에서 에이전트의 "작업 중" 신호를 본 적이 있나.
|
|
23
|
+
*
|
|
24
|
+
* 본 적이 있으면 그 탭은 에이전트 TUI 로 보고, 그 뒤로는 신호가 있을 때만 진행중으로 친다.
|
|
25
|
+
* Claude Code 는 놀고 있을 때도 하단 상태줄을 매초 다시 그리기 때문에
|
|
26
|
+
* "출력이 있다 = 진행중" 으로 보면 영원히 진행중에서 내려오지 않는다 (2026-09-01 실측).
|
|
27
|
+
*/
|
|
28
|
+
busyMode: boolean;
|
|
29
|
+
/** 마지막으로 "작업 중" 신호를 본 시각 — 진행중에서 내려올 시점을 이걸로 잰다 */
|
|
30
|
+
lastBusy: number;
|
|
21
31
|
}
|
package/dist/bind.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 훅 보고를 어느 탭에 붙일지 고르는 순수 규칙 — Angular/Tabby 에 기대지 않아 단위 테스트가 된다.
|
|
3
|
+
*
|
|
4
|
+
* 왜 PID 인가 — 예전 규칙 "처음 보고할 때의 활성 탭" 은 사용자가 방금 프롬프트를 넣은 탭이
|
|
5
|
+
* 곧 활성 탭이라는 가정인데, 파일 폴링이 400ms 마다 못 묶은 보고를 다시 시도하는 탓에
|
|
6
|
+
* **끝난 세션의 done 이 다음에 열리는 빈 탭을 붙잡았다** (2026-09-02 실측: 작업 중인 탭이
|
|
7
|
+
* "완료" 로, 그 탭의 진짜 세션은 주인이 있다며 거절돼 running 이 버려졌다).
|
|
8
|
+
*
|
|
9
|
+
* 훅은 자기 조상 프로세스 PID 를 함께 보낸다 — claude.exe → 탭 셸 → Tabby.exe 순서다.
|
|
10
|
+
* 탭마다 pty 가 띄운 셸 PID 를 알고 있으면 어느 탭의 보고인지 추측 없이 확정된다.
|
|
11
|
+
*/
|
|
12
|
+
export type BindMode = 'pid' | 'pid-miss' | 'legacy';
|
|
13
|
+
export interface BindPick<T> {
|
|
14
|
+
tab: T | null;
|
|
15
|
+
/**
|
|
16
|
+
* pid — 조상 PID 가 어떤 탭의 셸 PID 와 맞았다 (확정)
|
|
17
|
+
* pid-miss — pids 도 왔고 탭 PID 표도 있는데 맞는 탭이 없다. 활성 탭으로 추측하지 **않는다**
|
|
18
|
+
* (탭 PID 표가 아직 안 채워진 것일 수 있으니 호출자는 다음 폴링에 다시 본다)
|
|
19
|
+
* legacy — pids 가 없거나(옛 훅·수동 호출) 탭 PID 를 하나도 모른다. 호출자가 예전 활성 탭 규칙을 쓴다
|
|
20
|
+
*/
|
|
21
|
+
mode: BindMode;
|
|
22
|
+
}
|
|
23
|
+
export declare function pickTabByPids<T>(pids: number[] | undefined, tabPids: Map<T, number[]>): BindPick<T>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare function claudeSettingsPath(): string;
|
|
2
|
+
/** 훅 스크립트의 실제 경로. dist/index.js 기준으로 한 단계 위가 패키지 뿌리다 */
|
|
3
|
+
export declare function notifyScriptPath(): string;
|
|
4
|
+
/** 이 환경에서 훅을 걸 수 있나 — 통보 스크립트가 PowerShell 이라 Windows 전용이다 */
|
|
5
|
+
export declare function hooksSupported(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* 우리 훅이 세 이벤트에 모두 걸려 있나 — 파일을 읽지 않는 순수 판정.
|
|
8
|
+
* 파일 접근과 분리해 둔 이유는 이 판단을 테스트로 묶어 두기 위해서다.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isMerged(settings: any): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* 설정 객체에 우리 훅을 더한 새 객체를 돌려준다 (원본은 건드리지 않는다).
|
|
13
|
+
* 이미 우리 것이 있으면 명령줄만 지금 경로로 갈아끼우고, 남이 걸어 둔 훅은 그대로 둔다.
|
|
14
|
+
*/
|
|
15
|
+
export declare function mergeHooks(settings: any, script: string): any;
|
|
16
|
+
/** 우리 훅만 걷어낸 새 객체. 비어 버린 이벤트 키는 지워서 설정을 깨끗하게 남긴다 */
|
|
17
|
+
export declare function stripHooks(settings: any): any;
|
|
18
|
+
export declare function hooksInstalled(): boolean;
|
|
19
|
+
/** 훅을 등록한다 */
|
|
20
|
+
export declare function installHooks(): void;
|
|
21
|
+
/** 훅을 뗀다 */
|
|
22
|
+
export declare function uninstallHooks(): void;
|