@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.
Files changed (108) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +59 -10
  3. package/VERSION.md +3 -3
  4. package/bin/lib/client-config.mjs +293 -0
  5. package/bin/lib/menu-core.mjs +509 -131
  6. package/bin/lib/skill-installation.mjs +215 -0
  7. package/bin/skill-master-bootstrap-global.mjs +2 -1
  8. package/bin/skill-master-doctor.mjs +92 -32
  9. package/bin/skill-master-install-global-skills.mjs +4 -42
  10. package/bin/skill-master-install-project-skills.mjs +97 -0
  11. package/bin/skill-master-menu.mjs +91 -6
  12. package/bin/skill-master-register-clients.mjs +91 -115
  13. package/docs/operations/GUIA_MULTI_COMPUTADOR.md +262 -0
  14. package/docs/operations/GUIA_NPM_PUBLICO.md +147 -0
  15. package/docs/operations/MENU_VISUAL_EVIDENCE_2026-06-28.md +66 -0
  16. package/docs/operations/assets/menu-frame-compact.html +76 -0
  17. package/docs/operations/assets/menu-frame-compact.png +0 -0
  18. package/docs/operations/assets/menu-frame-large.html +84 -0
  19. package/docs/operations/assets/menu-frame-large.png +0 -0
  20. package/docs/operations/assets/menu-frame-running.html +80 -0
  21. package/docs/operations/assets/menu-frame-running.png +0 -0
  22. package/docs/operations/cross-platform-auth-transfer/ANALISE_COMPATIBILIDADE_MCP_2026-06-28.md +140 -0
  23. package/docs/operations/cross-platform-auth-transfer/README_TRANSFERENCIA.md +85 -0
  24. package/docs/operations/reborn-menu-cyberpunk-transfer/ANALISE_MENU_REBORN_CYBERPUNK_2026-06-28.md +174 -0
  25. package/docs/operations/reborn-menu-cyberpunk-transfer/HANDOFF_IMPLEMENTACAO_REBORN_CYBERPUNK_2026-06-28.md +119 -0
  26. package/docs/operations/reborn-menu-cyberpunk-transfer/ORDEM_DE_EXECUCAO_MENU_REBORN_CYBERPUNK.md +134 -0
  27. package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA.md +84 -0
  28. package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA_REBORN_PACKAGE.md +56 -0
  29. package/docs/operations/reborn-menu-cyberpunk-transfer/references/cyan-hud-frame-sheet.jpg +0 -0
  30. package/docs/operations/reborn-menu-cyberpunk-transfer/references/cyberpunk-pattern-sheet.jpg +0 -0
  31. package/docs/operations/reborn-menu-cyberpunk-transfer/references/fluid-workflow-windows.gif +0 -0
  32. package/docs/prompt-tasks/PROMPT_TASK_001_BOOTSTRAP_SKILL_MASTER_MCP.md +6 -0
  33. package/docs/prompt-tasks/PROMPT_TASK_002_AUTO_UPDATE_LAUNCHER.md +6 -0
  34. package/docs/prompt-tasks/PROMPT_TASK_003_REMOTE_MANIFEST_AND_RELEASES.md +6 -0
  35. package/docs/prompt-tasks/PROMPT_TASK_004_MULTI_USER_DISTRIBUTION.md +6 -0
  36. package/docs/prompt-tasks/PROMPT_TASK_005_SECURITY_AND_QUALITY_GATE.md +6 -0
  37. package/docs/prompt-tasks/PROMPT_TASK_006_MASTER_ACIONAMENTO_APRENDIZADO.md +83 -0
  38. package/docs/prompt-tasks/PROMPT_TASK_007_PERSONA_ORQUESTRADORA.md +88 -0
  39. package/docs/prompt-tasks/PROMPT_TASK_008_PROMPT_ROUTER_MODOS_ATIVACAO.md +156 -0
  40. package/docs/prompt-tasks/PROMPT_TASK_009_PIPELINE_APRENDIZADO_SUCESSO.md +105 -0
  41. package/docs/prompt-tasks/PROMPT_TASK_010_EVALS_GOVERNANCA_ATIVACAO.md +119 -0
  42. package/docs/prompt-tasks/PROMPT_TASK_011_MENU_NOTIFICACOES_NOTION.md +120 -0
  43. package/docs/prompt-tasks/PROMPT_TASK_012_MENU_CYBERPUNK_PIXEL_FRAME.md +123 -0
  44. package/docs/prompt-tasks/PROMPT_TASK_013_MENU_FLUID_DNA_ANIMATION.md +114 -0
  45. package/docs/prompt-tasks/PROMPT_TASK_014_MENU_FUNCTIONAL_PARITY_QA.md +157 -0
  46. package/docs/prompt-tasks/PROMPT_TASK_015_TRANSFER_RELEASE_HANDOFF.md +127 -0
  47. package/docs/prompt-tasks/PROMPT_TASK_016_CROSS_PLATFORM_MCP_AUTH_REGISTRATION.md +107 -0
  48. package/docs/prompt-tasks/PROMPT_TASK_018_NPM_PUBLISH_2FA_SETUP.md +80 -0
  49. package/docs/prompt-tasks/PROMPT_TASK_MASTER_EXECUTOR.md +6 -0
  50. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/SKILL.md +399 -0
  51. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/common-patterns.md +331 -0
  52. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/complete-examples.md +872 -0
  53. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/component-patterns.md +502 -0
  54. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/data-fetching.md +767 -0
  55. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/file-organization.md +502 -0
  56. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/loading-and-error-states.md +501 -0
  57. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/performance.md +406 -0
  58. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/routing-guide.md +364 -0
  59. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/styling-guide.md +428 -0
  60. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/typescript-standards.md +418 -0
  61. package/docs/skill-candidates/v0.0.11/git-version-control-ops/SKILL.md +34 -0
  62. package/docs/skill-candidates/v0.0.11/go-engineering/SKILL.md +34 -0
  63. package/docs/skill-candidates/v0.0.11/java-engineering/SKILL.md +34 -0
  64. package/docs/skill-candidates/v0.0.11/javascript-engineering/SKILL.md +34 -0
  65. package/docs/skill-candidates/v0.0.11/json-contract-design/SKILL.md +34 -0
  66. package/docs/skill-candidates/v0.0.11/multi-client-mcp-ops/SKILL.md +36 -0
  67. package/docs/skill-candidates/v0.0.11/nextjs/SKILL.md +745 -0
  68. package/docs/skill-candidates/v0.0.11/nextjs/agents/openai.yaml +3 -0
  69. package/docs/skill-candidates/v0.0.11/nextjs/references/app-router-files.md +94 -0
  70. package/docs/skill-candidates/v0.0.11/python-engineering/SKILL.md +34 -0
  71. package/docs/skill-candidates/v0.0.11/ruby-engineering/SKILL.md +34 -0
  72. package/docs/skill-candidates/v0.0.11/senior-fullstack/SKILL.md +209 -0
  73. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/architecture_patterns.md +103 -0
  74. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/development_workflows.md +103 -0
  75. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/tech_stack_guide.md +103 -0
  76. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
  77. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
  78. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/project_scaffolder.py +114 -0
  79. package/docs/skill-candidates/v0.0.11/shadcn/SKILL.md +573 -0
  80. package/docs/skill-candidates/v0.0.11/shadcn/agents/openai.yaml +3 -0
  81. package/docs/skill-candidates/v0.0.11/sql-postgresql-engineering/SKILL.md +34 -0
  82. package/docs/skill-candidates/v0.0.11/terminal-shell-ops/SKILL.md +34 -0
  83. package/docs/skill-candidates/v0.0.11/typescript-expert/SKILL.md +429 -0
  84. package/docs/skill-candidates/v0.0.11/typescript-expert/references/tsconfig-strict.json +92 -0
  85. package/docs/skill-candidates/v0.0.11/typescript-expert/references/typescript-cheatsheet.md +383 -0
  86. package/docs/skill-candidates/v0.0.11/typescript-expert/references/utility-types.ts +335 -0
  87. package/docs/skill-candidates/v0.0.11/typescript-expert/scripts/ts_diagnostic.py +203 -0
  88. package/docs/skill-candidates/v0.0.11/ui-component-primitives/SKILL.md +34 -0
  89. package/docs/skill-candidates/v0.0.11/web-mobile-design-systems/SKILL.md +34 -0
  90. package/docs/skill-candidates/v0.0.11/windows-linux-platform-ops/SKILL.md +34 -0
  91. package/docs/skill-candidates/v0.0.12/csharp-senior-master-engineering/SKILL.md +32 -0
  92. package/docs/skill-candidates/v0.0.12/css-senior-master-engineering/SKILL.md +32 -0
  93. package/docs/skill-candidates/v0.0.12/go-senior-master-engineering/SKILL.md +32 -0
  94. package/docs/skill-candidates/v0.0.12/html-senior-master-engineering/SKILL.md +32 -0
  95. package/docs/skill-candidates/v0.0.12/javascript-senior-master-engineering/SKILL.md +32 -0
  96. package/docs/skill-candidates/v0.0.12/json-senior-master-engineering/SKILL.md +32 -0
  97. package/docs/skill-candidates/v0.0.12/python-senior-master-engineering/SKILL.md +32 -0
  98. package/docs/skill-candidates/v0.0.12/react-senior-master-engineering/SKILL.md +32 -0
  99. package/docs/skill-candidates/v0.0.12/ruby-senior-master-engineering/SKILL.md +32 -0
  100. package/docs/skill-candidates/v0.0.12/senior-master-code-optimizer/SKILL.md +48 -0
  101. package/docs/skill-candidates/v0.0.12/sql-senior-master-engineering/SKILL.md +31 -0
  102. package/docs/skill-candidates/v0.0.12/typescript-senior-master-engineering/SKILL.md +35 -0
  103. package/examples/client-configs/claude-code.commands.md +11 -7
  104. package/manifests/channels/beta.json +7 -7
  105. package/manifests/channels/stable.json +8 -8
  106. package/package.json +14 -2
  107. package/scripts/render-menu-evidence.mjs +130 -0
  108. 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 o binario global skill-master-mcp.
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
- const server = parsed?.mcpServers?.skill_master;
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: Boolean(parsed),
87
- configured: server?.command === 'skill-master-mcp',
88
- command: server?.command ?? null,
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: content.includes('[mcp_servers.skill_master]') && content.includes('command = "skill-master-mcp"'),
102
- command: content.includes('skill-master-mcp') ? 'skill-master-mcp' : null,
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 packageJson = readJson(path.join(rootDir, 'package.json'));
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(path.join(process.env.CODEX_HOME ?? path.join(os.homedir(), '.codex'), 'config.toml'))],
118
- ['Claude Desktop', jsonClientState(defaultClaudeConfigPath())],
119
- ['Gemini CLI', jsonClientState(path.join(os.homedir(), '.gemini', 'settings.json'))],
120
- ['Antigravity', jsonClientState(path.join(os.homedir(), '.gemini', 'config', 'mcp_config.json'))],
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.filePath
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, `${name} configurado`, detail));
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, readdirSync, cpSync, mkdirSync } from 'node:fs';
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.10
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
- if (!dryRun) {
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.');