synthesisui 0.16.424 → 0.16.426

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.
@@ -0,0 +1,167 @@
1
+ import { resolve } from "node:path";
2
+ import { readToken, resolveRegistry } from "../config.js";
3
+ import { installedSlugs } from "../installed.js";
4
+ import { body, paint, section } from "../output.js";
5
+ const isState = (x) => !!x &&
6
+ typeof x === "object" &&
7
+ typeof x.on === "boolean" &&
8
+ typeof x.landsOn === "string";
9
+ /**
10
+ * O ESTADO, EM UMA LINHA - e o nome do sistema junto, porque um repo pode ter dois.
11
+ *
12
+ * O SLUG É O LOCAL, NUNCA O QUE VOLTOU DA REDE - achado da revisão de QA no fecho. Ele é a
13
+ * PERGUNTA, não a resposta: num repo com dois sistemas instalados, uma resposta que trouxesse
14
+ * outro nome faria o terminal dizer que mudou o sistema em que ela não mexeu. A lei de imprimir o
15
+ * lido de volta vale para o ESTADO, que é o que a rota decide.
16
+ */
17
+ const stateLine = (s, slug) => `Autopilot is ${s.on ? "on" : "off"} for you in ${slug}.`;
18
+ /**
19
+ * POR QUE ELE ESTÁ ASSIM - e as três respostas são coisas diferentes.
20
+ *
21
+ * `unavailable` é a lacuna declarada: dizer "alguém te desligou" sobre uma tabela que aquele banco
22
+ * ainda não tem é falso duas vezes - ninguém desligou, e o que houve foi uma leitura que não
23
+ * respondeu. Lacuna calada é bug (lei 8).
24
+ */
25
+ const whyLine = (s) => s.why === "chosen"
26
+ ? `you switched this ${s.on ? "on" : "off"} yourself, and it stands even if the system default changes.`
27
+ : s.why === "default"
28
+ ? "you have no choice of your own here, so the system default answers for you."
29
+ : "per-person Autopilot has not reached this system yet, so nobody switched you off - off is the honest answer until it does.";
30
+ /** Onde o trabalho dela cai - a segunda pergunta de quem acabou de mudar a automação. */
31
+ const landsLine = (s, base, slug) => s.landsOn === "branch"
32
+ ? `your work lands in YOUR branch, not on the main line your team installs - it reaches them when whoever owns this system approves it: ${base}/dashboard/mine/${slug}`
33
+ : "your work goes straight to the main line your team installs.";
34
+ function say(s, base, slug) {
35
+ console.log(section("Autopilot"));
36
+ console.log(body(paint.strong(stateLine(s, slug))));
37
+ console.log(body(paint.dim(whyLine(s))));
38
+ console.log(body(paint.dim(landsLine(s, base, slug))));
39
+ console.log("");
40
+ }
41
+ export async function autopilot(opts) {
42
+ const root = resolve(opts.dir ?? process.cwd());
43
+ const base = resolveRegistry(opts.registry);
44
+ const asked = opts.wanted?.trim().toLowerCase();
45
+ /**
46
+ * A PALAVRA É CONFERIDA ANTES DE QUALQUER IDA À REDE - e antes do login, inclusive. Mandar
47
+ * `maybe` para o servidor e deixá-lo recusar gastaria uma volta para dizer o que já se sabe
48
+ * aqui, e devolveria a ela uma frase sobre a rota em vez das duas escolhas que existem.
49
+ */
50
+ if (asked && asked !== "on" && asked !== "off") {
51
+ console.log(section("Autopilot"));
52
+ console.log(body(`"${opts.wanted}" is not a choice here. The two are: ${paint.strong("on")} and ${paint.strong("off")}.`));
53
+ console.log(body(paint.faint(" synthesisui autopilot # what it is right now, without changing it")));
54
+ /**
55
+ * E ELE SAI COM FALHA - achado da revisão de QA no fecho: um script que roda
56
+ * `synthesisui autopilot $CHOICE` com a variável vazia ou com um valor digitado errado
57
+ * seguiria como se tivesse mudado. É a mesma lei do 403, e o caminho mais provável de chegar
58
+ * aqui é justamente automação, não uma pessoa digitando.
59
+ */
60
+ process.exitCode = 1;
61
+ return;
62
+ }
63
+ const token = await readToken(opts.home);
64
+ if (!token) {
65
+ console.log(section("Autopilot"));
66
+ console.log(body("Not logged in, so there is nothing to read here - this switch is yours on the platform, not a file in this clone:"));
67
+ console.log(body(paint.blue(" synthesisui login")));
68
+ return;
69
+ }
70
+ /**
71
+ * QUAL SISTEMA - o `.lock` é o que diz qual slug este repositório alimenta.
72
+ *
73
+ * Num repo com dois, ele age no primeiro em ordem alfabética, e a saída NOMEIA qual: um comando
74
+ * que age calado sobre "o primeiro" é um comando que ela não tem como conferir.
75
+ */
76
+ const installed = await installedSlugs(root);
77
+ const slug = installed[0];
78
+ if (!slug) {
79
+ console.log(section("Autopilot"));
80
+ console.log(body("No installed system here, so there is no Autopilot to read. Install the one this repo follows first:"));
81
+ console.log(body(paint.blue(" npx synthesisui@latest add <slug>")));
82
+ console.log(body(paint.faint(" npx synthesisui@latest list --mine # the slugs you own")));
83
+ return;
84
+ }
85
+ const url = `${base}/api/registry/ds/${slug}/autopilot`;
86
+ const auth = { authorization: `Bearer ${token}` };
87
+ /** A leitura, e ela é a mesma nos dois caminhos - perguntar, e dizer o que continua valendo. */
88
+ const read = async () => {
89
+ const res = await fetch(url, { headers: auth });
90
+ if (!res.ok)
91
+ return null;
92
+ const data = (await res.json().catch(() => null));
93
+ return isState(data) ? data : null;
94
+ };
95
+ const unreachable = (why) => {
96
+ console.log(section("Autopilot"));
97
+ console.log(body(`This machine could not reach the platform, so nothing was read and nothing was changed: ${base}${why instanceof Error ? ` (${why.message})` : ""}. Try again when you are back online, or point it at the right place with --registry <url>.`));
98
+ process.exitCode = 1;
99
+ };
100
+ if (!asked) {
101
+ try {
102
+ const now = await read();
103
+ if (!now) {
104
+ console.log(section("Autopilot"));
105
+ console.log(body(`${paint.strong(slug)} did not answer for this account at ${base}. If your session is old, log in again: ${paint.blue("synthesisui login")}`));
106
+ process.exitCode = 1;
107
+ return;
108
+ }
109
+ say(now, base, slug);
110
+ }
111
+ catch (error) {
112
+ unreachable(error);
113
+ }
114
+ return;
115
+ }
116
+ try {
117
+ const res = await fetch(url, {
118
+ method: "POST",
119
+ headers: { ...auth, "content-type": "application/json" },
120
+ body: JSON.stringify({ choice: asked }),
121
+ });
122
+ if (res.status === 403) {
123
+ /**
124
+ * A RECUSA VEM DO SERVIDOR, INTEIRA - ela nomeia o papel que resolve, e é isso que separa
125
+ * "não deu" de "fale com quem administra as pessoas deste grupo".
126
+ */
127
+ const said = (await res.json().catch(() => null));
128
+ console.log(section("Autopilot"));
129
+ console.log(body(said?.error ??
130
+ "That is not yours to change here, and the server did not say who it belongs to."));
131
+ process.exitCode = 1;
132
+ /** E O QUE CONTINUA VALENDO, porque uma recusa sem o estado deixa ela sem saber onde está. */
133
+ const now = await read().catch(() => null);
134
+ if (now)
135
+ say(now, base, slug);
136
+ return;
137
+ }
138
+ if (res.status === 404) {
139
+ console.log(section("Autopilot"));
140
+ console.log(body(`${paint.strong(slug)} does not reach this account at ${base}, so there is nothing to change here. If your session is old, log in again: ${paint.blue("synthesisui login")}`));
141
+ process.exitCode = 1;
142
+ return;
143
+ }
144
+ if (!res.ok) {
145
+ console.log(section("Autopilot"));
146
+ console.log(body(`${base} answered ${res.status} to that, so nothing was changed. Nothing of yours was lost.`));
147
+ process.exitCode = 1;
148
+ return;
149
+ }
150
+ /**
151
+ * O ESTADO IMPRESSO É O QUE A ROTA RELEU DO BANCO depois de escrever - nunca o que este
152
+ * processo pediu. Ver o cabeçalho: um interruptor que parece ligado e não está é pior que um
153
+ * que recusa.
154
+ */
155
+ const now = (await res.json().catch(() => null));
156
+ if (!isState(now)) {
157
+ console.log(section("Autopilot"));
158
+ console.log(body(`${base} answered something this version cannot read, so it is not saying what the switch is now. Upgrade and try again: npx synthesisui@latest autopilot`));
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+ say(now, base, slug);
163
+ }
164
+ catch (error) {
165
+ unreachable(error);
166
+ }
167
+ }
@@ -42,6 +42,21 @@ import { resolveReadParts, siblingProjects, takeCensus, } from "./import.js";
42
42
  export function draftLine(slug, base) {
43
43
  return `this went into your DRAFT - your repository still has what you installed. It reaches the disk once you publish${base ? `: ${base}/dashboard/mine/${slug}/publish` : ""}\n then: npx synthesisui@latest upgrade ${slug}`;
44
44
  }
45
+ /**
46
+ * O TRABALHO DELA FOI PARA A RAMIFICAÇÃO DELA, E ISSO SE DIZ - `INV-BRANCH-02`.
47
+ *
48
+ * O QUE O CLIENTE VIA SEM ISTO: `62 of 62 components written.` - a mesma frase de quem move a
49
+ * linha principal. Ela fecharia o terminal achando que o time recebeu, e descobriria o contrário
50
+ * num dia em que estivesse contando com aquilo. É a lacuna calada que a lei 8 proíbe: o cliente
51
+ * perdoa o que a gente diz que não faz, e não perdoa descobrir sozinho.
52
+ *
53
+ * A FRASE DIZ TRÊS COISAS, nesta ordem: onde o trabalho está, que ele está inteiro, e o que falta
54
+ * para alcançar o time. Sem a terceira ela é um aviso sem saída - e quem lê não tem o que fazer
55
+ * com ele.
56
+ */
57
+ export function branchLine(slug, base) {
58
+ return `this went to YOUR branch, not to the main line your team installs - nothing of it was lost. It reaches them when whoever owns this system approves it${base ? `: ${base}/dashboard/mine/${slug}` : ""}`;
59
+ }
45
60
  export function decisionLine(d, slug,
46
61
  /** Onde o sistema dele vive - o `publish` mora lá, e sem o endereço a frase manda procurar. */
47
62
  base) {
@@ -629,6 +644,12 @@ export async function remeasure(args) {
629
644
  console.log("");
630
645
  console.log(section("Sent"));
631
646
  console.log(body(`${out.written ?? 0} of ${out.total ?? 0} components written.`));
647
+ /**
648
+ * E ONDE ELE CAIU, logo abaixo do número - porque é o número que ela leria como "o time
649
+ * recebeu".
650
+ */
651
+ if (out.landedOn === "branch")
652
+ console.log(body(paint.strong(branchLine(slug, base))));
632
653
  /**
633
654
  * O QUE VEIO DOS ARQUIVOS DELE, DITO - e antes de qualquer outra nota, porque é a única parte
634
655
  * desta saída que fala do trabalho que ELE acabou de fazer.
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ import { add } from "./commands/add.js";
8
8
  import { adopt } from "./commands/adopt.js";
9
9
  import { advise } from "./commands/advise.js";
10
10
  import { align } from "./commands/align.js";
11
+ import { autopilot } from "./commands/autopilot.js";
11
12
  import { ci } from "./commands/ci.js";
12
13
  import { clean } from "./commands/clean.js";
13
14
  import { component } from "./commands/component.js";
@@ -88,6 +89,11 @@ Usage - governance (deterministic, FREE):
88
89
  declare, and says what it offers instead. create: it
89
90
  reports and gets out of the way. No argument answers
90
91
  where you are. Local to this clone, never committed
92
+ synthesisui autopilot [on|off] the Autopilot, FOR YOU in this system: on applies what it
93
+ finds on your work without asking, off stops it acting
94
+ for you - your sync still goes up either way. No argument
95
+ answers where you are, and it always says which line your
96
+ work is landing in
91
97
  synthesisui hook the check itself; installed by connect, run by your editor
92
98
  synthesisui mcp the system as tools; installed by connect, run by your agent
93
99
 
@@ -286,6 +292,20 @@ async function main() {
286
292
  case "mode":
287
293
  await mode({ dir, ...(args[0] ? { wanted: args[0] } : {}) });
288
294
  break;
295
+ /**
296
+ * O INTERRUPTOR DELA NA PLATAFORMA - ver `autopilot.ts`.
297
+ *
298
+ * O irmão de `mode`, e a diferença importa: `mode` é local a este clone, e este muda um estado
299
+ * que mora no servidor e que a tela de configurações mexe pela outra porta. Sem argumento ele
300
+ * RESPONDE, pela mesma razão dos dois.
301
+ */
302
+ case "autopilot":
303
+ await autopilot({
304
+ dir,
305
+ registry,
306
+ ...(args[0] ? { wanted: args[0] } : {}),
307
+ });
308
+ break;
289
309
  // Long-lived: it owns stdin/stdout until the client closes the pipe, so
290
310
  // it must not be reached by anything that prints.
291
311
  case "mcp":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.424",
3
+ "version": "0.16.426",
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": {