@promovaweb/specsfy 0.8.1 → 0.9.2
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/CHANGELOG.md +30 -0
- package/README.md +26 -14
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -4
- package/dist/cli.js.map +1 -1
- package/dist/clickupfy.d.ts +8 -0
- package/dist/clickupfy.d.ts.map +1 -1
- package/dist/clickupfy.js +23 -7
- package/dist/clickupfy.js.map +1 -1
- package/dist/installer.d.ts +2 -2
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +9 -7
- package/dist/installer.js.map +1 -1
- package/dist/prerequisites.d.ts +5 -5
- package/dist/prerequisites.d.ts.map +1 -1
- package/dist/prerequisites.js +10 -32
- package/dist/prerequisites.js.map +1 -1
- package/dist/tui.d.ts +5 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +104 -19
- package/dist/tui.js.map +1 -1
- package/dist/updater.d.ts +30 -4
- package/dist/updater.d.ts.map +1 -1
- package/dist/updater.js +226 -41
- package/dist/updater.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/prerequisites.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/** Diagnóstico compartilhado pelos fluxos de setup, update e upgrade. */
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
|
-
import { access,
|
|
4
|
-
import { createRequire } from "node:module";
|
|
3
|
+
import { access, stat } from "node:fs/promises";
|
|
5
4
|
import { delimiter, join, resolve } from "node:path";
|
|
6
5
|
const MINIMUM_NODE_VERSION = [22, 20, 0];
|
|
7
6
|
/** Informa se a versão do runtime satisfaz o contrato do pacote. */
|
|
@@ -17,24 +16,18 @@ export function nodeVersionSupported(version) {
|
|
|
17
16
|
return true;
|
|
18
17
|
}
|
|
19
18
|
/**
|
|
20
|
-
* Resolve o
|
|
19
|
+
* Resolve o `npx` que chama a CLI oficial `skills` sob demanda.
|
|
21
20
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* Toda materialização do Specsfy passa por `npx skills add`, para usar a
|
|
22
|
+
* versão publicada e tornar o comando apresentado à pessoa explícito.
|
|
24
23
|
*/
|
|
25
|
-
export async function
|
|
24
|
+
export async function resolveNpxSkillsCommand(path = process.env.PATH ?? "", override = process.env.SPECSFY_NPX_COMMAND, _launcher = process.argv[1]) {
|
|
26
25
|
if (override) {
|
|
27
26
|
const executable = resolve(override);
|
|
28
|
-
return (await isExecutable(executable)) ? [executable] : undefined;
|
|
27
|
+
return (await isExecutable(executable)) ? [executable, "skills"] : undefined;
|
|
29
28
|
}
|
|
30
|
-
const skills = await findExecutable("skills", path);
|
|
31
|
-
if (skills)
|
|
32
|
-
return [skills];
|
|
33
|
-
const packaged = await resolvePackagedSkills(launcher);
|
|
34
|
-
if (packaged)
|
|
35
|
-
return [process.execPath, packaged];
|
|
36
29
|
const npx = await findExecutable("npx", path);
|
|
37
|
-
return npx ? [npx, "
|
|
30
|
+
return npx ? [npx, "skills"] : undefined;
|
|
38
31
|
}
|
|
39
32
|
/** Verifica todos os recursos usados pelos comandos de instalação e atualização. */
|
|
40
33
|
export async function checkPrerequisites(project, options = {}) {
|
|
@@ -42,7 +35,7 @@ export async function checkPrerequisites(project, options = {}) {
|
|
|
42
35
|
const nodeVersion = options.nodeVersion ?? process.versions.node;
|
|
43
36
|
const git = await findExecutable("git", path);
|
|
44
37
|
const npm = await findExecutable("npm", path);
|
|
45
|
-
const skills = await
|
|
38
|
+
const skills = await resolveNpxSkillsCommand(path, options.npxOverride ?? process.env.SPECSFY_NPX_COMMAND, options.skillsLauncher ?? process.argv[1]);
|
|
46
39
|
const target = resolve(project);
|
|
47
40
|
let projectOk = false;
|
|
48
41
|
try {
|
|
@@ -69,9 +62,8 @@ export async function checkPrerequisites(project, options = {}) {
|
|
|
69
62
|
name: "skills",
|
|
70
63
|
ok: Boolean(skills),
|
|
71
64
|
detail: skills
|
|
72
|
-
? `skills
|
|
73
|
-
: "
|
|
74
|
-
"disponibilize `skills` ou `npx` no PATH",
|
|
65
|
+
? `instalação de skills disponível por ${skills.join(" ")}`
|
|
66
|
+
: "npx não encontrado; instale o npm e disponibilize `npx` no PATH",
|
|
75
67
|
command: skills,
|
|
76
68
|
},
|
|
77
69
|
{
|
|
@@ -108,20 +100,6 @@ async function findExecutable(name, path) {
|
|
|
108
100
|
}
|
|
109
101
|
return undefined;
|
|
110
102
|
}
|
|
111
|
-
/** Localiza a dependência `skills` a partir do launcher instalado do Specsfy. */
|
|
112
|
-
async function resolvePackagedSkills(launcher) {
|
|
113
|
-
if (!launcher)
|
|
114
|
-
return undefined;
|
|
115
|
-
try {
|
|
116
|
-
const require = createRequire(await realpath(resolve(launcher)));
|
|
117
|
-
const executable = require.resolve("skills/bin/cli.mjs");
|
|
118
|
-
await access(executable, constants.R_OK);
|
|
119
|
-
return executable;
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
return undefined;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
103
|
async function isExecutable(path) {
|
|
126
104
|
try {
|
|
127
105
|
await access(path, constants.X_OK);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prerequisites.js","sourceRoot":"","sources":["../src/prerequisites.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"prerequisites.js","sourceRoot":"","sources":["../src/prerequisites.ts"],"names":[],"mappings":"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"}
|
package/dist/tui.d.ts
CHANGED
|
@@ -119,6 +119,10 @@ export declare class SpecsfyTui {
|
|
|
119
119
|
private mountShell;
|
|
120
120
|
private bindKeys;
|
|
121
121
|
private showTab;
|
|
122
|
+
/** Recupera um alvo navegável quando um painel foi recriado ou fechado. */
|
|
123
|
+
private focusActiveTab;
|
|
124
|
+
/** Renderiza somente enquanto a tela ainda pertence ao ciclo atual. */
|
|
125
|
+
private renderScreen;
|
|
122
126
|
/**
|
|
123
127
|
* Retorna um nível por vez: fecha modal, limpa busca e volta ao Home.
|
|
124
128
|
*
|
|
@@ -135,6 +139,7 @@ export declare class SpecsfyTui {
|
|
|
135
139
|
private renderSkills;
|
|
136
140
|
private renderAbout;
|
|
137
141
|
private refreshAll;
|
|
142
|
+
private refreshAllInternal;
|
|
138
143
|
private refreshIfChanged;
|
|
139
144
|
private skillOptions;
|
|
140
145
|
private visibleSkills;
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
|
package/dist/tui.js
CHANGED
|
@@ -119,6 +119,7 @@ export class SpecsfyTui {
|
|
|
119
119
|
#status;
|
|
120
120
|
#projectInput;
|
|
121
121
|
#modal;
|
|
122
|
+
#modalFocus;
|
|
122
123
|
#lastBackAt = 0;
|
|
123
124
|
#tabButtons = new Map();
|
|
124
125
|
#activeTab = "home";
|
|
@@ -129,6 +130,8 @@ export class SpecsfyTui {
|
|
|
129
130
|
#catalogError = "";
|
|
130
131
|
#installed = new Set();
|
|
131
132
|
#selected = new Set();
|
|
133
|
+
#selectionDirty = false;
|
|
134
|
+
#loaded = false;
|
|
132
135
|
#detected = new Set();
|
|
133
136
|
#skillFilter = "all";
|
|
134
137
|
#skillQuery = "";
|
|
@@ -136,10 +139,13 @@ export class SpecsfyTui {
|
|
|
136
139
|
#suppressSkillToggleUntil = 0;
|
|
137
140
|
#fingerprints = { specs: "", backlogs: "", lock: "" };
|
|
138
141
|
#poller;
|
|
142
|
+
#refreshPromise;
|
|
139
143
|
#testRunning = false;
|
|
140
144
|
#testResultTab = "summary";
|
|
141
145
|
#testSummary = "Nenhuma execução nesta sessão.";
|
|
142
146
|
#testOutput = [];
|
|
147
|
+
#testSummaryPanel;
|
|
148
|
+
#testOutputPanel;
|
|
143
149
|
constructor(project = process.cwd()) {
|
|
144
150
|
this.project = resolvePath(project);
|
|
145
151
|
}
|
|
@@ -158,6 +164,10 @@ export class SpecsfyTui {
|
|
|
158
164
|
});
|
|
159
165
|
await this.start({ screen });
|
|
160
166
|
await new Promise((resolve) => {
|
|
167
|
+
if (screenDestroyed(screen)) {
|
|
168
|
+
resolve();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
161
171
|
screen.once("destroy", () => {
|
|
162
172
|
resolve();
|
|
163
173
|
});
|
|
@@ -170,6 +180,9 @@ export class SpecsfyTui {
|
|
|
170
180
|
* terminais virtuais, sem manter um processo pendurado durante os testes.
|
|
171
181
|
*/
|
|
172
182
|
async start(options = {}) {
|
|
183
|
+
if (this.#screen && !screenDestroyed(this.#screen)) {
|
|
184
|
+
throw new Error("a TUI já foi iniciada nesta instância");
|
|
185
|
+
}
|
|
173
186
|
const screen = options.screen ??
|
|
174
187
|
blessed.screen({
|
|
175
188
|
smartCSR: true,
|
|
@@ -187,13 +200,20 @@ export class SpecsfyTui {
|
|
|
187
200
|
if (this.#poller)
|
|
188
201
|
clearInterval(this.#poller);
|
|
189
202
|
this.#poller = undefined;
|
|
203
|
+
this.#refreshPromise = undefined;
|
|
204
|
+
this.#modal = undefined;
|
|
205
|
+
this.#modalFocus = undefined;
|
|
190
206
|
});
|
|
191
207
|
this.showStatus("Carregando projeto…");
|
|
192
208
|
await this.refreshAll(!options.catalog);
|
|
193
209
|
this.showTab("home");
|
|
194
210
|
if (options.watch !== false) {
|
|
195
211
|
const config = await loadConfig(this.project);
|
|
196
|
-
|
|
212
|
+
if (screenDestroyed(screen))
|
|
213
|
+
return;
|
|
214
|
+
this.#poller = setInterval(() => void this.refreshIfChanged().catch((error) => {
|
|
215
|
+
this.showStatus(`Erro ao atualizar automaticamente: ${errorMessage(error)}`);
|
|
216
|
+
}), config.watch_interval * 1000);
|
|
197
217
|
}
|
|
198
218
|
}
|
|
199
219
|
mountShell(screen) {
|
|
@@ -378,6 +398,8 @@ export class SpecsfyTui {
|
|
|
378
398
|
}
|
|
379
399
|
for (const child of [...body.children])
|
|
380
400
|
child.destroy();
|
|
401
|
+
this.#testSummaryPanel = undefined;
|
|
402
|
+
this.#testOutputPanel = undefined;
|
|
381
403
|
if (tab === "home")
|
|
382
404
|
this.renderHome(body);
|
|
383
405
|
else if (tab === "backlogs")
|
|
@@ -390,7 +412,24 @@ export class SpecsfyTui {
|
|
|
390
412
|
this.renderSkills(body);
|
|
391
413
|
else
|
|
392
414
|
this.renderAbout(body);
|
|
393
|
-
this
|
|
415
|
+
this.focusActiveTab();
|
|
416
|
+
if (!screenDestroyed(this.#screen))
|
|
417
|
+
this.#screen.render();
|
|
418
|
+
}
|
|
419
|
+
/** Recupera um alvo navegável quando um painel foi recriado ou fechado. */
|
|
420
|
+
focusActiveTab() {
|
|
421
|
+
const screen = this.#screen;
|
|
422
|
+
if (!screen || screenDestroyed(screen))
|
|
423
|
+
return;
|
|
424
|
+
const focused = screen.focused;
|
|
425
|
+
if (focused && !focused.detached && focused.visible)
|
|
426
|
+
return;
|
|
427
|
+
this.#tabButtons.get(this.#activeTab)?.focus();
|
|
428
|
+
}
|
|
429
|
+
/** Renderiza somente enquanto a tela ainda pertence ao ciclo atual. */
|
|
430
|
+
renderScreen() {
|
|
431
|
+
if (this.#screen && !screenDestroyed(this.#screen))
|
|
432
|
+
this.#screen.render();
|
|
394
433
|
}
|
|
395
434
|
/**
|
|
396
435
|
* Retorna um nível por vez: fecha modal, limpa busca e volta ao Home.
|
|
@@ -406,7 +445,13 @@ export class SpecsfyTui {
|
|
|
406
445
|
if (this.#modal) {
|
|
407
446
|
this.#modal.destroy();
|
|
408
447
|
this.#modal = undefined;
|
|
409
|
-
this.#
|
|
448
|
+
const focus = this.#modalFocus;
|
|
449
|
+
this.#modalFocus = undefined;
|
|
450
|
+
if (focus && !focus.detached && focus.visible)
|
|
451
|
+
focus.focus();
|
|
452
|
+
else
|
|
453
|
+
this.focusActiveTab();
|
|
454
|
+
this.renderScreen();
|
|
410
455
|
return;
|
|
411
456
|
}
|
|
412
457
|
if (this.#activeTab === "skills" && this.#skillQuery) {
|
|
@@ -520,7 +565,7 @@ export class SpecsfyTui {
|
|
|
520
565
|
preview.setContent(item
|
|
521
566
|
? renderMarkdown(formatBacklogPreview(item.content))
|
|
522
567
|
: "Crie arquivos em specs/backlog/<NNNN>-<slug>.md para visualizá-los aqui.");
|
|
523
|
-
this
|
|
568
|
+
this.renderScreen();
|
|
524
569
|
};
|
|
525
570
|
list.on("select item", updatePreview);
|
|
526
571
|
list.on("keypress", updatePreview);
|
|
@@ -614,7 +659,9 @@ export class SpecsfyTui {
|
|
|
614
659
|
border: { fg: TUI_THEME.focusBackground },
|
|
615
660
|
},
|
|
616
661
|
});
|
|
662
|
+
this.#modalFocus = screen.focused;
|
|
617
663
|
this.#modal = modal;
|
|
664
|
+
screen.focusPush(modal);
|
|
618
665
|
modal.focus();
|
|
619
666
|
screen.render();
|
|
620
667
|
}
|
|
@@ -677,7 +724,7 @@ export class SpecsfyTui {
|
|
|
677
724
|
this.showTab("tests");
|
|
678
725
|
});
|
|
679
726
|
if (this.#testResultTab === "summary") {
|
|
680
|
-
blessed.box({
|
|
727
|
+
this.#testSummaryPanel = blessed.box({
|
|
681
728
|
parent: body,
|
|
682
729
|
top: 6,
|
|
683
730
|
left: 1,
|
|
@@ -698,7 +745,7 @@ export class SpecsfyTui {
|
|
|
698
745
|
// O blessed.log agenda a rolagem depois de setContent e acessa widgets
|
|
699
746
|
// destruídos quando a saída ao vivo recria a aba. A caixa preserva a
|
|
700
747
|
// rolagem sem deixar callbacks pendentes entre duas renderizações.
|
|
701
|
-
blessed.box({
|
|
748
|
+
this.#testOutputPanel = blessed.box({
|
|
702
749
|
parent: body,
|
|
703
750
|
top: 6,
|
|
704
751
|
left: 1,
|
|
@@ -720,9 +767,9 @@ export class SpecsfyTui {
|
|
|
720
767
|
button.focus();
|
|
721
768
|
}
|
|
722
769
|
async runTests() {
|
|
723
|
-
this
|
|
724
|
-
if (this.#testRunning)
|
|
770
|
+
if (this.#modal || this.#testRunning)
|
|
725
771
|
return;
|
|
772
|
+
this.showTab("tests");
|
|
726
773
|
this.#testRunning = true;
|
|
727
774
|
this.#testResultTab = "output";
|
|
728
775
|
this.#testOutput = [];
|
|
@@ -732,27 +779,32 @@ export class SpecsfyTui {
|
|
|
732
779
|
try {
|
|
733
780
|
const result = await runProjectTests(this.project, (line) => {
|
|
734
781
|
this.#testOutput.push(line);
|
|
782
|
+
this.#testOutputPanel?.setContent(this.#testOutput.join("\n"));
|
|
735
783
|
if (this.#activeTab === "tests" && this.#testResultTab === "output") {
|
|
736
|
-
this.
|
|
784
|
+
this.renderScreen();
|
|
737
785
|
}
|
|
738
786
|
});
|
|
739
787
|
this.#testSummary = formatTestRun(result);
|
|
788
|
+
this.#testSummaryPanel?.setContent(this.#testSummary);
|
|
740
789
|
this.#testResultTab = "summary";
|
|
741
790
|
this.showStatus(`${result.exit_code === 0 ? "Testes passaram" : "Testes falharam"} · ` +
|
|
742
791
|
`${result.duration_seconds.toFixed(2)}s · exit code ${result.exit_code}`);
|
|
743
|
-
this
|
|
792
|
+
if (this.#activeTab === "tests")
|
|
793
|
+
this.showTab("tests");
|
|
744
794
|
}
|
|
745
795
|
catch (error) {
|
|
746
796
|
const message = `Erro ao executar testes: ${errorMessage(error)}`;
|
|
747
797
|
this.#testSummary = message;
|
|
798
|
+
this.#testSummaryPanel?.setContent(message);
|
|
748
799
|
this.#testOutput.push(message);
|
|
749
800
|
this.#testResultTab = "summary";
|
|
750
801
|
this.showStatus(message);
|
|
751
|
-
this
|
|
802
|
+
if (this.#activeTab === "tests")
|
|
803
|
+
this.showTab("tests");
|
|
752
804
|
}
|
|
753
805
|
finally {
|
|
754
806
|
this.#testRunning = false;
|
|
755
|
-
this
|
|
807
|
+
this.renderScreen();
|
|
756
808
|
}
|
|
757
809
|
}
|
|
758
810
|
renderSkills(body) {
|
|
@@ -904,7 +956,7 @@ export class SpecsfyTui {
|
|
|
904
956
|
detail.setContent(option
|
|
905
957
|
? formatSkillDetail(option, this.#installed, this.#selected, this.#detected)
|
|
906
958
|
: "Nenhuma skill visível.\n\nAjuste a busca ou os filtros para continuar.");
|
|
907
|
-
this
|
|
959
|
+
this.renderScreen();
|
|
908
960
|
};
|
|
909
961
|
list.on("select item", updateDetail);
|
|
910
962
|
list.on("keypress", () => setImmediate(updateDetail));
|
|
@@ -956,7 +1008,18 @@ export class SpecsfyTui {
|
|
|
956
1008
|
"Ctrl+Q encerra a interface.",
|
|
957
1009
|
});
|
|
958
1010
|
}
|
|
959
|
-
|
|
1011
|
+
refreshAll(reloadCatalog) {
|
|
1012
|
+
if (this.#refreshPromise)
|
|
1013
|
+
return this.#refreshPromise;
|
|
1014
|
+
const promise = this.refreshAllInternal(reloadCatalog);
|
|
1015
|
+
const tracked = promise.finally(() => {
|
|
1016
|
+
if (this.#refreshPromise === tracked)
|
|
1017
|
+
this.#refreshPromise = undefined;
|
|
1018
|
+
});
|
|
1019
|
+
this.#refreshPromise = tracked;
|
|
1020
|
+
return tracked;
|
|
1021
|
+
}
|
|
1022
|
+
async refreshAllInternal(reloadCatalog) {
|
|
960
1023
|
try {
|
|
961
1024
|
const [specs, backlogs, lock] = await Promise.all([
|
|
962
1025
|
scanSpecs(this.project),
|
|
@@ -965,8 +1028,8 @@ export class SpecsfyTui {
|
|
|
965
1028
|
]);
|
|
966
1029
|
this.#specs = specs;
|
|
967
1030
|
this.#backlogs = backlogs;
|
|
968
|
-
|
|
969
|
-
this.#
|
|
1031
|
+
const installed = new Set(Object.keys(lock.skills).filter(isSpecsfySkill));
|
|
1032
|
+
this.#installed = installed;
|
|
970
1033
|
if (reloadCatalog || !this.#catalog) {
|
|
971
1034
|
try {
|
|
972
1035
|
this.#catalog = await Catalog.fetch();
|
|
@@ -974,10 +1037,14 @@ export class SpecsfyTui {
|
|
|
974
1037
|
this.#catalogError = "";
|
|
975
1038
|
}
|
|
976
1039
|
catch (error) {
|
|
977
|
-
this.#catalogEntries = [];
|
|
978
1040
|
this.#catalogError = errorMessage(error);
|
|
979
1041
|
}
|
|
980
1042
|
}
|
|
1043
|
+
const available = new Set(buildSkillOptions(this.#catalogEntries, installed).map((option) => option.name));
|
|
1044
|
+
this.#selected = this.#loaded && this.#selectionDirty
|
|
1045
|
+
? new Set([...this.#selected].filter((name) => available.has(name)))
|
|
1046
|
+
: new Set(installed);
|
|
1047
|
+
this.#loaded = true;
|
|
981
1048
|
this.#fingerprints = {
|
|
982
1049
|
specs: await specsFingerprint(this.project),
|
|
983
1050
|
backlogs: await backlogsFingerprint(this.project),
|
|
@@ -1019,20 +1086,26 @@ export class SpecsfyTui {
|
|
|
1019
1086
|
}
|
|
1020
1087
|
selectFramework() {
|
|
1021
1088
|
this.#selected = new Set([...this.#selected, ...FRAMEWORK_SKILLS]);
|
|
1089
|
+
this.#selectionDirty = true;
|
|
1022
1090
|
this.showStatus("As skills do framework foram selecionadas. Use ^A para aplicar.");
|
|
1023
1091
|
this.showTab("skills");
|
|
1024
1092
|
}
|
|
1025
1093
|
async detectSkills() {
|
|
1094
|
+
if (this.#modal)
|
|
1095
|
+
return;
|
|
1026
1096
|
this.showTab("skills");
|
|
1097
|
+
const startedOnSkills = this.#activeTab === "skills";
|
|
1027
1098
|
try {
|
|
1028
1099
|
this.#catalog ??= await Catalog.fetch();
|
|
1029
1100
|
this.#catalogEntries = this.#catalog.entries;
|
|
1030
1101
|
const entries = await this.#catalog.detect(this.project);
|
|
1031
1102
|
this.#detected = new Set(entries.map((entry) => entry.name));
|
|
1032
1103
|
this.#selected = new Set([...this.#selected, ...this.#detected]);
|
|
1104
|
+
this.#selectionDirty = true;
|
|
1033
1105
|
this.#skillFilter = "detected";
|
|
1034
1106
|
this.showStatus(`Skills detectadas e selecionadas: ${[...this.#detected].sort().join(", ") || "nenhuma skill"}`);
|
|
1035
|
-
this
|
|
1107
|
+
if (startedOnSkills && this.#activeTab === "skills")
|
|
1108
|
+
this.showTab("skills");
|
|
1036
1109
|
}
|
|
1037
1110
|
catch (error) {
|
|
1038
1111
|
this.showStatus(`Erro: ${errorMessage(error)}`);
|
|
@@ -1049,21 +1122,26 @@ export class SpecsfyTui {
|
|
|
1049
1122
|
else {
|
|
1050
1123
|
this.#selected.add(this.#selectedSkill);
|
|
1051
1124
|
}
|
|
1125
|
+
this.#selectionDirty = true;
|
|
1052
1126
|
this.showTab("skills");
|
|
1053
1127
|
}
|
|
1054
1128
|
selectVisible() {
|
|
1055
1129
|
this.#suppressSkillToggleUntil = Date.now() + 100;
|
|
1056
1130
|
for (const option of this.visibleSkills())
|
|
1057
1131
|
this.#selected.add(option.name);
|
|
1132
|
+
this.#selectionDirty = true;
|
|
1058
1133
|
this.showTab("skills");
|
|
1059
1134
|
}
|
|
1060
1135
|
clearVisible() {
|
|
1061
1136
|
this.#suppressSkillToggleUntil = Date.now() + 100;
|
|
1062
1137
|
for (const option of this.visibleSkills())
|
|
1063
1138
|
this.#selected.delete(option.name);
|
|
1139
|
+
this.#selectionDirty = true;
|
|
1064
1140
|
this.showTab("skills");
|
|
1065
1141
|
}
|
|
1066
1142
|
async applySkills() {
|
|
1143
|
+
if (this.#modal)
|
|
1144
|
+
return;
|
|
1067
1145
|
this.showTab("skills");
|
|
1068
1146
|
try {
|
|
1069
1147
|
const selected = new Set([...this.#selected].filter(isSpecsfySkill));
|
|
@@ -1093,6 +1171,7 @@ export class SpecsfyTui {
|
|
|
1093
1171
|
}
|
|
1094
1172
|
if (toRemove.length)
|
|
1095
1173
|
changed.push(...(await installer.remove(toRemove.sort())));
|
|
1174
|
+
this.#selectionDirty = false;
|
|
1096
1175
|
await this.refreshAll(false);
|
|
1097
1176
|
this.showStatus(changed.length
|
|
1098
1177
|
? `Seleção aplicada: ${changed.length} alteração(ões).`
|
|
@@ -1103,6 +1182,8 @@ export class SpecsfyTui {
|
|
|
1103
1182
|
}
|
|
1104
1183
|
}
|
|
1105
1184
|
async updateSkills() {
|
|
1185
|
+
if (this.#modal)
|
|
1186
|
+
return;
|
|
1106
1187
|
this.showTab("skills");
|
|
1107
1188
|
try {
|
|
1108
1189
|
const changed = await (await SkillInstaller.create(this.project)).updateAll();
|
|
@@ -1117,7 +1198,7 @@ export class SpecsfyTui {
|
|
|
1117
1198
|
}
|
|
1118
1199
|
showStatus(message) {
|
|
1119
1200
|
this.#status?.setContent(message);
|
|
1120
|
-
this
|
|
1201
|
+
this.renderScreen();
|
|
1121
1202
|
}
|
|
1122
1203
|
}
|
|
1123
1204
|
/** Cria as opções base, especialistas e instalações fora do catálogo atual. */
|
|
@@ -1299,4 +1380,8 @@ function terminalScrollbar() {
|
|
|
1299
1380
|
style: { bg: TUI_THEME.focusBackground },
|
|
1300
1381
|
};
|
|
1301
1382
|
}
|
|
1383
|
+
/** Detecta o estado encerrado sem depender da tipagem incompleta do blessed. */
|
|
1384
|
+
function screenDestroyed(screen) {
|
|
1385
|
+
return Boolean(screen.destroyed);
|
|
1386
|
+
}
|
|
1302
1387
|
//# sourceMappingURL=tui.js.map
|