storyforge 0.4.9 → 0.4.11

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.
@@ -8,7 +8,7 @@ import { spawn, spawnSync } from "child_process";
8
8
  import * as crypto from "crypto";
9
9
  var HEARTBEAT_INTERVAL_MS = 3e4;
10
10
  var POLL_INTERVAL_MS = 3e3;
11
- var CLI_TIMEOUT_MS = 5 * 60 * 1e3;
11
+ var CLI_TIMEOUT_MS = Number(process.env.SCRIPT_GEN_TIMEOUT_MS) || 20 * 60 * 1e3;
12
12
  var BridgePoller = class {
13
13
  baseUrl;
14
14
  token;
package/dist/index.js CHANGED
@@ -17,6 +17,12 @@ import * as path from "path";
17
17
  import * as os from "os";
18
18
  var FORGE_DIR = path.join(os.homedir(), ".forge");
19
19
  var CREDS_PATH = path.join(FORGE_DIR, "credentials.json");
20
+ var FORGE_ENV_PATHS = [
21
+ path.join(FORGE_DIR, ".env"),
22
+ // ~/.forge/.env
23
+ path.join(os.homedir(), ".forge.env")
24
+ // ~/.forge.env (legacy short form)
25
+ ];
20
26
  function getForgeDir() {
21
27
  fs.mkdirSync(FORGE_DIR, { recursive: true });
22
28
  return FORGE_DIR;
@@ -32,6 +38,35 @@ function loadCredentials() {
32
38
  return null;
33
39
  }
34
40
  }
41
+ function loadDotEnv() {
42
+ const loaded = [];
43
+ const sources = [];
44
+ const candidates = [path.resolve(process.cwd(), ".env"), ...FORGE_ENV_PATHS];
45
+ for (const file of candidates) {
46
+ let content;
47
+ try {
48
+ content = fs.readFileSync(file, "utf-8");
49
+ } catch {
50
+ continue;
51
+ }
52
+ sources.push(file);
53
+ for (const rawLine of content.split(/\r?\n/)) {
54
+ const line = rawLine.trim();
55
+ if (!line || line.startsWith("#")) continue;
56
+ const eq = line.indexOf("=");
57
+ if (eq < 0) continue;
58
+ const key = line.slice(0, eq).trim();
59
+ let val = line.slice(eq + 1).trim();
60
+ if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
61
+ val = val.slice(1, -1);
62
+ }
63
+ if (!key || process.env[key] != null) continue;
64
+ process.env[key] = val;
65
+ loaded.push(key);
66
+ }
67
+ }
68
+ return { loaded, sources };
69
+ }
35
70
 
36
71
  // src/utils/script-prompt.ts
37
72
  var STYLE_GUIDES = {
@@ -512,7 +547,7 @@ var exec = promisify(execCb);
512
547
  var PORT = 4444;
513
548
  function runCliPipingStdin(cmd, args, stdinData, opts = {}) {
514
549
  const maxBytes = (opts.maxBufferMB ?? 16) * 1024 * 1024;
515
- return new Promise((resolve2, reject) => {
550
+ return new Promise((resolve3, reject) => {
516
551
  const proc = spawn(cmd, args, { stdio: ["pipe", "pipe", "pipe"] });
517
552
  let stdout = "";
518
553
  let stderr = "";
@@ -545,7 +580,7 @@ function runCliPipingStdin(cmd, args, stdinData, opts = {}) {
545
580
  });
546
581
  proc.on("close", (code) => {
547
582
  if (timer) clearTimeout(timer);
548
- resolve2({ stdout, stderr, code });
583
+ resolve3({ stdout, stderr, code });
549
584
  });
550
585
  proc.stdin.end(stdinData);
551
586
  });
@@ -796,10 +831,14 @@ function openBrowser(url) {
796
831
  });
797
832
  }
798
833
  async function devCommand(options) {
834
+ const env = loadDotEnv();
799
835
  const port = parseInt(options.port || String(PORT), 10);
800
836
  const dir = path2.resolve(options.dir || process.cwd());
801
837
  console.log("");
802
838
  log.info(`Forge \u2014 ${dir}`);
839
+ if (env.loaded.length > 0) {
840
+ log.info(`Loaded env: ${env.loaded.join(", ")} from ${env.sources.join(", ")}`);
841
+ }
803
842
  const counts = scanAssets(dir);
804
843
  const total = Object.values(counts).reduce((a, b) => a + b, 0);
805
844
  if (total > 0) {
@@ -1027,8 +1066,9 @@ async function devCommand(options) {
1027
1066
  try {
1028
1067
  log.info(`[script-gen] Generating via ${cli} CLI \xB7 model=${model}`);
1029
1068
  const args = cli === "codex" ? ["exec", "-", "--model", model] : ["-p", "--model", model, "--no-session-persistence"];
1069
+ const timeoutMs = Number(process.env.SCRIPT_GEN_TIMEOUT_MS) || 12e5;
1030
1070
  const { stdout, code, stderr } = await runCliPipingStdin(cli, args, prompt2, {
1031
- timeoutMs: 3e5,
1071
+ timeoutMs,
1032
1072
  maxBufferMB: 16
1033
1073
  });
1034
1074
  if (code !== 0) {
@@ -1423,9 +1463,9 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
1423
1463
  }
1424
1464
  const boundary = boundaryM[1];
1425
1465
  const chunks = [];
1426
- await new Promise((resolve2, reject) => {
1466
+ await new Promise((resolve3, reject) => {
1427
1467
  req.on("data", (c) => chunks.push(Buffer.from(c)));
1428
- req.on("end", resolve2);
1468
+ req.on("end", resolve3);
1429
1469
  req.on("error", reject);
1430
1470
  });
1431
1471
  const body = Buffer.concat(chunks);
@@ -1537,7 +1577,7 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
1537
1577
  return "0.0.0";
1538
1578
  })();
1539
1579
  void (async () => {
1540
- const { BridgePoller } = await import("./bridge-poller-5FFV2LML.js");
1580
+ const { BridgePoller } = await import("./bridge-poller-IRROEZID.js");
1541
1581
  const poller = new BridgePoller({ baseUrl: bridgeUrl, token: bridgeToken, clientVersion: `storyforge ${pkgVersion}` });
1542
1582
  poller.start();
1543
1583
  })();
@@ -1545,7 +1585,12 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
1545
1585
  console.log(` Bridge tunnel \u2192 ${bridgeUrl}/api/cli-bridge/* (outbound polling)`);
1546
1586
  } else {
1547
1587
  console.log("");
1548
- console.log(" Bridge tunnel disabled \u2014 set FORGE_BRIDGE_TOKEN to expose your CLI seats to forge.algo-thinker.com");
1588
+ console.log(" Bridge tunnel disabled \u2014 set FORGE_BRIDGE_TOKEN to expose your CLI seats.");
1589
+ console.log(" Vercel env vars do NOT reach this laptop. Pick ONE of these:");
1590
+ console.log(" a) export FORGE_BRIDGE_TOKEN=xxx in your shell, then re-run storyforge");
1591
+ console.log(" b) drop FORGE_BRIDGE_TOKEN=xxx into ./.env (cwd) or ~/.forge/.env");
1592
+ console.log(" c) one-shot: FORGE_BRIDGE_TOKEN=xxx npx storyforge");
1593
+ console.log(` Use the SAME token value you set on Vercel as FORGE_BRIDGE_TOKEN.`);
1549
1594
  }
1550
1595
  console.log("");
1551
1596
  console.log(" Ctrl+C to stop");
@@ -1557,10 +1602,10 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
1557
1602
  import * as readline from "readline";
1558
1603
  function prompt(question) {
1559
1604
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1560
- return new Promise((resolve2) => {
1605
+ return new Promise((resolve3) => {
1561
1606
  rl.question(question, (answer) => {
1562
1607
  rl.close();
1563
- resolve2(answer.trim());
1608
+ resolve3(answer.trim());
1564
1609
  });
1565
1610
  });
1566
1611
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyforge",
3
- "version": "0.4.9",
3
+ "version": "0.4.11",
4
4
  "description": "StoryForge — local bridge for the Forge video production web app. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "bin": {