buttercut 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/settings.local.json +9 -1
- data/.claude/skills +1 -0
- data/CLAUDE.md +1 -278
- data/LICENSE +106 -21
- data/README.md +13 -8
- data/lib/buttercut/version.rb +1 -1
- data/templates/library_template.yaml +14 -2
- data/templates/plan_template.md +53 -0
- data/templates/roughcut_template.yaml +3 -20
- data/templates/settings_template.yaml +9 -0
- metadata +6 -35
- data/.claude/scripts/script_extractor.rb +0 -66
- data/.claude/skills/analyze-video/SKILL.md +0 -97
- data/.claude/skills/analyze-video/prepare_visual_script.rb +0 -25
- data/.claude/skills/backup-library/SKILL.md +0 -26
- data/.claude/skills/backup-library/backup_libraries.rb +0 -46
- data/.claude/skills/release/SKILL.md +0 -214
- data/.claude/skills/roughcut/SKILL.md +0 -71
- data/.claude/skills/roughcut/agent_instructions.md +0 -109
- data/.claude/skills/roughcut/export_to_fcpxml.rb +0 -132
- data/.claude/skills/setup/SKILL.md +0 -47
- data/.claude/skills/setup/advanced-setup.md +0 -141
- data/.claude/skills/setup/simple-setup.md +0 -185
- data/.claude/skills/setup/verify_install.rb +0 -124
- data/.claude/skills/transcribe-audio/SKILL.md +0 -90
- data/.claude/skills/transcribe-audio/prepare_audio_script.rb +0 -48
- data/.claude/skills/transcribe-audio/refine_instructions.md +0 -114
- data/.claude/skills/update-buttercut/SKILL.md +0 -54
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: buttercut
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Ford
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: nokogiri
|
|
@@ -24,20 +24,6 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1.13'
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: rubyzip
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - "~>"
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '2.3'
|
|
34
|
-
type: :runtime
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - "~>"
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '2.3'
|
|
41
27
|
- !ruby/object:Gem::Dependency
|
|
42
28
|
name: rspec
|
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -62,25 +48,9 @@ extensions: []
|
|
|
62
48
|
extra_rdoc_files: []
|
|
63
49
|
files:
|
|
64
50
|
- ".claude/commands/worktree.md"
|
|
65
|
-
- ".claude/scripts/script_extractor.rb"
|
|
66
51
|
- ".claude/settings.json"
|
|
67
52
|
- ".claude/settings.local.json"
|
|
68
|
-
- ".claude/skills
|
|
69
|
-
- ".claude/skills/analyze-video/prepare_visual_script.rb"
|
|
70
|
-
- ".claude/skills/backup-library/SKILL.md"
|
|
71
|
-
- ".claude/skills/backup-library/backup_libraries.rb"
|
|
72
|
-
- ".claude/skills/release/SKILL.md"
|
|
73
|
-
- ".claude/skills/roughcut/SKILL.md"
|
|
74
|
-
- ".claude/skills/roughcut/agent_instructions.md"
|
|
75
|
-
- ".claude/skills/roughcut/export_to_fcpxml.rb"
|
|
76
|
-
- ".claude/skills/setup/SKILL.md"
|
|
77
|
-
- ".claude/skills/setup/advanced-setup.md"
|
|
78
|
-
- ".claude/skills/setup/simple-setup.md"
|
|
79
|
-
- ".claude/skills/setup/verify_install.rb"
|
|
80
|
-
- ".claude/skills/transcribe-audio/SKILL.md"
|
|
81
|
-
- ".claude/skills/transcribe-audio/prepare_audio_script.rb"
|
|
82
|
-
- ".claude/skills/transcribe-audio/refine_instructions.md"
|
|
83
|
-
- ".claude/skills/update-buttercut/SKILL.md"
|
|
53
|
+
- ".claude/skills"
|
|
84
54
|
- CLAUDE.md
|
|
85
55
|
- LICENSE
|
|
86
56
|
- README.md
|
|
@@ -91,11 +61,12 @@ files:
|
|
|
91
61
|
- lib/buttercut/fcpx.rb
|
|
92
62
|
- lib/buttercut/version.rb
|
|
93
63
|
- templates/library_template.yaml
|
|
64
|
+
- templates/plan_template.md
|
|
94
65
|
- templates/roughcut_template.yaml
|
|
95
66
|
- templates/settings_template.yaml
|
|
96
67
|
homepage: https://github.com/andrewford/buttercut
|
|
97
68
|
licenses:
|
|
98
|
-
-
|
|
69
|
+
- Nonstandard
|
|
99
70
|
metadata: {}
|
|
100
71
|
post_install_message:
|
|
101
72
|
rdoc_options: []
|
|
@@ -112,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
112
83
|
- !ruby/object:Gem::Version
|
|
113
84
|
version: '0'
|
|
114
85
|
requirements: []
|
|
115
|
-
rubygems_version: 3.5.
|
|
86
|
+
rubygems_version: 3.5.22
|
|
116
87
|
signing_key:
|
|
117
88
|
specification_version: 4
|
|
118
89
|
summary: Video Editor XML generator with Agent skills for analyzing video, creating
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# Extract the plain-text script from a WhisperX-style transcript JSON.
|
|
3
|
-
#
|
|
4
|
-
# Usage:
|
|
5
|
-
# ruby .claude/scripts/script_extractor.rb <transcript.json> <output.txt>
|
|
6
|
-
#
|
|
7
|
-
# Output is one segment per paragraph (blank line between), trimmed, suitable
|
|
8
|
-
# for proofreading by a human or a sub-agent without the overhead of the full
|
|
9
|
-
# transcript JSON (word-level timing, scores, etc.).
|
|
10
|
-
|
|
11
|
-
require 'json'
|
|
12
|
-
|
|
13
|
-
class ScriptExtractor
|
|
14
|
-
def self.extract(transcript_path, output_path)
|
|
15
|
-
new(transcript_path, output_path).extract
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def initialize(transcript_path, output_path)
|
|
19
|
-
raise ArgumentError, "transcript_path is required" if transcript_path.nil? || transcript_path.empty?
|
|
20
|
-
raise ArgumentError, "output_path is required" if output_path.nil? || output_path.empty?
|
|
21
|
-
@transcript_path = transcript_path
|
|
22
|
-
@output_path = output_path
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def extract
|
|
26
|
-
write_output(format_script)
|
|
27
|
-
report
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
attr_reader :transcript_path, :output_path
|
|
33
|
-
|
|
34
|
-
def data
|
|
35
|
-
@data ||= JSON.parse(File.read(transcript_path))
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def segments
|
|
39
|
-
data["segments"] or raise "transcript JSON has no 'segments' key: #{transcript_path}"
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def format_script
|
|
43
|
-
paragraphs = segments.map { |s| s["text"].to_s.strip }.reject(&:empty?)
|
|
44
|
-
paragraphs.join("\n\n") + "\n"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def write_output(text)
|
|
48
|
-
File.write(output_path, text)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def report
|
|
52
|
-
in_kb = (File.size(transcript_path) / 1024.0).round(1)
|
|
53
|
-
out_kb = (File.size(output_path) / 1024.0).round(1)
|
|
54
|
-
puts "Extracted script: #{output_path} (#{out_kb} KB from #{in_kb} KB source, #{segments.size} segments)"
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
if __FILE__ == $PROGRAM_NAME
|
|
59
|
-
transcript_path, output_path = ARGV
|
|
60
|
-
abort("usage: script_extractor.rb <transcript.json> <output.txt>") unless transcript_path && output_path
|
|
61
|
-
abort("file not found: #{transcript_path}") unless File.file?(transcript_path)
|
|
62
|
-
if File.expand_path(output_path) == File.expand_path(transcript_path)
|
|
63
|
-
abort("output path must differ from transcript path: #{transcript_path}")
|
|
64
|
-
end
|
|
65
|
-
ScriptExtractor.extract(transcript_path, output_path)
|
|
66
|
-
end
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: analyze-video
|
|
3
|
-
description: Adds visual descriptions to transcripts by extracting and analyzing video frames with ffmpeg. Creates visual transcript with periodic visual descriptions of the video clip. Use when all files have audio transcripts present (transcript) but don't yet have visual transcripts created (visual_transcript).
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: Analyze Video
|
|
7
|
-
|
|
8
|
-
Add visual descriptions to audio transcripts by extracting JPG frames with ffmpeg and analyzing them. **Never read video files directly** - extract frames first.
|
|
9
|
-
|
|
10
|
-
## Prerequisites
|
|
11
|
-
|
|
12
|
-
Videos must have audio transcripts. Run **transcribe-audio** skill first if needed.
|
|
13
|
-
|
|
14
|
-
## Workflow
|
|
15
|
-
|
|
16
|
-
### 1. Inputs from the parent
|
|
17
|
-
|
|
18
|
-
This skill runs as a sub-agent. Do NOT read `library.yaml` or `settings.yaml` — the parent has that context and passes everything inline in your prompt. Expect these inputs:
|
|
19
|
-
|
|
20
|
-
- `video_path` — absolute path to the video file
|
|
21
|
-
- `audio_transcript_path` — absolute path to the prepared audio transcript JSON
|
|
22
|
-
- `visual_transcript_path` — absolute path to write the visual transcript JSON
|
|
23
|
-
|
|
24
|
-
### 2. Copy & Clean Audio Transcript
|
|
25
|
-
|
|
26
|
-
Don't read the audio transcript, just copy it and then prepare it by using the prepare_visual_script.rb file. This removes word-level timing data and prettifies the JSON for easier editing:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
cp <audio_transcript_path> <visual_transcript_path>
|
|
30
|
-
ruby .claude/skills/analyze-video/prepare_visual_script.rb <visual_transcript_path>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### 3. Extract Frames (Binary Search)
|
|
34
|
-
|
|
35
|
-
Create frame directory: `mkdir -p tmp/frames/[video_name]`
|
|
36
|
-
|
|
37
|
-
**Videos ≤30s:** Extract one frame at 2s
|
|
38
|
-
**Videos >30s:** Extract start (2s), middle (duration/2), end (duration-2s)
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
ffmpeg -ss 00:00:02 -i video.mov -vframes 1 -vf "scale=1280:-1" tmp/frames/[video_name]/start.jpg
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
**Subdivide when:** Footage start, middle and end have different subjects, setting or angle changes
|
|
45
|
-
**Stop when:** The footage no longer seems to be changing or only has minor changes
|
|
46
|
-
**Never sample** more frequently than once per 30 seconds
|
|
47
|
-
|
|
48
|
-
### 4. Add Visual Descriptions
|
|
49
|
-
|
|
50
|
-
Read the visual video json file that you created earlier.
|
|
51
|
-
|
|
52
|
-
**Read the JPG frames** from `tmp/frames/[video_name]/` using Read tool, then **Edit** the file at `<visual_transcript_path>`:
|
|
53
|
-
|
|
54
|
-
Do these incrementally. You don't need to create a program or script to do this, just incrementally edit the json whenever you read new frames.
|
|
55
|
-
|
|
56
|
-
**Dialogue segments - add `visual` field:**
|
|
57
|
-
```json
|
|
58
|
-
{
|
|
59
|
-
"start": 2.917,
|
|
60
|
-
"end": 7.586,
|
|
61
|
-
"text": "Hey, good afternoon everybody.",
|
|
62
|
-
"visual": "Man in red shirt speaking to camera in medium shot. Home office with bookshelf. Natural lighting.",
|
|
63
|
-
"words": [...]
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**B-roll segments - insert new entries:**
|
|
68
|
-
```json
|
|
69
|
-
{
|
|
70
|
-
"start": 35.474,
|
|
71
|
-
"end": 56.162,
|
|
72
|
-
"text": "",
|
|
73
|
-
"visual": "Green bicycle parked in front of building. Urban street with trees.",
|
|
74
|
-
"b_roll": true,
|
|
75
|
-
"words": []
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
**Guidelines:**
|
|
80
|
-
- Descriptions should be 3 sentences max.
|
|
81
|
-
- First segment: detailed (subject, setting, shot type, lighting, camera style)
|
|
82
|
-
- Continuing shots: brief if similar, otherwise can be up to 3 sentences if drastically different.
|
|
83
|
-
|
|
84
|
-
### 5. Cleanup & Return
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
rm -rf tmp/frames/[video_name]
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Return structured response:
|
|
91
|
-
```
|
|
92
|
-
✓ [video_filename.mov] analyzed successfully
|
|
93
|
-
Visual transcript: <visual_transcript_path>
|
|
94
|
-
Video path: <video_path>
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**DO NOT update library.yaml** - parent agent handles this to avoid race conditions in parallel execution.
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
require 'json'
|
|
3
|
-
|
|
4
|
-
abort "Usage: ruby prepare_visual_script.rb <json_file>" if ARGV.empty?
|
|
5
|
-
abort "Error: File not found: #{ARGV[0]}" unless File.exist?(ARGV[0])
|
|
6
|
-
|
|
7
|
-
begin
|
|
8
|
-
data = JSON.parse(File.read(ARGV[0]))
|
|
9
|
-
|
|
10
|
-
data['segments']&.each { |s| s.delete('words') }
|
|
11
|
-
data.delete('word_segments')
|
|
12
|
-
|
|
13
|
-
# Reorder keys: language and video_path first, then segments, then everything else
|
|
14
|
-
reordered = {}
|
|
15
|
-
reordered['language'] = data['language'] if data['language']
|
|
16
|
-
reordered['video_path'] = data['video_path'] if data['video_path']
|
|
17
|
-
reordered['segments'] = data['segments'] if data['segments']
|
|
18
|
-
# Add any other keys that might exist
|
|
19
|
-
data.each { |k, v| reordered[k] = v unless reordered.key?(k) }
|
|
20
|
-
|
|
21
|
-
File.write(ARGV[0], JSON.pretty_generate(reordered))
|
|
22
|
-
puts "Prettified: #{ARGV[0]} (word-level timing removed)"
|
|
23
|
-
rescue JSON::ParserError => e
|
|
24
|
-
abort "Error: Invalid JSON - #{e.message}"
|
|
25
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: backup-library
|
|
3
|
-
description: Creates compressed ZIP backups of libraries directory. Backs up library.yaml, transcripts, and roughcuts (not video files). This skill can also be useful when you need to restore a library.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: Backup Library
|
|
7
|
-
|
|
8
|
-
Verify libraries directory exists:
|
|
9
|
-
```bash
|
|
10
|
-
ls -la libraries/
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Run backup:
|
|
14
|
-
```bash
|
|
15
|
-
ruby .claude/skills/backup-library/backup_libraries.rb
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Creates `backups/libraries_YYYYMMDD_HHMMSS.zip` containing the entire libraries directory.
|
|
19
|
-
|
|
20
|
-
## Restore Library
|
|
21
|
-
|
|
22
|
-
To restore from a backup, extract the ZIP file to the project root.
|
|
23
|
-
```bash
|
|
24
|
-
unzip backups/libraries_timestamp.zip -d .
|
|
25
|
-
```
|
|
26
|
-
This restores all libraries to their original locations.
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Library Backup Utility
|
|
5
|
-
# Creates compressed ZIP backups of the entire libraries directory
|
|
6
|
-
|
|
7
|
-
require 'fileutils'
|
|
8
|
-
require 'time'
|
|
9
|
-
require 'zip'
|
|
10
|
-
|
|
11
|
-
class LibraryBackup
|
|
12
|
-
def initialize(project_root = Dir.pwd)
|
|
13
|
-
@libraries_dir = File.join(project_root, 'libraries')
|
|
14
|
-
@backups_dir = File.join(project_root, 'backups')
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def backup
|
|
18
|
-
unless Dir.exist?(@libraries_dir)
|
|
19
|
-
puts "❌ No libraries directory found"
|
|
20
|
-
return nil
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
FileUtils.mkdir_p(@backups_dir)
|
|
24
|
-
|
|
25
|
-
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
|
26
|
-
backup_path = File.join(@backups_dir, "libraries_#{timestamp}.zip")
|
|
27
|
-
|
|
28
|
-
puts "📦 Creating backup: #{backup_path}"
|
|
29
|
-
|
|
30
|
-
files = Dir.glob(File.join(@libraries_dir, '**', '*')).select { |f| File.file?(f) }
|
|
31
|
-
|
|
32
|
-
Zip::File.open(backup_path, create: true) do |zipfile|
|
|
33
|
-
files.each do |file|
|
|
34
|
-
zipfile.add(file.sub("#{File.dirname(@libraries_dir)}/", ''), file)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
puts "✅ Backed up #{files.size} files"
|
|
39
|
-
backup_path
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# CLI
|
|
44
|
-
if __FILE__ == $PROGRAM_NAME
|
|
45
|
-
LibraryBackup.new.backup
|
|
46
|
-
end
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: release
|
|
3
|
-
description: Creates a new ButterCut release with version bump, changelog, git tag, gem build, and GitHub release. Use when publishing a new version.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: Release ButterCut
|
|
7
|
-
|
|
8
|
-
Guides through the complete release process: version bump, changelog, git operations, gem publishing, and GitHub release creation.
|
|
9
|
-
|
|
10
|
-
## When to Use
|
|
11
|
-
|
|
12
|
-
- Publishing a new version of ButterCut
|
|
13
|
-
- After merging features or fixes that should be released
|
|
14
|
-
- Creating the first v0.1.0 release
|
|
15
|
-
|
|
16
|
-
## Workflow
|
|
17
|
-
|
|
18
|
-
### 1. Run Tests First
|
|
19
|
-
|
|
20
|
-
**CRITICAL: Always run tests before releasing. Never release if tests fail.**
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
bundle exec rspec
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
If any tests fail, STOP immediately and ask user to fix before proceeding with release.
|
|
27
|
-
|
|
28
|
-
### 2. Check Current State
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
# Read current version
|
|
32
|
-
cat lib/buttercut/version.rb
|
|
33
|
-
|
|
34
|
-
# Check git status (must be clean)
|
|
35
|
-
git status
|
|
36
|
-
|
|
37
|
-
# Check existing tags
|
|
38
|
-
git tag -l
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
If git status is not clean, stop and ask user to commit or stash changes before proceeding.
|
|
42
|
-
|
|
43
|
-
### 3. Determine New Version
|
|
44
|
-
|
|
45
|
-
Ask user what type of release following [Semantic Versioning](https://semver.org/):
|
|
46
|
-
- **MAJOR** (1.0.0): Breaking changes
|
|
47
|
-
- **MINOR** (0.2.0): New features, backward compatible
|
|
48
|
-
- **PATCH** (0.1.1): Bug fixes, backward compatible
|
|
49
|
-
|
|
50
|
-
Calculate new version number based on current version and release type.
|
|
51
|
-
|
|
52
|
-
### 4. Update Version File
|
|
53
|
-
|
|
54
|
-
Edit `lib/buttercut/version.rb` with the new version:
|
|
55
|
-
|
|
56
|
-
```ruby
|
|
57
|
-
class ButterCut
|
|
58
|
-
VERSION = "0.2.0" # Update this
|
|
59
|
-
end
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### 5. Update Gemfile.lock
|
|
63
|
-
|
|
64
|
-
Run `bundle install` so `Gemfile.lock` reflects the new version:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
bundle install
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Verify the version updated in `Gemfile.lock` before proceeding.
|
|
71
|
-
|
|
72
|
-
### 6. Gather Changelog Notes
|
|
73
|
-
|
|
74
|
-
Ask user for release notes. Prompt with:
|
|
75
|
-
- What changed in this release?
|
|
76
|
-
- Any new features?
|
|
77
|
-
- Any bug fixes?
|
|
78
|
-
- Any breaking changes?
|
|
79
|
-
|
|
80
|
-
### 7. Update or Create CHANGELOG.md
|
|
81
|
-
|
|
82
|
-
If `CHANGELOG.md` exists, prepend new entry. Otherwise create it:
|
|
83
|
-
|
|
84
|
-
```markdown
|
|
85
|
-
# Changelog
|
|
86
|
-
|
|
87
|
-
All notable changes to ButterCut will be documented in this file.
|
|
88
|
-
|
|
89
|
-
## [0.2.0] - 2025-01-21
|
|
90
|
-
|
|
91
|
-
### Added
|
|
92
|
-
- Feature X
|
|
93
|
-
- Support for Y
|
|
94
|
-
|
|
95
|
-
### Fixed
|
|
96
|
-
- Bug in Z
|
|
97
|
-
|
|
98
|
-
### Changed
|
|
99
|
-
- Improved W
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### 8. Commit Version Bump
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
git add lib/buttercut/version.rb Gemfile.lock CHANGELOG.md
|
|
106
|
-
git commit -m "Bump version to 0.2.0"
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### 9. Create and Push Git Tag
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
git tag v0.2.0
|
|
113
|
-
git push origin main
|
|
114
|
-
git push origin v0.2.0
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### 10. Build Gem
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
gem build buttercut.gemspec
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
This creates `buttercut-0.2.0.gem` file.
|
|
124
|
-
|
|
125
|
-
### 11. Publish to RubyGems
|
|
126
|
-
|
|
127
|
-
**First time setup check:**
|
|
128
|
-
|
|
129
|
-
If this is the first release, verify RubyGems authentication:
|
|
130
|
-
```bash
|
|
131
|
-
gem signin
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
If not authenticated, provide instructions:
|
|
135
|
-
1. Sign up at https://rubygems.org
|
|
136
|
-
2. Run `gem signin` and follow prompts
|
|
137
|
-
3. Store credentials for future releases
|
|
138
|
-
|
|
139
|
-
**Publish the gem:**
|
|
140
|
-
```bash
|
|
141
|
-
gem push buttercut-0.2.0.gem
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
This makes the gem available for `gem install buttercut` worldwide.
|
|
145
|
-
|
|
146
|
-
### 12. Create GitHub Release
|
|
147
|
-
|
|
148
|
-
**Using GitHub CLI:**
|
|
149
|
-
```bash
|
|
150
|
-
gh release create v0.2.0 \
|
|
151
|
-
--title "v0.2.0" \
|
|
152
|
-
--notes "[Release notes from changelog]" \
|
|
153
|
-
buttercut-0.2.0.gem
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
**If `gh` CLI not available:**
|
|
157
|
-
|
|
158
|
-
Guide user through manual release creation:
|
|
159
|
-
1. Go to https://github.com/andrewford/buttercut/releases/new
|
|
160
|
-
2. Choose tag: v0.2.0
|
|
161
|
-
3. Set title: v0.2.0
|
|
162
|
-
4. Paste changelog notes in description
|
|
163
|
-
5. Attach buttercut-0.2.0.gem file
|
|
164
|
-
6. Click "Publish release"
|
|
165
|
-
|
|
166
|
-
Then wait for user confirmation that release is created before proceeding to cleanup.
|
|
167
|
-
|
|
168
|
-
### 13. Cleanup
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
# Remove local gem file (it's on RubyGems and GitHub now)
|
|
172
|
-
rm buttercut-0.2.0.gem
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### 14. Verify Release
|
|
176
|
-
|
|
177
|
-
Check that everything worked:
|
|
178
|
-
- RubyGems page: https://rubygems.org/gems/buttercut
|
|
179
|
-
- GitHub releases: https://github.com/andrewford/buttercut/releases
|
|
180
|
-
- Git tags: `git tag -l`
|
|
181
|
-
|
|
182
|
-
### 15. Return Success Response
|
|
183
|
-
|
|
184
|
-
Provide summary:
|
|
185
|
-
```
|
|
186
|
-
✓ ButterCut 0.2.0 released successfully
|
|
187
|
-
|
|
188
|
-
Version: 0.2.0
|
|
189
|
-
Git tag: v0.2.0
|
|
190
|
-
RubyGems: Published at https://rubygems.org/gems/buttercut
|
|
191
|
-
GitHub Release: https://github.com/andrewford/buttercut/releases/tag/v0.2.0
|
|
192
|
-
|
|
193
|
-
Installation:
|
|
194
|
-
gem install buttercut
|
|
195
|
-
|
|
196
|
-
Upgrade:
|
|
197
|
-
gem update buttercut
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Critical Principles
|
|
201
|
-
|
|
202
|
-
**Always run tests first** - Never release if tests fail
|
|
203
|
-
**Git must be clean** - No uncommitted changes before release
|
|
204
|
-
**Push before publish** - Tags must be pushed before creating GitHub release
|
|
205
|
-
**Semantic versioning** - Follow semver strictly for version numbers
|
|
206
|
-
**Changelog required** - Every release needs documented changes
|
|
207
|
-
|
|
208
|
-
## Common Issues
|
|
209
|
-
|
|
210
|
-
**Tests failing:** Ask user to fix tests before proceeding
|
|
211
|
-
**Git not clean:** Ask user to commit or stash changes first
|
|
212
|
-
**Tag already exists:** Verify this isn't a duplicate release
|
|
213
|
-
**RubyGems authentication:** Guide through `gem signin` process
|
|
214
|
-
**GitHub CLI not installed:** Provide manual release instructions
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: roughcut
|
|
3
|
-
description: Creates video rough cut yaml file for use with Buttercut gem. Concatenates visual transcripts with file markers, creates a roughcut yaml with clip selections, then exports to XML format. Use this skill when users want a "roughcut", "sequence" or "scene" generated. These are all the same thing, just with different lengths.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: Create Rough Cut
|
|
7
|
-
|
|
8
|
-
This skill handles the editorial process of creating rough cut timeline scripts from transcribed video footage. It launches a specialized agent that analyzes transcripts, makes editorial decisions, outputs a structured YAML rough cut, and exports it to Final Cut Pro XML format.
|
|
9
|
-
|
|
10
|
-
**Note:** This skill is used for both full-length rough cuts (multiple minutes) and short sequences (30-60 seconds).
|
|
11
|
-
|
|
12
|
-
## Prerequisites Check
|
|
13
|
-
|
|
14
|
-
Before launching the roughcut agent, verify all transcripts are complete:
|
|
15
|
-
|
|
16
|
-
1. **Check library exists:**
|
|
17
|
-
```bash
|
|
18
|
-
ls libraries/[library-name]/library.yaml
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
2. **Verify visual transcripts:**
|
|
22
|
-
Read `libraries/[library-name]/library.yaml` and check that every video entry has both:
|
|
23
|
-
- `transcript` populated (audio transcript filename)
|
|
24
|
-
- `visual_transcript` populated (visual descriptions filename)
|
|
25
|
-
|
|
26
|
-
If any visual transcripts are missing:
|
|
27
|
-
- Inform user that transcript processing must be completed first
|
|
28
|
-
- Ask if they want Claude to finish transcript processing using the `transcribe-audio` and `analyze-video` skills
|
|
29
|
-
- Do not proceed with roughcut creation until all transcripts are complete
|
|
30
|
-
|
|
31
|
-
## Launch Roughcut Agent
|
|
32
|
-
|
|
33
|
-
Once prerequisites are verified, launch the roughcut creation agent using the Task tool:
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
Task tool with:
|
|
37
|
-
- subagent_type: "general-purpose"
|
|
38
|
-
- description: "Create rough cut from visual transcripts"
|
|
39
|
-
- prompt: [See agent prompt template below]
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### Agent Prompt Template
|
|
43
|
-
|
|
44
|
-
When launching the agent, provide a detailed prompt with all necessary context:
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
You are a video editor AI agent creating a rough cut or sequence for the "{library_name}" library.
|
|
48
|
-
|
|
49
|
-
USER REQUEST: {what_user_asked_for}
|
|
50
|
-
|
|
51
|
-
LIBRARY CONTEXT:
|
|
52
|
-
{paste relevant content from library.yaml - footage_summary, user_context, etc.}
|
|
53
|
-
|
|
54
|
-
YOUR TASK:
|
|
55
|
-
1. Read the roughcut creation instructions from .claude/skills/roughcut/agent_instructions.md
|
|
56
|
-
2. Follow those instructions to create the rough cut
|
|
57
|
-
3. Return the paths to the created YAML and XML files when complete
|
|
58
|
-
|
|
59
|
-
DELIVERABLES:
|
|
60
|
-
- Rough cut YAML file at: libraries/{library_name}/roughcuts/{roughcut_name}_{datetime}.yaml
|
|
61
|
-
- Exported XML file for user's chosen video editor
|
|
62
|
-
- Backup created via backup-library skill
|
|
63
|
-
|
|
64
|
-
Begin by reading the agent instructions file.
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## After Agent Completes
|
|
68
|
-
|
|
69
|
-
When the agent returns:
|
|
70
|
-
1. Inform the user of the created roughcut file (the xml file, not the yaml file) and its location
|
|
71
|
-
2. Confirm the rough cut is ready to import into their video editor
|