synthesisui 0.16.140 → 0.16.141
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/dist/commands/import.js +1 -1
- package/dist/commands/sync.js +145 -1
- package/dist/index.js +19 -4
- package/package.json +1 -1
package/dist/commands/import.js
CHANGED
|
@@ -2254,7 +2254,7 @@ function rootBehaviour(tag, sketch) {
|
|
|
2254
2254
|
? { rootProps: first.behaviourProps }
|
|
2255
2255
|
: {};
|
|
2256
2256
|
}
|
|
2257
|
-
async function resolveReadParts(census, root) {
|
|
2257
|
+
export async function resolveReadParts(census, root) {
|
|
2258
2258
|
/**
|
|
2259
2259
|
* A READING IS OPTIONAL HERE. THE SKETCH IS NOT.
|
|
2260
2260
|
*
|
package/dist/commands/sync.js
CHANGED
|
@@ -3,8 +3,9 @@ import { join, resolve } from "node:path";
|
|
|
3
3
|
import { readToken, resolveRegistry } from "../config.js";
|
|
4
4
|
import { readEvents } from "../doctor/ledger.js";
|
|
5
5
|
import { checkableName, closeRequest, readRequests, verifyAndCloseRequests, } from "../doctor/requests.js";
|
|
6
|
-
import { body, section } from "../output.js";
|
|
6
|
+
import { body, paint, section } from "../output.js";
|
|
7
7
|
import { repoStateOf } from "../repo-state.js";
|
|
8
|
+
import { resolveReadParts, takeCensus } from "./import.js";
|
|
8
9
|
/**
|
|
9
10
|
* What each decision means ON THIS MACHINE - the card decides, the sync
|
|
10
11
|
* enacts. The web never touches the local file; this line is printed right
|
|
@@ -83,6 +84,19 @@ export async function sync(opts) {
|
|
|
83
84
|
console.log(body("No installed system here, so there is nowhere to sync to."));
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* A MEDIÇÃO NOVA, ANTES DO REGISTRO - e é isto que faz um conserto de leitura alcançar alguém.
|
|
89
|
+
*
|
|
90
|
+
* Um leitor novo do CLI precisa OLHAR o repo: o que a plataforma guarda é o censo, e o fonte fica
|
|
91
|
+
* aqui por decisão de privacidade. Essa passada é irredutível. O que era redutível é a cerimônia -
|
|
92
|
+
* até hoje "re-importar" significava a skill inteira, seis perguntas, e um agente reescrevendo 261
|
|
93
|
+
* anatomias que já estavam gravadas (dono, 05/08).
|
|
94
|
+
*
|
|
95
|
+
* Então: a plataforma devolve o que já foi decidido (o escopo e a leitura), o CLI mede com o leitor
|
|
96
|
+
* ATUAL, funde a leitura no censo fresco, AVISA o que seria reescrito, e envia. Sem entrevista.
|
|
97
|
+
*/
|
|
98
|
+
if (!opts.recordOnly)
|
|
99
|
+
await remeasure({ root, base, token, slug, cli: opts.cli });
|
|
86
100
|
// Verification first, so the snapshot never reports "open" about something
|
|
87
101
|
// the installed css already delivers - a request closes because a machine
|
|
88
102
|
// CHECKED, not because someone remembered to say so (dono, 29/07).
|
|
@@ -152,3 +166,133 @@ export async function sync(opts) {
|
|
|
152
166
|
console.log(body(`The record lives on your system's overview:`));
|
|
153
167
|
console.log(body(` ${base}/dashboard/mine/${slug}`));
|
|
154
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* MEDE DE NOVO, AVISA, E ENVIA - o corpo do `sync` que faz um leitor novo chegar num sistema.
|
|
171
|
+
*
|
|
172
|
+
* A ordem é a lei aqui, e cada passo existe por um caso real:
|
|
173
|
+
*
|
|
174
|
+
* 1. a plataforma devolve o ESCOPO e a LEITURA já gravados. Sem isto, o `sync` teria que
|
|
175
|
+
* perguntar de novo o que já foi decidido, e um agente reescreveria 261 anatomias.
|
|
176
|
+
* 2. mede com o leitor ATUAL - é o único passo que precisa estar nesta máquina, porque o fonte
|
|
177
|
+
* dele não sai daqui.
|
|
178
|
+
* 3. funde a leitura gravada no censo fresco. A anatomia é do agente; a medição é nossa.
|
|
179
|
+
* 4. AVISA antes de enviar o que seria reescrito, e pergunta. Avisar depois de escrever não é
|
|
180
|
+
* avisar.
|
|
181
|
+
* 5. envia para a rota que atualiza o RASCUNHO pelo slug - nada publicado se move.
|
|
182
|
+
*/
|
|
183
|
+
async function remeasure(args) {
|
|
184
|
+
const { root, base, token, slug } = args;
|
|
185
|
+
const head = await fetch(`${base}/api/registry/ds/${slug}/reading`, {
|
|
186
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
187
|
+
}).catch(() => null);
|
|
188
|
+
if (!head?.ok) {
|
|
189
|
+
console.log(section("Sync"));
|
|
190
|
+
console.log(body(head
|
|
191
|
+
? `The registry answered ${head.status} for this system's reading, so nothing was re-measured. The record below still travels.`
|
|
192
|
+
: "Could not reach the registry, so nothing was re-measured. The record below still travels."));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const stored = (await head.json());
|
|
196
|
+
/**
|
|
197
|
+
* SEM CENSO GRAVADO NÃO HÁ O QUE REMEDIR CONTRA. Um sistema que nasceu da galeria não tem escopo
|
|
198
|
+
* nem leitura, e medir o repo dele produziria um censo de um projeto que ninguém mapeou para ele.
|
|
199
|
+
*/
|
|
200
|
+
if (!stored.hasCensus) {
|
|
201
|
+
console.log(section("Sync"));
|
|
202
|
+
console.log(body(`"${slug}" did not come from an import, so there is no measurement to refresh. Import it first: npx synthesisui import`));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
console.log(section("Measuring your repository again"));
|
|
206
|
+
console.log(body(paint.faint(`${stored.scope ? `scope ${stored.scope}` : "the whole repo"} · the reading you already authored travels unchanged`)));
|
|
207
|
+
const census = await takeCensus(stored.scope ? join(root, stored.scope) : root, {
|
|
208
|
+
...(stored.scope ? { scopeLabel: stored.scope } : {}),
|
|
209
|
+
...(args.cli ? { cli: args.cli } : {}),
|
|
210
|
+
/** O `--usage` é EVIDÊNCIA e leva rótulo: sem ele o censo não sabe de que app o número veio. */
|
|
211
|
+
usage: (stored.usage ?? []).map((u) => ({
|
|
212
|
+
path: join(root, u),
|
|
213
|
+
label: u,
|
|
214
|
+
})),
|
|
215
|
+
}).catch(() => null);
|
|
216
|
+
if (!census) {
|
|
217
|
+
console.log(body("The measurement failed, so nothing was sent."));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
/** A LEITURA GRAVADA ENTRA NO CENSO FRESCO - ver a rota `reading`. */
|
|
221
|
+
if (stored.reading)
|
|
222
|
+
census.reading = stored.reading;
|
|
223
|
+
await resolveReadParts(census, root).catch(() => { });
|
|
224
|
+
/**
|
|
225
|
+
* O AVISO, ANTES DE ENVIAR. `edited` são as receitas que uma pessoa escreveu na tela; o cruzamento
|
|
226
|
+
* com o que acabou de ser medido é uma interseção de conjuntos, e é por isso que ele mora aqui em
|
|
227
|
+
* vez de virar um gêmeo da regra que vive na plataforma.
|
|
228
|
+
*/
|
|
229
|
+
const slugOf = (name) => name
|
|
230
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
231
|
+
.toLowerCase()
|
|
232
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
233
|
+
.replace(/^-|-$/g, "");
|
|
234
|
+
const arriving = new Set(Object.keys(census.looks ?? {}).map(slugOf));
|
|
235
|
+
/**
|
|
236
|
+
* SÓ O QUE ESTE ENVIO TOCA. Uma receita que a pessoa editou e que a medição não traz fica onde
|
|
237
|
+
* está, e listá-la seria assustar sem motivo - o erro mais fácil de cometer neste aviso.
|
|
238
|
+
*/
|
|
239
|
+
const hit = (stored.draft?.edited ?? []).filter((e) => arriving.has(e.component));
|
|
240
|
+
if (hit.length > 0) {
|
|
241
|
+
console.log("");
|
|
242
|
+
console.log(section("You have an active draft"));
|
|
243
|
+
console.log(body(stored.draft?.warning ??
|
|
244
|
+
`${hit.length} of the ${stored.draft?.components ?? "?"} components in it were written on the screen, and this send would rewrite them.`));
|
|
245
|
+
console.log(body(paint.faint(hit
|
|
246
|
+
.slice(0, 6)
|
|
247
|
+
.map((e) => `${e.component}${e.at ? ` (${e.at.slice(0, 10)})` : ""}`)
|
|
248
|
+
.join(" · "))));
|
|
249
|
+
if (!(await askToOverwrite())) {
|
|
250
|
+
console.log(body("Nothing was sent. Your draft is untouched."));
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const res = await fetch(`${base}/api/registry/ds/${slug}/census`, {
|
|
255
|
+
method: "POST",
|
|
256
|
+
headers: {
|
|
257
|
+
"content-type": "application/json",
|
|
258
|
+
Authorization: `Bearer ${token}`,
|
|
259
|
+
},
|
|
260
|
+
body: JSON.stringify({ census }),
|
|
261
|
+
}).catch(() => null);
|
|
262
|
+
if (!res?.ok) {
|
|
263
|
+
console.log(body(res
|
|
264
|
+
? `The registry answered ${res.status}. Nothing was written.`
|
|
265
|
+
: "Could not reach the registry. Nothing was written."));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const out = (await res.json());
|
|
269
|
+
console.log("");
|
|
270
|
+
console.log(section("Sent"));
|
|
271
|
+
console.log(body(`${out.written ?? 0} of ${out.total ?? 0} components written.`));
|
|
272
|
+
for (const note of out.notes ?? [])
|
|
273
|
+
console.log(body(paint.faint(note)));
|
|
274
|
+
if (out.url)
|
|
275
|
+
console.log(body(out.url));
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Pergunta uma vez, e só num terminal de verdade.
|
|
279
|
+
*
|
|
280
|
+
* Sem TTY a resposta é NÃO: uma invocação por script que sobrescreve trabalho de alguém porque
|
|
281
|
+
* ninguém estava lá para dizer não é o pior default possível. `--yes` é o caminho explícito.
|
|
282
|
+
*/
|
|
283
|
+
async function askToOverwrite() {
|
|
284
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
285
|
+
return false;
|
|
286
|
+
const { createInterface } = await import("node:readline/promises");
|
|
287
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
288
|
+
try {
|
|
289
|
+
const answer = await rl.question(" send anyway? [y/N]: ");
|
|
290
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
finally {
|
|
296
|
+
rl.close();
|
|
297
|
+
}
|
|
298
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -54,8 +54,10 @@ Usage - governance (deterministic, FREE):
|
|
|
54
54
|
something no reader would change
|
|
55
55
|
synthesisui request [component|token] the queue of what your agent needed and the system
|
|
56
56
|
refused to invent (--done <id> closes one)
|
|
57
|
-
synthesisui sync
|
|
58
|
-
|
|
57
|
+
synthesisui sync re-measure this repo with the current reader and send it,
|
|
58
|
+
reusing the reading you already authored, plus the local
|
|
59
|
+
record - checks, fixes, open requests (--record-only skips
|
|
60
|
+
the measurement, --yes skips the overwrite question)
|
|
59
61
|
synthesisui hook the check itself; installed by connect, run by your editor
|
|
60
62
|
synthesisui mcp the system as tools; installed by connect, run by your agent
|
|
61
63
|
|
|
@@ -422,8 +424,21 @@ async function main() {
|
|
|
422
424
|
await clean({ dir, force: flags.force === true });
|
|
423
425
|
break;
|
|
424
426
|
case "sync":
|
|
425
|
-
|
|
426
|
-
|
|
427
|
+
/**
|
|
428
|
+
* A versão que reporta o estado do repo - ver `repoStateOf` - e que MEDE: desde 05/08 o `sync`
|
|
429
|
+
* remede o repo com o leitor atual e reenvia, reusando a leitura já gravada. É o único comando
|
|
430
|
+
* do lado do cliente para fazer um conserto de leitura chegar.
|
|
431
|
+
*
|
|
432
|
+
* `--record-only` manda só o registro, e `--yes` não pergunta antes de sobrescrever receita
|
|
433
|
+
* escrita na tela. O default é medir e perguntar.
|
|
434
|
+
*/
|
|
435
|
+
await sync({
|
|
436
|
+
dir,
|
|
437
|
+
registry,
|
|
438
|
+
cli: CLI_VERSION,
|
|
439
|
+
recordOnly: args.includes("--record-only"),
|
|
440
|
+
yes: args.includes("--yes"),
|
|
441
|
+
});
|
|
427
442
|
break;
|
|
428
443
|
case "request": {
|
|
429
444
|
// `synthesisui request` lists; `request component --name x --for "..."`
|
package/package.json
CHANGED