Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
bdf2c28
chore: set up pnpm workspace for client + server split
amide-init Sep 23, 2026
5c2eb0c
chore: add root package.json, workspace lockfile, and .gitignore
amide-init Sep 23, 2026
aaddf5a
feat(server): scaffold Bun + Hono backend package
amide-init Sep 23, 2026
6e8d0ec
feat(server): add Prisma client on the libsql driver adapter
amide-init Sep 23, 2026
18109ed
feat(server): copy AI transcription/filler-word and captions libs
amide-init Sep 23, 2026
29e0221
feat(server): copy FFmpeg rendering libs
amide-init Sep 23, 2026
aebd73c
feat(server): copy shared video/timeline math and request validation
amide-init Sep 23, 2026
2e29d8c
feat(server): copy storage lib, dropping the Next-specific stream bridge
amide-init Sep 23, 2026
c7ad989
feat(server): add projects list/detail/rename/delete Hono routes
amide-init Sep 23, 2026
aaec1c5
feat(server): add video Range-serving Hono route
amide-init Sep 23, 2026
91c0bf9
feat(server): add streaming video upload Hono route
amide-init Sep 23, 2026
58c6408
feat(server): add transcription and transcript Hono routes
amide-init Sep 23, 2026
ebdd12d
feat(server): add operations, filler-words, captions, and logo Hono r…
amide-init Sep 23, 2026
1b22729
feat(server): add render job Hono routes
amide-init Sep 23, 2026
91bdbb5
feat(server): wire up the Hono app entrypoint
amide-init Sep 23, 2026
1c14121
fix(server): advertise Accept-Ranges on the plain video response too
amide-init Sep 23, 2026
34ad348
feat(client): scaffold Vite entrypoint alongside the still-running Ne…
amide-init Sep 23, 2026
1b3cb31
feat(client): add React Router routes, replacing Next's app router
amide-init Sep 23, 2026
9b9b577
feat(client): swap next/link and useRouter for react-router-dom
amide-init Sep 23, 2026
78bc95d
feat(client): delete the Next.js app
amide-init Sep 23, 2026
c544c7c
chore(client): finish tooling cleanup after removing Next.js
amide-init Sep 23, 2026
28e0205
docs: update README/CONTRIBUTING/setup script for client+server split
amide-init Sep 23, 2026
1e6af32
docs: update claude.md for the client/server split
amide-init Sep 23, 2026
39d6691
feat(server): add request logging, unify all logs behind one template
amide-init Sep 23, 2026
ca24889
feat: add server-bundle staging script for Tauri packaging (Phase 0)
amide-init Sep 23, 2026
504c001
feat(server): serve the built client + SPA fallback (Phase 1)
amide-init Sep 23, 2026
e6adf86
feat: scaffold bare Tauri project (Phase 2)
amide-init Sep 23, 2026
9a00bf4
fix: use pnpm's hoisted node-linker for the server bundle's node_modules
amide-init Sep 23, 2026
fcc3369
feat: wire up the packaged app's server spawn/lifecycle (Phase 3)
amide-init Sep 23, 2026
eb12eb8
docs: document the Tauri macOS app packaging
amide-init Sep 23, 2026
fedc01f
fix: navigate the webview once the server is actually ready
amide-init Sep 23, 2026
759fc12
fix: exclude src-tauri from client eslint
amide-init Sep 23, 2026
e7099e9
feat: add an in-app first-run setup screen for the OpenAI API key
amide-init Sep 23, 2026
f9c1daf
fix: make the Tauri build portable, add a dmg release target
amide-init Sep 23, 2026
bed87cb
fix: bring ci.yml up to date with the client/server split
amide-init Sep 23, 2026
655ffa8
feat: add CI workflow to build and release the macOS app
amide-init Sep 23, 2026
57e27a9
docs: add a download page for the macOS app and link it from README/nav
amide-init Sep 23, 2026
3f7dad8
docs: fix stale Next.js references left over from the client/server s…
amide-init Sep 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/build-macos-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Build macOS App

on:
push:
tags: ["v*.*.*"]
workflow_dispatch:

permissions:
contents: write

jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
with:
version: 10

- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
cache-dependency-path: pnpm-lock.yaml

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- uses: dtolnay/rust-toolchain@stable

- name: Install dependencies
run: pnpm install --frozen-lockfile

# Runs beforeBuildCommand internally (builds the Vite client, then
# scripts/prepare-server-bundle.sh stages the backend) before
# compiling and bundling the Rust shell -- one command covers the
# whole pipeline, see client/src-tauri/tauri.conf.json.
- name: Build the Tauri app
working-directory: client
run: pnpm exec tauri build

- name: Zip the .app bundle
working-directory: client/src-tauri/target/release/bundle/macos
run: ditto -c -k --sequesterRsrc --keepParent "AI Video Editor.app" "AI-Video-Editor-macos-arm64.app.zip"

# Uploaded on every run (including workflow_dispatch) so the build
# can be verified end-to-end -- downloaded from the run's own
# artifacts -- before this workflow is ever allowed to touch a real
# public release.
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: macos-app
path: |
client/src-tauri/target/release/bundle/macos/AI-Video-Editor-macos-arm64.app.zip
client/src-tauri/target/release/bundle/dmg/*.dmg
if-no-files-found: error

# Only attaches to a public GitHub Release when this run was
# actually triggered by a version tag push -- a manual
# workflow_dispatch run never touches the public releases page.
- name: Attach to release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: |
client/src-tauri/target/release/bundle/macos/AI-Video-Editor-macos-arm64.app.zip
client/src-tauri/target/release/bundle/dmg/*.dmg
24 changes: 13 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ on:
jobs:
lint-and-build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: client
steps:
- uses: actions/checkout@v4

Expand All @@ -23,13 +20,18 @@ jobs:
with:
node-version: 20
cache: pnpm
cache-dependency-path: client/pnpm-lock.yaml
cache-dependency-path: pnpm-lock.yaml

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Generate Prisma client
run: pnpm exec prisma generate
- name: Generate Prisma client (server)
working-directory: server
run: bunx prisma generate

- name: Lint
run: pnpm run lint
Expand All @@ -40,9 +42,9 @@ jobs:
- name: Build
run: pnpm run build
env:
# Not required anymore (lib/ai/{transcribe,filler-words}.ts now
# construct their OpenAI client lazily on first call, not at
# module load, so `next build` succeeds even with this unset) --
# kept as defense-in-depth against that regressing back to eager
# construction. Not a real secret, no API calls happen during build.
# Not required for the build itself (lib/ai/{transcribe,filler-words}.ts
# construct their OpenAI client lazily, only on first real call --
# nothing at build time imports/executes that code) -- kept as
# defense-in-depth in case that ever regresses. Not a real secret,
# no API calls happen during build.
OPENAI_API_KEY: dummy-key-for-ci-build-only
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# dependencies
node_modules

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*
!.env.example

# typescript
*.tsbuildinfo

# staged Tauri backend bundle (built by scripts/prepare-server-bundle.sh)
/server-bundle
36 changes: 20 additions & 16 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,32 @@ issues for bugs and ideas.
## Running it locally

On macOS, `./scripts/setup-mac.sh` handles all of this for you (Node/pnpm/
FFmpeg via Homebrew, `pnpm install`, `prisma generate`, and `.env`) --
Bun/FFmpeg via Homebrew, `pnpm install`, `prisma generate`, and `.env`) --
see the README's "macOS quick start". Otherwise, manually:

```bash
cd client
pnpm install
cp .env.example .env # then fill in OPENAI_API_KEY
pnpm exec prisma generate
pnpm run dev
pnpm install # installs deps for client + server
cd server
cp .env.example .env # then fill in OPENAI_API_KEY
bunx prisma generate
cd ..
pnpm run dev # runs the Vite client and Bun backend together
```

Open [http://localhost:3000](http://localhost:3000). See
[`.env.example`](./client/.env.example) for what each variable does.
Open [http://localhost:5173](http://localhost:5173). See
[`server/.env.example`](./server/.env.example) for what each variable
does.

You'll also need [FFmpeg](https://ffmpeg.org/download.html) on your
machine for transcript editing and export to work. If burning in captions
fails with `No such filter: 'subtitles'`, your FFmpeg build doesn't
include libass — see the `FFMPEG_PATH` note in `.env.example` (or just use
`scripts/setup-mac.sh`, which installs and points at a build that has it).
You'll also need [FFmpeg](https://ffmpeg.org/download.html) and
[Bun](https://bun.sh) (the backend's runtime) on your machine. If burning
in captions fails with `No such filter: 'subtitles'`, your FFmpeg build
doesn't include libass — see the `FFMPEG_PATH` note in `.env.example` (or
just use `scripts/setup-mac.sh`, which installs and points at a build
that has it).

## Before submitting a PR

```bash
cd client
pnpm run lint
pnpm run test
pnpm run build
Expand All @@ -40,8 +42,10 @@ pnpm run build
All three must pass — CI runs the same three commands on every PR. If
you're changing pure logic (timeline math, transcript mapping, ffmpeg
argument/filter-string building, validation, path handling), add or update
a test in the matching `*.test.ts` file rather than only checking it by
hand — `pnpm run test:watch` re-runs on save.
a test in the matching `*.test.ts` file in whichever package (`client/` or
`server/`) owns that code, rather than only checking it by hand --
`pnpm --filter client test:watch` or `pnpm --filter server test:watch`
re-runs on save.

## Project structure and conventions

Expand Down
72 changes: 48 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ the actual export drifting apart, which happened in practice for several
of these (see the issue tracker's closed bugs).

Local persistence (SQLite via Prisma) and project CRUD are built and in
use. The separate `server/` directory isn't — see the
[issue tracker](https://github.com/amide-init/transcriptcut/issues) for the
full breakdown of what's done vs. planned. Everything currently runs
inside the `client/` Next.js app, including the API routes.
use. The app is a Vite React SPA (`client/`) talking to a Bun/Hono
backend (`server/`) — the two run as separate processes, kept in one
piece by `pnpm run dev` from the repo root. This split (no server-side
rendering, one deployable backend unit) is prep for an eventual native
Mac app via Tauri; see the [issue tracker](https://github.com/amide-init/transcriptcut/issues)
for the full breakdown of what's done vs. planned.

There is no login — v1 is a single local user by design, not a gap to
fill in. **Don't expose this to a public or shared network** without
Expand All @@ -57,9 +59,9 @@ adding real authentication first; see `claude.md` section 18.

```text
claude.md — product spec
client/ — Next.js app (editor UI + API routes)
client/ — Vite + React editor UI (SPA, no server rendering)
server/ — Bun + Hono backend (API routes, FFmpeg, Prisma/SQLite, OpenAI)
docs/ — documentation site (VitePress, deployed to GitHub Pages)
server/ — reserved for future use, not in use yet
```

## Documentation
Expand All @@ -77,40 +79,63 @@ pnpm install
pnpm run dev
```

## Running the client
## Running the app

Requires [FFmpeg](https://ffmpeg.org/download.html) on your machine
(used for cuts and export) and an OpenAI API key (used server-side only,
for transcription).
Requires [FFmpeg](https://ffmpeg.org/download.html) and
[Bun](https://bun.sh) (the backend's runtime) on your machine, plus an
OpenAI API key (used server-side only, for transcription).

### macOS quick start

[`scripts/setup-mac.sh`](./scripts/setup-mac.sh) installs Node/pnpm/FFmpeg
(with subtitle burn-in support) via Homebrew if you don't already have
them, installs dependencies, and walks you through `.env`:
[`scripts/setup-mac.sh`](./scripts/setup-mac.sh) installs Node/pnpm/Bun/
FFmpeg (with subtitle burn-in support) via Homebrew if you don't already
have them, installs dependencies for the whole workspace, and walks you
through `.env`:

```bash
git clone https://github.com/amide-init/transcriptcut.git
cd transcriptcut
./scripts/setup-mac.sh
```

Then `cd client && pnpm run dev`. Safe to re-run -- it only installs
what's missing and never overwrites an existing `.env`.
Then `pnpm run dev` from the repo root. Safe to re-run -- it only
installs what's missing and never overwrites an existing `.env`.

### Manual setup (any platform)

```bash
pnpm install # installs deps for client + server
cd server
cp .env.example .env # then fill in OPENAI_API_KEY
bunx prisma generate
cd ..
pnpm run dev # runs the Vite client and Bun backend together
```

Open [http://localhost:5173](http://localhost:5173). See
[`server/.env.example`](./server/.env.example) for what each variable
does, and [`CONTRIBUTING.md`](./CONTRIBUTING.md) for more.

### Download

A native macOS app is also available (Apple Silicon only) — no need to
clone the repo or run anything. Grab it from the
**[docs download page](https://amide-init.github.io/transcriptcut/download)**,
which also covers the one-time Gatekeeper step (this build is ad-hoc
signed, not signed with a paid Apple Developer account) and the
first-launch API key setup.

To build it yourself instead:

```bash
cd client
pnpm install
cp .env.example .env # then fill in OPENAI_API_KEY
pnpm exec prisma generate
pnpm run dev
pnpm exec tauri build
```

Open [http://localhost:3000](http://localhost:3000). See
[`.env.example`](./client/.env.example) for what each variable does, and
[`CONTRIBUTING.md`](./CONTRIBUTING.md) for more.
Produces `client/src-tauri/target/release/bundle/{macos,dmg}/`. See
`claude.md` section 35 for how it's wired together, and
[`.github/workflows/build-macos-app.yml`](./.github/workflows/build-macos-app.yml)
for how CI builds and releases it on a version tag push.

## Testing

Expand All @@ -120,8 +145,7 @@ builder, path-traversal safety, and the CSS-preview/ffmpeg-export formula
parity work described in the issue tracker:

```bash
cd client
pnpm run test
pnpm run test # runs both client and server test suites
```

CI runs the same command on every PR. There's no end-to-end/UI test suite
Expand Down
Loading
Loading