@haposoft/cafekit 0.16.0-rc.8 → 0.16.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 (297) hide show
  1. package/README.md +116 -27
  2. package/bin/__tests__/codex-hooks-ownership.test.js +239 -0
  3. package/bin/__tests__/codex-hooks.test.js +50 -0
  4. package/bin/__tests__/codex-native.test.js +1882 -70
  5. package/bin/__tests__/develop-contract.test.js +400 -23
  6. package/bin/__tests__/installer-safety.test.js +3 -3
  7. package/bin/__tests__/optional-skill-inventory.test.js +249 -0
  8. package/bin/__tests__/output-styles.test.js +214 -0
  9. package/bin/__tests__/package-inventory.test.js +1735 -98
  10. package/bin/__tests__/runtime-schema.test.js +111 -0
  11. package/bin/__tests__/secret-output-guardrail.test.js +122 -0
  12. package/bin/__tests__/skill-routing-source.test.js +172 -0
  13. package/bin/__tests__/specs-v2-execution-closeout.test.js +1 -1
  14. package/bin/install.js +10 -0
  15. package/bin/lib/codex-install.js +170 -5
  16. package/bin/lib/context.js +14 -0
  17. package/bin/lib/i18n.js +12 -6
  18. package/bin/lib/skill-deps.js +5 -5
  19. package/bin/phases/claude-runtime.js +23 -0
  20. package/bin/phases/claude-settings.js +8 -0
  21. package/bin/phases/codex-hooks.js +156 -0
  22. package/bin/phases/codex-runtime.js +29 -38
  23. package/bin/phases/copy-payload.js +8 -2
  24. package/bin/phases/select-skill-bundles.js +96 -0
  25. package/bin/phases/skill-inventory.js +71 -0
  26. package/bin/phases/skills-setup.js +9 -2
  27. package/bin/phases/write-metadata.js +8 -5
  28. package/package.json +8 -2
  29. package/src/claude/CLAUDE.md +3 -3
  30. package/src/claude/agents/brainstormer.md +52 -69
  31. package/src/claude/agents/code-auditor.md +32 -14
  32. package/src/claude/agents/debugger.md +35 -20
  33. package/src/claude/agents/deployer.md +12 -5
  34. package/src/claude/agents/docs-keeper.md +11 -1
  35. package/src/claude/agents/implementer.md +25 -13
  36. package/src/claude/agents/inspector.md +6 -3
  37. package/src/claude/agents/project-manager.md +1 -1
  38. package/src/claude/agents/researcher.md +26 -55
  39. package/src/claude/agents/spec-maker.md +12 -7
  40. package/src/claude/agents/strategist.md +52 -0
  41. package/src/claude/agents/test-runner.md +117 -132
  42. package/src/claude/agents/ui-ux-designer.md +1 -1
  43. package/src/claude/hooks/__tests__/fixtures/statusline-default.golden +1 -0
  44. package/src/claude/hooks/__tests__/precompact.test.js +158 -0
  45. package/src/claude/hooks/__tests__/spec-gate.test.js +10 -3
  46. package/src/claude/hooks/__tests__/state.test.js +5 -0
  47. package/src/claude/hooks/__tests__/statusline.test.js +196 -0
  48. package/src/claude/hooks/agent.cjs +1 -1
  49. package/src/claude/hooks/docs-sync.cjs +12 -10
  50. package/src/claude/hooks/inspect-block.cjs +1 -1
  51. package/src/claude/hooks/lib/config.cjs +3 -0
  52. package/src/claude/hooks/lib/hook-state-dir.cjs +39 -0
  53. package/src/claude/hooks/lib/secret-keywords.cjs +42 -0
  54. package/src/claude/hooks/precompact.cjs +105 -0
  55. package/src/claude/hooks/rules.cjs +1 -1
  56. package/src/claude/hooks/secret-output-guardrail.cjs +43 -0
  57. package/src/claude/hooks/session.cjs +27 -1
  58. package/src/claude/hooks/spec-gate.cjs +3 -3
  59. package/src/claude/hooks/spec-state.cjs +2 -2
  60. package/src/claude/hooks/state.cjs +1 -1
  61. package/src/claude/hooks/task-scaffold-guard.cjs +1 -1
  62. package/src/claude/hooks/usage.cjs +1 -1
  63. package/src/claude/migration-manifest.json +29 -15
  64. package/src/claude/output-styles/coding-level-0-eli5.md +103 -0
  65. package/src/claude/output-styles/coding-level-1-junior.md +124 -0
  66. package/src/claude/output-styles/coding-level-2-mid.md +146 -0
  67. package/src/claude/output-styles/coding-level-3-senior.md +148 -0
  68. package/src/claude/output-styles/coding-level-4-lead.md +159 -0
  69. package/src/claude/output-styles/coding-level-5-god.md +91 -0
  70. package/src/claude/references/debugger/core-philosophy.md +5 -3
  71. package/src/claude/references/debugger/frontend-verification.md +2 -2
  72. package/src/claude/references/debugger/log-ci-analysis.md +13 -1
  73. package/src/claude/references/debugger/parallel-agent-hydration.md +19 -34
  74. package/src/claude/references/debugger/performance-diagnostics.md +2 -2
  75. package/src/claude/references/debugger/root-cause-tracing.md +37 -6
  76. package/src/claude/references/debugger/side-effect-gate.md +3 -1
  77. package/src/claude/references/debugger/verification-protocol.md +13 -12
  78. package/src/claude/rules/orchestrator.md +7 -1
  79. package/src/claude/rules/process-management.md +39 -0
  80. package/src/claude/rules/review-audit-self-decision.md +48 -0
  81. package/src/claude/rules/skill-domain-routing.md +26 -24
  82. package/src/claude/rules/skill-workflow-routing.md +22 -14
  83. package/src/claude/rules/workflow.md +3 -3
  84. package/src/claude/runtime.json +1 -0
  85. package/src/claude/runtime.schema.json +205 -0
  86. package/src/claude/scripts/generate-skill-catalog.cjs +156 -122
  87. package/src/claude/scripts/provenance.cjs +18 -5
  88. package/src/claude/scripts/workflow-policy.cjs +1 -1
  89. package/src/claude/settings/settings.json +16 -0
  90. package/src/claude/skills/agent-browser/SKILL.md +1 -1
  91. package/src/claude/skills/ai-multimodal/SKILL.md +1 -1
  92. package/src/claude/skills/brainstorm/SKILL.md +193 -172
  93. package/src/claude/skills/brainstorm/references/question-framework.md +105 -167
  94. package/src/claude/skills/chrome-devtools/SKILL.md +1 -1
  95. package/src/claude/skills/code-review/SKILL.md +43 -25
  96. package/src/claude/skills/code-review/references/spec-compliance-review.md +3 -4
  97. package/src/claude/skills/code-review/references/verification-gate.md +1 -1
  98. package/src/claude/skills/debug/SKILL.md +48 -19
  99. package/src/claude/skills/delegate/SKILL.md +1 -1
  100. package/src/claude/skills/develop/SKILL.md +92 -65
  101. package/src/claude/skills/develop/references/parallel-waves.md +36 -63
  102. package/src/claude/skills/develop/references/quality-gate.md +31 -4
  103. package/src/claude/skills/develop/references/subagent-patterns.md +21 -7
  104. package/src/claude/skills/docs/SKILL.md +42 -23
  105. package/src/claude/skills/docs/references/init-workflow.md +4 -4
  106. package/src/claude/skills/docs/references/reconstruct-workflow.md +6 -6
  107. package/src/claude/skills/docs/references/standard-docs-workflow.md +6 -2
  108. package/src/claude/skills/docs/references/summarize-workflow.md +2 -2
  109. package/src/claude/skills/docs/references/update-workflow.md +9 -7
  110. package/src/claude/skills/docs/templates/requirements-as-is.md +1 -1
  111. package/src/claude/skills/docx/SKILL.md +1 -1
  112. package/src/claude/skills/git/SKILL.md +1 -1
  113. package/src/claude/skills/git/references/commit-protocols.md +1 -1
  114. package/src/claude/skills/git/references/finish-branch.md +1 -1
  115. package/src/claude/skills/hotfix/SKILL.md +159 -170
  116. package/src/claude/skills/hotfix/references/diagnosis-protocol.md +14 -9
  117. package/src/claude/skills/hotfix/references/parallel-patterns.md +27 -13
  118. package/src/claude/skills/hotfix/references/prevention-gate.md +5 -0
  119. package/src/claude/skills/hotfix/references/review-cycle.md +21 -15
  120. package/src/claude/skills/hotfix/references/workflow-specialized.md +53 -21
  121. package/src/claude/skills/inspect/SKILL.md +55 -46
  122. package/src/claude/skills/inspect/references/internal-inspection.md +21 -5
  123. package/src/claude/skills/loop/SKILL.md +114 -0
  124. package/src/claude/skills/loop/references/bounded-loop-protocol.md +104 -0
  125. package/src/claude/skills/loop/references/metric-and-guard-contract.md +76 -0
  126. package/src/claude/skills/pdf/SKILL.md +1 -1
  127. package/src/claude/skills/pptx/SKILL.md +1 -1
  128. package/src/claude/skills/question/SKILL.md +16 -13
  129. package/src/claude/skills/research/SKILL.md +70 -43
  130. package/src/claude/skills/route/SKILL.md +94 -0
  131. package/src/claude/skills/route/references/agent-timing.md +46 -0
  132. package/src/claude/skills/route/references/chaining-patterns.md +53 -0
  133. package/src/claude/skills/route/references/task-taxonomy.md +48 -0
  134. package/src/claude/skills/specs/SKILL.md +41 -60
  135. package/src/claude/skills/specs/references/review.md +11 -8
  136. package/src/claude/skills/specs/references/templates.md +34 -18
  137. package/src/claude/skills/specs/templates/requirements-init.md +1 -1
  138. package/src/claude/skills/specs/templates/research.md +2 -2
  139. package/src/claude/skills/sync/SKILL.md +6 -6
  140. package/src/claude/skills/sync/references/sync-protocols.md +1 -1
  141. package/src/claude/skills/test/SKILL.md +120 -120
  142. package/src/claude/skills/test/references/execution-strategy.md +208 -361
  143. package/src/claude/skills/test/references/failure-triage.md +55 -121
  144. package/src/claude/skills/test/references/test-memory.md +20 -34
  145. package/src/claude/skills/ui-ux-pro-max/SKILL.md +1 -1
  146. package/src/claude/skills/web-testing/SKILL.md +1 -1
  147. package/src/claude/skills/xlsx/SKILL.md +1 -1
  148. package/src/claude/status.cjs +135 -33
  149. package/src/codex/AGENTS.md +14 -4
  150. package/src/codex/hooks/docs-sync.cjs +8 -3
  151. package/src/codex/hooks/lib/hook-context.cjs +18 -4
  152. package/src/codex/hooks/rules.cjs +29 -1
  153. package/src/codex/hooks/secret-output-guardrail.cjs +30 -0
  154. package/src/codex/hooks/spec-gate.cjs +3 -8
  155. package/src/codex/hooks/spec-state.cjs +2 -1
  156. package/src/codex/hooks.json +5 -0
  157. package/src/codex/runtime.json +2 -0
  158. package/src/common/.env.example +1 -1
  159. package/src/claude/skills/backend-development/SKILL.md +0 -101
  160. package/src/claude/skills/backend-development/references/backend-api-design.md +0 -495
  161. package/src/claude/skills/backend-development/references/backend-architecture.md +0 -454
  162. package/src/claude/skills/backend-development/references/backend-authentication.md +0 -338
  163. package/src/claude/skills/backend-development/references/backend-code-quality.md +0 -659
  164. package/src/claude/skills/backend-development/references/backend-debugging.md +0 -904
  165. package/src/claude/skills/backend-development/references/backend-devops.md +0 -491
  166. package/src/claude/skills/backend-development/references/backend-mindset.md +0 -387
  167. package/src/claude/skills/backend-development/references/backend-performance.md +0 -397
  168. package/src/claude/skills/backend-development/references/backend-security.md +0 -342
  169. package/src/claude/skills/backend-development/references/backend-technologies.md +0 -256
  170. package/src/claude/skills/backend-development/references/backend-testing.md +0 -429
  171. package/src/claude/skills/devops/.env.example +0 -76
  172. package/src/claude/skills/devops/SKILL.md +0 -102
  173. package/src/claude/skills/devops/references/browser-rendering.md +0 -305
  174. package/src/claude/skills/devops/references/cloudflare-d1-kv.md +0 -123
  175. package/src/claude/skills/devops/references/cloudflare-platform.md +0 -271
  176. package/src/claude/skills/devops/references/cloudflare-r2-storage.md +0 -280
  177. package/src/claude/skills/devops/references/cloudflare-workers-advanced.md +0 -312
  178. package/src/claude/skills/devops/references/cloudflare-workers-apis.md +0 -309
  179. package/src/claude/skills/devops/references/cloudflare-workers-basics.md +0 -418
  180. package/src/claude/skills/devops/references/docker-basics.md +0 -297
  181. package/src/claude/skills/devops/references/docker-compose.md +0 -292
  182. package/src/claude/skills/devops/references/gcloud-platform.md +0 -297
  183. package/src/claude/skills/devops/references/gcloud-services.md +0 -304
  184. package/src/claude/skills/devops/references/kubernetes-basics.md +0 -95
  185. package/src/claude/skills/devops/references/kubernetes-helm-advanced.md +0 -70
  186. package/src/claude/skills/devops/references/kubernetes-helm.md +0 -81
  187. package/src/claude/skills/devops/references/kubernetes-kubectl.md +0 -74
  188. package/src/claude/skills/devops/references/kubernetes-security-advanced.md +0 -94
  189. package/src/claude/skills/devops/references/kubernetes-security.md +0 -89
  190. package/src/claude/skills/devops/references/kubernetes-troubleshooting-advanced.md +0 -74
  191. package/src/claude/skills/devops/references/kubernetes-troubleshooting.md +0 -49
  192. package/src/claude/skills/devops/references/kubernetes-workflows-advanced.md +0 -75
  193. package/src/claude/skills/devops/references/kubernetes-workflows.md +0 -76
  194. package/src/claude/skills/devops/scripts/cloudflare_deploy.py +0 -269
  195. package/src/claude/skills/devops/scripts/docker_optimize.py +0 -332
  196. package/src/claude/skills/devops/scripts/requirements.txt +0 -20
  197. package/src/claude/skills/devops/scripts/tests/requirements.txt +0 -3
  198. package/src/claude/skills/devops/scripts/tests/test_cloudflare_deploy.py +0 -285
  199. package/src/claude/skills/devops/scripts/tests/test_docker_optimize.py +0 -436
  200. package/src/claude/skills/frontend-design/SKILL.md +0 -135
  201. package/src/claude/skills/frontend-design/references/ai-multimodal-overview.md +0 -165
  202. package/src/claude/skills/frontend-design/references/analysis-best-practices.md +0 -80
  203. package/src/claude/skills/frontend-design/references/analysis-prompts.md +0 -141
  204. package/src/claude/skills/frontend-design/references/analysis-techniques.md +0 -118
  205. package/src/claude/skills/frontend-design/references/animejs.md +0 -396
  206. package/src/claude/skills/frontend-design/references/anti-slop-rules.md +0 -103
  207. package/src/claude/skills/frontend-design/references/asset-generation.md +0 -337
  208. package/src/claude/skills/frontend-design/references/bento-motion-engine.md +0 -142
  209. package/src/claude/skills/frontend-design/references/design-extraction-overview.md +0 -71
  210. package/src/claude/skills/frontend-design/references/extraction-best-practices.md +0 -141
  211. package/src/claude/skills/frontend-design/references/extraction-output-templates.md +0 -162
  212. package/src/claude/skills/frontend-design/references/extraction-prompts.md +0 -127
  213. package/src/claude/skills/frontend-design/references/magicui-components.md +0 -129
  214. package/src/claude/skills/frontend-design/references/performance-guardrails.md +0 -169
  215. package/src/claude/skills/frontend-design/references/premium-design-patterns.md +0 -93
  216. package/src/claude/skills/frontend-design/references/redesign-audit-checklist.md +0 -114
  217. package/src/claude/skills/frontend-design/references/technical-accessibility.md +0 -119
  218. package/src/claude/skills/frontend-design/references/technical-best-practices.md +0 -97
  219. package/src/claude/skills/frontend-design/references/technical-optimization.md +0 -44
  220. package/src/claude/skills/frontend-design/references/technical-overview.md +0 -90
  221. package/src/claude/skills/frontend-design/references/technical-workflows.md +0 -150
  222. package/src/claude/skills/frontend-design/references/visual-analysis-overview.md +0 -95
  223. package/src/claude/skills/frontend-design/references/workflow-3d.md +0 -102
  224. package/src/claude/skills/frontend-design/references/workflow-describe.md +0 -87
  225. package/src/claude/skills/frontend-design/references/workflow-immersive.md +0 -87
  226. package/src/claude/skills/frontend-design/references/workflow-quick.md +0 -57
  227. package/src/claude/skills/frontend-design/references/workflow-screenshot.md +0 -63
  228. package/src/claude/skills/frontend-design/references/workflow-video.md +0 -74
  229. package/src/claude/skills/frontend-development/SKILL.md +0 -406
  230. package/src/claude/skills/frontend-development/resources/common-patterns.md +0 -331
  231. package/src/claude/skills/frontend-development/resources/complete-examples.md +0 -872
  232. package/src/claude/skills/frontend-development/resources/component-patterns.md +0 -502
  233. package/src/claude/skills/frontend-development/resources/data-fetching.md +0 -767
  234. package/src/claude/skills/frontend-development/resources/file-organization.md +0 -502
  235. package/src/claude/skills/frontend-development/resources/loading-and-error-states.md +0 -501
  236. package/src/claude/skills/frontend-development/resources/performance.md +0 -406
  237. package/src/claude/skills/frontend-development/resources/routing-guide.md +0 -364
  238. package/src/claude/skills/frontend-development/resources/styling-guide.md +0 -428
  239. package/src/claude/skills/frontend-development/resources/typescript-standards.md +0 -418
  240. package/src/claude/skills/mobile-development/SKILL.md +0 -218
  241. package/src/claude/skills/mobile-development/references/mobile-android.md +0 -604
  242. package/src/claude/skills/mobile-development/references/mobile-best-practices.md +0 -544
  243. package/src/claude/skills/mobile-development/references/mobile-debugging.md +0 -1089
  244. package/src/claude/skills/mobile-development/references/mobile-frameworks.md +0 -465
  245. package/src/claude/skills/mobile-development/references/mobile-ios.md +0 -496
  246. package/src/claude/skills/mobile-development/references/mobile-mindset.md +0 -542
  247. package/src/claude/skills/react-best-practices/AGENTS.md +0 -2249
  248. package/src/claude/skills/react-best-practices/README.md +0 -123
  249. package/src/claude/skills/react-best-practices/SKILL.md +0 -128
  250. package/src/claude/skills/react-best-practices/metadata.json +0 -15
  251. package/src/claude/skills/react-best-practices/rules/_sections.md +0 -46
  252. package/src/claude/skills/react-best-practices/rules/_template.md +0 -28
  253. package/src/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  254. package/src/claude/skills/react-best-practices/rules/advanced-use-latest.md +0 -49
  255. package/src/claude/skills/react-best-practices/rules/async-api-routes.md +0 -38
  256. package/src/claude/skills/react-best-practices/rules/async-defer-await.md +0 -80
  257. package/src/claude/skills/react-best-practices/rules/async-dependencies.md +0 -36
  258. package/src/claude/skills/react-best-practices/rules/async-parallel.md +0 -28
  259. package/src/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +0 -99
  260. package/src/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +0 -59
  261. package/src/claude/skills/react-best-practices/rules/bundle-conditional.md +0 -31
  262. package/src/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +0 -49
  263. package/src/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  264. package/src/claude/skills/react-best-practices/rules/bundle-preload.md +0 -50
  265. package/src/claude/skills/react-best-practices/rules/client-event-listeners.md +0 -74
  266. package/src/claude/skills/react-best-practices/rules/client-swr-dedup.md +0 -56
  267. package/src/claude/skills/react-best-practices/rules/js-batch-dom-css.md +0 -82
  268. package/src/claude/skills/react-best-practices/rules/js-cache-function-results.md +0 -80
  269. package/src/claude/skills/react-best-practices/rules/js-cache-property-access.md +0 -28
  270. package/src/claude/skills/react-best-practices/rules/js-cache-storage.md +0 -70
  271. package/src/claude/skills/react-best-practices/rules/js-combine-iterations.md +0 -32
  272. package/src/claude/skills/react-best-practices/rules/js-early-exit.md +0 -50
  273. package/src/claude/skills/react-best-practices/rules/js-hoist-regexp.md +0 -45
  274. package/src/claude/skills/react-best-practices/rules/js-index-maps.md +0 -37
  275. package/src/claude/skills/react-best-practices/rules/js-length-check-first.md +0 -49
  276. package/src/claude/skills/react-best-practices/rules/js-min-max-loop.md +0 -82
  277. package/src/claude/skills/react-best-practices/rules/js-set-map-lookups.md +0 -24
  278. package/src/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +0 -57
  279. package/src/claude/skills/react-best-practices/rules/rendering-activity.md +0 -26
  280. package/src/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  281. package/src/claude/skills/react-best-practices/rules/rendering-conditional-render.md +0 -40
  282. package/src/claude/skills/react-best-practices/rules/rendering-content-visibility.md +0 -38
  283. package/src/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  284. package/src/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  285. package/src/claude/skills/react-best-practices/rules/rendering-svg-precision.md +0 -28
  286. package/src/claude/skills/react-best-practices/rules/rerender-defer-reads.md +0 -39
  287. package/src/claude/skills/react-best-practices/rules/rerender-dependencies.md +0 -45
  288. package/src/claude/skills/react-best-practices/rules/rerender-derived-state.md +0 -29
  289. package/src/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +0 -74
  290. package/src/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  291. package/src/claude/skills/react-best-practices/rules/rerender-memo.md +0 -44
  292. package/src/claude/skills/react-best-practices/rules/rerender-transitions.md +0 -40
  293. package/src/claude/skills/react-best-practices/rules/server-after-nonblocking.md +0 -73
  294. package/src/claude/skills/react-best-practices/rules/server-cache-lru.md +0 -41
  295. package/src/claude/skills/react-best-practices/rules/server-cache-react.md +0 -26
  296. package/src/claude/skills/react-best-practices/rules/server-parallel-fetching.md +0 -79
  297. package/src/claude/skills/react-best-practices/rules/server-serialization.md +0 -38
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Copyright (c) 2026 Haposoft. MIT License.
4
+ *
5
+ * PreCompact Hook — precompact.cjs
6
+ * Implements: https://docs.anthropic.com/en/docs/claude-code/hooks
7
+ *
8
+ * Compaction drops the transcript that told the session where it was. The
9
+ * existing SessionStart warning tells the operator something was lost but not
10
+ * what, so recovery starts from a blank slate and the session re-derives facts
11
+ * it already had. This hook writes down the machine-checkable anchors just
12
+ * before the drop: branch, HEAD, how dirty the tree is, and which task the
13
+ * packet says is in flight. `session.cjs` prints them back on the compact
14
+ * restart.
15
+ *
16
+ * Only facts the runtime can re-derive are recorded. Nothing here is proof of
17
+ * work and nothing here grants an authorization; a compacted session must still
18
+ * re-ask for a pending confirmation.
19
+ *
20
+ * Storage: the hook state directory (temp when run from source).
21
+ * Exit: 0 always (fail-open).
22
+ */
23
+
24
+ const fs = require('fs');
25
+ const path = require('path');
26
+ const { spawnSync } = require('child_process');
27
+
28
+ const RECOVERY_FILE = 'compact-recovery.json';
29
+
30
+ function gitLine(root, args) {
31
+ const result = spawnSync('git', ['-C', root, ...args], { encoding: 'utf8' });
32
+ if (result.error || result.status !== 0) return null;
33
+ const value = String(result.stdout || '').trim();
34
+ return value === '' ? null : value;
35
+ }
36
+
37
+ function projectRoot(payload) {
38
+ const configured = typeof process.env.CLAUDE_PROJECT_DIR === 'string' ? process.env.CLAUDE_PROJECT_DIR.trim() : '';
39
+ const candidates = [configured, typeof payload.cwd === 'string' ? payload.cwd.trim() : '', process.cwd()];
40
+ for (const candidate of candidates) {
41
+ if (!candidate) continue;
42
+ try { return fs.realpathSync(path.resolve(candidate)); } catch { /* next */ }
43
+ }
44
+ return process.cwd();
45
+ }
46
+
47
+ /** The one task the packet currently says is in flight, if any. */
48
+ function activeTask(root) {
49
+ try {
50
+ const RESOLVER = require(path.join(__dirname, '..', 'scripts', 'spec-resolver.cjs'));
51
+ if (typeof RESOLVER.resolveWorkflowCandidate !== 'function') return null;
52
+ const resolved = RESOLVER.resolveWorkflowCandidate({ projectRoot: root, runtime: {}, target: null });
53
+ if (!resolved || resolved.error || resolved.layoutKind !== 'process-v3') return null;
54
+ const registry = resolved.taskRegistry || {};
55
+ const inProgress = Object.keys(registry).filter((taskPath) => registry[taskPath]?.status === 'in_progress');
56
+ return {
57
+ feature: resolved.featureName || null,
58
+ in_progress: inProgress,
59
+ counts: Object.values(registry).reduce((acc, task) => {
60
+ const status = task?.status || 'pending';
61
+ acc[status] = (acc[status] || 0) + 1;
62
+ return acc;
63
+ }, {}),
64
+ };
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+
70
+ try {
71
+ const stdin = fs.readFileSync(0, 'utf8').trim();
72
+ const payload = stdin ? JSON.parse(stdin) : {};
73
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) process.exit(0);
74
+
75
+ const root = projectRoot(payload);
76
+ const status = gitLine(root, ['status', '--porcelain']);
77
+ const record = {
78
+ captured_at: new Date().toISOString(),
79
+ trigger: typeof payload.trigger === 'string' ? payload.trigger : null,
80
+ session_id: typeof payload.session_id === 'string' ? payload.session_id : null,
81
+ project_root: root,
82
+ branch: gitLine(root, ['rev-parse', '--abbrev-ref', 'HEAD']),
83
+ head: gitLine(root, ['rev-parse', '--short', 'HEAD']),
84
+ dirty_count: status === null ? null : status.split('\n').filter((line) => line.trim() !== '').length,
85
+ workflow: activeTask(root),
86
+ };
87
+
88
+ const dir = require('./lib/hook-state-dir.cjs').hookStateDir();
89
+ fs.mkdirSync(dir, { recursive: true });
90
+ const target = path.join(dir, RECOVERY_FILE);
91
+ const temp = `${target}.${process.pid}.tmp`;
92
+ fs.writeFileSync(temp, `${JSON.stringify(record, null, 2)}\n`);
93
+ fs.renameSync(temp, target);
94
+ process.exit(0);
95
+ } catch (error) {
96
+ try {
97
+ const dir = require('./lib/hook-state-dir.cjs').hookStateDir();
98
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
99
+ fs.appendFileSync(
100
+ path.join(dir, 'hook-log.jsonl'),
101
+ `${JSON.stringify({ ts: new Date().toISOString(), hook: 'precompact', status: 'crash', error: error.message })}\n`,
102
+ );
103
+ } catch (_) { /* fail-open */ }
104
+ process.exit(0);
105
+ }
@@ -93,7 +93,7 @@ try {
93
93
  } catch (e) {
94
94
  try {
95
95
  const fs = require('fs'), p = require('path');
96
- const d = p.join(__dirname, '.logs');
96
+ const d = require('./lib/hook-state-dir.cjs').hookStateDir();
97
97
  if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true });
98
98
  fs.appendFileSync(p.join(d, 'hook-log.jsonl'),
99
99
  JSON.stringify({ ts: new Date().toISOString(), hook: 'rules', status: 'crash', error: e.message }) + '\n');
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Copyright (c) 2026 Haposoft. MIT License.
4
+ *
5
+ * UserPromptSubmit Hook — secret-output-guardrail.cjs
6
+ * Implements: https://docs.anthropic.com/en/docs/claude-code/hooks
7
+ *
8
+ * The privacy hook gates whether a sensitive file may be read. Nothing gated what
9
+ * happens after that approval, so an approved read could still put a raw key into
10
+ * the transcript — where it survives compaction, is written to disk, and is replayed
11
+ * to the model on every later turn. This injects a reminder when the prompt itself is
12
+ * about credential handling.
13
+ *
14
+ * It reads the prompt and never echoes it: no prompt text and no matched value is
15
+ * written out, so the guardrail cannot itself become the leak.
16
+ *
17
+ * Exit: 0 always (fail-open)
18
+ */
19
+
20
+ try {
21
+ const fs = require('fs');
22
+ const { REMINDER, containsSecretKeyword } = require('./lib/secret-keywords.cjs');
23
+
24
+ const stdin = fs.readFileSync(0, 'utf8').trim();
25
+ if (!stdin) process.exit(0);
26
+
27
+ const payload = JSON.parse(stdin);
28
+ const prompt = String(payload.prompt || payload.user_prompt || '');
29
+ if (!containsSecretKeyword(prompt)) process.exit(0);
30
+
31
+ console.log(REMINDER);
32
+ process.exit(0);
33
+
34
+ } catch (e) {
35
+ try {
36
+ const fs = require('fs'), p = require('path');
37
+ const d = require('./lib/hook-state-dir.cjs').hookStateDir();
38
+ if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true });
39
+ fs.appendFileSync(p.join(d, 'hook-log.jsonl'),
40
+ JSON.stringify({ ts: new Date().toISOString(), hook: 'secret-output-guardrail', status: 'crash', error: e.message }) + '\n');
41
+ } catch (_) {}
42
+ process.exit(0);
43
+ }
@@ -261,6 +261,32 @@ try {
261
261
  console.log('Any pending confirmations requested via AskUserQuestion might have been lost.');
262
262
  console.log('Do not proceed without explicitly asking the user again to ensure safety.');
263
263
  console.log('Use AskUserQuestion: "The chat context was compressed. Do I still have permission to proceed?"');
264
+
265
+ // Anchors captured by the PreCompact hook. These are re-derivable facts, not
266
+ // proof and not an authorization: they save the session from rebuilding its
267
+ // bearings, and nothing more.
268
+ try {
269
+ const fs2 = require('fs'), p2 = require('path');
270
+ const file = p2.join(require('./lib/hook-state-dir.cjs').hookStateDir(), 'compact-recovery.json');
271
+ const record = JSON.parse(fs2.readFileSync(file, 'utf8'));
272
+ const parts = [];
273
+ if (record.branch) parts.push(`branch ${record.branch}`);
274
+ if (record.head) parts.push(`HEAD ${record.head}`);
275
+ if (typeof record.dirty_count === 'number') parts.push(`${record.dirty_count} uncommitted path(s)`);
276
+ console.log('\n=== State before compaction ===');
277
+ if (record.captured_at) console.log(`Captured: ${record.captured_at}`);
278
+ if (parts.length) console.log(`Repository: ${parts.join(' | ')}`);
279
+ const workflow = record.workflow;
280
+ if (workflow && workflow.feature) {
281
+ const counts = Object.entries(workflow.counts || {}).map(([k, v]) => `${v} ${k}`).join(', ');
282
+ console.log(`Feature: ${workflow.feature}${counts ? ` (${counts})` : ''}`);
283
+ if (Array.isArray(workflow.in_progress) && workflow.in_progress.length > 0) {
284
+ console.log(`In flight: ${workflow.in_progress.join(', ')}`);
285
+ }
286
+ }
287
+ console.log('Re-read these from disk before acting; they describe the moment before compaction.');
288
+ console.log('=== End of pre-compaction state ===');
289
+ } catch (_) { /* no capture available */ }
264
290
  }
265
291
 
266
292
  process.exit(0);
@@ -269,7 +295,7 @@ try {
269
295
  } catch (e) {
270
296
  try {
271
297
  const fs = require('fs'), p = require('path');
272
- const d = p.join(__dirname, '.logs');
298
+ const d = require('./lib/hook-state-dir.cjs').hookStateDir();
273
299
  if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true });
274
300
  fs.appendFileSync(p.join(d, 'hook-log.jsonl'),
275
301
  JSON.stringify({ ts: new Date().toISOString(), hook: 'session', status: 'crash', error: e.message }) + '\n');
@@ -44,7 +44,7 @@ function projectRoot(payload = {}) {
44
44
 
45
45
  function logCrash(error) {
46
46
  try {
47
- const d = path.join(__dirname, '.logs');
47
+ const d = require('./lib/hook-state-dir.cjs').hookStateDir();
48
48
  if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true });
49
49
  fs.appendFileSync(
50
50
  path.join(d, 'hook-log.jsonl'),
@@ -202,7 +202,7 @@ try {
202
202
  process.exit(0);
203
203
  }
204
204
  const taskRegistry = resolved.taskRegistry || activeSpec.task_registry || {};
205
- const cacheFile = path.join(__dirname, '.logs', 'spec-gate-last.json');
205
+ const cacheFile = path.join(require('./lib/hook-state-dir.cjs').hookStateDir(), 'spec-gate-last.json');
206
206
  const cacheExists = fs.existsSync(cacheFile);
207
207
  let cache = {};
208
208
  if (cacheExists) {
@@ -220,7 +220,7 @@ try {
220
220
  if (staleFlashTasks.length > 0) {
221
221
  process.stdout.write(JSON.stringify({
222
222
  decision: 'block',
223
- reason: `Completion gate: ${staleFlashTasks.length} task(s) marked done with FLASH_UNVERIFIED (${staleFlashTasks.join(', ')}). Run /hapo:test for exact proof, then use explicit sync-finalize.`
223
+ reason: `Completion gate: ${staleFlashTasks.length} task(s) marked done with FLASH_UNVERIFIED (${staleFlashTasks.join(', ')}). Run /cf:test for exact proof, then use explicit sync-finalize.`
224
224
  }) + '\n');
225
225
  process.exit(0);
226
226
  }
@@ -16,7 +16,7 @@ const path = require('path');
16
16
 
17
17
  function logCrash(error) {
18
18
  try {
19
- const d = path.join(__dirname, '.logs');
19
+ const d = require('./lib/hook-state-dir.cjs').hookStateDir();
20
20
  if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true });
21
21
  fs.appendFileSync(
22
22
  path.join(d, 'hook-log.jsonl'),
@@ -182,7 +182,7 @@ try {
182
182
  total: taskEntries.length,
183
183
  featureReceiptPresent,
184
184
  });
185
- const cacheFile = path.join(__dirname, '.logs', 'tollgate-last.txt');
185
+ const cacheFile = path.join(require('./lib/hook-state-dir.cjs').hookStateDir(), 'tollgate-last.txt');
186
186
 
187
187
  let lastKey = '';
188
188
  if (stateKey) {
@@ -280,7 +280,7 @@ try {
280
280
  try {
281
281
  const fs = require('fs');
282
282
  const path = require('path');
283
- const logDir = path.join(__dirname, '.logs');
283
+ const logDir = require('./lib/hook-state-dir.cjs').hookStateDir();
284
284
  if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
285
285
  fs.appendFileSync(
286
286
  path.join(logDir, 'hook-log.jsonl'),
@@ -84,7 +84,7 @@ try {
84
84
  // Never let a hook crash block the user — log and fail-open.
85
85
  try {
86
86
  const fs = require('fs'), p = require('path');
87
- const d = p.join(__dirname, '.logs');
87
+ const d = require('./lib/hook-state-dir.cjs').hookStateDir();
88
88
  if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true });
89
89
  fs.appendFileSync(p.join(d, 'hook-log.jsonl'),
90
90
  JSON.stringify({ ts: new Date().toISOString(), hook: 'task-scaffold-guard', status: 'crash', error: e.message }) + '\n');
@@ -187,7 +187,7 @@ async function main() {
187
187
  try {
188
188
  const fs = require('fs');
189
189
  const p = require('path');
190
- const logDir = p.join(__dirname, '.logs');
190
+ const logDir = require('./lib/hook-state-dir.cjs').hookStateDir();
191
191
  if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
192
192
  fs.appendFileSync(p.join(logDir, 'hook-log.jsonl'),
193
193
  JSON.stringify({ ts: new Date().toISOString(), hook: p.basename(__filename, '.cjs'), status: 'crash', error: e.message }) + '\n');
@@ -7,35 +7,35 @@
7
7
  "skills": {
8
8
  "required": [
9
9
  "agent-browser",
10
- "ai-multimodal",
11
- "backend-development",
12
10
  "brainstorm",
13
11
  "chrome-devtools",
14
12
  "code-review",
15
13
  "debug",
16
14
  "delegate",
17
15
  "develop",
18
- "devops",
19
- "docs",
20
- "docx",
21
- "frontend-design",
22
- "frontend-development",
23
16
  "git",
24
17
  "hotfix",
25
18
  "inspect",
26
- "mobile-development",
27
- "pdf",
28
- "pptx",
19
+ "loop",
29
20
  "question",
30
- "react-best-practices",
31
21
  "research",
22
+ "route",
32
23
  "specs",
33
24
  "sync",
34
25
  "test",
35
26
  "ui-ux-pro-max",
36
- "web-testing",
37
- "xlsx"
38
- ]
27
+ "web-testing"
28
+ ],
29
+ "bundles": {
30
+ "documentSkills": [
31
+ "ai-multimodal",
32
+ "docs",
33
+ "docx",
34
+ "pdf",
35
+ "pptx",
36
+ "xlsx"
37
+ ]
38
+ }
39
39
  },
40
40
  "agents": {
41
41
  "required": [
@@ -51,7 +51,8 @@
51
51
  "researcher.md",
52
52
  "spec-maker.md",
53
53
  "ui-ux-designer.md",
54
- "deployer.md"
54
+ "deployer.md",
55
+ "strategist.md"
55
56
  ]
56
57
  },
57
58
  "scripts": {
@@ -78,6 +79,14 @@
78
79
  "assumed": []
79
80
  },
80
81
  "obsolete": {
82
+ "skills": [
83
+ "backend-development",
84
+ "frontend-development",
85
+ "frontend-design",
86
+ "mobile-development",
87
+ "devops",
88
+ "react-best-practices"
89
+ ],
81
90
  "agents": {
82
91
  "claude": ["agents/god-developer.md"],
83
92
  "codex": ["agents/god_developer.toml"]
@@ -112,12 +121,15 @@
112
121
  "files": [
113
122
  "gitignore",
114
123
  "runtime.json",
124
+ "runtime.schema.json",
115
125
  "status.cjs",
116
126
  "hooks/session.cjs",
127
+ "hooks/precompact.cjs",
117
128
  "hooks/docs-sync.cjs",
118
129
  "hooks/agent.cjs",
119
130
  "hooks/usage.cjs",
120
131
  "hooks/privacy-block.cjs",
132
+ "hooks/secret-output-guardrail.cjs",
121
133
  "hooks/inspect-block.cjs",
122
134
  "hooks/task-scaffold-guard.cjs",
123
135
  "hooks/rules.cjs",
@@ -135,7 +147,9 @@
135
147
  "hooks/lib/config.cjs",
136
148
  "hooks/lib/context.cjs",
137
149
  "hooks/lib/detect.cjs",
150
+ "hooks/lib/hook-state-dir.cjs",
138
151
  "hooks/lib/privacy-command-analysis.cjs",
152
+ "hooks/lib/secret-keywords.cjs",
139
153
  "hooks/lib/runtime-path-safety.cjs"
140
154
  ]
141
155
  },
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: ELI5 Mode (Level 0)
3
+ description: Explain Like I'm 5 - For complete beginners with zero coding experience
4
+ keep-coding-instructions: true
5
+ ---
6
+
7
+ # ELI5 Communication Mode
8
+
9
+ You are teaching someone who has NEVER written a single line of code. They don't know what a "variable" or "function" is. Your mission is to build confidence while teaching.
10
+
11
+ ---
12
+
13
+ ## MANDATORY RULES (You MUST follow ALL of these)
14
+
15
+ ### Language Rules
16
+ 1. **MUST** use at least ONE real-world analogy per concept (cooking recipes, LEGO blocks, labeled boxes, etc.)
17
+ 2. **MUST** define EVERY technical term on first use with a simple comparison
18
+ 3. **MUST** spell out ALL acronyms and explain them (e.g., "API - Application Programming Interface - think of it like a waiter taking your order to the kitchen")
19
+ 4. **MUST** use "we" language to create partnership ("Let's try...", "We can...")
20
+ 5. **MUST** end EVERY response with a check-in: "Does this make sense so far? Any questions about [specific topic]?"
21
+
22
+ ### Code Rules
23
+ 1. **MUST** add a comment explaining what EVERY single line does
24
+ 2. **MUST** keep code blocks to 5-10 lines maximum - break larger examples into steps
25
+ 3. **MUST** use descriptive variable names that read like plain English (e.g., `numberOfApples` not `n`)
26
+ 4. **MUST** show the expected output/result after EVERY code block
27
+ 5. **MUST** start with the SIMPLEST possible version, then add complexity gradually
28
+
29
+ ### Teaching Rules
30
+ 1. **MUST** explain the "why" BEFORE the "how"
31
+ 2. **MUST** use visual metaphors and real-world comparisons
32
+ 3. **MUST** celebrate progress: "Great question!", "You're getting it!"
33
+ 4. **MUST** encourage experimentation: "Try changing X to see what happens!"
34
+ 5. **MUST** preemptively explain anything that might be confusing
35
+
36
+ ---
37
+
38
+ ## FORBIDDEN at this level (You MUST NOT do these)
39
+
40
+ 1. **NEVER** assume they know ANY programming concept
41
+ 2. **NEVER** use technical jargon without explaining it first
42
+ 3. **NEVER** show code blocks longer than 10 lines
43
+ 4. **NEVER** use acronyms without spelling them out AND explaining
44
+ 5. **NEVER** skip steps - break everything into the smallest pieces
45
+ 6. **NEVER** use phrases like "obviously", "simply", "just", "easy"
46
+ 7. **NEVER** make them feel stupid for not knowing something
47
+ 8. **NEVER** dive into code without first explaining the concept
48
+
49
+ ---
50
+
51
+ ## Required Response Structure
52
+
53
+ Every response MUST follow this structure:
54
+
55
+ ### 1. Big Picture (1-2 sentences)
56
+ What are we trying to accomplish? Use everyday language.
57
+
58
+ ### 2. Real-World Analogy
59
+ How does this relate to something they already know? (cooking, organizing, games, etc.)
60
+
61
+ ### 3. Baby Steps
62
+ Break down into the SMALLEST possible steps. Number each step.
63
+ - Show ONE concept at a time
64
+ - Explain before showing code
65
+ - Show code with full comments
66
+ - Show expected output
67
+
68
+ ### 4. Try It Yourself
69
+ Give them something simple to experiment with.
70
+ "Try changing the number 5 to 10 and see what happens!"
71
+
72
+ ### 5. Check-In
73
+ "Does this make sense so far? Any questions about [specific topic we just covered]?"
74
+
75
+ ---
76
+
77
+ ## Example Response Pattern
78
+
79
+ **Question:** "What is a variable?"
80
+
81
+ **Response:**
82
+
83
+ ### Big Picture
84
+ A variable is like a labeled box where you can store information that you want to use later.
85
+
86
+ ### Real-World Analogy
87
+ Imagine you have a box, and you put a sticky note on it that says "Age". Inside the box, you put a piece of paper with the number 25. Whenever you need to know what's in the "Age" box, you just look inside!
88
+
89
+ ### Let's Try It
90
+ ```python
91
+ # This creates a "box" called my_age and puts 25 inside it
92
+ my_age = 25
93
+
94
+ # This looks inside the box and shows us what's there
95
+ print(my_age)
96
+ ```
97
+ **Output:** `25`
98
+
99
+ ### Try It Yourself
100
+ Try changing `25` to your actual age and run it again. What do you see?
101
+
102
+ ### Check-In
103
+ Does this make sense? Any questions about how variables work?
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: Junior Developer Mode (Level 1)
3
+ description: Educational explanations for developers with 0-2 years experience
4
+ keep-coding-instructions: true
5
+ ---
6
+
7
+ # Junior Developer Communication Mode
8
+
9
+ You are mentoring a junior developer who understands basic programming (variables, functions, loops) but is building professional knowledge. They need to understand WHY things work, not just HOW.
10
+
11
+ ---
12
+
13
+ ## MANDATORY RULES (You MUST follow ALL of these)
14
+
15
+ ### Explanation Rules
16
+ 1. **MUST** always explain WHY before showing HOW
17
+ 2. **MUST** explain the reasoning behind every decision ("We use X because...")
18
+ 3. **MUST** point out common mistakes beginners make and how to avoid them
19
+ 4. **MUST** connect new concepts to ones they likely already know
20
+ 5. **MUST** include a "Key Takeaways" section at the end of significant explanations
21
+
22
+ ### Code Rules
23
+ 1. **MUST** add comments for non-obvious logic (not every line, but important parts)
24
+ 2. **MUST** use meaningful variable/function names that express intent
25
+ 3. **MUST** show before/after comparisons when refactoring or improving code
26
+ 4. **MUST** explain what each import/dependency does on first use
27
+ 5. **MUST** keep code blocks under 30 lines - split larger examples
28
+
29
+ ### Teaching Rules
30
+ 1. **MUST** define technical terms on first use (briefly, not ELI5-level)
31
+ 2. **MUST** mention alternative approaches briefly ("Another way is... but we chose X because...")
32
+ 3. **MUST** encourage good habits: testing, documentation, version control
33
+ 4. **MUST** include relevant documentation links for further learning
34
+ 5. **MUST** suggest what to learn next after completing a task
35
+
36
+ ---
37
+
38
+ ## FORBIDDEN at this level (You MUST NOT do these)
39
+
40
+ 1. **NEVER** assume they know advanced patterns (design patterns, architecture)
41
+ 2. **NEVER** skip explaining WHY - always give reasoning
42
+ 3. **NEVER** use advanced jargon without brief explanation (middleware, decorator, etc.)
43
+ 4. **NEVER** show complex solutions without building up to them
44
+ 5. **NEVER** ignore error handling - always show proper error handling
45
+ 6. **NEVER** forget to mention common pitfalls
46
+
47
+ ---
48
+
49
+ ## Required Response Structure
50
+
51
+ ### 1. Context (2-3 sentences)
52
+ What problem are we solving? Why does it matter?
53
+
54
+ ### 2. Approach
55
+ Why are we doing it this way? What are we trying to achieve?
56
+
57
+ ### 3. Implementation
58
+ Step-by-step with explanatory comments.
59
+ - Explain imports and dependencies
60
+ - Show the code with helpful comments
61
+ - Explain non-obvious parts
62
+
63
+ ### 4. Common Pitfalls
64
+ What mistakes do beginners often make here?
65
+
66
+ ### 5. Key Takeaways
67
+ Bullet points of what to remember from this.
68
+
69
+ ### 6. Learn More (Optional)
70
+ Links or concepts to explore for deeper understanding.
71
+
72
+ ---
73
+
74
+ ## Example Response Pattern
75
+
76
+ **Question:** "How do I make an API call?"
77
+
78
+ **Response:**
79
+
80
+ ### Context
81
+ When your app needs data from another service (like weather data or user info), you make an API call. Think of it as your app asking another computer for information.
82
+
83
+ ### Approach
84
+ We'll use the `fetch` API because it's built into modern browsers and Node.js 18+. It returns a Promise, which lets us handle the response when it arrives.
85
+
86
+ ### Implementation
87
+ ```javascript
88
+ // fetch returns a Promise - we use async/await to wait for the response
89
+ async function getUser(userId) {
90
+ try {
91
+ // Make the request to the API
92
+ const response = await fetch(`https://api.example.com/users/${userId}`);
93
+
94
+ // Check if the request was successful (status 200-299)
95
+ if (!response.ok) {
96
+ throw new Error(`HTTP error! status: ${response.status}`);
97
+ }
98
+
99
+ // Parse the JSON body - this is also async
100
+ const user = await response.json();
101
+ return user;
102
+
103
+ } catch (error) {
104
+ // Always handle errors - network can fail, API can be down
105
+ console.error('Failed to fetch user:', error);
106
+ throw error;
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### Common Pitfalls
112
+ - **Forgetting `await`**: Without it, you get a Promise object instead of the data
113
+ - **Not checking `response.ok`**: fetch doesn't throw on 404 or 500 errors
114
+ - **Skipping error handling**: Network requests can fail - always use try/catch
115
+
116
+ ### Key Takeaways
117
+ - Use `async/await` for cleaner Promise handling
118
+ - Always check `response.ok` before parsing
119
+ - Always wrap API calls in try/catch
120
+ - Parse JSON with `response.json()` (also returns a Promise)
121
+
122
+ ### Learn More
123
+ - [MDN: Using Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
124
+ - [JavaScript.info: Async/Await](https://javascript.info/async-await)