demobite 1.10.0 → 1.11.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/launcher/index.mjs +48 -6
- package/package.json +1 -1
package/launcher/index.mjs
CHANGED
|
@@ -210,6 +210,19 @@ if (arg === "listen") {
|
|
|
210
210
|
}
|
|
211
211
|
const name = (argvRest[argvRest.indexOf("--name") + 1] && argvRest.includes("--name")) ? argvRest[argvRest.indexOf("--name") + 1] : os.hostname().replace(/\.local$/, "");
|
|
212
212
|
const agentBin = (() => { const r = spawnSync(process.platform === "win32" ? "where" : "which", ["claude"], { encoding: "utf8" }); return r.status === 0 ? r.stdout.trim().split("\n")[0] : null; })();
|
|
213
|
+
// What the agent is (version) and how it is set (the person's model and
|
|
214
|
+
// effort in ~/.claude/settings.json) — the rail shows it, the chat agent can
|
|
215
|
+
// speak to it. The model that FILMS is ours (JOB_MODEL), passed per job: the
|
|
216
|
+
// output quality is DemoBites' to defend, never a hidden knob on the machine.
|
|
217
|
+
const JOB_MODEL = process.env.DEMOBITES_JOB_MODEL || "sonnet";
|
|
218
|
+
const agentInfo = (() => {
|
|
219
|
+
if (!agentBin) return { agent: null, agent_version: null, model: null, effort: null, job_model: null };
|
|
220
|
+
const v = spawnSync(agentBin, ["--version"], { encoding: "utf8", timeout: 8000 });
|
|
221
|
+
const version = v.status === 0 ? (v.stdout.trim().match(/\d+\.\d+(?:\.\d+)?/) || [null])[0] : null;
|
|
222
|
+
let settings = {};
|
|
223
|
+
try { settings = JSON.parse(fs.readFileSync(path.join(os.homedir(), ".claude", "settings.json"), "utf8")); } catch { /* defaults */ }
|
|
224
|
+
return { agent: "Claude Code", agent_version: version, model: typeof settings.model === "string" ? settings.model : null, effort: typeof settings.effortLevel === "string" ? settings.effortLevel : (typeof settings.effort === "string" ? settings.effort : null), job_model: JOB_MODEL };
|
|
225
|
+
})();
|
|
213
226
|
// The repo this listener was started in (the Code signal on the rail): the
|
|
214
227
|
// git remote's owner/name, or null when the folder is not a repo.
|
|
215
228
|
const repo = (() => {
|
|
@@ -221,7 +234,7 @@ if (arg === "listen") {
|
|
|
221
234
|
const readiness = () => {
|
|
222
235
|
let signins = [];
|
|
223
236
|
try { signins = Object.keys(JSON.parse(fs.readFileSync(path.join(process.cwd(), ".recorder", "signins.json"), "utf8")).origins || {}); } catch { /* none */ }
|
|
224
|
-
return {
|
|
237
|
+
return { ...agentInfo, chrome: haveChrome, recorder: pkg.version, signins, cwd: process.cwd(), platform: process.platform, repo };
|
|
225
238
|
};
|
|
226
239
|
const api = async (body) => {
|
|
227
240
|
try {
|
|
@@ -234,11 +247,39 @@ if (arg === "listen") {
|
|
|
234
247
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
235
248
|
|
|
236
249
|
console.log(`\n Listening as "${name}" for ${cfg.workspace?.name ?? "your workspace"} on ${base.replace(/^https?:\/\//, "")}.`);
|
|
237
|
-
console.log(` Ask for a demo in the app (Create → Agentic Capture). ${agentBin ?
|
|
238
|
-
|
|
250
|
+
console.log(` Ask for a demo in the app (Create → Agentic Capture). ${agentBin ? `Claude Code${agentInfo.agent_version ? " " + agentInfo.agent_version : ""} found; demos film on ${JOB_MODEL} unless you pick another model in the app.` : "! Claude Code was not found on this machine — install it and sign in, it does the thinking."}`);
|
|
251
|
+
// The one thing the person must know, boxed (founder 2026-10-15): this
|
|
252
|
+
// window is the machine's side of every recording.
|
|
253
|
+
console.log(`
|
|
254
|
+
┌──────────────────────────────────────────────────────────┐
|
|
255
|
+
│ │
|
|
256
|
+
│ LEAVE THIS WINDOW OPEN │
|
|
257
|
+
│ │
|
|
258
|
+
│ It is your machine's side of every recording: │
|
|
259
|
+
│ the camera, the sign-ins, the coding agent run here. │
|
|
260
|
+
│ Closing it, or Ctrl-C, stops the listening. │
|
|
261
|
+
│ │
|
|
262
|
+
└──────────────────────────────────────────────────────────┘
|
|
263
|
+
`);
|
|
264
|
+
// A line that visibly lives (founder: "look at the terminal, it's stuck"):
|
|
265
|
+
// a heartbeat with a clock while we wait, cleared while a job prints.
|
|
266
|
+
const startedAt = Date.now();
|
|
267
|
+
const tty = !!process.stdout.isTTY;
|
|
268
|
+
let ticker = null;
|
|
269
|
+
const tick = () => {
|
|
270
|
+
const s = Math.floor((Date.now() - startedAt) / 1000);
|
|
271
|
+
const clock = `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
|
|
272
|
+
const dot = s % 2 ? "●" : "○";
|
|
273
|
+
process.stdout.write(`\r\x1b[2K ${dot} Listening · ${clock} · waiting for a demo from the app`);
|
|
274
|
+
};
|
|
275
|
+
const waitOn = () => { if (tty && !ticker) { tick(); ticker = setInterval(tick, 1000); } };
|
|
276
|
+
const waitOff = () => { if (ticker) { clearInterval(ticker); ticker = null; process.stdout.write("\r\x1b[2K"); } };
|
|
277
|
+
waitOn();
|
|
239
278
|
|
|
240
279
|
const runJob = async (job) => {
|
|
241
|
-
|
|
280
|
+
waitOff();
|
|
281
|
+
const model = typeof job.model === "string" && job.model ? job.model : JOB_MODEL;
|
|
282
|
+
console.log(`\n ▶ Job ${job.id}: ${job.brief.slice(0, 100)}${job.brief.length > 100 ? "…" : ""} (filming on ${model})`);
|
|
242
283
|
if (!agentBin) { await event(job.id, "failed", { message: "Claude Code is not installed on this machine" }); return; }
|
|
243
284
|
await event(job.id, "started", { machine: name });
|
|
244
285
|
const prompt = [
|
|
@@ -247,7 +288,7 @@ if (arg === "listen") {
|
|
|
247
288
|
job.url ? `Address to start from: ${job.url}` : "Address: work it out from this project (the saved config, the codebase).",
|
|
248
289
|
`Show the storyboard before filming: ${job.review_storyboard ? "yes — run storyboard.mjs await and obey its answer" : "no — storyboard.mjs await returns film at once"}.`,
|
|
249
290
|
].join("\n");
|
|
250
|
-
const child = (await import("node:child_process")).spawn(agentBin, ["-p", prompt, "--output-format", "stream-json", "--verbose", "--dangerously-skip-permissions"], {
|
|
291
|
+
const child = (await import("node:child_process")).spawn(agentBin, ["-p", prompt, "--model", model, "--output-format", "stream-json", "--verbose", "--dangerously-skip-permissions"], {
|
|
251
292
|
cwd: process.cwd(),
|
|
252
293
|
env: { ...process.env, RECORDER_JOB: job.id, RECORDER_BASE: base, RECORDER_LISTEN: "1" },
|
|
253
294
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -276,7 +317,8 @@ if (arg === "listen") {
|
|
|
276
317
|
if (code === 0) await event(job.id, "note", { text: "The agent finished without a ready signal." });
|
|
277
318
|
await event(job.id, "failed", { message: code === 0 ? "The demo did not come through — try again" : `The agent stopped (exit ${code})` });
|
|
278
319
|
}
|
|
279
|
-
console.log(` ■ Job ${job.id} ${st?.status ?? "ended"}
|
|
320
|
+
console.log(` ■ Job ${job.id} ${st?.status ?? "ended"}.\n`);
|
|
321
|
+
waitOn();
|
|
280
322
|
};
|
|
281
323
|
|
|
282
324
|
for (;;) {
|
package/package.json
CHANGED