pixelkiln 0.89.1 → 0.89.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/dist/index.cjs CHANGED
@@ -73,6 +73,7 @@ __export(index_exports, {
73
73
  LockEntrySchema: () => LockEntrySchema,
74
74
  LockHistoryEntrySchema: () => LockHistoryEntrySchema,
75
75
  LockSchema: () => LockSchema,
76
+ LockTerrainSettingsSchema: () => LockTerrainSettingsSchema,
76
77
  MAX_DOWNLOAD_BYTES: () => MAX_DOWNLOAD_BYTES,
77
78
  MAX_HAND_EDIT_BYTES: () => MAX_HAND_EDIT_BYTES,
78
79
  MAX_RETRIES: () => MAX_RETRIES,
@@ -344,6 +345,7 @@ __export(index_exports, {
344
345
  summarize: () => summarize,
345
346
  tagAdopted: () => tagAdopted,
346
347
  terrainCost: () => terrainCost,
348
+ terrainSettings: () => terrainSettings,
347
349
  terrainTileCount: () => terrainTileCount,
348
350
  tileFeatureOutputCount: () => tileFeatureOutputCount,
349
351
  tileVariationCount: () => tileVariationCount,
@@ -1693,6 +1695,18 @@ var LockTerrainConnectSchema = import_zod.z.record(
1693
1695
  TerrainSideSchema,
1694
1696
  import_zod.z.object({ sourceAssetId: import_zod.z.string().min(1), sourceObjectId: import_zod.z.string().min(1) }).strict()
1695
1697
  );
1698
+ var LockTerrainSettingsSchema = import_zod.z.object({
1699
+ terrainMode: import_zod.z.string().optional(),
1700
+ terrainShapeStyle: import_zod.z.string().optional(),
1701
+ terrainSpreadX: import_zod.z.number().optional(),
1702
+ terrainSlopeSize: import_zod.z.number().optional(),
1703
+ terrainRaggedness: import_zod.z.number().optional(),
1704
+ terrainTransitionSize: import_zod.z.number().optional(),
1705
+ terrainView: import_zod.z.string().optional(),
1706
+ terrainLowerDescription: import_zod.z.string().optional(),
1707
+ terrainUpperDescription: import_zod.z.string().optional(),
1708
+ terrainTransitionDescription: import_zod.z.string().optional()
1709
+ });
1696
1710
  var LockHistoryEntrySchema = import_zod.z.object({
1697
1711
  specHash: import_zod.z.string(),
1698
1712
  generator: GeneratorSchema,
@@ -1717,6 +1731,8 @@ var LockHistoryEntrySchema = import_zod.z.object({
1717
1731
  postprocess: PostprocessSchema.optional(),
1718
1732
  /** A connected terrain set's other sets; see LockEntrySchema.terrainConnect. */
1719
1733
  terrainConnect: LockTerrainConnectSchema.optional(),
1734
+ /** A terrain set's settings outside specHash; see LockEntrySchema.terrainSettings. */
1735
+ terrainSettings: LockTerrainSettingsSchema.optional(),
1720
1736
  /** When the replacement was submitted. */
1721
1737
  retiredAt: import_zod.z.string()
1722
1738
  });
@@ -1791,6 +1807,14 @@ var LockEntrySchema = import_zod.z.object({
1791
1807
  * Absent (not null) otherwise, so other entries do not grow the key.
1792
1808
  */
1793
1809
  terrainConnect: LockTerrainConnectSchema.optional(),
1810
+ /**
1811
+ * For a terrain set: the settings it was submitted with that `specHash`
1812
+ * leaves out (see LockTerrainSettingsSchema). The plan marks the entry
1813
+ * stale when the manifest's differ. Absent on entries submitted before
1814
+ * it was recorded, which are taken as current, and on every other
1815
+ * generator's entries.
1816
+ */
1817
+ terrainSettings: LockTerrainSettingsSchema.optional(),
1794
1818
  /**
1795
1819
  * Output hashes owned by the previous generation while its replacement is
1796
1820
  * pending. They authorize replacing only unchanged PixelKiln-owned files.
@@ -4315,8 +4339,9 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
4315
4339
  uiColorPalette: spec.uiColorPalette,
4316
4340
  // The older terrain knobs (terrainMode, terrainTransitionSize, and the
4317
4341
  // rest) were never part of this hash, and adding them now would make
4318
- // every existing terrain entry stale. The Pro shape controls added
4319
- // after them are identity, each only when set.
4342
+ // every existing terrain entry stale; terrainSettings below records
4343
+ // them per entry instead. The Pro shape controls added after them are
4344
+ // identity, each only when set.
4320
4345
  terrainRoundness: spec.terrainRoundness,
4321
4346
  terrainBoundaryAmplitude: spec.terrainBoundaryAmplitude,
4322
4347
  terrainBoundarySeed: spec.terrainBoundarySeed,
@@ -4442,6 +4467,22 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
4442
4467
  })
4443
4468
  );
4444
4469
  }
4470
+ function terrainSettings(spec) {
4471
+ if (spec.generator !== "terrain") return void 0;
4472
+ const settings = {
4473
+ terrainMode: spec.terrainMode,
4474
+ terrainShapeStyle: spec.terrainShapeStyle,
4475
+ terrainSpreadX: spec.terrainSpreadX,
4476
+ terrainSlopeSize: spec.terrainSlopeSize,
4477
+ terrainRaggedness: spec.terrainRaggedness,
4478
+ terrainTransitionSize: spec.terrainTransitionSize,
4479
+ terrainView: spec.terrainView,
4480
+ terrainLowerDescription: spec.terrainLowerDescription,
4481
+ terrainUpperDescription: spec.terrainUpperDescription,
4482
+ terrainTransitionDescription: spec.terrainTransitionDescription
4483
+ };
4484
+ return Object.fromEntries(Object.entries(settings).filter(([, value]) => value !== void 0));
4485
+ }
4445
4486
 
4446
4487
  // src/pixellab-mcp.ts
4447
4488
  var PIXELLAB_MCP_URL = "https://api.pixellab.ai/mcp";
@@ -13364,6 +13405,15 @@ function changedTerrainConnection(spec, entry, lock) {
13364
13405
  }
13365
13406
  return null;
13366
13407
  }
13408
+ function changedTerrainSettings(spec, entry) {
13409
+ const recorded = entry.terrainSettings;
13410
+ const current = terrainSettings(spec);
13411
+ if (!recorded || !current) return null;
13412
+ const show = (value) => value === void 0 ? "unset" : JSON.stringify(value);
13413
+ const fields = /* @__PURE__ */ new Set([...Object.keys(recorded), ...Object.keys(current)]);
13414
+ const changes = [...fields].filter((field) => recorded[field] !== current[field]).map((field) => `${field} changed from ${show(recorded[field])} to ${show(current[field])}`);
13415
+ return changes.length ? changes.join("; ") : null;
13416
+ }
13367
13417
  function resumeCommandForStatus(status) {
13368
13418
  if (status === "pending" || status === "processing") return "poll";
13369
13419
  if (status === "review") return "pick";
@@ -13396,6 +13446,7 @@ async function buildPlan(specs, lock, opts = {}) {
13396
13446
  let state;
13397
13447
  let reason;
13398
13448
  const changedConnection = entry ? changedTerrainConnection(spec, entry, lock) : null;
13449
+ const changedSettings = entry ? changedTerrainSettings(spec, entry) : null;
13399
13450
  const revision = await inspectRevisionReadiness(spec, lock);
13400
13451
  if (revision && !revision.ready) {
13401
13452
  state = "blocked";
@@ -13434,6 +13485,9 @@ async function buildPlan(specs, lock, opts = {}) {
13434
13485
  } else if (changedConnection) {
13435
13486
  state = "stale";
13436
13487
  reason = `connected set ${changedConnection} was regenerated; draw this set from its new terrain`;
13488
+ } else if (changedSettings) {
13489
+ state = "stale";
13490
+ reason = changedSettings;
13437
13491
  } else if (entry.status === "download-failed") {
13438
13492
  state = "recoverable";
13439
13493
  const force = entry.error?.includes("pass --force") ? " --force" : "";
@@ -14903,6 +14957,7 @@ function retireGeneration(entry, retiredAt) {
14903
14957
  provider: entry.provider,
14904
14958
  postprocess: entry.postprocess,
14905
14959
  ...entry.terrainConnect ? { terrainConnect: entry.terrainConnect } : {},
14960
+ ...entry.terrainSettings ? { terrainSettings: entry.terrainSettings } : {},
14906
14961
  retiredAt
14907
14962
  };
14908
14963
  }
@@ -14997,6 +15052,9 @@ async function revertGeneration(provider, spec, lock, lockPath, opts) {
14997
15052
  // A connected set comes back with the connection it was drawn from, so
14998
15053
  // the plan compares the restored generation, not the one it replaced.
14999
15054
  terrainConnect: generation.terrainConnect,
15055
+ // Likewise its settings; a generation from before they were recorded
15056
+ // comes back with none and is taken as current.
15057
+ terrainSettings: generation.terrainSettings,
15000
15058
  history
15001
15059
  });
15002
15060
  await saveLock(lockPath, lock);
@@ -16074,6 +16132,9 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
16074
16132
  referenceSha256: spec.character.outfit.reference.sha256
16075
16133
  } : null,
16076
16134
  terrainConnect: spec.terrainConnect ? terrainConnect : void 0,
16135
+ // The terrain knobs specHash leaves out, so the plan can tell a
16136
+ // changed one; undefined (no key) for every other generator.
16137
+ terrainSettings: terrainSettings(spec),
16077
16138
  status: "pending",
16078
16139
  jobId: previousJobId ?? null,
16079
16140
  ...previousJobId ? { submissionComplete: false } : { submissionComplete: void 0 },
@@ -21086,6 +21147,7 @@ async function workspaceStatus(ws, dir) {
21086
21147
  LockEntrySchema,
21087
21148
  LockHistoryEntrySchema,
21088
21149
  LockSchema,
21150
+ LockTerrainSettingsSchema,
21089
21151
  MAX_DOWNLOAD_BYTES,
21090
21152
  MAX_HAND_EDIT_BYTES,
21091
21153
  MAX_RETRIES,
@@ -21357,6 +21419,7 @@ async function workspaceStatus(ws, dir) {
21357
21419
  summarize,
21358
21420
  tagAdopted,
21359
21421
  terrainCost,
21422
+ terrainSettings,
21360
21423
  terrainTileCount,
21361
21424
  tileFeatureOutputCount,
21362
21425
  tileVariationCount,