agentreel 0.3.3 → 0.3.4
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/bin/agentreel.mjs +25 -6
- package/package.json +1 -1
- package/scripts/cli_demo.py +6 -3
package/bin/agentreel.mjs
CHANGED
|
@@ -30,6 +30,7 @@ function parseArgs() {
|
|
|
30
30
|
else if (arg === "--output" || arg === "-o") flags.output = args[++i];
|
|
31
31
|
else if (arg === "--music") flags.music = args[++i];
|
|
32
32
|
else if (arg === "--auth" || arg === "-a") flags.auth = args[++i];
|
|
33
|
+
else if (arg === "--guidelines" || arg === "-g") flags.guidelines = args[++i];
|
|
33
34
|
else if (arg === "--no-share") flags.noShare = true;
|
|
34
35
|
}
|
|
35
36
|
return flags;
|
|
@@ -49,6 +50,7 @@ Flags:
|
|
|
49
50
|
-t, --title <text> video title
|
|
50
51
|
-o, --output <file> output file (default: agentreel.mp4)
|
|
51
52
|
-a, --auth <file> Playwright storage state (cookies/auth) for browser demos
|
|
53
|
+
-g, --guidelines <text> guidelines for highlight generation (e.g. "focus on speed")
|
|
52
54
|
--music <file> path to background music mp3
|
|
53
55
|
--no-share skip the share prompt
|
|
54
56
|
-h, --help show help
|
|
@@ -111,13 +113,14 @@ function recordCLI(command, workDir, context) {
|
|
|
111
113
|
return outFile;
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
function extractHighlightsFromCast(castPath, context) {
|
|
116
|
+
function extractHighlightsFromCast(castPath, context, guidelines) {
|
|
115
117
|
const python = findPython();
|
|
116
118
|
const script = join(ROOT, "scripts", "cli_demo.py");
|
|
117
119
|
const outFile = castPath + "-highlights.json";
|
|
118
120
|
|
|
119
121
|
const args = [script, "--highlights", castPath, outFile];
|
|
120
122
|
if (context) args.push(context);
|
|
123
|
+
if (guidelines) args.push(guidelines);
|
|
121
124
|
|
|
122
125
|
execFileSync(python, args, { stdio: ["ignore", "inherit", "inherit"], env: process.env });
|
|
123
126
|
return outFile;
|
|
@@ -160,12 +163,28 @@ function extractBrowserHighlights(videoPath, task) {
|
|
|
160
163
|
|
|
161
164
|
// ── Browser Highlight Builder ───────────────────────────────
|
|
162
165
|
|
|
163
|
-
function buildBrowserHighlights(clicks, videoPath, task) {
|
|
166
|
+
function buildBrowserHighlights(clicks, videoPath, task, guidelines) {
|
|
164
167
|
const CLIP_DUR = 7;
|
|
165
168
|
const MIN_HIGHLIGHTS = 3;
|
|
166
169
|
const MAX_HIGHLIGHTS = 4;
|
|
167
|
-
|
|
168
|
-
|
|
170
|
+
// Ask Claude to generate labels/overlays based on the task
|
|
171
|
+
let labels, overlays;
|
|
172
|
+
try {
|
|
173
|
+
const guidelinesLine = guidelines ? `\nGuidelines: ${guidelines}` : "";
|
|
174
|
+
const genPrompt = `Generate exactly 4 highlight labels and overlay captions for a short browser demo video.
|
|
175
|
+
Task: ${task}${guidelinesLine}
|
|
176
|
+
|
|
177
|
+
Return a JSON object: {"labels": ["word1", "word2", "word3", "word4"], "overlays": ["**caption1**", "**caption2**", "**caption3**", "**caption4**"]}
|
|
178
|
+
Labels: 1-2 words each, specific to this app (not generic). Overlays: short punchy captions with **markdown bold** for emphasis. Return ONLY JSON.`;
|
|
179
|
+
const result = execFileSync("claude", ["-p", genPrompt, "--output-format", "text"], {
|
|
180
|
+
encoding: "utf-8", timeout: 30000, stdio: ["ignore", "pipe", "ignore"],
|
|
181
|
+
}).trim();
|
|
182
|
+
const parsed = JSON.parse(result.replace(/```json?\n?/g, "").replace(/```/g, "").trim());
|
|
183
|
+
labels = parsed.labels?.length >= 4 ? parsed.labels : null;
|
|
184
|
+
overlays = parsed.overlays?.length >= 4 ? parsed.overlays : null;
|
|
185
|
+
} catch { /* fall through */ }
|
|
186
|
+
if (!labels) labels = ["Overview", "Interact", "Navigate", "Result"];
|
|
187
|
+
if (!overlays) overlays = ["**First look**", "**Key action**", "**Exploring**", "**The result**"];
|
|
169
188
|
|
|
170
189
|
// Estimate video duration from last click or default to 25s
|
|
171
190
|
const lastClickTime = clicks.length > 0 ? clicks[clicks.length - 1].timeSec : 0;
|
|
@@ -409,7 +428,7 @@ async function main() {
|
|
|
409
428
|
const castPath = recordCLI(demoCmd, process.cwd(), prompt);
|
|
410
429
|
|
|
411
430
|
console.error("Step 2/3: Extracting highlights...");
|
|
412
|
-
const highlightsPath = extractHighlightsFromCast(castPath, prompt);
|
|
431
|
+
const highlightsPath = extractHighlightsFromCast(castPath, prompt, flags.guidelines);
|
|
413
432
|
const highlights = JSON.parse(readFileSync(highlightsPath, "utf-8"));
|
|
414
433
|
console.error(` ${highlights.length} highlights extracted`);
|
|
415
434
|
|
|
@@ -449,7 +468,7 @@ async function main() {
|
|
|
449
468
|
console.error(` ${allClicks.length} clicks captured`);
|
|
450
469
|
}
|
|
451
470
|
|
|
452
|
-
const highlights = buildBrowserHighlights(allClicks, videoPath, task);
|
|
471
|
+
const highlights = buildBrowserHighlights(allClicks, videoPath, task, flags.guidelines);
|
|
453
472
|
|
|
454
473
|
console.error("Step 3/3: Rendering video...");
|
|
455
474
|
await renderVideo({
|
package/package.json
CHANGED
package/scripts/cli_demo.py
CHANGED
|
@@ -195,7 +195,7 @@ def record_demo(steps: list[dict], workdir: str, output_path: str):
|
|
|
195
195
|
print(f"Saved: {output_path}", file=sys.stderr)
|
|
196
196
|
|
|
197
197
|
|
|
198
|
-
def extract_highlights(cast_path: str, context: str) -> list[dict]:
|
|
198
|
+
def extract_highlights(cast_path: str, context: str, guidelines: str = "") -> list[dict]:
|
|
199
199
|
"""Ask Claude to pick 3-4 highlight moments from the recorded session."""
|
|
200
200
|
# Read the asciicast and strip to just the text content
|
|
201
201
|
lines_output = []
|
|
@@ -214,13 +214,15 @@ def extract_highlights(cast_path: str, context: str) -> list[dict]:
|
|
|
214
214
|
# Clean ANSI for Claude to read, but keep the raw for display
|
|
215
215
|
clean = re.sub(r'\x1b\[[0-9;]*[a-zA-Z]', '', raw_output)
|
|
216
216
|
|
|
217
|
+
guidelines_block = f"\n\nAdditional guidelines: {guidelines}" if guidelines else ""
|
|
218
|
+
|
|
217
219
|
prompt = f"""You are creating a highlights reel for a CLI tool demo video. Here is the full terminal output:
|
|
218
220
|
|
|
219
221
|
---
|
|
220
222
|
{clean[:3000]}
|
|
221
223
|
---
|
|
222
224
|
|
|
223
|
-
Context: {context}
|
|
225
|
+
Context: {context}{guidelines_block}
|
|
224
226
|
|
|
225
227
|
Pick 3-4 highlight moments that would look impressive in a short video. For each highlight, return:
|
|
226
228
|
- "label": short label (1-2 words) like "Initialize", "Configure", "Run", "Results"
|
|
@@ -274,8 +276,9 @@ if __name__ == "__main__":
|
|
|
274
276
|
cast_file = sys.argv[2]
|
|
275
277
|
output = sys.argv[3]
|
|
276
278
|
context = sys.argv[4] if len(sys.argv) > 4 else ""
|
|
279
|
+
guidelines = sys.argv[5] if len(sys.argv) > 5 else ""
|
|
277
280
|
print(f"Extracting highlights from: {cast_file}", file=sys.stderr)
|
|
278
|
-
highlights = extract_highlights(cast_file, context)
|
|
281
|
+
highlights = extract_highlights(cast_file, context, guidelines)
|
|
279
282
|
with open(output, "w") as f:
|
|
280
283
|
json.dump(highlights, f, indent=2)
|
|
281
284
|
print(f"Saved {len(highlights)} highlights to: {output}", file=sys.stderr)
|