Files
Mateusz Tymek d9cee8be1a Spec review
2026-01-17 10:46:21 +01:00

168 lines
7.3 KiB
Markdown

## ADDED Requirements
### Requirement: Workspace Context Collection
The plugin SHALL collect the file paths of all currently open markdown notes in the Obsidian workspace.
#### Scenario: Collect open note paths
- **WHEN** the plugin needs to gather workspace context
- **THEN** it retrieves all leaves of type "markdown" from the workspace
- **AND** extracts the file path from each leaf's view
- **AND** deduplicates paths (same file may be open in multiple panes)
### Requirement: Selected Text Collection
The plugin SHALL collect the currently selected text from the active editor, if any selection exists.
#### Scenario: Collect selected text with source
- **WHEN** the plugin needs to gather workspace context
- **AND** text is selected in the active editor
- **THEN** it retrieves the selected text content
- **AND** identifies the source file path of the selection
#### Scenario: No selection present
- **WHEN** the plugin needs to gather workspace context
- **AND** no text is selected in the active editor
- **THEN** the selected text portion of the context is omitted
#### Scenario: Selection truncation
- **WHEN** the selected text exceeds `maxSelectionLength` characters
- **THEN** the selection is truncated to the configured limit
- **AND** an indicator is added showing truncation occurred
### Requirement: Context Injection to OpenCode
The plugin SHALL inject the workspace context (open notes and selected text) into the OpenCode session currently displayed in the embedded iframe.
#### Scenario: Inject context on workspace change
- **WHEN** the user opens, closes, or switches between notes
- **AND** the setting "Inject workspace context" is enabled
- **AND** the OpenCode server is running
- **AND** a `sessionID` can be resolved from the current iframe URL
- **THEN** the plugin sends the workspace context to that session
- **AND** the context is injected using `session.prompt({ noReply: true })` (no AI response triggered)
#### Scenario: Inject context on selection change
- **WHEN** the user changes their text selection in an editor
- **AND** the setting is enabled
- **AND** the OpenCode server is running
- **THEN** the plugin updates the workspace context (debounced)
#### Scenario: Initial context injection
- **WHEN** the OpenCode server transitions to running state
- **AND** the setting is enabled
- **AND** a tracked session exists (created on first open)
- **THEN** the plugin injects the current workspace context
### Requirement: Context Replacement (Non-Destructive)
The plugin SHALL replace previous context injections rather than accumulating them.
#### Scenario: Update previous context part
- **WHEN** the plugin injects new context
- **AND** a previous context part exists for the session
- **THEN** the plugin updates the previous context part in-place to match the new context
- **AND** no new context message is added to the session history
#### Scenario: Ignore previous context part and re-inject
- **WHEN** in-place update is not available
- **AND** a previous context part exists for the session
- **THEN** the plugin marks the previous context part as `ignored: true`
- **AND** injects new context with `noReply: true`
- **AND** stores the new message/part IDs for future updates
#### Scenario: Replacement failure handling
- **WHEN** a previous context part cannot be updated or ignored (already removed, invalid IDs)
- **THEN** the plugin continues with fresh context injection
- **AND** logs the error to console for debugging
#### Scenario: Never revert
- **WHEN** updating context
- **THEN** the plugin MUST NOT call `session.revert()` as part of this feature
### Requirement: Debounced Context Updates
The plugin SHALL debounce workspace change events to prevent excessive API calls.
### Requirement: Session Tracking and URL Persistence
The plugin SHALL create and track an OpenCode session and preserve the iframe URL for the duration of the Obsidian process.
#### Scenario: Create session on first view open
- **WHEN** the OpenCode view is opened for the first time in the current Obsidian run
- **AND** the OpenCode server is running
- **THEN** the plugin creates a new OpenCode session
- **AND** updates the iframe URL to the session route
- **AND** stores that URL for later restores
#### Scenario: Restore last URL on reopen
- **WHEN** the OpenCode view is closed and reopened
- **AND** a previous iframe URL was stored in memory
- **THEN** the iframe is loaded with the stored URL
#### Scenario: Adopt user-changed session
- **WHEN** the user navigates to a different session within the iframe UI
- **AND** the plugin is about to inject context
- **THEN** the plugin reads the iframe `src` URL
- **AND** resolves the session ID from that URL
- **AND** updates the tracked session and stored URL to match
#### Scenario: No session route
- **WHEN** the iframe URL does not contain a session route
- **AND** the plugin is about to inject context
- **THEN** the plugin does not inject any context
#### Scenario: Invalidate stored URL when base changes
- **WHEN** hostname, port, or project directory changes
- **THEN** the plugin clears the stored URL and tracked session
- **AND** a new session is created on the next first open
#### Scenario: Rapid file switching
- **WHEN** the user rapidly opens or closes multiple files
- **THEN** the plugin waits 2 seconds after the last change before sending context update
- **AND** only one API call is made for the batch of changes
#### Scenario: Rapid selection changes
- **WHEN** the user is actively selecting text (dragging)
- **THEN** the plugin waits 2 seconds after selection stabilizes before updating context
### Requirement: Context Injection Settings
The plugin SHALL provide settings to control workspace context injection behavior.
#### Scenario: Enable/disable toggle
- **WHEN** the user disables "Inject workspace context"
- **THEN** the plugin does not register workspace event listeners
- **AND** no context is injected into OpenCode sessions
#### Scenario: Enabled by default
- **WHEN** the plugin is installed fresh
- **THEN** the "Inject workspace context" setting defaults to enabled
#### Scenario: Limit number of notes
- **WHEN** more than `maxNotesInContext` notes are open
- **THEN** the plugin includes only the first N paths
- **AND** the default limit is 20 notes
#### Scenario: Limit selection length
- **WHEN** the selected text exceeds `maxSelectionLength` characters
- **THEN** the plugin truncates the selection
- **AND** the default limit is 2000 characters
### Requirement: Context Format
The plugin SHALL format the context as a system reminder containing file paths and optional selected text.
#### Scenario: Context message format with selection
- **WHEN** context is injected
- **AND** text is selected
- **THEN** the message is wrapped in `<system-reminder>` tags
- **AND** includes a header "Currently open notes in Obsidian:"
- **AND** lists each file path as a bullet point
- **AND** includes a "Selected text (from <filepath>):" section
- **AND** wraps the selected text in triple quotes
#### Scenario: Context message format without selection
- **WHEN** context is injected
- **AND** no text is selected
- **THEN** the message contains only the open notes section
- **AND** the selected text section is omitted
#### Scenario: Empty context
- **WHEN** no markdown files are open
- **AND** no text is selected
- **THEN** no context message is injected
- **AND** any previous injected context part is marked as `ignored: true`