Skip to content

Release v0.30.0: per-command help, journal-checked undo, whisper.cpp word timings - #153

Merged
renezander030 merged 11 commits into
masterfrom
release/v0.30.0
Oct 16, 2026
Merged

renezander030 merged 11 commits into
masterfrom
release/v0.30.0

Conversation

@renezander030

Copy link
Copy Markdown
Owner

v0.30.0

Six changes ranked by user impact, plus a behaviour-preserving cleanup. Version bump, CHANGELOG [0.30.0], README "New in v0.30.0" (EN + zh) and docs/command-reference.json are included. Nothing is tagged or published.

Ranked changes

# Change Score Why
1 Independent history snapshots 26.83 On CapCut 9.5 (Windows) the app rewrites <draft>.bak in place when it saves. Snapshots were hard links to that .bak, so the app's save overwrote the undo history too (#151). Snapshots are now their own files.
2 Restore checks recovery files against the write journal 26.83 restore compares the .bak or snapshot with the sha256 the journal recorded before the write. A changed file is refused (refused [backup-changed] / [snapshot-changed]) with a pointer to an intact step; --force-write overrides. History without a journal entry restores as unverified.
3 Word timings from whisper.cpp tokens 21 With --karaoke or --word-reveal, caption runs whisper.cpp with -ojf and builds words from tokens: BPE pieces joined on their leading space, CJK one word per token, U+FFFD byte pieces merged, zero-length tokens kept. Falls back to an even split when a segment has no tokens.
4 restore --list shows integrity 19.17 Each snapshot lists intact, changed or unverified, so a damaged history is visible before a restore.
5 --words reads whisper.cpp full JSON 17.5 caption --words detects a whisper-cli -ojf file and reports words_format: "whisper-cpp".
6 capcut <command> --help and capcut help <command> 14 On master, none of the 87 registered commands printed its own help: 79 errored and 8 ran instead. Help is rendered from the command registry, the same source as describe.

Six, not nine: the other candidates were either already shipped (back-to-back rounding is covered by lint segment-overlap --fix; bilingual caption tracks by import-srt --track-name/--clone-style), too large to verify here (single-binary distribution across platforms), partial (catalogue font apply) or speculative (macOS xattr preservation). The canonical-file decision in #50 stays as is.

Cleanup (no behaviour change)

  • One owner each for mask fields, referenced media, ffmpeg probing and animation placement; a duplicate hexToRgb removed.
  • One owner for the write-journal digest (src/journal-digest.ts), one whisper.cpp offsets-to-microseconds rule, and the recovery history read once per restore.
  • whisper.cpp word tests go through parseWhisperJson instead of a test-only export.

Verification

  • npm test: 1255 tests, 1254 pass, 0 fail, 1 skipped (master: 1232).
  • npm run lint, npm run wasm:verify (7), Python tests (19), npm pack + smoke:package: pass.
  • whisper.cpp end to end with a real whisper-cli 1.9.5 build; its -ojf output is the test fixture test/fixtures/whisper-cpp/jfk-ojf.json.
  • Shipped .d.ts files and the 34 library exports are identical to master. Intended contract changes only: per-command help output, describe / docs/command-reference.json, version.
  • Cold start: the integrity check is loaded lazily at the restore dispatch, so the startup import list is unchanged.

Review notes

  • Base: 6e53e8a (current master).
  • Behaviour changes to know about: restore refuses a changed .bak or snapshot unless --force-write; caption --karaoke/--word-reveal uses -ojf, which needs whisper.cpp 1.5.1 or newer.
  • Overlap with Fix: portable skill scripts + two read-path bugs found on a JianYing 9.0.0 host #149 (currently conflicting): both touch CHANGELOG.md, src/caption.ts and src/index.ts. This PR does not touch doctor, segment tables, whisper.ts or the skill scripts.
  • Commits, in order: cleanup refactor; independent snapshots + journal check; per-command help; whisper.cpp word timings; release metadata; lazy integrity import; three follow-up refactors; test through the module interface; CHANGELOG count correction.

…obing and animation placement

- src/mask-fields.ts owns the three mask array variants, the populated-variant
  check and the JianYing 9.6 masks/common_masks rule, which decorators and lint
  each carried a copy of.
- The sidecar note counts referencedMedia() instead of re-walking the
  materials, and lint shares the one local-path predicate.
- render: one ffmpeg listing helper and one missing-filter refusal frame;
  spawn count and message text unchanged.
- factory uses decorators' hex-to-RGB conversion instead of a copy.
- addImageAnim and addTextAnim place animations through one placeAnimation
  (slot rule, end-anchored outros, duration check, entry shape).

Behaviour-preserving: CLI help, describe registry, lib exports and the
shipped .d.ts files are unchanged. New tests pin the render refusal texts and
the animation entries.
…rnal

History snapshots were published as a hard link to <draft>.bak. CapCut 9.5
rewrites .bak in place when it saves, so the snapshot changed with it and
`restore` put back the app-save state instead of the pre-write draft (#151).

- Each snapshot is now its own file.
- `restore` and `restore --step N` compare the file with the journal's
  before_sha256 first. A file that changed since the CLI wrote it is refused
  with `refused [backup-changed]` / `refused [snapshot-changed]`; the .bak
  refusal points at `--step 1` when that snapshot is intact. `--force-write`
  restores it anyway.
- `restore --list` reports `integrity` per step: intact, changed, or
  unverified (no journal entry). Restore results carry the same field.

Pre-0.30.0 snapshots that still share bytes with a rewritten .bak list as
changed.
None of the 87 commands printed its own help: 79 read `--help` as an
argument and failed (`add-text --help`: "No draft found at: --help"), and 8
ran instead (`doctor --help` ran the checks). Now `<command> --help`,
`<command> -h` and `help <command>` print that command's usage, options,
global options, output, prerequisites and exit codes, rendered from the same
registry as `describe` and the generated command reference. `help` alone, or
an unknown command, prints the full help as before.
With --karaoke or --word-reveal, caption ran whisper.cpp with -oj, which
writes segments only, so word times were an even split of each segment and
sub-word pieces lost their word boundary.

- caption runs whisper.cpp with -ojf (full JSON) and times each word from its
  tokens' offsets. A token that starts with a space opens a word, any other
  token (sub-word piece, punctuation) continues it; in Chinese and Japanese
  every token is its own word. [_BEG_] / [_TT_n] tokens are skipped, and a
  word stamped from == to runs to the next word's start.
- A segment whose tokens do not spell its text (a character split across
  tokens) keeps the even split; plain -oj output parses as before.
- caption --words reads whisper.cpp full JSON (`words_format: "whisper-cpp"`);
  a segment that cannot be split into words stays one entry with its own
  timing.

Tested against real whisper-cli 1.9.5 output (test/fixtures/whisper-cpp).
…word timings

Version bump, CHANGELOG section, README highlights (EN + zh) and the regenerated command reference.
Keeps history-integrity out of the modules every invocation loads (cold-start budget).
src/journal-digest.ts holds the sha256 rule that the write journal records
and the restore integrity check compares against; draft.ts and
history-integrity.ts each carried a copy. No behaviour change.
whisperCppSpanUs replaces the identical segment and token conversions, and
parseWhisperJson builds the even-split fallback only for segments that carry
tokens. Output is byte-identical (golden over real -ojf and edge inputs).
readRecoveryHistory replaces snapshotsWithIntegrity + backupIntegrity: one
call lists the snapshots and reads the journal once, and owns the rule that
.bak is checked against the newest snapshot's entry. Same results and
messages.
The sub-word, CJK and broken-token cases now exercise the caption module's
interface, and whisperCppWords is private again.
Measured on the 0.29.0 build over all 87 registered commands: none printed
its own help; 79 failed and 8 ran instead.
@renezander030
renezander030 merged commit 02a20fa into master Oct 16, 2026
14 checks passed
@renezander030
renezander030 deleted the release/v0.30.0 branch October 16, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant