coxpit 5.7.0 → 5.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coxpit",
3
- "version": "5.7.0",
3
+ "version": "5.9.0",
4
4
  "description": "Self-hosted cockpit for running a fleet of AI coding agents across your own machines — parallel worktree runs, live board, compare & merge, web terminal, design capture.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/board.ts CHANGED
@@ -882,7 +882,7 @@ ${ICON_SPRITE}
882
882
  <div class="ws"><span class="dot" id="wsdot"></span><span id="wstext">connecting</span></div>
883
883
  <button class="btn-ghost sm" id="bell" title="notify when a run settles"><svg class="ic"><use href="#i-bell-off"/></svg></button>
884
884
  <button class="btn-ghost sm" id="remoteBtn" title="reach this daemon from elsewhere (Tailscale · recipes)"><svg class="ic"><use href="#i-external-link"/></svg></button>
885
- <a class="cockpit-link" href="/cockpit" title="터미널 우선 셸 (preview)">◨ Cockpit</a>
885
+ <a class="cockpit-link" href="/cockpit" title="터미널 우선 셸 — 데스크톱 앱 기본 뷰">◨ Cockpit</a>
886
886
  <div class="machines" id="machines"></div>
887
887
  </header>
888
888
  <div class="scrim" id="scrim"></div>
package/src/cockpit.ts CHANGED
@@ -81,7 +81,7 @@ export const COCKPIT_HTML = /* html */ `<!doctype html>
81
81
  .pb-btn{background:none;border:1px solid var(--line);border-radius:6px;color:var(--muted);font-size:11px;padding:3px 9px;cursor:pointer;font-family:var(--mono)}
82
82
  .pb-btn:hover:not([disabled]){color:var(--ink);border-color:var(--line-hi)}
83
83
  .pb-btn[disabled]{opacity:.4;cursor:default}
84
- .panes{flex:1;display:grid;gap:1px;background:var(--line);padding:1px;min-height:0}
84
+ .panes{flex:1;display:none;gap:1px;background:var(--line);padding:1px;min-height:0} /* 초기 숨김 — layoutPanes 가 페인 있을 때만 grid 로 */
85
85
  .pane{display:flex;flex-direction:column;background:var(--bg);min-width:0;min-height:0;overflow:hidden}
86
86
  .pane.focus .pane-h{background:var(--brand-dim)}
87
87
  .pane.focus{box-shadow:inset 0 0 0 1px rgba(78,201,176,.4)}
@@ -109,7 +109,13 @@ export const COCKPIT_HTML = /* html */ `<!doctype html>
109
109
  .empty .card{max-width:440px}
110
110
  .empty .glyph{font-family:var(--mono);font-size:24px;color:#2c3444;letter-spacing:5px;margin-bottom:14px}
111
111
  .empty h1{font-family:var(--mono);font-size:16px;margin:0 0 8px;color:var(--ink)}
112
- .empty p{color:var(--muted);font-size:13px;margin:0}
112
+ .empty p{color:var(--muted);font-size:13px;margin:0 0 18px}
113
+ .empty .cta{display:inline-flex;align-items:center;gap:8px;font-family:var(--mono);font-size:13px;font-weight:600;
114
+ color:var(--brand-ink);background:var(--brand);border:none;border-radius:9px;padding:10px 16px;cursor:pointer}
115
+ .empty .cta:hover{filter:brightness(1.06)}
116
+ .empty .hint{color:var(--faint);font-size:11.5px;margin-top:12px}
117
+ .pb-btn.session{color:var(--brand);border-color:rgba(78,201,176,.35)}
118
+ .pb-btn.session:hover:not([disabled]){background:var(--brand-dim);border-color:var(--brand)}
113
119
 
114
120
  .reqbar{display:flex;align-items:center;gap:9px;border-top:1px solid var(--line);background:var(--surface);padding:9px 12px;font-family:var(--mono)}
115
121
  .modes{display:inline-flex;gap:2px;border:1px solid var(--line);border-radius:8px;padding:2px;background:var(--panel)}
@@ -172,8 +178,7 @@ export const COCKPIT_HTML = /* html */ `<!doctype html>
172
178
  </div>
173
179
  <div class="right">
174
180
  <span class="ws" id="ws"><span class="dot"></span><span id="wstext">connecting</span></span>
175
- <span class="wip">preview · Phase 4</span>
176
- <a class="toggle" href="/">← Board</a>
181
+ <a class="toggle" href="/" title="보드(모니터) 뷰로">← Board</a>
177
182
  </div>
178
183
  </header>
179
184
 
@@ -189,14 +194,17 @@ export const COCKPIT_HTML = /* html */ `<!doctype html>
189
194
  <span id="paneCount">0 panes</span>
190
195
  <span style="color:var(--faint)">· run 을 열수록 자동 분할(타일)</span>
191
196
  <span class="grow"></span>
197
+ <button class="pb-btn session" id="sessionBtn" title="에이전트에 안 묶인 자유 작업 세션(터미널) 열기">+ Session</button>
192
198
  <button class="pb-btn" id="closeBtn" disabled title="포커스 페인 닫기">× close focused</button>
193
199
  </div>
194
200
  <div class="panes" id="panes"></div>
195
201
  <div class="empty" id="empty">
196
202
  <div class="card">
197
203
  <div class="glyph">⌗ ⌗ ⌗</div>
198
- <h1>페인이 비어 있습니다</h1>
199
- <p>왼쪽 트리에서 <b>run</b> 을 클릭하면 에이전트 터미널이 여기 페인으로 열립니다. 여러 열면 자동으로 분할(타일)됩니다.</p>
204
+ <h1>여기서 작업을 시작하세요</h1>
205
+ <p>직접 몰고 <b>작업 세션</b>(자유 터미널)열거나, 아래 요청바로 에이전트를 팬아웃하세요. 트리의 <b>run</b> 클릭해도 터미널이 페인으로 열립니다.</p>
206
+ <button class="cta" id="sessionCta">+ 새 작업 세션 열기</button>
207
+ <div class="hint">세션 = repo 워크트리 + tmux 셸. 그 안에서 <code>claude</code> 를 띄워 “이 프로젝트 구현해줘” 처럼 직접 지시할 수 있습니다.</div>
200
208
  </div>
201
209
  </div>
202
210
  <div class="reqbar">
@@ -453,6 +461,30 @@ export const COCKPIT_HTML = /* html */ `<!doctype html>
453
461
  }
454
462
  $('closeBtn').addEventListener('click', function(){ if (focusId) closePane(focusId); });
455
463
 
464
+ // ── 자유 작업 세션(workbench) — 에이전트에 안 묶인 터미널. repo 워크트리 + tmux 셸. ──
465
+ var openingSession = false;
466
+ async function openSession(){
467
+ if (openingSession) return;
468
+ var repos = fleet.repos||[];
469
+ if (!repos.length){ toast('먼저 repo 를 등록하세요 — 보드(← Board)에서 Add repository'); return; }
470
+ var repoId = Number($('reqRepo').value) || repos[0].id;
471
+ var rp = repoById[repoId];
472
+ openingSession = true; $('sessionBtn').disabled = true;
473
+ try{
474
+ var res = await fetch('/api/workbench',{method:'POST',headers:{'content-type':'application/json'},
475
+ body:JSON.stringify({repoId:repoId, title:'Session'})});
476
+ var j = await res.json().catch(function(){return{};});
477
+ if (res.ok && j.runId){
478
+ await hydrate();
479
+ openRunPane(j.runId);
480
+ toast('세션 열림'+(rp?(' · '+rp.name):'')+' — 이 터미널에서 직접 에이전트를 구동하세요');
481
+ } else { toast('세션 실패: '+(j.detail||j.error||res.status)); }
482
+ }catch(e){ toast('세션 실패: '+e); }
483
+ finally{ openingSession=false; $('sessionBtn').disabled=false; }
484
+ }
485
+ $('sessionBtn').addEventListener('click', openSession);
486
+ $('sessionCta').addEventListener('click', openSession);
487
+
456
488
  // ── 요청바: New(팬아웃) / Steer / Broadcast ──
457
489
  var reqMode = 'new';
458
490
  function focusRun(){ if (!focusId) return null; var p = panes.find(function(x){return x.id===focusId;}); return p?p.runId:null; }
@@ -640,6 +672,7 @@ export const COCKPIT_HTML = /* html */ `<!doctype html>
640
672
  function scheduleHydrate(){ if (hydT) return; hydT = setTimeout(function(){ hydT=null; hydrate(); }, 400); }
641
673
 
642
674
  setMode('new');
675
+ layoutPanes(); // 초기 빈 상태 정합(paneCount·close 비활성·panes 숨김)
643
676
  hydrate();
644
677
  wsConnect();
645
678
  window.addEventListener('resize', function(){ panes.forEach(fitPane); });