mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-03 05:59:43 +02:00
Merge remote-tracking branch 'origin/master' into cod-28-security-public-assets
This commit is contained in:
@@ -32,6 +32,9 @@ run('chmod dist/index.js', 'chmod +x dist/index.js');
|
||||
// 2. Copy static assets (clean first to remove stale hashed files from previous builds)
|
||||
run('clean public', 'rm -rf dist/web/public');
|
||||
run('prepare dirs', 'mkdir -p dist/web dist/templates dist/web/public/vendor');
|
||||
// Fetch the opt-in gesture overlay's MediaPipe wasm + model into src/ (idempotent,
|
||||
// non-fatal, kept out of git) so the copy below carries them into dist/.
|
||||
run('gesture assets', 'node scripts/fetch-gesture-assets.mjs');
|
||||
run('copy web assets', 'cp -r src/web/public dist/web/');
|
||||
run('copy template', 'cp src/templates/case-template.md dist/templates/');
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ KillMode=process
|
||||
Environment=NODE_ENV=production
|
||||
Environment=HOME=/home/arkon
|
||||
Environment=NODE_COMPILE_CACHE=/home/arkon/.codeman/compile-cache
|
||||
# Make the gesture-control overlay AVAILABLE (CSP widening + /gesture/ assets +
|
||||
# window.__codemanGestureAvailable). The actual on/off stays the per-user
|
||||
# `gestureControlEnabled` toggle in App Settings → Display → Input (default OFF).
|
||||
Environment=CODEMAN_GESTURE=1
|
||||
|
||||
# Logging
|
||||
StandardOutput=journal
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @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}`);
|
||||
});
|
||||
@@ -312,6 +312,20 @@ if (isGlobalInstall) {
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 4b. Fetch gesture-overlay runtime assets (MediaPipe wasm + model) for dev mode
|
||||
// (src/web/public/gesture/). Opt-in feature (CODEMAN_GESTURE=1); non-fatal.
|
||||
// Large binaries kept out of git; the build copies them into dist/.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
if (!isGlobalInstall) {
|
||||
try {
|
||||
execSync(`node "${join(import.meta.dirname, 'fetch-gesture-assets.mjs')}"`, { stdio: 'inherit' });
|
||||
} catch {
|
||||
// Non-fatal — the gesture overlay is opt-in.
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 5. Install git pre-commit hook (format check)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# run-beta.sh — launch a BETA Codeman isolated from a production instance.
|
||||
#
|
||||
# Codeman's data dir (~/.codeman) and tmux socket (-L codeman) are process-wide
|
||||
# and shared by every instance on the machine. The code now DEFAULTS to that
|
||||
# production layout on port 3000 (safe for master / existing installs), so a beta
|
||||
# build no longer isolates itself automatically — this wrapper opts it in:
|
||||
#
|
||||
# CODEMAN_INSTANCE=beta → data dir ~/.codeman-beta + tmux socket codeman-beta
|
||||
# CODEMAN_PORT=5000 → listen on 5000 instead of 3000
|
||||
#
|
||||
# Result: the beta runs side-by-side with prod and can never discover/attach to
|
||||
# prod's live tmux sessions or clobber prod's state.json. Override either var to
|
||||
# run additional named instances, e.g. CODEMAN_INSTANCE=foo CODEMAN_PORT=5050.
|
||||
#
|
||||
# Usage: ./scripts/run-beta.sh [extra `codeman web` flags]
|
||||
# Build first (the beta runs the compiled dist): npm run build
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
export CODEMAN_INSTANCE="${CODEMAN_INSTANCE:-beta}"
|
||||
export CODEMAN_PORT="${CODEMAN_PORT:-5000}"
|
||||
|
||||
DIST="$(cd "$(dirname "$0")/.." && pwd)/dist/index.js"
|
||||
if [ ! -f "$DIST" ]; then
|
||||
echo "dist not found at $DIST — run 'npm run build' first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting beta Codeman: instance='$CODEMAN_INSTANCE' (~/.codeman-$CODEMAN_INSTANCE, -L codeman-$CODEMAN_INSTANCE) on port $CODEMAN_PORT"
|
||||
exec node "$DIST" web "$@"
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# span-codeman.sh — open a Codeman window stretched across ALL displays, so that
|
||||
# in-page floating session panels can be dragged from one physical monitor to
|
||||
# the other. Spawned by the header "multi-monitor" button (POST
|
||||
# /api/system/span-displays), or run by hand at the desk.
|
||||
#
|
||||
# ── PREREQUISITE (one-time, manual) ──────────────────────────────────────────
|
||||
# System Settings → Desktop & Dock → turn OFF "Displays have separate Spaces",
|
||||
# then LOG OUT and back in. Until you do, macOS keeps every window on a single
|
||||
# display and this script's window will clamp to one monitor instead of spanning.
|
||||
# (Equivalent CLI: `defaults write com.apple.spaces spans-displays -bool true`,
|
||||
# still needs a re-login. Revert with `-bool false`.)
|
||||
#
|
||||
# Why a maximized --app window and not fullscreen: browser fullscreen is
|
||||
# per-display and will NOT span. We size a windowed app to the union of all
|
||||
# displays instead. macOS only.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
URL="${1:-http://localhost:5000}"
|
||||
|
||||
# Union rect of all displays in top-left-origin points — exactly what Chromium's
|
||||
# --window-position/--window-size expect. Finder's desktop window bounds already
|
||||
# encloses every monitor (and handles a monitor placed left/above via a negative
|
||||
# origin), so no per-display math or coordinate flipping is needed.
|
||||
bounds=$(osascript -e 'tell application "Finder" to get bounds of window of desktop')
|
||||
X=$(echo "$bounds" | awk -F', *' '{print $1}')
|
||||
Y=$(echo "$bounds" | awk -F', *' '{print $2}')
|
||||
R=$(echo "$bounds" | awk -F', *' '{print $3}')
|
||||
B=$(echo "$bounds" | awk -F', *' '{print $4}')
|
||||
W=$((R - X))
|
||||
H=$((B - Y))
|
||||
echo "Display union: position ${X},${Y} size ${W}x${H}"
|
||||
|
||||
# Pick a Chromium-family browser. Brave leads the list — plain Google Chrome
|
||||
# bounced when launched this way on the desk machine (created its profile then
|
||||
# exited without a window). Force a specific one with, e.g.,
|
||||
# BROWSER="Google Chrome" ./span-codeman.sh
|
||||
app="${BROWSER:-}"
|
||||
if [ -z "$app" ]; then
|
||||
for c in "Brave Browser" "Google Chrome" "Google Chrome Beta" "Chromium" "Microsoft Edge"; do
|
||||
[ -x "/Applications/$c.app/Contents/MacOS/$c" ] && app="$c" && break
|
||||
done
|
||||
fi
|
||||
bin="/Applications/$app.app/Contents/MacOS/$app"
|
||||
[ -n "$app" ] && [ -x "$bin" ] || { echo "No Chrome-family browser found (BROWSER='$app')" >&2; exit 1; }
|
||||
|
||||
# A dedicated, PER-BROWSER profile forces a FRESH instance — an already-running
|
||||
# browser would hand the URL to itself and silently ignore the geometry flags.
|
||||
# Per-browser so a Chrome-made profile can't confuse Brave (or vice-versa).
|
||||
slug=$(echo "$app" | tr '[:upper:] ' '[:lower:]-')
|
||||
profile="$HOME/.codeman-gesture-$slug"
|
||||
|
||||
echo "Browser: $bin"
|
||||
echo "URL: $URL"
|
||||
|
||||
# Detach so the caller (terminal / web server) isn't blocked for the window's life.
|
||||
nohup "$bin" \
|
||||
--app="$URL" \
|
||||
--user-data-dir="$profile" \
|
||||
--window-position="${X},${Y}" \
|
||||
--window-size="${W},${H}" \
|
||||
--no-first-run \
|
||||
--no-default-browser-check \
|
||||
>/dev/null 2>&1 &
|
||||
|
||||
echo "Launched spanning window (pid $!)."
|
||||
echo "If it filled only one monitor, the 'separate Spaces' prerequisite above"
|
||||
echo "isn't active yet — toggle it off, log out/in, and re-run."
|
||||
Reference in New Issue
Block a user