demobite 1.16.0 → 1.17.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.
@@ -332,7 +332,7 @@ if (arg === "listen") {
332
332
  await event(job.id, "started", { machine: name });
333
333
  const takeDir = path.join(process.cwd(), ".recorder", "takes", job.id);
334
334
  fs.mkdirSync(takeDir, { recursive: true });
335
- fs.writeFileSync(path.join(takeDir, "job.json"), JSON.stringify({ id: job.id, brief: job.brief, url: job.url ?? null, model, review_storyboard: job.review_storyboard !== false }, null, 2) + "\n");
335
+ fs.writeFileSync(path.join(takeDir, "job.json"), JSON.stringify({ id: job.id, brief: job.brief, url: job.url ?? null, model, review_storyboard: job.review_storyboard !== false, ...(job.retake_of ? { retake_of: job.retake_of, retake_note: job.retake_note ?? null, storyboard: job.storyboard ?? null } : {}) }, null, 2) + "\n");
336
336
  // Spawned async (1.14.1): a spawnSync here blocked the event loop, so the 5 s heartbeat never fired
337
337
  // during a take and the rail called the machine offline mid-recording (founder 2026-10-15 17:39).
338
338
  const child = (await import("node:child_process")).spawn("node", [path.join(dest, "scripts", "plan.mjs"), takeDir], { cwd: process.cwd(), stdio: "inherit", env: { ...process.env, RECORDER_JOB: job.id, RECORDER_BASE: base, RECORDER_LISTEN: "1" } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "demobite",
3
- "version": "1.16.0",
3
+ "version": "1.17.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"
@@ -197,7 +197,11 @@ const firstMessage = () => {
197
197
  `## The app's words on the starting screen\n${vocab}`,
198
198
  `## Workspace rules (version ${rules.version || 0})\n${rules.lines?.length ? rules.lines.map((l, i) => `${i + 1}. ${l}`).join("\n") : "(none)"}`,
199
199
  `## The project's files${codeOn ? " (this machine sits in the app's repository; read_file is on)" : " (no code here)"}\n${listFiles()}`,
200
- codeOn ? `Write the storyboard, probe it, fix it, probe again, then submit_storyboard.` : `There is no code: explore first (explore from the starting address, looking_for = the brief's nouns), then write the storyboard, probe it, fix it, probe again, then submit_storyboard.`,
200
+ // A RETAKE (founder 2026-10-15): the same demo again, because the app changed under it. The previous
201
+ // storyboard is the base; the note says what to keep an eye on; the probe finds what moved.
202
+ job.retake_of && job.storyboard
203
+ ? `## This is a retake\nThe person wants the same demo filmed again, the same length and the same shots, because the app changed since. Their note: "${(job.retake_note || "no note").replace(/"/g, "'")}". ${job.storyboard.storyboard ? "Start from the previous storyboard below: keep its steps and its lines; probe it; fix only what no longer resolves or what the note names; then submit_storyboard. Never explore when the probe passes." : "Only the previous storyboard's lines survive (below): rebuild the same steps with the same lines, find the controls again, probe, then submit_storyboard."}\n\n## The previous storyboard\n${JSON.stringify(job.storyboard.storyboard ?? job.storyboard.steps ?? job.storyboard)}`
204
+ : codeOn ? `Write the storyboard, probe it, fix it, probe again, then submit_storyboard.` : `There is no code: explore first (explore from the starting address, looking_for = the brief's nouns), then write the storyboard, probe it, fix it, probe again, then submit_storyboard.`,
201
205
  ];
202
206
  return parts.join("\n\n");
203
207
  };
@@ -63,7 +63,8 @@ if (mode === "await") {
63
63
  rows.forEach((r, i) => boxOut.push(`│ ${`${String(i + 1).padStart(2)} ${mmss(r.at)} ${cap2(r.text + (r.pointed ? " — pointed at, not pressed" : ""), W2 - 14)}`.padEnd(W2 - 2)} │`));
64
64
  boxOut.push(`│ ${"".padEnd(W2 - 2)} │`); boxOut.push(`└${"─".repeat(W2)}┘`);
65
65
  if (!listening) { console.log(boxOut.join("\n")); console.log("film"); process.exit(0); }
66
- await postEvent("storyboard", { box: boxOut.join("\n"), total: mmss(total), steps: rows.map((r, i) => ({ n: i + 1, at: mmss(r.at), text: r.text, pointed: r.pointed })) });
66
+ // The whole storyboard rides along (1.17.0): a retake starts from it, selectors and all.
67
+ await postEvent("storyboard", { box: boxOut.join("\n"), total: mmss(total), steps: rows.map((r, i) => ({ n: i + 1, at: mmss(r.at), text: r.text, pointed: r.pointed })), storyboard: sb });
67
68
  const started = Date.now();
68
69
  while (Date.now() - started < 30 * 60 * 1000) {
69
70
  const st = await poll();