@toolplex/client 0.1.28 → 0.1.30

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.
@@ -13,6 +13,7 @@ const logLevel = process.env.LOG_LEVEL || "info";
13
13
  // These are provided by the host application (e.g., Electron desktop)
14
14
  const bundledDependencies = {
15
15
  node: process.env.TOOLPLEX_NODE_PATH,
16
+ npm: process.env.TOOLPLEX_NPM_PATH,
16
17
  npx: process.env.TOOLPLEX_NPX_PATH,
17
18
  python: process.env.TOOLPLEX_PYTHON_PATH,
18
19
  pip: process.env.TOOLPLEX_PIP_PATH,
@@ -46,7 +46,7 @@ declare class Registry {
46
46
  * Get the path for a specific bundled dependency by name.
47
47
  * Returns undefined if the dependency is not available.
48
48
  */
49
- static getBundledDependencyPath(depName: "node" | "python" | "git" | "uvx" | "npx"): string | undefined;
49
+ static getBundledDependencyPath(depName: "node" | "npm" | "python" | "git" | "uvx" | "npx"): string | undefined;
50
50
  /**
51
51
  * Set the server configuration (includes session resume history).
52
52
  */
@@ -20,7 +20,7 @@ export async function handleLookupEntityTool(params) {
20
20
  if (params.entity_type === "server") {
21
21
  policyEnforcer.enforceUseServerPolicy(params.entity_id);
22
22
  }
23
- const lookupResponse = await apiService.lookupEntity(params.entity_type, params.entity_id);
23
+ const lookupResponse = await apiService.lookupEntity(params.entity_type, params.entity_id, params.include_readme);
24
24
  // Annotate installed server using resultAnnotators
25
25
  if (params.entity_type === "server" &&
26
26
  lookupResponse &&
@@ -20,7 +20,7 @@ export declare class ToolplexApiService {
20
20
  eventType: LogTelemetryRequest["event_type"];
21
21
  data: Partial<Omit<LogTelemetryRequest, "event_type">>;
22
22
  }>): Promise<LogTelemetryBatchResponse>;
23
- lookupEntity(entityType: "server" | "playbook" | "feedback", entityId: string): Promise<any>;
23
+ lookupEntity(entityType: "server" | "playbook" | "feedback", entityId: string, includeReadme?: boolean): Promise<any>;
24
24
  search(query: string, expandedKeywords?: string[], filter?: string, size?: number, scope?: string): Promise<SearchResponse>;
25
25
  createPlaybook(playbook_name: string, description: string, actions: Array<PlaybookAction>, domain?: string, keywords?: string[], requirements?: string[], privacy?: "public" | "private", sourcePlaybookId?: string, forkReason?: string): Promise<CreatePlaybookResponse>;
26
26
  logPlaybookUsage(playbookId: string, success: boolean, errorMessage?: string): Promise<LogPlaybookUsageResponse>;
@@ -93,7 +93,7 @@ export class ToolplexApiService {
93
93
  return { success: false };
94
94
  }
95
95
  }
96
- async lookupEntity(entityType, entityId) {
96
+ async lookupEntity(entityType, entityId, includeReadme) {
97
97
  try {
98
98
  const response = await fetch(`${this.baseUrl}/lookup-entity`, {
99
99
  method: "POST",
@@ -101,6 +101,7 @@ export class ToolplexApiService {
101
101
  body: JSON.stringify({
102
102
  entity_type: entityType,
103
103
  entity_id: entityId,
104
+ include_readme: includeReadme,
104
105
  }),
105
106
  });
106
107
  return this.handleFetchResponse(response);
@@ -52,9 +52,42 @@ export async function serve(config) {
52
52
  },
53
53
  });
54
54
  // Initialize server manager clients
55
+ // Use bundled node if available, otherwise fall back to system "node"
56
+ // Pass bundled dependency paths so the server-manager can initialize its Registry
55
57
  await logger.info("Initializing server manager clients");
58
+ const nodeCommand = config.bundledDependencies?.node || "node";
56
59
  const serverManagerClients = {
57
- node: new StdioServerManagerClient("node", [path.join(__dirname, "..", "server-manager", "index.js")], { LOG_LEVEL: config.logLevel }),
60
+ node: new StdioServerManagerClient(nodeCommand, [path.join(__dirname, "..", "server-manager", "index.js")], {
61
+ LOG_LEVEL: config.logLevel,
62
+ // Pass the current PATH which includes bundled bin directories
63
+ PATH: process.env.PATH,
64
+ // Pass all bundled dependency paths to server-manager
65
+ // These are critical for proper command resolution (e.g., npx -> node + npx-cli.js)
66
+ ...(config.bundledDependencies?.node && {
67
+ TOOLPLEX_NODE_PATH: config.bundledDependencies.node,
68
+ }),
69
+ ...(config.bundledDependencies?.npm && {
70
+ TOOLPLEX_NPM_PATH: config.bundledDependencies.npm,
71
+ }),
72
+ ...(config.bundledDependencies?.npx && {
73
+ TOOLPLEX_NPX_PATH: config.bundledDependencies.npx,
74
+ }),
75
+ ...(config.bundledDependencies?.python && {
76
+ TOOLPLEX_PYTHON_PATH: config.bundledDependencies.python,
77
+ }),
78
+ ...(config.bundledDependencies?.pip && {
79
+ TOOLPLEX_PIP_PATH: config.bundledDependencies.pip,
80
+ }),
81
+ ...(config.bundledDependencies?.uv && {
82
+ TOOLPLEX_UV_PATH: config.bundledDependencies.uv,
83
+ }),
84
+ ...(config.bundledDependencies?.uvx && {
85
+ TOOLPLEX_UVX_PATH: config.bundledDependencies.uvx,
86
+ }),
87
+ ...(config.bundledDependencies?.git && {
88
+ TOOLPLEX_GIT_PATH: config.bundledDependencies.git,
89
+ }),
90
+ }),
58
91
  };
59
92
  // Start all server manager clients
60
93
  await logger.info("Starting server manager clients");
@@ -1,12 +1,30 @@
1
+ /**
2
+ * Result of resolving a command, which may need to be invoked via node
3
+ * if it's a .js script (e.g., bundled npm/npx on Unix).
4
+ */
5
+ export interface ResolvedCommand {
6
+ command: string;
7
+ prependArgs: string[];
8
+ }
1
9
  export declare class RuntimeCheck {
10
+ /**
11
+ * Resolve a dependency and return both the command and any prepended args needed.
12
+ * This handles the case where bundled npm/npx on Unix are .js scripts that
13
+ * need to be invoked via node.
14
+ *
15
+ * @param commandName - The command to resolve (e.g., "npx", "node", "uvx")
16
+ * @returns ResolvedCommand with command and prependArgs
17
+ * @throws Error if the command is not available
18
+ */
19
+ static resolveCommandWithArgs(commandName: string): ResolvedCommand;
2
20
  /**
3
21
  * Resolve a dependency path with priority order:
4
22
  * 1. Bundled dependencies (if provided by host application like ToolPlex Desktop)
5
23
  * 2. System PATH (fallback for standalone @client usage)
6
24
  * 3. Error if neither available
7
25
  *
8
- * This allows ToolPlex Desktop to provide reliable bundled dependencies while
9
- * still supporting standalone users who have system dependencies installed.
26
+ * NOTE: This returns just the path. For npm/npx which may be .js files on Unix,
27
+ * use resolveCommandWithArgs() instead to get the proper invocation.
10
28
  *
11
29
  * @param commandName - The command to resolve
12
30
  * @returns The full path to the command executable
@@ -8,12 +8,14 @@ const INSTALL_HINTS = {
8
8
  python: "Install Python: https://www.python.org/downloads/. Or check if you have `python3` installed.",
9
9
  python3: "Install Python: https://www.python.org/downloads/. Or check if you have `python` installed.",
10
10
  node: "Install Node.js: https://nodejs.org/en/download/",
11
+ npm: "Install npm (comes with Node.js): https://nodejs.org/en/download/",
11
12
  npx: "Install npx (comes with Node.js): https://nodejs.org/en/download/",
12
13
  git: "Install Git: https://git-scm.com/downloads",
13
14
  };
14
15
  // Commands that should use bundled dependencies (required)
15
16
  const BUNDLED_DEPENDENCY_COMMANDS = [
16
17
  "node",
18
+ "npm",
17
19
  "python",
18
20
  "python3",
19
21
  "git",
@@ -22,44 +24,54 @@ const BUNDLED_DEPENDENCY_COMMANDS = [
22
24
  ];
23
25
  export class RuntimeCheck {
24
26
  /**
25
- * Resolve a dependency path with priority order:
26
- * 1. Bundled dependencies (if provided by host application like ToolPlex Desktop)
27
- * 2. System PATH (fallback for standalone @client usage)
28
- * 3. Error if neither available
29
- *
30
- * This allows ToolPlex Desktop to provide reliable bundled dependencies while
31
- * still supporting standalone users who have system dependencies installed.
27
+ * Resolve a dependency and return both the command and any prepended args needed.
28
+ * This handles the case where bundled npm/npx on Unix are .js scripts that
29
+ * need to be invoked via node.
32
30
  *
33
- * @param commandName - The command to resolve
34
- * @returns The full path to the command executable
35
- * @throws Error if the command is not available in bundled deps or system PATH
31
+ * @param commandName - The command to resolve (e.g., "npx", "node", "uvx")
32
+ * @returns ResolvedCommand with command and prependArgs
33
+ * @throws Error if the command is not available
36
34
  */
37
- static resolveDependency(commandName) {
38
- // Check if this is a known bundled dependency type
35
+ static resolveCommandWithArgs(commandName) {
39
36
  const isBundledDep = BUNDLED_DEPENDENCY_COMMANDS.includes(commandName);
40
37
  if (isBundledDep) {
41
- // Priority 1: Try bundled dependency first (preferred for ToolPlex Desktop)
38
+ // Priority 1: Try bundled dependency first
42
39
  const bundledPath = Registry.getBundledDependencyPath(commandName);
43
40
  if (bundledPath && fs.existsSync(bundledPath)) {
44
- return bundledPath;
41
+ // Check if this is a .js file that needs to be invoked via node
42
+ if (bundledPath.endsWith(".js")) {
43
+ const nodePath = Registry.getBundledDependencyPath("node");
44
+ if (nodePath && fs.existsSync(nodePath)) {
45
+ return {
46
+ command: nodePath,
47
+ prependArgs: [bundledPath],
48
+ };
49
+ }
50
+ // Fallback to system node if bundled node not available
51
+ return {
52
+ command: "node",
53
+ prependArgs: [bundledPath],
54
+ };
55
+ }
56
+ return { command: bundledPath, prependArgs: [] };
45
57
  }
46
- // Handle python3 -> python mapping for bundled deps
58
+ // Handle python3 -> python mapping
47
59
  if (commandName === "python3") {
48
60
  const pythonPath = Registry.getBundledDependencyPath("python");
49
61
  if (pythonPath && fs.existsSync(pythonPath)) {
50
- return pythonPath;
62
+ return { command: pythonPath, prependArgs: [] };
51
63
  }
52
64
  }
53
- // Priority 2: Fall back to system PATH (for standalone @client usage)
65
+ // Priority 2: Fall back to system PATH
54
66
  const enhancedPath = getEnhancedPath();
55
67
  const resolved = which.sync(commandName, {
56
68
  path: enhancedPath,
57
69
  nothrow: true,
58
70
  });
59
71
  if (resolved) {
60
- return resolved;
72
+ return { command: resolved, prependArgs: [] };
61
73
  }
62
- // Priority 3: Neither bundled nor system available - error
74
+ // Priority 3: Error
63
75
  const hint = INSTALL_HINTS[commandName];
64
76
  throw new Error(`Missing required command: '${commandName}'.\n` +
65
77
  `This command is not available in bundled dependencies or system PATH.\n` +
@@ -78,7 +90,28 @@ export class RuntimeCheck {
78
90
  }
79
91
  throw new Error(`Command '${commandName}' not found in enhanced PATH. Please install it manually or check your config.`);
80
92
  }
81
- return resolved;
93
+ return { command: resolved, prependArgs: [] };
94
+ }
95
+ /**
96
+ * Resolve a dependency path with priority order:
97
+ * 1. Bundled dependencies (if provided by host application like ToolPlex Desktop)
98
+ * 2. System PATH (fallback for standalone @client usage)
99
+ * 3. Error if neither available
100
+ *
101
+ * NOTE: This returns just the path. For npm/npx which may be .js files on Unix,
102
+ * use resolveCommandWithArgs() instead to get the proper invocation.
103
+ *
104
+ * @param commandName - The command to resolve
105
+ * @returns The full path to the command executable
106
+ * @throws Error if the command is not available in bundled deps or system PATH
107
+ */
108
+ static resolveDependency(commandName) {
109
+ const resolved = this.resolveCommandWithArgs(commandName);
110
+ // If there are prepend args, the first one is the actual script path
111
+ if (resolved.prependArgs.length > 0) {
112
+ return resolved.prependArgs[0];
113
+ }
114
+ return resolved.command;
82
115
  }
83
116
  /**
84
117
  * Validate that a command is available (either bundled or in system PATH).
@@ -1,6 +1,34 @@
1
1
  import { ServerManagerProtocol } from "./stdioServer.js";
2
2
  import { FileLogger } from "../shared/fileLogger.js";
3
+ import Registry from "../mcp-server/registry.js";
3
4
  FileLogger.initialize("server-manager");
5
+ // Initialize bundled dependencies from environment variables.
6
+ // These are passed from the MCP server process which received them from Electron.
7
+ // This is critical for proper command resolution (e.g., npx -> node + npx-cli.js).
8
+ //
9
+ // NOTE: We do NOT call Registry.init() here because that does heavy initialization
10
+ // (API services, caches, etc.) that the server-manager doesn't need. We only need
11
+ // the bundled dependency paths for command resolution.
12
+ function initializeBundledDeps() {
13
+ const bundledDependencies = {
14
+ node: process.env.TOOLPLEX_NODE_PATH,
15
+ npm: process.env.TOOLPLEX_NPM_PATH,
16
+ npx: process.env.TOOLPLEX_NPX_PATH,
17
+ python: process.env.TOOLPLEX_PYTHON_PATH,
18
+ pip: process.env.TOOLPLEX_PIP_PATH,
19
+ uv: process.env.TOOLPLEX_UV_PATH,
20
+ uvx: process.env.TOOLPLEX_UVX_PATH,
21
+ git: process.env.TOOLPLEX_GIT_PATH,
22
+ };
23
+ // Only set if we have at least one bundled dep
24
+ const hasAnyBundledDep = Object.values(bundledDependencies).some(Boolean);
25
+ if (hasAnyBundledDep) {
26
+ Registry.setBundledDependencies(bundledDependencies);
27
+ FileLogger.debug(`Server-manager initialized with bundled deps: ${JSON.stringify(bundledDependencies)}`);
28
+ }
29
+ }
30
+ // Initialize bundled deps and start
31
+ initializeBundledDeps();
4
32
  const protocol = new ServerManagerProtocol();
5
33
  protocol.start().catch((error) => {
6
34
  console.error("Failed to start server:", error);
@@ -242,18 +242,35 @@ export class ServerManager {
242
242
  else if (config.transport === "stdio") {
243
243
  if (!config.command)
244
244
  throw new Error("Command is required for stdio transport");
245
- // Use RuntimeCheck to resolve the command, which prioritizes bundled dependencies
246
- const { RuntimeCheck } = await import("../mcp-server/utils/runtimeCheck.js");
247
- // Extract command name first (handles paths with spaces correctly)
248
- const commandName = RuntimeCheck.extractCommandName(config.command);
249
- const resolvedCommand = RuntimeCheck.resolveDependency(commandName);
250
- const enhancedPath = getEnhancedPath();
245
+ // Use the inherited PATH from the parent process (MCP server -> Electron).
246
+ // This PATH already includes bundled bin directories prepended, so commands
247
+ // like "npx", "uvx", "git" will resolve to bundled versions first.
248
+ // We use process.env.PATH directly instead of rebuilding with getEnhancedPath()
249
+ // to preserve the bundled directories that were set up by Electron.
250
+ const inheritedPath = process.env.PATH || getEnhancedPath();
251
+ // For the command itself, resolve it properly handling the case where
252
+ // bundled npm/npx on Unix are .js scripts that need to be invoked via node.
253
+ let resolvedCommand = config.command;
254
+ let prependArgs = [];
255
+ if (!config.command.startsWith("/") &&
256
+ !/^[A-Za-z]:[\\/]/.test(config.command)) {
257
+ // It's a relative command name (like "npx"), resolve via RuntimeCheck
258
+ const { RuntimeCheck } = await import("../mcp-server/utils/runtimeCheck.js");
259
+ const commandName = RuntimeCheck.extractCommandName(config.command);
260
+ const resolved = RuntimeCheck.resolveCommandWithArgs(commandName);
261
+ resolvedCommand = resolved.command;
262
+ prependArgs = resolved.prependArgs;
263
+ }
264
+ // Combine prependArgs with config.args
265
+ // e.g., if npx is a .js file: command="node", prependArgs=["/path/to/npx-cli.js"]
266
+ // then args become ["/path/to/npx-cli.js", "-y", "@wonderwhy-er/desktop-commander"]
267
+ const finalArgs = [...prependArgs, ...(config.args || [])];
251
268
  const serverParams = {
252
269
  command: resolvedCommand,
253
- args: config.args || [],
270
+ args: finalArgs,
254
271
  env: {
255
272
  ...process.env,
256
- PATH: enhancedPath,
273
+ PATH: inheritedPath,
257
274
  ...(config.env || {}),
258
275
  },
259
276
  stderr: "pipe",
@@ -4,9 +4,14 @@ export type LogLevel = "error" | "warn" | "info" | "debug";
4
4
  /**
5
5
  * Paths to bundled dependencies provided by the host application (e.g., Electron).
6
6
  * These dependencies are required for MCP server installations and execution.
7
+ *
8
+ * NOTE: On Unix systems, npm/npx paths point to the actual CLI .js files
9
+ * (e.g., lib/node_modules/npm/bin/npx-cli.js) because electron-builder dereferences
10
+ * symlinks during packaging. These must be invoked via `node <script>`.
7
11
  */
8
12
  export interface BundledDependencies {
9
13
  node?: string;
14
+ npm?: string;
10
15
  npx?: string;
11
16
  python?: string;
12
17
  pip?: string;
@@ -140,12 +145,15 @@ export type SearchParams = z.infer<typeof SearchParamsSchema>;
140
145
  export declare const LookupEntityParamsSchema: z.ZodObject<{
141
146
  entity_type: z.ZodEnum<["server", "playbook", "feedback"]>;
142
147
  entity_id: z.ZodString;
148
+ include_readme: z.ZodOptional<z.ZodBoolean>;
143
149
  }, "strip", z.ZodTypeAny, {
144
150
  entity_type: "server" | "playbook" | "feedback";
145
151
  entity_id: string;
152
+ include_readme?: boolean | undefined;
146
153
  }, {
147
154
  entity_type: "server" | "playbook" | "feedback";
148
155
  entity_id: string;
156
+ include_readme?: boolean | undefined;
149
157
  }>;
150
158
  export type LookupEntityParams = z.infer<typeof LookupEntityParamsSchema>;
151
159
  export declare const InstallParamsSchema: z.ZodObject<{
@@ -51,6 +51,7 @@ export const SearchParamsSchema = z.object({
51
51
  export const LookupEntityParamsSchema = z.object({
52
52
  entity_type: z.enum(["server", "playbook", "feedback"]),
53
53
  entity_id: z.string(),
54
+ include_readme: z.boolean().optional(),
54
55
  });
55
56
  // --------------------
56
57
  // InstallParams
@@ -93,7 +93,7 @@ export class ToolplexApiService {
93
93
  return { success: false };
94
94
  }
95
95
  }
96
- async lookupEntity(entityType, entityId) {
96
+ async lookupEntity(entityType, entityId, includeReadme) {
97
97
  try {
98
98
  const response = await fetch(`${this.baseUrl}/lookup-entity`, {
99
99
  method: "POST",
@@ -101,6 +101,7 @@ export class ToolplexApiService {
101
101
  body: JSON.stringify({
102
102
  entity_type: entityType,
103
103
  entity_id: entityId,
104
+ include_readme: includeReadme,
104
105
  }),
105
106
  });
106
107
  return this.handleFetchResponse(response);
@@ -8,12 +8,14 @@ const INSTALL_HINTS = {
8
8
  python: "Install Python: https://www.python.org/downloads/. Or check if you have `python3` installed.",
9
9
  python3: "Install Python: https://www.python.org/downloads/. Or check if you have `python` installed.",
10
10
  node: "Install Node.js: https://nodejs.org/en/download/",
11
+ npm: "Install npm (comes with Node.js): https://nodejs.org/en/download/",
11
12
  npx: "Install npx (comes with Node.js): https://nodejs.org/en/download/",
12
13
  git: "Install Git: https://git-scm.com/downloads",
13
14
  };
14
15
  // Commands that should use bundled dependencies (required)
15
16
  const BUNDLED_DEPENDENCY_COMMANDS = [
16
17
  "node",
18
+ "npm",
17
19
  "python",
18
20
  "python3",
19
21
  "git",
@@ -22,44 +24,54 @@ const BUNDLED_DEPENDENCY_COMMANDS = [
22
24
  ];
23
25
  export class RuntimeCheck {
24
26
  /**
25
- * Resolve a dependency path with priority order:
26
- * 1. Bundled dependencies (if provided by host application like ToolPlex Desktop)
27
- * 2. System PATH (fallback for standalone @client usage)
28
- * 3. Error if neither available
29
- *
30
- * This allows ToolPlex Desktop to provide reliable bundled dependencies while
31
- * still supporting standalone users who have system dependencies installed.
27
+ * Resolve a dependency and return both the command and any prepended args needed.
28
+ * This handles the case where bundled npm/npx on Unix are .js scripts that
29
+ * need to be invoked via node.
32
30
  *
33
- * @param commandName - The command to resolve
34
- * @returns The full path to the command executable
35
- * @throws Error if the command is not available in bundled deps or system PATH
31
+ * @param commandName - The command to resolve (e.g., "npx", "node", "uvx")
32
+ * @returns ResolvedCommand with command and prependArgs
33
+ * @throws Error if the command is not available
36
34
  */
37
- static resolveDependency(commandName) {
38
- // Check if this is a known bundled dependency type
35
+ static resolveCommandWithArgs(commandName) {
39
36
  const isBundledDep = BUNDLED_DEPENDENCY_COMMANDS.includes(commandName);
40
37
  if (isBundledDep) {
41
- // Priority 1: Try bundled dependency first (preferred for ToolPlex Desktop)
38
+ // Priority 1: Try bundled dependency first
42
39
  const bundledPath = Registry.getBundledDependencyPath(commandName);
43
40
  if (bundledPath && fs.existsSync(bundledPath)) {
44
- return bundledPath;
41
+ // Check if this is a .js file that needs to be invoked via node
42
+ if (bundledPath.endsWith(".js")) {
43
+ const nodePath = Registry.getBundledDependencyPath("node");
44
+ if (nodePath && fs.existsSync(nodePath)) {
45
+ return {
46
+ command: nodePath,
47
+ prependArgs: [bundledPath],
48
+ };
49
+ }
50
+ // Fallback to system node if bundled node not available
51
+ return {
52
+ command: "node",
53
+ prependArgs: [bundledPath],
54
+ };
55
+ }
56
+ return { command: bundledPath, prependArgs: [] };
45
57
  }
46
- // Handle python3 -> python mapping for bundled deps
58
+ // Handle python3 -> python mapping
47
59
  if (commandName === "python3") {
48
60
  const pythonPath = Registry.getBundledDependencyPath("python");
49
61
  if (pythonPath && fs.existsSync(pythonPath)) {
50
- return pythonPath;
62
+ return { command: pythonPath, prependArgs: [] };
51
63
  }
52
64
  }
53
- // Priority 2: Fall back to system PATH (for standalone @client usage)
65
+ // Priority 2: Fall back to system PATH
54
66
  const enhancedPath = getEnhancedPath();
55
67
  const resolved = which.sync(commandName, {
56
68
  path: enhancedPath,
57
69
  nothrow: true,
58
70
  });
59
71
  if (resolved) {
60
- return resolved;
72
+ return { command: resolved, prependArgs: [] };
61
73
  }
62
- // Priority 3: Neither bundled nor system available - error
74
+ // Priority 3: Error
63
75
  const hint = INSTALL_HINTS[commandName];
64
76
  throw new Error(`Missing required command: '${commandName}'.\n` +
65
77
  `This command is not available in bundled dependencies or system PATH.\n` +
@@ -78,7 +90,28 @@ export class RuntimeCheck {
78
90
  }
79
91
  throw new Error(`Command '${commandName}' not found in enhanced PATH. Please install it manually or check your config.`);
80
92
  }
81
- return resolved;
93
+ return { command: resolved, prependArgs: [] };
94
+ }
95
+ /**
96
+ * Resolve a dependency path with priority order:
97
+ * 1. Bundled dependencies (if provided by host application like ToolPlex Desktop)
98
+ * 2. System PATH (fallback for standalone @client usage)
99
+ * 3. Error if neither available
100
+ *
101
+ * NOTE: This returns just the path. For npm/npx which may be .js files on Unix,
102
+ * use resolveCommandWithArgs() instead to get the proper invocation.
103
+ *
104
+ * @param commandName - The command to resolve
105
+ * @returns The full path to the command executable
106
+ * @throws Error if the command is not available in bundled deps or system PATH
107
+ */
108
+ static resolveDependency(commandName) {
109
+ const resolved = this.resolveCommandWithArgs(commandName);
110
+ // If there are prepend args, the first one is the actual script path
111
+ if (resolved.prependArgs.length > 0) {
112
+ return resolved.prependArgs[0];
113
+ }
114
+ return resolved.command;
82
115
  }
83
116
  /**
84
117
  * Validate that a command is available (either bundled or in system PATH).
@@ -51,6 +51,7 @@ export const SearchParamsSchema = z.object({
51
51
  export const LookupEntityParamsSchema = z.object({
52
52
  entity_type: z.enum(["server", "playbook", "feedback"]),
53
53
  entity_id: z.string(),
54
+ include_readme: z.boolean().optional(),
54
55
  });
55
56
  // --------------------
56
57
  // InstallParams
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "0.1.28";
1
+ export declare const version = "0.1.30";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '0.1.28';
1
+ export const version = '0.1.30';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolplex/client",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
4
4
  "author": "ToolPlex LLC",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "description": "The official ToolPlex client for AI agent tool discovery and execution",