@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 +15 -0
- package/README.md +96 -6
- package/VERSION.md +2 -2
- package/bin/lib/menu-core.mjs +353 -0
- package/bin/skill-master-activation.mjs +163 -0
- package/bin/skill-master-eval-activation.mjs +32 -0
- package/bin/skill-master-menu.mjs +136 -143
- package/bin/skill-master-success-skills.mjs +307 -0
- package/dist/activation-evals.d.ts +32 -0
- package/dist/activation-evals.d.ts.map +1 -0
- package/dist/activation-evals.js +116 -0
- package/dist/activation-evals.js.map +1 -0
- package/dist/index.js +326 -1
- package/dist/index.js.map +1 -1
- package/dist/prompt-router.d.ts +43 -0
- package/dist/prompt-router.d.ts.map +1 -0
- package/dist/prompt-router.js +308 -0
- package/dist/prompt-router.js.map +1 -0
- package/dist/success-learning.d.ts +147 -0
- package/dist/success-learning.d.ts.map +1 -0
- package/dist/success-learning.js +444 -0
- package/dist/success-learning.js.map +1 -0
- package/docs/architecture/APRENDIZADO_DE_IMPLEMENTACOES_BEM_SUCEDIDAS.md +125 -0
- package/docs/architecture/ARQUITETURA_AUTO_UPDATE.md +9 -0
- package/docs/architecture/PLANO_MASTER_ACIONAMENTO_AUTOMATICO_E_APRENDIZADO.md +341 -0
- package/docs/architecture/REDE_SEGURA_DE_SKILLS.md +148 -0
- package/manifests/channels/beta.json +6 -5
- package/manifests/channels/stable.json +7 -6
- package/network/approved-skills.json +51 -2
- package/network/unapproved-skill-candidates.json +77 -0
- package/package.json +9 -3
- package/sources.json +4 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import prompts from 'prompts';
|
|
9
|
+
import { buildCatalog, loadConfig } from '../dist/catalog.js';
|
|
10
|
+
import { routeSkillMasterPrompt } from '../dist/prompt-router.js';
|
|
11
|
+
|
|
12
|
+
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
13
|
+
const skillMasterHome = process.env.SKILL_MASTER_HOME ?? path.join(os.homedir(), '.skill-master');
|
|
14
|
+
const activationConfigPath = process.env.SKILL_MASTER_ACTIVATION_CONFIG
|
|
15
|
+
?? path.join(skillMasterHome, 'activation.json');
|
|
16
|
+
const sourcesConfigPath = process.env.SKILL_MASTER_CONFIG ?? path.join(rootDir, 'sources.json');
|
|
17
|
+
const workspace = process.env.SKILL_MASTER_WORKSPACE ?? process.cwd();
|
|
18
|
+
|
|
19
|
+
const defaultConfig = {
|
|
20
|
+
activationMode: 'balanced',
|
|
21
|
+
riskTolerance: 'normal',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const isTty = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
25
|
+
|
|
26
|
+
const readActivationConfig = () => {
|
|
27
|
+
if (!existsSync(activationConfigPath)) return defaultConfig;
|
|
28
|
+
return { ...defaultConfig, ...JSON.parse(readFileSync(activationConfigPath, 'utf8')) };
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const writeActivationConfig = (config) => {
|
|
32
|
+
mkdirSync(path.dirname(activationConfigPath), { recursive: true });
|
|
33
|
+
writeFileSync(activationConfigPath, JSON.stringify(config, null, 2), 'utf8');
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const parseArgs = (argv) => {
|
|
37
|
+
const parsed = {
|
|
38
|
+
command: 'status',
|
|
39
|
+
mode: null,
|
|
40
|
+
prompt: null,
|
|
41
|
+
format: 'markdown',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
45
|
+
const arg = argv[index];
|
|
46
|
+
if (arg === '--status') parsed.command = 'status';
|
|
47
|
+
else if (arg === '--set-mode') {
|
|
48
|
+
parsed.command = 'set-mode';
|
|
49
|
+
parsed.mode = argv[++index] ?? null;
|
|
50
|
+
} else if (arg === '--route-prompt') {
|
|
51
|
+
parsed.command = 'route-prompt';
|
|
52
|
+
parsed.prompt = argv[++index] ?? null;
|
|
53
|
+
} else if (arg === '--route-prompt-interactive') parsed.command = 'route-prompt-interactive';
|
|
54
|
+
else if (arg === '--notion-summary') parsed.command = 'notion-summary';
|
|
55
|
+
else if (arg === '--json') parsed.format = 'json';
|
|
56
|
+
else if (arg === '--help' || arg === '-h') parsed.command = 'help';
|
|
57
|
+
else throw new Error(`Unknown argument: ${arg}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return parsed;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const loadSkills = async () => {
|
|
64
|
+
const config = await loadConfig(sourcesConfigPath);
|
|
65
|
+
const catalog = await buildCatalog(config, { cwd: workspace, includeWeb: false });
|
|
66
|
+
return catalog.skills;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const routePrompt = async (prompt, { format }) => {
|
|
70
|
+
if (!prompt) throw new Error('Missing prompt.');
|
|
71
|
+
const config = readActivationConfig();
|
|
72
|
+
const skills = await loadSkills();
|
|
73
|
+
const decision = routeSkillMasterPrompt(skills, prompt, {
|
|
74
|
+
activationMode: config.activationMode,
|
|
75
|
+
riskTolerance: config.riskTolerance,
|
|
76
|
+
limit: 8,
|
|
77
|
+
sourceKinds: ['workspace', 'local', 'plugin'],
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (format === 'json') {
|
|
81
|
+
console.log(JSON.stringify(decision, null, 2));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log('Skill Master - prompt router');
|
|
86
|
+
console.log(`- Ativar: ${decision.shouldActivate ? 'sim' : 'nao'}`);
|
|
87
|
+
console.log(`- Modo: ${decision.activationMode}`);
|
|
88
|
+
console.log(`- Execucao: ${decision.executionMode}`);
|
|
89
|
+
console.log(`- Persona: ${decision.personaOverlay}`);
|
|
90
|
+
console.log(`- Proxima acao: ${decision.nextAction}`);
|
|
91
|
+
if (decision.recommendedSkills.length > 0) {
|
|
92
|
+
console.log('- Skills:');
|
|
93
|
+
for (const skill of decision.recommendedSkills.slice(0, 5)) {
|
|
94
|
+
console.log(` - ${skill.name} (${skill.source})`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const printStatus = () => {
|
|
100
|
+
const config = readActivationConfig();
|
|
101
|
+
console.log('Skill Master - modo de ativacao');
|
|
102
|
+
console.log(`- Config: ${activationConfigPath}`);
|
|
103
|
+
console.log(`- Modo: ${config.activationMode}`);
|
|
104
|
+
console.log(`- Tolerancia de risco: ${config.riskTolerance}`);
|
|
105
|
+
console.log(`- Workspace: ${workspace}`);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const setMode = (mode) => {
|
|
109
|
+
if (!['manual', 'balanced', 'always-on-assisted'].includes(mode)) {
|
|
110
|
+
throw new Error('Mode must be manual, balanced, or always-on-assisted.');
|
|
111
|
+
}
|
|
112
|
+
const config = { ...readActivationConfig(), activationMode: mode };
|
|
113
|
+
writeActivationConfig(config);
|
|
114
|
+
console.log(`Modo de ativacao atualizado para: ${mode}`);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const routePromptInteractive = async (format) => {
|
|
118
|
+
if (!isTty()) throw new Error('Interactive prompt routing requires a TTY.');
|
|
119
|
+
const response = await prompts({
|
|
120
|
+
type: 'text',
|
|
121
|
+
name: 'prompt',
|
|
122
|
+
message: 'Qual prompt voce quer avaliar?',
|
|
123
|
+
validate: (value) => value.trim().length >= 3 || 'Informe ao menos 3 caracteres.',
|
|
124
|
+
});
|
|
125
|
+
await routePrompt(response.prompt, { format });
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const printNotionSummary = () => {
|
|
129
|
+
const config = readActivationConfig();
|
|
130
|
+
console.log('## Resumo para Notion - Skill Master Activation');
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log(`- Modo atual: ${config.activationMode}`);
|
|
133
|
+
console.log(`- Tolerancia de risco: ${config.riskTolerance}`);
|
|
134
|
+
console.log(`- Workspace: ${workspace}`);
|
|
135
|
+
console.log('- Politica: nenhuma publicacao sem autorizacao explicita.');
|
|
136
|
+
console.log('- Recomendacao: registrar mudancas de modo, decisoes de skills aprendidas e releases pendentes no ledger do Skill Master.');
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const printHelp = () => {
|
|
140
|
+
console.log(`Skill Master Activation
|
|
141
|
+
|
|
142
|
+
Usage:
|
|
143
|
+
skill-master-activation --status
|
|
144
|
+
skill-master-activation --set-mode manual|balanced|always-on-assisted
|
|
145
|
+
skill-master-activation --route-prompt "prompt" [--json]
|
|
146
|
+
skill-master-activation --route-prompt-interactive
|
|
147
|
+
skill-master-activation --notion-summary
|
|
148
|
+
`);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const args = parseArgs(process.argv.slice(2));
|
|
153
|
+
if (args.command === 'help') printHelp();
|
|
154
|
+
else if (args.command === 'status') printStatus();
|
|
155
|
+
else if (args.command === 'set-mode') setMode(args.mode);
|
|
156
|
+
else if (args.command === 'route-prompt') await routePrompt(args.prompt, { format: args.format });
|
|
157
|
+
else if (args.command === 'route-prompt-interactive') await routePromptInteractive(args.format);
|
|
158
|
+
else if (args.command === 'notion-summary') printNotionSummary();
|
|
159
|
+
else throw new Error(`Unsupported command: ${args.command}`);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
process.stderr.write(`[skill_master] ${error instanceof Error ? error.message : String(error)}\n`);
|
|
162
|
+
process.exitCode = 1;
|
|
163
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { runActivationEvals } from '../dist/activation-evals.js';
|
|
4
|
+
|
|
5
|
+
const report = runActivationEvals();
|
|
6
|
+
const asJson = process.argv.includes('--json');
|
|
7
|
+
|
|
8
|
+
if (asJson) {
|
|
9
|
+
console.log(JSON.stringify(report, null, 2));
|
|
10
|
+
} else {
|
|
11
|
+
console.log('Skill Master Activation Evals');
|
|
12
|
+
console.log(`- Generated at: ${report.generatedAt}`);
|
|
13
|
+
console.log(`- Total: ${report.total}`);
|
|
14
|
+
console.log(`- Passed: ${report.passed}`);
|
|
15
|
+
console.log(`- Failed: ${report.failed}`);
|
|
16
|
+
console.log(`- Accuracy: ${(report.accuracy * 100).toFixed(1)}%`);
|
|
17
|
+
console.log(`- False positives: ${report.falsePositives}`);
|
|
18
|
+
console.log(`- False negatives: ${report.falseNegatives}`);
|
|
19
|
+
console.log(`- Correct blocks: ${report.correctBlocks}`);
|
|
20
|
+
console.log(`- Recommendation: ${report.recommendation}`);
|
|
21
|
+
|
|
22
|
+
const failed = report.results.filter((result) => !result.passed);
|
|
23
|
+
if (failed.length > 0) {
|
|
24
|
+
console.log('');
|
|
25
|
+
console.log('Failed cases:');
|
|
26
|
+
for (const result of failed) {
|
|
27
|
+
console.log(`- ${result.case.id}: ${result.findings.join('; ')}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
process.exitCode = report.recommendation === 'balanced-ready' ? 0 : 1;
|
|
@@ -1,179 +1,172 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
3
|
+
import prompts from 'prompts';
|
|
4
|
+
import { dirname } from 'node:path';
|
|
6
5
|
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
['2', commands.check],
|
|
53
|
-
['3', commands.build],
|
|
54
|
-
['4', commands.publicNpm],
|
|
55
|
-
['5', commands.updateGlobal],
|
|
56
|
-
['6', commands.privateRegistry],
|
|
57
|
-
];
|
|
58
|
-
|
|
59
|
-
function readJson(relativePath) {
|
|
60
|
-
const target = join(rootDir, relativePath);
|
|
61
|
-
if (!existsSync(target)) {
|
|
62
|
-
return null;
|
|
6
|
+
import {
|
|
7
|
+
buildMenuChoices,
|
|
8
|
+
buildMenuCommands,
|
|
9
|
+
formatActionHeader,
|
|
10
|
+
formatHelp,
|
|
11
|
+
formatMenuBanner,
|
|
12
|
+
formatResultMessage,
|
|
13
|
+
formatStatusReport,
|
|
14
|
+
getMenuStatus,
|
|
15
|
+
isInteractiveTerminal,
|
|
16
|
+
resolveActionKey,
|
|
17
|
+
runCommand,
|
|
18
|
+
} from './lib/menu-core.mjs';
|
|
19
|
+
|
|
20
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
21
|
+
const rootDir = dirname(dirname(currentFile));
|
|
22
|
+
const commands = buildMenuCommands({ rootDir, currentFile });
|
|
23
|
+
|
|
24
|
+
function parseArgs(argv) {
|
|
25
|
+
const parsed = {
|
|
26
|
+
help: false,
|
|
27
|
+
status: false,
|
|
28
|
+
yes: false,
|
|
29
|
+
run: null,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
33
|
+
const arg = argv[i];
|
|
34
|
+
switch (arg) {
|
|
35
|
+
case '--help':
|
|
36
|
+
case '-h':
|
|
37
|
+
parsed.help = true;
|
|
38
|
+
break;
|
|
39
|
+
case '--status':
|
|
40
|
+
parsed.status = true;
|
|
41
|
+
break;
|
|
42
|
+
case '--yes':
|
|
43
|
+
parsed.yes = true;
|
|
44
|
+
break;
|
|
45
|
+
case '--run':
|
|
46
|
+
parsed.run = argv[++i] ?? null;
|
|
47
|
+
break;
|
|
48
|
+
default:
|
|
49
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
50
|
+
}
|
|
63
51
|
}
|
|
64
52
|
|
|
65
|
-
return
|
|
53
|
+
return parsed;
|
|
66
54
|
}
|
|
67
55
|
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
56
|
+
function printHelp() {
|
|
57
|
+
console.log(formatHelp(commands));
|
|
58
|
+
}
|
|
73
59
|
|
|
74
|
-
|
|
60
|
+
function printStatus() {
|
|
61
|
+
console.log(formatStatusReport(getMenuStatus(rootDir)));
|
|
75
62
|
}
|
|
76
63
|
|
|
77
|
-
function
|
|
78
|
-
|
|
64
|
+
async function runSelectedAction(action, { yes = false, useColor = false } = {}) {
|
|
65
|
+
if (action.confirmMessage && !yes) {
|
|
66
|
+
if (!isInteractiveTerminal()) {
|
|
67
|
+
throw new Error(`Action ${action.key} requires --yes outside an interactive terminal.`);
|
|
68
|
+
}
|
|
79
69
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
const confirmation = await prompts({
|
|
71
|
+
type: 'confirm',
|
|
72
|
+
name: 'confirmed',
|
|
73
|
+
message: action.confirmMessage,
|
|
74
|
+
initial: false,
|
|
75
|
+
});
|
|
84
76
|
|
|
85
|
-
|
|
86
|
-
|
|
77
|
+
if (!confirmation.confirmed) {
|
|
78
|
+
return { cancelled: true, code: 0 };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
console.log('');
|
|
83
|
+
console.log(formatActionHeader(action, { useColor }));
|
|
84
|
+
console.log('');
|
|
85
|
+
const code = await runCommand(action, { cwd: rootDir });
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log(formatResultMessage(code, { useColor }));
|
|
88
|
+
return { cancelled: false, code };
|
|
91
89
|
}
|
|
92
90
|
|
|
93
|
-
function
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
console.log('\nVERSION.md:');
|
|
108
|
-
console.log(firstLines);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
91
|
+
async function runVisualMenu() {
|
|
92
|
+
while (true) {
|
|
93
|
+
console.clear();
|
|
94
|
+
const status = getMenuStatus(rootDir);
|
|
95
|
+
console.log(formatMenuBanner(status, { useColor: true }));
|
|
96
|
+
console.log('');
|
|
97
|
+
|
|
98
|
+
const selection = await prompts({
|
|
99
|
+
type: 'select',
|
|
100
|
+
name: 'action',
|
|
101
|
+
message: 'Escolha uma acao',
|
|
102
|
+
choices: buildMenuChoices(commands),
|
|
103
|
+
initial: 0,
|
|
104
|
+
});
|
|
111
105
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
106
|
+
if (!selection.action || selection.action === '__exit__') {
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
115
109
|
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
stdio: 'inherit',
|
|
121
|
-
});
|
|
110
|
+
const action = commands.find((entry) => entry.key === selection.action);
|
|
111
|
+
if (!action) {
|
|
112
|
+
return 1;
|
|
113
|
+
}
|
|
122
114
|
|
|
123
|
-
|
|
124
|
-
|
|
115
|
+
const result = await runSelectedAction(action, { useColor: true });
|
|
116
|
+
if (result.cancelled) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const nextStep = await prompts({
|
|
121
|
+
type: 'toggle',
|
|
122
|
+
name: 'keepGoing',
|
|
123
|
+
message: 'Voltar ao menu?',
|
|
124
|
+
initial: true,
|
|
125
|
+
active: 'sim',
|
|
126
|
+
inactive: 'nao',
|
|
125
127
|
});
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
while (true) {
|
|
134
|
-
console.log('\nSkill Master Menu');
|
|
135
|
-
for (const [key, item] of menuItems) {
|
|
136
|
-
console.log(` ${key}. ${item.label}`);
|
|
137
|
-
}
|
|
138
|
-
console.log(' 0. Sair');
|
|
139
|
-
|
|
140
|
-
const answer = (await rl.question('\nEscolha uma opcao: ')).trim();
|
|
141
|
-
|
|
142
|
-
if (answer === '0' || answer.toLowerCase() === 'q') {
|
|
143
|
-
return 0;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const selected = menuItems.find(([key]) => key === answer)?.[1];
|
|
147
|
-
if (!selected) {
|
|
148
|
-
console.log('Opcao invalida.');
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const code = await runCommand(selected);
|
|
153
|
-
if (code !== 0) {
|
|
154
|
-
console.log(`\nComando terminou com codigo ${code}.`);
|
|
155
|
-
}
|
|
129
|
+
if (!nextStep.keepGoing) {
|
|
130
|
+
return result.code;
|
|
156
131
|
}
|
|
157
|
-
} finally {
|
|
158
|
-
rl.close();
|
|
159
132
|
}
|
|
160
133
|
}
|
|
161
134
|
|
|
162
135
|
async function main() {
|
|
163
|
-
const args = process.argv.slice(2);
|
|
136
|
+
const args = parseArgs(process.argv.slice(2));
|
|
164
137
|
|
|
165
|
-
if (args.
|
|
138
|
+
if (args.help) {
|
|
166
139
|
printHelp();
|
|
167
140
|
return 0;
|
|
168
141
|
}
|
|
169
142
|
|
|
170
|
-
if (args.
|
|
143
|
+
if (args.status) {
|
|
171
144
|
printStatus();
|
|
172
145
|
return 0;
|
|
173
146
|
}
|
|
174
147
|
|
|
175
|
-
|
|
148
|
+
if (args.run) {
|
|
149
|
+
const actionKey = resolveActionKey(args.run, commands);
|
|
150
|
+
if (!actionKey) {
|
|
151
|
+
throw new Error(`Unknown action: ${args.run}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const action = commands.find((entry) => entry.key === actionKey);
|
|
155
|
+
const result = await runSelectedAction(action, { yes: args.yes, useColor: isInteractiveTerminal() });
|
|
156
|
+
return result.code;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!isInteractiveTerminal()) {
|
|
160
|
+
throw new Error('Interactive menu requires a TTY. Use --run <acao> or --status in automated environments.');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return runVisualMenu();
|
|
176
164
|
}
|
|
177
165
|
|
|
178
|
-
|
|
179
|
-
process.exitCode =
|
|
166
|
+
try {
|
|
167
|
+
process.exitCode = await main();
|
|
168
|
+
} catch (error) {
|
|
169
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
170
|
+
process.stderr.write(`[skill_master] ${message}\n`);
|
|
171
|
+
process.exitCode = 1;
|
|
172
|
+
}
|