docs: add v0.1.0 release polish spec and implementation plan
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
763
docs/superpowers/plans/2026-09-22-v0.1-release-polish.md
Normal file
763
docs/superpowers/plans/2026-09-22-v0.1-release-polish.md
Normal file
@@ -0,0 +1,763 @@
|
|||||||
|
# v0.1.0 Release Polish Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Prepare GUI Video Clipper for its initial tagged v0.1.0 release — versioning, branding, About dialog, LICENSE, README, history scrub, and push to remote.
|
||||||
|
|
||||||
|
**Architecture:** All changes are config/metadata/UI polish — no backend feature work. A `VERSION` file is the single source of truth, synced to manifests via a bump script. An `AboutDialog.svelte` component exposes version/author/license info. `git-filter-repo` scrubs leftover personal paths from history before the first push.
|
||||||
|
|
||||||
|
**Tech Stack:** Svelte 5, Tauri v2, Rust, shell scripting, git-filter-repo
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- Official title: "GUI Video Clipper"
|
||||||
|
- App identifier: `xyz.cottongin.gui-video-clipper`
|
||||||
|
- Author: cottongin
|
||||||
|
- License: MIT, copyright 2026
|
||||||
|
- Remote: `git@code.cottongin.xyz:cottongin/gui-video-clipper.git`
|
||||||
|
- Version: `0.1.0`
|
||||||
|
- No new npm or crate dependencies
|
||||||
|
- The string `REDACTED_USERNAME` must not appear anywhere in the final repo (files or git history)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: VERSION file and bump script
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `VERSION`
|
||||||
|
- Create: `scripts/bump-version.sh`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: Nothing
|
||||||
|
- Produces: `VERSION` file containing `0.1.0`. `scripts/bump-version.sh` that reads `VERSION` (or accepts a version argument) and patches `package.json`, `src-tauri/Cargo.toml`, and `src-tauri/tauri.conf.json`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Create the VERSION file**
|
||||||
|
|
||||||
|
Create `VERSION` at the project root with exactly this content (no trailing newline):
|
||||||
|
|
||||||
|
```
|
||||||
|
0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Create the bump script**
|
||||||
|
|
||||||
|
Create `scripts/bump-version.sh`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
VERSION_FILE="$PROJECT_ROOT/VERSION"
|
||||||
|
|
||||||
|
if [ $# -ge 1 ]; then
|
||||||
|
echo "$1" > "$VERSION_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$VERSION_FILE" ]; then
|
||||||
|
echo "ERROR: VERSION file not found at $VERSION_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION=$(cat "$VERSION_FILE")
|
||||||
|
|
||||||
|
# Sanitize: strip leading v/V, trim whitespace
|
||||||
|
VERSION=$(echo "$VERSION" | sed 's/^[vV]//' | tr -d '[:space:]')
|
||||||
|
|
||||||
|
# Validate semver (X.Y.Z)
|
||||||
|
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
|
||||||
|
echo "ERROR: '$VERSION' is not valid semver (expected X.Y.Z)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Bumping to version $VERSION"
|
||||||
|
|
||||||
|
# 1. package.json
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
npm pkg set "version=$VERSION" --json 2>/dev/null || npm pkg set "version=$VERSION"
|
||||||
|
echo " ✓ package.json"
|
||||||
|
|
||||||
|
# 2. src-tauri/Cargo.toml — update [package] version (first version = line)
|
||||||
|
sed -i '' "s/^version = \".*\"/version = \"$VERSION\"/" "$PROJECT_ROOT/src-tauri/Cargo.toml"
|
||||||
|
echo " ✓ src-tauri/Cargo.toml"
|
||||||
|
|
||||||
|
# 3. src-tauri/tauri.conf.json
|
||||||
|
node -e "
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = '$PROJECT_ROOT/src-tauri/tauri.conf.json';
|
||||||
|
const conf = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||||
|
conf.version = '$VERSION';
|
||||||
|
fs.writeFileSync(path, JSON.stringify(conf, null, 2) + '\n');
|
||||||
|
"
|
||||||
|
echo " ✓ src-tauri/tauri.conf.json"
|
||||||
|
|
||||||
|
# 4. Sync Cargo.lock
|
||||||
|
cd "$PROJECT_ROOT/src-tauri"
|
||||||
|
cargo generate-lockfile 2>/dev/null
|
||||||
|
echo " ✓ src-tauri/Cargo.lock"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done — all manifests set to $VERSION"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Make the script executable**
|
||||||
|
|
||||||
|
Run: `chmod +x scripts/bump-version.sh`
|
||||||
|
|
||||||
|
- [ ] **Step 4: Test the bump script**
|
||||||
|
|
||||||
|
Run: `./scripts/bump-version.sh`
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
Bumping to version 0.1.0
|
||||||
|
✓ package.json
|
||||||
|
✓ src-tauri/Cargo.toml
|
||||||
|
✓ src-tauri/tauri.conf.json
|
||||||
|
✓ src-tauri/Cargo.lock
|
||||||
|
|
||||||
|
Done — all manifests set to 0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify the files were updated:
|
||||||
|
|
||||||
|
Run: `grep '"version"' package.json src-tauri/tauri.conf.json && grep '^version' src-tauri/Cargo.toml`
|
||||||
|
|
||||||
|
Expected: all three show `0.1.0`.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Test the sanitization (leading v, trailing newline)**
|
||||||
|
|
||||||
|
Run: `echo "v0.1.0 " > VERSION && ./scripts/bump-version.sh`
|
||||||
|
|
||||||
|
Expected: script prints `Bumping to version 0.1.0` (strips the `v` and whitespace) and completes successfully.
|
||||||
|
|
||||||
|
Reset: `echo -n "0.1.0" > VERSION`
|
||||||
|
|
||||||
|
- [ ] **Step 6: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add VERSION scripts/bump-version.sh
|
||||||
|
git commit -m "chore: add VERSION file and bump-version.sh script"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Metadata cleanup — config files and Rust crate rename
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src-tauri/tauri.conf.json`
|
||||||
|
- Modify: `src-tauri/Cargo.toml`
|
||||||
|
- Modify: `src-tauri/src/main.rs`
|
||||||
|
- Modify: `index.html`
|
||||||
|
- Modify: `src/lib/components/SetupWizard.svelte`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: Nothing (standalone metadata changes)
|
||||||
|
- Produces: All placeholder values replaced with real project metadata. The Rust lib crate is renamed from `tauri_app_lib` to `gui_video_clipper_lib`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Update `src-tauri/tauri.conf.json`**
|
||||||
|
|
||||||
|
Replace the following values:
|
||||||
|
|
||||||
|
- `"productName": "Video Clipper"` → `"productName": "GUI Video Clipper"`
|
||||||
|
- `"identifier": "xyz.cottongin.gui-video-clipper"` → `"identifier": "xyz.cottongin.gui-video-clipper"`
|
||||||
|
- `"title": "Video Clipper"` → `"title": "GUI Video Clipper"`
|
||||||
|
|
||||||
|
- [ ] **Step 2: Update `src-tauri/Cargo.toml`**
|
||||||
|
|
||||||
|
Replace the following values in the `[package]` section:
|
||||||
|
|
||||||
|
- `name = "tauri-app"` → `name = "gui-video-clipper"`
|
||||||
|
- `description = "A Tauri App"` → `description = "A macOS GUI app for clipping online videos"`
|
||||||
|
- `authors = ["you"]` → `authors = ["cottongin"]`
|
||||||
|
|
||||||
|
In the `[lib]` section:
|
||||||
|
|
||||||
|
- `name = "tauri_app_lib"` → `name = "gui_video_clipper_lib"`
|
||||||
|
|
||||||
|
- [ ] **Step 3: Update `src-tauri/src/main.rs`**
|
||||||
|
|
||||||
|
Replace `tauri_app_lib::run()` with `gui_video_clipper_lib::run()`.
|
||||||
|
|
||||||
|
The full file should be:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
gui_video_clipper_lib::run()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Update `index.html`**
|
||||||
|
|
||||||
|
Replace `<title>Video Clipper</title>` with `<title>GUI Video Clipper</title>`.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Update `src/lib/components/SetupWizard.svelte`**
|
||||||
|
|
||||||
|
Replace the string `Video Clipper requires` with `GUI Video Clipper requires` (line 82).
|
||||||
|
|
||||||
|
- [ ] **Step 6: Sync Cargo.lock after crate rename**
|
||||||
|
|
||||||
|
Run: `cd src-tauri && cargo generate-lockfile`
|
||||||
|
|
||||||
|
This updates the `Cargo.lock` entry from `tauri-app` to `gui-video-clipper`.
|
||||||
|
|
||||||
|
- [ ] **Step 7: Verify the build compiles**
|
||||||
|
|
||||||
|
Run: `cd src-tauri && cargo check`
|
||||||
|
|
||||||
|
Expected: compiles without errors. The lib name change is picked up via `Cargo.toml` and `main.rs`.
|
||||||
|
|
||||||
|
- [ ] **Step 8: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src-tauri/tauri.conf.json src-tauri/Cargo.toml src-tauri/Cargo.lock src-tauri/src/main.rs index.html src/lib/components/SetupWizard.svelte
|
||||||
|
git commit -m "chore: replace placeholder metadata with real project values"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Path scrubbing in plan docs
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `docs/superpowers/plans/2026-09-21-video-clipper.md`
|
||||||
|
- Modify: `docs/superpowers/plans/2026-09-22-paged-teleprompter-subtitles.md`
|
||||||
|
- Modify: `docs/superpowers/plans/2026-09-22-extended-caption-styling.md`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: Nothing
|
||||||
|
- Produces: All absolute paths containing the personal username are replaced with relative equivalents.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Replace absolute paths in all three plan files**
|
||||||
|
|
||||||
|
In each of the three files, replace all occurrences of `` (with trailing slash) with an empty string — this leaves just the command after `cd ... &&` becomes just the command.
|
||||||
|
|
||||||
|
Also replace any remaining occurrences of `` (without trailing slash) with `.` (current directory).
|
||||||
|
|
||||||
|
The specific patterns to replace in order (longer match first):
|
||||||
|
1. `` → `` (empty — removes the cd entirely, leaving just the command)
|
||||||
|
2. `cd ` → `cd .` (standalone cd references)
|
||||||
|
3. `` → `` (path prefixes before filenames)
|
||||||
|
4. `` → `.` (any remaining)
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify no personal paths remain**
|
||||||
|
|
||||||
|
Run: `grep -r "REDACTED_USERNAME" docs/superpowers/plans/`
|
||||||
|
|
||||||
|
Expected: no output (no matches).
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add docs/superpowers/plans/
|
||||||
|
git commit -m "chore: replace absolute paths with relative equivalents in plan docs"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: LICENSE file
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `LICENSE`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: Nothing
|
||||||
|
- Produces: MIT license file at project root.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Create the LICENSE file**
|
||||||
|
|
||||||
|
Create `LICENSE` at the project root with this exact content:
|
||||||
|
|
||||||
|
```
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 cottongin
|
||||||
|
|
||||||
|
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.
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add LICENSE
|
||||||
|
git commit -m "chore: add MIT license"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 5: README rewrite
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `README.md`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: Nothing
|
||||||
|
- Produces: Full README replacing the stock Tauri template.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Rewrite README.md**
|
||||||
|
|
||||||
|
Replace the entire contents of `README.md` with:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# GUI Video Clipper
|
||||||
|
|
||||||
|
A macOS desktop app for clipping segments from online videos. Paste a URL, scrub the timeline, mark your clips, and export — without manually downloading the video first.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **URL Input** — Paste a YouTube (or other supported) URL and start working immediately
|
||||||
|
- **Video Preview** — Scrub, seek, and frame-step through the video with full transport controls
|
||||||
|
- **Mark In/Out** — Set clip boundaries with keyboard shortcuts (I/O) or transport buttons
|
||||||
|
- **Timeline** — Visual timeline with waveform display and thumbnail strip
|
||||||
|
- **Clip Export** — Export clips in lossless (stream copy) or precise (re-encode) modes
|
||||||
|
- **Captions** — Download subtitles, preview with karaoke-style highlighting, burn into exports
|
||||||
|
- **Setup Wizard** — Automatically detects and installs required dependencies (ffmpeg, yt-dlp)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **macOS** (primary target platform)
|
||||||
|
- **Node.js** (v18+)
|
||||||
|
- **Rust** toolchain ([rustup.rs](https://rustup.rs))
|
||||||
|
|
||||||
|
ffmpeg and yt-dlp are detected (and can be installed) automatically by the built-in setup wizard on first launch.
|
||||||
|
|
||||||
|
## Build & Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install frontend dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Development (hot-reload)
|
||||||
|
npm run tauri dev
|
||||||
|
|
||||||
|
# Production build
|
||||||
|
npm run tauri build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
GUI Video Clipper is built with [Tauri v2](https://v2.tauri.app/) (Rust backend) and [Svelte 5](https://svelte.dev/) (TypeScript frontend).
|
||||||
|
|
||||||
|
### Backend (Rust)
|
||||||
|
|
||||||
|
- **Video Resolver** — Resolves URLs via yt-dlp, extracts metadata and stream URLs
|
||||||
|
- **Download Manager** — Manages preview and high-quality downloads with progress tracking
|
||||||
|
- **Media Server** — Local HTTP server for streaming video to the frontend player
|
||||||
|
- **Waveform Generator** — Extracts audio waveform data at multiple zoom tiers via ffmpeg
|
||||||
|
- **Thumbnail Extractor** — Generates timeline thumbnail strips from keyframes
|
||||||
|
- **Export Pipeline** — Handles clip extraction with ffmpeg (lossless and precise modes)
|
||||||
|
- **Subtitle Downloader** — Fetches and converts subtitles for preview and burn-in
|
||||||
|
|
||||||
|
### Frontend (Svelte 5 + TypeScript)
|
||||||
|
|
||||||
|
- **Timeline** — Canvas-based timeline with waveform, thumbnails, and clip region rendering
|
||||||
|
- **Transport Controls** — Play/pause, seek, frame-step, shuttle (J/K/L), keyboard shortcuts
|
||||||
|
- **Video Player** — HTML5 video element connected to the local media server
|
||||||
|
- **Export Dialog** — Configure and execute clip exports with progress tracking
|
||||||
|
- **Caption Settings** — Font, color, shadow, and positioning controls for subtitle burn-in
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Create a feature branch (`git checkout -b feat/my-feature`)
|
||||||
|
3. Make your changes
|
||||||
|
4. Run checks: `npm run check`
|
||||||
|
5. Commit with a descriptive message
|
||||||
|
6. Open a pull request
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add README.md
|
||||||
|
git commit -m "docs: rewrite README with full project documentation"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 6: About dialog
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/lib/components/AboutDialog.svelte`
|
||||||
|
- Modify: `src/App.svelte`
|
||||||
|
- Modify: `src/lib/components/StatusBar.svelte`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `getVersion()` from `@tauri-apps/api/app`. Existing `showAboutDialog` state from `App.svelte` (added in this task). `onClose` callback prop (same pattern as `PreferencesPanel`).
|
||||||
|
- Produces: `AboutDialog.svelte` component with `{ onClose: () => void }` props. Clickable version label in `StatusBar` that calls `onOpenAbout` callback. Toolbar info button and `⌘/` shortcut in `App.svelte`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Create `AboutDialog.svelte`**
|
||||||
|
|
||||||
|
Create `src/lib/components/AboutDialog.svelte`:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<script lang="ts">
|
||||||
|
import { getVersion } from '@tauri-apps/api/app';
|
||||||
|
|
||||||
|
let { onClose }: { onClose: () => void } = $props();
|
||||||
|
|
||||||
|
let version = $state('');
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
getVersion().then((v) => {
|
||||||
|
version = v;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="overlay" role="presentation" onclick={onClose}>
|
||||||
|
<div class="dialog" role="dialog" onclick={(e) => e.stopPropagation()}>
|
||||||
|
<img class="app-icon" src="/favicon.svg" alt="GUI Video Clipper icon" />
|
||||||
|
<h2>GUI Video Clipper</h2>
|
||||||
|
{#if version}
|
||||||
|
<span class="version">v{version}</span>
|
||||||
|
{/if}
|
||||||
|
<p class="author">by cottongin</p>
|
||||||
|
<p class="license">MIT License</p>
|
||||||
|
<a
|
||||||
|
class="repo-link"
|
||||||
|
href="https://code.cottongin.xyz/cottongin/gui-video-clipper"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
code.cottongin.xyz/cottongin/gui-video-clipper
|
||||||
|
</a>
|
||||||
|
<div class="actions">
|
||||||
|
<button class="primary" onclick={onClose}>Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 32px;
|
||||||
|
max-width: 360px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-icon {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
.author {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-link {
|
||||||
|
color: var(--accent);
|
||||||
|
font-size: 12px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary {
|
||||||
|
background: var(--accent);
|
||||||
|
color: var(--bg-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Add `showAboutDialog` state and import to `App.svelte`**
|
||||||
|
|
||||||
|
In `src/App.svelte`, add the import at the top of the `<script>` block (after the other component imports):
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import AboutDialog from '$lib/components/AboutDialog.svelte';
|
||||||
|
```
|
||||||
|
|
||||||
|
Add a new state variable alongside the existing dialog states:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
let showAboutDialog = $state(false);
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Add the About dialog render block to `App.svelte`**
|
||||||
|
|
||||||
|
Add the following block after the existing `{#if showExportDialog}` block (before the ProcessingModal block):
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
{#if showAboutDialog}
|
||||||
|
<AboutDialog onClose={() => (showAboutDialog = false)} />
|
||||||
|
{/if}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Add the ⌘/ keyboard shortcut to `App.svelte`**
|
||||||
|
|
||||||
|
In the `handleGlobalKeydown` function's switch statement, add a new case before the `default:` case:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
case '/':
|
||||||
|
if (e.metaKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
showAboutDialog = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Add the info button to the toolbar in `App.svelte`**
|
||||||
|
|
||||||
|
In the `<header class="toolbar">` section, add an info button before the existing prefs button:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<button class="about-btn" onclick={() => (showAboutDialog = true)} title="About">ℹ</button>
|
||||||
|
<button class="prefs-btn" onclick={() => (showPreferences = true)} title="Preferences">⚙</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the corresponding style (in the `<style>` block, next to the existing `.prefs-btn` rule):
|
||||||
|
|
||||||
|
```css
|
||||||
|
.about-btn {
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: Update `StatusBar.svelte` to accept and use `onOpenAbout` callback**
|
||||||
|
|
||||||
|
In `src/lib/components/StatusBar.svelte`, update the script to accept a new prop and import `getVersion`:
|
||||||
|
|
||||||
|
Add imports at the top:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { getVersion } from '@tauri-apps/api/app';
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the prop and version state:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
let { onOpenAbout }: { onOpenAbout?: () => void } = $props();
|
||||||
|
|
||||||
|
let appVersion = $state('');
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
getVersion().then((v) => {
|
||||||
|
appVersion = v;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
At the end of the `<div class="status-bar">` template (just before the closing `</div>`), add:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
{#if appVersion}
|
||||||
|
<button class="version-btn" onclick={() => onOpenAbout?.()} title="About GUI Video Clipper">
|
||||||
|
v{appVersion}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the style:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.version-btn {
|
||||||
|
margin-left: auto;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
padding: 2px 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-btn:hover {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 7: Pass the callback from `App.svelte` to `StatusBar`**
|
||||||
|
|
||||||
|
In `src/App.svelte`, update the `<StatusBar />` usage to:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<StatusBar onOpenAbout={() => (showAboutDialog = true)} />
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 8: Verify the frontend compiles**
|
||||||
|
|
||||||
|
Run: `npm run check`
|
||||||
|
|
||||||
|
Expected: no errors.
|
||||||
|
|
||||||
|
- [ ] **Step 9: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/lib/components/AboutDialog.svelte src/App.svelte src/lib/components/StatusBar.svelte
|
||||||
|
git commit -m "feat: add About dialog with version, author, and license info"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 7: Stage all untracked files and commit the release
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `docs/superpowers/specs/2026-09-22-v0.1-release-polish-design.md` (already exists, just needs staging)
|
||||||
|
- All other untracked files from git status
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: All changes from Tasks 1-6
|
||||||
|
- Produces: A clean commit history with all project files tracked.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Verify no `REDACTED_USERNAME` remains in tracked files**
|
||||||
|
|
||||||
|
Run: `grep -r "REDACTED_USERNAME" --include="*.json" --include="*.toml" --include="*.rs" --include="*.svelte" --include="*.html" --include="*.ts" --include="*.md" .`
|
||||||
|
|
||||||
|
Expected: no matches in any source file. (If any remain, fix them before proceeding.)
|
||||||
|
|
||||||
|
- [ ] **Step 2: Stage and commit the spec and plan docs**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add docs/superpowers/specs/2026-09-22-v0.1-release-polish-design.md
|
||||||
|
git add docs/superpowers/plans/2026-09-22-v0.1-release-polish.md
|
||||||
|
git commit -m "docs: add v0.1.0 release polish spec and implementation plan"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Final build verification**
|
||||||
|
|
||||||
|
Run: `npm run check && cd src-tauri && cargo check`
|
||||||
|
|
||||||
|
Expected: both pass without errors.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 8: Git history scrub and push to remote
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create (temporary): `replacements.txt`
|
||||||
|
- No permanent file changes — this task rewrites git history.
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: A fully committed repo with no dirty working tree.
|
||||||
|
- Produces: Clean git history with no `REDACTED_USERNAME` references. Tagged `v0.1.0` release pushed to remote.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Create the replacements file**
|
||||||
|
|
||||||
|
Create `replacements.txt` in the project root (this file will NOT be committed):
|
||||||
|
|
||||||
|
```
|
||||||
|
xyz.cottongin.gui-video-clipper==>xyz.cottongin.gui-video-clipper
|
||||||
|
==>
|
||||||
|
==>
|
||||||
|
==>
|
||||||
|
```
|
||||||
|
|
||||||
|
Each line uses `==>` as the separator between old and new values. The path replacements have empty right-hand sides to delete the paths entirely. Longer matches come first to avoid partial replacements.
|
||||||
|
|
||||||
|
**Note:** This rewrite will also affect the spec and plan docs themselves (they contain the old values as documentation). The "before" columns in tables will be mangled. This is expected — a complete scrub is the goal.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run git-filter-repo**
|
||||||
|
|
||||||
|
Run: `git filter-repo --replace-text replacements.txt --force`
|
||||||
|
|
||||||
|
Expected: rewrites all commits. Output shows the number of commits processed.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Verify the scrub was successful**
|
||||||
|
|
||||||
|
Run: `git log --all -p --no-color | grep -i "REDACTED_USERNAME" | head -20`
|
||||||
|
|
||||||
|
Expected: no output (no matches anywhere in the history).
|
||||||
|
|
||||||
|
Also verify the working tree is still clean:
|
||||||
|
|
||||||
|
Run: `git status`
|
||||||
|
|
||||||
|
Expected: clean working tree (filter-repo rewrites blobs in place).
|
||||||
|
|
||||||
|
- [ ] **Step 4: Clean up the replacements file**
|
||||||
|
|
||||||
|
Run: `rm replacements.txt`
|
||||||
|
|
||||||
|
- [ ] **Step 5: Add the remote**
|
||||||
|
|
||||||
|
Run: `git remote add origin git@code.cottongin.xyz:cottongin/gui-video-clipper.git`
|
||||||
|
|
||||||
|
(git-filter-repo removes remotes by default, so this is always needed.)
|
||||||
|
|
||||||
|
- [ ] **Step 6: Tag the release**
|
||||||
|
|
||||||
|
Run: `git tag -a v0.1.0 -m "Initial release"`
|
||||||
|
|
||||||
|
- [ ] **Step 7: Push to remote**
|
||||||
|
|
||||||
|
Run: `git push -u origin main && git push origin v0.1.0`
|
||||||
|
|
||||||
|
Expected: main branch and v0.1.0 tag pushed successfully.
|
||||||
|
|
||||||
|
- [ ] **Step 8: Verify the remote**
|
||||||
|
|
||||||
|
Run: `git log --oneline -5 && git tag -l && git remote -v`
|
||||||
|
|
||||||
|
Expected: shows recent commits with new hashes, `v0.1.0` tag, and the origin remote URL.
|
||||||
225
docs/superpowers/specs/2026-09-22-v0.1-release-polish-design.md
Normal file
225
docs/superpowers/specs/2026-09-22-v0.1-release-polish-design.md
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
# GUI Video Clipper — v0.1.0 Release Polish Design Spec
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Prepare the GUI Video Clipper project for its initial `v0.1.0` tagged release. This covers versioning infrastructure, metadata cleanup, branding, an About dialog, licensing, a proper README, and pushing to the remote repository.
|
||||||
|
|
||||||
|
**Official title:** GUI Video Clipper
|
||||||
|
**Short title:** gui-vc
|
||||||
|
**Author:** cottongin
|
||||||
|
**Remote:** `git@code.cottongin.xyz:cottongin/gui-video-clipper.git`
|
||||||
|
**License:** MIT (2026)
|
||||||
|
**App identifier:** `xyz.cottongin.gui-video-clipper`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Versioning Infrastructure
|
||||||
|
|
||||||
|
### VERSION File
|
||||||
|
|
||||||
|
A plain-text `VERSION` file at the project root. Contains the semantic version with no prefix or trailing whitespace:
|
||||||
|
|
||||||
|
```
|
||||||
|
0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bump Script
|
||||||
|
|
||||||
|
`scripts/bump-version.sh` — a shell script that synchronizes the version across all manifest files.
|
||||||
|
|
||||||
|
**Behavior:**
|
||||||
|
1. If given an argument (`./scripts/bump-version.sh 0.2.0`), write that version to `VERSION`. Otherwise, read the current `VERSION`.
|
||||||
|
2. Sanitize the value: strip leading `v` or `V`, trim all trailing whitespace/newlines.
|
||||||
|
3. Validate the result matches semver (`X.Y.Z`). Exit with an error if not.
|
||||||
|
4. Patch `package.json` via `npm pkg set version=$VERSION`.
|
||||||
|
5. Patch `src-tauri/Cargo.toml`: update the `version = "..."` line under `[package]`.
|
||||||
|
6. Patch `src-tauri/tauri.conf.json`: update the `"version": "..."` field.
|
||||||
|
7. Run `cd src-tauri && cargo generate-lockfile` to sync `Cargo.lock`.
|
||||||
|
8. Print a summary of all updated files and the new version.
|
||||||
|
|
||||||
|
### Frontend Version Access
|
||||||
|
|
||||||
|
The frontend reads the version at runtime via `getVersion()` from `@tauri-apps/api/app`. This reads from the built `tauri.conf.json` — no custom Tauri command needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Metadata Cleanup
|
||||||
|
|
||||||
|
Replace all placeholder/template values:
|
||||||
|
|
||||||
|
| File | Field | Current | New |
|
||||||
|
|------|-------|---------|-----|
|
||||||
|
| `src-tauri/tauri.conf.json` | `productName` | `"Video Clipper"` | `"GUI Video Clipper"` |
|
||||||
|
| `src-tauri/tauri.conf.json` | `identifier` | `"xyz.cottongin.gui-video-clipper"` | `"xyz.cottongin.gui-video-clipper"` |
|
||||||
|
| `src-tauri/tauri.conf.json` | `windows[0].title` | `"Video Clipper"` | `"GUI Video Clipper"` |
|
||||||
|
| `src-tauri/Cargo.toml` | `name` | `"tauri-app"` | `"gui-video-clipper"` |
|
||||||
|
| `src-tauri/Cargo.toml` | `description` | `"A Tauri App"` | `"A macOS GUI app for clipping online videos"` |
|
||||||
|
| `src-tauri/Cargo.toml` | `authors` | `["you"]` | `["cottongin"]` |
|
||||||
|
| `src-tauri/Cargo.toml` | `lib.name` | `"tauri_app_lib"` | `"gui_video_clipper_lib"` |
|
||||||
|
| `src-tauri/src/main.rs` | `run()` call | `tauri_app_lib::run()` | `gui_video_clipper_lib::run()` |
|
||||||
|
| `index.html` | `<title>` | `"Video Clipper"` | `"GUI Video Clipper"` |
|
||||||
|
| `src/lib/components/SetupWizard.svelte` | body text | `"Video Clipper requires…"` | `"GUI Video Clipper requires…"` |
|
||||||
|
|
||||||
|
The `Cargo.lock` entry for `tauri-app` will auto-update when `cargo generate-lockfile` runs after the crate rename.
|
||||||
|
|
||||||
|
### Path Scrubbing
|
||||||
|
|
||||||
|
Three files under `docs/superpowers/plans/` contain absolute paths with a username that should not appear in the public repo. Replace all occurrences of the absolute project path with relative equivalents (e.g., `cd /Users/.../gui-video-clipper &&` becomes just the command itself, or a relative path).
|
||||||
|
|
||||||
|
Affected files:
|
||||||
|
- `docs/superpowers/plans/2026-09-21-video-clipper.md`
|
||||||
|
- `docs/superpowers/plans/2026-09-22-paged-teleprompter-subtitles.md`
|
||||||
|
- `docs/superpowers/plans/2026-09-22-extended-caption-styling.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. About Dialog
|
||||||
|
|
||||||
|
### Component: `AboutDialog.svelte`
|
||||||
|
|
||||||
|
A modal overlay following the existing pattern used by `PreferencesPanel` and `ExportDialog`.
|
||||||
|
|
||||||
|
**Contents (top to bottom):**
|
||||||
|
- App icon (the scissors/film strip SVG, rendered as an `<img>` or inline SVG, ~64px)
|
||||||
|
- "GUI Video Clipper" as the title
|
||||||
|
- Version string (e.g., "v0.1.0") read via `getVersion()` from `@tauri-apps/api/app`
|
||||||
|
- "by cottongin"
|
||||||
|
- "MIT License"
|
||||||
|
- Link to repo: `https://code.cottongin.xyz/cottongin/gui-video-clipper`
|
||||||
|
- "Close" button
|
||||||
|
|
||||||
|
**Styling:** Matches the existing dark theme (Catppuccin Mocha palette). Centered modal, rounded corners, consistent with `PreferencesPanel`.
|
||||||
|
|
||||||
|
### Triggers
|
||||||
|
|
||||||
|
Three ways to open the About dialog:
|
||||||
|
|
||||||
|
1. **Toolbar button:** An `(i)` / info button in the header toolbar, next to the existing `⚙` preferences button.
|
||||||
|
2. **Keyboard shortcut:** `⌘/` — added to the global `handleGlobalKeydown` in `App.svelte`.
|
||||||
|
3. **Status bar version:** A clickable `v0.1.0` label in `StatusBar.svelte`.
|
||||||
|
|
||||||
|
All three toggle the same `showAboutDialog` state in `App.svelte`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Window Title
|
||||||
|
|
||||||
|
The window title is set statically in `tauri.conf.json` as `"GUI Video Clipper"`. No runtime version suffix — the version is available in the About dialog.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. LICENSE & README
|
||||||
|
|
||||||
|
### LICENSE
|
||||||
|
|
||||||
|
A standard MIT license file at project root (`LICENSE`).
|
||||||
|
|
||||||
|
```
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 cottongin
|
||||||
|
|
||||||
|
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.
|
||||||
|
```
|
||||||
|
|
||||||
|
### README.md
|
||||||
|
|
||||||
|
Full rewrite replacing the stock Tauri template. Sections:
|
||||||
|
|
||||||
|
1. **Title & Description** — "GUI Video Clipper" with a one-line description: a macOS desktop app for clipping segments from online videos.
|
||||||
|
2. **Features** — URL input (YouTube, etc.), video preview with scrubbing, mark in/out points, timeline with waveform and thumbnails, clip export (lossless and precise modes), caption/subtitle support with burn-in, automatic dependency setup wizard.
|
||||||
|
3. **Prerequisites** — macOS, Node.js, Rust toolchain. ffmpeg and yt-dlp are installed automatically by the setup wizard.
|
||||||
|
4. **Build & Run** — `npm install`, `npm run tauri dev` (development), `npm run tauri build` (production).
|
||||||
|
5. **Architecture** — Tauri v2 backend (Rust) + Svelte 5 frontend (TypeScript). Brief description of the major components: video resolver, media server, waveform generator, thumbnail extractor, export pipeline.
|
||||||
|
6. **Contributing** — Fork, branch, PR workflow. Run `npm run check` before submitting.
|
||||||
|
7. **License** — MIT, with a link to the LICENSE file.
|
||||||
|
|
||||||
|
No screenshots.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Icons
|
||||||
|
|
||||||
|
The custom icon set (scissors cutting a film strip, dark background) is already in place at `src-tauri/icons/` with all required sizes:
|
||||||
|
- `icon.svg` (source) + color variants in `variants/`
|
||||||
|
- `icon.png` (512x512), `32x32.png`, `128x128.png`, `128x128@2x.png`
|
||||||
|
- `icon.icns` (macOS), `icon.ico` (Windows)
|
||||||
|
- Windows Store logos (`Square*.png`, `StoreLogo.png`)
|
||||||
|
- iOS and Android directories
|
||||||
|
|
||||||
|
The `tauri.conf.json` bundle icon paths already reference the correct files. **No changes needed.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Git History Scrub
|
||||||
|
|
||||||
|
The committed history contains `REDACTED_USERNAME` in blob content (not in author/committer fields — those are already `cottongin`). Specifically:
|
||||||
|
|
||||||
|
- `src-tauri/tauri.conf.json`: the old `"xyz.cottongin.gui-video-clipper"` identifier
|
||||||
|
- `docs/superpowers/plans/*.md`: absolute paths like ``
|
||||||
|
|
||||||
|
### Approach: `git-filter-repo --replace-text`
|
||||||
|
|
||||||
|
After all code/config changes are committed, use `git-filter-repo` to rewrite history:
|
||||||
|
|
||||||
|
1. Create a replacements file (e.g., `replacements.txt`) with literal string replacements:
|
||||||
|
```
|
||||||
|
xyz.cottongin.gui-video-clipper==>xyz.cottongin.gui-video-clipper
|
||||||
|
==>
|
||||||
|
==>
|
||||||
|
```
|
||||||
|
Each line is `OLD==>NEW`. The path replacements remove the absolute prefix, leaving just the command (or a relative path). Order matters — longer matches first.
|
||||||
|
|
||||||
|
2. Run: `git filter-repo --replace-text replacements.txt --force`
|
||||||
|
|
||||||
|
3. Verify: `git log --all -p | grep -i REDACTED_USERNAME` should return nothing.
|
||||||
|
|
||||||
|
4. Clean up: remove `replacements.txt` (it's a one-time tool, not committed).
|
||||||
|
|
||||||
|
**Important:** `git-filter-repo` rewrites all commit hashes. Since this repo has never been pushed to a remote, that's fine — there's no shared history to disrupt. The remote must be re-added after `filter-repo` runs (it strips remotes by default).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Commit, Remote & Tag
|
||||||
|
|
||||||
|
### Commit Strategy
|
||||||
|
|
||||||
|
1. Make all code/config changes (sections 1-5 above).
|
||||||
|
2. Stage and commit everything — including all currently untracked files (`chat-summaries/`, `docs/superpowers/`, new source files under `src-tauri/src/services/`, `src/lib/components/ProcessingModal.svelte`, `src/lib/utils/vttParser.ts`).
|
||||||
|
3. Use a descriptive commit message: `chore: v0.1.0 release polish — versioning, branding, about dialog, license, readme`.
|
||||||
|
|
||||||
|
### History Scrub
|
||||||
|
|
||||||
|
4. Run the `git-filter-repo --replace-text` pass (Section 7).
|
||||||
|
5. Verify no `REDACTED_USERNAME` remains in any blob.
|
||||||
|
|
||||||
|
### Remote & Tag
|
||||||
|
|
||||||
|
6. Re-add the remote (filter-repo removes it): `git remote add origin git@code.cottongin.xyz:cottongin/gui-video-clipper.git`
|
||||||
|
7. Tag: `git tag -a v0.1.0 -m "Initial release"`
|
||||||
|
8. Push: `git push -u origin main && git push origin v0.1.0`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
|
||||||
|
- No CI/CD pipeline setup (future work).
|
||||||
|
- No `.dmg` / installer packaging (future work).
|
||||||
|
- No changelog generation (future work).
|
||||||
|
- No automated version bumping via git hooks.
|
||||||
Reference in New Issue
Block a user