tabby-agentdeck 0.2.1 → 1.0.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.
@@ -0,0 +1,100 @@
1
+ /**
2
+ * 미리보기 패널의 순수 로직 — 파일 종류 판정, PTY 출력에서 경로 줍기, 최근 목록 관리.
3
+ *
4
+ * DOM 도 fs 도 건드리지 않는다. 이 파일만 테스트로 묶어 두고(test/viewer.test.js),
5
+ * 화면·파일 접근은 viewPanel.ts 가 맡는다 — dock.ts / deck.service.ts 를 가른 것과 같은 방식이다.
6
+ *
7
+ * **왜 에이전트 훅이 아니라 화면 출력에서 경로를 줍나 —** 훅이 있는 것은 Claude Code 뿐이다
8
+ * (src/claudeHooks.ts). Codex·Gemini 도 같은 패널을 쓰게 하려면 셋이 공통으로 하는 일에
9
+ * 기대야 하고, 그건 "만진 파일 경로를 화면에 찍는다" 다. 그래서 이 경로가 기본이고
10
+ * 훅은 나중에 정확도를 더하는 보강일 뿐이다.
11
+ */
12
+ export type ViewKind = 'markdown' | 'image' | 'table' | 'text' | 'binary';
13
+ export declare function extensionOf(file: string): string;
14
+ export declare function classify(file: string): ViewKind;
15
+ /** 미리보기로 열어 볼 가치가 있는 확장자인가 — PTY 에서 주운 경로를 거르는 데 쓴다 */
16
+ export declare function isKnownExt(file: string): boolean;
17
+ /**
18
+ * ANSI 제어 시퀀스와 TUI 가 그리는 테두리 문자를 걷어낸다.
19
+ *
20
+ * 경로를 주우려면 필요하다 — 에이전트 TUI 는 `│ Edited src/a.ts │` 처럼 테두리 안에 글자를
21
+ * 그리고, 색을 붙이려고 경로 중간에 SGR 을 끼워 넣기도 한다.
22
+ */
23
+ export declare function stripAnsi(data: string): string;
24
+ /**
25
+ * 출력 한 조각에서 파일 경로 후보를 뽑는다.
26
+ *
27
+ * 여기서는 **후보까지만** 낸다 — 실제로 있는 파일인지, 상대경로를 어느 cwd 로 푸는지는
28
+ * 패널이 fs 로 확인한다. 순수 함수로 남겨 두면 규칙을 테스트로 고정할 수 있다.
29
+ *
30
+ * 걸러내는 것: 확장자를 모르는 것 / 잘려서 `…` 이 들어간 것 / URL / 버전 번호처럼 보이는 것.
31
+ */
32
+ export declare function extractPaths(data: string): string[];
33
+ /**
34
+ * 최근 목록에 하나를 얹는다 (같은 것은 위로 올리고, 최대 개수를 넘으면 뒤를 버린다).
35
+ * 원본을 바꾸지 않고 새 배열을 돌려준다 — 렌더가 이전 배열과 비교할 수 있어야 한다.
36
+ */
37
+ export declare function pushRecent(list: readonly string[], file: string, max: number): string[];
38
+ /**
39
+ * CSV/TSV 한 장을 표로 가른다.
40
+ *
41
+ * 따옴표로 감싼 칸(`"a,b"`)과 그 안의 이스케이프(`""`)까지만 본다 — 기획데이터를 편집하는
42
+ * 도구가 아니라 눈으로 확인하는 미리보기라서 그 이상은 필요하지 않다.
43
+ */
44
+ export declare function parseDelimited(text: string, delimiter?: string): string[][];
45
+ /** 확장자로 구분자를 고른다 */
46
+ export declare function delimiterFor(file: string): string;
47
+ export declare function formatBytes(bytes: number): string;
48
+ /**
49
+ * 새 파일을 주웠을 때 패널이 스스로 무엇을 할지.
50
+ *
51
+ * - `open` : 닫혀 있으면 **열면서** 띄운다
52
+ * - `show` : 읽어만 둔다 — 열려 있으면 그 자리에 띄우고, 닫혀 있으면 **다음에 열 때** 보이게
53
+ * 대상만 갈아 둔다 (기본). 스스로 열지는 않는다
54
+ * - `manual` : 아무것도 하지 않는다. 경로는 최근 칩에만 쌓이고 여닫기·고르기는 사람 몫이다
55
+ *
56
+ * 사용자에게는 이게 목록이 아니라 **토글 두 개**로 보인다 (`viewerPreload`/`viewerAutoOpen`) —
57
+ * `followModeOf` 가 그 둘을 여기로 접는다. 안쪽을 셋으로 유지하는 이유는 판정이 세 갈래이고
58
+ * (`planFollow`) 테스트가 그 표를 계약으로 박아 두었기 때문이다.
59
+ */
60
+ export type FollowMode = 'open' | 'show' | 'manual';
61
+ /**
62
+ * 토글 두 개를 모드로 접는다.
63
+ *
64
+ * - 읽어두기 끔 → `manual` (자동으로 열기는 의미가 없어진다)
65
+ * - 읽어두기 + 자동으로 열기 → `open`
66
+ * - 읽어두기만 → `show` (기본)
67
+ *
68
+ * 두 축으로 가른 이유 — 목록 하나로는 "내용을 채워 둘까" 와 "화면을 빼앗아도 될까" 를 한 번에
69
+ * 골라야 했다. 사람이 실제로 정하고 싶은 것은 그 둘이 따로다 (2026-09-10 유저 결정:
70
+ * "읽어두기는 켜고, 자동으로 열기는 꺼라 — 내가 열면 그때까지 만진 게 보이면 된다").
71
+ */
72
+ export declare function followModeOf(preload: unknown, autoOpen: unknown): FollowMode;
73
+ /**
74
+ * 옛 설정을 토글 두 개로 옮긴다 — 기동 때 **한 번만** 돈다 (`migrateFollowConfig`).
75
+ *
76
+ * 고른 적이 없으면 `null` 을 주고, 그러면 새 기본값(읽어두기 ON / 자동열기 OFF)이 그대로 쓰인다.
77
+ * 읽는 시점에 옛 값을 보는 방식(0.17.0 의 `followMode(raw, legacy)`)을 버린 이유는, 토글은
78
+ * boolean 이라 "아직 안 골랐다" 를 표현할 자리가 없어서다 — 빈 값을 두면 토글이 꺼져 보이는데
79
+ * 실제 동작은 켜져 있는 상태가 된다. 그래서 한 번 적고 옛 값을 비운다.
80
+ */
81
+ export declare function migrateFollow(raw: unknown, legacy?: unknown): {
82
+ preload: boolean;
83
+ autoOpen: boolean;
84
+ } | null;
85
+ /**
86
+ * 새 파일을 주웠다 — 지금 무엇을 할까.
87
+ *
88
+ * - `none` : 아무것도 하지 않는다 (칩만 쌓인다)
89
+ * - `show` : 이미 열려 있으니 그 자리에 띄운다
90
+ * - `open` : 닫혀 있으니 열면서 띄운다
91
+ * - `stage` : 닫혀 있다 — 그리지 않고 **대상만 갈아 둔다.** 사람이 여는 순간 이 파일이 보인다
92
+ *
93
+ * `stage` 를 둔 이유 — 예전에는 이 자리가 `none` 이라, 닫아 두고 일하다 패널을 열면 **아까
94
+ * 보던 옛 파일**이 떠 있었다(`lastViewed` 가 그때 멈춰 있었다). "작업 막 진행하다가 패널을
95
+ * 열면 지금까지 건드린 것이 보여야 한다" 가 이 패널의 요점이므로, 열지는 않되 읽어는 둔다.
96
+ *
97
+ * **편집 중에는 무조건 `none`** 이다 — 자동으로 화면을 바꾸면 사람이 치던 것을 밀어낸다.
98
+ * 모드보다 이 규칙이 앞선다.
99
+ */
100
+ export declare function planFollow(mode: FollowMode, opened: boolean, editing: boolean): 'none' | 'show' | 'open' | 'stage';
@@ -18,15 +18,23 @@
18
18
  프롬프트 컨텍스트로 주입되기 때문이다.
19
19
 
20
20
  .PARAMETER Status
21
- running(진행중) / waiting(승인대기) / done(완료) / error(오류) / idle(대기)
21
+ running(진행중) / waiting(승인대기) / limited(한도 도달) / done(완료) / error(오류) / idle(대기)
22
+
23
+ StopFailure 훅에서는 -Status 를 그대로 쓰지 않는다 — 훅 JSON 의 `error` 가 rate_limit(사용량 한도)이면
24
+ limited 로, 그 밖이면 error 로 보낸다. 이벤트 하나에 matcher 두 개를 거는 대신 여기서 가른다.
22
25
 
23
26
  .EXAMPLE
24
- # settings.json
25
- # "UserPromptSubmit": powershell -NoProfile -File agentdeck-notify.ps1 -Status running
26
- # "Stop": powershell -NoProfile -File agentdeck-notify.ps1 -Status done
27
+ # settings.json (src/claudeHooks.ts PLAN 이 원본)
28
+ # "UserPromptSubmit": -Status running 지시를 받았다
29
+ # "Notification": -Status waiting 승인을 기다린다 (유휴 알림은 걸러낸다)
30
+ # "PostToolUse": -Status running 승인 뒤 도구가 돌았다
31
+ # "PostToolUseFailure": -Status running 도구가 실패했다 — 에이전트는 계속 일한다
32
+ # "PermissionDenied": -Status running 사람이 거부했다 — 에이전트는 계속 일한다
33
+ # "Stop": -Status done 답이 끝났다
34
+ # "StopFailure": -Status error 턴이 실패로 끝났다 (rate_limit 이면 limited)
27
35
  #>
28
36
  param(
29
- [ValidateSet('running', 'waiting', 'done', 'error', 'idle')]
37
+ [ValidateSet('running', 'waiting', 'limited', 'done', 'error', 'idle')]
30
38
  [string]$Status,
31
39
 
32
40
  # 사람이 셸에서 직접 붙이는 작업 이름. 이때만 라벨을 보낸다
@@ -85,22 +93,55 @@ if (Test-Path $file) {
85
93
  } catch { }
86
94
  }
87
95
 
88
- # --- 프로세스 계보(pids) ---
89
- # 사이드바가 이 보고를 어느 탭에 붙일지 정하는 근거. 훅 프로세스의 조상을 위로 따라가면
90
- # (훅 pwsh) <- bash <- claude.exe <- 탭 셸(powershell/pwsh) <- Tabby.exe 가 나오고,
91
- # 플러그인은 탭별 셸 PID 와 맞춰 어느 탭인지 확정한다 (src/bind.ts).
92
- # 예전 규칙 "처음 보고할 때의 활성 탭" 은 끝난 세션의 done 이 새 탭에 박히는 사고를 냈다 (2026-09-02 실측).
96
+ # --- StopFailure: 한도 도달인가 그냥 오류인가 ---
97
+ # 턴이 실패로 끝나면 Claude Code 는 Stop 대신 StopFailure 를 쏘고 `error` 에 원인 코드를 싣는다
98
+ # (rate_limit / overloaded / server_error / authentication_failed / max_output_tokens …, 2.1.263 실측).
99
+ # 사용량 한도(429 "You've hit your session limit · resets 12pm")는 error=rate_limit 이다 — 사람이 승인할 것이
100
+ # 없고 리셋까지 기다려야 하는 상태라 승인대기·오류와 구분해 limited 로 보낸다. 나머지는 error.
101
+ # 부연(reason)에는 limited 면 화면에 찍힌 마지막 문장(last_assistant_message: 리셋 시각이 들어 있다)을,
102
+ # 그 밖의 오류면 error 코드를 싣는다. 줄이는 일은 플러그인(src/reason.ts)이 한다.
103
+ $failReason = ''
104
+ if ($hook -and [string]$hook.hook_event_name -eq 'StopFailure') {
105
+ $code = [string]$hook.error
106
+ $Status = if ($code -eq 'rate_limit') { 'limited' } else { 'error' }
107
+ # limited 는 화면 문구(리셋 시각이 들어 있다), 그 밖은 error 코드만 — 상세(error_details)는 배지 한 줄에 안 들어간다
108
+ $failReason = if ($Status -eq 'limited' -and $hook.last_assistant_message) { [string]$hook.last_assistant_message } else { $code }
109
+ }
110
+
111
+ # --- 진행중 중복 보고 생략 ---
112
+ # PostToolUse 는 도구가 돌 때마다 발화한다. 이미 running 인데 running 을 또 쓰면 파일·TCP 만 흔들고
113
+ # 사이드바는 변하지 않는다(경과시간이 매 도구마다 0 으로 되돌아가기까지 한다). 라벨 지정도 없으면 여기서 끝낸다 —
114
+ # 아래 계보 조회(~450ms)까지 건너뛰므로 도구마다 붙는 비용이 사실상 없다
115
+ if ($Status -eq 'running' -and $prevStatus -eq 'running' -and -not $Label) { exit 0 }
116
+
117
+ # --- 어느 탭인가: tabId (1순위) / 프로세스 계보 pids (폴백) ---
118
+ # 사이드바가 이 보고를 어느 탭에 붙일지 정하는 근거. 예전 규칙 "처음 보고할 때의 활성 탭" 은
119
+ # 끝난 세션의 done 이 새 탭에 박히는 사고를 냈다 (2026-09-02 실측). 지금은 두 단계다.
120
+ #
121
+ # 1) tabId — 플러그인이 탭을 열 때 그 셸의 환경에 AGENTDECK_TAB=<id> 를 심는다 (src/tabenv.ts,
122
+ # notify.service.ts stampRoot). 그 셸에서 뜬 claude 와 이 훅은 환경을 그대로 물려받으므로
123
+ # $env:AGENTDECK_TAB 을 읽어 보내면 플러그인이 표에서 바로 찾는다. 이게 있으면 아래 계보 조회를
124
+ # 통째로 건너뛴다 — Win32_Process 전체 조회(~450ms)가 빠져 훅이 수십 ms 안에 끝난다.
125
+ # $prev 에 남은 pids 캐시는 읽지도 않는다 — payload 에 pids 를 넣지 않으니 무해하다.
93
126
  #
94
- # 훅 JSON 이 있을 때만 계산한다 — 셸에서 사람이 -SessionId 로 직접 부르면 조상이 탭 셸 자체라
95
- # 걸러지고 Tabby.exe 만 남아 어느 탭에도 안 맞는다. 그 경로는 예전 활성 탭 규칙에 맡긴다.
127
+ # 2) pids — 환경변수가 없는 셸: 이 버전 이전에 열린 탭, 재시작으로 복원된 탭(셸이 이미 떠 있어 새 값을
128
+ # 못 심는다), Tabby 밖에서 뜬 claude. 훅 프로세스의 조상을 위로 따라가면
129
+ # (훅 pwsh) <- bash <- claude.exe <- 탭 셸(powershell/pwsh) <- Tabby.exe 가 나오고,
130
+ # 플러그인은 탭별 셸 PID 와 맞춰 어느 탭인지 확정한다 (src/bind.ts).
96
131
  #
97
- # 비용 — Win32_Process 전체 조회가 ~450ms 라 세션당 한 번만 하고 status 파일에 캐시한다
98
- # (홉마다 필터 조회하면 ~2초로 더 느리다). 캐시는 claude 프로세스(claudePid)가 살아 있고
99
- # 이름이 같을 때만 재사용한다 — `claude --resume` 을 다른 탭에서 띄우면 PID 가 바뀌어 다시 계산된다.
132
+ # 훅 JSON 이 있을 때만 계산한다 — 셸에서 사람이 -SessionId 로 직접 부르면 조상이 탭 셸 자체라
133
+ # 걸러지고 Tabby.exe 만 남아 어느 탭에도 안 맞는다. 그 경로는 예전 활성 탭 규칙에 맡긴다.
134
+ #
135
+ # 비용 — Win32_Process 전체 조회가 ~450ms 라 세션당 한 번만 하고 status 파일에 캐시한다
136
+ # (홉마다 필터 조회하면 ~2초로 더 느리다). 캐시는 claude 프로세스(claudePid)가 살아 있고
137
+ # 이름이 같을 때만 재사용한다 — `claude --resume` 을 다른 탭에서 띄우면 PID 가 바뀌어 다시 계산된다.
138
+ $tabId = ([string]$env:AGENTDECK_TAB).Trim()
100
139
  $pids = @()
101
140
  $claudePid = 0
102
141
  $claudeName = ''
103
- if ($hook) {
142
+ if ($tabId) {
143
+ # 탭이 확정됐다 — 계보는 계산하지 않는다
144
+ } elseif ($hook) {
104
145
  $reuse = $false
105
146
  if ($prev -and $prev.pids -and $prev.claudePid) {
106
147
  $aliveProc = Get-Process -Id ([int]$prev.claudePid) -ErrorAction SilentlyContinue
@@ -148,10 +189,26 @@ if ($hook) {
148
189
  if ($Status -eq 'waiting') {
149
190
  $msg = if ($hook -and $hook.message) { [string]$hook.message } else { '' }
150
191
  $idleNotice = $msg -match '(?i)waiting for your input|idle'
151
- $alreadyFinished = $prevStatus -eq 'done' -or $prevStatus -eq 'idle'
192
+ $alreadyFinished = $prevStatus -eq 'done' -or $prevStatus -eq 'idle' -or $prevStatus -eq 'limited'
152
193
  if ($idleNotice -or $alreadyFinished) { exit 0 }
153
194
  }
154
195
 
196
+ # --- 부연(reason) ---
197
+ # waiting: Notification 의 message 원문("Claude needs your permission to use Bash" 등).
198
+ # limited/error: 위 StopFailure 블록이 고른 문장.
199
+ # 짧게 줄이는 일(-> "Bash 권한", "12pm 리셋")은 플러그인(src/reason.ts)이 한다 — 문구 규칙이 바뀌면 한 곳만 고치면 된다.
200
+ # 해당 상태일 때만 넣고 다른 상태에서는 키 자체를 빼서, 플러그인이 상태가 바뀌면 이유를 비우게 한다.
201
+ $reason = ''
202
+ if ($Status -eq 'waiting' -and $hook -and $hook.message) {
203
+ $reason = [string]$hook.message
204
+ } elseif ($failReason) {
205
+ $reason = $failReason
206
+ }
207
+ if ($reason) {
208
+ $reason = ($reason -replace '\s+', ' ').Trim()
209
+ if ($reason.Length -gt 120) { $reason = $reason.Substring(0, 120).TrimEnd() }
210
+ }
211
+
155
212
  # --- 라벨 결정 ---
156
213
  # **이 훅은 라벨을 만들지 않는다.** 작업 이름은 플러그인이 Enter 시점에 입력창을 읽어
157
214
  # 무조건 갱신하는 경로(claimEnterLabel / enterAsLabel)가 전담한다. 훅이 낼 수 있는 건
@@ -177,6 +234,8 @@ $payload = [ordered]@{
177
234
  ts = [int64](([datetime]::UtcNow - [datetime]'1970-01-01').TotalMilliseconds)
178
235
  }
179
236
  if ($newLabel) { $payload['label'] = $newLabel }
237
+ if ($reason) { $payload['reason'] = $reason }
238
+ if ($tabId) { $payload['tabId'] = $tabId }
180
239
  if ($pids.Count -gt 0) {
181
240
  $payload['pids'] = [int[]]$pids
182
241
  $payload['claudePid'] = $claudePid
@@ -11,7 +11,7 @@
11
11
  ConPTY 가 API 로 변환해 전달하므로 확실히 통과한다.
12
12
 
13
13
  .PARAMETER Status
14
- running(진행중) / waiting(승인대기) / done(완료) / error(오류) / idle(대기)
14
+ running(진행중) / waiting(승인대기) / limited(한도 도달) / done(완료) / error(오류) / idle(대기)
15
15
 
16
16
  .PARAMETER Label
17
17
  사이드바에 함께 보일 작업 이름.
@@ -22,7 +22,7 @@
22
22
  #>
23
23
  param(
24
24
  [Parameter(Mandatory = $true)]
25
- [ValidateSet('running', 'waiting', 'done', 'error', 'idle')]
25
+ [ValidateSet('running', 'waiting', 'limited', 'done', 'error', 'idle')]
26
26
  [string]$Status,
27
27
 
28
28
  [string]$Label = ''
package/install.ps1 CHANGED
@@ -1,17 +1,12 @@
1
1
  <#
2
2
  .SYNOPSIS
3
- AgentDeck 플러그인을 Tabby 에 연결하고, 관리자 권한 실행 바로가기를 만든다.
3
+ AgentDeck 플러그인을 Tabby 에 연결한다.
4
4
 
5
5
  .DESCRIPTION
6
6
  Tabby 는 사용자 플러그인 디렉토리(userData/plugins/node_modules)를 스캔하므로
7
7
  이 스크립트는 그곳에 프로젝트 폴더를 가리키는 junction 을 만든다.
8
8
  소스를 고치고 `npm run build` 만 하면 Tabby 재시작으로 바로 반영된다.
9
9
 
10
- .PARAMETER Shortcut
11
- 바탕화면에 "Tabby (AgentDeck)" 관리자 권한 바로가기를 만든다.
12
- Tabby 를 관리자로 띄우면 그 안에서 열리는 모든 탭이 권한을 물려받으므로
13
- 탭마다 UAC 창이 뜨는 것을 피할 수 있다.
14
-
15
10
  .PARAMETER Hooks
16
11
  Claude Code 설정(~/.claude/settings.json)에 상태 통보 훅을 등록한다.
17
12
 
@@ -20,10 +15,9 @@
20
15
  등록하지 않아도 동작은 하지만(출력 패턴 폴백) 판정이 그만큼 흔들린다.
21
16
 
22
17
  .EXAMPLE
23
- powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1 -Shortcut -Hooks
18
+ powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1 -Hooks
24
19
  #>
25
20
  param(
26
- [switch]$Shortcut,
27
21
  [switch]$Hooks
28
22
  )
29
23
 
@@ -113,28 +107,5 @@ if ($Hooks) {
113
107
  Write-Host "저장: $settingsPath (백업: $settingsPath.agentdeck-backup)"
114
108
  }
115
109
 
116
- # 3) 관리자 권한 바로가기
117
- if ($Shortcut) {
118
- $exe = Join-Path $env:LOCALAPPDATA 'Programs\Tabby\Tabby.exe'
119
- if (-not (Test-Path $exe)) {
120
- throw "Tabby.exe 를 찾지 못했다: $exe"
121
- }
122
-
123
- $lnkPath = Join-Path ([Environment]::GetFolderPath('Desktop')) 'Tabby (AgentDeck).lnk'
124
- $shell = New-Object -ComObject WScript.Shell
125
- $lnk = $shell.CreateShortcut($lnkPath)
126
- $lnk.TargetPath = $exe
127
- $lnk.WorkingDirectory = Split-Path $exe
128
- $lnk.Description = 'Tabby + AgentDeck (관리자 권한)'
129
- $lnk.Save()
130
-
131
- # 바로가기에 "관리자 권한으로 실행" 플래그를 세운다 (.lnk 바이너리의 21번째 바이트 0x20 비트)
132
- $bytes = [System.IO.File]::ReadAllBytes($lnkPath)
133
- $bytes[0x15] = $bytes[0x15] -bor 0x20
134
- [System.IO.File]::WriteAllBytes($lnkPath, $bytes)
135
-
136
- Write-Host "바로가기 생성: $lnkPath (관리자 권한)"
137
- }
138
-
139
110
  Write-Host ""
140
111
  Write-Host "Tabby 를 재시작하면 적용된다."
package/package.json CHANGED
@@ -1,50 +1,50 @@
1
- {
2
- "name": "tabby-agentdeck",
3
- "version": "0.2.1",
4
- "description": "Run AI coding agents side by side in Tabby - a live deck of agent sessions with status, agent-friendly hotkeys and image paste",
5
- "keywords": [
6
- "tabby-plugin",
7
- "tabby",
8
- "ai",
9
- "agent",
10
- "claude-code",
11
- "codex",
12
- "terminal"
13
- ],
14
- "main": "dist/index.js",
15
- "typings": "dist/index.d.ts",
16
- "scripts": {
17
- "build": "webpack --progress --color",
18
- "watch": "webpack --progress --color --watch",
19
- "test": "tsc src/prompt.ts src/detect.ts src/claudeHooks.ts src/screen.ts src/bind.ts --outDir .tmp --module commonjs --target es2019 --skipLibCheck --experimentalDecorators --esModuleInterop && node test/prompt.test.js && node test/detect.test.js && node test/claudeHooks.test.js && node test/screen.test.js && node test/bind.test.js"
20
- },
21
- "files": [
22
- "dist",
23
- "hooks",
24
- "install.ps1"
25
- ],
26
- "license": "MIT",
27
- "devDependencies": {
28
- "@angular/common": "^15.2.6",
29
- "@angular/core": "^15.2.6",
30
- "@angular/forms": "^15.2.6",
31
- "@types/node": "^20.19.43",
32
- "@types/webpack-env": "^1.18.4",
33
- "css-loader": "^6.10.0",
34
- "rxjs": "^7.5.7",
35
- "sass": "^1.71.1",
36
- "sass-loader": "^14.1.1",
37
- "style-loader": "^3.3.4",
38
- "tabby-core": "^1.0.231-nightly.0",
39
- "tabby-local": "^1.0.231-nightly.0",
40
- "tabby-settings": "^1.0.231-nightly.0",
41
- "tabby-terminal": "^1.0.231-nightly.0",
42
- "ts-loader": "^9.5.1",
43
- "typescript": "^4.9.5",
44
- "webpack": "^5.90.0",
45
- "webpack-cli": "^5.1.4"
46
- },
47
- "author": {
48
- "name": "junggon"
49
- }
50
- }
1
+ {
2
+ "name": "tabby-agentdeck",
3
+ "version": "1.0.0",
4
+ "description": "Run AI coding agents side by side in Tabby - a live deck of agent sessions with status, a preview panel for the files they touch, agent-friendly hotkeys and image paste",
5
+ "keywords": [
6
+ "tabby-plugin",
7
+ "tabby",
8
+ "ai",
9
+ "agent",
10
+ "claude-code",
11
+ "codex",
12
+ "terminal"
13
+ ],
14
+ "main": "dist/index.js",
15
+ "typings": "dist/index.d.ts",
16
+ "scripts": {
17
+ "build": "webpack --progress --color",
18
+ "watch": "webpack --progress --color --watch",
19
+ "test": "tsc src/prompt.ts src/detect.ts src/claudeHooks.ts src/screen.ts src/bind.ts src/order.ts src/reason.ts src/tabenv.ts src/viewer.ts src/markdown.ts src/ime.ts src/gitDiff.ts src/agents.ts src/group.ts src/gitCommit.ts src/diag.ts src/subagents.ts src/nav.ts src/api.ts src/dock.ts src/status.service.ts src/profile.service.ts src/recovery.service.ts --outDir .tmp --module commonjs --target es2019 --skipLibCheck --experimentalDecorators --esModuleInterop && node test/prompt.test.js && node test/detect.test.js && node test/claudeHooks.test.js && node test/screen.test.js && node test/bind.test.js && node test/order.test.js && node test/reason.test.js && node test/tabenv.test.js && node test/viewer.test.js && node test/markdown.test.js && node test/ime.test.js && node test/gitDiff.test.js && node test/agents.test.js && node test/group.test.js && node test/gitCommit.test.js && node test/diag.test.js && node test/subagents.test.js && node test/nav.test.js && node test/api.test.js && node test/dock.test.js && node test/status.service.test.js && node test/profile.service.test.js && node test/recovery.service.test.js"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "hooks",
24
+ "install.ps1"
25
+ ],
26
+ "license": "MIT",
27
+ "devDependencies": {
28
+ "@angular/common": "^15.2.6",
29
+ "@angular/core": "^15.2.6",
30
+ "@angular/forms": "^15.2.6",
31
+ "@types/node": "^20.19.43",
32
+ "@types/webpack-env": "^1.18.4",
33
+ "css-loader": "^6.10.0",
34
+ "rxjs": "^7.5.7",
35
+ "sass": "^1.71.1",
36
+ "sass-loader": "^14.1.1",
37
+ "style-loader": "^3.3.4",
38
+ "tabby-core": "^1.0.231-nightly.0",
39
+ "tabby-local": "^1.0.231-nightly.0",
40
+ "tabby-settings": "^1.0.231-nightly.0",
41
+ "tabby-terminal": "^1.0.231-nightly.0",
42
+ "ts-loader": "^9.5.1",
43
+ "typescript": "^4.9.5",
44
+ "webpack": "^5.90.0",
45
+ "webpack-cli": "^5.1.4"
46
+ },
47
+ "author": {
48
+ "name": "junggon"
49
+ }
50
+ }