@keepylabs/cutroom 0.5.5 → 0.5.7

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.
Files changed (2) hide show
  1. package/cutroom.mjs +32 -12
  2. package/package.json +1 -1
package/cutroom.mjs CHANGED
@@ -8,7 +8,25 @@ var __export = (target, all) => {
8
8
 
9
9
  // src/community/local/server.ts
10
10
  import { homedir as homedir3 } from "node:os";
11
- import { join as join4 } from "node:path";
11
+ import { delimiter, join as join4 } from "node:path";
12
+
13
+ // src/community/local/proc.ts
14
+ import { spawnSync } from "node:child_process";
15
+ var WIN = process.platform === "win32";
16
+ var quote = (a) => /[\s"&|<>^()%!,;=']/.test(a) ? `"${a.replace(/"/g, '\\"')}"` : a;
17
+ function run(cmd, args, opt = {}) {
18
+ const o = { encoding: "utf8", ...opt };
19
+ if (WIN && cmd === "npx") return spawnSync(["npx", ...args].map(quote).join(" "), { ...o, shell: true });
20
+ return spawnSync(cmd, args, o);
21
+ }
22
+ var has = (bin) => spawnSync(WIN ? "where" : "which", [bin], { stdio: "ignore" }).status === 0;
23
+ var installLine = (tool) => WIN ? { ffmpeg: "winget install --id Gyan.FFmpeg -e", node: "winget install --id OpenJS.NodeJS.LTS -e", "node-update": "winget upgrade --id OpenJS.NodeJS.LTS -e" }[tool] : { ffmpeg: "brew install ffmpeg", node: "brew install node", "node-update": "brew upgrade node" }[tool];
24
+ var NODE_MIN = 22;
25
+ function nodeMajor() {
26
+ const r = spawnSync("node", ["--version"], { encoding: "utf8", shell: WIN });
27
+ const m = (r.stdout ?? "").match(/v(\d+)/);
28
+ return m ? Number(m[1]) : 0;
29
+ }
12
30
 
13
31
  // node_modules/@modelcontextprotocol/server/dist/chunk-Br0eD_fh.mjs
14
32
  var __create = Object.create;
@@ -21541,10 +21559,10 @@ import { homedir as homedir2 } from "node:os";
21541
21559
  import { basename, extname, join as join3, resolve as resolve2 } from "node:path";
21542
21560
 
21543
21561
  // src/community/local/measure.ts
21544
- import { execFileSync, spawnSync } from "node:child_process";
21562
+ import { execFileSync, spawnSync as spawnSync2 } from "node:child_process";
21545
21563
  import { mkdirSync, readFileSync } from "node:fs";
21546
21564
  import { join } from "node:path";
21547
- var ffmpegErr = (args) => spawnSync("ffmpeg", ["-nostdin", "-hide_banner", ...args], { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }).stderr ?? "";
21565
+ var ffmpegErr = (args) => spawnSync2("ffmpeg", ["-nostdin", "-hide_banner", ...args], { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }).stderr ?? "";
21548
21566
  function probe(file) {
21549
21567
  const info = JSON.parse(execFileSync("ffprobe", ["-v", "error", "-print_format", "json", "-show_format", "-show_streams", file], { encoding: "utf8" }));
21550
21568
  const v = info.streams.find((s) => s.codec_type === "video");
@@ -21635,13 +21653,12 @@ function technicalChecks(file) {
21635
21653
  }
21636
21654
 
21637
21655
  // src/community/local/tools.ts
21638
- import { spawnSync as spawnSync2 } from "node:child_process";
21639
21656
  import { createWriteStream, existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
21640
21657
  import { homedir } from "node:os";
21641
21658
  import { join as join2, resolve } from "node:path";
21642
21659
  import { Readable } from "node:stream";
21643
21660
  import { pipeline } from "node:stream/promises";
21644
- var VERSION = "0.5.5";
21661
+ var VERSION = "0.5.7";
21645
21662
  var GATEWAY = () => (process.env.CUTROOM_GATEWAY || "https://keepylabs.com/api/cutroom").replace(/\/$/, "");
21646
21663
  var HOME = () => process.env.CUTROOM_HOME || join2(homedir(), "Cutroom");
21647
21664
  async function call(op, body = {}, fetchImpl = fetch) {
@@ -21663,7 +21680,6 @@ async function call(op, body = {}, fetchImpl = fetch) {
21663
21680
  if (!res.ok) throw new Error(json?.error ?? `Cutroom error (HTTP ${res.status}).`);
21664
21681
  return json;
21665
21682
  }
21666
- var has = (bin) => spawnSync2("which", [bin]).status === 0;
21667
21683
  var slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
21668
21684
  var day = () => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
21669
21685
  var fmt = (t) => `${Math.floor(t / 60)}:${(t % 60).toFixed(1).padStart(4, "0")}`;
@@ -21675,8 +21691,12 @@ async function download(url2, target) {
21675
21691
  }
21676
21692
  async function doctor() {
21677
21693
  const checks = [
21678
- { name: "ffmpeg", ok: has("ffmpeg") && has("ffprobe"), fix: "brew install ffmpeg" },
21679
- { name: "Node.js (for rendering)", ok: has("npx"), fix: "brew install node" }
21694
+ { name: "ffmpeg", ok: has("ffmpeg") && has("ffprobe"), fix: installLine("ffmpeg") },
21695
+ (() => {
21696
+ const v = has("npx") ? nodeMajor() : 0;
21697
+ if (!v) return { name: "Node.js (for rendering)", ok: false, fix: installLine("node") };
21698
+ return v >= NODE_MIN ? { name: `Node.js ${v} (for rendering)`, ok: true } : { name: `Node.js ${v} is too old (rendering needs ${NODE_MIN} or newer)`, ok: false, fix: installLine("node-update") };
21699
+ })()
21680
21700
  ];
21681
21701
  let member = null;
21682
21702
  try {
@@ -21700,7 +21720,7 @@ function beatBounds(duration3, cuts, words) {
21700
21720
  return [...out, duration3];
21701
21721
  }
21702
21722
  function localWords(file, dir) {
21703
- const r = spawnSync2("npx", ["--yes", "hyperframes@0.8.99", "transcribe", file, "--json", "-d", dir], { cwd: dir, encoding: "utf8", maxBuffer: 1 << 28 });
21723
+ const r = run("npx", ["--yes", "hyperframes@0.8.99", "transcribe", file, "--json", "-d", dir], { cwd: dir, encoding: "utf8", maxBuffer: 1 << 28 });
21704
21724
  try {
21705
21725
  const meta2 = JSON.parse(r.stdout.trim().split("\n").pop() ?? "{}");
21706
21726
  if (r.status !== 0 || !meta2.ok) return null;
@@ -21880,7 +21900,7 @@ async function creatorTeardown(input) {
21880
21900
  var HF = "hyperframes@0.8.99";
21881
21901
  var day2 = () => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
21882
21902
  var slug2 = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40) || "reel";
21883
- var sh = (cmd, args, cwd) => spawnSync3(cmd, args, { cwd, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
21903
+ var sh = (cmd, args, cwd) => run(cmd, args, { cwd, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
21884
21904
  var tail = (s) => (s ?? "").trim().split("\n").slice(-6).join("\n");
21885
21905
  var projectFile = (folder) => join3(folder, ".cutroom", "project.json");
21886
21906
  var resolveProject = (p) => {
@@ -22223,13 +22243,13 @@ async function qaVideo(input) {
22223
22243
  }
22224
22244
 
22225
22245
  // src/community/local/server.ts
22226
- process.env.PATH = [process.env.PATH, "/opt/homebrew/bin", "/usr/local/bin", join4(homedir3(), ".local", "bin")].filter(Boolean).join(":");
22246
+ process.env.PATH = (WIN ? [process.env.PATH, join4(process.env.LOCALAPPDATA ?? join4(homedir3(), "AppData", "Local"), "Microsoft", "WinGet", "Links"), "C:\\Program Files\\nodejs"] : [process.env.PATH, "/opt/homebrew/bin", "/usr/local/bin", join4(homedir3(), ".local", "bin")]).filter(Boolean).join(delimiter);
22227
22247
  var result = (value) => ({ content: [{ type: "text", text: typeof value === "string" ? value : JSON.stringify(value, null, 2) }] });
22228
22248
  var failure2 = (error2) => ({ isError: true, content: [{ type: "text", text: error2 instanceof Error ? error2.message : String(error2) }] });
22229
22249
  var safe = (op) => Promise.resolve().then(op).then(result).catch(failure2);
22230
22250
  var INSTRUCTIONS = `Cutroom: short-form video help. Speak plainly; the user is not technical. Never show tool or effect codes; use plain names.
22231
22251
 
22232
- Setup or any failure: cutroom_doctor, then a short checklist. Missing ffmpeg or Node.js: ask, then run "brew install ffmpeg" or "brew install node". Key problem: reconnect Cutroom with their key from the Cutroom key space on Whop; never ask them to paste the key into the chat.
22252
+ Setup or any failure: cutroom_doctor, then a short checklist. Missing ffmpeg or Node.js: ask, then run the fix line cutroom_doctor gives (brew on a Mac, winget on Windows). Key problem: reconnect Cutroom with their key from the Cutroom key space on Whop; never ask them to paste the key into the chat.
22233
22253
 
22234
22254
  Finish a video (a raw video of them talking: edit it, captions, effects, make it a reel): get_method('finish_video') first and follow it step by step. Nothing renders until they approve the plan.
22235
22255
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keepylabs/cutroom",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "Cutroom for Claude Code: hooks and scripts with scoring, reel breakdowns, creator teardowns, and finishing your own videos with QA. Needs a Keepy Labs membership key.",
5
5
  "type": "module",
6
6
  "bin": {