@fprad0/skill-master-mcp 0.0.10 → 0.0.12
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 +12 -1
- package/README.md +59 -10
- package/VERSION.md +3 -3
- package/bin/lib/client-config.mjs +293 -0
- package/bin/lib/menu-core.mjs +509 -131
- package/bin/lib/skill-installation.mjs +215 -0
- package/bin/skill-master-bootstrap-global.mjs +2 -1
- package/bin/skill-master-doctor.mjs +92 -32
- package/bin/skill-master-install-global-skills.mjs +4 -42
- package/bin/skill-master-install-project-skills.mjs +97 -0
- package/bin/skill-master-menu.mjs +91 -6
- package/bin/skill-master-register-clients.mjs +91 -115
- package/docs/operations/GUIA_MULTI_COMPUTADOR.md +262 -0
- package/docs/operations/GUIA_NPM_PUBLICO.md +147 -0
- package/docs/operations/MENU_VISUAL_EVIDENCE_2026-06-28.md +66 -0
- package/docs/operations/assets/menu-frame-compact.html +76 -0
- package/docs/operations/assets/menu-frame-compact.png +0 -0
- package/docs/operations/assets/menu-frame-large.html +84 -0
- package/docs/operations/assets/menu-frame-large.png +0 -0
- package/docs/operations/assets/menu-frame-running.html +80 -0
- package/docs/operations/assets/menu-frame-running.png +0 -0
- package/docs/operations/cross-platform-auth-transfer/ANALISE_COMPATIBILIDADE_MCP_2026-06-28.md +140 -0
- package/docs/operations/cross-platform-auth-transfer/README_TRANSFERENCIA.md +85 -0
- package/docs/operations/reborn-menu-cyberpunk-transfer/ANALISE_MENU_REBORN_CYBERPUNK_2026-06-28.md +174 -0
- package/docs/operations/reborn-menu-cyberpunk-transfer/HANDOFF_IMPLEMENTACAO_REBORN_CYBERPUNK_2026-06-28.md +119 -0
- package/docs/operations/reborn-menu-cyberpunk-transfer/ORDEM_DE_EXECUCAO_MENU_REBORN_CYBERPUNK.md +134 -0
- package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA.md +84 -0
- package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA_REBORN_PACKAGE.md +56 -0
- package/docs/operations/reborn-menu-cyberpunk-transfer/references/cyan-hud-frame-sheet.jpg +0 -0
- package/docs/operations/reborn-menu-cyberpunk-transfer/references/cyberpunk-pattern-sheet.jpg +0 -0
- package/docs/operations/reborn-menu-cyberpunk-transfer/references/fluid-workflow-windows.gif +0 -0
- package/docs/prompt-tasks/PROMPT_TASK_001_BOOTSTRAP_SKILL_MASTER_MCP.md +6 -0
- package/docs/prompt-tasks/PROMPT_TASK_002_AUTO_UPDATE_LAUNCHER.md +6 -0
- package/docs/prompt-tasks/PROMPT_TASK_003_REMOTE_MANIFEST_AND_RELEASES.md +6 -0
- package/docs/prompt-tasks/PROMPT_TASK_004_MULTI_USER_DISTRIBUTION.md +6 -0
- package/docs/prompt-tasks/PROMPT_TASK_005_SECURITY_AND_QUALITY_GATE.md +6 -0
- package/docs/prompt-tasks/PROMPT_TASK_006_MASTER_ACIONAMENTO_APRENDIZADO.md +83 -0
- package/docs/prompt-tasks/PROMPT_TASK_007_PERSONA_ORQUESTRADORA.md +88 -0
- package/docs/prompt-tasks/PROMPT_TASK_008_PROMPT_ROUTER_MODOS_ATIVACAO.md +156 -0
- package/docs/prompt-tasks/PROMPT_TASK_009_PIPELINE_APRENDIZADO_SUCESSO.md +105 -0
- package/docs/prompt-tasks/PROMPT_TASK_010_EVALS_GOVERNANCA_ATIVACAO.md +119 -0
- package/docs/prompt-tasks/PROMPT_TASK_011_MENU_NOTIFICACOES_NOTION.md +120 -0
- package/docs/prompt-tasks/PROMPT_TASK_012_MENU_CYBERPUNK_PIXEL_FRAME.md +123 -0
- package/docs/prompt-tasks/PROMPT_TASK_013_MENU_FLUID_DNA_ANIMATION.md +114 -0
- package/docs/prompt-tasks/PROMPT_TASK_014_MENU_FUNCTIONAL_PARITY_QA.md +157 -0
- package/docs/prompt-tasks/PROMPT_TASK_015_TRANSFER_RELEASE_HANDOFF.md +127 -0
- package/docs/prompt-tasks/PROMPT_TASK_016_CROSS_PLATFORM_MCP_AUTH_REGISTRATION.md +107 -0
- package/docs/prompt-tasks/PROMPT_TASK_018_NPM_PUBLISH_2FA_SETUP.md +80 -0
- package/docs/prompt-tasks/PROMPT_TASK_MASTER_EXECUTOR.md +6 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/SKILL.md +399 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/common-patterns.md +331 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/complete-examples.md +872 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/component-patterns.md +502 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/data-fetching.md +767 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/file-organization.md +502 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/loading-and-error-states.md +501 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/performance.md +406 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/routing-guide.md +364 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/styling-guide.md +428 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/typescript-standards.md +418 -0
- package/docs/skill-candidates/v0.0.11/git-version-control-ops/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/go-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/java-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/javascript-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/json-contract-design/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/multi-client-mcp-ops/SKILL.md +36 -0
- package/docs/skill-candidates/v0.0.11/nextjs/SKILL.md +745 -0
- package/docs/skill-candidates/v0.0.11/nextjs/agents/openai.yaml +3 -0
- package/docs/skill-candidates/v0.0.11/nextjs/references/app-router-files.md +94 -0
- package/docs/skill-candidates/v0.0.11/python-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/ruby-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/SKILL.md +209 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/references/architecture_patterns.md +103 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/references/development_workflows.md +103 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/references/tech_stack_guide.md +103 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/project_scaffolder.py +114 -0
- package/docs/skill-candidates/v0.0.11/shadcn/SKILL.md +573 -0
- package/docs/skill-candidates/v0.0.11/shadcn/agents/openai.yaml +3 -0
- package/docs/skill-candidates/v0.0.11/sql-postgresql-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/terminal-shell-ops/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/SKILL.md +429 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/references/tsconfig-strict.json +92 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/references/typescript-cheatsheet.md +383 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/references/utility-types.ts +335 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/scripts/ts_diagnostic.py +203 -0
- package/docs/skill-candidates/v0.0.11/ui-component-primitives/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/web-mobile-design-systems/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/windows-linux-platform-ops/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.12/csharp-senior-master-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.12/css-senior-master-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.12/go-senior-master-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.12/html-senior-master-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.12/javascript-senior-master-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.12/json-senior-master-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.12/python-senior-master-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.12/react-senior-master-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.12/ruby-senior-master-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.12/senior-master-code-optimizer/SKILL.md +48 -0
- package/docs/skill-candidates/v0.0.12/sql-senior-master-engineering/SKILL.md +31 -0
- package/docs/skill-candidates/v0.0.12/typescript-senior-master-engineering/SKILL.md +35 -0
- package/examples/client-configs/claude-code.commands.md +11 -7
- package/manifests/channels/beta.json +7 -7
- package/manifests/channels/stable.json +8 -8
- package/package.json +14 -2
- package/scripts/render-menu-evidence.mjs +130 -0
- package/scripts/verify-menu-actions.mjs +117 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cpSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
readdirSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
} from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_PROJECT_SKILL_ROOTS = [
|
|
12
|
+
'.agents/skills',
|
|
13
|
+
'.codex/skills',
|
|
14
|
+
'.claude/skills',
|
|
15
|
+
'.gemini/skills',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export function listSkillSources(sourcePath) {
|
|
19
|
+
const entries = readdirSync(sourcePath, { withFileTypes: true });
|
|
20
|
+
const directSkills = entries
|
|
21
|
+
.filter((entry) => entry.isDirectory() && existsSync(path.join(sourcePath, entry.name, 'SKILL.md')))
|
|
22
|
+
.map((entry) => ({ name: entry.name, path: path.join(sourcePath, entry.name) }));
|
|
23
|
+
|
|
24
|
+
if (directSkills.length) {
|
|
25
|
+
return directSkills.sort((left, right) => left.name.localeCompare(right.name));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return entries
|
|
29
|
+
.filter((entry) => entry.isDirectory())
|
|
30
|
+
.flatMap((entry) => {
|
|
31
|
+
const versionPath = path.join(sourcePath, entry.name);
|
|
32
|
+
return readdirSync(versionPath, { withFileTypes: true })
|
|
33
|
+
.filter((skillEntry) => skillEntry.isDirectory() && existsSync(path.join(versionPath, skillEntry.name, 'SKILL.md')))
|
|
34
|
+
.map((skillEntry) => ({ name: skillEntry.name, path: path.join(versionPath, skillEntry.name) }));
|
|
35
|
+
})
|
|
36
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function parseRootList(value) {
|
|
40
|
+
return String(value ?? '')
|
|
41
|
+
.split(',')
|
|
42
|
+
.map((entry) => entry.trim())
|
|
43
|
+
.filter(Boolean);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function normalizeProjectSkillRoots(projectRoot, roots = DEFAULT_PROJECT_SKILL_ROOTS) {
|
|
47
|
+
const uniqueRoots = Array.from(new Set(roots.map((root) => {
|
|
48
|
+
const normalized = root.replace(/\\/g, '/');
|
|
49
|
+
return path.isAbsolute(normalized) ? normalized : normalized.replace(/^\.\//, '');
|
|
50
|
+
})));
|
|
51
|
+
return uniqueRoots.map((root) => ({
|
|
52
|
+
relative: root,
|
|
53
|
+
absolute: path.isAbsolute(root) ? root : path.resolve(projectRoot, root),
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function installSkillsToTarget({ skills, target, overwrite = false, dryRun = false }) {
|
|
58
|
+
if (!dryRun) {
|
|
59
|
+
mkdirSync(target, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const installed = [];
|
|
63
|
+
const skipped = [];
|
|
64
|
+
|
|
65
|
+
for (const skill of skills) {
|
|
66
|
+
const destination = path.join(target, skill.name);
|
|
67
|
+
if (existsSync(destination) && !overwrite) {
|
|
68
|
+
skipped.push(skill.name);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!dryRun) {
|
|
73
|
+
cpSync(skill.path, destination, { recursive: true, force: overwrite });
|
|
74
|
+
}
|
|
75
|
+
installed.push(skill.name);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { target, installed, skipped };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function buildProjectSkillCatalog({
|
|
82
|
+
projectRoot,
|
|
83
|
+
skillRoots,
|
|
84
|
+
skills,
|
|
85
|
+
packageName,
|
|
86
|
+
packageVersion,
|
|
87
|
+
}) {
|
|
88
|
+
return {
|
|
89
|
+
schemaVersion: 1,
|
|
90
|
+
generatedAt: new Date().toISOString(),
|
|
91
|
+
packageName,
|
|
92
|
+
packageVersion,
|
|
93
|
+
projectRoot,
|
|
94
|
+
skillRoots: skillRoots.map((root) => root.relative),
|
|
95
|
+
skillCount: Array.from(new Set(skills.map((skill) => skill.name))).length,
|
|
96
|
+
skills: Array.from(new Set(skills.map((skill) => skill.name))).sort(),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function writeProjectSkillCatalog({ projectRoot, catalog, catalogPath = '.skill-master/catalog.json', dryRun = false }) {
|
|
101
|
+
const absolutePath = path.isAbsolute(catalogPath)
|
|
102
|
+
? catalogPath
|
|
103
|
+
: path.resolve(projectRoot, catalogPath);
|
|
104
|
+
|
|
105
|
+
if (!dryRun) {
|
|
106
|
+
mkdirSync(path.dirname(absolutePath), { recursive: true });
|
|
107
|
+
writeFileSync(absolutePath, `${JSON.stringify(catalog, null, 2)}\n`, 'utf8');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return absolutePath;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function syncProjectPackageJson({
|
|
114
|
+
projectRoot,
|
|
115
|
+
skillRoots,
|
|
116
|
+
catalogPath = '.skill-master/catalog.json',
|
|
117
|
+
packageName,
|
|
118
|
+
packageVersion,
|
|
119
|
+
createIfMissing = false,
|
|
120
|
+
dryRun = false,
|
|
121
|
+
}) {
|
|
122
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
123
|
+
const packageJsonExists = existsSync(packageJsonPath);
|
|
124
|
+
|
|
125
|
+
if (!packageJsonExists && !createIfMissing) {
|
|
126
|
+
return { path: packageJsonPath, status: 'missing' };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const current = packageJsonExists
|
|
130
|
+
? JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
|
131
|
+
: { private: true };
|
|
132
|
+
|
|
133
|
+
const scripts = current.scripts && typeof current.scripts === 'object' ? current.scripts : {};
|
|
134
|
+
const installScript = 'skill-master-install-project-skills --sync-package-json';
|
|
135
|
+
|
|
136
|
+
const next = {
|
|
137
|
+
...current,
|
|
138
|
+
scripts: {
|
|
139
|
+
...scripts,
|
|
140
|
+
'skill-master:install-project-skills': scripts['skill-master:install-project-skills'] ?? installScript,
|
|
141
|
+
},
|
|
142
|
+
skillMaster: {
|
|
143
|
+
...(current.skillMaster && typeof current.skillMaster === 'object' ? current.skillMaster : {}),
|
|
144
|
+
package: packageName,
|
|
145
|
+
packageVersion,
|
|
146
|
+
projectSkillRoots: skillRoots.map((root) => root.relative),
|
|
147
|
+
projectSkillCatalog: catalogPath,
|
|
148
|
+
installCommand: installScript,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
if (!dryRun) {
|
|
153
|
+
writeFileSync(packageJsonPath, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (dryRun) {
|
|
157
|
+
return { path: packageJsonPath, status: packageJsonExists ? 'would-update' : 'would-create' };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return { path: packageJsonPath, status: packageJsonExists ? 'updated' : 'created' };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function installProjectSkills({
|
|
164
|
+
source,
|
|
165
|
+
projectRoot,
|
|
166
|
+
roots = DEFAULT_PROJECT_SKILL_ROOTS,
|
|
167
|
+
overwrite = false,
|
|
168
|
+
dryRun = false,
|
|
169
|
+
writeCatalog = true,
|
|
170
|
+
syncPackageJson = true,
|
|
171
|
+
createPackageJson = false,
|
|
172
|
+
catalogPath = '.skill-master/catalog.json',
|
|
173
|
+
packageName,
|
|
174
|
+
packageVersion,
|
|
175
|
+
}) {
|
|
176
|
+
const skills = listSkillSources(source);
|
|
177
|
+
const skillRoots = normalizeProjectSkillRoots(projectRoot, roots);
|
|
178
|
+
const targets = skillRoots.map((root) => installSkillsToTarget({
|
|
179
|
+
skills,
|
|
180
|
+
target: root.absolute,
|
|
181
|
+
overwrite,
|
|
182
|
+
dryRun,
|
|
183
|
+
}));
|
|
184
|
+
const catalog = buildProjectSkillCatalog({
|
|
185
|
+
projectRoot,
|
|
186
|
+
skillRoots,
|
|
187
|
+
skills,
|
|
188
|
+
packageName,
|
|
189
|
+
packageVersion,
|
|
190
|
+
});
|
|
191
|
+
const writtenCatalogPath = writeCatalog
|
|
192
|
+
? writeProjectSkillCatalog({ projectRoot, catalog, catalogPath, dryRun })
|
|
193
|
+
: null;
|
|
194
|
+
const packageJson = syncPackageJson
|
|
195
|
+
? syncProjectPackageJson({
|
|
196
|
+
projectRoot,
|
|
197
|
+
skillRoots,
|
|
198
|
+
catalogPath,
|
|
199
|
+
packageName,
|
|
200
|
+
packageVersion,
|
|
201
|
+
createIfMissing: createPackageJson,
|
|
202
|
+
dryRun,
|
|
203
|
+
})
|
|
204
|
+
: { path: path.join(projectRoot, 'package.json'), status: 'skipped' };
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
source,
|
|
208
|
+
projectRoot,
|
|
209
|
+
roots: skillRoots,
|
|
210
|
+
skills,
|
|
211
|
+
targets,
|
|
212
|
+
catalogPath: writtenCatalogPath,
|
|
213
|
+
packageJson,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
@@ -15,7 +15,8 @@ Uso:
|
|
|
15
15
|
skill-master-bootstrap-global
|
|
16
16
|
|
|
17
17
|
Instala as skills globais embutidas e registra o MCP skill_master em Codex,
|
|
18
|
-
Claude Desktop, Gemini e Antigravity usando
|
|
18
|
+
Claude Desktop, Gemini e Antigravity usando Node absoluto e o entrypoint
|
|
19
|
+
absoluto do pacote, sem depender do PATH do app desktop.
|
|
19
20
|
Reinicie os clientes depois da execucao.
|
|
20
21
|
`);
|
|
21
22
|
process.exit(0);
|
|
@@ -4,6 +4,11 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import {
|
|
8
|
+
assessCodexConfigContent,
|
|
9
|
+
assessMcpServerConfig,
|
|
10
|
+
defaultClientConfigPaths,
|
|
11
|
+
} from './lib/client-config.mjs';
|
|
7
12
|
|
|
8
13
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
9
14
|
const rootDir = path.resolve(here, '..');
|
|
@@ -18,7 +23,10 @@ Uso:
|
|
|
18
23
|
skill-master-doctor --strict
|
|
19
24
|
|
|
20
25
|
Valida pacote, binarios, skills globais e registro MCP em Codex, Claude,
|
|
21
|
-
Gemini e Antigravity. Nao publica versoes e nao altera configuracoes.
|
|
26
|
+
Claude Code, Gemini e Antigravity. Nao publica versoes e nao altera configuracoes.
|
|
27
|
+
|
|
28
|
+
O registro recomendado usa Node absoluto + bin/skill-master.mjs absoluto para
|
|
29
|
+
evitar falhas de PATH em apps desktop no Windows, Linux e macOS.
|
|
22
30
|
`);
|
|
23
31
|
process.exit(0);
|
|
24
32
|
}
|
|
@@ -37,6 +45,18 @@ const REQUIRED_GLOBAL_SKILLS = [
|
|
|
37
45
|
'mcp-client-readiness',
|
|
38
46
|
'terminal-menu-operations',
|
|
39
47
|
'terminal-pixel-art-tui',
|
|
48
|
+
'senior-master-code-optimizer',
|
|
49
|
+
'typescript-senior-master-engineering',
|
|
50
|
+
'python-senior-master-engineering',
|
|
51
|
+
'javascript-senior-master-engineering',
|
|
52
|
+
'go-senior-master-engineering',
|
|
53
|
+
'sql-senior-master-engineering',
|
|
54
|
+
'json-senior-master-engineering',
|
|
55
|
+
'ruby-senior-master-engineering',
|
|
56
|
+
'react-senior-master-engineering',
|
|
57
|
+
'html-senior-master-engineering',
|
|
58
|
+
'css-senior-master-engineering',
|
|
59
|
+
'csharp-senior-master-engineering',
|
|
40
60
|
];
|
|
41
61
|
|
|
42
62
|
const REQUIRED_BINS = [
|
|
@@ -45,29 +65,18 @@ const REQUIRED_BINS = [
|
|
|
45
65
|
'skill-master-update',
|
|
46
66
|
'skill-master-bootstrap-global',
|
|
47
67
|
'skill-master-install-global-skills',
|
|
68
|
+
'skill-master-install-project-skills',
|
|
48
69
|
'skill-master-register-clients',
|
|
49
70
|
'skill-master-doctor',
|
|
50
71
|
];
|
|
51
72
|
|
|
52
|
-
function defaultClaudeConfigPath() {
|
|
53
|
-
if (process.platform === 'win32') {
|
|
54
|
-
return path.join(process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (process.platform === 'darwin') {
|
|
58
|
-
return path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return path.join(os.homedir(), '.config', 'Claude', 'claude_desktop_config.json');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
73
|
function readJson(filePath) {
|
|
65
|
-
if (!existsSync(filePath)) return null;
|
|
74
|
+
if (!existsSync(filePath)) return { present: false, invalid: false, value: null };
|
|
66
75
|
try {
|
|
67
76
|
const raw = readFileSync(filePath, 'utf8').trim();
|
|
68
|
-
return raw ? JSON.parse(raw) : {};
|
|
77
|
+
return { present: true, invalid: false, value: raw ? JSON.parse(raw) : {} };
|
|
69
78
|
} catch {
|
|
70
|
-
return null;
|
|
79
|
+
return { present: true, invalid: true, value: null };
|
|
71
80
|
}
|
|
72
81
|
}
|
|
73
82
|
|
|
@@ -78,28 +87,71 @@ function commandExists(command) {
|
|
|
78
87
|
return result.status === 0;
|
|
79
88
|
}
|
|
80
89
|
|
|
90
|
+
function claudeCodeState() {
|
|
91
|
+
if (!commandExists('claude')) {
|
|
92
|
+
return {
|
|
93
|
+
filePath: 'claude CLI',
|
|
94
|
+
present: false,
|
|
95
|
+
configured: true,
|
|
96
|
+
optionalMissing: true,
|
|
97
|
+
mode: 'cli-missing',
|
|
98
|
+
command: null,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const result = spawnSync('claude', ['mcp', 'list'], {
|
|
103
|
+
encoding: 'utf8',
|
|
104
|
+
timeout: 10000,
|
|
105
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
106
|
+
});
|
|
107
|
+
const output = `${result.stdout ?? ''}${result.stderr ?? ''}`;
|
|
108
|
+
const configured = /skill[-_]master/i.test(output);
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
filePath: 'claude mcp list',
|
|
112
|
+
present: true,
|
|
113
|
+
configured,
|
|
114
|
+
mode: configured ? 'claude-cli' : result.status === 0 ? 'missing' : 'list-failed',
|
|
115
|
+
command: configured ? 'claude mcp list' : output.trim() || null,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
81
119
|
function jsonClientState(filePath) {
|
|
82
120
|
const parsed = readJson(filePath);
|
|
83
|
-
|
|
121
|
+
if (parsed.invalid) {
|
|
122
|
+
return {
|
|
123
|
+
filePath,
|
|
124
|
+
present: true,
|
|
125
|
+
configured: false,
|
|
126
|
+
mode: 'invalid-json',
|
|
127
|
+
command: null,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const server = parsed.value?.mcpServers?.skill_master;
|
|
132
|
+
const assessment = assessMcpServerConfig(server);
|
|
84
133
|
return {
|
|
85
134
|
filePath,
|
|
86
|
-
present:
|
|
87
|
-
configured:
|
|
88
|
-
|
|
135
|
+
present: parsed.present,
|
|
136
|
+
configured: assessment.robust,
|
|
137
|
+
mode: assessment.mode,
|
|
138
|
+
command: assessment.command,
|
|
89
139
|
};
|
|
90
140
|
}
|
|
91
141
|
|
|
92
142
|
function codexState(filePath) {
|
|
93
143
|
if (!existsSync(filePath)) {
|
|
94
|
-
return { filePath, present: false, configured: false, command: null };
|
|
144
|
+
return { filePath, present: false, configured: false, mode: 'missing', command: null };
|
|
95
145
|
}
|
|
96
146
|
|
|
97
147
|
const content = readFileSync(filePath, 'utf8');
|
|
148
|
+
const assessment = assessCodexConfigContent(content);
|
|
98
149
|
return {
|
|
99
150
|
filePath,
|
|
100
151
|
present: true,
|
|
101
|
-
configured:
|
|
102
|
-
|
|
152
|
+
configured: assessment.robust,
|
|
153
|
+
mode: assessment.mode,
|
|
154
|
+
command: assessment.command,
|
|
103
155
|
};
|
|
104
156
|
}
|
|
105
157
|
|
|
@@ -108,16 +160,19 @@ function resultLine(ok, label, detail) {
|
|
|
108
160
|
return `[${marker}] ${label}${detail ? ` - ${detail}` : ''}`;
|
|
109
161
|
}
|
|
110
162
|
|
|
111
|
-
const
|
|
163
|
+
const packageJsonState = readJson(path.join(rootDir, 'package.json'));
|
|
164
|
+
const packageJson = packageJsonState.value;
|
|
112
165
|
const globalSkillsRoot = path.join(process.env.CODEX_HOME ?? path.join(os.homedir(), '.codex'), 'skills');
|
|
113
166
|
const installedSkills = REQUIRED_GLOBAL_SKILLS.filter((skill) => existsSync(path.join(globalSkillsRoot, skill, 'SKILL.md')));
|
|
114
167
|
const missingSkills = REQUIRED_GLOBAL_SKILLS.filter((skill) => !installedSkills.includes(skill));
|
|
115
168
|
|
|
169
|
+
const clientPaths = defaultClientConfigPaths();
|
|
116
170
|
const clients = [
|
|
117
|
-
['Codex', codexState(
|
|
118
|
-
['Claude Desktop', jsonClientState(
|
|
119
|
-
['
|
|
120
|
-
['
|
|
171
|
+
['Codex', codexState(clientPaths.codex)],
|
|
172
|
+
['Claude Desktop', jsonClientState(clientPaths.claude)],
|
|
173
|
+
['Claude Code', claudeCodeState()],
|
|
174
|
+
['Gemini CLI', jsonClientState(clientPaths.gemini)],
|
|
175
|
+
['Antigravity', jsonClientState(clientPaths.antigravity)],
|
|
121
176
|
];
|
|
122
177
|
|
|
123
178
|
const binResults = REQUIRED_BINS.map((bin) => [bin, commandExists(bin)]);
|
|
@@ -143,12 +198,15 @@ console.log(`- Skills root: ${globalSkillsRoot}`);
|
|
|
143
198
|
|
|
144
199
|
console.log('');
|
|
145
200
|
for (const [name, state] of clients) {
|
|
201
|
+
const label = state.optionalMissing ? `${name} opcional` : `${name} configurado`;
|
|
146
202
|
const detail = state.configured
|
|
147
|
-
? state.
|
|
203
|
+
? state.optionalMissing
|
|
204
|
+
? `CLI nao encontrado; pule se voce nao usa Claude Code neste computador`
|
|
205
|
+
: `${state.mode} em ${state.filePath}`
|
|
148
206
|
: state.present
|
|
149
|
-
? `presente, mas command=${state.command ?? 'nao encontrado'} em ${state.filePath}`
|
|
207
|
+
? `presente, mas mode=${state.mode} command=${state.command ?? 'nao encontrado'} em ${state.filePath}`
|
|
150
208
|
: `ausente em ${state.filePath}`;
|
|
151
|
-
console.log(resultLine(state.configured,
|
|
209
|
+
console.log(resultLine(state.configured, label, detail));
|
|
152
210
|
}
|
|
153
211
|
|
|
154
212
|
const ready = packageOk && allBinsOk && allSkillsOk && allClientsOk;
|
|
@@ -158,9 +216,11 @@ console.log(resultLine(ready, 'Readiness global', ready ? 'pronto' : 'requer aca
|
|
|
158
216
|
if (!ready) {
|
|
159
217
|
console.log('');
|
|
160
218
|
console.log('Proximo comando recomendado:');
|
|
219
|
+
console.log(' skill-master-register-clients --apply-all --force');
|
|
220
|
+
console.log(' skill-master-register-clients --apply-claude-code --claude-code-scope user');
|
|
161
221
|
console.log(' skill-master-menu --run bootstrap-global --yes');
|
|
162
222
|
console.log('');
|
|
163
|
-
console.log('Depois reinicie Codex, Claude, Gemini e Antigravity.');
|
|
223
|
+
console.log('Depois reinicie Codex, Claude Desktop, Claude Code, Gemini e Antigravity.');
|
|
164
224
|
}
|
|
165
225
|
|
|
166
226
|
if (has('--strict') && !ready) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { existsSync
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { installSkillsToTarget, listSkillSources } from './lib/skill-installation.mjs';
|
|
6
7
|
|
|
7
8
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
8
9
|
const rootDir = path.resolve(here, '..');
|
|
@@ -24,7 +25,7 @@ Uso:
|
|
|
24
25
|
skill-master-install-global-skills --overwrite
|
|
25
26
|
skill-master-install-global-skills --dry-run
|
|
26
27
|
skill-master-install-global-skills --target ~/.codex/skills
|
|
27
|
-
skill-master-install-global-skills --source ./docs/skill-candidates/v0.0.
|
|
28
|
+
skill-master-install-global-skills --source ./docs/skill-candidates/v0.0.11
|
|
28
29
|
|
|
29
30
|
Instala as skills globais embutidas em CODEX_HOME/skills ou ~/.codex/skills.
|
|
30
31
|
Quando --source aponta para docs/skill-candidates, todas as pastas versionadas v*
|
|
@@ -43,48 +44,9 @@ if (!existsSync(source)) {
|
|
|
43
44
|
process.exit(1);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
const listSkillSources = (sourcePath) => {
|
|
47
|
-
const entries = readdirSync(sourcePath, { withFileTypes: true });
|
|
48
|
-
const directSkills = entries
|
|
49
|
-
.filter((entry) => entry.isDirectory() && existsSync(path.join(sourcePath, entry.name, 'SKILL.md')))
|
|
50
|
-
.map((entry) => ({ name: entry.name, path: path.join(sourcePath, entry.name) }));
|
|
51
|
-
|
|
52
|
-
if (directSkills.length) {
|
|
53
|
-
return directSkills;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return entries
|
|
57
|
-
.filter((entry) => entry.isDirectory())
|
|
58
|
-
.flatMap((entry) => {
|
|
59
|
-
const versionPath = path.join(sourcePath, entry.name);
|
|
60
|
-
return readdirSync(versionPath, { withFileTypes: true })
|
|
61
|
-
.filter((skillEntry) => skillEntry.isDirectory() && existsSync(path.join(versionPath, skillEntry.name, 'SKILL.md')))
|
|
62
|
-
.map((skillEntry) => ({ name: skillEntry.name, path: path.join(versionPath, skillEntry.name) }));
|
|
63
|
-
})
|
|
64
|
-
.sort((left, right) => left.name.localeCompare(right.name));
|
|
65
|
-
};
|
|
66
|
-
|
|
67
47
|
const skills = listSkillSources(source);
|
|
68
48
|
|
|
69
|
-
|
|
70
|
-
mkdirSync(target, { recursive: true });
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const installed = [];
|
|
74
|
-
const skipped = [];
|
|
75
|
-
|
|
76
|
-
for (const skill of skills) {
|
|
77
|
-
const from = skill.path;
|
|
78
|
-
const to = path.join(target, skill.name);
|
|
79
|
-
if (existsSync(to) && !overwrite) {
|
|
80
|
-
skipped.push(skill.name);
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
if (!dryRun) {
|
|
84
|
-
cpSync(from, to, { recursive: true, force: overwrite });
|
|
85
|
-
}
|
|
86
|
-
installed.push(skill.name);
|
|
87
|
-
}
|
|
49
|
+
const { installed, skipped } = installSkillsToTarget({ skills, target, overwrite, dryRun });
|
|
88
50
|
|
|
89
51
|
console.log('[skill_master] Global skills installer');
|
|
90
52
|
console.log(`- Source: ${source}`);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_PROJECT_SKILL_ROOTS,
|
|
7
|
+
installProjectSkills,
|
|
8
|
+
parseRootList,
|
|
9
|
+
} from './lib/skill-installation.mjs';
|
|
10
|
+
|
|
11
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const rootDir = path.resolve(here, '..');
|
|
13
|
+
const defaultSource = path.join(rootDir, 'docs', 'skill-candidates');
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
|
|
16
|
+
const has = (flag) => args.includes(flag);
|
|
17
|
+
const readValue = (flag, fallback) => {
|
|
18
|
+
const index = args.indexOf(flag);
|
|
19
|
+
return index >= 0 ? args[index + 1] : fallback;
|
|
20
|
+
};
|
|
21
|
+
const readValues = (flag) => args.flatMap((arg, index) => arg === flag ? [args[index + 1]] : []).filter(Boolean);
|
|
22
|
+
|
|
23
|
+
if (has('--help') || has('-h')) {
|
|
24
|
+
console.log(`Skill Master project skills installer
|
|
25
|
+
|
|
26
|
+
Uso:
|
|
27
|
+
skill-master-install-project-skills
|
|
28
|
+
skill-master-install-project-skills --project-root .
|
|
29
|
+
skill-master-install-project-skills --sync-package-json
|
|
30
|
+
skill-master-install-project-skills --roots ".agents/skills,.codex/skills,.claude/skills,.gemini/skills"
|
|
31
|
+
skill-master-install-project-skills --root .custom/skills --root .codex/skills
|
|
32
|
+
skill-master-install-project-skills --overwrite
|
|
33
|
+
skill-master-install-project-skills --dry-run
|
|
34
|
+
|
|
35
|
+
Instala as skills embutidas em roots de projeto para agentes e clientes locais.
|
|
36
|
+
Por padrao usa o diretorio atual como projeto e as roots:
|
|
37
|
+
${DEFAULT_PROJECT_SKILL_ROOTS.join(', ')}
|
|
38
|
+
|
|
39
|
+
Tambem escreve .skill-master/catalog.json. Quando --sync-package-json e usado,
|
|
40
|
+
registra scripts e metadados em package.json sem alterar package-lock.json
|
|
41
|
+
manualmente; para projetos npm, rode npm install --package-lock-only se quiser
|
|
42
|
+
materializar o lock do proprio projeto.
|
|
43
|
+
`);
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const packageJson = JSON.parse(readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
|
|
48
|
+
const source = readValue('--source', defaultSource);
|
|
49
|
+
const projectRoot = path.resolve(readValue('--project-root', process.cwd()));
|
|
50
|
+
const explicitRoots = readValues('--root');
|
|
51
|
+
const csvRoots = parseRootList(readValue('--roots', ''));
|
|
52
|
+
const roots = explicitRoots.length ? explicitRoots : csvRoots.length ? csvRoots : DEFAULT_PROJECT_SKILL_ROOTS;
|
|
53
|
+
const overwrite = has('--overwrite');
|
|
54
|
+
const dryRun = has('--dry-run');
|
|
55
|
+
const writeCatalog = !has('--no-catalog');
|
|
56
|
+
const syncPackageJson = has('--sync-package-json') || (!has('--no-package-json') && existsSync(path.join(projectRoot, 'package.json')));
|
|
57
|
+
const createPackageJson = has('--create-package-json');
|
|
58
|
+
const catalogPath = readValue('--catalog-path', '.skill-master/catalog.json');
|
|
59
|
+
|
|
60
|
+
if (!existsSync(source)) {
|
|
61
|
+
console.error(`[skill_master] Source not found: ${source}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!existsSync(projectRoot)) {
|
|
66
|
+
console.error(`[skill_master] Project root not found: ${projectRoot}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const result = installProjectSkills({
|
|
71
|
+
source,
|
|
72
|
+
projectRoot,
|
|
73
|
+
roots,
|
|
74
|
+
overwrite,
|
|
75
|
+
dryRun,
|
|
76
|
+
writeCatalog,
|
|
77
|
+
syncPackageJson,
|
|
78
|
+
createPackageJson,
|
|
79
|
+
catalogPath,
|
|
80
|
+
packageName: packageJson.name,
|
|
81
|
+
packageVersion: packageJson.version,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const uniqueSkillCount = new Set(result.skills.map((skill) => skill.name)).size;
|
|
85
|
+
|
|
86
|
+
console.log('[skill_master] Project skills installer');
|
|
87
|
+
console.log(`- Source: ${source}`);
|
|
88
|
+
console.log(`- Project: ${projectRoot}`);
|
|
89
|
+
console.log(`- Skill roots: ${result.roots.map((root) => root.relative).join(', ')}`);
|
|
90
|
+
console.log(`- Skills cataloged: ${uniqueSkillCount}`);
|
|
91
|
+
for (const target of result.targets) {
|
|
92
|
+
console.log(`- Target ${target.target}: installed ${target.installed.length}, skipped ${target.skipped.length}`);
|
|
93
|
+
}
|
|
94
|
+
if (result.catalogPath) console.log(`- Catalog: ${result.catalogPath}`);
|
|
95
|
+
console.log(`- package.json: ${result.packageJson.status} (${result.packageJson.path})`);
|
|
96
|
+
if (dryRun) console.log('- Dry run: no files were written.');
|
|
97
|
+
console.log('[skill_master] Restart or rescan the MCP client so project-local skills can be discovered.');
|