Files
opencode-obsidian/openspec/project.md
2026-01-04 21:32:03 +00:00

135 lines
4.7 KiB
Markdown

# Project Context
## Purpose
Obsidian plugin that embeds the OpenCode AI assistant via an iframe. The plugin spawns a local OpenCode server process and displays its web UI in the Obsidian sidebar, enabling AI-assisted coding and note-taking within Obsidian.
## Tech Stack
- **TypeScript** - Primary language with strict null checks
- **Obsidian Plugin API** - For UI integration, views, settings, and commands
- **esbuild** - Bundler (ES2018 target, CommonJS output)
- **Node.js child_process** - For spawning the OpenCode server process
- **Bun** - Package manager and runtime
## Project Conventions
### Code Style
**Imports:**
- ES modules with named imports
- Order: Obsidian API → Node.js builtins → local modules
- Use `type` keyword 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";
```
**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 for classes | `ProcessManager.ts`, `OpenCodeView.ts` |
**TypeScript Patterns:**
- `strictNullChecks` enabled - always handle null/undefined
- Union types for state: `"stopped" | "starting" | "running" | "error"`
- `async/await` over raw Promises
- Explicit return types on public methods
### Architecture Patterns
**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)
└── icons.ts # Custom icon registration
```
**Obsidian 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()`
**State Management:**
- Callback-based subscriptions for state changes
- Centralized state in manager classes (ProcessManager)
- Immediate notification on state change via callbacks
**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)
### Testing Strategy
Not currently configured. If adding tests:
- Use Vitest for test runner
- Place tests in `src/__tests__/` or `*.test.ts` files
- Add ESLint with `@typescript-eslint/parser` for linting
### Git Workflow
Standard feature branch workflow. Commit messages should be concise and describe the change.
## Domain Context
**OpenCode Server:**
- OpenCode is an AI assistant CLI that can run as a web server
- The plugin spawns `opencode serve` with port/hostname/CORS flags
- Server health is checked via `/global/health` endpoint
- Project directory is encoded as base64 in the URL path
**Obsidian Integration:**
- View is registered with `OPENCODE_VIEW_TYPE` constant
- Opens in right sidebar by default
- Supports lazy start (starts server when view opens)
- Auto-start option available in settings
**Process States:**
- `stopped` - Server not running
- `starting` - Server spawn initiated, waiting for health check
- `running` - Server healthy and responding
- `error` - Server failed to start or crashed
## Important Constraints
**Desktop Only:**
- Uses Node.js APIs (`child_process.spawn()`) unavailable on mobile
- File system access via vault adapter requires desktop
- Check for desktop environment before adding mobile-incompatible features
**Build Output:**
- Must produce single `main.js` file (CommonJS format)
- External: `obsidian`, `electron`, CodeMirror modules, Node.js builtins
**TypeScript Config:**
- Target: ES6
- Module: ESNext (bundled to CJS)
- Strict null checks enabled
- No implicit any
## External Dependencies
**Runtime:**
- OpenCode CLI must be installed on user's system (configurable path)
- Default port: 14096, hostname: 127.0.0.1
**Development:**
- `obsidian` - Obsidian API types and runtime
- `@types/node` - Node.js type definitions
- `esbuild` - Build bundler
- `typescript` - Type checking