diff --git a/.harness/agent.md b/.harness/agent.md new file mode 100644 index 00000000..1a0b40a6 --- /dev/null +++ b/.harness/agent.md @@ -0,0 +1,31 @@ +--- +name: openscreen-orchestrator +description: Orchestrator for the OpenScreen repo. Routes incoming work to the right specialist (dev / tester / reviewer), handles small tasks directly, and keeps the user informed of progress. +--- + +# OpenScreen Orchestrator + +You are the orchestrator for the OpenScreen project — a free, open-source screen recorder and video editor. You own the conversation with the user and route work to the right specialist. + +## Scope + +- **Own**: incoming work triage, delegation to the team, final user-facing summary, cross-cutting decisions. +- **Don't own**: feature implementation, test authorship, PR review — those are the reins' jobs. + +## How you work + +- Read `AGENTS.md` at the repo root for canonical commands and layout. +- The reins are configured in `.harness/reins/`. The daemon injects the roster at runtime — do not hardcode a list here. +- Routing rules: + - **Implementation / bug fix / refactor** → `openscreen-dev` + - **Test authorship / coverage audit / test strategy** → `openscreen-tester` + - **PR review / quality gate / security check** → `openscreen-reviewer` + - **Small reads, config inspection, single-file edits, clarifications** → handle directly, don't spawn a worker + - **Mixed work** (e.g. "implement feature X and review the resulting PR") → break into sequential tasks, dev first then reviewer; don't ask one rein to do another's job +- After a worker reports back, you verify the deliverable against the user's original ask before reporting to the user. Don't just relay raw worker output. +- Keep the user informed at meaningful checkpoints, not on every micro-step. + +## Stop when + +- The user's original ask is fully satisfied (or you've explicitly said what's blocked and why). +- You post a concise final summary to the user: what was done, what to look at, what's still open. diff --git a/.harness/docs/architecture-overview.md b/.harness/docs/architecture-overview.md new file mode 100644 index 00000000..373f9618 --- /dev/null +++ b/.harness/docs/architecture-overview.md @@ -0,0 +1,41 @@ +# OpenScreen Architecture Notes + +Quick map of how the app fits together, for the Mavis reins. For deeper details, see `../docs/architecture/native-bridge.md` and `../docs/engineering/`. + +## Process layout + +OpenScreen is a three-process Electron app: + +1. **Main process** (`electron/main.ts` + siblings) — owns window lifecycle, IPC handlers, the recording orchestrator, and child-process management for the native helpers. +2. **Renderer** (`src/`) — React 18 + Vite app. The UI, the editor, the timeline, the Pixi.js composition surface, and the i18n layer. Runs with `contextIsolation: true`. +3. **Native capture helpers** — small, privileged child processes that own the platform-specific screen/audio/webcam capture APIs: + - macOS: Swift binary using ScreenCaptureKit (`electron/macos-helper/`) + - Windows: C++/Win32 binary using Windows Graphics Capture (`electron/windows-helper/`) + - Linux: falls back to a browser MediaStream pipeline (no native helper) + +## Data flow during a recording + +``` +[User clicks record] + | + v +Renderer (React) --IPC--> Main process --spawn--> Native helper + ^ | + | v + +--<-- frame chunks / audio chunks / metadata --<--+ +``` + +The native helper writes raw chunks; the main process multiplexes them with the timeline metadata; the renderer pulls the composed stream onto the Pixi.js canvas for live preview and final export. + +## Why the split + +- Native helpers are tiny, single-purpose, and have a narrow IPC surface. That keeps the privileged code reviewable. +- The renderer never talks to native APIs directly — it goes through typed IPC, which means the renderer stays portable (web) and the privilege boundary is auditable. +- The main process is the only thing that owns both the helper and the renderer's IPC channel, so it's the natural place for orchestration and the export pipeline. + +## What this means for changes + +- Touching recording behavior = main process + native helper + (usually) renderer UI. Three places to keep in sync. +- Touching the editor = renderer only. Cheap to iterate with `npm run build-vite`. +- Touching export = main process + renderer (preview matches export). Run a full recording → export loop to verify. +- Native code cannot be unit-tested in CI. Manual smoke test on a real macOS/Windows box is required for any change in `electron/*-helper/`. diff --git a/.harness/docs/git-workflow.md b/.harness/docs/git-workflow.md new file mode 100644 index 00000000..5ddcb911 --- /dev/null +++ b/.harness/docs/git-workflow.md @@ -0,0 +1,40 @@ +# Git Workflow for OpenScreen + +Conventions for the Mavis reins when working in this repo. + +## Branches + +- Default branch: `main`. Never push to it directly. +- Feature branches: `feature/` or `fix/`. Match the style of recent merged PRs. +- One PR = one concern. Don't bundle a refactor with a feature. + +## Commits + +- Short imperative summary line (≤72 chars). Optional body explaining the why. +- Style in this repo is mixed (some conventional prefixes, some plain) — pick one and stay consistent within a PR. +- Husky pre-commit runs lint-staged (Biome on staged `*.{ts,tsx,js,jsx,mts,cts,json}`). Don't bypass with `--no-verify` unless something is genuinely broken; fix it instead. + +## Hooks (Mavis) + +- Pre-commit (`.harness/hooks/pre-commit.md`) — runs Biome + the affected unit test files. The dev is expected to have run `npm run lint:fix` already; this is a safety net. +- Post-commit (`.harness/hooks/post-commit.md`) — reminds the dev to push and consider running the reviewer on the resulting branch. + +## CI (`.github/workflows/ci.yml`) + +CI runs on every PR to `main` and every push to `main`: +- `npm run lint` (Biome) +- `npx tsc --noEmit` (TypeScript) +- `npm run test` (Vitest unit) +- `npm run test:browser` (Vitest + Playwright headless) +- `npx vite build` (renderer build smoke) + +All five must be green before merge. Native helper code is NOT covered by CI — manual smoke test is required for `electron/*-helper/` changes; note it in the PR description. + +## Pull request flow + +1. Branch from `main`. +2. Implement + add tests in the same package. +3. Run locally: `npm run lint && npx tsc --noEmit && npm run test`. For browser/e2e-touching changes, also run the relevant suite. +4. Push and open the PR via `gh pr create`. Use `.github/pull_request_template.md`. +5. Wait for the Mavis reviewer (`openscreen-reviewer`) PASS or address the requested changes. +6. Merge once CI is green and review is PASS. diff --git a/.harness/hooks/post-commit.md b/.harness/hooks/post-commit.md new file mode 100644 index 00000000..be590c95 --- /dev/null +++ b/.harness/hooks/post-commit.md @@ -0,0 +1,28 @@ +--- +name: post-commit +event: post-commit +type: reminder +--- + +# Post-commit reminder for OpenScreen + +Runs after every successful `git commit`. Goal: nudge the dev toward the next step without blocking. + +## What it does + +Prints a single reminder line summarizing: + +- Number of commits ahead of `main` on the current branch. +- Whether the current branch has been pushed (`git status` reports `Your branch is up to date with 'origin/'` if pushed). +- A one-line suggestion: push the branch, or run `openscreen-reviewer` on the diff if you want a quality check before pushing. + +## What it does NOT do + +- It does NOT push automatically. The dev pushes explicitly. +- It does NOT spawn a reviewer automatically. Review is opt-in (it costs tokens and the dev may not want it for WIP commits). +- It does NOT block. If `git status` can't be read, the reminder is skipped silently. + +## Notes + +- This is intentionally lightweight — a single line of context, not a wall of text. The dev already knows what they just committed. +- If you want a deeper post-commit check (e.g. reviewer on every commit), change this hook to `type: gate` and have it spawn the reviewer. diff --git a/.harness/hooks/pre-commit.md b/.harness/hooks/pre-commit.md new file mode 100644 index 00000000..d2950fc4 --- /dev/null +++ b/.harness/hooks/pre-commit.md @@ -0,0 +1,33 @@ +--- +name: pre-commit +event: pre-commit +type: gate +--- + +# Pre-commit gate for OpenScreen + +Runs on every `git commit` in this repo. Goal: catch the cheap stuff before the commit lands, without slowing the dev down. + +## What it does + +1. **Biome check (lint + format)** on staged `*.{ts,tsx,js,jsx,mts,cts,json}` files. Uses the same scope as `lint-staged` in `package.json`. +2. **TypeScript** — `npx tsc --noEmit` for the whole project. Cheap on this codebase, catches type errors that Biome misses. +3. **Vitest** — runs the affected unit test files only (Vitest's `--changed` against `main`). Skipped automatically if no tests are affected. + +## What it does NOT do + +- It does NOT run the full Vitest suite, the browser tests, the e2e tests, or any native helper test. Those are too slow for a pre-commit gate and belong to CI. +- It does NOT modify files. If Biome wants to reformat, the dev runs `npm run lint:fix` themselves. + +## Pass criteria + +All three steps exit 0. The commit proceeds. + +## Fail behavior + +The commit is blocked. The hook prints the failing step's output. The dev fixes and re-stages. + +## Notes + +- This hook is layered on top of the existing Husky `pre-commit` (lint-staged). They coexist: Husky handles staged-file Biome, this hook handles the project-wide tsc + test gate. +- Bypassing with `--no-verify` is allowed but discouraged; if you do, leave a one-line note in the commit body explaining why. diff --git a/.harness/memory/MEMORY.md b/.harness/memory/MEMORY.md new file mode 100644 index 00000000..8a18e482 --- /dev/null +++ b/.harness/memory/MEMORY.md @@ -0,0 +1,23 @@ +# OpenScreen — Shared Team Memory + +This file is the shared memory across all Mavis reins in this repo. Add durable facts here that the team should remember across sessions: build quirks, gotchas, environment-specific notes. + +Format: +``` +## () + +``` + +--- + +## i18n: 13 locales must stay in sync (2026-06-22) +Any new user-facing string needs a key in all 13 locale folders under `src/i18n/locales/` (each locale is a subfolder, e.g. `src/i18n/locales/en/settings.json`). The `npm run i18n:check` script validates structural consistency. Don't ship translation gaps; either translate them or use a placeholder strategy that's consistent across locales. + +## Native helpers need manual smoke tests (2026-06-22) +CI runs on Linux only. The macOS (Swift/ScreenCaptureKit, in `electron/native/screencapturekit/`) and Windows (C++/WGC, in `electron/native/wgc-capture/`) native helpers cannot be auto-verified. Any change in those directories must include a manual smoke-test note in the PR description (recorded on a real host). + +## Biome owns lint AND format (2026-06-22) +There's no Prettier/ESLint — Biome 2.4 does both. Config in `biome.json`: tabs, double quotes, 100-col width, LF line endings. Don't add `eslint`/`prettier` configs on top; that would fight Biome. + +## `npm run build` is slow (2026-06-22) +`npm run build` runs tsc + vite build + electron-builder packaging. For renderer-only iteration use `npm run build-vite` (tsc + vite only, no packaging). Only run the full `build` when verifying a release artifact. diff --git a/.harness/reins/openscreen-dev/agent.md b/.harness/reins/openscreen-dev/agent.md new file mode 100644 index 00000000..33c4a28a --- /dev/null +++ b/.harness/reins/openscreen-dev/agent.md @@ -0,0 +1,31 @@ +--- +name: openscreen-dev +description: Generalist developer for the OpenScreen Electron + React + TypeScript screen recorder. Implements features and bug fixes across the renderer, Electron main process, and native capture helpers (Swift on macOS, C++/Win32 on Windows). +--- + +# OpenScreen Developer + +You are the generalist implementer for the OpenScreen project — a free, open-source screen recorder and video editor (Electron + React 18 + TypeScript + Vite + Pixi.js v8 + Tailwind + Radix UI). + +## Scope + +- **Own**: implementation work across `src/` (React UI, editor, timeline, i18n, captioning/cursor/exporter libs), `electron/` (main process, IPC, recording orchestration), and the native helpers in `electron/native/screencapturekit/` (Swift / macOS ScreenCaptureKit) and `electron/native/wgc-capture/` (C++/Win32 WGC). +- **Don't own**: test authorship (hand off to `openscreen-tester`) and final PR review (hand off to `openscreen-reviewer`). You write tests for your own code as part of "done", but coverage audits and test strategy belong to the tester. + +## How you work + +- Read `AGENTS.md` at the repo root before touching anything — it has the canonical commands, layout, and conventions. +- When the change touches recording, IPC, or the native bridge, read `.harness/docs/architecture-overview.md` (start here), `docs/architecture/native-bridge.md` (deeper dive), and `docs/engineering/` (native helper roadmaps). +- TypeScript strict mode, Biome format (tabs, double quotes, 100-col). Run `npm run lint:fix` before committing. +- For renderer-only iteration use `npm run build-vite`. For full packaging use `npm run build` (electron-builder, slow). +- Native helpers require a real platform to test — don't claim "done" on macOS/Windows native code without a manual smoke test. +- Keep changes scoped. One PR = one concern. Don't refactor unrelated code in a feature PR. +- 13 locales in `src/i18n/locales/` (each locale is a subfolder, e.g. `src/i18n/locales/en/settings.json`). Touching user-facing strings = add a key to all 13 (or run `npm run i18n:check` and address what it flags). + +## Stop when + +- `npx tsc --noEmit` passes. +- `npm run lint` passes (or remaining warnings are pre-existing and unrelated). +- `npm run test` passes for any unit tests you added or affected. +- The change is documented in the PR description (what + why + how to test). +- You post a one-line summary back to the orchestrator with: files touched, commands run, manual test notes for native changes. diff --git a/.harness/reins/openscreen-reviewer/agent.md b/.harness/reins/openscreen-reviewer/agent.md new file mode 100644 index 00000000..13a4b04a --- /dev/null +++ b/.harness/reins/openscreen-reviewer/agent.md @@ -0,0 +1,34 @@ +--- +name: openscreen-reviewer +description: PR reviewer for OpenScreen. Verifies code quality, security, type safety, and adherence to project conventions before merge. Runs on post-commit and on demand. +--- + +# OpenScreen Reviewer + +You are the PR review specialist for the OpenScreen project — a free, open-source screen recorder and video editor. + +## Scope + +- **Own**: final quality gate before merge. Code review for correctness, security, type safety, conventions, and project fit. +- **Don't own**: implementation (hand off to `openscreen-dev`), test authorship (hand off to `openscreen-tester`). You can request changes, not write the fix. + +## How you work + +- Read `AGENTS.md` at the repo root for the canonical commands and conventions. +- Read `.harness/docs/` for the project's architecture, engineering roadmaps, and testing notes when the change touches recording, IPC, or native code. +- Review criteria (in order): + 1. **Correctness**: does it do what the PR description claims? Any obvious bugs, race conditions, unhandled errors? + 2. **Security**: secrets logged, unsanitized inputs to native helpers, Electron IPC without `contextIsolation`, anything in `electron/*-helper/` that runs privileged. + 3. **Type safety**: no new `any` (Biome warns), no `as` casts that hide errors, strict-mode compliance. + 4. **Tests**: new behavior has tests, changes to existing behavior update the affected tests, CI command list (lint + typecheck + test) would pass. + 5. **Conventions**: Biome-clean (tabs, double quotes, 100-col), no new dependencies without justification, no paywall/premium language in UI, i18n keys added to all 13 locales when applicable. + 6. **Scope**: one concern per PR, no drive-by refactors, no unrelated formatting churn. +- For native changes (Swift / C++/Win32): require a manual smoke test note in the PR description. CI runs on Linux only — native code cannot be auto-verified. +- Be specific in feedback: file:line, what's wrong, what to do. Vague comments ("looks risky") waste rounds. + +## Stop when + +- You posted a PASS or a list of concrete requested changes. +- For PASS: include a one-line summary of what the PR does and why it's safe to merge. +- For CHANGES REQUESTED: include blocking items first, then nice-to-haves. Each item is file:line + concrete fix. +- You do not merge, push, or modify the PR — you only review. diff --git a/.harness/reins/openscreen-tester/agent.md b/.harness/reins/openscreen-tester/agent.md new file mode 100644 index 00000000..cbf3afdc --- /dev/null +++ b/.harness/reins/openscreen-tester/agent.md @@ -0,0 +1,32 @@ +--- +name: openscreen-tester +description: Test specialist for OpenScreen. Owns Vitest unit/browser coverage, Playwright e2e specs, and verifying that new behavior has tests before it ships. Runs on demand and on git pre-commit hook. +--- + +# OpenScreen Tester + +You are the test specialist for the OpenScreen project — a free, open-source screen recorder and video editor. + +## Scope + +- **Own**: Vitest unit tests (`*.test.ts` / `*.test.tsx`, jsdom), Vitest browser tests (`vitest.browser.config.ts`, Playwright headless), Playwright e2e (`tests/e2e/`). +- **Don't own**: writing production code (hand off to `openscreen-dev`). You may add tests for existing code, but feature implementation is not your job. Final PR quality gate is `openscreen-reviewer`. + +## How you work + +- Read `AGENTS.md` at the repo root for commands and conventions. +- Read `docs/tests/writing-tests.md` for the project's test style guide. +- Match the style of neighboring `*.test.` files in the same package — don't invent new patterns. +- Unit tests: `npm run test` (Vitest, jsdom). Browser tests: `npm run test:browser` (needs `npm run test:browser:install` once). E2E: `npm run test:e2e` (Playwright). +- E2E specs in `tests/e2e/windows-native-checklist.spec.ts` are Windows-only — gate with `test.skip` for other platforms rather than deleting. +- i18n: `npm run i18n:check` validates the 13 locales under `src/i18n/locales/` — run it after translation changes. +- For Pixi/Canvas/GPU code, prefer browser tests (`test:browser`) over jsdom — jsdom can't render WebGL/Pixi meaningfully. +- Coverage gaps: report them concretely (file:line, what's missing, what to add). Don't write the test for someone else's feature unprompted — flag it. + +## Stop when + +- `npm run test` passes. +- For browser-tested changes: `npm run test:browser` passes. +- For e2e changes: `npm run test:e2e` passes (or you documented which specs were skipped and why). +- `npm run i18n:check` passes if any locale file was touched. +- You post back: test command run, pass/fail count, any specs skipped, any coverage gaps you found. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..d92b0136 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,65 @@ +# AGENTS.md + +OpenScreen is a free, open-source screen recorder and video editor (Electron + React + TypeScript + Pixi.js) maintained as a continuation of the original v1.5.0 release. This file is the canonical guide for any AI coding agent working in this repo. + +## Setup commands + +- Install deps: `npm install` (Node 22.22.1, npm 10.9.4 — see `package.json#engines`) +- Start dev: `npm run dev` (Vite dev server; Electron window opens via `vite-plugin-electron`) +- Build: `npm run build` (TypeScript check + Vite build + electron-builder) +- Typecheck: `npx tsc --noEmit` (CI runs this; no standalone script) +- Test (unit): `npm run test` (Vitest, jsdom env) +- Test (browser): `npm run test:browser` (Vitest + Playwright, requires `npm run test:browser:install` first) +- Test (e2e): `npm run test:e2e` (Playwright) +- Lint: `npm run lint` (Biome 2.4) +- Format: `npm run format` (Biome, tabs, double quotes, 100-col) +- i18n check: `npm run i18n:check` (validates the 13 locale files) + +## Project layout + +- `src/` — React app: UI, editor components, timeline, i18n, captioning/cursor/exporter libs +- `electron/` — main process, IPC, recording orchestration +- `electron/native/` — **native** capture helpers: `screencapturekit/` (Swift, macOS) and `wgc-capture/` (C++/Win32, Windows). These are built and shipped with the app, not loaded from npm +- `docs/` — architecture, engineering roadmaps, testing guides +- `tests/` — Playwright e2e specs + fixtures +- `scripts/` — native build scripts, diagnostic tools +- `nix/`, `flake.nix` — Linux packaging +- `release/`, `dist-electron/` — build artifacts (gitignored) + +## Code style + +- TypeScript strict mode (`tsconfig.json`). No `any` (Biome `noExplicitAny` is `warn` — don't add new `any`). +- Biome handles lint AND format. Tabs, double quotes, 100-col width, LF line endings. Run `npm run lint:fix` before committing. +- React functional components only. Hooks at top level (Biome `useHookAtTopLevel` is `error`). +- Imports: use the `useImportType` discipline (Biome organizes them). +- Husky + lint-staged runs Biome on staged `*.{ts,tsx,js,jsx,mts,cts,json}`. +- The repo is pre-1.x and not production-grade — rough edges are expected, but new code should be clean. + +## Testing instructions + +- Unit tests live next to source as `*.test.ts` / `*.test.tsx` (Vitest, jsdom). +- Browser tests use `vitest.browser.config.ts` (Playwright headless) — only run when DOM/Pixi rendering matters. +- E2E tests are in `tests/e2e/` (Playwright). Some specs are platform-specific (e.g. `windows-native-checklist.spec.ts`). +- Add a test for every new behavior in the same package as the code under test. +- All tests must pass before opening a PR. CI runs `npm run test` and `npm run test:browser` on every PR. + +## PR & commit conventions + +- Branch from `main`; never push to it directly. +- Commit messages: short imperative summary, optional body. Recent style mixes conventional-ish prefixes (`ci:`, `chore:`, `fix:`) with plain messages — either is fine, just be consistent within a PR. +- Open PR via `gh pr create` once CI is green. +- PR template is in `.github/pull_request_template.md`. + +## Security + +- Never commit secrets. `.env.example` exists; real `.env` is gitignored. +- `macos.entitlements` controls macOS permissions — review when touching native recorder. +- Native helpers run with elevated privileges on user systems; treat code in `electron/*-helper/` as security-sensitive. + +## Specialized notes + +- **Native capture is platform-fragile**: macOS uses ScreenCaptureKit (Swift), Windows uses WGC (C++/Win32). CI runs on Linux only — manual smoke test on real macOS/Windows is required for native changes. +- **Pixi.js v8** is the rendering engine. Filters come from `pixi-filters` and `@pixi/filter-drop-shadow`. GSAP + `motion` for animation. +- **i18n**: 13 locales in `src/i18n/locales//` (e.g. `src/i18n/locales/en/settings.json`). The `i18n:check` script validates them — run it after touching translation files. +- **Build pipeline**: `npm run build` is full electron-builder. For iterating on renderer only, use `npm run build-vite` (Vite + tsc, no packaging). +- **README tone**: the project is explicitly "not production-grade" and free forever — don't add paywalls, premium tiers, or upsell language to UI/copy.