zmarketplace 0.7.2 → 0.7.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/opencode.ts +39 -83
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zmarketplace",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "Cross-agent marketplace search: find, audit, and install plugins/skills/themes/prompts across pi, omp, claude code, opencode, gemini cli, and codex",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/opencode.ts CHANGED
@@ -1,102 +1,58 @@
1
1
  /**
2
- * OpenCode plugin entry point.
3
- *
4
- * OpenCode plugins export functions that return hooks.
5
- * This plugin provides a `zmarketplace` tool the agent can call.
6
- *
7
- * OpenCode does NOT support slash commands from plugins.
8
- * For /zmarketplace, create a command file:
9
- * ~/.config/opencode/commands/zmarketplace.md
2
+ * OpenCode plugin provides zmarketplace as a tool.
3
+ * Uses bunx CLI under the hood (no complex logic that can crash).
10
4
  *
11
5
  * Install: add "zmarketplace" to opencode.json plugin array.
12
6
  */
13
7
 
14
- import { search } from "./core/search.ts";
15
- import { getDetail } from "./core/detail.ts";
16
- import { auditPackage } from "./core/audit.ts";
17
- import type { SearchOptions } from "./core/types.ts";
18
-
19
- interface ToolContext {
20
- sessionID?: string;
21
- messageID?: string;
22
- agent?: string;
23
- directory?: string;
24
- worktree?: string;
25
- ask?(message: string): Promise<string>;
26
- }
27
-
28
- interface ToolDef {
29
- description: string;
30
- args: Record<string, unknown>;
31
- execute(args: Record<string, unknown>, ctx: ToolContext): Promise<string>;
8
+ interface ShellAPI {
9
+ // Bun shell template literal
10
+ (strings: TemplateStringsArray, ...values: unknown[]): { quiet(): Promise<{ stdout: Buffer; stderr: Buffer; exitCode: number }> };
32
11
  }
33
12
 
34
13
  interface PluginCtx {
35
14
  project?: unknown;
36
- client?: unknown;
37
15
  directory?: string;
38
16
  worktree?: string;
17
+ $?: ShellAPI;
39
18
  }
40
19
 
41
- /** The zmarketplace tool definition. */
42
- const zmarketplaceTool: ToolDef = {
43
- description:
44
- "Search, inspect, audit, and install packages across agent ecosystems " +
45
- "(pi, omp, claude code, opencode, gemini cli, codex). " +
46
- "Actions: search, detail, audit. " +
47
- "Sources: npm, Claude marketplace, Gemini extensions, MCP registry, Smithery, GitHub.",
48
- args: {
49
- action: { type: "string", description: "search, detail, or audit" },
50
- query: { type: "string", description: "Search query (for search)" },
51
- name: { type: "string", description: "Package name (for detail/audit)" },
52
- ecosystem: {
53
- type: "string",
54
- description: "Filter: pi, claude, opencode, gemini, codex, npm, all",
55
- },
56
- limit: { type: "number", description: "Max results (default 20)" },
57
- },
58
-
59
- async execute(args: Record<string, unknown>): Promise<string> {
60
- const action = args["action"] as string;
61
-
62
- if (action === "search") {
63
- const opts: SearchOptions = {
64
- query: (args["query"] as string) ?? "",
65
- ecosystem: (args["ecosystem"] as SearchOptions["ecosystem"]) ?? "all",
66
- limit: (args["limit"] as number) ?? 20,
67
- };
68
- const results = await search(opts);
69
- if (results.length === 0) return "No packages found.";
70
- return results.map(r =>
71
- `${r.name} [${r.ecosystems.filter(e => e !== "unknown").join(",")}] (${r.source})\n ${r.description.slice(0, 100)}\n Install: ${r.installCommand ?? "n/a"}`
72
- ).join("\n\n");
73
- }
74
-
75
- if (action === "detail") {
76
- const name = args["name"] as string;
77
- if (!name) return "Error: name required.";
78
- const detail = await getDetail(name);
79
- if (!detail) return `Package "${name}" not found.`;
80
- return `${detail.name} v${detail.version}\n${detail.description}\nDeps: ${detail.dependencyCount} Size: ${detail.size ? (detail.size / 1024).toFixed(1) + " KB" : "?"}\n${detail.npmUrl ?? ""}`;
81
- }
82
-
83
- if (action === "audit") {
84
- const name = args["name"] as string;
85
- if (!name) return "Error: name required.";
86
- const report = await auditPackage(name, { deepScan: true });
87
- return `${report.summary}\nFindings:\n${report.findings.map(f => `[${f.severity}] ${f.reason}`).join("\n") || "None"}`;
88
- }
89
-
90
- return `Unknown action: ${action}`;
91
- },
92
- };
20
+ /** Run a shell command and return stdout as string. */
21
+ async function runCmd($: ShellAPI | undefined, cmd: string): Promise<string> {
22
+ if (!$) return "Error: shell not available. Use: bunx zmarketplace " + cmd;
23
+ try {
24
+ const result = await $`bunx zmarketplace ${cmd}`.quiet();
25
+ const stdout = result.stdout?.toString() ?? "";
26
+ const stderr = result.stderr?.toString() ?? "";
27
+ return stdout || stderr || "No output.";
28
+ } catch (err) {
29
+ return `Error: ${err instanceof Error ? err.message : String(err)}`;
30
+ }
31
+ }
93
32
 
94
- /** OpenCode plugin — provides zmarketplace as a tool the agent can call. */
95
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
- export const ZmarketplacePlugin = async (_ctx: PluginCtx): Promise<{ tool: Record<string, ToolDef> }> => {
33
+ /** OpenCode plugin — registers zmarketplace tool. */
34
+ export const ZmarketplacePlugin = async (ctx: PluginCtx) => {
35
+ const $ = ctx.$;
97
36
  return {
98
37
  tool: {
99
- zmarketplace: zmarketplaceTool,
38
+ zmarketplace: {
39
+ description:
40
+ "Search, inspect, audit, and install packages across agent ecosystems " +
41
+ "(pi, omp, claude, opencode, gemini, codex, npm). " +
42
+ "Actions: search <query>, detail <name>, audit <name>",
43
+ args: {
44
+ action: { type: "string", description: "search, detail, or audit" },
45
+ query: { type: "string", description: "Search query or package name" },
46
+ },
47
+ async execute(args: { action?: string; query?: string }): Promise<string> {
48
+ const action = args.action ?? "search";
49
+ const query = args.query ?? "";
50
+
51
+ if (action === "detail") return runCmd($, `detail ${query}`);
52
+ if (action === "audit") return runCmd($, `audit ${query}`);
53
+ return runCmd($, `search "${query}" --limit=10`);
54
+ },
55
+ },
100
56
  },
101
57
  };
102
58
  };