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,560 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Force Triage Reports
4
+ *
5
+ * Standalone script that force-spawns a deputy-CTO triage agent immediately,
6
+ * bypassing the hourly automation's triage check interval and cooldowns.
7
+ *
8
+ * Called by the /triage slash command via the agent-tracker MCP tool.
9
+ *
10
+ * Usage:
11
+ * node scripts/force-triage-reports.js --project-dir /path/to/project
12
+ *
13
+ * @version 1.0.0
14
+ */
15
+
16
+ import * as fs from 'fs';
17
+ import * as path from 'path';
18
+ import * as os from 'os';
19
+ import { fileURLToPath } from 'url';
20
+ import { spawn, execSync, execFileSync } from 'child_process';
21
+
22
+ const __filename = fileURLToPath(import.meta.url);
23
+ const __dirname = path.dirname(__filename);
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // CLI ARGS
27
+ // ---------------------------------------------------------------------------
28
+
29
+ function parseArgs() {
30
+ const args = process.argv.slice(2);
31
+ const result = {
32
+ projectDir: process.env.CLAUDE_PROJECT_DIR || process.cwd(),
33
+ };
34
+
35
+ for (let i = 0; i < args.length; i++) {
36
+ if (args[i] === '--project-dir' && args[i + 1]) {
37
+ result.projectDir = args[++i];
38
+ }
39
+ }
40
+
41
+ return result;
42
+ }
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // AGENT TRACKER IMPORT
46
+ // ---------------------------------------------------------------------------
47
+
48
+ let registerSpawn, updateAgent, AGENT_TYPES, HOOK_TYPES;
49
+
50
+ async function loadAgentTracker(projectDir) {
51
+ const trackerPath = path.join(projectDir, '.claude', 'hooks', 'agent-tracker.js');
52
+ if (!fs.existsSync(trackerPath)) {
53
+ const frameworkTracker = path.resolve(__dirname, '..', '.claude', 'hooks', 'agent-tracker.js');
54
+ if (fs.existsSync(frameworkTracker)) {
55
+ const mod = await import(frameworkTracker);
56
+ registerSpawn = mod.registerSpawn;
57
+ updateAgent = mod.updateAgent;
58
+ AGENT_TYPES = mod.AGENT_TYPES;
59
+ HOOK_TYPES = mod.HOOK_TYPES;
60
+ return;
61
+ }
62
+ throw new Error(`agent-tracker.js not found at ${trackerPath}`);
63
+ }
64
+ const mod = await import(trackerPath);
65
+ registerSpawn = mod.registerSpawn;
66
+ updateAgent = mod.updateAgent;
67
+ AGENT_TYPES = mod.AGENT_TYPES;
68
+ HOOK_TYPES = mod.HOOK_TYPES;
69
+ }
70
+
71
+ // ---------------------------------------------------------------------------
72
+ // CREDENTIAL CACHE (duplicated from force-spawn-tasks.js)
73
+ // ---------------------------------------------------------------------------
74
+
75
+ let resolvedCredentials = {};
76
+ let credentialsResolved = false;
77
+
78
+ function ensureCredentials(projectDir) {
79
+ if (credentialsResolved) return;
80
+ credentialsResolved = true;
81
+ preResolveCredentials(projectDir);
82
+ }
83
+
84
+ function preResolveCredentials(projectDir) {
85
+ const hasServiceAccount = !!process.env.OP_SERVICE_ACCOUNT_TOKEN;
86
+ const isLaunchdService = process.env.GENTYR_LAUNCHD_SERVICE === 'true';
87
+
88
+ if (isLaunchdService && !hasServiceAccount) {
89
+ return;
90
+ }
91
+
92
+ const mappingsPath = path.join(projectDir, '.claude', 'vault-mappings.json');
93
+ const actionsPath = path.join(projectDir, '.claude', 'hooks', 'protected-actions.json');
94
+
95
+ let mappings = {};
96
+ let servers = {};
97
+
98
+ try {
99
+ const data = JSON.parse(fs.readFileSync(mappingsPath, 'utf8'));
100
+ mappings = data.mappings || {};
101
+ } catch {
102
+ return;
103
+ }
104
+
105
+ try {
106
+ const actions = JSON.parse(fs.readFileSync(actionsPath, 'utf8'));
107
+ servers = actions.servers || {};
108
+ } catch {
109
+ return;
110
+ }
111
+
112
+ const allKeys = new Set();
113
+ for (const server of Object.values(servers)) {
114
+ if (server.credentialKeys) {
115
+ for (const key of server.credentialKeys) {
116
+ allKeys.add(key);
117
+ }
118
+ }
119
+ }
120
+
121
+ for (const key of allKeys) {
122
+ if (process.env[key]) continue;
123
+
124
+ const ref = mappings[key];
125
+ if (!ref) continue;
126
+
127
+ if (ref.startsWith('op://')) {
128
+ try {
129
+ const value = execFileSync('op', ['read', ref], {
130
+ encoding: 'utf-8',
131
+ timeout: 15000,
132
+ stdio: 'pipe',
133
+ }).trim();
134
+
135
+ if (value) {
136
+ resolvedCredentials[key] = value;
137
+ }
138
+ } catch {
139
+ // Skip failed credential resolution
140
+ }
141
+ } else {
142
+ resolvedCredentials[key] = ref;
143
+ }
144
+ }
145
+ }
146
+
147
+ function buildSpawnEnv(agentId, projectDir) {
148
+ ensureCredentials(projectDir);
149
+ return {
150
+ ...process.env,
151
+ ...resolvedCredentials,
152
+ CLAUDE_PROJECT_DIR: projectDir,
153
+ CLAUDE_SPAWNED_SESSION: 'true',
154
+ CLAUDE_AGENT_ID: agentId,
155
+ };
156
+ }
157
+
158
+ // ---------------------------------------------------------------------------
159
+ // DB HELPERS
160
+ // ---------------------------------------------------------------------------
161
+
162
+ let Database = null;
163
+
164
+ async function loadDatabase() {
165
+ try {
166
+ Database = (await import('better-sqlite3')).default;
167
+ } catch {
168
+ // Non-fatal but will prevent report count queries
169
+ }
170
+ }
171
+
172
+ function countPendingReports(ctoReportsDbPath) {
173
+ if (!Database || !fs.existsSync(ctoReportsDbPath)) return 0;
174
+
175
+ try {
176
+ const db = new Database(ctoReportsDbPath, { readonly: true });
177
+ const row = db.prepare("SELECT COUNT(*) as cnt FROM reports WHERE triage_status = 'pending'").get();
178
+ db.close();
179
+ return row?.cnt || 0;
180
+ } catch {
181
+ return 0;
182
+ }
183
+ }
184
+
185
+ // ---------------------------------------------------------------------------
186
+ // CONCURRENCY CHECK
187
+ // ---------------------------------------------------------------------------
188
+
189
+ function countRunningAgents() {
190
+ try {
191
+ const result = execSync(
192
+ "pgrep -cf 'claude.*--dangerously-skip-permissions'",
193
+ { encoding: 'utf8', timeout: 5000, stdio: 'pipe' }
194
+ ).trim();
195
+ return parseInt(result, 10) || 0;
196
+ } catch {
197
+ return 0;
198
+ }
199
+ }
200
+
201
+ // ---------------------------------------------------------------------------
202
+ // SESSION ID DISCOVERY
203
+ // ---------------------------------------------------------------------------
204
+
205
+ function getSessionDir(projectDir) {
206
+ const projectPath = projectDir.replace(/[^a-zA-Z0-9]/g, '-').replace(/^-/, '');
207
+ return path.join(os.homedir(), '.claude', 'projects', `-${projectPath}`);
208
+ }
209
+
210
+ function discoverSessionId(projectDir, spawnTimeMs) {
211
+ const sessionDir = getSessionDir(projectDir);
212
+ if (!fs.existsSync(sessionDir)) return null;
213
+
214
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
215
+
216
+ try {
217
+ const files = fs.readdirSync(sessionDir)
218
+ .filter(f => f.endsWith('.jsonl'))
219
+ .map(f => {
220
+ const filePath = path.join(sessionDir, f);
221
+ const stat = fs.statSync(filePath);
222
+ return { name: f, mtime: stat.mtimeMs, size: stat.size };
223
+ })
224
+ .filter(f => {
225
+ const id = f.name.replace('.jsonl', '');
226
+ return UUID_REGEX.test(id) && f.mtime >= spawnTimeMs;
227
+ })
228
+ .sort((a, b) => b.mtime - a.mtime);
229
+
230
+ if (files.length === 0) return null;
231
+ return files[0].name.replace('.jsonl', '');
232
+ } catch {
233
+ return null;
234
+ }
235
+ }
236
+
237
+ function pollForSessionId(projectDir, spawnTimeMs, maxWaitMs = 3000, intervalMs = 500) {
238
+ const deadline = Date.now() + maxWaitMs;
239
+
240
+ while (Date.now() < deadline) {
241
+ const sessionId = discoverSessionId(projectDir, spawnTimeMs);
242
+ if (sessionId) return sessionId;
243
+
244
+ // Synchronous sleep via busy-wait with Atomics for minimal CPU
245
+ const waitMs = Math.min(intervalMs, deadline - Date.now());
246
+ if (waitMs > 0) {
247
+ try {
248
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, waitMs);
249
+ } catch {
250
+ // Fallback: busy-wait
251
+ const end = Date.now() + waitMs;
252
+ while (Date.now() < end) { /* spin */ }
253
+ }
254
+ }
255
+ }
256
+
257
+ return null;
258
+ }
259
+
260
+ // ---------------------------------------------------------------------------
261
+ // TRIAGE PROMPT BUILDER
262
+ // ---------------------------------------------------------------------------
263
+
264
+ function buildTriagePrompt(agentId) {
265
+ return `[Task][report-triage][AGENT:${agentId}] You are an orchestrator performing REPORT TRIAGE.
266
+
267
+ ## IMMEDIATE ACTION
268
+
269
+ Your first action MUST be to spawn the deputy-cto sub-agent:
270
+ \`\`\`
271
+ Task(subagent_type='deputy-cto', prompt='Triage all pending agent reports. Use mcp__agent-reports__get_reports_for_triage to get reports, then investigate and decide on each.')
272
+ \`\`\`
273
+
274
+ The deputy-cto sub-agent has specialized instructions loaded from .claude/agents/deputy-cto.md.
275
+
276
+ ## Mission
277
+
278
+ Triage all pending agent reports that are ready (past cooldown). For each report:
279
+ 1. Investigate to understand the context
280
+ 2. Decide whether to handle it yourself, escalate to CTO, or dismiss
281
+ 3. Take appropriate action
282
+
283
+ ## Step 1: Get Reports Ready for Triage
284
+
285
+ \`\`\`
286
+ mcp__agent-reports__get_reports_for_triage({ limit: 10 })
287
+ \`\`\`
288
+
289
+ This returns reports that are:
290
+ - Status = pending
291
+ - Past the 1-hour per-item cooldown (if previously attempted)
292
+
293
+ If no reports are returned, output "No reports ready for triage" and exit.
294
+
295
+ ## Step 2: Triage Each Report
296
+
297
+ For each report from the list above:
298
+
299
+ ### 2a: Start Triage
300
+ \`\`\`
301
+ mcp__agent-reports__start_triage({ id: "<report-id>" })
302
+ \`\`\`
303
+
304
+ ### 2b: Read the Report
305
+ \`\`\`
306
+ mcp__agent-reports__read_report({ id: "<report-id>" })
307
+ \`\`\`
308
+
309
+ ### 2c: Investigate
310
+
311
+ **Search for related work:**
312
+ \`\`\`
313
+ mcp__todo-db__list_tasks({ limit: 50 }) // Check current tasks
314
+ mcp__deputy-cto__search_cleared_items({ query: "<keywords from report>" }) // Check past CTO items
315
+ mcp__agent-tracker__search_sessions({ query: "<keywords>", limit: 10 }) // Search session history
316
+ \`\`\`
317
+
318
+ **If needed, search the codebase:**
319
+ - Use Grep to find related code
320
+ - Use Read to examine specific files mentioned in the report
321
+
322
+ ### 2d: Check Auto-Escalation Rules
323
+
324
+ **ALWAYS ESCALATE (no exceptions):**
325
+ - **G002 Violations**: Any report mentioning stub code, placeholder, TODO, FIXME, or "not implemented"
326
+ - **Security vulnerabilities**: Any report with category "security" or mentioning vulnerabilities
327
+ - **Bypass requests**: Any bypass-request type (these require CTO approval)
328
+
329
+ If the report matches ANY auto-escalation rule, skip to "If ESCALATING" - do not self-handle or dismiss.
330
+
331
+ ### 2e: Apply Decision Framework (if no auto-escalation)
332
+
333
+ | ESCALATE to CTO | SELF-HANDLE | DISMISS |
334
+ |-----------------|-------------|---------|
335
+ | Breaking change to users | Issue already in todos | Already resolved |
336
+ | Architectural decision needed | Similar issue recently fixed | Not a real problem |
337
+ | Resource/budget implications | Clear fix, low risk | False positive |
338
+ | Cross-team coordination | Obvious code quality fix | Duplicate report |
339
+ | Uncertain about approach | Documentation/test gap | Informational only |
340
+ | High priority + ambiguity | Performance fix clear path | Outdated concern |
341
+ | Policy/process change | Routine maintenance | |
342
+ | | Isolated bug fix | |
343
+
344
+ **Decision Rules:**
345
+ - **>80% confident** you know the right action → self-handle
346
+ - **<80% confident** OR sensitive → escalate
347
+ - **Not actionable** (already fixed, false positive, duplicate) → dismiss
348
+
349
+ ### 2f: Take Action
350
+
351
+ **If SELF-HANDLING:**
352
+ \`\`\`
353
+ // Create an urgent task — dispatched immediately by the urgent dispatcher
354
+ mcp__todo-db__create_task({
355
+ section: "CODE-REVIEWER", // Choose based on task type (see section mapping below)
356
+ title: "Brief actionable title",
357
+ description: "Full context: what to fix, where, why, and acceptance criteria",
358
+ assigned_by: "deputy-cto",
359
+ priority: "urgent"
360
+ })
361
+
362
+ // Complete the triage
363
+ mcp__agent-reports__complete_triage({
364
+ id: "<report-id>",
365
+ status: "self_handled",
366
+ outcome: "Created urgent task to [brief description of fix]"
367
+ })
368
+ \`\`\`
369
+
370
+ Section mapping for self-handled tasks:
371
+ - Code changes (full agent sequence) → "CODE-REVIEWER"
372
+ - Research/analysis only → "INVESTIGATOR & PLANNER"
373
+ - Test creation/updates → "TEST-WRITER"
374
+ - Documentation/cleanup → "PROJECT-MANAGER"
375
+ - Orchestration/delegation → "DEPUTY-CTO"
376
+
377
+ **If ESCALATING:**
378
+ \`\`\`
379
+ // Add to CTO queue with context
380
+ mcp__deputy-cto__add_question({
381
+ type: "escalation", // or "decision" if CTO needs to choose
382
+ title: "Brief title of the issue",
383
+ description: "Context from investigation + why CTO input needed",
384
+ suggested_options: ["Option A", "Option B"], // if applicable
385
+ recommendation: "Your recommended course of action and why" // REQUIRED for escalations
386
+ })
387
+
388
+ // Complete the triage
389
+ mcp__agent-reports__complete_triage({
390
+ id: "<report-id>",
391
+ status: "escalated",
392
+ outcome: "Escalated: [reason CTO input is needed]"
393
+ })
394
+ \`\`\`
395
+
396
+ **If DISMISSING:**
397
+ \`\`\`
398
+ // Complete the triage - no further action needed
399
+ mcp__agent-reports__complete_triage({
400
+ id: "<report-id>",
401
+ status: "dismissed",
402
+ outcome: "Dismissed: [reason - e.g., already resolved, not actionable, duplicate]"
403
+ })
404
+ \`\`\`
405
+
406
+ **IMPORTANT: Only dismiss when you have clear evidence** the issue is not actionable.
407
+ If in doubt, escalate instead.
408
+
409
+ ## Question Types for Escalation
410
+
411
+ Use the appropriate type when calling \`add_question\`:
412
+ - \`decision\` - CTO needs to choose between options
413
+ - \`approval\` - CTO needs to approve a proposed action
414
+ - \`question\` - Seeking CTO guidance/input
415
+ - \`escalation\` - Raising awareness of an issue
416
+
417
+ ## IMPORTANT
418
+
419
+ - Process ALL reports returned by get_reports_for_triage
420
+ - Always call \`start_triage\` before investigating
421
+ - Always call \`complete_triage\` when done
422
+ - Be thorough in investigation but efficient in execution
423
+ - When self-handling, the spawned task prompt should be detailed enough to succeed independently
424
+
425
+ ## Output
426
+
427
+ After processing all reports, output a summary:
428
+ - How many self-handled vs escalated vs dismissed
429
+ - Brief description of each action taken`;
430
+ }
431
+
432
+ // ---------------------------------------------------------------------------
433
+ // MAIN
434
+ // ---------------------------------------------------------------------------
435
+
436
+ async function main() {
437
+ const config = parseArgs();
438
+
439
+ // Load dependencies
440
+ await loadDatabase();
441
+ await loadAgentTracker(config.projectDir);
442
+
443
+ const ctoReportsDbPath = path.join(config.projectDir, '.claude', 'cto-reports.db');
444
+ const pendingReports = countPendingReports(ctoReportsDbPath);
445
+
446
+ if (pendingReports === 0) {
447
+ console.log(JSON.stringify({
448
+ agentId: null,
449
+ pid: null,
450
+ sessionId: null,
451
+ pendingReports: 0,
452
+ message: 'No pending reports to triage',
453
+ }));
454
+ process.exit(0);
455
+ }
456
+
457
+ // Reap completed agents before counting to free slots
458
+ try {
459
+ const { reapCompletedAgents } = await import('./reap-completed-agents.js');
460
+ reapCompletedAgents(config.projectDir);
461
+ } catch {
462
+ // Non-fatal
463
+ }
464
+
465
+ // Check concurrency
466
+ const runningAgents = countRunningAgents();
467
+ const automationConfigPath = path.join(config.projectDir, '.claude', 'state', 'automation-config.json');
468
+ let maxConcurrent = 10;
469
+ try {
470
+ const automationConfig = JSON.parse(fs.readFileSync(automationConfigPath, 'utf8'));
471
+ maxConcurrent = automationConfig?.effective?.MAX_CONCURRENT_AGENTS ?? 10;
472
+ } catch {
473
+ // Use default
474
+ }
475
+
476
+ if (runningAgents >= maxConcurrent) {
477
+ console.log(JSON.stringify({
478
+ agentId: null,
479
+ pid: null,
480
+ sessionId: null,
481
+ pendingReports,
482
+ message: `Concurrency limit reached (${runningAgents}/${maxConcurrent}). Cannot spawn triage agent.`,
483
+ }));
484
+ process.exit(0);
485
+ }
486
+
487
+ // Register spawn
488
+ const agentId = registerSpawn({
489
+ type: AGENT_TYPES.DEPUTY_CTO_REVIEW,
490
+ hookType: HOOK_TYPES.HOURLY_AUTOMATION,
491
+ description: `Force-triage: deputy-cto - ${pendingReports} pending reports`,
492
+ prompt: '',
493
+ metadata: { source: 'force-triage-reports', pendingReports },
494
+ });
495
+
496
+ // Build prompt with embedded agent ID
497
+ const prompt = buildTriagePrompt(agentId);
498
+
499
+ // Store the prompt
500
+ if (updateAgent) {
501
+ updateAgent(agentId, { prompt });
502
+ }
503
+
504
+ // Record spawn time for session discovery
505
+ const spawnTimeMs = Date.now();
506
+
507
+ // Spawn detached claude process
508
+ try {
509
+ const mcpConfig = path.join(config.projectDir, '.mcp.json');
510
+ const claude = spawn('claude', [
511
+ '--dangerously-skip-permissions',
512
+ '--mcp-config', mcpConfig,
513
+ '--output-format', 'json',
514
+ '-p',
515
+ prompt,
516
+ ], {
517
+ detached: true,
518
+ stdio: 'ignore',
519
+ cwd: config.projectDir,
520
+ env: buildSpawnEnv(agentId, config.projectDir),
521
+ });
522
+
523
+ claude.unref();
524
+
525
+ // Store PID
526
+ if (updateAgent) {
527
+ updateAgent(agentId, { pid: claude.pid, status: 'running' });
528
+ }
529
+
530
+ // Poll for session ID
531
+ const sessionId = pollForSessionId(config.projectDir, spawnTimeMs);
532
+
533
+ console.log(JSON.stringify({
534
+ agentId,
535
+ pid: claude.pid,
536
+ sessionId,
537
+ pendingReports,
538
+ }));
539
+ } catch (err) {
540
+ console.log(JSON.stringify({
541
+ agentId,
542
+ pid: null,
543
+ sessionId: null,
544
+ pendingReports,
545
+ error: `Spawn failed: ${err.message}`,
546
+ }));
547
+ process.exit(1);
548
+ }
549
+ }
550
+
551
+ main().catch((err) => {
552
+ console.log(JSON.stringify({
553
+ agentId: null,
554
+ pid: null,
555
+ sessionId: null,
556
+ pendingReports: 0,
557
+ error: `Fatal error: ${err.message}`,
558
+ }));
559
+ process.exit(1);
560
+ });
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Generate Protected Actions Spec
4
+ *
5
+ * Reads protected-actions.json and generates a spec file at
6
+ * specs/reference/PROTECTED-ACTIONS.md for agent discovery.
7
+ *
8
+ * Usage:
9
+ * node scripts/generate-protected-actions-spec.js [--path /project]
10
+ *
11
+ * @version 1.0.0
12
+ */
13
+
14
+ import fs from 'fs';
15
+ import path from 'path';
16
+
17
+ // ============================================================================
18
+ // Configuration
19
+ // ============================================================================
20
+
21
+ let PROJECT_DIR = process.cwd();
22
+
23
+ // Parse --path argument
24
+ const pathIndex = process.argv.indexOf('--path');
25
+ if (pathIndex !== -1 && process.argv[pathIndex + 1]) {
26
+ PROJECT_DIR = path.resolve(process.argv[pathIndex + 1]);
27
+ }
28
+
29
+ const PROTECTED_ACTIONS_PATH = path.join(PROJECT_DIR, '.claude', 'hooks', 'protected-actions.json');
30
+ const SPEC_OUTPUT_PATH = path.join(PROJECT_DIR, 'specs', 'reference', 'PROTECTED-ACTIONS.md');
31
+
32
+ // ============================================================================
33
+ // Main
34
+ // ============================================================================
35
+
36
+ function main() {
37
+ // Check if config exists
38
+ if (!fs.existsSync(PROTECTED_ACTIONS_PATH)) {
39
+ console.log('No protected-actions.json found. Skipping spec generation.');
40
+ return;
41
+ }
42
+
43
+ // Read config
44
+ let config;
45
+ try {
46
+ config = JSON.parse(fs.readFileSync(PROTECTED_ACTIONS_PATH, 'utf8'));
47
+ } catch (err) {
48
+ console.error(`Error reading protected-actions.json: ${err.message}`);
49
+ process.exit(1);
50
+ }
51
+
52
+ const servers = config.servers || {};
53
+ const serverCount = Object.keys(servers).length;
54
+
55
+ if (serverCount === 0) {
56
+ console.log('No protected servers configured. Skipping spec generation.');
57
+ return;
58
+ }
59
+
60
+ // Generate spec content
61
+ const now = new Date().toISOString();
62
+ let content = `# Protected Actions Specification
63
+
64
+ > Auto-generated from protected-actions.json
65
+ > Last updated: ${now}
66
+
67
+ ## Overview
68
+
69
+ This document lists all MCP actions that require CTO approval before execution.
70
+ When you call a protected action without approval, it will be blocked and you'll
71
+ receive a 6-character approval code.
72
+
73
+ ## Approval Workflow
74
+
75
+ 1. **Call protected action** → Blocked with code (e.g., \`A7X9K2\`)
76
+ 2. **Stop and inform CTO** → Display the approval message
77
+ 3. **CTO types approval** → e.g., \`APPROVE PROD A7X9K2\`
78
+ 4. **Retry the action** → Succeeds (one-time use, 5-minute expiry)
79
+
80
+ ## Protected Servers
81
+
82
+ `;
83
+
84
+ // Add each server
85
+ for (const [serverName, serverConfig] of Object.entries(servers)) {
86
+ const tools = serverConfig.tools === '*' ? 'All tools' : serverConfig.tools.join(', ');
87
+ const protection = serverConfig.protection || 'approval-only';
88
+
89
+ content += `### ${serverName}
90
+
91
+ | Property | Value |
92
+ |----------|-------|
93
+ | **Protection** | ${protection} |
94
+ | **Approval Phrase** | \`${serverConfig.phrase}\` |
95
+ | **Protected Tools** | ${tools} |
96
+ ${serverConfig.description ? `| **Description** | ${serverConfig.description} |` : ''}
97
+
98
+ **To approve:** CTO types \`${serverConfig.phrase} <CODE>\`
99
+
100
+ ---
101
+
102
+ `;
103
+ }
104
+
105
+ // Add usage section
106
+ content += `## Agent Instructions
107
+
108
+ ### Before calling protected actions:
109
+ - Use \`mcp__deputy-cto__list_protections()\` to see what's protected
110
+ - Be prepared for the action to be blocked
111
+
112
+ ### When action is blocked:
113
+ 1. Note the 6-character code in the error message
114
+ 2. Inform the CTO: "Please type: \`{PHRASE} {CODE}\`"
115
+ 3. **DO NOT retry until CTO confirms approval**
116
+ 4. After CTO types approval, retry the action
117
+
118
+ ### Checking request status:
119
+ - Use \`mcp__deputy-cto__get_protected_action_request({ code: "XXXXXX" })\`
120
+ - Status will be "pending" or "approved"
121
+
122
+ ## Security Notes
123
+
124
+ - **One-time use**: Each approval code can only be used once
125
+ - **5-minute expiry**: Approvals expire if not used
126
+ - **Human-only**: Only CTO keyboard input can approve (agents cannot forge)
127
+ - **Credential isolation**: For \`credential-isolated\` servers, credentials are encrypted and only decrypted upon approval
128
+ `;
129
+
130
+ // Ensure directory exists
131
+ const specDir = path.dirname(SPEC_OUTPUT_PATH);
132
+ if (!fs.existsSync(specDir)) {
133
+ fs.mkdirSync(specDir, { recursive: true });
134
+ }
135
+
136
+ // Write spec file
137
+ fs.writeFileSync(SPEC_OUTPUT_PATH, content);
138
+ console.log(`Generated: ${SPEC_OUTPUT_PATH}`);
139
+ console.log(`Protected servers: ${serverCount}`);
140
+ }
141
+
142
+ main();