@zhijiewang/openharness 0.1.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 (135) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/CONTRIBUTING.md +55 -0
  3. package/LICENSE +21 -0
  4. package/README.md +154 -0
  5. package/data/models.json +74 -0
  6. package/data/prompts/system.md +25 -0
  7. package/data/skills/code-review.md +19 -0
  8. package/data/skills/commit.md +17 -0
  9. package/data/skills/debug.md +24 -0
  10. package/data/skills/tdd.md +22 -0
  11. package/dist/Tool.d.ts +45 -0
  12. package/dist/Tool.d.ts.map +1 -0
  13. package/dist/Tool.js +62 -0
  14. package/dist/Tool.js.map +1 -0
  15. package/dist/components/App.d.ts +16 -0
  16. package/dist/components/App.d.ts.map +1 -0
  17. package/dist/components/App.js +25 -0
  18. package/dist/components/App.js.map +1 -0
  19. package/dist/components/Messages.d.ts +9 -0
  20. package/dist/components/Messages.d.ts.map +1 -0
  21. package/dist/components/Messages.js +23 -0
  22. package/dist/components/Messages.js.map +1 -0
  23. package/dist/components/PermissionPrompt.d.ts +9 -0
  24. package/dist/components/PermissionPrompt.d.ts.map +1 -0
  25. package/dist/components/PermissionPrompt.js +18 -0
  26. package/dist/components/PermissionPrompt.js.map +1 -0
  27. package/dist/components/REPL.d.ts +15 -0
  28. package/dist/components/REPL.d.ts.map +1 -0
  29. package/dist/components/REPL.js +114 -0
  30. package/dist/components/REPL.js.map +1 -0
  31. package/dist/components/Spinner.d.ts +7 -0
  32. package/dist/components/Spinner.d.ts.map +1 -0
  33. package/dist/components/Spinner.js +7 -0
  34. package/dist/components/Spinner.js.map +1 -0
  35. package/dist/components/TextInput.d.ts +7 -0
  36. package/dist/components/TextInput.d.ts.map +1 -0
  37. package/dist/components/TextInput.js +37 -0
  38. package/dist/components/TextInput.js.map +1 -0
  39. package/dist/components/ToolCallDisplay.d.ts +12 -0
  40. package/dist/components/ToolCallDisplay.d.ts.map +1 -0
  41. package/dist/components/ToolCallDisplay.js +16 -0
  42. package/dist/components/ToolCallDisplay.js.map +1 -0
  43. package/dist/harness/cost.d.ts +33 -0
  44. package/dist/harness/cost.d.ts.map +1 -0
  45. package/dist/harness/cost.js +68 -0
  46. package/dist/harness/cost.js.map +1 -0
  47. package/dist/harness/onboarding.d.ts +17 -0
  48. package/dist/harness/onboarding.d.ts.map +1 -0
  49. package/dist/harness/onboarding.js +99 -0
  50. package/dist/harness/onboarding.js.map +1 -0
  51. package/dist/harness/rules.d.ts +8 -0
  52. package/dist/harness/rules.d.ts.map +1 -0
  53. package/dist/harness/rules.js +66 -0
  54. package/dist/harness/rules.js.map +1 -0
  55. package/dist/harness/session.d.ts +24 -0
  56. package/dist/harness/session.d.ts.map +1 -0
  57. package/dist/harness/session.js +56 -0
  58. package/dist/harness/session.js.map +1 -0
  59. package/dist/main.d.ts +12 -0
  60. package/dist/main.d.ts.map +1 -0
  61. package/dist/main.js +177 -0
  62. package/dist/main.js.map +1 -0
  63. package/dist/providers/anthropic.d.ts +27 -0
  64. package/dist/providers/anthropic.d.ts.map +1 -0
  65. package/dist/providers/anthropic.js +291 -0
  66. package/dist/providers/anthropic.js.map +1 -0
  67. package/dist/providers/base.d.ts +41 -0
  68. package/dist/providers/base.d.ts.map +1 -0
  69. package/dist/providers/base.js +5 -0
  70. package/dist/providers/base.js.map +1 -0
  71. package/dist/providers/index.d.ts +12 -0
  72. package/dist/providers/index.d.ts.map +1 -0
  73. package/dist/providers/index.js +57 -0
  74. package/dist/providers/index.js.map +1 -0
  75. package/dist/providers/ollama.d.ts +19 -0
  76. package/dist/providers/ollama.d.ts.map +1 -0
  77. package/dist/providers/ollama.js +233 -0
  78. package/dist/providers/ollama.js.map +1 -0
  79. package/dist/providers/openai.d.ts +21 -0
  80. package/dist/providers/openai.d.ts.map +1 -0
  81. package/dist/providers/openai.js +242 -0
  82. package/dist/providers/openai.js.map +1 -0
  83. package/dist/providers/openrouter.d.ts +25 -0
  84. package/dist/providers/openrouter.d.ts.map +1 -0
  85. package/dist/providers/openrouter.js +278 -0
  86. package/dist/providers/openrouter.js.map +1 -0
  87. package/dist/query.d.ts +35 -0
  88. package/dist/query.d.ts.map +1 -0
  89. package/dist/query.js +185 -0
  90. package/dist/query.js.map +1 -0
  91. package/dist/tools/BashTool/index.d.ts +15 -0
  92. package/dist/tools/BashTool/index.d.ts.map +1 -0
  93. package/dist/tools/BashTool/index.js +78 -0
  94. package/dist/tools/BashTool/index.js.map +1 -0
  95. package/dist/tools/FileEditTool/index.d.ts +21 -0
  96. package/dist/tools/FileEditTool/index.d.ts.map +1 -0
  97. package/dist/tools/FileEditTool/index.js +70 -0
  98. package/dist/tools/FileEditTool/index.js.map +1 -0
  99. package/dist/tools/FileReadTool/index.d.ts +18 -0
  100. package/dist/tools/FileReadTool/index.d.ts.map +1 -0
  101. package/dist/tools/FileReadTool/index.js +63 -0
  102. package/dist/tools/FileReadTool/index.js.map +1 -0
  103. package/dist/tools/FileWriteTool/index.d.ts +15 -0
  104. package/dist/tools/FileWriteTool/index.d.ts.map +1 -0
  105. package/dist/tools/FileWriteTool/index.js +42 -0
  106. package/dist/tools/FileWriteTool/index.js.map +1 -0
  107. package/dist/tools/GlobTool/index.d.ts +15 -0
  108. package/dist/tools/GlobTool/index.d.ts.map +1 -0
  109. package/dist/tools/GlobTool/index.js +126 -0
  110. package/dist/tools/GlobTool/index.js.map +1 -0
  111. package/dist/tools/GrepTool/index.d.ts +21 -0
  112. package/dist/tools/GrepTool/index.d.ts.map +1 -0
  113. package/dist/tools/GrepTool/index.js +125 -0
  114. package/dist/tools/GrepTool/index.js.map +1 -0
  115. package/dist/tools/WebFetchTool/index.d.ts +12 -0
  116. package/dist/tools/WebFetchTool/index.d.ts.map +1 -0
  117. package/dist/tools/WebFetchTool/index.js +98 -0
  118. package/dist/tools/WebFetchTool/index.js.map +1 -0
  119. package/dist/tools.d.ts +9 -0
  120. package/dist/tools.d.ts.map +1 -0
  121. package/dist/tools.js +25 -0
  122. package/dist/tools.js.map +1 -0
  123. package/dist/types/events.d.ts +49 -0
  124. package/dist/types/events.d.ts.map +1 -0
  125. package/dist/types/events.js +5 -0
  126. package/dist/types/events.js.map +1 -0
  127. package/dist/types/message.d.ts +27 -0
  128. package/dist/types/message.d.ts.map +1 -0
  129. package/dist/types/message.js +22 -0
  130. package/dist/types/message.js.map +1 -0
  131. package/dist/types/permissions.d.ts +22 -0
  132. package/dist/types/permissions.d.ts.map +1 -0
  133. package/dist/types/permissions.js +27 -0
  134. package/dist/types/permissions.js.map +1 -0
  135. package/package.json +55 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-04-01)
4
+
5
+ Initial alpha release. TypeScript rewrite.
6
+
7
+ ### Features
8
+ - Single TypeScript process with React+Ink terminal UI
9
+ - Agent loop with async generator streaming (mirrors Claude Code's query.ts)
10
+ - 5 LLM providers: Ollama, OpenAI, Anthropic, OpenRouter, OpenAI-compatible
11
+ - 7 tools: Read, Edit, Write, Bash, Glob, Grep, WebFetch (all with Zod schemas)
12
+ - Permission gate with ask/trust/deny modes and risk-based tool approval
13
+ - Tool concurrency: read-only parallel, write serial
14
+ - Project rules (.oh/RULES.md)
15
+ - Cost tracking with per-model breakdown
16
+ - Session persistence
17
+ - Project auto-detection (15+ languages, 20+ frameworks)
18
+ - Global install: `npm install -g openharness` then just `oh`
@@ -0,0 +1,55 @@
1
+ # Contributing to OpenHarness
2
+
3
+ Thanks for your interest in contributing.
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ git clone https://github.com/zhijiewong/openharness.git
9
+ cd openharness
10
+ npm install
11
+ ```
12
+
13
+ ## Development
14
+
15
+ ```bash
16
+ npx tsx src/main.tsx # run in dev mode
17
+ npx tsc --noEmit # type check
18
+ npm test # run tests
19
+ npm install -g . # install globally to test `oh` command
20
+ ```
21
+
22
+ ## Making Changes
23
+
24
+ 1. Open an issue or discussion before starting large changes.
25
+ 2. Create a branch from `main`.
26
+ 3. Run `npx tsc --noEmit` and ensure zero errors before submitting a PR.
27
+ 4. Keep the README and CLI help text in sync with code changes.
28
+
29
+ ## Adding a New Provider
30
+
31
+ 1. Create `src/providers/yourprovider.ts` implementing the `Provider` interface from `src/providers/base.ts`.
32
+ 2. Implement `stream()`, `complete()`, `listModels()`, and `healthCheck()`.
33
+ 3. Add a case in `src/providers/index.ts:createProviderInstance()`.
34
+ 4. Add model pricing to `src/harness/cost.ts:MODEL_PRICING`.
35
+
36
+ ## Adding a New Tool
37
+
38
+ 1. Create `src/tools/YourTool/index.ts` implementing the `Tool` interface from `src/Tool.ts`.
39
+ 2. Define a Zod input schema, set `name`, `description`, `riskLevel`.
40
+ 3. Implement `call()`, `isReadOnly()`, `isConcurrencySafe()`, `prompt()`.
41
+ 4. Register it in `src/tools.ts:getAllTools()`.
42
+
43
+ ## Code Style
44
+
45
+ - TypeScript strict mode.
46
+ - Use Zod for all input validation.
47
+ - Async generators for streaming.
48
+ - No CLA required.
49
+
50
+ ## Reporting Issues
51
+
52
+ Open an issue on GitHub with:
53
+ - What you expected vs what happened
54
+ - Steps to reproduce
55
+ - Node.js version and OS
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wangz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # OpenHarness
2
+
3
+ ```
4
+ ___
5
+ / \
6
+ ( ) ___ ___ ___ _ _ _ _ _ ___ _ _ ___ ___ ___
7
+ `~w~` / _ \| _ \| __| \| | || | /_\ | _ \ \| | __/ __/ __|
8
+ (( )) | (_) | _/| _|| .` | __ |/ _ \| / .` | _|\__ \__ \
9
+ ))(( \___/|_| |___|_|\_|_||_/_/ \_\_|_\_|\_|___|___/___/
10
+ (( ))
11
+ `--`
12
+ ```
13
+
14
+ Open-source terminal coding agent. Build your own Claude Code with any LLM.
15
+
16
+ ![Status: Alpha](https://img.shields.io/badge/status-alpha-orange)
17
+ ![Node.js 18+](https://img.shields.io/badge/node-18%2B-green)
18
+ ![TypeScript](https://img.shields.io/badge/typescript-strict-blue)
19
+ ![License: MIT](https://img.shields.io/badge/license-MIT-green)
20
+
21
+ ---
22
+
23
+ ## Quick Start
24
+
25
+ ```bash
26
+ npm install -g openharness
27
+ oh
28
+ ```
29
+
30
+ That's it. Just type `oh` to start chatting with your local Ollama model.
31
+
32
+ ```bash
33
+ oh # auto-detect Ollama, start chatting
34
+ oh --model ollama/qwen2.5:7b # specific model
35
+ oh --model gpt-4o # use OpenAI (needs OPENAI_API_KEY)
36
+ oh --trust # auto-approve all tool calls
37
+ ```
38
+
39
+ ## Install
40
+
41
+ Requires **Node.js 18+**.
42
+
43
+ ```bash
44
+ # From npm (when published)
45
+ npm install -g openharness
46
+
47
+ # From source
48
+ git clone https://github.com/zhijiewong/openharness.git
49
+ cd openharness
50
+ npm install
51
+ npm install -g .
52
+ oh
53
+ ```
54
+
55
+ ## Why OpenHarness?
56
+
57
+ 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).
58
+
59
+ ## Tools
60
+
61
+ | Tool | Risk | Description |
62
+ |------|------|-------------|
63
+ | Read | low | Read files with line ranges |
64
+ | Edit | medium | Search-and-replace edits |
65
+ | Write | medium | Create or overwrite files |
66
+ | Bash | high | Shell commands with timeout |
67
+ | Glob | low | Find files by pattern |
68
+ | Grep | low | Regex content search |
69
+ | WebFetch | medium | Fetch URL content |
70
+
71
+ Low-risk tools auto-approve. Medium and high risk require confirmation in `ask` mode.
72
+
73
+ ## Commands
74
+
75
+ ```bash
76
+ oh # start chatting (default command)
77
+ oh --model MODEL # use a specific model
78
+ oh --trust # auto-approve all tools
79
+ oh --deny # block all non-read tools
80
+ oh --resume ID # resume a saved session
81
+ oh models # list models and pricing
82
+ oh tools # list tools and risk levels
83
+ oh init # set up .oh/ for current project
84
+ oh sessions # list saved sessions
85
+ oh rules # show project rules
86
+ oh --version # show version
87
+ ```
88
+
89
+ ## Providers
90
+
91
+ ```bash
92
+ # Local (free, no API key)
93
+ oh --model ollama/llama3
94
+ oh --model ollama/qwen2.5:7b-instruct
95
+
96
+ # Cloud (set API key as env var)
97
+ OPENAI_API_KEY=sk-... oh --model gpt-4o
98
+ ANTHROPIC_API_KEY=sk-ant-... oh --model claude-sonnet-4-6
99
+ OPENROUTER_API_KEY=sk-or-... oh --model openrouter/deepseek-chat
100
+ ```
101
+
102
+ ## Project Rules
103
+
104
+ Create `.oh/RULES.md` in any repo (or run `oh init`):
105
+
106
+ ```markdown
107
+ - Always run tests after changes
108
+ - Use strict TypeScript
109
+ - Never commit to main directly
110
+ ```
111
+
112
+ Rules load automatically into every session.
113
+
114
+ ## Tech Stack
115
+
116
+ | | OpenHarness | Claude Code |
117
+ |---|---|---|
118
+ | Language | TypeScript (strict) | TypeScript (strict) |
119
+ | Runtime | Node.js 18+ | Bun |
120
+ | Terminal UI | React + Ink | React + custom Ink fork |
121
+ | Tool schemas | Zod | Zod |
122
+ | Agent loop | async generators | async generators |
123
+ | Providers | Any (5 built-in) | Anthropic only |
124
+ | License | MIT | Proprietary |
125
+
126
+ ## Development
127
+
128
+ ```bash
129
+ git clone https://github.com/zhijiewong/openharness.git
130
+ cd openharness
131
+ npm install
132
+ npx tsx src/main.tsx # run in dev mode
133
+ npx tsc --noEmit # type check
134
+ ```
135
+
136
+ ### Adding a provider
137
+
138
+ Create `src/providers/yourprovider.ts` implementing the `Provider` interface, add a case in `src/providers/index.ts`.
139
+
140
+ ### Adding a tool
141
+
142
+ Create `src/tools/YourTool/index.ts` implementing the `Tool` interface with a Zod input schema, register it in `src/tools.ts`.
143
+
144
+ ## Contributing
145
+
146
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
147
+
148
+ ## License
149
+
150
+ MIT
151
+
152
+ ---
153
+
154
+ This project is not affiliated with Anthropic.
@@ -0,0 +1,74 @@
1
+ {
2
+ "gpt-4o": {
3
+ "provider": "openai",
4
+ "context_window": 128000,
5
+ "supports_tools": true,
6
+ "supports_vision": true,
7
+ "input_cost_per_mtok": 2.50,
8
+ "output_cost_per_mtok": 10.00
9
+ },
10
+ "gpt-4o-mini": {
11
+ "provider": "openai",
12
+ "context_window": 128000,
13
+ "supports_tools": true,
14
+ "supports_vision": true,
15
+ "input_cost_per_mtok": 0.15,
16
+ "output_cost_per_mtok": 0.60
17
+ },
18
+ "o3-mini": {
19
+ "provider": "openai",
20
+ "context_window": 200000,
21
+ "supports_tools": true,
22
+ "supports_vision": false,
23
+ "input_cost_per_mtok": 1.10,
24
+ "output_cost_per_mtok": 4.40
25
+ },
26
+ "claude-sonnet-4-6": {
27
+ "provider": "anthropic",
28
+ "context_window": 200000,
29
+ "supports_tools": true,
30
+ "supports_vision": true,
31
+ "input_cost_per_mtok": 3.00,
32
+ "output_cost_per_mtok": 15.00
33
+ },
34
+ "claude-haiku-4-5": {
35
+ "provider": "anthropic",
36
+ "context_window": 200000,
37
+ "supports_tools": true,
38
+ "supports_vision": true,
39
+ "input_cost_per_mtok": 0.80,
40
+ "output_cost_per_mtok": 4.00
41
+ },
42
+ "claude-opus-4-6": {
43
+ "provider": "anthropic",
44
+ "context_window": 200000,
45
+ "supports_tools": true,
46
+ "supports_vision": true,
47
+ "input_cost_per_mtok": 15.00,
48
+ "output_cost_per_mtok": 75.00
49
+ },
50
+ "deepseek-chat": {
51
+ "provider": "deepseek",
52
+ "context_window": 64000,
53
+ "supports_tools": true,
54
+ "supports_vision": false,
55
+ "input_cost_per_mtok": 0.14,
56
+ "output_cost_per_mtok": 0.28
57
+ },
58
+ "deepseek-coder": {
59
+ "provider": "deepseek",
60
+ "context_window": 64000,
61
+ "supports_tools": true,
62
+ "supports_vision": false,
63
+ "input_cost_per_mtok": 0.14,
64
+ "output_cost_per_mtok": 0.28
65
+ },
66
+ "qwen-turbo": {
67
+ "provider": "qwen",
68
+ "context_window": 128000,
69
+ "supports_tools": true,
70
+ "supports_vision": false,
71
+ "input_cost_per_mtok": 0.20,
72
+ "output_cost_per_mtok": 0.60
73
+ }
74
+ }
@@ -0,0 +1,25 @@
1
+ You are an AI coding assistant powered by OpenHarness. You help users with software engineering tasks by reading files, editing code, running commands, and managing their codebase.
2
+
3
+ # Core Principles
4
+
5
+ - Be concise and direct. Lead with the answer or action, not reasoning.
6
+ - Read code before suggesting changes. Understand existing patterns.
7
+ - Make the smallest change that solves the problem.
8
+ - Don't add features, refactoring, or improvements beyond what was asked.
9
+ - Don't add error handling for scenarios that can't happen.
10
+ - Prioritize writing safe, secure code. Watch for injection, XSS, and OWASP top 10.
11
+
12
+ # Tool Usage
13
+
14
+ - Use Read to examine files before editing them.
15
+ - Use Glob/Grep to find files and code patterns.
16
+ - Use Edit for targeted changes (not Write for modifying existing files).
17
+ - Use Bash for running tests, git commands, and system operations.
18
+ - Ask permission before destructive operations (delete, overwrite, force push).
19
+
20
+ # Working Style
21
+
22
+ - Break complex tasks into steps.
23
+ - Run tests after making changes.
24
+ - Use git to track progress on multi-step tasks.
25
+ - When stuck, explain what you tried and ask for guidance.
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: code-review
3
+ description: Systematic code review for bugs, security, and quality
4
+ whenToUse: When reviewing code changes, PRs, or completed implementations
5
+ allowedTools: [Read, Glob, Grep, Bash]
6
+ ---
7
+
8
+ # Code Review
9
+
10
+ Review the code systematically for:
11
+
12
+ 1. **Correctness** — Does the code do what it claims? Logic errors?
13
+ 2. **Security** — SQL injection, XSS, command injection, path traversal, secrets in code?
14
+ 3. **Error handling** — Are errors caught and handled appropriately?
15
+ 4. **Edge cases** — Null/empty inputs, boundary conditions, concurrent access?
16
+ 5. **Performance** — Unnecessary loops, missing indexes, N+1 queries?
17
+ 6. **Readability** — Clear naming, reasonable complexity, adequate (not excessive) comments?
18
+
19
+ Report findings with file path, line number, severity (critical/warning/info), and suggested fix.
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: commit
3
+ description: Create well-formed git commits
4
+ whenToUse: When the user asks to commit changes or create a PR
5
+ allowedTools: [Bash, Read, Glob]
6
+ ---
7
+
8
+ # Git Commit Workflow
9
+
10
+ 1. Run `git status` and `git diff` to see what changed
11
+ 2. Run `git log --oneline -5` to match the repo's commit message style
12
+ 3. Stage specific files (not `git add -A`) to avoid committing secrets or binaries
13
+ 4. Write a concise commit message:
14
+ - First line: imperative mood, under 72 chars, describes the "why"
15
+ - Body (if needed): explain context, not just what changed
16
+ 5. Create the commit
17
+ 6. Run `git status` to verify success
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: debug
3
+ description: Systematic debugging approach
4
+ whenToUse: When encountering any bug, test failure, or unexpected behavior
5
+ allowedTools: [Read, Bash, Grep, Glob]
6
+ ---
7
+
8
+ # Systematic Debugging
9
+
10
+ Follow this process:
11
+
12
+ 1. **Reproduce** — Confirm the bug exists. Run the failing test or command.
13
+ 2. **Read the error** — What does the error message actually say? Read the full stack trace.
14
+ 3. **Locate** — Find the exact line where the error occurs. Read the surrounding code.
15
+ 4. **Understand** — Why does this code produce the wrong result? Trace the data flow.
16
+ 5. **Hypothesize** — Form a specific theory about the cause.
17
+ 6. **Verify** — Test your theory with a minimal change or print statement.
18
+ 7. **Fix** — Make the smallest change that fixes the bug.
19
+ 8. **Confirm** — Run the test/command again to verify the fix works.
20
+
21
+ Rules:
22
+ - Don't guess. Read the error message carefully.
23
+ - Don't change multiple things at once.
24
+ - Don't skip the reproduce step.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: tdd
3
+ description: Test-driven development workflow
4
+ whenToUse: When implementing any feature or bugfix, before writing implementation code
5
+ allowedTools: [Read, Edit, Write, Bash, Glob, Grep]
6
+ ---
7
+
8
+ # Test-Driven Development
9
+
10
+ Follow this workflow strictly:
11
+
12
+ 1. **Write the test first** — Create a failing test that describes the expected behavior
13
+ 2. **Run the test** — Verify it fails for the right reason
14
+ 3. **Write minimal implementation** — Only enough code to make the test pass
15
+ 4. **Run tests again** — Verify all tests pass
16
+ 5. **Refactor** — Clean up the code while keeping tests green
17
+
18
+ Rules:
19
+ - Never write implementation before the test
20
+ - Each test should test one thing
21
+ - Keep tests fast and isolated
22
+ - Use descriptive test names that explain the behavior
package/dist/Tool.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Tool interface — mirrors Claude Code's Tool.ts pattern.
3
+ * Every tool implements this interface with Zod input validation.
4
+ */
5
+ import type { z } from "zod";
6
+ import type { RiskLevel } from "./types/permissions.js";
7
+ export type ToolResult = {
8
+ output: string;
9
+ isError: boolean;
10
+ };
11
+ export type ToolContext = {
12
+ workingDir: string;
13
+ abortSignal?: AbortSignal;
14
+ };
15
+ export type Tool<Input extends z.ZodType = z.ZodType> = {
16
+ readonly name: string;
17
+ readonly description: string;
18
+ readonly inputSchema: Input;
19
+ readonly riskLevel: RiskLevel;
20
+ /** Whether this invocation is read-only (no side effects). */
21
+ isReadOnly(input: z.infer<Input>): boolean;
22
+ /** Whether this tool can run in parallel with other tools. */
23
+ isConcurrencySafe(input: z.infer<Input>): boolean;
24
+ /** Execute the tool. */
25
+ call(input: z.infer<Input>, context: ToolContext): Promise<ToolResult>;
26
+ /** Generate the prompt description for the LLM. */
27
+ prompt(): string;
28
+ };
29
+ export type Tools = Tool[];
30
+ /**
31
+ * Convert tool to the format expected by OpenAI-compatible APIs.
32
+ */
33
+ export declare function toolToAPIFormat(tool: Tool): {
34
+ type: "function";
35
+ function: {
36
+ name: string;
37
+ description: string;
38
+ parameters: unknown;
39
+ };
40
+ };
41
+ /**
42
+ * Find a tool by name from a list of tools.
43
+ */
44
+ export declare function findToolByName(tools: Tools, name: string): Tool | undefined;
45
+ //# sourceMappingURL=Tool.d.ts.map
@@ -0,0 +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,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,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;CAC3B,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"}
package/dist/Tool.js ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Tool interface — mirrors Claude Code's Tool.ts pattern.
3
+ * Every tool implements this interface with Zod input validation.
4
+ */
5
+ /**
6
+ * Convert tool to the format expected by OpenAI-compatible APIs.
7
+ */
8
+ export function toolToAPIFormat(tool) {
9
+ return {
10
+ type: "function",
11
+ function: {
12
+ name: tool.name,
13
+ description: tool.prompt(),
14
+ parameters: zodToJsonSchema(tool.inputSchema),
15
+ },
16
+ };
17
+ }
18
+ /**
19
+ * Simple Zod-to-JSON-Schema converter for tool parameters.
20
+ * Handles the common cases (object, string, number, boolean, optional).
21
+ */
22
+ function zodToJsonSchema(schema) {
23
+ // Zod provides .description and ._def for introspection
24
+ const def = schema._def;
25
+ if (def?.typeName === "ZodObject") {
26
+ const shape = schema.shape;
27
+ const properties = {};
28
+ const required = [];
29
+ for (const [key, value] of Object.entries(shape)) {
30
+ const field = value;
31
+ const fieldDef = field._def;
32
+ if (fieldDef?.typeName === "ZodOptional") {
33
+ properties[key] = zodToJsonSchema(fieldDef.innerType);
34
+ }
35
+ else {
36
+ properties[key] = zodToJsonSchema(field);
37
+ required.push(key);
38
+ }
39
+ // Add description if present
40
+ if (field.description) {
41
+ properties[key].description = field.description;
42
+ }
43
+ }
44
+ return { type: "object", properties, required };
45
+ }
46
+ if (def?.typeName === "ZodString")
47
+ return { type: "string" };
48
+ if (def?.typeName === "ZodNumber")
49
+ return { type: "number" };
50
+ if (def?.typeName === "ZodBoolean")
51
+ return { type: "boolean" };
52
+ if (def?.typeName === "ZodArray")
53
+ return { type: "array", items: zodToJsonSchema(def.type) };
54
+ return { type: "string" }; // fallback
55
+ }
56
+ /**
57
+ * Find a tool by name from a list of tools.
58
+ */
59
+ export function findToolByName(tools, name) {
60
+ return tools.find((t) => t.name === name);
61
+ }
62
+ //# sourceMappingURL=Tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tool.js","sourceRoot":"","sources":["../src/Tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoCH;;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"}
@@ -0,0 +1,16 @@
1
+ import type { Provider } from "../providers/base.js";
2
+ import type { Tools } from "../Tool.js";
3
+ import type { PermissionMode } from "../types/permissions.js";
4
+ import type { Message } from "../types/message.js";
5
+ type AppProps = {
6
+ provider: Provider;
7
+ tools: Tools;
8
+ permissionMode: PermissionMode;
9
+ systemPrompt?: string;
10
+ model?: string;
11
+ initialMessages?: Message[];
12
+ };
13
+ declare const DEFAULT_SYSTEM_PROMPT = "You are OpenHarness, an AI coding assistant running in the user's terminal.\nYou have access to tools for reading, writing, and editing files, running shell commands, and searching the codebase.\nBe concise. Use tools proactively to help the user.";
14
+ export default function App({ provider, tools, permissionMode, systemPrompt, model, initialMessages, }: AppProps): import("react/jsx-runtime").JSX.Element;
15
+ export { DEFAULT_SYSTEM_PROMPT };
16
+ //# sourceMappingURL=App.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { loadRulesAsPrompt } from "../harness/rules.js";
4
+ import { detectProject, projectContextToPrompt } from "../harness/onboarding.js";
5
+ import REPL from "./REPL.js";
6
+ const DEFAULT_SYSTEM_PROMPT = `You are OpenHarness, an AI coding assistant running in the user's terminal.
7
+ You have access to tools for reading, writing, and editing files, running shell commands, and searching the codebase.
8
+ Be concise. Use tools proactively to help the user.`;
9
+ export default function App({ provider, tools, permissionMode, systemPrompt, model, initialMessages, }) {
10
+ // Build full system prompt with rules and project context
11
+ const fullSystemPrompt = useMemo(() => {
12
+ const parts = [systemPrompt || DEFAULT_SYSTEM_PROMPT];
13
+ const projectCtx = detectProject();
14
+ const projectPrompt = projectContextToPrompt(projectCtx);
15
+ if (projectPrompt)
16
+ parts.push(projectPrompt);
17
+ const rulesPrompt = loadRulesAsPrompt();
18
+ if (rulesPrompt)
19
+ parts.push(rulesPrompt);
20
+ return parts.join("\n\n");
21
+ }, [systemPrompt]);
22
+ return (_jsx(REPL, { provider: provider, tools: tools, permissionMode: permissionMode, systemPrompt: fullSystemPrompt, model: model, initialMessages: initialMessages }));
23
+ }
24
+ export { DEFAULT_SYSTEM_PROMPT };
25
+ //# sourceMappingURL=App.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"App.js","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAKvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACjF,OAAO,IAAI,MAAM,WAAW,CAAC;AAW7B,MAAM,qBAAqB,GAAG;;oDAEsB,CAAC;AAErD,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,EAC1B,QAAQ,EACR,KAAK,EACL,cAAc,EACd,YAAY,EACZ,KAAK,EACL,eAAe,GACN;IACT,0DAA0D;IAC1D,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,EAAE;QACpC,MAAM,KAAK,GAAa,CAAC,YAAY,IAAI,qBAAqB,CAAC,CAAC;QAEhE,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;QACnC,MAAM,aAAa,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;QACzD,IAAI,aAAa;YAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAE7C,MAAM,WAAW,GAAG,iBAAiB,EAAE,CAAC;QACxC,IAAI,WAAW;YAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAEzC,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAEnB,OAAO,CACL,KAAC,IAAI,IACH,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,EACZ,cAAc,EAAE,cAAc,EAC9B,YAAY,EAAE,gBAAgB,EAC9B,KAAK,EAAE,KAAK,EACZ,eAAe,EAAE,eAAe,GAChC,CACH,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Message } from "../types/message.js";
2
+ import type { ToolCallState } from "./ToolCallDisplay.js";
3
+ type MessagesProps = {
4
+ messages: Message[];
5
+ toolCalls: Map<string, ToolCallState>;
6
+ };
7
+ export default function Messages({ messages, toolCalls }: MessagesProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=Messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Messages.d.ts","sourceRoot":"","sources":["../../src/components/Messages.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,aAAa,2CAQtE"}
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import ToolCallDisplay from "./ToolCallDisplay.js";
4
+ export default function Messages({ messages, toolCalls }) {
5
+ return (_jsx(Box, { flexDirection: "column", children: messages.map((msg) => (_jsx(MessageRow, { message: msg, toolCalls: toolCalls }, msg.uuid))) }));
6
+ }
7
+ function MessageRow({ message, toolCalls, }) {
8
+ const { role, content } = message;
9
+ if (role === "user") {
10
+ return (_jsxs(Box, { marginY: 0, children: [_jsx(Text, { color: "cyan", bold: true, children: "❯ " }), _jsx(Text, { bold: true, children: content })] }));
11
+ }
12
+ if (role === "assistant") {
13
+ return (_jsxs(Box, { flexDirection: "column", marginY: 0, children: [content ? (_jsxs(Box, { children: [_jsx(Text, { color: "magenta", bold: true, children: "◆ " }), _jsx(Text, { children: content })] })) : null, message.toolCalls?.map((tc) => {
14
+ const state = toolCalls.get(tc.id);
15
+ return state ? _jsx(ToolCallDisplay, { toolCall: state }, tc.id) : null;
16
+ })] }));
17
+ }
18
+ if (role === "tool") {
19
+ return null; // Tool results shown inline via ToolCallDisplay
20
+ }
21
+ return null;
22
+ }
23
+ //# sourceMappingURL=Messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Messages.js","sourceRoot":"","sources":["../../src/components/Messages.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAGhC,OAAO,eAAe,MAAM,sBAAsB,CAAC;AAOnD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAiB;IACrE,OAAO,CACL,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,YACxB,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACrB,KAAC,UAAU,IAAgB,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,IAA5C,GAAG,CAAC,IAAI,CAAwC,CAClE,CAAC,GACE,CACP,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,EAClB,OAAO,EACP,SAAS,GAIV;IACC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAElC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,CACL,MAAC,GAAG,IAAC,OAAO,EAAE,CAAC,aACb,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,kBAAE,IAAI,GAAQ,EACrC,KAAC,IAAI,IAAC,IAAI,kBAAE,OAAO,GAAQ,IACvB,CACP,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,aACnC,OAAO,CAAC,CAAC,CAAC,CACT,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,kBAAE,IAAI,GAAQ,EACxC,KAAC,IAAI,cAAE,OAAO,GAAQ,IAClB,CACP,CAAC,CAAC,CAAC,IAAI,EACP,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;oBAC7B,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;oBACnC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAC,eAAe,IAAa,QAAQ,EAAE,KAAK,IAAtB,EAAE,CAAC,EAAE,CAAqB,CAAC,CAAC,CAAC,IAAI,CAAC;gBACzE,CAAC,CAAC,IACE,CACP,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,CAAC,gDAAgD;IAC/D,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,9 @@
1
+ type PermissionPromptProps = {
2
+ toolName: string;
3
+ description: string;
4
+ riskLevel: string;
5
+ onResolve: (allowed: boolean) => void;
6
+ };
7
+ export default function PermissionPrompt({ toolName, description, riskLevel, onResolve, }: PermissionPromptProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=PermissionPrompt.d.ts.map