Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .changeset/serious-turtles-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"hai-build-code-generator": minor
---

Merged changes from Cline 3.20.3 (see [changelog](https://github.com/cline/cline/blob/main/CHANGELOG.md#3203)).
12 changes: 10 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"ecmaVersion": 6,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"plugins": ["@typescript-eslint", "eslint-rules"],
"rules": {
"@typescript-eslint/naming-convention": [
"warn",
Expand All @@ -19,7 +19,15 @@
"eqeqeq": "warn",
"no-throw-literal": "warn",
"semi": "off",
"react-hooks/exhaustive-deps": "off"
"react-hooks/exhaustive-deps": "off",
"eslint-rules/no-direct-vscode-api": "warn",
"no-restricted-syntax": [
"error",
{
"selector": "VariableDeclarator[id.type=\"ObjectPattern\"][init.object.name=\"process\"][init.property.name=\"env\"]",
"message": "Use process.env.VARIABLE_NAME directly instead of destructuring"
}
]
},
"ignorePatterns": ["out", "dist", "**/*.d.ts"]
}
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
demo.gif filter=lfs diff=lfs merge=lfs -text
assets/docs/demo.gif filter=lfs diff=lfs merge=lfs -text

* text=auto eol=lf
32 changes: 13 additions & 19 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ body:
- type: markdown
attributes:
value: |
**Important:** All bug reports must be reproducible using Claude 3.5 Sonnet. Cline uses complex prompts so less capable models may not work as expected.
**Important:** All bug reports must be reproducible using Claude 4 Sonnet. HAI uses complex prompts so less capable models may not work as expected.
- type: textarea
id: what-happened
attributes:
Expand All @@ -24,7 +24,7 @@ body:
2.
3.
validations:
required: true
required: false
- type: textarea
id: logs
attributes:
Expand All @@ -36,23 +36,22 @@ body:
attributes:
label: Provider/Model
description: What provider and model were you using when the issue occurred?
placeholder: "e.g., cline:anthropic/claude-3.7-sonnet, gemini:gemini-2.5-pro-exp-03-25"
validations:
required: true
- type: input
id: operating-system
attributes:
label: Operating System
description: What operating system are you using?
placeholder: "e.g., Windows 11, macOS Sonoma, Ubuntu 22.04"
placeholder: "e.g., anthropic/claude-3.7-sonnet, gemini:gemini-2.5-pro-exp-03-25"
validations:
required: true
- type: textarea
id: system-info
attributes:
label: System Info
description: What system information is relevant to the issue?
placeholder: "e.g., CPU: Intel Core i7-11700K, GPU: NVIDIA GeForce RTX 3070, RAM: 32GB DDR4"
label: System Information
description: What operating system and hardware are you using?
placeholder: |
Operating System: Windows 11, macOS Sonoma, Ubuntu 22.04, etc.
Hardware: CPU, GPU, RAM specifications if relevant
e.g.,
OS: Windows 11
CPU: Intel Core i7-11700K
GPU: NVIDIA GeForce RTX 3070
RAM: 32GB DDR4
validations:
required: true
- type: input
Expand All @@ -63,8 +62,3 @@ body:
placeholder: "e.g., 1.2.3"
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context about the problem here, such as screenshots or related issues.
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@

### Additional Notes

<!-- Add any additional notes for reviewers -->
<!-- Add any additional notes for reviewers -->
25 changes: 25 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# This workflow will only label and/or close 30 issues at a time in order to avoid exceeding a rate limit.
# More info: https://docs.github.com/en/actions/use-cases-and-examples/project-management/closing-inactive-issues
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"

jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
days-before-issue-stale: 60
days-before-issue-close: 14
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 60 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
days-before-pr-stale: -1
days-before-pr-close: -1
exempt-issue-labels: "pinned,security"
repo-token: ${{ secrets.GITHUB_TOKEN }}
32 changes: 32 additions & 0 deletions .github/workflows/test-stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Test Stale Issues Workflow
on:
workflow_dispatch:
inputs:
days-before-stale:
description: "Days before an issue becomes stale"
required: true
default: "1"
days-before-close:
description: "Days before a stale issue is closed"
required: true
default: "1"

jobs:
test-stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@28ca103
with:
days-before-issue-stale: ${{ github.event.inputs.days-before-stale }}
days-before-issue-close: ${{ github.event.inputs.days-before-close }}
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for ${{ github.event.inputs.days-before-stale }} days with no activity."
close-issue-message: "This issue was closed because it has been inactive for ${{ github.event.inputs.days-before-close }} days since being marked as stale."
days-before-pr-stale: -1
days-before-pr-close: -1
exempt-issue-labels: "pinned,security"
repo-token: ${{ secrets.GITHUB_TOKEN }}
debug-only: true
15 changes: 13 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ jobs:
if: steps.webview-cache.outputs.cache-hit != 'true'
run: cd webview-ui && npm ci

- name: Install xvfb on Linux
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y xvfb

- name: Install local modules on windows
if: runner.os == 'Windows' && steps.root-cache.outputs.cache-hit == 'true'
run: |
npm install eslint-plugin-eslint-rules
cd webview-ui/ && npm install eslint-plugin-eslint-rules

- name: Set up NPM on Windows
if: runner.os == 'Windows'
run: |
Expand All @@ -86,8 +96,9 @@ jobs:
- name: Build Tests and Extension
run: npm run pretest

- name: Unit Tests
run: npm run test:unit
# Unit Tests disabled due to module system conflicts between backend and webview-ui
# - name: Unit Tests
# run: npm run test:unit

# Run extension tests with coverage
- name: Extension Tests with Coverage
Expand Down
24 changes: 14 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,33 @@ tmp
*.vsix

.DS_Store
.idea

pnpm-lock.yaml
.hai/

.haiignore
.clineignore

.env
.venv
.actrc

webview-ui/src/**/*.js
webview-ui/src/**/*.js.map

# Ignore coverage directories and files
coverage
# But don't ignore the coverage scripts in .github/scripts/
!.github/scripts/coverage/

*evals.env

# Generated proto files
src/shared/proto/*.ts
src/core/controller/*/methods.ts
src/core/controller/*/index.ts
src/core/controller/grpc-service-config.ts
## Generated files ##
src/generated/
src/shared/proto/
webview-ui/src/services/grpc-client.ts
src/standalone/server-setup.ts

# E2E Tests
test-results

# TAG:HAI
.hai/
.hai.config
.haiignore
11 changes: 6 additions & 5 deletions .hairules/hai-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ Key providers include:
- **OpenRouter**: Meta-provider supporting multiple model providers
- **AWS Bedrock**: Integration with Amazon's AI services
- **Gemini**: Google's AI models
- **Cerebras**: High-performance inference with Llama, Qwen, and DeepSeek models
- **Ollama**: Local model hosting
- **LM Studio**: Local model hosting
- **VSCode LM**: VSCode's built-in language models
Expand Down Expand Up @@ -220,7 +221,7 @@ class Task {
await pWaitFor(() => this.userMessageContentReady)

// 4. Continue loop with tool result
const recDidEndLoop = await this.recursivelyMakeHAIRequests(
const recDidEndLoop = await this.recursivelyMakeClineRequests(
this.userMessageContent
)
}
Expand Down Expand Up @@ -430,7 +431,7 @@ The Task class provides robust task state management and resumption capabilities
class Task {
async resumeTaskFromHistory() {
// 1. Load saved state
this.clineMessages = await getSavedHAIMessages(this.getContext(), this.taskId)
this.clineMessages = await getSavedClineMessages(this.getContext(), this.taskId)
this.apiConversationHistory = await getSavedApiConversationHistory(this.getContext(), this.taskId)

// 2. Handle interrupted tool executions
Expand Down Expand Up @@ -462,7 +463,7 @@ class Task {
private async saveTaskState() {
// Save conversation history
await saveApiConversationHistory(this.getContext(), this.taskId, this.apiConversationHistory)
await saveHAIMessages(this.getContext(), this.taskId, this.clineMessages)
await saveClineMessages(this.getContext(), this.taskId, this.clineMessages)

// Create checkpoint
const commitHash = await this.checkpointTracker?.commit()
Expand Down Expand Up @@ -715,7 +716,7 @@ The Controller class manages MCP servers through the McpHub service:
class Controller {
mcpHub?: McpHub

constructor(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel, webviewProvider: WebviewProvider) {
constructor(context: vscode.ExtensionContext, webviewProvider: WebviewProvider) {
this.mcpHub = new McpHub(this)
}

Expand All @@ -734,7 +735,7 @@ class Controller {
const task = `Set up the MCP server from ${mcpDetails.githubUrl}...`

// Initialize task and show chat view
await this.initHAIWithTask(task)
await this.initClineWithTask(task)
}
}
```
Expand Down
89 changes: 89 additions & 0 deletions .hairules/protobuf-development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# HAI Protobuf Development Guide

This guide outlines how to add new gRPC endpoints for communication between the webview (frontend) and the extension host (backend).

## Overview

HAI uses [Protobuf](https://protobuf.dev/) to define a strongly-typed API, ensuring efficient and type-safe communication. All definitions are in the `/proto` directory. The compiler and plugins are included as project dependencies, so no manual installation is needed.

## Key Concepts & Best Practices

- **File Structure**: Each feature domain should have its own `.proto` file (e.g., `account.proto`, `task.proto`).
- **Message Design**:
- For simple, single-value data, use the shared types in `proto/common.proto` (e.g., `StringRequest`, `Empty`, `Int64Request`). This promotes consistency.
- For complex data structures, define custom messages within the feature's `.proto` file (see `task.proto` for examples like `NewTaskRequest`).
- **Naming Conventions**:
- Services: `PascalCaseService` (e.g., `AccountService`).
- RPCs: `camelCase` (e.g., `accountEmailIdentified`).
- Messages: `PascalCase` (e.g., `StringRequest`).
- **Streaming**: For server-to-client streaming, use the `stream` keyword on the response type. See `subscribeToAuthCallback` in `account.proto` for an example.

---

## 4-Step Development Workflow

Here’s how to add a new RPC, using `scrollToSettings` as an example.

### 1. Define the RPC in a `.proto` File

Add your service method to the appropriate file in the `proto/` directory.

**File: `proto/ui.proto`**
```proto
service UiService {
// ... other RPCs
// Scrolls to a specific settings section in the settings view
rpc scrollToSettings(StringRequest) returns (KeyValuePair);
}
```
Here, we use the common `StringRequest` and `KeyValuePair` types.

### 2. Compile Definitions

After editing a `.proto` file, regenerate the TypeScript code. From the project root, run:
```bash
npm run protos
```
This command compiles all `.proto` files and outputs the generated code to `src/generated/` and `src/shared/`. Do not edit these generated files manually.

### 3. Implement the Backend Handler

Create the RPC implementation in the backend. Handlers are located in `src/core/controller/[service-name]/`.

**File: `src/core/controller/ui/scrollToSettings.ts`**
```typescript
import { Controller } from ".."
import { StringRequest, KeyValuePair } from "../../../shared/proto/common"

/**
* Executes a scroll to settings action
* @param controller The controller instance
* @param request The request containing the ID of the settings section to scroll to
* @returns KeyValuePair with action and value fields for the UI to process
*/
export async function scrollToSettings(controller: Controller, request: StringRequest): Promise<KeyValuePair> {
return KeyValuePair.create({
key: "scrollToSettings",
value: request.value || "",
})
}
```

### 4. Call the RPC from the Webview

Call the new RPC from a React component in `webview-ui/`. The generated client makes this simple.

**File: `webview-ui/src/components/browser/BrowserSettingsMenu.tsx`** (Example)
```tsx
import { UiServiceClient } from "../../../services/grpc"
import { StringRequest } from "../../../../shared/proto/common"

// ... inside a React component
const handleMenuClick = async () => {
try {
await UiServiceClient.scrollToSettings(StringRequest.create({ value: "browser" }))
} catch (error) {
console.error("Error scrolling to browser settings:", error)
}
}
```
Loading
Loading