@fprad0/skill-master-mcp 0.0.6 → 0.0.8

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 CHANGED
@@ -7,6 +7,21 @@ All notable changes to `skill_master` will be tracked here.
7
7
  - Prepare a public npm publication path with dedicated workflow and operator guide.
8
8
  - Upgrade release automation from Node `20` to Node `22`.
9
9
 
10
+ ## [0.0.8] - 2026-06-27
11
+
12
+ - Add `skill_master_prompt_router` with `manual`, `balanced`, and `always-on-assisted` activation modes.
13
+ - Add Dev Senior Master persona routing, safety gates, Notion/update detection, and learned-skill signals.
14
+ - Add success-learning flows for human approval packages, local/global activation, study decisions, and rejection history.
15
+ - Add `skill-master-activation`, `skill-master-success-skills`, and `skill-master-eval-activation` operator CLIs.
16
+ - Expand the terminal menu with activation status, prompt recommendations, learned-skill notifications, study/reject actions, and Notion summaries.
17
+ - Add activation evals with positive, negative, and risk cases plus `npm run eval:activation`.
18
+
19
+ ## [0.0.7] - 2026-06-26
20
+
21
+ - Add a visual terminal menu for `skill-master-menu` using `prompts`, with TTY detection and direct action mode.
22
+ - Extract the menu core into a reusable module for tests and future UI changes.
23
+ - Keep the package compatible with Node `18+` instead of moving to a heavier TUI stack.
24
+
10
25
  ## [0.0.6] - 2026-06-26
11
26
 
12
27
  - Harden `skill-master-configure-private-registry` with HTTPS registry validation, scoped token handling, redacted dry-runs, timestamped backups, and POSIX `0600` permissions.
package/README.md CHANGED
@@ -108,18 +108,21 @@ npm install -g @fprad0/skill-master-mcp
108
108
  npx -y @fprad0/skill-master-mcp@latest
109
109
  ```
110
110
 
111
- Estado atual validado em `2026-06-26`:
111
+ Estado atual preparado em `2026-06-27`:
112
112
 
113
- - pacote publico publicado: `@fprad0/skill-master-mcp@0.0.5`
114
- - dist-tag `latest` apontando para `0.0.5`
115
- - workflow `Publish Skill Master to npmjs` concluido com sucesso
116
- - `npm install` e `npx` confirmados
113
+ - release local preparada: `@fprad0/skill-master-mcp@0.0.8`
114
+ - validacao de pacote por tarball local confirmada
115
+ - publicacao no npmjs aguardando autenticacao npmjs nesta maquina
116
+ - apos publicar, validar `npm install`, `npx` e dist-tag `latest`
117
117
 
118
118
  Comandos globais principais:
119
119
 
120
120
  ```bash
121
+ skill-master-activation
122
+ skill-master-eval-activation
121
123
  skill-master-mcp
122
124
  skill-master-menu
125
+ skill-master-success-skills
123
126
  skill-master-update
124
127
  skill-master-configure-private-registry
125
128
  ```
@@ -130,6 +133,44 @@ O `skill-master-mcp` deve continuar reservado para clientes MCP via `stdio`. Par
130
133
  skill-master-menu
131
134
  ```
132
135
 
136
+ O menu agora possui modo visual interativo para terminal com TTY e tambem aceita execucao direta por acao:
137
+
138
+ ```bash
139
+ skill-master-menu --run status
140
+ skill-master-menu --run check
141
+ skill-master-menu --run update --yes
142
+ skill-master-menu --run notifications
143
+ skill-master-menu --run study-skills
144
+ skill-master-menu --run approval-package
145
+ skill-master-menu --run activation-status
146
+ skill-master-menu --run recommend-prompt
147
+ skill-master-menu --run notion-summary
148
+ ```
149
+
150
+ O menu visual usa `prompts` para ficar mais legivel no terminal e manter compatibilidade com `Node 18+`.
151
+
152
+ O menu tambem mostra notificacoes de skills aprendidas pendentes e links externos para estudo. As acoes de ativacao sao:
153
+
154
+ - `skill-master-menu --run activate-learned-local`: instala uma skill aprovada em `.codex/skills` do workspace atual.
155
+ - `skill-master-menu --run activate-learned-global`: instala uma skill aprovada em `${CODEX_HOME:-~/.codex}/skills`.
156
+ - `skill-master-menu --run mark-study`: registra uma skill candidata como material para estudo.
157
+ - `skill-master-menu --run reject-skill`: rejeita uma skill candidata preservando historico.
158
+
159
+ Para modo de ativacao e recomendacao local:
160
+
161
+ ```bash
162
+ skill-master-activation --status
163
+ skill-master-activation --set-mode balanced
164
+ skill-master-activation --route-prompt "skill-master, recomende skills para este prompt"
165
+ skill-master-activation --notion-summary
166
+ ```
167
+
168
+ Para rodar as avaliacoes de ativacao antes de release:
169
+
170
+ ```bash
171
+ npm run eval:activation
172
+ ```
173
+
133
174
  Para atualizar a instalacao global via npm sem iniciar o servidor MCP:
134
175
 
135
176
  ```bash
@@ -190,18 +231,62 @@ O `skill_master` pode aprender com as skills ja existentes em cada maquina insta
190
231
  Ferramentas MCP principais:
191
232
 
192
233
  - `skill_master_refresh_catalog`
234
+ - `skill_master_prompt_router`
235
+ - `skill_master_activation_check`
236
+ - `skill_master_recommend`
193
237
  - `skill_master_prepare_skill_contribution`
194
238
  - `skill_master_review_skill_contribution`
239
+ - `skill_master_prepare_success_skill`
240
+ - `skill_master_review_success_skill`
241
+ - `skill_master_list_unapproved_success_skills`
242
+ - `skill_master_prepare_success_skill_approval_package`
243
+ - `skill_master_activate_success_skill`
195
244
 
196
245
  O pacote de contribuicao nao envia arquivos automaticamente, nao executa skills desconhecidas e nao inclui caminhos completos ou corpo bruto por padrao.
197
246
 
247
+ O fluxo de aprendizado por implementacoes bem-sucedidas cria rascunhos locais em staging, gera pacote de aprovacao humana e permite ativacao explicita em escopo local ou global. Ele exige evidencias, revisa risco/duplicidade e mantem candidatos externos como nao aprovados ate revisao humana. Nenhuma skill aprendida e publicada automaticamente.
248
+
198
249
  Leia:
199
250
 
200
251
  - [Rede segura de skills](docs/architecture/REDE_SEGURA_DE_SKILLS.md)
252
+ - [Aprendizado de implementacoes bem-sucedidas](docs/architecture/APRENDIZADO_DE_IMPLEMENTACOES_BEM_SUCEDIDAS.md)
201
253
 
202
254
  ## Modos de ativacao em prompts
203
255
 
204
- A partir da versao `0.0.4`, clientes e agentes podem usar `skill_master_activation_check` antes de decidir se devem acionar recomendacoes de skills.
256
+ Clientes e agentes podem usar `skill_master_prompt_router` como camada principal antes de decidir se devem acionar recomendacoes de skills, aplicar persona ou bloquear uma acao sensivel.
257
+
258
+ Modos suportados:
259
+
260
+ - `manual`: ativa apenas com mencao direta ao Skill Master ou gate bloqueante.
261
+ - `balanced`: modo recomendado; ativa por mencao direta, tarefa tecnica com skill relevante, Notion, aprendizado, validacao, MCP ou publicacao.
262
+ - `always-on-assisted`: avalia quase todo prompt, mas retorna `executionMode: no-op` quando nao houver ganho claro.
263
+
264
+ Exemplo de chamada conceitual:
265
+
266
+ ```json
267
+ {
268
+ "prompt": "skill-master, veja se existe uma skill para validar este deploy",
269
+ "activationMode": "balanced",
270
+ "riskTolerance": "normal"
271
+ }
272
+ ```
273
+
274
+ Saida esperada:
275
+
276
+ ```json
277
+ {
278
+ "shouldActivate": true,
279
+ "personaOverlay": "Dev Senior Master",
280
+ "executionMode": "assist",
281
+ "safetyGates": [],
282
+ "learningOpportunity": false,
283
+ "notionUpdateNeeded": false
284
+ }
285
+ ```
286
+
287
+ Use `skill_master_activation_check` quando precisar apenas de uma decisao menor e retrocompativel de ativacao/recomendacao.
288
+
289
+ Restricoes explicitas como `sem publicar`, `nao publicar` ou `nao publique` sao tratadas como execucao local. O router deve registrar `publication_explicitly_disabled` e nao pode transformar essa frase em autorizacao ou intencao de release.
205
290
 
206
291
  Ativacao explicita:
207
292
 
@@ -231,6 +316,11 @@ Cliente: chama skill_master_activation_check.
231
316
  Cliente: se ativar, chama skill_master_recommend ou segue as recomendacoes retornadas.
232
317
  ```
233
318
 
319
+ Diagnostico importante:
320
+
321
+ - `skill_master_list_sources` mostra `configPath`, `workspace` e se `workspaceRoots` esta configurado.
322
+ - Se `workspaceRoots` estiver vazio, skills em `.codex/skills` do projeto nao serao catalogadas ate atualizar `sources.json` e reiniciar o processo MCP.
323
+
234
324
  ## Atualizacao automatica via npm
235
325
 
236
326
  Para instalacoes feitas por `npm install -g`, o caminho seguro de auto-update e executar `skill-master-update` fora do processo MCP.
package/VERSION.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  Versão funcional planejada: `00.02`
4
4
 
5
- Versão técnica para empacotamento semântico: `0.0.6`
5
+ Versão técnica para empacotamento semântico: `0.0.8`
6
6
 
7
7
  ## Observação
8
8
 
9
- O nome `00.02` será usado na comunicação e nos documentos. Para ferramentas que exigem SemVer, como npm e alguns fluxos de release, usar `0.0.6`.
9
+ O nome `00.02` será usado na comunicação e nos documentos. Para ferramentas que exigem SemVer, como npm e alguns fluxos de release, usar `0.0.8`.
@@ -0,0 +1,353 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import process from 'node:process';
5
+
6
+ const ANSI = {
7
+ reset: '\x1b[0m',
8
+ bold: '\x1b[1m',
9
+ dim: '\x1b[2m',
10
+ cyan: '\x1b[36m',
11
+ green: '\x1b[32m',
12
+ yellow: '\x1b[33m',
13
+ red: '\x1b[31m',
14
+ };
15
+
16
+ function colorize(text, color, enabled) {
17
+ return enabled ? `${color}${text}${ANSI.reset}` : text;
18
+ }
19
+
20
+ export function readJson(rootDir, relativePath) {
21
+ const target = join(rootDir, relativePath);
22
+ if (!existsSync(target)) {
23
+ return null;
24
+ }
25
+
26
+ return JSON.parse(readFileSync(target, 'utf8'));
27
+ }
28
+
29
+ export function readText(rootDir, relativePath) {
30
+ const target = join(rootDir, relativePath);
31
+ if (!existsSync(target)) {
32
+ return null;
33
+ }
34
+
35
+ return readFileSync(target, 'utf8').trim();
36
+ }
37
+
38
+ export function getMenuStatus(rootDir) {
39
+ const packageJson = readJson(rootDir, 'package.json');
40
+ const stableManifest = readJson(rootDir, 'manifests/channels/stable.json');
41
+ const versionText = readText(rootDir, 'VERSION.md');
42
+ const successLearningDir = process.env.SKILL_MASTER_SUCCESS_LEARNING_DIR
43
+ ?? join(process.env.SKILL_MASTER_HOME ?? join(process.env.HOME ?? process.env.USERPROFILE ?? '', '.skill-master'), 'data', 'success-learning');
44
+ const studyCandidates = readJson(rootDir, 'network/unapproved-skill-candidates.json');
45
+
46
+ return {
47
+ packageName: packageJson?.name ?? 'nao encontrado',
48
+ semver: packageJson?.version ?? 'nao encontrado',
49
+ manifestVersion: stableManifest?.version ?? 'nao encontrado',
50
+ manifestSemver: stableManifest?.semver ?? 'nao encontrado',
51
+ versionText,
52
+ rootDir,
53
+ pendingSuccessDrafts: countManifestFiles(successLearningDir),
54
+ studyCandidates: Array.isArray(studyCandidates?.candidates) ? studyCandidates.candidates.length : 0,
55
+ };
56
+ }
57
+
58
+ function countManifestFiles(directory) {
59
+ if (!directory || !existsSync(directory)) {
60
+ return 0;
61
+ }
62
+
63
+ let count = 0;
64
+ const visit = (current) => {
65
+ for (const entry of readdirSync(current, { withFileTypes: true })) {
66
+ const fullPath = join(current, entry.name);
67
+ if (entry.isDirectory()) visit(fullPath);
68
+ else if (entry.isFile() && entry.name === 'manifest.json') count += 1;
69
+ }
70
+ };
71
+
72
+ visit(directory);
73
+ return count;
74
+ }
75
+
76
+ export function buildMenuCommands({ rootDir, currentFile, nodeExecPath = process.execPath }) {
77
+ return [
78
+ {
79
+ key: 'status',
80
+ aliases: ['status'],
81
+ label: 'Status local',
82
+ description: 'Mostra versao local, manifesto e informacoes do pacote.',
83
+ command: nodeExecPath,
84
+ args: [currentFile, '--status'],
85
+ },
86
+ {
87
+ key: 'check',
88
+ aliases: ['check', 'gate'],
89
+ label: 'Rodar gate completo',
90
+ description: 'Executa build, testes e validacao de manifestos.',
91
+ command: 'npm',
92
+ args: ['run', 'check'],
93
+ },
94
+ {
95
+ key: 'build',
96
+ aliases: ['build'],
97
+ label: 'Rodar build',
98
+ description: 'Compila o projeto localmente.',
99
+ command: 'npm',
100
+ args: ['run', 'build'],
101
+ },
102
+ {
103
+ key: 'publicNpm',
104
+ aliases: ['public-npm', 'npm', 'registry'],
105
+ label: 'Validar pacote no npm publico',
106
+ description: 'Consulta a versao publicada em registry.npmjs.org.',
107
+ command: 'npm',
108
+ args: [
109
+ 'view',
110
+ '@fprad0/skill-master-mcp',
111
+ 'version',
112
+ '--registry=https://registry.npmjs.org',
113
+ ],
114
+ },
115
+ {
116
+ key: 'updateGlobal',
117
+ aliases: ['update', 'update-global'],
118
+ label: 'Atualizar pacote global via npm',
119
+ description: 'Atualiza a instalacao global e exige reinicio do cliente MCP.',
120
+ command: nodeExecPath,
121
+ args: [join(rootDir, 'bin', 'skill-master-update.mjs')],
122
+ confirmMessage: 'Atualizar o pacote global agora?',
123
+ },
124
+ {
125
+ key: 'privateRegistry',
126
+ aliases: ['private-registry', 'private', 'github-packages'],
127
+ label: 'Configurar registry privado GitHub Packages',
128
+ description: 'Prepara o .npmrc e valida o acesso ao pacote privado.',
129
+ command: nodeExecPath,
130
+ args: ['scripts/configure-private-registry.mjs', '--validate'],
131
+ confirmMessage: 'Rodar a configuracao de registry privado agora?',
132
+ },
133
+ {
134
+ key: 'activationStatus',
135
+ aliases: ['activation-status', 'modo', 'modo-ativacao'],
136
+ label: 'Modo de ativacao atual',
137
+ description: 'Mostra o modo manual, balanced ou always-on-assisted configurado localmente.',
138
+ command: nodeExecPath,
139
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--status'],
140
+ },
141
+ {
142
+ key: 'activationBalanced',
143
+ aliases: ['set-balanced', 'balanced'],
144
+ label: 'Usar modo balanced',
145
+ description: 'Define balanced como modo padrao de ativacao do Skill Master.',
146
+ command: nodeExecPath,
147
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--set-mode', 'balanced'],
148
+ },
149
+ {
150
+ key: 'activationAlwaysOn',
151
+ aliases: ['set-always-on', 'always-on-assisted'],
152
+ label: 'Usar modo always-on-assisted',
153
+ description: 'Define avaliacao assistida quase sempre ativa, mantendo no-op quando nao houver ganho.',
154
+ command: nodeExecPath,
155
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--set-mode', 'always-on-assisted'],
156
+ confirmMessage: 'Alterar o modo local para always-on-assisted?',
157
+ },
158
+ {
159
+ key: 'promptRecommendation',
160
+ aliases: ['recommend-prompt', 'recomendar-prompt', 'prompt-router'],
161
+ label: 'Ver recomendacao para um prompt',
162
+ description: 'Abre um fluxo interativo para avaliar um prompt pelo router local.',
163
+ command: nodeExecPath,
164
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--route-prompt-interactive'],
165
+ },
166
+ {
167
+ key: 'successNotifications',
168
+ aliases: ['notifications', 'notificacoes', 'success-notifications'],
169
+ label: 'Notificacoes de skills aprendidas',
170
+ description: 'Mostra drafts pendentes, aprovacoes e skills externas para estudar.',
171
+ command: nodeExecPath,
172
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--notify'],
173
+ },
174
+ {
175
+ key: 'studySkills',
176
+ aliases: ['study-skills', 'skills-estudo', 'estudar'],
177
+ label: 'Skills para estudar',
178
+ description: 'Lista skills externas e links de criadores ainda nao aprovados.',
179
+ command: nodeExecPath,
180
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--study'],
181
+ },
182
+ {
183
+ key: 'approvalPackage',
184
+ aliases: ['approval-package', 'aprovar', 'pacote-aprovacao'],
185
+ label: 'Gerar pacote de aprovacao humana',
186
+ description: 'Cria um relatorio local para revisar e aprovar skills aprendidas.',
187
+ command: nodeExecPath,
188
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--approval-package'],
189
+ },
190
+ {
191
+ key: 'markLearnedStudy',
192
+ aliases: ['mark-study', 'manter-estudo'],
193
+ label: 'Manter skill candidata para estudo',
194
+ description: 'Seleciona uma candidata e registra decisao de manter para estudo.',
195
+ command: nodeExecPath,
196
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--mark-study-interactive'],
197
+ },
198
+ {
199
+ key: 'rejectLearnedSkill',
200
+ aliases: ['reject-skill', 'rejeitar-skill'],
201
+ label: 'Rejeitar skill candidata',
202
+ description: 'Seleciona uma candidata, registra rejeicao e preserva historico.',
203
+ command: nodeExecPath,
204
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--reject-interactive'],
205
+ confirmMessage: 'Abrir fluxo para rejeitar uma skill candidata?',
206
+ },
207
+ {
208
+ key: 'activateLearnedLocal',
209
+ aliases: ['activate-learned-local', 'ativar-local', 'skill-local'],
210
+ label: 'Ativar skill aprendida no workspace',
211
+ description: 'Instala uma skill aprendida em .codex/skills do projeto atual.',
212
+ command: nodeExecPath,
213
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--activate-interactive', '--target', 'local'],
214
+ confirmMessage: 'Selecionar e ativar uma skill aprendida no workspace atual?',
215
+ },
216
+ {
217
+ key: 'activateLearnedGlobal',
218
+ aliases: ['activate-learned-global', 'ativar-global', 'skill-global'],
219
+ label: 'Ativar skill aprendida global',
220
+ description: 'Instala uma skill aprendida em CODEX_HOME/skills ou ~/.codex/skills.',
221
+ command: nodeExecPath,
222
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--activate-interactive', '--target', 'global'],
223
+ confirmMessage: 'Selecionar e ativar uma skill aprendida como skill global deste usuario?',
224
+ },
225
+ {
226
+ key: 'notionSummary',
227
+ aliases: ['notion-summary', 'resumo-notion'],
228
+ label: 'Abrir resumo para Notion',
229
+ description: 'Mostra um resumo copiavel do estado de ativacao para registrar no ledger Notion.',
230
+ command: nodeExecPath,
231
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--notion-summary'],
232
+ },
233
+ ];
234
+ }
235
+
236
+ export function buildMenuChoices(commands) {
237
+ return commands.map((command) => ({
238
+ title: command.label,
239
+ description: command.description,
240
+ value: command.key,
241
+ })).concat({
242
+ title: 'Sair',
243
+ description: 'Fecha o menu operacional.',
244
+ value: '__exit__',
245
+ });
246
+ }
247
+
248
+ export function resolveActionKey(input, commands) {
249
+ const normalized = (input ?? '').trim().toLowerCase();
250
+ if (!normalized) {
251
+ return null;
252
+ }
253
+
254
+ return commands.find((command) =>
255
+ command.key.toLowerCase() === normalized || command.aliases.includes(normalized),
256
+ )?.key ?? null;
257
+ }
258
+
259
+ export function isInteractiveTerminal() {
260
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
261
+ }
262
+
263
+ export function formatStatusReport(status) {
264
+ const lines = [
265
+ 'Skill Master MCP - status local',
266
+ `Diretorio: ${status.rootDir}`,
267
+ `Pacote: ${status.packageName}`,
268
+ `Semver local: ${status.semver}`,
269
+ `Manifesto stable: ${status.manifestVersion}`,
270
+ `Manifesto semver: ${status.manifestSemver}`,
271
+ `Drafts de skills aprendidas: ${status.pendingSuccessDrafts}`,
272
+ `Skills externas para estudar: ${status.studyCandidates}`,
273
+ ];
274
+
275
+ if (status.versionText) {
276
+ lines.push('', 'VERSION.md:');
277
+ lines.push(...status.versionText.split('\n').slice(0, 6));
278
+ }
279
+
280
+ return lines.join('\n');
281
+ }
282
+
283
+ function renderPanelLines(lines, { color = ANSI.cyan, useColor = false } = {}) {
284
+ const width = Math.max(...lines.map((line) => line.length), 24);
285
+ const border = `+${'-'.repeat(width + 2)}+`;
286
+ const paintedBorder = colorize(border, color, useColor);
287
+ const body = lines.map((line) => `| ${line.padEnd(width)} |`);
288
+ return [paintedBorder, ...body, paintedBorder].join('\n');
289
+ }
290
+
291
+ export function formatMenuBanner(status, { useColor = false } = {}) {
292
+ const lines = [
293
+ colorize('Skill Master MCP', ANSI.bold, useColor),
294
+ 'Menu operacional para manutencao local',
295
+ `Versao local ${status.semver} | canal ${status.manifestVersion}`,
296
+ `Pendencias: ${status.pendingSuccessDrafts} drafts | estudo: ${status.studyCandidates} links`,
297
+ colorize('Setas + Enter para navegar', ANSI.dim, useColor),
298
+ ];
299
+ return renderPanelLines(lines, { color: ANSI.cyan, useColor });
300
+ }
301
+
302
+ export function formatActionHeader(action, { useColor = false } = {}) {
303
+ return renderPanelLines(
304
+ [
305
+ colorize(action.label, ANSI.bold, useColor),
306
+ action.description,
307
+ ],
308
+ { color: ANSI.green, useColor },
309
+ );
310
+ }
311
+
312
+ export function formatResultMessage(code, { useColor = false } = {}) {
313
+ if (code === 0) {
314
+ return colorize('Comando concluido com sucesso.', ANSI.green, useColor);
315
+ }
316
+
317
+ return colorize(`Comando terminou com codigo ${code}.`, ANSI.red, useColor);
318
+ }
319
+
320
+ export function formatHelp(commands) {
321
+ const actionList = commands.map((command) => ` - ${command.key}: ${command.label}`).join('\n');
322
+
323
+ return `Skill Master Menu
324
+
325
+ Uso:
326
+ skill-master-menu
327
+ skill-master-menu --status
328
+ skill-master-menu --run <acao>
329
+ skill-master-menu --run update --yes
330
+ skill-master-menu --help
331
+
332
+ Acoes disponiveis:
333
+ ${actionList}
334
+
335
+ O comando de menu e voltado para operacao humana. O binario MCP stdio continua sendo:
336
+ skill-master-mcp
337
+ `;
338
+ }
339
+
340
+ export function runCommand(action, { cwd, env = process.env } = {}) {
341
+ return new Promise((resolve) => {
342
+ const child = spawn(action.command, action.args, {
343
+ cwd,
344
+ env,
345
+ shell: process.platform === 'win32',
346
+ stdio: 'inherit',
347
+ });
348
+
349
+ child.on('close', (code) => {
350
+ resolve(code ?? 1);
351
+ });
352
+ });
353
+ }