gentyr 1.3.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 (599) hide show
  1. package/.claude/agents/antipattern-hunter.md +176 -0
  2. package/.claude/agents/code-reviewer.md +205 -0
  3. package/.claude/agents/code-writer.md +154 -0
  4. package/.claude/agents/deputy-cto.md +309 -0
  5. package/.claude/agents/feedback-agent.md +101 -0
  6. package/.claude/agents/investigator.md +136 -0
  7. package/.claude/agents/product-manager.md +97 -0
  8. package/.claude/agents/project-manager.md +116 -0
  9. package/.claude/agents/repo-hygiene-expert.md +626 -0
  10. package/.claude/agents/secret-manager.md +324 -0
  11. package/.claude/agents/test-writer.md +354 -0
  12. package/.claude/commands/configure-personas.md +144 -0
  13. package/.claude/commands/cto-report.md +36 -0
  14. package/.claude/commands/demo.md +89 -0
  15. package/.claude/commands/deputy-cto.md +345 -0
  16. package/.claude/commands/hotfix.md +31 -0
  17. package/.claude/commands/overdrive-gentyr.md +167 -0
  18. package/.claude/commands/product-manager.md +32 -0
  19. package/.claude/commands/push-migrations.md +86 -0
  20. package/.claude/commands/push-secrets.md +97 -0
  21. package/.claude/commands/services.json.example +30 -0
  22. package/.claude/commands/setup-gentyr.md +396 -0
  23. package/.claude/commands/show.md +42 -0
  24. package/.claude/commands/spawn-tasks.md +79 -0
  25. package/.claude/commands/toggle-automation-gentyr.md +75 -0
  26. package/.claude/commands/toggle-product-manager.md +19 -0
  27. package/.claude/commands/triage.md +69 -0
  28. package/.claude/hooks/README.md +686 -0
  29. package/.claude/hooks/__tests__/README.md +129 -0
  30. package/.claude/hooks/agent-tracker.js +434 -0
  31. package/.claude/hooks/antipattern-hunter-hook.js +401 -0
  32. package/.claude/hooks/api-key-watcher.js +289 -0
  33. package/.claude/hooks/block-no-verify.js +301 -0
  34. package/.claude/hooks/bypass-approval-hook.js +313 -0
  35. package/.claude/hooks/compliance-checker.js +1309 -0
  36. package/.claude/hooks/config-reader.js +143 -0
  37. package/.claude/hooks/credential-file-guard.js +1139 -0
  38. package/.claude/hooks/credential-health-check.js +168 -0
  39. package/.claude/hooks/credential-sync-hook.js +79 -0
  40. package/.claude/hooks/cto-notification-hook.js +656 -0
  41. package/.claude/hooks/feedback-launcher.js +424 -0
  42. package/.claude/hooks/feedback-orchestrator.js +367 -0
  43. package/.claude/hooks/gentyr-splash.js +47 -0
  44. package/.claude/hooks/gentyr-sync.js +389 -0
  45. package/.claude/hooks/hourly-automation.js +3340 -0
  46. package/.claude/hooks/key-sync.js +899 -0
  47. package/.claude/hooks/lib/approval-utils.js +731 -0
  48. package/.claude/hooks/lib/feature-branch-helper.js +102 -0
  49. package/.claude/hooks/lib/worktree-manager.js +330 -0
  50. package/.claude/hooks/mapping-validator.js +285 -0
  51. package/.claude/hooks/plan-executor.js +398 -0
  52. package/.claude/hooks/playwright-cli-guard.js +104 -0
  53. package/.claude/hooks/playwright-health-check.js +71 -0
  54. package/.claude/hooks/pre-commit-review.js +725 -0
  55. package/.claude/hooks/prompts/local-spec-enforcement.md +310 -0
  56. package/.claude/hooks/prompts/mapping-fix.md +92 -0
  57. package/.claude/hooks/prompts/mapping-review.md +140 -0
  58. package/.claude/hooks/prompts/schema-mapper.md +185 -0
  59. package/.claude/hooks/prompts/spec-enforcement.md +233 -0
  60. package/.claude/hooks/protected-action-approval-hook.js +336 -0
  61. package/.claude/hooks/protected-action-gate.js +562 -0
  62. package/.claude/hooks/protected-actions.json +208 -0
  63. package/.claude/hooks/protected-actions.json.template +122 -0
  64. package/.claude/hooks/quota-monitor.js +490 -0
  65. package/.claude/hooks/reporters/jest-failure-reporter.js +401 -0
  66. package/.claude/hooks/reporters/playwright-failure-reporter.js +446 -0
  67. package/.claude/hooks/reporters/vitest-failure-reporter.js +443 -0
  68. package/.claude/hooks/schema-mapper-hook.js +544 -0
  69. package/.claude/hooks/secret-leak-detector.js +216 -0
  70. package/.claude/hooks/session-reviver.js +514 -0
  71. package/.claude/hooks/slash-command-prefetch.js +1145 -0
  72. package/.claude/hooks/stale-work-detector.js +205 -0
  73. package/.claude/hooks/stop-continue-hook.js +414 -0
  74. package/.claude/hooks/todo-maintenance.js +522 -0
  75. package/.claude/hooks/todo-processing-prompt.md +75 -0
  76. package/.claude/hooks/usage-optimizer.js +791 -0
  77. package/.claude/mcp/README.md +246 -0
  78. package/.claude/settings.json.template +168 -0
  79. package/.mcp.json.template +207 -0
  80. package/CLAUDE.md +340 -0
  81. package/CLAUDE.md.gentyr-section +89 -0
  82. package/LICENSE +21 -0
  83. package/README.md +297 -0
  84. package/cli/commands/init.js +471 -0
  85. package/cli/commands/migrate.js +132 -0
  86. package/cli/commands/protect.js +271 -0
  87. package/cli/commands/scaffold.js +48 -0
  88. package/cli/commands/status.js +133 -0
  89. package/cli/commands/sync.js +101 -0
  90. package/cli/commands/uninstall.js +207 -0
  91. package/cli/index.js +111 -0
  92. package/cli/lib/config-gen.js +214 -0
  93. package/cli/lib/resolve-framework.js +97 -0
  94. package/cli/lib/state.js +140 -0
  95. package/cli/lib/symlinks.js +260 -0
  96. package/docs/AUTOMATION-SYSTEMS.md +484 -0
  97. package/docs/BINARY-PATCHING.md +212 -0
  98. package/docs/CHANGELOG.md +2830 -0
  99. package/docs/CREDENTIAL-DETECTION.md +151 -0
  100. package/docs/CTO-DASHBOARD.md +476 -0
  101. package/docs/DEPLOYMENT-FLOW.md +477 -0
  102. package/docs/DEVELOPER.md +116 -0
  103. package/docs/Executive.md +372 -0
  104. package/docs/SECRET-PATHS.md +77 -0
  105. package/docs/SETUP-GUIDE.md +419 -0
  106. package/docs/STACK.md +109 -0
  107. package/docs/TESTING.md +440 -0
  108. package/docs/assets/claude-logo.svg +3 -0
  109. package/docs/sessions/2026-01-24-spec-suite-implementation.md +190 -0
  110. package/docs/sessions/2026-02-15-feedback-e2e-audit.md +484 -0
  111. package/docs/sessions/2026-02-20-credential-rotation-experiments.md +340 -0
  112. package/docs/sessions/TEST-COVERAGE-REPORT-2026-02-20.md +168 -0
  113. package/docs/shared/EPHEMERAL-STATE-FILES.md +115 -0
  114. package/docs/shared/PROTECTION-SYSTEM.md +341 -0
  115. package/husky/post-commit +10 -0
  116. package/husky/pre-commit +40 -0
  117. package/husky/pre-push +94 -0
  118. package/package.json +43 -0
  119. package/packages/cto-dashboard/package-lock.json +3510 -0
  120. package/packages/cto-dashboard/package.json +41 -0
  121. package/packages/cto-dashboard/pnpm-lock.yaml +2168 -0
  122. package/packages/mcp-servers/dist/__testUtils__/fixtures.d.ts +220 -0
  123. package/packages/mcp-servers/dist/__testUtils__/fixtures.d.ts.map +1 -0
  124. package/packages/mcp-servers/dist/__testUtils__/fixtures.js +376 -0
  125. package/packages/mcp-servers/dist/__testUtils__/fixtures.js.map +1 -0
  126. package/packages/mcp-servers/dist/__testUtils__/index.d.ts +121 -0
  127. package/packages/mcp-servers/dist/__testUtils__/index.d.ts.map +1 -0
  128. package/packages/mcp-servers/dist/__testUtils__/index.js +180 -0
  129. package/packages/mcp-servers/dist/__testUtils__/index.js.map +1 -0
  130. package/packages/mcp-servers/dist/__testUtils__/schemas.d.ts +84 -0
  131. package/packages/mcp-servers/dist/__testUtils__/schemas.d.ts.map +1 -0
  132. package/packages/mcp-servers/dist/__testUtils__/schemas.js +309 -0
  133. package/packages/mcp-servers/dist/__testUtils__/schemas.js.map +1 -0
  134. package/packages/mcp-servers/dist/agent-reports/index.d.ts +7 -0
  135. package/packages/mcp-servers/dist/agent-reports/index.d.ts.map +1 -0
  136. package/packages/mcp-servers/dist/agent-reports/index.js +8 -0
  137. package/packages/mcp-servers/dist/agent-reports/index.js.map +1 -0
  138. package/packages/mcp-servers/dist/agent-reports/server.d.ts +22 -0
  139. package/packages/mcp-servers/dist/agent-reports/server.d.ts.map +1 -0
  140. package/packages/mcp-servers/dist/agent-reports/server.js +535 -0
  141. package/packages/mcp-servers/dist/agent-reports/server.js.map +1 -0
  142. package/packages/mcp-servers/dist/agent-reports/types.d.ts +258 -0
  143. package/packages/mcp-servers/dist/agent-reports/types.d.ts.map +1 -0
  144. package/packages/mcp-servers/dist/agent-reports/types.js +81 -0
  145. package/packages/mcp-servers/dist/agent-reports/types.js.map +1 -0
  146. package/packages/mcp-servers/dist/agent-tracker/index.d.ts +5 -0
  147. package/packages/mcp-servers/dist/agent-tracker/index.d.ts.map +1 -0
  148. package/packages/mcp-servers/dist/agent-tracker/index.js +5 -0
  149. package/packages/mcp-servers/dist/agent-tracker/index.js.map +1 -0
  150. package/packages/mcp-servers/dist/agent-tracker/server.d.ts +12 -0
  151. package/packages/mcp-servers/dist/agent-tracker/server.d.ts.map +1 -0
  152. package/packages/mcp-servers/dist/agent-tracker/server.js +919 -0
  153. package/packages/mcp-servers/dist/agent-tracker/server.js.map +1 -0
  154. package/packages/mcp-servers/dist/agent-tracker/types.d.ts +328 -0
  155. package/packages/mcp-servers/dist/agent-tracker/types.d.ts.map +1 -0
  156. package/packages/mcp-servers/dist/agent-tracker/types.js +128 -0
  157. package/packages/mcp-servers/dist/agent-tracker/types.js.map +1 -0
  158. package/packages/mcp-servers/dist/chrome-bridge/browser-tips.d.ts +27 -0
  159. package/packages/mcp-servers/dist/chrome-bridge/browser-tips.d.ts.map +1 -0
  160. package/packages/mcp-servers/dist/chrome-bridge/browser-tips.js +167 -0
  161. package/packages/mcp-servers/dist/chrome-bridge/browser-tips.js.map +1 -0
  162. package/packages/mcp-servers/dist/chrome-bridge/index.d.ts +6 -0
  163. package/packages/mcp-servers/dist/chrome-bridge/index.d.ts.map +1 -0
  164. package/packages/mcp-servers/dist/chrome-bridge/index.js +6 -0
  165. package/packages/mcp-servers/dist/chrome-bridge/index.js.map +1 -0
  166. package/packages/mcp-servers/dist/chrome-bridge/server.d.ts +13 -0
  167. package/packages/mcp-servers/dist/chrome-bridge/server.d.ts.map +1 -0
  168. package/packages/mcp-servers/dist/chrome-bridge/server.js +959 -0
  169. package/packages/mcp-servers/dist/chrome-bridge/server.js.map +1 -0
  170. package/packages/mcp-servers/dist/chrome-bridge/types.d.ts +41 -0
  171. package/packages/mcp-servers/dist/chrome-bridge/types.d.ts.map +1 -0
  172. package/packages/mcp-servers/dist/chrome-bridge/types.js +8 -0
  173. package/packages/mcp-servers/dist/chrome-bridge/types.js.map +1 -0
  174. package/packages/mcp-servers/dist/cloudflare/index.d.ts +8 -0
  175. package/packages/mcp-servers/dist/cloudflare/index.d.ts.map +1 -0
  176. package/packages/mcp-servers/dist/cloudflare/index.js +8 -0
  177. package/packages/mcp-servers/dist/cloudflare/index.js.map +1 -0
  178. package/packages/mcp-servers/dist/cloudflare/server.d.ts +16 -0
  179. package/packages/mcp-servers/dist/cloudflare/server.d.ts.map +1 -0
  180. package/packages/mcp-servers/dist/cloudflare/server.js +253 -0
  181. package/packages/mcp-servers/dist/cloudflare/server.js.map +1 -0
  182. package/packages/mcp-servers/dist/cloudflare/types.d.ts +141 -0
  183. package/packages/mcp-servers/dist/cloudflare/types.d.ts.map +1 -0
  184. package/packages/mcp-servers/dist/cloudflare/types.js +53 -0
  185. package/packages/mcp-servers/dist/cloudflare/types.js.map +1 -0
  186. package/packages/mcp-servers/dist/codecov/index.d.ts +7 -0
  187. package/packages/mcp-servers/dist/codecov/index.d.ts.map +1 -0
  188. package/packages/mcp-servers/dist/codecov/index.js +7 -0
  189. package/packages/mcp-servers/dist/codecov/index.js.map +1 -0
  190. package/packages/mcp-servers/dist/codecov/server.d.ts +21 -0
  191. package/packages/mcp-servers/dist/codecov/server.d.ts.map +1 -0
  192. package/packages/mcp-servers/dist/codecov/server.js +376 -0
  193. package/packages/mcp-servers/dist/codecov/server.js.map +1 -0
  194. package/packages/mcp-servers/dist/codecov/types.d.ts +269 -0
  195. package/packages/mcp-servers/dist/codecov/types.d.ts.map +1 -0
  196. package/packages/mcp-servers/dist/codecov/types.js +128 -0
  197. package/packages/mcp-servers/dist/codecov/types.js.map +1 -0
  198. package/packages/mcp-servers/dist/cto-report/index.d.ts +9 -0
  199. package/packages/mcp-servers/dist/cto-report/index.d.ts.map +1 -0
  200. package/packages/mcp-servers/dist/cto-report/index.js +9 -0
  201. package/packages/mcp-servers/dist/cto-report/index.js.map +1 -0
  202. package/packages/mcp-servers/dist/cto-report/server.d.ts +14 -0
  203. package/packages/mcp-servers/dist/cto-report/server.d.ts.map +1 -0
  204. package/packages/mcp-servers/dist/cto-report/server.js +859 -0
  205. package/packages/mcp-servers/dist/cto-report/server.js.map +1 -0
  206. package/packages/mcp-servers/dist/cto-report/types.d.ts +213 -0
  207. package/packages/mcp-servers/dist/cto-report/types.d.ts.map +1 -0
  208. package/packages/mcp-servers/dist/cto-report/types.js +29 -0
  209. package/packages/mcp-servers/dist/cto-report/types.js.map +1 -0
  210. package/packages/mcp-servers/dist/cto-reports/index.d.ts +7 -0
  211. package/packages/mcp-servers/dist/cto-reports/index.d.ts.map +1 -0
  212. package/packages/mcp-servers/dist/cto-reports/index.js +8 -0
  213. package/packages/mcp-servers/dist/cto-reports/index.js.map +1 -0
  214. package/packages/mcp-servers/dist/cto-reports/server.d.ts +20 -0
  215. package/packages/mcp-servers/dist/cto-reports/server.d.ts.map +1 -0
  216. package/packages/mcp-servers/dist/cto-reports/server.js +538 -0
  217. package/packages/mcp-servers/dist/cto-reports/server.js.map +1 -0
  218. package/packages/mcp-servers/dist/cto-reports/types.d.ts +236 -0
  219. package/packages/mcp-servers/dist/cto-reports/types.d.ts.map +1 -0
  220. package/packages/mcp-servers/dist/cto-reports/types.js +77 -0
  221. package/packages/mcp-servers/dist/cto-reports/types.js.map +1 -0
  222. package/packages/mcp-servers/dist/deputy-cto/index.d.ts +7 -0
  223. package/packages/mcp-servers/dist/deputy-cto/index.d.ts.map +1 -0
  224. package/packages/mcp-servers/dist/deputy-cto/index.js +8 -0
  225. package/packages/mcp-servers/dist/deputy-cto/index.js.map +1 -0
  226. package/packages/mcp-servers/dist/deputy-cto/server.d.ts +23 -0
  227. package/packages/mcp-servers/dist/deputy-cto/server.d.ts.map +1 -0
  228. package/packages/mcp-servers/dist/deputy-cto/server.js +1700 -0
  229. package/packages/mcp-servers/dist/deputy-cto/server.js.map +1 -0
  230. package/packages/mcp-servers/dist/deputy-cto/types.d.ts +439 -0
  231. package/packages/mcp-servers/dist/deputy-cto/types.d.ts.map +1 -0
  232. package/packages/mcp-servers/dist/deputy-cto/types.js +102 -0
  233. package/packages/mcp-servers/dist/deputy-cto/types.js.map +1 -0
  234. package/packages/mcp-servers/dist/elastic-logs/index.d.ts +5 -0
  235. package/packages/mcp-servers/dist/elastic-logs/index.d.ts.map +1 -0
  236. package/packages/mcp-servers/dist/elastic-logs/index.js +5 -0
  237. package/packages/mcp-servers/dist/elastic-logs/index.js.map +1 -0
  238. package/packages/mcp-servers/dist/elastic-logs/server.d.ts +18 -0
  239. package/packages/mcp-servers/dist/elastic-logs/server.d.ts.map +1 -0
  240. package/packages/mcp-servers/dist/elastic-logs/server.js +259 -0
  241. package/packages/mcp-servers/dist/elastic-logs/server.js.map +1 -0
  242. package/packages/mcp-servers/dist/elastic-logs/types.d.ts +107 -0
  243. package/packages/mcp-servers/dist/elastic-logs/types.d.ts.map +1 -0
  244. package/packages/mcp-servers/dist/elastic-logs/types.js +31 -0
  245. package/packages/mcp-servers/dist/elastic-logs/types.js.map +1 -0
  246. package/packages/mcp-servers/dist/feedback-explorer/index.d.ts +2 -0
  247. package/packages/mcp-servers/dist/feedback-explorer/index.d.ts.map +1 -0
  248. package/packages/mcp-servers/dist/feedback-explorer/index.js +2 -0
  249. package/packages/mcp-servers/dist/feedback-explorer/index.js.map +1 -0
  250. package/packages/mcp-servers/dist/feedback-explorer/server.d.ts +21 -0
  251. package/packages/mcp-servers/dist/feedback-explorer/server.d.ts.map +1 -0
  252. package/packages/mcp-servers/dist/feedback-explorer/server.js +580 -0
  253. package/packages/mcp-servers/dist/feedback-explorer/server.js.map +1 -0
  254. package/packages/mcp-servers/dist/feedback-explorer/types.d.ts +331 -0
  255. package/packages/mcp-servers/dist/feedback-explorer/types.d.ts.map +1 -0
  256. package/packages/mcp-servers/dist/feedback-explorer/types.js +40 -0
  257. package/packages/mcp-servers/dist/feedback-explorer/types.js.map +1 -0
  258. package/packages/mcp-servers/dist/feedback-reporter/index.d.ts +9 -0
  259. package/packages/mcp-servers/dist/feedback-reporter/index.d.ts.map +1 -0
  260. package/packages/mcp-servers/dist/feedback-reporter/index.js +9 -0
  261. package/packages/mcp-servers/dist/feedback-reporter/index.js.map +1 -0
  262. package/packages/mcp-servers/dist/feedback-reporter/server.d.ts +36 -0
  263. package/packages/mcp-servers/dist/feedback-reporter/server.d.ts.map +1 -0
  264. package/packages/mcp-servers/dist/feedback-reporter/server.js +392 -0
  265. package/packages/mcp-servers/dist/feedback-reporter/server.js.map +1 -0
  266. package/packages/mcp-servers/dist/feedback-reporter/types.d.ts +152 -0
  267. package/packages/mcp-servers/dist/feedback-reporter/types.d.ts.map +1 -0
  268. package/packages/mcp-servers/dist/feedback-reporter/types.js +67 -0
  269. package/packages/mcp-servers/dist/feedback-reporter/types.js.map +1 -0
  270. package/packages/mcp-servers/dist/github/index.d.ts +7 -0
  271. package/packages/mcp-servers/dist/github/index.d.ts.map +1 -0
  272. package/packages/mcp-servers/dist/github/index.js +7 -0
  273. package/packages/mcp-servers/dist/github/index.js.map +1 -0
  274. package/packages/mcp-servers/dist/github/server.d.ts +15 -0
  275. package/packages/mcp-servers/dist/github/server.d.ts.map +1 -0
  276. package/packages/mcp-servers/dist/github/server.js +686 -0
  277. package/packages/mcp-servers/dist/github/server.js.map +1 -0
  278. package/packages/mcp-servers/dist/github/types.d.ts +660 -0
  279. package/packages/mcp-servers/dist/github/types.d.ts.map +1 -0
  280. package/packages/mcp-servers/dist/github/types.js +209 -0
  281. package/packages/mcp-servers/dist/github/types.js.map +1 -0
  282. package/packages/mcp-servers/dist/index.d.ts +30 -0
  283. package/packages/mcp-servers/dist/index.d.ts.map +1 -0
  284. package/packages/mcp-servers/dist/index.js +32 -0
  285. package/packages/mcp-servers/dist/index.js.map +1 -0
  286. package/packages/mcp-servers/dist/makerkit-docs/index.d.ts +5 -0
  287. package/packages/mcp-servers/dist/makerkit-docs/index.d.ts.map +1 -0
  288. package/packages/mcp-servers/dist/makerkit-docs/index.js +5 -0
  289. package/packages/mcp-servers/dist/makerkit-docs/index.js.map +1 -0
  290. package/packages/mcp-servers/dist/makerkit-docs/server.d.ts +15 -0
  291. package/packages/mcp-servers/dist/makerkit-docs/server.d.ts.map +1 -0
  292. package/packages/mcp-servers/dist/makerkit-docs/server.js +252 -0
  293. package/packages/mcp-servers/dist/makerkit-docs/server.js.map +1 -0
  294. package/packages/mcp-servers/dist/makerkit-docs/types.d.ts +74 -0
  295. package/packages/mcp-servers/dist/makerkit-docs/types.d.ts.map +1 -0
  296. package/packages/mcp-servers/dist/makerkit-docs/types.js +20 -0
  297. package/packages/mcp-servers/dist/makerkit-docs/types.js.map +1 -0
  298. package/packages/mcp-servers/dist/onepassword/index.d.ts +2 -0
  299. package/packages/mcp-servers/dist/onepassword/index.d.ts.map +1 -0
  300. package/packages/mcp-servers/dist/onepassword/index.js +2 -0
  301. package/packages/mcp-servers/dist/onepassword/index.js.map +1 -0
  302. package/packages/mcp-servers/dist/onepassword/server.d.ts +2 -0
  303. package/packages/mcp-servers/dist/onepassword/server.d.ts.map +1 -0
  304. package/packages/mcp-servers/dist/onepassword/server.js +159 -0
  305. package/packages/mcp-servers/dist/onepassword/server.js.map +1 -0
  306. package/packages/mcp-servers/dist/onepassword/types.d.ts +55 -0
  307. package/packages/mcp-servers/dist/onepassword/types.d.ts.map +1 -0
  308. package/packages/mcp-servers/dist/onepassword/types.js +22 -0
  309. package/packages/mcp-servers/dist/onepassword/types.js.map +1 -0
  310. package/packages/mcp-servers/dist/playwright/helpers.d.ts +20 -0
  311. package/packages/mcp-servers/dist/playwright/helpers.d.ts.map +1 -0
  312. package/packages/mcp-servers/dist/playwright/helpers.js +31 -0
  313. package/packages/mcp-servers/dist/playwright/helpers.js.map +1 -0
  314. package/packages/mcp-servers/dist/playwright/index.d.ts +5 -0
  315. package/packages/mcp-servers/dist/playwright/index.d.ts.map +1 -0
  316. package/packages/mcp-servers/dist/playwright/index.js +5 -0
  317. package/packages/mcp-servers/dist/playwright/index.js.map +1 -0
  318. package/packages/mcp-servers/dist/playwright/server.d.ts +13 -0
  319. package/packages/mcp-servers/dist/playwright/server.d.ts.map +1 -0
  320. package/packages/mcp-servers/dist/playwright/server.js +1201 -0
  321. package/packages/mcp-servers/dist/playwright/server.js.map +1 -0
  322. package/packages/mcp-servers/dist/playwright/types.d.ts +216 -0
  323. package/packages/mcp-servers/dist/playwright/types.d.ts.map +1 -0
  324. package/packages/mcp-servers/dist/playwright/types.js +172 -0
  325. package/packages/mcp-servers/dist/playwright/types.js.map +1 -0
  326. package/packages/mcp-servers/dist/playwright-feedback/browser-manager.d.ts +39 -0
  327. package/packages/mcp-servers/dist/playwright-feedback/browser-manager.d.ts.map +1 -0
  328. package/packages/mcp-servers/dist/playwright-feedback/browser-manager.js +71 -0
  329. package/packages/mcp-servers/dist/playwright-feedback/browser-manager.js.map +1 -0
  330. package/packages/mcp-servers/dist/playwright-feedback/index.d.ts +5 -0
  331. package/packages/mcp-servers/dist/playwright-feedback/index.d.ts.map +1 -0
  332. package/packages/mcp-servers/dist/playwright-feedback/index.js +5 -0
  333. package/packages/mcp-servers/dist/playwright-feedback/index.js.map +1 -0
  334. package/packages/mcp-servers/dist/playwright-feedback/server.d.ts +34 -0
  335. package/packages/mcp-servers/dist/playwright-feedback/server.d.ts.map +1 -0
  336. package/packages/mcp-servers/dist/playwright-feedback/server.js +538 -0
  337. package/packages/mcp-servers/dist/playwright-feedback/server.js.map +1 -0
  338. package/packages/mcp-servers/dist/playwright-feedback/types.d.ts +305 -0
  339. package/packages/mcp-servers/dist/playwright-feedback/types.d.ts.map +1 -0
  340. package/packages/mcp-servers/dist/playwright-feedback/types.js +123 -0
  341. package/packages/mcp-servers/dist/playwright-feedback/types.js.map +1 -0
  342. package/packages/mcp-servers/dist/product-manager/server.d.ts +17 -0
  343. package/packages/mcp-servers/dist/product-manager/server.d.ts.map +1 -0
  344. package/packages/mcp-servers/dist/product-manager/server.js +690 -0
  345. package/packages/mcp-servers/dist/product-manager/server.js.map +1 -0
  346. package/packages/mcp-servers/dist/product-manager/types.d.ts +286 -0
  347. package/packages/mcp-servers/dist/product-manager/types.d.ts.map +1 -0
  348. package/packages/mcp-servers/dist/product-manager/types.js +99 -0
  349. package/packages/mcp-servers/dist/product-manager/types.js.map +1 -0
  350. package/packages/mcp-servers/dist/programmatic-feedback/index.d.ts +7 -0
  351. package/packages/mcp-servers/dist/programmatic-feedback/index.d.ts.map +1 -0
  352. package/packages/mcp-servers/dist/programmatic-feedback/index.js +7 -0
  353. package/packages/mcp-servers/dist/programmatic-feedback/index.js.map +1 -0
  354. package/packages/mcp-servers/dist/programmatic-feedback/sandbox.d.ts +19 -0
  355. package/packages/mcp-servers/dist/programmatic-feedback/sandbox.d.ts.map +1 -0
  356. package/packages/mcp-servers/dist/programmatic-feedback/sandbox.js +174 -0
  357. package/packages/mcp-servers/dist/programmatic-feedback/sandbox.js.map +1 -0
  358. package/packages/mcp-servers/dist/programmatic-feedback/server.d.ts +35 -0
  359. package/packages/mcp-servers/dist/programmatic-feedback/server.d.ts.map +1 -0
  360. package/packages/mcp-servers/dist/programmatic-feedback/server.js +465 -0
  361. package/packages/mcp-servers/dist/programmatic-feedback/server.js.map +1 -0
  362. package/packages/mcp-servers/dist/programmatic-feedback/types.d.ts +127 -0
  363. package/packages/mcp-servers/dist/programmatic-feedback/types.d.ts.map +1 -0
  364. package/packages/mcp-servers/dist/programmatic-feedback/types.js +80 -0
  365. package/packages/mcp-servers/dist/programmatic-feedback/types.js.map +1 -0
  366. package/packages/mcp-servers/dist/render/index.d.ts +8 -0
  367. package/packages/mcp-servers/dist/render/index.d.ts.map +1 -0
  368. package/packages/mcp-servers/dist/render/index.js +8 -0
  369. package/packages/mcp-servers/dist/render/index.js.map +1 -0
  370. package/packages/mcp-servers/dist/render/server.d.ts +15 -0
  371. package/packages/mcp-servers/dist/render/server.d.ts.map +1 -0
  372. package/packages/mcp-servers/dist/render/server.js +428 -0
  373. package/packages/mcp-servers/dist/render/server.js.map +1 -0
  374. package/packages/mcp-servers/dist/render/types.d.ts +273 -0
  375. package/packages/mcp-servers/dist/render/types.d.ts.map +1 -0
  376. package/packages/mcp-servers/dist/render/types.js +102 -0
  377. package/packages/mcp-servers/dist/render/types.js.map +1 -0
  378. package/packages/mcp-servers/dist/resend/index.d.ts +7 -0
  379. package/packages/mcp-servers/dist/resend/index.d.ts.map +1 -0
  380. package/packages/mcp-servers/dist/resend/index.js +7 -0
  381. package/packages/mcp-servers/dist/resend/index.js.map +1 -0
  382. package/packages/mcp-servers/dist/resend/server.d.ts +15 -0
  383. package/packages/mcp-servers/dist/resend/server.d.ts.map +1 -0
  384. package/packages/mcp-servers/dist/resend/server.js +298 -0
  385. package/packages/mcp-servers/dist/resend/server.js.map +1 -0
  386. package/packages/mcp-servers/dist/resend/types.d.ts +222 -0
  387. package/packages/mcp-servers/dist/resend/types.d.ts.map +1 -0
  388. package/packages/mcp-servers/dist/resend/types.js +58 -0
  389. package/packages/mcp-servers/dist/resend/types.js.map +1 -0
  390. package/packages/mcp-servers/dist/review-queue/index.d.ts +6 -0
  391. package/packages/mcp-servers/dist/review-queue/index.d.ts.map +1 -0
  392. package/packages/mcp-servers/dist/review-queue/index.js +6 -0
  393. package/packages/mcp-servers/dist/review-queue/index.js.map +1 -0
  394. package/packages/mcp-servers/dist/review-queue/server.d.ts +17 -0
  395. package/packages/mcp-servers/dist/review-queue/server.d.ts.map +1 -0
  396. package/packages/mcp-servers/dist/review-queue/server.js +348 -0
  397. package/packages/mcp-servers/dist/review-queue/server.js.map +1 -0
  398. package/packages/mcp-servers/dist/review-queue/types.d.ts +162 -0
  399. package/packages/mcp-servers/dist/review-queue/types.d.ts.map +1 -0
  400. package/packages/mcp-servers/dist/review-queue/types.js +56 -0
  401. package/packages/mcp-servers/dist/review-queue/types.js.map +1 -0
  402. package/packages/mcp-servers/dist/secret-sync/server.d.ts +19 -0
  403. package/packages/mcp-servers/dist/secret-sync/server.d.ts.map +1 -0
  404. package/packages/mcp-servers/dist/secret-sync/server.js +1139 -0
  405. package/packages/mcp-servers/dist/secret-sync/server.js.map +1 -0
  406. package/packages/mcp-servers/dist/secret-sync/types.d.ts +442 -0
  407. package/packages/mcp-servers/dist/secret-sync/types.d.ts.map +1 -0
  408. package/packages/mcp-servers/dist/secret-sync/types.js +113 -0
  409. package/packages/mcp-servers/dist/secret-sync/types.js.map +1 -0
  410. package/packages/mcp-servers/dist/session-events/index.d.ts +5 -0
  411. package/packages/mcp-servers/dist/session-events/index.d.ts.map +1 -0
  412. package/packages/mcp-servers/dist/session-events/index.js +5 -0
  413. package/packages/mcp-servers/dist/session-events/index.js.map +1 -0
  414. package/packages/mcp-servers/dist/session-events/server.d.ts +11 -0
  415. package/packages/mcp-servers/dist/session-events/server.d.ts.map +1 -0
  416. package/packages/mcp-servers/dist/session-events/server.js +290 -0
  417. package/packages/mcp-servers/dist/session-events/server.js.map +1 -0
  418. package/packages/mcp-servers/dist/session-events/types.d.ts +213 -0
  419. package/packages/mcp-servers/dist/session-events/types.d.ts.map +1 -0
  420. package/packages/mcp-servers/dist/session-events/types.js +69 -0
  421. package/packages/mcp-servers/dist/session-events/types.js.map +1 -0
  422. package/packages/mcp-servers/dist/session-restart/index.d.ts +9 -0
  423. package/packages/mcp-servers/dist/session-restart/index.d.ts.map +1 -0
  424. package/packages/mcp-servers/dist/session-restart/index.js +9 -0
  425. package/packages/mcp-servers/dist/session-restart/index.js.map +1 -0
  426. package/packages/mcp-servers/dist/session-restart/server.d.ts +20 -0
  427. package/packages/mcp-servers/dist/session-restart/server.d.ts.map +1 -0
  428. package/packages/mcp-servers/dist/session-restart/server.js +411 -0
  429. package/packages/mcp-servers/dist/session-restart/server.js.map +1 -0
  430. package/packages/mcp-servers/dist/session-restart/types.d.ts +26 -0
  431. package/packages/mcp-servers/dist/session-restart/types.d.ts.map +1 -0
  432. package/packages/mcp-servers/dist/session-restart/types.js +16 -0
  433. package/packages/mcp-servers/dist/session-restart/types.js.map +1 -0
  434. package/packages/mcp-servers/dist/setup-helper/index.d.ts +5 -0
  435. package/packages/mcp-servers/dist/setup-helper/index.d.ts.map +1 -0
  436. package/packages/mcp-servers/dist/setup-helper/index.js +5 -0
  437. package/packages/mcp-servers/dist/setup-helper/index.js.map +1 -0
  438. package/packages/mcp-servers/dist/setup-helper/server.d.ts +14 -0
  439. package/packages/mcp-servers/dist/setup-helper/server.d.ts.map +1 -0
  440. package/packages/mcp-servers/dist/setup-helper/server.js +454 -0
  441. package/packages/mcp-servers/dist/setup-helper/server.js.map +1 -0
  442. package/packages/mcp-servers/dist/setup-helper/types.d.ts +81 -0
  443. package/packages/mcp-servers/dist/setup-helper/types.d.ts.map +1 -0
  444. package/packages/mcp-servers/dist/setup-helper/types.js +41 -0
  445. package/packages/mcp-servers/dist/setup-helper/types.js.map +1 -0
  446. package/packages/mcp-servers/dist/shared/audited-server.d.ts +31 -0
  447. package/packages/mcp-servers/dist/shared/audited-server.d.ts.map +1 -0
  448. package/packages/mcp-servers/dist/shared/audited-server.js +126 -0
  449. package/packages/mcp-servers/dist/shared/audited-server.js.map +1 -0
  450. package/packages/mcp-servers/dist/shared/constants.d.ts +26 -0
  451. package/packages/mcp-servers/dist/shared/constants.d.ts.map +1 -0
  452. package/packages/mcp-servers/dist/shared/constants.js +41 -0
  453. package/packages/mcp-servers/dist/shared/constants.js.map +1 -0
  454. package/packages/mcp-servers/dist/shared/index.d.ts +6 -0
  455. package/packages/mcp-servers/dist/shared/index.d.ts.map +1 -0
  456. package/packages/mcp-servers/dist/shared/index.js +6 -0
  457. package/packages/mcp-servers/dist/shared/index.js.map +1 -0
  458. package/packages/mcp-servers/dist/shared/readonly-db.d.ts +11 -0
  459. package/packages/mcp-servers/dist/shared/readonly-db.d.ts.map +1 -0
  460. package/packages/mcp-servers/dist/shared/readonly-db.js +47 -0
  461. package/packages/mcp-servers/dist/shared/readonly-db.js.map +1 -0
  462. package/packages/mcp-servers/dist/shared/resolve-framework.d.ts +20 -0
  463. package/packages/mcp-servers/dist/shared/resolve-framework.d.ts.map +1 -0
  464. package/packages/mcp-servers/dist/shared/resolve-framework.js +65 -0
  465. package/packages/mcp-servers/dist/shared/resolve-framework.js.map +1 -0
  466. package/packages/mcp-servers/dist/shared/server.d.ts +86 -0
  467. package/packages/mcp-servers/dist/shared/server.d.ts.map +1 -0
  468. package/packages/mcp-servers/dist/shared/server.js +291 -0
  469. package/packages/mcp-servers/dist/shared/server.js.map +1 -0
  470. package/packages/mcp-servers/dist/shared/types.d.ts +113 -0
  471. package/packages/mcp-servers/dist/shared/types.d.ts.map +1 -0
  472. package/packages/mcp-servers/dist/shared/types.js +36 -0
  473. package/packages/mcp-servers/dist/shared/types.js.map +1 -0
  474. package/packages/mcp-servers/dist/show/server.d.ts +12 -0
  475. package/packages/mcp-servers/dist/show/server.d.ts.map +1 -0
  476. package/packages/mcp-servers/dist/show/server.js +97 -0
  477. package/packages/mcp-servers/dist/show/server.js.map +1 -0
  478. package/packages/mcp-servers/dist/show/types.d.ts +19 -0
  479. package/packages/mcp-servers/dist/show/types.d.ts.map +1 -0
  480. package/packages/mcp-servers/dist/show/types.js +32 -0
  481. package/packages/mcp-servers/dist/show/types.js.map +1 -0
  482. package/packages/mcp-servers/dist/specs-browser/index.d.ts +5 -0
  483. package/packages/mcp-servers/dist/specs-browser/index.d.ts.map +1 -0
  484. package/packages/mcp-servers/dist/specs-browser/index.js +5 -0
  485. package/packages/mcp-servers/dist/specs-browser/index.js.map +1 -0
  486. package/packages/mcp-servers/dist/specs-browser/server.d.ts +13 -0
  487. package/packages/mcp-servers/dist/specs-browser/server.d.ts.map +1 -0
  488. package/packages/mcp-servers/dist/specs-browser/server.js +692 -0
  489. package/packages/mcp-servers/dist/specs-browser/server.js.map +1 -0
  490. package/packages/mcp-servers/dist/specs-browser/types.d.ts +337 -0
  491. package/packages/mcp-servers/dist/specs-browser/types.d.ts.map +1 -0
  492. package/packages/mcp-servers/dist/specs-browser/types.js +134 -0
  493. package/packages/mcp-servers/dist/specs-browser/types.js.map +1 -0
  494. package/packages/mcp-servers/dist/supabase/index.d.ts +10 -0
  495. package/packages/mcp-servers/dist/supabase/index.d.ts.map +1 -0
  496. package/packages/mcp-servers/dist/supabase/index.js +10 -0
  497. package/packages/mcp-servers/dist/supabase/index.js.map +1 -0
  498. package/packages/mcp-servers/dist/supabase/server.d.ts +20 -0
  499. package/packages/mcp-servers/dist/supabase/server.d.ts.map +1 -0
  500. package/packages/mcp-servers/dist/supabase/server.js +451 -0
  501. package/packages/mcp-servers/dist/supabase/server.js.map +1 -0
  502. package/packages/mcp-servers/dist/supabase/types.d.ts +196 -0
  503. package/packages/mcp-servers/dist/supabase/types.d.ts.map +1 -0
  504. package/packages/mcp-servers/dist/supabase/types.js +76 -0
  505. package/packages/mcp-servers/dist/supabase/types.js.map +1 -0
  506. package/packages/mcp-servers/dist/todo-db/index.d.ts +5 -0
  507. package/packages/mcp-servers/dist/todo-db/index.d.ts.map +1 -0
  508. package/packages/mcp-servers/dist/todo-db/index.js +5 -0
  509. package/packages/mcp-servers/dist/todo-db/index.js.map +1 -0
  510. package/packages/mcp-servers/dist/todo-db/server.d.ts +13 -0
  511. package/packages/mcp-servers/dist/todo-db/server.d.ts.map +1 -0
  512. package/packages/mcp-servers/dist/todo-db/server.js +649 -0
  513. package/packages/mcp-servers/dist/todo-db/server.js.map +1 -0
  514. package/packages/mcp-servers/dist/todo-db/types.d.ts +225 -0
  515. package/packages/mcp-servers/dist/todo-db/types.d.ts.map +1 -0
  516. package/packages/mcp-servers/dist/todo-db/types.js +69 -0
  517. package/packages/mcp-servers/dist/todo-db/types.js.map +1 -0
  518. package/packages/mcp-servers/dist/user-feedback/index.d.ts +7 -0
  519. package/packages/mcp-servers/dist/user-feedback/index.d.ts.map +1 -0
  520. package/packages/mcp-servers/dist/user-feedback/index.js +8 -0
  521. package/packages/mcp-servers/dist/user-feedback/index.js.map +1 -0
  522. package/packages/mcp-servers/dist/user-feedback/server.d.ts +25 -0
  523. package/packages/mcp-servers/dist/user-feedback/server.d.ts.map +1 -0
  524. package/packages/mcp-servers/dist/user-feedback/server.js +914 -0
  525. package/packages/mcp-servers/dist/user-feedback/server.js.map +1 -0
  526. package/packages/mcp-servers/dist/user-feedback/types.d.ts +415 -0
  527. package/packages/mcp-servers/dist/user-feedback/types.d.ts.map +1 -0
  528. package/packages/mcp-servers/dist/user-feedback/types.js +132 -0
  529. package/packages/mcp-servers/dist/user-feedback/types.js.map +1 -0
  530. package/packages/mcp-servers/dist/vercel/index.d.ts +9 -0
  531. package/packages/mcp-servers/dist/vercel/index.d.ts.map +1 -0
  532. package/packages/mcp-servers/dist/vercel/index.js +9 -0
  533. package/packages/mcp-servers/dist/vercel/index.js.map +1 -0
  534. package/packages/mcp-servers/dist/vercel/server.d.ts +17 -0
  535. package/packages/mcp-servers/dist/vercel/server.d.ts.map +1 -0
  536. package/packages/mcp-servers/dist/vercel/server.js +265 -0
  537. package/packages/mcp-servers/dist/vercel/server.js.map +1 -0
  538. package/packages/mcp-servers/dist/vercel/types.d.ts +189 -0
  539. package/packages/mcp-servers/dist/vercel/types.d.ts.map +1 -0
  540. package/packages/mcp-servers/dist/vercel/types.js +65 -0
  541. package/packages/mcp-servers/dist/vercel/types.js.map +1 -0
  542. package/packages/mcp-servers/package-lock.json +3765 -0
  543. package/packages/mcp-servers/package.json +64 -0
  544. package/packages/mcp-servers/test/reporters/test-failure-reporter.ts +372 -0
  545. package/packages/mcp-servers/vitest.config.ts +27 -0
  546. package/scripts/__tests__/README.md +163 -0
  547. package/scripts/apply-credential-hardening.sh +271 -0
  548. package/scripts/credential-providers/manual.js +56 -0
  549. package/scripts/credential-providers/onepassword.js +85 -0
  550. package/scripts/credential-providers/provider-interface.js +104 -0
  551. package/scripts/encrypt-credential.js +337 -0
  552. package/scripts/feedback-launcher.js +338 -0
  553. package/scripts/feedback-orchestrator.js +373 -0
  554. package/scripts/fix-mcp-launcher-issues.sh +97 -0
  555. package/scripts/force-spawn-tasks.js +651 -0
  556. package/scripts/force-triage-reports.js +560 -0
  557. package/scripts/generate-protected-actions-spec.js +142 -0
  558. package/scripts/generate-proxy-certs.sh +158 -0
  559. package/scripts/grant-chrome-ext-permissions.sh +242 -0
  560. package/scripts/mcp-launcher.js +125 -0
  561. package/scripts/merge-settings.cjs +167 -0
  562. package/scripts/patch-clawd.py +844 -0
  563. package/scripts/patch-credential-cache.py +313 -0
  564. package/scripts/patches/credential-file-guard-patched.mjs +573 -0
  565. package/scripts/patches/credential-file-guard.js.patched +573 -0
  566. package/scripts/patches/verify-tokenizer.mjs +132 -0
  567. package/scripts/protect-framework.sh +478 -0
  568. package/scripts/readme-chrome.template +12 -0
  569. package/scripts/reap-completed-agents.js +439 -0
  570. package/scripts/reinstall.sh +86 -0
  571. package/scripts/resign-node.sh +185 -0
  572. package/scripts/rotation-proxy.js +656 -0
  573. package/scripts/rotation-stress-monitor.mjs +862 -0
  574. package/scripts/setup-automation-service.sh +648 -0
  575. package/scripts/setup-check.js +251 -0
  576. package/scripts/watch-claude-version.js +142 -0
  577. package/specs/framework/CORE-INVARIANTS.md +161 -0
  578. package/specs/patterns/AGENT-PATTERNS.md +223 -0
  579. package/specs/patterns/HOOK-PATTERNS.md +242 -0
  580. package/specs/patterns/MCP-SERVER-PATTERNS.md +144 -0
  581. package/templates/config/gitignore.template +14 -0
  582. package/templates/config/merge-chain-check.yml.template +51 -0
  583. package/templates/config/package.json.template +18 -0
  584. package/templates/config/pnpm-workspace.yaml +5 -0
  585. package/templates/config/services.json.template +18 -0
  586. package/templates/config/tsconfig.base.json +17 -0
  587. package/templates/scaffold/integrations/_template/.gitkeep +0 -0
  588. package/templates/scaffold/packages/logger/package.json +17 -0
  589. package/templates/scaffold/packages/logger/src/logger.ts +44 -0
  590. package/templates/scaffold/packages/shared/package.json +17 -0
  591. package/templates/scaffold/packages/shared/src/errors.ts +43 -0
  592. package/templates/scaffold/products/_product/apps/backend/package.json +21 -0
  593. package/templates/scaffold/products/_product/apps/backend/src/index.ts +17 -0
  594. package/templates/scaffold/products/_product/apps/extension/.gitkeep +0 -0
  595. package/templates/scaffold/products/_product/apps/web/.gitkeep +0 -0
  596. package/templates/scaffold/specs/global/.gitkeep +0 -0
  597. package/templates/scaffold/specs/local/.gitkeep +0 -0
  598. package/templates/scaffold/specs/reference/.gitkeep +0 -0
  599. package/version.json +15 -0
@@ -0,0 +1,562 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PreToolUse Hook: Protected Action Gate
4
+ *
5
+ * Intercepts MCP tool calls and blocks protected actions that haven't
6
+ * been approved by the CTO. When blocked, generates an approval code
7
+ * that the CTO must type to authorize the action.
8
+ *
9
+ * Security Model:
10
+ * - Agent cannot bypass: PreToolUse hooks run before tool execution
11
+ * - Agent cannot forge approval: UserPromptSubmit = human keyboard only
12
+ * - One-time codes: Each approval is tied to a specific request
13
+ * - Time-limited: Codes expire after 5 minutes
14
+ * - G001 Fail-Closed: If config is corrupted, all protected servers are blocked
15
+ *
16
+ * SECURITY: This file should be root-owned via protect-framework.sh
17
+ *
18
+ * @version 2.0.0
19
+ */
20
+
21
+ import fs from 'fs';
22
+ import path from 'path';
23
+ import crypto from 'crypto';
24
+ import { fileURLToPath } from 'url';
25
+
26
+ const __filename = fileURLToPath(import.meta.url);
27
+ const __dirname = path.dirname(__filename);
28
+
29
+ // ============================================================================
30
+ // Configuration
31
+ // ============================================================================
32
+
33
+ const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || path.resolve(__dirname, '..', '..');
34
+ const PROTECTED_ACTIONS_PATH = path.join(PROJECT_DIR, '.claude', 'hooks', 'protected-actions.json');
35
+ const PROTECTION_KEY_PATH = path.join(PROJECT_DIR, '.claude', 'protection-key');
36
+
37
+ // PreToolUse hooks receive tool info via environment variables
38
+ const toolName = process.env.TOOL_NAME || '';
39
+ const toolInput = process.env.TOOL_INPUT || '{}';
40
+
41
+ // ============================================================================
42
+ // HMAC Signing (Fix 2: Anti-Forgery)
43
+ // ============================================================================
44
+
45
+ /**
46
+ * Load the protection key for HMAC signing.
47
+ * Returns null if key file doesn't exist (fail-closed handled by caller).
48
+ * @returns {string|null} Base64-encoded key or null
49
+ */
50
+ function loadProtectionKey() {
51
+ try {
52
+ if (!fs.existsSync(PROTECTION_KEY_PATH)) {
53
+ return null;
54
+ }
55
+ return fs.readFileSync(PROTECTION_KEY_PATH, 'utf8').trim();
56
+ } catch (err) {
57
+ return null;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Compute HMAC-SHA256 over pipe-delimited fields.
63
+ * @param {string} key - Base64-encoded key
64
+ * @param {...string} fields - Fields to include in HMAC
65
+ * @returns {string} Hex-encoded HMAC
66
+ */
67
+ function computeHmac(key, ...fields) {
68
+ const keyBuffer = Buffer.from(key, 'base64');
69
+ return crypto.createHmac('sha256', keyBuffer)
70
+ .update(fields.join('|'))
71
+ .digest('hex');
72
+ }
73
+
74
+ // ============================================================================
75
+ // MCP Tool Detection
76
+ // ============================================================================
77
+
78
+ /**
79
+ * Parse MCP tool name into server and tool components
80
+ * Format: mcp__servername__toolname
81
+ * Server names use hyphens (not underscores), tool names use underscores.
82
+ * @param {string} name - Full tool name
83
+ * @returns {object|null} { server, tool } or null if not an MCP tool
84
+ */
85
+ function parseMcpToolName(name) {
86
+ // Server name: alphanumeric + hyphens (no underscores)
87
+ // Tool name: alphanumeric + underscores + hyphens
88
+ const match = name.match(/^mcp__([a-zA-Z0-9-]+)__([a-zA-Z0-9_-]+)$/);
89
+ if (!match) {
90
+ return null;
91
+ }
92
+ return {
93
+ server: match[1],
94
+ tool: match[2],
95
+ };
96
+ }
97
+
98
+ // ============================================================================
99
+ // Protection Check
100
+ // ============================================================================
101
+
102
+ /**
103
+ * Load protected actions configuration
104
+ * @returns {object} Config object with 'servers' property, or object with 'error' flag
105
+ */
106
+ function loadProtectedActions() {
107
+ try {
108
+ if (!fs.existsSync(PROTECTED_ACTIONS_PATH)) {
109
+ // G001 Fail-Closed: Config missing = block all MCP actions
110
+ // An adversarial agent could delete this file to bypass protections (A4/C5)
111
+ return { servers: {}, notConfigured: true };
112
+ }
113
+ const config = JSON.parse(fs.readFileSync(PROTECTED_ACTIONS_PATH, 'utf8'));
114
+ if (!config.servers) {
115
+ config.servers = {};
116
+ }
117
+ return config;
118
+ } catch (err) {
119
+ // G001: Fail closed - if we can't read config, assume ALL MCP actions are blocked
120
+ // This prevents an adversary from corrupting the config to bypass protections
121
+ console.error(`[protected-action-gate] G001 FAIL-CLOSED: Config error, blocking all MCP actions: ${err.message}`);
122
+ return { error: true, message: err.message };
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Check if a server:tool is protected
128
+ * @param {string} server - MCP server name
129
+ * @param {string} tool - Tool name
130
+ * @param {object} config - Protected actions config
131
+ * @returns {object|null} Protection config or null if not protected
132
+ */
133
+ function getProtection(server, tool, config) {
134
+ if (!config || !config.servers || !config.servers[server]) {
135
+ return null;
136
+ }
137
+
138
+ const serverConfig = config.servers[server];
139
+
140
+ // Check if this tool is protected
141
+ if (serverConfig.tools === '*') {
142
+ return serverConfig;
143
+ }
144
+
145
+ if (Array.isArray(serverConfig.tools) && serverConfig.tools.includes(tool)) {
146
+ return serverConfig;
147
+ }
148
+
149
+ return null;
150
+ }
151
+
152
+ // ============================================================================
153
+ // Approval Check
154
+ // ============================================================================
155
+
156
+ const APPROVALS_PATH = path.join(PROJECT_DIR, '.claude', 'protected-action-approvals.json');
157
+
158
+ const LOCK_PATH = APPROVALS_PATH + '.lock';
159
+
160
+ /**
161
+ * Acquire an advisory lock on the approvals file.
162
+ * Uses exclusive file creation (O_CREAT | O_EXCL) as a cross-process mutex.
163
+ * Retries with backoff for up to 2 seconds.
164
+ * @returns {boolean} true if lock acquired
165
+ */
166
+ function acquireLock() {
167
+ const maxAttempts = 10;
168
+ const baseDelay = 50; // ms
169
+ for (let i = 0; i < maxAttempts; i++) {
170
+ try {
171
+ const fd = fs.openSync(LOCK_PATH, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY);
172
+ fs.writeSync(fd, String(process.pid));
173
+ fs.closeSync(fd);
174
+ return true;
175
+ } catch (err) {
176
+ // Check for stale lock (older than 10 seconds)
177
+ try {
178
+ const stat = fs.statSync(LOCK_PATH);
179
+ if (Date.now() - stat.mtimeMs > 10000) {
180
+ fs.unlinkSync(LOCK_PATH);
181
+ continue; // Retry immediately after removing stale lock
182
+ }
183
+ } catch { /* lock file gone, retry */ }
184
+
185
+ // Exponential backoff
186
+ const delay = baseDelay * Math.pow(2, i);
187
+ const start = Date.now();
188
+ while (Date.now() - start < delay) { /* busy wait */ }
189
+ }
190
+ }
191
+ return false;
192
+ }
193
+
194
+ /**
195
+ * Release the advisory lock.
196
+ */
197
+ function releaseLock() {
198
+ try {
199
+ fs.unlinkSync(LOCK_PATH);
200
+ } catch { /* already released */ }
201
+ }
202
+
203
+ /**
204
+ * Load current approvals
205
+ * @returns {object}
206
+ */
207
+ function loadApprovals() {
208
+ try {
209
+ if (!fs.existsSync(APPROVALS_PATH)) {
210
+ return { approvals: {} };
211
+ }
212
+ return JSON.parse(fs.readFileSync(APPROVALS_PATH, 'utf8'));
213
+ } catch (err) {
214
+ return { approvals: {} };
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Save approvals
220
+ * @param {object} approvals
221
+ */
222
+ function saveApprovals(approvals) {
223
+ const dir = path.dirname(APPROVALS_PATH);
224
+ if (!fs.existsSync(dir)) {
225
+ fs.mkdirSync(dir, { recursive: true });
226
+ }
227
+ fs.writeFileSync(APPROVALS_PATH, JSON.stringify(approvals, null, 2));
228
+ }
229
+
230
+ /**
231
+ * Check if there's a valid approval for this action.
232
+ * Verifies HMAC signatures to prevent agent forgery (Fix 2).
233
+ * Uses file locking to prevent TOCTOU race conditions on approval consumption.
234
+ * @param {string} server - MCP server name
235
+ * @param {string} tool - Tool name
236
+ * @param {object} args - Tool arguments (used to verify approval is scoped to these exact args)
237
+ * @returns {object|null} Approval if valid, null otherwise
238
+ */
239
+ function checkApproval(server, tool, args) {
240
+ // Acquire lock to prevent TOCTOU race: two concurrent checks consuming same approval
241
+ if (!acquireLock()) {
242
+ console.error('[protected-action-gate] G001 FAIL-CLOSED: Could not acquire approvals lock. Blocking action.');
243
+ return null;
244
+ }
245
+
246
+ try {
247
+ const approvals = loadApprovals();
248
+ const now = Date.now();
249
+ const key = loadProtectionKey();
250
+ let dirty = false;
251
+
252
+ // Hash the current call's arguments to verify they match the approved args
253
+ const argsHash = crypto.createHash('sha256')
254
+ .update(JSON.stringify(args || {}))
255
+ .digest('hex');
256
+
257
+ for (const [code, request] of Object.entries(approvals.approvals)) {
258
+ if (request.status !== 'approved') continue;
259
+ if (request.expires_timestamp < now) continue;
260
+ if (request.server !== server) continue;
261
+ if (request.tool !== tool) continue;
262
+
263
+ // Verify args match what was approved (prevents bait-and-switch attack)
264
+ if (request.argsHash && request.argsHash !== argsHash) {
265
+ continue; // Args don't match the approved request
266
+ }
267
+
268
+ // HMAC verification (Fix 2): Verify signatures to prevent agent forgery
269
+ // argsHash is included in HMAC to bind approval to specific arguments
270
+ if (key) {
271
+ // Verify pending_hmac (was this request created by this hook with these args?)
272
+ const expectedPendingHmac = computeHmac(key, code, server, tool, request.argsHash || argsHash, String(request.expires_timestamp));
273
+ if (request.pending_hmac !== expectedPendingHmac) {
274
+ // Forged pending request - delete it
275
+ console.error(`[protected-action-gate] FORGERY DETECTED: Invalid pending_hmac for ${code}. Deleting.`);
276
+ delete approvals.approvals[code];
277
+ dirty = true;
278
+ continue;
279
+ }
280
+
281
+ // Verify approved_hmac (was this approval created by the approval hook?)
282
+ const expectedApprovedHmac = computeHmac(key, code, server, tool, 'approved', request.argsHash || argsHash, String(request.expires_timestamp));
283
+ if (request.approved_hmac !== expectedApprovedHmac) {
284
+ // Forged approval - delete it
285
+ console.error(`[protected-action-gate] FORGERY DETECTED: Invalid approved_hmac for ${code}. Deleting.`);
286
+ delete approvals.approvals[code];
287
+ dirty = true;
288
+ continue;
289
+ }
290
+ } else if (request.pending_hmac || request.approved_hmac) {
291
+ // G001 Fail-Closed: Request has HMAC fields but we can't verify them
292
+ // (protection key missing/unreadable). Reject rather than skip verification.
293
+ console.error(`[protected-action-gate] G001 FAIL-CLOSED: Cannot verify HMAC for ${code} (protection key missing). Skipping.`);
294
+ continue;
295
+ }
296
+
297
+ // Found a valid, HMAC-verified approval - consume it (one-time use)
298
+ delete approvals.approvals[code];
299
+ saveApprovals(approvals);
300
+
301
+ return request;
302
+ }
303
+
304
+ // Save if we deleted forged entries
305
+ if (dirty) {
306
+ saveApprovals(approvals);
307
+ }
308
+
309
+ return null;
310
+ } finally {
311
+ releaseLock();
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Generate a 6-character alphanumeric approval code using crypto-secure randomness
317
+ * Excludes confusing characters: 0/O, 1/I/L
318
+ */
319
+ function generateCode() {
320
+ const chars = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789';
321
+ let code = '';
322
+ const randomBytes = crypto.randomBytes(6);
323
+ for (let i = 0; i < 6; i++) {
324
+ code += chars.charAt(randomBytes[i] % chars.length);
325
+ }
326
+ return code;
327
+ }
328
+
329
+ /**
330
+ * Create a pending approval request with HMAC signing (Fix 2).
331
+ * @param {string} server - MCP server name
332
+ * @param {string} tool - Tool name
333
+ * @param {object} args - Tool arguments
334
+ * @param {string} phrase - Approval phrase
335
+ * @param {object} [options] - Additional options
336
+ * @param {string} [options.approvalMode] - 'cto' (default) or 'deputy-cto'
337
+ * @returns {object} Request details
338
+ */
339
+ function createRequest(server, tool, args, phrase, options = {}) {
340
+ const code = generateCode();
341
+ const now = Date.now();
342
+ const expiryMs = 5 * 60 * 1000; // 5 minutes
343
+ const expiresTimestamp = now + expiryMs;
344
+
345
+ // Hash the args to bind the approval to these specific arguments (prevents bait-and-switch)
346
+ const argsHash = crypto.createHash('sha256')
347
+ .update(JSON.stringify(args || {}))
348
+ .digest('hex');
349
+
350
+ // Compute HMAC for pending request (prevents agent forgery)
351
+ // Includes argsHash so approval is bound to exact arguments shown to CTO
352
+ const key = loadProtectionKey();
353
+ const pendingHmac = key ? computeHmac(key, code, server, tool, argsHash, String(expiresTimestamp)) : undefined;
354
+
355
+ // Acquire lock for atomic read-modify-write
356
+ if (!acquireLock()) {
357
+ console.error('[protected-action-gate] Warning: Could not acquire lock for createRequest. Proceeding without lock.');
358
+ }
359
+
360
+ try {
361
+ const approvals = loadApprovals();
362
+ approvals.approvals[code] = {
363
+ server,
364
+ tool,
365
+ args,
366
+ argsHash,
367
+ phrase,
368
+ code,
369
+ status: 'pending',
370
+ approval_mode: options.approvalMode || 'cto',
371
+ created_at: new Date(now).toISOString(),
372
+ created_timestamp: now,
373
+ expires_at: new Date(expiresTimestamp).toISOString(),
374
+ expires_timestamp: expiresTimestamp,
375
+ ...(pendingHmac && { pending_hmac: pendingHmac }),
376
+ };
377
+
378
+ // Clean expired requests
379
+ const validApprovals = {};
380
+ for (const [key, val] of Object.entries(approvals.approvals)) {
381
+ if (val.expires_timestamp > now) {
382
+ validApprovals[key] = val;
383
+ }
384
+ }
385
+ approvals.approvals = validApprovals;
386
+
387
+ saveApprovals(approvals);
388
+ } finally {
389
+ releaseLock();
390
+ }
391
+
392
+ return {
393
+ code,
394
+ phrase,
395
+ message: `${phrase} ${code}`,
396
+ };
397
+ }
398
+
399
+ // ============================================================================
400
+ // Main
401
+ // ============================================================================
402
+
403
+ function main() {
404
+ // Only check MCP tool calls
405
+ const mcpInfo = parseMcpToolName(toolName);
406
+ if (!mcpInfo) {
407
+ // Not an MCP tool, allow
408
+ process.exit(0);
409
+ }
410
+
411
+ // Load config
412
+ const config = loadProtectedActions();
413
+
414
+ // G001: If config is corrupted/unreadable, block ALL MCP actions
415
+ if (config.error) {
416
+ console.error('');
417
+ console.error('══════════════════════════════════════════════════════════════════════');
418
+ console.error(' G001 FAIL-CLOSED: Protected actions config is corrupted');
419
+ console.error('');
420
+ console.error(` Error: ${config.message}`);
421
+ console.error('');
422
+ console.error(' ALL MCP actions are blocked until config is fixed.');
423
+ console.error(' Fix the config file at: .claude/hooks/protected-actions.json');
424
+ console.error('══════════════════════════════════════════════════════════════════════');
425
+ console.error('');
426
+ process.exit(1);
427
+ }
428
+
429
+ // G001 Fail-Closed: If config file is missing, block ALL MCP actions
430
+ // This prevents attack A4/C5: agent deletes/moves config to bypass protections
431
+ if (config.notConfigured) {
432
+ console.error('');
433
+ console.error('══════════════════════════════════════════════════════════════════════');
434
+ console.error(' G001 FAIL-CLOSED: Protected actions config not found');
435
+ console.error('');
436
+ console.error(' File: .claude/hooks/protected-actions.json');
437
+ console.error(' ALL MCP actions are blocked until config is restored.');
438
+ console.error(' Run: setup.sh --path <project> to reinstall GENTYR');
439
+ console.error('══════════════════════════════════════════════════════════════════════');
440
+ console.error('');
441
+ process.exit(1);
442
+ }
443
+
444
+ // Check if this action is protected
445
+ const protection = getProtection(mcpInfo.server, mcpInfo.tool, config);
446
+ if (!protection) {
447
+ // Not a protected tool — but is this a known server? (Fix 3: MCP Server Allowlist)
448
+ // 1. Server IS in config.servers but this specific tool isn't protected -> allow (unprotected tool on known server)
449
+ if (config.servers[mcpInfo.server]) {
450
+ process.exit(0);
451
+ }
452
+
453
+ // 2. Server IS in allowedUnprotectedServers -> allow (framework/internal server)
454
+ const allowedServers = config.allowedUnprotectedServers || [];
455
+ if (allowedServers.includes(mcpInfo.server)) {
456
+ process.exit(0);
457
+ }
458
+
459
+ // 3. Unknown server -> BLOCK (prevents MCP server aliasing attack C2)
460
+ console.error('');
461
+ console.error('══════════════════════════════════════════════════════════════════════');
462
+ console.error(' BLOCKED: Unrecognized MCP Server');
463
+ console.error('');
464
+ console.error(` Server: ${mcpInfo.server}`);
465
+ console.error(` Tool: ${mcpInfo.tool}`);
466
+ console.error('');
467
+ console.error(' This MCP server is not in the protected-actions.json config.');
468
+ console.error(' To allow this server, add it to "allowedUnprotectedServers"');
469
+ console.error(' or "servers" in .claude/hooks/protected-actions.json');
470
+ console.error('══════════════════════════════════════════════════════════════════════');
471
+ console.error('');
472
+ process.exit(1);
473
+ }
474
+
475
+ // Parse tool arguments
476
+ let args = {};
477
+ try {
478
+ args = JSON.parse(toolInput);
479
+ } catch (err) {
480
+ // Can't parse args, but still need to check protection
481
+ }
482
+
483
+ // G001 Fail-Closed: If protection key is missing and we have protected actions,
484
+ // we cannot verify HMAC signatures. Block the action rather than allowing unsigned approvals.
485
+ const protectionKey = loadProtectionKey();
486
+ if (!protectionKey) {
487
+ console.error('');
488
+ console.error('══════════════════════════════════════════════════════════════════════');
489
+ console.error(' G001 FAIL-CLOSED: Protection key missing');
490
+ console.error('');
491
+ console.error(' File: .claude/protection-key');
492
+ console.error(' Cannot verify approval signatures without protection key.');
493
+ console.error(' Run: setup.sh --path <project> to reinstall GENTYR');
494
+ console.error('══════════════════════════════════════════════════════════════════════');
495
+ console.error('');
496
+ process.exit(1);
497
+ }
498
+
499
+ // Check for valid approval (HMAC-verified, args-scoped)
500
+ const approval = checkApproval(mcpInfo.server, mcpInfo.tool, args);
501
+ if (approval) {
502
+ // Has valid, HMAC-verified approval, allow
503
+ console.error(`[protected-action-gate] Approval verified for ${mcpInfo.server}:${mcpInfo.tool}`);
504
+ process.exit(0);
505
+ }
506
+
507
+ // Determine approval mode from protection config
508
+ const approvalMode = protection.protection || 'approval-only';
509
+ const isDeputyCtoMode = approvalMode === 'deputy-cto-approval';
510
+
511
+ // No approval - block and request one
512
+ const request = createRequest(mcpInfo.server, mcpInfo.tool, args, protection.phrase, {
513
+ approvalMode: isDeputyCtoMode ? 'deputy-cto' : 'cto',
514
+ });
515
+
516
+ // Output block message
517
+ console.error('');
518
+ console.error('══════════════════════════════════════════════════════════════════════');
519
+ if (isDeputyCtoMode) {
520
+ console.error(' PROTECTED ACTION BLOCKED: Deputy-CTO Approval Required');
521
+ } else {
522
+ console.error(' PROTECTED ACTION BLOCKED: CTO Approval Required');
523
+ }
524
+ console.error('');
525
+ console.error(` Server: ${mcpInfo.server}`);
526
+ console.error(` Tool: ${mcpInfo.tool}`);
527
+ console.error('');
528
+ if (Object.keys(args).length > 0) {
529
+ console.error(' Arguments:');
530
+ const argsStr = JSON.stringify(args, null, 2).split('\n');
531
+ argsStr.forEach(line => console.error(` ${line}`));
532
+ console.error('');
533
+ }
534
+ console.error(' ─────────────────────────────────────────────────────────────────────');
535
+ console.error('');
536
+ if (isDeputyCtoMode) {
537
+ console.error(` Request code: ${request.code}`);
538
+ console.error('');
539
+ console.error(' Submit a report to deputy-cto for triage:');
540
+ console.error(` mcp__agent-reports__report_to_deputy_cto`);
541
+ console.error(` title: "Protected Action Request: ${mcpInfo.server}.${mcpInfo.tool}"`);
542
+ console.error(` Include code ${request.code} in summary.`);
543
+ console.error('');
544
+ console.error(' Deputy-CTO can approve, deny, or escalate to CTO.');
545
+ console.error(' For CTO escalation, CTO must type:');
546
+ console.error(` ${request.message}`);
547
+ } else {
548
+ console.error(` To approve, CTO must type exactly:`);
549
+ console.error('');
550
+ console.error(` ${request.message}`);
551
+ }
552
+ console.error('');
553
+ console.error(' This code expires in 5 minutes.');
554
+ console.error(' After approval, retry this action.');
555
+ console.error('══════════════════════════════════════════════════════════════════════');
556
+ console.error('');
557
+
558
+ // Exit with error to block the tool call
559
+ process.exit(1);
560
+ }
561
+
562
+ main();