coxpit 5.0.1 → 5.0.3
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 +1 -1
- package/src/board.ts +49 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coxpit",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.3",
|
|
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
|
@@ -58,7 +58,10 @@ export const BOARD_HTML = /* html */ `<!doctype html>
|
|
|
58
58
|
.mdot.on{background:var(--s-done)}
|
|
59
59
|
|
|
60
60
|
/* ── layout ─────────────────────────────── */
|
|
61
|
-
|
|
61
|
+
/* fixed viewport height so the rail stays put and each column scrolls on its own
|
|
62
|
+
(the board grew tall with many cards and dragged the rail's + New below the fold) */
|
|
63
|
+
.layout{display:grid;grid-template-columns:318px 1fr;height:calc(100vh - 55px);overflow:hidden}
|
|
64
|
+
.layout > aside,.layout > main{min-height:0}
|
|
62
65
|
aside{border-right:1px solid var(--line);padding:20px 18px;background:var(--surface);
|
|
63
66
|
display:flex;flex-direction:column;gap:26px}
|
|
64
67
|
main{padding:20px;overflow:auto}
|
|
@@ -138,7 +141,7 @@ export const BOARD_HTML = /* html */ `<!doctype html>
|
|
|
138
141
|
/* rail repo-row actions — icon-ghost, never white: transparent bg · muted icon · hover ink + surface */
|
|
139
142
|
#repoList .repo .rmbtn{background:transparent;border:1px solid transparent;color:var(--muted);cursor:pointer;
|
|
140
143
|
padding:3px;display:inline-flex;border-radius:6px;transition:color .15s,background .15s,border-color .15s}
|
|
141
|
-
#repoList .repo .rmbtn:hover{color:var(--ink);background:var(--
|
|
144
|
+
#repoList .repo .rmbtn:hover{color:var(--ink);background:var(--surface2)}
|
|
142
145
|
#repoList .repo .rmbtn .ic{width:13px;height:13px;color:inherit}
|
|
143
146
|
.navi{display:flex;align-items:center;gap:9px;padding:7px 10px;border-radius:8px;color:var(--muted);
|
|
144
147
|
cursor:pointer;font-size:13px;border:none;background:transparent;width:100%;text-align:left;font-family:var(--sans)}
|
|
@@ -182,9 +185,24 @@ export const BOARD_HTML = /* html */ `<!doctype html>
|
|
|
182
185
|
.sheet-h .sp{flex:1}.sheet-h .x{color:var(--muted);cursor:pointer;background:none;border:none;padding:2px}
|
|
183
186
|
.sheet #taskForm{display:flex;flex-direction:column;gap:13px;min-height:0}
|
|
184
187
|
.sheet-body{display:flex;flex-direction:column;gap:8px;overflow-y:auto;min-height:0;max-height:60vh;padding:1px}
|
|
185
|
-
.sheet-f{display:flex;align-items:center;gap:
|
|
186
|
-
.sheet-f #modeSeg{flex:
|
|
187
|
-
.sheet-f #
|
|
188
|
+
.sheet-f{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding-top:12px;border-top:1px solid var(--line)}
|
|
189
|
+
.sheet-f #modeSeg{flex:0 0 auto}
|
|
190
|
+
.sheet-f #taskCountStep{flex:0 0 auto;margin-left:auto}
|
|
191
|
+
.sheet-f #runFleetBtn{flex:1 1 100%;justify-content:center}
|
|
192
|
+
/* agent-mode switch — compact toggle (dry ⇄ real), never a native checkbox/white box */
|
|
193
|
+
.realtog{display:inline-flex;align-items:center;gap:8px;background:#0e1118;border:1px solid var(--line);
|
|
194
|
+
border-radius:999px;padding:5px 13px 5px 6px;cursor:pointer;font-family:var(--sans);font-size:12px;
|
|
195
|
+
font-weight:600;color:var(--muted);white-space:nowrap;transition:color .15s,border-color .15s}
|
|
196
|
+
.realtog:hover{border-color:var(--brand)}
|
|
197
|
+
.realtog .realtog-knob{width:30px;height:17px;border-radius:999px;background:var(--surface2);
|
|
198
|
+
position:relative;flex:none;transition:background .18s}
|
|
199
|
+
.realtog .realtog-knob::after{content:"";position:absolute;top:2px;left:2px;width:13px;height:13px;
|
|
200
|
+
border-radius:50%;background:var(--faint);transition:transform .18s,background .18s}
|
|
201
|
+
.realtog .realtog-hint{font-family:var(--mono);font-size:10px;font-weight:400;color:var(--faint)}
|
|
202
|
+
.realtog[aria-checked="true"]{color:var(--brand);border-color:rgba(78,201,176,.4)}
|
|
203
|
+
.realtog[aria-checked="true"] .realtog-knob{background:var(--brand-dim)}
|
|
204
|
+
.realtog[aria-checked="true"] .realtog-knob::after{transform:translateX(13px);background:var(--brand)}
|
|
205
|
+
.realtog:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
|
|
188
206
|
/* progressive Options reveal (rarely-used Task fields) */
|
|
189
207
|
.opt{border:1px solid var(--line);border-radius:var(--r-ctl);background:#0e1118;overflow:hidden}
|
|
190
208
|
.opt-h{width:100%;display:flex;align-items:center;gap:8px;background:transparent;border:none;cursor:pointer;
|
|
@@ -221,7 +239,8 @@ export const BOARD_HTML = /* html */ `<!doctype html>
|
|
|
221
239
|
.dd-btn:hover{border-color:var(--line-hi)}
|
|
222
240
|
.dd.open .dd-btn{border-color:rgba(78,201,176,.55)}
|
|
223
241
|
.dd-lbl{flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
|
|
224
|
-
.dd-car{color:var(--faint);
|
|
242
|
+
.dd-car{color:var(--faint);display:inline-flex;align-items:center;transition:transform .15s}
|
|
243
|
+
.dd-car .ic{width:13px;height:13px}
|
|
225
244
|
.dd.open .dd-car{transform:rotate(180deg)}
|
|
226
245
|
.dd-panel{position:absolute;top:calc(100% + 5px);left:0;right:0;z-index:40;background:var(--surface2);
|
|
227
246
|
border:1px solid var(--line-hi);border-radius:9px;box-shadow:var(--shadow);max-height:230px;
|
|
@@ -249,7 +268,7 @@ export const BOARD_HTML = /* html */ `<!doctype html>
|
|
|
249
268
|
.seg{display:flex;gap:3px;padding:3px;border:1px solid var(--line);border-radius:var(--r-ctl);background:#0e1118}
|
|
250
269
|
/* slim single-row option — matches the type/provider seg height; the risky hint rides inline, subtle */
|
|
251
270
|
.seg-opt{flex:1;display:inline-flex;flex-direction:row;align-items:center;justify-content:center;gap:5px;
|
|
252
|
-
padding:6px 8px;border:none;min-width:0;
|
|
271
|
+
padding:6px 8px;border:none;min-width:0;white-space:nowrap;line-height:1.2;
|
|
253
272
|
background:transparent;color:var(--muted);font-size:12px;font-weight:600;cursor:pointer;
|
|
254
273
|
border-radius:calc(var(--r-ctl) - 3px);transition:background .15s,color .15s}
|
|
255
274
|
.seg-opt:hover{color:var(--ink)}
|
|
@@ -710,7 +729,7 @@ export const BOARD_HTML = /* html */ `<!doctype html>
|
|
|
710
729
|
.menu-btn{display:none;font-size:15px;padding:5px 10px}
|
|
711
730
|
.scrim{position:fixed;inset:0;top:54px;background:rgba(5,7,10,.5);z-index:29;display:none}
|
|
712
731
|
@media (max-width:860px){
|
|
713
|
-
.layout{grid-template-columns:1fr;
|
|
732
|
+
.layout{grid-template-columns:1fr;height:calc(100dvh - 55px)}
|
|
714
733
|
/* 사이드바 = 오프캔버스 드로어 — 플릿이 첫 화면, 런처는 ☰ 뒤에 */
|
|
715
734
|
.menu-btn{display:inline-flex}
|
|
716
735
|
aside{position:fixed;top:54px;bottom:0;left:0;width:min(86vw,340px);max-width:100vw;z-index:30;
|
|
@@ -880,10 +899,11 @@ ${ICON_SPRITE}
|
|
|
880
899
|
</div>
|
|
881
900
|
</div>
|
|
882
901
|
<div class="sheet-f" id="sheetFooter">
|
|
883
|
-
<
|
|
884
|
-
<
|
|
885
|
-
<
|
|
886
|
-
|
|
902
|
+
<button type="button" id="modeSeg" class="realtog" role="switch" aria-checked="false" title="Dry run rehearses the full pipeline with zero credits. Turn on to run the real agent CLI.">
|
|
903
|
+
<span class="realtog-knob"></span>
|
|
904
|
+
<span class="realtog-lbl" id="modeRealLbl">Dry run</span>
|
|
905
|
+
<span class="realtog-hint" id="modeRealHint">rehearsal</span>
|
|
906
|
+
</button>
|
|
887
907
|
<input type="checkbox" id="taskReal" hidden />
|
|
888
908
|
<div class="stepper" id="taskCountStep" title="agents — 1 for a job, N to explore variants">
|
|
889
909
|
<button type="button" class="stp" id="cntDown" aria-label="fewer agents"><svg class="ic"><use href="#i-minus"/></svg></button>
|
|
@@ -1199,7 +1219,7 @@ function dressSelect(id){
|
|
|
1199
1219
|
const sel = $(id); if(!sel || sel.dataset.dd) return;
|
|
1200
1220
|
sel.dataset.dd = '1';
|
|
1201
1221
|
const dd = document.createElement('div'); dd.className = 'dd';
|
|
1202
|
-
dd.innerHTML = '<button type="button" class="dd-btn"><span class="dd-lbl"></span><span class="dd-car"
|
|
1222
|
+
dd.innerHTML = '<button type="button" class="dd-btn"><span class="dd-lbl"></span><span class="dd-car"><svg class="ic"><use href="#i-chevron-down"/></svg></span></button><div class="dd-panel"></div>';
|
|
1203
1223
|
sel.parentNode.insertBefore(dd, sel);
|
|
1204
1224
|
sel.style.display = 'none';
|
|
1205
1225
|
dd.querySelector('.dd-btn').addEventListener('click', (e)=>{
|
|
@@ -1760,19 +1780,19 @@ function renderRail(){
|
|
|
1760
1780
|
const cnt = railCounts();
|
|
1761
1781
|
let html = '';
|
|
1762
1782
|
if (repos.length){
|
|
1763
|
-
html += '<
|
|
1764
|
-
+ ic('layers')+'<span class="nm">All repositories</span></
|
|
1783
|
+
html += '<div class="repo'+(selectedRepo==null?' on':'')+'" role="button" tabindex="0" data-repo="all">'
|
|
1784
|
+
+ ic('layers')+'<span class="nm">All repositories</span></div>';
|
|
1765
1785
|
for (const r of repos){
|
|
1766
1786
|
const c = cnt.get(r.id) || { active:0, attn:false };
|
|
1767
1787
|
const on = selectedRepo===r.id;
|
|
1768
|
-
html += '<
|
|
1788
|
+
html += '<div class="repo'+(on?' on':'')+'" role="button" tabindex="0" data-repo="'+r.id+'" title="'+escA(r.path||r.name)+'">'
|
|
1769
1789
|
+ ic('folder')+'<span class="nm">'+esc(r.name)+'</span>'
|
|
1770
1790
|
+ (c.attn ? '<span class="attn" title="a run needs a hand"></span>' : '')
|
|
1771
1791
|
+ (c.active>0 ? '<span class="cnt">'+c.active+'</span>' : '')
|
|
1772
1792
|
+ '<span class="rowmenu">'
|
|
1773
1793
|
+ '<button type="button" class="rmbtn" data-rbranch="'+r.id+'" title="base branch">'+ic('branch')+'</button>'
|
|
1774
1794
|
+ '<button type="button" class="rmbtn" data-rremove="'+r.id+'" title="remove">'+ic('x')+'</button>'
|
|
1775
|
-
+ '</span></
|
|
1795
|
+
+ '</span></div>';
|
|
1776
1796
|
}
|
|
1777
1797
|
} else {
|
|
1778
1798
|
// empty state — 첫 repo 추가 CTA
|
|
@@ -1800,6 +1820,12 @@ $('repoList').addEventListener('click', (e)=>{
|
|
|
1800
1820
|
const row = e.target.closest('.repo[data-repo]'); if(!row) return;
|
|
1801
1821
|
setScope(row.dataset.repo==='all' ? null : Number(row.dataset.repo));
|
|
1802
1822
|
});
|
|
1823
|
+
$('repoList').addEventListener('keydown', (e)=>{
|
|
1824
|
+
if (e.key!=='Enter' && e.key!==' ') return;
|
|
1825
|
+
const row = e.target.closest('.repo[data-repo]'); if(!row) return;
|
|
1826
|
+
e.preventDefault();
|
|
1827
|
+
setScope(row.dataset.repo==='all' ? null : Number(row.dataset.repo));
|
|
1828
|
+
});
|
|
1803
1829
|
$('captures').addEventListener('click', async (e)=>{
|
|
1804
1830
|
const b = e.target.closest('button[data-delcap]'); if(!b) return;
|
|
1805
1831
|
await fetch('/api/design/'+b.dataset.delcap,{method:'DELETE'});
|
|
@@ -3030,7 +3056,7 @@ function setV(tab){
|
|
|
3030
3056
|
$('panelBench').hidden = tab!=='bench';
|
|
3031
3057
|
$('panelBench').style.display = tab==='bench' ? 'flex' : 'none';
|
|
3032
3058
|
// footer adapts: Task=Dry/Real·count·Run fleet · Goal=Dry/Real·Plan & run · Workbench=Open workbench only
|
|
3033
|
-
$('modeSeg').style.display = tab==='bench' ? 'none' : 'flex'; // workbench 는 에이전트 없음
|
|
3059
|
+
$('modeSeg').style.display = tab==='bench' ? 'none' : 'inline-flex'; // workbench 는 에이전트 없음
|
|
3034
3060
|
$('taskCountStep').style.display = tab==='task' ? 'flex' : 'none'; // count 는 Task 만(플래너·워크벤치는 1)
|
|
3035
3061
|
$('runFleetBtn').innerHTML = ic(L_ICON[tab]) + ' ' + L_LABEL[tab];
|
|
3036
3062
|
}
|
|
@@ -3174,18 +3200,15 @@ $('cntDown').addEventListener('click', ()=>stepCount(-1));
|
|
|
3174
3200
|
$('cntUp').addEventListener('click', ()=>stepCount(1));
|
|
3175
3201
|
$('taskCount').addEventListener('change', ()=>stepCount(0)); // clamp manual typing
|
|
3176
3202
|
|
|
3177
|
-
/* ── agent mode
|
|
3178
|
-
const segOpts = Array.from(document.querySelectorAll('#modeSeg .seg-opt'));
|
|
3203
|
+
/* ── agent mode switch (compact toggle mirroring hidden #taskReal) ── */
|
|
3179
3204
|
function setMode(real, persist){
|
|
3180
3205
|
$('taskReal').checked = real;
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
b.setAttribute('aria-pressed', on ? 'true' : 'false');
|
|
3185
|
-
}
|
|
3206
|
+
$('modeSeg').setAttribute('aria-checked', real ? 'true' : 'false');
|
|
3207
|
+
$('modeRealLbl').textContent = real ? 'Real agent' : 'Dry run';
|
|
3208
|
+
$('modeRealHint').textContent = real ? 'spends credits' : 'rehearsal';
|
|
3186
3209
|
if (persist) try { localStorage.setItem('coxpit.real', real ? '1' : '0'); } catch {}
|
|
3187
3210
|
}
|
|
3188
|
-
|
|
3211
|
+
$('modeSeg').addEventListener('click', ()=>setMode(!$('taskReal').checked, true));
|
|
3189
3212
|
let savedMode = null;
|
|
3190
3213
|
try { savedMode = localStorage.getItem('coxpit.real'); } catch {}
|
|
3191
3214
|
setMode(savedMode === '1', false);
|