Issue Title
Add configurable base path setting to override project.basePath for opencode.exe working directory
Problem Description
When Rider opens a Visual Studio solution file (.sln) that's nested in a subdirectory, the plugin uses project.basePath as the working directory for opencode.exe 1 . This results in opencode running from the solution directory rather than the parent code directory, which may not be the desired working directory for file operations and Git commands.
Proposed Solution
Add an optional "Custom Base Path" setting to the connection dialog that allows users to override the default project.basePath. When not specified, the plugin will continue using project.basePath for backward compatibility.
Implementation Details
1. UI Changes
File: src/main/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialog.kt
- Add a new text field for custom base path in
createCenterPanel() 2
- Add persistence property
PROP_CUSTOM_BASE_PATH following the existing pattern 3
- Update
ConnectionInfo data class to include customBasePath field 4
2. Service Layer Changes
File: src/main/kotlin/ai/opencode/ide/jetbrains/OpenCodeService.kt
- Modify
createTerminalUI() to use custom path when available 1
- Update
processConnectionChoice() to pass the custom base path parameter
3. Code Changes Required
// In OpenCodeConnectDialog.kt
private const val PROP_CUSTOM_BASE_PATH = "opencode.customBasePath"
// Add to createCenterPanel()
val basePathLabel = JBLabel("Custom base path (optional):")
val basePathField = JBTextField()
basePathField.toolTipText = "Override project base path for opencode.exe working directory"
// In OpenCodeService.kt
val workingDir = connectionInfo.customBasePath ?: project.basePath
val widget = terminalView.createLocalShellWidget(workingDir, tabName)
Test Requirements
Based on the existing test infrastructure 5 , add the following test cases:
File: src/test/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialogTest.kt
- Test custom base path field validation
- Test persistence of custom base path setting
- Test default behavior when custom base path is empty
File: src/test/kotlin/ai/opencode/ide/jetbrains/OpenCodeServiceTest.kt
- Test terminal creation with custom base path
- Test fallback to project.basePath when custom path is null
- Test path resolution with custom base path
Backward Compatibility
- Setting defaults to null/empty, preserving current behavior
- Existing users will see no change in functionality
- New users can optionally specify custom base path
Acceptance Criteria
- ✅ Custom base path field appears in connection dialog
- ✅ Setting is persisted across IDE sessions
- ✅ Terminal uses custom path when specified
- ✅ Falls back to project.basePath when empty
- ✅ All existing functionality remains unchanged
- ✅ Test coverage for new functionality
Notes
This change leverages the existing settings infrastructure 6 and follows the same pattern as password persistence. The implementation is minimal and focused on solving the Rider solution scenario while maintaining full backward compatibility.
Wiki pages you might want to explore:
Citations
File: src/main/kotlin/ai/opencode/ide/jetbrains/OpenCodeService.kt (L682-684)
val terminalView = TerminalView.getInstance(project)
val tabName = "$OPEN_CODE_TAB_PREFIX($port)"
val widget = terminalView.createLocalShellWidget(project.basePath, tabName)
File: src/main/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialog.kt (L27-32)
data class ConnectionInfo(
val hostname: String,
val port: Int,
val password: String?,
val useWebInterface: Boolean
)
File: src/main/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialog.kt (L53-89)
override fun createCenterPanel(): JComponent {
val panel = JPanel(BorderLayout(0, JBUI.scale(8)))
panel.preferredSize = Dimension(JBUI.scale(300), JBUI.scale(140))
val formPanel = JPanel(GridLayout(4, 1, 0, JBUI.scale(4)))
val addressLabel = JBLabel("Server address:")
val passwordLabel = JBLabel("Server password (optional):")
// Load saved values
val props = PropertiesComponent.getInstance()
// Always suggest a new available port by default
addressField.text = "127.0.0.1:$defaultPort"
// Load saved password (Base64 encoded for basic obfuscation)
try {
val encodedPassword = props.getValue(PROP_LAST_PASSWORD, "")
if (encodedPassword.isNotBlank()) {
val decodedPassword = String(Base64.getDecoder().decode(encodedPassword))
passwordField.text = decodedPassword
}
} catch (e: Exception) {
// Ignore if password retrieval fails
}
addressField.toolTipText = "Format: hostname:port (e.g., 127.0.0.1:4096)"
passwordField.toolTipText = "OPENCODE_SERVER_PASSWORD"
passwordField.emptyText.text = "For remote OpenCode servers"
formPanel.add(addressLabel)
formPanel.add(addressField)
formPanel.add(passwordLabel)
formPanel.add(passwordField)
panel.add(formPanel, BorderLayout.CENTER)
return panel
}
File: src/main/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialog.kt (L151-154)
companion object {
private const val PROP_LAST_ADDRESS = "opencode.lastAddress"
private const val PROP_LAST_PASSWORD = "opencode.lastPassword"
File: AGENTS.md (L42-49)
- **Run Single Test Class** (Preferred for targeted validation):
```bash
./gradlew test --tests "ai.opencode.ide.jetbrains.util.PortFinderTest"
- Run Single Test Method (Precision testing):
./gradlew test --tests "ai.opencode.ide.jetbrains.util.PortFinderTest.testPortAvailability"
Issue Title
Add configurable base path setting to override project.basePath for opencode.exe working directory
Problem Description
When Rider opens a Visual Studio solution file (.sln) that's nested in a subdirectory, the plugin uses
project.basePathas the working directory for opencode.exe 1 . This results in opencode running from the solution directory rather than the parent code directory, which may not be the desired working directory for file operations and Git commands.Proposed Solution
Add an optional "Custom Base Path" setting to the connection dialog that allows users to override the default
project.basePath. When not specified, the plugin will continue usingproject.basePathfor backward compatibility.Implementation Details
1. UI Changes
File:
src/main/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialog.ktcreateCenterPanel()2PROP_CUSTOM_BASE_PATHfollowing the existing pattern 3ConnectionInfodata class to includecustomBasePathfield 42. Service Layer Changes
File:
src/main/kotlin/ai/opencode/ide/jetbrains/OpenCodeService.ktcreateTerminalUI()to use custom path when available 1processConnectionChoice()to pass the custom base path parameter3. Code Changes Required
Test Requirements
Based on the existing test infrastructure 5 , add the following test cases:
File:
src/test/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialogTest.ktFile:
src/test/kotlin/ai/opencode/ide/jetbrains/OpenCodeServiceTest.ktBackward Compatibility
Acceptance Criteria
Notes
This change leverages the existing settings infrastructure 6 and follows the same pattern as password persistence. The implementation is minimal and focused on solving the Rider solution scenario while maintaining full backward compatibility.
Wiki pages you might want to explore:
Citations
File: src/main/kotlin/ai/opencode/ide/jetbrains/OpenCodeService.kt (L682-684)
File: src/main/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialog.kt (L27-32)
File: src/main/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialog.kt (L53-89)
File: src/main/kotlin/ai/opencode/ide/jetbrains/ui/OpenCodeConnectDialog.kt (L151-154)
File: AGENTS.md (L42-49)