scenri 0.10.3 → 0.11.1
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 +45 -0
- package/dist/{chunk-UUYMUOZQ.js → chunk-K6IELFL3.js} +51 -2
- package/dist/{cli-3KKS7BE4.js → cli-GMRPOISO.js} +3 -3
- package/dist/index.js +2 -2
- package/dist/serve.js +211 -13
- package/dist/{src-QZZDZM7I.js → src-TC4UQ7H6.js} +3 -3
- package/package.json +1 -1
- package/studio-dist/assets/{index-ELZxH19c.css → index-BWeypLhE.css} +1 -1
- package/studio-dist/assets/index-Dtkr2AoI.js +107 -0
- package/studio-dist/index.html +2 -2
- package/studio-dist/assets/index-DICg38Xm.js +0 -107
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.11.1](https://github.com/tonygorb/Scenri/compare/v0.11.0...v0.11.1) (2026-09-18)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* pause first-use guidance, and a bar panel opened from another stays open ([ad6fb8d](https://github.com/tonygorb/Scenri/commit/ad6fb8d3146f7e51ab257fdaab9c74cbef88dad8))
|
|
9
|
+
* **studio:** a bar panel opened while another is open stays open ([fb43b43](https://github.com/tonygorb/Scenri/commit/fb43b43c5e7cf44ce0bcd7a5dd3daf815b4c6875))
|
|
10
|
+
* **studio:** pause first-use guidance until it is finished ([6fd33f0](https://github.com/tonygorb/Scenri/commit/6fd33f074e2af8373a1ae8cdd7690468cc6e90dd))
|
|
11
|
+
|
|
12
|
+
## [0.11.0](https://github.com/tonygorb/Scenri/compare/v0.10.3...v0.11.0) (2026-09-18)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* first use, a tutor that walks the real task, with First steps and Learn ([47e9775](https://github.com/tonygorb/Scenri/commit/47e977569049803f0544ce19ad0289cdc8e187f5))
|
|
18
|
+
* Learn, every lesson in one place, begun and continued with the same tutor ([1d378e1](https://github.com/tonygorb/Scenri/commit/1d378e17f22a8ebf64878d67caa0996027e5f1f6))
|
|
19
|
+
* **studio:** New lands on Create with the add panel open ([674bf9c](https://github.com/tonygorb/Scenri/commit/674bf9cbb369443e75b78586210a0b0b12c94826))
|
|
20
|
+
* **studio:** New's plus rides a gold disc ([673a17b](https://github.com/tonygorb/Scenri/commit/673a17b1e48eb491ecc2c9a1d122955d11e24d0d))
|
|
21
|
+
* **studio:** the brand menu leads with where you have been and stays one height ([e28a857](https://github.com/tonygorb/Scenri/commit/e28a8573f797f75815687239cd58c1b4d01518e7))
|
|
22
|
+
* **studio:** the new top bar ([e1d262b](https://github.com/tonygorb/Scenri/commit/e1d262b9eb21a4fd788dae8acd487096223b87c6))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* a product made from the picker is named, and Enter on a control is that control's ([7383c7b](https://github.com/tonygorb/Scenri/commit/7383c7baa6fde61dcbf060c68cb429960caee73a))
|
|
28
|
+
* a task ended on a surface is not begun there again, and an empty chip panel foot is not drawn ([2b450fd](https://github.com/tonygorb/Scenri/commit/2b450fd3b7aeb875fee5649b670f3839af0f7894))
|
|
29
|
+
* closing Learn gives the keyboard back to Help when what opened it is gone ([c12d690](https://github.com/tonygorb/Scenri/commit/c12d690fad3e7ce4d1cfaed05aa6982a97d5de4c))
|
|
30
|
+
* in the walk a chip comes in through its ask and leaves only through Back ([a0e9fea](https://github.com/tonygorb/Scenri/commit/a0e9fea7426755ba020f766f0a0678df96542e2c))
|
|
31
|
+
* **studio:** a bar menu answers the next click, even while it is closing ([7b0af47](https://github.com/tonygorb/Scenri/commit/7b0af476d0af0691be60616687955c3521171787))
|
|
32
|
+
* **studio:** a brand icon that is its own ground fills its circle ([0f356fb](https://github.com/tonygorb/Scenri/commit/0f356fbbd19e899ae41751851f873fedbce4d9b5))
|
|
33
|
+
* **studio:** a brand's circle shows its icon, or its initial, never a shrunken wordmark ([6c8415d](https://github.com/tonygorb/Scenri/commit/6c8415da61b261629cee734366a1cece630a58c4))
|
|
34
|
+
* **studio:** New pressed with the add panel open leaves it open and focuses the brief ([37050a4](https://github.com/tonygorb/Scenri/commit/37050a4e4b99f431649f97423ab6596f8ba52dad))
|
|
35
|
+
* **studio:** New wears round ends, the mark shows its box, and Clear all joins its list ([2ed412e](https://github.com/tonygorb/Scenri/commit/2ed412e1faf4d60378b0996f02373ea804b27fe9))
|
|
36
|
+
* **studio:** New's plus sits on an ink disc, and the bar no longer shrinks ([86ceaa3](https://github.com/tonygorb/Scenri/commit/86ceaa33dc16856a1c3fa2e4950360d1a77c5eec))
|
|
37
|
+
* **studio:** pointing at New's plus lights the whole button ([d3a4973](https://github.com/tonygorb/Scenri/commit/d3a4973dc8ee9a0ce090e24fd3f3f8a591c1b0f5))
|
|
38
|
+
* **studio:** the bar wears the full Scenri lockup, bare ([25efd02](https://github.com/tonygorb/Scenri/commit/25efd0292c1d0982ec1f027364489306cf294bea))
|
|
39
|
+
* **studio:** the brand list ends on a whole row ([a20da23](https://github.com/tonygorb/Scenri/commit/a20da23fd89240fd533944ad222c62144795a12e))
|
|
40
|
+
* **studio:** the brand list fades into the line under it while there is more ([18073f8](https://github.com/tonygorb/Scenri/commit/18073f8ea67157c64bbb7b676eb9aade51276614))
|
|
41
|
+
* **studio:** the brand list is ten rows tall ([df5b4e1](https://github.com/tonygorb/Scenri/commit/df5b4e1b834aabf9b4dc22338e83ce99a19550e3))
|
|
42
|
+
* **studio:** the brand list runs straight into the line under it ([402e017](https://github.com/tonygorb/Scenri/commit/402e0176e3bb7ae5cc799af77de4852e92608ba1))
|
|
43
|
+
* **studio:** the brand menu is one compact list ([1e3dc70](https://github.com/tonygorb/Scenri/commit/1e3dc7002cae58fbc8bacc567cf3a924a38a6a1c))
|
|
44
|
+
* **studio:** the brand menu is one list, and the help button leaves this branch ([2e717d1](https://github.com/tonygorb/Scenri/commit/2e717d1474f45e625e85bef36b69d3397cb20925))
|
|
45
|
+
* the tutor keeps what a moment is about in sight, and lets people go their own way ([41e667e](https://github.com/tonygorb/Scenri/commit/41e667e94a930d85bf1ad88fbba4bf00ae6f5ece))
|
|
46
|
+
* the welcome reads top to bottom, speaks plainly, and opens again from Help ([7edb94f](https://github.com/tonygorb/Scenri/commit/7edb94f289e17c1c4255cc6ef683758bc21aea17))
|
|
47
|
+
|
|
3
48
|
## [0.10.3](https://github.com/tonygorb/Scenri/compare/v0.10.2...v0.10.3) (2026-09-18)
|
|
4
49
|
|
|
5
50
|
|
|
@@ -1344,6 +1344,55 @@ function createStore(db) {
|
|
|
1344
1344
|
setOverlays(id, overlays) {
|
|
1345
1345
|
db.prepare("UPDATE nodes SET overlays=? WHERE id=?").run(JSON.stringify(overlays), id);
|
|
1346
1346
|
},
|
|
1347
|
+
// first use: what the library already proves, read by the guide record
|
|
1348
|
+
/** The database's own clock, in the format every node's created_at uses. */
|
|
1349
|
+
now() {
|
|
1350
|
+
return db.prepare("SELECT strftime('%Y-%m-%d %H:%M:%f','now') AS t").get().t;
|
|
1351
|
+
},
|
|
1352
|
+
/** Whether any brand holds a finished shot, or a finished refinement, with a picture. */
|
|
1353
|
+
hasFinishedNode(kind) {
|
|
1354
|
+
return !!db.prepare("SELECT 1 FROM nodes WHERE kind=? AND status='done' AND images != '[]' LIMIT 1").get(kind);
|
|
1355
|
+
},
|
|
1356
|
+
/** Whether any brand has imported a product from a store. */
|
|
1357
|
+
hasCatalogProduct() {
|
|
1358
|
+
return !!db.prepare("SELECT 1 FROM catalog_products LIMIT 1").get();
|
|
1359
|
+
},
|
|
1360
|
+
/** A brand's shots of one kind made at or after a moment, newest first: what a guided task has made. */
|
|
1361
|
+
nodesSince(brandId, kind, since, limit = 8) {
|
|
1362
|
+
const rows = db.prepare(
|
|
1363
|
+
`SELECT id, kind, status, images, created_at FROM nodes
|
|
1364
|
+
WHERE project_id IN (SELECT id FROM projects WHERE brand_id = ?)
|
|
1365
|
+
AND kind = ? AND created_at >= ?
|
|
1366
|
+
ORDER BY created_at DESC, id DESC LIMIT ?`
|
|
1367
|
+
).all(brandId, kind, since, limit);
|
|
1368
|
+
return rows.map((r) => ({
|
|
1369
|
+
id: r.id,
|
|
1370
|
+
kind: r.kind,
|
|
1371
|
+
status: r.status,
|
|
1372
|
+
images: (() => {
|
|
1373
|
+
try {
|
|
1374
|
+
const a = JSON.parse(r.images);
|
|
1375
|
+
return Array.isArray(a) ? a.length : 0;
|
|
1376
|
+
} catch {
|
|
1377
|
+
return 0;
|
|
1378
|
+
}
|
|
1379
|
+
})(),
|
|
1380
|
+
createdAt: r.created_at
|
|
1381
|
+
}));
|
|
1382
|
+
},
|
|
1383
|
+
/** The newest presenter draft a brand started at or after a moment, never an edit session's. */
|
|
1384
|
+
presenterDraftSince(brandId, since) {
|
|
1385
|
+
const rows = db.prepare(
|
|
1386
|
+
"SELECT id, json FROM presenter_drafts WHERE brand_id = ? AND created_at >= ? ORDER BY created_at DESC, id DESC"
|
|
1387
|
+
).all(brandId, since);
|
|
1388
|
+
for (const r of rows) {
|
|
1389
|
+
try {
|
|
1390
|
+
if (!JSON.parse(r.json)?.presenterId) return r.id;
|
|
1391
|
+
} catch {
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
return null;
|
|
1395
|
+
},
|
|
1347
1396
|
// settings
|
|
1348
1397
|
getSetting(key) {
|
|
1349
1398
|
const r = db.prepare("SELECT value FROM settings WHERE key=?").get(key);
|
|
@@ -2175,5 +2224,5 @@ function createCore(homeDir = defaultHome()) {
|
|
|
2175
2224
|
}
|
|
2176
2225
|
|
|
2177
2226
|
export { ASPECT_TOLERANCE, BUDGET_EXHAUSTED, EDIT_REFERENCE_ROLE_DIRECTIVE, REFERENCE_ROLE_DIRECTIVE, SCHEMA_VERSION, STEM_MIN, SchemaTooNewError, SpendCapError, TRIGRAM_MIN, budgetSize, createCatalogStore, createCore, createStore, defaultHome, fold, ftsMatch, matchesQuery, ratioLabel, searchTerms, termMatches, uniqueProjectSlug, uniqueSetSlug, uniqueSlug };
|
|
2178
|
-
//# sourceMappingURL=chunk-
|
|
2179
|
-
//# sourceMappingURL=chunk-
|
|
2227
|
+
//# sourceMappingURL=chunk-K6IELFL3.js.map
|
|
2228
|
+
//# sourceMappingURL=chunk-K6IELFL3.js.map
|
|
@@ -463,7 +463,7 @@ async function addOrRepair(ownEntry, say, over) {
|
|
|
463
463
|
}
|
|
464
464
|
async function rememberDecline(home) {
|
|
465
465
|
try {
|
|
466
|
-
const { createCore } = await import('./src-
|
|
466
|
+
const { createCore } = await import('./src-TC4UQ7H6.js');
|
|
467
467
|
const core = createCore(home);
|
|
468
468
|
try {
|
|
469
469
|
core.store.setSetting("desktop.prompt", "declined");
|
|
@@ -530,5 +530,5 @@ function tail(path, bytes = 4096) {
|
|
|
530
530
|
}
|
|
531
531
|
|
|
532
532
|
export { addToDesktop, assetsDirFor, installDeps, runDesktopCommand, runExecFile, runOpenCommand };
|
|
533
|
-
//# sourceMappingURL=cli-
|
|
534
|
-
//# sourceMappingURL=cli-
|
|
533
|
+
//# sourceMappingURL=cli-GMRPOISO.js.map
|
|
534
|
+
//# sourceMappingURL=cli-GMRPOISO.js.map
|
package/dist/index.js
CHANGED
|
@@ -86,12 +86,12 @@ try {
|
|
|
86
86
|
break;
|
|
87
87
|
}
|
|
88
88
|
case "desktop": {
|
|
89
|
-
const { runDesktopCommand } = await import('./cli-
|
|
89
|
+
const { runDesktopCommand } = await import('./cli-GMRPOISO.js');
|
|
90
90
|
process.exit(await runDesktopCommand(command, fileURLToPath(import.meta.url)));
|
|
91
91
|
break;
|
|
92
92
|
}
|
|
93
93
|
case "open": {
|
|
94
|
-
const { runOpenCommand } = await import('./cli-
|
|
94
|
+
const { runOpenCommand } = await import('./cli-GMRPOISO.js');
|
|
95
95
|
process.exit(await runOpenCommand(fileURLToPath(import.meta.url)));
|
|
96
96
|
break;
|
|
97
97
|
}
|
package/dist/serve.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createUpdateChecker, classify, findNpm, isReleaseTriplet, stageVersion } from './chunk-YK37H6DM.js';
|
|
2
2
|
import { shouldAdoptRunning, anotherScenriLines, portBusyLines } from './chunk-CMLJGPYC.js';
|
|
3
|
-
import { SchemaTooNewError, createCore, BUDGET_EXHAUSTED, SpendCapError, EDIT_REFERENCE_ROLE_DIRECTIVE, REFERENCE_ROLE_DIRECTIVE, ratioLabel, searchTerms, termMatches, budgetSize, SCHEMA_VERSION, ASPECT_TOLERANCE } from './chunk-
|
|
3
|
+
import { SchemaTooNewError, createCore, BUDGET_EXHAUSTED, SpendCapError, EDIT_REFERENCE_ROLE_DIRECTIVE, REFERENCE_ROLE_DIRECTIVE, ratioLabel, searchTerms, termMatches, budgetSize, SCHEMA_VERSION, ASPECT_TOLERANCE } from './chunk-K6IELFL3.js';
|
|
4
4
|
import { detectInstallKind } from './chunk-PAIAXRAC.js';
|
|
5
5
|
export { detectInstallKind } from './chunk-PAIAXRAC.js';
|
|
6
6
|
import { readMeta, repoSlug } from './chunk-Y3ZPBPLP.js';
|
|
@@ -1287,12 +1287,12 @@ function createCodexAnalyzer(opts = {}) {
|
|
|
1287
1287
|
};
|
|
1288
1288
|
}
|
|
1289
1289
|
function buildPrompt(req, refCount, problems) {
|
|
1290
|
-
const
|
|
1290
|
+
const evidence2 = refCount === 0 ? "You have no reference images. Work from the description alone." : refCount === 1 ? "One reference image is attached." : `${refCount} reference images are attached.`;
|
|
1291
1291
|
const body = req.kind === "presenter" ? presenterBody(req, refCount) : sceneBody(req);
|
|
1292
1292
|
const revision = req.priorDraft ? ` You are revising an existing record, not starting over: keep everything that is not being corrected. Current record: ${JSON.stringify(req.priorDraft)}.` : "";
|
|
1293
1293
|
const correction = req.correction ? ` The correction to apply: ${req.correction}.` : "";
|
|
1294
1294
|
const retry = problems.length ? ` Your last answer was rejected: ${problems.join(" ")} Fix exactly that and write the file again.` : "";
|
|
1295
|
-
return `${
|
|
1295
|
+
return `${evidence2}${revision}${correction} ${body} Write strict JSON, and nothing but JSON, to a file called ${OUT_FILE} in the current directory (you may run the commands needed to write it). Do not browse the web or explore files. No prose, no markdown fences, no commentary.${retry}`;
|
|
1296
1296
|
}
|
|
1297
1297
|
function presenterBody(req, refCount) {
|
|
1298
1298
|
const same = refCount > 1 ? " Every attached photograph is the same person." : "";
|
|
@@ -3248,7 +3248,7 @@ function compileBrief(brief, ctx) {
|
|
|
3248
3248
|
);
|
|
3249
3249
|
if (names.length) {
|
|
3250
3250
|
warnings.push(
|
|
3251
|
-
`${names.join(" and ")} ${names.length === 1 ? "was" : "were"} left out
|
|
3251
|
+
`${names.join(" and ")} ${names.length === 1 ? "was" : "were"} left out: ${ctx.engineCaps.displayName} reads no reference images.`
|
|
3252
3252
|
);
|
|
3253
3253
|
}
|
|
3254
3254
|
}
|
|
@@ -5207,18 +5207,18 @@ function mergeScrape(existing, scraped) {
|
|
|
5207
5207
|
async function inspectMark(buf, toPng2) {
|
|
5208
5208
|
const png = await toPng2(buf);
|
|
5209
5209
|
const meta = await sharp21(png).metadata();
|
|
5210
|
-
let
|
|
5210
|
+
let blank2 = false;
|
|
5211
5211
|
try {
|
|
5212
5212
|
const flat = await sharp21(png).flatten({ background: "#ffffff" }).toBuffer();
|
|
5213
5213
|
const stats = await sharp21(flat).stats();
|
|
5214
|
-
|
|
5214
|
+
blank2 = stats.channels.slice(0, 3).every((c) => c.min > 200);
|
|
5215
5215
|
} catch {
|
|
5216
5216
|
}
|
|
5217
5217
|
return {
|
|
5218
5218
|
longEdge: Math.max(meta.width ?? 0, meta.height ?? 0) || null,
|
|
5219
5219
|
width: meta.width ?? null,
|
|
5220
5220
|
height: meta.height ?? null,
|
|
5221
|
-
blank
|
|
5221
|
+
blank: blank2
|
|
5222
5222
|
};
|
|
5223
5223
|
}
|
|
5224
5224
|
|
|
@@ -11287,7 +11287,7 @@ function defaultShowcaseDir() {
|
|
|
11287
11287
|
|
|
11288
11288
|
// src/routes/showcase.ts
|
|
11289
11289
|
function registerShowcaseRoutes(app, deps) {
|
|
11290
|
-
const { templatesRoot } = deps;
|
|
11290
|
+
const { templatesRoot, thumbs } = deps;
|
|
11291
11291
|
const { showcase } = loadShowcase(join(templatesRoot, "showcase"));
|
|
11292
11292
|
const showcaseHeroPath = (id) => contentFile(templatesRoot, "previews", "showcase", `${id}.jpg`);
|
|
11293
11293
|
const decorateShowcase = (s) => ({
|
|
@@ -11301,7 +11301,8 @@ function registerShowcaseRoutes(app, deps) {
|
|
|
11301
11301
|
app.get("/api/showcase-previews/:file", async (req, reply) => {
|
|
11302
11302
|
const m = /^([a-z0-9-]+)\.jpg$/.exec(String(req.params.file));
|
|
11303
11303
|
if (!m || !existsSync(showcaseHeroPath(m[1]))) return reply.status(404).send({ error: "no preview" });
|
|
11304
|
-
|
|
11304
|
+
const path = showcaseHeroPath(m[1]);
|
|
11305
|
+
return serveJpegSized(req, reply, path, thumbs, fileKey("showcase", m[1], path));
|
|
11305
11306
|
});
|
|
11306
11307
|
}
|
|
11307
11308
|
|
|
@@ -11703,6 +11704,43 @@ function registerImageRoutes(app, deps) {
|
|
|
11703
11704
|
|
|
11704
11705
|
// src/release/notes.data.ts
|
|
11705
11706
|
var RELEASES = [
|
|
11707
|
+
{
|
|
11708
|
+
version: "0.11.1",
|
|
11709
|
+
date: "2026-09-18",
|
|
11710
|
+
sections: [
|
|
11711
|
+
{
|
|
11712
|
+
heading: "Learn",
|
|
11713
|
+
body: "The welcome, the guided first shot, First steps and Learn are paused for now while they are finished. Nothing of them opens by itself, and Help no longer lists them."
|
|
11714
|
+
},
|
|
11715
|
+
{
|
|
11716
|
+
heading: "Fixes",
|
|
11717
|
+
body: "With a panel in the top bar open, pressing another control in the bar opens its panel and keeps it open, instead of opening it and closing it again at once."
|
|
11718
|
+
}
|
|
11719
|
+
]
|
|
11720
|
+
},
|
|
11721
|
+
{
|
|
11722
|
+
version: "0.11.0",
|
|
11723
|
+
date: "2026-09-18",
|
|
11724
|
+
title: "A new top bar, and a tutor that makes your first shot with you.",
|
|
11725
|
+
sections: [
|
|
11726
|
+
{
|
|
11727
|
+
heading: "Top bar",
|
|
11728
|
+
body: "The five places sit in the middle of the bar, with the one you are on underlined. New opens Create with the add panel open, and its arrow adds a product, presenter or scene instead. Activity replaces the bell: while a shot renders it shows that picture inside a filling ring, and its panel lists what is in progress and your notifications together, with Mark all read and Clear all. On a phone every panel in the bar opens as a sheet."
|
|
11729
|
+
},
|
|
11730
|
+
{
|
|
11731
|
+
heading: "Brand",
|
|
11732
|
+
body: "The brand menu is one short list, the brand you are in first and the rest A to Z, with a search once it grows long, so Settings and Shut down stay in reach. A brand's circle shows its icon, or its initial, never a shrunken wordmark."
|
|
11733
|
+
},
|
|
11734
|
+
{
|
|
11735
|
+
heading: "Learn",
|
|
11736
|
+
body: "A new install is welcomed and makes its first shot with a tutor, one step at a time: a product, a presenter, a scene, then the words. First steps on Home lists four lessons to start with and leaves once they are done, and Learn holds all five, from adding your product to refining a shot. Help sits in the corner of the page from 1024 pixels wide and in the bar below that, with Learn, the welcome, keyboard shortcuts and What's new."
|
|
11737
|
+
},
|
|
11738
|
+
{
|
|
11739
|
+
heading: "Fixes",
|
|
11740
|
+
body: "A product made from the picker goes into the brief by its name instead of as a missing product, and Enter on a focused control in Create presses that control rather than opening the selected shot."
|
|
11741
|
+
}
|
|
11742
|
+
]
|
|
11743
|
+
},
|
|
11706
11744
|
{
|
|
11707
11745
|
version: "0.10.3",
|
|
11708
11746
|
date: "2026-09-18",
|
|
@@ -12765,6 +12803,165 @@ function registerSystemRoutes(app, deps) {
|
|
|
12765
12803
|
});
|
|
12766
12804
|
}
|
|
12767
12805
|
|
|
12806
|
+
// src/routes/guide.ts
|
|
12807
|
+
var TASKS = ["first-shot", "refine", "product", "presenter", "scene"];
|
|
12808
|
+
var MILESTONES = ["shot", "refine", "product", "presenter", "scene"];
|
|
12809
|
+
var KEY = "guide";
|
|
12810
|
+
var isTask = (t) => TASKS.includes(t);
|
|
12811
|
+
var isMilestone = (m) => MILESTONES.includes(m);
|
|
12812
|
+
var num2 = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? n : 0;
|
|
12813
|
+
function blank(eligible) {
|
|
12814
|
+
return { v: 2, eligible, welcome: null, hidden: null, done: {}, dismissed: [], active: null };
|
|
12815
|
+
}
|
|
12816
|
+
function parse2(raw) {
|
|
12817
|
+
if (!raw) return null;
|
|
12818
|
+
try {
|
|
12819
|
+
const j = JSON.parse(raw);
|
|
12820
|
+
if (typeof j.eligible !== "boolean") return null;
|
|
12821
|
+
if (j.v !== 2) return null;
|
|
12822
|
+
const done = {};
|
|
12823
|
+
if (j.done && typeof j.done === "object") {
|
|
12824
|
+
for (const [k, at] of Object.entries(j.done)) if (isMilestone(k) && typeof at === "string") done[k] = at;
|
|
12825
|
+
}
|
|
12826
|
+
const a = j.active;
|
|
12827
|
+
const b = a?.baseline;
|
|
12828
|
+
const active = a && isTask(a.task) && typeof a.brandId === "string" && typeof a.since === "string" ? {
|
|
12829
|
+
task: a.task,
|
|
12830
|
+
brandId: a.brandId,
|
|
12831
|
+
since: a.since,
|
|
12832
|
+
baseline: { products: num2(b?.products), presenters: num2(b?.presenters), scenes: num2(b?.scenes) },
|
|
12833
|
+
...a.paused === true ? { paused: true } : {}
|
|
12834
|
+
} : null;
|
|
12835
|
+
return {
|
|
12836
|
+
v: 2,
|
|
12837
|
+
eligible: j.eligible,
|
|
12838
|
+
welcome: j.welcome === "taken" || j.welcome === "declined" ? j.welcome : null,
|
|
12839
|
+
hidden: typeof j.hidden === "boolean" ? j.hidden : null,
|
|
12840
|
+
done,
|
|
12841
|
+
dismissed: Array.isArray(j.dismissed) ? j.dismissed.filter(isTask) : [],
|
|
12842
|
+
active
|
|
12843
|
+
};
|
|
12844
|
+
} catch {
|
|
12845
|
+
return null;
|
|
12846
|
+
}
|
|
12847
|
+
}
|
|
12848
|
+
function write(store, r) {
|
|
12849
|
+
store.setSetting(KEY, JSON.stringify(r));
|
|
12850
|
+
}
|
|
12851
|
+
function stampGuide(store, version) {
|
|
12852
|
+
if (store.getSetting(KEY) !== null) return;
|
|
12853
|
+
const eligible = store.listBrands().length === 0;
|
|
12854
|
+
if (eligible) {
|
|
12855
|
+
if (!store.getSetting("install.firstVersion")) store.setSetting("install.firstVersion", version);
|
|
12856
|
+
const seen = store.getSetting("whatsnew.seen");
|
|
12857
|
+
if (!seen || compareSemver(seen, version) < 0) store.setSetting("whatsnew.seen", version);
|
|
12858
|
+
}
|
|
12859
|
+
write(store, blank(eligible));
|
|
12860
|
+
}
|
|
12861
|
+
function countsOf(core, brandId) {
|
|
12862
|
+
const brand = core.store.getBrand(brandId);
|
|
12863
|
+
if (!brand) return null;
|
|
12864
|
+
const json = brand.json;
|
|
12865
|
+
const characters = Array.isArray(json?.characters) ? json.characters : [];
|
|
12866
|
+
return {
|
|
12867
|
+
presenters: characters.filter((c) => c?.origin === "custom" && !c?.supersededBy).length,
|
|
12868
|
+
scenes: Array.isArray(json?.scenes) ? json.scenes.length : 0,
|
|
12869
|
+
products: core.catalog.listLibraryProducts(brandId, json).length
|
|
12870
|
+
};
|
|
12871
|
+
}
|
|
12872
|
+
var ownPresenter = (b) => (b.json?.characters ?? []).some((c) => c?.origin === "custom" && !c?.supersededBy);
|
|
12873
|
+
function evidence(core, m) {
|
|
12874
|
+
const { store } = core;
|
|
12875
|
+
switch (m) {
|
|
12876
|
+
case "shot":
|
|
12877
|
+
return store.hasFinishedNode("generation");
|
|
12878
|
+
case "refine":
|
|
12879
|
+
return store.hasFinishedNode("edit");
|
|
12880
|
+
case "presenter":
|
|
12881
|
+
return store.listBrands().some(ownPresenter);
|
|
12882
|
+
case "scene":
|
|
12883
|
+
return store.listBrands().some((b) => (b.json?.scenes ?? []).length > 0);
|
|
12884
|
+
case "product":
|
|
12885
|
+
return store.hasCatalogProduct() || store.listBrands().some((b) => (b.json?.products ?? []).length > 0);
|
|
12886
|
+
}
|
|
12887
|
+
}
|
|
12888
|
+
function load2(store) {
|
|
12889
|
+
return parse2(store.getSetting(KEY)) ?? blank(false);
|
|
12890
|
+
}
|
|
12891
|
+
function readGuide(core, env) {
|
|
12892
|
+
const r = load2(core.store);
|
|
12893
|
+
let changed = false;
|
|
12894
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
12895
|
+
for (const m of MILESTONES) {
|
|
12896
|
+
if (!r.done[m] && evidence(core, m)) {
|
|
12897
|
+
r.done[m] = at;
|
|
12898
|
+
changed = true;
|
|
12899
|
+
}
|
|
12900
|
+
}
|
|
12901
|
+
if (r.active && !core.store.getBrand(r.active.brandId)) {
|
|
12902
|
+
r.active = null;
|
|
12903
|
+
changed = true;
|
|
12904
|
+
}
|
|
12905
|
+
if (changed) write(core.store, r);
|
|
12906
|
+
const a = r.active;
|
|
12907
|
+
const nodeKind = a?.task === "first-shot" ? "generation" : a?.task === "refine" ? "edit" : null;
|
|
12908
|
+
const eligible = r.eligible && env.SCENRI_NO_GUIDE !== "1";
|
|
12909
|
+
return {
|
|
12910
|
+
eligible,
|
|
12911
|
+
welcome: r.welcome,
|
|
12912
|
+
hidden: r.hidden ?? !eligible,
|
|
12913
|
+
done: r.done,
|
|
12914
|
+
dismissed: r.dismissed,
|
|
12915
|
+
active: a,
|
|
12916
|
+
activeNodes: a && nodeKind ? core.store.nodesSince(a.brandId, nodeKind, a.since) : [],
|
|
12917
|
+
activeDraftId: a?.task === "presenter" ? core.store.presenterDraftSince(a.brandId, a.since) : null,
|
|
12918
|
+
counts: a ? countsOf(core, a.brandId) : null
|
|
12919
|
+
};
|
|
12920
|
+
}
|
|
12921
|
+
function applyIntent(core, body) {
|
|
12922
|
+
const b = body ?? {};
|
|
12923
|
+
const r = load2(core.store);
|
|
12924
|
+
if ("welcome" in b) {
|
|
12925
|
+
if (b.welcome !== "taken" && b.welcome !== "declined") return "welcome is taken or declined";
|
|
12926
|
+
r.welcome = b.welcome;
|
|
12927
|
+
} else if ("start" in b) {
|
|
12928
|
+
const s = b.start ?? {};
|
|
12929
|
+
if (!isTask(s.task)) return "unknown task";
|
|
12930
|
+
if (typeof s.brandId !== "string") return "brandId required";
|
|
12931
|
+
const baseline = countsOf(core, s.brandId);
|
|
12932
|
+
if (!baseline) return "brand not found";
|
|
12933
|
+
const held = r.active;
|
|
12934
|
+
if (held && held.paused && held.task === s.task && held.brandId === s.brandId) {
|
|
12935
|
+
const { paused: _, ...going } = held;
|
|
12936
|
+
r.active = going;
|
|
12937
|
+
} else r.active = { task: s.task, brandId: s.brandId, since: core.store.now(), baseline };
|
|
12938
|
+
r.dismissed = r.dismissed.filter((t) => t !== s.task);
|
|
12939
|
+
} else if ("finish" in b) {
|
|
12940
|
+
if (!isTask(b.finish)) return "unknown task";
|
|
12941
|
+
if (r.active?.task === b.finish) r.active = null;
|
|
12942
|
+
} else if ("dismiss" in b) {
|
|
12943
|
+
if (!isTask(b.dismiss)) return "unknown task";
|
|
12944
|
+
if (!r.dismissed.includes(b.dismiss)) r.dismissed.push(b.dismiss);
|
|
12945
|
+
if (r.active?.task === b.dismiss) r.active = { ...r.active, paused: true };
|
|
12946
|
+
} else if ("hidden" in b) {
|
|
12947
|
+
if (typeof b.hidden !== "boolean") return "hidden is true or false";
|
|
12948
|
+
r.hidden = b.hidden;
|
|
12949
|
+
} else return "unknown intent";
|
|
12950
|
+
write(core.store, r);
|
|
12951
|
+
return null;
|
|
12952
|
+
}
|
|
12953
|
+
function registerGuideRoutes(app, deps) {
|
|
12954
|
+
const { core } = deps;
|
|
12955
|
+
const env = deps.env ?? process.env;
|
|
12956
|
+
stampGuide(core.store, deps.version);
|
|
12957
|
+
app.get("/api/guide", async () => readGuide(core, env));
|
|
12958
|
+
app.post("/api/guide", async (req, reply) => {
|
|
12959
|
+
const error = applyIntent(core, req.body);
|
|
12960
|
+
if (error) return reply.status(400).send({ error });
|
|
12961
|
+
return readGuide(core, env);
|
|
12962
|
+
});
|
|
12963
|
+
}
|
|
12964
|
+
|
|
12768
12965
|
// src/routes/desktop.ts
|
|
12769
12966
|
function registerDesktopRoutes(app, deps) {
|
|
12770
12967
|
const { core, runtime } = deps;
|
|
@@ -12779,7 +12976,7 @@ function registerDesktopRoutes(app, deps) {
|
|
|
12779
12976
|
record: null
|
|
12780
12977
|
};
|
|
12781
12978
|
}
|
|
12782
|
-
const { installDeps } = await import('./cli-
|
|
12979
|
+
const { installDeps } = await import('./cli-GMRPOISO.js');
|
|
12783
12980
|
const { desktopStatus } = await import('./install-VXJPLYWM.js');
|
|
12784
12981
|
return desktopStatus(installDeps(runtime.entry));
|
|
12785
12982
|
});
|
|
@@ -12787,7 +12984,7 @@ function registerDesktopRoutes(app, deps) {
|
|
|
12787
12984
|
if (!runtime.entry) {
|
|
12788
12985
|
return { ok: false, reason: "unsupported", message: "Desktop shortcuts are not available on this system yet." };
|
|
12789
12986
|
}
|
|
12790
|
-
const { addToDesktop } = await import('./cli-
|
|
12987
|
+
const { addToDesktop } = await import('./cli-GMRPOISO.js');
|
|
12791
12988
|
return addToDesktop(runtime.entry);
|
|
12792
12989
|
});
|
|
12793
12990
|
app.get("/api/desktop", async () => {
|
|
@@ -13080,7 +13277,7 @@ function buildServer(opts) {
|
|
|
13080
13277
|
const { demoProducts } = loadDemoProducts(join(templatesRoot, "demo-products"));
|
|
13081
13278
|
const demoProductById = demoProductResolver(demoProducts);
|
|
13082
13279
|
registerDemoProductRoutes(app, { templatesRoot, demoProducts, demoProductById, thumbs });
|
|
13083
|
-
registerShowcaseRoutes(app, { templatesRoot });
|
|
13280
|
+
registerShowcaseRoutes(app, { templatesRoot, thumbs });
|
|
13084
13281
|
app.get("/api/formats", async () => FORMATS);
|
|
13085
13282
|
function briefInputsOnly(brief) {
|
|
13086
13283
|
const {
|
|
@@ -14260,6 +14457,7 @@ function buildServer(opts) {
|
|
|
14260
14457
|
return drained;
|
|
14261
14458
|
});
|
|
14262
14459
|
registerSystemRoutes(app, { core, thumbs });
|
|
14460
|
+
registerGuideRoutes(app, { core, version: meta.version });
|
|
14263
14461
|
registerDesktopRoutes(app, {
|
|
14264
14462
|
core,
|
|
14265
14463
|
runtime,
|
|
@@ -14427,7 +14625,7 @@ async function run() {
|
|
|
14427
14625
|
}
|
|
14428
14626
|
}
|
|
14429
14627
|
const ownEntry = fileURLToPath(import.meta.url);
|
|
14430
|
-
const { addToDesktop, installDeps } = await import('./cli-
|
|
14628
|
+
const { addToDesktop, installDeps } = await import('./cli-GMRPOISO.js');
|
|
14431
14629
|
const { refreshLauncher } = await import('./refresh-5HBDLLLB.js');
|
|
14432
14630
|
const { askOnTerminal, offerDesktop, shouldOfferDesktop } = await import('./offer-W6NJXMWT.js');
|
|
14433
14631
|
const { launcherInstalled } = await import('./paths-6ZXRZUHY.js');
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { ASPECT_TOLERANCE, BUDGET_EXHAUSTED, EDIT_REFERENCE_ROLE_DIRECTIVE, REFERENCE_ROLE_DIRECTIVE, SCHEMA_VERSION, STEM_MIN, SchemaTooNewError, SpendCapError, TRIGRAM_MIN, budgetSize, createCatalogStore, createCore, createStore, defaultHome, fold, ftsMatch, matchesQuery, ratioLabel, searchTerms, termMatches, uniqueProjectSlug, uniqueSetSlug, uniqueSlug } from './chunk-
|
|
2
|
-
//# sourceMappingURL=src-
|
|
3
|
-
//# sourceMappingURL=src-
|
|
1
|
+
export { ASPECT_TOLERANCE, BUDGET_EXHAUSTED, EDIT_REFERENCE_ROLE_DIRECTIVE, REFERENCE_ROLE_DIRECTIVE, SCHEMA_VERSION, STEM_MIN, SchemaTooNewError, SpendCapError, TRIGRAM_MIN, budgetSize, createCatalogStore, createCore, createStore, defaultHome, fold, ftsMatch, matchesQuery, ratioLabel, searchTerms, termMatches, uniqueProjectSlug, uniqueSetSlug, uniqueSlug } from './chunk-K6IELFL3.js';
|
|
2
|
+
//# sourceMappingURL=src-TC4UQ7H6.js.map
|
|
3
|
+
//# sourceMappingURL=src-TC4UQ7H6.js.map
|