scenri 0.3.3 → 0.3.5
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 +24 -0
- package/dist/{chunk-GA7P7K2M.js → chunk-3W2RHBZC.js} +23 -5
- package/dist/{cli-GQLRYYGU.js → cli-HF5KPURA.js} +5 -4
- package/dist/index.js +1 -1
- package/dist/serve.js +55 -10
- package/package.json +1 -1
- package/studio-dist/assets/index-BAT6ODG-.js +102 -0
- package/studio-dist/index.html +1 -1
- package/studio-dist/assets/index-BGiMfD5T.js +0 -102
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.5](https://github.com/tonygorb/Scenri/compare/v0.3.4...v0.3.5) (2026-08-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* keep untrusted text out of the Windows shell lines ([f564c35](https://github.com/tonygorb/Scenri/commit/f564c358dc018f2e7e52e00eae004122690dc2be))
|
|
9
|
+
* make the Codex engine and updates work on Windows ([f94f420](https://github.com/tonygorb/Scenri/commit/f94f42069049b65920dfc95491a074cfd3617b8f))
|
|
10
|
+
* make the Codex engine and updates work on Windows ([f21cb9d](https://github.com/tonygorb/Scenri/commit/f21cb9d513f291bfc64585f9f3a3f67ea5738bde))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Performance Improvements
|
|
14
|
+
|
|
15
|
+
* cut the e2e wall clock roughly in half ([2cacbce](https://github.com/tonygorb/Scenri/commit/2cacbced34b6c58541c0b7942cd107aaa234f477))
|
|
16
|
+
|
|
17
|
+
## [0.3.4](https://github.com/tonygorb/Scenri/compare/v0.3.3...v0.3.4) (2026-08-20)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* presenter references are identity, not wardrobe ([dc372fd](https://github.com/tonygorb/Scenri/commit/dc372fd40d7e15d7d8dc72b5ec8f41993e078ae9))
|
|
23
|
+
* presenter references are identity, not wardrobe ([c8bca43](https://github.com/tonygorb/Scenri/commit/c8bca431730a2d4c41d2783fb6eba2c564af5141))
|
|
24
|
+
* stop custom presenter and scene pages freezing the whole app ([fcf88dd](https://github.com/tonygorb/Scenri/commit/fcf88ddbcd57d01354c833cf9f8456fa1b0b0434))
|
|
25
|
+
* stop custom presenter and scene pages freezing the whole app ([8595078](https://github.com/tonygorb/Scenri/commit/859507893892cb23a7ff2f132f273db4dbd0a0f9))
|
|
26
|
+
|
|
3
27
|
## [0.3.3](https://github.com/tonygorb/Scenri/compare/v0.3.2...v0.3.3) (2026-08-20)
|
|
4
28
|
|
|
5
29
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { stagingDir, versionsDir, isValidVersionDir, pruneStaged, entryOf } from './chunk-4MAFHYAD.js';
|
|
2
2
|
import { spawnSync, spawn } from 'child_process';
|
|
3
|
-
import { rmSync, mkdirSync, readFileSync, renameSync } from 'fs';
|
|
3
|
+
import { existsSync, rmSync, mkdirSync, readFileSync, renameSync } from 'fs';
|
|
4
4
|
import { join, dirname } from 'path';
|
|
5
5
|
|
|
6
6
|
// src/update/check.ts
|
|
@@ -97,6 +97,7 @@ function createUpdateChecker(deps) {
|
|
|
97
97
|
}
|
|
98
98
|
function findNpm(opts = {}) {
|
|
99
99
|
const env = opts.env ?? process.env;
|
|
100
|
+
const platform = opts.platform ?? process.platform;
|
|
100
101
|
const canRun = opts.canRun ?? ((argv) => {
|
|
101
102
|
try {
|
|
102
103
|
return spawnSync(argv[0], [...argv.slice(1), "--version"], { stdio: "ignore", timeout: 1e4 }).status === 0;
|
|
@@ -104,9 +105,26 @@ function findNpm(opts = {}) {
|
|
|
104
105
|
return false;
|
|
105
106
|
}
|
|
106
107
|
});
|
|
107
|
-
if (canRun(["npm"])) return ["npm"];
|
|
108
|
-
const ep = env.npm_execpath;
|
|
108
|
+
if (platform !== "win32" && canRun(["npm"])) return ["npm"];
|
|
109
|
+
const ep = env.npm_execpath?.replace(/npx-cli\.js$/, "npm-cli.js");
|
|
109
110
|
if (ep && /npm-cli\.js$/.test(ep) && canRun([process.execPath, ep])) return [process.execPath, ep];
|
|
111
|
+
if (platform === "win32") {
|
|
112
|
+
const cli = windowsNpmCli();
|
|
113
|
+
if (cli && canRun([process.execPath, cli])) return [process.execPath, cli];
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
function windowsNpmCli() {
|
|
118
|
+
try {
|
|
119
|
+
const out = spawnSync("where", ["npm"], { encoding: "utf8", timeout: 1e4 });
|
|
120
|
+
if (out.status !== 0 || !out.stdout) return null;
|
|
121
|
+
for (const line of out.stdout.split(/\r?\n/)) {
|
|
122
|
+
if (!/npm(\.cmd)?$/i.test(line.trim())) continue;
|
|
123
|
+
const cli = join(dirname(line.trim()), "node_modules", "npm", "bin", "npm-cli.js");
|
|
124
|
+
if (existsSync(cli)) return cli;
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
110
128
|
return null;
|
|
111
129
|
}
|
|
112
130
|
function run(argv) {
|
|
@@ -202,5 +220,5 @@ async function stageVersion(deps) {
|
|
|
202
220
|
}
|
|
203
221
|
|
|
204
222
|
export { classify, createUpdateChecker, fetchDistTagLatest, findNpm, stageVersion };
|
|
205
|
-
//# sourceMappingURL=chunk-
|
|
206
|
-
//# sourceMappingURL=chunk-
|
|
223
|
+
//# sourceMappingURL=chunk-3W2RHBZC.js.map
|
|
224
|
+
//# sourceMappingURL=chunk-3W2RHBZC.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { stageVersion, fetchDistTagLatest, findNpm } from './chunk-
|
|
1
|
+
import { stageVersion, fetchDistTagLatest, findNpm } from './chunk-3W2RHBZC.js';
|
|
2
2
|
import { readMeta } from './chunk-Y3ZPBPLP.js';
|
|
3
3
|
import { defaultHome, newestStaged, compareSemver } from './chunk-4MAFHYAD.js';
|
|
4
4
|
|
|
@@ -43,7 +43,8 @@ async function runUpdateCommand(opts) {
|
|
|
43
43
|
}
|
|
44
44
|
if (!findNpm()) {
|
|
45
45
|
console.error(" npm is not reachable from here, so nothing can be downloaded.");
|
|
46
|
-
console.error("
|
|
46
|
+
console.error(" Run the newest version directly with: npx scenri@latest");
|
|
47
|
+
console.error(" (or install Node.js with npm and try again)");
|
|
47
48
|
return 1;
|
|
48
49
|
}
|
|
49
50
|
console.log(` downloading ${meta.name} ${latest}\u2026`);
|
|
@@ -62,5 +63,5 @@ async function runUpdateCommand(opts) {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
export { runUpdateCommand };
|
|
65
|
-
//# sourceMappingURL=cli-
|
|
66
|
-
//# sourceMappingURL=cli-
|
|
66
|
+
//# sourceMappingURL=cli-HF5KPURA.js.map
|
|
67
|
+
//# sourceMappingURL=cli-HF5KPURA.js.map
|
package/dist/index.js
CHANGED
|
@@ -64,7 +64,7 @@ try {
|
|
|
64
64
|
await (await import('./serve.js')).serve();
|
|
65
65
|
break;
|
|
66
66
|
case "update": {
|
|
67
|
-
const { runUpdateCommand } = await import('./cli-
|
|
67
|
+
const { runUpdateCommand } = await import('./cli-HF5KPURA.js');
|
|
68
68
|
process.exit(await runUpdateCommand(command));
|
|
69
69
|
break;
|
|
70
70
|
}
|
package/dist/serve.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { portBusyLines } from './chunk-WGIZJXNE.js';
|
|
2
|
-
import { createUpdateChecker, classify, stageVersion, findNpm } from './chunk-
|
|
2
|
+
import { createUpdateChecker, classify, stageVersion, findNpm } from './chunk-3W2RHBZC.js';
|
|
3
3
|
import { readMeta, repoSlug } from './chunk-Y3ZPBPLP.js';
|
|
4
4
|
import { newestStaged, compareSemver } from './chunk-4MAFHYAD.js';
|
|
5
5
|
import { networkInterfaces, homedir, tmpdir } from 'os';
|
|
@@ -1271,7 +1271,7 @@ function createCatalogStore(db) {
|
|
|
1271
1271
|
// ../core/src/engine.ts
|
|
1272
1272
|
var REFERENCE_ROLE_DIRECTIVE = {
|
|
1273
1273
|
product: "the exact product \u2014 preserve its label, shape, colors and design faithfully; do not redesign it",
|
|
1274
|
-
character: "the exact person \u2014
|
|
1274
|
+
character: "the exact person \u2014 match their face, facial structure, skin, hair and build exactly; their clothing, pose and background are capture context, not styling to reproduce",
|
|
1275
1275
|
brand: "the brand's own mark \u2014 if the direction calls for the mark to appear, reproduce it exactly as drawn, same colours, letterforms and proportions; otherwise take only its colour and treatment, and never its subject, geometry or composition",
|
|
1276
1276
|
scene: "a reference for the environment and light only \u2014 take no subject, product or person from it",
|
|
1277
1277
|
composition: "a reference for framing, camera angle and pose only \u2014 take no subject, color, material or branding from it",
|
|
@@ -1280,7 +1280,7 @@ var REFERENCE_ROLE_DIRECTIVE = {
|
|
|
1280
1280
|
};
|
|
1281
1281
|
var EDIT_REFERENCE_ROLE_DIRECTIVE = {
|
|
1282
1282
|
product: "the exact product: keep or restore its label, shape and design faithfully",
|
|
1283
|
-
character: "the exact person: keep their face, hair and build faithfully",
|
|
1283
|
+
character: "the exact person: keep their face, facial structure, skin, hair and build faithfully; take no clothing, pose or background from this reference, and keep the source image's existing outfit unless the instruction changes it",
|
|
1284
1284
|
brand: "the brand's own mark: reproduce it exactly as drawn wherever it appears, never redrawn or re-lettered",
|
|
1285
1285
|
scene: "a reference for environment and light only",
|
|
1286
1286
|
composition: "a reference for framing and pose only",
|
|
@@ -1857,11 +1857,17 @@ function execArgs(dir, promptText, effort = "low") {
|
|
|
1857
1857
|
function createRunner(opts = {}) {
|
|
1858
1858
|
const spawnImpl = opts.spawnImpl ?? spawn;
|
|
1859
1859
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
1860
|
+
const platform = opts.platform ?? process.platform;
|
|
1861
|
+
const winArg = (a) => `"${a.replace(/[\r\n]+/g, " ").replace(/"/g, "'").replace(/%/g, " percent ")}"`;
|
|
1862
|
+
const spawnCodex = (args) => platform === "win32" ? spawnImpl(["codex", ...args].map(winArg).join(" "), [], {
|
|
1863
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1864
|
+
shell: true
|
|
1865
|
+
}) : spawnImpl("codex", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
1860
1866
|
function run2(args, signal) {
|
|
1861
1867
|
return new Promise((resolve, reject) => {
|
|
1862
1868
|
let child;
|
|
1863
1869
|
try {
|
|
1864
|
-
child =
|
|
1870
|
+
child = spawnCodex(args);
|
|
1865
1871
|
} catch (err) {
|
|
1866
1872
|
reject(new Error(`Failed to spawn codex: ${err.message}`));
|
|
1867
1873
|
return;
|
|
@@ -1930,7 +1936,7 @@ function createRunner(opts = {}) {
|
|
|
1930
1936
|
};
|
|
1931
1937
|
let child;
|
|
1932
1938
|
try {
|
|
1933
|
-
child =
|
|
1939
|
+
child = spawnCodex(args);
|
|
1934
1940
|
} catch {
|
|
1935
1941
|
done(false);
|
|
1936
1942
|
return;
|
|
@@ -1944,6 +1950,9 @@ function createRunner(opts = {}) {
|
|
|
1944
1950
|
});
|
|
1945
1951
|
}
|
|
1946
1952
|
async function probe() {
|
|
1953
|
+
if (process.env.SCENRI_NO_CODEX === "1") {
|
|
1954
|
+
return { ok: false, reason: NOT_INSTALLED_REASON, code: "not-installed" };
|
|
1955
|
+
}
|
|
1947
1956
|
if (!await exitedZero(["--version"])) {
|
|
1948
1957
|
return { ok: false, reason: NOT_INSTALLED_REASON, code: "not-installed" };
|
|
1949
1958
|
}
|
|
@@ -2105,6 +2114,7 @@ function stateFrom(avail) {
|
|
|
2105
2114
|
}
|
|
2106
2115
|
function createCodexSetup(opts = {}) {
|
|
2107
2116
|
const spawnImpl = opts.spawnImpl ?? spawn;
|
|
2117
|
+
const platform = opts.platform ?? process.platform;
|
|
2108
2118
|
const runner = createRunner(opts);
|
|
2109
2119
|
const installTimeoutMs = opts.installTimeoutMs ?? DEFAULT_INSTALL_TIMEOUT_MS;
|
|
2110
2120
|
function run2(cmd, args, timeoutMs) {
|
|
@@ -2123,7 +2133,7 @@ function createCodexSetup(opts = {}) {
|
|
|
2123
2133
|
done({ code: null, stderr, spawnError: `${cmd} timed out after ${timeoutMs}ms` });
|
|
2124
2134
|
}, timeoutMs);
|
|
2125
2135
|
try {
|
|
2126
|
-
child = spawnImpl(cmd, args, { stdio: ["ignore", "pipe", "pipe"], shell:
|
|
2136
|
+
child = spawnImpl(cmd, args, { stdio: ["ignore", "pipe", "pipe"], shell: platform === "win32" });
|
|
2127
2137
|
} catch (err) {
|
|
2128
2138
|
done({ code: null, stderr, spawnError: err.message });
|
|
2129
2139
|
return;
|
|
@@ -2156,7 +2166,7 @@ function createCodexSetup(opts = {}) {
|
|
|
2156
2166
|
}
|
|
2157
2167
|
return { ok: true };
|
|
2158
2168
|
}
|
|
2159
|
-
if (
|
|
2169
|
+
if (platform !== "win32" && /EACCES|permission denied/i.test(res.stderr)) {
|
|
2160
2170
|
return {
|
|
2161
2171
|
ok: false,
|
|
2162
2172
|
fallbackCommand: INSTALL_COMMAND_SUDO,
|
|
@@ -2487,7 +2497,14 @@ async function resolvePresenterImages(core, templatesRoot, presenter) {
|
|
|
2487
2497
|
const hash = core.images.save(png);
|
|
2488
2498
|
shots.push({ file: `asset:${hash}`, angle, locked: true });
|
|
2489
2499
|
}
|
|
2490
|
-
|
|
2500
|
+
if (!shots.length) return null;
|
|
2501
|
+
return {
|
|
2502
|
+
id: presenter.id,
|
|
2503
|
+
name: presenter.name,
|
|
2504
|
+
...presenter.identityNotes ? { identityNotes: presenter.identityNotes } : {},
|
|
2505
|
+
...presenter.negativeConstraints?.length ? { negativeConstraints: presenter.negativeConstraints } : {},
|
|
2506
|
+
shots
|
|
2507
|
+
};
|
|
2491
2508
|
}
|
|
2492
2509
|
async function brandJsonWithResolvedPresenters(core, templatesRoot, presenters, brandJson, tokens) {
|
|
2493
2510
|
const existing = brandJson?.characters ?? [];
|
|
@@ -2793,7 +2810,7 @@ function compileBrief(brief, ctx) {
|
|
|
2793
2810
|
attachments.push({ role: "character", id: c.id, label: c.name, hash: chash, essential: i === 0 });
|
|
2794
2811
|
});
|
|
2795
2812
|
personDirectives.push(
|
|
2796
|
-
"The attached person reference is the same person every time:
|
|
2813
|
+
"The attached person reference is the same person every time: match their face, facial structure, skin, hair and build exactly. Their outfit, pose, background and lighting are neutral studio capture conditions, not styling direction: dress and style them for this shot, to a commercial standard, following any wardrobe the direction itself specifies."
|
|
2797
2814
|
);
|
|
2798
2815
|
if (c.identityNotes) personDirectives.push(String(c.identityNotes));
|
|
2799
2816
|
if (c.negativeConstraints?.length)
|
|
@@ -2891,10 +2908,14 @@ function compileBrief(brief, ctx) {
|
|
|
2891
2908
|
const sceneCamera = inlineTemplates[0]?.camera?.trim() || ctx.template?.camera?.trim() || "";
|
|
2892
2909
|
const cameraDirectives = sceneCamera && !shotSpecifiesCamera(sentence) ? [`Camera for this shot: ${sceneCamera}`] : [];
|
|
2893
2910
|
const guard = scene ? sceneGuardDirectives({ hasProduct: !!productId, hasPerson }) : [];
|
|
2911
|
+
const pairDirectives = productId && hasPerson ? [
|
|
2912
|
+
"If the attached product is something a person wears, the presenter wears that exact product, with the rest of the outfit styled around it; otherwise the presenter presents or uses the product naturally."
|
|
2913
|
+
] : [];
|
|
2894
2914
|
const brandLines = brandRuleDirectives(ctx.brand);
|
|
2895
2915
|
const allDirectives = [
|
|
2896
2916
|
...productDirectives,
|
|
2897
2917
|
...personDirectives,
|
|
2918
|
+
...pairDirectives,
|
|
2898
2919
|
...otherDirectives,
|
|
2899
2920
|
...cameraDirectives,
|
|
2900
2921
|
...brandLines,
|
|
@@ -6524,6 +6545,30 @@ function registerImageRoutes(app, deps) {
|
|
|
6524
6545
|
|
|
6525
6546
|
// src/release/notes.data.ts
|
|
6526
6547
|
var RELEASES = [
|
|
6548
|
+
{
|
|
6549
|
+
version: "0.3.5",
|
|
6550
|
+
date: "2026-08-21",
|
|
6551
|
+
sections: [
|
|
6552
|
+
{
|
|
6553
|
+
heading: "Fixes",
|
|
6554
|
+
body: "Setting up the Codex engine on Windows no longer reports a successful install as missing, and updates can now find npm there. When npm truly is unreachable, the update command points to the one-line recovery instead of a dead end."
|
|
6555
|
+
}
|
|
6556
|
+
]
|
|
6557
|
+
},
|
|
6558
|
+
{
|
|
6559
|
+
version: "0.3.4",
|
|
6560
|
+
date: "2026-08-21",
|
|
6561
|
+
sections: [
|
|
6562
|
+
{
|
|
6563
|
+
heading: "Presenters",
|
|
6564
|
+
body: "A presenter's reference photos now define who they are, not what they wear. The neutral studio outfit from their reference set no longer follows them into finished shots; wardrobe comes from the shot, the product and the scene instead, and refining an image keeps the outfit it already has."
|
|
6565
|
+
},
|
|
6566
|
+
{
|
|
6567
|
+
heading: "Fixes",
|
|
6568
|
+
body: "Opening a presenter or scene you built yourself no longer freezes the app."
|
|
6569
|
+
}
|
|
6570
|
+
]
|
|
6571
|
+
},
|
|
6527
6572
|
{
|
|
6528
6573
|
version: "0.3.3",
|
|
6529
6574
|
date: "2026-08-20",
|
|
@@ -6867,7 +6912,7 @@ function registerSystemRoutes(app, deps) {
|
|
|
6867
6912
|
}
|
|
6868
6913
|
core.close();
|
|
6869
6914
|
for (const name of ["scenri.db", "scenri.db-wal", "scenri.db-shm", "images", "backups"]) {
|
|
6870
|
-
rmSync(join(core.home, name), { recursive: true, force: true });
|
|
6915
|
+
rmSync(join(core.home, name), { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
6871
6916
|
}
|
|
6872
6917
|
return { ok: true, scope };
|
|
6873
6918
|
});
|