cli4ai 0.8.2 → 0.9.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.
@@ -73,18 +73,26 @@ export async function executeTool(
73
73
  entryPath: string,
74
74
  runtime: string,
75
75
  command: string,
76
- args: Record<string, string>
76
+ args: Record<string, string>,
77
+ argOrder?: string[]
77
78
  ): Promise<McpToolResult> {
78
79
  return new Promise((resolve) => {
79
80
  // Build command arguments
80
81
  const cmdArgs = [command];
81
- for (const [key, value] of Object.entries(args)) {
82
- if (value !== undefined && value !== '') {
83
- cmdArgs.push(value);
84
- }
82
+
83
+ // Prefer manifest-defined arg order (positional), fall back to stable ordering.
84
+ const orderedKeys = argOrder ?? Object.keys(args).sort();
85
+ for (const key of orderedKeys) {
86
+ const value = args[key];
87
+ if (value !== undefined && value !== '') cmdArgs.push(value);
85
88
  }
86
89
 
87
- const proc = spawn(runtime, ['run', entryPath, ...cmdArgs], {
90
+ const runtimeArgs =
91
+ runtime === 'node'
92
+ ? [entryPath, ...cmdArgs]
93
+ : ['run', entryPath, ...cmdArgs];
94
+
95
+ const proc = spawn(runtime, runtimeArgs, {
88
96
  stdio: ['pipe', 'pipe', 'pipe'],
89
97
  env: { ...process.env }
90
98
  });
@@ -2,7 +2,7 @@
2
2
  * Tests for mcp/config-gen.ts
3
3
  */
4
4
 
5
- import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
5
+ import { describe, test, expect, beforeEach, afterEach } from 'vitest';
6
6
  import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from 'fs';
7
7
  import { join } from 'path';
8
8
  import { tmpdir } from 'os';
package/src/mcp/server.ts CHANGED
@@ -251,10 +251,9 @@ export class McpServer {
251
251
 
252
252
  // Execute the CLI tool
253
253
  const entryPath = resolve(this.packagePath, this.manifest.entry);
254
- const runtime = this.manifest.runtime || 'bun';
255
254
 
256
255
  try {
257
- const result = await this.executeCommand(runtime, entryPath, cmdArgs);
256
+ const result = await this.executeCommand(entryPath, cmdArgs);
258
257
  auditLog(this.manifest.name, name, args, 'success');
259
258
  this.sendResult(id, {
260
259
  content: [{ type: 'text', text: result }]
@@ -269,30 +268,25 @@ export class McpServer {
269
268
  }
270
269
  }
271
270
 
272
- private executeCommand(runtime: string, entryPath: string, args: string[]): Promise<string> {
271
+ private executeCommand(entryPath: string, args: string[]): Promise<string> {
273
272
  return new Promise((resolve, reject) => {
274
- // Build runtime-specific command and arguments
275
- // - bun: bun run <file> [args]
276
- // - node: node <file> [args]
273
+ // Use tsx for TypeScript files, node for JavaScript
277
274
  let cmd: string;
278
275
  let cmdArgs: string[];
279
- switch (runtime) {
280
- case 'node':
281
- cmd = 'node';
282
- cmdArgs = [entryPath, ...args];
283
- break;
284
- case 'bun':
285
- default:
286
- cmd = 'bun';
287
- cmdArgs = ['run', entryPath, ...args];
288
- break;
276
+ if (entryPath.endsWith('.ts') || entryPath.endsWith('.tsx')) {
277
+ cmd = 'npx';
278
+ cmdArgs = ['tsx', entryPath, ...args];
279
+ } else {
280
+ cmd = 'node';
281
+ cmdArgs = [entryPath, ...args];
289
282
  }
290
283
 
291
284
  // Inject secrets from manifest env definitions
285
+ // SECURITY: Use package-scoped secret lookup (tries scoped first, then global)
292
286
  const secretsEnv: Record<string, string> = {};
293
287
  if (this.manifest.env) {
294
288
  for (const key of Object.keys(this.manifest.env)) {
295
- const value = getSecret(key);
289
+ const value = getSecret(key, this.manifest.name);
296
290
  if (value) {
297
291
  secretsEnv[key] = value;
298
292
  }