mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-10 01:09:43 +02:00
chore: bump version to 0.1580
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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`)
|
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`
|
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.1579 (must match `package.json` for npm publish)
|
**Version**: 0.1580 (must match `package.json` for npm publish)
|
||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
|
|||||||
Generated
+13
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "claudeman",
|
"name": "claudeman",
|
||||||
"version": "0.1536",
|
"version": "0.1579",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "claudeman",
|
"name": "claudeman",
|
||||||
"version": "0.1536",
|
"version": "0.1579",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"xterm": "^5.3.0",
|
"xterm": "^5.3.0",
|
||||||
"xterm-addon-fit": "^0.8.0",
|
"xterm-addon-fit": "^0.8.0",
|
||||||
|
"xterm-addon-webgl": "^0.16.0",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -4862,6 +4863,16 @@
|
|||||||
"xterm": "^5.0.0"
|
"xterm": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/xterm-addon-webgl": {
|
||||||
|
"version": "0.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0.tgz",
|
||||||
|
"integrity": "sha512-E8cq1AiqNOv0M/FghPT+zPAEnvIQRDbAbkb04rRYSxUym69elPWVJ4sv22FCLBqM/3LcrmBLl/pELnBebVFKgA==",
|
||||||
|
"deprecated": "This package is now deprecated. Move to @xterm/addon-webgl instead.",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"xterm": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|||||||
+3
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claudeman",
|
"name": "claudeman",
|
||||||
"version": "0.1579",
|
"version": "0.1580",
|
||||||
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
|
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "node scripts/postinstall.js",
|
"postinstall": "node scripts/postinstall.js",
|
||||||
"build": "tsc && chmod +x dist/index.js && mkdir -p dist/web dist/templates dist/web/public/vendor && cp -r src/web/public dist/web/ && cp src/templates/case-template.md dist/templates/ && cp node_modules/xterm/css/xterm.css dist/web/public/vendor/ && npx esbuild node_modules/xterm/lib/xterm.js --minify --outfile=dist/web/public/vendor/xterm.min.js && npx esbuild node_modules/xterm-addon-fit/lib/xterm-addon-fit.js --minify --outfile=dist/web/public/vendor/xterm-addon-fit.min.js && npx esbuild dist/web/public/app.js --minify --drop:console --outfile=dist/web/public/app.js --allow-overwrite && npx esbuild dist/web/public/styles.css --minify --outfile=dist/web/public/styles.css --allow-overwrite && npx esbuild dist/web/public/mobile.css --minify --outfile=dist/web/public/mobile.css --allow-overwrite",
|
"build": "tsc && chmod +x dist/index.js && mkdir -p dist/web dist/templates dist/web/public/vendor && cp -r src/web/public dist/web/ && cp src/templates/case-template.md dist/templates/ && cp node_modules/xterm/css/xterm.css dist/web/public/vendor/ && npx esbuild node_modules/xterm/lib/xterm.js --minify --outfile=dist/web/public/vendor/xterm.min.js && npx esbuild node_modules/xterm-addon-fit/lib/xterm-addon-fit.js --minify --outfile=dist/web/public/vendor/xterm-addon-fit.min.js && cp node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js dist/web/public/vendor/xterm-addon-webgl.min.js && npx esbuild dist/web/public/app.js --minify --drop:console --outfile=dist/web/public/app.js --allow-overwrite && npx esbuild dist/web/public/styles.css --minify --outfile=dist/web/public/styles.css --allow-overwrite && npx esbuild dist/web/public/mobile.css --minify --outfile=dist/web/public/mobile.css --allow-overwrite && for f in dist/web/public/*.js dist/web/public/*.css dist/web/public/*.html dist/web/public/vendor/*.js dist/web/public/vendor/*.css; do [ -f \"$f\" ] && gzip -9 -k \"$f\" && brotli -9 -k \"$f\"; done",
|
||||||
"start": "node dist/index.js",
|
"start": "node dist/index.js",
|
||||||
"dev": "tsx src/index.ts",
|
"dev": "tsx src/index.ts",
|
||||||
"web": "node dist/index.js web",
|
"web": "node dist/index.js web",
|
||||||
@@ -47,6 +47,7 @@
|
|||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"xterm": "^5.3.0",
|
"xterm": "^5.3.0",
|
||||||
"xterm-addon-fit": "^0.8.0",
|
"xterm-addon-fit": "^0.8.0",
|
||||||
|
"xterm-addon-webgl": "^0.16.0",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -467,6 +467,10 @@ export class Session extends EventEmitter {
|
|||||||
return this._terminalBuffer.value;
|
return this._terminalBuffer.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get terminalBufferLength(): number {
|
||||||
|
return this._terminalBuffer.length;
|
||||||
|
}
|
||||||
|
|
||||||
get textOutput(): string {
|
get textOutput(): string {
|
||||||
return this._textOutput.value;
|
return this._textOutput.value;
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-3
@@ -33,6 +33,15 @@ const WINDOW_MIN_WIDTH_PX = 200;
|
|||||||
const WINDOW_MIN_HEIGHT_PX = 200;
|
const WINDOW_MIN_HEIGHT_PX = 200;
|
||||||
const WINDOW_DEFAULT_WIDTH_PX = 300;
|
const WINDOW_DEFAULT_WIDTH_PX = 300;
|
||||||
|
|
||||||
|
// Scheduler API — prioritize terminal writes over background UI updates.
|
||||||
|
// scheduler.postTask('background') defers non-critical work (connection lines, panel renders)
|
||||||
|
// so the main thread stays free for terminal rendering at 60fps.
|
||||||
|
const _hasScheduler = typeof globalThis.scheduler?.postTask === 'function';
|
||||||
|
function scheduleBackground(fn) {
|
||||||
|
if (_hasScheduler) { scheduler.postTask(fn, { priority: 'background' }); }
|
||||||
|
else { requestAnimationFrame(fn); }
|
||||||
|
}
|
||||||
|
|
||||||
// DEC mode 2026 - Synchronized Output
|
// DEC mode 2026 - Synchronized Output
|
||||||
// Wrap terminal writes with these markers to prevent partial-frame flicker.
|
// Wrap terminal writes with these markers to prevent partial-frame flicker.
|
||||||
// Terminal buffers all output between markers and renders atomically.
|
// Terminal buffers all output between markers and renders atomically.
|
||||||
@@ -1871,6 +1880,16 @@ class ClaudemanApp {
|
|||||||
|
|
||||||
const container = document.getElementById('terminalContainer');
|
const container = document.getElementById('terminalContainer');
|
||||||
this.terminal.open(container);
|
this.terminal.open(container);
|
||||||
|
|
||||||
|
// Activate WebGL renderer for up to 900% faster rendering (fallback to canvas on failure)
|
||||||
|
if (typeof WebglAddon !== 'undefined') {
|
||||||
|
try {
|
||||||
|
const webglAddon = new WebglAddon.WebglAddon();
|
||||||
|
webglAddon.onContextLoss(() => { webglAddon.dispose(); });
|
||||||
|
this.terminal.loadAddon(webglAddon);
|
||||||
|
} catch (_e) { /* WebGL2 unavailable — canvas renderer used */ }
|
||||||
|
}
|
||||||
|
|
||||||
this._localEchoOverlay = new LocalEchoOverlay(this.terminal);
|
this._localEchoOverlay = new LocalEchoOverlay(this.terminal);
|
||||||
|
|
||||||
// On mobile Safari, delay initial fit() to allow layout to settle
|
// On mobile Safari, delay initial fit() to allow layout to settle
|
||||||
@@ -3624,6 +3643,16 @@ class ClaudemanApp {
|
|||||||
this.subagentToolResults.delete(data.agentId);
|
this.subagentToolResults.delete(data.agentId);
|
||||||
}
|
}
|
||||||
}, 5 * 60 * 1000); // 5 minutes
|
}, 5 * 60 * 1000); // 5 minutes
|
||||||
|
|
||||||
|
// Prune stale completed agents from main maps after 30 minutes
|
||||||
|
// Keeps subagents/subagentParentMap from growing unbounded in 24h sessions
|
||||||
|
setTimeout(() => {
|
||||||
|
const agent = this.subagents.get(data.agentId);
|
||||||
|
if (agent?.status === 'completed' && !this.subagentWindows.has(data.agentId)) {
|
||||||
|
this.subagents.delete(data.agentId);
|
||||||
|
this.subagentParentMap.delete(data.agentId);
|
||||||
|
}
|
||||||
|
}, 30 * 60 * 1000); // 30 minutes
|
||||||
});
|
});
|
||||||
|
|
||||||
// ========== Image Detection Events (Screenshots & Generated Images) ==========
|
// ========== Image Detection Events (Screenshots & Generated Images) ==========
|
||||||
@@ -12399,7 +12428,7 @@ class ClaudemanApp {
|
|||||||
clearTimeout(this._subagentPanelRenderTimeout);
|
clearTimeout(this._subagentPanelRenderTimeout);
|
||||||
}
|
}
|
||||||
this._subagentPanelRenderTimeout = setTimeout(() => {
|
this._subagentPanelRenderTimeout = setTimeout(() => {
|
||||||
this._renderSubagentPanelImmediate();
|
scheduleBackground(() => this._renderSubagentPanelImmediate());
|
||||||
}, 150);
|
}, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12902,10 +12931,11 @@ class ClaudemanApp {
|
|||||||
// This map stores agentId -> sessionId, where sessionId is the tab's data-id.
|
// This map stores agentId -> sessionId, where sessionId is the tab's data-id.
|
||||||
|
|
||||||
updateConnectionLines() {
|
updateConnectionLines() {
|
||||||
// Coalesce multiple calls within the same frame into a single rAF
|
// Coalesce multiple calls — uses background scheduler priority to avoid
|
||||||
|
// competing with terminal writes for main thread time
|
||||||
if (!this._connectionLinesScheduled) {
|
if (!this._connectionLinesScheduled) {
|
||||||
this._connectionLinesScheduled = true;
|
this._connectionLinesScheduled = true;
|
||||||
requestAnimationFrame(() => {
|
scheduleBackground(() => {
|
||||||
this._connectionLinesScheduled = false;
|
this._connectionLinesScheduled = false;
|
||||||
this._updateConnectionLinesImmediate();
|
this._updateConnectionLinesImmediate();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
'defer' preserves execution order (xterm loads before fit addon). -->
|
'defer' preserves execution order (xterm loads before fit addon). -->
|
||||||
<script defer src="vendor/xterm.min.js"></script>
|
<script defer src="vendor/xterm.min.js"></script>
|
||||||
<script defer src="vendor/xterm-addon-fit.min.js"></script>
|
<script defer src="vendor/xterm-addon-fit.min.js"></script>
|
||||||
|
<script defer src="vendor/xterm-addon-webgl.min.js"></script>
|
||||||
<!-- Synchronous mobile detection — runs before first paint to prevent panel flash -->
|
<!-- Synchronous mobile detection — runs before first paint to prevent panel flash -->
|
||||||
<script>if(window.innerWidth<768||(('ontouchstart' in window||navigator.maxTouchPoints>0)&&window.innerWidth<1024))document.documentElement.classList.add('mobile-init');</script>
|
<script>if(window.innerWidth<768||(('ontouchstart' in window||navigator.maxTouchPoints>0)&&window.innerWidth<1024))document.documentElement.classList.add('mobile-init');</script>
|
||||||
<!-- Inline critical CSS for instant skeleton paint (before styles.css loads) -->
|
<!-- Inline critical CSS for instant skeleton paint (before styles.css loads) -->
|
||||||
|
|||||||
@@ -2990,6 +2990,8 @@ body {
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border-left: 2px solid var(--border);
|
border-left: 2px solid var(--border);
|
||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
|
content-visibility: auto;
|
||||||
|
contain-intrinsic-size: auto 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-event:hover {
|
.timeline-event:hover {
|
||||||
@@ -3874,6 +3876,8 @@ kbd {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
animation: notif-slide-in 0.2s ease;
|
animation: notif-slide-in 0.2s ease;
|
||||||
|
content-visibility: auto;
|
||||||
|
contain-intrinsic-size: auto 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notif-item:hover {
|
.notif-item:hover {
|
||||||
@@ -4631,6 +4635,8 @@ kbd {
|
|||||||
margin-bottom: 0.4rem;
|
margin-bottom: 0.4rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
|
content-visibility: auto;
|
||||||
|
contain-intrinsic-size: auto 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subagent-item:hover {
|
.subagent-item:hover {
|
||||||
@@ -5731,6 +5737,8 @@ kbd {
|
|||||||
|
|
||||||
.log-viewer-window-body .log-line {
|
.log-viewer-window-body .log-line {
|
||||||
padding: 0.1rem 0;
|
padding: 0.1rem 0;
|
||||||
|
content-visibility: auto;
|
||||||
|
contain-intrinsic-size: auto 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-viewer-window-body .log-error {
|
.log-viewer-window-body .log-error {
|
||||||
|
|||||||
+26
-23
@@ -632,11 +632,13 @@ export class WebServer extends EventEmitter {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Serve static files — versioned assets (?v=X) are immutable, cache aggressively
|
// Serve static files — versioned assets (?v=X) are immutable, cache aggressively
|
||||||
|
// preCompressed: serve pre-built .br/.gz files (from build step) to avoid per-request CPU compression
|
||||||
await this.app.register(fastifyStatic, {
|
await this.app.register(fastifyStatic, {
|
||||||
root: join(__dirname, 'public'),
|
root: join(__dirname, 'public'),
|
||||||
prefix: '/',
|
prefix: '/',
|
||||||
maxAge: '1y',
|
maxAge: '1y',
|
||||||
immutable: true,
|
immutable: true,
|
||||||
|
preCompressed: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// SSE endpoint for real-time updates
|
// SSE endpoint for real-time updates
|
||||||
@@ -1756,32 +1758,15 @@ export class WebServer extends EventEmitter {
|
|||||||
return createErrorResponse(ApiErrorCode.NOT_FOUND, 'Session not found');
|
return createErrorResponse(ApiErrorCode.NOT_FOUND, 'Session not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean the buffer: remove junk before actual Claude content
|
|
||||||
let cleanBuffer = session.terminalBuffer;
|
|
||||||
|
|
||||||
// Find where Claude banner starts (has color codes before "Claude")
|
|
||||||
const claudeMatch = cleanBuffer.match(CLAUDE_BANNER_PATTERN);
|
|
||||||
if (claudeMatch && claudeMatch.index !== undefined && claudeMatch.index > 0) {
|
|
||||||
// Find the start of that line
|
|
||||||
let lineStart = claudeMatch.index;
|
|
||||||
while (lineStart > 0 && cleanBuffer[lineStart - 1] !== '\n') {
|
|
||||||
lineStart--;
|
|
||||||
}
|
|
||||||
cleanBuffer = cleanBuffer.slice(lineStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove Ctrl+L and leading whitespace
|
|
||||||
cleanBuffer = cleanBuffer
|
|
||||||
.replace(CTRL_L_PATTERN, '')
|
|
||||||
.replace(LEADING_WHITESPACE_PATTERN, '');
|
|
||||||
|
|
||||||
// Optionally truncate to last N bytes for faster initial load
|
|
||||||
const tailBytes = query.tail ? parseInt(query.tail, 10) : 0;
|
const tailBytes = query.tail ? parseInt(query.tail, 10) : 0;
|
||||||
const fullSize = cleanBuffer.length;
|
const fullSize = session.terminalBufferLength;
|
||||||
let truncated = false;
|
let truncated = false;
|
||||||
|
let cleanBuffer: string;
|
||||||
|
|
||||||
if (tailBytes > 0 && cleanBuffer.length > tailBytes) {
|
if (tailBytes > 0 && fullSize > tailBytes) {
|
||||||
cleanBuffer = cleanBuffer.slice(-tailBytes);
|
// Fast path: tail from the end, skip expensive banner search on full 2MB buffer.
|
||||||
|
// Banner is near the top and gets discarded by tail anyway.
|
||||||
|
cleanBuffer = session.terminalBuffer.slice(-tailBytes);
|
||||||
truncated = true;
|
truncated = true;
|
||||||
// Avoid starting mid-ANSI-escape: find first newline within the first 4KB
|
// Avoid starting mid-ANSI-escape: find first newline within the first 4KB
|
||||||
// and start from there. This prevents xterm.js from parsing a partial escape
|
// and start from there. This prevents xterm.js from parsing a partial escape
|
||||||
@@ -1790,8 +1775,26 @@ export class WebServer extends EventEmitter {
|
|||||||
if (firstNewline > 0 && firstNewline < 4096) {
|
if (firstNewline > 0 && firstNewline < 4096) {
|
||||||
cleanBuffer = cleanBuffer.slice(firstNewline + 1);
|
cleanBuffer = cleanBuffer.slice(firstNewline + 1);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Full buffer: clean junk before actual Claude content
|
||||||
|
cleanBuffer = session.terminalBuffer;
|
||||||
|
|
||||||
|
// Find where Claude banner starts (has color codes before "Claude")
|
||||||
|
const claudeMatch = cleanBuffer.match(CLAUDE_BANNER_PATTERN);
|
||||||
|
if (claudeMatch && claudeMatch.index !== undefined && claudeMatch.index > 0) {
|
||||||
|
let lineStart = claudeMatch.index;
|
||||||
|
while (lineStart > 0 && cleanBuffer[lineStart - 1] !== '\n') {
|
||||||
|
lineStart--;
|
||||||
|
}
|
||||||
|
cleanBuffer = cleanBuffer.slice(lineStart);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove Ctrl+L and leading whitespace (cheap on tailed subset)
|
||||||
|
cleanBuffer = cleanBuffer
|
||||||
|
.replace(CTRL_L_PATTERN, '')
|
||||||
|
.replace(LEADING_WHITESPACE_PATTERN, '');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
terminalBuffer: cleanBuffer,
|
terminalBuffer: cleanBuffer,
|
||||||
status: session.status,
|
status: session.status,
|
||||||
|
|||||||
Reference in New Issue
Block a user