@zhijiewang/openharness 0.9.3 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/README.md +87 -24
  2. package/dist/Tool.d.ts.map +1 -1
  3. package/dist/Tool.js +7 -1
  4. package/dist/Tool.js.map +1 -1
  5. package/dist/Tool.test.js +8 -2
  6. package/dist/Tool.test.js.map +1 -1
  7. package/dist/agents/roles.d.ts +25 -0
  8. package/dist/agents/roles.d.ts.map +1 -0
  9. package/dist/agents/roles.js +116 -0
  10. package/dist/agents/roles.js.map +1 -0
  11. package/dist/agents/roles.test.d.ts +2 -0
  12. package/dist/agents/roles.test.d.ts.map +1 -0
  13. package/dist/agents/roles.test.js +38 -0
  14. package/dist/agents/roles.test.js.map +1 -0
  15. package/dist/commands/commands-new.test.d.ts +5 -0
  16. package/dist/commands/commands-new.test.d.ts.map +1 -0
  17. package/dist/commands/commands-new.test.js +132 -0
  18. package/dist/commands/commands-new.test.js.map +1 -0
  19. package/dist/commands/commands.test.js +31 -0
  20. package/dist/commands/commands.test.js.map +1 -1
  21. package/dist/commands/index.d.ts +2 -0
  22. package/dist/commands/index.d.ts.map +1 -1
  23. package/dist/commands/index.js +199 -6
  24. package/dist/commands/index.js.map +1 -1
  25. package/dist/components/REPL.js +1 -1
  26. package/dist/components/REPL.js.map +1 -1
  27. package/dist/git/git.test.js +33 -1
  28. package/dist/git/git.test.js.map +1 -1
  29. package/dist/git/index.d.ts +12 -0
  30. package/dist/git/index.d.ts.map +1 -1
  31. package/dist/git/index.js +47 -2
  32. package/dist/git/index.js.map +1 -1
  33. package/dist/harness/checkpoints.d.ts +36 -0
  34. package/dist/harness/checkpoints.d.ts.map +1 -0
  35. package/dist/harness/checkpoints.js +156 -0
  36. package/dist/harness/checkpoints.js.map +1 -0
  37. package/dist/harness/config.d.ts +3 -0
  38. package/dist/harness/config.d.ts.map +1 -1
  39. package/dist/harness/config.js +35 -2
  40. package/dist/harness/config.js.map +1 -1
  41. package/dist/harness/config.test.js +21 -1
  42. package/dist/harness/config.test.js.map +1 -1
  43. package/dist/harness/hooks-env.test.d.ts +5 -0
  44. package/dist/harness/hooks-env.test.d.ts.map +1 -0
  45. package/dist/harness/hooks-env.test.js +41 -0
  46. package/dist/harness/hooks-env.test.js.map +1 -0
  47. package/dist/harness/hooks.d.ts +7 -0
  48. package/dist/harness/hooks.d.ts.map +1 -1
  49. package/dist/harness/hooks.js +14 -0
  50. package/dist/harness/hooks.js.map +1 -1
  51. package/dist/harness/keybindings.d.ts.map +1 -1
  52. package/dist/harness/keybindings.js +4 -0
  53. package/dist/harness/keybindings.js.map +1 -1
  54. package/dist/harness/memory.d.ts +19 -0
  55. package/dist/harness/memory.d.ts.map +1 -1
  56. package/dist/harness/memory.js +85 -0
  57. package/dist/harness/memory.js.map +1 -1
  58. package/dist/harness/onboarding.d.ts +1 -1
  59. package/dist/harness/onboarding.d.ts.map +1 -1
  60. package/dist/harness/onboarding.js +59 -4
  61. package/dist/harness/onboarding.js.map +1 -1
  62. package/dist/harness/onboarding.test.d.ts +5 -0
  63. package/dist/harness/onboarding.test.d.ts.map +1 -0
  64. package/dist/harness/onboarding.test.js +93 -0
  65. package/dist/harness/onboarding.test.js.map +1 -0
  66. package/dist/harness/rules.d.ts +6 -1
  67. package/dist/harness/rules.d.ts.map +1 -1
  68. package/dist/harness/rules.js +52 -5
  69. package/dist/harness/rules.js.map +1 -1
  70. package/dist/harness/rules.test.js +30 -1
  71. package/dist/harness/rules.test.js.map +1 -1
  72. package/dist/harness/session.d.ts +8 -1
  73. package/dist/harness/session.d.ts.map +1 -1
  74. package/dist/harness/session.js +13 -5
  75. package/dist/harness/session.js.map +1 -1
  76. package/dist/harness/store.d.ts +46 -0
  77. package/dist/harness/store.d.ts.map +1 -0
  78. package/dist/harness/store.js +56 -0
  79. package/dist/harness/store.js.map +1 -0
  80. package/dist/harness/store.test.d.ts +2 -0
  81. package/dist/harness/store.test.d.ts.map +1 -0
  82. package/dist/harness/store.test.js +71 -0
  83. package/dist/harness/store.test.js.map +1 -0
  84. package/dist/harness/submit-handler.d.ts +2 -0
  85. package/dist/harness/submit-handler.d.ts.map +1 -1
  86. package/dist/harness/submit-handler.js +3 -0
  87. package/dist/harness/submit-handler.js.map +1 -1
  88. package/dist/main.js +153 -26
  89. package/dist/main.js.map +1 -1
  90. package/dist/mcp/client.d.ts +2 -0
  91. package/dist/mcp/client.d.ts.map +1 -1
  92. package/dist/mcp/client.js +10 -2
  93. package/dist/mcp/client.js.map +1 -1
  94. package/dist/mcp/loader.d.ts +2 -0
  95. package/dist/mcp/loader.d.ts.map +1 -1
  96. package/dist/mcp/loader.js +34 -18
  97. package/dist/mcp/loader.js.map +1 -1
  98. package/dist/mcp/loader.test.d.ts +7 -0
  99. package/dist/mcp/loader.test.d.ts.map +1 -0
  100. package/dist/mcp/loader.test.js +25 -0
  101. package/dist/mcp/loader.test.js.map +1 -0
  102. package/dist/providers/anthropic-convert.test.d.ts +5 -0
  103. package/dist/providers/anthropic-convert.test.d.ts.map +1 -0
  104. package/dist/providers/anthropic-convert.test.js +98 -0
  105. package/dist/providers/anthropic-convert.test.js.map +1 -0
  106. package/dist/providers/anthropic.d.ts.map +1 -1
  107. package/dist/providers/anthropic.js +23 -4
  108. package/dist/providers/anthropic.js.map +1 -1
  109. package/dist/providers/stream-parsing.test.d.ts +6 -0
  110. package/dist/providers/stream-parsing.test.d.ts.map +1 -0
  111. package/dist/providers/stream-parsing.test.js +174 -0
  112. package/dist/providers/stream-parsing.test.js.map +1 -0
  113. package/dist/query/compress.d.ts +17 -0
  114. package/dist/query/compress.d.ts.map +1 -0
  115. package/dist/query/compress.js +115 -0
  116. package/dist/query/compress.js.map +1 -0
  117. package/dist/query/errors.d.ts +10 -0
  118. package/dist/query/errors.d.ts.map +1 -0
  119. package/dist/query/errors.js +22 -0
  120. package/dist/query/errors.js.map +1 -0
  121. package/dist/query/index.d.ts +15 -0
  122. package/dist/query/index.d.ts.map +1 -0
  123. package/dist/query/index.js +199 -0
  124. package/dist/query/index.js.map +1 -0
  125. package/dist/query/tools.d.ts +17 -0
  126. package/dist/query/tools.d.ts.map +1 -0
  127. package/dist/query/tools.js +129 -0
  128. package/dist/query/tools.js.map +1 -0
  129. package/dist/query/types.d.ts +31 -0
  130. package/dist/query/types.d.ts.map +1 -0
  131. package/dist/query/types.js +5 -0
  132. package/dist/query/types.js.map +1 -0
  133. package/dist/query.d.ts +8 -38
  134. package/dist/query.d.ts.map +1 -1
  135. package/dist/query.js +7 -444
  136. package/dist/query.js.map +1 -1
  137. package/dist/query.test.js +1 -1
  138. package/dist/query.test.js.map +1 -1
  139. package/dist/renderer/cells.d.ts.map +1 -1
  140. package/dist/renderer/cells.js +15 -2
  141. package/dist/renderer/cells.js.map +1 -1
  142. package/dist/renderer/colors.d.ts +8 -0
  143. package/dist/renderer/colors.d.ts.map +1 -0
  144. package/dist/renderer/colors.js +18 -0
  145. package/dist/renderer/colors.js.map +1 -0
  146. package/dist/renderer/diff.test.d.ts +5 -0
  147. package/dist/renderer/diff.test.d.ts.map +1 -0
  148. package/dist/renderer/diff.test.js +140 -0
  149. package/dist/renderer/diff.test.js.map +1 -0
  150. package/dist/renderer/differ.d.ts +1 -5
  151. package/dist/renderer/differ.d.ts.map +1 -1
  152. package/dist/renderer/differ.js +3 -20
  153. package/dist/renderer/differ.js.map +1 -1
  154. package/dist/renderer/e2e.test.js +136 -53
  155. package/dist/renderer/e2e.test.js.map +1 -1
  156. package/dist/renderer/image.test.d.ts +5 -0
  157. package/dist/renderer/image.test.d.ts.map +1 -0
  158. package/dist/renderer/image.test.js +66 -0
  159. package/dist/renderer/image.test.js.map +1 -0
  160. package/dist/renderer/index.d.ts +28 -16
  161. package/dist/renderer/index.d.ts.map +1 -1
  162. package/dist/renderer/index.js +289 -222
  163. package/dist/renderer/index.js.map +1 -1
  164. package/dist/renderer/layout.d.ts +14 -5
  165. package/dist/renderer/layout.d.ts.map +1 -1
  166. package/dist/renderer/layout.js +522 -388
  167. package/dist/renderer/layout.js.map +1 -1
  168. package/dist/renderer/markdown.d.ts.map +1 -1
  169. package/dist/renderer/markdown.js +42 -36
  170. package/dist/renderer/markdown.js.map +1 -1
  171. package/dist/renderer/perf.test.js +1 -4
  172. package/dist/renderer/perf.test.js.map +1 -1
  173. package/dist/renderer/session-browser.test.d.ts +6 -0
  174. package/dist/renderer/session-browser.test.d.ts.map +1 -0
  175. package/dist/renderer/session-browser.test.js +95 -0
  176. package/dist/renderer/session-browser.test.js.map +1 -0
  177. package/dist/renderer/ui-ux.test.d.ts +15 -0
  178. package/dist/renderer/ui-ux.test.d.ts.map +1 -0
  179. package/dist/renderer/ui-ux.test.js +470 -0
  180. package/dist/renderer/ui-ux.test.js.map +1 -0
  181. package/dist/repl.d.ts.map +1 -1
  182. package/dist/repl.js +192 -67
  183. package/dist/repl.js.map +1 -1
  184. package/dist/services/StreamingToolExecutor.d.ts.map +1 -1
  185. package/dist/services/StreamingToolExecutor.js +4 -2
  186. package/dist/services/StreamingToolExecutor.js.map +1 -1
  187. package/dist/services/agent-messaging.d.ts +68 -0
  188. package/dist/services/agent-messaging.d.ts.map +1 -0
  189. package/dist/services/agent-messaging.js +121 -0
  190. package/dist/services/agent-messaging.js.map +1 -0
  191. package/dist/services/agent-messaging.test.d.ts +2 -0
  192. package/dist/services/agent-messaging.test.d.ts.map +1 -0
  193. package/dist/services/agent-messaging.test.js +88 -0
  194. package/dist/services/agent-messaging.test.js.map +1 -0
  195. package/dist/services/cron.d.ts +40 -0
  196. package/dist/services/cron.d.ts.map +1 -0
  197. package/dist/services/cron.js +90 -0
  198. package/dist/services/cron.js.map +1 -0
  199. package/dist/services/cron.test.d.ts +2 -0
  200. package/dist/services/cron.test.d.ts.map +1 -0
  201. package/dist/services/cron.test.js +49 -0
  202. package/dist/services/cron.test.js.map +1 -0
  203. package/dist/tools/AgentTool/index.d.ts +9 -0
  204. package/dist/tools/AgentTool/index.d.ts.map +1 -1
  205. package/dist/tools/AgentTool/index.js +89 -6
  206. package/dist/tools/AgentTool/index.js.map +1 -1
  207. package/dist/tools/BashTool/index.d.ts +6 -0
  208. package/dist/tools/BashTool/index.d.ts.map +1 -1
  209. package/dist/tools/BashTool/index.js +39 -1
  210. package/dist/tools/BashTool/index.js.map +1 -1
  211. package/dist/tools/FileEditTool/index.js +4 -4
  212. package/dist/tools/FileEditTool/index.js.map +1 -1
  213. package/dist/tools/FileReadTool/index.d.ts +3 -0
  214. package/dist/tools/FileReadTool/index.d.ts.map +1 -1
  215. package/dist/tools/FileReadTool/index.js +102 -4
  216. package/dist/tools/FileReadTool/index.js.map +1 -1
  217. package/dist/tools/FileWriteTool/index.d.ts.map +1 -1
  218. package/dist/tools/FileWriteTool/index.js +20 -5
  219. package/dist/tools/FileWriteTool/index.js.map +1 -1
  220. package/dist/tools/GlobTool/index.d.ts.map +1 -1
  221. package/dist/tools/GlobTool/index.js +4 -61
  222. package/dist/tools/GlobTool/index.js.map +1 -1
  223. package/dist/tools/GrepTool/index.d.ts +30 -0
  224. package/dist/tools/GrepTool/index.d.ts.map +1 -1
  225. package/dist/tools/GrepTool/index.js +153 -72
  226. package/dist/tools/GrepTool/index.js.map +1 -1
  227. package/dist/tools/LSTool/index.d.ts +3 -0
  228. package/dist/tools/LSTool/index.d.ts.map +1 -1
  229. package/dist/tools/LSTool/index.js +44 -29
  230. package/dist/tools/LSTool/index.js.map +1 -1
  231. package/dist/tools/TaskCreateTool/index.d.ts +6 -0
  232. package/dist/tools/TaskCreateTool/index.d.ts.map +1 -1
  233. package/dist/tools/TaskCreateTool/index.js +8 -2
  234. package/dist/tools/TaskCreateTool/index.js.map +1 -1
  235. package/dist/tools/TaskGetTool/index.d.ts +12 -0
  236. package/dist/tools/TaskGetTool/index.d.ts.map +1 -0
  237. package/dist/tools/TaskGetTool/index.js +50 -0
  238. package/dist/tools/TaskGetTool/index.js.map +1 -0
  239. package/dist/tools/TaskOutputTool/index.d.ts +15 -0
  240. package/dist/tools/TaskOutputTool/index.d.ts.map +1 -0
  241. package/dist/tools/TaskOutputTool/index.js +45 -0
  242. package/dist/tools/TaskOutputTool/index.js.map +1 -0
  243. package/dist/tools/TaskStopTool/index.d.ts +15 -0
  244. package/dist/tools/TaskStopTool/index.d.ts.map +1 -0
  245. package/dist/tools/TaskStopTool/index.js +51 -0
  246. package/dist/tools/TaskStopTool/index.js.map +1 -0
  247. package/dist/tools/TaskUpdateTool/index.d.ts +21 -3
  248. package/dist/tools/TaskUpdateTool/index.d.ts.map +1 -1
  249. package/dist/tools/TaskUpdateTool/index.js +48 -3
  250. package/dist/tools/TaskUpdateTool/index.js.map +1 -1
  251. package/dist/tools/tools-basic.test.js +191 -2
  252. package/dist/tools/tools-basic.test.js.map +1 -1
  253. package/dist/tools.d.ts.map +1 -1
  254. package/dist/tools.js +6 -0
  255. package/dist/tools.js.map +1 -1
  256. package/dist/types/permissions.d.ts +2 -2
  257. package/dist/types/permissions.d.ts.map +1 -1
  258. package/dist/types/permissions.js +59 -13
  259. package/dist/types/permissions.js.map +1 -1
  260. package/dist/types/permissions.test.js +57 -0
  261. package/dist/types/permissions.test.js.map +1 -1
  262. package/dist/utils/bash-safety.d.ts +18 -0
  263. package/dist/utils/bash-safety.d.ts.map +1 -0
  264. package/dist/utils/bash-safety.js +227 -0
  265. package/dist/utils/bash-safety.js.map +1 -0
  266. package/dist/utils/bash-safety.test.d.ts +2 -0
  267. package/dist/utils/bash-safety.test.d.ts.map +1 -0
  268. package/dist/utils/bash-safety.test.js +112 -0
  269. package/dist/utils/bash-safety.test.js.map +1 -0
  270. package/dist/utils/fs.d.ts +15 -0
  271. package/dist/utils/fs.d.ts.map +1 -0
  272. package/dist/utils/fs.js +64 -0
  273. package/dist/utils/fs.js.map +1 -0
  274. package/dist/utils/fs.test.d.ts +5 -0
  275. package/dist/utils/fs.test.d.ts.map +1 -0
  276. package/dist/utils/fs.test.js +82 -0
  277. package/dist/utils/fs.test.js.map +1 -0
  278. package/dist/utils/safe-env.d.ts +10 -0
  279. package/dist/utils/safe-env.d.ts.map +1 -0
  280. package/dist/utils/safe-env.js +40 -0
  281. package/dist/utils/safe-env.js.map +1 -0
  282. package/package.json +3 -1
package/README.md CHANGED
@@ -49,36 +49,42 @@ Most AI coding agents are locked to one provider or cost $20+/month. OpenHarness
49
49
  |---|---|---|---|---|
50
50
  | Any LLM | Yes (Ollama, OpenAI, Anthropic, OpenRouter, any OpenAI-compatible) | Anthropic only | Yes | Yes |
51
51
  | Free local models | Ollama native | No | Yes | Yes |
52
- | Tools | 18 with permission gates | 40+ | File-focused | 20+ |
53
- | Git integration | Auto-commit + /undo | Yes | Deep git | Basic |
54
- | Slash commands | 19 built-in | 80+ | Some | Some |
55
- | Headless/CI mode | `oh run --json` | Yes | Yes | Yes |
56
- | Terminal UI | Custom cell-level renderer + React/Ink | React + Ink | Basic | BubbleTea |
52
+ | Tools | 25 with permission gates | 43+ | File-focused | 20+ |
53
+ | Permission modes | 7 (ask, trust, deny, acceptEdits, plan, auto, bypass) | 7 | Basic | Basic |
54
+ | Git integration | Auto-commit + /undo + /rewind checkpoints | Yes | Deep git | Basic |
55
+ | Slash commands | 30+ built-in | 80+ | Some | Some |
56
+ | Headless/CI mode | `oh -p "prompt"` or `oh run --json` | Yes | Yes | Yes |
57
+ | GitHub Action | Built-in PR review action | Yes | No | No |
58
+ | Agent roles | 6 specializations (reviewer, tester, debugger...) | Yes | No | No |
59
+ | Vim mode | hjkl, w/b/e, 0/$, x, d, i/a/I/A/o | Full vim | No | No |
60
+ | Prompt caching | Anthropic cache_control | Yes | No | No |
61
+ | Bash security | AST-based command analysis | AST analysis | No | No |
62
+ | Companion | Cybergotchi virtual pet | Basic | No | No |
63
+ | Terminal UI | Sequential renderer (Ink pattern) | React + Ink | Basic | BubbleTea |
57
64
  | Language | TypeScript | TypeScript | Python | Go |
58
65
  | License | MIT | Proprietary | Apache 2.0 | MIT |
59
66
  | Price | Free (BYOK) | $20+/month | Free (BYOK) | Free (BYOK) |
60
67
 
61
68
  ## Terminal UI
62
69
 
63
- OpenHarness features a custom cell-level diffing renderer built for performance and rich display.
70
+ OpenHarness features a sequential terminal renderer inspired by Ink/Claude Code's default mode. Completed messages flush to native scrollback (scrollable), while the live area (streaming, spinner, input) rewrites in-place using relative cursor movement.
64
71
 
65
72
  ### Keybindings
66
73
 
67
74
  | Key | Action |
68
75
  |-----|--------|
69
76
  | `Enter` | Submit prompt |
77
+ | `Alt+Enter` | Insert newline (multi-line input) |
70
78
  | `↑` / `↓` | Navigate input history |
71
79
  | `Ctrl+C` | Cancel current request / exit |
72
80
  | `Ctrl+A` / `Ctrl+E` | Jump to start / end of input |
73
- | `Ctrl+F` | Search through conversation (Enter to cycle matches, Esc to close) |
74
81
  | `Ctrl+O` | Toggle thinking block expansion |
75
82
  | `Ctrl+K` | Toggle code block expansion in messages |
76
- | `Page Up` / `Page Down` | Scroll message history (10 rows) |
77
- | `Shift+↑` / `Shift+↓` | Scroll message history (3 rows) |
78
- | `Mouse scroll` | Scroll message history (3 rows per tick) |
79
- | `Tab` | Autocomplete slash commands / cycle tool call outputs |
83
+ | `Tab` | Autocomplete slash commands / file paths / cycle tool outputs |
80
84
  | `/vim` | Toggle Vim mode (normal/insert) |
81
85
 
86
+ Scrolling is handled by the terminal's native scrollbar. Completed messages flow into the terminal scrollback buffer. Use your terminal's search (e.g., `Ctrl+Shift+F` in VS Code) to search conversation history.
87
+
82
88
  ### Features
83
89
 
84
90
  - **Markdown rendering** — headings, code blocks, bold, italic, lists, tables, blockquotes, links
@@ -88,15 +94,13 @@ OpenHarness features a custom cell-level diffing renderer built for performance
88
94
  - **Shimmer spinner** — animated "Thinking" indicator with color transitions (magenta → yellow at 30s → red at 60s)
89
95
  - **Tool call display** — args preview, live streaming output, result summaries (line counts, elapsed time), expand/collapse with `Tab`
90
96
  - **Permission prompts** — bordered box with risk coloring, bold colored **Y**es/**N**o/**D**iff keys, syntax-highlighted inline diffs
91
- - **Search mode** — `Ctrl+F` to search conversation with live match count and navigation
92
97
  - **Status line** — model name, token count, cost, context usage bar (customizable via config)
93
98
  - **Context warning** — yellow alert when context window exceeds 75%
94
- - **Scroll indicator** — footer shows `↑ N more above` / `↓ N more below` when content overflows
95
- - **Scrollback** — Page Up/Down, Shift+arrows, or mouse scroll wheel to navigate history
96
- - **Mouse support** — scroll wheel for messages, auto-enabled via SGR mouse tracking
97
- - **Autocomplete** — slash commands with descriptions shown in popup; Tab to cycle
99
+ - **Native terminal scrollbar** — completed messages flow into scrollback; use your terminal's scrollbar and search
100
+ - **Multi-line input** — `Alt+Enter` for newlines; paste detection auto-inserts newlines
101
+ - **Autocomplete** — slash commands and file paths with descriptions; Tab to cycle
102
+ - **File path autocomplete** — Tab-completes paths with `[dir]`/`[file]` indicators
98
103
  - **Session browser** — `/browse` to interactively browse and resume past sessions
99
- - **Alternate screen buffer** — preserves terminal scrollback; clean restore on exit
100
104
  - **Companion mascot** — animated Cybergotchi in the footer (toggle with `/companion off|on`)
101
105
 
102
106
  ### Themes
@@ -119,7 +123,7 @@ statusLineFormat: '{model} │ {tokens} │ {cost} │ {ctx}'
119
123
 
120
124
  Available variables: `{model}`, `{tokens}` (input↑ output↓), `{cost}` ($X.XXXX), `{ctx}` (context usage bar). Empty sections are automatically collapsed.
121
125
 
122
- ## Tools (18)
126
+ ## Tools (25)
123
127
 
124
128
  | Tool | Risk | Description |
125
129
  |------|------|-------------|
@@ -145,7 +149,7 @@ Available variables: `{model}`, `{tokens}` (input↑ output↓), `{cost}` ($X.XX
145
149
 
146
150
  Low-risk read-only tools auto-approve. Medium and high risk tools require confirmation in `ask` mode. Use `--trust` to skip all prompts.
147
151
 
148
- ## Slash Commands (19)
152
+ ## Slash Commands (30+)
149
153
 
150
154
  Type these during a chat session. Aliases: `/q` exit, `/h` help, `/c` commit, `/m` model, `/s` status.
151
155
 
@@ -208,6 +212,10 @@ Control how aggressively OpenHarness auto-approves tool calls:
208
212
  | `deny` | `--deny` | Only allow low-risk read-only operations |
209
213
  | `acceptEdits` | `--permission-mode acceptEdits` | Auto-approve file edits, ask for Bash/WebFetch/Agent |
210
214
  | `plan` | `--permission-mode plan` | Read-only mode — block all write operations |
215
+ | `auto` | `--auto` | Auto-approve all, block dangerous bash (AST-analyzed) |
216
+ | `bypassPermissions` | `--permission-mode bypassPermissions` | Approve everything unconditionally (CI only) |
217
+
218
+ Bash commands are analyzed by a lightweight AST parser that detects destructive patterns (`rm -rf`, `git push --force`, `curl | bash`, etc.) and adjusts risk level accordingly.
211
219
 
212
220
  Set permanently in `.oh/config.yaml`: `permissionMode: 'acceptEdits'`
213
221
 
@@ -311,20 +319,75 @@ oh: Write tests/app.test.ts
311
319
  - `/diff` shows what changed
312
320
  - Your dirty files are safe — committed separately before AI edits
313
321
 
322
+ ## Checkpoints & Rewind
323
+
324
+ Every file modification is automatically checkpointed before execution. If something goes wrong:
325
+
326
+ ```
327
+ /rewind # restore files from the last checkpoint
328
+ /undo # revert the last AI git commit
329
+ ```
330
+
331
+ Checkpoints are stored in `.oh/checkpoints/` and cover FileWrite, FileEdit, and Bash commands that modify files.
332
+
333
+ ## Agent Roles
334
+
335
+ Dispatch specialized sub-agents for focused tasks:
336
+
337
+ ```
338
+ /roles # list all available roles
339
+ ```
340
+
341
+ | Role | Description |
342
+ |------|-------------|
343
+ | `code-reviewer` | Find bugs, security issues, style problems |
344
+ | `test-writer` | Generate unit and integration tests |
345
+ | `docs-writer` | Write documentation and comments |
346
+ | `debugger` | Systematic bug investigation |
347
+ | `refactorer` | Simplify code without changing behavior |
348
+ | `security-auditor` | OWASP, injection, secrets, CVE scanning |
349
+
350
+ The LLM can dispatch these via `Agent({ subagent_type: 'code-reviewer', prompt: '...' })`.
351
+
314
352
  ## Headless Mode
315
353
 
316
- Run a single prompt without interactive UI — perfect for CI/CD:
354
+ Run a single prompt without interactive UI — perfect for CI/CD and scripting:
317
355
 
318
356
  ```bash
357
+ # Chat command with -p flag (recommended)
358
+ oh -p "fix the failing tests" --model ollama/llama3 --trust
359
+ oh -p "review src/query.ts" --auto --output-format json
360
+
361
+ # Run command (alternative)
319
362
  oh run "fix the failing tests" --model ollama/llama3 --trust
320
363
  oh run "add error handling to api.ts" --json # JSON output
321
- oh run "explain this codebase" --model gpt-4o
322
364
 
323
- # Pipe stdin — prompt from stdin, or prepend context
365
+ # Pipe stdin
324
366
  cat error.log | oh run "what's wrong here?"
325
367
  git diff | oh run "review these changes"
326
- oh run - < prompt.txt # read full prompt from file
327
- oh run "fix this:" < broken.py # prepend arg, append stdin
368
+ ```
369
+
370
+ ### GitHub Action for PR Review
371
+
372
+ OpenHarness includes a built-in GitHub Action for automated code review:
373
+
374
+ ```yaml
375
+ # .github/workflows/ai-review.yml
376
+ on:
377
+ pull_request:
378
+ types: [opened, synchronize]
379
+
380
+ jobs:
381
+ review:
382
+ runs-on: ubuntu-latest
383
+ steps:
384
+ - uses: actions/checkout@v4
385
+ with:
386
+ fetch-depth: 0
387
+ - uses: ./.github/actions/review
388
+ with:
389
+ model: 'claude-sonnet-4-6'
390
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
328
391
  ```
329
392
 
330
393
  Exit code 0 on success, 1 on failure.
@@ -1 +1 @@
1
- {"version":3,"file":"Tool.d.ts","sourceRoot":"","sources":["../src/Tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,gDAAgD;IAChD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,iEAAiE;IACjE,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7E,CAAC;AAEF,MAAM,MAAM,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAE9B,8DAA8D;IAC9D,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;IAE3C,8DAA8D;IAC9D,iBAAiB,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;IAElD,wBAAwB;IACxB,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvE,mDAAmD;IACnD,MAAM,IAAI,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;AAE3B;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG;IAC3C,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;CACtE,CASA;AA4CD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAE3E"}
1
+ {"version":3,"file":"Tool.d.ts","sourceRoot":"","sources":["../src/Tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,gDAAgD;IAChD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,iEAAiE;IACjE,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7E,CAAC;AAEF,MAAM,MAAM,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAE9B,8DAA8D;IAC9D,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;IAE3C,8DAA8D;IAC9D,iBAAiB,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;IAElD,wBAAwB;IACxB,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvE,mDAAmD;IACnD,MAAM,IAAI,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;AAE3B;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG;IAC3C,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;CACtE,CASA;AA4CD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAO3E"}
package/dist/Tool.js CHANGED
@@ -57,6 +57,12 @@ function zodToJsonSchema(schema) {
57
57
  * Find a tool by name from a list of tools.
58
58
  */
59
59
  export function findToolByName(tools, name) {
60
- return tools.find((t) => t.name === name);
60
+ // Exact match first
61
+ const exact = tools.find((t) => t.name === name);
62
+ if (exact)
63
+ return exact;
64
+ // Case-insensitive fallback
65
+ const lower = name.toLowerCase();
66
+ return tools.find((t) => t.name.toLowerCase() === lower);
61
67
  }
62
68
  //# sourceMappingURL=Tool.js.map
package/dist/Tool.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Tool.js","sourceRoot":"","sources":["../src/Tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgDH;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAU;IAIxC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE;YAC1B,UAAU,EAAE,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC;SAC9C;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,MAAiB;IACxC,wDAAwD;IACxD,MAAM,GAAG,GAAI,MAAc,CAAC,IAAI,CAAC;IAEjC,IAAI,GAAG,EAAE,QAAQ,KAAK,WAAW,EAAE,CAAC;QAClC,MAAM,KAAK,GAAI,MAA2B,CAAC,KAAK,CAAC;QACjD,MAAM,UAAU,GAA4B,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,KAAkB,CAAC;YACjC,MAAM,QAAQ,GAAI,KAAa,CAAC,IAAI,CAAC;YAErC,IAAI,QAAQ,EAAE,QAAQ,KAAK,aAAa,EAAE,CAAC;gBACzC,UAAU,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;gBACzC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC;YAED,6BAA6B;YAC7B,IAAK,KAAa,CAAC,WAAW,EAAE,CAAC;gBAC9B,UAAU,CAAC,GAAG,CAAS,CAAC,WAAW,GAAI,KAAa,CAAC,WAAW,CAAC;YACpE,CAAC;QACH,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,GAAG,EAAE,QAAQ,KAAK,WAAW;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC7D,IAAI,GAAG,EAAE,QAAQ,KAAK,WAAW;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC7D,IAAI,GAAG,EAAE,QAAQ,KAAK,YAAY;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC/D,IAAI,GAAG,EAAE,QAAQ,KAAK,UAAU;QAC9B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;IAE7D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,WAAW;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAY,EAAE,IAAY;IACvD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"Tool.js","sourceRoot":"","sources":["../src/Tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgDH;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAU;IAIxC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE;YAC1B,UAAU,EAAE,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC;SAC9C;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,MAAiB;IACxC,wDAAwD;IACxD,MAAM,GAAG,GAAI,MAAc,CAAC,IAAI,CAAC;IAEjC,IAAI,GAAG,EAAE,QAAQ,KAAK,WAAW,EAAE,CAAC;QAClC,MAAM,KAAK,GAAI,MAA2B,CAAC,KAAK,CAAC;QACjD,MAAM,UAAU,GAA4B,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,KAAkB,CAAC;YACjC,MAAM,QAAQ,GAAI,KAAa,CAAC,IAAI,CAAC;YAErC,IAAI,QAAQ,EAAE,QAAQ,KAAK,aAAa,EAAE,CAAC;gBACzC,UAAU,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;gBACzC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC;YAED,6BAA6B;YAC7B,IAAK,KAAa,CAAC,WAAW,EAAE,CAAC;gBAC9B,UAAU,CAAC,GAAG,CAAS,CAAC,WAAW,GAAI,KAAa,CAAC,WAAW,CAAC;YACpE,CAAC;QACH,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,GAAG,EAAE,QAAQ,KAAK,WAAW;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC7D,IAAI,GAAG,EAAE,QAAQ,KAAK,WAAW;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC7D,IAAI,GAAG,EAAE,QAAQ,KAAK,YAAY;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC/D,IAAI,GAAG,EAAE,QAAQ,KAAK,UAAU;QAC9B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;IAE7D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,WAAW;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAY,EAAE,IAAY;IACvD,oBAAoB;IACpB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACjD,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,4BAA4B;IAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC;AAC3D,CAAC"}
package/dist/Tool.test.js CHANGED
@@ -34,9 +34,15 @@ describe('findToolByName', () => {
34
34
  const found = findToolByName(tools, 'NonExistent');
35
35
  assert.equal(found, undefined);
36
36
  });
37
- it('is case-sensitive', () => {
37
+ it('falls back to case-insensitive match', () => {
38
38
  const found = findToolByName(tools, 'bash');
39
- assert.equal(found, undefined);
39
+ assert.ok(found);
40
+ assert.equal(found.name, 'Bash');
41
+ });
42
+ it('prefers exact match over case-insensitive', () => {
43
+ const found = findToolByName(tools, 'Bash');
44
+ assert.ok(found);
45
+ assert.equal(found.name, 'Bash');
40
46
  });
41
47
  });
42
48
  //# sourceMappingURL=Tool.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Tool.test.js","sourceRoot":"","sources":["../src/Tool.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;QACnF,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,UAA8B,CAAC;QACjE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,MAAM,KAAK,GAAG;QACZ,cAAc,CAAC,MAAM,CAAC;QACtB,cAAc,CAAC,MAAM,CAAC;QACtB,cAAc,CAAC,OAAO,CAAC;KACxB,CAAC;IAEF,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QACjB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"Tool.test.js","sourceRoot":"","sources":["../src/Tool.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;QACnF,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,UAA8B,CAAC;QACjE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,MAAM,KAAK,GAAG;QACZ,cAAc,CAAC,MAAM,CAAC;QACtB,cAAc,CAAC,MAAM,CAAC;QACtB,cAAc,CAAC,OAAO,CAAC;KACxB,CAAC;IAEF,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QACjB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QACjB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QACjB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Agent roles — pre-defined specializations for sub-agents.
3
+ *
4
+ * Each role has a name, description, and system prompt supplement
5
+ * that tunes the agent's behavior for a specific task type.
6
+ *
7
+ * Usage:
8
+ * const role = getRole('code-reviewer');
9
+ * const systemPrompt = basePrompt + '\n\n' + role.systemPromptSupplement;
10
+ */
11
+ export type AgentRole = {
12
+ id: string;
13
+ name: string;
14
+ description: string;
15
+ systemPromptSupplement: string;
16
+ /** Suggested tools to include (empty = all tools) */
17
+ suggestedTools?: string[];
18
+ };
19
+ /** Get a role by ID */
20
+ export declare function getRole(id: string): AgentRole | undefined;
21
+ /** List all available roles */
22
+ export declare function listRoles(): AgentRole[];
23
+ /** Get role IDs */
24
+ export declare function getRoleIds(): string[];
25
+ //# sourceMappingURL=roles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.d.ts","sourceRoot":"","sources":["../../src/agents/roles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAgGF,uBAAuB;AACvB,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAEzD;AAED,+BAA+B;AAC/B,wBAAgB,SAAS,IAAI,SAAS,EAAE,CAEvC;AAED,mBAAmB;AACnB,wBAAgB,UAAU,IAAI,MAAM,EAAE,CAErC"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Agent roles — pre-defined specializations for sub-agents.
3
+ *
4
+ * Each role has a name, description, and system prompt supplement
5
+ * that tunes the agent's behavior for a specific task type.
6
+ *
7
+ * Usage:
8
+ * const role = getRole('code-reviewer');
9
+ * const systemPrompt = basePrompt + '\n\n' + role.systemPromptSupplement;
10
+ */
11
+ const roles = [
12
+ {
13
+ id: 'code-reviewer',
14
+ name: 'Code Reviewer',
15
+ description: 'Reviews code for bugs, security issues, style, and correctness',
16
+ systemPromptSupplement: `You are a code reviewer. Your job is to:
17
+ - Find bugs, logic errors, and edge cases
18
+ - Identify security vulnerabilities (SQL injection, XSS, command injection, path traversal)
19
+ - Check for proper error handling and resource cleanup
20
+ - Flag code style issues and inconsistencies with the codebase
21
+ - Verify that changes match the stated intent
22
+
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'],
25
+ },
26
+ {
27
+ id: 'test-writer',
28
+ name: 'Test Writer',
29
+ description: 'Writes unit and integration tests for new or changed code',
30
+ systemPromptSupplement: `You are a test writer. Your job is to:
31
+ - Write comprehensive tests for the specified code
32
+ - Cover happy paths, edge cases, error conditions, and boundary values
33
+ - Follow the existing test patterns in the codebase (check test files for conventions)
34
+ - Use the project's test framework (check package.json for test dependencies)
35
+ - Ensure tests are deterministic and don't depend on external services
36
+ - Include both positive and negative test cases
37
+
38
+ Read existing tests first to match the style, then write new tests.`,
39
+ suggestedTools: ['FileRead', 'FileWrite', 'Glob', 'Grep', 'Bash'],
40
+ },
41
+ {
42
+ id: 'docs-writer',
43
+ name: 'Documentation Writer',
44
+ description: 'Writes and updates documentation, READMEs, and inline comments',
45
+ systemPromptSupplement: `You are a documentation writer. Your job is to:
46
+ - Write clear, concise documentation for code, APIs, and features
47
+ - Update READMEs when functionality changes
48
+ - Add JSDoc/TSDoc comments to public functions and types
49
+ - Create usage examples and code snippets
50
+ - Document configuration options, environment variables, and CLI flags
51
+ - Keep documentation in sync with the actual code
52
+
53
+ Write for the target audience (developers using this project). Be practical, not verbose.`,
54
+ suggestedTools: ['FileRead', 'FileWrite', 'FileEdit', 'Glob', 'Grep'],
55
+ },
56
+ {
57
+ id: 'debugger',
58
+ name: 'Debugger',
59
+ description: 'Investigates and diagnoses bugs by tracing data flow and reading logs',
60
+ systemPromptSupplement: `You are a debugger. Your job is to:
61
+ - Reproduce the reported issue by understanding the steps
62
+ - Trace data flow from the error backward to find the root cause
63
+ - Read error messages, stack traces, and logs carefully
64
+ - Check recent changes (git log, git diff) that might have introduced the issue
65
+ - Verify assumptions by reading the actual code, not guessing
66
+ - Propose a minimal fix that addresses the root cause, not the symptom
67
+
68
+ Follow systematic debugging: read errors → reproduce → check changes → trace data → form hypothesis → test minimally.`,
69
+ suggestedTools: ['FileRead', 'Glob', 'Grep', 'Bash', 'LS'],
70
+ },
71
+ {
72
+ id: 'refactorer',
73
+ name: 'Refactorer',
74
+ description: 'Restructures and simplifies code while preserving behavior',
75
+ systemPromptSupplement: `You are a code refactorer. Your job is to:
76
+ - Simplify complex code without changing behavior
77
+ - Extract common patterns into reusable functions
78
+ - Reduce duplication (DRY principle)
79
+ - Improve naming for clarity
80
+ - Break large functions/files into focused modules
81
+ - Ensure all existing tests still pass after refactoring
82
+
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'],
85
+ },
86
+ {
87
+ id: 'security-auditor',
88
+ name: 'Security Auditor',
89
+ description: 'Audits code for security vulnerabilities and compliance issues',
90
+ systemPromptSupplement: `You are a security auditor. Your job is to:
91
+ - Scan for OWASP Top 10 vulnerabilities
92
+ - Check for command injection in shell execution
93
+ - Verify input validation at system boundaries
94
+ - Check for hardcoded secrets, API keys, or credentials
95
+ - Review authentication and authorization logic
96
+ - Check for insecure defaults (permissions, CORS, cookies)
97
+ - Verify proper use of cryptographic functions
98
+ - Check dependency versions for known CVEs
99
+
100
+ Report findings with severity (Critical/High/Medium/Low), affected file:line, and recommended fix.`,
101
+ suggestedTools: ['FileRead', 'Glob', 'Grep', 'Bash'],
102
+ },
103
+ ];
104
+ /** Get a role by ID */
105
+ export function getRole(id) {
106
+ return roles.find(r => r.id === id);
107
+ }
108
+ /** List all available roles */
109
+ export function listRoles() {
110
+ return [...roles];
111
+ }
112
+ /** Get role IDs */
113
+ export function getRoleIds() {
114
+ return roles.map(r => r.id);
115
+ }
116
+ //# sourceMappingURL=roles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.js","sourceRoot":"","sources":["../../src/agents/roles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,MAAM,KAAK,GAAgB;IACzB;QACE,EAAE,EAAE,eAAe;QACnB,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,gEAAgE;QAC7E,sBAAsB,EAAE;;;;;;;kLAOsJ;QAC9K,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC;KACnD;IACD;QACE,EAAE,EAAE,aAAa;QACjB,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,2DAA2D;QACxE,sBAAsB,EAAE;;;;;;;;oEAQwC;QAChE,cAAc,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAClE;IACD;QACE,EAAE,EAAE,aAAa;QACjB,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,gEAAgE;QAC7E,sBAAsB,EAAE;;;;;;;;0FAQ8D;QACtF,cAAc,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC;KACtE;IACD;QACE,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,uEAAuE;QACpF,sBAAsB,EAAE;;;;;;;;sHAQ0F;QAClH,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC;KAC3D;IACD;QACE,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,4DAA4D;QACzE,sBAAsB,EAAE;;;;;;;;6HAQiG;QACzH,cAAc,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAC9E;IACD;QACE,EAAE,EAAE,kBAAkB;QACtB,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,gEAAgE;QAC7E,sBAAsB,EAAE;;;;;;;;;;mGAUuE;QAC/F,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KACrD;CACF,CAAC;AAEF,uBAAuB;AACvB,MAAM,UAAU,OAAO,CAAC,EAAU;IAChC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,SAAS;IACvB,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,mBAAmB;AACnB,MAAM,UAAU,UAAU;IACxB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=roles.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.test.d.ts","sourceRoot":"","sources":["../../src/agents/roles.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,38 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { getRole, listRoles, getRoleIds } from './roles.js';
4
+ describe('agent roles', () => {
5
+ it('lists all roles', () => {
6
+ const roles = listRoles();
7
+ assert.ok(roles.length >= 6);
8
+ assert.ok(roles.find(r => r.id === 'code-reviewer'));
9
+ assert.ok(roles.find(r => r.id === 'test-writer'));
10
+ assert.ok(roles.find(r => r.id === 'debugger'));
11
+ assert.ok(roles.find(r => r.id === 'security-auditor'));
12
+ });
13
+ it('gets role by ID', () => {
14
+ const role = getRole('code-reviewer');
15
+ assert.ok(role);
16
+ assert.strictEqual(role.name, 'Code Reviewer');
17
+ assert.ok(role.systemPromptSupplement.length > 50);
18
+ assert.ok(role.suggestedTools.includes('FileRead'));
19
+ });
20
+ it('returns undefined for unknown role', () => {
21
+ assert.strictEqual(getRole('nonexistent'), undefined);
22
+ });
23
+ it('getRoleIds returns all IDs', () => {
24
+ const ids = getRoleIds();
25
+ assert.ok(ids.includes('code-reviewer'));
26
+ assert.ok(ids.includes('test-writer'));
27
+ assert.ok(ids.includes('refactorer'));
28
+ });
29
+ it('every role has required fields', () => {
30
+ for (const role of listRoles()) {
31
+ assert.ok(role.id, `role missing id`);
32
+ assert.ok(role.name, `role ${role.id} missing name`);
33
+ assert.ok(role.description, `role ${role.id} missing description`);
34
+ assert.ok(role.systemPromptSupplement.length > 20, `role ${role.id} has short prompt`);
35
+ }
36
+ });
37
+ });
38
+ //# sourceMappingURL=roles.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.test.js","sourceRoot":"","sources":["../../src/agents/roles.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5D,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;QACzB,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,eAAe,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,aAAa,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,kBAAkB,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;QACzB,MAAM,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAChB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAC/C,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,cAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;QACzB,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,EAAE,CAAC;YAC/B,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;YACtC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC;YACrD,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,IAAI,CAAC,EAAE,sBAAsB,CAAC,CAAC;YACnE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,GAAG,EAAE,EAAE,QAAQ,IAAI,CAAC,EAAE,mBAAmB,CAAC,CAAC;QACzF,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for new slash commands: /doctor, /context, /mcp, /keys, /fast, /pin, /unpin
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=commands-new.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-new.test.d.ts","sourceRoot":"","sources":["../../src/commands/commands-new.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Tests for new slash commands: /doctor, /context, /mcp, /keys, /fast, /pin, /unpin
3
+ */
4
+ import test from 'node:test';
5
+ import assert from 'node:assert/strict';
6
+ import { processSlashCommand } from './index.js';
7
+ import { createUserMessage, createAssistantMessage } from '../types/message.js';
8
+ function makeCtx(overrides = {}) {
9
+ return {
10
+ messages: [],
11
+ model: 'gpt-4o',
12
+ providerName: 'openai',
13
+ permissionMode: 'ask',
14
+ totalCost: 0.05,
15
+ totalInputTokens: 2000,
16
+ totalOutputTokens: 1000,
17
+ sessionId: 'test-sess-123',
18
+ ...overrides,
19
+ };
20
+ }
21
+ // ── /doctor ──
22
+ test('/doctor shows diagnostic info', () => {
23
+ const result = processSlashCommand('/doctor', makeCtx());
24
+ assert.ok(result);
25
+ assert.equal(result.handled, true);
26
+ assert.ok(result.output.includes('Provider'));
27
+ assert.ok(result.output.includes('openai'));
28
+ assert.ok(result.output.includes('Model'));
29
+ assert.ok(result.output.includes('gpt-4o'));
30
+ assert.ok(result.output.includes('Session'));
31
+ });
32
+ // ── /context ──
33
+ test('/context shows context window breakdown', () => {
34
+ const msgs = [
35
+ createUserMessage('What is 2+2?'),
36
+ createAssistantMessage('2+2 = 4'),
37
+ createUserMessage('Thanks'),
38
+ ];
39
+ const result = processSlashCommand('/context', makeCtx({ messages: msgs }));
40
+ assert.ok(result);
41
+ assert.equal(result.handled, true);
42
+ assert.ok(result.output.includes('Context window'));
43
+ assert.ok(result.output.includes('tokens'));
44
+ assert.ok(result.output.includes('# 1'));
45
+ assert.ok(result.output.includes('# 2'));
46
+ assert.ok(result.output.includes('# 3'));
47
+ });
48
+ test('/context with empty messages', () => {
49
+ const result = processSlashCommand('/context', makeCtx());
50
+ assert.ok(result);
51
+ assert.equal(result.handled, true);
52
+ assert.ok(result.output.includes('Context window'));
53
+ assert.ok(result.output.includes('0%'));
54
+ });
55
+ // ── /mcp ──
56
+ test('/mcp shows no servers message when none connected', () => {
57
+ const result = processSlashCommand('/mcp', makeCtx());
58
+ assert.ok(result);
59
+ assert.equal(result.handled, true);
60
+ assert.ok(result.output.includes('No MCP') || result.output.includes('MCP'));
61
+ });
62
+ // ── /keys ──
63
+ test('/keys shows keyboard shortcuts', () => {
64
+ const result = processSlashCommand('/keys', makeCtx());
65
+ assert.ok(result);
66
+ assert.equal(result.handled, true);
67
+ assert.ok(result.output.includes('Keyboard Shortcuts'));
68
+ assert.ok(result.output.includes('Navigation'));
69
+ assert.ok(result.output.includes('Ctrl+K'));
70
+ assert.ok(result.output.includes('Ctrl+O'));
71
+ assert.ok(result.output.includes('Scroll wheel'));
72
+ });
73
+ test('/keys includes custom keybindings section', () => {
74
+ const result = processSlashCommand('/keys', makeCtx());
75
+ assert.ok(result);
76
+ assert.ok(result.output.includes('keybindings'));
77
+ // Default bindings should appear
78
+ assert.ok(result.output.includes('/diff'));
79
+ });
80
+ // ── /fast ──
81
+ test('/fast returns toggleFastMode', () => {
82
+ const result = processSlashCommand('/fast', makeCtx());
83
+ assert.ok(result);
84
+ assert.equal(result.handled, true);
85
+ assert.equal(result.toggleFastMode, true);
86
+ });
87
+ // ── /pin ──
88
+ test('/pin with valid index returns compactedMessages with pinned flag', () => {
89
+ const msgs = [createUserMessage('hello'), createAssistantMessage('world')];
90
+ const result = processSlashCommand('/pin 1', makeCtx({ messages: msgs }));
91
+ assert.ok(result);
92
+ assert.equal(result.handled, true);
93
+ assert.ok(result.output.includes('pinned'));
94
+ assert.ok(result.compactedMessages);
95
+ assert.equal(result.compactedMessages.length, 2);
96
+ assert.equal(result.compactedMessages[0].meta?.pinned, true);
97
+ assert.equal(result.compactedMessages[1].meta?.pinned, undefined);
98
+ });
99
+ test('/pin with out-of-range index shows usage', () => {
100
+ const result = processSlashCommand('/pin 99', makeCtx({ messages: [createUserMessage('x')] }));
101
+ assert.ok(result);
102
+ assert.ok(result.output.includes('Usage'));
103
+ });
104
+ test('/pin without args shows usage', () => {
105
+ const result = processSlashCommand('/pin', makeCtx());
106
+ assert.ok(result);
107
+ assert.ok(result.output.includes('Usage'));
108
+ });
109
+ // ── /unpin ──
110
+ test('/unpin removes pinned flag', () => {
111
+ const msgs = [createUserMessage('hello'), createAssistantMessage('world')];
112
+ // Pin first, then unpin
113
+ const pinResult = processSlashCommand('/pin 1', makeCtx({ messages: msgs }));
114
+ const pinnedMsgs = pinResult.compactedMessages;
115
+ const unpinResult = processSlashCommand('/unpin 1', makeCtx({ messages: pinnedMsgs }));
116
+ assert.ok(unpinResult);
117
+ assert.ok(unpinResult.output.includes('unpinned'));
118
+ assert.equal(unpinResult.compactedMessages[0].meta?.pinned, false);
119
+ });
120
+ // ── aliases ──
121
+ test('/s alias maps to /status', () => {
122
+ const result = processSlashCommand('/s', makeCtx());
123
+ assert.ok(result);
124
+ assert.ok(result.output.includes('Model'));
125
+ });
126
+ test('/h alias maps to /help', () => {
127
+ const result = processSlashCommand('/h', makeCtx());
128
+ assert.ok(result);
129
+ assert.ok(result.output.includes('Session'));
130
+ assert.ok(result.output.includes('Git'));
131
+ });
132
+ //# sourceMappingURL=commands-new.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-new.test.js","sourceRoot":"","sources":["../../src/commands/commands-new.test.ts"],"names":[],"mappings":"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"}