@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.
- package/dist/mcp-server/index.js +1 -0
- package/dist/mcp-server/registry.d.ts +1 -1
- package/dist/mcp-server/toolHandlers/lookupEntityHandler.js +1 -1
- package/dist/mcp-server/toolplexApi/service.d.ts +1 -1
- package/dist/mcp-server/toolplexApi/service.js +2 -1
- package/dist/mcp-server/toolplexServer.js +34 -1
- package/dist/mcp-server/utils/runtimeCheck.d.ts +20 -2
- package/dist/mcp-server/utils/runtimeCheck.js +53 -20
- package/dist/server-manager/index.js +28 -0
- package/dist/server-manager/serverManager.js +25 -8
- package/dist/shared/mcpServerTypes.d.ts +8 -0
- package/dist/shared/mcpServerTypes.js +1 -0
- package/dist/src/mcp-server/toolplexApi/service.js +2 -1
- package/dist/src/mcp-server/utils/runtimeCheck.js +53 -20
- package/dist/src/shared/mcpServerTypes.js +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/mcp-server/index.js
CHANGED
|
@@ -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(
|
|
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
|
|
9
|
-
*
|
|
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
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
|
35
|
-
* @throws Error if the command is not available
|
|
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
|
|
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
|
|
38
|
+
// Priority 1: Try bundled dependency first
|
|
42
39
|
const bundledPath = Registry.getBundledDependencyPath(commandName);
|
|
43
40
|
if (bundledPath && fs.existsSync(bundledPath)) {
|
|
44
|
-
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
246
|
-
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
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:
|
|
270
|
+
args: finalArgs,
|
|
254
271
|
env: {
|
|
255
272
|
...process.env,
|
|
256
|
-
PATH:
|
|
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
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
|
35
|
-
* @throws Error if the command is not available
|
|
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
|
|
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
|
|
38
|
+
// Priority 1: Try bundled dependency first
|
|
42
39
|
const bundledPath = Registry.getBundledDependencyPath(commandName);
|
|
43
40
|
if (bundledPath && fs.existsSync(bundledPath)) {
|
|
44
|
-
|
|
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
|
|
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
|
|
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:
|
|
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.
|
|
1
|
+
export declare const version = "0.1.30";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '0.1.
|
|
1
|
+
export const version = '0.1.30';
|