synthesisui 0.16.177 → 0.16.178

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.
@@ -39,6 +39,8 @@ async function writeGovernanceIgnore(projectRoot) {
39
39
  "# both are rewritten in full on every run and would conflict on every merge.\n" +
40
40
  "census.json\n" +
41
41
  "ledger.jsonl\n" +
42
+ /** O cursor de envio descreve ESTE clone, não o repositório - ver `markSent`. */
43
+ ".ledger-sent\n" +
42
44
  "not-expressed.md\n", "utf8");
43
45
  }
44
46
  /**
@@ -2,7 +2,7 @@ import { readdir, readFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
4
  import { readToken, resolveRegistry } from "../config.js";
5
- import { readEvents } from "../doctor/ledger.js";
5
+ import { unsentEvents } from "../doctor/ledger.js";
6
6
  import { measuredScope } from "../measured-scope.js";
7
7
  import { READER } from "../reader-version.js";
8
8
  /**
@@ -124,7 +124,12 @@ opts = {}) {
124
124
  */
125
125
  run: "npx synthesisui sync",
126
126
  });
127
- const events = await readEvents(root).catch(() => []);
127
+ /**
128
+ * SÓ O QUE NÃO SUBIU - ver `unsentEvents`. Isto contava o arquivo inteiro, e como o ledger é
129
+ * append-only e o `sync` manda tudo (a plataforma deduplica), a linha nunca mais saía da tela e o
130
+ * número só crescia.
131
+ */
132
+ const events = await unsentEvents(root).catch(() => []);
128
133
  if (events.length > 0)
129
134
  out.push({
130
135
  says: `${events.length} checked write${events.length === 1 ? "" : "s"} recorded here and not sent - the platform is scoring this repo on older evidence.`,
@@ -1,7 +1,7 @@
1
1
  import { readdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { join, resolve } from "node:path";
3
3
  import { readToken, resolveRegistry } from "../config.js";
4
- import { readEvents } from "../doctor/ledger.js";
4
+ import { markSent, readEvents } from "../doctor/ledger.js";
5
5
  import { checkableName, closeRequest, readRequests, verifyAndCloseRequests, } from "../doctor/requests.js";
6
6
  import { measuredScope, rememberScope } from "../measured-scope.js";
7
7
  import { body, paint, section, snippet } from "../output.js";
@@ -114,6 +114,11 @@ export async function sync(opts) {
114
114
  console.log(body(err.message ?? `The registry answered ${res.status}.`));
115
115
  return;
116
116
  }
117
+ /**
118
+ * O QUE SUBIU, ANOTADO - senão o `align` continua pedindo o envio do que acabou de ser enviado.
119
+ * Depois da resposta OK, e nunca antes: marcar um envio que falhou perderia os eventos de vez.
120
+ */
121
+ await markSent(root, events);
117
122
  const out = (await res.json());
118
123
  console.log(section("Sync"));
119
124
  console.log(body(`${out.eventsReceived} checks sent, ${out.eventsNew} new. ${out.requestsNow} open request${out.requestsNow === 1 ? "" : "s"}.`));
@@ -46,6 +46,55 @@ export async function appendEvent(root, event) {
46
46
  // is a ledger that gets the hook uninstalled.
47
47
  }
48
48
  }
49
+ /**
50
+ * ATÉ ONDE ESTE REPO JÁ MANDOU - e a ausência disto fazia o `align` mentir para sempre.
51
+ *
52
+ * O ledger é APPEND-ONLY e o `sync` manda o arquivo inteiro; a plataforma deduplica (em 07/08 uma
53
+ * rodada reportou "6 checks sent, 1 new"). Só que o `align` contava TODAS as linhas e dizia "6
54
+ * checked writes recorded here and not sent" - sobre cinco que tinham subido minutos antes. O número
55
+ * só crescia, então aquela linha nunca mais sairia da tela, e um aviso permanente é um aviso que a
56
+ * pessoa aprende a pular (dono, 07/08: *"quer apostar que você vai achar algo errado?"*).
57
+ *
58
+ * A CONTAGEM E A HORA, as duas: a contagem responde sozinha enquanto o arquivo só cresce, e a hora
59
+ * dá como perceber que ele foi trocado por outro - aí a contagem antiga não vale mais nada.
60
+ */
61
+ const SENT_FILE = ".ledger-sent";
62
+ const sentPath = (root) => join(root, "_synthesisui", SENT_FILE);
63
+ export async function readSent(root) {
64
+ const raw = await readFile(sentPath(root), "utf8").catch(() => "");
65
+ if (!raw)
66
+ return { count: 0 };
67
+ try {
68
+ const v = JSON.parse(raw);
69
+ return {
70
+ count: typeof v.count === "number" && v.count >= 0 ? v.count : 0,
71
+ ...(typeof v.at === "string" ? { at: v.at } : {}),
72
+ };
73
+ }
74
+ catch {
75
+ return { count: 0 };
76
+ }
77
+ }
78
+ export async function markSent(root, events) {
79
+ const last = events[events.length - 1]?.at;
80
+ await writeFile(sentPath(root), `${JSON.stringify({ count: events.length, ...(last ? { at: last } : {}) })}\n`, "utf8").catch(() => {
81
+ /** O registro nunca pode custar o envio: o pior caso é o aviso reaparecer uma vez. */
82
+ });
83
+ }
84
+ /**
85
+ * Os eventos que este repo ainda não mandou.
86
+ *
87
+ * Se a contagem gravada é maior que o arquivo, alguém o trocou ou apagou - e aí a marca não descreve
88
+ * mais este arquivo. Contar tudo de novo é a leitura honesta: um envio a mais custa nada, e a
89
+ * plataforma deduplica.
90
+ */
91
+ export async function unsentEvents(root) {
92
+ const all = await readEvents(root);
93
+ const { count } = await readSent(root);
94
+ if (count <= 0 || count > all.length)
95
+ return all;
96
+ return all.slice(count);
97
+ }
49
98
  export async function readEvents(root) {
50
99
  const raw = await readFile(ledgerPath(root), "utf8").catch(() => "");
51
100
  if (!raw)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.177",
3
+ "version": "0.16.178",
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": {