@magicpixelart/cli 0.5.32 → 0.5.34

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 CHANGED
@@ -5,6 +5,19 @@ All notable changes to `@magicpixelart/cli` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [0.5.34] - 2026-10-06
9
+
10
+ ### Fixed
11
+ - `push --force` no longer fails with "Too many sprites (max 20 per request)" when more than 20 files are retried; the retry round is now sent in small batches.
12
+
13
+ ## [0.5.33] - 2026-10-06
14
+
15
+ ### Fixed
16
+ - Local edits to game files that were never changed in MagicPixel no longer fail as "also changed in MagicPixel". Push now sends the cloud timestamp it last saw, and sync no longer records the local file as MagicPixel's copy when the server has no cached hash.
17
+
18
+ ### Changed
19
+ - Watch header now reads "N game sprites connected" — it counts game PNGs matched by `connect`, not files waiting in MagicPixel.
20
+
8
21
  ## [0.5.32] - 2026-10-05
9
22
 
10
23
  ### Fixed
package/dist/api.js CHANGED
@@ -423,6 +423,15 @@ function isTransientPushError(e) {
423
423
  export async function pushSpritesAdaptive(sprites, retryOpts) {
424
424
  if (sprites.length === 0)
425
425
  return [];
426
+ // Never send more than one batch per request — callers (e.g. the --force
427
+ // retry round) may hand over every refused sprite at once.
428
+ if (sprites.length > PUSH_BATCH_SIZE) {
429
+ const out = [];
430
+ for (let i = 0; i < sprites.length; i += PUSH_BATCH_SIZE) {
431
+ out.push(...(await pushSpritesAdaptive(sprites.slice(i, i + PUSH_BATCH_SIZE), retryOpts)));
432
+ }
433
+ return out;
434
+ }
426
435
  try {
427
436
  return await pushSprites(sprites, retryOpts);
428
437
  }
@@ -215,6 +215,7 @@ export async function runPushWith(config, state, opts = {}) {
215
215
  assetId: a.assetId,
216
216
  layerIdx: a.layerIdx,
217
217
  baseSha256: a.baseSha256,
218
+ ...(a.baseUpdatedAt ? { baseUpdatedAt: a.baseUpdatedAt } : {}),
218
219
  flatten: opts.flatten === true,
219
220
  ...(opts.replace ? { replace: true } : {}),
220
221
  });
@@ -1377,12 +1377,14 @@ async function runOnce(opts, runOpts = {}) {
1377
1377
  // After a write, the actual downloaded bytes are the disk/cloud baseline.
1378
1378
  // The manifest hash may be null or represent a cached composite while the
1379
1379
  // download endpoint serves storage bytes for a single-artboard document.
1380
+ const prev = nextSynced[entry.key];
1381
+ // Never let the local game file stand in for MagicPixel's composite when
1382
+ // the manifest has no cached hash: keep the last real cloud baseline.
1380
1383
  const sha = writtenKeys.has(entry.key)
1381
1384
  ? await fileSha256(pathFor(entry))
1382
- : (entry.sha256 ?? (await fileSha256(pathFor(entry))));
1385
+ : (entry.sha256 ?? prev?.sha256 ?? (await fileSha256(pathFor(entry))));
1383
1386
  if (!sha)
1384
1387
  continue;
1385
- const prev = nextSynced[entry.key];
1386
1388
  const diskSha256 = writtenKeys.has(entry.key)
1387
1389
  ? sha
1388
1390
  : (shaByEntryId.get(entry.id) ?? prev?.diskSha256 ?? sha);
@@ -151,6 +151,7 @@ export function planPush(candidates, synced, opts = {}) {
151
151
  // A later explicit `push` can then safely keep the local copy without
152
152
  // bypassing the server's optimistic-concurrency check.
153
153
  baseSha256: known.pendingCloudSha256 ?? known.sha256,
154
+ ...(known.cloudUpdatedAt && !known.pendingCloudSha256 ? { baseUpdatedAt: known.cloudUpdatedAt } : {}),
154
155
  });
155
156
  continue;
156
157
  }
@@ -13,10 +13,10 @@ export function formatWatchSpriteLine(c) {
13
13
  if (set === 0 && pulled === 0)
14
14
  return null;
15
15
  if (set > 0 && pulled > 0 && set !== pulled) {
16
- return ` Sprites: ${fmt(set)} in your game · ${fmt(pulled)} last pulled from MagicPixel`;
16
+ return ` Sprites: ${fmt(set)} game sprites connected · ${fmt(pulled)} last pulled from MagicPixel`;
17
17
  }
18
18
  if (set > 0)
19
- return ` Sprites: ${fmt(set)} in your game`;
19
+ return ` Sprites: ${fmt(set)} game sprites connected`;
20
20
  return ` Sprites: ${fmt(pulled)}`;
21
21
  }
22
22
  /** How long a single watch tick may run before the heartbeat starts printing. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magicpixelart/cli",
3
- "version": "0.5.32",
3
+ "version": "0.5.34",
4
4
  "description": "Sync MagicPixel pixel-art assets to your local project.",
5
5
  "type": "module",
6
6
  "bin": {