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,439 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Agent Reaper — Precision process cleanup for completed spawned Claude sessions.
4
+ *
5
+ * Finds agents tracked by agent-tracker that have finished their work
6
+ * (last JSONL line is assistant-only text with no tool_use) and kills them.
7
+ *
8
+ * Safety guarantees:
9
+ * - Only kills processes whose session file starts with [Task] (automated)
10
+ * - Only kills processes whose last assistant message has no tool_use blocks
11
+ * - Never kills interactive (non-[Task]) sessions
12
+ * - Never kills processes it can't match to a known session file
13
+ * - Processes that are already dead are simply marked completed
14
+ *
15
+ * @version 2.0.0
16
+ */
17
+
18
+ import fs from 'fs';
19
+ import path from 'path';
20
+ import os from 'os';
21
+
22
+ // Lazy-loaded SQLite for TODO reconciliation
23
+ let Database = null;
24
+ try {
25
+ Database = (await import('better-sqlite3')).default;
26
+ } catch {
27
+ // Non-fatal: TODO reconciliation will be skipped
28
+ }
29
+
30
+ // ============================================================================
31
+ // Configuration
32
+ // ============================================================================
33
+
34
+ const CLAUDE_PROJECTS_DIR = path.join(os.homedir(), '.claude', 'projects');
35
+ const HEAD_BYTES = 2000; // Bytes to read from start of JSONL for agent ID match
36
+ const TAIL_BYTES = 4000; // Bytes to read from end of JSONL for completion check
37
+
38
+ // ============================================================================
39
+ // Core Functions
40
+ // ============================================================================
41
+
42
+ /**
43
+ * Check if a process is alive.
44
+ * @param {number} pid
45
+ * @returns {boolean}
46
+ */
47
+ function isProcessAlive(pid) {
48
+ try {
49
+ process.kill(pid, 0);
50
+ return true;
51
+ } catch (err) {
52
+ return err.code !== 'ESRCH';
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Discover the normalized session directory for a project.
58
+ * @param {string} projectDir
59
+ * @returns {string|null}
60
+ */
61
+ function getSessionDir(projectDir) {
62
+ const projectPath = projectDir.replace(/[^a-zA-Z0-9]/g, '-');
63
+ const sessionDir = path.join(CLAUDE_PROJECTS_DIR, projectPath);
64
+ if (fs.existsSync(sessionDir)) return sessionDir;
65
+
66
+ const altPath = path.join(CLAUDE_PROJECTS_DIR, projectPath.replace(/^-/, ''));
67
+ if (fs.existsSync(altPath)) return altPath;
68
+
69
+ return null;
70
+ }
71
+
72
+ /**
73
+ * Read the first N bytes of a file using a file descriptor (no full-file read).
74
+ * @param {string} filePath
75
+ * @param {number} numBytes
76
+ * @returns {string}
77
+ */
78
+ function readHead(filePath, numBytes) {
79
+ let fd;
80
+ try {
81
+ fd = fs.openSync(filePath, 'r');
82
+ const buf = Buffer.alloc(numBytes);
83
+ const bytesRead = fs.readSync(fd, buf, 0, numBytes, 0);
84
+ return buf.toString('utf8', 0, bytesRead);
85
+ } catch {
86
+ return '';
87
+ } finally {
88
+ if (fd !== undefined) fs.closeSync(fd);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Read the last N bytes of a file using a file descriptor (seek to end).
94
+ * @param {string} filePath
95
+ * @param {number} numBytes
96
+ * @returns {string}
97
+ */
98
+ function readTail(filePath, numBytes) {
99
+ let fd;
100
+ try {
101
+ fd = fs.openSync(filePath, 'r');
102
+ const stat = fs.fstatSync(fd);
103
+ const start = Math.max(0, stat.size - numBytes);
104
+ const buf = Buffer.alloc(Math.min(numBytes, stat.size));
105
+ const bytesRead = fs.readSync(fd, buf, 0, buf.length, start);
106
+ return buf.toString('utf8', 0, bytesRead);
107
+ } catch {
108
+ return '';
109
+ } finally {
110
+ if (fd !== undefined) fs.closeSync(fd);
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Find the session file that contains a given agent tracking ID
116
+ * by scanning the first bytes of each JSONL file.
117
+ *
118
+ * @param {string} sessionDir - Directory containing JSONL session files
119
+ * @param {string} agentId - The agent ID to search for (e.g. "agent-mlr08lpw-2444b1e0")
120
+ * @returns {string|null} Full path to matching session file, or null
121
+ */
122
+ function findSessionFileByAgentId(sessionDir, agentId) {
123
+ const marker = `[AGENT:${agentId}]`;
124
+
125
+ let files;
126
+ try {
127
+ files = fs.readdirSync(sessionDir).filter(f => f.endsWith('.jsonl'));
128
+ } catch {
129
+ return null;
130
+ }
131
+
132
+ for (const file of files) {
133
+ const filePath = path.join(sessionDir, file);
134
+ const head = readHead(filePath, HEAD_BYTES);
135
+ if (head.includes(marker)) {
136
+ return filePath;
137
+ }
138
+ }
139
+
140
+ return null;
141
+ }
142
+
143
+ /**
144
+ * Check if a session's last assistant message indicates completion.
145
+ * Completion = last JSON line is type=assistant with text-only content (no tool_use).
146
+ *
147
+ * @param {string} sessionFile - Path to the JSONL session file
148
+ * @returns {boolean}
149
+ */
150
+ function isSessionComplete(sessionFile) {
151
+ const tail = readTail(sessionFile, TAIL_BYTES);
152
+ if (!tail) return false;
153
+
154
+ // Split into lines and find the last parseable JSON line
155
+ const lines = tail.split('\n').filter(l => l.trim());
156
+
157
+ // Work backwards to find the last parseable line
158
+ for (let i = lines.length - 1; i >= 0; i--) {
159
+ let parsed;
160
+ try {
161
+ parsed = JSON.parse(lines[i]);
162
+ } catch {
163
+ continue;
164
+ }
165
+
166
+ // Must be an assistant message
167
+ if (parsed.type !== 'assistant') return false;
168
+
169
+ // Check content array for tool_use blocks
170
+ const content = parsed.message?.content;
171
+ if (!Array.isArray(content)) {
172
+ // If content isn't an array, it's text-only — session is complete
173
+ return true;
174
+ }
175
+
176
+ // If any content block is tool_use, agent is still working
177
+ const hasToolUse = content.some(c => c.type === 'tool_use');
178
+ return !hasToolUse;
179
+ }
180
+
181
+ return false;
182
+ }
183
+
184
+ /**
185
+ * Verify that a session is automated (starts with [Task]) — defense-in-depth.
186
+ *
187
+ * @param {string} sessionFile - Path to the JSONL session file
188
+ * @returns {boolean}
189
+ */
190
+ function isAutomatedSession(sessionFile) {
191
+ const head = readHead(sessionFile, HEAD_BYTES);
192
+ return head.includes('[Task]');
193
+ }
194
+
195
+ /**
196
+ * Check if a session JSONL contains evidence of a complete_task MCP tool call.
197
+ * Searches the last 16KB for the tool name pattern.
198
+ *
199
+ * @param {string} sessionFile - Path to the JSONL session file
200
+ * @returns {boolean}
201
+ */
202
+ function sessionContainsCompleteTask(sessionFile) {
203
+ const tail = readTail(sessionFile, 16384);
204
+ return tail.includes('"mcp__todo-db__complete_task"') ||
205
+ tail.includes('"name":"complete_task"');
206
+ }
207
+
208
+ /**
209
+ * Reconcile a TODO item after an agent is reaped.
210
+ * - If session completed normally but forgot to mark TODO: mark it completed
211
+ * - If session died unexpectedly: reset TODO to pending for re-spawn
212
+ *
213
+ * @param {object} agent - Agent record from tracker history
214
+ * @param {string} projectDir - Project directory
215
+ * @param {string} reapReason - Why the agent was reaped
216
+ * @returns {{ action: string, taskId: string } | null}
217
+ */
218
+ function reconcileTodo(agent, projectDir, reapReason) {
219
+ if (!Database) return null;
220
+
221
+ // Only reconcile agents that have a linked task ID
222
+ const taskId = agent.metadata?.taskId;
223
+ if (!taskId) return null;
224
+
225
+ const todoDbPath = path.join(projectDir, '.claude', 'todo.db');
226
+ if (!fs.existsSync(todoDbPath)) return null;
227
+
228
+ let db;
229
+ try {
230
+ db = new Database(todoDbPath);
231
+
232
+ // Check current task status
233
+ const task = db.prepare('SELECT id, status FROM tasks WHERE id = ?').get(taskId);
234
+ if (!task) return null;
235
+
236
+ // Only act on in_progress tasks (already completed = no action needed)
237
+ if (task.status !== 'in_progress') return null;
238
+
239
+ if (reapReason === 'session_complete') {
240
+ // Agent completed normally - check if it called complete_task
241
+ const sessionFile = agent.sessionFile;
242
+ if (sessionFile && fs.existsSync(sessionFile) && sessionContainsCompleteTask(sessionFile)) {
243
+ // complete_task was called, TODO should already be marked - no action needed
244
+ return null;
245
+ }
246
+ // Agent finished but didn't mark TODO as complete
247
+ db.prepare("UPDATE tasks SET status = 'completed' WHERE id = ?").run(taskId);
248
+ return { action: 'completed', taskId };
249
+ }
250
+
251
+ if (reapReason === 'process_already_dead') {
252
+ // Session died unexpectedly - reset TODO so automation can re-spawn
253
+ db.prepare("UPDATE tasks SET status = 'pending', started_at = NULL WHERE id = ?").run(taskId);
254
+ return { action: 'reset_to_pending', taskId };
255
+ }
256
+
257
+ return null;
258
+ } catch {
259
+ return null;
260
+ } finally {
261
+ if (db) {
262
+ try { db.close(); } catch { /* ignore */ }
263
+ }
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Reap completed automated agents.
269
+ *
270
+ * @param {string} projectDir - The project directory
271
+ * @returns {{ reaped: Array<{agentId: string, pid: number, reason: string}>, skipped: Array<{agentId: string, reason: string}>, errors: Array<{agentId: string, error: string}>, todoReconciled: Array<{agentId: string, taskId: string, action: string}> }}
272
+ */
273
+ export function reapCompletedAgents(projectDir) {
274
+ const result = { reaped: [], skipped: [], errors: [], todoReconciled: [] };
275
+
276
+ // Load agent tracker
277
+ const historyPath = path.join(projectDir, '.claude', 'state', 'agent-tracker-history.json');
278
+ let history;
279
+ try {
280
+ if (!fs.existsSync(historyPath)) return result;
281
+ history = JSON.parse(fs.readFileSync(historyPath, 'utf8'));
282
+ } catch {
283
+ return result;
284
+ }
285
+
286
+ if (!Array.isArray(history.agents)) return result;
287
+
288
+ // Find the session directory
289
+ const sessionDir = getSessionDir(projectDir);
290
+ if (!sessionDir) return result;
291
+
292
+ // Track whether we made any changes
293
+ let dirty = false;
294
+
295
+ for (const agent of history.agents) {
296
+ // Only process agents with status=running and a stored PID
297
+ if (agent.status !== 'running' || !agent.pid) continue;
298
+
299
+ const agentId = agent.id;
300
+ const pid = agent.pid;
301
+
302
+ // Step 1: Check if process is still alive
303
+ if (!isProcessAlive(pid)) {
304
+ // Try to discover session file before marking dead (needed for TODO reconciliation)
305
+ if (!agent.sessionFile) {
306
+ const discovered = findSessionFileByAgentId(sessionDir, agentId);
307
+ if (discovered) {
308
+ agent.sessionFile = discovered;
309
+ }
310
+ }
311
+
312
+ agent.status = 'completed';
313
+ agent.reapReason = 'process_already_dead';
314
+ agent.reapedAt = new Date().toISOString();
315
+ dirty = true;
316
+ result.reaped.push({ agentId, pid, reason: 'process_already_dead' });
317
+
318
+ // Reconcile linked TODO item
319
+ const todoResult = reconcileTodo(agent, projectDir, 'process_already_dead');
320
+ if (todoResult) {
321
+ result.todoReconciled.push({ agentId, ...todoResult });
322
+ }
323
+ continue;
324
+ }
325
+
326
+ // Step 2: Discover session file (use cached if available)
327
+ let sessionFile = agent.sessionFile || null;
328
+ if (!sessionFile) {
329
+ sessionFile = findSessionFileByAgentId(sessionDir, agentId);
330
+ if (!sessionFile) {
331
+ result.skipped.push({ agentId, reason: 'session_file_not_found' });
332
+ continue;
333
+ }
334
+ // Cache for future runs
335
+ agent.sessionFile = sessionFile;
336
+ dirty = true;
337
+ }
338
+
339
+ // Step 3: Check completion via JSONL
340
+ if (!isSessionComplete(sessionFile)) {
341
+ result.skipped.push({ agentId, reason: 'session_not_complete' });
342
+ continue;
343
+ }
344
+
345
+ // Step 4: Verify automated session (defense-in-depth)
346
+ if (!isAutomatedSession(sessionFile)) {
347
+ result.skipped.push({ agentId, reason: 'not_automated_session' });
348
+ continue;
349
+ }
350
+
351
+ // Step 5: Kill the process
352
+ try {
353
+ process.kill(pid, 'SIGKILL');
354
+ agent.status = 'reaped';
355
+ agent.reapedAt = new Date().toISOString();
356
+ agent.reapReason = 'session_complete';
357
+ dirty = true;
358
+ result.reaped.push({ agentId, pid, reason: 'session_complete' });
359
+
360
+ // Reconcile linked TODO item
361
+ const todoResult = reconcileTodo(agent, projectDir, 'session_complete');
362
+ if (todoResult) {
363
+ result.todoReconciled.push({ agentId, ...todoResult });
364
+ }
365
+ } catch (err) {
366
+ if (err.code === 'ESRCH') {
367
+ // Already dead between our check and kill
368
+ agent.status = 'completed';
369
+ agent.reapedAt = new Date().toISOString();
370
+ agent.reapReason = 'process_already_dead';
371
+ dirty = true;
372
+ result.reaped.push({ agentId, pid, reason: 'process_already_dead' });
373
+
374
+ // Reconcile linked TODO item
375
+ const todoResult = reconcileTodo(agent, projectDir, 'process_already_dead');
376
+ if (todoResult) {
377
+ result.todoReconciled.push({ agentId, ...todoResult });
378
+ }
379
+ } else {
380
+ result.errors.push({ agentId, error: `kill failed: ${err.message}` });
381
+ }
382
+ }
383
+ }
384
+
385
+ // Write back if changes were made
386
+ if (dirty) {
387
+ try {
388
+ fs.writeFileSync(historyPath, JSON.stringify(history, null, 2), 'utf8');
389
+ } catch (err) {
390
+ result.errors.push({ agentId: '_history_write', error: err.message });
391
+ }
392
+ }
393
+
394
+ return result;
395
+ }
396
+
397
+ // ============================================================================
398
+ // CLI Entry Point
399
+ // ============================================================================
400
+
401
+ if (process.argv[1] && (
402
+ process.argv[1].endsWith('reap-completed-agents.js') ||
403
+ process.argv[1].endsWith('reap-completed-agents')
404
+ )) {
405
+ const projectDir = process.argv[2] || process.env.CLAUDE_PROJECT_DIR || process.cwd();
406
+ const result = reapCompletedAgents(projectDir);
407
+
408
+ if (result.reaped.length > 0) {
409
+ console.log(`Reaped ${result.reaped.length} completed agent(s):`);
410
+ for (const r of result.reaped) {
411
+ console.log(` ${r.agentId} (PID ${r.pid}): ${r.reason}`);
412
+ }
413
+ }
414
+
415
+ if (result.skipped.length > 0) {
416
+ console.log(`Skipped ${result.skipped.length} agent(s):`);
417
+ for (const s of result.skipped) {
418
+ console.log(` ${s.agentId}: ${s.reason}`);
419
+ }
420
+ }
421
+
422
+ if (result.errors.length > 0) {
423
+ console.error(`Errors: ${result.errors.length}`);
424
+ for (const e of result.errors) {
425
+ console.error(` ${e.agentId}: ${e.error}`);
426
+ }
427
+ }
428
+
429
+ if (result.todoReconciled.length > 0) {
430
+ console.log(`TODO reconciled for ${result.todoReconciled.length} agent(s):`);
431
+ for (const t of result.todoReconciled) {
432
+ console.log(` ${t.agentId}: TODO ${t.taskId} → ${t.action}`);
433
+ }
434
+ }
435
+
436
+ if (result.reaped.length === 0 && result.skipped.length === 0) {
437
+ console.log('No agents with tracking data found (expected for pre-tracking agents).');
438
+ }
439
+ }
@@ -0,0 +1,86 @@
1
+ #!/bin/bash
2
+ # Reinstall GENTYR (unprotect → install → protect)
3
+ #
4
+ # Usage: sudo scripts/reinstall.sh --path /path/to/project [--op-token <token>] [--makerkit|--no-makerkit]
5
+ #
6
+ # Requires sudo since it handles protection.
7
+ # After reinstall, start a new Claude Code session and run /setup-gentyr
8
+ # to configure credentials interactively.
9
+ #
10
+ # DEPRECATION NOTICE:
11
+ # This script will be superseded by the `npx gentyr` CLI in a future release.
12
+ # Prefer: sudo npx gentyr sync --path /path/to/project
13
+
14
+ set -e
15
+
16
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
17
+ PROJECT_DIR=""
18
+ OP_TOKEN=""
19
+ MAKERKIT_FLAG=""
20
+
21
+ while [[ $# -gt 0 ]]; do
22
+ case "$1" in
23
+ --path)
24
+ PROJECT_DIR="$2"
25
+ shift 2
26
+ ;;
27
+ --op-token)
28
+ OP_TOKEN="$2"
29
+ shift 2
30
+ ;;
31
+ --makerkit)
32
+ MAKERKIT_FLAG="--makerkit"
33
+ shift
34
+ ;;
35
+ --no-makerkit)
36
+ MAKERKIT_FLAG="--no-makerkit"
37
+ shift
38
+ ;;
39
+ *)
40
+ echo "Usage: sudo $0 --path /path/to/project [--op-token <token>] [--makerkit|--no-makerkit]"
41
+ exit 1
42
+ ;;
43
+ esac
44
+ done
45
+
46
+ if [ -z "$PROJECT_DIR" ]; then
47
+ echo "Usage: sudo $0 --path /path/to/project [--op-token <token>] [--makerkit|--no-makerkit]"
48
+ exit 1
49
+ fi
50
+
51
+ if [ "$EUID" -ne 0 ]; then
52
+ echo "Error: requires sudo"
53
+ echo "Usage: sudo $0 --path /path/to/project"
54
+ exit 1
55
+ fi
56
+
57
+ ORIGINAL_USER="${SUDO_USER:-$(logname 2>/dev/null || echo $USER)}"
58
+
59
+ echo "Reinstalling framework at: $PROJECT_DIR"
60
+ echo "Running install step as: $ORIGINAL_USER"
61
+ echo ""
62
+
63
+ # 1. Unprotect (as root)
64
+ "$SCRIPT_DIR/setup.sh" --path "$PROJECT_DIR" --unprotect-only 2>/dev/null || true
65
+
66
+ # 2. Install (as user)
67
+ SETUP_ARGS=(--path "$PROJECT_DIR")
68
+ if [ -n "$OP_TOKEN" ]; then
69
+ SETUP_ARGS+=(--op-token "$OP_TOKEN")
70
+ fi
71
+ if [ -n "$MAKERKIT_FLAG" ]; then
72
+ SETUP_ARGS+=("$MAKERKIT_FLAG")
73
+ fi
74
+ sudo -u "$ORIGINAL_USER" "$SCRIPT_DIR/setup.sh" "${SETUP_ARGS[@]}"
75
+
76
+ # 3. Protect (as root)
77
+ "$SCRIPT_DIR/setup.sh" --path "$PROJECT_DIR" --protect-only
78
+
79
+ echo ""
80
+ echo "════════════════════════════════════════════════════════════"
81
+ echo " Reinstall complete!"
82
+ echo ""
83
+ echo " Next steps:"
84
+ echo " 1. Start a new Claude Code session"
85
+ echo " 2. Run /setup-gentyr to configure credentials"
86
+ echo "════════════════════════════════════════════════════════════"
@@ -0,0 +1,185 @@
1
+ #!/bin/bash
2
+ # Re-sign Homebrew's Node.js binary for macOS TCC persistence
3
+ #
4
+ # macOS TCC (Transparency, Consent, and Control) requires binaries to have
5
+ # a stable code identity to remember permission grants. Homebrew's node is
6
+ # ad-hoc signed (no team identifier), so macOS re-prompts on every new
7
+ # process. This script creates a self-signed certificate and re-signs node,
8
+ # giving it a stable identity that TCC can persist.
9
+ #
10
+ # Run after: brew upgrade node
11
+ # Run during: GENTYR setup (called automatically by setup.sh)
12
+ #
13
+ # Usage: scripts/resign-node.sh [--check] [--trigger-tcc]
14
+
15
+ set -eo pipefail
16
+
17
+ CERT_NAME="NodeLocalDev"
18
+ RED='\033[0;31m'
19
+ GREEN='\033[0;32m'
20
+ YELLOW='\033[1;33m'
21
+ NC='\033[0m'
22
+
23
+ # Resolve the actual node binary (follow symlinks)
24
+ NODE_SYMLINK="/opt/homebrew/bin/node"
25
+ if [ ! -e "$NODE_SYMLINK" ]; then
26
+ # Fallback for non-Homebrew installs
27
+ NODE_SYMLINK="$(which node 2>/dev/null || true)"
28
+ if [ -z "$NODE_SYMLINK" ]; then
29
+ echo -e "${RED}Error: node not found${NC}"
30
+ exit 1
31
+ fi
32
+ fi
33
+ NODE_PATH="$(readlink -f "$NODE_SYMLINK" 2>/dev/null || realpath "$NODE_SYMLINK" 2>/dev/null || echo "$NODE_SYMLINK")"
34
+
35
+ # --check mode: just report current signing status
36
+ if [ "$1" = "--check" ]; then
37
+ AUTHORITY=$(codesign -dvv "$NODE_PATH" 2>&1 | grep "^Authority=" | head -1 | cut -d= -f2)
38
+ if [ "$AUTHORITY" = "$CERT_NAME" ]; then
39
+ echo -e "${GREEN}Node is signed with $CERT_NAME${NC}"
40
+ echo " Binary: $NODE_PATH"
41
+ exit 0
42
+ elif echo "$AUTHORITY" | grep -q "adhoc"; then
43
+ echo -e "${YELLOW}Node has ad-hoc signature (TCC prompts will repeat)${NC}"
44
+ echo " Binary: $NODE_PATH"
45
+ exit 1
46
+ else
47
+ echo -e "${YELLOW}Node signed by: ${AUTHORITY:-unknown}${NC}"
48
+ echo " Binary: $NODE_PATH"
49
+ exit 1
50
+ fi
51
+ fi
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # TCC trigger: run op through node so macOS attributes the access to node
55
+ # ---------------------------------------------------------------------------
56
+ trigger_tcc_prompt() {
57
+ # Check if op is installed
58
+ if ! command -v op &>/dev/null; then
59
+ echo -e " ${YELLOW}1Password CLI (op) not found - skipping TCC trigger${NC}"
60
+ return 0
61
+ fi
62
+
63
+ echo -e "${YELLOW}Triggering macOS TCC permission for 1Password access...${NC}"
64
+ echo -e " (If a macOS dialog appears, click Allow to grant permission)"
65
+
66
+ # Run op through node so macOS attributes the IPC access to node's code identity.
67
+ # This mirrors what hourly-automation.js does with execFileSync('op', ...).
68
+ TCC_RESULT=$("$NODE_PATH" -e "
69
+ const { execFileSync } = require('child_process');
70
+ try {
71
+ execFileSync('op', ['vault', 'list', '--format', 'json'], {
72
+ encoding: 'utf-8',
73
+ timeout: 30000,
74
+ stdio: 'pipe',
75
+ });
76
+ process.stdout.write('ok');
77
+ } catch (err) {
78
+ process.stderr.write(err.message || 'failed');
79
+ process.exit(1);
80
+ }
81
+ " 2>/dev/null) || true
82
+
83
+ if [ "$TCC_RESULT" = "ok" ]; then
84
+ echo -e " ${GREEN}TCC permission granted - verifying persistence...${NC}"
85
+ # Run a second time to confirm no new prompt appears
86
+ VERIFY_RESULT=$("$NODE_PATH" -e "
87
+ const { execFileSync } = require('child_process');
88
+ try {
89
+ execFileSync('op', ['vault', 'list', '--format', 'json'], {
90
+ encoding: 'utf-8',
91
+ timeout: 15000,
92
+ stdio: 'pipe',
93
+ });
94
+ process.stdout.write('persisted');
95
+ } catch {
96
+ process.stdout.write('failed');
97
+ }
98
+ " 2>/dev/null) || true
99
+
100
+ if [ "$VERIFY_RESULT" = "persisted" ]; then
101
+ echo -e " ${GREEN}TCC permission verified and persisted - no future prompts expected${NC}"
102
+ else
103
+ echo -e " ${YELLOW}TCC verification inconclusive - permission may need re-granting${NC}"
104
+ fi
105
+ else
106
+ echo -e " ${YELLOW}1Password access check failed (may not be signed in)${NC}"
107
+ echo -e " ${YELLOW}TCC prompt will appear on first automation run instead${NC}"
108
+ fi
109
+ }
110
+
111
+ # --trigger-tcc mode: just trigger and verify TCC without re-signing
112
+ if [ "$1" = "--trigger-tcc" ]; then
113
+ trigger_tcc_prompt
114
+ exit 0
115
+ fi
116
+
117
+ echo -e "${YELLOW}Re-signing node for macOS TCC persistence...${NC}"
118
+ echo " Binary: $NODE_PATH"
119
+
120
+ # Check if certificate exists
121
+ CERT_EXISTS=$(security find-identity -v -p codesigning 2>&1 | grep "$CERT_NAME" || true)
122
+
123
+ if [ -z "$CERT_EXISTS" ]; then
124
+ echo -e " ${YELLOW}Creating self-signed codesigning certificate '$CERT_NAME'...${NC}"
125
+
126
+ # Generate certificate with openssl
127
+ TMPDIR_CERT="$(mktemp -d)"
128
+ openssl req -x509 -newkey rsa:2048 \
129
+ -keyout "$TMPDIR_CERT/key.pem" \
130
+ -out "$TMPDIR_CERT/cert.pem" \
131
+ -days 3650 \
132
+ -nodes \
133
+ -subj "/CN=$CERT_NAME/O=LocalDev" \
134
+ -addext "keyUsage=digitalSignature" \
135
+ -addext "extendedKeyUsage=codeSigning" \
136
+ 2>/dev/null
137
+
138
+ # Create PKCS12 bundle and import into login keychain
139
+ openssl pkcs12 -export \
140
+ -out "$TMPDIR_CERT/cert.p12" \
141
+ -inkey "$TMPDIR_CERT/key.pem" \
142
+ -in "$TMPDIR_CERT/cert.pem" \
143
+ -passout pass:temp123 \
144
+ 2>/dev/null
145
+
146
+ security import "$TMPDIR_CERT/cert.p12" \
147
+ -k ~/Library/Keychains/login.keychain-db \
148
+ -P temp123 \
149
+ -T /usr/bin/codesign \
150
+ -T /usr/bin/security \
151
+ 2>/dev/null
152
+
153
+ # Trust the certificate for code signing
154
+ security add-trusted-cert -d -r trustRoot -p codeSign \
155
+ -k ~/Library/Keychains/login.keychain-db \
156
+ "$TMPDIR_CERT/cert.pem" \
157
+ 2>/dev/null
158
+
159
+ # Clean up temp files
160
+ rm -rf "$TMPDIR_CERT"
161
+
162
+ echo -e " ${GREEN}Certificate '$CERT_NAME' created and trusted${NC}"
163
+ fi
164
+
165
+ # Check current signature
166
+ CURRENT_AUTHORITY=$(codesign -dvv "$NODE_PATH" 2>&1 | grep "^Authority=" | head -1 | cut -d= -f2)
167
+ if [ "$CURRENT_AUTHORITY" = "$CERT_NAME" ]; then
168
+ echo -e " ${GREEN}Already signed with $CERT_NAME - no re-signing needed${NC}"
169
+ trigger_tcc_prompt
170
+ exit 0
171
+ fi
172
+
173
+ # Re-sign the node binary
174
+ codesign -fs "$CERT_NAME" "$NODE_PATH" 2>&1
175
+ echo -e " ${GREEN}Signed: $NODE_PATH${NC}"
176
+
177
+ # Verify
178
+ VERIFY=$(codesign -dvv "$NODE_PATH" 2>&1 | grep "^Authority=" | head -1)
179
+ echo -e " ${GREEN}Verified: $VERIFY${NC}"
180
+ echo ""
181
+ echo -e "${GREEN}Done. Node re-signed with $CERT_NAME.${NC}"
182
+
183
+ # Trigger TCC prompt so the user grants permission now (during setup),
184
+ # not randomly later during background automation.
185
+ trigger_tcc_prompt