chore(vault): track .obsidian plugin configs (incl. obsidian-git settings)
This commit is contained in:
@@ -0,0 +1,456 @@
|
||||
# OpenSpec Instructions
|
||||
|
||||
Instructions for AI coding assistants using OpenSpec for spec-driven development.
|
||||
|
||||
## TL;DR Quick Checklist
|
||||
|
||||
- Search existing work: `openspec spec list --long`, `openspec list` (use `rg` only for full-text search)
|
||||
- Decide scope: new capability vs modify existing capability
|
||||
- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)
|
||||
- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability
|
||||
- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement
|
||||
- Validate: `openspec validate [change-id] --strict` and fix issues
|
||||
- Request approval: Do not start implementation until proposal is approved
|
||||
|
||||
## Three-Stage Workflow
|
||||
|
||||
### Stage 1: Creating Changes
|
||||
Create proposal when you need to:
|
||||
- Add features or functionality
|
||||
- Make breaking changes (API, schema)
|
||||
- Change architecture or patterns
|
||||
- Optimize performance (changes behavior)
|
||||
- Update security patterns
|
||||
|
||||
Triggers (examples):
|
||||
- "Help me create a change proposal"
|
||||
- "Help me plan a change"
|
||||
- "Help me create a proposal"
|
||||
- "I want to create a spec proposal"
|
||||
- "I want to create a spec"
|
||||
|
||||
Loose matching guidance:
|
||||
- Contains one of: `proposal`, `change`, `spec`
|
||||
- With one of: `create`, `plan`, `make`, `start`, `help`
|
||||
|
||||
Skip proposal for:
|
||||
- Bug fixes (restore intended behavior)
|
||||
- Typos, formatting, comments
|
||||
- Dependency updates (non-breaking)
|
||||
- Configuration changes
|
||||
- Tests for existing behavior
|
||||
|
||||
**Workflow**
|
||||
1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.
|
||||
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.
|
||||
3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.
|
||||
4. Run `openspec validate <id> --strict` and resolve any issues before sharing the proposal.
|
||||
|
||||
### Stage 2: Implementing Changes
|
||||
Track these steps as TODOs and complete them one by one.
|
||||
1. **Read proposal.md** - Understand what's being built
|
||||
2. **Read design.md** (if exists) - Review technical decisions
|
||||
3. **Read tasks.md** - Get implementation checklist
|
||||
4. **Implement tasks sequentially** - Complete in order
|
||||
5. **Confirm completion** - Ensure every item in `tasks.md` is finished before updating statuses
|
||||
6. **Update checklist** - After all work is done, set every task to `- [x]` so the list reflects reality
|
||||
7. **Approval gate** - Do not start implementation until the proposal is reviewed and approved
|
||||
|
||||
### Stage 3: Archiving Changes
|
||||
After deployment, create separate PR to:
|
||||
- Move `changes/[name]/` → `changes/archive/YYYY-MM-DD-[name]/`
|
||||
- Update `specs/` if capabilities changed
|
||||
- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)
|
||||
- Run `openspec validate --strict` to confirm the archived change passes checks
|
||||
|
||||
## Before Any Task
|
||||
|
||||
**Context Checklist:**
|
||||
- [ ] Read relevant specs in `specs/[capability]/spec.md`
|
||||
- [ ] Check pending changes in `changes/` for conflicts
|
||||
- [ ] Read `openspec/project.md` for conventions
|
||||
- [ ] Run `openspec list` to see active changes
|
||||
- [ ] Run `openspec list --specs` to see existing capabilities
|
||||
|
||||
**Before Creating Specs:**
|
||||
- Always check if capability already exists
|
||||
- Prefer modifying existing specs over creating duplicates
|
||||
- Use `openspec show [spec]` to review current state
|
||||
- If request is ambiguous, ask 1–2 clarifying questions before scaffolding
|
||||
|
||||
### Search Guidance
|
||||
- Enumerate specs: `openspec spec list --long` (or `--json` for scripts)
|
||||
- Enumerate changes: `openspec list` (or `openspec change list --json` - deprecated but available)
|
||||
- Show details:
|
||||
- Spec: `openspec show <spec-id> --type spec` (use `--json` for filters)
|
||||
- Change: `openspec show <change-id> --json --deltas-only`
|
||||
- Full-text search (use ripgrep): `rg -n "Requirement:|Scenario:" openspec/specs`
|
||||
|
||||
## Quick Start
|
||||
|
||||
### CLI Commands
|
||||
|
||||
```bash
|
||||
# Essential commands
|
||||
openspec list # List active changes
|
||||
openspec list --specs # List specifications
|
||||
openspec show [item] # Display change or spec
|
||||
openspec validate [item] # Validate changes or specs
|
||||
openspec archive <change-id> [--yes|-y] # Archive after deployment (add --yes for non-interactive runs)
|
||||
|
||||
# Project management
|
||||
openspec init [path] # Initialize OpenSpec
|
||||
openspec update [path] # Update instruction files
|
||||
|
||||
# Interactive mode
|
||||
openspec show # Prompts for selection
|
||||
openspec validate # Bulk validation mode
|
||||
|
||||
# Debugging
|
||||
openspec show [change] --json --deltas-only
|
||||
openspec validate [change] --strict
|
||||
```
|
||||
|
||||
### Command Flags
|
||||
|
||||
- `--json` - Machine-readable output
|
||||
- `--type change|spec` - Disambiguate items
|
||||
- `--strict` - Comprehensive validation
|
||||
- `--no-interactive` - Disable prompts
|
||||
- `--skip-specs` - Archive without spec updates
|
||||
- `--yes`/`-y` - Skip confirmation prompts (non-interactive archive)
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
openspec/
|
||||
├── project.md # Project conventions
|
||||
├── specs/ # Current truth - what IS built
|
||||
│ └── [capability]/ # Single focused capability
|
||||
│ ├── spec.md # Requirements and scenarios
|
||||
│ └── design.md # Technical patterns
|
||||
├── changes/ # Proposals - what SHOULD change
|
||||
│ ├── [change-name]/
|
||||
│ │ ├── proposal.md # Why, what, impact
|
||||
│ │ ├── tasks.md # Implementation checklist
|
||||
│ │ ├── design.md # Technical decisions (optional; see criteria)
|
||||
│ │ └── specs/ # Delta changes
|
||||
│ │ └── [capability]/
|
||||
│ │ └── spec.md # ADDED/MODIFIED/REMOVED
|
||||
│ └── archive/ # Completed changes
|
||||
```
|
||||
|
||||
## Creating Change Proposals
|
||||
|
||||
### Decision Tree
|
||||
|
||||
```
|
||||
New request?
|
||||
├─ Bug fix restoring spec behavior? → Fix directly
|
||||
├─ Typo/format/comment? → Fix directly
|
||||
├─ New feature/capability? → Create proposal
|
||||
├─ Breaking change? → Create proposal
|
||||
├─ Architecture change? → Create proposal
|
||||
└─ Unclear? → Create proposal (safer)
|
||||
```
|
||||
|
||||
### Proposal Structure
|
||||
|
||||
1. **Create directory:** `changes/[change-id]/` (kebab-case, verb-led, unique)
|
||||
|
||||
2. **Write proposal.md:**
|
||||
```markdown
|
||||
# Change: [Brief description of change]
|
||||
|
||||
## Why
|
||||
[1-2 sentences on problem/opportunity]
|
||||
|
||||
## What Changes
|
||||
- [Bullet list of changes]
|
||||
- [Mark breaking changes with **BREAKING**]
|
||||
|
||||
## Impact
|
||||
- Affected specs: [list capabilities]
|
||||
- Affected code: [key files/systems]
|
||||
```
|
||||
|
||||
3. **Create spec deltas:** `specs/[capability]/spec.md`
|
||||
```markdown
|
||||
## ADDED Requirements
|
||||
### Requirement: New Feature
|
||||
The system SHALL provide...
|
||||
|
||||
#### Scenario: Success case
|
||||
- **WHEN** user performs action
|
||||
- **THEN** expected result
|
||||
|
||||
## MODIFIED Requirements
|
||||
### Requirement: Existing Feature
|
||||
[Complete modified requirement]
|
||||
|
||||
## REMOVED Requirements
|
||||
### Requirement: Old Feature
|
||||
**Reason**: [Why removing]
|
||||
**Migration**: [How to handle]
|
||||
```
|
||||
If multiple capabilities are affected, create multiple delta files under `changes/[change-id]/specs/<capability>/spec.md`—one per capability.
|
||||
|
||||
4. **Create tasks.md:**
|
||||
```markdown
|
||||
## 1. Implementation
|
||||
- [ ] 1.1 Create database schema
|
||||
- [ ] 1.2 Implement API endpoint
|
||||
- [ ] 1.3 Add frontend component
|
||||
- [ ] 1.4 Write tests
|
||||
```
|
||||
|
||||
5. **Create design.md when needed:**
|
||||
Create `design.md` if any of the following apply; otherwise omit it:
|
||||
- Cross-cutting change (multiple services/modules) or a new architectural pattern
|
||||
- New external dependency or significant data model changes
|
||||
- Security, performance, or migration complexity
|
||||
- Ambiguity that benefits from technical decisions before coding
|
||||
|
||||
Minimal `design.md` skeleton:
|
||||
```markdown
|
||||
## Context
|
||||
[Background, constraints, stakeholders]
|
||||
|
||||
## Goals / Non-Goals
|
||||
- Goals: [...]
|
||||
- Non-Goals: [...]
|
||||
|
||||
## Decisions
|
||||
- Decision: [What and why]
|
||||
- Alternatives considered: [Options + rationale]
|
||||
|
||||
## Risks / Trade-offs
|
||||
- [Risk] → Mitigation
|
||||
|
||||
## Migration Plan
|
||||
[Steps, rollback]
|
||||
|
||||
## Open Questions
|
||||
- [...]
|
||||
```
|
||||
|
||||
## Spec File Format
|
||||
|
||||
### Critical: Scenario Formatting
|
||||
|
||||
**CORRECT** (use #### headers):
|
||||
```markdown
|
||||
#### Scenario: User login success
|
||||
- **WHEN** valid credentials provided
|
||||
- **THEN** return JWT token
|
||||
```
|
||||
|
||||
**WRONG** (don't use bullets or bold):
|
||||
```markdown
|
||||
- **Scenario: User login** ❌
|
||||
**Scenario**: User login ❌
|
||||
### Scenario: User login ❌
|
||||
```
|
||||
|
||||
Every requirement MUST have at least one scenario.
|
||||
|
||||
### Requirement Wording
|
||||
- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)
|
||||
|
||||
### Delta Operations
|
||||
|
||||
- `## ADDED Requirements` - New capabilities
|
||||
- `## MODIFIED Requirements` - Changed behavior
|
||||
- `## REMOVED Requirements` - Deprecated features
|
||||
- `## RENAMED Requirements` - Name changes
|
||||
|
||||
Headers matched with `trim(header)` - whitespace ignored.
|
||||
|
||||
#### When to use ADDED vs MODIFIED
|
||||
- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding "Slash Command Configuration") rather than altering the semantics of an existing requirement.
|
||||
- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.
|
||||
- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.
|
||||
|
||||
Common pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you aren’t explicitly changing the existing requirement, add a new requirement under ADDED instead.
|
||||
|
||||
Authoring a MODIFIED requirement correctly:
|
||||
1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.
|
||||
2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).
|
||||
3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.
|
||||
4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.
|
||||
|
||||
Example for RENAMED:
|
||||
```markdown
|
||||
## RENAMED Requirements
|
||||
- FROM: `### Requirement: Login`
|
||||
- TO: `### Requirement: User Authentication`
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Errors
|
||||
|
||||
**"Change must have at least one delta"**
|
||||
- Check `changes/[name]/specs/` exists with .md files
|
||||
- Verify files have operation prefixes (## ADDED Requirements)
|
||||
|
||||
**"Requirement must have at least one scenario"**
|
||||
- Check scenarios use `#### Scenario:` format (4 hashtags)
|
||||
- Don't use bullet points or bold for scenario headers
|
||||
|
||||
**Silent scenario parsing failures**
|
||||
- Exact format required: `#### Scenario: Name`
|
||||
- Debug with: `openspec show [change] --json --deltas-only`
|
||||
|
||||
### Validation Tips
|
||||
|
||||
```bash
|
||||
# Always use strict mode for comprehensive checks
|
||||
openspec validate [change] --strict
|
||||
|
||||
# Debug delta parsing
|
||||
openspec show [change] --json | jq '.deltas'
|
||||
|
||||
# Check specific requirement
|
||||
openspec show [spec] --json -r 1
|
||||
```
|
||||
|
||||
## Happy Path Script
|
||||
|
||||
```bash
|
||||
# 1) Explore current state
|
||||
openspec spec list --long
|
||||
openspec list
|
||||
# Optional full-text search:
|
||||
# rg -n "Requirement:|Scenario:" openspec/specs
|
||||
# rg -n "^#|Requirement:" openspec/changes
|
||||
|
||||
# 2) Choose change id and scaffold
|
||||
CHANGE=add-two-factor-auth
|
||||
mkdir -p openspec/changes/$CHANGE/{specs/auth}
|
||||
printf "## Why\n...\n\n## What Changes\n- ...\n\n## Impact\n- ...\n" > openspec/changes/$CHANGE/proposal.md
|
||||
printf "## 1. Implementation\n- [ ] 1.1 ...\n" > openspec/changes/$CHANGE/tasks.md
|
||||
|
||||
# 3) Add deltas (example)
|
||||
cat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'
|
||||
## ADDED Requirements
|
||||
### Requirement: Two-Factor Authentication
|
||||
Users MUST provide a second factor during login.
|
||||
|
||||
#### Scenario: OTP required
|
||||
- **WHEN** valid credentials are provided
|
||||
- **THEN** an OTP challenge is required
|
||||
EOF
|
||||
|
||||
# 4) Validate
|
||||
openspec validate $CHANGE --strict
|
||||
```
|
||||
|
||||
## Multi-Capability Example
|
||||
|
||||
```
|
||||
openspec/changes/add-2fa-notify/
|
||||
├── proposal.md
|
||||
├── tasks.md
|
||||
└── specs/
|
||||
├── auth/
|
||||
│ └── spec.md # ADDED: Two-Factor Authentication
|
||||
└── notifications/
|
||||
└── spec.md # ADDED: OTP email notification
|
||||
```
|
||||
|
||||
auth/spec.md
|
||||
```markdown
|
||||
## ADDED Requirements
|
||||
### Requirement: Two-Factor Authentication
|
||||
...
|
||||
```
|
||||
|
||||
notifications/spec.md
|
||||
```markdown
|
||||
## ADDED Requirements
|
||||
### Requirement: OTP Email Notification
|
||||
...
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Simplicity First
|
||||
- Default to <100 lines of new code
|
||||
- Single-file implementations until proven insufficient
|
||||
- Avoid frameworks without clear justification
|
||||
- Choose boring, proven patterns
|
||||
|
||||
### Complexity Triggers
|
||||
Only add complexity with:
|
||||
- Performance data showing current solution too slow
|
||||
- Concrete scale requirements (>1000 users, >100MB data)
|
||||
- Multiple proven use cases requiring abstraction
|
||||
|
||||
### Clear References
|
||||
- Use `file.ts:42` format for code locations
|
||||
- Reference specs as `specs/auth/spec.md`
|
||||
- Link related changes and PRs
|
||||
|
||||
### Capability Naming
|
||||
- Use verb-noun: `user-auth`, `payment-capture`
|
||||
- Single purpose per capability
|
||||
- 10-minute understandability rule
|
||||
- Split if description needs "AND"
|
||||
|
||||
### Change ID Naming
|
||||
- Use kebab-case, short and descriptive: `add-two-factor-auth`
|
||||
- Prefer verb-led prefixes: `add-`, `update-`, `remove-`, `refactor-`
|
||||
- Ensure uniqueness; if taken, append `-2`, `-3`, etc.
|
||||
|
||||
## Tool Selection Guide
|
||||
|
||||
| Task | Tool | Why |
|
||||
|------|------|-----|
|
||||
| Find files by pattern | Glob | Fast pattern matching |
|
||||
| Search code content | Grep | Optimized regex search |
|
||||
| Read specific files | Read | Direct file access |
|
||||
| Explore unknown scope | Task | Multi-step investigation |
|
||||
|
||||
## Error Recovery
|
||||
|
||||
### Change Conflicts
|
||||
1. Run `openspec list` to see active changes
|
||||
2. Check for overlapping specs
|
||||
3. Coordinate with change owners
|
||||
4. Consider combining proposals
|
||||
|
||||
### Validation Failures
|
||||
1. Run with `--strict` flag
|
||||
2. Check JSON output for details
|
||||
3. Verify spec file format
|
||||
4. Ensure scenarios properly formatted
|
||||
|
||||
### Missing Context
|
||||
1. Read project.md first
|
||||
2. Check related specs
|
||||
3. Review recent archives
|
||||
4. Ask for clarification
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Stage Indicators
|
||||
- `changes/` - Proposed, not yet built
|
||||
- `specs/` - Built and deployed
|
||||
- `archive/` - Completed changes
|
||||
|
||||
### File Purposes
|
||||
- `proposal.md` - Why and what
|
||||
- `tasks.md` - Implementation steps
|
||||
- `design.md` - Technical decisions
|
||||
- `spec.md` - Requirements and behavior
|
||||
|
||||
### CLI Essentials
|
||||
```bash
|
||||
openspec list # What's in progress?
|
||||
openspec show [item] # View details
|
||||
openspec validate --strict # Is it correct?
|
||||
openspec archive <change-id> [--yes|-y] # Mark complete (add --yes for automation)
|
||||
```
|
||||
|
||||
Remember: Specs are truth. Changes are proposals. Keep them in sync.
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
# Change: Add Default View Location Setting
|
||||
|
||||
## Why
|
||||
Users may prefer to have the OpenCode panel open in the main editor area instead of the sidebar, depending on their workflow and screen size. Currently, the view always opens in the right sidebar with no option to change this behavior.
|
||||
|
||||
## What Changes
|
||||
- Add a new `defaultViewLocation` setting with options: `"sidebar"` or `"main"`
|
||||
- Update view activation logic to respect this setting when opening the panel
|
||||
- Sidebar opens in the right leaf (current behavior)
|
||||
- Main opens in a new tab in the main editor area
|
||||
|
||||
## Impact
|
||||
- Affected specs: `001-mvp-opencode-embed` (Settings Configuration, Sidebar View Registration, Ribbon Icon)
|
||||
- Affected code: `src/types.ts`, `src/main.ts`, `src/SettingsTab.ts`
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Settings Configuration
|
||||
The plugin SHALL provide configurable settings for server port, hostname, executable path, project directory, auto-start behavior, and default view location.
|
||||
|
||||
#### Scenario: Settings persistence
|
||||
- **WHEN** the user modifies settings
|
||||
- **THEN** changes are persisted to plugin data
|
||||
- **AND** the process manager is updated with new settings
|
||||
|
||||
#### Scenario: Default view location options
|
||||
- **WHEN** the user configures default view location
|
||||
- **THEN** the options available are "sidebar" and "main"
|
||||
- **AND** the default value is "sidebar"
|
||||
|
||||
### Requirement: Sidebar View Registration
|
||||
The plugin SHALL register an ItemView that displays in either the Obsidian sidebar or main editor area based on user settings.
|
||||
|
||||
#### Scenario: View activation in sidebar
|
||||
- **WHEN** the user clicks the ribbon icon or runs the toggle command
|
||||
- **AND** the default view location is set to "sidebar"
|
||||
- **THEN** the OpenCode view opens in the right sidebar
|
||||
- **AND** if the view already exists, it is revealed
|
||||
|
||||
#### Scenario: View activation in main area
|
||||
- **WHEN** the user clicks the ribbon icon or runs the toggle command
|
||||
- **AND** the default view location is set to "main"
|
||||
- **THEN** the OpenCode view opens as a new tab in the main editor area
|
||||
- **AND** if the view already exists in any location, it is revealed
|
||||
|
||||
### Requirement: Ribbon Icon
|
||||
The plugin SHALL add a ribbon icon that activates the OpenCode view in the configured default location.
|
||||
|
||||
#### Scenario: Ribbon icon click
|
||||
- **WHEN** the user clicks the OpenCode ribbon icon
|
||||
- **THEN** the OpenCode view is activated in the location specified by the default view location setting
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
## 1. Implementation
|
||||
|
||||
- [ ] 1.1 Add `defaultViewLocation` type and setting to `src/types.ts`
|
||||
- Add type: `"sidebar" | "main"`
|
||||
- Add to `OpenCodeSettings` interface
|
||||
- Add default value `"sidebar"` to `DEFAULT_SETTINGS`
|
||||
|
||||
- [ ] 1.2 Update `src/main.ts` view activation logic
|
||||
- Modify `activateView()` method to check `defaultViewLocation` setting
|
||||
- For "sidebar": use `getLeaf("right")` (existing behavior)
|
||||
- For "main": use `getLeaf("tab")` to open in main editor area
|
||||
- Ensure existing view detection works for both locations
|
||||
|
||||
- [ ] 1.3 Add setting UI to `src/SettingsTab.ts`
|
||||
- Add dropdown setting for "Default view location"
|
||||
- Options: "Sidebar" and "Main window"
|
||||
- Description explaining the behavior difference
|
||||
|
||||
- [ ] 1.4 Test the feature
|
||||
- Verify sidebar mode opens in right sidebar
|
||||
- Verify main mode opens as a tab in editor area
|
||||
- Verify toggling reveals existing view regardless of location
|
||||
- Verify setting persists across plugin reload
|
||||
Vendored
+121
@@ -0,0 +1,121 @@
|
||||
## Context
|
||||
|
||||
This plugin embeds the OpenCode AI assistant into Obsidian by spawning a local server process and displaying its web UI in an iframe within the Obsidian sidebar. The design prioritizes simplicity and reliability for the MVP.
|
||||
|
||||
**Constraints:**
|
||||
- Desktop-only (requires Node.js child_process APIs)
|
||||
- Must work within Obsidian's plugin sandbox
|
||||
- OpenCode CLI must be installed separately by the user
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Seamless embedding of OpenCode UI in Obsidian sidebar
|
||||
- Reliable server process lifecycle management
|
||||
- Configurable server and project settings
|
||||
- Quick access via ribbon icon and keyboard shortcut
|
||||
|
||||
**Non-Goals:**
|
||||
- Mobile support (not possible due to Node.js dependencies)
|
||||
- Native UI rendering (OpenCode provides its own web UI)
|
||||
- Multiple simultaneous OpenCode instances
|
||||
- Deep Obsidian integration (file linking, note references)
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Iframe Embedding vs Native Rendering
|
||||
**Decision:** Embed OpenCode's web UI via iframe rather than building native Obsidian UI.
|
||||
|
||||
**Rationale:**
|
||||
- Can be up and running quickly
|
||||
- OpenCode already provides a full-featured web interface
|
||||
- Reduces maintenance burden - UI updates come from OpenCode automatically
|
||||
- Allows feature parity with standalone OpenCode web experience
|
||||
|
||||
**Trade-offs:**
|
||||
- Limited ability to customize UI appearance
|
||||
- Requires CORS configuration (`--cors app://obsidian.md`)
|
||||
- Iframe isolation limits some interactions
|
||||
|
||||
### 2. Process State Machine
|
||||
**Decision:** Use a 4-state machine: `stopped` → `starting` → `running` | `error`
|
||||
|
||||
**Rationale:**
|
||||
- Clear, predictable state transitions
|
||||
- Enables reactive UI that shows appropriate content for each state
|
||||
- Prevents race conditions (can't start while starting)
|
||||
|
||||
**States:**
|
||||
- `stopped`: Server not running, show start button
|
||||
- `starting`: Spawn initiated, polling health endpoint, show spinner
|
||||
- `running`: Health check passed, show iframe
|
||||
- `error`: Spawn failed or health check timeout, show retry option
|
||||
|
||||
### 3. Lazy Start Strategy
|
||||
**Decision:** Start server when view opens, not when plugin loads.
|
||||
|
||||
**Rationale:**
|
||||
- Faster Obsidian startup (server spawn is ~2-5 seconds)
|
||||
- User may not need OpenCode every session
|
||||
- Auto-start available as opt-in setting for users who prefer it
|
||||
|
||||
**Implementation:** `OpenCodeView.onOpen()` calls `plugin.startServer()` if state is `stopped`.
|
||||
|
||||
### 4. Health Check Polling
|
||||
**Decision:** Poll `/global/health` endpoint every 500ms during startup, with 15-second timeout.
|
||||
|
||||
**Rationale:**
|
||||
- Server needs time to initialize before accepting connections
|
||||
- Polling is simple and reliable
|
||||
- 15 seconds accommodates slow systems without waiting too long
|
||||
|
||||
**Trade-offs:**
|
||||
- Slight delay before iframe loads (typically 1-3 seconds)
|
||||
- Could use server stdout parsing instead, but health endpoint is more reliable
|
||||
|
||||
### 5. Graceful Shutdown
|
||||
**Decision:** SIGTERM first, SIGKILL after 2-second timeout.
|
||||
|
||||
**Rationale:**
|
||||
- Allows server to clean up resources gracefully
|
||||
- SIGKILL fallback ensures process doesn't hang
|
||||
- 2 seconds is sufficient for typical cleanup
|
||||
|
||||
### 6. Project Directory Encoding
|
||||
**Decision:** Encode project directory as base64 in URL path (e.g., `http://127.0.0.1:14096/{base64-path}`).
|
||||
|
||||
**Rationale:**
|
||||
- OpenCode server supports multiple projects via URL routing
|
||||
- Base64 handles special characters in paths safely
|
||||
- Allows future support for switching projects without server restart
|
||||
|
||||
### 7. Callback-Based State Subscriptions
|
||||
**Decision:** Use callback array pattern for state change notifications.
|
||||
|
||||
**Rationale:**
|
||||
- Simpler than event emitters or observables for this scale
|
||||
- View subscribes to plugin state changes in `onOpen()`
|
||||
- Immediate notification ensures UI stays in sync
|
||||
|
||||
**Implementation:**
|
||||
```typescript
|
||||
plugin.onProcessStateChange((state) => {
|
||||
this.currentState = state;
|
||||
this.updateView();
|
||||
});
|
||||
```
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| OpenCode CLI not installed | Clear error message with settings link |
|
||||
| Port already in use | Health check detects existing server, reuses it |
|
||||
| Server crash during use | View shows error state, user can retry |
|
||||
| Slow server startup | 15-second timeout with spinner feedback |
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should we support multiple project directories (tabs/switcher)?
|
||||
- Should settings changes hot-reload the iframe without full restart?
|
||||
- Should we add connection status indicator in header?
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
# Change: Document MVP Capabilities
|
||||
|
||||
## Why
|
||||
The Obsidian OpenCode plugin MVP has been implemented but lacks formal specification. This change retroactively documents the existing functionality to establish a baseline specification that can be expanded as the MVP is polished.
|
||||
|
||||
## What Changes
|
||||
- **ADDED** `001-mvp-opencode-embed` capability spec covering:
|
||||
- Server process management (spawn, health check, shutdown, state machine)
|
||||
- Sidebar view with iframe embedding and state-reactive UI
|
||||
- Plugin settings with validation
|
||||
- Commands and ribbon icon integration
|
||||
|
||||
## Impact
|
||||
- Affected specs: None (new spec)
|
||||
- Affected code: None (documentation only)
|
||||
- This is a retroactive documentation effort with no code changes
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Server Process Spawning
|
||||
The plugin SHALL spawn the OpenCode server process using the configured executable path, port, and hostname when the user initiates server start.
|
||||
|
||||
#### Scenario: Successful server spawn
|
||||
- **WHEN** the user starts the server
|
||||
- **THEN** the plugin spawns `opencode serve --port <port> --hostname <hostname> --cors app://obsidian.md`
|
||||
- **AND** the process runs with the vault directory as the working directory
|
||||
|
||||
### Requirement: Server Health Checking
|
||||
The plugin SHALL verify server availability by polling a health endpoint during startup.
|
||||
|
||||
#### Scenario: Health check during startup
|
||||
- **WHEN** the server process is spawned
|
||||
- **THEN** the plugin polls `GET /global/health` every 500ms
|
||||
- **AND** transitions to running state when the endpoint returns HTTP 200
|
||||
- **AND** transitions to error state if 15 seconds elapse without success
|
||||
|
||||
#### Scenario: Existing server detected
|
||||
- **WHEN** the user starts the server
|
||||
- **AND** a server is already running on the configured port
|
||||
- **THEN** the plugin reuses the existing server
|
||||
- **AND** transitions directly to running state
|
||||
|
||||
### Requirement: Server Shutdown
|
||||
The plugin SHALL gracefully terminate the server process when stopping.
|
||||
|
||||
#### Scenario: Graceful shutdown
|
||||
- **WHEN** the user stops the server
|
||||
- **THEN** the plugin sends SIGTERM to the process
|
||||
- **AND** sends SIGKILL after 2 seconds if the process is still running
|
||||
|
||||
### Requirement: Process State Management
|
||||
The plugin SHALL maintain a state machine with states: stopped, starting, running, and error.
|
||||
|
||||
#### Scenario: State transitions
|
||||
- **WHEN** the server is not running
|
||||
- **THEN** the state is `stopped`
|
||||
- **WHEN** spawn is initiated
|
||||
- **THEN** the state transitions to `starting`
|
||||
- **WHEN** health check succeeds
|
||||
- **THEN** the state transitions to `running`
|
||||
- **WHEN** spawn fails or health check times out
|
||||
- **THEN** the state transitions to `error`
|
||||
|
||||
### Requirement: Sidebar View Registration
|
||||
The plugin SHALL register an ItemView that displays in the Obsidian sidebar.
|
||||
|
||||
#### Scenario: View activation
|
||||
- **WHEN** the user clicks the ribbon icon or runs the toggle command
|
||||
- **THEN** the OpenCode view opens in the right sidebar
|
||||
- **AND** if the view already exists, it is revealed
|
||||
|
||||
### Requirement: View State Rendering
|
||||
The plugin SHALL render different UI content based on the current process state.
|
||||
|
||||
#### Scenario: Stopped state UI
|
||||
- **WHEN** the process state is `stopped`
|
||||
- **THEN** the view displays a "Start OpenCode" button
|
||||
|
||||
#### Scenario: Starting state UI
|
||||
- **WHEN** the process state is `starting`
|
||||
- **THEN** the view displays a loading spinner with "Starting OpenCode..." message
|
||||
|
||||
#### Scenario: Running state UI
|
||||
- **WHEN** the process state is `running`
|
||||
- **THEN** the view displays a header with controls and an iframe loading the server URL
|
||||
|
||||
#### Scenario: Error state UI
|
||||
- **WHEN** the process state is `error`
|
||||
- **THEN** the view displays an error message with "Retry" and "Open Settings" buttons
|
||||
|
||||
### Requirement: Iframe Controls
|
||||
The plugin SHALL provide controls in the view header when the server is running.
|
||||
|
||||
#### Scenario: Header controls available
|
||||
- **WHEN** the server is running
|
||||
- **THEN** the header displays reload and stop buttons
|
||||
- **AND** clicking reload refreshes the iframe
|
||||
- **AND** clicking stop terminates the server
|
||||
|
||||
### Requirement: Lazy Server Start
|
||||
The plugin SHALL start the server automatically when the view is opened if not already running.
|
||||
|
||||
#### Scenario: Auto-start on view open
|
||||
- **WHEN** the user opens the OpenCode view
|
||||
- **AND** the server is in `stopped` state
|
||||
- **THEN** the plugin initiates server start
|
||||
|
||||
### Requirement: Settings Configuration
|
||||
The plugin SHALL provide configurable settings for server port, hostname, executable path, project directory, and auto-start behavior.
|
||||
|
||||
#### Scenario: Settings persistence
|
||||
- **WHEN** the user modifies settings
|
||||
- **THEN** changes are persisted to plugin data
|
||||
- **AND** the process manager is updated with new settings
|
||||
|
||||
### Requirement: Project Directory Validation
|
||||
The plugin SHALL validate the project directory setting and support tilde expansion.
|
||||
|
||||
#### Scenario: Valid absolute path
|
||||
- **WHEN** the user enters an absolute path or path starting with ~
|
||||
- **AND** the path exists and is a directory
|
||||
- **THEN** the setting is saved with the expanded path
|
||||
|
||||
#### Scenario: Invalid path rejection
|
||||
- **WHEN** the user enters a relative path or non-existent path
|
||||
- **THEN** a notice is displayed explaining the error
|
||||
- **AND** the setting is not saved
|
||||
|
||||
### Requirement: Project Directory Auto-Restart
|
||||
The plugin SHALL restart the server when the project directory setting changes while running.
|
||||
|
||||
#### Scenario: Restart on directory change
|
||||
- **WHEN** the user changes the project directory
|
||||
- **AND** the server is currently running
|
||||
- **THEN** the plugin stops and restarts the server with the new directory
|
||||
|
||||
### Requirement: Commands Registration
|
||||
The plugin SHALL register commands for toggling the view and controlling the server.
|
||||
|
||||
#### Scenario: Toggle command
|
||||
- **WHEN** the user runs "Toggle OpenCode panel" command or presses Mod+Shift+O
|
||||
- **THEN** the view opens if closed, or closes if open
|
||||
|
||||
#### Scenario: Start and stop commands
|
||||
- **WHEN** the user runs "Start OpenCode server" command
|
||||
- **THEN** the server starts
|
||||
- **WHEN** the user runs "Stop OpenCode server" command
|
||||
- **THEN** the server stops
|
||||
|
||||
### Requirement: Ribbon Icon
|
||||
The plugin SHALL add a ribbon icon that activates the OpenCode view.
|
||||
|
||||
#### Scenario: Ribbon icon click
|
||||
- **WHEN** the user clicks the OpenCode ribbon icon
|
||||
- **THEN** the OpenCode view is activated in the right sidebar
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
## 1. Documentation
|
||||
- [x] 1.1 Create proposal.md
|
||||
- [x] 1.2 Create design.md with architectural decisions
|
||||
- [x] 1.3 Create specs/001-mvp-opencode-embed/spec.md with requirements and scenarios
|
||||
- [x] 1.4 Validate with `openspec validate document-mvp-capabilities --strict`
|
||||
@@ -0,0 +1,134 @@
|
||||
# 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
|
||||
@@ -0,0 +1,35 @@
|
||||
# OpenCode-Obsidian Plugin roadmap and ideas
|
||||
|
||||
## Roadmap
|
||||
|
||||
### 0.1
|
||||
|
||||
* Versioning and changelog
|
||||
|
||||
### 0.2
|
||||
|
||||
* Windows support
|
||||
* 3-4 sample skills useful in a vault
|
||||
|
||||
### 0.3
|
||||
* AGENTS.md initialization
|
||||
|
||||
### 1.0
|
||||
|
||||
* TBD
|
||||
|
||||
## Ideas
|
||||
|
||||
### Skills
|
||||
|
||||
This repository should contain a set of Agent Skills that can be enabled from the settings page.
|
||||
|
||||
### AGENTS.md initialization
|
||||
|
||||
OpenCode could be asked to generate initial AGENTS.md file for the vault, based on a template/prompt.
|
||||
|
||||
### "Native" Obsidian integration
|
||||
|
||||
Implement custom UI connecting to OpenCode server in order to have a seamless integration with Obsidian (clickable links, etc). This would be nice but also quite tedious (would need to re-implement large chunks of OC UI). Not sure if this is worth the effort.
|
||||
|
||||
Status: on-hold
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Server Process Spawning
|
||||
The plugin SHALL spawn the OpenCode server process using the configured executable path, port, and hostname when the user initiates server start.
|
||||
|
||||
#### Scenario: Successful server spawn
|
||||
- **WHEN** the user starts the server
|
||||
- **THEN** the plugin spawns `opencode serve --port <port> --hostname <hostname> --cors app://obsidian.md`
|
||||
- **AND** the process runs with the vault directory as the working directory
|
||||
|
||||
### Requirement: Server Health Checking
|
||||
The plugin SHALL verify server availability by polling a health endpoint during startup.
|
||||
|
||||
#### Scenario: Health check during startup
|
||||
- **WHEN** the server process is spawned
|
||||
- **THEN** the plugin polls `GET /global/health` every 500ms
|
||||
- **AND** transitions to running state when the endpoint returns HTTP 200
|
||||
- **AND** transitions to error state if 15 seconds elapse without success
|
||||
|
||||
#### Scenario: Existing server detected
|
||||
- **WHEN** the user starts the server
|
||||
- **AND** a server is already running on the configured port
|
||||
- **THEN** the plugin reuses the existing server
|
||||
- **AND** transitions directly to running state
|
||||
|
||||
### Requirement: Server Shutdown
|
||||
The plugin SHALL gracefully terminate the server process when stopping.
|
||||
|
||||
#### Scenario: Graceful shutdown
|
||||
- **WHEN** the user stops the server
|
||||
- **THEN** the plugin sends SIGTERM to the process
|
||||
- **AND** sends SIGKILL after 2 seconds if the process is still running
|
||||
|
||||
### Requirement: Process State Management
|
||||
The plugin SHALL maintain a state machine with states: stopped, starting, running, and error.
|
||||
|
||||
#### Scenario: State transitions
|
||||
- **WHEN** the server is not running
|
||||
- **THEN** the state is `stopped`
|
||||
- **WHEN** spawn is initiated
|
||||
- **THEN** the state transitions to `starting`
|
||||
- **WHEN** health check succeeds
|
||||
- **THEN** the state transitions to `running`
|
||||
- **WHEN** spawn fails or health check times out
|
||||
- **THEN** the state transitions to `error`
|
||||
|
||||
### Requirement: Sidebar View Registration
|
||||
The plugin SHALL register an ItemView that displays in either the Obsidian sidebar or main editor area based on user settings.
|
||||
|
||||
#### Scenario: View activation in sidebar
|
||||
- **WHEN** the user clicks the ribbon icon or runs the toggle command
|
||||
- **AND** the default view location is set to "sidebar"
|
||||
- **THEN** the OpenCode view opens in the right sidebar
|
||||
- **AND** if the view already exists, it is revealed
|
||||
|
||||
#### Scenario: View activation in main area
|
||||
- **WHEN** the user clicks the ribbon icon or runs the toggle command
|
||||
- **AND** the default view location is set to "main"
|
||||
- **THEN** the OpenCode view opens as a new tab in the main editor area
|
||||
- **AND** if the view already exists in any location, it is revealed
|
||||
|
||||
### Requirement: View State Rendering
|
||||
The plugin SHALL render different UI content based on the current process state.
|
||||
|
||||
#### Scenario: Stopped state UI
|
||||
- **WHEN** the process state is `stopped`
|
||||
- **THEN** the view displays a "Start OpenCode" button
|
||||
|
||||
#### Scenario: Starting state UI
|
||||
- **WHEN** the process state is `starting`
|
||||
- **THEN** the view displays a loading spinner with "Starting OpenCode..." message
|
||||
|
||||
#### Scenario: Running state UI
|
||||
- **WHEN** the process state is `running`
|
||||
- **THEN** the view displays a header with controls and an iframe loading the server URL
|
||||
|
||||
#### Scenario: Error state UI
|
||||
- **WHEN** the process state is `error`
|
||||
- **THEN** the view displays an error message with "Retry" and "Open Settings" buttons
|
||||
|
||||
### Requirement: Iframe Controls
|
||||
The plugin SHALL provide controls in the view header when the server is running.
|
||||
|
||||
#### Scenario: Header controls available
|
||||
- **WHEN** the server is running
|
||||
- **THEN** the header displays reload and stop buttons
|
||||
- **AND** clicking reload refreshes the iframe
|
||||
- **AND** clicking stop terminates the server
|
||||
|
||||
### Requirement: Lazy Server Start
|
||||
The plugin SHALL start the server automatically when the view is opened if not already running.
|
||||
|
||||
#### Scenario: Auto-start on view open
|
||||
- **WHEN** the user opens the OpenCode view
|
||||
- **AND** the server is in `stopped` state
|
||||
- **THEN** the plugin initiates server start
|
||||
|
||||
### Requirement: Settings Configuration
|
||||
The plugin SHALL provide configurable settings for server port, hostname, executable path, project directory, auto-start behavior, and default view location.
|
||||
|
||||
#### Scenario: Settings persistence
|
||||
- **WHEN** the user modifies settings
|
||||
- **THEN** changes are persisted to plugin data
|
||||
- **AND** the process manager is updated with new settings
|
||||
|
||||
#### Scenario: Default view location options
|
||||
- **WHEN** the user configures default view location
|
||||
- **THEN** the options available are "sidebar" and "main"
|
||||
- **AND** the default value is "sidebar"
|
||||
|
||||
### Requirement: Project Directory Validation
|
||||
The plugin SHALL validate the project directory setting and support tilde expansion.
|
||||
|
||||
#### Scenario: Valid absolute path
|
||||
- **WHEN** the user enters an absolute path or path starting with ~
|
||||
- **AND** the path exists and is a directory
|
||||
- **THEN** the setting is saved with the expanded path
|
||||
|
||||
#### Scenario: Invalid path rejection
|
||||
- **WHEN** the user enters a relative path or non-existent path
|
||||
- **THEN** a notice is displayed explaining the error
|
||||
- **AND** the setting is not saved
|
||||
|
||||
### Requirement: Project Directory Auto-Restart
|
||||
The plugin SHALL restart the server when the project directory setting changes while running.
|
||||
|
||||
#### Scenario: Restart on directory change
|
||||
- **WHEN** the user changes the project directory
|
||||
- **AND** the server is currently running
|
||||
- **THEN** the plugin stops and restarts the server with the new directory
|
||||
|
||||
### Requirement: Commands Registration
|
||||
The plugin SHALL register commands for toggling the view and controlling the server.
|
||||
|
||||
#### Scenario: Toggle command
|
||||
- **WHEN** the user runs "Toggle OpenCode panel" command or presses Mod+Shift+O
|
||||
- **THEN** the view opens if closed, or closes if open
|
||||
|
||||
#### Scenario: Start and stop commands
|
||||
- **WHEN** the user runs "Start OpenCode server" command
|
||||
- **THEN** the server starts
|
||||
- **WHEN** the user runs "Stop OpenCode server" command
|
||||
- **THEN** the server stops
|
||||
|
||||
### Requirement: Ribbon Icon
|
||||
The plugin SHALL add a ribbon icon that activates the OpenCode view in the configured default location.
|
||||
|
||||
#### Scenario: Ribbon icon click
|
||||
- **WHEN** the user clicks the OpenCode ribbon icon
|
||||
- **THEN** the OpenCode view is activated in the location specified by the default view location setting
|
||||
Reference in New Issue
Block a user