Allow configuring starting dir
This commit is contained in:
82
main.js
82
main.js
@@ -34,7 +34,8 @@ var DEFAULT_SETTINGS = {
|
|||||||
port: 14096,
|
port: 14096,
|
||||||
hostname: "127.0.0.1",
|
hostname: "127.0.0.1",
|
||||||
autoStart: false,
|
autoStart: false,
|
||||||
opencodePath: "opencode"
|
opencodePath: "opencode",
|
||||||
|
projectDirectory: ""
|
||||||
};
|
};
|
||||||
var OPENCODE_VIEW_TYPE = "opencode-view";
|
var OPENCODE_VIEW_TYPE = "opencode-view";
|
||||||
|
|
||||||
@@ -210,9 +211,21 @@ var OpenCodeView = class extends import_obsidian.ItemView {
|
|||||||
|
|
||||||
// src/SettingsTab.ts
|
// src/SettingsTab.ts
|
||||||
var import_obsidian2 = require("obsidian");
|
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 {
|
var OpenCodeSettingTab = class extends import_obsidian2.PluginSettingTab {
|
||||||
constructor(app, plugin) {
|
constructor(app, plugin) {
|
||||||
super(app, plugin);
|
super(app, plugin);
|
||||||
|
this.validateTimeout = null;
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
display() {
|
display() {
|
||||||
@@ -243,6 +256,18 @@ var OpenCodeSettingTab = class extends import_obsidian2.PluginSettingTab {
|
|||||||
await this.plugin.saveSettings();
|
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" });
|
containerEl.createEl("h3", { text: "Behavior" });
|
||||||
new import_obsidian2.Setting(containerEl).setName("Auto-start server").setDesc(
|
new import_obsidian2.Setting(containerEl).setName("Auto-start server").setDesc(
|
||||||
"Automatically start the OpenCode server when Obsidian opens (not recommended for faster startup)"
|
"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" });
|
const statusContainer = containerEl.createDiv({ cls: "opencode-settings-status" });
|
||||||
this.renderServerStatus(statusContainer);
|
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) {
|
renderServerStatus(container) {
|
||||||
container.empty();
|
container.empty();
|
||||||
const state = this.plugin.getProcessState();
|
const state = this.plugin.getProcessState();
|
||||||
@@ -343,6 +395,9 @@ var ProcessManager = class {
|
|||||||
updateSettings(settings) {
|
updateSettings(settings) {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
}
|
}
|
||||||
|
updateProjectDirectory(directory) {
|
||||||
|
this.projectDirectory = directory;
|
||||||
|
}
|
||||||
getState() {
|
getState() {
|
||||||
return this.state;
|
return this.state;
|
||||||
}
|
}
|
||||||
@@ -500,13 +555,14 @@ var OpenCodePlugin = class extends import_obsidian4.Plugin {
|
|||||||
console.log("Loading OpenCode plugin");
|
console.log("Loading OpenCode plugin");
|
||||||
await this.loadSettings();
|
await this.loadSettings();
|
||||||
const vaultPath = this.getVaultPath();
|
const vaultPath = this.getVaultPath();
|
||||||
|
const projectDirectory = this.getProjectDirectory();
|
||||||
this.processManager = new ProcessManager(
|
this.processManager = new ProcessManager(
|
||||||
this.settings,
|
this.settings,
|
||||||
vaultPath,
|
vaultPath,
|
||||||
vaultPath,
|
projectDirectory,
|
||||||
(state) => this.notifyStateChange(state)
|
(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.registerView(OPENCODE_VIEW_TYPE, (leaf) => new OpenCodeView(leaf, this));
|
||||||
this.addRibbonIcon("terminal", "OpenCode", () => {
|
this.addRibbonIcon("terminal", "OpenCode", () => {
|
||||||
this.activateView();
|
this.activateView();
|
||||||
@@ -561,6 +617,18 @@ var OpenCodePlugin = class extends import_obsidian4.Plugin {
|
|||||||
this.processManager.updateSettings(this.settings);
|
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
|
// Get existing view leaf if any
|
||||||
getExistingLeaf() {
|
getExistingLeaf() {
|
||||||
const leaves = this.app.workspace.getLeavesOfType(OPENCODE_VIEW_TYPE);
|
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
|
// Get the vault path - this is the root directory of the Obsidian vault
|
||||||
// which will be passed to OpenCode as the project directory
|
|
||||||
getVaultPath() {
|
getVaultPath() {
|
||||||
const adapter = this.app.vault.adapter;
|
const adapter = this.app.vault.adapter;
|
||||||
const vaultPath = adapter.basePath || "";
|
const vaultPath = adapter.basePath || "";
|
||||||
@@ -645,4 +712,11 @@ var OpenCodePlugin = class extends import_obsidian4.Plugin {
|
|||||||
}
|
}
|
||||||
return vaultPath;
|
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;
|
this.onStateChange = onStateChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSettings(settings: OpenCodeSettings) {
|
updateSettings(settings: OpenCodeSettings): void {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateProjectDirectory(directory: string): void {
|
||||||
|
this.projectDirectory = directory;
|
||||||
|
}
|
||||||
|
|
||||||
getState(): ProcessState {
|
getState(): ProcessState {
|
||||||
return this.state;
|
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";
|
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 {
|
export class OpenCodeSettingTab extends PluginSettingTab {
|
||||||
plugin: OpenCodePlugin;
|
plugin: OpenCodePlugin;
|
||||||
|
private validateTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
constructor(app: App, plugin: OpenCodePlugin) {
|
constructor(app: App, plugin: OpenCodePlugin) {
|
||||||
super(app, plugin);
|
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
|
// Behavior settings section
|
||||||
containerEl.createEl("h3", { text: "Behavior" });
|
containerEl.createEl("h3", { text: "Behavior" });
|
||||||
|
|
||||||
@@ -86,6 +119,44 @@ export class OpenCodeSettingTab extends PluginSettingTab {
|
|||||||
this.renderServerStatus(statusContainer);
|
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 {
|
private renderServerStatus(container: HTMLElement): void {
|
||||||
container.empty();
|
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
|
// Get the vault directory path to pass to OpenCode
|
||||||
const vaultPath = this.getVaultPath();
|
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.processManager = new ProcessManager(
|
||||||
this.settings,
|
this.settings,
|
||||||
vaultPath,
|
vaultPath,
|
||||||
vaultPath,
|
projectDirectory,
|
||||||
(state) => this.notifyStateChange(state)
|
(state) => this.notifyStateChange(state)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("[OpenCode] Configured with vault directory:", vaultPath);
|
console.log("[OpenCode] Configured with project directory:", projectDirectory);
|
||||||
|
|
||||||
// Register the OpenCode view
|
// Register the OpenCode view
|
||||||
this.registerView(OPENCODE_VIEW_TYPE, (leaf) => new OpenCodeView(leaf, this));
|
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
|
// Get existing view leaf if any
|
||||||
private getExistingLeaf(): WorkspaceLeaf | null {
|
private getExistingLeaf(): WorkspaceLeaf | null {
|
||||||
const leaves = this.app.workspace.getLeavesOfType(OPENCODE_VIEW_TYPE);
|
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
|
// 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 {
|
private getVaultPath(): string {
|
||||||
const adapter = this.app.vault.adapter as any;
|
const adapter = this.app.vault.adapter as any;
|
||||||
const vaultPath = adapter.basePath || "";
|
const vaultPath = adapter.basePath || "";
|
||||||
@@ -202,4 +219,12 @@ export default class OpenCodePlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
return vaultPath;
|
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;
|
hostname: string;
|
||||||
autoStart: boolean;
|
autoStart: boolean;
|
||||||
opencodePath: string;
|
opencodePath: string;
|
||||||
|
projectDirectory: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_SETTINGS: OpenCodeSettings = {
|
export const DEFAULT_SETTINGS: OpenCodeSettings = {
|
||||||
@@ -10,6 +11,7 @@ export const DEFAULT_SETTINGS: OpenCodeSettings = {
|
|||||||
hostname: "127.0.0.1",
|
hostname: "127.0.0.1",
|
||||||
autoStart: false,
|
autoStart: false,
|
||||||
opencodePath: "opencode",
|
opencodePath: "opencode",
|
||||||
|
projectDirectory: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OPENCODE_VIEW_TYPE = "opencode-view";
|
export const OPENCODE_VIEW_TYPE = "opencode-view";
|
||||||
|
|||||||
Reference in New Issue
Block a user