@plinth-music/cli 0.20.0 → 0.20.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 CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  Notable changes to `@plinth-music/cli`. Grouped by what a user notices, not by PR.
4
4
 
5
+ ## 0.20.1 - 2026-09-07
6
+
7
+ One code PR since `0.20.0` (`v0.20.0..fcfc83b`, #185; #183, #184, #186 and #187 docs). A
8
+ patch: no new command and no new sync surface.
9
+
10
+ ⚠️ **Plinth no longer tells you it set aside an edit you did not make.** When a memory store
11
+ switches from a stored blob to a generated index, the daemon refuses the local copy and keeps
12
+ a copy of what it replaced. It was doing that even when your file already matched the
13
+ canonical body byte for byte — so it wrote a conflict stash that preserved nothing and
14
+ reported a lost edit that never existed. Both stop. The canonical body is still written, so
15
+ the daemon's own change is still recognised as its own; nothing else about the refusal moves.
16
+
17
+ Existing conflict stashes are untouched: this changes what the daemon writes from now on and
18
+ prunes nothing. An audit of one live workspace during the 0.20.0 release found 30 stashes, 9
19
+ of them byte-identical to the file they sat beside; those stay until a separate pass decides
20
+ what is safe to remove.
21
+
5
22
  ## 0.20.0 - 2026-09-07
6
23
 
7
24
  Two code PRs since `0.19.0` (`v0.19.0..f583f98`, #180 and #181; #179 docs). A minor: there
@@ -58,8 +75,13 @@ rewrite.
58
75
  - The generated pointer to a fact body no longer states a shape that stops being true the day
59
76
  the index lines carry dates.
60
77
 
61
- The desktop app pins `@plinth-music/cli` exact. v1.12.0 (6 September) pins 0.19.0, so this
62
- release does not reach the app until a further desktop release repins.
78
+ The desktop app pins `@plinth-music/cli` exact, and **v1.13.0 (7 September, the same evening)
79
+ repins it to 0.20.0** — so this release reaches the packaged app as well as npm.
80
+
81
+ *As published to npm, this entry closed by saying the desktop pinned 0.19.0 and that the release
82
+ did not reach the app. That was true at 19:03 and the repin shipped at 19:27. The npm tarball
83
+ keeps the older sentence; `npm unpublish` is a 72-hour window that a superseded line does not
84
+ justify spending.*
63
85
 
64
86
  ## 0.19.0 - 2026-09-06
65
87
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha": "c64be63205838c6c84948c91356c6929dcdf4e58",
2
+ "sha": "ce2c0b25730aa0568e286215be1ad6d1dc066688",
3
3
  "dirty": false,
4
- "built_at": "2026-09-07T18:58:52.384Z"
4
+ "built_at": "2026-09-07T21:05:46.844Z"
5
5
  }
package/dist/cli.js CHANGED
@@ -7584,7 +7584,7 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
7584
7584
  // package.json
7585
7585
  var package_default = {
7586
7586
  name: "@plinth-music/cli",
7587
- version: "0.20.0",
7587
+ version: "0.20.1",
7588
7588
  description: "Plinth capstone sync daemon and CLI",
7589
7589
  type: "module",
7590
7590
  private: false,
@@ -35547,6 +35547,10 @@ function isGeneratedMemoryStash(label, deps) {
35547
35547
 
35548
35548
  // src/lib/memory-facts/refuse.ts
35549
35549
  function refuseGeneratedMemoryEdit(args) {
35550
+ if (args.localContent === args.canonicalBody) {
35551
+ args.writeCanonical(args.canonicalBody);
35552
+ return { state: args.state, stashPath: null };
35553
+ }
35550
35554
  const stashPath = stashConflict({
35551
35555
  workspaceSlug: args.workspaceSlug,
35552
35556
  entityType: args.conflictEntity,
@@ -38398,7 +38402,7 @@ async function pushArtistMemory(args) {
38398
38402
  };
38399
38403
  return {
38400
38404
  state: persistEntry2(refused.state, stamped),
38401
- outcome: { kind: "generated_refused", slug, stashPath: refused.stashPath }
38405
+ outcome: refused.stashPath === null ? { kind: "noop", slug } : { kind: "generated_refused", slug, stashPath: refused.stashPath }
38402
38406
  };
38403
38407
  }
38404
38408
  const acked = entry2.memory_hash;
@@ -40829,7 +40833,7 @@ async function pushWorkspaceMemory(args) {
40829
40833
  });
40830
40834
  return {
40831
40835
  state: next2,
40832
- outcome: { kind: "generated_refused", stashPath: refused.stashPath }
40836
+ outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
40833
40837
  };
40834
40838
  }
40835
40839
  const gate = applySecretGate({
@@ -40897,7 +40901,7 @@ async function pushWorkspaceMemory(args) {
40897
40901
  });
40898
40902
  return {
40899
40903
  state: next2,
40900
- outcome: { kind: "generated_refused", stashPath: refused.stashPath }
40904
+ outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
40901
40905
  };
40902
40906
  }
40903
40907
  {
@@ -40946,7 +40950,7 @@ async function pushWorkspaceMemory(args) {
40946
40950
  });
40947
40951
  return {
40948
40952
  state: next2,
40949
- outcome: { kind: "generated_refused", stashPath: refused.stashPath }
40953
+ outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
40950
40954
  };
40951
40955
  }
40952
40956
  }
@@ -41221,7 +41225,7 @@ async function pushSingleton(descriptor, args) {
41221
41225
  const next2 = persist2(descriptor, refused.state, ackedFrom(cloud, stableHash(cloud.body_md)));
41222
41226
  return {
41223
41227
  state: next2,
41224
- outcome: { kind: "generated_refused", stashPath: refused.stashPath }
41228
+ outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
41225
41229
  };
41226
41230
  }
41227
41231
  let gated = state;
@@ -41284,7 +41288,7 @@ async function pushSingleton(descriptor, args) {
41284
41288
  const next2 = persist2(descriptor, refused.state, ackedFrom(cloud, stableHash(cloud.body_md)));
41285
41289
  return {
41286
41290
  state: next2,
41287
- outcome: { kind: "generated_refused", stashPath: refused.stashPath }
41291
+ outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
41288
41292
  };
41289
41293
  }
41290
41294
  {
@@ -41325,7 +41329,7 @@ async function pushSingleton(descriptor, args) {
41325
41329
  const next2 = persist2(descriptor, refused.state, ackedFrom(cloud, stableHash(cloud.body_md)));
41326
41330
  return {
41327
41331
  state: next2,
41328
- outcome: { kind: "generated_refused", stashPath: refused.stashPath }
41332
+ outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
41329
41333
  };
41330
41334
  }
41331
41335
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plinth-music/cli",
3
- "version": "0.20.0",
3
+ "version": "0.20.1",
4
4
  "description": "Plinth capstone sync daemon and CLI",
5
5
  "type": "module",
6
6
  "private": false,