Allow configuring starting dir
This commit is contained in:
82
main.js
82
main.js
@@ -34,7 +34,8 @@ var DEFAULT_SETTINGS = {
|
||||
port: 14096,
|
||||
hostname: "127.0.0.1",
|
||||
autoStart: false,
|
||||
opencodePath: "opencode"
|
||||
opencodePath: "opencode",
|
||||
projectDirectory: ""
|
||||
};
|
||||
var OPENCODE_VIEW_TYPE = "opencode-view";
|
||||
|
||||
@@ -210,9 +211,21 @@ var OpenCodeView = class extends import_obsidian.ItemView {
|
||||
|
||||
// src/SettingsTab.ts
|
||||
var import_obsidian2 = require("obsidian");
|
||||
var import_fs = require("fs");
|
||||
var import_os = require("os");
|
||||
function expandTilde(path) {
|
||||
if (path === "~") {
|
||||
return (0, import_os.homedir)();
|
||||
}
|
||||
if (path.startsWith("~/")) {
|
||||
return path.replace("~", (0, import_os.homedir)());
|
||||
}
|
||||
return path;
|
||||
}
|
||||
var OpenCodeSettingTab = class extends import_obsidian2.PluginSettingTab {
|
||||
constructor(app, plugin) {
|
||||
super(app, plugin);
|
||||
this.validateTimeout = null;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
display() {
|
||||
@@ -243,6 +256,18 @@ var OpenCodeSettingTab = class extends import_obsidian2.PluginSettingTab {
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
new import_obsidian2.Setting(containerEl).setName("Project directory").setDesc(
|
||||
"Override the starting directory for OpenCode. Leave empty to use the vault root. Supports ~ for home directory."
|
||||
).addText(
|
||||
(text) => text.setPlaceholder("/path/to/project or ~/project").setValue(this.plugin.settings.projectDirectory).onChange((value) => {
|
||||
if (this.validateTimeout) {
|
||||
clearTimeout(this.validateTimeout);
|
||||
}
|
||||
this.validateTimeout = setTimeout(async () => {
|
||||
await this.validateAndSetProjectDirectory(value);
|
||||
}, 500);
|
||||
})
|
||||
);
|
||||
containerEl.createEl("h3", { text: "Behavior" });
|
||||
new import_obsidian2.Setting(containerEl).setName("Auto-start server").setDesc(
|
||||
"Automatically start the OpenCode server when Obsidian opens (not recommended for faster startup)"
|
||||
@@ -256,6 +281,33 @@ var OpenCodeSettingTab = class extends import_obsidian2.PluginSettingTab {
|
||||
const statusContainer = containerEl.createDiv({ cls: "opencode-settings-status" });
|
||||
this.renderServerStatus(statusContainer);
|
||||
}
|
||||
async validateAndSetProjectDirectory(value) {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) {
|
||||
await this.plugin.updateProjectDirectory("");
|
||||
return;
|
||||
}
|
||||
if (!trimmed.startsWith("/") && !trimmed.startsWith("~") && !trimmed.match(/^[A-Za-z]:\\/)) {
|
||||
new import_obsidian2.Notice("Project directory must be an absolute path (or start with ~)");
|
||||
return;
|
||||
}
|
||||
const expanded = expandTilde(trimmed);
|
||||
try {
|
||||
if (!(0, import_fs.existsSync)(expanded)) {
|
||||
new import_obsidian2.Notice("Project directory does not exist");
|
||||
return;
|
||||
}
|
||||
const stat = (0, import_fs.statSync)(expanded);
|
||||
if (!stat.isDirectory()) {
|
||||
new import_obsidian2.Notice("Project directory path is not a directory");
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
new import_obsidian2.Notice(`Failed to validate path: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
await this.plugin.updateProjectDirectory(expanded);
|
||||
}
|
||||
renderServerStatus(container) {
|
||||
container.empty();
|
||||
const state = this.plugin.getProcessState();
|
||||
@@ -343,6 +395,9 @@ var ProcessManager = class {
|
||||
updateSettings(settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
updateProjectDirectory(directory) {
|
||||
this.projectDirectory = directory;
|
||||
}
|
||||
getState() {
|
||||
return this.state;
|
||||
}
|
||||
@@ -500,13 +555,14 @@ var OpenCodePlugin = class extends import_obsidian4.Plugin {
|
||||
console.log("Loading OpenCode plugin");
|
||||
await this.loadSettings();
|
||||
const vaultPath = this.getVaultPath();
|
||||
const projectDirectory = this.getProjectDirectory();
|
||||
this.processManager = new ProcessManager(
|
||||
this.settings,
|
||||
vaultPath,
|
||||
vaultPath,
|
||||
projectDirectory,
|
||||
(state) => this.notifyStateChange(state)
|
||||
);
|
||||
console.log("[OpenCode] Configured with vault directory:", vaultPath);
|
||||
console.log("[OpenCode] Configured with project directory:", projectDirectory);
|
||||
this.registerView(OPENCODE_VIEW_TYPE, (leaf) => new OpenCodeView(leaf, this));
|
||||
this.addRibbonIcon("terminal", "OpenCode", () => {
|
||||
this.activateView();
|
||||
@@ -561,6 +617,18 @@ var OpenCodePlugin = class extends import_obsidian4.Plugin {
|
||||
this.processManager.updateSettings(this.settings);
|
||||
}
|
||||
}
|
||||
// Update project directory and restart server if running
|
||||
async updateProjectDirectory(directory) {
|
||||
this.settings.projectDirectory = directory;
|
||||
await this.saveData(this.settings);
|
||||
if (this.processManager) {
|
||||
this.processManager.updateProjectDirectory(this.getProjectDirectory());
|
||||
if (this.getProcessState() === "running") {
|
||||
this.stopServer();
|
||||
await this.startServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get existing view leaf if any
|
||||
getExistingLeaf() {
|
||||
const leaves = this.app.workspace.getLeavesOfType(OPENCODE_VIEW_TYPE);
|
||||
@@ -636,7 +704,6 @@ var OpenCodePlugin = class extends import_obsidian4.Plugin {
|
||||
}
|
||||
}
|
||||
// Get the vault path - this is the root directory of the Obsidian vault
|
||||
// which will be passed to OpenCode as the project directory
|
||||
getVaultPath() {
|
||||
const adapter = this.app.vault.adapter;
|
||||
const vaultPath = adapter.basePath || "";
|
||||
@@ -645,4 +712,11 @@ var OpenCodePlugin = class extends import_obsidian4.Plugin {
|
||||
}
|
||||
return vaultPath;
|
||||
}
|
||||
// Get the project directory - uses the configured setting if set, otherwise vault path
|
||||
getProjectDirectory() {
|
||||
if (this.settings.projectDirectory) {
|
||||
return this.settings.projectDirectory;
|
||||
}
|
||||
return this.getVaultPath();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,10 +25,14 @@ export class ProcessManager {
|
||||
this.onStateChange = onStateChange;
|
||||
}
|
||||
|
||||
updateSettings(settings: OpenCodeSettings) {
|
||||
updateSettings(settings: OpenCodeSettings): void {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
updateProjectDirectory(directory: string): void {
|
||||
this.projectDirectory = directory;
|
||||
}
|
||||
|
||||
getState(): ProcessState {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
import { App, PluginSettingTab, Setting } from "obsidian";
|
||||
import { App, PluginSettingTab, Setting, Notice } from "obsidian";
|
||||
import { existsSync, statSync } from "fs";
|
||||
import { homedir } from "os";
|
||||
import type OpenCodePlugin from "./main";
|
||||
|
||||
function expandTilde(path: string): string {
|
||||
if (path === "~") {
|
||||
return homedir();
|
||||
}
|
||||
if (path.startsWith("~/")) {
|
||||
return path.replace("~", homedir());
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
export class OpenCodeSettingTab extends PluginSettingTab {
|
||||
plugin: OpenCodePlugin;
|
||||
private validateTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
constructor(app: App, plugin: OpenCodePlugin) {
|
||||
super(app, plugin);
|
||||
@@ -62,6 +75,26 @@ export class OpenCodeSettingTab extends PluginSettingTab {
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Project directory")
|
||||
.setDesc(
|
||||
"Override the starting directory for OpenCode. Leave empty to use the vault root. Supports ~ for home directory."
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("/path/to/project or ~/project")
|
||||
.setValue(this.plugin.settings.projectDirectory)
|
||||
.onChange((value) => {
|
||||
// Debounce validation to avoid spamming notices on every keypress
|
||||
if (this.validateTimeout) {
|
||||
clearTimeout(this.validateTimeout);
|
||||
}
|
||||
this.validateTimeout = setTimeout(async () => {
|
||||
await this.validateAndSetProjectDirectory(value);
|
||||
}, 500);
|
||||
})
|
||||
);
|
||||
|
||||
// Behavior settings section
|
||||
containerEl.createEl("h3", { text: "Behavior" });
|
||||
|
||||
@@ -86,6 +119,44 @@ export class OpenCodeSettingTab extends PluginSettingTab {
|
||||
this.renderServerStatus(statusContainer);
|
||||
}
|
||||
|
||||
private async validateAndSetProjectDirectory(value: string): Promise<void> {
|
||||
const trimmed = value.trim();
|
||||
|
||||
// Empty value is valid - means use vault root
|
||||
if (!trimmed) {
|
||||
await this.plugin.updateProjectDirectory("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate absolute path (supports ~, /, and Windows drive letters)
|
||||
if (!trimmed.startsWith("/") && !trimmed.startsWith("~") && !trimmed.match(/^[A-Za-z]:\\/)) {
|
||||
new Notice("Project directory must be an absolute path (or start with ~)");
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand tilde for validation
|
||||
const expanded = expandTilde(trimmed);
|
||||
|
||||
// Validate path exists and is a directory
|
||||
try {
|
||||
if (!existsSync(expanded)) {
|
||||
new Notice("Project directory does not exist");
|
||||
return;
|
||||
}
|
||||
const stat = statSync(expanded);
|
||||
if (!stat.isDirectory()) {
|
||||
new Notice("Project directory path is not a directory");
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
new Notice(`Failed to validate path: ${(error as Error).message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the expanded path
|
||||
await this.plugin.updateProjectDirectory(expanded);
|
||||
}
|
||||
|
||||
private renderServerStatus(container: HTMLElement): void {
|
||||
container.empty();
|
||||
|
||||
|
||||
33
src/main.ts
33
src/main.ts
@@ -16,16 +16,18 @@ export default class OpenCodePlugin extends Plugin {
|
||||
|
||||
// Get the vault directory path to pass to OpenCode
|
||||
const vaultPath = this.getVaultPath();
|
||||
const projectDirectory = this.getProjectDirectory();
|
||||
|
||||
// Initialize process manager with vault as the project directory
|
||||
// Initialize process manager with vault as the working directory
|
||||
// and either the configured project directory or vault as the project
|
||||
this.processManager = new ProcessManager(
|
||||
this.settings,
|
||||
vaultPath,
|
||||
vaultPath,
|
||||
projectDirectory,
|
||||
(state) => this.notifyStateChange(state)
|
||||
);
|
||||
|
||||
console.log("[OpenCode] Configured with vault directory:", vaultPath);
|
||||
console.log("[OpenCode] Configured with project directory:", projectDirectory);
|
||||
|
||||
// Register the OpenCode view
|
||||
this.registerView(OPENCODE_VIEW_TYPE, (leaf) => new OpenCodeView(leaf, this));
|
||||
@@ -105,6 +107,22 @@ export default class OpenCodePlugin extends Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
// Update project directory and restart server if running
|
||||
async updateProjectDirectory(directory: string): Promise<void> {
|
||||
this.settings.projectDirectory = directory;
|
||||
await this.saveData(this.settings);
|
||||
|
||||
if (this.processManager) {
|
||||
this.processManager.updateProjectDirectory(this.getProjectDirectory());
|
||||
|
||||
// Restart server if it's currently running
|
||||
if (this.getProcessState() === "running") {
|
||||
this.stopServer();
|
||||
await this.startServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get existing view leaf if any
|
||||
private getExistingLeaf(): WorkspaceLeaf | null {
|
||||
const leaves = this.app.workspace.getLeavesOfType(OPENCODE_VIEW_TYPE);
|
||||
@@ -193,7 +211,6 @@ export default class OpenCodePlugin extends Plugin {
|
||||
}
|
||||
|
||||
// Get the vault path - this is the root directory of the Obsidian vault
|
||||
// which will be passed to OpenCode as the project directory
|
||||
private getVaultPath(): string {
|
||||
const adapter = this.app.vault.adapter as any;
|
||||
const vaultPath = adapter.basePath || "";
|
||||
@@ -202,4 +219,12 @@ export default class OpenCodePlugin extends Plugin {
|
||||
}
|
||||
return vaultPath;
|
||||
}
|
||||
|
||||
// Get the project directory - uses the configured setting if set, otherwise vault path
|
||||
getProjectDirectory(): string {
|
||||
if (this.settings.projectDirectory) {
|
||||
return this.settings.projectDirectory;
|
||||
}
|
||||
return this.getVaultPath();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ export interface OpenCodeSettings {
|
||||
hostname: string;
|
||||
autoStart: boolean;
|
||||
opencodePath: string;
|
||||
projectDirectory: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: OpenCodeSettings = {
|
||||
@@ -10,6 +11,7 @@ export const DEFAULT_SETTINGS: OpenCodeSettings = {
|
||||
hostname: "127.0.0.1",
|
||||
autoStart: false,
|
||||
opencodePath: "opencode",
|
||||
projectDirectory: "",
|
||||
};
|
||||
|
||||
export const OPENCODE_VIEW_TYPE = "opencode-view";
|
||||
|
||||
Reference in New Issue
Block a user