synthesisui 0.13.0 → 0.14.0

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.
@@ -206,6 +206,12 @@ export async function add(slug, opts) {
206
206
  console.log(line(` Prefer next/font or self-hosting? Fine - just register these exact families: ${customFontFamilies(families).join(", ")}.`));
207
207
  }
208
208
  console.log(section("Next"));
209
+ // FIRST, and before anything that assumes the setup worked. The block above
210
+ // is four manual edits across two files, one of them with a relative path
211
+ // the command itself has to warn about. Without a way to check, the person
212
+ // does not know whether they finished - and the next thing they see is a
213
+ // coverage number that reads 0% when an import is missing.
214
+ console.log(line(`synthesisui doctor confirm the setup above actually took`));
209
215
  console.log(line(`synthesisui component ${payload.slug} button bring a component in as YOUR code`));
210
216
  console.log(line(`synthesisui template ${payload.slug} landing materialize a whole page`));
211
217
  console.log("");
@@ -257,11 +257,32 @@ export async function doctor(opts) {
257
257
  const overrides = [];
258
258
  const used = new Map();
259
259
  const known = new Set(recipes.keys());
260
+ /**
261
+ * INSTALLED IS NOT THE SAME AS WORKING.
262
+ *
263
+ * `init` ends in four manual edits across two files. Skip them - or get the
264
+ * relative path in the import wrong, which the command itself warns about -
265
+ * and the next run reports "Token coverage 0%" with no explanation
266
+ * (reproduced 27/07 on a fresh project). The tool knows the system is
267
+ * installed, because it just read 85 tokens out of it, and reports a number
268
+ * that reads as failure when the truth is an unfinished setup.
269
+ *
270
+ * Nobody debugs from 0%. They conclude the product does not work.
271
+ */
272
+ const wiring = { imported: false, scoped: false };
260
273
  for await (const file of scopes.length > 0 ? walkAll(scopes) : walk(root)) {
261
274
  const src = await readFile(file, "utf8").catch(() => "");
262
275
  if (!src)
263
276
  continue;
264
277
  const rel = relative(root, file);
278
+ // The two facts that decide whether an installed system reaches the
279
+ // browser at all. Free: these files are already open and in memory.
280
+ if (table.slug) {
281
+ if (src.includes(`_synthesisui/ds/${table.slug}/tokens.css`))
282
+ wiring.imported = true;
283
+ if (src.includes(`data-ds="${table.slug}"`))
284
+ wiring.scoped = true;
285
+ }
265
286
  reports.push(scanSource(rel, src, table));
266
287
  if (recipes.size > 0) {
267
288
  for (const o of findOverrides(src, recipes))
@@ -329,6 +350,25 @@ export async function doctor(opts) {
329
350
  // 0 of 0 is not a perfect score, it is an empty measurement - printing a
330
351
  // full bar there would be the report's first lie.
331
352
  const measurable = d.tokenUses + d.findings.length > 0;
353
+ // Before the number, because the number is the thing that misleads. An
354
+ // installed-but-unwired system reads 0%, and 0% reads as "broken product"
355
+ // rather than "one import missing".
356
+ const unwired = table.source === "installed" && (!wiring.imported || !wiring.scoped);
357
+ if (unwired) {
358
+ console.log("");
359
+ console.log(body(`${table.name ?? table.slug} is installed - but not wired up yet.`));
360
+ console.log("");
361
+ console.log(body(wiring.imported
362
+ ? ` ✓ some stylesheet imports _synthesisui/ds/${table.slug}/tokens.css`
363
+ : ` ✗ no stylesheet imports _synthesisui/ds/${table.slug}/tokens.css`));
364
+ console.log(body(wiring.scoped
365
+ ? ` ✓ data-ds="${table.slug}" found`
366
+ : ` ✗ no element carries data-ds="${table.slug}"`));
367
+ console.log("");
368
+ console.log(body(`Until both are true, none of the ${table.byName.size} tokens reach the browser`));
369
+ console.log(body("and the number below cannot mean anything."));
370
+ console.log(body("The exact snippets are in the output of `init`."));
371
+ }
332
372
  if (hasSystem && measurable) {
333
373
  console.log("");
334
374
  console.log(body(`Token coverage ${meter(d.coverage)} ${String(d.coverage).padStart(3)}%`));
@@ -661,6 +701,42 @@ export async function doctor(opts) {
661
701
  }
662
702
  console.log("");
663
703
  console.log(body("synthesisui doctor --verbose every finding, file by file"));
704
+ /**
705
+ * THE READER WHO GOT A NUMBER AND NOWHERE TO GO.
706
+ *
707
+ * Someone with no system at all is told to start one. Someone running OUR
708
+ * system has commands everywhere. The person in between - who already owns
709
+ * a design system, which is precisely the ICP - got the report and silence,
710
+ * and closed the terminal (walked 27/07).
711
+ *
712
+ * The sentence follows from THEIR number rather than pitching: the value
713
+ * is not that we would name these, it is that their agent has no way to
714
+ * know they should be named. That is also the line worth pasting into a
715
+ * thread, which is the other job this paragraph does.
716
+ */
717
+ if (table.source === "yours") {
718
+ const named = d.findings.filter((f) => f.token).length;
719
+ const anonymous = d.findings.length - named;
720
+ console.log("");
721
+ console.log(body(named > 0
722
+ ? `${named} of these already have a name in your own system.`
723
+ : "None of these have a name in your system yet."));
724
+ if (anonymous > 0) {
725
+ console.log(body(`The other ${anonymous} do not - and your coding agent has no way to know they should.`));
726
+ }
727
+ console.log("");
728
+ // Careful about what is being offered. This reader ALREADY has a design
729
+ // system, so "install ours" would mean replacing theirs, and a CTA that
730
+ // pretends otherwise is the kind of confident overclaim that costs
731
+ // trust the first time somebody follows it. What they are missing is
732
+ // not tokens - it is a contract their agent reads before writing UI.
733
+ console.log(body("Your tokens exist. What your agent is missing is a contract:"));
734
+ console.log(body("rules it reads BEFORE writing UI, and a manifest of what exists."));
735
+ console.log("");
736
+ console.log(snippet(["npx synthesisui@latest init --ds <slug>"]));
737
+ console.log(body("starts you on a system that ships one - browse them at"));
738
+ console.log(body("https://www.synthesisui.com/gallery"));
739
+ }
664
740
  console.log("");
665
741
  }
666
742
  if (opts.strict) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
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": {