pixelkiln 0.85.0 → 0.86.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/dist/index.cjs CHANGED
@@ -638,8 +638,16 @@ var RevisionDitheringSchema = import_zod.z.enum(["none", "2x2", "4x4", "8x8"]);
638
638
  var RevisionSchema = import_zod.z.object({
639
639
  /** What kind of controlled change the provider workflow performs. */
640
640
  mode: RevisionModeSchema,
641
- /** Parent asset id in the same style. */
641
+ /** Parent asset id. It lives in this asset's own style unless `fromStyle` names another. */
642
642
  from: import_zod.z.string().min(1),
643
+ /**
644
+ * The style the parent lives in, when it is not this asset's own. The
645
+ * parent is generated by that style's provider and model, and this
646
+ * revision starts from its output file, so a chain (generate with one
647
+ * model, clean up with another) is declared instead of restated by hand.
648
+ * Styles may depend on one another but not in a cycle.
649
+ */
650
+ fromStyle: import_zod.z.string().min(1).optional(),
643
651
  /** Manifest-relative black/white PNG. Required only for masked inpainting. */
644
652
  mask: import_zod.z.string().min(1).optional(),
645
653
  /** Provider-neutral edit strength. The active adapter must bind it explicitly. */
@@ -1500,6 +1508,7 @@ var LockEntrySchema = import_zod.z.object({
1500
1508
  revision: import_zod.z.object({
1501
1509
  mode: RevisionModeSchema,
1502
1510
  sourceAssetId: import_zod.z.string().min(1),
1511
+ sourceStyleId: import_zod.z.string().min(1).optional(),
1503
1512
  sourceSha256: import_zod.z.string().regex(/^[0-9a-f]{64}$/),
1504
1513
  maskSha256: import_zod.z.string().regex(/^[0-9a-f]{64}$/).optional(),
1505
1514
  strength: import_zod.z.number().min(0).max(1).optional(),
@@ -3962,6 +3971,7 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
3962
3971
  revision: spec.revision ? {
3963
3972
  mode: spec.revision.mode,
3964
3973
  from: spec.revision.sourceAssetId,
3974
+ fromStyle: spec.revision.sourceStyleId,
3965
3975
  sourceSha256: spec.revision.sourceSha256,
3966
3976
  maskSha256: spec.revision.maskSha256,
3967
3977
  strength: spec.revision.strength,
@@ -8776,13 +8786,24 @@ ${issues}`);
8776
8786
  }
8777
8787
  }
8778
8788
  if (asset.revision) {
8779
- if (!parsed.data.assets[asset.revision.from]) {
8789
+ const parent = parsed.data.assets[asset.revision.from];
8790
+ if (!parent) {
8780
8791
  unknownReferences.push(
8781
8792
  `assets.${assetId}.revision.from: unknown asset "${asset.revision.from}"`
8782
8793
  );
8783
8794
  } else if (asset.revision.from === assetId) {
8784
8795
  unknownReferences.push(`assets.${assetId}.revision.from: an asset cannot revise itself`);
8785
8796
  }
8797
+ const fromStyle = asset.revision.fromStyle;
8798
+ if (fromStyle) {
8799
+ if (!styleIds.has(fromStyle)) {
8800
+ unknownReferences.push(`assets.${assetId}.revision.fromStyle: unknown style "${fromStyle}"`);
8801
+ } else if (parent && parent.styles.length && !parent.styles.includes(fromStyle)) {
8802
+ unknownReferences.push(
8803
+ `assets.${assetId}.revision.fromStyle: "${asset.revision.from}" is not in style "${fromStyle}"`
8804
+ );
8805
+ }
8806
+ }
8786
8807
  }
8787
8808
  for (const shape of ["state", "animation"]) {
8788
8809
  const of = asset[shape]?.of;
@@ -8898,7 +8919,7 @@ async function resolveSpecs(loaded, filter) {
8898
8919
  return provider;
8899
8920
  };
8900
8921
  const specs = [];
8901
- const styleIds = Object.keys(manifest.styles).filter(
8922
+ const requestedStyleIds = Object.keys(manifest.styles).filter(
8902
8923
  (id) => !filter?.styles?.length || filter.styles.includes(id)
8903
8924
  );
8904
8925
  for (const unknownStyle of filter?.styles ?? []) {
@@ -8923,6 +8944,39 @@ async function resolveSpecs(loaded, filter) {
8923
8944
  current = parentAssetId(manifest.assets[current]);
8924
8945
  }
8925
8946
  }
8947
+ const styleDependencies = /* @__PURE__ */ new Map();
8948
+ for (const styleId of Object.keys(manifest.styles)) {
8949
+ const needed = /* @__PURE__ */ new Set();
8950
+ for (const assetId of resolutionAssetIds) {
8951
+ const asset = manifest.assets[assetId];
8952
+ if (asset?.styles.length && !asset.styles.includes(styleId)) continue;
8953
+ const fromStyle = asset?.revision?.fromStyle;
8954
+ if (fromStyle && fromStyle !== styleId) needed.add(fromStyle);
8955
+ }
8956
+ styleDependencies.set(styleId, needed);
8957
+ }
8958
+ const styleIds = [];
8959
+ const emitStyles = new Set(requestedStyleIds);
8960
+ {
8961
+ const placed = /* @__PURE__ */ new Set();
8962
+ const visiting = [];
8963
+ const place = (styleId) => {
8964
+ if (placed.has(styleId)) return;
8965
+ const cycleStart = visiting.indexOf(styleId);
8966
+ if (cycleStart >= 0) {
8967
+ throw new Error(
8968
+ `Styles revise each other in a cycle: ${[...visiting.slice(cycleStart), styleId].join(" -> ")}. revision.fromStyle must form a chain, not a loop.`
8969
+ );
8970
+ }
8971
+ visiting.push(styleId);
8972
+ for (const dependency of styleDependencies.get(styleId) ?? []) place(dependency);
8973
+ visiting.pop();
8974
+ placed.add(styleId);
8975
+ styleIds.push(styleId);
8976
+ };
8977
+ for (const styleId of requestedStyleIds) place(styleId);
8978
+ }
8979
+ const styleFinalizers = /* @__PURE__ */ new Map();
8926
8980
  const styleImageCache = /* @__PURE__ */ new Map();
8927
8981
  async function loadStyleImage(rel, what = "Style image") {
8928
8982
  const abs = import_node_path6.default.resolve(root, rel);
@@ -9310,7 +9364,8 @@ async function resolveSpecs(loaded, filter) {
9310
9364
  `Provider "${activeProvider.id}" does not support ${asset.revision.mode} revisions`
9311
9365
  );
9312
9366
  }
9313
- const sourceSpec = await finalize(asset.revision.from);
9367
+ const sourceStyleId = asset.revision.fromStyle && asset.revision.fromStyle !== styleId ? asset.revision.fromStyle : void 0;
9368
+ const sourceSpec = sourceStyleId ? await styleFinalizers.get(sourceStyleId)(asset.revision.from) : await finalize(asset.revision.from);
9314
9369
  const sourceStem = sourceSpec.quality?.outFile ?? (sourceSpec.source ? import_node_path6.default.resolve(root, sourceSpec.source) : sourceSpec.outFile);
9315
9370
  const sourceMembers = await revisionSourceMembers(sourceStem, `revision source ${asset.revision.from}`);
9316
9371
  const sourceFile = sourceMembers?.[0]?.file ?? sourceStem;
@@ -9332,6 +9387,7 @@ async function resolveSpecs(loaded, filter) {
9332
9387
  resolved.revision = {
9333
9388
  mode: asset.revision.mode,
9334
9389
  sourceAssetId: asset.revision.from,
9390
+ ...sourceStyleId ? { sourceStyleId } : {},
9335
9391
  sourceFile,
9336
9392
  sourceSha256: sourceImage?.hash ?? null,
9337
9393
  sourceWidth: sourceImage?.width ?? null,
@@ -9453,6 +9509,8 @@ async function resolveSpecs(loaded, filter) {
9453
9509
  finalized.add(assetId);
9454
9510
  return resolved;
9455
9511
  };
9512
+ styleFinalizers.set(styleId, finalize);
9513
+ if (!emitStyles.has(styleId)) continue;
9456
9514
  for (const assetId of Object.keys(manifest.assets)) {
9457
9515
  if (!requestedAssetIds.has(assetId) || !styleSpecs.has(assetId)) continue;
9458
9516
  specs.push(await finalize(assetId));
@@ -11284,7 +11342,7 @@ async function inspectRevision(spec, lock, seen) {
11284
11342
  if (!dependency.ready) {
11285
11343
  return {
11286
11344
  ready: false,
11287
- reason: `revision source ${spec.styleId}/${revision.sourceAssetId} is not ready: ${dependency.reason}`
11345
+ reason: `revision source ${revision.sourceStyleId ?? spec.styleId}/${revision.sourceAssetId} is not ready: ${dependency.reason}`
11288
11346
  };
11289
11347
  }
11290
11348
  if (revision.sourceMembers) {
@@ -14195,6 +14253,7 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
14195
14253
  revision: spec.revision ? {
14196
14254
  mode: spec.revision.mode,
14197
14255
  sourceAssetId: spec.revision.sourceAssetId,
14256
+ ...spec.revision.sourceStyleId ? { sourceStyleId: spec.revision.sourceStyleId } : {},
14198
14257
  sourceSha256: spec.revision.sourceSha256,
14199
14258
  ...spec.revision.maskSha256 ? { maskSha256: spec.revision.maskSha256 } : {},
14200
14259
  ...spec.revision.strength == null ? {} : { strength: spec.revision.strength },
@@ -17122,7 +17181,7 @@ async function buildGallerySnapshot(opts) {
17122
17181
  recordedSpecHash: entry?.specHash ?? null,
17123
17182
  currentSpecHash: spec.specHash,
17124
17183
  revision: entry?.revision ?? null,
17125
- revisionParentKey: spec.revision ? lockKey(spec.styleId, spec.revision.sourceAssetId) : entry?.revision ? lockKey(spec.styleId, entry.revision.sourceAssetId) : null,
17184
+ revisionParentKey: spec.revision ? lockKey(spec.revision.sourceStyleId ?? spec.styleId, spec.revision.sourceAssetId) : entry?.revision ? lockKey(entry.revision.sourceStyleId ?? spec.styleId, entry.revision.sourceAssetId) : null,
17126
17185
  mirrorOfKey: spec.mirror ? lockKey(spec.styleId, spec.mirror.sourceAssetId) : entry?.mirror ? lockKey(spec.styleId, entry.mirror.sourceAssetId) : null,
17127
17186
  skeleton: spec.revision?.mode === "animate-skeleton" && spec.revision.keypointsFile ? {
17128
17187
  keypointsFile: portableOutputPath(spec.revision.keypointsFile, root),
@@ -17192,7 +17251,7 @@ async function buildGallerySnapshot(opts) {
17192
17251
  recordedSpecHash: entry.specHash,
17193
17252
  currentSpecHash: null,
17194
17253
  revision: entry.revision,
17195
- revisionParentKey: entry.revision ? lockKey(entry.styleId, entry.revision.sourceAssetId) : null,
17254
+ revisionParentKey: entry.revision ? lockKey(entry.revision.sourceStyleId ?? entry.styleId, entry.revision.sourceAssetId) : null,
17196
17255
  mirrorOfKey: entry.mirror ? lockKey(entry.styleId, entry.mirror.sourceAssetId) : null,
17197
17256
  skeleton: null,
17198
17257
  character: describeCharacter(void 0, entry),