opencode-marketplace 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli.ts +17 -0
- package/src/commands/scan.ts +3 -3
- package/src/config.ts +65 -0
- package/src/discovery.ts +3 -3
- package/src/paths.ts +20 -10
- package/src/types.ts +4 -0
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { list } from "./commands/list";
|
|
|
6
6
|
import { scan } from "./commands/scan";
|
|
7
7
|
import { uninstall } from "./commands/uninstall";
|
|
8
8
|
import { update } from "./commands/update";
|
|
9
|
+
import { setAgentsOverride } from "./config";
|
|
9
10
|
|
|
10
11
|
export function run(argv = process.argv) {
|
|
11
12
|
const cli = cac("opencode-marketplace");
|
|
@@ -19,11 +20,15 @@ export function run(argv = process.argv) {
|
|
|
19
20
|
)
|
|
20
21
|
.option("--force", "Overwrite existing components", { default: false })
|
|
21
22
|
.option("-i, --interactive", "Interactively select components to install", { default: false })
|
|
23
|
+
.option("--agents", "Install skills to ~/.agents/skills/ (overrides config)")
|
|
22
24
|
.action(async (path, options) => {
|
|
23
25
|
if (options.scope !== "user" && options.scope !== "project") {
|
|
24
26
|
console.error(`Invalid scope: ${options.scope}. Must be 'user' or 'project'.`);
|
|
25
27
|
process.exit(1);
|
|
26
28
|
}
|
|
29
|
+
if (options.agents) {
|
|
30
|
+
setAgentsOverride();
|
|
31
|
+
}
|
|
27
32
|
|
|
28
33
|
try {
|
|
29
34
|
await install(path, options);
|
|
@@ -41,18 +46,26 @@ export function run(argv = process.argv) {
|
|
|
41
46
|
.command("import [config-path]", "Install plugins from import config file")
|
|
42
47
|
.option("--target-dir <dir>", "Custom installation directory (overrides ~/.config/opencode)")
|
|
43
48
|
.option("--force", "Overwrite existing components", { default: false })
|
|
49
|
+
.option("--agents", "Install skills to ~/.agents/skills/ (overrides config)")
|
|
44
50
|
.action((configPath, options) => {
|
|
51
|
+
if (options.agents) {
|
|
52
|
+
setAgentsOverride();
|
|
53
|
+
}
|
|
45
54
|
return importPlugins(configPath, options);
|
|
46
55
|
});
|
|
47
56
|
|
|
48
57
|
cli
|
|
49
58
|
.command("uninstall <name>", "Uninstall a plugin")
|
|
50
59
|
.option("--scope <scope>", "Installation scope (user/project)", { default: "user" })
|
|
60
|
+
.option("--agents", "Install skills to ~/.agents/skills/ (overrides config)")
|
|
51
61
|
.action((name, options) => {
|
|
52
62
|
if (options.scope !== "user" && options.scope !== "project") {
|
|
53
63
|
console.error(`Invalid scope: ${options.scope}. Must be 'user' or 'project'.`);
|
|
54
64
|
process.exit(1);
|
|
55
65
|
}
|
|
66
|
+
if (options.agents) {
|
|
67
|
+
setAgentsOverride();
|
|
68
|
+
}
|
|
56
69
|
return uninstall(name, options);
|
|
57
70
|
});
|
|
58
71
|
|
|
@@ -76,11 +89,15 @@ export function run(argv = process.argv) {
|
|
|
76
89
|
cli
|
|
77
90
|
.command("update <name>", "Update a plugin from its remote source")
|
|
78
91
|
.option("--scope <scope>", "Installation scope (user/project)", { default: "user" })
|
|
92
|
+
.option("--agents", "Install skills to ~/.agents/skills/ (overrides config)")
|
|
79
93
|
.action((name, options) => {
|
|
80
94
|
if (options.scope !== "user" && options.scope !== "project") {
|
|
81
95
|
console.error(`Invalid scope: ${options.scope}. Must be 'user' or 'project'.`);
|
|
82
96
|
process.exit(1);
|
|
83
97
|
}
|
|
98
|
+
if (options.agents) {
|
|
99
|
+
setAgentsOverride();
|
|
100
|
+
}
|
|
84
101
|
return update(name, options);
|
|
85
102
|
});
|
|
86
103
|
|
package/src/commands/scan.ts
CHANGED
|
@@ -96,9 +96,9 @@ export async function scan(path: string, options: ScanOptions): Promise<void> {
|
|
|
96
96
|
console.log("No components found.");
|
|
97
97
|
console.log();
|
|
98
98
|
console.log("Expected directories:");
|
|
99
|
-
console.log(" - .opencode/
|
|
100
|
-
console.log(" - .opencode/
|
|
101
|
-
console.log(" - .opencode/
|
|
99
|
+
console.log(" - .opencode/commands/, .claude/commands/, commands/, or command/");
|
|
100
|
+
console.log(" - .opencode/agents/, .claude/agents/, agents/, or agent/");
|
|
101
|
+
console.log(" - .opencode/skills/, .claude/skills/, skills/, or skill/");
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
104
|
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, normalize } from "node:path";
|
|
4
|
+
import type { OcmConfig } from "./types";
|
|
5
|
+
|
|
6
|
+
function getDefaultSkillsBase(): string {
|
|
7
|
+
return join(homedir(), ".agents");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let cachedConfig: OcmConfig | null = null;
|
|
11
|
+
let agentsOverride = false;
|
|
12
|
+
|
|
13
|
+
export function setAgentsOverride(): void {
|
|
14
|
+
agentsOverride = true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getConfigPath(): string {
|
|
18
|
+
return join(homedir(), ".config", "opencode", "ocm-config.json");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function loadConfig(): OcmConfig {
|
|
22
|
+
if (cachedConfig !== null) {
|
|
23
|
+
return cachedConfig;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const configPath = getConfigPath();
|
|
27
|
+
|
|
28
|
+
if (!existsSync(configPath)) {
|
|
29
|
+
cachedConfig = {};
|
|
30
|
+
return cachedConfig;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const content = readFileSync(configPath, "utf-8");
|
|
35
|
+
const parsed = JSON.parse(content);
|
|
36
|
+
cachedConfig = {};
|
|
37
|
+
|
|
38
|
+
if (parsed && typeof parsed === "object" && typeof parsed.skillsPath === "string") {
|
|
39
|
+
let skillsPath = parsed.skillsPath;
|
|
40
|
+
if (skillsPath.startsWith("~/") || skillsPath === "~") {
|
|
41
|
+
skillsPath = join(homedir(), skillsPath.slice(2));
|
|
42
|
+
}
|
|
43
|
+
cachedConfig.skillsPath = normalize(skillsPath);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return cachedConfig;
|
|
47
|
+
} catch {
|
|
48
|
+
cachedConfig = {};
|
|
49
|
+
return cachedConfig;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function resolveUserSkillsPath(): string {
|
|
54
|
+
if (agentsOverride) {
|
|
55
|
+
return join(getDefaultSkillsBase(), "skills");
|
|
56
|
+
}
|
|
57
|
+
const config = loadConfig();
|
|
58
|
+
const base = config.skillsPath || getDefaultSkillsBase();
|
|
59
|
+
return join(base, "skills");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function resetConfigCache(): void {
|
|
63
|
+
cachedConfig = null;
|
|
64
|
+
agentsOverride = false;
|
|
65
|
+
}
|
package/src/discovery.ts
CHANGED
|
@@ -5,9 +5,9 @@ import type { ComponentType, DiscoveredComponent } from "./types";
|
|
|
5
5
|
import { getComponentTargetName } from "./types";
|
|
6
6
|
|
|
7
7
|
const SEARCH_PATHS: Record<ComponentType, string[]> = {
|
|
8
|
-
command: [".opencode/
|
|
9
|
-
agent: [".opencode/
|
|
10
|
-
skill: [".opencode/
|
|
8
|
+
command: [".opencode/commands", ".claude/commands", "commands", "command"],
|
|
9
|
+
agent: [".opencode/agents", ".claude/agents", "agents", "agent"],
|
|
10
|
+
skill: [".opencode/skills", ".claude/skills", "skills", "skill"],
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
/**
|
package/src/paths.ts
CHANGED
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
import { mkdir } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, normalize } from "node:path";
|
|
4
|
+
import { resolveUserSkillsPath } from "./config";
|
|
4
5
|
import type { ComponentType, Scope } from "./types";
|
|
5
6
|
import { getComponentTargetName } from "./types";
|
|
6
7
|
|
|
8
|
+
function pluralizeType(type: ComponentType): string {
|
|
9
|
+
return `${type}s`;
|
|
10
|
+
}
|
|
11
|
+
|
|
7
12
|
/**
|
|
8
13
|
* Returns the base directory for a component type with trailing slash.
|
|
9
14
|
* Examples:
|
|
10
|
-
* - User scope: "~/.config/opencode/
|
|
11
|
-
* - Project scope: ".opencode/
|
|
15
|
+
* - User scope: "~/.config/opencode/commands/", "~/.agents/skills/"
|
|
16
|
+
* - Project scope: ".opencode/commands/"
|
|
12
17
|
*/
|
|
13
18
|
export function getComponentDir(type: ComponentType, scope: Scope, targetDir?: string): string {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
if (scope === "user") {
|
|
20
|
+
if (targetDir) {
|
|
21
|
+
return `${normalize(join(targetDir, pluralizeType(type)))}/`;
|
|
22
|
+
}
|
|
23
|
+
if (type === "skill") {
|
|
24
|
+
return `${normalize(resolveUserSkillsPath())}/`;
|
|
25
|
+
}
|
|
26
|
+
return `${normalize(join(homedir(), ".config", "opencode", pluralizeType(type)))}/`;
|
|
27
|
+
}
|
|
18
28
|
|
|
19
|
-
return `${normalize(
|
|
29
|
+
return `${normalize(join(process.cwd(), ".opencode", pluralizeType(type)))}/`;
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
/**
|
|
@@ -24,8 +34,8 @@ export function getComponentDir(type: ComponentType, scope: Scope, targetDir?: s
|
|
|
24
34
|
* Handles both files (commands/agents) and directories (skills).
|
|
25
35
|
*
|
|
26
36
|
* Examples:
|
|
27
|
-
* - Command: "~/.config/opencode/
|
|
28
|
-
* - Skill: "~/.
|
|
37
|
+
* - Command: "~/.config/opencode/commands/myplugin--reflect.md"
|
|
38
|
+
* - Skill: "~/.agents/skills/myplugin--code-review/"
|
|
29
39
|
*/
|
|
30
40
|
export function getComponentTargetPath(
|
|
31
41
|
pluginName: string,
|
|
@@ -47,7 +57,7 @@ export function getComponentTargetPath(
|
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
/**
|
|
50
|
-
* Ensures all component directories (
|
|
60
|
+
* Ensures all component directories (commands, agents, skills) exist for the given scope.
|
|
51
61
|
* Idempotent - safe to call multiple times.
|
|
52
62
|
*/
|
|
53
63
|
export async function ensureComponentDirsExist(scope: Scope, targetDir?: string): Promise<void> {
|