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,731 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Approval Utilities for Protected MCP Actions
4
+ *
5
+ * Provides encryption, code generation, and approval validation
6
+ * for the CTO-protected MCP action system.
7
+ *
8
+ * Security Model:
9
+ * - Credentials encrypted with AES-256-GCM
10
+ * - Decryption key stored in .claude/protection-key (root-owned)
11
+ * - Approval codes are 6-char alphanumeric, one-time use
12
+ * - Approvals expire after 5 minutes
13
+ *
14
+ * @version 1.0.0
15
+ */
16
+
17
+ import fs from 'fs';
18
+ import path from 'path';
19
+ import crypto from 'crypto';
20
+
21
+ // ============================================================================
22
+ // Configuration
23
+ // ============================================================================
24
+
25
+ const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
26
+ const PROTECTION_KEY_PATH = path.join(PROJECT_DIR, '.claude', 'protection-key');
27
+ const PROTECTED_ACTIONS_PATH = path.join(PROJECT_DIR, '.claude', 'hooks', 'protected-actions.json');
28
+ const APPROVALS_PATH = path.join(PROJECT_DIR, '.claude', 'protected-action-approvals.json');
29
+ const DEPUTY_CTO_DB = path.join(PROJECT_DIR, '.claude', 'deputy-cto.db');
30
+
31
+ // Token expires after 5 minutes
32
+ const TOKEN_EXPIRY_MS = 5 * 60 * 1000;
33
+
34
+ // Lock file for TOCTOU-safe approval consumption
35
+ const LOCK_PATH = APPROVALS_PATH + '.lock';
36
+
37
+ // Encryption constants
38
+ const ALGORITHM = 'aes-256-gcm';
39
+ const KEY_LENGTH = 32; // 256 bits
40
+ const IV_LENGTH = 16;
41
+ const AUTH_TAG_LENGTH = 16;
42
+ const ENCRYPTED_PREFIX = '${GENTYR_ENCRYPTED:';
43
+ const ENCRYPTED_SUFFIX = '}';
44
+
45
+ // ============================================================================
46
+ // Code Generation
47
+ // ============================================================================
48
+
49
+ /**
50
+ * Generate a 6-character alphanumeric approval code
51
+ * Excludes confusing characters: 0/O, 1/I/L
52
+ */
53
+ export function generateCode() {
54
+ const chars = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789';
55
+ let code = '';
56
+ const randomBytes = crypto.randomBytes(6);
57
+ for (let i = 0; i < 6; i++) {
58
+ code += chars.charAt(randomBytes[i] % chars.length);
59
+ }
60
+ return code;
61
+ }
62
+
63
+ // ============================================================================
64
+ // HMAC Signing (shared across hooks)
65
+ // ============================================================================
66
+
67
+ /**
68
+ * Compute HMAC-SHA256 over pipe-delimited fields.
69
+ * Shared function used by createRequest, checkApproval, and external hooks
70
+ * (protected-action-gate, protected-action-approval-hook, deputy-cto server).
71
+ *
72
+ * @param {string} keyBase64 - Base64-encoded protection key
73
+ * @param {...string} fields - Fields to include in HMAC
74
+ * @returns {string} Hex-encoded HMAC
75
+ */
76
+ export function computeHmac(keyBase64, ...fields) {
77
+ const keyBuffer = Buffer.from(keyBase64, 'base64');
78
+ return crypto.createHmac('sha256', keyBuffer)
79
+ .update(fields.join('|'))
80
+ .digest('hex');
81
+ }
82
+
83
+ // ============================================================================
84
+ // File Locking (TOCTOU protection for approval consumption)
85
+ // ============================================================================
86
+
87
+ /**
88
+ * Acquire an advisory lock on the approvals file.
89
+ * Uses exclusive file creation (O_CREAT | O_EXCL) as a cross-process mutex.
90
+ * Retries with backoff for up to 2 seconds.
91
+ * @returns {boolean} true if lock acquired
92
+ */
93
+ function acquireLock() {
94
+ const maxAttempts = 10;
95
+ const baseDelay = 50; // ms
96
+ for (let i = 0; i < maxAttempts; i++) {
97
+ try {
98
+ const fd = fs.openSync(LOCK_PATH, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY);
99
+ fs.writeSync(fd, String(process.pid));
100
+ fs.closeSync(fd);
101
+ return true;
102
+ } catch (err) {
103
+ // Check for stale lock (older than 10 seconds)
104
+ try {
105
+ const stat = fs.statSync(LOCK_PATH);
106
+ if (Date.now() - stat.mtimeMs > 10000) {
107
+ fs.unlinkSync(LOCK_PATH);
108
+ continue; // Retry immediately after removing stale lock
109
+ }
110
+ } catch { /* lock file gone, retry */ }
111
+
112
+ // Exponential backoff
113
+ const delay = baseDelay * Math.pow(2, i);
114
+ const start = Date.now();
115
+ while (Date.now() - start < delay) { /* busy wait */ }
116
+ }
117
+ }
118
+ return false;
119
+ }
120
+
121
+ /**
122
+ * Release the advisory lock.
123
+ */
124
+ function releaseLock() {
125
+ try {
126
+ fs.unlinkSync(LOCK_PATH);
127
+ } catch { /* already released */ }
128
+ }
129
+
130
+ // ============================================================================
131
+ // Encryption / Decryption
132
+ // ============================================================================
133
+
134
+ /**
135
+ * Generate a new protection key
136
+ * @returns {string} Base64-encoded key
137
+ */
138
+ export function generateProtectionKey() {
139
+ return crypto.randomBytes(KEY_LENGTH).toString('base64');
140
+ }
141
+
142
+ /**
143
+ * Read the protection key from disk
144
+ * @returns {Buffer|null} The key buffer or null if not found
145
+ */
146
+ export function readProtectionKey() {
147
+ try {
148
+ if (!fs.existsSync(PROTECTION_KEY_PATH)) {
149
+ return null;
150
+ }
151
+ const keyBase64 = fs.readFileSync(PROTECTION_KEY_PATH, 'utf8').trim();
152
+ return Buffer.from(keyBase64, 'base64');
153
+ } catch (err) {
154
+ console.error(`[approval-utils] Failed to read protection key: ${err.message}`);
155
+ return null;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Write the protection key to disk
161
+ * Note: Caller should ensure root ownership after writing
162
+ * @param {string} keyBase64 - Base64-encoded key
163
+ */
164
+ export function writeProtectionKey(keyBase64) {
165
+ const dir = path.dirname(PROTECTION_KEY_PATH);
166
+ if (!fs.existsSync(dir)) {
167
+ fs.mkdirSync(dir, { recursive: true });
168
+ }
169
+ fs.writeFileSync(PROTECTION_KEY_PATH, keyBase64 + '\n', { mode: 0o600 });
170
+ }
171
+
172
+ /**
173
+ * Encrypt a credential value
174
+ * @param {string} value - Plain text value to encrypt
175
+ * @param {Buffer} key - Encryption key
176
+ * @returns {string} Encrypted string in ${GENTYR_ENCRYPTED:...} format
177
+ */
178
+ export function encryptCredential(value, key) {
179
+ const iv = crypto.randomBytes(IV_LENGTH);
180
+ const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
181
+
182
+ let encrypted = cipher.update(value, 'utf8', 'base64');
183
+ encrypted += cipher.final('base64');
184
+
185
+ const authTag = cipher.getAuthTag();
186
+
187
+ // Format: iv:authTag:ciphertext (all base64)
188
+ const payload = `${iv.toString('base64')}:${authTag.toString('base64')}:${encrypted}`;
189
+ return `${ENCRYPTED_PREFIX}${payload}${ENCRYPTED_SUFFIX}`;
190
+ }
191
+
192
+ /**
193
+ * Decrypt a credential value
194
+ * @param {string} encryptedValue - Value in ${GENTYR_ENCRYPTED:...} format
195
+ * @param {Buffer} key - Decryption key
196
+ * @returns {string|null} Decrypted value or null on failure
197
+ */
198
+ export function decryptCredential(encryptedValue, key) {
199
+ try {
200
+ if (!encryptedValue.startsWith(ENCRYPTED_PREFIX) || !encryptedValue.endsWith(ENCRYPTED_SUFFIX)) {
201
+ return null;
202
+ }
203
+
204
+ const payload = encryptedValue.slice(ENCRYPTED_PREFIX.length, -ENCRYPTED_SUFFIX.length);
205
+ const [ivBase64, authTagBase64, ciphertext] = payload.split(':');
206
+
207
+ if (!ivBase64 || !authTagBase64 || !ciphertext) {
208
+ return null;
209
+ }
210
+
211
+ const iv = Buffer.from(ivBase64, 'base64');
212
+ const authTag = Buffer.from(authTagBase64, 'base64');
213
+
214
+ const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
215
+ decipher.setAuthTag(authTag);
216
+
217
+ let decrypted = decipher.update(ciphertext, 'base64', 'utf8');
218
+ decrypted += decipher.final('utf8');
219
+
220
+ return decrypted;
221
+ } catch (err) {
222
+ console.error(`[approval-utils] Decryption failed: ${err.message}`);
223
+ return null;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Check if a value is encrypted
229
+ * @param {string} value - Value to check
230
+ * @returns {boolean}
231
+ */
232
+ export function isEncrypted(value) {
233
+ return typeof value === 'string' &&
234
+ value.startsWith(ENCRYPTED_PREFIX) &&
235
+ value.endsWith(ENCRYPTED_SUFFIX);
236
+ }
237
+
238
+ // ============================================================================
239
+ // Protected Actions Configuration
240
+ // ============================================================================
241
+
242
+ /**
243
+ * Load protected actions configuration
244
+ * @returns {object|null} Configuration or null if not found
245
+ */
246
+ export function loadProtectedActions() {
247
+ try {
248
+ if (!fs.existsSync(PROTECTED_ACTIONS_PATH)) {
249
+ return null;
250
+ }
251
+ return JSON.parse(fs.readFileSync(PROTECTED_ACTIONS_PATH, 'utf8'));
252
+ } catch (err) {
253
+ console.error(`[approval-utils] Failed to load protected actions: ${err.message}`);
254
+ return null;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Save protected actions configuration
260
+ * @param {object} config - Configuration to save
261
+ */
262
+ export function saveProtectedActions(config) {
263
+ const dir = path.dirname(PROTECTED_ACTIONS_PATH);
264
+ if (!fs.existsSync(dir)) {
265
+ fs.mkdirSync(dir, { recursive: true });
266
+ }
267
+ fs.writeFileSync(PROTECTED_ACTIONS_PATH, JSON.stringify(config, null, 2));
268
+ }
269
+
270
+ /**
271
+ * Check if a server:tool is protected
272
+ * @param {string} server - MCP server name
273
+ * @param {string} tool - Tool name
274
+ * @param {object} config - Protected actions config (optional, loads if not provided)
275
+ * @returns {object|null} Protection config or null if not protected
276
+ */
277
+ export function getProtection(server, tool, config = null) {
278
+ const cfg = config || loadProtectedActions();
279
+ if (!cfg || !cfg.servers || !cfg.servers[server]) {
280
+ return null;
281
+ }
282
+
283
+ const serverConfig = cfg.servers[server];
284
+
285
+ // Check if this tool is protected
286
+ if (serverConfig.tools === '*') {
287
+ return serverConfig;
288
+ }
289
+
290
+ if (Array.isArray(serverConfig.tools) && serverConfig.tools.includes(tool)) {
291
+ return serverConfig;
292
+ }
293
+
294
+ return null;
295
+ }
296
+
297
+ // ============================================================================
298
+ // Approval Management
299
+ // ============================================================================
300
+
301
+ /**
302
+ * Load current approvals
303
+ * @returns {object} Approvals object (may be empty)
304
+ */
305
+ export function loadApprovals() {
306
+ try {
307
+ if (!fs.existsSync(APPROVALS_PATH)) {
308
+ return { approvals: {} };
309
+ }
310
+ const data = JSON.parse(fs.readFileSync(APPROVALS_PATH, 'utf8'));
311
+ if (!data || typeof data !== 'object' || !data.approvals || typeof data.approvals !== 'object') {
312
+ return { approvals: {} };
313
+ }
314
+ return data;
315
+ } catch (err) {
316
+ return { approvals: {} };
317
+ }
318
+ }
319
+
320
+ /**
321
+ * Save approvals
322
+ * @param {object} approvals - Approvals object
323
+ */
324
+ export function saveApprovals(approvals) {
325
+ const dir = path.dirname(APPROVALS_PATH);
326
+ if (!fs.existsSync(dir)) {
327
+ fs.mkdirSync(dir, { recursive: true });
328
+ }
329
+ fs.writeFileSync(APPROVALS_PATH, JSON.stringify(approvals, null, 2));
330
+ }
331
+
332
+ /**
333
+ * Create a pending approval request
334
+ * @param {string} server - MCP server name (or '__file__' for file approvals)
335
+ * @param {string} tool - Tool name (or file config key for file approvals)
336
+ * @param {object} args - Tool arguments
337
+ * @param {string} phrase - Approval phrase (e.g., "APPROVE PROD")
338
+ * @param {object} [options] - Additional options
339
+ * @param {string} [options.approvalMode] - 'cto' (default) or 'deputy-cto'
340
+ * @returns {object} Request details including code
341
+ */
342
+ export function createRequest(server, tool, args, phrase, options = {}) {
343
+ const code = generateCode();
344
+ const now = Date.now();
345
+ const expiresTimestamp = now + TOKEN_EXPIRY_MS;
346
+
347
+ // Hash the args to bind the approval to these specific arguments
348
+ const argsHash = crypto.createHash('sha256')
349
+ .update(JSON.stringify(args || {}))
350
+ .digest('hex');
351
+
352
+ // Compute HMAC for pending request (prevents agent forgery)
353
+ const key = readProtectionKey();
354
+ const keyBase64 = key ? key.toString('base64') : null;
355
+ let pendingHmac;
356
+ if (keyBase64) {
357
+ pendingHmac = computeHmac(keyBase64, code, server, tool, argsHash, String(expiresTimestamp));
358
+ }
359
+
360
+ const approvals = loadApprovals();
361
+ approvals.approvals[code] = {
362
+ server,
363
+ tool,
364
+ args,
365
+ argsHash,
366
+ phrase,
367
+ code,
368
+ status: 'pending',
369
+ approval_mode: options.approvalMode || 'cto',
370
+ created_at: new Date(now).toISOString(),
371
+ created_timestamp: now,
372
+ expires_at: new Date(expiresTimestamp).toISOString(),
373
+ expires_timestamp: expiresTimestamp,
374
+ ...(pendingHmac && { pending_hmac: pendingHmac }),
375
+ };
376
+
377
+ // Clean expired requests
378
+ const validApprovals = {};
379
+ for (const [k, val] of Object.entries(approvals.approvals)) {
380
+ if (val.expires_timestamp > now) {
381
+ validApprovals[k] = val;
382
+ }
383
+ }
384
+ approvals.approvals = validApprovals;
385
+
386
+ saveApprovals(approvals);
387
+
388
+ return {
389
+ code,
390
+ server,
391
+ tool,
392
+ phrase,
393
+ message: `CTO must type: ${phrase} ${code}`,
394
+ expires_in_minutes: Math.round(TOKEN_EXPIRY_MS / 60000),
395
+ };
396
+ }
397
+
398
+ /**
399
+ * Validate an approval code and mark as approved
400
+ * @param {string} phrase - The approval phrase (e.g., "APPROVE PROD")
401
+ * @param {string} code - The 6-character code
402
+ * @returns {object} Validation result
403
+ */
404
+ export function validateApproval(phrase, code) {
405
+ const approvals = loadApprovals();
406
+ const request = approvals.approvals[code.toUpperCase()];
407
+
408
+ if (!request) {
409
+ return { valid: false, reason: 'No pending request with this code' };
410
+ }
411
+
412
+ if (request.status === 'approved') {
413
+ return { valid: false, reason: 'This code has already been used' };
414
+ }
415
+
416
+ if (Date.now() > request.expires_timestamp) {
417
+ // Clean up expired request
418
+ delete approvals.approvals[code.toUpperCase()];
419
+ saveApprovals(approvals);
420
+ return { valid: false, reason: 'Approval code has expired' };
421
+ }
422
+
423
+ // Verify phrase matches (case-insensitive)
424
+ if (request.phrase.toUpperCase() !== phrase.toUpperCase()) {
425
+ return {
426
+ valid: false,
427
+ reason: `Wrong approval phrase. Expected: ${request.phrase}`
428
+ };
429
+ }
430
+
431
+ // Mark as approved
432
+ request.status = 'approved';
433
+ request.approved_at = new Date().toISOString();
434
+ request.approved_timestamp = Date.now();
435
+ saveApprovals(approvals);
436
+
437
+ return {
438
+ valid: true,
439
+ server: request.server,
440
+ tool: request.tool,
441
+ args: request.args,
442
+ request,
443
+ };
444
+ }
445
+
446
+ /**
447
+ * Check if there's a valid approval for a server:tool call.
448
+ * Verifies HMAC signatures to prevent agent forgery.
449
+ * Uses file locking to prevent TOCTOU race conditions on approval consumption.
450
+ *
451
+ * @param {string} server - MCP server name (or '__file__' for file approvals)
452
+ * @param {string} tool - Tool name (or file config key for file approvals)
453
+ * @param {object} [args] - Tool arguments (used to verify approval is scoped to these exact args)
454
+ * @returns {object|null} Approval if valid, null otherwise
455
+ */
456
+ export function checkApproval(server, tool, args) {
457
+ // Acquire lock to prevent TOCTOU race: two concurrent checks consuming same approval
458
+ if (!acquireLock()) {
459
+ console.error('[approval-utils] G001 FAIL-CLOSED: Could not acquire approvals lock. Blocking action.');
460
+ return null;
461
+ }
462
+
463
+ try {
464
+ const approvals = loadApprovals();
465
+ const now = Date.now();
466
+ const key = readProtectionKey();
467
+ const keyBase64 = key ? key.toString('base64') : null;
468
+ let dirty = false;
469
+
470
+ // Hash the current call's arguments to verify they match the approved args
471
+ const argsHash = crypto.createHash('sha256')
472
+ .update(JSON.stringify(args || {}))
473
+ .digest('hex');
474
+
475
+ for (const [code, request] of Object.entries(approvals.approvals)) {
476
+ if (request.status !== 'approved') continue;
477
+ if (request.expires_timestamp < now) continue;
478
+ if (request.server !== server) continue;
479
+ if (request.tool !== tool) continue;
480
+
481
+ // Verify args match what was approved (prevents bait-and-switch attack)
482
+ if (request.argsHash && request.argsHash !== argsHash) {
483
+ continue; // Args don't match the approved request
484
+ }
485
+
486
+ // HMAC verification: Verify signatures to prevent agent forgery
487
+ if (keyBase64) {
488
+ // Verify pending_hmac (was this request created by the hook with these args?)
489
+ if (request.pending_hmac) {
490
+ const expectedPendingHmac = computeHmac(keyBase64, code, server, tool, request.argsHash || argsHash, String(request.expires_timestamp));
491
+ if (request.pending_hmac !== expectedPendingHmac) {
492
+ console.error(`[approval-utils] FORGERY DETECTED: Invalid pending_hmac for ${code}. Deleting.`);
493
+ delete approvals.approvals[code];
494
+ dirty = true;
495
+ continue;
496
+ }
497
+ }
498
+
499
+ // Verify approved_hmac (was this approval created by the approval hook?)
500
+ if (request.approved_hmac) {
501
+ const expectedApprovedHmac = computeHmac(keyBase64, code, server, tool, 'approved', request.argsHash || argsHash, String(request.expires_timestamp));
502
+ if (request.approved_hmac !== expectedApprovedHmac) {
503
+ console.error(`[approval-utils] FORGERY DETECTED: Invalid approved_hmac for ${code}. Deleting.`);
504
+ delete approvals.approvals[code];
505
+ dirty = true;
506
+ continue;
507
+ }
508
+ }
509
+ } else if (request.pending_hmac || request.approved_hmac) {
510
+ // G001 Fail-Closed: Request has HMAC fields but we can't verify them
511
+ // (protection key missing/unreadable). Reject rather than skip verification.
512
+ console.error(`[approval-utils] G001 FAIL-CLOSED: Cannot verify HMAC for ${code} (protection key missing). Skipping.`);
513
+ continue;
514
+ }
515
+
516
+ // Found a valid, HMAC-verified approval - consume it (one-time use)
517
+ delete approvals.approvals[code];
518
+ saveApprovals(approvals);
519
+
520
+ return request;
521
+ }
522
+
523
+ // Save if we deleted forged entries
524
+ if (dirty) {
525
+ saveApprovals(approvals);
526
+ }
527
+
528
+ return null;
529
+ } finally {
530
+ releaseLock();
531
+ }
532
+ }
533
+
534
+ /**
535
+ * Get all pending requests (for display/debugging)
536
+ * @returns {object[]} List of pending requests
537
+ */
538
+ export function getPendingRequests() {
539
+ const approvals = loadApprovals();
540
+ const now = Date.now();
541
+
542
+ return Object.values(approvals.approvals)
543
+ .filter(r => r.status === 'pending' && r.expires_timestamp > now)
544
+ .map(r => ({
545
+ code: r.code,
546
+ server: r.server,
547
+ tool: r.tool,
548
+ phrase: r.phrase,
549
+ created_at: r.created_at,
550
+ expires_at: r.expires_at,
551
+ }));
552
+ }
553
+
554
+ // ============================================================================
555
+ // Database Helpers (for integration with deputy-cto.db)
556
+ // ============================================================================
557
+
558
+ /**
559
+ * Create a protected-action-request in deputy-cto.db
560
+ * This allows the request to show up in CTO notifications
561
+ * @param {string} server - MCP server name
562
+ * @param {string} tool - Tool name
563
+ * @param {object} args - Tool arguments
564
+ * @param {string} code - Approval code
565
+ * @param {string} phrase - Approval phrase
566
+ * @returns {string|null} Question ID or null on failure
567
+ */
568
+ export async function createDbRequest(server, tool, args, code, phrase) {
569
+ try {
570
+ const Database = (await import('better-sqlite3')).default;
571
+
572
+ if (!fs.existsSync(DEPUTY_CTO_DB)) {
573
+ console.error('[approval-utils] deputy-cto.db not found');
574
+ return null;
575
+ }
576
+
577
+ const db = new Database(DEPUTY_CTO_DB);
578
+ const id = crypto.randomUUID();
579
+ const now = new Date();
580
+
581
+ const description = `**Protected Action Request**
582
+
583
+ **Server:** ${server}
584
+ **Tool:** ${tool}
585
+ **Arguments:** \`\`\`json
586
+ ${JSON.stringify(args, null, 2)}
587
+ \`\`\`
588
+
589
+ ---
590
+
591
+ **CTO Action Required:**
592
+ To approve this action, type exactly: **${phrase} ${code}**
593
+
594
+ This approval will expire in 5 minutes.`;
595
+
596
+ const context = JSON.stringify({ code, server, tool, args, phrase });
597
+
598
+ db.prepare(`
599
+ INSERT INTO questions (id, type, status, title, description, context, created_at, created_timestamp)
600
+ VALUES (?, 'protected-action-request', 'pending', ?, ?, ?, ?, ?)
601
+ `).run(
602
+ id,
603
+ `Protected Action: ${server}:${tool}`,
604
+ description,
605
+ context,
606
+ now.toISOString(),
607
+ Math.floor(now.getTime() / 1000)
608
+ );
609
+
610
+ db.close();
611
+ return id;
612
+ } catch (err) {
613
+ console.error(`[approval-utils] Failed to create DB request: ${err.message}`);
614
+ return null;
615
+ }
616
+ }
617
+
618
+ /**
619
+ * Validate an approval code against deputy-cto.db
620
+ * @param {string} code - The 6-character code
621
+ * @returns {object} Validation result with question details
622
+ */
623
+ export async function validateDbApproval(code) {
624
+ try {
625
+ const Database = (await import('better-sqlite3')).default;
626
+
627
+ if (!fs.existsSync(DEPUTY_CTO_DB)) {
628
+ return { valid: false, reason: 'Database not found' };
629
+ }
630
+
631
+ const db = new Database(DEPUTY_CTO_DB, { readonly: true });
632
+
633
+ // Look for pending protected-action-request with this code in context
634
+ const question = db.prepare(`
635
+ SELECT id, title, context, created_at FROM questions
636
+ WHERE type = 'protected-action-request'
637
+ AND status = 'pending'
638
+ AND context LIKE ?
639
+ `).get(`%"code":"${code}"%`);
640
+
641
+ db.close();
642
+
643
+ if (!question) {
644
+ return { valid: false, reason: 'No pending request with this code' };
645
+ }
646
+
647
+ const context = JSON.parse(question.context);
648
+
649
+ return {
650
+ valid: true,
651
+ question_id: question.id,
652
+ server: context.server,
653
+ tool: context.tool,
654
+ args: context.args,
655
+ phrase: context.phrase,
656
+ created_at: question.created_at,
657
+ };
658
+ } catch (err) {
659
+ return { valid: false, reason: `Database error: ${err.message}` };
660
+ }
661
+ }
662
+
663
+ /**
664
+ * Mark a protected-action-request as answered in deputy-cto.db
665
+ * @param {string} questionId - Question UUID
666
+ */
667
+ export async function markDbRequestApproved(questionId) {
668
+ try {
669
+ const Database = (await import('better-sqlite3')).default;
670
+
671
+ if (!fs.existsSync(DEPUTY_CTO_DB)) {
672
+ return;
673
+ }
674
+
675
+ const db = new Database(DEPUTY_CTO_DB);
676
+
677
+ db.prepare(`
678
+ UPDATE questions
679
+ SET status = 'answered', answer = 'APPROVED', answered_at = ?
680
+ WHERE id = ?
681
+ `).run(new Date().toISOString(), questionId);
682
+
683
+ db.close();
684
+ } catch (err) {
685
+ console.error(`[approval-utils] Failed to mark request approved: ${err.message}`);
686
+ }
687
+ }
688
+
689
+ // ============================================================================
690
+ // Exports
691
+ // ============================================================================
692
+
693
+ export default {
694
+ // Code generation
695
+ generateCode,
696
+
697
+ // HMAC
698
+ computeHmac,
699
+
700
+ // Encryption
701
+ generateProtectionKey,
702
+ readProtectionKey,
703
+ writeProtectionKey,
704
+ encryptCredential,
705
+ decryptCredential,
706
+ isEncrypted,
707
+
708
+ // Configuration
709
+ loadProtectedActions,
710
+ saveProtectedActions,
711
+ getProtection,
712
+
713
+ // Approvals
714
+ loadApprovals,
715
+ saveApprovals,
716
+ createRequest,
717
+ validateApproval,
718
+ checkApproval,
719
+ getPendingRequests,
720
+
721
+ // Database integration
722
+ createDbRequest,
723
+ validateDbApproval,
724
+ markDbRequestApproved,
725
+
726
+ // Constants
727
+ PROTECTION_KEY_PATH,
728
+ PROTECTED_ACTIONS_PATH,
729
+ APPROVALS_PATH,
730
+ TOKEN_EXPIRY_MS,
731
+ };