Skip to content

Commit bde5527

Browse files
authored
Merge pull request #3 from j4rviscmd/feat/auto-copy-command-files
fix: resolve commands directory path for both bundled and dev environments
2 parents 15ac815 + 655aa12 commit bde5527

File tree

2 files changed

+89
-29
lines changed

2 files changed

+89
-29
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "opencode-agent-modes",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"description": "OpenCode plugin to switch agent modes between performance and economy presets",
55
"module": "src/index.ts",
66
"main": "dist/index.js",

src/config/command-installer.ts

Lines changed: 88 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,115 @@
1-
import { copyFileSync, mkdirSync, readdirSync, existsSync } from "node:fs";
2-
import { homedir } from "node:os";
3-
import { dirname, join } from "node:path";
4-
import { fileURLToPath } from "node:url";
1+
/**
2+
* @fileoverview Command file installer for OpenCode slash commands.
3+
*
4+
* This module handles copying slash command markdown files from the plugin's
5+
* commands directory to OpenCode's configuration directory during plugin
6+
* initialization. This ensures command files are available without requiring
7+
* manual postinstall script execution.
8+
*
9+
* @module config/command-installer
10+
*/
11+
12+
import { copyFileSync, mkdirSync, readdirSync, existsSync } from 'node:fs'
13+
import { homedir } from 'node:os'
14+
import { dirname, join } from 'node:path'
15+
import { fileURLToPath } from 'node:url'
16+
17+
/**
18+
* Target directory for OpenCode command files.
19+
*
20+
* This is the standard location where OpenCode looks for slash command
21+
* markdown files: `~/.config/opencode/command/`
22+
*
23+
* @constant
24+
*/
25+
const COMMANDS_DEST = join(homedir(), '.config', 'opencode', 'command')
526

627
/**
7-
* Target directory for OpenCode command files
28+
* Finds the commands source directory.
29+
*
30+
* Tries multiple candidate paths to support both production and development
31+
* environments by checking relative paths from the current module location:
32+
* - Production: bundled dist/index.js -> ../commands
33+
* - Development: src/config/command-installer.ts -> ../../commands
34+
*
35+
* The function checks each candidate path in order and returns the first
36+
* one that exists on the filesystem.
37+
*
38+
* @returns Absolute path to commands directory if found, or null if none
39+
* of the candidate paths exist
40+
*
41+
* @example
42+
* ```typescript
43+
* const commandsDir = findCommandsDir();
44+
* if (commandsDir) {
45+
* console.log(`Commands found at: ${commandsDir}`);
46+
* } else {
47+
* console.log('Commands directory not found');
48+
* }
49+
* ```
850
*/
9-
const COMMANDS_DEST = join(homedir(), ".config", "opencode", "command");
51+
function findCommandsDir(): string | null {
52+
const __dirname = dirname(fileURLToPath(import.meta.url))
53+
54+
// Try multiple paths to support different build outputs
55+
const candidates = [
56+
join(__dirname, '..', 'commands'), // Production: dist/ -> commands/
57+
join(__dirname, '..', '..', 'commands'), // Development: src/config/ -> commands/
58+
]
59+
60+
return candidates.find(existsSync) ?? null
61+
}
1062

1163
/**
1264
* Copies slash command markdown files to OpenCode's command directory.
1365
*
1466
* This function is called during plugin initialization to ensure
1567
* command files are available without manual postinstall execution.
68+
* It creates the destination directory if it doesn't exist and copies
69+
* all `.md` files from the source commands directory.
70+
*
71+
* The function is designed to be non-fatal: if copying fails (e.g., due to
72+
* permission issues), it logs a warning but doesn't throw an error,
73+
* allowing the plugin to continue initializing.
1674
*
17-
* @returns Number of files copied, or -1 if source directory not found
75+
* @returns Number of files successfully copied, or -1 if source directory
76+
* not found or an error occurred during copying
77+
*
78+
* @example
79+
* ```typescript
80+
* const copied = copyCommandFiles();
81+
* if (copied > 0) {
82+
* console.log(`Copied ${copied} command files`);
83+
* }
84+
* ```
1885
*/
1986
export function copyCommandFiles(): number {
20-
// Resolve the commands directory relative to this file
21-
// In dist: dist/config/command-installer.js -> dist/../commands = commands/
22-
const __dirname = dirname(fileURLToPath(import.meta.url));
23-
const commandsSrc = join(__dirname, "..", "..", "commands");
87+
const commandsSrc = findCommandsDir()
2488

25-
// Skip if commands directory doesn't exist (shouldn't happen in production)
26-
if (!existsSync(commandsSrc)) {
27-
console.warn(
28-
"[agent-mode-switcher] Commands directory not found:",
29-
commandsSrc
30-
);
31-
return -1;
89+
// Skip if commands directory doesn't exist
90+
if (!commandsSrc) {
91+
return -1
3292
}
3393

3494
try {
35-
// Ensure destination directory exists
36-
mkdirSync(COMMANDS_DEST, { recursive: true });
95+
// Create destination directory with parents if needed
96+
mkdirSync(COMMANDS_DEST, { recursive: true })
3797

38-
// Find all markdown files in the commands directory
39-
const files = readdirSync(commandsSrc).filter((f) => f.endsWith(".md"));
98+
// Filter only markdown files
99+
const files = readdirSync(commandsSrc).filter((f) => f.endsWith('.md'))
40100

41-
// Copy each command file to the OpenCode config directory
101+
// Copy each command file to the destination
42102
for (const file of files) {
43-
copyFileSync(join(commandsSrc, file), join(COMMANDS_DEST, file));
103+
copyFileSync(join(commandsSrc, file), join(COMMANDS_DEST, file))
44104
}
45105

46-
return files.length;
106+
return files.length
47107
} catch (error) {
48108
// Non-fatal: log warning but don't block plugin initialization
49109
console.warn(
50-
"[agent-mode-switcher] Warning: Could not copy command files:",
110+
'[agent-mode-switcher] Warning: Could not copy command files:',
51111
error instanceof Error ? error.message : String(error)
52-
);
53-
return -1;
112+
)
113+
return -1
54114
}
55115
}

0 commit comments

Comments
 (0)