wispy-cli 2.4.2 → 2.4.4

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/bin/wispy.mjs CHANGED
@@ -499,7 +499,6 @@ if (args[0] === "doctor") {
499
499
 
500
500
  // 3. API key configured
501
501
  if (config) {
502
- const provider = config.provider ?? "unknown";
503
502
  const envMap = {
504
503
  google: "GOOGLE_AI_KEY",
505
504
  anthropic: "ANTHROPIC_API_KEY",
@@ -509,14 +508,22 @@ if (args[0] === "doctor") {
509
508
  deepseek: "DEEPSEEK_API_KEY",
510
509
  ollama: null,
511
510
  };
512
- const envKey = envMap[provider];
513
- if (envKey === null) {
514
- check("AI provider (Ollama)", true, "no key needed");
515
- } else if (envKey) {
516
- const key = config.apiKey || process.env[envKey];
517
- check(`API key (${provider})`, !!key && key.length > 10, key ? "configured" : `run 'wispy setup provider'`);
511
+ // Support both old (config.provider) and new (config.providers) format
512
+ const providers = config.providers ? Object.keys(config.providers) : (config.provider ? [config.provider] : []);
513
+ if (providers.length === 0) {
514
+ check("AI provider", false, "no provider configured — run 'wispy setup provider'");
518
515
  } else {
519
- check("AI provider", false, `Unknown provider: ${provider}`);
516
+ for (const provider of providers) {
517
+ const envKey = envMap[provider];
518
+ if (envKey === null) {
519
+ check(`AI provider (${provider})`, true, "no key needed");
520
+ } else if (envKey) {
521
+ const key = config.providers?.[provider]?.apiKey || config.apiKey || process.env[envKey];
522
+ check(`API key (${provider})`, !!key && key.length > 10, key ? "configured" : `run 'wispy setup provider'`);
523
+ } else {
524
+ check(`AI provider (${provider})`, false, `unknown provider`);
525
+ }
526
+ }
520
527
  }
521
528
  } else {
522
529
  info("AI provider", "skipped (no config)");
@@ -192,14 +192,34 @@ export class PermissionManager {
192
192
  return this._approvalHandler(action);
193
193
  }
194
194
 
195
- // Default: CLI readline prompt
195
+ // Default: CLI single-key prompt (no extra readline to avoid stdin conflicts)
196
196
  return new Promise((resolve) => {
197
- const rl = createInterface({ input: process.stdin, output: process.stdout });
198
- const prompt = `\n⚠️ ${action.label ?? `${action.toolName}()`} — Allow? [y/N] `;
199
- rl.question(prompt, (answer) => {
200
- rl.close();
201
- resolve(answer.trim().toLowerCase() === "y" || answer.trim().toLowerCase() === "yes");
202
- });
197
+ const label = action.label ?? `${action.toolName}(${JSON.stringify(action.args ?? {}).slice(0, 60)})`;
198
+ process.stdout.write(`\n⚠️ ${label} — Allow? [y/N] `);
199
+
200
+ if (process.stdin.isTTY) {
201
+ const wasRaw = process.stdin.isRaw;
202
+ process.stdin.setRawMode(true);
203
+ process.stdin.resume();
204
+ process.stdin.once('data', (data) => {
205
+ const ch = data.toString().toLowerCase();
206
+ process.stdin.setRawMode(wasRaw);
207
+ if (ch === 'y') {
208
+ process.stdout.write('y\n');
209
+ resolve(true);
210
+ } else {
211
+ process.stdout.write(ch === '\x03' ? '\n' : 'n\n');
212
+ resolve(false);
213
+ }
214
+ });
215
+ } else {
216
+ // Non-TTY fallback
217
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
218
+ rl.question('', (answer) => {
219
+ rl.close();
220
+ resolve(answer.trim().toLowerCase() === 'y');
221
+ });
222
+ }
203
223
  });
204
224
  }
205
225
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wispy-cli",
3
- "version": "2.4.2",
3
+ "version": "2.4.4",
4
4
  "description": "🌿 Wispy — AI workspace assistant with trustworthy execution (harness, receipts, approvals, diffs)",
5
5
  "license": "MIT",
6
6
  "author": "Minseo & Poropo",