Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5fd2f6e
chore(provenance): add reproducible FreeCut package baseline
lightninglu10 Aug 15, 2026
e2733fd
chore(provenance): add reproducible FreeCut package baseline
lightninglu10 Aug 15, 2026
11d63a9
feat(editor): add CodePress command adapter boundary
lightninglu10 Aug 15, 2026
212a18c
fix(editor): harden fractional frame adapter paths
lightninglu10 Aug 16, 2026
86722c5
fix(editor): close adapter boundary review gaps
lightninglu10 Aug 16, 2026
6d6e5a4
Merge pull request #2 from quantfive/pr3-freecut-adapter-5319
lightninglu10 Aug 16, 2026
856d605
feat(editor): add host-backed FreeCut surface
lightninglu10 Aug 17, 2026
e5b6d19
fix(editor): guard host mode from audio skim persistence
lightninglu10 Aug 17, 2026
f9abfb2
Merge pull request #4 from quantfive/freecut-host-surface-5319
lightninglu10 Aug 17, 2026
050aa1d
feat(package): publish host-backed editor surface
lightninglu10 Aug 17, 2026
524f43d
chore(package): publish editor surface privately
lightninglu10 Aug 17, 2026
60ac3e5
fix(package): keep private publish guard below quality threshold
lightninglu10 Aug 17, 2026
fd487df
fix(package): gate publish on packed consumer smoke
lightninglu10 Aug 17, 2026
4979b48
fix(package): keep consumer smoke outside root check
lightninglu10 Aug 17, 2026
87aee5c
Merge pull request #5 from quantfive/freecut-frontend-package-5319
lightninglu10 Aug 17, 2026
8077bbd
Add caption commands and FreeCut caption UI (#3)
lightninglu10 Aug 17, 2026
352a5a1
fix(release): fetch full history for editor surface publish (#6)
lightninglu10 Aug 17, 2026
1a570eb
fix(release): publish editor surface tarball as local file (#7)
lightninglu10 Aug 18, 2026
77d2b49
feat(editor): add host-backed transcript consumer
lightninglu10 Aug 19, 2026
431988e
fix(editor): keep host-visible sidebar tab across authoritative snaps…
lightninglu10 Aug 19, 2026
5a6d87d
publish the editor surface to public npm via trusted publishing
lightninglu10 Aug 20, 2026
efc6b07
point the publish and sync workflows at codepress-main
lightninglu10 Aug 20, 2026
652fcd3
drop the stale github packages line from the surface readme
lightninglu10 Aug 20, 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
44 changes: 42 additions & 2 deletions .fallowrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,19 @@
"src/features/effects/components/panels/gpu-wheels-panel.tsx",
"src/features/effects/components/panels/gpu-curves-panel.tsx",
"src/features/timeline/components/timeline.tsx",
"src/features/timeline/services/reverse-conform-service.ts"
"src/features/timeline/services/reverse-conform-service.ts",
// PR3's contract validator and pure edit engine are intentionally
// branch-dense boundary code; they are covered by conformance tests and
// should not be treated as UI health hotspots.
"src/features/editor/codepress/adapter.ts",
"src/features/editor/codepress/contract.ts",
"src/features/editor/codepress/document.ts",
"src/features/editor/codepress/edit-engine.ts",
"src/features/editor/codepress/timing.ts",
"src/features/editor/codepress/translation.ts"
]
},
"usedClassMembers": ["addEventListener", "removeEventListener"],
"usedClassMembers": ["addEventListener", "removeEventListener", "subscribe"],
"rules": {},
"ignoreExports": [
{
Expand Down Expand Up @@ -124,6 +133,37 @@
{
"file": "src/features/editor/deps/timeline-store.ts",
"exports": ["*"]
},
{
// Controlled PR3 package surface: these exports are consumed by the
// future CodePress shell/worker boundary rather than the current app
// entrypoint. Keep them visible to type/lint/tests, not dead-code trim.
"file": "src/features/editor/codepress/adapter.ts",
"exports": ["*"]
},
{
"file": "src/features/editor/codepress/contract.ts",
"exports": ["*"]
},
{
"file": "src/features/editor/codepress/controlled-editor.ts",
"exports": ["*"]
},
{
"file": "src/features/editor/codepress/document.ts",
"exports": ["*"]
},
{
"file": "src/features/editor/codepress/edit-engine.ts",
"exports": ["*"]
},
{
"file": "src/features/editor/codepress/timing.ts",
"exports": ["*"]
},
{
"file": "src/features/editor/codepress/translation.ts",
"exports": ["*"]
}
]
}
92 changes: 92 additions & 0 deletions .github/workflows/publish-editor-surface.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: Publish FreeCut editor surface

on:
workflow_dispatch:
push:
branches:
- codepress-main
tags:
- 'freecut-editor-surface-v*'

permissions:
contents: read
# npm trusted publishing (OIDC): the job exchanges the GitHub Actions
# identity token for a short-lived npm credential, so there is no NPM_TOKEN
# to store or rotate. Requires a trusted publisher configured on npmjs.com
# for this repository and this workflow filename.
id-token: write

concurrency:
group: publish-freecut-editor-surface
cancel-in-progress: false

jobs:
publish:
name: Publish @quantfive/freecut-editor-surface
# Manual runs are intentionally limited to staging; tag pushes are
# already constrained by the trigger below and must match the package
# version in the validation step.
if: github.event_name == 'push' || github.ref_name == 'staging'
# A merge that does not bump the version is a no-op, not a failure: npm
# rejects republishing an existing version, and the branch trigger fires
# on every qualifying merge.
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22.14.0'
cache: npm
registry-url: https://registry.npmjs.org

- name: Select pinned npm
run: npm install --global npm@11.8.0

- name: Install locked dependencies
run: npm ci --ignore-scripts

- name: Verify provenance
run: npm run verify:provenance

- name: Validate release tag
if: startsWith(github.ref, 'refs/tags/')
shell: bash
run: |
set -euo pipefail
tag_version="${GITHUB_REF_NAME#freecut-editor-surface-v}"
package_version="$(node -p "require('./packages/freecut-editor/package.json').version")"
if [[ "${GITHUB_REF_NAME}" != freecut-editor-surface-v* || "${tag_version}" != "${package_version}" ]]; then
echo "Release tag ${GITHUB_REF_NAME} must match package version ${package_version}." >&2
exit 1
fi

- name: Build deterministic package artifact
run: npm run package:editor-surface

- name: Verify packed artifact as an installed consumer
shell: bash
run: |
set -euo pipefail
package_version="$(node -p "require('./packages/freecut-editor/package.json').version")"
artifact="artifacts/freecut-editor-surface-${package_version}.tgz"
test -f "${artifact}"
npm run test:editor-surface:consumer -- --artifact "${artifact}"

- name: Publish to the public npm registry
shell: bash
run: |
set -euo pipefail
package_version="$(node -p "require('./packages/freecut-editor/package.json').version")"
artifact="artifacts/freecut-editor-surface-${package_version}.tgz"
test -f "${artifact}"
if npm view "@quantfive/freecut-editor-surface@${package_version}" version >/dev/null 2>&1; then
echo "::notice::@quantfive/freecut-editor-surface@${package_version} is already published; nothing to do."
exit 0
fi
npm publish "./${artifact}" --provenance --access public
49 changes: 49 additions & 0 deletions .github/workflows/reproducible-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Reproducible Package Baseline

on:
pull_request:
push:
branches:
- main
- staging

permissions:
contents: read

jobs:
package:
name: Verify and package baseline
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22.14.0'
cache: npm

- name: Select pinned npm
run: npm install --global npm@11.8.0

- name: Install locked dependencies
run: npm ci --ignore-scripts

- name: Verify provenance, dependency, and asset inventories
run: npm run verify:provenance

- name: Build and package
run: npm run package:reproducible

- name: Rebuild and compare package bytes
shell: bash
run: |
artifact="$(find artifacts -maxdepth 1 -type f -name 'freecut-*.tar.gz' -print -quit)"
test -n "$artifact"
cp "$artifact" "$RUNNER_TEMP/freecut-first.tar.gz"
npm run package:reproducible
cmp --silent "$RUNNER_TEMP/freecut-first.tar.gz" "$artifact"
38 changes: 38 additions & 0 deletions .github/workflows/sync-upstream.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Keep `main` a clean mirror of upstream walterlow/freecut.
#
# Nothing CodePress-owned is ever committed to `main`. Our work lives on the
# `codepress-main` integration branch, and upstream reaches it through a reviewed
# PR (`main` -> `codepress-main`) rather than by landing here directly. That keeps
# `gh repo sync` a fast-forward, so this job never has to resolve a conflict
# unattended.
name: sync-upstream

on:
schedule:
- cron: "0 8 * * 1" # Mondays, 08:00 UTC
workflow_dispatch:

permissions:
contents: write

jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Fast-forward main from upstream
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh repo sync ${{ github.repository }} --source walterlow/freecut --branch main

# Surface the delta so upstream drift is visible without anyone going
# looking for it. This opens nothing and merges nothing by itself.
- name: Report how far codepress-main trails main
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
behind="$(gh api "repos/${{ github.repository }}/compare/codepress-main...main" --jq '.ahead_by')"
if [ "${behind:-0}" -gt 0 ]; then
echo "::warning::codepress-main is $behind commit(s) behind upstream main. Open a PR from main into codepress-main to integrate."
else
echo "codepress-main is up to date with upstream main."
fi
46 changes: 46 additions & 0 deletions docs/pr2-provenance-and-packaging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# PR2 provenance and reproducible packaging

This fork baseline is the mechanical deliverable for [CodePress issue #5319](https://github.com/quantfive/codepress/issues/5319), PR 2. It records the selected FreeCut source and makes a clean install, build, and package check repeatable. It does not add editor behavior, embed commands, CodePress integration, or the PR 3 adapter.

## Source of record

The selected upstream is [`walterlow/freecut`](https://github.com/walterlow/freecut), the repository named by issue #5319. The requested [`FreeCutEditor/freecut`](https://github.com/FreeCutEditor/freecut) path was not resolvable when the fork was created. The fork is [`quantfive/freecut`](https://github.com/quantfive/freecut).

The exact source revision is:

```text
4d62e8082c5eb387a96275bcbd323d28f6e41a62
```

`provenance/freecut-baseline.json` records the commit, Git tree, deterministic `git archive` checksum, fork URL, and the retained MIT license checksum. The source archive checksum is computed over:

```bash
SOURCE_DATE_EPOCH=0 git archive --format=tar \
--prefix=freecut-4d62e8082c5eb387a96275bcbd323d28f6e41a62/ \
4d62e8082c5eb387a96275bcbd323d28f6e41a62 | shasum -a 256
```

The existing `LICENSE`, `src/infrastructure/audio/THIRD_PARTY_LICENSE`, and Anime4K `NOTICE.md` are retained and copied into the package artifact's notices directory. The existing bundled Anime4K weights remain unchanged; their upstream attribution is preserved in that notice.

## Inventories

- `provenance/dependency-inventory.json` records every direct runtime and development dependency exactly as declared by `package.json`, plus the lockfile version and checksum. The lockfile is the install source of truth; this PR does not upgrade dependencies.
- `provenance/asset-inventory.json` records tracked public assets, source preview assets, and the bundled Anime4K model/notice directory by file count, byte count, and a canonical SHA-256 inventory hash.
- `provenance/freecut-baseline.json` lists the optional model identifiers and network services that are deliberately not package inputs.

The optional model code remains in the upstream source, but its weights/caches are not downloaded by the package command. The baseline also excludes the loopback headless `/v1` service, remote font/Lottie services, model/CDN endpoints, Remotion, and all CodePress backend/UI/command-contract work. These exclusions are documentation and packaging boundaries only; they do not change runtime behavior.

## Clean reproducible package

Use Node.js 22.14.0 and npm 11.8.0, matching the CI workflow:

```bash
npm install --global npm@11.8.0
npm ci --ignore-scripts
npm run verify:provenance
npm run package:reproducible
```

`package:reproducible` removes the ignored `dist/` output, runs the production build, verifies provenance/inventory checks, and writes `artifacts/freecut-<source-revision>.tar.gz`. The archive has sorted paths, normalized metadata, zero timestamps, and uid/gid 0. It contains the built `dist/`, package manifests, provenance manifests, the MIT license, and retained notices.

Run the command twice and compare the resulting archive with `cmp` to verify byte-for-byte reproducibility. CI performs that comparison on every pull request and push to `main` or `staging`.
17 changes: 11 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@
"dev:quiet": "vp dev --host --mode perf",
"dev:compare": "node scripts/run-dev-and-perf.mjs",
"build": "vp build",
"build:editor-surface": "vp build --config vite.editor-package.config.ts",
"test:editor-surface:consumer": "node scripts/test-editor-surface-consumer.mjs",
"verify:provenance": "node scripts/package-reproducible.mjs --verify-only",
"package:reproducible": "node scripts/package-reproducible.mjs",
"package:editor-surface": "node scripts/package-editor-surface.mjs",
"build:perf": "vp build --mode perf",
"lint": "vp lint src headless vite.config.ts",
"lint:fix": "vp lint src headless vite.config.ts --fix",
"format": "vp fmt src headless vite.config.ts package.json .oxlintrc.json .oxfmtrc.json",
"format:check": "vp fmt src headless vite.config.ts package.json .oxlintrc.json .oxfmtrc.json --check",
"lint": "vp lint src packages/freecut-editor/src packages/freecut-editor/consumer-smoke.test.tsx packages/freecut-editor/consumer-smoke.setup.ts packages/freecut-editor/consumer-smoke-style.d.ts scripts/package-editor-surface.mjs scripts/test-editor-surface-consumer.mjs headless vite.config.ts vite.editor-package.config.ts vite.editor-package.test.config.ts",
"lint:fix": "vp lint src packages/freecut-editor/src packages/freecut-editor/consumer-smoke.test.tsx packages/freecut-editor/consumer-smoke.setup.ts packages/freecut-editor/consumer-smoke-style.d.ts scripts/package-editor-surface.mjs scripts/test-editor-surface-consumer.mjs headless vite.config.ts vite.editor-package.config.ts vite.editor-package.test.config.ts --fix",
"format": "vp fmt src packages/freecut-editor/src packages/freecut-editor/consumer-smoke.test.tsx packages/freecut-editor/consumer-smoke.setup.ts packages/freecut-editor/consumer-smoke-style.d.ts scripts/package-editor-surface.mjs scripts/test-editor-surface-consumer.mjs headless vite.config.ts vite.editor-package.config.ts vite.editor-package.test.config.ts package.json packages/freecut-editor/package.json .oxlintrc.json .oxfmtrc.json",
"format:check": "vp fmt src packages/freecut-editor/src packages/freecut-editor/consumer-smoke.test.tsx packages/freecut-editor/consumer-smoke.setup.ts packages/freecut-editor/consumer-smoke-style.d.ts scripts/package-editor-surface.mjs scripts/test-editor-surface-consumer.mjs headless vite.config.ts vite.editor-package.config.ts vite.editor-package.test.config.ts package.json packages/freecut-editor/package.json .oxlintrc.json .oxfmtrc.json --check",
"check:boundaries": "node scripts/check-feature-boundaries.mjs",
"check:deps-contracts": "node scripts/check-deps-contract-boundaries.mjs",
"check:legacy-lib-imports": "node scripts/check-legacy-lib-imports.mjs",
Expand All @@ -24,8 +29,8 @@
"check:edge-budgets": "node scripts/check-feature-edge-budgets.mjs",
"report:feature-edges": "node scripts/report-feature-edges.mjs",
"report:feature-edges:json": "node scripts/report-feature-edges.mjs --json",
"check": "vp check --no-fmt src headless vite.config.ts",
"check:fix": "vp check src headless vite.config.ts package.json .oxlintrc.json .oxfmtrc.json --fix",
"check": "vp check --no-fmt src packages/freecut-editor/src headless vite.config.ts vite.editor-package.config.ts vite.editor-package.test.config.ts",
"check:fix": "vp check src packages/freecut-editor/src headless vite.config.ts vite.editor-package.config.ts vite.editor-package.test.config.ts package.json packages/freecut-editor/package.json .oxlintrc.json .oxfmtrc.json --fix",
"verify": "vp run check && vp run check:boundaries && vp run check:deps-contracts && vp run check:legacy-lib-imports && vp run check:deps-wrapper-health && vp run check:unused-exports && vp run check:unused-class-members && vp run check:changed-health && vp run check:edge-budgets && vp test run && vp build && npm run headless:test:portable",
"preview": "vp preview",
"preview:perf": "vp preview --host --strictPort --port 4173",
Expand Down
21 changes: 21 additions & 0 deletions packages/freecut-editor/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 FreeCut

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading