chore: bump version to 0.1619

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-02-24 16:24:03 +01:00
co-authored by Claude Opus 4.6
parent 3c29b1fa6e
commit fcca197e81
5 changed files with 120 additions and 16 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ When user says "COM":
1. Increment version in BOTH `package.json` AND `CLAUDE.md` (verify they match with `grep version package.json && grep Version CLAUDE.md`)
2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web`
**Version**: 0.1618 (must match `package.json`)
**Version**: 0.1619 (must match `package.json`)
## Project Overview
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "claudeman",
"version": "0.1618",
"version": "0.1619",
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
"type": "module",
"main": "dist/index.js",
+68 -11
View File
@@ -16057,22 +16057,76 @@ class ClaudemanApp {
let html = '';
for (const muxSession of this.muxSessions) {
const stats = muxSession.stats || { memoryMB: 0, cpuPercent: 0, childCount: 0 };
const modeClass = muxSession.mode === 'shell' ? 'shell' : '';
// Look up rich session data by sessionId
const session = this.sessions.get(muxSession.sessionId);
const status = session ? session.status : 'unknown';
const isWorking = session ? session.isWorking : false;
// Status badge
let statusLabel, statusClass;
if (status === 'idle' && !isWorking) {
statusLabel = 'IDLE';
statusClass = 'status-idle';
} else if (status === 'busy' || isWorking) {
statusLabel = 'WORKING';
statusClass = 'status-working';
} else if (status === 'stopped') {
statusLabel = 'STOPPED';
statusClass = 'status-stopped';
} else {
statusLabel = status.toUpperCase();
statusClass = '';
}
// Token and cost info
const tokens = session && session.tokens ? session.tokens : null;
const totalCost = session ? session.totalCost : 0;
const model = session ? (session.cliModel || '') : '';
const modelShort = model.includes('opus') ? 'opus' : model.includes('sonnet') ? 'sonnet' : model.includes('haiku') ? 'haiku' : '';
// Ralph/Todo progress
const todoStats = session ? session.ralphTodoStats : null;
let todoHtml = '';
if (todoStats && todoStats.total > 0) {
const pct = Math.round((todoStats.completed / todoStats.total) * 100);
todoHtml = `<span class="process-stat todo-progress">${todoStats.completed}/${todoStats.total} (${pct}%)</span>`;
}
// Format tokens
let tokenHtml = '';
if (tokens && tokens.total > 0) {
const totalK = (tokens.total / 1000).toFixed(1);
tokenHtml = `<span class="process-stat tokens">${totalK}k tok</span>`;
}
// Format cost
let costHtml = '';
if (totalCost > 0) {
costHtml = `<span class="process-stat cost">$${totalCost.toFixed(2)}</span>`;
}
// Model badge
let modelHtml = '';
if (modelShort) {
modelHtml = `<span class="monitor-model-badge ${modelShort}">${modelShort}</span>`;
}
html += `
<div class="process-item">
<span class="process-mode ${modeClass}">${muxSession.mode}</span>
<span class="monitor-status-badge ${statusClass}">${statusLabel}</span>
<div class="process-info">
<div class="process-name">${this.escapeHtml(muxSession.name || muxSession.muxName)}</div>
<div class="process-name">${modelHtml} ${this.escapeHtml(muxSession.name || muxSession.muxName)}</div>
<div class="process-meta">
${tokenHtml}
${costHtml}
${todoHtml}
<span class="process-stat memory">${stats.memoryMB}MB</span>
<span class="process-stat cpu">${stats.cpuPercent}%</span>
<span class="process-stat children">${stats.childCount} children</span>
<span>PID: ${muxSession.pid}</span>
</div>
</div>
<div class="process-actions">
<button class="btn-toolbar btn-sm btn-danger" onclick="app.killMuxSession('${this.escapeHtml(muxSession.sessionId)}')" title="Kill tmux session">Kill</button>
<button class="btn-toolbar btn-sm btn-danger" onclick="app.killMuxSession('${this.escapeHtml(muxSession.sessionId)}')" title="Kill session">Kill</button>
</div>
</div>
`;
@@ -16128,13 +16182,16 @@ class ClaudemanApp {
if (!confirm('Kill this mux session?')) return;
try {
await fetch(`/api/mux-sessions/${sessionId}`, { method: 'DELETE' });
// Use closeSession to properly clean up both the session tab and tmux process
// (closeSession handles its own toast messaging)
await this.closeSession(sessionId, true);
} catch (err) {
// Fallback: kill mux directly if session cleanup fails
try { await fetch(`/api/mux-sessions/${sessionId}`, { method: 'DELETE' }); } catch (_ignored) {}
this.showToast('Tmux session killed', 'success');
}
this.muxSessions = this.muxSessions.filter(s => s.sessionId !== sessionId);
this.renderMuxSessions();
this.showToast('Tmux session killed', 'success');
} catch (err) {
this.showToast('Failed to kill tmux session', 'error');
}
}
async reconcileMuxSessions() {
+3 -3
View File
@@ -8,8 +8,8 @@
<meta name="google" content="notranslate">
<title>Claudeman</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' stop-color='%2360a5fa'/%3E%3Cstop offset='100%25' stop-color='%233b82f6'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='32' height='32' rx='6' fill='%230a0a0a'/%3E%3Cpath d='M18 4L8 18h6l-2 10 10-14h-6z' fill='url(%23g)'/%3E%3C/svg%3E">
<link rel="stylesheet" href="styles.css?v=0.1597">
<link rel="stylesheet" href="mobile.css?v=0.1597" media="(max-width: 1023px)">
<link rel="stylesheet" href="styles.css?v=0.1618">
<link rel="stylesheet" href="mobile.css?v=0.1618" media="(max-width: 1023px)">
<!-- xterm.css loaded async — terminal won't display until xterm.js runs anyway -->
<link rel="preload" href="vendor/xterm.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="vendor/xterm.css"></noscript>
@@ -1560,6 +1560,6 @@
<!-- Lines drawn dynamically -->
</svg>
<script defer src="app.js?v=0.1597"></script>
<script defer src="app.js?v=0.1618"></script>
</body>
</html>
+47
View File
@@ -4291,6 +4291,53 @@ kbd {
color: var(--yellow);
}
/* Monitor status badges */
.monitor-status-badge {
font-size: 0.55rem;
font-weight: 700;
padding: 2px 6px;
border-radius: 3px;
text-transform: uppercase;
letter-spacing: 0.5px;
white-space: nowrap;
min-width: 52px;
text-align: center;
}
.monitor-status-badge.status-idle {
background: rgba(234, 179, 8, 0.2);
color: var(--yellow);
}
.monitor-status-badge.status-working {
background: rgba(74, 222, 128, 0.2);
color: var(--green);
animation: pulse-working 2s ease-in-out infinite;
}
.monitor-status-badge.status-stopped {
background: rgba(239, 68, 68, 0.2);
color: var(--red, #ef4444);
}
@keyframes pulse-working {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
/* Monitor model badges */
.monitor-model-badge {
font-size: 0.55rem;
padding: 1px 4px;
border-radius: 2px;
font-weight: 600;
text-transform: uppercase;
}
.monitor-model-badge.opus { background: rgba(168, 85, 247, 0.2); color: #c084fc; }
.monitor-model-badge.sonnet { background: rgba(59, 130, 246, 0.2); color: #60a5fa; }
.monitor-model-badge.haiku { background: rgba(74, 222, 128, 0.2); color: #4ade80; }
/* Monitor stat colors */
.process-stat.tokens { color: var(--accent-hover); }
.process-stat.cost { color: #f59e0b; }
.process-stat.todo-progress { color: #c084fc; }
/* Combined Monitor Panel (Tmux Sessions + Background Tasks) */
.monitor-panel {
position: fixed;