@zhijiewang/openharness 0.11.1 → 0.12.1

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 (520) hide show
  1. package/README.md +212 -23
  2. package/dist/DeferredTool.d.ts +34 -0
  3. package/dist/DeferredTool.js +62 -0
  4. package/dist/agents/roles.js +62 -6
  5. package/dist/commands/index.js +31 -2
  6. package/dist/harness/config.d.ts +15 -0
  7. package/dist/harness/config.js +45 -23
  8. package/dist/harness/memory.d.ts +12 -0
  9. package/dist/harness/memory.js +53 -2
  10. package/dist/harness/session.d.ts +19 -0
  11. package/dist/harness/session.js +53 -0
  12. package/dist/harness/verification.d.ts +41 -0
  13. package/dist/harness/verification.js +197 -0
  14. package/dist/mcp/registry.d.ts +31 -0
  15. package/dist/mcp/registry.js +180 -0
  16. package/dist/query/index.js +9 -1
  17. package/dist/query/tools.js +30 -4
  18. package/dist/repl.js +34 -0
  19. package/dist/services/AgentDispatcher.d.ts +1 -0
  20. package/dist/services/AgentDispatcher.js +10 -1
  21. package/dist/services/CronExecutor.d.ts +38 -0
  22. package/dist/services/CronExecutor.js +130 -0
  23. package/dist/services/StreamingToolExecutor.js +28 -0
  24. package/dist/services/cron.d.ts +4 -0
  25. package/dist/services/cron.js +27 -0
  26. package/dist/tools/AgentTool/index.d.ts +3 -0
  27. package/dist/tools/AgentTool/index.js +17 -4
  28. package/dist/tools/MemoryTool/index.d.ts +2 -2
  29. package/dist/tools/ToolSearchTool/index.js +7 -0
  30. package/dist/tools.d.ts +8 -0
  31. package/dist/tools.js +40 -41
  32. package/package.json +5 -2
  33. package/dist/Tool.d.ts.map +0 -1
  34. package/dist/Tool.js.map +0 -1
  35. package/dist/Tool.test.d.ts +0 -2
  36. package/dist/Tool.test.d.ts.map +0 -1
  37. package/dist/Tool.test.js +0 -48
  38. package/dist/Tool.test.js.map +0 -1
  39. package/dist/agents/roles.d.ts.map +0 -1
  40. package/dist/agents/roles.js.map +0 -1
  41. package/dist/agents/roles.test.d.ts +0 -2
  42. package/dist/agents/roles.test.d.ts.map +0 -1
  43. package/dist/agents/roles.test.js +0 -38
  44. package/dist/agents/roles.test.js.map +0 -1
  45. package/dist/commands/commands-new.test.d.ts +0 -5
  46. package/dist/commands/commands-new.test.d.ts.map +0 -1
  47. package/dist/commands/commands-new.test.js +0 -132
  48. package/dist/commands/commands-new.test.js.map +0 -1
  49. package/dist/commands/commands.test.d.ts +0 -2
  50. package/dist/commands/commands.test.d.ts.map +0 -1
  51. package/dist/commands/commands.test.js +0 -98
  52. package/dist/commands/commands.test.js.map +0 -1
  53. package/dist/commands/cybergotchi.d.ts.map +0 -1
  54. package/dist/commands/cybergotchi.js.map +0 -1
  55. package/dist/commands/index.d.ts.map +0 -1
  56. package/dist/commands/index.js.map +0 -1
  57. package/dist/components/App.d.ts.map +0 -1
  58. package/dist/components/App.js.map +0 -1
  59. package/dist/components/CompanionFooter.d.ts.map +0 -1
  60. package/dist/components/CompanionFooter.js.map +0 -1
  61. package/dist/components/CybergotchiBubble.d.ts.map +0 -1
  62. package/dist/components/CybergotchiBubble.js.map +0 -1
  63. package/dist/components/CybergotchiPanel.d.ts.map +0 -1
  64. package/dist/components/CybergotchiPanel.js.map +0 -1
  65. package/dist/components/CybergotchiPanelConnected.d.ts.map +0 -1
  66. package/dist/components/CybergotchiPanelConnected.js.map +0 -1
  67. package/dist/components/CybergotchiSetup.d.ts.map +0 -1
  68. package/dist/components/CybergotchiSetup.js.map +0 -1
  69. package/dist/components/CybergotchiSprite.d.ts.map +0 -1
  70. package/dist/components/CybergotchiSprite.js.map +0 -1
  71. package/dist/components/DiffView.d.ts.map +0 -1
  72. package/dist/components/DiffView.js.map +0 -1
  73. package/dist/components/ErrorBoundary.d.ts.map +0 -1
  74. package/dist/components/ErrorBoundary.js.map +0 -1
  75. package/dist/components/InitWizard.d.ts.map +0 -1
  76. package/dist/components/InitWizard.js.map +0 -1
  77. package/dist/components/Markdown.d.ts.map +0 -1
  78. package/dist/components/Markdown.js.map +0 -1
  79. package/dist/components/Messages.d.ts.map +0 -1
  80. package/dist/components/Messages.js.map +0 -1
  81. package/dist/components/PermissionPrompt.d.ts.map +0 -1
  82. package/dist/components/PermissionPrompt.js.map +0 -1
  83. package/dist/components/REPL.d.ts.map +0 -1
  84. package/dist/components/REPL.js.map +0 -1
  85. package/dist/components/Spinner.d.ts.map +0 -1
  86. package/dist/components/Spinner.js.map +0 -1
  87. package/dist/components/TextInput.d.ts.map +0 -1
  88. package/dist/components/TextInput.js.map +0 -1
  89. package/dist/components/ToolCallDisplay.d.ts.map +0 -1
  90. package/dist/components/ToolCallDisplay.js.map +0 -1
  91. package/dist/cybergotchi/bones.d.ts.map +0 -1
  92. package/dist/cybergotchi/bones.js.map +0 -1
  93. package/dist/cybergotchi/bones.test.d.ts +0 -2
  94. package/dist/cybergotchi/bones.test.d.ts.map +0 -1
  95. package/dist/cybergotchi/bones.test.js +0 -100
  96. package/dist/cybergotchi/bones.test.js.map +0 -1
  97. package/dist/cybergotchi/config.d.ts.map +0 -1
  98. package/dist/cybergotchi/config.js.map +0 -1
  99. package/dist/cybergotchi/events.d.ts.map +0 -1
  100. package/dist/cybergotchi/events.js.map +0 -1
  101. package/dist/cybergotchi/needs.d.ts.map +0 -1
  102. package/dist/cybergotchi/needs.js.map +0 -1
  103. package/dist/cybergotchi/needs.test.d.ts +0 -2
  104. package/dist/cybergotchi/needs.test.d.ts.map +0 -1
  105. package/dist/cybergotchi/needs.test.js +0 -150
  106. package/dist/cybergotchi/needs.test.js.map +0 -1
  107. package/dist/cybergotchi/personality.d.ts.map +0 -1
  108. package/dist/cybergotchi/personality.js.map +0 -1
  109. package/dist/cybergotchi/species.d.ts.map +0 -1
  110. package/dist/cybergotchi/species.js.map +0 -1
  111. package/dist/cybergotchi/speech.d.ts.map +0 -1
  112. package/dist/cybergotchi/speech.js.map +0 -1
  113. package/dist/cybergotchi/types.d.ts.map +0 -1
  114. package/dist/cybergotchi/types.js.map +0 -1
  115. package/dist/cybergotchi/useCybergotchi.d.ts.map +0 -1
  116. package/dist/cybergotchi/useCybergotchi.js.map +0 -1
  117. package/dist/git/git.test.d.ts +0 -2
  118. package/dist/git/git.test.d.ts.map +0 -1
  119. package/dist/git/git.test.js +0 -141
  120. package/dist/git/git.test.js.map +0 -1
  121. package/dist/git/index.d.ts.map +0 -1
  122. package/dist/git/index.js.map +0 -1
  123. package/dist/harness/checkpoints.d.ts.map +0 -1
  124. package/dist/harness/checkpoints.js.map +0 -1
  125. package/dist/harness/config.d.ts.map +0 -1
  126. package/dist/harness/config.js.map +0 -1
  127. package/dist/harness/config.test.d.ts +0 -2
  128. package/dist/harness/config.test.d.ts.map +0 -1
  129. package/dist/harness/config.test.js +0 -107
  130. package/dist/harness/config.test.js.map +0 -1
  131. package/dist/harness/context-warning.d.ts.map +0 -1
  132. package/dist/harness/context-warning.js.map +0 -1
  133. package/dist/harness/context-warning.test.d.ts +0 -2
  134. package/dist/harness/context-warning.test.d.ts.map +0 -1
  135. package/dist/harness/context-warning.test.js +0 -72
  136. package/dist/harness/context-warning.test.js.map +0 -1
  137. package/dist/harness/cost.d.ts.map +0 -1
  138. package/dist/harness/cost.js.map +0 -1
  139. package/dist/harness/cost.test.d.ts +0 -2
  140. package/dist/harness/cost.test.d.ts.map +0 -1
  141. package/dist/harness/cost.test.js +0 -43
  142. package/dist/harness/cost.test.js.map +0 -1
  143. package/dist/harness/credentials.d.ts.map +0 -1
  144. package/dist/harness/credentials.js.map +0 -1
  145. package/dist/harness/credentials.test.d.ts +0 -2
  146. package/dist/harness/credentials.test.d.ts.map +0 -1
  147. package/dist/harness/credentials.test.js +0 -113
  148. package/dist/harness/credentials.test.js.map +0 -1
  149. package/dist/harness/hooks-env.test.d.ts +0 -5
  150. package/dist/harness/hooks-env.test.d.ts.map +0 -1
  151. package/dist/harness/hooks-env.test.js +0 -41
  152. package/dist/harness/hooks-env.test.js.map +0 -1
  153. package/dist/harness/hooks.d.ts.map +0 -1
  154. package/dist/harness/hooks.js.map +0 -1
  155. package/dist/harness/hooks.test.d.ts +0 -2
  156. package/dist/harness/hooks.test.d.ts.map +0 -1
  157. package/dist/harness/hooks.test.js +0 -24
  158. package/dist/harness/hooks.test.js.map +0 -1
  159. package/dist/harness/keybindings.d.ts.map +0 -1
  160. package/dist/harness/keybindings.js.map +0 -1
  161. package/dist/harness/keybindings.test.d.ts +0 -2
  162. package/dist/harness/keybindings.test.d.ts.map +0 -1
  163. package/dist/harness/keybindings.test.js +0 -38
  164. package/dist/harness/keybindings.test.js.map +0 -1
  165. package/dist/harness/memory.d.ts.map +0 -1
  166. package/dist/harness/memory.js.map +0 -1
  167. package/dist/harness/memory.test.d.ts +0 -2
  168. package/dist/harness/memory.test.d.ts.map +0 -1
  169. package/dist/harness/memory.test.js +0 -65
  170. package/dist/harness/memory.test.js.map +0 -1
  171. package/dist/harness/onboarding.d.ts.map +0 -1
  172. package/dist/harness/onboarding.js.map +0 -1
  173. package/dist/harness/onboarding.test.d.ts +0 -5
  174. package/dist/harness/onboarding.test.d.ts.map +0 -1
  175. package/dist/harness/onboarding.test.js +0 -93
  176. package/dist/harness/onboarding.test.js.map +0 -1
  177. package/dist/harness/plugins.d.ts.map +0 -1
  178. package/dist/harness/plugins.js.map +0 -1
  179. package/dist/harness/plugins.test.d.ts +0 -2
  180. package/dist/harness/plugins.test.d.ts.map +0 -1
  181. package/dist/harness/plugins.test.js +0 -97
  182. package/dist/harness/plugins.test.js.map +0 -1
  183. package/dist/harness/rules.d.ts.map +0 -1
  184. package/dist/harness/rules.js.map +0 -1
  185. package/dist/harness/rules.test.d.ts +0 -2
  186. package/dist/harness/rules.test.d.ts.map +0 -1
  187. package/dist/harness/rules.test.js +0 -54
  188. package/dist/harness/rules.test.js.map +0 -1
  189. package/dist/harness/session.d.ts.map +0 -1
  190. package/dist/harness/session.js.map +0 -1
  191. package/dist/harness/session.test.d.ts +0 -2
  192. package/dist/harness/session.test.d.ts.map +0 -1
  193. package/dist/harness/session.test.js +0 -37
  194. package/dist/harness/session.test.js.map +0 -1
  195. package/dist/harness/store.d.ts.map +0 -1
  196. package/dist/harness/store.js.map +0 -1
  197. package/dist/harness/store.test.d.ts +0 -2
  198. package/dist/harness/store.test.d.ts.map +0 -1
  199. package/dist/harness/store.test.js +0 -71
  200. package/dist/harness/store.test.js.map +0 -1
  201. package/dist/harness/submit-handler.d.ts.map +0 -1
  202. package/dist/harness/submit-handler.js.map +0 -1
  203. package/dist/harness/submit-handler.test.d.ts +0 -2
  204. package/dist/harness/submit-handler.test.d.ts.map +0 -1
  205. package/dist/harness/submit-handler.test.js +0 -62
  206. package/dist/harness/submit-handler.test.js.map +0 -1
  207. package/dist/lsp/client.d.ts.map +0 -1
  208. package/dist/lsp/client.js.map +0 -1
  209. package/dist/lsp/client.test.d.ts +0 -2
  210. package/dist/lsp/client.test.d.ts.map +0 -1
  211. package/dist/lsp/client.test.js +0 -44
  212. package/dist/lsp/client.test.js.map +0 -1
  213. package/dist/main.d.ts.map +0 -1
  214. package/dist/main.js.map +0 -1
  215. package/dist/mcp/DeferredMcpTool.d.ts.map +0 -1
  216. package/dist/mcp/DeferredMcpTool.js.map +0 -1
  217. package/dist/mcp/McpTool.d.ts.map +0 -1
  218. package/dist/mcp/McpTool.js.map +0 -1
  219. package/dist/mcp/McpTool.test.d.ts +0 -2
  220. package/dist/mcp/McpTool.test.d.ts.map +0 -1
  221. package/dist/mcp/McpTool.test.js +0 -53
  222. package/dist/mcp/McpTool.test.js.map +0 -1
  223. package/dist/mcp/client.d.ts.map +0 -1
  224. package/dist/mcp/client.js.map +0 -1
  225. package/dist/mcp/loader.d.ts.map +0 -1
  226. package/dist/mcp/loader.js.map +0 -1
  227. package/dist/mcp/loader.test.d.ts +0 -7
  228. package/dist/mcp/loader.test.d.ts.map +0 -1
  229. package/dist/mcp/loader.test.js +0 -25
  230. package/dist/mcp/loader.test.js.map +0 -1
  231. package/dist/mcp/schema.d.ts.map +0 -1
  232. package/dist/mcp/schema.js.map +0 -1
  233. package/dist/mcp/schema.test.d.ts +0 -2
  234. package/dist/mcp/schema.test.d.ts.map +0 -1
  235. package/dist/mcp/schema.test.js +0 -33
  236. package/dist/mcp/schema.test.js.map +0 -1
  237. package/dist/mcp/server.d.ts.map +0 -1
  238. package/dist/mcp/server.js.map +0 -1
  239. package/dist/mcp/server.test.d.ts +0 -2
  240. package/dist/mcp/server.test.d.ts.map +0 -1
  241. package/dist/mcp/server.test.js +0 -54
  242. package/dist/mcp/server.test.js.map +0 -1
  243. package/dist/mcp/types.d.ts.map +0 -1
  244. package/dist/mcp/types.js.map +0 -1
  245. package/dist/providers/anthropic-convert.test.d.ts +0 -5
  246. package/dist/providers/anthropic-convert.test.d.ts.map +0 -1
  247. package/dist/providers/anthropic-convert.test.js +0 -98
  248. package/dist/providers/anthropic-convert.test.js.map +0 -1
  249. package/dist/providers/anthropic.d.ts.map +0 -1
  250. package/dist/providers/anthropic.js.map +0 -1
  251. package/dist/providers/anthropic.test.d.ts +0 -2
  252. package/dist/providers/anthropic.test.d.ts.map +0 -1
  253. package/dist/providers/anthropic.test.js +0 -18
  254. package/dist/providers/anthropic.test.js.map +0 -1
  255. package/dist/providers/base.d.ts.map +0 -1
  256. package/dist/providers/base.js.map +0 -1
  257. package/dist/providers/index.d.ts.map +0 -1
  258. package/dist/providers/index.js.map +0 -1
  259. package/dist/providers/llamacpp.d.ts.map +0 -1
  260. package/dist/providers/llamacpp.js.map +0 -1
  261. package/dist/providers/llamacpp.test.d.ts +0 -2
  262. package/dist/providers/llamacpp.test.d.ts.map +0 -1
  263. package/dist/providers/llamacpp.test.js +0 -33
  264. package/dist/providers/llamacpp.test.js.map +0 -1
  265. package/dist/providers/message-format.test.d.ts +0 -2
  266. package/dist/providers/message-format.test.d.ts.map +0 -1
  267. package/dist/providers/message-format.test.js +0 -31
  268. package/dist/providers/message-format.test.js.map +0 -1
  269. package/dist/providers/ollama.d.ts.map +0 -1
  270. package/dist/providers/ollama.js.map +0 -1
  271. package/dist/providers/ollama.test.d.ts +0 -2
  272. package/dist/providers/ollama.test.d.ts.map +0 -1
  273. package/dist/providers/ollama.test.js +0 -40
  274. package/dist/providers/ollama.test.js.map +0 -1
  275. package/dist/providers/openai.d.ts.map +0 -1
  276. package/dist/providers/openai.js.map +0 -1
  277. package/dist/providers/openai.test.d.ts +0 -2
  278. package/dist/providers/openai.test.d.ts.map +0 -1
  279. package/dist/providers/openai.test.js +0 -23
  280. package/dist/providers/openai.test.js.map +0 -1
  281. package/dist/providers/openrouter.d.ts.map +0 -1
  282. package/dist/providers/openrouter.js.map +0 -1
  283. package/dist/providers/stream-parsing.test.d.ts +0 -6
  284. package/dist/providers/stream-parsing.test.d.ts.map +0 -1
  285. package/dist/providers/stream-parsing.test.js +0 -174
  286. package/dist/providers/stream-parsing.test.js.map +0 -1
  287. package/dist/query/compress.d.ts.map +0 -1
  288. package/dist/query/compress.js.map +0 -1
  289. package/dist/query/errors.d.ts.map +0 -1
  290. package/dist/query/errors.js.map +0 -1
  291. package/dist/query/index.d.ts.map +0 -1
  292. package/dist/query/index.js.map +0 -1
  293. package/dist/query/tools.d.ts.map +0 -1
  294. package/dist/query/tools.js.map +0 -1
  295. package/dist/query/types.d.ts.map +0 -1
  296. package/dist/query/types.js.map +0 -1
  297. package/dist/query.d.ts.map +0 -1
  298. package/dist/query.js.map +0 -1
  299. package/dist/query.test.d.ts +0 -2
  300. package/dist/query.test.d.ts.map +0 -1
  301. package/dist/query.test.js +0 -121
  302. package/dist/query.test.js.map +0 -1
  303. package/dist/remote/server.d.ts.map +0 -1
  304. package/dist/remote/server.js.map +0 -1
  305. package/dist/remote/server.test.d.ts +0 -2
  306. package/dist/remote/server.test.d.ts.map +0 -1
  307. package/dist/remote/server.test.js +0 -120
  308. package/dist/remote/server.test.js.map +0 -1
  309. package/dist/renderer/cells.d.ts.map +0 -1
  310. package/dist/renderer/cells.js.map +0 -1
  311. package/dist/renderer/cells.test.d.ts +0 -2
  312. package/dist/renderer/cells.test.d.ts.map +0 -1
  313. package/dist/renderer/cells.test.js +0 -69
  314. package/dist/renderer/cells.test.js.map +0 -1
  315. package/dist/renderer/colors.d.ts.map +0 -1
  316. package/dist/renderer/colors.js.map +0 -1
  317. package/dist/renderer/diff.d.ts.map +0 -1
  318. package/dist/renderer/diff.js.map +0 -1
  319. package/dist/renderer/diff.test.d.ts +0 -5
  320. package/dist/renderer/diff.test.d.ts.map +0 -1
  321. package/dist/renderer/diff.test.js +0 -140
  322. package/dist/renderer/diff.test.js.map +0 -1
  323. package/dist/renderer/differ.d.ts.map +0 -1
  324. package/dist/renderer/differ.js.map +0 -1
  325. package/dist/renderer/e2e.test.d.ts +0 -6
  326. package/dist/renderer/e2e.test.d.ts.map +0 -1
  327. package/dist/renderer/e2e.test.js +0 -702
  328. package/dist/renderer/e2e.test.js.map +0 -1
  329. package/dist/renderer/image.d.ts.map +0 -1
  330. package/dist/renderer/image.js.map +0 -1
  331. package/dist/renderer/image.test.d.ts +0 -5
  332. package/dist/renderer/image.test.d.ts.map +0 -1
  333. package/dist/renderer/image.test.js +0 -66
  334. package/dist/renderer/image.test.js.map +0 -1
  335. package/dist/renderer/index.d.ts.map +0 -1
  336. package/dist/renderer/index.js.map +0 -1
  337. package/dist/renderer/input.d.ts.map +0 -1
  338. package/dist/renderer/input.js.map +0 -1
  339. package/dist/renderer/input.test.d.ts +0 -5
  340. package/dist/renderer/input.test.d.ts.map +0 -1
  341. package/dist/renderer/input.test.js +0 -129
  342. package/dist/renderer/input.test.js.map +0 -1
  343. package/dist/renderer/layout.d.ts.map +0 -1
  344. package/dist/renderer/layout.js.map +0 -1
  345. package/dist/renderer/markdown.d.ts.map +0 -1
  346. package/dist/renderer/markdown.js.map +0 -1
  347. package/dist/renderer/markdown.test.d.ts +0 -2
  348. package/dist/renderer/markdown.test.d.ts.map +0 -1
  349. package/dist/renderer/markdown.test.js +0 -81
  350. package/dist/renderer/markdown.test.js.map +0 -1
  351. package/dist/renderer/perf.test.d.ts +0 -2
  352. package/dist/renderer/perf.test.d.ts.map +0 -1
  353. package/dist/renderer/perf.test.js +0 -128
  354. package/dist/renderer/perf.test.js.map +0 -1
  355. package/dist/renderer/session-browser.d.ts.map +0 -1
  356. package/dist/renderer/session-browser.js.map +0 -1
  357. package/dist/renderer/session-browser.test.d.ts +0 -6
  358. package/dist/renderer/session-browser.test.d.ts.map +0 -1
  359. package/dist/renderer/session-browser.test.js +0 -95
  360. package/dist/renderer/session-browser.test.js.map +0 -1
  361. package/dist/renderer/ui-ux.test.d.ts +0 -15
  362. package/dist/renderer/ui-ux.test.d.ts.map +0 -1
  363. package/dist/renderer/ui-ux.test.js +0 -470
  364. package/dist/renderer/ui-ux.test.js.map +0 -1
  365. package/dist/repl.d.ts.map +0 -1
  366. package/dist/repl.js.map +0 -1
  367. package/dist/services/AgentDispatcher.d.ts.map +0 -1
  368. package/dist/services/AgentDispatcher.js.map +0 -1
  369. package/dist/services/AgentDispatcher.test.d.ts +0 -2
  370. package/dist/services/AgentDispatcher.test.d.ts.map +0 -1
  371. package/dist/services/AgentDispatcher.test.js +0 -66
  372. package/dist/services/AgentDispatcher.test.js.map +0 -1
  373. package/dist/services/StreamingToolExecutor.d.ts.map +0 -1
  374. package/dist/services/StreamingToolExecutor.js.map +0 -1
  375. package/dist/services/StreamingToolExecutor.test.d.ts +0 -2
  376. package/dist/services/StreamingToolExecutor.test.d.ts.map +0 -1
  377. package/dist/services/StreamingToolExecutor.test.js +0 -103
  378. package/dist/services/StreamingToolExecutor.test.js.map +0 -1
  379. package/dist/services/agent-messaging.d.ts.map +0 -1
  380. package/dist/services/agent-messaging.js.map +0 -1
  381. package/dist/services/agent-messaging.test.d.ts +0 -2
  382. package/dist/services/agent-messaging.test.d.ts.map +0 -1
  383. package/dist/services/agent-messaging.test.js +0 -88
  384. package/dist/services/agent-messaging.test.js.map +0 -1
  385. package/dist/services/cron.d.ts.map +0 -1
  386. package/dist/services/cron.js.map +0 -1
  387. package/dist/services/cron.test.d.ts +0 -2
  388. package/dist/services/cron.test.d.ts.map +0 -1
  389. package/dist/services/cron.test.js +0 -49
  390. package/dist/services/cron.test.js.map +0 -1
  391. package/dist/test-helpers.d.ts +0 -31
  392. package/dist/test-helpers.d.ts.map +0 -1
  393. package/dist/test-helpers.js +0 -106
  394. package/dist/test-helpers.js.map +0 -1
  395. package/dist/tools/AgentTool/index.d.ts.map +0 -1
  396. package/dist/tools/AgentTool/index.js.map +0 -1
  397. package/dist/tools/AskUserTool/index.d.ts.map +0 -1
  398. package/dist/tools/AskUserTool/index.js.map +0 -1
  399. package/dist/tools/BashTool/index.d.ts.map +0 -1
  400. package/dist/tools/BashTool/index.js.map +0 -1
  401. package/dist/tools/CronTool/index.d.ts.map +0 -1
  402. package/dist/tools/CronTool/index.js.map +0 -1
  403. package/dist/tools/DiagnosticsTool/index.d.ts.map +0 -1
  404. package/dist/tools/DiagnosticsTool/index.js.map +0 -1
  405. package/dist/tools/EnterPlanModeTool/index.d.ts.map +0 -1
  406. package/dist/tools/EnterPlanModeTool/index.js.map +0 -1
  407. package/dist/tools/EnterWorktreeTool/index.d.ts.map +0 -1
  408. package/dist/tools/EnterWorktreeTool/index.js.map +0 -1
  409. package/dist/tools/ExitPlanModeTool/index.d.ts.map +0 -1
  410. package/dist/tools/ExitPlanModeTool/index.js.map +0 -1
  411. package/dist/tools/ExitWorktreeTool/index.d.ts.map +0 -1
  412. package/dist/tools/ExitWorktreeTool/index.js.map +0 -1
  413. package/dist/tools/FileEditTool/index.d.ts.map +0 -1
  414. package/dist/tools/FileEditTool/index.js.map +0 -1
  415. package/dist/tools/FileReadTool/index.d.ts.map +0 -1
  416. package/dist/tools/FileReadTool/index.js.map +0 -1
  417. package/dist/tools/FileWriteTool/index.d.ts.map +0 -1
  418. package/dist/tools/FileWriteTool/index.js.map +0 -1
  419. package/dist/tools/GlobTool/index.d.ts.map +0 -1
  420. package/dist/tools/GlobTool/index.js.map +0 -1
  421. package/dist/tools/GrepTool/index.d.ts.map +0 -1
  422. package/dist/tools/GrepTool/index.js.map +0 -1
  423. package/dist/tools/ImageReadTool/index.d.ts.map +0 -1
  424. package/dist/tools/ImageReadTool/index.js.map +0 -1
  425. package/dist/tools/KillProcessTool/index.d.ts.map +0 -1
  426. package/dist/tools/KillProcessTool/index.js.map +0 -1
  427. package/dist/tools/LSTool/index.d.ts.map +0 -1
  428. package/dist/tools/LSTool/index.js.map +0 -1
  429. package/dist/tools/MemoryTool/index.d.ts.map +0 -1
  430. package/dist/tools/MemoryTool/index.js.map +0 -1
  431. package/dist/tools/MultiEditTool/index.d.ts.map +0 -1
  432. package/dist/tools/MultiEditTool/index.js.map +0 -1
  433. package/dist/tools/NotebookEditTool/index.d.ts.map +0 -1
  434. package/dist/tools/NotebookEditTool/index.js.map +0 -1
  435. package/dist/tools/ParallelAgentTool/index.d.ts.map +0 -1
  436. package/dist/tools/ParallelAgentTool/index.js.map +0 -1
  437. package/dist/tools/RemoteTriggerTool/index.d.ts.map +0 -1
  438. package/dist/tools/RemoteTriggerTool/index.js.map +0 -1
  439. package/dist/tools/SendMessageTool/index.d.ts.map +0 -1
  440. package/dist/tools/SendMessageTool/index.js.map +0 -1
  441. package/dist/tools/SkillTool/index.d.ts.map +0 -1
  442. package/dist/tools/SkillTool/index.js.map +0 -1
  443. package/dist/tools/TaskCreateTool/index.d.ts.map +0 -1
  444. package/dist/tools/TaskCreateTool/index.js.map +0 -1
  445. package/dist/tools/TaskGetTool/index.d.ts.map +0 -1
  446. package/dist/tools/TaskGetTool/index.js.map +0 -1
  447. package/dist/tools/TaskListTool/index.d.ts.map +0 -1
  448. package/dist/tools/TaskListTool/index.js.map +0 -1
  449. package/dist/tools/TaskOutputTool/index.d.ts.map +0 -1
  450. package/dist/tools/TaskOutputTool/index.js.map +0 -1
  451. package/dist/tools/TaskStopTool/index.d.ts.map +0 -1
  452. package/dist/tools/TaskStopTool/index.js.map +0 -1
  453. package/dist/tools/TaskUpdateTool/index.d.ts.map +0 -1
  454. package/dist/tools/TaskUpdateTool/index.js.map +0 -1
  455. package/dist/tools/ToolSearchTool/index.d.ts.map +0 -1
  456. package/dist/tools/ToolSearchTool/index.js.map +0 -1
  457. package/dist/tools/WebFetchTool/index.d.ts.map +0 -1
  458. package/dist/tools/WebFetchTool/index.js.map +0 -1
  459. package/dist/tools/WebSearchTool/index.d.ts.map +0 -1
  460. package/dist/tools/WebSearchTool/index.js.map +0 -1
  461. package/dist/tools/file-edit.test.d.ts +0 -2
  462. package/dist/tools/file-edit.test.d.ts.map +0 -1
  463. package/dist/tools/file-edit.test.js +0 -35
  464. package/dist/tools/file-edit.test.js.map +0 -1
  465. package/dist/tools/tools-basic.test.d.ts +0 -6
  466. package/dist/tools/tools-basic.test.d.ts.map +0 -1
  467. package/dist/tools/tools-basic.test.js +0 -379
  468. package/dist/tools/tools-basic.test.js.map +0 -1
  469. package/dist/tools/web-fetch.test.d.ts +0 -2
  470. package/dist/tools/web-fetch.test.d.ts.map +0 -1
  471. package/dist/tools/web-fetch.test.js +0 -27
  472. package/dist/tools/web-fetch.test.js.map +0 -1
  473. package/dist/tools.d.ts.map +0 -1
  474. package/dist/tools.js.map +0 -1
  475. package/dist/types/events.d.ts.map +0 -1
  476. package/dist/types/events.js.map +0 -1
  477. package/dist/types/message.d.ts.map +0 -1
  478. package/dist/types/message.js.map +0 -1
  479. package/dist/types/message.test.d.ts +0 -2
  480. package/dist/types/message.test.d.ts.map +0 -1
  481. package/dist/types/message.test.js +0 -46
  482. package/dist/types/message.test.js.map +0 -1
  483. package/dist/types/permissions.d.ts.map +0 -1
  484. package/dist/types/permissions.js.map +0 -1
  485. package/dist/types/permissions.test.d.ts +0 -2
  486. package/dist/types/permissions.test.d.ts.map +0 -1
  487. package/dist/types/permissions.test.js +0 -127
  488. package/dist/types/permissions.test.js.map +0 -1
  489. package/dist/utils/bash-safety.d.ts.map +0 -1
  490. package/dist/utils/bash-safety.js.map +0 -1
  491. package/dist/utils/bash-safety.test.d.ts +0 -2
  492. package/dist/utils/bash-safety.test.d.ts.map +0 -1
  493. package/dist/utils/bash-safety.test.js +0 -112
  494. package/dist/utils/bash-safety.test.js.map +0 -1
  495. package/dist/utils/diff-algorithm.d.ts.map +0 -1
  496. package/dist/utils/diff-algorithm.js.map +0 -1
  497. package/dist/utils/diff-algorithm.test.d.ts +0 -2
  498. package/dist/utils/diff-algorithm.test.d.ts.map +0 -1
  499. package/dist/utils/diff-algorithm.test.js +0 -49
  500. package/dist/utils/diff-algorithm.test.js.map +0 -1
  501. package/dist/utils/format.d.ts.map +0 -1
  502. package/dist/utils/format.js.map +0 -1
  503. package/dist/utils/fs.d.ts.map +0 -1
  504. package/dist/utils/fs.js.map +0 -1
  505. package/dist/utils/fs.test.d.ts +0 -5
  506. package/dist/utils/fs.test.d.ts.map +0 -1
  507. package/dist/utils/fs.test.js +0 -82
  508. package/dist/utils/fs.test.js.map +0 -1
  509. package/dist/utils/safe-env.d.ts.map +0 -1
  510. package/dist/utils/safe-env.js.map +0 -1
  511. package/dist/utils/theme-data.d.ts.map +0 -1
  512. package/dist/utils/theme-data.js.map +0 -1
  513. package/dist/utils/theme.d.ts.map +0 -1
  514. package/dist/utils/theme.js.map +0 -1
  515. package/dist/utils/tool-summary.d.ts.map +0 -1
  516. package/dist/utils/tool-summary.js.map +0 -1
  517. package/dist/utils/tool-summary.test.d.ts +0 -2
  518. package/dist/utils/tool-summary.test.d.ts.map +0 -1
  519. package/dist/utils/tool-summary.test.js +0 -93
  520. package/dist/utils/tool-summary.test.js.map +0 -1
package/README.md CHANGED
@@ -17,13 +17,34 @@
17
17
 
18
18
  AI coding agent in your terminal. Works with any LLM -- free local models or cloud APIs.
19
19
 
20
- [![npm version](https://img.shields.io/npm/v/@zhijiewang/openharness)](https://www.npmjs.com/package/@zhijiewang/openharness) [![npm downloads](https://img.shields.io/npm/dm/@zhijiewang/openharness)](https://www.npmjs.com/package/@zhijiewang/openharness) [![license](https://img.shields.io/npm/l/@zhijiewang/openharness)](LICENSE) ![Node.js 18+](https://img.shields.io/badge/node-18%2B-green) ![TypeScript](https://img.shields.io/badge/typescript-strict-blue) [![GitHub stars](https://img.shields.io/github/stars/zhijiewong/openharness)](https://github.com/zhijiewong/openharness) [![GitHub issues](https://img.shields.io/github/issues-raw/zhijiewong/openharness)](https://github.com/zhijiewong/openharness/issues) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](https://github.com/zhijiewong/openharness/pulls)
20
+ <p align="center">
21
+ <img src="assets/openharness_v0.11.1_4.gif" alt="OpenHarness demo" width="800" />
22
+ </p>
21
23
 
22
- ---
24
+ [![npm version](https://img.shields.io/npm/v/@zhijiewang/openharness)](https://www.npmjs.com/package/@zhijiewang/openharness) [![npm downloads](https://img.shields.io/npm/dm/@zhijiewang/openharness)](https://www.npmjs.com/package/@zhijiewang/openharness) [![license](https://img.shields.io/npm/l/@zhijiewang/openharness)](LICENSE) ![tests](https://img.shields.io/badge/tests-624-brightgreen) ![tools](https://img.shields.io/badge/tools-35-blue) ![Node.js 18+](https://img.shields.io/badge/node-18%2B-green) ![TypeScript](https://img.shields.io/badge/typescript-strict-blue) [![GitHub stars](https://img.shields.io/github/stars/zhijiewong/openharness)](https://github.com/zhijiewong/openharness) [![GitHub issues](https://img.shields.io/github/issues-raw/zhijiewong/openharness)](https://github.com/zhijiewong/openharness/issues) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](https://github.com/zhijiewong/openharness/pulls)
23
25
 
24
- <video src="https://github.com/user-attachments/assets/ed19a2cc-14d3-4db3-aa5b-3dc07c444498" controls width="100%"></video>
26
+ ---
25
27
 
26
- *OpenHarness reading files, running commands, and editing code — powered by a local Ollama model.*
28
+ ## Table of Contents
29
+
30
+ - [Quick Start](#quick-start)
31
+ - [Why OpenHarness?](#why-openharness)
32
+ - [Terminal UI](#terminal-ui)
33
+ - [Tools (35)](#tools-35)
34
+ - [Slash Commands (33)](#slash-commands-33)
35
+ - [Permission Modes](#permission-modes)
36
+ - [Hooks](#hooks)
37
+ - [Checkpoints & Rewind](#checkpoints--rewind)
38
+ - [Agent Roles](#agent-roles)
39
+ - [Headless Mode & CI/CD](#headless-mode)
40
+ - [Cybergotchi](#cybergotchi)
41
+ - [MCP Servers](#mcp-servers)
42
+ - [Providers](#providers)
43
+ - [FAQ](#faq)
44
+ - [Install](#install)
45
+ - [Development](#development)
46
+ - [Contributing](#contributing)
47
+ - [Community](#community)
27
48
 
28
49
  ---
29
50
 
@@ -42,7 +63,17 @@ oh # auto-detect local model
42
63
  oh --model ollama/qwen2.5:7b # specific model
43
64
  oh --model gpt-4o # cloud model (needs OPENAI_API_KEY)
44
65
  oh --trust # auto-approve all tool calls
45
- oh run "fix the tests" --json # headless mode for CI/CD
66
+ oh --auto # auto-approve, block dangerous bash
67
+ oh -p "fix the tests" --trust # headless mode (single prompt, exit)
68
+ oh run "review code" --json # CI/CD with JSON output
69
+ ```
70
+
71
+ **In-session commands:**
72
+ ```
73
+ /rewind # undo last AI file change (checkpoint restore)
74
+ /roles # list agent specializations
75
+ /vim # toggle vim mode
76
+ Ctrl+O # flush transcript to scrollback for review
46
77
  ```
47
78
 
48
79
  ## Why OpenHarness?
@@ -53,7 +84,7 @@ Most AI coding agents are locked to one provider or cost $20+/month. OpenHarness
53
84
  |---|---|---|---|---|
54
85
  | Any LLM | Yes (Ollama, OpenAI, Anthropic, OpenRouter, any OpenAI-compatible) | Anthropic only | Yes | Yes |
55
86
  | Free local models | Ollama native | No | Yes | Yes |
56
- | Tools | 25 with permission gates | 43+ | File-focused | 20+ |
87
+ | Tools | 35 with permission gates | 43+ | File-focused | 20+ |
57
88
  | Permission modes | 7 (ask, trust, deny, acceptEdits, plan, auto, bypass) | 7 | Basic | Basic |
58
89
  | Git integration | Auto-commit + /undo + /rewind checkpoints | Yes | Deep git | Basic |
59
90
  | Slash commands | 30+ built-in | 80+ | Some | Some |
@@ -127,33 +158,59 @@ statusLineFormat: '{model} │ {tokens} │ {cost} │ {ctx}'
127
158
 
128
159
  Available variables: `{model}`, `{tokens}` (input↑ output↓), `{cost}` ($X.XXXX), `{ctx}` (context usage bar). Empty sections are automatically collapsed.
129
160
 
130
- ## Tools (25)
161
+ ## Tools (35)
131
162
 
132
163
  | Tool | Risk | Description |
133
164
  |------|------|-------------|
134
- | Bash | high | Execute shell commands with live streaming output |
135
- | Read | low | Read files with line ranges |
165
+ | **Core** | | |
166
+ | Bash | high | Execute shell commands with live streaming output (AST safety analysis) |
167
+ | Read | low | Read files with line ranges, PDF support |
136
168
  | ImageRead | low | Read images/PDFs for multimodal analysis |
137
169
  | Write | medium | Create or overwrite files |
138
170
  | Edit | medium | Search-and-replace edits |
171
+ | MultiEdit | medium | Atomic multi-file edits (all succeed or none) |
139
172
  | Glob | low | Find files by pattern |
140
- | Grep | low | Regex content search |
173
+ | Grep | low | Regex content search with context lines |
141
174
  | LS | low | List directory contents with sizes |
175
+ | **Web** | | |
142
176
  | WebFetch | medium | Fetch URL content (SSRF-protected) |
143
177
  | WebSearch | medium | Search the web |
178
+ | RemoteTrigger | high | HTTP requests to webhooks/APIs |
179
+ | **Tasks** | | |
144
180
  | TaskCreate | low | Create structured tasks |
145
181
  | TaskUpdate | low | Update task status |
146
182
  | TaskList | low | List all tasks |
183
+ | TaskGet | low | Get task details |
184
+ | TaskStop | low | Stop a running task |
185
+ | TaskOutput | low | Get task output |
186
+ | **Agents** | | |
187
+ | Agent | medium | Spawn a sub-agent (with role specialization) |
188
+ | ParallelAgent | medium | Dispatch multiple agents with DAG dependencies |
189
+ | SendMessage | low | Agent-to-agent peer messaging |
147
190
  | AskUser | low | Ask user a question with options |
148
- | Skill | low | Invoke a skill from .oh/skills/ |
149
- | Agent | medium | Spawn a sub-agent for delegation |
191
+ | **Scheduling** | | |
192
+ | CronCreate | medium | Schedule recurring tasks |
193
+ | CronDelete | medium | Remove scheduled tasks |
194
+ | CronList | low | List all scheduled tasks |
195
+ | **Planning** | | |
150
196
  | EnterPlanMode | low | Enter structured planning mode |
151
197
  | ExitPlanMode | low | Exit planning mode |
198
+ | **Code Intelligence** | | |
199
+ | Diagnostics | low | LSP-based code diagnostics |
152
200
  | NotebookEdit | medium | Edit Jupyter notebooks |
201
+ | **Memory & Discovery** | | |
202
+ | Memory | low | Save/list/search persistent memories |
203
+ | Skill | low | Invoke a skill from .oh/skills/ |
204
+ | ToolSearch | low | Find tools by description |
205
+ | **Git Worktrees** | | |
206
+ | EnterWorktree | medium | Create isolated git worktree |
207
+ | ExitWorktree | medium | Remove a git worktree |
208
+ | **Process** | | |
209
+ | KillProcess | high | Stop processes by PID or name |
153
210
 
154
- Low-risk read-only tools auto-approve. Medium and high risk tools require confirmation in `ask` mode. Use `--trust` to skip all prompts.
211
+ Low-risk read-only tools auto-approve. Medium and high risk tools require confirmation in `ask` mode. Use `--trust` or `--auto` to skip prompts.
155
212
 
156
- ## Slash Commands (30+)
213
+ ## Slash Commands (33)
157
214
 
158
215
  Type these during a chat session. Aliases: `/q` exit, `/h` help, `/c` commit, `/m` model, `/s` status.
159
216
 
@@ -309,6 +366,16 @@ mcpServers:
309
366
 
310
367
  MCP tools appear alongside built-in tools. `/status` shows connected servers.
311
368
 
369
+ **MCP Server Registry** — browse and install from a curated catalog:
370
+
371
+ ```
372
+ /mcp-registry # browse all available servers
373
+ /mcp-registry github # show install config for a specific server
374
+ /mcp-registry database # search by category
375
+ ```
376
+
377
+ Categories: filesystem, git, database, api, search, productivity, dev-tools, ai.
378
+
312
379
  ## Git Integration
313
380
 
314
381
  OpenHarness auto-commits AI edits in git repos:
@@ -334,6 +401,58 @@ Every file modification is automatically checkpointed before execution. If somet
334
401
 
335
402
  Checkpoints are stored in `.oh/checkpoints/` and cover FileWrite, FileEdit, and Bash commands that modify files.
336
403
 
404
+ ## Verification Loops
405
+
406
+ After every file edit (Edit, Write, MultiEdit), openHarness automatically runs language-appropriate lint/typecheck commands and feeds the results back into the agent context. This is the single highest-impact harness engineering pattern — research shows 2-3x quality improvement from automated feedback.
407
+
408
+ **Auto-detection** — if your project has `tsconfig.json`, `.eslintrc*`, `pyproject.toml`, `go.mod`, or `Cargo.toml`, verification rules are detected automatically. No configuration needed.
409
+
410
+ **Custom rules** via `.oh/config.yaml`:
411
+
412
+ ```yaml
413
+ verification:
414
+ enabled: true # default: true (auto-detect)
415
+ mode: warn # 'warn' appends to output, 'block' marks as error
416
+ rules:
417
+ - extensions: [".ts", ".tsx"]
418
+ lint: "npx tsc --noEmit 2>&1 | head -20"
419
+ timeout: 15000
420
+ - extensions: [".py"]
421
+ lint: "ruff check {file} 2>&1 | head -10"
422
+ ```
423
+
424
+ The agent sees `[Verification passed]` or `[Verification FAILED]` with the linter output after each edit, enabling self-correction.
425
+
426
+ ## Memory Consolidation
427
+
428
+ On session exit, openHarness automatically prunes stale memories using temporal decay:
429
+
430
+ - Memories not accessed in 30+ days lose 0.1 relevance per 30-day period
431
+ - Memories below 0.1 relevance are permanently deleted
432
+ - Updated relevance scores are persisted to memory files
433
+
434
+ This keeps the memory system lean and relevant. Configure in `.oh/config.yaml`:
435
+
436
+ ```yaml
437
+ memory:
438
+ consolidateOnExit: true # default: true
439
+ ```
440
+
441
+ ## Scheduled Tasks (Cron)
442
+
443
+ Create recurring tasks that run automatically in the background:
444
+
445
+ ```
446
+ # Via slash commands
447
+ /cron list # show all scheduled tasks
448
+ /cron create "check-tests" # create a new task (interactive)
449
+ /cron delete <id> # remove a task
450
+ ```
451
+
452
+ **Schedule syntax:** `every 5m`, `every 2h`, `every 1d`
453
+
454
+ The cron executor checks every 60 seconds for due tasks and runs them via sub-queries. Results are stored in `~/.oh/crons/history/`.
455
+
337
456
  ## Agent Roles
338
457
 
339
458
  Dispatch specialized sub-agents for focused tasks:
@@ -342,16 +461,25 @@ Dispatch specialized sub-agents for focused tasks:
342
461
  /roles # list all available roles
343
462
  ```
344
463
 
345
- | Role | Description |
346
- |------|-------------|
347
- | `code-reviewer` | Find bugs, security issues, style problems |
348
- | `test-writer` | Generate unit and integration tests |
349
- | `docs-writer` | Write documentation and comments |
350
- | `debugger` | Systematic bug investigation |
351
- | `refactorer` | Simplify code without changing behavior |
352
- | `security-auditor` | OWASP, injection, secrets, CVE scanning |
464
+ | Role | Description | Tools |
465
+ |------|-------------|-------|
466
+ | `code-reviewer` | Find bugs, security issues, style problems | Read-only |
467
+ | `test-writer` | Generate unit and integration tests | Read + Write |
468
+ | `docs-writer` | Write documentation and comments | Read + Write + Edit |
469
+ | `debugger` | Systematic bug investigation | Read-only + Bash |
470
+ | `refactorer` | Simplify code without changing behavior | All file tools + Bash |
471
+ | `security-auditor` | OWASP, injection, secrets, CVE scanning | Read-only + Bash |
472
+ | `evaluator` | Evaluate code quality and run tests (read-only) | Read-only + Bash + Diagnostics |
473
+ | `planner` | Design step-by-step implementation plans | Read-only + Bash |
474
+ | `architect` | Analyze architecture and design structural changes | Read-only |
475
+ | `migrator` | Systematic codebase migrations and upgrades | All file tools + Bash |
476
+
477
+ Each role restricts the sub-agent to only its suggested tools. You can also pass `allowed_tools` explicitly:
353
478
 
354
- The LLM can dispatch these via `Agent({ subagent_type: 'code-reviewer', prompt: '...' })`.
479
+ ```
480
+ Agent({ subagent_type: 'evaluator', prompt: 'Run all tests and report results' })
481
+ Agent({ allowed_tools: ['Read', 'Grep'], prompt: 'Search for all TODO comments' })
482
+ ```
355
483
 
356
484
  ## Headless Mode
357
485
 
@@ -446,6 +574,31 @@ oh --model llamacpp/my-model
446
574
  oh models # list available models
447
575
  ```
448
576
 
577
+ ## Configuration Hierarchy
578
+
579
+ Config is loaded in layers (later overrides earlier):
580
+
581
+ 1. **Global** `~/.oh/config.yaml` — default provider, model, theme for all projects
582
+ 2. **Project** `.oh/config.yaml` — project-specific settings
583
+ 3. **Local** `.oh/config.local.yaml` — personal overrides (gitignored)
584
+
585
+ Set your default provider once globally:
586
+
587
+ ```yaml
588
+ # ~/.oh/config.yaml
589
+ provider: ollama
590
+ model: llama3
591
+ permissionMode: ask
592
+ theme: dark
593
+ ```
594
+
595
+ Then per-project configs only need what's different:
596
+
597
+ ```yaml
598
+ # .oh/config.yaml
599
+ model: codellama # override just the model
600
+ ```
601
+
449
602
  ## Project Rules
450
603
 
451
604
  Create `.oh/RULES.md` in any repo (or run `oh init`):
@@ -458,6 +611,42 @@ Create `.oh/RULES.md` in any repo (or run `oh init`):
458
611
 
459
612
  Rules load automatically into every session.
460
613
 
614
+ ## How It Works
615
+
616
+ ```mermaid
617
+ graph LR
618
+ User[User Input] --> REPL[REPL Loop]
619
+ REPL --> Query[Query Engine]
620
+ Query --> Provider[LLM Provider]
621
+ Provider --> LLM[Ollama / OpenAI / Anthropic]
622
+ LLM --> Tools[Tool Execution]
623
+ Tools --> Permissions{Permission Check}
624
+ Permissions -->|Approved| Execute[Run Tool]
625
+ Permissions -->|Blocked| Deny[Deny & Report]
626
+ Execute --> Response[Stream Response]
627
+ Response --> REPL
628
+ ```
629
+
630
+ ## FAQ
631
+
632
+ **Does it work offline?**
633
+ Yes. Use Ollama with a local model — no internet or API key needed.
634
+
635
+ **How much does it cost?**
636
+ Free. OpenHarness is MIT licensed. You bring your own API key (BYOK) for cloud models, or use Ollama for free.
637
+
638
+ **Is it safe?**
639
+ Yes. 7 permission modes control what tools can do. Bash commands are analyzed by an AST parser that blocks destructive patterns (`rm -rf`, `curl | bash`, etc.). Every file change is checkpointed and reversible with `/rewind`.
640
+
641
+ **Can I use it in CI/CD?**
642
+ Yes. Use `oh -p "prompt" --auto` for headless execution, or the built-in GitHub Action for PR reviews.
643
+
644
+ **Does it support my language/framework?**
645
+ Yes. OpenHarness is language-agnostic — it reads, writes, and executes code in any language. Syntax highlighting covers 20+ languages.
646
+
647
+ **How does it compare to Claude Code?**
648
+ ~90% feature parity for CLI use cases. Main advantage: works with ANY LLM (not just Anthropic). See the [comparison table](#why-openharness) above.
649
+
461
650
  ## Install
462
651
 
463
652
  Requires **Node.js 18+**.
@@ -0,0 +1,34 @@
1
+ /**
2
+ * DeferredTool — lazy-loads tool schemas to reduce system prompt size.
3
+ *
4
+ * Wraps a built-in tool with a minimal prompt (name + description only).
5
+ * Full schema and prompt are loaded on first invocation or when resolved
6
+ * via ToolSearch. This mirrors the DeferredMcpTool pattern.
7
+ *
8
+ * Token savings: deferred tools contribute ~15 tokens to the system prompt
9
+ * instead of ~150, reducing context pressure by ~90% per deferred tool.
10
+ */
11
+ import { z } from "zod";
12
+ import type { Tool, ToolContext, ToolResult } from "./Tool.js";
13
+ import type { RiskLevel } from "./types/permissions.js";
14
+ export declare class DeferredTool implements Tool<z.ZodType> {
15
+ readonly name: string;
16
+ readonly description: string;
17
+ readonly inputSchema: z.ZodType;
18
+ readonly riskLevel: RiskLevel;
19
+ private inner;
20
+ private _activated;
21
+ constructor(tool: Tool);
22
+ /** Whether this tool has been activated (called or resolved) */
23
+ get activated(): boolean;
24
+ isReadOnly(input: unknown): boolean;
25
+ isConcurrencySafe(input: unknown): boolean;
26
+ call(input: any, context: ToolContext): Promise<ToolResult>;
27
+ /** Minimal prompt when deferred, full prompt when activated */
28
+ prompt(): string;
29
+ /** Get the full inner tool (for ToolSearch resolution) */
30
+ getInner(): Tool;
31
+ /** Activate this tool so it returns full prompt on next call to prompt() */
32
+ activate(): void;
33
+ }
34
+ //# sourceMappingURL=DeferredTool.d.ts.map
@@ -0,0 +1,62 @@
1
+ /**
2
+ * DeferredTool — lazy-loads tool schemas to reduce system prompt size.
3
+ *
4
+ * Wraps a built-in tool with a minimal prompt (name + description only).
5
+ * Full schema and prompt are loaded on first invocation or when resolved
6
+ * via ToolSearch. This mirrors the DeferredMcpTool pattern.
7
+ *
8
+ * Token savings: deferred tools contribute ~15 tokens to the system prompt
9
+ * instead of ~150, reducing context pressure by ~90% per deferred tool.
10
+ */
11
+ import { z } from "zod";
12
+ export class DeferredTool {
13
+ name;
14
+ description;
15
+ inputSchema;
16
+ riskLevel;
17
+ inner;
18
+ _activated = false;
19
+ constructor(tool) {
20
+ this.inner = tool;
21
+ this.name = tool.name;
22
+ this.description = tool.description;
23
+ this.riskLevel = tool.riskLevel;
24
+ // Permissive schema until activated — accepts any object
25
+ this.inputSchema = z.record(z.unknown());
26
+ }
27
+ /** Whether this tool has been activated (called or resolved) */
28
+ get activated() { return this._activated; }
29
+ isReadOnly(input) {
30
+ return this.inner.isReadOnly(input);
31
+ }
32
+ isConcurrencySafe(input) {
33
+ return this.inner.isConcurrencySafe(input);
34
+ }
35
+ async call(input, context) {
36
+ this._activated = true;
37
+ // Validate with the real schema
38
+ const parsed = this.inner.inputSchema.safeParse(input);
39
+ if (!parsed.success) {
40
+ return {
41
+ output: `Schema validation error: ${parsed.error.message}`,
42
+ isError: true,
43
+ };
44
+ }
45
+ return this.inner.call(parsed.data, context);
46
+ }
47
+ /** Minimal prompt when deferred, full prompt when activated */
48
+ prompt() {
49
+ if (this._activated)
50
+ return this.inner.prompt();
51
+ return `[deferred] ${this.name}: ${this.description}`;
52
+ }
53
+ /** Get the full inner tool (for ToolSearch resolution) */
54
+ getInner() {
55
+ return this.inner;
56
+ }
57
+ /** Activate this tool so it returns full prompt on next call to prompt() */
58
+ activate() {
59
+ this._activated = true;
60
+ }
61
+ }
62
+ //# sourceMappingURL=DeferredTool.js.map
@@ -21,7 +21,7 @@ const roles = [
21
21
  - Verify that changes match the stated intent
22
22
 
23
23
  Be specific: cite file paths, line numbers, and code snippets. Prioritize issues by severity (critical > major > minor). Don't mention things that look fine — focus on problems.`,
24
- suggestedTools: ['FileRead', 'Glob', 'Grep', 'LS'],
24
+ suggestedTools: ['Read', 'Glob', 'Grep', 'LS'],
25
25
  },
26
26
  {
27
27
  id: 'test-writer',
@@ -36,7 +36,7 @@ Be specific: cite file paths, line numbers, and code snippets. Prioritize issues
36
36
  - Include both positive and negative test cases
37
37
 
38
38
  Read existing tests first to match the style, then write new tests.`,
39
- suggestedTools: ['FileRead', 'FileWrite', 'Glob', 'Grep', 'Bash'],
39
+ suggestedTools: ['Read', 'Write', 'Glob', 'Grep', 'Bash'],
40
40
  },
41
41
  {
42
42
  id: 'docs-writer',
@@ -51,7 +51,7 @@ Read existing tests first to match the style, then write new tests.`,
51
51
  - Keep documentation in sync with the actual code
52
52
 
53
53
  Write for the target audience (developers using this project). Be practical, not verbose.`,
54
- suggestedTools: ['FileRead', 'FileWrite', 'FileEdit', 'Glob', 'Grep'],
54
+ suggestedTools: ['Read', 'Write', 'Edit', 'Glob', 'Grep'],
55
55
  },
56
56
  {
57
57
  id: 'debugger',
@@ -66,7 +66,7 @@ Write for the target audience (developers using this project). Be practical, not
66
66
  - Propose a minimal fix that addresses the root cause, not the symptom
67
67
 
68
68
  Follow systematic debugging: read errors → reproduce → check changes → trace data → form hypothesis → test minimally.`,
69
- suggestedTools: ['FileRead', 'Glob', 'Grep', 'Bash', 'LS'],
69
+ suggestedTools: ['Read', 'Glob', 'Grep', 'Bash', 'LS'],
70
70
  },
71
71
  {
72
72
  id: 'refactorer',
@@ -81,7 +81,7 @@ Follow systematic debugging: read errors → reproduce → check changes → tra
81
81
  - Ensure all existing tests still pass after refactoring
82
82
 
83
83
  Do NOT add new features or change behavior. The refactored code must be functionally identical. Run tests after each change.`,
84
- suggestedTools: ['FileRead', 'FileWrite', 'FileEdit', 'Glob', 'Grep', 'Bash'],
84
+ suggestedTools: ['Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash'],
85
85
  },
86
86
  {
87
87
  id: 'security-auditor',
@@ -98,7 +98,63 @@ Do NOT add new features or change behavior. The refactored code must be function
98
98
  - Check dependency versions for known CVEs
99
99
 
100
100
  Report findings with severity (Critical/High/Medium/Low), affected file:line, and recommended fix.`,
101
- suggestedTools: ['FileRead', 'Glob', 'Grep', 'Bash'],
101
+ suggestedTools: ['Read', 'Glob', 'Grep', 'Bash'],
102
+ },
103
+ {
104
+ id: 'evaluator',
105
+ name: 'Evaluator',
106
+ description: 'Evaluates code quality, correctness, and test results (read-only)',
107
+ systemPromptSupplement: `You are an evaluator agent. Your job is to:
108
+ - Review code changes for correctness and quality
109
+ - Run existing tests and report results
110
+ - Check for regressions against the stated requirements
111
+ - Verify that changes match the stated intent
112
+ - Provide a pass/fail assessment with specific findings
113
+
114
+ You CANNOT modify files. Only read, search, and run test/lint commands to evaluate.`,
115
+ suggestedTools: ['Read', 'Glob', 'Grep', 'LS', 'Bash', 'Diagnostics'],
116
+ },
117
+ {
118
+ id: 'planner',
119
+ name: 'Planner',
120
+ description: 'Designs step-by-step implementation plans from requirements',
121
+ systemPromptSupplement: `You are a planning agent. Your job is to:
122
+ - Read the codebase to understand architecture, patterns, and conventions
123
+ - Design a detailed step-by-step implementation plan for the given task
124
+ - Identify files to create, modify, or delete with specific change descriptions
125
+ - Flag risks, dependencies, and the recommended implementation order
126
+ - Estimate scope (number of files, complexity)
127
+
128
+ Do NOT implement anything. Your output is a plan document, not code. Read widely before planning.`,
129
+ suggestedTools: ['Read', 'Glob', 'Grep', 'LS', 'Bash'],
130
+ },
131
+ {
132
+ id: 'architect',
133
+ name: 'Architect',
134
+ description: 'Analyzes system architecture and designs structural changes',
135
+ systemPromptSupplement: `You are an architecture agent. Your job is to:
136
+ - Map the current system architecture (modules, dependencies, data flow)
137
+ - Identify architectural patterns and conventions in use
138
+ - Design structural changes that preserve existing patterns
139
+ - Evaluate trade-offs between approaches (performance, maintainability, complexity)
140
+ - Document interfaces, contracts, and integration points
141
+
142
+ Focus on the big picture: module boundaries, data flow, dependency graphs. Leave implementation details to other agents.`,
143
+ suggestedTools: ['Read', 'Glob', 'Grep', 'LS'],
144
+ },
145
+ {
146
+ id: 'migrator',
147
+ name: 'Migrator',
148
+ description: 'Performs codebase migrations (API upgrades, framework changes, renames)',
149
+ systemPromptSupplement: `You are a migration agent. Your job is to:
150
+ - Identify all occurrences of the pattern/API/convention being migrated
151
+ - Apply changes systematically across all affected files
152
+ - Preserve behavior while updating the implementation
153
+ - Run tests after each batch of changes to catch regressions
154
+ - Handle edge cases and conditional patterns that need manual review
155
+
156
+ Work methodically: search exhaustively, change incrementally, test after each batch. Never leave a migration half-done.`,
157
+ suggestedTools: ['Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash'],
102
158
  },
103
159
  ];
104
160
  /** Get a role by ID */
@@ -27,7 +27,7 @@ register("help", "Show available commands", () => {
27
27
  const categories = {
28
28
  'Session': ['clear', 'compact', 'export', 'history', 'browse', 'resume', 'fork', 'pin', 'unpin'],
29
29
  'Git': ['diff', 'undo', 'rewind', 'commit', 'log'],
30
- 'Info': ['help', 'cost', 'status', 'config', 'files', 'model', 'memory', 'doctor', 'context', 'mcp'],
30
+ 'Info': ['help', 'cost', 'status', 'config', 'files', 'model', 'memory', 'doctor', 'context', 'mcp', 'mcp-registry'],
31
31
  'Settings': ['theme', 'vim', 'companion', 'fast', 'keys'],
32
32
  'AI': ['plan', 'review', 'roles'],
33
33
  'Pet': ['cybergotchi'],
@@ -519,14 +519,43 @@ register("context", "Show context window usage breakdown", (_args, ctx) => {
519
519
  register("mcp", "Show MCP server status", () => {
520
520
  const mcp = connectedMcpServers();
521
521
  if (mcp.length === 0) {
522
- return { output: "No MCP servers connected.\nConfigure in .oh/config.yaml under mcpServers.", handled: true };
522
+ return { output: "No MCP servers connected.\nConfigure in .oh/config.yaml under mcpServers.\nRun /mcp-registry to browse available servers.", handled: true };
523
523
  }
524
524
  const lines = [`MCP Servers (${mcp.length} connected):\n`];
525
525
  for (const name of mcp) {
526
526
  lines.push(` ✓ ${name}`);
527
527
  }
528
+ lines.push("\nRun /mcp-registry to browse and add more servers.");
528
529
  return { output: lines.join("\n"), handled: true };
529
530
  });
531
+ register("mcp-registry", "Browse and add MCP servers from the curated registry", (args) => {
532
+ const { searchRegistry, formatRegistry, generateConfigBlock, MCP_REGISTRY } = require('../mcp/registry.js');
533
+ const query = args.trim();
534
+ if (!query) {
535
+ // Show full registry
536
+ const output = `MCP Server Registry (${MCP_REGISTRY.length} servers)\n${'─'.repeat(50)}\n\n${formatRegistry()}\n\nUsage:\n /mcp-registry <name> Show install config for a server\n /mcp-registry <keyword> Search by name, description, or category`;
537
+ return { output, handled: true };
538
+ }
539
+ // Search or show specific server
540
+ const results = searchRegistry(query);
541
+ if (results.length === 0) {
542
+ return { output: `No MCP servers found matching "${query}".`, handled: true };
543
+ }
544
+ if (results.length === 1) {
545
+ // Show install instructions
546
+ const entry = results[0];
547
+ const config = generateConfigBlock(entry);
548
+ const envNote = entry.envVars?.length
549
+ ? `\n\nRequired environment variables:\n${entry.envVars.map((v) => ` - ${v}`).join('\n')}`
550
+ : '';
551
+ return {
552
+ output: `${entry.name} — ${entry.description}\nPackage: ${entry.package}\nRisk: ${entry.riskLevel ?? 'medium'}${envNote}\n\nAdd to .oh/config.yaml under mcpServers:\n\n${config}`,
553
+ handled: true,
554
+ };
555
+ }
556
+ // Multiple results
557
+ return { output: `Found ${results.length} servers:\n\n${formatRegistry(results)}`, handled: true };
558
+ });
530
559
  function setPinned(args, ctx, pinned) {
531
560
  const idx = parseInt(args.trim(), 10);
532
561
  if (isNaN(idx) || idx < 1 || idx > ctx.messages.length) {
@@ -25,6 +25,11 @@ export type ToolPermissionRule = {
25
25
  action: "allow" | "deny" | "ask";
26
26
  pattern?: string;
27
27
  };
28
+ export type VerificationRuleConfig = {
29
+ extensions: string[];
30
+ lint?: string;
31
+ timeout?: number;
32
+ };
28
33
  export type OhConfig = {
29
34
  provider: string;
30
35
  model: string;
@@ -36,6 +41,16 @@ export type OhConfig = {
36
41
  hooks?: HooksConfig;
37
42
  toolPermissions?: ToolPermissionRule[];
38
43
  statusLineFormat?: string;
44
+ /** Verification loops — auto-run lint/typecheck after file edits */
45
+ verification?: {
46
+ enabled?: boolean;
47
+ mode?: 'warn' | 'block';
48
+ rules?: VerificationRuleConfig[];
49
+ };
50
+ /** Memory consolidation settings */
51
+ memory?: {
52
+ consolidateOnExit?: boolean;
53
+ };
39
54
  };
40
55
  /** Clear cached config (call after writes or to force re-read) */
41
56
  export declare function invalidateConfigCache(): void;