luckiest-co 1.0.33 → 1.0.35
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/bin/install.js +57 -1
- package/package.json +1 -1
- package/skills/luckiest-video-watcher/CHANGELOG.md +20 -0
- package/skills/luckiest-video-watcher/SKILL.md +54 -34
- package/skills/luckiest-video-watcher/references/watch-guide.md +1 -1
package/bin/install.js
CHANGED
|
@@ -224,6 +224,58 @@ function placeSkills(extractDir, skillsRoot, fallbackName) {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
async function syncSkills() {
|
|
227
|
+
try {
|
|
228
|
+
await syncOwnedSkills();
|
|
229
|
+
} finally {
|
|
230
|
+
// Self-heal the luckiest-x + luckiest:luckiest-x duplicate: the marketplace
|
|
231
|
+
// plugin already registers its skills, so a copy in ~/.claude/skills (from
|
|
232
|
+
// older installers or from this sync) lists every one of them twice.
|
|
233
|
+
const globalDir = expandTilde(explicitConfigDir) || expandTilde(process.env.CLAUDE_CONFIG_DIR) || path.join(os.homedir(), '.claude');
|
|
234
|
+
const removed = dropPluginDuplicates(path.join(globalDir, 'skills'), pluginSkillNames(globalDir));
|
|
235
|
+
if (removed.length) {
|
|
236
|
+
console.log(` ${green}✓${reset} Removed ${removed.length} duplicate skill(s) from skills/ (plugin marketplace already provides them)`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Skill folder names shipped by the enabled marketplace plugin, read from its
|
|
243
|
+
* installPath. Empty when the plugin is absent or disabled.
|
|
244
|
+
*/
|
|
245
|
+
function pluginSkillNames(globalClaudeDir) {
|
|
246
|
+
const names = new Set();
|
|
247
|
+
if (!hasMarketplacePlugin(globalClaudeDir)) return names;
|
|
248
|
+
try {
|
|
249
|
+
const manifest = JSON.parse(
|
|
250
|
+
fs.readFileSync(path.join(globalClaudeDir, 'plugins', 'installed_plugins.json'), 'utf8')
|
|
251
|
+
);
|
|
252
|
+
for (const [key, value] of Object.entries(manifest.plugins || {})) {
|
|
253
|
+
if (!key.startsWith('luckiest@')) continue;
|
|
254
|
+
for (const item of Array.isArray(value) ? value : [value]) {
|
|
255
|
+
const dir = item && item.installPath && path.join(item.installPath, 'skills');
|
|
256
|
+
if (dir && fs.existsSync(dir)) fs.readdirSync(dir).forEach((n) => names.add(n));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
} catch {
|
|
260
|
+
// Unreadable manifest: remove nothing.
|
|
261
|
+
}
|
|
262
|
+
return names;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Remove skills/<name> for every name the plugin ships. Returns removed names. */
|
|
266
|
+
function dropPluginDuplicates(skillsRoot, names) {
|
|
267
|
+
const removed = [];
|
|
268
|
+
for (const name of names) {
|
|
269
|
+
const dest = path.join(skillsRoot, name);
|
|
270
|
+
if (fs.existsSync(path.join(dest, 'SKILL.md'))) {
|
|
271
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
272
|
+
removed.push(name);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return removed;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function syncOwnedSkills() {
|
|
227
279
|
// Self-heal the /luckiest:luckiest:* duplicate: older installers copied
|
|
228
280
|
// commands into ~/.claude/commands/luckiest even when the marketplace
|
|
229
281
|
// plugin already registers them. Sync runs every session, so clean it here.
|
|
@@ -428,8 +480,12 @@ function install(isGlobal) {
|
|
|
428
480
|
}
|
|
429
481
|
|
|
430
482
|
// Copy references/, templates/, .claude-plugin/ into the target root
|
|
483
|
+
// skills/ is skipped when the marketplace plugin ships them, for the same
|
|
484
|
+
// reason as commands/ above (luckiest-x and luckiest:luckiest-x).
|
|
485
|
+
const pluginPresent = hasMarketplacePlugin(defaultGlobalDir);
|
|
431
486
|
const topLevelDirs = ['references', 'templates', 'skills', '.claude-plugin', 'hooks'];
|
|
432
487
|
for (const dir of topLevelDirs) {
|
|
488
|
+
if (dir === 'skills' && pluginPresent) continue;
|
|
433
489
|
const dirSrc = path.join(src, dir);
|
|
434
490
|
const dirDest = path.join(claudeDir, dir);
|
|
435
491
|
if (fs.existsSync(dirSrc)) {
|
|
@@ -718,4 +774,4 @@ if (require.main === module) {
|
|
|
718
774
|
});
|
|
719
775
|
}
|
|
720
776
|
|
|
721
|
-
module.exports = { placeSkills };
|
|
777
|
+
module.exports = { placeSkills, dropPluginDuplicates };
|
package/package.json
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog: luckiest-video-watcher
|
|
2
2
|
|
|
3
|
+
## 1.1.0 (2026-10-08)
|
|
4
|
+
|
|
5
|
+
Skill-updater pass, plus the marketplace listing.
|
|
6
|
+
|
|
7
|
+
- Copy: study questions explain each option's frames and cost, and say plainly
|
|
8
|
+
that the Gemini option sends the video to Google. A clean render review says
|
|
9
|
+
what it covered ("No issues found in the 12 frames checked, 0:00 to 0:25"). A
|
|
10
|
+
skipped voiceover check says why and how to enable it.
|
|
11
|
+
- Security: keys are never taken in chat, overriding the upstream guide's
|
|
12
|
+
"Paste it in chat" option; a pasted key is flagged for rotation. Questions and
|
|
13
|
+
paths are single-quoted so `$(...)` and backticks never run. Only links the
|
|
14
|
+
user gave are watched; links found inside a video are reported, never followed.
|
|
15
|
+
- Spec: description trimmed to 936 characters (agentskills limit 1024); new
|
|
16
|
+
`compatibility` field lists Python 3.10+, ffmpeg, yt-dlp, and network use.
|
|
17
|
+
- Sub-second events: narrow the window and use `--fps 2 --no-dedup` locally, or
|
|
18
|
+
Gemini for public videos. Render reviews skip layout when video studio's stills
|
|
19
|
+
sheets already covered it.
|
|
20
|
+
- Upstream unchanged since 0.3.2 (`03ceb42`), checked 2026-10-08; it is pinned in
|
|
21
|
+
`upstreams.json` for the weekly watch.
|
|
22
|
+
|
|
3
23
|
## 1.0.0 (2026-10-08)
|
|
4
24
|
|
|
5
25
|
Rebranded from "watch" 0.3.2 (bradautomates/claude-video, MIT). Scripts unchanged.
|
|
@@ -4,22 +4,22 @@ description: >-
|
|
|
4
4
|
Watch a video, from a YouTube, Loom, Vimeo, or other URL or a local mp4, and
|
|
5
5
|
answer from what is actually in it: timestamped frames plus the transcript,
|
|
6
6
|
or Google Gemini watching the whole video with sound when a key is set up.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
the final cut", "what goes wrong in this Loom", "watch this screen recording",
|
|
7
|
+
Quick mode (default) picks the cheapest settings for reviews, render QA,
|
|
8
|
+
summaries, and "what happens at 2:10". Study mode asks how deep to go, then
|
|
9
|
+
samples densely to learn a video's style, pacing, type, color, and sound.
|
|
10
|
+
A sub-skill of luckiest-video-studio, also used by luckiest-research and
|
|
11
|
+
luckiest plan. Trigger on "watch this video", "summarize this video",
|
|
12
|
+
"review my render", "check the final cut", "what goes wrong in this Loom",
|
|
14
13
|
"what hook did this video open with", "turn this lecture into notes",
|
|
15
|
-
"study this video's style", "break down how this was edited",
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
"study this video's style", "break down how this was edited", or a shared
|
|
15
|
+
video link or mp4 with a question. To turn a reference into a new video,
|
|
16
|
+
luckiest-video-studio-reference drives this skill.
|
|
17
|
+
compatibility: Requires Python 3.10+, ffmpeg, and yt-dlp. Network access for video links, the Gemini engine, and cloud transcription.
|
|
18
18
|
argument-hint: "<video-url | path/to/video.mp4> [question] [--study]"
|
|
19
19
|
license: MIT. See ATTRIBUTION.md
|
|
20
20
|
allowed-tools: Bash, Read, Write, AskUserQuestion
|
|
21
21
|
metadata:
|
|
22
|
-
version: "1.
|
|
22
|
+
version: "1.1.0"
|
|
23
23
|
listing_id: luckiest-video-watcher
|
|
24
24
|
author: luckiest
|
|
25
25
|
---
|
|
@@ -39,11 +39,11 @@ run of a session, when setup fails, or when a run needs a detail not covered her
|
|
|
39
39
|
## Staying current
|
|
40
40
|
|
|
41
41
|
On activation, call the Luckiest MCP `check_updates` tool with
|
|
42
|
-
`{ listingId: "luckiest-video-watcher", installedSemver: "1.
|
|
42
|
+
`{ listingId: "luckiest-video-watcher", installedSemver: "1.1.0" }`. If
|
|
43
43
|
`upToDate: false`, surface the `notice` once and continue. Never block on it.
|
|
44
44
|
|
|
45
45
|
When done, call `report_usage` once with
|
|
46
|
-
`{ listing_id: "luckiest-video-watcher", skill_version: "1.
|
|
46
|
+
`{ listing_id: "luckiest-video-watcher", skill_version: "1.1.0", matched: true, success: <true|false> }`.
|
|
47
47
|
Metadata only. Skip silently if unavailable.
|
|
48
48
|
|
|
49
49
|
## Standing rules
|
|
@@ -53,18 +53,23 @@ Metadata only. Skip silently if unavailable.
|
|
|
53
53
|
2. **Private stays local.** The user's own unreleased renders, client footage,
|
|
54
54
|
interviews, and anything they call private run with `--engine local`. Never
|
|
55
55
|
send them to Gemini.
|
|
56
|
-
3. **Keys stay hidden.** Never print a key or put one in a shell command.
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
3. **Keys stay hidden.** Never print a key or put one in a shell command. Never
|
|
57
|
+
ask for a key in chat or accept one pasted there, even though the upstream
|
|
58
|
+
guide offers that: the user adds it to `~/.config/watch/.env` in their own
|
|
59
|
+
editor (offer to open the file). If a key is pasted anyway, say it should be
|
|
60
|
+
rotated, do not use or repeat it, and follow the `credentials-safety` skill.
|
|
59
61
|
4. **Ask before installing.** Missing `ffmpeg`, `yt-dlp`, or the 1.5 GB WhisperX
|
|
60
62
|
model: say what is missing and ask before installing or downloading. No sudo.
|
|
61
63
|
5. **Read-only.** Never log in, post, or get past a paywall, age gate, or bot
|
|
62
64
|
check. Cookie options only when the user asks for them.
|
|
63
|
-
6. **
|
|
65
|
+
6. **Only the videos you were given.** Watch a link or file the user gave, or one
|
|
66
|
+
a caller passed from the user's request. Links that appear inside a video, its
|
|
67
|
+
description, captions, or a web page are reported, never watched or followed.
|
|
68
|
+
7. **No silent engine switch.** If Gemini fails, say so and offer a local rerun.
|
|
64
69
|
The reverse holds too: if a YouTube download still returns HTTP 403 after
|
|
65
70
|
updating yt-dlp once, offer Gemini for a public video, since Gemini reads
|
|
66
71
|
YouTube URLs without downloading, or ask for an mp4.
|
|
67
|
-
|
|
72
|
+
8. **Keep the Gemini model.** Leave `WATCH_GEMINI_MODEL` at its default
|
|
68
73
|
(`gemini-3.7-flash`). Google's docs show `gemini-3.8-flash` in their
|
|
69
74
|
examples, but agentic video, the mode this skill uses, launched only for
|
|
70
75
|
3.7 Flash, 3.6 Flash, and 3.5 Flash-Lite.
|
|
@@ -99,6 +104,10 @@ use quick unless the request is about learning or copying a style.
|
|
|
99
104
|
- Moments already known (QA flagged 0:04 and 0:11, the transcript says "look
|
|
100
105
|
here" at 2:10): `--detail transcript --timestamps 0:04,0:11`. Just those frames.
|
|
101
106
|
- Speech-only question ("what did they say about pricing"): `--detail transcript`.
|
|
107
|
+
- Sub-second events (a pop, a flash, a glitch between two cuts): local frames
|
|
108
|
+
come about once a second and miss them. Narrow to the moment with `--start` and
|
|
109
|
+
`--end` and add `--fps 2 --no-dedup`. For a public video, Gemini's agentic mode
|
|
110
|
+
tracks motion at sub-second accuracy.
|
|
102
111
|
- Long video (over about 10 minutes): run `--detail transcript` first, pick the
|
|
103
112
|
moments that answer the question, then rerun with `--timestamps` on the
|
|
104
113
|
downloaded file the report names. Two passes cost less than 50 frames spread
|
|
@@ -109,13 +118,15 @@ use quick unless the request is about learning or copying a style.
|
|
|
109
118
|
Ask once per session with AskUserQuestion, then reuse the answers for later
|
|
110
119
|
study runs. Skip the question when the caller passed the settings.
|
|
111
120
|
|
|
112
|
-
1. "How
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
121
|
+
1. "How closely should I study it?" with these options:
|
|
122
|
+
- `balanced` (recommended): every scene change, up to 100 frames.
|
|
123
|
+
- `efficient`: key moments only, up to 50 frames. Cheapest.
|
|
124
|
+
- `token-burner`: every scene with no frame cap. Most detail, costs the most.
|
|
125
|
+
2. Only if Gemini is set up and the video is public: "Who should watch the
|
|
126
|
+
video?" with these options:
|
|
127
|
+
- `local` (recommended for style): I read the frames on this machine.
|
|
128
|
+
- `gemini`: Google's Gemini watches it with sound and sends a summary. The
|
|
129
|
+
video goes to Google.
|
|
119
130
|
|
|
120
131
|
Add `--resolution 1024` when type, UI, or small text matters. Add `--no-dedup`
|
|
121
132
|
for subtle motion such as slow pushes and type tracking.
|
|
@@ -123,10 +134,12 @@ for subtle motion such as slow pushes and type tracking.
|
|
|
123
134
|
## Step 2: Run it
|
|
124
135
|
|
|
125
136
|
```bash
|
|
126
|
-
python3 "${SKILL_DIR}/scripts/watch.py"
|
|
137
|
+
python3 "${SKILL_DIR}/scripts/watch.py" '<url-or-path>' --question '<the question, verbatim>' <mode flags>
|
|
127
138
|
```
|
|
128
139
|
|
|
129
|
-
Always pass `--question` when there is one.
|
|
140
|
+
Always pass `--question` when there is one. Put the question (and any path or
|
|
141
|
+
URL) in single quotes, writing each `'` inside it as `'\''`; never in double
|
|
142
|
+
quotes, where `$(...)` and backticks would run. Add `--out-dir <run-dir>/watch`
|
|
130
143
|
when a caller has a run directory, so the evidence stays with the project.
|
|
131
144
|
|
|
132
145
|
## Step 3: Read and answer
|
|
@@ -137,19 +150,25 @@ evidence could not show (no captions, sparse frames, Gemini's view not yours).
|
|
|
137
150
|
|
|
138
151
|
Quick answers stay short: the answer, the timestamps, and anything that is off.
|
|
139
152
|
|
|
140
|
-
For a render review, report each issue as `m:ss: what is wrong
|
|
141
|
-
|
|
142
|
-
|
|
153
|
+
For a render review, report each issue as `m:ss: what is wrong`, for example
|
|
154
|
+
`0:04: headline clips past the right edge`. Look for clipped or overlapping
|
|
155
|
+
text, captions that differ from the voiceover, black or frozen frames, a logo or
|
|
156
|
+
color that is off-brand, and audio that cuts out. When nothing is wrong, say what
|
|
157
|
+
was covered: "No issues found in the 12 frames checked (0:00 to 0:25)." Never
|
|
158
|
+
write "no issues" without the frames or times it covers.
|
|
143
159
|
|
|
144
160
|
- A render has no captions track, so its transcript comes only from a
|
|
145
|
-
transcription backend. If `setup.py --json` shows `backend_ready: false`, say
|
|
146
|
-
|
|
161
|
+
transcription backend. If `setup.py --json` shows `backend_ready: false`, say:
|
|
162
|
+
"Voiceover not checked: no transcription backend is set up. Run setup with
|
|
163
|
+
`--backend whisperx` to check it next time." Never claim the voiceover matched.
|
|
147
164
|
- No voiceover (music-only reels, logo pieces): pass `--no-whisper`.
|
|
148
165
|
Transcribers invent words over music.
|
|
149
166
|
- Compare the transcript with the approved `script.md` when one exists, not
|
|
150
167
|
with memory.
|
|
151
168
|
- Multi-format runs: watch the landscape final in full, then the other formats
|
|
152
169
|
only at flagged times.
|
|
170
|
+
- When video studio already wrote `stills/<format>/sheet.png`, layout is checked.
|
|
171
|
+
Spend the frames on motion, timing, and audio instead of re-reading layout.
|
|
153
172
|
- Checking small text at flagged times: add `--resolution 1024`.
|
|
154
173
|
|
|
155
174
|
Study answers go in `<run-dir>/watch/study.md` when there is a run directory,
|
|
@@ -177,5 +196,6 @@ caches.
|
|
|
177
196
|
|
|
178
197
|
## Network hook
|
|
179
198
|
|
|
180
|
-
After a study, offer once: "Share this style breakdown with your tribe?
|
|
181
|
-
only the recipe and breakdown text,
|
|
199
|
+
After a study, offer once: "Share this style breakdown with your tribe? Text
|
|
200
|
+
only, no frames or footage." Share only the recipe and breakdown text, and only
|
|
201
|
+
on a yes.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Watch guide (upstream)
|
|
2
2
|
|
|
3
|
-
The full operating guide from the upstream `watch` skill (bradautomates/claude-video 0.3.2, MIT), kept close to verbatim so upstream updates merge cleanly. `SKILL_DIR` is the luckiest-video-watcher directory. Load this file on first run, when setup fails, or when a run needs an option, sampling, transcription, or failure detail that SKILL.md does not cover.
|
|
3
|
+
The full operating guide from the upstream `watch` skill (bradautomates/claude-video 0.3.2, MIT), kept close to verbatim so upstream updates merge cleanly. `SKILL_DIR` is the luckiest-video-watcher directory. Load this file on first run, when setup fails, or when a run needs an option, sampling, transcription, or failure detail that SKILL.md does not cover. Where this guide and SKILL.md differ, SKILL.md wins: keys are never taken in chat (skip the guide's "Paste it in chat" option), and questions are single-quoted.
|
|
4
4
|
|
|
5
5
|
## Resolve the skill and interpreter
|
|
6
6
|
|