scenri 0.3.0 → 0.3.2
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/CHANGELOG.md +16 -0
- package/README.md +6 -2
- package/dist/chunk-WGIZJXNE.js +36 -0
- package/dist/index.js +43 -33
- package/dist/serve.js +52 -4
- package/package.json +1 -1
- package/studio-dist/assets/{index-BaASA7BS.js → index-BGiMfD5T.js} +1 -1
- package/studio-dist/index.html +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.2](https://github.com/tonygorb/scenri/compare/v0.3.1...v0.3.2) (2026-08-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* suggest sudo and drop stale errors in the codex setup dialog ([da88610](https://github.com/tonygorb/scenri/commit/da886109666e9613b954a6f3d6c8299de0fdf944))
|
|
9
|
+
* suggest sudo and drop stale errors in the codex setup dialog ([1283f3c](https://github.com/tonygorb/scenri/commit/1283f3c5f93a3204bff6ba9e33ebc670b6004034))
|
|
10
|
+
|
|
11
|
+
## [0.3.1](https://github.com/tonygorb/scenri/compare/v0.3.0...v0.3.1) (2026-08-20)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* calm boot failures and stop the silent hang on a busy port ([d04946f](https://github.com/tonygorb/scenri/commit/d04946f011b204c230473f5338f0a32f8870a1d0))
|
|
17
|
+
* friendly first-run errors and the install guide ([b1782ad](https://github.com/tonygorb/scenri/commit/b1782adb4fc48807e384a208ee8894022d62d615))
|
|
18
|
+
|
|
3
19
|
## [0.3.0](https://github.com/tonygorb/scenri/compare/v0.2.3...v0.3.0) (2026-08-20)
|
|
4
20
|
|
|
5
21
|
|
package/README.md
CHANGED
|
@@ -19,6 +19,8 @@ Define a client's brand once. Then generate, branch, and art-direct on-brand ima
|
|
|
19
19
|
npx scenri
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
<sub>Needs [Node.js](https://nodejs.org) 22 or newer. New to any of this? The [install guide](docs/INSTALL.md) walks through every step.</sub>
|
|
23
|
+
|
|
22
24
|
<img src="https://raw.githubusercontent.com/tonygorb/scenri/main/docs/media/demo.gif" alt="The Scenri composer: a dollar sign opens a product picker and Selvedge Trucker is chosen, an at sign picks the presenter Maren, a slash picks the Editorial Walk scene, a line of written direction is typed after the three chips, the shot renders as a card in the wall, and it opens to show the picture beside the brief that made it" width="820">
|
|
23
25
|
|
|
24
26
|
<sub>Pick a product, pick a presenter, pick a scene, then write the direction. That is the brief.</sub>
|
|
@@ -55,15 +57,17 @@ The brand kit sits one gesture away in Settings and is the part that keeps outpu
|
|
|
55
57
|
|
|
56
58
|
## Run it
|
|
57
59
|
|
|
60
|
+
Scenri runs on [Node.js](https://nodejs.org), version 22 or newer. If you are not sure you have it, or terminals are not part of your day, the **[install guide](docs/INSTALL.md)** covers every step for macOS, Windows and Linux. With Node in place:
|
|
61
|
+
|
|
58
62
|
```bash
|
|
59
63
|
npx scenri
|
|
60
64
|
```
|
|
61
65
|
|
|
62
|
-
That is the whole install.
|
|
66
|
+
That is the whole install. npm asks once whether to proceed, downloads the current release, and opens `http://127.0.0.1:4747`. Keep the terminal window open while you work; closing it stops Scenri. Tomorrow the same command opens it again, with everything where you left it.
|
|
63
67
|
|
|
64
68
|
Generation runs on **Codex CLI**, an official helper from OpenAI that draws on your own ChatGPT plan. No API key to paste, and Scenri never charges you. Each image draws on your plan's Codex usage. You do not have to set it up by hand: if it is missing, Scenri offers to install it and to sign you in, both from the app. No ChatGPT plan? Add your own key from an image provider in Settings instead, see [Engines](#engines).
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
Two dependencies (`better-sqlite3` and `sharp`) ship native binaries, so on recent npm you may be asked to approve their install scripts once. Something not starting? See [troubleshooting](docs/INSTALL.md#troubleshooting).
|
|
67
71
|
|
|
68
72
|
<details>
|
|
69
73
|
<summary>Run from source</summary>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/bootError.ts
|
|
2
|
+
var INSTALL_GUIDE = "https://github.com/tonygorb/scenri/blob/main/docs/INSTALL.md";
|
|
3
|
+
var NATIVE_MARKERS = ["NODE_MODULE_VERSION", "Could not locate the bindings file", "ERR_DLOPEN_FAILED"];
|
|
4
|
+
function portBusyLines(port) {
|
|
5
|
+
const next = port + 1;
|
|
6
|
+
return [
|
|
7
|
+
`Port ${port} is in use by another app.`,
|
|
8
|
+
"Start Scenri on a different port:",
|
|
9
|
+
` macOS or Linux: SCENRI_PORT=${next} npx scenri`,
|
|
10
|
+
` Windows PowerShell: $env:SCENRI_PORT=${next}; npx scenri`
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
function bootErrorLines(err) {
|
|
14
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
15
|
+
const first = raw.split("\n")[0];
|
|
16
|
+
const code = err?.code;
|
|
17
|
+
const haystack = `${typeof code === "string" ? code : ""} ${raw}`;
|
|
18
|
+
if (NATIVE_MARKERS.some((marker) => haystack.includes(marker))) {
|
|
19
|
+
return [
|
|
20
|
+
"Scenri could not start: a native component failed to load.",
|
|
21
|
+
`(${first})`,
|
|
22
|
+
"This usually means Node changed since this copy of Scenri was installed.",
|
|
23
|
+
"Fix: install the current Node LTS from https://nodejs.org, then run npx scenri@latest."
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
return [
|
|
27
|
+
`Scenri could not start: ${first}`,
|
|
28
|
+
"If this keeps happening, run npx scenri@latest, or see the install guide:",
|
|
29
|
+
INSTALL_GUIDE,
|
|
30
|
+
"Set SCENRI_DEBUG=1 to see the full error."
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { bootErrorLines, portBusyLines };
|
|
35
|
+
//# sourceMappingURL=chunk-WGIZJXNE.js.map
|
|
36
|
+
//# sourceMappingURL=chunk-WGIZJXNE.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { bootErrorLines } from './chunk-WGIZJXNE.js';
|
|
3
|
+
|
|
2
4
|
// src/args.ts
|
|
3
5
|
function parseArgs(argv) {
|
|
4
6
|
const [first, ...rest] = argv;
|
|
@@ -41,43 +43,51 @@ SCENRI_CONTENT_URL.
|
|
|
41
43
|
|
|
42
44
|
// src/index.ts
|
|
43
45
|
var command = parseArgs(process.argv.slice(2));
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
break;
|
|
63
|
-
case "update": {
|
|
64
|
-
const { runUpdateCommand } = await import('./cli-GQLRYYGU.js');
|
|
65
|
-
process.exit(await runUpdateCommand(command));
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
case "launch": {
|
|
69
|
-
const ownEntry = process.argv[1] ?? "";
|
|
70
|
-
if (!/[\\/]dist[\\/]/.test(ownEntry)) {
|
|
46
|
+
try {
|
|
47
|
+
switch (command.cmd) {
|
|
48
|
+
case "version": {
|
|
49
|
+
const { readMeta } = await import('./meta-MPQPBPBK.js');
|
|
50
|
+
console.log(readMeta().version);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case "help":
|
|
54
|
+
console.log(helpText());
|
|
55
|
+
break;
|
|
56
|
+
case "error":
|
|
57
|
+
console.error(command.message);
|
|
58
|
+
process.exit(2);
|
|
59
|
+
break;
|
|
60
|
+
case "verify":
|
|
61
|
+
await (await import('./serve.js')).verify();
|
|
62
|
+
break;
|
|
63
|
+
case "serve":
|
|
71
64
|
await (await import('./serve.js')).serve();
|
|
72
65
|
break;
|
|
66
|
+
case "update": {
|
|
67
|
+
const { runUpdateCommand } = await import('./cli-GQLRYYGU.js');
|
|
68
|
+
process.exit(await runUpdateCommand(command));
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case "launch": {
|
|
72
|
+
const ownEntry = process.argv[1] ?? "";
|
|
73
|
+
if (!/[\\/]dist[\\/]/.test(ownEntry)) {
|
|
74
|
+
await (await import('./serve.js')).serve();
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
const { runLauncher } = await import('./launcher-RETYUGSR.js');
|
|
78
|
+
const { readMeta } = await import('./meta-MPQPBPBK.js');
|
|
79
|
+
const { defaultHome } = await import('./versionsDir-ILQ4CI7B.js');
|
|
80
|
+
const meta = readMeta();
|
|
81
|
+
process.exit(await runLauncher({ home: defaultHome(), pkg: meta.name, ownVersion: meta.version, ownEntry }));
|
|
82
|
+
break;
|
|
73
83
|
}
|
|
74
|
-
const { runLauncher } = await import('./launcher-RETYUGSR.js');
|
|
75
|
-
const { readMeta } = await import('./meta-MPQPBPBK.js');
|
|
76
|
-
const { defaultHome } = await import('./versionsDir-ILQ4CI7B.js');
|
|
77
|
-
const meta = readMeta();
|
|
78
|
-
process.exit(await runLauncher({ home: defaultHome(), pkg: meta.name, ownVersion: meta.version, ownEntry }));
|
|
79
|
-
break;
|
|
80
84
|
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
if (process.env.SCENRI_DEBUG === "1") throw err;
|
|
87
|
+
console.error("");
|
|
88
|
+
for (const line of bootErrorLines(err)) console.error(` ${line}`);
|
|
89
|
+
console.error("");
|
|
90
|
+
process.exit(1);
|
|
81
91
|
}
|
|
82
92
|
//# sourceMappingURL=index.js.map
|
|
83
93
|
//# sourceMappingURL=index.js.map
|
package/dist/serve.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { portBusyLines } from './chunk-WGIZJXNE.js';
|
|
1
2
|
import { createUpdateChecker, classify, stageVersion, findNpm } from './chunk-GA7P7K2M.js';
|
|
2
3
|
import { readMeta, repoSlug } from './chunk-Y3ZPBPLP.js';
|
|
3
4
|
import { newestStaged, compareSemver } from './chunk-4MAFHYAD.js';
|
|
@@ -2096,6 +2097,7 @@ function pick(v, allowed, max) {
|
|
|
2096
2097
|
}
|
|
2097
2098
|
var INSTALL_COMMAND = "npm install -g @openai/codex";
|
|
2098
2099
|
var INSTALL_DOCS_URL = "https://developers.openai.com/codex/cli";
|
|
2100
|
+
var INSTALL_COMMAND_SUDO = "sudo npm install -g @openai/codex";
|
|
2099
2101
|
var DEFAULT_INSTALL_TIMEOUT_MS = 18e4;
|
|
2100
2102
|
function stateFrom(avail) {
|
|
2101
2103
|
if (avail.ok) return "ready";
|
|
@@ -2154,6 +2156,14 @@ function createCodexSetup(opts = {}) {
|
|
|
2154
2156
|
}
|
|
2155
2157
|
return { ok: true };
|
|
2156
2158
|
}
|
|
2159
|
+
if (process.platform !== "win32" && /EACCES|permission denied/i.test(res.stderr)) {
|
|
2160
|
+
return {
|
|
2161
|
+
ok: false,
|
|
2162
|
+
fallbackCommand: INSTALL_COMMAND_SUDO,
|
|
2163
|
+
docsUrl: INSTALL_DOCS_URL,
|
|
2164
|
+
detail: "npm needs your password to install into its system folder. Run the command below and type your password when asked; it stays invisible while you type."
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2157
2167
|
const detail = (res.spawnError ?? res.stderr).trim().slice(0, 400) || void 0;
|
|
2158
2168
|
return { ok: false, fallbackCommand: INSTALL_COMMAND, docsUrl: INSTALL_DOCS_URL, detail };
|
|
2159
2169
|
},
|
|
@@ -6514,6 +6524,26 @@ function registerImageRoutes(app, deps) {
|
|
|
6514
6524
|
|
|
6515
6525
|
// src/release/notes.data.ts
|
|
6516
6526
|
var RELEASES = [
|
|
6527
|
+
{
|
|
6528
|
+
version: "0.3.2",
|
|
6529
|
+
date: "2026-08-20",
|
|
6530
|
+
sections: [
|
|
6531
|
+
{
|
|
6532
|
+
heading: "Fixes",
|
|
6533
|
+
body: "When your computer refuses the Codex CLI install, setup now offers the command that gets past it instead of repeating the one that just failed. And once a step has succeeded, an old error clears instead of lingering under the green check."
|
|
6534
|
+
}
|
|
6535
|
+
]
|
|
6536
|
+
},
|
|
6537
|
+
{
|
|
6538
|
+
version: "0.3.1",
|
|
6539
|
+
date: "2026-08-20",
|
|
6540
|
+
sections: [
|
|
6541
|
+
{
|
|
6542
|
+
heading: "Fixes",
|
|
6543
|
+
body: "Starting Scenri is calmer when something is wrong. A busy port or a failed start now explains itself in plain words instead of a stack trace, and the terminal says to keep its window open while Scenri runs."
|
|
6544
|
+
}
|
|
6545
|
+
]
|
|
6546
|
+
},
|
|
6517
6547
|
{
|
|
6518
6548
|
version: "0.3.0",
|
|
6519
6549
|
date: "2026-08-20",
|
|
@@ -7515,7 +7545,9 @@ async function run() {
|
|
|
7515
7545
|
continue;
|
|
7516
7546
|
}
|
|
7517
7547
|
try {
|
|
7518
|
-
const res = await fetch(`http://127.0.0.1:${PORT}/api/version
|
|
7548
|
+
const res = await fetch(`http://127.0.0.1:${PORT}/api/version`, {
|
|
7549
|
+
signal: AbortSignal.timeout(2e3)
|
|
7550
|
+
});
|
|
7519
7551
|
const info = await res.json();
|
|
7520
7552
|
if (info.name === readMeta().name) {
|
|
7521
7553
|
const url = `http://127.0.0.1:${PORT}`;
|
|
@@ -7533,6 +7565,10 @@ async function run() {
|
|
|
7533
7565
|
}
|
|
7534
7566
|
} catch {
|
|
7535
7567
|
}
|
|
7568
|
+
console.error("");
|
|
7569
|
+
for (const line of portBusyLines(PORT)) console.error(` ${line}`);
|
|
7570
|
+
console.error("");
|
|
7571
|
+
process.exit(1);
|
|
7536
7572
|
}
|
|
7537
7573
|
throw err;
|
|
7538
7574
|
}
|
|
@@ -7555,8 +7591,8 @@ async function run() {
|
|
|
7555
7591
|
console.log(`
|
|
7556
7592
|
Scenri Studio \u2192 ${localUrl}`);
|
|
7557
7593
|
for (const ip of reachableAt) console.log(` on your network \u2192 http://${ip}:${PORT}${query}`);
|
|
7558
|
-
console.log(` data dir \u2192 ${core.home}
|
|
7559
|
-
|
|
7594
|
+
console.log(` data dir \u2192 ${core.home}`);
|
|
7595
|
+
console.log(" Keep this window open while Scenri is running.\n");
|
|
7560
7596
|
if (!studioDist) console.log(" (studio UI not built, API only. Run: pnpm build)\n");
|
|
7561
7597
|
if (token) {
|
|
7562
7598
|
console.log(" Warning: the studio is reachable from your network.");
|
|
@@ -7566,10 +7602,22 @@ async function run() {
|
|
|
7566
7602
|
console.log(" For this machine only, unset SCENRI_HOST.\n");
|
|
7567
7603
|
}
|
|
7568
7604
|
if (process.env.SCENRI_NO_OPEN !== "1") {
|
|
7605
|
+
let told = false;
|
|
7606
|
+
const tellUrl = () => {
|
|
7607
|
+
if (told) return;
|
|
7608
|
+
told = true;
|
|
7609
|
+
console.log(` Open ${localUrl} in your browser.
|
|
7610
|
+
`);
|
|
7611
|
+
};
|
|
7569
7612
|
try {
|
|
7570
7613
|
const { default: open } = await import('open');
|
|
7571
|
-
await open(localUrl);
|
|
7614
|
+
const child = await open(localUrl);
|
|
7615
|
+
child.once("error", tellUrl);
|
|
7616
|
+
child.once("exit", (openExit) => {
|
|
7617
|
+
if (openExit !== null && openExit !== 0) tellUrl();
|
|
7618
|
+
});
|
|
7572
7619
|
} catch {
|
|
7620
|
+
tellUrl();
|
|
7573
7621
|
}
|
|
7574
7622
|
}
|
|
7575
7623
|
}
|