synthesisui 0.12.0 → 0.12.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.
@@ -6,6 +6,64 @@ import { diffLocalDocuments, localChangelogMarkdown, } from "../document-diff.js
6
6
  import { body, section, snippet } from "../output.js";
7
7
  import { fetchChangelog, fetchComponent, fetchDesignSystem, RegistryError, } from "../registry.js";
8
8
  import { add } from "./add.js";
9
+ /**
10
+ * The highest `v<n>` below `installed` among the folder names given, or the one
11
+ * asked for. Pure, so the version arithmetic can be tested without a disk.
12
+ */
13
+ export function pickSnapshot(names, installed, asked) {
14
+ const versions = names
15
+ .map((n) => /^v(\d+)$/.exec(n))
16
+ .filter((m) => m !== null)
17
+ .map((m) => Number(m[1]))
18
+ .filter((v) => v < installed)
19
+ .sort((a, b) => b - a);
20
+ if (asked !== undefined)
21
+ return versions.includes(asked) ? asked : null;
22
+ return versions[0] ?? null;
23
+ }
24
+ /**
25
+ * Re-diff two snapshots already on disk and rewrite UPGRADE.md. Touches
26
+ * nothing else: the artifacts are already correct, it is only the brief about
27
+ * them that was written by an older, wronger version of this tool.
28
+ */
29
+ async function rewriteBrief(slug, slugDir, from, to) {
30
+ const read = async (v) => JSON.parse(await readFile(join(slugDir, `v${v}`, "design-system.json"), "utf8"));
31
+ let local;
32
+ try {
33
+ local = diffLocalDocuments(await read(from), await read(to));
34
+ }
35
+ catch {
36
+ console.log(`✗ could not read both snapshots (v${from}, v${to}).`);
37
+ return;
38
+ }
39
+ const brief = [
40
+ localChangelogMarkdown(slug, from, to, local),
41
+ "",
42
+ "---",
43
+ "",
44
+ "## How to migrate this app",
45
+ "",
46
+ "- Fix the **Breaking** items first: search the codebase for each removed",
47
+ " token/component/variant and move usages to the closest replacement.",
48
+ "- Changed tokens re-theme automatically (CSS variables) - review screens",
49
+ " that hardcoded values instead of tokens.",
50
+ "- The full new contract lives in `design-system.json` / `GUIDE.md` next to this file.",
51
+ "",
52
+ ].join("\n");
53
+ await writeFile(join(slugDir, "UPGRADE.md"), brief, "utf8");
54
+ console.log(section(`Rewrote the brief: ${slug} v${from} → v${to}`));
55
+ if (local.breaking.length > 0) {
56
+ console.log(body(`Breaking changes (${local.breaking.length}):`));
57
+ console.log("");
58
+ console.log(snippet(local.breaking.map((i) => `- ${i}`)));
59
+ }
60
+ else {
61
+ console.log(body("No breaking changes between those two versions."));
62
+ }
63
+ console.log("");
64
+ console.log(body(`_synthesisui/ds/${slug}/UPGRADE.md`));
65
+ console.log("");
66
+ }
9
67
  /**
10
68
  * Marco B - `synthesisui upgrade <slug>`: brings the installed system to the
11
69
  * latest version, GUIDED. In one run it:
@@ -38,7 +96,25 @@ export async function upgrade(slug, opts) {
38
96
  console.log(`→ checking "${slug}" (installed: v${installed}) …`);
39
97
  const latest = await fetchDesignSystem(base, slug);
40
98
  if (latest.version === installed) {
41
- console.log(`✓ ${slug} is already at the latest version (v${installed}).`);
99
+ if (!opts.force) {
100
+ console.log(`✓ ${slug} is already at the latest version (v${installed}).`);
101
+ return;
102
+ }
103
+ // The brief is a PHOTOGRAPH: written once, at the moment of the upgrade,
104
+ // and it ages. When the tool that wrote it is fixed - as the breaking-change
105
+ // diff was on 25/07, after it had announced ten changes that were not
106
+ // breaking - the file on disk keeps the old answer and there is no way back
107
+ // to it, because there is no version gap left to trigger a rewrite. This is
108
+ // that way back: re-diff from the highest older snapshot still on disk.
109
+ const onDisk = await readdir(slugDir).catch(() => []);
110
+ const from = pickSnapshot(onDisk, installed, opts.from);
111
+ if (from === null) {
112
+ console.log(opts.from !== undefined
113
+ ? `✗ v${opts.from} is not on disk under ${slugDir}.`
114
+ : `✗ nothing to diff against: no snapshot older than v${installed} on disk.`);
115
+ return;
116
+ }
117
+ await rewriteBrief(slug, slugDir, from, installed);
42
118
  return;
43
119
  }
44
120
  if (latest.version < installed) {
package/dist/index.js CHANGED
@@ -52,6 +52,8 @@ Options:
52
52
  --instruction <s> refit: extra guidance for the adaptation
53
53
  --dry refit: adapt and print, but save nothing
54
54
  --force clean: apply the changes (without it, dry run)
55
+ upgrade: rewrite UPGRADE.md even with no version gap left
56
+ --from <n> upgrade --force: which older snapshot to diff from
55
57
  --strict doctor: exit 1 when drift is found in THIS repo (for CI)
56
58
  --strict-system doctor: also exit 1 when the system itself is inconsistent
57
59
  --verbose doctor: every finding, file by file (default is a summary)
@@ -267,7 +269,12 @@ async function main() {
267
269
  process.exitCode = 1;
268
270
  return;
269
271
  }
270
- await upgrade(slug, { registry, dir });
272
+ await upgrade(slug, {
273
+ registry,
274
+ dir,
275
+ force: flags.force === true,
276
+ from: typeof flags.from === "string" ? Number(flags.from) : undefined,
277
+ });
271
278
  break;
272
279
  }
273
280
  case "use": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Bring SynthesisUI design systems into any project - tokens, typed components, whole pages and an agent-ready CLAUDE.md manifest.",
5
5
  "type": "module",
6
6
  "bin": {