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.
- package/dist/commands/autopilot.js +167 -0
- package/dist/commands/sync.js +21 -0
- package/dist/index.js +20 -0
- package/package.json +1 -1
|
@@ -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
|
+
}
|
package/dist/commands/sync.js
CHANGED
|
@@ -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