@nhonh/qabot 0.2.3 → 0.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nhonh/qabot",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "description": "AI-powered universal QA automation tool. Import any project, AI analyzes and runs tests across all layers.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -34,11 +34,15 @@ export class AIEngine {
34
34
  }
35
35
 
36
36
  getProviderInfo() {
37
+ const preview = this.apiKey
38
+ ? this.apiKey.slice(0, 4) + "****" + this.apiKey.slice(-4)
39
+ : "";
37
40
  return {
38
41
  provider: this.provider,
39
42
  model: this.model,
40
43
  baseUrl: this.baseUrl,
41
44
  hasApiKey: !!this.apiKey,
45
+ apiKeyPreview: preview,
42
46
  };
43
47
  }
44
48
 
@@ -43,12 +43,43 @@ function showCurrentConfig(config) {
43
43
  ["Setting", "Value"],
44
44
  [
45
45
  ["Provider", info.provider || "none"],
46
- ["Model", info.model || "-"],
46
+ ["Model", info.model || "(proxy default)"],
47
47
  ["Base URL", info.baseUrl || "(default)"],
48
- ["API Key", info.hasApiKey ? "\u2713 configured" : "\u2717 missing"],
48
+ [
49
+ "API Key",
50
+ info.hasApiKey ? `\u2713 ${info.apiKeyPreview}` : "\u2717 missing",
51
+ ],
52
+ ["Auth Header", engine.authHeader || "(none)"],
53
+ [
54
+ "Key Source",
55
+ ai.apiKey
56
+ ? "config (apiKey)"
57
+ : ai.apiKeyEnv
58
+ ? `env ($${ai.apiKeyEnv})`
59
+ : "auto-detect",
60
+ ],
61
+ ["Available", engine.isAvailable() ? "\u2713 yes" : "\u2717 no"],
49
62
  ],
50
63
  );
51
64
  logger.blank();
65
+
66
+ if (!engine.isAvailable()) {
67
+ logger.warn("AI is not available. To fix:");
68
+ if (info.provider === "proxy") {
69
+ logger.dim(" Option 1: Set apiKey directly in qabot.config.json:");
70
+ logger.dim(' "ai": { "apiKey": "your-key", ... }');
71
+ logger.dim(
72
+ ` Option 2: Set env var: export ${ai.apiKeyEnv || "PROXY_API_KEY"}=your-key`,
73
+ );
74
+ logger.dim(
75
+ " Option 3: Remove auth requirement if proxy doesn't need it:",
76
+ );
77
+ logger.dim(' "ai": { "authHeader": null, ... }');
78
+ } else {
79
+ logger.dim(" Run: qabot auth");
80
+ }
81
+ logger.blank();
82
+ }
52
83
  }
53
84
 
54
85
  async function testConnection(config) {
@@ -60,7 +91,17 @@ async function testConnection(config) {
60
91
  return;
61
92
  }
62
93
 
94
+ const info = engine.getProviderInfo();
63
95
  logger.info(`Testing connection to ${chalk.bold(engine.provider)}...`);
96
+ logger.blank();
97
+ logger.dim(` Provider: ${info.provider}`);
98
+ logger.dim(` Model: ${info.model || "(none)"}`);
99
+ logger.dim(` Base URL: ${info.baseUrl}`);
100
+ logger.dim(
101
+ ` API Key: ${info.hasApiKey ? info.apiKeyPreview : "(none)"}`,
102
+ );
103
+ logger.dim(` Auth Header: ${engine.authHeader || "(none)"}`);
104
+ logger.blank();
64
105
 
65
106
  try {
66
107
  const response = await engine.complete("Reply with exactly: QABOT_OK");
@@ -76,6 +117,30 @@ async function testConnection(config) {
76
117
  }
77
118
  } catch (err) {
78
119
  logger.error(`Connection failed: ${err.message}`);
120
+ logger.blank();
121
+ logger.info("Troubleshooting:");
122
+ if (err.message.includes("401") || err.message.includes("auth")) {
123
+ logger.dim(" 1. Check API key is correct");
124
+ logger.dim(
125
+ ` 2. Verify env var: echo $${ai.apiKeyEnv || "PROXY_API_KEY"}`,
126
+ );
127
+ logger.dim(" 3. Or set apiKey directly in qabot.config.json:");
128
+ logger.dim(' "ai": { "apiKey": "your-key-here", ... }');
129
+ }
130
+ if (
131
+ err.message.includes("ECONNREFUSED") ||
132
+ err.message.includes("connect")
133
+ ) {
134
+ logger.dim(` 1. Check server is running at ${info.baseUrl}`);
135
+ logger.dim(" 2. Verify URL is correct in qabot.config.json");
136
+ }
137
+ if (err.message.includes("500")) {
138
+ logger.dim(" 1. Server error — check proxy/LLM server logs");
139
+ logger.dim(" 2. Model name may be wrong — verify ai.model in config");
140
+ logger.dim(
141
+ ` 3. Try: curl -X POST ${info.baseUrl} -H "Content-Type: application/json" -d '{"messages":[{"role":"user","content":"hi"}]}'`,
142
+ );
143
+ }
79
144
  }
80
145
  }
81
146
 
@@ -168,11 +233,8 @@ async function interactiveSetup(projectDir, config, isEmpty) {
168
233
  }
169
234
 
170
235
  if (proxyAnswers.apiKey) {
236
+ aiConfig.apiKey = proxyAnswers.apiKey;
171
237
  aiConfig.apiKeyEnv = "PROXY_API_KEY";
172
- logger.blank();
173
- logger.warn("Store your API key as an environment variable:");
174
- logger.dim(` export PROXY_API_KEY="${proxyAnswers.apiKey}"`);
175
- logger.dim(" Or add to .env file: PROXY_API_KEY=your-key");
176
238
  }
177
239
  } else if (provider === "ollama") {
178
240
  const { baseUrl, model } = await enquirer.prompt([
@@ -218,12 +280,8 @@ async function interactiveSetup(projectDir, config, isEmpty) {
218
280
 
219
281
  aiConfig.model = answers.model;
220
282
  aiConfig.apiKeyEnv = envName;
221
-
222
283
  if (answers.apiKey) {
223
- logger.blank();
224
- logger.warn("Store your API key as an environment variable:");
225
- logger.dim(` export ${envName}="${answers.apiKey}"`);
226
- logger.dim(` Or add to .env file: ${envName}=your-key`);
284
+ aiConfig.apiKey = answers.apiKey;
227
285
  }
228
286
  }
229
287
 
@@ -1,4 +1,4 @@
1
- export const VERSION = "0.2.3";
1
+ export const VERSION = "0.3.0";
2
2
  export const TOOL_NAME = "qabot";
3
3
 
4
4
  export const PROJECT_TYPES = [