demobite 1.0.5 → 1.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "demobite",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
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"
@@ -36,6 +36,20 @@ for (const [i, s] of STORYBOARD.steps.entries()) {
36
36
  }
37
37
 
38
38
  const DIR = path.resolve(outArg);
39
+
40
+ // RE-TAKE (founder 2026-09-02): the storyboard IS the bite's DNA. Keep a verbatim
41
+ // copy in the take dir so upload.mjs can stage it as the recording recipe —
42
+ // selectors, urls, typed text, hideCss — the wire manifest alone cannot re-film.
43
+ const ENGINE_VERSION = "1.0.6";
44
+ fs.mkdirSync(DIR, { recursive: true });
45
+ fs.writeFileSync(path.join(DIR, "storyboard.json"), JSON.stringify(STORYBOARD, null, 2));
46
+ try {
47
+ const cfgPath = path.resolve(".recorder/config.json");
48
+ const cfg = fs.existsSync(cfgPath) ? JSON.parse(fs.readFileSync(cfgPath, "utf8")) : {};
49
+ // Only the public shape — NEVER the api_key or workspace.
50
+ const config = { app: STORYBOARD.app ?? cfg.app ?? null, url: STORYBOARD.url ?? cfg.url ?? null, frame: cfg.frame ?? { width: 1920, height: 1080 }, base: cfg.base ?? "https://app.demobites.com" };
51
+ fs.writeFileSync(path.join(DIR, "recipe.json"), JSON.stringify({ version: 1, lane: "skill", engine: ENGINE_VERSION, config }, null, 2));
52
+ } catch (e) { console.error("recipe.json not written:", e.message); }
39
53
  fs.mkdirSync(DIR, { recursive: true });
40
54
 
41
55
  // LAW (supersampled capture, measured 2026-08-09): deviceScaleFactor is a
package/skill/SKILL.md CHANGED
@@ -281,7 +281,8 @@ DELETE <base>/api/recorder/key (Authorization: Bearer <api_key>)
281
281
  -> { revoked: true } (logout)
282
282
 
283
283
  PUT <base>/api/recorder/stage (Authorization: Bearer <api_key>)
284
- { filename, sizeBytes, previewSizeBytes, manifest }
284
+ { filename, sizeBytes, previewSizeBytes, manifest, recipe? }
285
+ // recipe = { version:1, lane:'skill', engine, storyboard, config:{app,url,frame,base} } — the RE-TAKE DNA (never the api_key)
285
286
  -> { stagingId, uploadUrl, previewUploadUrl, videoKey, previewUrl }
286
287
 
287
288
  GET <base>/api/recorder/stage?id=<stagingId> (Authorization: Bearer <api_key>)
@@ -40,6 +40,19 @@ const base = cfg.base.replace(/\/+$/, "");
40
40
 
41
41
  const cleanPath = path.join(dir, "clean.mp4");
42
42
  const wirePath = path.join(dir, "manifest.demobites.json");
43
+ // Recording recipe (RE-TAKE, 2026-09-02): storyboard + public config, written by
44
+ // record.mjs. Staged next to the manifest so the bite can be re-filmed later.
45
+ // Absent on takes filmed by older engines — staging still works without it.
46
+ let recipe = null;
47
+ try {
48
+ const sbPath = path.join(dir, "storyboard.json");
49
+ const rcPath = path.join(dir, "recipe.json");
50
+ if (fs.existsSync(sbPath)) {
51
+ const rc = fs.existsSync(rcPath) ? JSON.parse(fs.readFileSync(rcPath, "utf8")) : {};
52
+ recipe = { version: 1, lane: rc.lane ?? "skill", engine: rc.engine ?? null, storyboard: JSON.parse(fs.readFileSync(sbPath, "utf8")), config: rc.config ?? {} };
53
+ if (recipe.config && "api_key" in recipe.config) delete recipe.config.api_key;
54
+ }
55
+ } catch (e) { console.error("recipe skipped:", e.message); }
43
56
  if (!fs.existsSync(cleanPath)) { console.error(`${cleanPath} not found. Run: node scripts/trim.mjs ${dir}`); process.exit(1); }
44
57
  if (!fs.existsSync(wirePath)) { console.error(`${wirePath} not found. Run: node scripts/manifest.mjs ${dir}`); process.exit(1); }
45
58
  const manifest = JSON.parse(fs.readFileSync(wirePath, "utf8"));
@@ -124,7 +137,7 @@ try {
124
137
  stageRes = await fetch(`${base}/api/recorder/stage`, {
125
138
  method: "PUT",
126
139
  headers: authHeaders,
127
- body: JSON.stringify({ filename: "take.zip", sizeBytes, previewSizeBytes, manifest }),
140
+ body: JSON.stringify({ filename: "take.zip", sizeBytes, previewSizeBytes, manifest, ...(recipe ? { recipe } : {}) }),
128
141
  });
129
142
  } catch (e) {
130
143
  console.error(`Could not reach ${base}: ${e.message}`);