136 lines
4.2 KiB
Markdown
136 lines
4.2 KiB
Markdown
# AGENTS.md - Obsidian OpenCode Plugin
|
|
|
|
Guidelines for AI coding agents working on the obsidian-opencode plugin.
|
|
|
|
## Project Overview
|
|
|
|
Obsidian plugin that embeds the OpenCode AI assistant via an iframe. Spawns a local server process and displays its web UI in the Obsidian sidebar.
|
|
|
|
**Tech Stack:** TypeScript, Obsidian Plugin API, esbuild, Node.js child processes
|
|
|
|
## Build Commands
|
|
|
|
```bash
|
|
bun install # Install dependencies
|
|
bun run dev # Development (watch mode)
|
|
bun run build # Production (type-check + bundle)
|
|
```
|
|
|
|
Output: `main.js` (CommonJS bundle)
|
|
|
|
## Testing & Linting
|
|
|
|
**Not configured.** If adding:
|
|
- Tests: Vitest, files in `src/__tests__/` or `*.test.ts`
|
|
- Linting: ESLint + `@typescript-eslint/parser`
|
|
- Scripts: `"test": "vitest run"`, `"lint": "eslint src"`
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/
|
|
├── main.ts # Plugin entry, extends Plugin
|
|
├── types.ts # Types and constants
|
|
├── OpenCodeView.ts # Sidebar view (ItemView) with iframe
|
|
├── ProcessManager.ts # Server process lifecycle
|
|
└── SettingsTab.ts # Settings UI (PluginSettingTab)
|
|
```
|
|
|
|
## Code Style
|
|
|
|
### Imports
|
|
- ES modules with named imports
|
|
- Order: Obsidian API, Node.js builtins, local modules
|
|
- Use `type` for type-only imports
|
|
- Relative paths with `./` prefix
|
|
|
|
```typescript
|
|
import { Plugin, WorkspaceLeaf, Notice } from "obsidian";
|
|
import { spawn, ChildProcess } from "child_process";
|
|
import type OpenCodePlugin from "./main";
|
|
import { OpenCodeSettings, DEFAULT_SETTINGS } from "./types";
|
|
```
|
|
|
|
### Exports
|
|
- `export default class` for main plugin
|
|
- Named exports for other classes/types/constants
|
|
- One class per file, filename matches class (PascalCase)
|
|
|
|
### Naming Conventions
|
|
|
|
| Type | Convention | Example |
|
|
|------|------------|---------|
|
|
| Classes | PascalCase | `OpenCodePlugin`, `ProcessManager` |
|
|
| Interfaces/Types | PascalCase | `OpenCodeSettings`, `ProcessState` |
|
|
| Constants | UPPER_CASE or camelCase | `DEFAULT_SETTINGS`, `OPENCODE_VIEW_TYPE` |
|
|
| Variables/functions | camelCase | `getVaultPath`, `startServer` |
|
|
| Private members | camelCase (no prefix) | `private processManager` |
|
|
| Files | PascalCase (classes), lowercase (entry) | `ProcessManager.ts`, `main.ts` |
|
|
|
|
### TypeScript Patterns
|
|
- `strictNullChecks` enabled - handle null/undefined
|
|
- Union types for state: `"stopped" | "starting" | "running" | "error"`
|
|
- `async/await` over Promises
|
|
- Explicit return types on public methods
|
|
|
|
```typescript
|
|
getProcessState(): ProcessState {
|
|
return this.processManager?.getState() ?? "stopped";
|
|
}
|
|
```
|
|
|
|
### Error Handling
|
|
- try/catch for async operations
|
|
- `console.error()` for debugging
|
|
- `new Notice()` for user-facing errors
|
|
- Boolean returns for success/failure
|
|
- Silent catch for non-critical ops (health checks)
|
|
|
|
```typescript
|
|
try {
|
|
await this.processManager.start();
|
|
} catch (error) {
|
|
console.error("Failed to start:", error);
|
|
new Notice(`Failed to start OpenCode: ${error.message}`);
|
|
return false;
|
|
}
|
|
```
|
|
|
|
### Obsidian API Patterns
|
|
- Extend `Plugin` with `onload()`/`onunload()` lifecycle
|
|
- Extend `ItemView` for views: `getViewType()`, `onOpen()`, `onClose()`
|
|
- Extend `PluginSettingTab` for settings: `display()`
|
|
- DOM helpers: `createEl()`, `createDiv()`, `setIcon()`
|
|
- Register in `onload()`, clean up in `onunload()`
|
|
|
|
```typescript
|
|
this.registerView(OPENCODE_VIEW_TYPE, (leaf) => new OpenCodeView(leaf, this));
|
|
this.addCommand({ id: "toggle-view", name: "Toggle panel", callback: () => this.toggleView() });
|
|
```
|
|
|
|
### DOM Creation
|
|
```typescript
|
|
const container = this.contentEl.createDiv({ cls: "opencode-container" });
|
|
container.createEl("h3", { text: "Title" });
|
|
container.createEl("button", { text: "Click", cls: "mod-cta" });
|
|
```
|
|
|
|
### State Management
|
|
- Callback-based subscriptions
|
|
- Centralized state in manager classes
|
|
- Immediate notification on state change
|
|
|
|
## Config Summary
|
|
|
|
**tsconfig.json:** ES6 target, ESNext modules, strictNullChecks, noImplicitAny
|
|
|
|
**esbuild:** CJS format, es2018 target, node platform. Externals: obsidian, electron, CodeMirror, Node builtins
|
|
|
|
## Desktop-Only
|
|
|
|
Uses Node.js APIs unavailable on mobile:
|
|
- `child_process.spawn()` for server process
|
|
- File system via vault adapter
|
|
|
|
Check for desktop environment before adding mobile-incompatible features.
|