demobite 1.12.0 → 1.13.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.
@@ -313,6 +313,9 @@ if (arg === "listen") {
313
313
  waitOff();
314
314
  if (job.kind === "look" || job.kind === "signin") return runLookOrSignin(job);
315
315
  const model = typeof job.model === "string" && job.model ? job.model : JOB_MODEL;
316
+ // Alive while filming (1.13.0): a heartbeat every 20 s so the rail never shows this machine
317
+ // offline mid-take (the gap after the last step used to do exactly that).
318
+ const heartbeat = setInterval(() => { void api({ action: "checkin", machine_id: listen.machine_id, name, readiness: readiness(), busy: true }); }, 20000);
316
319
  console.log(`\n ▶ Job ${job.id}: ${job.brief.slice(0, 100)}${job.brief.length > 100 ? "…" : ""} (filming on ${model})`);
317
320
  if (!agentBin) { await event(job.id, "failed", { message: "Claude Code is not installed on this machine" }); return; }
318
321
  await event(job.id, "started", { machine: name });
@@ -351,6 +354,7 @@ if (arg === "listen") {
351
354
  if (code === 0) await event(job.id, "note", { text: "The agent finished without a ready signal." });
352
355
  await event(job.id, "failed", { message: code === 0 ? "The demo did not come through — try again" : `The agent stopped (exit ${code})` });
353
356
  }
357
+ clearInterval(heartbeat);
354
358
  console.log(` ■ Job ${job.id} ${st?.status ?? "ended"}.\n`);
355
359
  waitOn();
356
360
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "demobite",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "The DemoBites agentic recorder — you prompt, it films a real browser, and DemoBites turns the take into an editable demo bite.",
5
5
  "bin": {
6
6
  "demobite": "launcher/index.mjs"
@@ -1211,6 +1211,7 @@ try {
1211
1211
 
1212
1212
  clearInterval(sampler);
1213
1213
  manifest.duration = t();
1214
+ void postEvent("finishing", { text: "Camera off. Saving the take…" });
1214
1215
  const video = page.video();
1215
1216
  await ctx.close();
1216
1217
  if (video) {
package/scripts/trim.mjs CHANGED
@@ -16,6 +16,8 @@ if (!dir) {
16
16
  process.exit(2);
17
17
  }
18
18
  import { ffmpeg as FFMPEG, ffprobe as FFPROBE, requireMediaTools } from "./media-tools.mjs";
19
+ const postEvent = await import("./listen-event.mjs").then((m) => m.postEvent).catch(() => async () => null);
20
+ void postEvent("finishing", { text: "Trimming the take to the real first and last frame…" });
19
21
  requireMediaTools();
20
22
 
21
23
  const raw = path.join(dir, "raw.webm");
@@ -26,6 +26,7 @@ import fs from "node:fs";
26
26
  import os from "node:os";
27
27
  import path from "node:path";
28
28
  import { spawnSync } from "node:child_process";
29
+ const postEvent = await import("./listen-event.mjs").then((m) => m.postEvent).catch(() => async () => null);
29
30
 
30
31
  const dir = process.argv[2];
31
32
  if (!dir) {
@@ -180,6 +181,7 @@ function storeZip(name, data) {
180
181
  return Buffer.concat([local, nameBuf, data, central, nameBuf, eocd]);
181
182
  }
182
183
 
184
+ void postEvent("finishing", { text: "Packing the take…" });
183
185
  const zipPath = path.join(dir, "take.zip");
184
186
  fs.rmSync(zipPath, { force: true });
185
187
  const staging = fs.mkdtempSync(path.join(os.tmpdir(), "rec-zip-"));
@@ -261,6 +263,7 @@ if (!stagingId || !uploadUrl || !previewUploadUrl) {
261
263
 
262
264
  // ── S3 PUTs: the ZIP for ingestion, the MP4 for the preview player ─────────
263
265
  console.log("Uploading take...");
266
+ void postEvent("finishing", { text: "Uploading the take to your workspace…" });
264
267
  async function putS3(url, contentType, filePath, label) {
265
268
  let res;
266
269
  try {