@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,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 };