mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
Make the branch genuinely master-mergeable and fix several review findings: - Defaults are now prod-safe: CODEMAN_INSTANCE defaults to '' (→ ~/.codeman, -L codeman) and the web port back to 3000, so an existing install upgrades cleanly. Port also honors a new CODEMAN_PORT env var. Run the beta isolated alongside prod with scripts/run-beta.sh (CODEMAN_INSTANCE=beta + PORT 5000). - .gitignore: anchor the root `public` symlink rule to `/public` (a bare `public` also swallowed src/web/public, silently un-staging new web assets); ignore the gesture wasm/model binaries explicitly instead. - span-displays: add a macOS-only guard (400 elsewhere instead of spawning a bash that fails invisibly); extract resolveSpanUrl() for unit testing. - server.ts: memoize asset-version stat() calls (~1s TTL) so each index render doesn't re-stat every script/link tag. - styles.css: hide the multi-monitor button in solo (detached) windows. - app.js: require two consecutive unanswered roll-calls before redocking, so a timer-throttled background popup isn't wrongly un-marked. - index.html: make the "skip to terminal" link base-href-safe (onclick scroll) so it doesn't navigate to the dashboard from a /session/:id window. - Tests: test/config/instance.test.ts, test/routes/system-span-displays.test.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59 lines
2.8 KiB
JavaScript
59 lines
2.8 KiB
JavaScript
/**
|
|
* @fileoverview Fetch the gesture-overlay runtime assets (MediaPipe wasm + the
|
|
* gesture-recognizer model) into src/web/public/gesture/ so Codeman can serve
|
|
* them same-origin (a browser content-blocker otherwise blocks the public CDNs
|
|
* and the overlay fails to start). These are large binaries (~27 MB) kept OUT of
|
|
* git (ignored explicitly via `src/web/public/gesture/wasm/` + `*.task` in
|
|
* .gitignore); they are fetched here at install (postinstall) and build time.
|
|
*
|
|
* Idempotent: skips files already present. Non-fatal: the gesture overlay is
|
|
* opt-in (CODEMAN_GESTURE=1), so a fetch failure only warns — it must not break
|
|
* `npm install` / `npm run build`. The build then copies src/web/public into
|
|
* dist/ as usual, so prod gets these too.
|
|
*
|
|
* The @mediapipe/tasks-vision version MUST match the one bundled into the gesture
|
|
* overlay (Ark0N/codeman-gesture-control) so the wasm loader matches its JS API.
|
|
*/
|
|
import { mkdirSync, existsSync, statSync, writeFileSync } from 'node:fs';
|
|
import { join, dirname } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const GESTURE = join(__dirname, '..', 'src', 'web', 'public', 'gesture');
|
|
const WASM = join(GESTURE, 'wasm');
|
|
|
|
const MP_VERSION = '0.10.21'; // keep in sync with the gesture overlay's @mediapipe/tasks-vision
|
|
const WASM_BASE = `https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@${MP_VERSION}/wasm`;
|
|
const MODEL_URL =
|
|
'https://storage.googleapis.com/mediapipe-models/gesture_recognizer/gesture_recognizer/float16/1/gesture_recognizer.task';
|
|
|
|
const ASSETS = [
|
|
{ url: `${WASM_BASE}/vision_wasm_internal.js`, path: join(WASM, 'vision_wasm_internal.js') },
|
|
{ url: `${WASM_BASE}/vision_wasm_internal.wasm`, path: join(WASM, 'vision_wasm_internal.wasm') },
|
|
{ url: `${WASM_BASE}/vision_wasm_nosimd_internal.js`, path: join(WASM, 'vision_wasm_nosimd_internal.js') },
|
|
{ url: `${WASM_BASE}/vision_wasm_nosimd_internal.wasm`, path: join(WASM, 'vision_wasm_nosimd_internal.wasm') },
|
|
{ url: MODEL_URL, path: join(GESTURE, 'gesture_recognizer.task') },
|
|
];
|
|
|
|
async function main() {
|
|
mkdirSync(WASM, { recursive: true });
|
|
let fetched = 0;
|
|
let skipped = 0;
|
|
for (const a of ASSETS) {
|
|
if (existsSync(a.path) && statSync(a.path).size > 0) {
|
|
skipped++;
|
|
continue;
|
|
}
|
|
const res = await fetch(a.url);
|
|
if (!res.ok) throw new Error(`HTTP ${res.status} for ${a.url}`);
|
|
writeFileSync(a.path, Buffer.from(await res.arrayBuffer()));
|
|
fetched++;
|
|
}
|
|
console.log(`[gesture] MediaPipe assets ready (${fetched} fetched, ${skipped} cached) → ${GESTURE}`);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
// Non-fatal: opt-in feature. Warn and exit 0 so install/build still succeed.
|
|
console.warn(`[gesture] could not fetch MediaPipe assets — overlay disabled until fetched: ${err.message}`);
|
|
});
|