mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 06:59:42 +02:00
feat(gesture): port session improvements — direct detach, Run/Run Shell taps, self-hosted MediaPipe, cache-bust
Updates the opt-in gesture overlay (still gated by CODEMAN_GESTURE=1):
- Bundle (gesture-codeman.js) rebuilt from Ark0N/codeman-gesture-control:
- Detach now calls window.app.detachSession(id) directly (the on-tab pop-out
hook) instead of a separate /session/:id window.open reimplementation.
- Pinch a session tab → ghost follows your hand → pull out to undock.
- Pinch the Run (#runBtn → app.run()) or Run Shell (.btn-shell →
app.runShell()) toolbar button to fire it; drift cancels the tap.
- Camera shows fullscreen-dimmed by default (⛶ toggles a corner preview).
- Robust start-error reporting; GPU→CPU MediaPipe delegate fallback.
- Self-hosted MediaPipe (no CDN): serves the wasm runtime + gesture_recognizer
.task from /gesture/ so a browser content-blocker can't break startup. The
overlay points wasmBase/modelUrl there. (~27MB of assets; could later be a
build/postinstall fetch instead of committed blobs.)
- server.ts: cache-bust the injected bundle URL with its mtime (?v=), since
static is served with a 1-year cache — a redeploy is now never stale.
format:check / lint scope (src/**/*.ts) clean; server.ts typechecks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+17
-2
@@ -36,7 +36,7 @@ import fastifyMultipart from '@fastify/multipart';
|
||||
import { startPasteImageGc } from './paste-image-gc.js';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { existsSync, mkdirSync, readFileSync, chmodSync, rmSync } from 'node:fs';
|
||||
import { existsSync, mkdirSync, readFileSync, chmodSync, rmSync, statSync } from 'node:fs';
|
||||
import fs from 'node:fs/promises';
|
||||
import { execSync } from 'node:child_process';
|
||||
import { hostname as getHostname } from 'node:os';
|
||||
@@ -1012,11 +1012,26 @@ export class WebServer extends EventEmitter {
|
||||
// same-origin from /gesture/ so 'self' covers it; CSP is widened to match in
|
||||
// registerSecurityHeaders under the same flag.
|
||||
if (!soloSessionId && process.env.CODEMAN_GESTURE === '1') {
|
||||
html = html.replace('</head>', `<script type="module" src="/gesture/gesture-codeman.js"></script>\n</head>`);
|
||||
const v = this.gestureBundleVersion();
|
||||
html = html.replace('</head>', `<script type="module" src="/gesture/gesture-codeman.js${v}"></script>\n</head>`);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
/** Cache-busting query for the gesture bundle: its mtime, re-read per render.
|
||||
* The bundle is served from /gesture/ with a 1-year cache, so without a
|
||||
* version that changes on redeploy the browser would keep running a stale
|
||||
* bundle forever. Re-stat'ing each render means a freshly copied-in bundle is
|
||||
* picked up with no server restart. Empty string if the file is missing. */
|
||||
private gestureBundleVersion(): string {
|
||||
try {
|
||||
const p = join(__dirname, 'public', 'gesture', 'gesture-codeman.js');
|
||||
return `?v=${Math.floor(statSync(p).mtimeMs)}`;
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
private async setupSessionListeners(session: Session): Promise<void> {
|
||||
// Create run summary tracker for this session
|
||||
const summaryTracker = new RunSummaryTracker(session.id, session.name);
|
||||
|
||||
Reference in New Issue
Block a user