synthesisui 0.16.202 → 0.16.203
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/align.js +74 -9
- package/dist/commands/connect.js +50 -11
- package/dist/shell-answer.js +35 -0
- package/dist/shell-hook.js +52 -3
- package/package.json +1 -1
package/dist/commands/align.js
CHANGED
|
@@ -148,11 +148,7 @@ opts = {}) {
|
|
|
148
148
|
* o único lugar que fala sem ser perguntado. Apontava `connect` até 07/08, quando o dono nomeou a
|
|
149
149
|
* incoerência - a palavra que significa atualizar era a única que não atualizava.
|
|
150
150
|
*/
|
|
151
|
-
|
|
152
|
-
out.push({
|
|
153
|
-
says: `the files under _synthesisui/ds/${lock.slug} were written by CLI ${lock.cli} and you are running ${cli} - the design system's version has not changed, but what this CLI writes into that folder has.`,
|
|
154
|
-
run: "npx synthesisui upgrade",
|
|
155
|
-
});
|
|
151
|
+
const folderBehind = cli && lock.cli && lock.cli !== cli ? lock.cli : null;
|
|
156
152
|
/**
|
|
157
153
|
* O HOOK, MEDIDO NELE MESMO - e não pelo `.lock`, que é um proxy que se move sozinho.
|
|
158
154
|
*
|
|
@@ -165,11 +161,39 @@ opts = {}) {
|
|
|
165
161
|
* nunca está atrás por si.
|
|
166
162
|
*/
|
|
167
163
|
const pinned = await pinnedHookVersion(root).catch(() => null);
|
|
168
|
-
|
|
164
|
+
const hookBehind = cli && pinned && pinned !== cli ? pinned : null;
|
|
165
|
+
/**
|
|
166
|
+
* UMA CAUSA, UMA LINHA - e as duas metades nomeadas dentro dela.
|
|
167
|
+
*
|
|
168
|
+
* A pasta e o hook são dois lugares diferentes e por isso são duas verificações: o `.lock` já
|
|
169
|
+
* disse 0.16.180 com o `PostToolUse` pinado em 0.16.178, e um alarme desligado por um conserto
|
|
170
|
+
* parcial é pior que alarme nenhum. Mas quando os dois estão na MESMA versão anterior, a causa é
|
|
171
|
+
* uma só - alguém subiu o CLI - e o remédio é um só.
|
|
172
|
+
*
|
|
173
|
+
* O que isso custava: duas frases de ~185 caracteres repetindo "e você está rodando X", com
|
|
174
|
+
* `npx synthesisui upgrade` impresso duas vezes numa mensagem de cinco linhas. O dono leu e
|
|
175
|
+
* chamou de grande demais (11/08), e ele estava certo pelo motivo errado: não era prolixidade,
|
|
176
|
+
* era a mesma coisa dita duas vezes.
|
|
177
|
+
*
|
|
178
|
+
* Divergiram, voltam a ser dois fatos - que é o caso em que a distinção existe para servir.
|
|
179
|
+
*/
|
|
180
|
+
if (folderBehind && hookBehind && folderBehind === hookBehind)
|
|
169
181
|
out.push({
|
|
170
|
-
says: `
|
|
182
|
+
says: `you are running CLI ${cli} and two things here are still on ${folderBehind}: the files under _synthesisui/ds/${lock.slug}, and the check that runs after every write - so your agent's edits are read by the older one.`,
|
|
171
183
|
run: "npx synthesisui upgrade",
|
|
172
184
|
});
|
|
185
|
+
else {
|
|
186
|
+
if (folderBehind)
|
|
187
|
+
out.push({
|
|
188
|
+
says: `the files under _synthesisui/ds/${lock.slug} were written by CLI ${folderBehind} and you are running ${cli} - the design system's version has not changed, but what this CLI writes into that folder has.`,
|
|
189
|
+
run: "npx synthesisui upgrade",
|
|
190
|
+
});
|
|
191
|
+
if (hookBehind)
|
|
192
|
+
out.push({
|
|
193
|
+
says: `the check that runs after every write is pinned to CLI ${hookBehind} and you are running ${cli} - your agent's edits are being checked by an older reader than the one measuring this repo.`,
|
|
194
|
+
run: "npx synthesisui upgrade",
|
|
195
|
+
});
|
|
196
|
+
}
|
|
173
197
|
if (cli && lock.version == null)
|
|
174
198
|
out.push({
|
|
175
199
|
says: `"${lock.slug}" has no version recorded, so nothing can tell whether the CSS in this repo is the one the platform publishes.`,
|
|
@@ -328,10 +352,51 @@ from = "session") {
|
|
|
328
352
|
: from === "shell"
|
|
329
353
|
? "This repo is out of alignment with the design system that governs it:"
|
|
330
354
|
: "Before this session starts, this environment is out of alignment with the design system that governs it:",
|
|
331
|
-
|
|
332
|
-
...items.map((m) => ` - ${m.says}${m.run ? `\n ${m.run}` : ""}${m.then ? `\n then, to pick up where you left off:\n ${m.then}` : ""}`),
|
|
355
|
+
...grouped(items),
|
|
333
356
|
].join("\n");
|
|
334
357
|
}
|
|
358
|
+
/**
|
|
359
|
+
* UM COMANDO APARECE UMA VEZ, com todos os fatos que ele resolve acima dele.
|
|
360
|
+
*
|
|
361
|
+
* O dono leu esta mensagem em 11/08 e a chamou de grande demais. Ela era - mas por repetição, não
|
|
362
|
+
* por prolixidade: as duas linhas diziam a MESMA causa (o CLI andou) e propunham o MESMO comando,
|
|
363
|
+
* e `npx synthesisui upgrade` saía duas vezes numa mensagem de cinco linhas.
|
|
364
|
+
*
|
|
365
|
+
* Contado no código: 5 dos achados propõem `upgrade`, 3 propõem `sync`, 1 propõe `login`. No pior
|
|
366
|
+
* caso alguém via o mesmo comando cinco vezes.
|
|
367
|
+
*
|
|
368
|
+
* Os FATOS continuam separados, um por linha, porque são coisas diferentes que estão erradas - e
|
|
369
|
+
* é isso que a pessoa precisa saber. O que some é a repetição do remédio. E eles não se fundem
|
|
370
|
+
* quando divergem: o `.lock` já disse 0.16.180 com o hook pinado em 0.16.178, e são dois fatos.
|
|
371
|
+
*
|
|
372
|
+
* A ordem é a da primeira aparição: o primeiro achado decide onde o grupo dele fica.
|
|
373
|
+
*/
|
|
374
|
+
function grouped(items) {
|
|
375
|
+
const order = [];
|
|
376
|
+
const byRun = new Map();
|
|
377
|
+
for (const m of items) {
|
|
378
|
+
/** O `then` entra na chave: dois achados só compartilham bloco se o remédio for o mesmo INTEIRO. */
|
|
379
|
+
const key = `${m.run ?? ""}\u0000${m.then ?? ""}`;
|
|
380
|
+
if (!byRun.has(key)) {
|
|
381
|
+
byRun.set(key, []);
|
|
382
|
+
order.push(key);
|
|
383
|
+
}
|
|
384
|
+
byRun.get(key)?.push(m);
|
|
385
|
+
}
|
|
386
|
+
const out = [];
|
|
387
|
+
for (const key of order) {
|
|
388
|
+
const group = byRun.get(key) ?? [];
|
|
389
|
+
for (const m of group)
|
|
390
|
+
out.push(` - ${m.says}`);
|
|
391
|
+
const { run, then } = group[0];
|
|
392
|
+
if (run)
|
|
393
|
+
out.push(` ${run}`);
|
|
394
|
+
/** O `then` sai numa linha própria e rotulada: um segundo comando solto lê como parte do primeiro. */
|
|
395
|
+
if (then)
|
|
396
|
+
out.push(` then, to pick up where you left off:\n ${then}`);
|
|
397
|
+
}
|
|
398
|
+
return out;
|
|
399
|
+
}
|
|
335
400
|
/**
|
|
336
401
|
* `synthesisui align` - o comando que o hook de sessão roda.
|
|
337
402
|
*
|
package/dist/commands/connect.js
CHANGED
|
@@ -4,7 +4,8 @@ import { wireAgent } from "../agent-wiring.js";
|
|
|
4
4
|
import { blockHomes, syncClaudeMd } from "../claude-md.js";
|
|
5
5
|
import { resolveRegistry } from "../config.js";
|
|
6
6
|
import { body, paint, section, snippet } from "../output.js";
|
|
7
|
-
import {
|
|
7
|
+
import { readShellAnswer, rememberShellNo } from "../shell-answer.js";
|
|
8
|
+
import { existingRc, hasHook, pinnedInHook, rcPathFor, shellFrom, shellSnippet, withHook, } from "../shell-hook.js";
|
|
8
9
|
import { IMPORT_SKILL, IMPORT_SKILL_PATH } from "../skill-import.js";
|
|
9
10
|
import { INIT_SKILL, INIT_SKILL_PATH } from "../skill-init.js";
|
|
10
11
|
import { add } from "./add.js";
|
|
@@ -118,25 +119,48 @@ async function refreshInstall(root, cli, registry) {
|
|
|
118
119
|
* Sem TTY (CI, um agente rodando o comando) não há a quem perguntar, e a resposta certa é não
|
|
119
120
|
* escrever - um pipeline não deveria acordar com o perfil de shell de alguém alterado.
|
|
120
121
|
*/
|
|
121
|
-
async function offerShellHook(asked
|
|
122
|
+
async function offerShellHook(asked,
|
|
123
|
+
/** A versão que fica pinada no bloco - ver `shellSnippet`. */
|
|
124
|
+
version) {
|
|
122
125
|
const shell = shellFrom(process.env);
|
|
123
126
|
if (!shell)
|
|
124
127
|
return;
|
|
125
|
-
|
|
128
|
+
/**
|
|
129
|
+
* O PERFIL QUE EXISTE E QUE O SHELL LÊ - e quando não há nenhum, a gente não cria.
|
|
130
|
+
*
|
|
131
|
+
* Acrescentar a um `.zshrc` que a pessoa mantém é uma coisa; CRIAR um perfil que ela nunca teve é
|
|
132
|
+
* outra, e é maior que a pergunta que fizemos. Quem pediu com `--shell` já decidiu, e aí o padrão
|
|
133
|
+
* vale. Ver `existingRc` - ele também é o que impede escrever num `.bashrc` que um login shell de
|
|
134
|
+
* macOS nunca lê.
|
|
135
|
+
*/
|
|
136
|
+
const rc = (await existingRc(shell)) ?? (asked ? rcPathFor(shell) : null);
|
|
137
|
+
if (!rc)
|
|
138
|
+
return;
|
|
126
139
|
const current = await readFile(rc, "utf8").catch(() => null);
|
|
127
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* JÁ INSTALADO: rematerializa, mas DIZENDO ANTES - e o antes é o conserto.
|
|
142
|
+
*
|
|
143
|
+
* Isto escrevia calado e avisava depois, numa linha que a pessoa pode rolar sem ver. O arquivo é
|
|
144
|
+
* dela e de todos os outros projetos dela, e um `.zshrc` que muda sem uma palavra é a definição
|
|
145
|
+
* de invasivo (dono, 11/08). Ela consentiu em TER o bloco; mover o que está dentro dele é manter
|
|
146
|
+
* o que ela aceitou, então isto informa em vez de perguntar - mas informa ANTES.
|
|
147
|
+
*
|
|
148
|
+
* E passou a acontecer mais: com a versão pinada no bloco, todo bump do CLI o muda. Os dois
|
|
149
|
+
* consertos são um só - ver `shellSnippet`.
|
|
150
|
+
*/
|
|
128
151
|
if (current != null && hasHook(current)) {
|
|
129
|
-
const next = withHook(current, shellSnippet(shell));
|
|
152
|
+
const next = withHook(current, shellSnippet(shell, version));
|
|
130
153
|
if (next !== current) {
|
|
131
|
-
|
|
154
|
+
const was = pinnedInHook(current);
|
|
132
155
|
console.log("");
|
|
133
|
-
console.log(body(`
|
|
156
|
+
console.log(body(`Updating the terminal check in ${rc} - ${was ? `it was pinned to ${was}` : "it was on an unpinned version"}, moving it to ${version}.`));
|
|
157
|
+
await writeFile(rc, next, "utf8").catch(() => { });
|
|
134
158
|
}
|
|
135
159
|
return;
|
|
136
160
|
}
|
|
137
161
|
/** `--shell` é alguém que já decidiu - perguntar de novo seria não ter escutado. */
|
|
138
162
|
if (asked) {
|
|
139
|
-
await writeFile(rc, withHook(current ?? "", shellSnippet(shell)), "utf8");
|
|
163
|
+
await writeFile(rc, withHook(current ?? "", shellSnippet(shell, version)), "utf8");
|
|
140
164
|
console.log("");
|
|
141
165
|
console.log(body(`Terminal check written to ${rc}.`));
|
|
142
166
|
console.log(body(`Open a new terminal, or run: source ${rc}`));
|
|
@@ -149,6 +173,18 @@ async function offerShellHook(asked) {
|
|
|
149
173
|
console.log(body(paint.blue(" npx synthesisui@latest connect --shell")));
|
|
150
174
|
return;
|
|
151
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* ELE JÁ DISSE NÃO - e uma recusa que não é lembrada não é uma decisão.
|
|
178
|
+
*
|
|
179
|
+
* Fica a linha calada com o caminho de volta, que é a mesma forma da recusa na tela dele: sumir
|
|
180
|
+
* de vez esconderia algo que ele pode querer rever; perguntar de novo a cada `connect` é o que
|
|
181
|
+
* transforma a recusa em nada. Ver `shell-answer.ts`.
|
|
182
|
+
*/
|
|
183
|
+
const said = await readShellAnswer();
|
|
184
|
+
if (said) {
|
|
185
|
+
console.log(body(paint.faint(`You said no to this on ${said.at.slice(0, 10)}. It stays off - \`npx synthesisui@latest connect --shell\` turns it on.`)));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
152
188
|
const { createInterface } = await import("node:readline/promises");
|
|
153
189
|
const rl = createInterface({
|
|
154
190
|
input: process.stdin,
|
|
@@ -156,9 +192,11 @@ async function offerShellHook(asked) {
|
|
|
156
192
|
});
|
|
157
193
|
const answer = await rl.question(` Add it to ${rc}? [y/N] `).catch(() => "");
|
|
158
194
|
rl.close();
|
|
159
|
-
if (!/^y(es)?$/i.test(answer.trim()))
|
|
195
|
+
if (!/^y(es)?$/i.test(answer.trim())) {
|
|
196
|
+
await rememberShellNo(rc);
|
|
160
197
|
return;
|
|
161
|
-
|
|
198
|
+
}
|
|
199
|
+
await writeFile(rc, withHook(current ?? "", shellSnippet(shell, version)), "utf8");
|
|
162
200
|
console.log(body(`Written. Open a new terminal, or run: source ${rc}`));
|
|
163
201
|
}
|
|
164
202
|
export async function connect(opts) {
|
|
@@ -318,7 +356,8 @@ export async function connect(opts) {
|
|
|
318
356
|
console.log(body(paint.dim("Your PRs can carry this too: annotations on the exact line, and a ratchet that fails only when drift goes UP - never on the debt you already have.")));
|
|
319
357
|
console.log(paint.blue(snippet(["npx synthesisui@latest ci"])));
|
|
320
358
|
}
|
|
321
|
-
|
|
359
|
+
/** A mesma versão que a fiação do editor recebe - os dois pinam no mesmo número. */
|
|
360
|
+
await offerShellHook(opts.shell === true, opts.version);
|
|
322
361
|
/**
|
|
323
362
|
* O REINÍCIO SÓ QUANDO ELE É NECESSÁRIO - e pedi-lo sempre é o que fez o dono achar que reiniciar
|
|
324
363
|
* o editor fazia parte do fluxo (07/08).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* A RESPOSTA DELE SOBRE O TERMINAL, GRAVADA - senão a pergunta não decide nada.
|
|
6
|
+
*
|
|
7
|
+
* O dono rodou `connect` duas vezes num dia e foi perguntado das duas (11/08). O código já não
|
|
8
|
+
* pergunta quando o bloco EXISTE - ele reescreve calado e sai. O que não existia era memória do
|
|
9
|
+
* "não": quem recusa é perguntado de novo em toda conexão, para sempre.
|
|
10
|
+
*
|
|
11
|
+
* É a mesma lei que a tela dele já segue em `meta.declined`: *sem gravar, o botão não decide nada*.
|
|
12
|
+
* E é a mesma forma da recusa lá - ela não SOME, vira uma linha calada com o caminho de volta:
|
|
13
|
+
* sumir de vez esconderia uma decisão que ele pode querer rever, e continuar cobrando transforma a
|
|
14
|
+
* recusa em nada.
|
|
15
|
+
*
|
|
16
|
+
* MORA NO HOME, ao lado das credenciais, porque a decisão é da MÁQUINA e não do repositório - é o
|
|
17
|
+
* `.zshrc` dela que está em jogo, e ele é o mesmo para todos os projetos que ela tem. Gravar isso
|
|
18
|
+
* dentro de um repo faria a pessoa ser perguntada outra vez no próximo clone.
|
|
19
|
+
*/
|
|
20
|
+
const answerPath = (home = homedir()) => join(home, ".synthesisui", "shell.json");
|
|
21
|
+
export async function readShellAnswer(home) {
|
|
22
|
+
try {
|
|
23
|
+
const raw = JSON.parse(await readFile(answerPath(home), "utf8"));
|
|
24
|
+
return raw?.answered === "no" ? raw : null;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Nunca derruba o comando: uma recusa que não grava custa uma pergunta, não a conexão. */
|
|
31
|
+
export async function rememberShellNo(rc, home) {
|
|
32
|
+
const path = answerPath(home);
|
|
33
|
+
await mkdir(dirname(path), { recursive: true }).catch(() => { });
|
|
34
|
+
await writeFile(path, `${JSON.stringify({ answered: "no", at: new Date().toISOString(), rc }, null, 2)}\n`, "utf8").catch(() => { });
|
|
35
|
+
}
|
package/dist/shell-hook.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
1
2
|
import { homedir } from "node:os";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
/**
|
|
@@ -29,7 +30,20 @@ export const HOOK_END = "# <<< synthesisui align <<<";
|
|
|
29
30
|
* `add-zsh-hook chpwd`, o bash tem `PROMPT_COMMAND` e nenhum equivalente de `chpwd`, então lá a
|
|
30
31
|
* função se protege sozinha comparando o diretório com o da última vez.
|
|
31
32
|
*/
|
|
32
|
-
|
|
33
|
+
/**
|
|
34
|
+
* A VERSÃO FICA PINADA AQUI TAMBÉM - e a incoerência que isso resolve estava escrita nos dois lados.
|
|
35
|
+
*
|
|
36
|
+
* O hook do editor é pinado de propósito, e o comentário de `agent-wiring` diz por quê: *"um check
|
|
37
|
+
* que muda sob você é indebugável"*. Este rodava `npx --yes synthesisui align` sem versão - sempre
|
|
38
|
+
* o `latest`, resolvido a cada hora, na máquina de todo mundo que disse sim. O mesmo argumento,
|
|
39
|
+
* duas decisões opostas; e o lado despinado é o que ninguém consegue depurar quando um `align`
|
|
40
|
+
* ruim sai: ele é silencioso por desenho (`2>/dev/null`, em background).
|
|
41
|
+
*
|
|
42
|
+
* O PREÇO, dito porque é real: pinar faz o bloco MUDAR a cada bump do CLI, então o `connect` passa
|
|
43
|
+
* a reescrever um arquivo que é da PESSOA com mais frequência. É por isso que a reescrita passou a
|
|
44
|
+
* falar antes de escrever, em vez de avisar depois - os dois consertos são um só.
|
|
45
|
+
*/
|
|
46
|
+
export function shellSnippet(shell, version) {
|
|
33
47
|
const body = shell === "zsh"
|
|
34
48
|
? [
|
|
35
49
|
"sui_align() {",
|
|
@@ -41,7 +55,7 @@ export function shellSnippet(shell) {
|
|
|
41
55
|
' (( $(date +%s) - $(stat -c %Y "$stamp" 2>/dev/null || echo 0) < 3600 )) && return',
|
|
42
56
|
" fi",
|
|
43
57
|
' : > "$stamp"',
|
|
44
|
-
|
|
58
|
+
` (npx --yes synthesisui@${version} align --shell 2>/dev/null &)`,
|
|
45
59
|
"}",
|
|
46
60
|
"autoload -U add-zsh-hook",
|
|
47
61
|
"add-zsh-hook chpwd sui_align",
|
|
@@ -59,7 +73,7 @@ export function shellSnippet(shell) {
|
|
|
59
73
|
' [ $(( $(date +%s) - $(stat -c %Y "$stamp" 2>/dev/null || echo 0) )) -lt 3600 ] && return 0',
|
|
60
74
|
" fi",
|
|
61
75
|
' : > "$stamp"',
|
|
62
|
-
|
|
76
|
+
` (npx --yes synthesisui@${version} align --shell 2>/dev/null &)`,
|
|
63
77
|
"}",
|
|
64
78
|
'case "$PROMPT_COMMAND" in *sui_align*) ;; *) PROMPT_COMMAND="sui_align;$PROMPT_COMMAND" ;; esac',
|
|
65
79
|
];
|
|
@@ -76,11 +90,46 @@ export function shellSnippet(shell) {
|
|
|
76
90
|
export function rcPathFor(shell, home = homedir()) {
|
|
77
91
|
return join(home, shell === "zsh" ? ".zshrc" : ".bashrc");
|
|
78
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* O PERFIL QUE EXISTE E QUE É LIDO - e `null` quando não há nenhum.
|
|
95
|
+
*
|
|
96
|
+
* Duas coisas que `rcPathFor` sozinho não sabe, e as duas escrevem no home de alguém:
|
|
97
|
+
*
|
|
98
|
+
* O ARQUIVO PODE NÃO EXISTIR. Acrescentar um bloco a um `.zshrc` que a pessoa mantém é uma coisa;
|
|
99
|
+
* CRIAR um perfil de shell que ela nunca teve é outra, e é maior do que a pergunta que fizemos.
|
|
100
|
+
*
|
|
101
|
+
* `.bashrc` NÃO É LIDO POR TODO BASH. Num login shell de macOS quem é lido é o `.bash_profile`,
|
|
102
|
+
* então escrever no `.bashrc` ali instala um aviso que nunca dispara - a pessoa diz sim, a gente
|
|
103
|
+
* escreve, e nada acontece nunca. Uma promessa que falha em silêncio é pior que a recusa.
|
|
104
|
+
*
|
|
105
|
+
* A ordem para bash é a que o shell usa: o perfil de login primeiro, o `.bashrc` depois.
|
|
106
|
+
*/
|
|
107
|
+
export async function existingRc(shell, home = homedir()) {
|
|
108
|
+
const candidates = shell === "zsh"
|
|
109
|
+
? [".zshrc"]
|
|
110
|
+
: [".bash_profile", ".bash_login", ".profile", ".bashrc"];
|
|
111
|
+
for (const name of candidates) {
|
|
112
|
+
const path = join(home, name);
|
|
113
|
+
if (await readFile(path, "utf8").then(() => true, () => false))
|
|
114
|
+
return path;
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
79
118
|
/** Qual shell, lido do ambiente. `null` quando não é um dos dois - aí não há o que escrever. */
|
|
80
119
|
export function shellFrom(env) {
|
|
81
120
|
const name = (env.SHELL ?? "").split("/").pop();
|
|
82
121
|
return name === "zsh" || name === "bash" ? name : null;
|
|
83
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* A VERSÃO PINADA DENTRO DO BLOCO - para o `connect` poder dizer o que MOVE antes de mover.
|
|
125
|
+
*
|
|
126
|
+
* `null` num bloco escrito antes da pinagem, e a frase trata isso: "was on an unpinned version"
|
|
127
|
+
* é diferente de "was on 0.16.201", e inventar um número ali seria mentir sobre o arquivo de
|
|
128
|
+
* alguém.
|
|
129
|
+
*/
|
|
130
|
+
export function pinnedInHook(text) {
|
|
131
|
+
return /synthesisui@(\d+\.\d+\.\d+)\s+align/.exec(text)?.[1] ?? null;
|
|
132
|
+
}
|
|
84
133
|
export function hasHook(text) {
|
|
85
134
|
return text.includes(HOOK_BEGIN);
|
|
86
135
|
}
|
package/package.json
CHANGED