@ebowwa/coder 0.2.1 → 0.7.64

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 (401) hide show
  1. package/README.md +31 -32
  2. package/dist/core/__tests__/permissions.test.d.ts +12 -0
  3. package/dist/core/__tests__/permissions.test.d.ts.map +1 -0
  4. package/dist/core/__tests__/permissions.test.js +851 -0
  5. package/dist/core/agent-loop/__tests__/compaction.test.d.ts +5 -0
  6. package/dist/core/agent-loop/__tests__/compaction.test.d.ts.map +1 -0
  7. package/dist/core/agent-loop/__tests__/compaction.test.js +209 -0
  8. package/dist/core/agent-loop/__tests__/formatters.test.d.ts +5 -0
  9. package/dist/core/agent-loop/__tests__/formatters.test.d.ts.map +1 -0
  10. package/dist/core/agent-loop/__tests__/formatters.test.js +195 -0
  11. package/dist/core/agent-loop/__tests__/index.test.d.ts +5 -0
  12. package/dist/core/agent-loop/__tests__/index.test.d.ts.map +1 -0
  13. package/dist/core/agent-loop/__tests__/index.test.js +121 -0
  14. package/dist/core/agent-loop/__tests__/loop-state.test.d.ts +5 -0
  15. package/dist/core/agent-loop/__tests__/loop-state.test.d.ts.map +1 -0
  16. package/dist/core/agent-loop/__tests__/loop-state.test.js +340 -0
  17. package/dist/core/agent-loop/__tests__/message-builder.test.d.ts +5 -0
  18. package/dist/core/agent-loop/__tests__/message-builder.test.d.ts.map +1 -0
  19. package/dist/core/agent-loop/__tests__/message-builder.test.js +178 -0
  20. package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts +5 -0
  21. package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts.map +1 -0
  22. package/dist/core/agent-loop/__tests__/tool-executor.test.js +331 -0
  23. package/dist/core/agent-loop/compaction.d.ts +39 -0
  24. package/dist/core/agent-loop/compaction.d.ts.map +1 -0
  25. package/dist/core/agent-loop/compaction.js +51 -0
  26. package/dist/core/agent-loop/formatters.d.ts +21 -0
  27. package/dist/core/agent-loop/formatters.d.ts.map +1 -0
  28. package/dist/core/agent-loop/formatters.js +42 -0
  29. package/dist/core/agent-loop/index.d.ts +25 -0
  30. package/dist/core/agent-loop/index.d.ts.map +1 -0
  31. package/dist/core/agent-loop/index.js +83 -0
  32. package/dist/core/agent-loop/loop-state.d.ts +74 -0
  33. package/dist/core/agent-loop/loop-state.d.ts.map +1 -0
  34. package/dist/core/agent-loop/loop-state.js +147 -0
  35. package/dist/core/agent-loop/message-builder.d.ts +13 -0
  36. package/dist/core/agent-loop/message-builder.d.ts.map +1 -0
  37. package/dist/core/agent-loop/message-builder.js +49 -0
  38. package/dist/core/agent-loop/tool-executor.d.ts +23 -0
  39. package/dist/core/agent-loop/tool-executor.d.ts.map +1 -0
  40. package/dist/core/agent-loop/tool-executor.js +152 -0
  41. package/dist/core/agent-loop/turn-executor.d.ts +57 -0
  42. package/dist/core/agent-loop/turn-executor.d.ts.map +1 -0
  43. package/dist/core/agent-loop/turn-executor.js +124 -0
  44. package/dist/core/agent-loop/types.d.ts +141 -0
  45. package/dist/core/agent-loop/types.d.ts.map +1 -0
  46. package/dist/core/agent-loop/types.js +4 -0
  47. package/dist/core/agent-loop.d.ts +17 -0
  48. package/dist/core/agent-loop.d.ts.map +1 -0
  49. package/dist/core/agent-loop.js +16 -0
  50. package/dist/core/api-client-impl.d.ts +62 -0
  51. package/dist/core/api-client-impl.d.ts.map +1 -0
  52. package/dist/core/api-client-impl.js +479 -0
  53. package/dist/core/api-client.d.ts +6 -0
  54. package/dist/core/api-client.d.ts.map +1 -0
  55. package/dist/core/api-client.js +5 -0
  56. package/dist/core/checkpoints.d.ts +128 -0
  57. package/dist/core/checkpoints.d.ts.map +1 -0
  58. package/dist/core/checkpoints.js +438 -0
  59. package/dist/core/claude-md.d.ts +71 -0
  60. package/dist/core/claude-md.d.ts.map +1 -0
  61. package/dist/core/claude-md.js +198 -0
  62. package/dist/core/cognitive-security/hooks.d.ts +138 -0
  63. package/dist/core/cognitive-security/hooks.d.ts.map +1 -0
  64. package/dist/core/cognitive-security/hooks.js +389 -0
  65. package/dist/core/cognitive-security/index.d.ts +751 -0
  66. package/dist/core/cognitive-security/index.d.ts.map +1 -0
  67. package/dist/core/cognitive-security/index.js +1123 -0
  68. package/dist/core/cognitive-security/middleware.d.ts +136 -0
  69. package/dist/core/cognitive-security/middleware.d.ts.map +1 -0
  70. package/dist/core/cognitive-security/middleware.js +376 -0
  71. package/dist/core/config-loader.d.ts +127 -0
  72. package/dist/core/config-loader.d.ts.map +1 -0
  73. package/dist/core/config-loader.js +219 -0
  74. package/dist/core/context-compaction.d.ts +87 -0
  75. package/dist/core/context-compaction.d.ts.map +1 -0
  76. package/dist/core/context-compaction.js +428 -0
  77. package/dist/core/git-status.d.ts +25 -0
  78. package/dist/core/git-status.d.ts.map +1 -0
  79. package/dist/core/git-status.js +204 -0
  80. package/dist/core/image.d.ts +69 -0
  81. package/dist/core/image.d.ts.map +1 -0
  82. package/dist/core/image.js +290 -0
  83. package/dist/core/image.test.d.ts +2 -0
  84. package/dist/core/image.test.d.ts.map +1 -0
  85. package/dist/core/image.test.js +149 -0
  86. package/dist/core/models.d.ts +123 -0
  87. package/dist/core/models.d.ts.map +1 -0
  88. package/dist/core/models.js +325 -0
  89. package/dist/core/permissions.d.ts +81 -0
  90. package/dist/core/permissions.d.ts.map +1 -0
  91. package/dist/core/permissions.js +327 -0
  92. package/dist/core/retry.d.ts +25 -0
  93. package/dist/core/retry.d.ts.map +1 -0
  94. package/dist/core/retry.js +121 -0
  95. package/dist/core/session-store.d.ts +9 -0
  96. package/dist/core/session-store.d.ts.map +1 -0
  97. package/dist/core/session-store.js +10 -0
  98. package/dist/core/sessions/export.d.ts +47 -0
  99. package/dist/core/sessions/export.d.ts.map +1 -0
  100. package/dist/core/sessions/export.js +256 -0
  101. package/dist/core/sessions/index.d.ts +132 -0
  102. package/dist/core/sessions/index.d.ts.map +1 -0
  103. package/dist/core/sessions/index.js +442 -0
  104. package/dist/core/sessions/metadata.d.ts +77 -0
  105. package/dist/core/sessions/metadata.d.ts.map +1 -0
  106. package/dist/core/sessions/metadata.js +233 -0
  107. package/dist/core/sessions/persistence.d.ts +72 -0
  108. package/dist/core/sessions/persistence.d.ts.map +1 -0
  109. package/dist/core/sessions/persistence.js +201 -0
  110. package/dist/core/sessions/types.d.ts +110 -0
  111. package/dist/core/sessions/types.d.ts.map +1 -0
  112. package/dist/core/sessions/types.js +4 -0
  113. package/dist/core/stream-highlighter.d.ts +18 -0
  114. package/dist/core/stream-highlighter.d.ts.map +1 -0
  115. package/dist/core/stream-highlighter.js +916 -0
  116. package/dist/core/system-reminders.d.ts +89 -0
  117. package/dist/core/system-reminders.d.ts.map +1 -0
  118. package/dist/core/system-reminders.js +285 -0
  119. package/dist/ecosystem/hooks/__tests__/index.test.d.ts +5 -0
  120. package/dist/ecosystem/hooks/__tests__/index.test.d.ts.map +1 -0
  121. package/dist/ecosystem/hooks/__tests__/index.test.js +458 -0
  122. package/dist/ecosystem/hooks/index.d.ts +59 -0
  123. package/dist/ecosystem/hooks/index.d.ts.map +1 -0
  124. package/dist/ecosystem/hooks/index.js +294 -0
  125. package/dist/ecosystem/hooks/prompt-evaluator.d.ts +32 -0
  126. package/dist/ecosystem/hooks/prompt-evaluator.d.ts.map +1 -0
  127. package/dist/ecosystem/hooks/prompt-evaluator.js +229 -0
  128. package/dist/ecosystem/skills/index.d.ts +55 -0
  129. package/dist/ecosystem/skills/index.d.ts.map +1 -0
  130. package/dist/ecosystem/skills/index.js +258 -0
  131. package/dist/ecosystem/tools/__tests__/index.test.d.ts +7 -0
  132. package/dist/ecosystem/tools/__tests__/index.test.d.ts.map +1 -0
  133. package/dist/ecosystem/tools/__tests__/index.test.js +856 -0
  134. package/dist/ecosystem/tools/index.d.ts +24 -0
  135. package/dist/ecosystem/tools/index.d.ts.map +1 -0
  136. package/dist/ecosystem/tools/index.js +1709 -0
  137. package/dist/index.d.ts +24 -0
  138. package/dist/index.d.ts.map +1 -0
  139. package/dist/index.js +32 -2
  140. package/dist/interfaces/mcp/client.d.ts +40 -0
  141. package/dist/interfaces/mcp/client.d.ts.map +1 -0
  142. package/dist/interfaces/mcp/client.js +309 -0
  143. package/dist/interfaces/ui/index.d.ts +36 -0
  144. package/dist/interfaces/ui/index.d.ts.map +1 -0
  145. package/dist/interfaces/ui/index.js +61 -0
  146. package/dist/interfaces/ui/spinner.d.ts +140 -0
  147. package/dist/interfaces/ui/spinner.d.ts.map +1 -0
  148. package/dist/interfaces/ui/spinner.js +342 -0
  149. package/dist/interfaces/ui/terminal/cli/index.d.ts +12 -0
  150. package/dist/interfaces/ui/terminal/cli/index.d.ts.map +1 -0
  151. package/dist/interfaces/ui/terminal/cli/index.js +167 -0
  152. package/dist/interfaces/ui/terminal/shared/args.d.ts +39 -0
  153. package/dist/interfaces/ui/terminal/shared/args.d.ts.map +1 -0
  154. package/dist/interfaces/ui/terminal/shared/args.js +176 -0
  155. package/dist/interfaces/ui/terminal/shared/index.d.ts +11 -0
  156. package/dist/interfaces/ui/terminal/shared/index.d.ts.map +1 -0
  157. package/dist/interfaces/ui/terminal/shared/index.js +16 -0
  158. package/dist/interfaces/ui/terminal/shared/loading-state.d.ts +124 -0
  159. package/dist/interfaces/ui/terminal/shared/loading-state.d.ts.map +1 -0
  160. package/dist/interfaces/ui/terminal/shared/loading-state.js +246 -0
  161. package/dist/interfaces/ui/terminal/shared/query.d.ts +22 -0
  162. package/dist/interfaces/ui/terminal/shared/query.d.ts.map +1 -0
  163. package/dist/interfaces/ui/terminal/shared/query.js +100 -0
  164. package/dist/interfaces/ui/terminal/shared/setup.d.ts +33 -0
  165. package/dist/interfaces/ui/terminal/shared/setup.d.ts.map +1 -0
  166. package/dist/interfaces/ui/terminal/shared/setup.js +226 -0
  167. package/dist/interfaces/ui/terminal/shared/status-line.d.ts +117 -0
  168. package/dist/interfaces/ui/terminal/shared/status-line.d.ts.map +1 -0
  169. package/dist/interfaces/ui/terminal/shared/status-line.js +267 -0
  170. package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts +38 -0
  171. package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts.map +1 -0
  172. package/dist/interfaces/ui/terminal/shared/system-prompt.js +102 -0
  173. package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts +39 -0
  174. package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts.map +1 -0
  175. package/dist/interfaces/ui/terminal/tui/HelpPanel.js +215 -0
  176. package/dist/interfaces/ui/terminal/tui/InputContext.d.ts +91 -0
  177. package/dist/interfaces/ui/terminal/tui/InputContext.d.ts.map +1 -0
  178. package/dist/interfaces/ui/terminal/tui/InputContext.js +154 -0
  179. package/dist/interfaces/ui/terminal/tui/InputField.d.ts +18 -0
  180. package/dist/interfaces/ui/terminal/tui/InputField.d.ts.map +1 -0
  181. package/dist/interfaces/ui/terminal/tui/InputField.js +41 -0
  182. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts +16 -0
  183. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts.map +1 -0
  184. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.js +451 -0
  185. package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts +10 -0
  186. package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts.map +1 -0
  187. package/dist/interfaces/ui/terminal/tui/MessageArea.js +91 -0
  188. package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts +48 -0
  189. package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts.map +1 -0
  190. package/dist/interfaces/ui/terminal/tui/MessageStore.js +151 -0
  191. package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts +9 -0
  192. package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts.map +1 -0
  193. package/dist/interfaces/ui/terminal/tui/StatusBar.js +36 -0
  194. package/dist/interfaces/ui/terminal/tui/commands.d.ts +21 -0
  195. package/dist/interfaces/ui/terminal/tui/commands.d.ts.map +1 -0
  196. package/dist/interfaces/ui/terminal/tui/commands.js +359 -0
  197. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts +115 -0
  198. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts.map +1 -0
  199. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.js +306 -0
  200. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts +92 -0
  201. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts.map +1 -0
  202. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.js +399 -0
  203. package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts +59 -0
  204. package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts.map +1 -0
  205. package/dist/interfaces/ui/terminal/tui/components/PaneManager.js +139 -0
  206. package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts +68 -0
  207. package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts.map +1 -0
  208. package/dist/interfaces/ui/terminal/tui/components/Sidebar.js +340 -0
  209. package/dist/interfaces/ui/terminal/tui/components/index.d.ts +23 -0
  210. package/dist/interfaces/ui/terminal/tui/components/index.d.ts.map +1 -0
  211. package/dist/interfaces/ui/terminal/tui/components/index.js +51 -0
  212. package/dist/interfaces/ui/terminal/tui/console.d.ts +20 -0
  213. package/dist/interfaces/ui/terminal/tui/console.d.ts.map +1 -0
  214. package/dist/interfaces/ui/terminal/tui/console.js +46 -0
  215. package/dist/interfaces/ui/terminal/tui/index.d.ts +20 -0
  216. package/dist/interfaces/ui/terminal/tui/index.d.ts.map +1 -0
  217. package/dist/interfaces/ui/terminal/tui/index.js +28 -0
  218. package/dist/interfaces/ui/terminal/tui/run.d.ts +13 -0
  219. package/dist/interfaces/ui/terminal/tui/run.d.ts.map +1 -0
  220. package/dist/interfaces/ui/terminal/tui/run.js +31 -0
  221. package/dist/interfaces/ui/terminal/tui/spinner.d.ts +44 -0
  222. package/dist/interfaces/ui/terminal/tui/spinner.d.ts.map +1 -0
  223. package/dist/interfaces/ui/terminal/tui/spinner.js +59 -0
  224. package/dist/interfaces/ui/terminal/tui/tui-app.d.ts +39 -0
  225. package/dist/interfaces/ui/terminal/tui/tui-app.d.ts.map +1 -0
  226. package/dist/interfaces/ui/terminal/tui/tui-app.js +198 -0
  227. package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts +167 -0
  228. package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts.map +1 -0
  229. package/dist/interfaces/ui/terminal/tui/tui-footer.js +330 -0
  230. package/dist/interfaces/ui/terminal/tui/types.d.ts +165 -0
  231. package/dist/interfaces/ui/terminal/tui/types.d.ts.map +1 -0
  232. package/dist/interfaces/ui/terminal/tui/types.js +5 -0
  233. package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts +23 -0
  234. package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts.map +1 -0
  235. package/dist/interfaces/ui/terminal/tui/useInputHandler.js +72 -0
  236. package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts +90 -0
  237. package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts.map +1 -0
  238. package/dist/interfaces/ui/terminal/tui/useNativeInput.js +188 -0
  239. package/dist/native/index.d.ts +480 -0
  240. package/dist/native/index.d.ts.map +1 -0
  241. package/dist/native/index.js +1625 -0
  242. package/dist/teammates/index.d.ts +161 -0
  243. package/dist/teammates/index.d.ts.map +1 -0
  244. package/dist/teammates/index.js +827 -0
  245. package/dist/types/index.d.ts +482 -0
  246. package/dist/types/index.d.ts.map +1 -0
  247. package/dist/types/index.js +52 -0
  248. package/native/README.md +5 -5
  249. package/native/index.darwin-arm64.node +0 -0
  250. package/native/index.node +0 -0
  251. package/native/package.json +4 -4
  252. package/package.json +33 -16
  253. package/packages/src/core/__tests__/permissions.test.ts +1091 -0
  254. package/packages/src/core/agent-loop/__tests__/compaction.test.ts +280 -0
  255. package/packages/src/core/agent-loop/__tests__/formatters.test.ts +234 -0
  256. package/packages/src/core/agent-loop/__tests__/index.test.ts +162 -0
  257. package/packages/src/core/agent-loop/__tests__/loop-state.test.ts +413 -0
  258. package/packages/src/core/agent-loop/__tests__/message-builder.test.ts +229 -0
  259. package/packages/src/core/agent-loop/__tests__/tool-executor.test.ts +457 -0
  260. package/packages/src/core/agent-loop/compaction.ts +88 -0
  261. package/packages/src/core/agent-loop/formatters.ts +50 -0
  262. package/packages/src/core/agent-loop/index.ts +135 -0
  263. package/packages/src/core/agent-loop/loop-state.ts +187 -0
  264. package/packages/src/core/agent-loop/message-builder.ts +62 -0
  265. package/packages/src/core/agent-loop/tool-executor.ts +211 -0
  266. package/packages/src/core/agent-loop/turn-executor.ts +222 -0
  267. package/packages/src/core/agent-loop/types.ts +148 -0
  268. package/packages/src/core/agent-loop.ts +18 -0
  269. package/packages/src/core/api-client-impl.ts +619 -0
  270. package/packages/src/core/api-client.ts +6 -0
  271. package/packages/src/core/checkpoints.ts +606 -0
  272. package/packages/src/core/claude-md.ts +272 -0
  273. package/packages/src/core/cognitive-security/hooks.ts +590 -0
  274. package/packages/src/core/cognitive-security/index.ts +2041 -0
  275. package/packages/src/core/cognitive-security/middleware.ts +536 -0
  276. package/packages/src/core/config-loader.ts +324 -0
  277. package/packages/src/core/context-compaction.ts +578 -0
  278. package/packages/src/core/git-status.ts +262 -0
  279. package/packages/src/core/image.test.ts +180 -0
  280. package/packages/src/core/image.ts +350 -0
  281. package/packages/src/core/lmdb.db +0 -0
  282. package/packages/src/core/lmdb.db-lock +0 -0
  283. package/packages/src/core/models.ts +430 -0
  284. package/packages/src/core/normalizers/todo +4 -0
  285. package/packages/src/core/permissions.ts +431 -0
  286. package/packages/src/core/retry.ts +170 -0
  287. package/packages/src/core/session-store.ts +36 -0
  288. package/packages/src/core/sessions/export.ts +329 -0
  289. package/packages/src/core/sessions/index.ts +587 -0
  290. package/packages/src/core/sessions/metadata.ts +309 -0
  291. package/packages/src/core/sessions/persistence.ts +244 -0
  292. package/packages/src/core/sessions/types.ts +169 -0
  293. package/packages/src/core/stream-highlighter.ts +1123 -0
  294. package/packages/src/core/system-reminders.ts +402 -0
  295. package/packages/src/core/todo +8 -0
  296. package/packages/src/ecosystem/hooks/__tests__/index.test.ts +561 -0
  297. package/packages/src/ecosystem/hooks/index.ts +341 -0
  298. package/packages/src/ecosystem/hooks/prompt-evaluator.ts +300 -0
  299. package/packages/src/ecosystem/skills/index.ts +295 -0
  300. package/packages/src/ecosystem/tools/__tests__/index.test.ts +1335 -0
  301. package/packages/src/ecosystem/tools/index.ts +1877 -0
  302. package/packages/src/index.ts +120 -0
  303. package/packages/src/interfaces/mcp/client.ts +389 -0
  304. package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
  305. package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
  306. package/packages/src/interfaces/ui/index.ts +161 -0
  307. package/packages/src/interfaces/ui/lmdb.db +0 -0
  308. package/packages/src/interfaces/ui/lmdb.db-lock +0 -0
  309. package/packages/src/interfaces/ui/spinner.ts +451 -0
  310. package/packages/src/interfaces/ui/terminal/cli/index.ts +228 -0
  311. package/packages/src/interfaces/ui/terminal/lmdb.db +0 -0
  312. package/packages/src/interfaces/ui/terminal/lmdb.db-lock +0 -0
  313. package/packages/src/interfaces/ui/terminal/shared/args.ts +222 -0
  314. package/packages/src/interfaces/ui/terminal/shared/index.ts +71 -0
  315. package/packages/src/interfaces/ui/terminal/shared/loading-state.ts +322 -0
  316. package/packages/src/interfaces/ui/terminal/shared/query.ts +146 -0
  317. package/packages/src/interfaces/ui/terminal/shared/setup.ts +295 -0
  318. package/packages/src/interfaces/ui/terminal/shared/status-line.ts +358 -0
  319. package/packages/src/interfaces/ui/terminal/shared/system-prompt.ts +146 -0
  320. package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +262 -0
  321. package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +232 -0
  322. package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +62 -0
  323. package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +537 -0
  324. package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +107 -0
  325. package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +240 -0
  326. package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +54 -0
  327. package/packages/src/interfaces/ui/terminal/tui/commands.ts +438 -0
  328. package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +584 -0
  329. package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +614 -0
  330. package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +333 -0
  331. package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +604 -0
  332. package/packages/src/interfaces/ui/terminal/tui/components/index.ts +118 -0
  333. package/packages/src/interfaces/ui/terminal/tui/console.ts +49 -0
  334. package/packages/src/interfaces/ui/terminal/tui/index.ts +90 -0
  335. package/packages/src/interfaces/ui/terminal/tui/run.tsx +42 -0
  336. package/packages/src/interfaces/ui/terminal/tui/spinner.ts +69 -0
  337. package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +390 -0
  338. package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +422 -0
  339. package/packages/src/interfaces/ui/terminal/tui/types.ts +186 -0
  340. package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +104 -0
  341. package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +239 -0
  342. package/packages/src/lmdb.db +0 -0
  343. package/packages/src/lmdb.db-lock +0 -0
  344. package/packages/src/native/index.ts +2345 -0
  345. package/packages/src/teammates/index.ts +982 -0
  346. package/packages/src/types/index.ts +722 -0
  347. package/dist/cli.js +0 -148
  348. package/dist/index-0pkak453.js +0 -136
  349. package/dist/index-0qd0x8b4.js +0 -110
  350. package/dist/index-0x3kprq6.js +0 -240
  351. package/dist/index-1eawy937.js +0 -308
  352. package/dist/index-24m2aygy.js +0 -240
  353. package/dist/index-29xcjnne.js +0 -280
  354. package/dist/index-2avyytn5.js +0 -349
  355. package/dist/index-4ms367ey.js +0 -136
  356. package/dist/index-4w2t3b0m.js +0 -240
  357. package/dist/index-4xfgd8nz.js +0 -261
  358. package/dist/index-5acjp9gc.js +0 -157
  359. package/dist/index-5s15hr56.js +0 -136
  360. package/dist/index-6e4wf341.js +0 -349
  361. package/dist/index-6fvnkedw.js +0 -240
  362. package/dist/index-6rqpmd4g.js +0 -128
  363. package/dist/index-77ckwnbm.js +0 -280
  364. package/dist/index-9knxy49k.js +0 -128
  365. package/dist/index-9zrnw4zx.js +0 -128
  366. package/dist/index-bk21w99v.js +0 -280
  367. package/dist/index-c41n76fv.js +0 -240
  368. package/dist/index-cb4ppjdt.js +0 -255
  369. package/dist/index-cfb2edt6.js +0 -240
  370. package/dist/index-cmfa38hh.js +0 -308
  371. package/dist/index-datjz8q1.js +0 -257
  372. package/dist/index-eadf4wvn.js +0 -240
  373. package/dist/index-em5k0m3z.js +0 -345
  374. package/dist/index-gh8r333a.js +0 -110
  375. package/dist/index-gkx6k2tr.js +0 -261
  376. package/dist/index-h5cabfks.js +0 -155
  377. package/dist/index-hcrpwyy3.js +0 -261
  378. package/dist/index-hk7fwwa8.js +0 -257
  379. package/dist/index-jb8cw7f8.js +0 -136
  380. package/dist/index-kbyw4th1.js +0 -347
  381. package/dist/index-kgj5gqnm.js +0 -345
  382. package/dist/index-mdf6xp1z.js +0 -255
  383. package/dist/index-mrhv8kvc.js +0 -280
  384. package/dist/index-mt4743dd.js +0 -161
  385. package/dist/index-qnwsg97q.js +0 -240
  386. package/dist/index-qwdy6x44.js +0 -261
  387. package/dist/index-rmj77261.js +0 -157
  388. package/dist/index-sbbw1a61.js +0 -349
  389. package/dist/index-svy5bcpn.js +0 -345
  390. package/dist/index-tvmy7tm9.js +0 -261
  391. package/dist/index-tzz4vzkj.js +0 -312
  392. package/dist/index-vz80zmhe.js +0 -110
  393. package/dist/index-wed2fk67.js +0 -240
  394. package/dist/index-wksgzz8e.js +0 -280
  395. package/dist/index-wn2m4wma.js +0 -240
  396. package/dist/index-xha05vjc.js +0 -257
  397. package/dist/index-yc6eh8p8.js +0 -136
  398. package/dist/index-ycjxx9ft.js +0 -240
  399. package/dist/index-z0gzd0fc.js +0 -110
  400. package/dist/index-z8cwtf8j.js +0 -240
  401. package/dist/index-zy5mtt00.js +0 -128
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Hook System - Lifecycle event handlers
3
+ */
4
+
5
+ import type { HookEvent, HookDefinition, HookInput, HookOutput } from "../../types/index.js";
6
+ import { spawn } from "child_process";
7
+
8
+ export type HookHandler = (input: HookInput) => Promise<HookOutput>;
9
+
10
+ /**
11
+ * Prompt evaluator function type - calls LLM to evaluate hook prompt
12
+ */
13
+ export type PromptEvaluator = (prompt: string, context: HookInput) => Promise<HookOutput>;
14
+
15
+ /**
16
+ * Extended hook definition that supports shell commands, in-process handlers, and LLM prompts
17
+ */
18
+ export interface ExtendedHookDefinition extends HookDefinition {
19
+ /** In-process handler function (alternative to command) */
20
+ handler?: HookHandler;
21
+ /** Prompt template for LLM-based evaluation (alternative to command) */
22
+ prompt?: string;
23
+ /** Matcher pattern for filtering which tools this hook applies to */
24
+ _matcher?: string;
25
+ }
26
+
27
+ export class HookManager {
28
+ private hooks = new Map<HookEvent, ExtendedHookDefinition[]>();
29
+ private timeout: number;
30
+ private promptEvaluator?: PromptEvaluator;
31
+
32
+ constructor(timeout = 60000, promptEvaluator?: PromptEvaluator) {
33
+ this.timeout = timeout;
34
+ this.promptEvaluator = promptEvaluator;
35
+ }
36
+
37
+ /**
38
+ * Set the prompt evaluator for LLM-based hooks
39
+ */
40
+ setPromptEvaluator(evaluator: PromptEvaluator): void {
41
+ this.promptEvaluator = evaluator;
42
+ }
43
+
44
+ register(event: HookEvent, definition: HookDefinition | ExtendedHookDefinition): void {
45
+ if (!this.hooks.has(event)) {
46
+ this.hooks.set(event, []);
47
+ }
48
+ this.hooks.get(event)?.push(definition as ExtendedHookDefinition);
49
+ }
50
+
51
+ /**
52
+ * Register an in-process handler for an event
53
+ */
54
+ registerHandler(event: HookEvent, handler: HookHandler, options?: { timeout?: number; enabled?: boolean }): void {
55
+ this.register(event, {
56
+ event,
57
+ command: "", // Not used for in-process handlers
58
+ handler,
59
+ timeout: options?.timeout,
60
+ enabled: options?.enabled ?? true,
61
+ });
62
+ }
63
+
64
+ registerAll(hooks: Record<HookEvent, HookDefinition[]>): void {
65
+ for (const [event, definitions] of Object.entries(hooks)) {
66
+ for (const def of definitions) {
67
+ this.register(event as HookEvent, def);
68
+ }
69
+ }
70
+ }
71
+
72
+ async execute(event: HookEvent, input: Omit<HookInput, "event" | "timestamp">): Promise<HookOutput> {
73
+ const definitions = this.hooks.get(event);
74
+ if (!definitions || definitions.length === 0) {
75
+ return { decision: "allow" };
76
+ }
77
+
78
+ const fullInput: HookInput = {
79
+ ...input,
80
+ event,
81
+ timestamp: Date.now(),
82
+ };
83
+
84
+ for (const def of definitions) {
85
+ if (def.enabled === false) continue;
86
+
87
+ // Check matcher if present
88
+ if (def._matcher && input.tool_name) {
89
+ try {
90
+ const regex = new RegExp(def._matcher);
91
+ if (!regex.test(input.tool_name)) {
92
+ // Matcher doesn't match, skip this hook
93
+ continue;
94
+ }
95
+ } catch {
96
+ // Invalid regex, skip
97
+ continue;
98
+ }
99
+ }
100
+
101
+ const result = await this.executeHook(def, fullInput);
102
+
103
+ if (result.decision === "deny" || result.decision === "block") {
104
+ return result;
105
+ }
106
+
107
+ // Apply modified input if provided
108
+ if (result.modified_input) {
109
+ Object.assign(input, result.modified_input);
110
+ }
111
+ }
112
+
113
+ return { decision: "allow" };
114
+ }
115
+
116
+ private async executeHook(def: ExtendedHookDefinition, input: HookInput): Promise<HookOutput> {
117
+ // If handler function is provided, use it directly
118
+ if (def.handler) {
119
+ try {
120
+ return await def.handler(input);
121
+ } catch (error) {
122
+ const errorMessage = error instanceof Error ? error.message : String(error);
123
+ return {
124
+ decision: "deny",
125
+ reason: `Hook handler error: ${errorMessage}`,
126
+ errors: [errorMessage],
127
+ };
128
+ }
129
+ }
130
+
131
+ // If prompt is provided, use LLM evaluation
132
+ if (def.prompt && this.promptEvaluator) {
133
+ try {
134
+ return await this.promptEvaluator(def.prompt, input);
135
+ } catch (error) {
136
+ const errorMessage = error instanceof Error ? error.message : String(error);
137
+ return {
138
+ decision: "deny",
139
+ reason: `Prompt hook error: ${errorMessage}`,
140
+ errors: [errorMessage],
141
+ };
142
+ }
143
+ }
144
+
145
+ // Skip hooks with empty commands (e.g., prompt-type hooks without evaluator)
146
+ if (!def.command || def.command.trim() === "") {
147
+ // Allow the operation to proceed if there's no command to execute
148
+ return { decision: "allow" };
149
+ }
150
+
151
+ // Shell command execution
152
+ const timeout = def.timeout || this.timeout;
153
+
154
+ try {
155
+ const result = await new Promise<HookOutput>((resolve, reject) => {
156
+ const proc = spawn(def.command, [], {
157
+ shell: true,
158
+ stdio: ["pipe", "pipe", "pipe"],
159
+ });
160
+
161
+ let stdout = "";
162
+ let stderr = "";
163
+ let timedOut = false;
164
+
165
+ const timer = setTimeout(() => {
166
+ timedOut = true;
167
+ proc.kill();
168
+ resolve({
169
+ decision: "deny",
170
+ reason: "Hook timeout",
171
+ errors: ["Hook execution timed out"],
172
+ });
173
+ }, timeout);
174
+
175
+ proc.stdout?.on("data", (data: Buffer) => {
176
+ stdout += data.toString();
177
+ });
178
+
179
+ proc.stderr?.on("data", (data: Buffer) => {
180
+ stderr += data.toString();
181
+ });
182
+
183
+ proc.on("close", (code: number | null) => {
184
+ clearTimeout(timer);
185
+ if (timedOut) return; // Already resolved
186
+
187
+ // Try to parse JSON from stdout first (works for all exit codes)
188
+ let parsedOutput: HookOutput | null = null;
189
+ if (stdout.trim()) {
190
+ try {
191
+ parsedOutput = JSON.parse(stdout) as HookOutput;
192
+ } catch {
193
+ // stdout not valid JSON, ignore
194
+ }
195
+ }
196
+
197
+ if (code === 0) {
198
+ // Success - use parsed output or default to allow
199
+ resolve(parsedOutput || { decision: "allow" });
200
+ } else if (code === 1) {
201
+ // Deny - use parsed output or fall back to stderr
202
+ if (parsedOutput) {
203
+ resolve(parsedOutput);
204
+ } else {
205
+ resolve({
206
+ decision: "deny",
207
+ reason: stderr || "Hook denied execution",
208
+ errors: stderr ? [stderr] : ["Hook denied execution"],
209
+ });
210
+ }
211
+ } else if (code === 2) {
212
+ // Block - use parsed output or fall back to stderr
213
+ if (parsedOutput) {
214
+ resolve(parsedOutput);
215
+ } else {
216
+ resolve({
217
+ decision: "block",
218
+ reason: stderr || "Hook blocked execution",
219
+ errors: stderr ? [stderr] : ["Hook blocked execution"],
220
+ });
221
+ }
222
+ } else {
223
+ // Other error - default to deny
224
+ resolve({
225
+ decision: "deny",
226
+ reason: `Hook exited with code ${code}`,
227
+ errors: [`Hook exited with code ${code}`],
228
+ });
229
+ }
230
+ });
231
+
232
+ proc.on("error", (error: Error) => {
233
+ clearTimeout(timer);
234
+ resolve({
235
+ decision: "deny",
236
+ reason: `Hook error: ${error.message}`,
237
+ errors: [error.message],
238
+ });
239
+ });
240
+
241
+ // Send input via stdin
242
+ proc.stdin?.write(JSON.stringify(input));
243
+ proc.stdin?.end();
244
+ });
245
+
246
+ return result;
247
+ } catch (error) {
248
+ const errorMessage = error instanceof Error ? error.message : String(error);
249
+ return {
250
+ decision: "deny",
251
+ reason: `Hook execution failed: ${errorMessage}`,
252
+ errors: [errorMessage],
253
+ };
254
+ }
255
+ }
256
+
257
+ getHooks(event: HookEvent): ExtendedHookDefinition[] {
258
+ return this.hooks.get(event) || [];
259
+ }
260
+
261
+ clear(event?: HookEvent): void {
262
+ if (event) {
263
+ this.hooks.delete(event);
264
+ } else {
265
+ this.hooks.clear();
266
+ }
267
+ }
268
+ }
269
+
270
+ // ============================================
271
+ // BUILT-IN HOOKS
272
+ // ============================================
273
+
274
+ export const builtInHooks: Record<string, HookDefinition> = {
275
+ /**
276
+ * Example: Validate file paths before write
277
+ */
278
+ validateWrite: {
279
+ event: "PreToolUse",
280
+ command: `node -e '
281
+ const input = JSON.parse(require("fs").readFileSync(0, "utf8"));
282
+ if (input.tool_name === "Write") {
283
+ const path = input.tool_input.file_path;
284
+ if (path.includes("..") || path.startsWith("/etc/")) {
285
+ console.log(JSON.stringify({ decision: "deny", reason: "Unsafe path" }));
286
+ process.exit(1);
287
+ }
288
+ }
289
+ console.log(JSON.stringify({ decision: "allow" }));
290
+ '`,
291
+ timeout: 5000,
292
+ enabled: false,
293
+ },
294
+
295
+ /**
296
+ * Example: Log all tool uses
297
+ */
298
+ logToolUse: {
299
+ event: "PostToolUse",
300
+ command: `node -e '
301
+ const input = JSON.parse(require("fs").readFileSync(0, "utf8"));
302
+ console.error(\`[LOG] Tool: \${input.tool_name}\`);
303
+ console.log(JSON.stringify({ decision: "allow" }));
304
+ '`,
305
+ timeout: 5000,
306
+ enabled: false,
307
+ },
308
+ };
309
+
310
+ // ============================================
311
+ // HOOK EVENT DOCUMENTATION
312
+ // ============================================
313
+
314
+ export const hookEventDocs: Record<HookEvent, string> = {
315
+ PreToolUse: "Before a tool is executed. Can modify input or deny execution.",
316
+ PostToolUse: "After a tool successfully executes. Can process result.",
317
+ PostToolUseFailure: "After a tool fails. Can handle error or retry.",
318
+ Stop: "When the agent stops (end_turn, max_tokens, error).",
319
+ UserPromptSubmit: "When user submits a prompt. Can modify or reject.",
320
+ SessionStart: "When a new session starts.",
321
+ SessionEnd: "When a session ends.",
322
+ Notification: "When a notification is sent.",
323
+ ConfigChange: "When configuration changes.",
324
+ WorktreeCreate: "When a git worktree is created.",
325
+ };
326
+
327
+ /**
328
+ * Exit codes for hook commands:
329
+ * 0 = Success, allow execution
330
+ * 1 = Show stderr, deny execution
331
+ * 2 = Block execution silently
332
+ */
333
+ export const hookExitCodes = {
334
+ ALLOW: 0,
335
+ DENY: 1,
336
+ BLOCK: 2,
337
+ };
338
+
339
+ // Re-export prompt evaluator utilities
340
+ export { createPromptEvaluator, createMockPromptEvaluator } from "./prompt-evaluator.js";
341
+ export type { PromptEvaluatorOptions } from "./prompt-evaluator.js";
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Prompt Evaluator - LLM-based hook evaluation
3
+ *
4
+ * Evaluates hook prompts by calling the Claude API to make decisions
5
+ * about tool execution based on natural language rules.
6
+ */
7
+
8
+ import type { HookInput, HookOutput } from "../../types/index.js";
9
+ import type { PromptEvaluator } from "./index.js";
10
+
11
+ /**
12
+ * Options for creating a prompt evaluator
13
+ */
14
+ export interface PromptEvaluatorOptions {
15
+ /** Anthropic API key */
16
+ apiKey: string;
17
+ /** Model to use for evaluation (default: claude-haiku-4-5 for speed) */
18
+ model?: string;
19
+ /** Max tokens for response (default: 256) */
20
+ maxTokens?: number;
21
+ /** System prompt for the evaluator */
22
+ systemPrompt?: string;
23
+ /** Base URL for API (default: from ANTHROPIC_BASE_URL env or https://api.anthropic.com) */
24
+ baseUrl?: string;
25
+ }
26
+
27
+ /**
28
+ * Default system prompt for hook evaluation
29
+ */
30
+ const DEFAULT_SYSTEM_PROMPT = `You are a hook evaluator for Coder. Your job is to evaluate tool usage against security and best-practice rules.
31
+
32
+ You MUST respond with ONLY a valid JSON object in this exact format:
33
+ {
34
+ "decision": "allow" | "deny" | "block",
35
+ "reason": "Optional explanation for the decision",
36
+ "modified_input": { ... } // Optional: modified tool input if you want to change it
37
+ }
38
+
39
+ Rules:
40
+ - "allow": Let the tool execute normally
41
+ - "deny": Prevent execution and show the user the reason
42
+ - "block": Prevent execution silently (no message shown)
43
+ - Only modify input if absolutely necessary and you're certain of the correct format
44
+
45
+ Be concise and make quick decisions. Do not explain your reasoning in prose - only use the JSON format.`;
46
+
47
+ /**
48
+ * Interpolate variables in a prompt template
49
+ */
50
+ function interpolatePrompt(template: string, input: HookInput): string {
51
+ let result = template;
52
+
53
+ // Replace $ARGUMENTS with tool input as JSON
54
+ if (input.tool_input) {
55
+ result = result.replace(/\$ARGUMENTS/g, JSON.stringify(input.tool_input, null, 2));
56
+ }
57
+
58
+ // Replace $TOOL_NAME with tool name
59
+ if (input.tool_name) {
60
+ result = result.replace(/\$TOOL_NAME/g, input.tool_name);
61
+ }
62
+
63
+ // Replace $EVENT with event name
64
+ result = result.replace(/\$EVENT/g, input.event);
65
+
66
+ // Replace $SESSION_ID with session ID
67
+ if (input.session_id) {
68
+ result = result.replace(/\$SESSION_ID/g, input.session_id);
69
+ }
70
+
71
+ // Replace $TIMESTAMP with timestamp
72
+ result = result.replace(/\$TIMESTAMP/g, String(input.timestamp));
73
+
74
+ // Replace $ERROR with error message if present
75
+ if (input.error) {
76
+ result = result.replace(/\$ERROR/g, input.error);
77
+ }
78
+
79
+ // Replace $TOOL_RESULT with tool result if present
80
+ if (input.tool_result) {
81
+ const resultStr = typeof input.tool_result.content === "string"
82
+ ? input.tool_result.content
83
+ : JSON.stringify(input.tool_result.content);
84
+ result = result.replace(/\$TOOL_RESULT/g, resultStr);
85
+ }
86
+
87
+ return result;
88
+ }
89
+
90
+ /**
91
+ * Parse the LLM response into a HookOutput
92
+ * Supports multiple JSON formats:
93
+ * 1. Standard: { "decision": "allow" | "deny" | "block", "reason": "..." }
94
+ * 2. Standard format: { "continue": true/false, "hookSpecificOutput": {...} }
95
+ */
96
+ function parseHookOutput(responseText: string): HookOutput {
97
+ // Try to extract JSON from the response
98
+ // The model might wrap it in markdown code blocks or add extra text
99
+
100
+ let parsed: Record<string, unknown> | null = null;
101
+
102
+ // First, try direct parse
103
+ try {
104
+ parsed = JSON.parse(responseText) as Record<string, unknown>;
105
+ } catch {
106
+ // Not valid JSON directly
107
+ }
108
+
109
+ // Try to extract JSON from markdown code block
110
+ if (!parsed) {
111
+ const jsonBlockMatch = responseText.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
112
+ if (jsonBlockMatch?.[1]) {
113
+ try {
114
+ parsed = JSON.parse(jsonBlockMatch[1].trim()) as Record<string, unknown>;
115
+ } catch {
116
+ // Invalid JSON in code block
117
+ }
118
+ }
119
+ }
120
+
121
+ // Try to find JSON object anywhere in the response
122
+ if (!parsed) {
123
+ const jsonMatch = responseText.match(/\{[\s\S]*?\}/);
124
+ if (jsonMatch) {
125
+ try {
126
+ parsed = JSON.parse(jsonMatch[0]) as Record<string, unknown>;
127
+ } catch {
128
+ // Invalid JSON
129
+ }
130
+ }
131
+ }
132
+
133
+ if (!parsed) {
134
+ // If we can't parse JSON, default to allow with a warning
135
+ return {
136
+ decision: "allow",
137
+ reason: "Hook response could not be parsed as JSON, allowing by default",
138
+ };
139
+ }
140
+
141
+ // Format 1: Standard { decision: "allow" | "deny" | "block" }
142
+ if ("decision" in parsed) {
143
+ return {
144
+ decision: (parsed.decision as "allow" | "deny" | "block") || "allow",
145
+ reason: parsed.reason as string | undefined,
146
+ modified_input: parsed.modified_input as Record<string, unknown> | undefined,
147
+ };
148
+ }
149
+
150
+ // Format 2: Standard { continue: true/false, hookSpecificOutput: {...} }
151
+ if ("continue" in parsed) {
152
+ const shouldContinue = Boolean(parsed.continue);
153
+ if (shouldContinue) {
154
+ return { decision: "allow" };
155
+ }
156
+
157
+ // Extract reason from hookSpecificOutput if present
158
+ const hookOutput = parsed.hookSpecificOutput as Record<string, unknown> | undefined;
159
+ const reason = hookOutput?.permissionDecisionReason as string | undefined;
160
+
161
+ return {
162
+ decision: "deny",
163
+ reason: reason || "Hook denied execution",
164
+ };
165
+ }
166
+
167
+ // Unknown format, default to allow
168
+ return {
169
+ decision: "allow",
170
+ reason: "Unknown hook response format, allowing by default",
171
+ };
172
+ }
173
+
174
+ /**
175
+ * Make a non-streaming API call to Claude
176
+ */
177
+ async function callClaudeAPI(
178
+ apiKey: string,
179
+ model: string,
180
+ maxTokens: number,
181
+ systemPrompt: string,
182
+ userPrompt: string,
183
+ baseUrl: string = "https://api.anthropic.com"
184
+ ): Promise<string> {
185
+ const response = await fetch(`${baseUrl}/v1/messages`, {
186
+ method: "POST",
187
+ headers: {
188
+ "Content-Type": "application/json",
189
+ "x-api-key": apiKey,
190
+ "anthropic-version": "2023-06-01",
191
+ },
192
+ body: JSON.stringify({
193
+ model,
194
+ max_tokens: maxTokens,
195
+ system: systemPrompt,
196
+ messages: [
197
+ {
198
+ role: "user",
199
+ content: userPrompt,
200
+ },
201
+ ],
202
+ }),
203
+ });
204
+
205
+ if (!response.ok) {
206
+ const errorText = await response.text();
207
+ throw new Error(`API error: ${response.status} - ${errorText}`);
208
+ }
209
+
210
+ const data = await response.json() as {
211
+ content: Array<{ type: string; text?: string }>;
212
+ };
213
+
214
+ // Extract text from response
215
+ const textContent = data.content
216
+ .filter((block) => block.type === "text")
217
+ .map((block) => block.text || "")
218
+ .join("");
219
+
220
+ return textContent;
221
+ }
222
+
223
+ /**
224
+ * Create a prompt evaluator that uses the Claude API
225
+ */
226
+ export function createPromptEvaluator(options: PromptEvaluatorOptions): PromptEvaluator {
227
+ const {
228
+ apiKey,
229
+ model = "claude-haiku-4-5", // Use Haiku for fast evaluation
230
+ maxTokens = 256,
231
+ systemPrompt = DEFAULT_SYSTEM_PROMPT,
232
+ baseUrl = process.env.ANTHROPIC_BASE_URL || "https://api.anthropic.com",
233
+ } = options;
234
+
235
+ return async (promptTemplate: string, context: HookInput): Promise<HookOutput> => {
236
+ // Interpolate variables in the prompt
237
+ const userPrompt = interpolatePrompt(promptTemplate, context);
238
+
239
+ try {
240
+ // Call the API
241
+ const responseText = await callClaudeAPI(
242
+ apiKey,
243
+ model,
244
+ maxTokens,
245
+ systemPrompt,
246
+ userPrompt,
247
+ baseUrl
248
+ );
249
+
250
+ if (!responseText) {
251
+ return { decision: "allow" };
252
+ }
253
+
254
+ // Parse the response
255
+ return parseHookOutput(responseText);
256
+ } catch (error) {
257
+ const errorMessage = error instanceof Error ? error.message : String(error);
258
+ // On error, allow by default but log the issue
259
+ console.error(`[PromptEvaluator] Error evaluating hook: ${errorMessage}`);
260
+ return {
261
+ decision: "allow",
262
+ reason: `Hook evaluation failed: ${errorMessage}`,
263
+ };
264
+ }
265
+ };
266
+ }
267
+
268
+ /**
269
+ * Create a mock prompt evaluator for testing
270
+ * Returns canned responses based on patterns in the prompt
271
+ */
272
+ export function createMockPromptEvaluator(): PromptEvaluator {
273
+ return async (promptTemplate: string, context: HookInput): Promise<HookOutput> => {
274
+ // Simple mock logic for testing
275
+ const prompt = promptTemplate.toLowerCase();
276
+ const toolInput = context.tool_input;
277
+
278
+ // If checking for MCP alternatives and we have a Bash command
279
+ if (prompt.includes("mcp") && toolInput && "command" in toolInput) {
280
+ const command = String(toolInput.command);
281
+
282
+ // Check for common patterns that have MCP alternatives
283
+ if (command.includes("git status")) {
284
+ return {
285
+ decision: "deny",
286
+ reason: "Consider using the Git MCP tool instead of running git commands directly",
287
+ };
288
+ }
289
+ if (command.includes("gh ")) {
290
+ return {
291
+ decision: "deny",
292
+ reason: "Consider using the GitHub MCP tool instead of gh CLI",
293
+ };
294
+ }
295
+ }
296
+
297
+ // Default allow
298
+ return { decision: "allow" };
299
+ };
300
+ }