@zhijiewang/openharness 0.1.2 → 0.2.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 (120) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  3. package/.github/pull_request_template.md +24 -0
  4. package/CHANGELOG.md +1 -1
  5. package/CODE_OF_CONDUCT.md +43 -0
  6. package/README.md +109 -62
  7. package/SECURITY.md +21 -0
  8. package/dist/Tool.d.ts +1 -1
  9. package/dist/Tool.js +1 -1
  10. package/dist/commands/index.d.ts +37 -0
  11. package/dist/commands/index.d.ts.map +1 -0
  12. package/dist/commands/index.js +189 -0
  13. package/dist/commands/index.js.map +1 -0
  14. package/dist/components/App.d.ts.map +1 -1
  15. package/dist/components/App.js +3 -2
  16. package/dist/components/App.js.map +1 -1
  17. package/dist/components/ErrorBoundary.d.ts +17 -0
  18. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  19. package/dist/components/ErrorBoundary.js +19 -0
  20. package/dist/components/ErrorBoundary.js.map +1 -0
  21. package/dist/components/Markdown.d.ts.map +1 -1
  22. package/dist/components/Markdown.js +70 -18
  23. package/dist/components/Markdown.js.map +1 -1
  24. package/dist/components/Messages.d.ts.map +1 -1
  25. package/dist/components/Messages.js +10 -4
  26. package/dist/components/Messages.js.map +1 -1
  27. package/dist/components/PermissionPrompt.d.ts.map +1 -1
  28. package/dist/components/PermissionPrompt.js +25 -7
  29. package/dist/components/PermissionPrompt.js.map +1 -1
  30. package/dist/components/REPL.d.ts.map +1 -1
  31. package/dist/components/REPL.js +60 -6
  32. package/dist/components/REPL.js.map +1 -1
  33. package/dist/components/Spinner.d.ts +3 -2
  34. package/dist/components/Spinner.d.ts.map +1 -1
  35. package/dist/components/Spinner.js +22 -4
  36. package/dist/components/Spinner.js.map +1 -1
  37. package/dist/components/TextInput.d.ts.map +1 -1
  38. package/dist/components/TextInput.js +4 -1
  39. package/dist/components/TextInput.js.map +1 -1
  40. package/dist/git/index.d.ts +47 -0
  41. package/dist/git/index.d.ts.map +1 -0
  42. package/dist/git/index.js +151 -0
  43. package/dist/git/index.js.map +1 -0
  44. package/dist/harness/session.d.ts.map +1 -1
  45. package/dist/harness/session.js +2 -1
  46. package/dist/harness/session.js.map +1 -1
  47. package/dist/main.js +89 -3
  48. package/dist/main.js.map +1 -1
  49. package/dist/providers/openai.js +11 -1
  50. package/dist/providers/openai.js.map +1 -1
  51. package/dist/providers/openrouter.js +11 -1
  52. package/dist/providers/openrouter.js.map +1 -1
  53. package/dist/query.d.ts +15 -11
  54. package/dist/query.d.ts.map +1 -1
  55. package/dist/query.js +196 -80
  56. package/dist/query.js.map +1 -1
  57. package/dist/services/StreamingToolExecutor.d.ts +25 -0
  58. package/dist/services/StreamingToolExecutor.d.ts.map +1 -0
  59. package/dist/services/StreamingToolExecutor.js +107 -0
  60. package/dist/services/StreamingToolExecutor.js.map +1 -0
  61. package/dist/tools/AgentTool/index.d.ts +15 -0
  62. package/dist/tools/AgentTool/index.d.ts.map +1 -0
  63. package/dist/tools/AgentTool/index.js +30 -0
  64. package/dist/tools/AgentTool/index.js.map +1 -0
  65. package/dist/tools/AskUserTool/index.d.ts +15 -0
  66. package/dist/tools/AskUserTool/index.d.ts.map +1 -0
  67. package/dist/tools/AskUserTool/index.js +30 -0
  68. package/dist/tools/AskUserTool/index.js.map +1 -0
  69. package/dist/tools/EnterPlanModeTool/index.d.ts +6 -0
  70. package/dist/tools/EnterPlanModeTool/index.d.ts.map +1 -0
  71. package/dist/tools/EnterPlanModeTool/index.js +37 -0
  72. package/dist/tools/EnterPlanModeTool/index.js.map +1 -0
  73. package/dist/tools/ExitPlanModeTool/index.d.ts +6 -0
  74. package/dist/tools/ExitPlanModeTool/index.d.ts.map +1 -0
  75. package/dist/tools/ExitPlanModeTool/index.js +21 -0
  76. package/dist/tools/ExitPlanModeTool/index.js.map +1 -0
  77. package/dist/tools/NotebookEditTool/index.d.ts +18 -0
  78. package/dist/tools/NotebookEditTool/index.d.ts.map +1 -0
  79. package/dist/tools/NotebookEditTool/index.js +61 -0
  80. package/dist/tools/NotebookEditTool/index.js.map +1 -0
  81. package/dist/tools/SkillTool/index.d.ts +15 -0
  82. package/dist/tools/SkillTool/index.d.ts.map +1 -0
  83. package/dist/tools/SkillTool/index.js +49 -0
  84. package/dist/tools/SkillTool/index.js.map +1 -0
  85. package/dist/tools/TaskCreateTool/index.d.ts +15 -0
  86. package/dist/tools/TaskCreateTool/index.d.ts.map +1 -0
  87. package/dist/tools/TaskCreateTool/index.js +54 -0
  88. package/dist/tools/TaskCreateTool/index.js.map +1 -0
  89. package/dist/tools/TaskListTool/index.d.ts +6 -0
  90. package/dist/tools/TaskListTool/index.d.ts.map +1 -0
  91. package/dist/tools/TaskListTool/index.js +40 -0
  92. package/dist/tools/TaskListTool/index.js.map +1 -0
  93. package/dist/tools/TaskUpdateTool/index.d.ts +18 -0
  94. package/dist/tools/TaskUpdateTool/index.d.ts.map +1 -0
  95. package/dist/tools/TaskUpdateTool/index.js +50 -0
  96. package/dist/tools/TaskUpdateTool/index.js.map +1 -0
  97. package/dist/tools/WebSearchTool/index.d.ts +15 -0
  98. package/dist/tools/WebSearchTool/index.d.ts.map +1 -0
  99. package/dist/tools/WebSearchTool/index.js +76 -0
  100. package/dist/tools/WebSearchTool/index.js.map +1 -0
  101. package/dist/tools.d.ts.map +1 -1
  102. package/dist/tools.js +27 -0
  103. package/dist/tools.js.map +1 -1
  104. package/dist/types/message.d.ts +1 -1
  105. package/dist/types/message.js +1 -1
  106. package/dist/types/permissions.d.ts +2 -2
  107. package/dist/types/permissions.js +2 -2
  108. package/dist/utils/retry.d.ts +10 -0
  109. package/dist/utils/retry.d.ts.map +1 -0
  110. package/dist/utils/retry.js +23 -0
  111. package/dist/utils/retry.js.map +1 -0
  112. package/dist/utils/theme.d.ts +27 -0
  113. package/dist/utils/theme.d.ts.map +1 -0
  114. package/dist/utils/theme.js +45 -0
  115. package/dist/utils/theme.js.map +1 -0
  116. package/dist/utils/tokens.d.ts +18 -0
  117. package/dist/utils/tokens.d.ts.map +1 -0
  118. package/dist/utils/tokens.js +57 -0
  119. package/dist/utils/tokens.js.map +1 -0
  120. package/package.json +61 -57
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a bug in OpenHarness
4
+ labels: bug
5
+ ---
6
+
7
+ **Describe the bug**
8
+ A clear description of what the bug is.
9
+
10
+ **To reproduce**
11
+ Steps to reproduce the behavior:
12
+ 1. Run `oh ...`
13
+ 2. See error
14
+
15
+ **Expected behavior**
16
+ What you expected to happen.
17
+
18
+ **Environment**
19
+ - OS:
20
+ - Node version:
21
+ - OpenHarness version:
22
+ - LLM provider:
23
+
24
+ **Logs / error output**
25
+ ```
26
+ paste any relevant output here
27
+ ```
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for OpenHarness
4
+ labels: enhancement
5
+ ---
6
+
7
+ **Problem / motivation**
8
+ What problem does this solve, or what use case does it enable?
9
+
10
+ **Proposed solution**
11
+ Describe the feature you'd like.
12
+
13
+ **Alternatives considered**
14
+ Any other approaches you've thought about?
15
+
16
+ **Additional context**
17
+ Screenshots, examples, or links if relevant.
@@ -0,0 +1,24 @@
1
+ ## Summary
2
+
3
+ <!-- What does this PR do? -->
4
+
5
+ ## Related issue
6
+
7
+ Closes #
8
+
9
+ ## Type of change
10
+
11
+ - [ ] Bug fix
12
+ - [ ] New feature
13
+ - [ ] Breaking change
14
+ - [ ] Documentation
15
+
16
+ ## Testing
17
+
18
+ <!-- How did you test this? -->
19
+
20
+ ## Checklist
21
+
22
+ - [ ] Code builds without errors (`npm run build`)
23
+ - [ ] Types pass (`npm run typecheck`)
24
+ - [ ] Tests pass (`npm test`)
package/CHANGELOG.md CHANGED
@@ -6,7 +6,7 @@ Initial alpha release. TypeScript rewrite.
6
6
 
7
7
  ### Features
8
8
  - Single TypeScript process with React+Ink terminal UI
9
- - Agent loop with async generator streaming (mirrors Claude Code's query.ts)
9
+ - Agent loop with async generator streaming
10
10
  - 5 LLM providers: Ollama, OpenAI, Anthropic, OpenRouter, OpenAI-compatible
11
11
  - 7 tools: Read, Edit, Write, Bash, Glob, Grep, WebFetch (all with Zod schemas)
12
12
  - Permission gate with ask/trust/deny modes and risk-based tool approval
@@ -0,0 +1,43 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment:
12
+
13
+ - Demonstrating empathy and kindness toward other people
14
+ - Being respectful of differing opinions, viewpoints, and experiences
15
+ - Giving and gracefully accepting constructive feedback
16
+ - Accepting responsibility and apologizing to those affected by our mistakes
17
+ - Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior:
20
+
21
+ - The use of sexualized language or imagery, and sexual attention or advances of any kind
22
+ - Trolling, insulting or derogatory comments, and personal or political attacks
23
+ - Public or private harassment
24
+ - Publishing others' private information without explicit permission
25
+ - Other conduct which could reasonably be considered inappropriate in a professional setting
26
+
27
+ ## Enforcement Responsibilities
28
+
29
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ ## Scope
32
+
33
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces.
34
+
35
+ ## Enforcement
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at the repository's issue tracker or by contacting the maintainer directly via GitHub.
38
+
39
+ All complaints will be reviewed and investigated promptly and fairly.
40
+
41
+ ## Attribution
42
+
43
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
package/README.md CHANGED
@@ -11,12 +11,19 @@
11
11
  `--`
12
12
  ```
13
13
 
14
- Open-source terminal coding agent. Build your own Claude Code with any LLM.
14
+ AI coding agent in your terminal. Works with any LLM -- free local models or cloud APIs.
15
15
 
16
- ![Status: Alpha](https://img.shields.io/badge/status-alpha-orange)
16
+ ![npm](https://img.shields.io/npm/v/@zhijiewang/openharness)
17
17
  ![Node.js 18+](https://img.shields.io/badge/node-18%2B-green)
18
18
  ![TypeScript](https://img.shields.io/badge/typescript-strict-blue)
19
19
  ![License: MIT](https://img.shields.io/badge/license-MIT-green)
20
+ ![Status: Alpha](https://img.shields.io/badge/status-alpha-orange)
21
+
22
+ ---
23
+
24
+ <video src="https://github.com/user-attachments/assets/ed19a2cc-14d3-4db3-aa5b-3dc07c444498" controls width="100%"></video>
25
+
26
+ *OpenHarness reading files, running commands, and editing code — powered by a local Ollama model.*
20
27
 
21
28
  ---
22
29
 
@@ -27,78 +34,120 @@ npm install -g @zhijiewang/openharness
27
34
  oh
28
35
  ```
29
36
 
30
- That's it. Just type `oh` to start chatting with your local Ollama model.
37
+ That's it. OpenHarness auto-detects Ollama and starts chatting. No API key needed.
31
38
 
32
39
  ```bash
33
- oh # auto-detect Ollama, start chatting
40
+ oh # auto-detect local model
34
41
  oh --model ollama/qwen2.5:7b # specific model
35
- oh --model gpt-4o # use OpenAI (needs OPENAI_API_KEY)
42
+ oh --model gpt-4o # cloud model (needs OPENAI_API_KEY)
36
43
  oh --trust # auto-approve all tool calls
37
- ```
38
-
39
- <!-- ![Demo](assets/demo.gif) -->
40
-
41
- ## Install
42
-
43
- Requires **Node.js 18+**.
44
-
45
- ```bash
46
- # From npm
47
- npm install -g @zhijiewang/openharness
48
-
49
- # From source
50
- git clone https://github.com/zhijiewong/openharness.git
51
- cd openharness
52
- npm install
53
- npm install -g .
54
- oh
44
+ oh run "fix the tests" --json # headless mode for CI/CD
55
45
  ```
56
46
 
57
47
  ## Why OpenHarness?
58
48
 
59
- Claude Code is powerful but locked to Anthropic. OpenHarness gives you the same architecture -- React+Ink terminal UI, async generator agent loop, Zod tool schemas, permission gates -- but works with **any LLM**. Local models via Ollama (free, offline, private), or cloud APIs (OpenAI, Anthropic, OpenRouter, DeepSeek, Groq, and any OpenAI-compatible endpoint).
49
+ Most AI coding agents are locked to one provider or cost $20+/month. OpenHarness works with any LLM -- run it free with Ollama on your own machine, or connect to any cloud API. Every AI edit is git-committed and reversible with `/undo`.
50
+
51
+ | | OpenHarness | Claude Code | Aider | OpenCode |
52
+ |---|---|---|---|---|
53
+ | Any LLM | Yes (Ollama, OpenAI, Anthropic, OpenRouter, any OpenAI-compatible) | Anthropic only | Yes | Yes |
54
+ | Free local models | Ollama native | No | Yes | Yes |
55
+ | Tools | 17 with permission gates | 40+ | File-focused | 20+ |
56
+ | Git integration | Auto-commit + /undo | Yes | Deep git | Basic |
57
+ | Slash commands | 16 built-in | 80+ | Some | Some |
58
+ | Headless/CI mode | `oh run --json` | Yes | Yes | Yes |
59
+ | Terminal UI | React + Ink | React + Ink | Basic | BubbleTea |
60
+ | Language | TypeScript | TypeScript | Python | Go |
61
+ | License | MIT | Proprietary | Apache 2.0 | MIT |
62
+ | Price | Free (BYOK) | $20+/month | Free (BYOK) | Free (BYOK) |
60
63
 
61
- ## Tools
64
+ ## Tools (17)
62
65
 
63
66
  | Tool | Risk | Description |
64
67
  |------|------|-------------|
68
+ | Bash | high | Execute shell commands with timeout |
65
69
  | Read | low | Read files with line ranges |
66
- | Edit | medium | Search-and-replace edits |
67
70
  | Write | medium | Create or overwrite files |
68
- | Bash | high | Shell commands with timeout |
71
+ | Edit | medium | Search-and-replace edits |
69
72
  | Glob | low | Find files by pattern |
70
73
  | Grep | low | Regex content search |
71
- | WebFetch | medium | Fetch URL content |
74
+ | WebFetch | medium | Fetch URL content (SSRF-protected) |
75
+ | WebSearch | medium | Search the web |
76
+ | TaskCreate | low | Create structured tasks |
77
+ | TaskUpdate | low | Update task status |
78
+ | TaskList | low | List all tasks |
79
+ | AskUser | low | Ask user a question with options |
80
+ | Skill | low | Invoke a skill from .oh/skills/ |
81
+ | Agent | medium | Spawn a sub-agent for delegation |
82
+ | EnterPlanMode | low | Enter structured planning mode |
83
+ | ExitPlanMode | low | Exit planning mode |
84
+ | NotebookEdit | medium | Edit Jupyter notebooks |
85
+
86
+ Low-risk read-only tools auto-approve. Medium and high risk tools require confirmation in `ask` mode. Use `--trust` to skip all prompts.
87
+
88
+ ## Slash Commands (16)
89
+
90
+ Type these during a chat session:
91
+
92
+ | Command | Description |
93
+ |---------|-------------|
94
+ | `/help` | Show all available commands |
95
+ | `/clear` | Clear conversation history |
96
+ | `/cost` | Show session cost and token usage |
97
+ | `/status` | Show model, mode, git branch, session info |
98
+ | `/diff` | Show uncommitted git changes |
99
+ | `/undo` | Undo last AI commit |
100
+ | `/commit [msg]` | Create a git commit |
101
+ | `/log` | Show recent git commits |
102
+ | `/files` | List files in context |
103
+ | `/model <name>` | Switch model mid-session |
104
+ | `/compact` | Compress conversation to free context |
105
+ | `/export` | Export conversation to markdown |
106
+ | `/plan` | Enter plan mode |
107
+ | `/review` | Review recent code changes |
108
+ | `/config` | Show configuration |
109
+ | `/memory` | View memories |
110
+
111
+ ## Git Integration
112
+
113
+ OpenHarness auto-commits AI edits in git repos:
114
+
115
+ ```
116
+ oh: Edit src/app.ts # auto-committed with "oh:" prefix
117
+ oh: Write tests/app.test.ts
118
+ ```
119
+
120
+ - Every AI file change is committed automatically
121
+ - `/undo` reverts the last AI commit (only OH commits, never yours)
122
+ - `/diff` shows what changed
123
+ - Your dirty files are safe — committed separately before AI edits
72
124
 
73
- Low-risk tools auto-approve. Medium and high risk require confirmation in `ask` mode.
125
+ ## Headless Mode
74
126
 
75
- ## Commands
127
+ Run a single prompt without interactive UI — perfect for CI/CD:
76
128
 
77
129
  ```bash
78
- oh # start chatting (default command)
79
- oh --model MODEL # use a specific model
80
- oh --trust # auto-approve all tools
81
- oh --deny # block all non-read tools
82
- oh --resume ID # resume a saved session
83
- oh models # list models and pricing
84
- oh tools # list tools and risk levels
85
- oh init # set up .oh/ for current project
86
- oh sessions # list saved sessions
87
- oh rules # show project rules
88
- oh --version # show version
130
+ oh run "fix the failing tests" --model ollama/llama3 --trust
131
+ oh run "add error handling to api.ts" --json # JSON output
132
+ oh run "explain this codebase" --model gpt-4o
89
133
  ```
90
134
 
135
+ Exit code 0 on success, 1 on failure.
136
+
91
137
  ## Providers
92
138
 
93
139
  ```bash
94
- # Local (free, no API key)
140
+ # Local (free, no API key needed)
95
141
  oh --model ollama/llama3
96
142
  oh --model ollama/qwen2.5:7b-instruct
97
143
 
98
- # Cloud (set API key as env var)
144
+ # Cloud
99
145
  OPENAI_API_KEY=sk-... oh --model gpt-4o
100
146
  ANTHROPIC_API_KEY=sk-ant-... oh --model claude-sonnet-4-6
101
147
  OPENROUTER_API_KEY=sk-or-... oh --model openrouter/deepseek-chat
148
+
149
+ # Any OpenAI-compatible endpoint
150
+ oh --model deepseek/deepseek-chat
102
151
  ```
103
152
 
104
153
  ## Project Rules
@@ -113,36 +162,37 @@ Create `.oh/RULES.md` in any repo (or run `oh init`):
113
162
 
114
163
  Rules load automatically into every session.
115
164
 
116
- ## Tech Stack
117
-
118
- | | OpenHarness | Claude Code |
119
- |---|---|---|
120
- | Language | TypeScript (strict) | TypeScript (strict) |
121
- | Runtime | Node.js 18+ | Bun |
122
- | Terminal UI | React + Ink | React + custom Ink fork |
123
- | Tool schemas | Zod | Zod |
124
- | Agent loop | async generators | async generators |
125
- | Providers | Any (5 built-in) | Anthropic only |
126
- | License | MIT | Proprietary |
165
+ ## Install
127
166
 
128
- ## Development
167
+ Requires **Node.js 18+**.
129
168
 
130
169
  ```bash
170
+ # From npm
171
+ npm install -g @zhijiewang/openharness
172
+
173
+ # From source
131
174
  git clone https://github.com/zhijiewong/openharness.git
132
175
  cd openharness
176
+ npm install && npm install -g .
177
+ ```
178
+
179
+ ## Development
180
+
181
+ ```bash
133
182
  npm install
134
183
  npx tsx src/main.tsx # run in dev mode
135
184
  npx tsc --noEmit # type check
185
+ npm test # run tests
136
186
  ```
137
187
 
138
- ### Adding a provider
139
-
140
- Create `src/providers/yourprovider.ts` implementing the `Provider` interface, add a case in `src/providers/index.ts`.
141
-
142
188
  ### Adding a tool
143
189
 
144
190
  Create `src/tools/YourTool/index.ts` implementing the `Tool` interface with a Zod input schema, register it in `src/tools.ts`.
145
191
 
192
+ ### Adding a provider
193
+
194
+ Create `src/providers/yourprovider.ts` implementing the `Provider` interface, add a case in `src/providers/index.ts`.
195
+
146
196
  ## Contributing
147
197
 
148
198
  See [CONTRIBUTING.md](CONTRIBUTING.md).
@@ -151,6 +201,3 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
151
201
 
152
202
  MIT
153
203
 
154
- ---
155
-
156
- This project is not affiliated with Anthropic.
package/SECURITY.md ADDED
@@ -0,0 +1,21 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ |---------|-----------|
7
+ | 0.1.x | ✅ |
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ Please **do not** report security vulnerabilities via public GitHub issues.
12
+
13
+ Instead, open a [GitHub Security Advisory](https://github.com/zhijiewong/openharness/security/advisories/new) or contact the maintainer directly via the profile on GitHub.
14
+
15
+ Please include:
16
+ - Description of the vulnerability
17
+ - Steps to reproduce
18
+ - Potential impact
19
+ - Suggested fix (if any)
20
+
21
+ You can expect a response within 48 hours. If confirmed, a patch will be prioritized and released as soon as possible.
package/dist/Tool.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tool interface — mirrors Claude Code's Tool.ts pattern.
2
+ * Tool interface — defines how tools are registered, validated, and executed.
3
3
  * Every tool implements this interface with Zod input validation.
4
4
  */
5
5
  import type { z } from "zod";
package/dist/Tool.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tool interface — mirrors Claude Code's Tool.ts pattern.
2
+ * Tool interface — defines how tools are registered, validated, and executed.
3
3
  * Every tool implements this interface with Zod input validation.
4
4
  */
5
5
  /**
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Slash command system — /help, /clear, /diff, /undo, /cost, etc.
3
+ *
4
+ * Commands are processed in the REPL before being sent to the LLM.
5
+ * If input starts with /, it's treated as a command.
6
+ */
7
+ import type { Message } from "../types/message.js";
8
+ export type CommandResult = {
9
+ /** Text output to display */
10
+ output: string;
11
+ /** If true, don't send to LLM */
12
+ handled: boolean;
13
+ /** If set, clear messages */
14
+ clearMessages?: boolean;
15
+ /** If set, update model */
16
+ newModel?: string;
17
+ /** If set, replace messages with compacted version */
18
+ compactedMessages?: Message[];
19
+ };
20
+ export type CommandContext = {
21
+ messages: Message[];
22
+ model: string;
23
+ permissionMode: string;
24
+ totalCost: number;
25
+ totalInputTokens: number;
26
+ totalOutputTokens: number;
27
+ sessionId: string;
28
+ };
29
+ /**
30
+ * Check if input is a slash command. If so, execute it.
31
+ */
32
+ export declare function processSlashCommand(input: string, context: CommandContext): CommandResult | null;
33
+ /**
34
+ * Get all registered command names (for autocomplete/display).
35
+ */
36
+ export declare function getCommandNames(): string[];
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,MAAM,aAAa,GAAG;IAC1B,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,6BAA6B;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,OAAO,EAAE,CAAC;CAC/B,CAAC;AAIF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AA4KF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,aAAa,GAAG,IAAI,CAiBhG;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C"}
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Slash command system — /help, /clear, /diff, /undo, /cost, etc.
3
+ *
4
+ * Commands are processed in the REPL before being sent to the LLM.
5
+ * If input starts with /, it's treated as a command.
6
+ */
7
+ import { writeFileSync, mkdirSync } from "node:fs";
8
+ import { dirname } from "node:path";
9
+ import { isGitRepo, gitDiff, gitUndo, gitCommit, gitLog, gitBranch } from "../git/index.js";
10
+ const commands = new Map();
11
+ function register(name, description, handler) {
12
+ commands.set(name, { description, handler });
13
+ }
14
+ // ── Register all commands ──
15
+ register("help", "Show available commands", () => {
16
+ const lines = ["Available commands:\n"];
17
+ for (const [name, { description }] of commands) {
18
+ lines.push(` /${name.padEnd(12)} ${description}`);
19
+ }
20
+ return { output: lines.join("\n"), handled: true };
21
+ });
22
+ register("clear", "Clear conversation history", () => {
23
+ return { output: "Conversation cleared.", handled: true, clearMessages: true };
24
+ });
25
+ register("cost", "Show session cost and token usage", (_args, ctx) => {
26
+ const lines = [
27
+ `Cost: $${ctx.totalCost.toFixed(4)}`,
28
+ `Tokens: ${ctx.totalInputTokens.toLocaleString()} input, ${ctx.totalOutputTokens.toLocaleString()} output`,
29
+ `Model: ${ctx.model}`,
30
+ `Session: ${ctx.sessionId}`,
31
+ ];
32
+ return { output: lines.join("\n"), handled: true };
33
+ });
34
+ register("status", "Show session status", (_args, ctx) => {
35
+ const lines = [
36
+ `Model: ${ctx.model}`,
37
+ `Mode: ${ctx.permissionMode}`,
38
+ `Messages: ${ctx.messages.length}`,
39
+ `Cost: $${ctx.totalCost.toFixed(4)}`,
40
+ `Session: ${ctx.sessionId}`,
41
+ ];
42
+ if (isGitRepo()) {
43
+ lines.push(`Git branch: ${gitBranch()}`);
44
+ }
45
+ return { output: lines.join("\n"), handled: true };
46
+ });
47
+ register("diff", "Show uncommitted git changes", () => {
48
+ if (!isGitRepo()) {
49
+ return { output: "Not a git repository.", handled: true };
50
+ }
51
+ const diff = gitDiff();
52
+ return { output: diff || "No uncommitted changes.", handled: true };
53
+ });
54
+ register("undo", "Undo last AI commit", () => {
55
+ if (!isGitRepo()) {
56
+ return { output: "Not a git repository.", handled: true };
57
+ }
58
+ const success = gitUndo();
59
+ return {
60
+ output: success ? "Undone. Last AI commit reverted." : "Nothing to undo (last commit wasn't from OpenHarness).",
61
+ handled: true,
62
+ };
63
+ });
64
+ register("commit", "Create a git commit", (args) => {
65
+ if (!isGitRepo()) {
66
+ return { output: "Not a git repository.", handled: true };
67
+ }
68
+ const message = args.trim() || "manual commit";
69
+ const success = gitCommit(message);
70
+ return { output: success ? `Committed: ${message}` : "Nothing to commit.", handled: true };
71
+ });
72
+ register("log", "Show recent git commits", () => {
73
+ if (!isGitRepo()) {
74
+ return { output: "Not a git repository.", handled: true };
75
+ }
76
+ return { output: gitLog(10) || "No commits yet.", handled: true };
77
+ });
78
+ register("files", "List files in context", (_args, ctx) => {
79
+ const files = new Set();
80
+ for (const msg of ctx.messages) {
81
+ // Extract file paths from tool calls
82
+ if (msg.toolCalls) {
83
+ for (const tc of msg.toolCalls) {
84
+ const path = tc.arguments?.file_path ?? tc.arguments?.path;
85
+ if (path)
86
+ files.add(String(path));
87
+ }
88
+ }
89
+ }
90
+ if (files.size === 0)
91
+ return { output: "No files in context yet.", handled: true };
92
+ return { output: `Files in context:\n${[...files].map(f => ` ${f}`).join("\n")}`, handled: true };
93
+ });
94
+ register("model", "Switch model (e.g., /model gpt-4o)", (args) => {
95
+ const model = args.trim();
96
+ if (!model)
97
+ return { output: "Usage: /model <model-name>", handled: true };
98
+ return { output: `Switched to ${model}.`, handled: true, newModel: model };
99
+ });
100
+ register("compact", "Compress conversation history", (_args, ctx) => {
101
+ const before = ctx.messages.length;
102
+ // Keep system messages + last 10 messages, truncate old tool results
103
+ const compacted = [];
104
+ const keepLast = 10;
105
+ const messages = ctx.messages;
106
+ for (let i = 0; i < messages.length; i++) {
107
+ const msg = messages[i];
108
+ const isRecent = i >= messages.length - keepLast;
109
+ if (msg.role === "system") {
110
+ compacted.push(msg);
111
+ }
112
+ else if (isRecent) {
113
+ compacted.push(msg);
114
+ }
115
+ else if (msg.role === "tool") {
116
+ // Truncate old tool results
117
+ compacted.push({ ...msg, content: "[compacted]" });
118
+ }
119
+ else {
120
+ compacted.push(msg);
121
+ }
122
+ }
123
+ return {
124
+ output: `Compacted: ${before} → ${compacted.length} messages. Old tool results truncated.`,
125
+ handled: true,
126
+ compactedMessages: compacted,
127
+ };
128
+ });
129
+ register("export", "Export conversation to file", (_args, ctx) => {
130
+ const lines = ctx.messages
131
+ .filter(m => m.role === "user" || m.role === "assistant")
132
+ .map(m => `${m.role === "user" ? "User" : "Assistant"}: ${m.content}`)
133
+ .join("\n\n");
134
+ const filename = `.oh/export-${ctx.sessionId}.md`;
135
+ try {
136
+ mkdirSync(dirname(filename), { recursive: true });
137
+ writeFileSync(filename, lines);
138
+ return { output: `Exported to ${filename}`, handled: true };
139
+ }
140
+ catch {
141
+ return { output: `Export failed. Content:\n\n${lines.slice(0, 500)}`, handled: true };
142
+ }
143
+ });
144
+ register("config", "Show current configuration", () => {
145
+ return { output: "Use: oh config show (in a new terminal)", handled: true };
146
+ });
147
+ register("memory", "View memories", () => {
148
+ return { output: "Use: oh memory (in a new terminal)", handled: true };
149
+ });
150
+ register("plan", "Enter plan mode", () => {
151
+ return { output: "Plan mode: describe what you want to build. I'll create a plan before implementing.", handled: false };
152
+ });
153
+ register("review", "Review recent code changes", () => {
154
+ if (!isGitRepo()) {
155
+ return { output: "Not a git repository.", handled: true };
156
+ }
157
+ const diff = gitDiff();
158
+ if (!diff)
159
+ return { output: "No changes to review.", handled: true };
160
+ // Pass to LLM for review
161
+ return { output: "", handled: false };
162
+ });
163
+ // ── Command Parser ──
164
+ /**
165
+ * Check if input is a slash command. If so, execute it.
166
+ */
167
+ export function processSlashCommand(input, context) {
168
+ const trimmed = input.trim();
169
+ if (!trimmed.startsWith("/"))
170
+ return null;
171
+ const spaceIdx = trimmed.indexOf(" ");
172
+ const name = (spaceIdx === -1 ? trimmed.slice(1) : trimmed.slice(1, spaceIdx)).toLowerCase();
173
+ const args = spaceIdx === -1 ? "" : trimmed.slice(spaceIdx + 1);
174
+ const cmd = commands.get(name);
175
+ if (!cmd) {
176
+ return {
177
+ output: `Unknown command: /${name}. Type /help for available commands.`,
178
+ handled: true,
179
+ };
180
+ }
181
+ return cmd.handler(args, context);
182
+ }
183
+ /**
184
+ * Get all registered command names (for autocomplete/display).
185
+ */
186
+ export function getCommandNames() {
187
+ return [...commands.keys()];
188
+ }
189
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAKnD,KAAK,QAAQ,GAAG;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;CAC7B,CAAC;AAEF,QAAA,MAAM,qBAAqB,4PAEyB,CAAC;AAErD,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,EAC1B,QAAQ,EACR,KAAK,EACL,cAAc,EACd,YAAY,EACZ,KAAK,EACL,eAAe,GAChB,EAAE,QAAQ,2CAyBV;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAOnD,KAAK,QAAQ,GAAG;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;CAC7B,CAAC;AAEF,QAAA,MAAM,qBAAqB,4PAEyB,CAAC;AAErD,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,EAC1B,QAAQ,EACR,KAAK,EACL,cAAc,EACd,YAAY,EACZ,KAAK,EACL,eAAe,GAChB,EAAE,QAAQ,2CA4BV;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}