@fprad0/skill-master-mcp 0.0.11 → 1.0.0

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 (337) hide show
  1. package/CHANGELOG.md +96 -83
  2. package/README.md +472 -443
  3. package/VERSION.md +9 -9
  4. package/bin/lib/bootstrap-global-core.mjs +34 -0
  5. package/bin/lib/client-config.mjs +293 -268
  6. package/bin/lib/doctor-core.mjs +202 -0
  7. package/bin/lib/menu-core.mjs +1629 -1154
  8. package/bin/lib/operation-result.mjs +59 -0
  9. package/bin/lib/register-clients-core.mjs +247 -0
  10. package/bin/lib/skill-installation.mjs +215 -0
  11. package/bin/lib/update-cli-core.mjs +117 -0
  12. package/bin/skill-master-activation.mjs +163 -163
  13. package/bin/skill-master-bootstrap-global.mjs +61 -49
  14. package/bin/skill-master-configure-private-registry.mjs +3 -3
  15. package/bin/skill-master-doctor.mjs +239 -181
  16. package/bin/skill-master-eval-activation.mjs +32 -32
  17. package/bin/skill-master-install-global-skills.mjs +59 -97
  18. package/bin/skill-master-install-project-skills.mjs +97 -0
  19. package/bin/skill-master-menu.mjs +406 -320
  20. package/bin/skill-master-register-clients.mjs +232 -98
  21. package/bin/skill-master-success-skills.mjs +307 -307
  22. package/bin/skill-master-update.mjs +121 -72
  23. package/bin/skill-master.mjs +3 -3
  24. package/dist/activation.d.ts.map +1 -1
  25. package/dist/activation.js +12 -0
  26. package/dist/activation.js.map +1 -1
  27. package/dist/prompt-router.d.ts.map +1 -1
  28. package/dist/prompt-router.js +19 -0
  29. package/dist/prompt-router.js.map +1 -1
  30. package/dist/recommender.d.ts.map +1 -1
  31. package/dist/recommender.js +4 -1
  32. package/dist/recommender.js.map +1 -1
  33. package/docs/architecture/APRENDIZADO_DE_IMPLEMENTACOES_BEM_SUCEDIDAS.md +125 -125
  34. package/docs/architecture/ARQUITETURA_AUTO_UPDATE.md +9 -9
  35. package/docs/architecture/PLANO_MASTER_ACIONAMENTO_AUTOMATICO_E_APRENDIZADO.md +341 -341
  36. package/docs/architecture/REDE_SEGURA_DE_SKILLS.md +148 -148
  37. package/docs/operations/GUIA_MULTI_COMPUTADOR.md +262 -255
  38. package/docs/operations/GUIA_NPM_PRIVADO.md +294 -294
  39. package/docs/operations/GUIA_NPM_PUBLICO.md +147 -147
  40. package/docs/operations/MENU_VISUAL_EVIDENCE_2026-06-28.md +66 -0
  41. package/docs/operations/assets/menu-frame-compact.html +76 -0
  42. package/docs/operations/assets/menu-frame-compact.png +0 -0
  43. package/docs/operations/assets/menu-frame-large.html +84 -0
  44. package/docs/operations/assets/menu-frame-large.png +0 -0
  45. package/docs/operations/assets/menu-frame-running.html +80 -0
  46. package/docs/operations/assets/menu-frame-running.png +0 -0
  47. package/docs/operations/cross-platform-auth-transfer/ANALISE_COMPATIBILIDADE_MCP_2026-06-28.md +140 -0
  48. package/docs/operations/cross-platform-auth-transfer/README_TRANSFERENCIA.md +85 -0
  49. package/docs/operations/reborn-menu-cyberpunk-transfer/ANALISE_MENU_REBORN_CYBERPUNK_2026-06-28.md +174 -0
  50. package/docs/operations/reborn-menu-cyberpunk-transfer/HANDOFF_IMPLEMENTACAO_REBORN_CYBERPUNK_2026-06-28.md +119 -0
  51. package/docs/operations/reborn-menu-cyberpunk-transfer/ORDEM_DE_EXECUCAO_MENU_REBORN_CYBERPUNK.md +134 -0
  52. package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA.md +84 -0
  53. package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA_REBORN_PACKAGE.md +56 -0
  54. package/docs/operations/reborn-menu-cyberpunk-transfer/references/cyan-hud-frame-sheet.jpg +0 -0
  55. package/docs/operations/reborn-menu-cyberpunk-transfer/references/cyberpunk-pattern-sheet.jpg +0 -0
  56. package/docs/operations/reborn-menu-cyberpunk-transfer/references/fluid-workflow-windows.gif +0 -0
  57. package/docs/operations/token-economy-transfer/ANALISE_AVANCADA_ECONOMIA_TOKENS_2026-06-30.md +141 -0
  58. package/docs/operations/token-economy-transfer/PLANO_DEV_SENIOR_MASTER_TOKEN_ECONOMY_2026-06-30.md +171 -0
  59. package/docs/operations/token-economy-transfer/README_TRANSFERENCIA_TOKEN_ECONOMY.md +31 -0
  60. package/docs/planning/MENU_RUNTIME_CORRECTION_PLAN_2026-06-30.md +551 -0
  61. package/docs/planning/V0_0_9_APROVACAO_CRITICA_MENSAGENS_DE_VENDA.md +85 -85
  62. package/docs/planning/V0_0_9_FONTES_E_CRITERIOS_DE_AUTORIDADE.md +139 -139
  63. package/docs/planning/V0_0_9_MATRIZ_SKILLS_MULTIDISCIPLINARES.md +105 -105
  64. package/docs/planning/V0_0_9_POLITICA_MORAL_CATOLICA_PARA_IA.md +181 -181
  65. package/docs/planning/V0_0_9_PROMPTS_EXECUCAO.md +59 -59
  66. package/docs/planning/V0_0_9_ROADMAP_DISCERNIMENTO_E_CONHECIMENTO_AMPLO.md +181 -181
  67. package/docs/prompt-tasks/PROMPT_TASK_001_BOOTSTRAP_SKILL_MASTER_MCP.md +6 -0
  68. package/docs/prompt-tasks/PROMPT_TASK_002_AUTO_UPDATE_LAUNCHER.md +6 -0
  69. package/docs/prompt-tasks/PROMPT_TASK_003_REMOTE_MANIFEST_AND_RELEASES.md +6 -0
  70. package/docs/prompt-tasks/PROMPT_TASK_004_MULTI_USER_DISTRIBUTION.md +6 -0
  71. package/docs/prompt-tasks/PROMPT_TASK_005_SECURITY_AND_QUALITY_GATE.md +6 -0
  72. package/docs/prompt-tasks/PROMPT_TASK_006_MASTER_ACIONAMENTO_APRENDIZADO.md +83 -0
  73. package/docs/prompt-tasks/PROMPT_TASK_007_PERSONA_ORQUESTRADORA.md +88 -0
  74. package/docs/prompt-tasks/PROMPT_TASK_008_PROMPT_ROUTER_MODOS_ATIVACAO.md +156 -0
  75. package/docs/prompt-tasks/PROMPT_TASK_009_PIPELINE_APRENDIZADO_SUCESSO.md +105 -0
  76. package/docs/prompt-tasks/PROMPT_TASK_010_EVALS_GOVERNANCA_ATIVACAO.md +119 -0
  77. package/docs/prompt-tasks/PROMPT_TASK_011_MENU_NOTIFICACOES_NOTION.md +120 -0
  78. package/docs/prompt-tasks/PROMPT_TASK_012_MENU_CYBERPUNK_PIXEL_FRAME.md +123 -0
  79. package/docs/prompt-tasks/PROMPT_TASK_013_MENU_FLUID_DNA_ANIMATION.md +114 -0
  80. package/docs/prompt-tasks/PROMPT_TASK_014_MENU_FUNCTIONAL_PARITY_QA.md +157 -0
  81. package/docs/prompt-tasks/PROMPT_TASK_015_TRANSFER_RELEASE_HANDOFF.md +127 -0
  82. package/docs/prompt-tasks/PROMPT_TASK_016_CROSS_PLATFORM_MCP_AUTH_REGISTRATION.md +107 -0
  83. package/docs/prompt-tasks/PROMPT_TASK_018_NPM_PUBLISH_2FA_SETUP.md +80 -0
  84. package/docs/prompt-tasks/PROMPT_TASK_019_TOKEN_ECONOMY_GLOBAL_SKILLS.md +56 -0
  85. package/docs/prompt-tasks/PROMPT_TASK_MASTER_EXECUTOR.md +6 -0
  86. package/docs/skill-candidates/v0.0.10/cli-creator/LICENSE.txt +201 -201
  87. package/docs/skill-candidates/v0.0.10/cli-creator/SKILL.md +160 -160
  88. package/docs/skill-candidates/v0.0.10/cli-creator/agents/openai.yaml +4 -4
  89. package/docs/skill-candidates/v0.0.10/cli-creator/references/agent-cli-patterns.md +154 -154
  90. package/docs/skill-candidates/v0.0.10/developer-workstation-ops/SKILL.md +32 -32
  91. package/docs/skill-candidates/v0.0.10/figma/LICENSE.txt +1 -1
  92. package/docs/skill-candidates/v0.0.10/figma/SKILL.md +42 -42
  93. package/docs/skill-candidates/v0.0.10/figma/agents/openai.yaml +14 -14
  94. package/docs/skill-candidates/v0.0.10/figma/assets/figma-small.svg +3 -3
  95. package/docs/skill-candidates/v0.0.10/figma/assets/icon.svg +28 -28
  96. package/docs/skill-candidates/v0.0.10/figma/references/figma-mcp-config.md +35 -35
  97. package/docs/skill-candidates/v0.0.10/figma/references/figma-tools-and-prompts.md +34 -34
  98. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/LICENSE.TXT +1 -1
  99. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/SKILL.md +349 -349
  100. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/agents/openai.yaml +14 -14
  101. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/figma-small.svg +3 -3
  102. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/icon.svg +28 -28
  103. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/references/mapping-checklist.md +7 -7
  104. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/scripts/normalize_node_id.py +25 -25
  105. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/LICENSE.TXT +1 -1
  106. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/SKILL.md +537 -537
  107. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/agents/openai.yaml +14 -14
  108. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/figma-small.svg +3 -3
  109. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/icon.svg +28 -28
  110. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/references/rule-template.md +15 -15
  111. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/scripts/check_agents_md.sh +9 -9
  112. package/docs/skill-candidates/v0.0.10/figma-generate-design/LICENSE.TXT +1 -1
  113. package/docs/skill-candidates/v0.0.10/figma-generate-design/SKILL.md +341 -341
  114. package/docs/skill-candidates/v0.0.10/figma-generate-design/agents/openai.yaml +14 -14
  115. package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/figma-small.svg +3 -3
  116. package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/icon.svg +28 -28
  117. package/docs/skill-candidates/v0.0.10/figma-generate-design/maintainers.yml +1 -1
  118. package/docs/skill-candidates/v0.0.10/figma-generate-library/LICENSE.TXT +1 -1
  119. package/docs/skill-candidates/v0.0.10/figma-generate-library/SKILL.md +314 -314
  120. package/docs/skill-candidates/v0.0.10/figma-generate-library/agents/openai.yaml +14 -14
  121. package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/figma-small.svg +3 -3
  122. package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/icon.svg +28 -28
  123. package/docs/skill-candidates/v0.0.10/figma-generate-library/maintainers.yml +3 -3
  124. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/code-connect-setup.md +260 -260
  125. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/component-creation.md +1014 -1014
  126. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/discovery-phase.md +518 -518
  127. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/documentation-creation.md +834 -834
  128. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/error-recovery.md +540 -540
  129. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/naming-conventions.md +527 -527
  130. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/token-creation.md +962 -962
  131. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/bindVariablesToComponent.js +110 -110
  132. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/cleanupOrphans.js +127 -127
  133. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createComponentWithVariants.js +148 -148
  134. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createDocumentationPage.js +139 -139
  135. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createSemanticTokens.js +108 -108
  136. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createVariableCollection.js +49 -49
  137. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/inspectFileStructure.js +121 -121
  138. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/rehydrateState.js +92 -92
  139. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/validateCreation.js +83 -83
  140. package/docs/skill-candidates/v0.0.10/figma-implement-design/LICENSE.txt +1 -1
  141. package/docs/skill-candidates/v0.0.10/figma-implement-design/SKILL.md +258 -258
  142. package/docs/skill-candidates/v0.0.10/figma-implement-design/agents/openai.yaml +14 -14
  143. package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/figma-small.svg +3 -3
  144. package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/icon.svg +28 -28
  145. package/docs/skill-candidates/v0.0.10/figma-use/LICENSE.TXT +1 -1
  146. package/docs/skill-candidates/v0.0.10/figma-use/SKILL.md +233 -233
  147. package/docs/skill-candidates/v0.0.10/figma-use/agents/openai.yaml +14 -14
  148. package/docs/skill-candidates/v0.0.10/figma-use/assets/figma-small.svg +3 -3
  149. package/docs/skill-candidates/v0.0.10/figma-use/assets/icon.svg +28 -28
  150. package/docs/skill-candidates/v0.0.10/figma-use/maintainers.yml +1 -1
  151. package/docs/skill-candidates/v0.0.10/figma-use/references/api-reference.md +301 -301
  152. package/docs/skill-candidates/v0.0.10/figma-use/references/common-patterns.md +512 -512
  153. package/docs/skill-candidates/v0.0.10/figma-use/references/component-patterns.md +488 -488
  154. package/docs/skill-candidates/v0.0.10/figma-use/references/effect-style-patterns.md +123 -123
  155. package/docs/skill-candidates/v0.0.10/figma-use/references/gotchas.md +599 -599
  156. package/docs/skill-candidates/v0.0.10/figma-use/references/maintainers.yml +12 -12
  157. package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-patterns.md +513 -513
  158. package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.d.ts +11293 -11293
  159. package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.index.md +441 -441
  160. package/docs/skill-candidates/v0.0.10/figma-use/references/text-style-patterns.md +203 -203
  161. package/docs/skill-candidates/v0.0.10/figma-use/references/validation-and-recovery.md +109 -109
  162. package/docs/skill-candidates/v0.0.10/figma-use/references/variable-patterns.md +354 -354
  163. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/maintainers.yml +9 -9
  164. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--creating.md +17 -17
  165. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--using.md +17 -17
  166. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components.md +50 -50
  167. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-effect-styles.md +52 -52
  168. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-text-styles.md +90 -90
  169. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--creating.md +13 -13
  170. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--using.md +13 -13
  171. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables.md +64 -64
  172. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds.md +41 -41
  173. package/docs/skill-candidates/v0.0.10/frontend-design/LICENSE.txt +177 -177
  174. package/docs/skill-candidates/v0.0.10/frontend-design/SKILL.md +55 -55
  175. package/docs/skill-candidates/v0.0.10/frontend-ui-ux-systems/SKILL.md +32 -32
  176. package/docs/skill-candidates/v0.0.10/github/SKILL.md +74 -74
  177. package/docs/skill-candidates/v0.0.10/github/agents/openai.yaml +6 -6
  178. package/docs/skill-candidates/v0.0.10/github/assets/github-small.svg +3 -3
  179. package/docs/skill-candidates/v0.0.10/image-graphic-design-rendering/SKILL.md +28 -28
  180. package/docs/skill-candidates/v0.0.10/language-quality-pt-en-fr-it-ru/SKILL.md +28 -28
  181. package/docs/skill-candidates/v0.0.10/math-physics-reasoning/SKILL.md +28 -28
  182. package/docs/skill-candidates/v0.0.10/mcp-builder/LICENSE.txt +201 -201
  183. package/docs/skill-candidates/v0.0.10/mcp-builder/SKILL.md +236 -236
  184. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/evaluation.md +601 -601
  185. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/mcp_best_practices.md +249 -249
  186. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/node_mcp_server.md +969 -969
  187. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/python_mcp_server.md +718 -718
  188. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/connections.py +151 -151
  189. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/evaluation.py +373 -373
  190. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/example_evaluation.xml +22 -22
  191. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/requirements.txt +2 -2
  192. package/docs/skill-candidates/v0.0.10/mcp-client-readiness/SKILL.md +31 -31
  193. package/docs/skill-candidates/v0.0.10/openai-docs/LICENSE.txt +201 -201
  194. package/docs/skill-candidates/v0.0.10/openai-docs/SKILL.md +161 -161
  195. package/docs/skill-candidates/v0.0.10/openai-docs/agents/openai.yaml +14 -14
  196. package/docs/skill-candidates/v0.0.10/openai-docs/assets/openai-small.svg +3 -3
  197. package/docs/skill-candidates/v0.0.10/openai-docs/references/latest-model.md +37 -37
  198. package/docs/skill-candidates/v0.0.10/openai-docs/references/prompting-guide.md +244 -244
  199. package/docs/skill-candidates/v0.0.10/openai-docs/references/upgrade-guide.md +181 -181
  200. package/docs/skill-candidates/v0.0.10/openai-docs/scripts/fetch-codex-manual.mjs +598 -598
  201. package/docs/skill-candidates/v0.0.10/openai-docs/scripts/resolve-latest-model-info.js +147 -147
  202. package/docs/skill-candidates/v0.0.10/playwright/NOTICE.txt +14 -14
  203. package/docs/skill-candidates/v0.0.10/playwright/SKILL.md +147 -147
  204. package/docs/skill-candidates/v0.0.10/playwright/agents/openai.yaml +6 -6
  205. package/docs/skill-candidates/v0.0.10/playwright/assets/playwright-small.svg +3 -3
  206. package/docs/skill-candidates/v0.0.10/playwright/references/cli.md +116 -116
  207. package/docs/skill-candidates/v0.0.10/playwright/references/workflows.md +95 -95
  208. package/docs/skill-candidates/v0.0.10/playwright/scripts/playwright_cli.sh +25 -25
  209. package/docs/skill-candidates/v0.0.10/polyglot-backend-engineering/SKILL.md +32 -32
  210. package/docs/skill-candidates/v0.0.10/screenshot/LICENSE.txt +201 -201
  211. package/docs/skill-candidates/v0.0.10/screenshot/SKILL.md +267 -267
  212. package/docs/skill-candidates/v0.0.10/screenshot/agents/openai.yaml +6 -6
  213. package/docs/skill-candidates/v0.0.10/screenshot/assets/screenshot-small.svg +5 -5
  214. package/docs/skill-candidates/v0.0.10/screenshot/scripts/ensure_macos_permissions.sh +54 -54
  215. package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_display_info.swift +22 -22
  216. package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_permissions.swift +40 -40
  217. package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_window_info.swift +126 -126
  218. package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.ps1 +163 -163
  219. package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.py +585 -585
  220. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/SKILL.md +62 -62
  221. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/agents/openai.yaml +4 -4
  222. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/activation-policy.md +77 -77
  223. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/human-approval-policy.md +83 -83
  224. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/persona-dev-senior-master.md +46 -46
  225. package/docs/skill-candidates/v0.0.10/terminal-menu-operations/SKILL.md +30 -30
  226. package/docs/skill-candidates/v0.0.10/terminal-pixel-art-tui/SKILL.md +43 -43
  227. package/docs/skill-candidates/v0.0.10/webapp-testing/LICENSE.txt +201 -201
  228. package/docs/skill-candidates/v0.0.10/webapp-testing/SKILL.md +95 -95
  229. package/docs/skill-candidates/v0.0.10/webapp-testing/examples/console_logging.py +34 -34
  230. package/docs/skill-candidates/v0.0.10/webapp-testing/examples/element_discovery.py +39 -39
  231. package/docs/skill-candidates/v0.0.10/webapp-testing/examples/static_html_automation.py +32 -32
  232. package/docs/skill-candidates/v0.0.10/webapp-testing/scripts/with_server.py +105 -105
  233. package/docs/skill-candidates/v0.0.10/winui-app/LICENSE.txt +201 -201
  234. package/docs/skill-candidates/v0.0.10/winui-app/SKILL.md +94 -94
  235. package/docs/skill-candidates/v0.0.10/winui-app/agents/openai.yaml +5 -5
  236. package/docs/skill-candidates/v0.0.10/winui-app/config.yaml +50 -50
  237. package/docs/skill-candidates/v0.0.10/winui-app/references/_sections.md +96 -96
  238. package/docs/skill-candidates/v0.0.10/winui-app/references/accessibility-input-and-localization.md +51 -51
  239. package/docs/skill-candidates/v0.0.10/winui-app/references/build-run-and-launch-verification.md +72 -72
  240. package/docs/skill-candidates/v0.0.10/winui-app/references/community-toolkit-controls-and-helpers.md +57 -57
  241. package/docs/skill-candidates/v0.0.10/winui-app/references/controls-layout-and-adaptive-ui.md +84 -84
  242. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-environment-audit-and-remediation.md +82 -82
  243. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-setup-and-project-selection.md +67 -67
  244. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-template-first-recovery.md +62 -62
  245. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-winui-app-structure.md +62 -62
  246. package/docs/skill-candidates/v0.0.10/winui-app/references/motion-animations-and-polish.md +45 -45
  247. package/docs/skill-candidates/v0.0.10/winui-app/references/performance-diagnostics-and-responsiveness.md +46 -46
  248. package/docs/skill-candidates/v0.0.10/winui-app/references/sample-source-map.md +37 -37
  249. package/docs/skill-candidates/v0.0.10/winui-app/references/shell-navigation-and-windowing.md +67 -67
  250. package/docs/skill-candidates/v0.0.10/winui-app/references/styling-theming-materials-and-icons.md +71 -71
  251. package/docs/skill-candidates/v0.0.10/winui-app/references/testing-debugging-and-review-checklists.md +77 -77
  252. package/docs/skill-candidates/v0.0.10/winui-app/references/windows-app-sdk-lifecycle-notifications-and-deployment.md +52 -52
  253. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/SKILL.md +398 -398
  254. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/common-patterns.md +330 -330
  255. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/complete-examples.md +871 -871
  256. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/component-patterns.md +501 -501
  257. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/data-fetching.md +766 -766
  258. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/file-organization.md +501 -501
  259. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/loading-and-error-states.md +500 -500
  260. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/performance.md +405 -405
  261. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/routing-guide.md +363 -363
  262. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/styling-guide.md +427 -427
  263. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/typescript-standards.md +417 -417
  264. package/docs/skill-candidates/v0.0.11/git-version-control-ops/SKILL.md +34 -34
  265. package/docs/skill-candidates/v0.0.11/go-engineering/SKILL.md +34 -34
  266. package/docs/skill-candidates/v0.0.11/java-engineering/SKILL.md +34 -34
  267. package/docs/skill-candidates/v0.0.11/javascript-engineering/SKILL.md +34 -34
  268. package/docs/skill-candidates/v0.0.11/json-contract-design/SKILL.md +34 -34
  269. package/docs/skill-candidates/v0.0.11/multi-client-mcp-ops/SKILL.md +36 -36
  270. package/docs/skill-candidates/v0.0.11/nextjs/SKILL.md +745 -745
  271. package/docs/skill-candidates/v0.0.11/nextjs/agents/openai.yaml +3 -3
  272. package/docs/skill-candidates/v0.0.11/nextjs/references/app-router-files.md +94 -94
  273. package/docs/skill-candidates/v0.0.11/python-engineering/SKILL.md +34 -34
  274. package/docs/skill-candidates/v0.0.11/ruby-engineering/SKILL.md +34 -34
  275. package/docs/skill-candidates/v0.0.11/senior-fullstack/SKILL.md +209 -209
  276. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/architecture_patterns.md +103 -103
  277. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/development_workflows.md +103 -103
  278. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/tech_stack_guide.md +103 -103
  279. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/code_quality_analyzer.py +114 -114
  280. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/fullstack_scaffolder.py +114 -114
  281. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/project_scaffolder.py +114 -114
  282. package/docs/skill-candidates/v0.0.11/shadcn/SKILL.md +573 -573
  283. package/docs/skill-candidates/v0.0.11/shadcn/agents/openai.yaml +3 -3
  284. package/docs/skill-candidates/v0.0.11/sql-postgresql-engineering/SKILL.md +34 -34
  285. package/docs/skill-candidates/v0.0.11/terminal-shell-ops/SKILL.md +34 -34
  286. package/docs/skill-candidates/v0.0.11/typescript-expert/SKILL.md +429 -429
  287. package/docs/skill-candidates/v0.0.11/typescript-expert/references/tsconfig-strict.json +91 -91
  288. package/docs/skill-candidates/v0.0.11/typescript-expert/references/typescript-cheatsheet.md +383 -383
  289. package/docs/skill-candidates/v0.0.11/typescript-expert/references/utility-types.ts +335 -335
  290. package/docs/skill-candidates/v0.0.11/typescript-expert/scripts/ts_diagnostic.py +203 -203
  291. package/docs/skill-candidates/v0.0.11/ui-component-primitives/SKILL.md +34 -34
  292. package/docs/skill-candidates/v0.0.11/web-mobile-design-systems/SKILL.md +34 -34
  293. package/docs/skill-candidates/v0.0.11/windows-linux-platform-ops/SKILL.md +34 -34
  294. package/docs/skill-candidates/v0.0.12/context-compression-handoff/SKILL.md +47 -0
  295. package/docs/skill-candidates/v0.0.12/csharp-senior-master-engineering/SKILL.md +32 -0
  296. package/docs/skill-candidates/v0.0.12/css-senior-master-engineering/SKILL.md +32 -0
  297. package/docs/skill-candidates/v0.0.12/go-senior-master-engineering/SKILL.md +32 -0
  298. package/docs/skill-candidates/v0.0.12/html-senior-master-engineering/SKILL.md +32 -0
  299. package/docs/skill-candidates/v0.0.12/javascript-senior-master-engineering/SKILL.md +32 -0
  300. package/docs/skill-candidates/v0.0.12/json-senior-master-engineering/SKILL.md +32 -0
  301. package/docs/skill-candidates/v0.0.12/prompt-budget-gate/SKILL.md +46 -0
  302. package/docs/skill-candidates/v0.0.12/python-senior-master-engineering/SKILL.md +32 -0
  303. package/docs/skill-candidates/v0.0.12/react-senior-master-engineering/SKILL.md +32 -0
  304. package/docs/skill-candidates/v0.0.12/ruby-senior-master-engineering/SKILL.md +32 -0
  305. package/docs/skill-candidates/v0.0.12/senior-master-code-optimizer/SKILL.md +48 -0
  306. package/docs/skill-candidates/v0.0.12/sql-senior-master-engineering/SKILL.md +31 -0
  307. package/docs/skill-candidates/v0.0.12/token-economy-orchestrator/SKILL.md +38 -0
  308. package/docs/skill-candidates/v0.0.12/typescript-senior-master-engineering/SKILL.md +35 -0
  309. package/docs/skill-candidates/v0.0.9/ai-ethics-human-dignity/SKILL.md +32 -32
  310. package/docs/skill-candidates/v0.0.9/broad-domain-router/SKILL.md +41 -41
  311. package/docs/skill-candidates/v0.0.9/catholic-moral-discernment/SKILL.md +31 -31
  312. package/docs/skill-candidates/v0.0.9/engineering-systems-master/SKILL.md +31 -31
  313. package/docs/skill-candidates/v0.0.9/language-quality-pt-en-fr/SKILL.md +28 -28
  314. package/docs/skill-candidates/v0.0.9/math-science-reasoning/SKILL.md +29 -29
  315. package/docs/skill-candidates/v0.0.9/philosophy-sociology-discernment/SKILL.md +28 -28
  316. package/docs/skill-candidates/v0.0.9/professional-boundary-triage/SKILL.md +40 -40
  317. package/docs/skill-candidates/v0.0.9/release-ethics-gate/SKILL.md +32 -32
  318. package/docs/skill-candidates/v0.0.9/source-authority-reviewer/SKILL.md +31 -31
  319. package/examples/client-configs/claude-code.commands.md +21 -17
  320. package/examples/client-configs/claude-code.project.mcp.json +18 -18
  321. package/examples/client-configs/claude-desktop.macos.json +18 -18
  322. package/examples/client-configs/claude-desktop.windows.json +20 -20
  323. package/examples/client-configs/codex.windows.toml +11 -11
  324. package/examples/client-configs/gemini-code-assist.intellij.mcp.json +18 -18
  325. package/examples/client-configs/gemini.linux.settings.json +21 -21
  326. package/examples/client-configs/gemini.windows.settings.json +23 -23
  327. package/examples/client-configs/generic-stdio.json +16 -16
  328. package/manifests/channels/beta.json +26 -26
  329. package/manifests/channels/stable.json +27 -27
  330. package/network/approved-skills.json +54 -54
  331. package/network/unapproved-skill-candidates.json +110 -110
  332. package/package.json +87 -78
  333. package/scripts/configure-private-registry.mjs +208 -208
  334. package/scripts/lib/private-registry.mjs +97 -97
  335. package/scripts/render-menu-evidence.mjs +130 -0
  336. package/scripts/verify-menu-actions.mjs +117 -115
  337. package/sources.json +11 -11
@@ -1,1154 +1,1629 @@
1
- import { spawn } from 'node:child_process';
2
- import { existsSync, readFileSync, readdirSync } from 'node:fs';
3
- import os from 'node:os';
4
- import { join } from 'node:path';
5
- import process from 'node:process';
6
- import {
7
- assessCodexConfigContent,
8
- assessMcpServerConfig,
9
- defaultClientConfigPaths,
10
- } from './client-config.mjs';
11
-
12
- const ANSI = {
13
- reset: '\x1b[0m',
14
- bold: '\x1b[1m',
15
- dim: '\x1b[2m',
16
- cyan: '\x1b[36m',
17
- green: '\x1b[32m',
18
- yellow: '\x1b[33m',
19
- red: '\x1b[31m',
20
- white: '\x1b[37m',
21
- gray: '\x1b[90m',
22
- teal: '\x1b[38;5;80m',
23
- amber: '\x1b[38;5;179m',
24
- blue: '\x1b[38;5;75m',
25
- };
26
-
27
- const REQUIRED_GLOBAL_SKILLS = [
28
- 'catholic-moral-discernment',
29
- 'ai-ethics-human-dignity',
30
- 'professional-boundary-triage',
31
- 'broad-domain-router',
32
- 'language-quality-pt-en-fr',
33
- 'math-science-reasoning',
34
- 'philosophy-sociology-discernment',
35
- 'engineering-systems-master',
36
- 'source-authority-reviewer',
37
- 'release-ethics-gate',
38
- 'mcp-client-readiness',
39
- 'terminal-menu-operations',
40
- 'terminal-pixel-art-tui',
41
- ];
42
-
43
- const BUNDLED_SKILL_DOMAIN_GROUPS = [
44
- {
45
- key: 'moral',
46
- label: 'moral-core',
47
- skills: [
48
- 'ai-ethics-human-dignity',
49
- 'broad-domain-router',
50
- 'catholic-moral-discernment',
51
- 'engineering-systems-master',
52
- 'language-quality-pt-en-fr',
53
- 'math-science-reasoning',
54
- 'philosophy-sociology-discernment',
55
- 'professional-boundary-triage',
56
- 'release-ethics-gate',
57
- 'source-authority-reviewer',
58
- ],
59
- },
60
- {
61
- key: 'frontend',
62
- label: 'frontend-ui',
63
- skills: [
64
- 'figma',
65
- 'figma-code-connect-components',
66
- 'figma-create-design-system-rules',
67
- 'figma-generate-design',
68
- 'figma-generate-library',
69
- 'figma-implement-design',
70
- 'figma-use',
71
- 'frontend-dev-guidelines',
72
- 'frontend-design',
73
- 'frontend-ui-ux-systems',
74
- 'nextjs',
75
- 'playwright',
76
- 'screenshot',
77
- 'senior-fullstack',
78
- 'shadcn',
79
- 'ui-component-primitives',
80
- 'webapp-testing',
81
- 'web-mobile-design-systems',
82
- 'winui-app',
83
- ],
84
- },
85
- {
86
- key: 'backend',
87
- label: 'backend-data',
88
- skills: [
89
- 'go-engineering',
90
- 'java-engineering',
91
- 'javascript-engineering',
92
- 'json-contract-design',
93
- 'mcp-builder',
94
- 'polyglot-backend-engineering',
95
- 'python-engineering',
96
- 'ruby-engineering',
97
- 'sql-postgresql-engineering',
98
- 'typescript-expert',
99
- ],
100
- },
101
- {
102
- key: 'ops',
103
- label: 'ops-clients',
104
- skills: [
105
- 'cli-creator',
106
- 'developer-workstation-ops',
107
- 'git-version-control-ops',
108
- 'github',
109
- 'mcp-client-readiness',
110
- 'multi-client-mcp-ops',
111
- 'openai-docs',
112
- 'skill-master-orchestrator',
113
- 'terminal-shell-ops',
114
- 'terminal-menu-operations',
115
- 'terminal-pixel-art-tui',
116
- 'windows-linux-platform-ops',
117
- ],
118
- },
119
- {
120
- key: 'knowledge',
121
- label: 'knowledge',
122
- skills: [
123
- 'language-quality-pt-en-fr-it-ru',
124
- 'math-physics-reasoning',
125
- ],
126
- },
127
- ];
128
-
129
- const COMMAND_AREA_LABELS = {
130
- status: 'diagnostico',
131
- doctor: 'diagnostico',
132
- check: 'desenvolvimento',
133
- build: 'desenvolvimento',
134
- publicNpm: 'distribuicao',
135
- updateGlobal: 'distribuicao',
136
- privateRegistry: 'registry',
137
- activationStatus: 'ativacao',
138
- activationBalanced: 'ativacao',
139
- activationAlwaysOn: 'ativacao',
140
- installGlobalSkills: 'skills-globais',
141
- bootstrapGlobal: 'bootstrap-global',
142
- registerClients: 'clientes-mcp',
143
- promptRecommendation: 'roteamento',
144
- successNotifications: 'aprendizado',
145
- studySkills: 'aprendizado',
146
- approvalPackage: 'aprovacao',
147
- markLearnedStudy: 'aprovacao',
148
- rejectLearnedSkill: 'aprovacao',
149
- activateLearnedLocal: 'ativacao-skill',
150
- activateLearnedGlobal: 'ativacao-skill',
151
- notionSummary: 'documentacao',
152
- };
153
-
154
- function colorize(text, color, enabled) {
155
- return enabled ? `${color}${text}${ANSI.reset}` : text;
156
- }
157
-
158
- function visibleLength(text) {
159
- return String(text).replace(/\x1b\[[0-9;]*m/g, '').length;
160
- }
161
-
162
- function fitText(text, width) {
163
- const value = String(text ?? '');
164
- if (visibleLength(value) <= width) {
165
- return `${value}${' '.repeat(width - visibleLength(value))}`;
166
- }
167
-
168
- return `${value.slice(0, Math.max(0, width - 1))}~`;
169
- }
170
-
171
- function splitText(text, width, maxLines = 3) {
172
- const words = String(text ?? '').split(/\s+/).filter(Boolean);
173
- const lines = [];
174
- let current = '';
175
-
176
- for (const word of words) {
177
- const next = current ? `${current} ${word}` : word;
178
- if (next.length <= width) {
179
- current = next;
180
- continue;
181
- }
182
- if (current) lines.push(current);
183
- current = word.length > width ? word.slice(0, width - 1) + '~' : word;
184
- if (lines.length >= maxLines) break;
185
- }
186
- if (current && lines.length < maxLines) lines.push(current);
187
- return lines.length ? lines : [''];
188
- }
189
-
190
- function globalSkillsRoot() {
191
- return join(process.env.CODEX_HOME ?? join(os.homedir(), '.codex'), 'skills');
192
- }
193
-
194
- function readClientConfigState(filePath) {
195
- if (!existsSync(filePath)) {
196
- return { present: false, kind: 'missing', globalCommand: false };
197
- }
198
-
199
- const content = readFileSync(filePath, 'utf8');
200
- const assessment = assessCodexConfigContent(content);
201
-
202
- return {
203
- present: true,
204
- kind: assessment.mode,
205
- globalCommand: assessment.robust,
206
- command: assessment.command,
207
- };
208
- }
209
-
210
- function readJsonState(filePath) {
211
- if (!existsSync(filePath)) {
212
- return { present: false, kind: 'missing', globalCommand: false };
213
- }
214
-
215
- try {
216
- const parsed = JSON.parse(readFileSync(filePath, 'utf8'));
217
- const server = parsed?.mcpServers?.skill_master;
218
- const assessment = assessMcpServerConfig(server);
219
- return {
220
- present: true,
221
- kind: assessment.mode,
222
- globalCommand: assessment.robust,
223
- command: assessment.command,
224
- };
225
- } catch {
226
- return { present: true, kind: 'invalid-json', globalCommand: false };
227
- }
228
- }
229
-
230
- function inspectGlobalReadiness() {
231
- const root = globalSkillsRoot();
232
- const installed = REQUIRED_GLOBAL_SKILLS.filter((name) => existsSync(join(root, name, 'SKILL.md')));
233
- const missing = REQUIRED_GLOBAL_SKILLS.filter((name) => !installed.includes(name));
234
- const clientPaths = defaultClientConfigPaths();
235
- const codex = readClientConfigState(clientPaths.codex);
236
- const claude = readJsonState(clientPaths.claude);
237
- const gemini = readJsonState(clientPaths.gemini);
238
- const antigravity = readJsonState(clientPaths.antigravity);
239
- const ready = missing.length === 0
240
- && codex.globalCommand
241
- && claude.globalCommand
242
- && gemini.globalCommand
243
- && antigravity.globalCommand;
244
- const mode = ready
245
- ? 'ready'
246
- : codex.present || claude.present || gemini.present || antigravity.present
247
- ? 'partial'
248
- : 'missing';
249
-
250
- return {
251
- root,
252
- required: REQUIRED_GLOBAL_SKILLS.length,
253
- installed,
254
- missing,
255
- ready,
256
- mode,
257
- codex,
258
- claude,
259
- gemini,
260
- antigravity,
261
- };
262
- }
263
-
264
- export function readJson(rootDir, relativePath) {
265
- const target = join(rootDir, relativePath);
266
- if (!existsSync(target)) {
267
- return null;
268
- }
269
-
270
- return JSON.parse(readFileSync(target, 'utf8'));
271
- }
272
-
273
- export function readText(rootDir, relativePath) {
274
- const target = join(rootDir, relativePath);
275
- if (!existsSync(target)) {
276
- return null;
277
- }
278
-
279
- return readFileSync(target, 'utf8').trim();
280
- }
281
-
282
- export function getMenuStatus(rootDir) {
283
- const packageJson = readJson(rootDir, 'package.json');
284
- const stableManifest = readJson(rootDir, 'manifests/channels/stable.json');
285
- const versionText = readText(rootDir, 'VERSION.md');
286
- const successLearningDir = process.env.SKILL_MASTER_SUCCESS_LEARNING_DIR
287
- ?? join(process.env.SKILL_MASTER_HOME ?? join(process.env.HOME ?? process.env.USERPROFILE ?? '', '.skill-master'), 'data', 'success-learning');
288
- const studyCandidates = readJson(rootDir, 'network/unapproved-skill-candidates.json');
289
- const globalReadiness = inspectGlobalReadiness();
290
- const bundledCatalog = inspectBundledSkillCatalog(rootDir);
291
-
292
- return {
293
- packageName: packageJson?.name ?? 'nao encontrado',
294
- semver: packageJson?.version ?? 'nao encontrado',
295
- manifestVersion: stableManifest?.version ?? 'nao encontrado',
296
- manifestSemver: stableManifest?.semver ?? 'nao encontrado',
297
- versionText,
298
- rootDir,
299
- pendingSuccessDrafts: countManifestFiles(successLearningDir),
300
- studyCandidates: Array.isArray(studyCandidates?.candidates) ? studyCandidates.candidates.length : 0,
301
- globalReadiness,
302
- bundledCatalog,
303
- };
304
- }
305
-
306
- function countManifestFiles(directory) {
307
- if (!directory || !existsSync(directory)) {
308
- return 0;
309
- }
310
-
311
- let count = 0;
312
- const visit = (current) => {
313
- for (const entry of readdirSync(current, { withFileTypes: true })) {
314
- const fullPath = join(current, entry.name);
315
- if (entry.isDirectory()) visit(fullPath);
316
- else if (entry.isFile() && entry.name === 'manifest.json') count += 1;
317
- }
318
- };
319
-
320
- visit(directory);
321
- return count;
322
- }
323
-
324
- function listBundledSkillNames(rootDir) {
325
- const source = join(rootDir, 'docs', 'skill-candidates');
326
- if (!existsSync(source)) {
327
- return [];
328
- }
329
-
330
- const entries = readdirSync(source, { withFileTypes: true });
331
- const directSkills = entries
332
- .filter((entry) => entry.isDirectory() && existsSync(join(source, entry.name, 'SKILL.md')))
333
- .map((entry) => entry.name);
334
-
335
- if (directSkills.length) {
336
- return Array.from(new Set(directSkills)).sort();
337
- }
338
-
339
- return Array.from(new Set(
340
- entries
341
- .filter((entry) => entry.isDirectory())
342
- .flatMap((entry) => {
343
- const versionPath = join(source, entry.name);
344
- return readdirSync(versionPath, { withFileTypes: true })
345
- .filter((skillEntry) => skillEntry.isDirectory() && existsSync(join(versionPath, skillEntry.name, 'SKILL.md')))
346
- .map((skillEntry) => skillEntry.name);
347
- }),
348
- )).sort();
349
- }
350
-
351
- function inspectBundledSkillCatalog(rootDir) {
352
- const names = listBundledSkillNames(rootDir);
353
- const categories = BUNDLED_SKILL_DOMAIN_GROUPS.map((group) => ({
354
- key: group.key,
355
- label: group.label,
356
- count: group.skills.filter((skill) => names.includes(skill)).length,
357
- }));
358
-
359
- return {
360
- total: names.length,
361
- names,
362
- categories,
363
- };
364
- }
365
-
366
- function formatBundledCategoryLine(catalog) {
367
- if (!catalog?.categories?.length) {
368
- return 'bundled skills: 0';
369
- }
370
-
371
- return catalog.categories
372
- .filter((category) => category.count > 0)
373
- .map((category) => `${category.label} ${category.count}`)
374
- .join(' | ');
375
- }
376
-
377
- function resolveCommandArea(action) {
378
- if (!action) {
379
- return 'geral';
380
- }
381
-
382
- return COMMAND_AREA_LABELS[action.key] ?? 'geral';
383
- }
384
-
385
- function formatActionCommand(action) {
386
- if (!action?.command) {
387
- return '';
388
- }
389
-
390
- return [action.command, ...(action.args ?? [])].join(' ');
391
- }
392
-
393
- export function buildMenuCommands({ rootDir, currentFile, nodeExecPath = process.execPath }) {
394
- const isDevCheckout = existsSync(join(rootDir, 'tsconfig.json')) && existsSync(join(rootDir, 'src'));
395
- const repoOnlyReason = 'Disponivel apenas no clone de desenvolvimento; no pacote npm use Doctor ou Status.';
396
-
397
- return [
398
- {
399
- key: 'status',
400
- aliases: ['status'],
401
- label: 'Status local',
402
- description: 'Mostra versao local, manifesto e informacoes do pacote.',
403
- details: ['Nao altera arquivos.', 'Use para confirmar se o menu esta lendo a instalacao correta.'],
404
- success: 'Relatorio impresso com versao, canal, skills globais e clientes configurados.',
405
- command: nodeExecPath,
406
- args: [currentFile, '--status'],
407
- },
408
- {
409
- key: 'doctor',
410
- aliases: ['doctor', 'diagnostico', 'verificar-menu', 'validar-menu'],
411
- label: 'Doctor do menu e clientes MCP',
412
- description: 'Valida pacote, binarios, skills globais e registros em Codex, Claude, Gemini e Antigravity.',
413
- details: ['Seguro para outros notebooks.', 'Nao publica versao e nao mexe em configuracoes sem uma acao separada.'],
414
- success: 'Mostra um relatorio GO/NO-GO com proximos comandos recomendados.',
415
- command: nodeExecPath,
416
- args: [join(rootDir, 'bin', 'skill-master-doctor.mjs')],
417
- },
418
- {
419
- key: 'check',
420
- aliases: ['check', 'gate'],
421
- label: 'Rodar gate completo',
422
- description: 'Executa build, testes e validacao de manifestos.',
423
- details: ['Exige clone do repositorio com src, testes e tsconfig.', 'Nao e uma acao indicada para instalacao global via npm.'],
424
- success: 'Build, testes e manifestos passam no checkout de desenvolvimento.',
425
- disabledReason: isDevCheckout ? null : repoOnlyReason,
426
- command: 'npm',
427
- args: ['run', 'check'],
428
- },
429
- {
430
- key: 'build',
431
- aliases: ['build'],
432
- label: 'Rodar build',
433
- description: 'Compila o projeto localmente.',
434
- details: ['Exige clone do repositorio com tsconfig.', 'Pacotes npm publicados ja usam dist precompilado.'],
435
- success: 'dist atualizado no checkout de desenvolvimento.',
436
- disabledReason: isDevCheckout ? null : repoOnlyReason,
437
- command: 'npm',
438
- args: ['run', 'build'],
439
- },
440
- {
441
- key: 'publicNpm',
442
- aliases: ['public-npm', 'npm', 'registry'],
443
- label: 'Validar pacote no npm publico',
444
- description: 'Consulta a versao publicada em registry.npmjs.org.',
445
- details: ['Usa somente leitura no registry publico.', 'Bom para confirmar se outro notebook consegue instalar por npm.'],
446
- success: 'Retorna a versao publicada atualmente no npmjs.',
447
- command: 'npm',
448
- args: [
449
- 'view',
450
- '@fprad0/skill-master-mcp',
451
- 'version',
452
- '--registry=https://registry.npmjs.org',
453
- ],
454
- },
455
- {
456
- key: 'updateGlobal',
457
- aliases: ['update', 'update-global'],
458
- label: 'Atualizar pacote global via npm',
459
- description: 'Atualiza a instalacao global e exige reinicio do cliente MCP.',
460
- details: ['Roda npm install -g fora do processo MCP stdio.', 'Use antes de abrir Codex, Claude, Gemini ou Antigravity.'],
461
- success: 'Pacote global atualizado para a versao latest do npm publico.',
462
- command: nodeExecPath,
463
- args: [join(rootDir, 'bin', 'skill-master-update.mjs')],
464
- confirmMessage: 'Atualizar o pacote global agora?',
465
- },
466
- {
467
- key: 'privateRegistry',
468
- aliases: ['private-registry', 'private', 'github-packages'],
469
- label: 'Configurar registry privado GitHub Packages',
470
- description: 'Prepara o .npmrc e valida o acesso ao pacote privado.',
471
- details: ['Uso avancado para ambientes privados.', 'Nao e necessario para o pacote publico do npmjs.'],
472
- success: '.npmrc configurado e validacao npm view executada.',
473
- command: nodeExecPath,
474
- args: ['scripts/configure-private-registry.mjs', '--validate'],
475
- confirmMessage: 'Rodar a configuracao de registry privado agora?',
476
- },
477
- {
478
- key: 'activationStatus',
479
- aliases: ['activation-status', 'modo', 'modo-ativacao'],
480
- label: 'Modo de ativacao atual',
481
- description: 'Mostra o modo manual, balanced ou always-on-assisted configurado localmente.',
482
- details: ['Nao altera configuracao.', 'Ajuda a entender quando o Skill Master deve sugerir skills.'],
483
- success: 'Modo atual e caminho da configuracao impressos no terminal.',
484
- command: nodeExecPath,
485
- args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--status'],
486
- },
487
- {
488
- key: 'activationBalanced',
489
- aliases: ['set-balanced', 'balanced'],
490
- label: 'Usar modo balanced',
491
- description: 'Define balanced como modo padrao de ativacao do Skill Master.',
492
- details: ['Recomendado para uso diario.', 'Ativa o MCP quando ha ganho claro para o prompt.'],
493
- success: 'Modo balanced salvo localmente.',
494
- command: nodeExecPath,
495
- args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--set-mode', 'balanced'],
496
- },
497
- {
498
- key: 'activationAlwaysOn',
499
- aliases: ['set-always-on', 'always-on-assisted'],
500
- label: 'Usar modo always-on-assisted',
501
- description: 'Define avaliacao assistida quase sempre ativa, mantendo no-op quando nao houver ganho.',
502
- details: ['Mais agressivo que balanced.', 'Indicado para usuarios que querem o Skill Master avaliando quase todos os prompts.'],
503
- success: 'Modo always-on-assisted salvo localmente.',
504
- command: nodeExecPath,
505
- args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--set-mode', 'always-on-assisted'],
506
- confirmMessage: 'Alterar o modo local para always-on-assisted?',
507
- },
508
- {
509
- key: 'installGlobalSkills',
510
- aliases: ['install-global-skills', 'skills-globais', 'global-skills'],
511
- label: 'Instalar skills globais do Skill Master',
512
- description: 'Copia as skills amplas e morais embutidas para CODEX_HOME/skills ou ~/.codex/skills.',
513
- details: ['Necessario para Codex descobrir as skills globais.', 'Pode ser reexecutado com seguranca pelo bootstrap.'],
514
- success: 'Skills globais copiadas para a pasta global do usuario.',
515
- command: nodeExecPath,
516
- args: [join(rootDir, 'bin', 'skill-master-install-global-skills.mjs')],
517
- confirmMessage: 'Instalar as skills globais embutidas neste usuario?',
518
- },
519
- {
520
- key: 'bootstrapGlobal',
521
- aliases: ['bootstrap-global', 'global-bootstrap', 'ativar-global-completo'],
522
- label: 'Ativar MCP global neste computador',
523
- description: 'Instala skills globais e registra Codex, Claude, Gemini e Antigravity no mesmo passo.',
524
- details: ['Acao principal para notebooks novos.', 'Depois reinicie os clientes para eles recarregarem MCP e skills.'],
525
- success: 'Skills instaladas e configuracoes MCP aplicadas nos clientes encontrados.',
526
- command: nodeExecPath,
527
- args: [join(rootDir, 'bin', 'skill-master-bootstrap-global.mjs')],
528
- confirmMessage: 'Executar o bootstrap global do Skill Master neste computador?',
529
- },
530
- {
531
- key: 'registerClients',
532
- aliases: ['register-clients', 'registrar-clientes', 'codex-claude-gemini', 'antigravity'],
533
- label: 'Registrar clientes MCP',
534
- description: 'Gera/aplica configuracoes MCP para Codex, Claude, Gemini e Antigravity reconhecerem skill_master.',
535
- details: ['Usa Node absoluto + bin/skill-master.mjs absoluto.', 'Preserva outros servidores MCP ja existentes nos JSONs.'],
536
- success: 'Arquivos de configuracao mesclados com o servidor skill_master.',
537
- command: nodeExecPath,
538
- args: [join(rootDir, 'bin', 'skill-master-register-clients.mjs'), '--apply-all'],
539
- confirmMessage: 'Aplicar registro do skill_master em Codex, Claude, Gemini e Antigravity?',
540
- },
541
- {
542
- key: 'promptRecommendation',
543
- aliases: ['recommend-prompt', 'recomendar-prompt', 'prompt-router'],
544
- label: 'Ver recomendacao para um prompt',
545
- description: 'Abre um fluxo interativo para avaliar um prompt pelo router local.',
546
- details: ['Ajuda a decidir se skill-master, skill_master ou skill-master-mcp deve agir.', 'Nao publica nem altera skills.'],
547
- success: 'Router imprime recomendacao, modo de ativacao e gates aplicaveis.',
548
- command: nodeExecPath,
549
- args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--route-prompt-interactive'],
550
- },
551
- {
552
- key: 'successNotifications',
553
- aliases: ['notifications', 'notificacoes', 'success-notifications'],
554
- label: 'Notificacoes de skills aprendidas',
555
- description: 'Mostra drafts pendentes, aprovacoes e skills externas para estudar.',
556
- details: ['Use para decidir o que aprovar, estudar ou rejeitar.', 'Nao ativa skill automaticamente.'],
557
- success: 'Lista de pendencias e proximas acoes exibida.',
558
- command: nodeExecPath,
559
- args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--notify'],
560
- },
561
- {
562
- key: 'studySkills',
563
- aliases: ['study-skills', 'skills-estudo', 'estudar'],
564
- label: 'Skills para estudar',
565
- description: 'Lista skills externas e links de criadores ainda nao aprovados.',
566
- details: ['Material de estudo, nao ativacao operacional.', 'Bom para revisao humana antes de virar skill local/global.'],
567
- success: 'Links e motivos de estudo exibidos.',
568
- command: nodeExecPath,
569
- args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--study'],
570
- },
571
- {
572
- key: 'approvalPackage',
573
- aliases: ['approval-package', 'aprovar', 'pacote-aprovacao'],
574
- label: 'Gerar pacote de aprovacao humana',
575
- description: 'Cria um relatorio local para revisar e aprovar skills aprendidas.',
576
- details: ['Exige decisao humana antes de ativacao.', 'Inclui riscos, evidencias e recomendacao.'],
577
- success: 'Pacote local de aprovacao gerado.',
578
- command: nodeExecPath,
579
- args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--approval-package'],
580
- },
581
- {
582
- key: 'markLearnedStudy',
583
- aliases: ['mark-study', 'manter-estudo'],
584
- label: 'Manter skill candidata para estudo',
585
- description: 'Seleciona uma candidata e registra decisao de manter para estudo.',
586
- details: ['Preserva historico sem ativar a skill.', 'Use quando a fonte ainda precisa revisao.'],
587
- success: 'Decisao registrada no historico local.',
588
- command: nodeExecPath,
589
- args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--mark-study-interactive'],
590
- },
591
- {
592
- key: 'rejectLearnedSkill',
593
- aliases: ['reject-skill', 'rejeitar-skill'],
594
- label: 'Rejeitar skill candidata',
595
- description: 'Seleciona uma candidata, registra rejeicao e preserva historico.',
596
- details: ['Nao apaga evidencias.', 'Use quando risco, fonte ou utilidade nao passam no gate.'],
597
- success: 'Rejeicao registrada com motivo.',
598
- command: nodeExecPath,
599
- args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--reject-interactive'],
600
- confirmMessage: 'Abrir fluxo para rejeitar uma skill candidata?',
601
- },
602
- {
603
- key: 'activateLearnedLocal',
604
- aliases: ['activate-learned-local', 'ativar-local', 'skill-local'],
605
- label: 'Ativar skill aprendida no workspace',
606
- description: 'Instala uma skill aprendida em .codex/skills do projeto atual.',
607
- details: ['Escopo limitado ao workspace.', 'Mais conservador que ativar globalmente.'],
608
- success: 'Skill copiada para .codex/skills do projeto.',
609
- command: nodeExecPath,
610
- args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--activate-interactive', '--target', 'local'],
611
- confirmMessage: 'Selecionar e ativar uma skill aprendida no workspace atual?',
612
- },
613
- {
614
- key: 'activateLearnedGlobal',
615
- aliases: ['activate-learned-global', 'ativar-global', 'skill-global'],
616
- label: 'Ativar skill aprendida global',
617
- description: 'Instala uma skill aprendida em CODEX_HOME/skills ou ~/.codex/skills.',
618
- details: ['Afeta todos os projetos deste usuario.', 'Use apenas depois de aprovacao humana.'],
619
- success: 'Skill instalada no diretorio global de skills.',
620
- command: nodeExecPath,
621
- args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--activate-interactive', '--target', 'global'],
622
- confirmMessage: 'Selecionar e ativar uma skill aprendida como skill global deste usuario?',
623
- },
624
- {
625
- key: 'notionSummary',
626
- aliases: ['notion-summary', 'resumo-notion'],
627
- label: 'Abrir resumo para Notion',
628
- description: 'Mostra um resumo copiavel do estado de ativacao para registrar no ledger Notion.',
629
- details: ['Nao escreve no Notion sozinho.', 'Gera texto de continuidade para documentacao.'],
630
- success: 'Resumo pronto para registro exibido.',
631
- command: nodeExecPath,
632
- args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--notion-summary'],
633
- },
634
- ];
635
- }
636
-
637
- export function buildMenuChoices(commands) {
638
- return commands.map((command) => ({
639
- title: command.label,
640
- description: [command.description, command.success ? `Resultado: ${command.success}` : null].filter(Boolean).join(' '),
641
- value: command.key,
642
- disabled: command.disabledReason ?? false,
643
- })).concat({
644
- title: 'Sair',
645
- description: 'Fecha o menu operacional.',
646
- value: '__exit__',
647
- });
648
- }
649
-
650
- export function resolveActionKey(input, commands) {
651
- const normalized = (input ?? '').trim().toLowerCase();
652
- if (!normalized) {
653
- return null;
654
- }
655
-
656
- return commands.find((command) =>
657
- command.key.toLowerCase() === normalized || command.aliases.includes(normalized),
658
- )?.key ?? null;
659
- }
660
-
661
- export function isInteractiveTerminal() {
662
- return Boolean(process.stdin.isTTY && process.stdout.isTTY);
663
- }
664
-
665
- export function formatStatusReport(status) {
666
- const readiness = status.globalReadiness;
667
- const bundledCatalog = status.bundledCatalog ?? { total: 0, categories: [] };
668
- const lines = [
669
- 'Skill Master MCP - status local',
670
- `Diretorio: ${status.rootDir}`,
671
- `Pacote: ${status.packageName}`,
672
- `Semver local: ${status.semver}`,
673
- `Manifesto stable: ${status.manifestVersion}`,
674
- `Manifesto semver: ${status.manifestSemver}`,
675
- `Drafts de skills aprendidas: ${status.pendingSuccessDrafts}`,
676
- `Skills externas para estudar: ${status.studyCandidates}`,
677
- `Global readiness: ${readiness.ready ? 'pronto' : readiness.mode}`,
678
- `Global skills instaladas: ${readiness.installed.length}/${readiness.required}`,
679
- `Bundle de skills embutidas: ${bundledCatalog.total}`,
680
- `Dominios do bundle: ${formatBundledCategoryLine(bundledCatalog)}`,
681
- `Codex MCP robusto: ${readiness.codex.globalCommand ? 'sim' : readiness.codex.kind}`,
682
- `Claude MCP robusto: ${readiness.claude.globalCommand ? 'sim' : readiness.claude.kind}`,
683
- `Gemini MCP robusto: ${readiness.gemini.globalCommand ? 'sim' : readiness.gemini.kind}`,
684
- `Antigravity MCP robusto: ${readiness.antigravity.globalCommand ? 'sim' : readiness.antigravity.kind}`,
685
- ];
686
-
687
- if (status.versionText) {
688
- lines.push('', 'VERSION.md:');
689
- lines.push(...status.versionText.split('\n').slice(0, 6));
690
- }
691
-
692
- return lines.join('\n');
693
- }
694
-
695
- function formatGlobalAlert(status, { useColor = false } = {}) {
696
- const readiness = status.globalReadiness;
697
- if (readiness.ready) {
698
- return renderPanelLines(
699
- [
700
- colorize('GLOBAL READY', ANSI.bold, useColor),
701
- 'O MCP esta registrado de forma robusta neste computador.',
702
- 'Codex, Claude, Gemini e Antigravity podem iniciar com Node absoluto.',
703
- 'A instalacao global e as skills embutidas ja estao prontas para uso.',
704
- ],
705
- { color: ANSI.green, useColor },
706
- );
707
- }
708
-
709
- return [
710
- renderPanelLines(
711
- [
712
- colorize('ALERTA GLOBAL', ANSI.bold, useColor),
713
- 'Este computador ainda nao esta pronto para uso global do Skill Master.',
714
- 'Execute agora: skill-master-menu --run bootstrap-global --yes',
715
- 'Isso instala as skills globais e registra Codex, Claude, Gemini e Antigravity com Node absoluto.',
716
- ],
717
- { color: ANSI.red, useColor },
718
- ),
719
- renderPanelLines(
720
- [
721
- colorize('AVISO SUTIL', ANSI.dim, useColor),
722
- 'Sem instalacao global, o MCP continua util localmente, mas nao fica integrado como parte do sistema em todos os clientes.',
723
- `Skills globais detectadas: ${readiness.installed.length}/${readiness.required}`,
724
- ],
725
- { color: ANSI.yellow, useColor },
726
- ),
727
- ].join('\n\n');
728
- }
729
-
730
- function renderPanelLines(lines, { color = ANSI.cyan, useColor = false } = {}) {
731
- const width = Math.max(...lines.map((line) => line.length), 24);
732
- const border = `+${'-'.repeat(width + 2)}+`;
733
- const paintedBorder = colorize(border, color, useColor);
734
- const body = lines.map((line) => `| ${line.padEnd(width)} |`);
735
- return [paintedBorder, ...body, paintedBorder].join('\n');
736
- }
737
-
738
- export function formatMenuBanner(status, { useColor = false } = {}) {
739
- const bundledCatalog = status.bundledCatalog ?? { total: 0, categories: [] };
740
- const lines = [
741
- colorize('Skill Master MCP', ANSI.bold, useColor),
742
- 'Menu operacional para manutencao local',
743
- `Versao local ${status.semver} | canal ${status.manifestVersion}`,
744
- `Pendencias: ${status.pendingSuccessDrafts} drafts | estudo: ${status.studyCandidates} links`,
745
- `Global: ${status.globalReadiness.ready ? 'pronto' : 'requer instalacao global'}`,
746
- `Bundle: ${bundledCatalog.total} skills | ${formatBundledCategoryLine(bundledCatalog)}`,
747
- colorize('Setas + Enter para navegar', ANSI.dim, useColor),
748
- ];
749
- return [
750
- renderPanelLines(lines, { color: ANSI.cyan, useColor }),
751
- formatGlobalAlert(status, { useColor }),
752
- ].join('\n\n');
753
- }
754
-
755
- function dnaPanelLines(tick, width, height, status, { useColor = false, compact = false } = {}) {
756
- const lines = [];
757
- const center = Math.floor(width / 2);
758
- const graphLeft = 2;
759
- const graphRight = Math.max(graphLeft + 8, width - 3);
760
- const graphWidth = Math.max(10, graphRight - graphLeft + 1);
761
- const radius = Math.max(3, Math.floor((graphWidth - 4) / 3.35));
762
- const phase = tick / 6;
763
- const bodyHeight = Math.max(compact ? 6 : 8, height - (compact ? 5 : 6));
764
- const scanRow = bodyHeight > 0 ? tick % bodyHeight : 0;
765
-
766
- lines.push(fitText(colorize('GENOME MATRIX', ANSI.bold, useColor), width));
767
- lines.push(fitText(colorize(compact ? 'lab helix / scan stable' : 'procedural intelligence helix', ANSI.dim, useColor), width));
768
- if (!compact) {
769
- lines.push(fitText(colorize('signal map / sync locked / low flicker', ANSI.gray, useColor), width));
770
- }
771
-
772
- const place = (cells, col, char, color) => {
773
- if (col >= 0 && col < width) cells[col] = colorize(char, color, useColor);
774
- };
775
-
776
- for (let row = 0; row < bodyHeight; row += 1) {
777
- const angle = row * 0.49 + phase;
778
- const left = Math.round(center + Math.sin(angle) * radius);
779
- const right = Math.round(center + Math.sin(angle + Math.PI) * radius);
780
- const min = Math.min(left, right);
781
- const max = Math.max(left, right);
782
- const chars = Array.from({ length: width }, () => ' ');
783
- const front = Math.cos(angle) >= 0;
784
- const leftColor = front ? ANSI.teal : ANSI.blue;
785
- const rightColor = front ? ANSI.amber : ANSI.gray;
786
- const bondColor = front ? ANSI.gray : ANSI.blue;
787
- const scanActive = row === scanRow;
788
-
789
- place(chars, graphLeft, row === 0 ? '┌' : row === bodyHeight - 1 ? '└' : '│', ANSI.gray);
790
- place(chars, graphRight, row === 0 ? '┐' : row === bodyHeight - 1 ? '┘' : '│', ANSI.gray);
791
-
792
- if (row === 0 || row === bodyHeight - 1) {
793
- for (let col = graphLeft + 1; col < graphRight; col += 1) {
794
- place(chars, col, '─', ANSI.gray);
795
- }
796
- }
797
-
798
- for (let col = min + 2; col < max - 1; col += 1) {
799
- const rungChar = row % 4 < 2 ? '═' : '─';
800
- place(chars, col, scanActive ? '█' : rungChar, scanActive ? ANSI.white : bondColor);
801
- }
802
-
803
- place(chars, left - 1, '▓', leftColor);
804
- place(chars, left, scanActive ? '█' : row % 2 === 0 ? '█' : '▓', scanActive ? ANSI.white : leftColor);
805
- place(chars, left + 1, '▓', leftColor);
806
- place(chars, right - 1, '▓', rightColor);
807
- place(chars, right, scanActive ? '█' : row % 2 === 0 ? '█' : '▓', scanActive ? ANSI.white : rightColor);
808
- place(chars, right + 1, '▓', rightColor);
809
-
810
- if (row % 4 === 1 || row % 4 === 2) {
811
- place(chars, center, scanActive ? '◆' : '◆', scanActive ? ANSI.white : ANSI.gray);
812
- }
813
-
814
- lines.push(chars.join(''));
815
- }
816
-
817
- lines.push(fitText('', width));
818
- lines.push(fitText(colorize(compact ? 'helix stable' : 'helix stable lattice aligned', ANSI.gray, useColor), width));
819
- lines.push(fitText(colorize(compact ? `global ${status.globalReadiness.installed.length}/${status.globalReadiness.required}` : `global ${status.globalReadiness.installed.length}/${status.globalReadiness.required} clients linked`, ANSI.amber, useColor), width));
820
-
821
- return lines.slice(0, height).map((line) => fitText(line, width));
822
- }
823
-
824
- function renderMeterBar(value, total, width, { useColor = false, color = ANSI.teal } = {}) {
825
- const safeTotal = Math.max(1, total);
826
- const safeValue = Math.max(0, Math.min(value, safeTotal));
827
- const fill = Math.round((safeValue / safeTotal) * width);
828
- const filled = ''.repeat(fill);
829
- const empty = '░'.repeat(Math.max(0, width - fill));
830
- return `${colorize(filled, color, useColor)}${colorize(empty, ANSI.gray, useColor)}`;
831
- }
832
-
833
- function renderSparkline(series, { useColor = false, color = ANSI.teal } = {}) {
834
- const blocks = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
835
- return series.map((value) => colorize(blocks[Math.max(0, Math.min(blocks.length - 1, value))], color, useColor)).join('');
836
- }
837
-
838
- function buildTelemetrySeries(seed, length, tick) {
839
- return Array.from({ length }, (_, index) => {
840
- const raw = Math.sin((index + 1 + seed) * 0.72 + tick * 0.18) + Math.cos((index + seed) * 0.33 + tick * 0.11);
841
- const normalized = Math.max(0, Math.min(1, (raw + 2) / 4));
842
- return Math.round(normalized * 7);
843
- });
844
- }
845
-
846
- function buildOverviewSignalLine(status, width, tick, { useColor = false, compact = false } = {}) {
847
- const signalWidth = Math.max(6, Math.min(compact ? 8 : 12, Math.floor(width / (compact ? 10 : 8))));
848
- const healthWidth = Math.max(6, Math.min(compact ? 8 : 12, Math.floor(width / (compact ? 10 : 8))));
849
- const signal = renderSparkline(
850
- buildTelemetrySeries(status.globalReadiness.installed.length + status.pendingSuccessDrafts, signalWidth, tick),
851
- { useColor, color: ANSI.teal },
852
- );
853
- const health = renderSparkline(
854
- buildTelemetrySeries(status.studyCandidates + (status.globalReadiness.ready ? 7 : 3), healthWidth, tick + 3),
855
- { useColor, color: ANSI.amber },
856
- );
857
- return compact
858
- ? `signal ${signal} health ${health}`
859
- : `signal ${signal} health ${health}`;
860
- }
861
-
862
- function telemetryPanelLines(status, selected, width, height, { useColor = false, tick = 0, compact = false } = {}) {
863
- const commandArea = resolveCommandArea(selected);
864
- const bundledCatalog = status.bundledCatalog ?? { total: 0, categories: [] };
865
- const categoryLead = bundledCatalog.categories
866
- ?.filter((category) => category.count > 0)
867
- .sort((left, right) => right.count - left.count)[0];
868
- const categoryName = categoryLead?.label ?? 'none';
869
- const categoryCount = categoryLead?.count ?? 0;
870
- const meterWidth = Math.max(8, Math.min(16, width - 14));
871
- const sparkWidth = Math.max(8, Math.min(compact ? 8 : 12, width - 18));
872
- const skillsSpark = renderSparkline(buildTelemetrySeries(status.globalReadiness.installed.length + categoryCount, sparkWidth, tick), { useColor, color: ANSI.amber });
873
- const draftsSpark = renderSparkline(buildTelemetrySeries(status.pendingSuccessDrafts + 2, sparkWidth, tick + 2), { useColor, color: ANSI.teal });
874
- const studySpark = renderSparkline(buildTelemetrySeries(status.studyCandidates + 4, sparkWidth, tick + 4), { useColor, color: ANSI.blue });
875
- const lines = [
876
- fitText(colorize('SYSTEM WINDOWS', ANSI.bold, useColor), width),
877
- fitText(colorize(`selected area ${commandArea}`, ANSI.gray, useColor), width),
878
- fitText(colorize(`dominant skill ${categoryName} ${categoryCount}`, ANSI.gray, useColor), width),
879
- fitText(`bundle ${String(bundledCatalog.total).padStart(2, '0')} ${renderMeterBar(bundledCatalog.total, Math.max(36, bundledCatalog.total), meterWidth, { useColor, color: ANSI.white })}`, width),
880
- fitText(`global ${status.globalReadiness.installed.length}/${status.globalReadiness.required} ${renderMeterBar(status.globalReadiness.installed.length, status.globalReadiness.required, meterWidth, { useColor, color: ANSI.amber })}`, width),
881
- fitText(`skills ${skillsSpark}`, width),
882
- fitText(`drafts ${String(status.pendingSuccessDrafts).padStart(2, '0')} ${renderMeterBar(status.pendingSuccessDrafts, Math.max(6, status.pendingSuccessDrafts || 1), meterWidth, { useColor, color: ANSI.teal })}`, width),
883
- fitText(`queue ${draftsSpark}`, width),
884
- fitText(`study ${String(status.studyCandidates).padStart(2, '0')} ${renderMeterBar(status.studyCandidates, Math.max(8, status.studyCandidates || 1), meterWidth, { useColor, color: ANSI.blue })}`, width),
885
- fitText(`links ${studySpark}`, width),
886
- fitText(colorize(compact ? 'codex / claude / gemini' : 'codex / claude / gemini / antigravity', ANSI.dim, useColor), width),
887
- ];
888
-
889
- return lines.slice(0, height).map((line) => fitText(line, width));
890
- }
891
-
892
- function renderBox(lines, width, title, { useColor = false, color = ANSI.cyan, style = 'normal' } = {}) {
893
- const innerWidth = Math.max(10, width - 4);
894
- const titleText = title ? ` ${title.toUpperCase()} ` : '';
895
- const topLeft = style === 'focus' ? '' : style === 'hud' ? '' : '';
896
- const topRight = style === 'focus' ? '╮' : style === 'hud' ? '┓' : '┐';
897
- const bottomLeft = style === 'focus' ? '╰' : style === 'hud' ? '┗' : '└';
898
- const bottomRight = style === 'focus' ? '' : style === 'hud' ? '' : '';
899
- const topFill = style === 'focus' ? '═' : '─';
900
- const bottomTail = style === 'focus' ? '══' : '┄┄';
901
- const top = `${topLeft}${titleText}${topFill.repeat(Math.max(0, width - 2 - titleText.length))}${topRight}`;
902
- const bottom = `${bottomLeft}${topFill.repeat(Math.max(0, width - 4))}${bottomTail}${bottomRight}`;
903
- const body = lines.map((line, index) => {
904
- const left = index === 0
905
- ? (style === 'focus' ? '╞' : '├')
906
- : index === lines.length - 1
907
- ? (style === 'focus' ? '╘' : '╰')
908
- : '│';
909
- const right = index === 0
910
- ? (style === 'focus' ? '╡' : '┤')
911
- : index === lines.length - 1
912
- ? (style === 'focus' ? '╛' : '╯')
913
- : '│';
914
- return `${colorize(left, color, useColor)} ${fitText(line, innerWidth)} ${colorize(right, color, useColor)}`;
915
- });
916
- return [
917
- colorize(top, color, useColor),
918
- ...body,
919
- colorize(bottom, color, useColor),
920
- ];
921
- }
922
-
923
- function joinHorizontalBoxes(boxes, gutter = 2) {
924
- const height = Math.max(...boxes.map((box) => box.lines.length));
925
- const gap = ' '.repeat(gutter);
926
- const rows = [];
927
-
928
- for (let index = 0; index < height; index += 1) {
929
- rows.push(boxes.map((box) => box.lines[index] ?? ' '.repeat(box.width)).join(gap));
930
- }
931
-
932
- return rows;
933
- }
934
-
935
- export function formatCyberMenuFrame(status, commands, selectedIndex, tick = 0, {
936
- columns = 120,
937
- rows = 32,
938
- useColor = false,
939
- } = {}) {
940
- const width = Math.max(72, Math.min(columns, 150));
941
- const height = Math.max(22, Math.min(rows - 1, 42));
942
- const compactMode = width < 104 || height < 27;
943
- const rightWidth = compactMode ? (width >= 92 ? 28 : 26) : width >= 132 ? 44 : width >= 108 ? 38 : 30;
944
- const gutter = 2;
945
- const leftWidth = width - rightWidth - gutter;
946
- const selected = commands[selectedIndex] ?? commands[0];
947
- const actionArea = resolveCommandArea(selected);
948
- const bundledCatalog = status.bundledCatalog ?? { total: 0, categories: [] };
949
- const summaryOuterHeight = compactMode ? 7 : 8;
950
- const bodyOuterHeight = Math.max(12, height - summaryOuterHeight - 1);
951
- const detailOuterHeight = compactMode
952
- ? Math.min(8, Math.max(7, Math.floor(bodyOuterHeight * 0.46)))
953
- : Math.min(10, Math.max(8, Math.floor(bodyOuterHeight * 0.42)));
954
- const actionOuterHeight = compactMode
955
- ? Math.max(8, bodyOuterHeight - detailOuterHeight)
956
- : Math.max(8, bodyOuterHeight - detailOuterHeight);
957
- const rightBottomOuterHeight = compactMode
958
- ? Math.min(8, Math.max(7, Math.floor(bodyOuterHeight * 0.4)))
959
- : Math.min(10, Math.max(8, Math.floor(bodyOuterHeight * 0.34)));
960
- const rightTopOuterHeight = Math.max(8, bodyOuterHeight - rightBottomOuterHeight);
961
- const summaryInnerWidth = width - 4;
962
- const actionInnerWidth = leftWidth - 4;
963
- const detailInnerWidth = leftWidth - 4;
964
- const rightInnerWidth = rightWidth - 4;
965
- const summaryInnerHeight = summaryOuterHeight - 2;
966
- const actionInnerHeight = actionOuterHeight - 2;
967
- const detailInnerHeight = detailOuterHeight - 2;
968
- const rightTopInnerHeight = rightTopOuterHeight - 2;
969
- const rightBottomInnerHeight = rightBottomOuterHeight - 2;
970
- const visibleActionRows = Math.max(compactMode ? 2 : 3, actionInnerHeight - (compactMode ? 2 : 3));
971
- const scrollStart = Math.min(
972
- Math.max(0, selectedIndex - Math.floor(visibleActionRows / 2)),
973
- Math.max(0, commands.length - visibleActionRows),
974
- );
975
- const visibleCommands = commands.slice(scrollStart, scrollStart + visibleActionRows);
976
-
977
- const summaryLines = compactMode
978
- ? [
979
- colorize('SKILL MASTER MENU', ANSI.bold, useColor),
980
- `version ${status.semver} | channel ${status.manifestVersion} | readiness ${status.globalReadiness.ready ? 'ready' : status.globalReadiness.mode}`,
981
- colorize(`GLOBAL SKILLS ${status.globalReadiness.installed.length}/${status.globalReadiness.required}`, ANSI.amber, useColor),
982
- `bundle ${bundledCatalog.total} | drafts ${status.pendingSuccessDrafts} | study ${status.studyCandidates}`,
983
- buildOverviewSignalLine(status, summaryInnerWidth, tick, { useColor, compact: true }),
984
- colorize('compact cyberpunk hud / operator safe', ANSI.dim, useColor),
985
- ]
986
- : [
987
- colorize('SKILL MASTER MENU', ANSI.bold, useColor),
988
- `version ${status.semver} | channel ${status.manifestVersion} | readiness ${status.globalReadiness.ready ? 'ready' : status.globalReadiness.mode}`,
989
- colorize(`GLOBAL SKILLS ${status.globalReadiness.installed.length}/${status.globalReadiness.required}`, ANSI.amber, useColor),
990
- `bundle ${bundledCatalog.total} | drafts ${status.pendingSuccessDrafts} | study ${status.studyCandidates}`,
991
- buildOverviewSignalLine(status, summaryInnerWidth, tick, { useColor, compact: false }),
992
- formatBundledCategoryLine(bundledCatalog),
993
- colorize('workflow windows / cyberpunk terminal / operator safe', ANSI.dim, useColor),
994
- ];
995
-
996
- const actionLines = [
997
- colorize('ACTION GRID', ANSI.gray, useColor),
998
- colorize('up/down move enter run q exit', ANSI.dim, useColor),
999
- ...visibleCommands.map((command, offset) => {
1000
- const index = scrollStart + offset;
1001
- const marker = index === selectedIndex ? '▸' : '·';
1002
- const disabled = command.disabledReason ? ' [off]' : '';
1003
- const label = `${marker} ${command.label}${disabled}`;
1004
- return index === selectedIndex
1005
- ? colorize(fitText(label, actionInnerWidth), ANSI.teal, useColor)
1006
- : fitText(label, actionInnerWidth);
1007
- }),
1008
- ];
1009
-
1010
- while (actionLines.length < actionInnerHeight) {
1011
- actionLines.push(fitText('', actionInnerWidth));
1012
- }
1013
-
1014
- const descriptionLines = [
1015
- colorize('DETAIL FOCUS', ANSI.amber, useColor),
1016
- colorize(selected?.label ?? 'Nenhuma acao', ANSI.bold, useColor),
1017
- fitText(colorize(`area ${actionArea} | action ${Math.min(selectedIndex + 1, commands.length)}/${commands.length}`, ANSI.gray, useColor), detailInnerWidth),
1018
- fitText(colorize('────────────────────────────────', ANSI.amber, useColor), detailInnerWidth),
1019
- ...splitText(selected?.description, detailInnerWidth, 1),
1020
- ...splitText(selected?.success ? `resultado: ${selected.success}` : '', detailInnerWidth, 1),
1021
- ...splitText(`exec: ${formatActionCommand(selected)}`, detailInnerWidth, 1),
1022
- ...(selected?.confirmMessage ? splitText(`confirmacao: ${selected.confirmMessage}`, detailInnerWidth, 2) : []),
1023
- ...(selected?.disabledReason ? splitText(`Indisponivel: ${selected.disabledReason}`, detailInnerWidth, 2) : []),
1024
- ];
1025
-
1026
- while (descriptionLines.length < detailInnerHeight) {
1027
- descriptionLines.push(fitText('', detailInnerWidth));
1028
- }
1029
-
1030
- const rightTopLines = dnaPanelLines(tick, rightInnerWidth, rightTopInnerHeight, status, { useColor, compact: compactMode });
1031
- const rightBottomLines = telemetryPanelLines(status, selected, rightInnerWidth, rightBottomInnerHeight, { useColor, tick, compact: compactMode });
1032
- const summaryBox = renderBox(
1033
- summaryLines.slice(0, summaryInnerHeight).map((line) => fitText(line, summaryInnerWidth)),
1034
- width,
1035
- 'overview',
1036
- { useColor, color: ANSI.white, style: 'hud' },
1037
- );
1038
- const actionBox = renderBox(
1039
- actionLines.slice(0, actionInnerHeight).map((line) => fitText(line, actionInnerWidth)),
1040
- leftWidth,
1041
- 'actions',
1042
- { useColor, color: ANSI.gray, style: 'normal' },
1043
- );
1044
- const detailBox = renderBox(
1045
- descriptionLines.slice(0, detailInnerHeight).map((line) => fitText(line, detailInnerWidth)),
1046
- leftWidth,
1047
- 'details',
1048
- { useColor, color: ANSI.amber, style: 'focus' },
1049
- );
1050
- const dnaBox = renderBox(rightTopLines, rightWidth, 'dna-core', { useColor, color: ANSI.white, style: 'hud' });
1051
- const telemetryBox = renderBox(rightBottomLines, rightWidth, 'telemetry', { useColor, color: ANSI.blue, style: 'normal' });
1052
- const bodyRows = joinHorizontalBoxes([
1053
- { lines: [...actionBox, ...detailBox], width: leftWidth },
1054
- { lines: [...dnaBox, ...telemetryBox], width: rightWidth },
1055
- ], gutter);
1056
-
1057
- return [...summaryBox, '', ...bodyRows].join('\n');
1058
- }
1059
-
1060
- export function formatRunningActionFrame(status, action, tick = 0, {
1061
- columns = 120,
1062
- rows = 32,
1063
- useColor = false,
1064
- } = {}) {
1065
- const width = Math.max(72, Math.min(columns, 150));
1066
- const height = Math.max(18, Math.min(rows - 1, 30));
1067
- const innerWidth = width - 4;
1068
- const commandArea = resolveCommandArea(action);
1069
- const pulse = renderSparkline(buildTelemetrySeries((status.globalReadiness.installed.length || 1) + tick, Math.max(8, Math.min(18, Math.floor(innerWidth / 5))), tick), { useColor, color: ANSI.teal });
1070
- const lines = [
1071
- colorize('EXECUTION TRANSFER', ANSI.bold, useColor),
1072
- fitText(colorize(`area ${commandArea} | launching ${action?.label ?? 'acao'}`, ANSI.amber, useColor), innerWidth),
1073
- fitText(colorize(`pulse ${pulse}`, ANSI.gray, useColor), innerWidth),
1074
- fitText('', innerWidth),
1075
- ...splitText(action?.description ?? '', innerWidth, 2),
1076
- ...splitText(action?.success ? `resultado esperado: ${action.success}` : '', innerWidth, 2),
1077
- ...splitText(`exec: ${formatActionCommand(action)}`, innerWidth, 2),
1078
- fitText('', innerWidth),
1079
- fitText(colorize('alternando do HUD para o stream real do comando...', ANSI.dim, useColor), innerWidth),
1080
- ];
1081
-
1082
- while (lines.length < Math.max(8, height - 2)) {
1083
- lines.push(fitText('', innerWidth));
1084
- }
1085
-
1086
- return renderBox(
1087
- lines.slice(0, Math.max(8, height - 2)).map((line) => fitText(line, innerWidth)),
1088
- width,
1089
- 'running',
1090
- { useColor, color: ANSI.teal, style: 'focus' },
1091
- ).join('\n');
1092
- }
1093
-
1094
- export function formatActionHeader(action, { useColor = false } = {}) {
1095
- const lines = [
1096
- colorize(action.label, ANSI.bold, useColor),
1097
- action.description,
1098
- ...(action.details ?? []),
1099
- action.success ? `Resultado esperado: ${action.success}` : null,
1100
- action.disabledReason ? `Indisponivel: ${action.disabledReason}` : null,
1101
- ].filter(Boolean);
1102
-
1103
- return renderPanelLines(
1104
- lines,
1105
- { color: ANSI.green, useColor },
1106
- );
1107
- }
1108
-
1109
- export function formatResultMessage(code, { useColor = false } = {}) {
1110
- if (code === 0) {
1111
- return colorize('Comando concluido com sucesso.', ANSI.green, useColor);
1112
- }
1113
-
1114
- return colorize(`Comando terminou com codigo ${code}.`, ANSI.red, useColor);
1115
- }
1116
-
1117
- export function formatHelp(commands) {
1118
- const actionList = commands.map((command) => {
1119
- const aliases = command.aliases.length ? ` aliases: ${command.aliases.join(', ')}` : '';
1120
- const disabled = command.disabledReason ? ` indisponivel: ${command.disabledReason}` : '';
1121
- return ` - ${command.key}: ${command.label}\n ${command.description}${aliases}${disabled}`;
1122
- }).join('\n');
1123
-
1124
- return `Skill Master Menu
1125
-
1126
- Uso:
1127
- skill-master-menu
1128
- skill-master-menu --status
1129
- skill-master-menu --run <acao>
1130
- skill-master-menu --run update --yes
1131
- skill-master-menu --help
1132
-
1133
- Acoes disponiveis:
1134
- ${actionList}
1135
-
1136
- O comando de menu e voltado para operacao humana. O binario MCP stdio continua sendo:
1137
- skill-master-mcp
1138
- `;
1139
- }
1140
-
1141
- export function runCommand(action, { cwd, env = process.env } = {}) {
1142
- return new Promise((resolve) => {
1143
- const child = spawn(action.command, action.args, {
1144
- cwd,
1145
- env,
1146
- shell: process.platform === 'win32',
1147
- stdio: 'inherit',
1148
- });
1149
-
1150
- child.on('close', (code) => {
1151
- resolve(code ?? 1);
1152
- });
1153
- });
1154
- }
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
3
+ import os from 'node:os';
4
+ import { dirname, join } from 'node:path';
5
+ import process from 'node:process';
6
+ import {
7
+ assessCodexConfigContent,
8
+ assessMcpServerConfig,
9
+ defaultClientConfigPaths,
10
+ } from './client-config.mjs';
11
+ import { buildOperationResultCopy } from './operation-result.mjs';
12
+
13
+ const ANSI = {
14
+ reset: '\x1b[0m',
15
+ bold: '\x1b[1m',
16
+ dim: '\x1b[2m',
17
+ cyan: '\x1b[36m',
18
+ green: '\x1b[32m',
19
+ yellow: '\x1b[33m',
20
+ red: '\x1b[31m',
21
+ white: '\x1b[37m',
22
+ gray: '\x1b[90m',
23
+ teal: '\x1b[38;5;80m',
24
+ amber: '\x1b[38;5;179m',
25
+ blue: '\x1b[38;5;75m',
26
+ rose: '\x1b[38;5;211m',
27
+ violet: '\x1b[38;5;141m',
28
+ };
29
+
30
+ const REQUIRED_GLOBAL_SKILLS = [
31
+ 'catholic-moral-discernment',
32
+ 'ai-ethics-human-dignity',
33
+ 'professional-boundary-triage',
34
+ 'broad-domain-router',
35
+ 'language-quality-pt-en-fr',
36
+ 'math-science-reasoning',
37
+ 'philosophy-sociology-discernment',
38
+ 'engineering-systems-master',
39
+ 'source-authority-reviewer',
40
+ 'release-ethics-gate',
41
+ 'mcp-client-readiness',
42
+ 'terminal-menu-operations',
43
+ 'terminal-pixel-art-tui',
44
+ 'senior-master-code-optimizer',
45
+ 'typescript-senior-master-engineering',
46
+ 'python-senior-master-engineering',
47
+ 'javascript-senior-master-engineering',
48
+ 'go-senior-master-engineering',
49
+ 'sql-senior-master-engineering',
50
+ 'json-senior-master-engineering',
51
+ 'ruby-senior-master-engineering',
52
+ 'react-senior-master-engineering',
53
+ 'html-senior-master-engineering',
54
+ 'css-senior-master-engineering',
55
+ 'csharp-senior-master-engineering',
56
+ ];
57
+
58
+ const BUNDLED_SKILL_DOMAIN_GROUPS = [
59
+ {
60
+ key: 'moral',
61
+ label: 'moral-core',
62
+ skills: [
63
+ 'ai-ethics-human-dignity',
64
+ 'broad-domain-router',
65
+ 'catholic-moral-discernment',
66
+ 'engineering-systems-master',
67
+ 'language-quality-pt-en-fr',
68
+ 'math-science-reasoning',
69
+ 'philosophy-sociology-discernment',
70
+ 'professional-boundary-triage',
71
+ 'release-ethics-gate',
72
+ 'source-authority-reviewer',
73
+ ],
74
+ },
75
+ {
76
+ key: 'frontend',
77
+ label: 'frontend-ui',
78
+ skills: [
79
+ 'figma',
80
+ 'figma-code-connect-components',
81
+ 'figma-create-design-system-rules',
82
+ 'figma-generate-design',
83
+ 'figma-generate-library',
84
+ 'figma-implement-design',
85
+ 'figma-use',
86
+ 'frontend-dev-guidelines',
87
+ 'frontend-design',
88
+ 'frontend-ui-ux-systems',
89
+ 'html-senior-master-engineering',
90
+ 'nextjs',
91
+ 'playwright',
92
+ 'react-senior-master-engineering',
93
+ 'screenshot',
94
+ 'senior-fullstack',
95
+ 'shadcn',
96
+ 'css-senior-master-engineering',
97
+ 'ui-component-primitives',
98
+ 'webapp-testing',
99
+ 'web-mobile-design-systems',
100
+ 'winui-app',
101
+ ],
102
+ },
103
+ {
104
+ key: 'backend',
105
+ label: 'backend-data',
106
+ skills: [
107
+ 'csharp-senior-master-engineering',
108
+ 'go-engineering',
109
+ 'go-senior-master-engineering',
110
+ 'java-engineering',
111
+ 'javascript-engineering',
112
+ 'javascript-senior-master-engineering',
113
+ 'json-contract-design',
114
+ 'json-senior-master-engineering',
115
+ 'mcp-builder',
116
+ 'polyglot-backend-engineering',
117
+ 'python-engineering',
118
+ 'python-senior-master-engineering',
119
+ 'ruby-engineering',
120
+ 'ruby-senior-master-engineering',
121
+ 'senior-master-code-optimizer',
122
+ 'sql-postgresql-engineering',
123
+ 'sql-senior-master-engineering',
124
+ 'typescript-expert',
125
+ 'typescript-senior-master-engineering',
126
+ ],
127
+ },
128
+ {
129
+ key: 'ops',
130
+ label: 'ops-clients',
131
+ skills: [
132
+ 'cli-creator',
133
+ 'developer-workstation-ops',
134
+ 'git-version-control-ops',
135
+ 'github',
136
+ 'mcp-client-readiness',
137
+ 'multi-client-mcp-ops',
138
+ 'openai-docs',
139
+ 'skill-master-orchestrator',
140
+ 'terminal-shell-ops',
141
+ 'terminal-menu-operations',
142
+ 'terminal-pixel-art-tui',
143
+ 'windows-linux-platform-ops',
144
+ ],
145
+ },
146
+ {
147
+ key: 'knowledge',
148
+ label: 'knowledge',
149
+ skills: [
150
+ 'language-quality-pt-en-fr-it-ru',
151
+ 'math-physics-reasoning',
152
+ ],
153
+ },
154
+ ];
155
+
156
+ const COMMAND_AREA_LABELS = {
157
+ status: 'diagnostico',
158
+ doctor: 'diagnostico',
159
+ check: 'desenvolvimento',
160
+ build: 'desenvolvimento',
161
+ publicNpm: 'distribuicao',
162
+ updateGlobal: 'distribuicao',
163
+ privateRegistry: 'registry',
164
+ activationStatus: 'ativacao',
165
+ activationBalanced: 'ativacao',
166
+ activationAlwaysOn: 'ativacao',
167
+ installGlobalSkills: 'skills-globais',
168
+ installProjectSkills: 'skills-projeto',
169
+ bootstrapGlobal: 'bootstrap-global',
170
+ registerClients: 'clientes-mcp',
171
+ promptRecommendation: 'roteamento',
172
+ successNotifications: 'aprendizado',
173
+ studySkills: 'aprendizado',
174
+ approvalPackage: 'aprovacao',
175
+ markLearnedStudy: 'aprovacao',
176
+ rejectLearnedSkill: 'aprovacao',
177
+ activateLearnedLocal: 'ativacao-skill',
178
+ activateLearnedGlobal: 'ativacao-skill',
179
+ notionSummary: 'documentacao',
180
+ };
181
+
182
+ const CRITICAL_SYSTEM_SETUP_ACTIONS = new Set([
183
+ 'bootstrapGlobal',
184
+ ]);
185
+
186
+ const SUPPORT_SYSTEM_SETUP_ACTIONS = new Set([
187
+ 'installGlobalSkills',
188
+ 'registerClients',
189
+ ]);
190
+
191
+ function colorize(text, color, enabled) {
192
+ return enabled ? `${color}${text}${ANSI.reset}` : text;
193
+ }
194
+
195
+ function getActionAttentionState(command, status) {
196
+ if (command?.disabledReason) return 'disabled';
197
+ if (!status?.globalReadiness?.ready) {
198
+ if (CRITICAL_SYSTEM_SETUP_ACTIONS.has(command?.key)) return 'critical';
199
+ if (SUPPORT_SYSTEM_SETUP_ACTIONS.has(command?.key)) return 'priority';
200
+ }
201
+ return 'normal';
202
+ }
203
+
204
+ function getActionAttentionBadge(command, status) {
205
+ const state = getActionAttentionState(command, status);
206
+ if (state === 'critical') return '[SETUP AGORA] ';
207
+ if (state === 'priority') return '[SISTEMA] ';
208
+ return '';
209
+ }
210
+
211
+ function getActionLineColor(command, selected, status) {
212
+ const state = getActionAttentionState(command, status);
213
+ if (selected && state === 'critical') return ANSI.rose;
214
+ if (selected && state === 'priority') return ANSI.amber;
215
+ if (selected) return ANSI.teal;
216
+ if (state === 'critical') return ANSI.rose;
217
+ if (state === 'priority') return ANSI.amber;
218
+ return null;
219
+ }
220
+
221
+ function buildSetupAlertLine(status, compact) {
222
+ if (status?.globalReadiness?.ready) return null;
223
+ return compact
224
+ ? 'SETUP GLOBAL PENDENTE -> use [SETUP AGORA] / [SISTEMA]'
225
+ : 'SETUP GLOBAL PENDENTE -> priorize [SETUP AGORA] e [SISTEMA] para autenticar o MCP no computador';
226
+ }
227
+
228
+ function visibleLength(text) {
229
+ return String(text).replace(/\x1b\[[0-9;]*m/g, '').length;
230
+ }
231
+
232
+ function fitText(text, width) {
233
+ const value = String(text ?? '');
234
+ if (visibleLength(value) <= width) {
235
+ return `${value}${' '.repeat(width - visibleLength(value))}`;
236
+ }
237
+
238
+ return `${value.slice(0, Math.max(0, width - 1))}~`;
239
+ }
240
+
241
+ function truncateVisibleText(text, width) {
242
+ if (width <= 0) return '';
243
+ const value = String(text ?? '');
244
+ let output = '';
245
+ let visible = 0;
246
+ let hasOpenAnsi = false;
247
+
248
+ for (let index = 0; index < value.length && visible < width;) {
249
+ if (value[index] === '\x1b' && value[index + 1] === '[') {
250
+ const end = value.indexOf('m', index);
251
+ if (end === -1) break;
252
+ const sequence = value.slice(index, end + 1);
253
+ output += sequence;
254
+ hasOpenAnsi = sequence !== ANSI.reset;
255
+ index = end + 1;
256
+ continue;
257
+ }
258
+
259
+ const [char] = Array.from(value.slice(index));
260
+ output += char;
261
+ visible += 1;
262
+ index += char.length;
263
+ }
264
+
265
+ return hasOpenAnsi ? `${output}${ANSI.reset}` : output;
266
+ }
267
+
268
+ function splitText(text, width, maxLines = 3) {
269
+ const words = String(text ?? '').split(/\s+/).filter(Boolean);
270
+ const lines = [];
271
+ let current = '';
272
+
273
+ for (const word of words) {
274
+ const next = current ? `${current} ${word}` : word;
275
+ if (next.length <= width) {
276
+ current = next;
277
+ continue;
278
+ }
279
+ if (current) lines.push(current);
280
+ current = word.length > width ? word.slice(0, width - 1) + '~' : word;
281
+ if (lines.length >= maxLines) break;
282
+ }
283
+ if (current && lines.length < maxLines) lines.push(current);
284
+ return lines.length ? lines : [''];
285
+ }
286
+
287
+ function globalSkillsRoot() {
288
+ return join(process.env.CODEX_HOME ?? join(os.homedir(), '.codex'), 'skills');
289
+ }
290
+
291
+ function readClientConfigState(filePath) {
292
+ if (!existsSync(filePath)) {
293
+ return { present: false, kind: 'missing', globalCommand: false };
294
+ }
295
+
296
+ const content = readFileSync(filePath, 'utf8');
297
+ const assessment = assessCodexConfigContent(content);
298
+
299
+ return {
300
+ present: true,
301
+ kind: assessment.mode,
302
+ globalCommand: assessment.robust,
303
+ command: assessment.command,
304
+ };
305
+ }
306
+
307
+ function readJsonState(filePath) {
308
+ if (!existsSync(filePath)) {
309
+ return { present: false, kind: 'missing', globalCommand: false };
310
+ }
311
+
312
+ try {
313
+ const parsed = JSON.parse(readFileSync(filePath, 'utf8'));
314
+ const server = parsed?.mcpServers?.skill_master;
315
+ const assessment = assessMcpServerConfig(server);
316
+ return {
317
+ present: true,
318
+ kind: assessment.mode,
319
+ globalCommand: assessment.robust,
320
+ command: assessment.command,
321
+ };
322
+ } catch {
323
+ return { present: true, kind: 'invalid-json', globalCommand: false };
324
+ }
325
+ }
326
+
327
+ function inspectGlobalReadiness() {
328
+ const root = globalSkillsRoot();
329
+ const installed = REQUIRED_GLOBAL_SKILLS.filter((name) => existsSync(join(root, name, 'SKILL.md')));
330
+ const missing = REQUIRED_GLOBAL_SKILLS.filter((name) => !installed.includes(name));
331
+ const clientPaths = defaultClientConfigPaths();
332
+ const codex = readClientConfigState(clientPaths.codex);
333
+ const claude = readJsonState(clientPaths.claude);
334
+ const gemini = readJsonState(clientPaths.gemini);
335
+ const antigravity = readJsonState(clientPaths.antigravity);
336
+ const ready = missing.length === 0
337
+ && codex.globalCommand
338
+ && claude.globalCommand
339
+ && gemini.globalCommand
340
+ && antigravity.globalCommand;
341
+ const mode = ready
342
+ ? 'ready'
343
+ : codex.present || claude.present || gemini.present || antigravity.present
344
+ ? 'partial'
345
+ : 'missing';
346
+
347
+ return {
348
+ root,
349
+ required: REQUIRED_GLOBAL_SKILLS.length,
350
+ installed,
351
+ missing,
352
+ ready,
353
+ mode,
354
+ codex,
355
+ claude,
356
+ gemini,
357
+ antigravity,
358
+ };
359
+ }
360
+
361
+ export function readJson(rootDir, relativePath) {
362
+ const target = join(rootDir, relativePath);
363
+ if (!existsSync(target)) {
364
+ return null;
365
+ }
366
+
367
+ return JSON.parse(readFileSync(target, 'utf8'));
368
+ }
369
+
370
+ export function readText(rootDir, relativePath) {
371
+ const target = join(rootDir, relativePath);
372
+ if (!existsSync(target)) {
373
+ return null;
374
+ }
375
+
376
+ return readFileSync(target, 'utf8').trim();
377
+ }
378
+
379
+ export function getMenuStatus(rootDir) {
380
+ const packageJson = readJson(rootDir, 'package.json');
381
+ const stableManifest = readJson(rootDir, 'manifests/channels/stable.json');
382
+ const versionText = readText(rootDir, 'VERSION.md');
383
+ const successLearningDir = process.env.SKILL_MASTER_SUCCESS_LEARNING_DIR
384
+ ?? join(process.env.SKILL_MASTER_HOME ?? join(process.env.HOME ?? process.env.USERPROFILE ?? '', '.skill-master'), 'data', 'success-learning');
385
+ const studyCandidates = readJson(rootDir, 'network/unapproved-skill-candidates.json');
386
+ const globalReadiness = inspectGlobalReadiness();
387
+ const bundledCatalog = inspectBundledSkillCatalog(rootDir);
388
+
389
+ return {
390
+ packageName: packageJson?.name ?? 'nao encontrado',
391
+ semver: packageJson?.version ?? 'nao encontrado',
392
+ manifestVersion: stableManifest?.version ?? 'nao encontrado',
393
+ manifestSemver: stableManifest?.semver ?? 'nao encontrado',
394
+ versionText,
395
+ rootDir,
396
+ pendingSuccessDrafts: countManifestFiles(successLearningDir),
397
+ studyCandidates: Array.isArray(studyCandidates?.candidates) ? studyCandidates.candidates.length : 0,
398
+ globalReadiness,
399
+ bundledCatalog,
400
+ };
401
+ }
402
+
403
+ function countManifestFiles(directory) {
404
+ if (!directory || !existsSync(directory)) {
405
+ return 0;
406
+ }
407
+
408
+ let count = 0;
409
+ const visit = (current) => {
410
+ for (const entry of readdirSync(current, { withFileTypes: true })) {
411
+ const fullPath = join(current, entry.name);
412
+ if (entry.isDirectory()) visit(fullPath);
413
+ else if (entry.isFile() && entry.name === 'manifest.json') count += 1;
414
+ }
415
+ };
416
+
417
+ visit(directory);
418
+ return count;
419
+ }
420
+
421
+ function listBundledSkillNames(rootDir) {
422
+ const source = join(rootDir, 'docs', 'skill-candidates');
423
+ if (!existsSync(source)) {
424
+ return [];
425
+ }
426
+
427
+ const entries = readdirSync(source, { withFileTypes: true });
428
+ const directSkills = entries
429
+ .filter((entry) => entry.isDirectory() && existsSync(join(source, entry.name, 'SKILL.md')))
430
+ .map((entry) => entry.name);
431
+
432
+ if (directSkills.length) {
433
+ return Array.from(new Set(directSkills)).sort();
434
+ }
435
+
436
+ return Array.from(new Set(
437
+ entries
438
+ .filter((entry) => entry.isDirectory())
439
+ .flatMap((entry) => {
440
+ const versionPath = join(source, entry.name);
441
+ return readdirSync(versionPath, { withFileTypes: true })
442
+ .filter((skillEntry) => skillEntry.isDirectory() && existsSync(join(versionPath, skillEntry.name, 'SKILL.md')))
443
+ .map((skillEntry) => skillEntry.name);
444
+ }),
445
+ )).sort();
446
+ }
447
+
448
+ function inspectBundledSkillCatalog(rootDir) {
449
+ const names = listBundledSkillNames(rootDir);
450
+ const categories = BUNDLED_SKILL_DOMAIN_GROUPS.map((group) => ({
451
+ key: group.key,
452
+ label: group.label,
453
+ count: group.skills.filter((skill) => names.includes(skill)).length,
454
+ }));
455
+
456
+ return {
457
+ total: names.length,
458
+ names,
459
+ categories,
460
+ };
461
+ }
462
+
463
+ function formatBundledCategoryLine(catalog) {
464
+ if (!catalog?.categories?.length) {
465
+ return 'bundled skills: 0';
466
+ }
467
+
468
+ return catalog.categories
469
+ .filter((category) => category.count > 0)
470
+ .map((category) => `${category.label} ${category.count}`)
471
+ .join(' | ');
472
+ }
473
+
474
+ function resolveCommandArea(action) {
475
+ if (!action) {
476
+ return 'geral';
477
+ }
478
+
479
+ return COMMAND_AREA_LABELS[action.key] ?? 'geral';
480
+ }
481
+
482
+ function formatActionCommand(action) {
483
+ if (!action?.command) {
484
+ return '';
485
+ }
486
+
487
+ return [action.command, ...(action.args ?? [])].join(' ');
488
+ }
489
+
490
+ function resolveNpmCommand(nodeExecPath) {
491
+ if (process.platform !== 'win32') {
492
+ return { command: 'npm', argsPrefix: [], shell: false };
493
+ }
494
+
495
+ const candidates = [
496
+ process.env.npm_execpath,
497
+ join(dirname(nodeExecPath), 'node_modules', 'npm', 'bin', 'npm-cli.js'),
498
+ ].filter(Boolean);
499
+ const npmCli = candidates.find((candidate) => existsSync(candidate));
500
+
501
+ if (npmCli) {
502
+ return { command: nodeExecPath, argsPrefix: [npmCli], shell: false };
503
+ }
504
+
505
+ return { command: 'npm.cmd', argsPrefix: [], shell: true };
506
+ }
507
+
508
+ export function buildMenuCommands({ rootDir, currentFile, nodeExecPath = process.execPath, invocationCwd = process.cwd() }) {
509
+ const isDevCheckout = existsSync(join(rootDir, 'tsconfig.json')) && existsSync(join(rootDir, 'src'));
510
+ const repoOnlyReason = 'Disponivel apenas no clone de desenvolvimento; no pacote npm use Doctor ou Status.';
511
+ const npmCommand = resolveNpmCommand(nodeExecPath);
512
+
513
+ return [
514
+ {
515
+ key: 'status',
516
+ aliases: ['status'],
517
+ label: 'Status local',
518
+ description: 'Mostra versao local, manifesto e informacoes do pacote.',
519
+ details: ['Nao altera arquivos.', 'Use para confirmar se o menu esta lendo a instalacao correta.'],
520
+ success: 'Relatorio impresso com versao, canal, skills globais e clientes configurados.',
521
+ command: nodeExecPath,
522
+ args: [currentFile, '--status'],
523
+ },
524
+ {
525
+ key: 'doctor',
526
+ aliases: ['doctor', 'diagnostico', 'verificar-menu', 'validar-menu'],
527
+ label: 'Doctor do menu e clientes MCP',
528
+ description: 'Valida pacote, binarios, skills globais e registros em Codex, Claude Desktop, Claude Code, Gemini e Antigravity.',
529
+ details: ['Seguro para outros notebooks.', 'Nao publica versao e nao mexe em configuracoes sem uma acao separada.'],
530
+ success: 'Mostra um relatorio GO/NO-GO com proximos comandos recomendados.',
531
+ command: nodeExecPath,
532
+ args: [join(rootDir, 'bin', 'skill-master-doctor.mjs')],
533
+ },
534
+ {
535
+ key: 'check',
536
+ aliases: ['check', 'gate'],
537
+ label: 'Rodar gate completo',
538
+ description: 'Executa build, testes e validacao de manifestos.',
539
+ details: ['Exige clone do repositorio com src, testes e tsconfig.', 'Nao e uma acao indicada para instalacao global via npm.'],
540
+ success: 'Build, testes e manifestos passam no checkout de desenvolvimento.',
541
+ disabledReason: isDevCheckout ? null : repoOnlyReason,
542
+ command: npmCommand.command,
543
+ args: [...npmCommand.argsPrefix, 'run', 'check'],
544
+ shell: npmCommand.shell,
545
+ },
546
+ {
547
+ key: 'build',
548
+ aliases: ['build'],
549
+ label: 'Rodar build',
550
+ description: 'Compila o projeto localmente.',
551
+ details: ['Exige clone do repositorio com tsconfig.', 'Pacotes npm publicados ja usam dist precompilado.'],
552
+ success: 'dist atualizado no checkout de desenvolvimento.',
553
+ disabledReason: isDevCheckout ? null : repoOnlyReason,
554
+ command: npmCommand.command,
555
+ args: [...npmCommand.argsPrefix, 'run', 'build'],
556
+ shell: npmCommand.shell,
557
+ },
558
+ {
559
+ key: 'publicNpm',
560
+ aliases: ['public-npm', 'npm', 'registry'],
561
+ label: 'Validar pacote no npm publico',
562
+ description: 'Consulta a versao publicada em registry.npmjs.org.',
563
+ details: ['Usa somente leitura no registry publico.', 'Bom para confirmar se outro notebook consegue instalar por npm.'],
564
+ success: 'Retorna a versao publicada atualmente no npmjs.',
565
+ command: npmCommand.command,
566
+ args: [
567
+ ...npmCommand.argsPrefix,
568
+ 'view',
569
+ '@fprad0/skill-master-mcp',
570
+ 'version',
571
+ '--registry=https://registry.npmjs.org',
572
+ ],
573
+ shell: npmCommand.shell,
574
+ },
575
+ {
576
+ key: 'updateGlobal',
577
+ aliases: ['update', 'update-global'],
578
+ label: 'Atualizar pacote global via npm',
579
+ description: 'Atualiza a instalacao global e exige reinicio do cliente MCP.',
580
+ details: [
581
+ 'A atualizacao deve ser feita fora do processo MCP stdio.',
582
+ 'Se o menu estiver usando o pacote global no Windows, o fluxo faz handoff seguro em vez de atualizar a pasta em uso.',
583
+ 'Use antes de abrir Codex, Claude, Gemini ou Antigravity.',
584
+ ],
585
+ success: 'Pacote global atualizado para a versao latest do npm publico.',
586
+ command: nodeExecPath,
587
+ args: [join(rootDir, 'bin', 'skill-master-update.mjs')],
588
+ confirmMessage: 'Atualizar o pacote global agora?',
589
+ },
590
+ {
591
+ key: 'privateRegistry',
592
+ aliases: ['private-registry', 'private', 'github-packages'],
593
+ label: 'Configurar registry privado GitHub Packages',
594
+ description: 'Prepara o .npmrc e valida o acesso ao pacote privado.',
595
+ details: ['Uso avancado para ambientes privados.', 'Nao e necessario para o pacote publico do npmjs.'],
596
+ success: '.npmrc configurado e validacao npm view executada.',
597
+ command: nodeExecPath,
598
+ args: ['scripts/configure-private-registry.mjs', '--validate'],
599
+ confirmMessage: 'Rodar a configuracao de registry privado agora?',
600
+ },
601
+ {
602
+ key: 'activationStatus',
603
+ aliases: ['activation-status', 'modo', 'modo-ativacao'],
604
+ label: 'Modo de ativacao atual',
605
+ description: 'Mostra o modo manual, balanced ou always-on-assisted configurado localmente.',
606
+ details: ['Nao altera configuracao.', 'Ajuda a entender quando o Skill Master deve sugerir skills.'],
607
+ success: 'Modo atual e caminho da configuracao impressos no terminal.',
608
+ command: nodeExecPath,
609
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--status'],
610
+ },
611
+ {
612
+ key: 'activationBalanced',
613
+ aliases: ['set-balanced', 'balanced'],
614
+ label: 'Usar modo balanced',
615
+ description: 'Define balanced como modo padrao de ativacao do Skill Master.',
616
+ details: ['Recomendado para uso diario.', 'Ativa o MCP quando ha ganho claro para o prompt.'],
617
+ success: 'Modo balanced salvo localmente.',
618
+ command: nodeExecPath,
619
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--set-mode', 'balanced'],
620
+ },
621
+ {
622
+ key: 'activationAlwaysOn',
623
+ aliases: ['set-always-on', 'always-on-assisted'],
624
+ label: 'Usar modo always-on-assisted',
625
+ description: 'Define avaliacao assistida quase sempre ativa, mantendo no-op quando nao houver ganho.',
626
+ details: ['Mais agressivo que balanced.', 'Indicado para usuarios que querem o Skill Master avaliando quase todos os prompts.'],
627
+ success: 'Modo always-on-assisted salvo localmente.',
628
+ command: nodeExecPath,
629
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--set-mode', 'always-on-assisted'],
630
+ confirmMessage: 'Alterar o modo local para always-on-assisted?',
631
+ },
632
+ {
633
+ key: 'installGlobalSkills',
634
+ aliases: ['install-global-skills', 'skills-globais', 'global-skills'],
635
+ label: 'Instalar skills globais do Skill Master',
636
+ description: 'Copia as skills amplas e morais embutidas para CODEX_HOME/skills ou ~/.codex/skills.',
637
+ details: ['Necessario para Codex descobrir as skills globais.', 'Pode ser reexecutado com seguranca pelo bootstrap.'],
638
+ success: 'Skills globais copiadas para a pasta global do usuario.',
639
+ command: nodeExecPath,
640
+ args: [join(rootDir, 'bin', 'skill-master-install-global-skills.mjs')],
641
+ confirmMessage: 'Instalar as skills globais embutidas neste usuario?',
642
+ },
643
+ {
644
+ key: 'installProjectSkills',
645
+ aliases: ['install-project-skills', 'skills-projeto', 'project-skills', 'agents-skills'],
646
+ label: 'Instalar skills no projeto atual',
647
+ description: 'Copia o bundle para .agents/skills, .codex/skills, .claude/skills e .gemini/skills do projeto onde o menu foi aberto.',
648
+ details: ['Registra .skill-master/catalog.json e metadados em package.json quando existir.', `Projeto alvo: ${invocationCwd}`],
649
+ success: 'Skills de projeto copiadas e catalogo local atualizado.',
650
+ command: nodeExecPath,
651
+ args: [join(rootDir, 'bin', 'skill-master-install-project-skills.mjs'), '--project-root', invocationCwd, '--sync-package-json'],
652
+ cwd: invocationCwd,
653
+ confirmMessage: 'Instalar e catalogar as skills do Skill Master no projeto atual?',
654
+ },
655
+ {
656
+ key: 'bootstrapGlobal',
657
+ aliases: ['bootstrap-global', 'global-bootstrap', 'ativar-global-completo'],
658
+ label: 'Ativar MCP global neste computador',
659
+ description: 'Instala skills globais e registra Codex, Claude, Gemini e Antigravity no mesmo passo.',
660
+ details: ['Acao principal para notebooks novos.', 'Depois reinicie os clientes para eles recarregarem MCP e skills.'],
661
+ success: 'Skills instaladas e configuracoes MCP aplicadas nos clientes encontrados.',
662
+ command: nodeExecPath,
663
+ args: [join(rootDir, 'bin', 'skill-master-bootstrap-global.mjs')],
664
+ confirmMessage: 'Executar o bootstrap global do Skill Master neste computador?',
665
+ },
666
+ {
667
+ key: 'registerClients',
668
+ aliases: ['register-clients', 'registrar-clientes', 'codex-claude-gemini', 'antigravity'],
669
+ label: 'Registrar clientes MCP',
670
+ description: 'Gera/aplica configuracoes MCP para Codex, Claude Desktop, Claude Code, Gemini e Antigravity reconhecerem skill_master.',
671
+ details: ['Usa Node absoluto e o entrypoint absoluto do pacote.', 'Claude Code e registrado via claude mcp add quando o CLI esta disponivel.'],
672
+ success: 'Arquivos de configuracao mesclados com o servidor skill_master.',
673
+ command: nodeExecPath,
674
+ args: [join(rootDir, 'bin', 'skill-master-register-clients.mjs'), '--apply-all'],
675
+ confirmMessage: 'Aplicar registro do skill_master em Codex, Claude, Gemini e Antigravity?',
676
+ },
677
+ {
678
+ key: 'promptRecommendation',
679
+ aliases: ['recommend-prompt', 'recomendar-prompt', 'prompt-router'],
680
+ label: 'Ver recomendacao para um prompt',
681
+ description: 'Abre um fluxo interativo para avaliar um prompt pelo router local.',
682
+ details: ['Ajuda a decidir se skill-master, skill_master ou skill-master-mcp deve agir.', 'Nao publica nem altera skills.'],
683
+ success: 'Router imprime recomendacao, modo de ativacao e gates aplicaveis.',
684
+ command: nodeExecPath,
685
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--route-prompt-interactive'],
686
+ },
687
+ {
688
+ key: 'successNotifications',
689
+ aliases: ['notifications', 'notificacoes', 'success-notifications'],
690
+ label: 'Notificacoes de skills aprendidas',
691
+ description: 'Mostra drafts pendentes, aprovacoes e skills externas para estudar.',
692
+ details: ['Use para decidir o que aprovar, estudar ou rejeitar.', 'Nao ativa skill automaticamente.'],
693
+ success: 'Lista de pendencias e proximas acoes exibida.',
694
+ command: nodeExecPath,
695
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--notify'],
696
+ },
697
+ {
698
+ key: 'studySkills',
699
+ aliases: ['study-skills', 'skills-estudo', 'estudar'],
700
+ label: 'Skills para estudar',
701
+ description: 'Lista skills externas e links de criadores ainda nao aprovados.',
702
+ details: ['Material de estudo, nao ativacao operacional.', 'Bom para revisao humana antes de virar skill local/global.'],
703
+ success: 'Links e motivos de estudo exibidos.',
704
+ command: nodeExecPath,
705
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--study'],
706
+ },
707
+ {
708
+ key: 'approvalPackage',
709
+ aliases: ['approval-package', 'aprovar', 'pacote-aprovacao'],
710
+ label: 'Gerar pacote de aprovacao humana',
711
+ description: 'Cria um relatorio local para revisar e aprovar skills aprendidas.',
712
+ details: ['Exige decisao humana antes de ativacao.', 'Inclui riscos, evidencias e recomendacao.'],
713
+ success: 'Pacote local de aprovacao gerado.',
714
+ command: nodeExecPath,
715
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--approval-package'],
716
+ },
717
+ {
718
+ key: 'markLearnedStudy',
719
+ aliases: ['mark-study', 'manter-estudo'],
720
+ label: 'Manter skill candidata para estudo',
721
+ description: 'Seleciona uma candidata e registra decisao de manter para estudo.',
722
+ details: ['Preserva historico sem ativar a skill.', 'Use quando a fonte ainda precisa revisao.'],
723
+ success: 'Decisao registrada no historico local.',
724
+ command: nodeExecPath,
725
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--mark-study-interactive'],
726
+ },
727
+ {
728
+ key: 'rejectLearnedSkill',
729
+ aliases: ['reject-skill', 'rejeitar-skill'],
730
+ label: 'Rejeitar skill candidata',
731
+ description: 'Seleciona uma candidata, registra rejeicao e preserva historico.',
732
+ details: ['Nao apaga evidencias.', 'Use quando risco, fonte ou utilidade nao passam no gate.'],
733
+ success: 'Rejeicao registrada com motivo.',
734
+ command: nodeExecPath,
735
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--reject-interactive'],
736
+ confirmMessage: 'Abrir fluxo para rejeitar uma skill candidata?',
737
+ },
738
+ {
739
+ key: 'activateLearnedLocal',
740
+ aliases: ['activate-learned-local', 'ativar-local', 'skill-local'],
741
+ label: 'Ativar skill aprendida no workspace',
742
+ description: 'Instala uma skill aprendida em .codex/skills do projeto atual.',
743
+ details: ['Escopo limitado ao workspace.', 'Mais conservador que ativar globalmente.'],
744
+ success: 'Skill copiada para .codex/skills do projeto.',
745
+ command: nodeExecPath,
746
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--activate-interactive', '--target', 'local'],
747
+ confirmMessage: 'Selecionar e ativar uma skill aprendida no workspace atual?',
748
+ },
749
+ {
750
+ key: 'activateLearnedGlobal',
751
+ aliases: ['activate-learned-global', 'ativar-global', 'skill-global'],
752
+ label: 'Ativar skill aprendida global',
753
+ description: 'Instala uma skill aprendida em CODEX_HOME/skills ou ~/.codex/skills.',
754
+ details: ['Afeta todos os projetos deste usuario.', 'Use apenas depois de aprovacao humana.'],
755
+ success: 'Skill instalada no diretorio global de skills.',
756
+ command: nodeExecPath,
757
+ args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--activate-interactive', '--target', 'global'],
758
+ confirmMessage: 'Selecionar e ativar uma skill aprendida como skill global deste usuario?',
759
+ },
760
+ {
761
+ key: 'notionSummary',
762
+ aliases: ['notion-summary', 'resumo-notion'],
763
+ label: 'Abrir resumo para Notion',
764
+ description: 'Mostra um resumo copiavel do estado de ativacao para registrar no ledger Notion.',
765
+ details: ['Nao escreve no Notion sozinho.', 'Gera texto de continuidade para documentacao.'],
766
+ success: 'Resumo pronto para registro exibido.',
767
+ command: nodeExecPath,
768
+ args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--notion-summary'],
769
+ },
770
+ ];
771
+ }
772
+
773
+ export function buildMenuChoices(commands) {
774
+ return commands.map((command) => ({
775
+ title: command.label,
776
+ description: [command.description, command.success ? `Resultado: ${command.success}` : null].filter(Boolean).join(' '),
777
+ value: command.key,
778
+ disabled: command.disabledReason ?? false,
779
+ })).concat({
780
+ title: 'Sair',
781
+ description: 'Fecha o menu operacional.',
782
+ value: '__exit__',
783
+ });
784
+ }
785
+
786
+ export function resolveInitialSelectedIndex(status, commands) {
787
+ if (!status?.globalReadiness?.ready) {
788
+ const bootstrapIndex = commands.findIndex((command) => command.key === 'bootstrapGlobal');
789
+ if (bootstrapIndex >= 0) return bootstrapIndex;
790
+ }
791
+ return 0;
792
+ }
793
+
794
+ export function resolveActionKey(input, commands) {
795
+ const normalized = (input ?? '').trim().toLowerCase();
796
+ if (!normalized) {
797
+ return null;
798
+ }
799
+
800
+ return commands.find((command) =>
801
+ command.key.toLowerCase() === normalized || command.aliases.includes(normalized),
802
+ )?.key ?? null;
803
+ }
804
+
805
+ export function isInteractiveTerminal() {
806
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
807
+ }
808
+
809
+ export function formatStatusReport(status) {
810
+ const readiness = status.globalReadiness;
811
+ const bundledCatalog = status.bundledCatalog ?? { total: 0, categories: [] };
812
+ const lines = [
813
+ 'Skill Master MCP - status local',
814
+ `Diretorio: ${status.rootDir}`,
815
+ `Pacote: ${status.packageName}`,
816
+ `Semver local: ${status.semver}`,
817
+ `Manifesto stable: ${status.manifestVersion}`,
818
+ `Manifesto semver: ${status.manifestSemver}`,
819
+ `Drafts de skills aprendidas: ${status.pendingSuccessDrafts}`,
820
+ `Skills externas para estudar: ${status.studyCandidates}`,
821
+ `Global readiness: ${readiness.ready ? 'pronto' : readiness.mode}`,
822
+ `Global skills instaladas: ${readiness.installed.length}/${readiness.required}`,
823
+ `Bundle de skills embutidas: ${bundledCatalog.total}`,
824
+ `Dominios do bundle: ${formatBundledCategoryLine(bundledCatalog)}`,
825
+ `Codex MCP robusto: ${readiness.codex.globalCommand ? 'sim' : readiness.codex.kind}`,
826
+ `Claude MCP robusto: ${readiness.claude.globalCommand ? 'sim' : readiness.claude.present ? readiness.claude.kind : 'ausente'}`,
827
+ `Gemini MCP robusto: ${readiness.gemini.globalCommand ? 'sim' : readiness.gemini.present ? readiness.gemini.kind : 'ausente'}`,
828
+ `Antigravity MCP robusto: ${readiness.antigravity.globalCommand ? 'sim' : readiness.antigravity.present ? readiness.antigravity.kind : 'ausente'}`,
829
+ ];
830
+
831
+ if (status.versionText) {
832
+ lines.push('', 'VERSION.md:');
833
+ lines.push(...status.versionText.split('\n').slice(0, 6));
834
+ }
835
+
836
+ return lines.join('\n');
837
+ }
838
+
839
+ function formatGlobalAlert(status, { useColor = false } = {}) {
840
+ const readiness = status.globalReadiness;
841
+ if (readiness.ready) {
842
+ return renderPanelLines(
843
+ [
844
+ colorize('GLOBAL READY', ANSI.bold, useColor),
845
+ 'O MCP esta registrado com Node absoluto neste computador.',
846
+ 'Codex, Claude Desktop, Claude Code, Gemini e Antigravity podem iniciar o servidor sem depender do PATH.',
847
+ 'A instalacao global e as skills embutidas ja estao prontas para uso.',
848
+ ],
849
+ { color: ANSI.green, useColor },
850
+ );
851
+ }
852
+
853
+ return [
854
+ renderPanelLines(
855
+ [
856
+ colorize('ALERTA GLOBAL', ANSI.bold, useColor),
857
+ 'Este computador ainda nao esta pronto para uso robusto do Skill Master.',
858
+ 'Execute agora: skill-master-menu --run bootstrap-global --yes',
859
+ 'Isso instala as skills globais e registra Codex, Claude Desktop, Claude Code, Gemini e Antigravity com Node absoluto.',
860
+ 'Ou migre somente os clientes: skill-master-register-clients --apply-all --force',
861
+ ],
862
+ { color: ANSI.red, useColor },
863
+ ),
864
+ renderPanelLines(
865
+ [
866
+ colorize('AVISO SUTIL', ANSI.dim, useColor),
867
+ 'Sem instalacao global, o MCP continua util localmente, mas nao fica integrado como parte do sistema em todos os clientes.',
868
+ `Skills globais detectadas: ${readiness.installed.length}/${readiness.required}`,
869
+ ],
870
+ { color: ANSI.yellow, useColor },
871
+ ),
872
+ ].join('\n\n');
873
+ }
874
+
875
+ function renderPanelLines(lines, { color = ANSI.cyan, useColor = false } = {}) {
876
+ const width = Math.max(...lines.map((line) => visibleLength(line)), 24) + 4;
877
+ return renderCyberFrame(
878
+ lines.map((line) => fitText(line, width - 4)),
879
+ width,
880
+ 'skill-master',
881
+ { color, useColor, style: 'data' },
882
+ ).join('\n');
883
+ }
884
+
885
+ function patternFill(pattern, width) {
886
+ if (width <= 0) return '';
887
+ return Array.from({ length: Math.ceil(width / pattern.length) }, () => pattern).join('').slice(0, width);
888
+ }
889
+
890
+ function frameTokens(style) {
891
+ if (style === 'focus') {
892
+ return { topLeft: '╭╼', topRight: '╾╮', bottomLeft: '╰╼', bottomRight: '╾╯', fill: '═', left: '▌ ', right: ' ', accent: '▰', micro: '▱' };
893
+ }
894
+ if (style === 'hud') {
895
+ return { topLeft: '┏╾', topRight: '╼┓', bottomLeft: '┗╾', bottomRight: '╼┛', fill: '─', left: '', right: '', accent: '', micro: '▱' };
896
+ }
897
+ if (style === 'running') {
898
+ return { topLeft: '╔╼', topRight: '╾╗', bottomLeft: '╚╼', bottomRight: '╾╝', fill: '', left: '▌▌', right: '▐▐', accent: '▰', micro: '▱' };
899
+ }
900
+ if (style === 'thin') {
901
+ return { topLeft: '┌╴', topRight: '╶┐', bottomLeft: '└╴', bottomRight: '╶┘', fill: '─', left: '│ ', right: ' │', accent: '▱', micro: '╍' };
902
+ }
903
+ return { topLeft: '╭╴', topRight: '╶╮', bottomLeft: '╰╴', bottomRight: '╶╯', fill: '─', left: '│ ', right: ' │', accent: '▰', micro: '▱' };
904
+ }
905
+
906
+ function fillWithPattern(text, width, fill) {
907
+ const length = visibleLength(text);
908
+ if (length >= width) return fitText(text, width);
909
+ return `${text}${patternFill(fill, width - length)}`;
910
+ }
911
+
912
+ function renderCyberRail(width, title, tokens, { bottom = false, tick = 0 } = {}) {
913
+ const left = bottom ? tokens.bottomLeft : tokens.topLeft;
914
+ const right = bottom ? tokens.bottomRight : tokens.topRight;
915
+ const innerWidth = Math.max(0, width - visibleLength(left) - visibleLength(right));
916
+ const phaseMicro = tick % 2 === 0 ? tokens.micro : tokens.fill;
917
+ const titleText = !bottom && title ? ` ${String(title).toUpperCase()} ` : '';
918
+ const titleWidth = titleText ? Math.min(visibleLength(titleText), Math.max(0, innerWidth - 8)) : 0;
919
+ const safeTitle = titleText ? fitText(titleText, titleWidth).trimEnd() : '';
920
+
921
+ if (bottom) {
922
+ const lead = patternFill(tokens.fill, Math.max(2, Math.floor(innerWidth * 0.18)));
923
+ const plate = innerWidth >= 34 ? `${tokens.accent}${tokens.accent}${tokens.accent}` : tokens.accent;
924
+ const vent = innerWidth >= 44 ? patternFill(`${phaseMicro}${tokens.fill}`, 8) : '';
925
+ return `${left}${fillWithPattern(`${lead}${plate}${tokens.fill}${vent}`, innerWidth, tokens.fill)}${right}`;
926
+ }
927
+
928
+ const leadWidth = Math.max(2, Math.min(10, Math.floor(innerWidth * 0.16)));
929
+ const lead = patternFill(tokens.fill, leadWidth);
930
+ const chip = innerWidth >= 36 ? `${tokens.accent}${phaseMicro}${phaseMicro}` : tokens.accent;
931
+ const tab = innerWidth >= 48 ? `${tokens.fill}${tokens.fill}${tokens.accent}${tokens.fill}` : tokens.fill;
932
+ return `${left}${fillWithPattern(`${lead}${safeTitle}${chip}${tab}`, innerWidth, tokens.fill)}${right}`;
933
+ }
934
+
935
+ function renderCyberFrame(lines, width, title, { useColor = false, color = ANSI.cyan, style = 'data', tick = 0 } = {}) {
936
+ const safeWidth = Math.max(16, width);
937
+ const innerWidth = safeWidth - 4;
938
+ const tokens = frameTokens(style);
939
+ const top = renderCyberRail(safeWidth, title, tokens, { tick });
940
+ const bottom = renderCyberRail(safeWidth, title, tokens, { bottom: true, tick });
941
+ const body = lines.map((line, index) => {
942
+ const marker = style === 'running' && index % 3 === Math.abs(tick % 3)
943
+ ? tokens.accent
944
+ : index === 0 || index === lines.length - 1
945
+ ? tokens.micro
946
+ : ' ';
947
+ const content = fitText(`${marker}${truncateVisibleText(line, Math.max(0, innerWidth - 1))}`, innerWidth);
948
+ return `${colorize(tokens.left, color, useColor)}${content}${colorize(tokens.right, color, useColor)}`;
949
+ });
950
+
951
+ return [
952
+ colorize(top, color, useColor),
953
+ ...body,
954
+ colorize(bottom, color, useColor),
955
+ ];
956
+ }
957
+
958
+ function renderCircuitRail(width, tick, { useColor = false, color = ANSI.teal } = {}) {
959
+ const patterns = ['<==/==>--', '<=/===/>-', '<<==--==>', '<==\\==>--'];
960
+ return colorize(patternFill(patterns[Math.abs(tick) % patterns.length], width), color, useColor);
961
+ }
962
+
963
+ function renderScanGrid(width, height, tick, { useColor = false } = {}) {
964
+ const lines = [];
965
+ const scanCol = width > 0 ? tick % width : 0;
966
+ const scanRow = height > 0 ? Math.floor(tick / 2) % height : 0;
967
+
968
+ for (let row = 0; row < height; row += 1) {
969
+ const cells = Array.from({ length: width }, (_, col) => {
970
+ if (row === scanRow && col % 3 === 0) return colorize('-', ANSI.white, useColor);
971
+ if (col === scanCol && row % 2 === 0) return colorize('|', ANSI.teal, useColor);
972
+ if ((row + col + tick) % 17 === 0) return colorize('+', ANSI.amber, useColor);
973
+ if (row % 4 === 0 && col % 8 === 0) return colorize('.', ANSI.gray, useColor);
974
+ return ' ';
975
+ });
976
+ lines.push(cells.join(''));
977
+ }
978
+
979
+ return lines;
980
+ }
981
+
982
+ const BRAILLE_DOTS = [
983
+ [0x01, 0x02, 0x04, 0x40],
984
+ [0x08, 0x10, 0x20, 0x80],
985
+ ];
986
+
987
+ function createBrailleCanvas(width, height) {
988
+ return {
989
+ width,
990
+ height,
991
+ dots: Array.from({ length: height }, () => Array.from({ length: width }, () => 0)),
992
+ colors: Array.from({ length: height }, () => Array.from({ length: width }, () => 'gray')),
993
+ priorities: Array.from({ length: height }, () => Array.from({ length: width }, () => -1)),
994
+ };
995
+ }
996
+
997
+ function plotBraille(canvas, x, y, color = 'gray', priority = 0) {
998
+ if (x < 0 || y < 0) return;
999
+ const cellX = Math.floor(x / 2);
1000
+ const cellY = Math.floor(y / 4);
1001
+ if (cellX < 0 || cellY < 0 || cellX >= canvas.width || cellY >= canvas.height) return;
1002
+ canvas.dots[cellY][cellX] |= BRAILLE_DOTS[x % 2][y % 4];
1003
+ if (priority >= canvas.priorities[cellY][cellX]) {
1004
+ canvas.colors[cellY][cellX] = color;
1005
+ canvas.priorities[cellY][cellX] = priority;
1006
+ }
1007
+ }
1008
+
1009
+ function plotBrailleThick(canvas, x, y, radius = 0, color = 'gray', priority = 0) {
1010
+ for (let dy = -radius; dy <= radius; dy += 1) {
1011
+ for (let dx = -radius; dx <= radius; dx += 1) {
1012
+ if (Math.abs(dx) + Math.abs(dy) <= radius + 1) {
1013
+ plotBraille(canvas, x + dx, y + dy, color, priority);
1014
+ }
1015
+ }
1016
+ }
1017
+ }
1018
+
1019
+ function drawBrailleLine(canvas, x0, y0, x1, y1, thickness = 0, color = 'gray', priority = 0) {
1020
+ const steps = Math.max(Math.abs(x1 - x0), Math.abs(y1 - y0), 1);
1021
+ for (let step = 0; step <= steps; step += 1) {
1022
+ const ratio = step / steps;
1023
+ const x = Math.round(x0 + (x1 - x0) * ratio);
1024
+ const y = Math.round(y0 + (y1 - y0) * ratio);
1025
+ plotBrailleThick(canvas, x, y, thickness, color, priority);
1026
+ }
1027
+ }
1028
+
1029
+ function renderBrailleCanvas(canvas, { useColor = false } = {}) {
1030
+ return canvas.dots.map((row, rowIndex) => row.map((value, colIndex) => {
1031
+ if (value === 0) return ' ';
1032
+ const color = ANSI[canvas.colors[rowIndex][colIndex]] ?? ANSI.teal;
1033
+ return colorize(String.fromCodePoint(0x2800 + value), color, useColor);
1034
+ }).join(''));
1035
+ }
1036
+
1037
+ function renderStatusCapsule(label, value, width, { useColor = false, color = ANSI.teal } = {}) {
1038
+ return fitText(`${colorize(`[${label}]`, color, useColor)} ${value}`, width);
1039
+ }
1040
+
1041
+ function summarizeClientReadiness(globalReadiness) {
1042
+ const states = [
1043
+ ['cx', globalReadiness?.codex?.globalCommand],
1044
+ ['cl', globalReadiness?.claude?.globalCommand],
1045
+ ['gm', globalReadiness?.gemini?.globalCommand],
1046
+ ['ag', globalReadiness?.antigravity?.globalCommand],
1047
+ ];
1048
+
1049
+ return states
1050
+ .map(([label, ready]) => `${label}${ready ? '+' : '-'}`)
1051
+ .join(' ');
1052
+ }
1053
+
1054
+ export function formatMenuBanner(status, { useColor = false } = {}) {
1055
+ const bundledCatalog = status.bundledCatalog ?? { total: 0, categories: [] };
1056
+ const lines = [
1057
+ colorize('Skill Master MCP', ANSI.bold, useColor),
1058
+ 'Menu operacional para manutencao local',
1059
+ `Versao local ${status.semver} | canal ${status.manifestVersion}`,
1060
+ `Pendencias: ${status.pendingSuccessDrafts} drafts | estudo: ${status.studyCandidates} links`,
1061
+ `Global: ${status.globalReadiness.ready ? 'pronto' : 'requer instalacao global'}`,
1062
+ `Bundle: ${bundledCatalog.total} skills | ${formatBundledCategoryLine(bundledCatalog)}`,
1063
+ colorize('Setas + Enter para navegar', ANSI.dim, useColor),
1064
+ ];
1065
+ return [
1066
+ renderPanelLines(lines, { color: ANSI.cyan, useColor }),
1067
+ formatGlobalAlert(status, { useColor }),
1068
+ ].join('\n\n');
1069
+ }
1070
+
1071
+ function dnaPanelLines(tick, width, height, status, selected, { useColor = false, compact = false } = {}) {
1072
+ const lines = [];
1073
+ const canvasWidth = Math.max(18, width);
1074
+ const canvasHeight = Math.max(compact ? 8 : 10, height - 4);
1075
+ const pixelWidth = canvasWidth * 2;
1076
+ const pixelHeight = canvasHeight * 4;
1077
+ const center = Math.floor(pixelWidth / 2);
1078
+ const amplitude = Math.max(8, Math.min(Math.floor(pixelWidth * 0.24), compact ? 12 : 18));
1079
+ const frameCount = 48;
1080
+ const frameRatio = (tick % frameCount) / frameCount;
1081
+ const phase = frameRatio * Math.PI * 2;
1082
+ const scanPhase = (1 - Math.cos(frameRatio * Math.PI * 2)) / 2;
1083
+ const pairEvery = compact ? 9 : 7;
1084
+ const actionArea = resolveCommandArea(selected);
1085
+ const canvas = createBrailleCanvas(canvasWidth, canvasHeight);
1086
+
1087
+ lines.push(fitText(colorize(`DNA CYBER HELIX / ${actionArea}`, ANSI.bold, useColor), width));
1088
+ lines.push(fitText(colorize(compact ? 'dual strand / focus' : 'dense helix / low flicker', ANSI.dim, useColor), width));
1089
+
1090
+ const twist = compact ? 0.17 : 0.155;
1091
+ const xA = (y) => Math.round(center + Math.sin(y * twist + phase) * amplitude);
1092
+ const xB = (y) => Math.round(center - Math.sin(y * twist + phase) * amplitude);
1093
+ const frontA = (y) => Math.cos(y * twist + phase) >= 0;
1094
+ const scanY = Math.floor(scanPhase * Math.max(1, pixelHeight - 1));
1095
+ const pulse = 0.82 + ((Math.sin(phase * 2) + 1) / 2) * 0.28;
1096
+
1097
+ for (let y = 0; y < pixelHeight; y += 8) {
1098
+ plotBrailleThick(canvas, center, y, 0, 'gray', 0);
1099
+ }
1100
+
1101
+ for (let y = 0; y < pixelHeight; y += 1) {
1102
+ if (y % 10 === 0) {
1103
+ for (let x = 2; x < pixelWidth - 2; x += 10) {
1104
+ plotBraille(canvas, x, y, 'gray', 0);
1105
+ }
1106
+ }
1107
+
1108
+ const a = xA(y);
1109
+ const b = xB(y);
1110
+ const previousA = xA(Math.max(0, y - 1));
1111
+ const previousB = xB(Math.max(0, y - 1));
1112
+ const active = Math.abs(y - scanY) <= 2;
1113
+ const nearA = frontA(y);
1114
+ const wave = y * twist + phase;
1115
+ const depthA = (Math.cos(wave) + 1) / 2;
1116
+ const depthB = 1 - depthA;
1117
+ const strandAWidth = Math.max(1, Math.round((compact ? 1 : 2) + depthA * 2 * pulse));
1118
+ const strandBWidth = Math.max(1, Math.round((compact ? 1 : 2) + depthB * 2 * pulse));
1119
+ const edgeSpread = compact ? 2 : 3;
1120
+ const strandAColor = active ? 'white' : nearA ? 'rose' : 'violet';
1121
+ const strandBColor = active ? 'white' : nearA ? 'teal' : 'blue';
1122
+ const strandAPriority = active ? 7 : nearA ? 5 : 3;
1123
+ const strandBPriority = active ? 7 : nearA ? 3 : 5;
1124
+
1125
+ if (y > 0) {
1126
+ drawBrailleLine(canvas, previousA - edgeSpread, y - 1, a - edgeSpread, y, 0, nearA ? 'gray' : 'blue', 1);
1127
+ drawBrailleLine(canvas, previousA + edgeSpread, y - 1, a + edgeSpread, y, 0, nearA ? 'gray' : 'blue', 1);
1128
+ drawBrailleLine(canvas, previousB - edgeSpread, y - 1, b - edgeSpread, y, 0, nearA ? 'blue' : 'gray', 1);
1129
+ drawBrailleLine(canvas, previousB + edgeSpread, y - 1, b + edgeSpread, y, 0, nearA ? 'blue' : 'gray', 1);
1130
+ drawBrailleLine(canvas, previousA, y - 1, a, y, strandAWidth, strandAColor, strandAPriority);
1131
+ drawBrailleLine(canvas, previousB, y - 1, b, y, strandBWidth, strandBColor, strandBPriority);
1132
+ } else {
1133
+ plotBrailleThick(canvas, a - edgeSpread, y, 0, nearA ? 'gray' : 'blue', 1);
1134
+ plotBrailleThick(canvas, a + edgeSpread, y, 0, nearA ? 'gray' : 'blue', 1);
1135
+ plotBrailleThick(canvas, b - edgeSpread, y, 0, nearA ? 'blue' : 'gray', 1);
1136
+ plotBrailleThick(canvas, b + edgeSpread, y, 0, nearA ? 'blue' : 'gray', 1);
1137
+ plotBrailleThick(canvas, a, y, strandAWidth, strandAColor, strandAPriority);
1138
+ plotBrailleThick(canvas, b, y, strandBWidth, strandBColor, strandBPriority);
1139
+ }
1140
+
1141
+ if ((y + tick) % pairEvery === 0 || active) {
1142
+ const left = Math.min(a, b);
1143
+ const right = Math.max(a, b);
1144
+ const rungColor = active ? 'white' : nearA ? 'teal' : 'rose';
1145
+ const rungPriority = active ? 6 : 4;
1146
+ drawBrailleLine(canvas, left + 3, y, right - 3, y, active ? 1 : 0, rungColor, rungPriority);
1147
+ for (let x = left + 3; x < right - 2; x += active ? 2 : 3) {
1148
+ plotBrailleThick(canvas, x, y, active ? 1 : 0, rungColor, rungPriority);
1149
+ }
1150
+ plotBrailleThick(canvas, Math.round((left + right) / 2), y, active ? 1 : 0, active ? 'white' : 'amber', rungPriority + 1);
1151
+ plotBrailleThick(canvas, a, y, active ? 1 : 0, strandAColor, strandAPriority + 1);
1152
+ plotBrailleThick(canvas, b, y, active ? 1 : 0, strandBColor, strandBPriority + 1);
1153
+ }
1154
+ }
1155
+
1156
+ for (const line of renderBrailleCanvas(canvas, { useColor })) {
1157
+ lines.push(line);
1158
+ }
1159
+
1160
+ lines.push(renderStatusCapsule('HELIX', `frames ${tick % frameCount}/${frameCount} | global ${status.globalReadiness.installed.length}/${status.globalReadiness.required}`, width, { useColor, color: ANSI.amber }));
1161
+
1162
+ return lines.slice(0, height).map((line) => fitText(line, width));
1163
+ }
1164
+
1165
+ function renderMeterBar(value, total, width, { useColor = false, color = ANSI.teal } = {}) {
1166
+ const safeTotal = Math.max(1, total);
1167
+ const safeValue = Math.max(0, Math.min(value, safeTotal));
1168
+ const fill = Math.round((safeValue / safeTotal) * width);
1169
+ const filled = '█'.repeat(fill);
1170
+ const empty = '░'.repeat(Math.max(0, width - fill));
1171
+ return `${colorize(filled, color, useColor)}${colorize(empty, ANSI.gray, useColor)}`;
1172
+ }
1173
+
1174
+ function renderSparkline(series, { useColor = false, color = ANSI.teal } = {}) {
1175
+ const blocks = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
1176
+ return series.map((value) => colorize(blocks[Math.max(0, Math.min(blocks.length - 1, value))], color, useColor)).join('');
1177
+ }
1178
+
1179
+ function buildTelemetrySeries(seed, length, tick) {
1180
+ return Array.from({ length }, (_, index) => {
1181
+ const raw = Math.sin((index + 1 + seed) * 0.72 + tick * 0.18) + Math.cos((index + seed) * 0.33 + tick * 0.11);
1182
+ const normalized = Math.max(0, Math.min(1, (raw + 2) / 4));
1183
+ return Math.round(normalized * 7);
1184
+ });
1185
+ }
1186
+
1187
+ function buildOverviewSignalLine(status, width, tick, { useColor = false, compact = false } = {}) {
1188
+ const signalWidth = Math.max(6, Math.min(compact ? 8 : 12, Math.floor(width / (compact ? 10 : 8))));
1189
+ const healthWidth = Math.max(6, Math.min(compact ? 8 : 12, Math.floor(width / (compact ? 10 : 8))));
1190
+ const signal = renderSparkline(
1191
+ buildTelemetrySeries(status.globalReadiness.installed.length + status.pendingSuccessDrafts, signalWidth, tick),
1192
+ { useColor, color: ANSI.teal },
1193
+ );
1194
+ const health = renderSparkline(
1195
+ buildTelemetrySeries(status.studyCandidates + (status.globalReadiness.ready ? 7 : 3), healthWidth, tick + 3),
1196
+ { useColor, color: ANSI.amber },
1197
+ );
1198
+ return compact
1199
+ ? `signal ${signal} health ${health}`
1200
+ : `signal ${signal} health ${health}`;
1201
+ }
1202
+
1203
+ function telemetryPanelLines(status, selected, width, height, { useColor = false, tick = 0, compact = false } = {}) {
1204
+ const commandArea = resolveCommandArea(selected);
1205
+ const bundledCatalog = status.bundledCatalog ?? { total: 0, categories: [] };
1206
+ const categoryLead = bundledCatalog.categories
1207
+ ?.filter((category) => category.count > 0)
1208
+ .sort((left, right) => right.count - left.count)[0];
1209
+ const categoryName = categoryLead?.label ?? 'none';
1210
+ const categoryCount = categoryLead?.count ?? 0;
1211
+ const meterWidth = Math.max(8, Math.min(16, width - 14));
1212
+ const sparkWidth = Math.max(8, Math.min(compact ? 8 : 12, width - 18));
1213
+ const skillsSpark = renderSparkline(buildTelemetrySeries(status.globalReadiness.installed.length + categoryCount, sparkWidth, tick), { useColor, color: ANSI.amber });
1214
+ const draftsSpark = renderSparkline(buildTelemetrySeries(status.pendingSuccessDrafts + 2, sparkWidth, tick + 2), { useColor, color: ANSI.teal });
1215
+ const studySpark = renderSparkline(buildTelemetrySeries(status.studyCandidates + 4, sparkWidth, tick + 4), { useColor, color: ANSI.blue });
1216
+ const lines = [
1217
+ fitText(colorize('SYSTEM WINDOWS', ANSI.bold, useColor), width),
1218
+ renderStatusCapsule('AREA', commandArea, width, { useColor, color: ANSI.blue }),
1219
+ renderStatusCapsule('LEAD', `${categoryName} ${categoryCount}`, width, { useColor, color: ANSI.gray }),
1220
+ fitText(`bundle ${String(bundledCatalog.total).padStart(2, '0')} ${renderMeterBar(bundledCatalog.total, Math.max(36, bundledCatalog.total), meterWidth, { useColor, color: ANSI.white })}`, width),
1221
+ fitText(`global ${status.globalReadiness.installed.length}/${status.globalReadiness.required} ${renderMeterBar(status.globalReadiness.installed.length, status.globalReadiness.required, meterWidth, { useColor, color: ANSI.amber })}`, width),
1222
+ renderStatusCapsule('LINK', summarizeClientReadiness(status.globalReadiness), width, { useColor, color: ANSI.teal }),
1223
+ fitText(`skills ${skillsSpark}`, width),
1224
+ fitText(`drafts ${String(status.pendingSuccessDrafts).padStart(2, '0')} ${renderMeterBar(status.pendingSuccessDrafts, Math.max(6, status.pendingSuccessDrafts || 1), meterWidth, { useColor, color: ANSI.teal })}`, width),
1225
+ fitText(`queue ${draftsSpark}`, width),
1226
+ fitText(`study ${String(status.studyCandidates).padStart(2, '0')} ${renderMeterBar(status.studyCandidates, Math.max(8, status.studyCandidates || 1), meterWidth, { useColor, color: ANSI.blue })}`, width),
1227
+ fitText(`links ${studySpark}`, width),
1228
+ fitText(colorize(compact ? 'codex / claude / gemini' : 'codex / claude / gemini / antigravity', ANSI.dim, useColor), width),
1229
+ ];
1230
+
1231
+ return lines.slice(0, height).map((line) => fitText(line, width));
1232
+ }
1233
+
1234
+ function cyberCorePanelLines(status, selected, width, height, { useColor = false, tick = 0, compact = false } = {}) {
1235
+ const actionArea = resolveCommandArea(selected);
1236
+ const gridHeight = Math.max(compact ? 4 : 6, height - (compact ? 5 : 6));
1237
+ const gridWidth = Math.max(12, width);
1238
+ const lines = [
1239
+ fitText(colorize('SKILL_MASTER CORE', ANSI.bold, useColor), width),
1240
+ fitText(colorize(compact ? 'cyber lattice / low flicker' : 'cyberpunk pixel art workflow engine', ANSI.dim, useColor), width),
1241
+ fitText(colorize(`area ${actionArea} | tick ${String(tick).padStart(3, '0')}`, ANSI.gray, useColor), width),
1242
+ fitText(renderCircuitRail(width, tick, { useColor, color: ANSI.teal }), width),
1243
+ ...renderScanGrid(gridWidth, gridHeight, tick, { useColor }).map((line) => fitText(line, width)),
1244
+ fitText(renderCircuitRail(width, tick + 2, { useColor, color: ANSI.amber }), width),
1245
+ fitText(colorize(`global ${status.globalReadiness.installed.length}/${status.globalReadiness.required} | bundle ${status.bundledCatalog?.total ?? 0}`, ANSI.gray, useColor), width),
1246
+ ];
1247
+
1248
+ return lines.slice(0, height).map((line) => fitText(line, width));
1249
+ }
1250
+
1251
+ function renderBox(lines, width, title, { useColor = false, color = ANSI.cyan, style = 'normal' } = {}) {
1252
+ const innerWidth = Math.max(10, width - 4);
1253
+ const titleText = title ? ` ${title.toUpperCase()} ` : '';
1254
+ const topLeft = style === 'focus' ? '╭' : style === 'hud' ? '┏' : '┌';
1255
+ const topRight = style === 'focus' ? '╮' : style === 'hud' ? '┓' : '┐';
1256
+ const bottomLeft = style === 'focus' ? '╰' : style === 'hud' ? '┗' : '└';
1257
+ const bottomRight = style === 'focus' ? '╯' : style === 'hud' ? '┛' : '┘';
1258
+ const topFill = style === 'focus' ? '═' : '─';
1259
+ const bottomTail = style === 'focus' ? '══' : '┄┄';
1260
+ const top = `${topLeft}${titleText}${topFill.repeat(Math.max(0, width - 2 - titleText.length))}${topRight}`;
1261
+ const bottom = `${bottomLeft}${topFill.repeat(Math.max(0, width - 4))}${bottomTail}${bottomRight}`;
1262
+ const body = lines.map((line, index) => {
1263
+ const left = index === 0
1264
+ ? (style === 'focus' ? '╞' : '├')
1265
+ : index === lines.length - 1
1266
+ ? (style === 'focus' ? '╘' : '╰')
1267
+ : '│';
1268
+ const right = index === 0
1269
+ ? (style === 'focus' ? '╡' : '┤')
1270
+ : index === lines.length - 1
1271
+ ? (style === 'focus' ? '╛' : '╯')
1272
+ : '│';
1273
+ return `${colorize(left, color, useColor)} ${fitText(line, innerWidth)} ${colorize(right, color, useColor)}`;
1274
+ });
1275
+ return [
1276
+ colorize(top, color, useColor),
1277
+ ...body,
1278
+ colorize(bottom, color, useColor),
1279
+ ];
1280
+ }
1281
+
1282
+ function joinHorizontalBoxes(boxes, gutter = 2) {
1283
+ const height = Math.max(...boxes.map((box) => box.lines.length));
1284
+ const gap = ' '.repeat(gutter);
1285
+ const rows = [];
1286
+
1287
+ for (let index = 0; index < height; index += 1) {
1288
+ rows.push(boxes.map((box) => box.lines[index] ?? ' '.repeat(box.width)).join(gap));
1289
+ }
1290
+
1291
+ return rows;
1292
+ }
1293
+
1294
+ export function formatCyberMenuFrame(status, commands, selectedIndex, tick = 0, {
1295
+ columns = 120,
1296
+ rows = 32,
1297
+ useColor = false,
1298
+ } = {}) {
1299
+ const width = Math.max(72, Math.min(columns, 150));
1300
+ const height = Math.max(22, Math.min(rows - 1, 42));
1301
+ const compactMode = width < 104 || height < 27;
1302
+ const rightWidth = compactMode ? (width >= 92 ? 28 : 26) : width >= 132 ? 44 : width >= 118 ? 34 : width >= 108 ? 32 : 30;
1303
+ const gutter = 2;
1304
+ const leftWidth = width - rightWidth - gutter;
1305
+ const selected = commands[selectedIndex] ?? commands[0];
1306
+ const actionArea = resolveCommandArea(selected);
1307
+ const bundledCatalog = status.bundledCatalog ?? { total: 0, categories: [] };
1308
+ const summaryOuterHeight = compactMode ? 7 : 9;
1309
+ const bodyOuterHeight = Math.max(12, height - summaryOuterHeight - 1);
1310
+ const detailOuterHeight = compactMode
1311
+ ? Math.min(8, Math.max(7, Math.floor(bodyOuterHeight * 0.46)))
1312
+ : Math.min(10, Math.max(8, Math.floor(bodyOuterHeight * 0.42)));
1313
+ const actionOuterHeight = compactMode
1314
+ ? Math.max(8, bodyOuterHeight - detailOuterHeight)
1315
+ : Math.max(8, bodyOuterHeight - detailOuterHeight);
1316
+ const rightBottomOuterHeight = compactMode
1317
+ ? Math.min(8, Math.max(7, Math.floor(bodyOuterHeight * 0.4)))
1318
+ : Math.min(10, Math.max(9, Math.floor(bodyOuterHeight * 0.36)));
1319
+ const rightTopOuterHeight = Math.max(8, bodyOuterHeight - rightBottomOuterHeight);
1320
+ const summaryInnerWidth = width - 4;
1321
+ const actionInnerWidth = leftWidth - 4;
1322
+ const detailInnerWidth = leftWidth - 4;
1323
+ const rightInnerWidth = rightWidth - 4;
1324
+ const summaryInnerHeight = summaryOuterHeight - 2;
1325
+ const actionInnerHeight = actionOuterHeight - 2;
1326
+ const detailInnerHeight = detailOuterHeight - 2;
1327
+ const rightTopInnerHeight = rightTopOuterHeight - 2;
1328
+ const rightBottomInnerHeight = rightBottomOuterHeight - 2;
1329
+ const visibleActionRows = Math.max(compactMode ? 2 : 3, actionInnerHeight - (compactMode ? 2 : 3));
1330
+ const scrollStart = Math.min(
1331
+ Math.max(0, selectedIndex - Math.floor(visibleActionRows / 2)),
1332
+ Math.max(0, commands.length - visibleActionRows),
1333
+ );
1334
+ const visibleCommands = commands.slice(scrollStart, scrollStart + visibleActionRows);
1335
+
1336
+ const summaryLines = compactMode
1337
+ ? [
1338
+ colorize('SKILL MASTER MENU', ANSI.bold, useColor),
1339
+ `version ${status.semver} | channel ${status.manifestVersion} | readiness ${status.globalReadiness.ready ? 'ready' : status.globalReadiness.mode}`,
1340
+ colorize(`GLOBAL SKILLS ${status.globalReadiness.installed.length}/${status.globalReadiness.required}`, ANSI.amber, useColor),
1341
+ `bundle ${bundledCatalog.total} | drafts ${status.pendingSuccessDrafts} | study ${status.studyCandidates}`,
1342
+ buildOverviewSignalLine(status, summaryInnerWidth, tick, { useColor, compact: true }),
1343
+ colorize(buildSetupAlertLine(status, true) ?? 'compact cyberpunk hud / operator safe', status.globalReadiness.ready ? ANSI.dim : ANSI.rose, useColor),
1344
+ ]
1345
+ : [
1346
+ colorize('SKILL MASTER MENU', ANSI.bold, useColor),
1347
+ `version ${status.semver} | channel ${status.manifestVersion} | readiness ${status.globalReadiness.ready ? 'ready' : status.globalReadiness.mode}`,
1348
+ colorize(`GLOBAL SKILLS ${status.globalReadiness.installed.length}/${status.globalReadiness.required}`, ANSI.amber, useColor),
1349
+ `bundle ${bundledCatalog.total} | drafts ${status.pendingSuccessDrafts} | study ${status.studyCandidates}`,
1350
+ renderStatusCapsule('FOCUS', `${actionArea} / ${selected?.key ?? 'status'}`, summaryInnerWidth, { useColor, color: ANSI.teal }),
1351
+ buildOverviewSignalLine(status, summaryInnerWidth, tick, { useColor, compact: false }),
1352
+ colorize(buildSetupAlertLine(status, false) ?? formatBundledCategoryLine(bundledCatalog), status.globalReadiness.ready ? ANSI.white : ANSI.rose, useColor),
1353
+ colorize(buildSetupAlertLine(status, false) ?? `clients ${summarizeClientReadiness(status.globalReadiness)}`, status.globalReadiness.ready ? ANSI.dim : ANSI.rose, useColor),
1354
+ ];
1355
+
1356
+ const actionLines = [
1357
+ colorize('ACTION MATRIX', ANSI.gray, useColor),
1358
+ colorize('up/down move enter run q exit', ANSI.dim, useColor),
1359
+ fitText(colorize(`window ${Math.min(selectedIndex + 1, commands.length)}/${commands.length} | visible ${visibleCommands.length}`, ANSI.gray, useColor), actionInnerWidth),
1360
+ ...visibleCommands.map((command, offset) => {
1361
+ const index = scrollStart + offset;
1362
+ const marker = index === selectedIndex ? '>' : '·';
1363
+ const disabled = command.disabledReason ? ' [off]' : '';
1364
+ const flair = index === selectedIndex && !compactMode ? ' ◢' : '';
1365
+ const badge = getActionAttentionBadge(command, status);
1366
+ const label = `${marker} ${badge}${command.label}${disabled}${flair}`;
1367
+ const color = getActionLineColor(command, index === selectedIndex, status);
1368
+ const fitted = fitText(label, actionInnerWidth);
1369
+ return color ? colorize(fitted, color, useColor) : fitted;
1370
+ }),
1371
+ ];
1372
+
1373
+ while (actionLines.length < actionInnerHeight) {
1374
+ actionLines.push(fitText('', actionInnerWidth));
1375
+ }
1376
+
1377
+ const descriptionLines = [
1378
+ colorize('DETAIL FOCUS', ANSI.amber, useColor),
1379
+ colorize(selected?.label ?? 'Nenhuma acao', ANSI.bold, useColor),
1380
+ renderStatusCapsule('AREA', `${actionArea} | action ${Math.min(selectedIndex + 1, commands.length)}/${commands.length}`, detailInnerWidth, { useColor, color: ANSI.gray }),
1381
+ fitText(colorize(patternFill('=-', 32), ANSI.amber, useColor), detailInnerWidth),
1382
+ ...(() => {
1383
+ const attention = getActionAttentionState(selected, status);
1384
+ if (attention === 'critical') {
1385
+ return splitText('priority: setup inicial fortemente recomendado. Esta acao autentica o MCP no sistema e prepara os clientes deste computador.', detailInnerWidth, 2);
1386
+ }
1387
+ if (attention === 'priority') {
1388
+ return splitText('priority: suporte ao setup global. Use junto do bootstrap para deixar Codex, Claude, Gemini e skills prontos neste computador.', detailInnerWidth, 2);
1389
+ }
1390
+ return [];
1391
+ })(),
1392
+ ...splitText(selected?.description ? `desc: ${selected.description}` : '', detailInnerWidth, 1),
1393
+ ...(selected?.key === 'updateGlobal'
1394
+ ? splitText('recommended: se houver handoff ou aviso, feche o menu, rode o comando exibido e reabra os clientes MCP depois.', detailInnerWidth, 3)
1395
+ : []),
1396
+ ...((selected?.details ?? []).flatMap((detail) => splitText(`detail: ${detail}`, detailInnerWidth, 2))),
1397
+ ...splitText(`exec: ${formatActionCommand(selected)}`, detailInnerWidth, 1),
1398
+ ...splitText(selected?.success ? `result: ${selected.success}` : '', detailInnerWidth, 1),
1399
+ ...(selected?.confirmMessage ? splitText(`confirmacao: ${selected.confirmMessage}`, detailInnerWidth, 2) : []),
1400
+ ...(selected?.disabledReason ? splitText(`Indisponivel: ${selected.disabledReason}`, detailInnerWidth, 2) : []),
1401
+ ];
1402
+
1403
+ while (descriptionLines.length < detailInnerHeight) {
1404
+ descriptionLines.push(fitText('', detailInnerWidth));
1405
+ }
1406
+
1407
+ const rightTopLines = dnaPanelLines(tick, rightInnerWidth, rightTopInnerHeight, status, selected, { useColor, compact: compactMode });
1408
+ const rightBottomLines = telemetryPanelLines(status, selected, rightInnerWidth, rightBottomInnerHeight, { useColor, tick, compact: compactMode });
1409
+ const summaryBox = renderCyberFrame(
1410
+ summaryLines.slice(0, summaryInnerHeight).map((line) => fitText(line, summaryInnerWidth)),
1411
+ width,
1412
+ 'overview',
1413
+ { useColor, color: ANSI.white, style: 'hud', tick },
1414
+ );
1415
+ const actionBox = renderCyberFrame(
1416
+ actionLines.slice(0, actionInnerHeight).map((line) => fitText(line, actionInnerWidth)),
1417
+ leftWidth,
1418
+ 'actions',
1419
+ { useColor, color: ANSI.gray, style: 'thin', tick },
1420
+ );
1421
+ const detailBox = renderCyberFrame(
1422
+ descriptionLines.slice(0, detailInnerHeight).map((line) => fitText(line, detailInnerWidth)),
1423
+ leftWidth,
1424
+ 'details',
1425
+ { useColor, color: ANSI.amber, style: 'focus', tick },
1426
+ );
1427
+ const dnaBox = renderCyberFrame(rightTopLines, rightWidth, 'dna-core', { useColor, color: ANSI.white, style: 'hud', tick });
1428
+ const telemetryBox = renderCyberFrame(rightBottomLines, rightWidth, 'telemetry', { useColor, color: ANSI.blue, style: 'thin', tick });
1429
+ const bodyRows = joinHorizontalBoxes([
1430
+ { lines: [...actionBox, ...detailBox], width: leftWidth },
1431
+ { lines: [...dnaBox, ...telemetryBox], width: rightWidth },
1432
+ ], gutter);
1433
+
1434
+ return [...summaryBox, '', ...bodyRows].join('\n');
1435
+ }
1436
+
1437
+ export function formatRunningActionFrame(status, action, tick = 0, {
1438
+ columns = 120,
1439
+ rows = 32,
1440
+ useColor = false,
1441
+ } = {}) {
1442
+ const width = Math.max(72, Math.min(columns, 150));
1443
+ const height = Math.max(18, Math.min(rows - 1, 30));
1444
+ const innerWidth = width - 4;
1445
+ const commandArea = resolveCommandArea(action);
1446
+ const pulse = renderSparkline(buildTelemetrySeries((status.globalReadiness.installed.length || 1) + tick, Math.max(8, Math.min(18, Math.floor(innerWidth / 5))), tick), { useColor, color: ANSI.teal });
1447
+ const gridHeight = Math.max(4, Math.min(8, height - 14));
1448
+ const lines = [
1449
+ colorize('SKILL_MASTER WORKFLOW ONLINE', ANSI.bold, useColor),
1450
+ fitText(colorize(`area ${commandArea} | launching ${action?.label ?? 'acao'}`, ANSI.amber, useColor), innerWidth),
1451
+ fitText(colorize(`pulse ${pulse}`, ANSI.gray, useColor), innerWidth),
1452
+ fitText(renderCircuitRail(innerWidth, tick, { useColor, color: ANSI.teal }), innerWidth),
1453
+ ...renderScanGrid(innerWidth, gridHeight, tick, { useColor }),
1454
+ fitText('', innerWidth),
1455
+ ...splitText(action?.description ?? '', innerWidth, 2),
1456
+ ...splitText(action?.success ? `resultado esperado: ${action.success}` : '', innerWidth, 2),
1457
+ ...splitText(`exec: ${formatActionCommand(action)}`, innerWidth, 2),
1458
+ fitText('', innerWidth),
1459
+ fitText(colorize('handoff: HUD -> stream real do comando', ANSI.dim, useColor), innerWidth),
1460
+ ];
1461
+
1462
+ while (lines.length < Math.max(8, height - 2)) {
1463
+ lines.push(fitText('', innerWidth));
1464
+ }
1465
+
1466
+ return renderCyberFrame(
1467
+ lines.slice(0, Math.max(8, height - 2)).map((line) => fitText(line, innerWidth)),
1468
+ width,
1469
+ 'running',
1470
+ { useColor, color: ANSI.teal, style: 'running', tick },
1471
+ ).join('\n');
1472
+ }
1473
+
1474
+ export function formatSkillMasterIntroFrame(status, tick = 0, {
1475
+ columns = 120,
1476
+ rows = 32,
1477
+ useColor = false,
1478
+ message = 'skill_master assumindo o workflow',
1479
+ } = {}) {
1480
+ const width = Math.max(72, Math.min(columns, 150));
1481
+ const height = Math.max(18, Math.min(rows - 1, 34));
1482
+ const innerWidth = width - 4;
1483
+ const gridHeight = Math.max(6, Math.min(12, height - 12));
1484
+ const signal = renderSparkline(buildTelemetrySeries(status.pendingSuccessDrafts + status.studyCandidates + 5, Math.max(12, Math.min(28, Math.floor(innerWidth / 4))), tick), { useColor, color: ANSI.teal });
1485
+ const lines = [
1486
+ colorize('REBORN / SKILL_MASTER', ANSI.bold, useColor),
1487
+ fitText(colorize(message, ANSI.amber, useColor), innerWidth),
1488
+ fitText(colorize(`package ${status.packageName} | version ${status.semver} | channel ${status.manifestVersion}`, ANSI.gray, useColor), innerWidth),
1489
+ fitText(colorize(`signal ${signal}`, ANSI.teal, useColor), innerWidth),
1490
+ fitText(renderCircuitRail(innerWidth, tick, { useColor, color: ANSI.white }), innerWidth),
1491
+ ...renderScanGrid(innerWidth, gridHeight, tick, { useColor }),
1492
+ fitText(renderCircuitRail(innerWidth, tick + 3, { useColor, color: ANSI.amber }), innerWidth),
1493
+ fitText(colorize(`global ${status.globalReadiness.installed.length}/${status.globalReadiness.required} | bundle ${status.bundledCatalog?.total ?? 0} | study ${status.studyCandidates}`, ANSI.gray, useColor), innerWidth),
1494
+ fitText(colorize('modo visual seguro: terminal humano ativo / stdio MCP preservado', ANSI.dim, useColor), innerWidth),
1495
+ ];
1496
+
1497
+ while (lines.length < Math.max(8, height - 2)) {
1498
+ lines.push(fitText('', innerWidth));
1499
+ }
1500
+
1501
+ return renderCyberFrame(
1502
+ lines.slice(0, Math.max(8, height - 2)).map((line) => fitText(line, innerWidth)),
1503
+ width,
1504
+ 'boot-sequence',
1505
+ { useColor, color: ANSI.teal, style: 'hud', tick },
1506
+ ).join('\n');
1507
+ }
1508
+
1509
+ export function formatCyberConfirmFrame(status, action, tick = 0, {
1510
+ columns = 120,
1511
+ rows = 32,
1512
+ useColor = false,
1513
+ } = {}) {
1514
+ const width = Math.max(72, Math.min(columns, 140));
1515
+ const height = Math.max(16, Math.min(rows - 1, 28));
1516
+ const innerWidth = width - 4;
1517
+ const commandArea = resolveCommandArea(action);
1518
+ const lines = [
1519
+ colorize('CONFIRMATION GATE', ANSI.bold, useColor),
1520
+ fitText(colorize(action?.confirmMessage ?? 'Confirmar acao?', ANSI.amber, useColor), innerWidth),
1521
+ fitText(`area ${commandArea} | action ${action?.key ?? 'unknown'}`, innerWidth),
1522
+ fitText(renderCircuitRail(innerWidth, tick, { useColor, color: ANSI.amber }), innerWidth),
1523
+ ...splitText(action?.description ?? '', innerWidth, 2),
1524
+ ...splitText(action?.success ? `resultado esperado: ${action.success}` : '', innerWidth, 2),
1525
+ fitText('', innerWidth),
1526
+ fitText(colorize('Y/Enter confirma N/Esc cancela', ANSI.teal, useColor), innerWidth),
1527
+ ];
1528
+
1529
+ while (lines.length < Math.max(8, height - 2)) {
1530
+ lines.push(fitText('', innerWidth));
1531
+ }
1532
+
1533
+ return renderCyberFrame(
1534
+ lines.slice(0, Math.max(8, height - 2)).map((line) => fitText(line, innerWidth)),
1535
+ width,
1536
+ 'subroutine',
1537
+ { useColor, color: ANSI.amber, style: 'focus', tick },
1538
+ ).join('\n');
1539
+ }
1540
+
1541
+ export function formatActionHeader(action, { useColor = false } = {}) {
1542
+ const lines = [
1543
+ colorize(action.label, ANSI.bold, useColor),
1544
+ action.description,
1545
+ ...(action.details ?? []),
1546
+ action.success ? `Resultado esperado: ${action.success}` : null,
1547
+ action.disabledReason ? `Indisponivel: ${action.disabledReason}` : null,
1548
+ ].filter(Boolean);
1549
+
1550
+ const width = Math.max(72, Math.min(120, Math.max(...lines.map((line) => visibleLength(line))) + 8));
1551
+ return renderCyberFrame(
1552
+ lines.map((line) => fitText(line, width - 4)),
1553
+ width,
1554
+ 'skill-master action',
1555
+ { color: ANSI.green, useColor, style: 'hud' },
1556
+ ).join('\n');
1557
+ }
1558
+
1559
+ export function formatResultMessage(code, { useColor = false } = {}) {
1560
+ const result = buildOperationResultCopy(code);
1561
+ const tone = result.kind === 'ok' ? 'ok' : result.kind === 'warning' ? 'warning' : 'error';
1562
+ const color = tone === 'ok' ? ANSI.green : tone === 'warning' ? ANSI.amber : ANSI.red;
1563
+ const lines = [
1564
+ colorize(result.heading, color, useColor),
1565
+ result.summary,
1566
+ result.next,
1567
+ tone === 'warning' ? 'consulte o proximo passo recomendado no log acima' : null,
1568
+ ];
1569
+
1570
+ return renderCyberFrame(
1571
+ lines.filter(Boolean).map((line) => fitText(line, 68)),
1572
+ 72,
1573
+ result.frameTitle,
1574
+ { color, useColor, style: tone === 'ok' ? 'hud' : 'focus' },
1575
+ ).join('\n');
1576
+ }
1577
+
1578
+ export function formatPlainResultMessage(code, { useColor = false } = {}) {
1579
+ const result = buildOperationResultCopy(code);
1580
+ const color = result.kind === 'ok' ? ANSI.green : result.kind === 'warning' ? ANSI.amber : ANSI.red;
1581
+ return colorize(result.summary, color, useColor);
1582
+ }
1583
+
1584
+ export function formatHelp(commands) {
1585
+ const actionList = commands.map((command) => {
1586
+ const aliases = command.aliases.length ? ` aliases: ${command.aliases.join(', ')}` : '';
1587
+ const disabled = command.disabledReason ? ` indisponivel: ${command.disabledReason}` : '';
1588
+ return ` - ${command.key}: ${command.label}\n ${command.description}${aliases}${disabled}`;
1589
+ }).join('\n');
1590
+
1591
+ return `Skill Master Menu
1592
+
1593
+ Uso:
1594
+ skill-master-menu
1595
+ skill-master-menu --status
1596
+ skill-master-menu --run <acao>
1597
+ skill-master-menu --run update --yes
1598
+ skill-master-menu --help
1599
+
1600
+ Acoes disponiveis:
1601
+ ${actionList}
1602
+
1603
+ O comando de menu e voltado para operacao humana. O binario MCP stdio continua sendo:
1604
+ skill-master-mcp
1605
+ `;
1606
+ }
1607
+
1608
+ export function runCommand(action, { cwd, env = process.env } = {}) {
1609
+ return new Promise((resolve, reject) => {
1610
+ let child;
1611
+
1612
+ try {
1613
+ child = spawn(action.command, action.args, {
1614
+ cwd,
1615
+ env,
1616
+ shell: Boolean(action.shell),
1617
+ stdio: 'inherit',
1618
+ });
1619
+ } catch (error) {
1620
+ reject(error);
1621
+ return;
1622
+ }
1623
+
1624
+ child.on('error', reject);
1625
+ child.on('close', (code) => {
1626
+ resolve(code ?? 1);
1627
+ });
1628
+ });
1629
+ }