@orchagent/cli 0.2.11 → 0.2.13

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.
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.printHumanOutput = printHumanOutput;
7
+ exports.formatJsonOutput = formatJsonOutput;
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ // Status symbols
10
+ const SYMBOLS = {
11
+ success: chalk_1.default.green('\u2713'), // checkmark
12
+ warning: chalk_1.default.yellow('\u26a0'), // warning sign
13
+ error: chalk_1.default.red('\u2717'), // X mark
14
+ };
15
+ // Category display names
16
+ const CATEGORY_NAMES = {
17
+ environment: 'Environment',
18
+ configuration: 'Configuration',
19
+ connectivity: 'Connectivity',
20
+ authentication: 'Authentication',
21
+ llm: 'LLM Configuration',
22
+ };
23
+ /**
24
+ * Group check results by category.
25
+ */
26
+ function groupByCategory(results) {
27
+ const groups = new Map();
28
+ // Define category order
29
+ const categoryOrder = [
30
+ 'environment',
31
+ 'configuration',
32
+ 'connectivity',
33
+ 'authentication',
34
+ 'llm',
35
+ ];
36
+ // Initialize groups in order
37
+ for (const cat of categoryOrder) {
38
+ groups.set(cat, []);
39
+ }
40
+ // Add results to groups
41
+ for (const result of results) {
42
+ const existing = groups.get(result.category) || [];
43
+ existing.push(result);
44
+ groups.set(result.category, existing);
45
+ }
46
+ // Remove empty groups
47
+ for (const [key, value] of groups) {
48
+ if (value.length === 0) {
49
+ groups.delete(key);
50
+ }
51
+ }
52
+ return groups;
53
+ }
54
+ /**
55
+ * Print human-readable output to stdout.
56
+ */
57
+ function printHumanOutput(results, summary, verbose) {
58
+ // Header
59
+ process.stdout.write('\n');
60
+ process.stdout.write(chalk_1.default.bold('OrchAgent Doctor\n'));
61
+ process.stdout.write('================\n\n');
62
+ // Group and print results
63
+ const groups = groupByCategory(results);
64
+ for (const [category, checks] of groups) {
65
+ const displayName = CATEGORY_NAMES[category] || category;
66
+ process.stdout.write(chalk_1.default.bold(`${displayName}\n`));
67
+ for (const check of checks) {
68
+ const symbol = SYMBOLS[check.status];
69
+ process.stdout.write(` ${symbol} ${check.message}\n`);
70
+ // Show fix suggestion for warnings/errors
71
+ if (check.fix && check.status !== 'success') {
72
+ process.stdout.write(chalk_1.default.dim(` \u2192 ${check.fix}\n`));
73
+ }
74
+ // Show details in verbose mode
75
+ if (verbose && check.details) {
76
+ for (const [key, value] of Object.entries(check.details)) {
77
+ const displayValue = typeof value === 'object' ? JSON.stringify(value) : String(value);
78
+ process.stdout.write(chalk_1.default.dim(` ${key}: ${displayValue}\n`));
79
+ }
80
+ }
81
+ }
82
+ process.stdout.write('\n');
83
+ }
84
+ // Summary line
85
+ const summaryParts = [];
86
+ if (summary.passed > 0) {
87
+ summaryParts.push(chalk_1.default.green(`${summary.passed} passed`));
88
+ }
89
+ if (summary.warnings > 0) {
90
+ summaryParts.push(chalk_1.default.yellow(`${summary.warnings} warning${summary.warnings > 1 ? 's' : ''}`));
91
+ }
92
+ if (summary.errors > 0) {
93
+ summaryParts.push(chalk_1.default.red(`${summary.errors} error${summary.errors > 1 ? 's' : ''}`));
94
+ }
95
+ process.stdout.write(`Summary: ${summaryParts.join(', ')}\n`);
96
+ }
97
+ /**
98
+ * Format results as JSON output.
99
+ */
100
+ function formatJsonOutput(results, summary) {
101
+ return {
102
+ summary,
103
+ checks: results,
104
+ };
105
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runAllChecks = runAllChecks;
4
+ exports.calculateSummary = calculateSummary;
5
+ const environment_1 = require("./checks/environment");
6
+ const config_1 = require("./checks/config");
7
+ const auth_1 = require("./checks/auth");
8
+ const connectivity_1 = require("./checks/connectivity");
9
+ const llm_1 = require("./checks/llm");
10
+ /**
11
+ * Run all diagnostic checks in order.
12
+ * Checks are organized by category and run in a logical sequence.
13
+ */
14
+ async function runAllChecks() {
15
+ const results = [];
16
+ // Environment checks (no dependencies)
17
+ const envResults = await (0, environment_1.runEnvironmentChecks)();
18
+ results.push(...envResults);
19
+ // Config checks (no dependencies)
20
+ const configResults = await (0, config_1.runConfigChecks)();
21
+ results.push(...configResults);
22
+ // Connectivity checks (test gateway before auth)
23
+ const connectivityResults = await (0, connectivity_1.runConnectivityChecks)();
24
+ results.push(...connectivityResults);
25
+ // Check if gateway is reachable before running auth/LLM checks
26
+ const gatewayOk = connectivityResults.some((r) => r.name === 'gateway_reachable' && r.status === 'success');
27
+ if (gatewayOk) {
28
+ // Auth checks (requires gateway)
29
+ const authResults = await (0, auth_1.runAuthChecks)();
30
+ results.push(...authResults);
31
+ // LLM checks (requires auth for server keys)
32
+ const llmResults = await (0, llm_1.runLlmChecks)();
33
+ results.push(...llmResults);
34
+ }
35
+ else {
36
+ // Add placeholder results when gateway is unreachable
37
+ results.push({
38
+ category: 'authentication',
39
+ name: 'api_key_present',
40
+ status: 'warning',
41
+ message: 'Skipped (gateway unreachable)',
42
+ details: { skipped: true, reason: 'gateway unreachable' },
43
+ });
44
+ results.push({
45
+ category: 'llm',
46
+ name: 'server_llm_keys',
47
+ status: 'warning',
48
+ message: 'Skipped (gateway unreachable)',
49
+ details: { skipped: true, reason: 'gateway unreachable' },
50
+ });
51
+ // Still check local LLM env vars since they don't require network
52
+ const localLlmCheck = (await (0, llm_1.runLlmChecks)()).find((r) => r.name === 'local_llm_env');
53
+ if (localLlmCheck) {
54
+ results.push(localLlmCheck);
55
+ }
56
+ }
57
+ return results;
58
+ }
59
+ /**
60
+ * Calculate summary statistics from check results.
61
+ */
62
+ function calculateSummary(results) {
63
+ return {
64
+ passed: results.filter((r) => r.status === 'success').length,
65
+ warnings: results.filter((r) => r.status === 'warning').length,
66
+ errors: results.filter((r) => r.status === 'error').length,
67
+ };
68
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -33,13 +33,15 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.CliError = void 0;
36
+ exports.NetworkError = exports.ExitCodes = exports.CliError = void 0;
37
37
  exports.formatError = formatError;
38
38
  exports.exitWithError = exitWithError;
39
+ exports.jsonInputError = jsonInputError;
39
40
  const Sentry = __importStar(require("@sentry/node"));
40
41
  const analytics_1 = require("./analytics");
41
42
  class CliError extends Error {
42
43
  exitCode;
44
+ cause;
43
45
  constructor(message, exitCode = 1) {
44
46
  super(message);
45
47
  this.exitCode = exitCode;
@@ -73,3 +75,41 @@ async function exitWithError(err) {
73
75
  }
74
76
  process.exit(1);
75
77
  }
78
+ exports.ExitCodes = {
79
+ SUCCESS: 0,
80
+ GENERAL_ERROR: 1,
81
+ AUTH_ERROR: 2,
82
+ PERMISSION_DENIED: 3,
83
+ NOT_FOUND: 4,
84
+ INVALID_INPUT: 5,
85
+ RATE_LIMITED: 6,
86
+ TIMEOUT: 7,
87
+ SERVER_ERROR: 8,
88
+ NETWORK_ERROR: 9,
89
+ };
90
+ class NetworkError extends CliError {
91
+ constructor(url, cause) {
92
+ const host = new URL(url).host;
93
+ super(`Unable to connect to ${host}\n\n` +
94
+ 'Possible causes:\n' +
95
+ ' - Network connectivity issues\n' +
96
+ ' - Service temporarily unavailable\n' +
97
+ ' - Firewall or proxy blocking the request\n\n' +
98
+ 'Check status at: https://status.orchagent.io', exports.ExitCodes.NETWORK_ERROR);
99
+ this.cause = cause;
100
+ }
101
+ }
102
+ exports.NetworkError = NetworkError;
103
+ function jsonInputError(flag) {
104
+ return new CliError(`Invalid JSON in --${flag} option.\n\n` +
105
+ 'Common causes:\n' +
106
+ ' - Shell special characters (!, $, `) need escaping\n' +
107
+ ' - Missing or mismatched quotes\n\n' +
108
+ 'Shell-specific tips:\n' +
109
+ ' - Bash/Zsh: Use single quotes: --data \'{"key": "value"}\'\n' +
110
+ ' - PowerShell: Use double quotes and escape: --data "{\\"key\\": \\"value\\"}"\n' +
111
+ ' - Any shell: Use a file: --data @input.json\n\n' +
112
+ 'Alternatives:\n' +
113
+ ` - Use a file: --${flag} @input.json\n` +
114
+ ` - Use stdin: echo '{"key":"value"}' | orch call agent --${flag} @-`, exports.ExitCodes.INVALID_INPUT);
115
+ }
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseLlmError = parseLlmError;
4
+ const errors_1 = require("./errors");
5
+ // Safe fallback messages by status code
6
+ const FALLBACKS = {
7
+ openai: {
8
+ 401: 'Invalid OpenAI API key. Check your OPENAI_API_KEY.',
9
+ 403: 'Access denied. Your API key may not have permission for this model.',
10
+ 429: 'Rate limit exceeded. Wait a moment and try again.',
11
+ 500: 'OpenAI service error. Try again later.',
12
+ 502: 'OpenAI is temporarily unavailable.',
13
+ 503: 'OpenAI is overloaded. Try again later.',
14
+ },
15
+ anthropic: {
16
+ 401: 'Invalid Anthropic API key. Check your ANTHROPIC_API_KEY.',
17
+ 403: 'Access denied. Your API key may not have permission for this model.',
18
+ 429: 'Rate limit exceeded. Wait a moment and try again.',
19
+ 500: 'Anthropic service error. Try again later.',
20
+ 502: 'Anthropic is temporarily unavailable.',
21
+ 503: 'Anthropic is overloaded. Try again later.',
22
+ },
23
+ gemini: {
24
+ 401: 'Invalid Gemini API key. Check your GEMINI_API_KEY.',
25
+ 403: 'Access denied. Your API key may not have permission for this model.',
26
+ 429: 'Rate limit exceeded. Wait a moment and try again.',
27
+ 500: 'Gemini service error. Try again later.',
28
+ 502: 'Gemini is temporarily unavailable.',
29
+ 503: 'Gemini is overloaded. Try again later.',
30
+ },
31
+ };
32
+ const DEFAULT = 'LLM provider error. Check your API key and try again.';
33
+ function isHtml(text) {
34
+ const t = text.trim().toLowerCase();
35
+ return t.startsWith('<!doctype') || t.startsWith('<html');
36
+ }
37
+ function sanitize(msg) {
38
+ if (msg.length > 200)
39
+ msg = msg.slice(0, 200) + '...';
40
+ return msg.replace(/https?:\/\/[^\s]+/g, '[URL]').trim();
41
+ }
42
+ function parseOpenAI(text, status) {
43
+ try {
44
+ const p = JSON.parse(text);
45
+ if (p.error?.message)
46
+ return sanitize(p.error.message);
47
+ }
48
+ catch { }
49
+ return FALLBACKS.openai[status] || DEFAULT;
50
+ }
51
+ function parseAnthropic(text, status) {
52
+ try {
53
+ const p = JSON.parse(text);
54
+ const msg = p.error?.message || p.message;
55
+ if (msg)
56
+ return sanitize(msg);
57
+ }
58
+ catch { }
59
+ return FALLBACKS.anthropic[status] || DEFAULT;
60
+ }
61
+ function parseGemini(text, status) {
62
+ try {
63
+ const p = JSON.parse(text);
64
+ if (p.error?.message)
65
+ return sanitize(p.error.message);
66
+ }
67
+ catch { }
68
+ return FALLBACKS.gemini[status] || DEFAULT;
69
+ }
70
+ function parseLlmError(provider, text, status) {
71
+ if (isHtml(text)) {
72
+ return new errors_1.CliError(`${provider} error: ${FALLBACKS[provider][status] || DEFAULT}`);
73
+ }
74
+ const msg = provider === 'openai' ? parseOpenAI(text, status)
75
+ : provider === 'anthropic' ? parseAnthropic(text, status)
76
+ : parseGemini(text, status);
77
+ const display = provider.charAt(0).toUpperCase() + provider.slice(1);
78
+ return new errors_1.CliError(`${display} API error: ${msg}`);
79
+ }
package/dist/lib/llm.js CHANGED
@@ -47,6 +47,7 @@ exports.buildPrompt = buildPrompt;
47
47
  exports.callLlm = callLlm;
48
48
  exports.validateProvider = validateProvider;
49
49
  const errors_1 = require("./errors");
50
+ const llm_errors_1 = require("./llm-errors");
50
51
  // Environment variable names for each provider
51
52
  exports.PROVIDER_ENV_VARS = {
52
53
  openai: 'OPENAI_API_KEY',
@@ -181,7 +182,7 @@ async function callOpenAI(apiKey, model, prompt, outputSchema) {
181
182
  });
182
183
  if (!response.ok) {
183
184
  const text = await response.text();
184
- throw new errors_1.CliError(`OpenAI API error: ${text}`);
185
+ throw (0, llm_errors_1.parseLlmError)('openai', text, response.status);
185
186
  }
186
187
  const data = (await response.json());
187
188
  const content = data.choices?.[0]?.message?.content || '';
@@ -208,7 +209,7 @@ async function callAnthropic(apiKey, model, prompt, _outputSchema) {
208
209
  });
209
210
  if (!response.ok) {
210
211
  const text = await response.text();
211
- throw new errors_1.CliError(`Anthropic API error: ${text}`);
212
+ throw (0, llm_errors_1.parseLlmError)('anthropic', text, response.status);
212
213
  }
213
214
  const data = (await response.json());
214
215
  const content = data.content?.[0]?.text || '';
@@ -230,7 +231,7 @@ async function callGemini(apiKey, model, prompt, _outputSchema) {
230
231
  });
231
232
  if (!response.ok) {
232
233
  const text = await response.text();
233
- throw new errors_1.CliError(`Gemini API error: ${text}`);
234
+ throw (0, llm_errors_1.parseLlmError)('gemini', text, response.status);
234
235
  }
235
236
  const data = (await response.json());
236
237
  const content = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchagent/cli",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "Command-line interface for the OrchAgent AI agent marketplace",
5
5
  "license": "MIT",
6
6
  "author": "OrchAgent <hello@orchagent.io>",