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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/extension-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@ export type {
ProgressUpdate,
AIContext,
WorkspaceContext,
AICommand,
AICommandResult,
AICommandHandlerFunction,
AICommandDefinition,
AICommandParameter,
AICommandExample,
} from "./types/index.js";
199 changes: 199 additions & 0 deletions packages/vscode-extension/VERIFY_AI_HOOKS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# How to Verify AI Agent Hooks Work

## Quick Verification Steps

### 1. Build Check

```bash
# From root directory
pnpm --filter lighthouse-extension run build
pnpm --filter lighthouse-extension run build:tsc
```

If builds succeed, the hooks are properly integrated.

### 2. Type Check

```bash
pnpm --filter lighthouse-extension run build:tsc
```

No TypeScript errors = hooks are correctly typed.

### 3. Test in VSCode Extension Host

#### Option A: Unit Test (Run existing extension test)

```bash
pnpm --filter lighthouse-extension run test -- extension.test.ts
```

Look for the "AI Agent Hooks" test section - it verifies:

- Hooks are exposed via `getAIAgentHooks()`
- All 4 methods are available
- Workspace context can be retrieved

#### Option B: Manual Verification in VSCode

1. **Package the extension:**

```bash
cd packages/vscode-extension
npm run package
```

2. **Install in VSCode:**
- Open VSCode
- Go to Extensions view
- Install from VSIX file

3. **Open Developer Console:**
- Press `Cmd+Shift+P` (Mac) or `Ctrl+Shift+P` (Windows/Linux)
- Type "Developer: Toggle Developer Tools"
- Go to Console tab

4. **Test the hooks:**

```javascript
// Get the extension instance
const ext = vscode.extensions.getExtension("lighthouse-web3.lighthouse-storage-for-vscode");
if (ext && ext.isActive) {
const extension = ext.exports?.extension;

// Get AI hooks
const aiHooks = extension?.getAIAgentHooks();

// Test getWorkspaceContext
const context = await aiHooks?.getWorkspaceContext();
console.log("Workspace context:", context);

// Test onProgress
const unsubscribe = aiHooks?.onProgress((progress) => {
console.log("Progress update:", progress);
});

// Test onAICommand (workspace context command)
const result = await aiHooks?.onAICommand("lighthouse.workspace.context", {});
console.log("Command result:", result);

// Cleanup
unsubscribe?.();
}
```

### 4. Programmatic Test Script

Create a test file `test-hooks-manual.ts`:

```typescript
import { createExtensionCore } from "@lighthouse-tooling/extension-core";
import { AIAgentHooksImpl } from "./src/ai/ai-agent-hooks";

async function testAIAgentHooks() {
console.log("Testing AI Agent Hooks...\n");

// Set API key
process.env.LIGHTHOUSE_API_KEY = "test-key";

// Create extension core
const extensionCore = createExtensionCore();
await extensionCore.initialize();

// Create AI hooks
const aiHooks = new AIAgentHooksImpl(extensionCore);

try {
// Test 1: getWorkspaceContext
console.log("Test 1: getWorkspaceContext()");
const context = await aiHooks.getWorkspaceContext();
console.log("✓ Workspace context retrieved:", !!context);
console.log(" - Project path:", context.projectPath || "N/A");
console.log(" - Files:", context.files?.length || 0);
console.log("");

// Test 2: onAICommand
console.log("Test 2: onAICommand()");
const result = await aiHooks.onAICommand("lighthouse.workspace.context", {});
console.log("✓ Command executed successfully:", !!result);
console.log("");

// Test 3: registerAIFunction
console.log("Test 3: registerAIFunction()");
let customFuncCalled = false;
aiHooks.registerAIFunction("test.custom", async (cmd) => {
customFuncCalled = true;
return { success: true, data: { message: "Custom function called" } };
});
const customResult = await aiHooks.onAICommand("test.custom", {});
console.log("✓ Custom function registered and called:", customFuncCalled);
console.log("");

// Test 4: onProgress
console.log("Test 4: onProgress()");
let progressReceived = false;
const unsubscribe = aiHooks.onProgress((progress) => {
progressReceived = true;
console.log(" Progress update received:", progress.title || "N/A");
});
console.log("✓ Progress callback registered");
unsubscribe();
console.log("✓ Unsubscribe function works");
console.log("");

console.log("✅ All tests passed!");
} catch (error) {
console.error("❌ Test failed:", error);
} finally {
aiHooks.dispose();
await extensionCore.dispose();
}
}

testAIAgentHooks();
```

Run with:

```bash
ts-node packages/vscode-extension/test-hooks-manual.ts
```

### 5. Check Build Output

Verify hooks are in the built code:

```bash
grep -i "getAIAgentHooks\|AIAgentHooks" packages/vscode-extension/dist/extension.js
```

Should show:

- `getAIAgentHooks()` method
- `AIAgentHooksImpl` class
- Import statements

### 6. Lint Check

```bash
pnpm --filter lighthouse-extension run lint
```

Should only show warnings (not errors) - errors mean something is broken.

## Expected Results

✅ **All good if:**

- Build succeeds without errors
- TypeScript compilation succeeds
- `getAIAgentHooks()` returns an object with 4 methods
- No runtime errors when calling hook methods
- Progress callbacks can be registered/unregistered

❌ **Something wrong if:**

- Build fails
- TypeScript errors
- Methods are undefined
- Runtime errors when using hooks
128 changes: 128 additions & 0 deletions packages/vscode-extension/src/__tests__/ai-agent-hooks.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* AI Agent Hooks Tests
* @fileoverview Tests for AI Agent Hooks implementation
*/

import { AIAgentHooksImpl } from "../ai/ai-agent-hooks";
import { createExtensionCore, type ExtensionCore } from "@lighthouse-tooling/extension-core";

describe("AIAgentHooksImpl", () => {
let extensionCore: ExtensionCore;
let aiHooks: AIAgentHooksImpl;

beforeEach(() => {
// Set API key for ExtensionCore's AI command handler
process.env.LIGHTHOUSE_API_KEY = "test-api-key";

// Create real extension core
extensionCore = createExtensionCore();
aiHooks = new AIAgentHooksImpl(extensionCore);
});

afterEach(async () => {
// Clean up
if (aiHooks) {
aiHooks.dispose();
}
if (extensionCore && extensionCore.isInitialized()) {
await extensionCore.dispose();
}
});

describe("initialization", () => {
it("should create AI hooks instance", () => {
expect(aiHooks).toBeDefined();
expect(aiHooks).toBeInstanceOf(AIAgentHooksImpl);
});
});

describe("getWorkspaceContext", () => {
it("should get workspace context", async () => {
// Initialize extension core first
await extensionCore.initialize();

const context = await aiHooks.getWorkspaceContext();

expect(context).toBeDefined();
expect(context).toHaveProperty("projectPath");
expect(context).toHaveProperty("files");
expect(context).toHaveProperty("datasets");
});
});

describe("onAICommand", () => {
beforeEach(async () => {
await extensionCore.initialize();
});

it("should handle workspace context command", async () => {
const result = await aiHooks.onAICommand("lighthouse.workspace.context", {});

expect(result).toBeDefined();
expect(result).toHaveProperty("projectPath");
});

it("should handle invalid command gracefully", async () => {
await expect(aiHooks.onAICommand("invalid.command", {})).rejects.toThrow();
});
});

describe("registerAIFunction", () => {
beforeEach(async () => {
await extensionCore.initialize();
});

it("should register custom AI function", async () => {
const handler = jest.fn().mockResolvedValue({
success: true,
data: { result: "test" },
});

aiHooks.registerAIFunction("custom.test", handler);

const result = await aiHooks.onAICommand("custom.test", { test: "value" });

expect(handler).toHaveBeenCalled();
expect(result).toEqual({ result: "test" });
});
});

describe("onProgress", () => {
beforeEach(async () => {
await extensionCore.initialize();
});

it("should subscribe to progress updates", () => {
const callback = jest.fn();
const unsubscribe = aiHooks.onProgress(callback);

expect(typeof unsubscribe).toBe("function");

// Unsubscribe
unsubscribe();
});

it("should allow multiple progress callbacks", () => {
const callback1 = jest.fn();
const callback2 = jest.fn();

const unsubscribe1 = aiHooks.onProgress(callback1);
const unsubscribe2 = aiHooks.onProgress(callback2);

expect(typeof unsubscribe1).toBe("function");
expect(typeof unsubscribe2).toBe("function");

unsubscribe1();
unsubscribe2();
});
});

describe("dispose", () => {
it("should dispose resources", () => {
const callback = jest.fn();
aiHooks.onProgress(callback);

expect(() => aiHooks.dispose()).not.toThrow();
});
});
});
25 changes: 25 additions & 0 deletions packages/vscode-extension/src/__tests__/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,29 @@ describe("LighthouseVSCodeExtension", () => {
expect(getLanguageFromExtension("test")).toBe("plaintext");
});
});

describe("AI Agent Hooks", () => {
beforeEach(async () => {
await extension.activate();
});

it("should expose AI agent hooks", () => {
const aiHooks = extension.getAIAgentHooks();

expect(aiHooks).toBeDefined();
expect(typeof aiHooks.onAICommand).toBe("function");
expect(typeof aiHooks.getWorkspaceContext).toBe("function");
expect(typeof aiHooks.registerAIFunction).toBe("function");
expect(typeof aiHooks.onProgress).toBe("function");
});

it("should get workspace context via hooks", async () => {
const aiHooks = extension.getAIAgentHooks();
const context = await aiHooks.getWorkspaceContext();

expect(context).toBeDefined();
expect(context).toHaveProperty("projectPath");
expect(context).toHaveProperty("files");
});
});
});
Loading
Loading