@fprad0/skill-master-mcp 0.0.12 → 1.0.1

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 (353) hide show
  1. package/CHANGELOG.md +100 -88
  2. package/README.md +472 -472
  3. package/VERSION.md +9 -9
  4. package/bin/lib/bootstrap-global-core.mjs +34 -0
  5. package/bin/lib/client-config.mjs +287 -285
  6. package/bin/lib/doctor-core.mjs +202 -0
  7. package/bin/lib/menu-core.mjs +1792 -1514
  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 -215
  11. package/bin/lib/update-cli-core.mjs +117 -0
  12. package/bin/skill-master-activation.mjs +165 -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 -228
  16. package/bin/skill-master-eval-activation.mjs +32 -32
  17. package/bin/skill-master-install-global-skills.mjs +59 -59
  18. package/bin/skill-master-install-project-skills.mjs +97 -97
  19. package/bin/skill-master-menu.mjs +489 -378
  20. package/bin/skill-master-register-clients.mjs +232 -153
  21. package/bin/skill-master-success-skills.mjs +357 -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 -262
  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 -66
  41. package/docs/operations/assets/menu-frame-compact.html +36 -33
  42. package/docs/operations/assets/menu-frame-dna-hero.html +87 -0
  43. package/docs/operations/assets/menu-frame-fine-helix.html +89 -0
  44. package/docs/operations/assets/menu-frame-large.html +44 -41
  45. package/docs/operations/assets/menu-frame-running.html +41 -38
  46. package/docs/operations/assets/menu-frame-score-10-contact-sheet.html +184 -0
  47. package/docs/operations/cross-platform-auth-transfer/ANALISE_COMPATIBILIDADE_MCP_2026-06-28.md +140 -140
  48. package/docs/operations/cross-platform-auth-transfer/README_TRANSFERENCIA.md +85 -85
  49. package/docs/operations/reborn-menu-cyberpunk-transfer/ANALISE_MENU_REBORN_CYBERPUNK_2026-06-28.md +174 -174
  50. package/docs/operations/reborn-menu-cyberpunk-transfer/HANDOFF_IMPLEMENTACAO_REBORN_CYBERPUNK_2026-06-28.md +119 -119
  51. package/docs/operations/reborn-menu-cyberpunk-transfer/ORDEM_DE_EXECUCAO_MENU_REBORN_CYBERPUNK.md +134 -134
  52. package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA.md +84 -84
  53. package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA_REBORN_PACKAGE.md +56 -56
  54. package/docs/operations/token-economy-transfer/ANALISE_AVANCADA_ECONOMIA_TOKENS_2026-06-30.md +141 -0
  55. package/docs/operations/token-economy-transfer/PLANO_DEV_SENIOR_MASTER_TOKEN_ECONOMY_2026-06-30.md +171 -0
  56. package/docs/operations/token-economy-transfer/README_TRANSFERENCIA_TOKEN_ECONOMY.md +31 -0
  57. package/docs/planning/MENU_RUNTIME_CORRECTION_PLAN_2026-06-30.md +551 -0
  58. package/docs/planning/V0_0_9_APROVACAO_CRITICA_MENSAGENS_DE_VENDA.md +85 -85
  59. package/docs/planning/V0_0_9_FONTES_E_CRITERIOS_DE_AUTORIDADE.md +139 -139
  60. package/docs/planning/V0_0_9_MATRIZ_SKILLS_MULTIDISCIPLINARES.md +105 -105
  61. package/docs/planning/V0_0_9_POLITICA_MORAL_CATOLICA_PARA_IA.md +181 -181
  62. package/docs/planning/V0_0_9_PROMPTS_EXECUCAO.md +59 -59
  63. package/docs/planning/V0_0_9_ROADMAP_DISCERNIMENTO_E_CONHECIMENTO_AMPLO.md +181 -181
  64. package/docs/planning/mcp-1.0.0/00_RESUMO_EXECUTIVO_AUDITORIA_MENU.md +118 -0
  65. package/docs/planning/mcp-1.0.0/01_MATRIZ_TESTES_MENU_E_RESULTADOS.md +250 -0
  66. package/docs/planning/mcp-1.0.0/02_PLANO_CORRECAO_ATIVAR_SKILL_APRENDIDA.md +200 -0
  67. package/docs/planning/mcp-1.0.0/03_PLANO_COMPATIBILIDADE_WINDOWS_LINUX_MACOS.md +167 -0
  68. package/docs/planning/mcp-1.0.0/04_PLANO_UI_CYBERPUNK_PIXEL_ART_E_PERFORMANCE.md +165 -0
  69. package/docs/planning/mcp-1.0.0/05_PROMPT_TASK_EXECUCAO_CORRECOES.md +151 -0
  70. package/docs/planning/mcp-1.0.0/06_CHECKLIST_REGRESSAO_PRE_RELEASE.md +159 -0
  71. package/docs/planning/mcp-1.0.0/07_RELATORIO_APLICACAO_CORRECOES_MENU_SKILL_MASTER.md +136 -0
  72. package/docs/planning/mcp-1.0.0/08_AUDITORIA_CRITICA_MENU_NOTA_E_DNA_REFINADO.md +184 -0
  73. package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/00_PROMPT_TASK_MASTER_NOTA_10_10.md +103 -0
  74. package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/01_PROMPT_TASK_FINE_HELIX_DNA.md +116 -0
  75. package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/02_PROMPT_TASK_DNA_HERO_BOOT_AND_MOTION.md +109 -0
  76. package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/03_PROMPT_TASK_MENU_UX_HELP_ERROR_COPY.md +99 -0
  77. package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/04_PROMPT_TASK_EVIDENCE_RENDERER_1_0_0.md +97 -0
  78. package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/05_PROMPT_TASK_CROSS_PLATFORM_UTF8_MOJIBAKE.md +99 -0
  79. package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/06_PROMPT_TASK_VISUAL_REGRESSION_QA.md +105 -0
  80. package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/07_PROMPT_TASK_PRE_RELEASE_SCORE_GATE_10_10.md +104 -0
  81. package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/README_ORDEM_EXECUCAO_NOTA_10_10.md +77 -0
  82. package/docs/prompt-tasks/PROMPT_TASK_001_BOOTSTRAP_SKILL_MASTER_MCP.md +6 -6
  83. package/docs/prompt-tasks/PROMPT_TASK_002_AUTO_UPDATE_LAUNCHER.md +6 -6
  84. package/docs/prompt-tasks/PROMPT_TASK_003_REMOTE_MANIFEST_AND_RELEASES.md +6 -6
  85. package/docs/prompt-tasks/PROMPT_TASK_004_MULTI_USER_DISTRIBUTION.md +6 -6
  86. package/docs/prompt-tasks/PROMPT_TASK_005_SECURITY_AND_QUALITY_GATE.md +6 -6
  87. package/docs/prompt-tasks/PROMPT_TASK_006_MASTER_ACIONAMENTO_APRENDIZADO.md +83 -83
  88. package/docs/prompt-tasks/PROMPT_TASK_007_PERSONA_ORQUESTRADORA.md +88 -88
  89. package/docs/prompt-tasks/PROMPT_TASK_008_PROMPT_ROUTER_MODOS_ATIVACAO.md +156 -156
  90. package/docs/prompt-tasks/PROMPT_TASK_009_PIPELINE_APRENDIZADO_SUCESSO.md +105 -105
  91. package/docs/prompt-tasks/PROMPT_TASK_010_EVALS_GOVERNANCA_ATIVACAO.md +119 -119
  92. package/docs/prompt-tasks/PROMPT_TASK_011_MENU_NOTIFICACOES_NOTION.md +120 -120
  93. package/docs/prompt-tasks/PROMPT_TASK_012_MENU_CYBERPUNK_PIXEL_FRAME.md +123 -123
  94. package/docs/prompt-tasks/PROMPT_TASK_013_MENU_FLUID_DNA_ANIMATION.md +114 -114
  95. package/docs/prompt-tasks/PROMPT_TASK_014_MENU_FUNCTIONAL_PARITY_QA.md +157 -157
  96. package/docs/prompt-tasks/PROMPT_TASK_015_TRANSFER_RELEASE_HANDOFF.md +127 -127
  97. package/docs/prompt-tasks/PROMPT_TASK_016_CROSS_PLATFORM_MCP_AUTH_REGISTRATION.md +107 -107
  98. package/docs/prompt-tasks/PROMPT_TASK_018_NPM_PUBLISH_2FA_SETUP.md +80 -80
  99. package/docs/prompt-tasks/PROMPT_TASK_019_TOKEN_ECONOMY_GLOBAL_SKILLS.md +56 -0
  100. package/docs/prompt-tasks/PROMPT_TASK_MASTER_EXECUTOR.md +6 -6
  101. package/docs/skill-candidates/v0.0.10/cli-creator/LICENSE.txt +201 -201
  102. package/docs/skill-candidates/v0.0.10/cli-creator/SKILL.md +160 -160
  103. package/docs/skill-candidates/v0.0.10/cli-creator/agents/openai.yaml +4 -4
  104. package/docs/skill-candidates/v0.0.10/cli-creator/references/agent-cli-patterns.md +154 -154
  105. package/docs/skill-candidates/v0.0.10/developer-workstation-ops/SKILL.md +32 -32
  106. package/docs/skill-candidates/v0.0.10/figma/LICENSE.txt +1 -1
  107. package/docs/skill-candidates/v0.0.10/figma/SKILL.md +42 -42
  108. package/docs/skill-candidates/v0.0.10/figma/agents/openai.yaml +14 -14
  109. package/docs/skill-candidates/v0.0.10/figma/assets/figma-small.svg +3 -3
  110. package/docs/skill-candidates/v0.0.10/figma/assets/icon.svg +28 -28
  111. package/docs/skill-candidates/v0.0.10/figma/references/figma-mcp-config.md +35 -35
  112. package/docs/skill-candidates/v0.0.10/figma/references/figma-tools-and-prompts.md +34 -34
  113. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/LICENSE.TXT +1 -1
  114. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/SKILL.md +349 -349
  115. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/agents/openai.yaml +14 -14
  116. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/figma-small.svg +3 -3
  117. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/icon.svg +28 -28
  118. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/references/mapping-checklist.md +7 -7
  119. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/scripts/normalize_node_id.py +25 -25
  120. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/LICENSE.TXT +1 -1
  121. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/SKILL.md +537 -537
  122. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/agents/openai.yaml +14 -14
  123. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/figma-small.svg +3 -3
  124. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/icon.svg +28 -28
  125. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/references/rule-template.md +15 -15
  126. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/scripts/check_agents_md.sh +9 -9
  127. package/docs/skill-candidates/v0.0.10/figma-generate-design/LICENSE.TXT +1 -1
  128. package/docs/skill-candidates/v0.0.10/figma-generate-design/SKILL.md +341 -341
  129. package/docs/skill-candidates/v0.0.10/figma-generate-design/agents/openai.yaml +14 -14
  130. package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/figma-small.svg +3 -3
  131. package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/icon.svg +28 -28
  132. package/docs/skill-candidates/v0.0.10/figma-generate-design/maintainers.yml +1 -1
  133. package/docs/skill-candidates/v0.0.10/figma-generate-library/LICENSE.TXT +1 -1
  134. package/docs/skill-candidates/v0.0.10/figma-generate-library/SKILL.md +314 -314
  135. package/docs/skill-candidates/v0.0.10/figma-generate-library/agents/openai.yaml +14 -14
  136. package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/figma-small.svg +3 -3
  137. package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/icon.svg +28 -28
  138. package/docs/skill-candidates/v0.0.10/figma-generate-library/maintainers.yml +3 -3
  139. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/code-connect-setup.md +260 -260
  140. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/component-creation.md +1014 -1014
  141. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/discovery-phase.md +518 -518
  142. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/documentation-creation.md +834 -834
  143. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/error-recovery.md +540 -540
  144. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/naming-conventions.md +527 -527
  145. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/token-creation.md +962 -962
  146. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/bindVariablesToComponent.js +110 -110
  147. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/cleanupOrphans.js +127 -127
  148. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createComponentWithVariants.js +148 -148
  149. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createDocumentationPage.js +139 -139
  150. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createSemanticTokens.js +108 -108
  151. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createVariableCollection.js +49 -49
  152. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/inspectFileStructure.js +121 -121
  153. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/rehydrateState.js +92 -92
  154. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/validateCreation.js +83 -83
  155. package/docs/skill-candidates/v0.0.10/figma-implement-design/LICENSE.txt +1 -1
  156. package/docs/skill-candidates/v0.0.10/figma-implement-design/SKILL.md +258 -258
  157. package/docs/skill-candidates/v0.0.10/figma-implement-design/agents/openai.yaml +14 -14
  158. package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/figma-small.svg +3 -3
  159. package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/icon.svg +28 -28
  160. package/docs/skill-candidates/v0.0.10/figma-use/LICENSE.TXT +1 -1
  161. package/docs/skill-candidates/v0.0.10/figma-use/SKILL.md +233 -233
  162. package/docs/skill-candidates/v0.0.10/figma-use/agents/openai.yaml +14 -14
  163. package/docs/skill-candidates/v0.0.10/figma-use/assets/figma-small.svg +3 -3
  164. package/docs/skill-candidates/v0.0.10/figma-use/assets/icon.svg +28 -28
  165. package/docs/skill-candidates/v0.0.10/figma-use/maintainers.yml +1 -1
  166. package/docs/skill-candidates/v0.0.10/figma-use/references/api-reference.md +301 -301
  167. package/docs/skill-candidates/v0.0.10/figma-use/references/common-patterns.md +512 -512
  168. package/docs/skill-candidates/v0.0.10/figma-use/references/component-patterns.md +488 -488
  169. package/docs/skill-candidates/v0.0.10/figma-use/references/effect-style-patterns.md +123 -123
  170. package/docs/skill-candidates/v0.0.10/figma-use/references/gotchas.md +599 -599
  171. package/docs/skill-candidates/v0.0.10/figma-use/references/maintainers.yml +12 -12
  172. package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-patterns.md +513 -513
  173. package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.d.ts +11293 -11293
  174. package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.index.md +441 -441
  175. package/docs/skill-candidates/v0.0.10/figma-use/references/text-style-patterns.md +203 -203
  176. package/docs/skill-candidates/v0.0.10/figma-use/references/validation-and-recovery.md +109 -109
  177. package/docs/skill-candidates/v0.0.10/figma-use/references/variable-patterns.md +354 -354
  178. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/maintainers.yml +9 -9
  179. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--creating.md +17 -17
  180. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--using.md +17 -17
  181. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components.md +50 -50
  182. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-effect-styles.md +52 -52
  183. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-text-styles.md +90 -90
  184. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--creating.md +13 -13
  185. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--using.md +13 -13
  186. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables.md +64 -64
  187. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds.md +41 -41
  188. package/docs/skill-candidates/v0.0.10/frontend-design/LICENSE.txt +177 -177
  189. package/docs/skill-candidates/v0.0.10/frontend-design/SKILL.md +55 -55
  190. package/docs/skill-candidates/v0.0.10/frontend-ui-ux-systems/SKILL.md +32 -32
  191. package/docs/skill-candidates/v0.0.10/github/SKILL.md +74 -74
  192. package/docs/skill-candidates/v0.0.10/github/agents/openai.yaml +6 -6
  193. package/docs/skill-candidates/v0.0.10/github/assets/github-small.svg +3 -3
  194. package/docs/skill-candidates/v0.0.10/image-graphic-design-rendering/SKILL.md +28 -28
  195. package/docs/skill-candidates/v0.0.10/language-quality-pt-en-fr-it-ru/SKILL.md +28 -28
  196. package/docs/skill-candidates/v0.0.10/math-physics-reasoning/SKILL.md +28 -28
  197. package/docs/skill-candidates/v0.0.10/mcp-builder/LICENSE.txt +201 -201
  198. package/docs/skill-candidates/v0.0.10/mcp-builder/SKILL.md +236 -236
  199. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/evaluation.md +601 -601
  200. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/mcp_best_practices.md +249 -249
  201. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/node_mcp_server.md +969 -969
  202. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/python_mcp_server.md +718 -718
  203. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/connections.py +151 -151
  204. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/evaluation.py +373 -373
  205. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/example_evaluation.xml +22 -22
  206. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/requirements.txt +2 -2
  207. package/docs/skill-candidates/v0.0.10/mcp-client-readiness/SKILL.md +31 -31
  208. package/docs/skill-candidates/v0.0.10/openai-docs/LICENSE.txt +201 -201
  209. package/docs/skill-candidates/v0.0.10/openai-docs/SKILL.md +161 -161
  210. package/docs/skill-candidates/v0.0.10/openai-docs/agents/openai.yaml +14 -14
  211. package/docs/skill-candidates/v0.0.10/openai-docs/assets/openai-small.svg +3 -3
  212. package/docs/skill-candidates/v0.0.10/openai-docs/references/latest-model.md +37 -37
  213. package/docs/skill-candidates/v0.0.10/openai-docs/references/prompting-guide.md +244 -244
  214. package/docs/skill-candidates/v0.0.10/openai-docs/references/upgrade-guide.md +181 -181
  215. package/docs/skill-candidates/v0.0.10/openai-docs/scripts/fetch-codex-manual.mjs +598 -598
  216. package/docs/skill-candidates/v0.0.10/openai-docs/scripts/resolve-latest-model-info.js +147 -147
  217. package/docs/skill-candidates/v0.0.10/playwright/NOTICE.txt +14 -14
  218. package/docs/skill-candidates/v0.0.10/playwright/SKILL.md +147 -147
  219. package/docs/skill-candidates/v0.0.10/playwright/agents/openai.yaml +6 -6
  220. package/docs/skill-candidates/v0.0.10/playwright/assets/playwright-small.svg +3 -3
  221. package/docs/skill-candidates/v0.0.10/playwright/references/cli.md +116 -116
  222. package/docs/skill-candidates/v0.0.10/playwright/references/workflows.md +95 -95
  223. package/docs/skill-candidates/v0.0.10/playwright/scripts/playwright_cli.sh +25 -25
  224. package/docs/skill-candidates/v0.0.10/polyglot-backend-engineering/SKILL.md +32 -32
  225. package/docs/skill-candidates/v0.0.10/screenshot/LICENSE.txt +201 -201
  226. package/docs/skill-candidates/v0.0.10/screenshot/SKILL.md +267 -267
  227. package/docs/skill-candidates/v0.0.10/screenshot/agents/openai.yaml +6 -6
  228. package/docs/skill-candidates/v0.0.10/screenshot/assets/screenshot-small.svg +5 -5
  229. package/docs/skill-candidates/v0.0.10/screenshot/scripts/ensure_macos_permissions.sh +54 -54
  230. package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_display_info.swift +22 -22
  231. package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_permissions.swift +40 -40
  232. package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_window_info.swift +126 -126
  233. package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.ps1 +163 -163
  234. package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.py +585 -585
  235. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/SKILL.md +62 -62
  236. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/agents/openai.yaml +4 -4
  237. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/activation-policy.md +77 -77
  238. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/human-approval-policy.md +83 -83
  239. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/persona-dev-senior-master.md +46 -46
  240. package/docs/skill-candidates/v0.0.10/terminal-menu-operations/SKILL.md +30 -30
  241. package/docs/skill-candidates/v0.0.10/terminal-pixel-art-tui/SKILL.md +43 -43
  242. package/docs/skill-candidates/v0.0.10/webapp-testing/LICENSE.txt +201 -201
  243. package/docs/skill-candidates/v0.0.10/webapp-testing/SKILL.md +95 -95
  244. package/docs/skill-candidates/v0.0.10/webapp-testing/examples/console_logging.py +34 -34
  245. package/docs/skill-candidates/v0.0.10/webapp-testing/examples/element_discovery.py +39 -39
  246. package/docs/skill-candidates/v0.0.10/webapp-testing/examples/static_html_automation.py +32 -32
  247. package/docs/skill-candidates/v0.0.10/webapp-testing/scripts/with_server.py +105 -105
  248. package/docs/skill-candidates/v0.0.10/winui-app/LICENSE.txt +201 -201
  249. package/docs/skill-candidates/v0.0.10/winui-app/SKILL.md +94 -94
  250. package/docs/skill-candidates/v0.0.10/winui-app/agents/openai.yaml +5 -5
  251. package/docs/skill-candidates/v0.0.10/winui-app/config.yaml +50 -50
  252. package/docs/skill-candidates/v0.0.10/winui-app/references/_sections.md +96 -96
  253. package/docs/skill-candidates/v0.0.10/winui-app/references/accessibility-input-and-localization.md +51 -51
  254. package/docs/skill-candidates/v0.0.10/winui-app/references/build-run-and-launch-verification.md +72 -72
  255. package/docs/skill-candidates/v0.0.10/winui-app/references/community-toolkit-controls-and-helpers.md +57 -57
  256. package/docs/skill-candidates/v0.0.10/winui-app/references/controls-layout-and-adaptive-ui.md +84 -84
  257. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-environment-audit-and-remediation.md +82 -82
  258. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-setup-and-project-selection.md +67 -67
  259. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-template-first-recovery.md +62 -62
  260. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-winui-app-structure.md +62 -62
  261. package/docs/skill-candidates/v0.0.10/winui-app/references/motion-animations-and-polish.md +45 -45
  262. package/docs/skill-candidates/v0.0.10/winui-app/references/performance-diagnostics-and-responsiveness.md +46 -46
  263. package/docs/skill-candidates/v0.0.10/winui-app/references/sample-source-map.md +37 -37
  264. package/docs/skill-candidates/v0.0.10/winui-app/references/shell-navigation-and-windowing.md +67 -67
  265. package/docs/skill-candidates/v0.0.10/winui-app/references/styling-theming-materials-and-icons.md +71 -71
  266. package/docs/skill-candidates/v0.0.10/winui-app/references/testing-debugging-and-review-checklists.md +77 -77
  267. package/docs/skill-candidates/v0.0.10/winui-app/references/windows-app-sdk-lifecycle-notifications-and-deployment.md +52 -52
  268. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/SKILL.md +398 -398
  269. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/common-patterns.md +330 -330
  270. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/complete-examples.md +871 -871
  271. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/component-patterns.md +501 -501
  272. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/data-fetching.md +766 -766
  273. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/file-organization.md +501 -501
  274. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/loading-and-error-states.md +500 -500
  275. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/performance.md +405 -405
  276. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/routing-guide.md +363 -363
  277. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/styling-guide.md +427 -427
  278. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/typescript-standards.md +417 -417
  279. package/docs/skill-candidates/v0.0.11/git-version-control-ops/SKILL.md +34 -34
  280. package/docs/skill-candidates/v0.0.11/go-engineering/SKILL.md +34 -34
  281. package/docs/skill-candidates/v0.0.11/java-engineering/SKILL.md +34 -34
  282. package/docs/skill-candidates/v0.0.11/javascript-engineering/SKILL.md +34 -34
  283. package/docs/skill-candidates/v0.0.11/json-contract-design/SKILL.md +34 -34
  284. package/docs/skill-candidates/v0.0.11/multi-client-mcp-ops/SKILL.md +36 -36
  285. package/docs/skill-candidates/v0.0.11/nextjs/SKILL.md +745 -745
  286. package/docs/skill-candidates/v0.0.11/nextjs/agents/openai.yaml +3 -3
  287. package/docs/skill-candidates/v0.0.11/nextjs/references/app-router-files.md +94 -94
  288. package/docs/skill-candidates/v0.0.11/python-engineering/SKILL.md +34 -34
  289. package/docs/skill-candidates/v0.0.11/ruby-engineering/SKILL.md +34 -34
  290. package/docs/skill-candidates/v0.0.11/senior-fullstack/SKILL.md +209 -209
  291. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/architecture_patterns.md +103 -103
  292. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/development_workflows.md +103 -103
  293. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/tech_stack_guide.md +103 -103
  294. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/code_quality_analyzer.py +114 -114
  295. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/fullstack_scaffolder.py +114 -114
  296. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/project_scaffolder.py +114 -114
  297. package/docs/skill-candidates/v0.0.11/shadcn/SKILL.md +573 -573
  298. package/docs/skill-candidates/v0.0.11/shadcn/agents/openai.yaml +3 -3
  299. package/docs/skill-candidates/v0.0.11/sql-postgresql-engineering/SKILL.md +34 -34
  300. package/docs/skill-candidates/v0.0.11/terminal-shell-ops/SKILL.md +34 -34
  301. package/docs/skill-candidates/v0.0.11/typescript-expert/SKILL.md +429 -429
  302. package/docs/skill-candidates/v0.0.11/typescript-expert/references/tsconfig-strict.json +91 -91
  303. package/docs/skill-candidates/v0.0.11/typescript-expert/references/typescript-cheatsheet.md +383 -383
  304. package/docs/skill-candidates/v0.0.11/typescript-expert/references/utility-types.ts +335 -335
  305. package/docs/skill-candidates/v0.0.11/typescript-expert/scripts/ts_diagnostic.py +203 -203
  306. package/docs/skill-candidates/v0.0.11/ui-component-primitives/SKILL.md +34 -34
  307. package/docs/skill-candidates/v0.0.11/web-mobile-design-systems/SKILL.md +34 -34
  308. package/docs/skill-candidates/v0.0.11/windows-linux-platform-ops/SKILL.md +34 -34
  309. package/docs/skill-candidates/v0.0.12/context-compression-handoff/SKILL.md +47 -0
  310. package/docs/skill-candidates/v0.0.12/csharp-senior-master-engineering/SKILL.md +32 -32
  311. package/docs/skill-candidates/v0.0.12/css-senior-master-engineering/SKILL.md +32 -32
  312. package/docs/skill-candidates/v0.0.12/go-senior-master-engineering/SKILL.md +32 -32
  313. package/docs/skill-candidates/v0.0.12/html-senior-master-engineering/SKILL.md +32 -32
  314. package/docs/skill-candidates/v0.0.12/javascript-senior-master-engineering/SKILL.md +32 -32
  315. package/docs/skill-candidates/v0.0.12/json-senior-master-engineering/SKILL.md +32 -32
  316. package/docs/skill-candidates/v0.0.12/prompt-budget-gate/SKILL.md +46 -0
  317. package/docs/skill-candidates/v0.0.12/python-senior-master-engineering/SKILL.md +32 -32
  318. package/docs/skill-candidates/v0.0.12/react-senior-master-engineering/SKILL.md +32 -32
  319. package/docs/skill-candidates/v0.0.12/ruby-senior-master-engineering/SKILL.md +32 -32
  320. package/docs/skill-candidates/v0.0.12/senior-master-code-optimizer/SKILL.md +48 -48
  321. package/docs/skill-candidates/v0.0.12/sql-senior-master-engineering/SKILL.md +31 -31
  322. package/docs/skill-candidates/v0.0.12/token-economy-orchestrator/SKILL.md +38 -0
  323. package/docs/skill-candidates/v0.0.12/typescript-senior-master-engineering/SKILL.md +35 -35
  324. package/docs/skill-candidates/v0.0.9/ai-ethics-human-dignity/SKILL.md +32 -32
  325. package/docs/skill-candidates/v0.0.9/broad-domain-router/SKILL.md +41 -41
  326. package/docs/skill-candidates/v0.0.9/catholic-moral-discernment/SKILL.md +31 -31
  327. package/docs/skill-candidates/v0.0.9/engineering-systems-master/SKILL.md +31 -31
  328. package/docs/skill-candidates/v0.0.9/language-quality-pt-en-fr/SKILL.md +28 -28
  329. package/docs/skill-candidates/v0.0.9/math-science-reasoning/SKILL.md +29 -29
  330. package/docs/skill-candidates/v0.0.9/philosophy-sociology-discernment/SKILL.md +28 -28
  331. package/docs/skill-candidates/v0.0.9/professional-boundary-triage/SKILL.md +40 -40
  332. package/docs/skill-candidates/v0.0.9/release-ethics-gate/SKILL.md +32 -32
  333. package/docs/skill-candidates/v0.0.9/source-authority-reviewer/SKILL.md +31 -31
  334. package/examples/client-configs/claude-code.commands.md +21 -21
  335. package/examples/client-configs/claude-code.project.mcp.json +18 -18
  336. package/examples/client-configs/claude-desktop.macos.json +18 -18
  337. package/examples/client-configs/claude-desktop.windows.json +20 -20
  338. package/examples/client-configs/codex.windows.toml +11 -11
  339. package/examples/client-configs/gemini-code-assist.intellij.mcp.json +18 -18
  340. package/examples/client-configs/gemini.linux.settings.json +21 -21
  341. package/examples/client-configs/gemini.windows.settings.json +23 -23
  342. package/examples/client-configs/generic-stdio.json +16 -16
  343. package/manifests/channels/beta.json +24 -24
  344. package/manifests/channels/stable.json +25 -25
  345. package/network/approved-skills.json +54 -54
  346. package/network/unapproved-skill-candidates.json +110 -110
  347. package/package.json +89 -86
  348. package/scripts/configure-private-registry.mjs +208 -208
  349. package/scripts/lib/private-registry.mjs +97 -97
  350. package/scripts/render-menu-evidence.mjs +196 -130
  351. package/scripts/verify-menu-actions.mjs +112 -107
  352. package/scripts/verify-menu-visual.mjs +90 -0
  353. package/sources.json +11 -11
@@ -1,598 +1,598 @@
1
- #!/usr/bin/env node
2
- import {
3
- access,
4
- mkdir,
5
- readFile,
6
- rename,
7
- rm,
8
- stat,
9
- writeFile,
10
- } from "node:fs/promises";
11
- import { constants as fsConstants } from "node:fs";
12
- import { execFile } from "node:child_process";
13
- import { createHash } from "node:crypto";
14
- import path from "node:path";
15
- import process from "node:process";
16
- import { pathToFileURL } from "node:url";
17
- import { inspect, promisify } from "node:util";
18
-
19
- const DEFAULT_MANUAL_URL = "https://developers.openai.com/codex/codex-manual.md";
20
- const DEFAULT_CACHE_DIR_NAME = "openai-docs-cache";
21
- const CACHE_FILE_NAME = "codex-manual.md";
22
- const OUTLINE_FILE_NAME = "codex-manual.outline.md";
23
- const HASH_HEADER = "x-content-sha256";
24
- const USER_AGENT = "codex-openai-docs";
25
- const execFileAsync = promisify(execFile);
26
-
27
- class ManualFetchError extends Error {
28
- constructor(message, options) {
29
- super(message, options);
30
- this.name = "ManualFetchError";
31
- }
32
- }
33
-
34
- const sha256 = (value) => createHash("sha256").update(value).digest("hex");
35
-
36
- const withTimeout = async (promiseFactory, timeoutMs) => {
37
- const controller = new AbortController();
38
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
39
- try {
40
- return await promiseFactory(controller.signal);
41
- } finally {
42
- clearTimeout(timeout);
43
- }
44
- };
45
-
46
- const proxyConfigured = () =>
47
- process.env.HTTP_PROXY ||
48
- process.env.HTTPS_PROXY ||
49
- process.env.http_proxy ||
50
- process.env.https_proxy;
51
-
52
- const responseHeaders = (headers) => ({
53
- get(name) {
54
- return headers.get(name.toLowerCase()) ?? null;
55
- },
56
- });
57
-
58
- const makeResponse = ({ body, headers, status }) => ({
59
- headers: responseHeaders(headers),
60
- ok: status >= 200 && status < 300,
61
- status,
62
- async text() {
63
- return body;
64
- },
65
- });
66
-
67
- const parseCurlHeaders = (rawHeaders) => {
68
- const normalized = rawHeaders.replace(/\r\n/g, "\n").trim();
69
- const blocks = normalized.split(/\n\n+/).filter(Boolean);
70
- const headerBlock = [...blocks]
71
- .reverse()
72
- .find((block) => block.startsWith("HTTP/"));
73
-
74
- if (!headerBlock) {
75
- throw new ManualFetchError("curl did not return HTTP response headers.");
76
- }
77
-
78
- const [statusLine, ...lines] = headerBlock.split("\n");
79
- const statusMatch = /^HTTP\/\S+\s+(\d{3})/.exec(statusLine);
80
- if (!statusMatch) {
81
- throw new ManualFetchError(
82
- `Could not parse HTTP status from curl response: ${statusLine}`
83
- );
84
- }
85
-
86
- const headers = new Map();
87
- lines.forEach((line) => {
88
- const separator = line.indexOf(":");
89
- if (separator === -1) return;
90
- const name = line.slice(0, separator).trim().toLowerCase();
91
- const value = line.slice(separator + 1).trim();
92
- headers.set(name, value);
93
- });
94
-
95
- return {
96
- headers,
97
- status: Number(statusMatch[1]),
98
- };
99
- };
100
-
101
- const tempFilePath = (cacheDir, suffix) =>
102
- path.join(
103
- cacheDir,
104
- `.fetch-codex-manual-${process.pid}-${Date.now()}-${Math.random()
105
- .toString(16)
106
- .slice(2)}${suffix}`
107
- );
108
-
109
- const requestManualWithCurl = async (url, { cacheDir, method, timeoutMs }) => {
110
- const headerPath = tempFilePath(cacheDir, ".headers");
111
- const bodyPath = tempFilePath(cacheDir, ".body");
112
- const curlNames =
113
- process.platform === "win32" ? ["curl.exe", "curl"] : ["curl"];
114
- const args = [
115
- "--silent",
116
- "--show-error",
117
- "--location",
118
- "--dump-header",
119
- headerPath,
120
- "--output",
121
- bodyPath,
122
- "--user-agent",
123
- USER_AGENT,
124
- "--max-time",
125
- String(Math.max(1, Math.ceil(timeoutMs / 1000))),
126
- ];
127
-
128
- if (method === "HEAD") {
129
- args.push("--head");
130
- } else {
131
- args.push("--request", method);
132
- }
133
- args.push(url);
134
-
135
- let lastError;
136
- for (const curlName of curlNames) {
137
- try {
138
- await execFileAsync(curlName, args, { windowsHide: true });
139
- const [rawHeaders, body] = await Promise.all([
140
- readFile(headerPath, "utf8"),
141
- readFile(bodyPath, "utf8"),
142
- ]);
143
- const { headers, status } = parseCurlHeaders(rawHeaders);
144
- return makeResponse({ body, headers, status });
145
- } catch (error) {
146
- lastError = error;
147
- if (error?.code !== "ENOENT") break;
148
- } finally {
149
- await Promise.all([
150
- rm(headerPath, { force: true }),
151
- rm(bodyPath, { force: true }),
152
- ]);
153
- }
154
- }
155
-
156
- if (lastError?.code === "ENOENT") {
157
- throw new ManualFetchError("curl is unavailable in this environment.", {
158
- cause: lastError,
159
- });
160
- }
161
- throw new ManualFetchError(`${method} ${url} could not be fetched.`, {
162
- cause: lastError,
163
- });
164
- };
165
-
166
- const requestManualWithFetch = async (url, { method, timeoutMs }) => {
167
- if (typeof fetch !== "function") {
168
- throw new ManualFetchError(
169
- "Native fetch is unavailable in this Node runtime."
170
- );
171
- }
172
-
173
- return withTimeout(
174
- (signal) =>
175
- fetch(url, {
176
- method,
177
- headers: { "User-Agent": USER_AGENT },
178
- signal,
179
- }),
180
- timeoutMs
181
- );
182
- };
183
-
184
- const requestManual = async (url, { cacheDir, method, timeoutMs }) => {
185
- const preferCurl = Boolean(proxyConfigured()) || typeof fetch !== "function";
186
- const transports = preferCurl
187
- ? [
188
- () => requestManualWithCurl(url, { cacheDir, method, timeoutMs }),
189
- () => requestManualWithFetch(url, { method, timeoutMs }),
190
- ]
191
- : [
192
- () => requestManualWithFetch(url, { method, timeoutMs }),
193
- () => requestManualWithCurl(url, { cacheDir, method, timeoutMs }),
194
- ];
195
-
196
- let lastError;
197
- for (const transport of transports) {
198
- try {
199
- const response = await transport();
200
- if (!response.ok) {
201
- throw new ManualFetchError(
202
- `${method} ${url} failed with HTTP ${response.status}.`
203
- );
204
- }
205
- return response;
206
- } catch (error) {
207
- lastError = error;
208
- }
209
- }
210
-
211
- throw new ManualFetchError(`${method} ${url} could not be fetched.`, {
212
- cause: lastError,
213
- });
214
- };
215
-
216
- const readHeaderSha = (response) => {
217
- const value = response.headers.get(HASH_HEADER);
218
- if (!value || !/^[a-f0-9]{64}$/i.test(value)) {
219
- throw new ManualFetchError(`Manual response is missing ${HASH_HEADER}.`);
220
- }
221
- return value.toLowerCase();
222
- };
223
-
224
- const nearestExistingParent = async (target) => {
225
- let current = target;
226
- while (true) {
227
- try {
228
- const info = await stat(current);
229
- return info.isDirectory() ? current : null;
230
- } catch (error) {
231
- if (error?.code !== "ENOENT") return null;
232
- }
233
-
234
- const parent = path.dirname(current);
235
- if (parent === current) return null;
236
- current = parent;
237
- }
238
- };
239
-
240
- const usableCacheDir = async (cacheDir) => {
241
- if (!cacheDir) return null;
242
- const resolved = path.resolve(cacheDir);
243
-
244
- try {
245
- const info = await stat(resolved);
246
- if (!info.isDirectory()) return null;
247
- } catch (error) {
248
- if (error?.code !== "ENOENT") return null;
249
- }
250
-
251
- const parent = await nearestExistingParent(resolved);
252
- if (!parent) return null;
253
-
254
- try {
255
- await access(parent, fsConstants.W_OK | fsConstants.X_OK);
256
- } catch {
257
- return null;
258
- }
259
-
260
- return resolved;
261
- };
262
-
263
- const defaultCacheDirCandidates = () => {
264
- const candidates = [];
265
- const seen = new Set();
266
- const pushCandidate = (candidate) => {
267
- if (!candidate || seen.has(candidate)) return;
268
- seen.add(candidate);
269
- candidates.push(candidate);
270
- };
271
-
272
- [process.env.TMPDIR, process.env.TEMP, process.env.TMP].forEach((baseDir) => {
273
- if (baseDir) {
274
- pushCandidate(path.join(baseDir, DEFAULT_CACHE_DIR_NAME));
275
- }
276
- });
277
-
278
- if (process.platform !== "win32") {
279
- pushCandidate(`/private/tmp/${DEFAULT_CACHE_DIR_NAME}`);
280
- pushCandidate(`/tmp/${DEFAULT_CACHE_DIR_NAME}`);
281
- }
282
-
283
- return candidates;
284
- };
285
-
286
- const resolveCacheDir = async (cacheDir) => {
287
- if (cacheDir) {
288
- return usableCacheDir(cacheDir);
289
- }
290
-
291
- for (const candidate of defaultCacheDirCandidates()) {
292
- const usable = await usableCacheDir(candidate);
293
- if (usable) return usable;
294
- }
295
-
296
- return null;
297
- };
298
-
299
- const cacheFilePath = (cacheDir) => path.join(cacheDir, CACHE_FILE_NAME);
300
-
301
- const outlineFilePath = (cacheDir) => path.join(cacheDir, OUTLINE_FILE_NAME);
302
-
303
- const manualLines = (manual) => {
304
- const lines = manual.replace(/\r\n/g, "\n").split("\n");
305
- if (lines[lines.length - 1] === "") lines.pop();
306
- return lines;
307
- };
308
-
309
- const sectionTitle = (rawTitle) =>
310
- rawTitle.replace(/\s+#+\s*$/, "").replace(/\s+/g, " ").trim();
311
-
312
- const buildOutline = (manual) => {
313
- const lines = manualLines(manual);
314
- const headings = [];
315
- let inFence = false;
316
-
317
- lines.forEach((line, index) => {
318
- if (/^\s*(```|~~~)/.test(line)) {
319
- inFence = !inFence;
320
- return;
321
- }
322
- if (inFence) return;
323
-
324
- const match = /^(#{1,6})\s+(.+?)\s*$/.exec(line);
325
- if (!match) return;
326
-
327
- const level = match[1].length;
328
- if (level < 2 || level > 3) return;
329
-
330
- headings.push({
331
- level,
332
- title: sectionTitle(match[2]),
333
- startLine: index + 1,
334
- endLine: lines.length,
335
- });
336
- });
337
-
338
- for (let index = 0; index < headings.length; index += 1) {
339
- const heading = headings[index];
340
- const nextPeer = headings
341
- .slice(index + 1)
342
- .find((candidate) => candidate.level <= heading.level);
343
- if (nextPeer) {
344
- heading.endLine = nextPeer.startLine - 1;
345
- }
346
- }
347
-
348
- if (headings.length === 0) {
349
- return {
350
- headingCount: 0,
351
- lineCount: lines.length,
352
- text: "No markdown headings found.",
353
- };
354
- }
355
-
356
- const minLevel = Math.min(...headings.map((heading) => heading.level));
357
- return {
358
- headingCount: headings.length,
359
- lineCount: lines.length,
360
- text: headings
361
- .map((heading) => {
362
- const indent = " ".repeat(heading.level - minLevel);
363
- return `${indent}- ${heading.title} (lines ${heading.startLine}-${heading.endLine})`;
364
- })
365
- .join("\n"),
366
- };
367
- };
368
-
369
- const outlineMarkdown = (outline) => `# Codex Manual Outline\n\n${outline.text}\n`;
370
-
371
- const manualStatusLine = (status) =>
372
- status.cacheStatus === "hit"
373
- ? "Manual status: local manual was already current."
374
- : "Manual status: local manual was updated.";
375
-
376
- const formatResult = ({ status, outlineText }) =>
377
- [
378
- `Manual path: ${status.manualPath}`,
379
- `Outline path: ${status.outlinePath}`,
380
- manualStatusLine(status),
381
- "",
382
- outlineText,
383
- ].join("\n");
384
-
385
- const readCachedManual = async (cacheDir, expectedSha256) => {
386
- try {
387
- const manual = await readFile(cacheFilePath(cacheDir), "utf8");
388
- return sha256(manual) === expectedSha256 ? manual : null;
389
- } catch {
390
- return null;
391
- }
392
- };
393
-
394
- const writeCachedManual = async (cacheDir, manual) => {
395
- await mkdir(cacheDir, { recursive: true });
396
- const tmpPath = tempFilePath(cacheDir, `.${CACHE_FILE_NAME}.tmp`);
397
- await writeFile(tmpPath, manual, "utf8");
398
- await rename(tmpPath, cacheFilePath(cacheDir));
399
- };
400
-
401
- const writeOutline = async (cacheDir, outlineText) => {
402
- await mkdir(cacheDir, { recursive: true });
403
- const tmpPath = tempFilePath(cacheDir, `.${OUTLINE_FILE_NAME}.tmp`);
404
- await writeFile(tmpPath, outlineText, "utf8");
405
- await rename(tmpPath, outlineFilePath(cacheDir));
406
- };
407
-
408
- const fetchCodexManual = async ({
409
- manualUrl = DEFAULT_MANUAL_URL,
410
- cacheDir,
411
- timeoutMs = 30000,
412
- } = {}) => {
413
- const resolvedCacheDir = await resolveCacheDir(cacheDir);
414
- if (!resolvedCacheDir) {
415
- throw new ManualFetchError(
416
- "Manual cache directory is unavailable; pass --cache-dir to override or use OpenAI Docs MCP fallback."
417
- );
418
- }
419
- await mkdir(resolvedCacheDir, { recursive: true });
420
-
421
- const headResponse = await requestManual(manualUrl, {
422
- cacheDir: resolvedCacheDir,
423
- method: "HEAD",
424
- timeoutMs,
425
- });
426
- const expectedSha256 = readHeaderSha(headResponse);
427
- const manualPath = cacheFilePath(resolvedCacheDir);
428
- const outlinePath = outlineFilePath(resolvedCacheDir);
429
- const checkedAt = new Date().toISOString();
430
-
431
- const cachedManual = await readCachedManual(resolvedCacheDir, expectedSha256);
432
- if (cachedManual !== null) {
433
- const outline = buildOutline(cachedManual);
434
- const outlineText = outlineMarkdown(outline);
435
- await writeOutline(resolvedCacheDir, outlineText);
436
-
437
- return {
438
- outlineText,
439
- status: {
440
- manualUrl,
441
- headerSha256: expectedSha256,
442
- fetchedManualSha256: expectedSha256,
443
- manualHashMatches: true,
444
- cacheStatus: "hit",
445
- cacheDir: resolvedCacheDir,
446
- manualPath,
447
- outlinePath,
448
- checkedAt,
449
- lineCount: outline.lineCount,
450
- headingCount: outline.headingCount,
451
- },
452
- };
453
- }
454
-
455
- const getResponse = await requestManual(manualUrl, {
456
- cacheDir: resolvedCacheDir,
457
- method: "GET",
458
- timeoutMs,
459
- });
460
- const getHeaderSha256 = readHeaderSha(getResponse);
461
- if (getHeaderSha256 !== expectedSha256) {
462
- throw new ManualFetchError(
463
- `${HASH_HEADER} changed between HEAD and GET for ${manualUrl}.`
464
- );
465
- }
466
-
467
- const manualText = await getResponse.text();
468
- const actualSha256 = sha256(manualText);
469
- const manualHashMatches = actualSha256 === expectedSha256;
470
- if (!manualHashMatches) {
471
- throw new ManualFetchError(
472
- `${HASH_HEADER} did not match the fetched manual body for ${manualUrl}.`
473
- );
474
- }
475
-
476
- await writeCachedManual(resolvedCacheDir, manualText);
477
- const outline = buildOutline(manualText);
478
- const outlineText = outlineMarkdown(outline);
479
- await writeOutline(resolvedCacheDir, outlineText);
480
-
481
- return {
482
- outlineText,
483
- status: {
484
- manualUrl,
485
- headerSha256: expectedSha256,
486
- fetchedManualSha256: actualSha256,
487
- manualHashMatches,
488
- cacheStatus: "updated",
489
- cacheDir: resolvedCacheDir,
490
- manualPath,
491
- outlinePath,
492
- checkedAt,
493
- lineCount: outline.lineCount,
494
- headingCount: outline.headingCount,
495
- },
496
- };
497
- };
498
-
499
- const parseArgs = (argv) => {
500
- const args = {
501
- manualUrl: DEFAULT_MANUAL_URL,
502
- cacheDir: undefined,
503
- timeoutMs: 30000,
504
- statusJson: false,
505
- };
506
-
507
- for (let index = 0; index < argv.length; index += 1) {
508
- const arg = argv[index];
509
- if (arg === "--manual-url") {
510
- args.manualUrl = argv[++index];
511
- } else if (arg === "--cache-dir") {
512
- args.cacheDir = argv[++index];
513
- } else if (arg === "--timeout-ms") {
514
- args.timeoutMs = Number(argv[++index]);
515
- } else if (arg === "--status-json") {
516
- args.statusJson = true;
517
- } else {
518
- throw new ManualFetchError(`Unknown argument: ${arg}`);
519
- }
520
- }
521
-
522
- if (!args.manualUrl) {
523
- throw new ManualFetchError("--manual-url cannot be empty.");
524
- }
525
- if (!Number.isFinite(args.timeoutMs) || args.timeoutMs <= 0) {
526
- throw new ManualFetchError("--timeout-ms must be a positive number.");
527
- }
528
-
529
- return args;
530
- };
531
-
532
- const main = async () => {
533
- const args = parseArgs(process.argv.slice(2));
534
- const { outlineText, status } = await fetchCodexManual(args);
535
-
536
- process.stdout.write(formatResult({ status, outlineText }));
537
-
538
- if (args.statusJson) {
539
- console.error(JSON.stringify(status));
540
- }
541
- };
542
-
543
- const envProxyHint = () => {
544
- if (proxyConfigured()) {
545
- return "Hint: proxy env vars are present. This helper prefers `curl` in proxied sessions; if requests still fail, verify `curl` is installed and the proxy configuration is valid.";
546
- }
547
- if (typeof fetch !== "function") {
548
- return "Hint: native fetch is unavailable in this Node runtime. Install `curl` or use a newer Node version to fetch the manual.";
549
- }
550
- if (process.platform === "win32") {
551
- return "Hint: on Windows, pass a cache dir under `%TEMP%` or `%TMP%`.";
552
- }
553
- return null;
554
- };
555
-
556
- const formatErrorDetails = (error) => {
557
- const details = inspect(error, {
558
- breakLength: 120,
559
- colors: false,
560
- compact: false,
561
- depth: 8,
562
- });
563
- if (!error?.cause) {
564
- return details;
565
- }
566
-
567
- return `${details}\n\nCause:\n${inspect(error.cause, {
568
- breakLength: 120,
569
- colors: false,
570
- compact: false,
571
- depth: 8,
572
- })}`;
573
- };
574
-
575
- const isCliEntrypoint = () => {
576
- const entrypoint = process.argv[1];
577
- if (!entrypoint) {
578
- return false;
579
- }
580
-
581
- return pathToFileURL(entrypoint).href === import.meta.url;
582
- };
583
-
584
- if (isCliEntrypoint()) {
585
- main().catch((error) => {
586
- console.error(`Error: ${error.message}`);
587
- const hint = envProxyHint();
588
- if (hint) {
589
- console.error(hint);
590
- }
591
- console.error("");
592
- console.error("Details:");
593
- console.error(formatErrorDetails(error));
594
- process.exitCode = 1;
595
- });
596
- }
597
-
598
- export { DEFAULT_MANUAL_URL, fetchCodexManual };
1
+ #!/usr/bin/env node
2
+ import {
3
+ access,
4
+ mkdir,
5
+ readFile,
6
+ rename,
7
+ rm,
8
+ stat,
9
+ writeFile,
10
+ } from "node:fs/promises";
11
+ import { constants as fsConstants } from "node:fs";
12
+ import { execFile } from "node:child_process";
13
+ import { createHash } from "node:crypto";
14
+ import path from "node:path";
15
+ import process from "node:process";
16
+ import { pathToFileURL } from "node:url";
17
+ import { inspect, promisify } from "node:util";
18
+
19
+ const DEFAULT_MANUAL_URL = "https://developers.openai.com/codex/codex-manual.md";
20
+ const DEFAULT_CACHE_DIR_NAME = "openai-docs-cache";
21
+ const CACHE_FILE_NAME = "codex-manual.md";
22
+ const OUTLINE_FILE_NAME = "codex-manual.outline.md";
23
+ const HASH_HEADER = "x-content-sha256";
24
+ const USER_AGENT = "codex-openai-docs";
25
+ const execFileAsync = promisify(execFile);
26
+
27
+ class ManualFetchError extends Error {
28
+ constructor(message, options) {
29
+ super(message, options);
30
+ this.name = "ManualFetchError";
31
+ }
32
+ }
33
+
34
+ const sha256 = (value) => createHash("sha256").update(value).digest("hex");
35
+
36
+ const withTimeout = async (promiseFactory, timeoutMs) => {
37
+ const controller = new AbortController();
38
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
39
+ try {
40
+ return await promiseFactory(controller.signal);
41
+ } finally {
42
+ clearTimeout(timeout);
43
+ }
44
+ };
45
+
46
+ const proxyConfigured = () =>
47
+ process.env.HTTP_PROXY ||
48
+ process.env.HTTPS_PROXY ||
49
+ process.env.http_proxy ||
50
+ process.env.https_proxy;
51
+
52
+ const responseHeaders = (headers) => ({
53
+ get(name) {
54
+ return headers.get(name.toLowerCase()) ?? null;
55
+ },
56
+ });
57
+
58
+ const makeResponse = ({ body, headers, status }) => ({
59
+ headers: responseHeaders(headers),
60
+ ok: status >= 200 && status < 300,
61
+ status,
62
+ async text() {
63
+ return body;
64
+ },
65
+ });
66
+
67
+ const parseCurlHeaders = (rawHeaders) => {
68
+ const normalized = rawHeaders.replace(/\r\n/g, "\n").trim();
69
+ const blocks = normalized.split(/\n\n+/).filter(Boolean);
70
+ const headerBlock = [...blocks]
71
+ .reverse()
72
+ .find((block) => block.startsWith("HTTP/"));
73
+
74
+ if (!headerBlock) {
75
+ throw new ManualFetchError("curl did not return HTTP response headers.");
76
+ }
77
+
78
+ const [statusLine, ...lines] = headerBlock.split("\n");
79
+ const statusMatch = /^HTTP\/\S+\s+(\d{3})/.exec(statusLine);
80
+ if (!statusMatch) {
81
+ throw new ManualFetchError(
82
+ `Could not parse HTTP status from curl response: ${statusLine}`
83
+ );
84
+ }
85
+
86
+ const headers = new Map();
87
+ lines.forEach((line) => {
88
+ const separator = line.indexOf(":");
89
+ if (separator === -1) return;
90
+ const name = line.slice(0, separator).trim().toLowerCase();
91
+ const value = line.slice(separator + 1).trim();
92
+ headers.set(name, value);
93
+ });
94
+
95
+ return {
96
+ headers,
97
+ status: Number(statusMatch[1]),
98
+ };
99
+ };
100
+
101
+ const tempFilePath = (cacheDir, suffix) =>
102
+ path.join(
103
+ cacheDir,
104
+ `.fetch-codex-manual-${process.pid}-${Date.now()}-${Math.random()
105
+ .toString(16)
106
+ .slice(2)}${suffix}`
107
+ );
108
+
109
+ const requestManualWithCurl = async (url, { cacheDir, method, timeoutMs }) => {
110
+ const headerPath = tempFilePath(cacheDir, ".headers");
111
+ const bodyPath = tempFilePath(cacheDir, ".body");
112
+ const curlNames =
113
+ process.platform === "win32" ? ["curl.exe", "curl"] : ["curl"];
114
+ const args = [
115
+ "--silent",
116
+ "--show-error",
117
+ "--location",
118
+ "--dump-header",
119
+ headerPath,
120
+ "--output",
121
+ bodyPath,
122
+ "--user-agent",
123
+ USER_AGENT,
124
+ "--max-time",
125
+ String(Math.max(1, Math.ceil(timeoutMs / 1000))),
126
+ ];
127
+
128
+ if (method === "HEAD") {
129
+ args.push("--head");
130
+ } else {
131
+ args.push("--request", method);
132
+ }
133
+ args.push(url);
134
+
135
+ let lastError;
136
+ for (const curlName of curlNames) {
137
+ try {
138
+ await execFileAsync(curlName, args, { windowsHide: true });
139
+ const [rawHeaders, body] = await Promise.all([
140
+ readFile(headerPath, "utf8"),
141
+ readFile(bodyPath, "utf8"),
142
+ ]);
143
+ const { headers, status } = parseCurlHeaders(rawHeaders);
144
+ return makeResponse({ body, headers, status });
145
+ } catch (error) {
146
+ lastError = error;
147
+ if (error?.code !== "ENOENT") break;
148
+ } finally {
149
+ await Promise.all([
150
+ rm(headerPath, { force: true }),
151
+ rm(bodyPath, { force: true }),
152
+ ]);
153
+ }
154
+ }
155
+
156
+ if (lastError?.code === "ENOENT") {
157
+ throw new ManualFetchError("curl is unavailable in this environment.", {
158
+ cause: lastError,
159
+ });
160
+ }
161
+ throw new ManualFetchError(`${method} ${url} could not be fetched.`, {
162
+ cause: lastError,
163
+ });
164
+ };
165
+
166
+ const requestManualWithFetch = async (url, { method, timeoutMs }) => {
167
+ if (typeof fetch !== "function") {
168
+ throw new ManualFetchError(
169
+ "Native fetch is unavailable in this Node runtime."
170
+ );
171
+ }
172
+
173
+ return withTimeout(
174
+ (signal) =>
175
+ fetch(url, {
176
+ method,
177
+ headers: { "User-Agent": USER_AGENT },
178
+ signal,
179
+ }),
180
+ timeoutMs
181
+ );
182
+ };
183
+
184
+ const requestManual = async (url, { cacheDir, method, timeoutMs }) => {
185
+ const preferCurl = Boolean(proxyConfigured()) || typeof fetch !== "function";
186
+ const transports = preferCurl
187
+ ? [
188
+ () => requestManualWithCurl(url, { cacheDir, method, timeoutMs }),
189
+ () => requestManualWithFetch(url, { method, timeoutMs }),
190
+ ]
191
+ : [
192
+ () => requestManualWithFetch(url, { method, timeoutMs }),
193
+ () => requestManualWithCurl(url, { cacheDir, method, timeoutMs }),
194
+ ];
195
+
196
+ let lastError;
197
+ for (const transport of transports) {
198
+ try {
199
+ const response = await transport();
200
+ if (!response.ok) {
201
+ throw new ManualFetchError(
202
+ `${method} ${url} failed with HTTP ${response.status}.`
203
+ );
204
+ }
205
+ return response;
206
+ } catch (error) {
207
+ lastError = error;
208
+ }
209
+ }
210
+
211
+ throw new ManualFetchError(`${method} ${url} could not be fetched.`, {
212
+ cause: lastError,
213
+ });
214
+ };
215
+
216
+ const readHeaderSha = (response) => {
217
+ const value = response.headers.get(HASH_HEADER);
218
+ if (!value || !/^[a-f0-9]{64}$/i.test(value)) {
219
+ throw new ManualFetchError(`Manual response is missing ${HASH_HEADER}.`);
220
+ }
221
+ return value.toLowerCase();
222
+ };
223
+
224
+ const nearestExistingParent = async (target) => {
225
+ let current = target;
226
+ while (true) {
227
+ try {
228
+ const info = await stat(current);
229
+ return info.isDirectory() ? current : null;
230
+ } catch (error) {
231
+ if (error?.code !== "ENOENT") return null;
232
+ }
233
+
234
+ const parent = path.dirname(current);
235
+ if (parent === current) return null;
236
+ current = parent;
237
+ }
238
+ };
239
+
240
+ const usableCacheDir = async (cacheDir) => {
241
+ if (!cacheDir) return null;
242
+ const resolved = path.resolve(cacheDir);
243
+
244
+ try {
245
+ const info = await stat(resolved);
246
+ if (!info.isDirectory()) return null;
247
+ } catch (error) {
248
+ if (error?.code !== "ENOENT") return null;
249
+ }
250
+
251
+ const parent = await nearestExistingParent(resolved);
252
+ if (!parent) return null;
253
+
254
+ try {
255
+ await access(parent, fsConstants.W_OK | fsConstants.X_OK);
256
+ } catch {
257
+ return null;
258
+ }
259
+
260
+ return resolved;
261
+ };
262
+
263
+ const defaultCacheDirCandidates = () => {
264
+ const candidates = [];
265
+ const seen = new Set();
266
+ const pushCandidate = (candidate) => {
267
+ if (!candidate || seen.has(candidate)) return;
268
+ seen.add(candidate);
269
+ candidates.push(candidate);
270
+ };
271
+
272
+ [process.env.TMPDIR, process.env.TEMP, process.env.TMP].forEach((baseDir) => {
273
+ if (baseDir) {
274
+ pushCandidate(path.join(baseDir, DEFAULT_CACHE_DIR_NAME));
275
+ }
276
+ });
277
+
278
+ if (process.platform !== "win32") {
279
+ pushCandidate(`/private/tmp/${DEFAULT_CACHE_DIR_NAME}`);
280
+ pushCandidate(`/tmp/${DEFAULT_CACHE_DIR_NAME}`);
281
+ }
282
+
283
+ return candidates;
284
+ };
285
+
286
+ const resolveCacheDir = async (cacheDir) => {
287
+ if (cacheDir) {
288
+ return usableCacheDir(cacheDir);
289
+ }
290
+
291
+ for (const candidate of defaultCacheDirCandidates()) {
292
+ const usable = await usableCacheDir(candidate);
293
+ if (usable) return usable;
294
+ }
295
+
296
+ return null;
297
+ };
298
+
299
+ const cacheFilePath = (cacheDir) => path.join(cacheDir, CACHE_FILE_NAME);
300
+
301
+ const outlineFilePath = (cacheDir) => path.join(cacheDir, OUTLINE_FILE_NAME);
302
+
303
+ const manualLines = (manual) => {
304
+ const lines = manual.replace(/\r\n/g, "\n").split("\n");
305
+ if (lines[lines.length - 1] === "") lines.pop();
306
+ return lines;
307
+ };
308
+
309
+ const sectionTitle = (rawTitle) =>
310
+ rawTitle.replace(/\s+#+\s*$/, "").replace(/\s+/g, " ").trim();
311
+
312
+ const buildOutline = (manual) => {
313
+ const lines = manualLines(manual);
314
+ const headings = [];
315
+ let inFence = false;
316
+
317
+ lines.forEach((line, index) => {
318
+ if (/^\s*(```|~~~)/.test(line)) {
319
+ inFence = !inFence;
320
+ return;
321
+ }
322
+ if (inFence) return;
323
+
324
+ const match = /^(#{1,6})\s+(.+?)\s*$/.exec(line);
325
+ if (!match) return;
326
+
327
+ const level = match[1].length;
328
+ if (level < 2 || level > 3) return;
329
+
330
+ headings.push({
331
+ level,
332
+ title: sectionTitle(match[2]),
333
+ startLine: index + 1,
334
+ endLine: lines.length,
335
+ });
336
+ });
337
+
338
+ for (let index = 0; index < headings.length; index += 1) {
339
+ const heading = headings[index];
340
+ const nextPeer = headings
341
+ .slice(index + 1)
342
+ .find((candidate) => candidate.level <= heading.level);
343
+ if (nextPeer) {
344
+ heading.endLine = nextPeer.startLine - 1;
345
+ }
346
+ }
347
+
348
+ if (headings.length === 0) {
349
+ return {
350
+ headingCount: 0,
351
+ lineCount: lines.length,
352
+ text: "No markdown headings found.",
353
+ };
354
+ }
355
+
356
+ const minLevel = Math.min(...headings.map((heading) => heading.level));
357
+ return {
358
+ headingCount: headings.length,
359
+ lineCount: lines.length,
360
+ text: headings
361
+ .map((heading) => {
362
+ const indent = " ".repeat(heading.level - minLevel);
363
+ return `${indent}- ${heading.title} (lines ${heading.startLine}-${heading.endLine})`;
364
+ })
365
+ .join("\n"),
366
+ };
367
+ };
368
+
369
+ const outlineMarkdown = (outline) => `# Codex Manual Outline\n\n${outline.text}\n`;
370
+
371
+ const manualStatusLine = (status) =>
372
+ status.cacheStatus === "hit"
373
+ ? "Manual status: local manual was already current."
374
+ : "Manual status: local manual was updated.";
375
+
376
+ const formatResult = ({ status, outlineText }) =>
377
+ [
378
+ `Manual path: ${status.manualPath}`,
379
+ `Outline path: ${status.outlinePath}`,
380
+ manualStatusLine(status),
381
+ "",
382
+ outlineText,
383
+ ].join("\n");
384
+
385
+ const readCachedManual = async (cacheDir, expectedSha256) => {
386
+ try {
387
+ const manual = await readFile(cacheFilePath(cacheDir), "utf8");
388
+ return sha256(manual) === expectedSha256 ? manual : null;
389
+ } catch {
390
+ return null;
391
+ }
392
+ };
393
+
394
+ const writeCachedManual = async (cacheDir, manual) => {
395
+ await mkdir(cacheDir, { recursive: true });
396
+ const tmpPath = tempFilePath(cacheDir, `.${CACHE_FILE_NAME}.tmp`);
397
+ await writeFile(tmpPath, manual, "utf8");
398
+ await rename(tmpPath, cacheFilePath(cacheDir));
399
+ };
400
+
401
+ const writeOutline = async (cacheDir, outlineText) => {
402
+ await mkdir(cacheDir, { recursive: true });
403
+ const tmpPath = tempFilePath(cacheDir, `.${OUTLINE_FILE_NAME}.tmp`);
404
+ await writeFile(tmpPath, outlineText, "utf8");
405
+ await rename(tmpPath, outlineFilePath(cacheDir));
406
+ };
407
+
408
+ const fetchCodexManual = async ({
409
+ manualUrl = DEFAULT_MANUAL_URL,
410
+ cacheDir,
411
+ timeoutMs = 30000,
412
+ } = {}) => {
413
+ const resolvedCacheDir = await resolveCacheDir(cacheDir);
414
+ if (!resolvedCacheDir) {
415
+ throw new ManualFetchError(
416
+ "Manual cache directory is unavailable; pass --cache-dir to override or use OpenAI Docs MCP fallback."
417
+ );
418
+ }
419
+ await mkdir(resolvedCacheDir, { recursive: true });
420
+
421
+ const headResponse = await requestManual(manualUrl, {
422
+ cacheDir: resolvedCacheDir,
423
+ method: "HEAD",
424
+ timeoutMs,
425
+ });
426
+ const expectedSha256 = readHeaderSha(headResponse);
427
+ const manualPath = cacheFilePath(resolvedCacheDir);
428
+ const outlinePath = outlineFilePath(resolvedCacheDir);
429
+ const checkedAt = new Date().toISOString();
430
+
431
+ const cachedManual = await readCachedManual(resolvedCacheDir, expectedSha256);
432
+ if (cachedManual !== null) {
433
+ const outline = buildOutline(cachedManual);
434
+ const outlineText = outlineMarkdown(outline);
435
+ await writeOutline(resolvedCacheDir, outlineText);
436
+
437
+ return {
438
+ outlineText,
439
+ status: {
440
+ manualUrl,
441
+ headerSha256: expectedSha256,
442
+ fetchedManualSha256: expectedSha256,
443
+ manualHashMatches: true,
444
+ cacheStatus: "hit",
445
+ cacheDir: resolvedCacheDir,
446
+ manualPath,
447
+ outlinePath,
448
+ checkedAt,
449
+ lineCount: outline.lineCount,
450
+ headingCount: outline.headingCount,
451
+ },
452
+ };
453
+ }
454
+
455
+ const getResponse = await requestManual(manualUrl, {
456
+ cacheDir: resolvedCacheDir,
457
+ method: "GET",
458
+ timeoutMs,
459
+ });
460
+ const getHeaderSha256 = readHeaderSha(getResponse);
461
+ if (getHeaderSha256 !== expectedSha256) {
462
+ throw new ManualFetchError(
463
+ `${HASH_HEADER} changed between HEAD and GET for ${manualUrl}.`
464
+ );
465
+ }
466
+
467
+ const manualText = await getResponse.text();
468
+ const actualSha256 = sha256(manualText);
469
+ const manualHashMatches = actualSha256 === expectedSha256;
470
+ if (!manualHashMatches) {
471
+ throw new ManualFetchError(
472
+ `${HASH_HEADER} did not match the fetched manual body for ${manualUrl}.`
473
+ );
474
+ }
475
+
476
+ await writeCachedManual(resolvedCacheDir, manualText);
477
+ const outline = buildOutline(manualText);
478
+ const outlineText = outlineMarkdown(outline);
479
+ await writeOutline(resolvedCacheDir, outlineText);
480
+
481
+ return {
482
+ outlineText,
483
+ status: {
484
+ manualUrl,
485
+ headerSha256: expectedSha256,
486
+ fetchedManualSha256: actualSha256,
487
+ manualHashMatches,
488
+ cacheStatus: "updated",
489
+ cacheDir: resolvedCacheDir,
490
+ manualPath,
491
+ outlinePath,
492
+ checkedAt,
493
+ lineCount: outline.lineCount,
494
+ headingCount: outline.headingCount,
495
+ },
496
+ };
497
+ };
498
+
499
+ const parseArgs = (argv) => {
500
+ const args = {
501
+ manualUrl: DEFAULT_MANUAL_URL,
502
+ cacheDir: undefined,
503
+ timeoutMs: 30000,
504
+ statusJson: false,
505
+ };
506
+
507
+ for (let index = 0; index < argv.length; index += 1) {
508
+ const arg = argv[index];
509
+ if (arg === "--manual-url") {
510
+ args.manualUrl = argv[++index];
511
+ } else if (arg === "--cache-dir") {
512
+ args.cacheDir = argv[++index];
513
+ } else if (arg === "--timeout-ms") {
514
+ args.timeoutMs = Number(argv[++index]);
515
+ } else if (arg === "--status-json") {
516
+ args.statusJson = true;
517
+ } else {
518
+ throw new ManualFetchError(`Unknown argument: ${arg}`);
519
+ }
520
+ }
521
+
522
+ if (!args.manualUrl) {
523
+ throw new ManualFetchError("--manual-url cannot be empty.");
524
+ }
525
+ if (!Number.isFinite(args.timeoutMs) || args.timeoutMs <= 0) {
526
+ throw new ManualFetchError("--timeout-ms must be a positive number.");
527
+ }
528
+
529
+ return args;
530
+ };
531
+
532
+ const main = async () => {
533
+ const args = parseArgs(process.argv.slice(2));
534
+ const { outlineText, status } = await fetchCodexManual(args);
535
+
536
+ process.stdout.write(formatResult({ status, outlineText }));
537
+
538
+ if (args.statusJson) {
539
+ console.error(JSON.stringify(status));
540
+ }
541
+ };
542
+
543
+ const envProxyHint = () => {
544
+ if (proxyConfigured()) {
545
+ return "Hint: proxy env vars are present. This helper prefers `curl` in proxied sessions; if requests still fail, verify `curl` is installed and the proxy configuration is valid.";
546
+ }
547
+ if (typeof fetch !== "function") {
548
+ return "Hint: native fetch is unavailable in this Node runtime. Install `curl` or use a newer Node version to fetch the manual.";
549
+ }
550
+ if (process.platform === "win32") {
551
+ return "Hint: on Windows, pass a cache dir under `%TEMP%` or `%TMP%`.";
552
+ }
553
+ return null;
554
+ };
555
+
556
+ const formatErrorDetails = (error) => {
557
+ const details = inspect(error, {
558
+ breakLength: 120,
559
+ colors: false,
560
+ compact: false,
561
+ depth: 8,
562
+ });
563
+ if (!error?.cause) {
564
+ return details;
565
+ }
566
+
567
+ return `${details}\n\nCause:\n${inspect(error.cause, {
568
+ breakLength: 120,
569
+ colors: false,
570
+ compact: false,
571
+ depth: 8,
572
+ })}`;
573
+ };
574
+
575
+ const isCliEntrypoint = () => {
576
+ const entrypoint = process.argv[1];
577
+ if (!entrypoint) {
578
+ return false;
579
+ }
580
+
581
+ return pathToFileURL(entrypoint).href === import.meta.url;
582
+ };
583
+
584
+ if (isCliEntrypoint()) {
585
+ main().catch((error) => {
586
+ console.error(`Error: ${error.message}`);
587
+ const hint = envProxyHint();
588
+ if (hint) {
589
+ console.error(hint);
590
+ }
591
+ console.error("");
592
+ console.error("Details:");
593
+ console.error(formatErrorDetails(error));
594
+ process.exitCode = 1;
595
+ });
596
+ }
597
+
598
+ export { DEFAULT_MANUAL_URL, fetchCodexManual };