demobites 1.35.0 → 1.37.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.
package/package.json
CHANGED
|
@@ -345,6 +345,10 @@ const wire = {
|
|
|
345
345
|
app: man.app ?? "App",
|
|
346
346
|
title: titleArg ?? man.title ?? `${man.app ?? "App"} demo`,
|
|
347
347
|
frame: { width: FW, height: FH },
|
|
348
|
+
// THE FILE IS ALREADY THE CANVAS (2026-10-18: the build re-encoded every take for 22 s). trim.mjs writes exactly
|
|
349
|
+
// what the ingest's transcode would produce — 1920x1080, 30 fps, h264 yuv420p, no audio, moov first — so the
|
|
350
|
+
// manifest says so and the ingest stream-copies it (its probe still checks; a file that deviates is encoded as ever).
|
|
351
|
+
...(FW === 1920 && FH === 1080 ? { normalized: { width: 1920, height: 1080, fps: 30 } } : {}),
|
|
348
352
|
// BROWSER HEADER (2026-09-16): true by default; DemoBites adds the dark macOS bar on top at ingest. A workspace rule "No browser header" sets it false.
|
|
349
353
|
...(typeof man.browserHeader === "boolean" ? { browserHeader: man.browserHeader } : {}),
|
|
350
354
|
// APPROVED STORY (founder 2026-10-15, bite 1228: "the storyteller is blabbing"): the lines came from the
|
package/skill/scripts/plan.mjs
CHANGED
|
@@ -136,7 +136,9 @@ const explore = (from, lookingFor, depth) => {
|
|
|
136
136
|
fs.mkdirSync(exDir, { recursive: true });
|
|
137
137
|
const child = spawnSync("node", [script("explore.mjs"), from, "--for", words, "--depth", String(Math.min(3, Math.max(1, Number(depth) || 2))), "--out", exDir], { cwd: process.cwd(), encoding: "utf8", env: process.env, maxBuffer: 64 * 1024 * 1024 });
|
|
138
138
|
const lines = (child.stdout || "").split("\n");
|
|
139
|
-
|
|
139
|
+
// THE PERSON HEARS PHASES, NOT FINDINGS (founder 2026-10-18: "Nothing beyond the start page matched… you need to
|
|
140
|
+
// control what you're showing to the user"): the exploration's lines stay in the log.
|
|
141
|
+
for (const l of lines) if (l.startsWith("· ")) console.log(l);
|
|
140
142
|
const last = lines.filter((l) => l.startsWith("RESULT ")).pop();
|
|
141
143
|
let res = null; try { res = JSON.parse(last.slice(7)); } catch { /* none */ }
|
|
142
144
|
if (!res) return [{ type: "text", text: `Exploring failed: ${(child.stderr || "").trim().split("\n").pop() || "no result"}` }];
|
|
@@ -241,13 +243,17 @@ let probes = 0;
|
|
|
241
243
|
let firstProbeAt = 0;
|
|
242
244
|
let asked = 0;
|
|
243
245
|
const capped = () => probes >= CAP_PROBES || (firstProbeAt && Date.now() - firstProbeAt > CAP_MS);
|
|
244
|
-
const CAP_TEXT = () => asked <
|
|
246
|
+
const CAP_TEXT = () => asked < 1
|
|
245
247
|
? `STOP (${probes} dry run${probes === 1 ? "" : "s"}, ${Math.round((Date.now() - (firstProbeAt || Date.now())) / 1000)} s since the first). No more dry runs, no more reading. Call ask_person NOW with ONE short question in plain words: what you were looking for, where you looked, and how they want to play it (where it is, or what to show instead). The person is there and knows the app. Their answer comes back as the result; then fix the storyboard from their words, probe once, and hand it in.`
|
|
246
248
|
: `STOP. Hand in the storyboard NOW with submit_storyboard: keep every step that passed; a step that failed becomes a hover or a settle on the nearest element the page does have, or goes; name in \`unsure\` what you could not find.`;
|
|
247
249
|
/** The question goes to the chat; the planner waits here for the person's word (up to 30 minutes). */
|
|
248
250
|
const askPerson = async (text) => {
|
|
249
251
|
const q = String(text || "").trim().slice(0, 600);
|
|
250
252
|
if (!q) return "ask_person needs a question.";
|
|
253
|
+
// ONE QUESTION, EVER (founder 2026-10-18: "at most one clarification… then go"; a second question three seconds
|
|
254
|
+
// after one dry run left him stuck): once answered, the planner works with what it has and hands in the
|
|
255
|
+
// storyboard, naming what it could not find in `unsure`. The person fixes it from the storyboard, not from a loop.
|
|
256
|
+
if (asked >= 1) return "You asked once and they answered. No more questions: hand in the storyboard NOW with submit_storyboard — keep every step that passed, turn a step you could not place into a hover or a settle on the nearest element the page has, and name what you could not find in `unsure`.";
|
|
251
257
|
say("Asking you in the chat…");
|
|
252
258
|
if (!listening) return "(no chat here: decide yourself and hand in the storyboard)";
|
|
253
259
|
await postEvent("question", { text: q });
|
|
@@ -273,7 +279,7 @@ const plan = async () => {
|
|
|
273
279
|
const res = await relay(messages);
|
|
274
280
|
const content = Array.isArray(res.content) ? res.content : [];
|
|
275
281
|
messages.push({ role: "assistant", content });
|
|
276
|
-
for (const b of content) if (b.type === "text" && b.text?.trim())
|
|
282
|
+
for (const b of content) if (b.type === "text" && b.text?.trim()) console.log(`· ${b.text.trim().split("\n")[0].replace(/^[#*\-\s]+/, "").slice(0, 140)}`);
|
|
277
283
|
const uses = content.filter((b) => b.type === "tool_use");
|
|
278
284
|
if (!uses.length) {
|
|
279
285
|
if (storyboard) return;
|