@orchagent/cli 0.3.24 → 0.3.25

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.
@@ -14,6 +14,27 @@ const chokidar_1 = __importDefault(require("chokidar"));
14
14
  const errors_1 = require("../lib/errors");
15
15
  const config_1 = require("../lib/config");
16
16
  const llm_1 = require("../lib/llm");
17
+ /**
18
+ * Validate a fixture and return helpful errors
19
+ */
20
+ function validateFixture(data, fixturePath) {
21
+ const fileName = path_1.default.basename(fixturePath);
22
+ if (typeof data !== 'object' || data === null) {
23
+ throw new errors_1.CliError(`Invalid fixture ${fileName}: must be a JSON object`);
24
+ }
25
+ const obj = data;
26
+ if (!obj.input || typeof obj.input !== 'object') {
27
+ throw new errors_1.CliError(`Invalid fixture ${fileName}: missing required "input" field.\n` +
28
+ ` Expected format: { "input": {...}, "expected_output": {...} }`);
29
+ }
30
+ if (!obj.expected_output && !obj.expected_contains) {
31
+ throw new errors_1.CliError(`Invalid fixture ${fileName}: must have "expected_output" or "expected_contains".\n` +
32
+ ` Add one of:\n` +
33
+ ` "expected_output": {"key": "exact value to match"}\n` +
34
+ ` "expected_contains": ["substring to find"]`);
35
+ }
36
+ return data;
37
+ }
17
38
  /**
18
39
  * Parse SKILL.md frontmatter
19
40
  */
@@ -70,8 +91,10 @@ function runCommand(command, args, cwd, verbose) {
70
91
  * Check if a command exists
71
92
  */
72
93
  async function commandExists(command) {
94
+ const isWindows = process.platform === 'win32';
95
+ const checker = isWindows ? 'where' : 'which';
73
96
  try {
74
- const proc = (0, child_process_1.spawn)('which', [command], { shell: true });
97
+ const proc = (0, child_process_1.spawn)(checker, [command], { shell: true, stdio: 'ignore' });
75
98
  return new Promise((resolve) => {
76
99
  proc.on('close', (code) => resolve(code === 0));
77
100
  proc.on('error', () => resolve(false));
@@ -204,22 +227,28 @@ async function discoverTests(agentDir) {
204
227
  */
205
228
  async function runPythonTests(agentDir, verbose) {
206
229
  process.stderr.write(chalk_1.default.blue('\nRunning Python tests...\n\n'));
207
- // Check if pytest is available
230
+ // Check if pytest is available directly
208
231
  const hasPytest = await commandExists('pytest');
209
- let command;
210
- let args;
211
232
  if (hasPytest) {
212
- command = 'pytest';
213
- args = verbose ? ['-v'] : [];
233
+ const args = verbose ? ['-v'] : [];
234
+ const { code } = await runCommand('pytest', args, agentDir, verbose);
235
+ return code;
214
236
  }
215
- else {
216
- command = 'python3';
217
- args = ['-m', 'pytest'];
218
- if (verbose)
219
- args.push('-v');
237
+ // Try Python commands in order of preference
238
+ const pythonCommands = process.platform === 'win32'
239
+ ? ['python', 'py', 'python3']
240
+ : ['python3', 'python'];
241
+ for (const pythonCmd of pythonCommands) {
242
+ if (await commandExists(pythonCmd)) {
243
+ const args = ['-m', 'pytest'];
244
+ if (verbose)
245
+ args.push('-v');
246
+ const { code } = await runCommand(pythonCmd, args, agentDir, verbose);
247
+ return code;
248
+ }
220
249
  }
221
- const { code } = await runCommand(command, args, agentDir, verbose);
222
- return code;
250
+ process.stderr.write(chalk_1.default.red('No Python interpreter found. Install Python and pytest.\n'));
251
+ return 1;
223
252
  }
224
253
  /**
225
254
  * Run JavaScript/TypeScript tests
@@ -292,8 +321,8 @@ async function runFixtureTests(agentDir, fixtures, verbose, config) {
292
321
  throw new errors_1.CliError('No LLM key found for fixture tests.\n' +
293
322
  'Set an environment variable (e.g., OPENAI_API_KEY) or run `orchagent keys add <provider>`');
294
323
  }
295
- const { provider, key } = detected;
296
- const model = (0, llm_1.getDefaultModel)(provider);
324
+ const { provider, key, model: serverModel } = detected;
325
+ const model = serverModel ?? (0, llm_1.getDefaultModel)(provider);
297
326
  let passed = 0;
298
327
  let failed = 0;
299
328
  for (const fixturePath of fixtures) {
@@ -301,7 +330,14 @@ async function runFixtureTests(agentDir, fixtures, verbose, config) {
301
330
  process.stderr.write(` ${fixtureName}: `);
302
331
  try {
303
332
  const raw = await promises_1.default.readFile(fixturePath, 'utf-8');
304
- const fixture = JSON.parse(raw);
333
+ let parsed;
334
+ try {
335
+ parsed = JSON.parse(raw);
336
+ }
337
+ catch (e) {
338
+ throw new errors_1.CliError(`Invalid JSON in ${path_1.default.basename(fixturePath)}: ${e.message}`);
339
+ }
340
+ const fixture = validateFixture(parsed, fixturePath);
305
341
  // Build and call LLM
306
342
  const fullPrompt = (0, llm_1.buildPrompt)(prompt, fixture.input);
307
343
  const result = await (0, llm_1.callLlm)(provider, key, model, fullPrompt, outputSchema);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchagent/cli",
3
- "version": "0.3.24",
3
+ "version": "0.3.25",
4
4
  "description": "Command-line interface for the orchagent AI agent marketplace",
5
5
  "license": "MIT",
6
6
  "author": "orchagent <hello@orchagent.io>",