clawzempic 1.0.6 → 1.0.8

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.
Files changed (2) hide show
  1. package/bin/clawzempic.js +87 -54
  2. package/package.json +1 -1
package/bin/clawzempic.js CHANGED
@@ -12,6 +12,11 @@
12
12
  * npx clawzempic test Verify your connection works
13
13
  * npx clawzempic status Check usage and savings
14
14
  * npx clawzempic doctor Diagnose common issues
15
+ *
16
+ * Flags:
17
+ * --key <key> Provide API key (skip interactive prompt)
18
+ * --yes, -y Auto-confirm all prompts (non-interactive)
19
+ * --no-test Skip connection test after init
15
20
  */
16
21
 
17
22
  import { createInterface } from 'node:readline/promises';
@@ -22,7 +27,7 @@ import { join, basename } from 'node:path';
22
27
  // ── Constants ─────────────────────────────────────────────────────────────────
23
28
 
24
29
  const API_BASE = 'https://api.clawzempic.ai';
25
- const VERSION = '1.0.6';
30
+ const VERSION = '1.0.8';
26
31
  const OPENCLAW_DIR_NAME = '.openclaw';
27
32
 
28
33
  // ── ANSI Colors (no dependencies) ─────────────────────────────────────────────
@@ -192,6 +197,8 @@ async function ask(question, opts = {}) {
192
197
  }
193
198
 
194
199
  async function confirm(question, defaultYes = true) {
200
+ // --yes flag auto-confirms everything
201
+ if (globalArgs?.yes) return true;
195
202
  const hint = defaultYes ? 'Y/n' : 'y/N';
196
203
  const answer = await ask(`${question} ${c.dim}(${hint})${c.reset}`, { required: false });
197
204
  if (!answer) return defaultYes;
@@ -281,7 +288,7 @@ const FRAMEWORKS = [
281
288
  return false;
282
289
  },
283
290
  envFile: '.env',
284
- envVars: { ANTHROPIC_API_KEY: null, ANTHROPIC_BASE_URL: API_BASE },
291
+ envVars: { LLM_API_KEY: null, LLM_BASE_URL: API_BASE },
285
292
  },
286
293
  {
287
294
  id: 'nanobot',
@@ -297,11 +304,11 @@ const FRAMEWORKS = [
297
304
  return false;
298
305
  },
299
306
  envFile: '.env',
300
- envVars: { ANTHROPIC_API_KEY: null, ANTHROPIC_BASE_URL: API_BASE },
307
+ envVars: { LLM_API_KEY: null, LLM_BASE_URL: API_BASE },
301
308
  },
302
309
  {
303
310
  id: 'python',
304
- name: 'Python (Anthropic SDK)',
311
+ name: 'Python (Anthropic/OpenRouter SDK)',
305
312
  detect: (dir) => {
306
313
  for (const f of ['requirements.txt', 'pyproject.toml', 'Pipfile']) {
307
314
  if (existsSync(join(dir, f))) {
@@ -314,7 +321,7 @@ const FRAMEWORKS = [
314
321
  return false;
315
322
  },
316
323
  envFile: '.env',
317
- envVars: { ANTHROPIC_API_KEY: null, ANTHROPIC_BASE_URL: API_BASE },
324
+ envVars: { LLM_API_KEY: null, LLM_BASE_URL: API_BASE },
318
325
  },
319
326
  {
320
327
  id: 'langchain',
@@ -331,11 +338,11 @@ const FRAMEWORKS = [
331
338
  return false;
332
339
  },
333
340
  envFile: '.env',
334
- envVars: { ANTHROPIC_API_KEY: null, ANTHROPIC_BASE_URL: API_BASE },
341
+ envVars: { LLM_API_KEY: null, LLM_BASE_URL: API_BASE },
335
342
  },
336
343
  {
337
344
  id: 'node',
338
- name: 'Node.js (Anthropic SDK)',
345
+ name: 'Node.js (Anthropic/OpenRouter SDK)',
339
346
  detect: (dir) => {
340
347
  if (existsSync(join(dir, 'package.json'))) {
341
348
  try {
@@ -346,7 +353,7 @@ const FRAMEWORKS = [
346
353
  return false;
347
354
  },
348
355
  envFile: '.env',
349
- envVars: { ANTHROPIC_API_KEY: null, ANTHROPIC_BASE_URL: API_BASE },
356
+ envVars: { LLM_API_KEY: null, LLM_BASE_URL: API_BASE },
350
357
  },
351
358
  ];
352
359
 
@@ -436,10 +443,12 @@ function findOpenClawDir(dir) {
436
443
  }
437
444
 
438
445
  /**
439
- * Check if this is OpenClaw v2026.2+ (has auth-profiles.json).
446
+ * Check if this is OpenClaw v2026.2+ (has auth-profiles.json or openclaw.json).
447
+ * Fresh installs may not have auth-profiles.json yet, but openclaw.json is always present.
440
448
  */
441
449
  function isModernOpenClaw(openclawDir) {
442
- return existsSync(join(openclawDir, 'auth-profiles.json'));
450
+ return existsSync(join(openclawDir, 'auth-profiles.json')) ||
451
+ existsSync(join(openclawDir, 'openclaw.json'));
443
452
  }
444
453
 
445
454
  /**
@@ -558,8 +567,8 @@ function findKeyInAuthProfiles(openclawDir) {
558
567
  * Find API key from all possible locations.
559
568
  */
560
569
  function findApiKey(dir) {
561
- // 1. Environment variables
562
- const envKey = process.env.CLAWZEMPIC_API_KEY || process.env.ANTHROPIC_API_KEY;
570
+ // 1. Environment variables (check new names first, fall back to old)
571
+ const envKey = process.env.CLAWZEMPIC_API_KEY || process.env.LLM_API_KEY || process.env.ANTHROPIC_API_KEY;
563
572
  if (envKey && (envKey.startsWith('sk-clwz-') || envKey.startsWith('sr_'))) {
564
573
  return { key: envKey, source: 'environment variable' };
565
574
  }
@@ -578,7 +587,7 @@ function findApiKey(dir) {
578
587
  if (existsSync(envPath)) {
579
588
  try {
580
589
  const content = readFileSync(envPath, 'utf8');
581
- const match = content.match(/^(?:CLAWZEMPIC_API_KEY|ANTHROPIC_API_KEY)\s*=\s*(.+)$/m);
590
+ const match = content.match(/^(?:CLAWZEMPIC_API_KEY|LLM_API_KEY|ANTHROPIC_API_KEY)\s*=\s*(.+)$/m);
582
591
  if (match) {
583
592
  const val = match[1].trim();
584
593
  if (val.startsWith('sk-clwz-') || val.startsWith('sr_')) {
@@ -778,7 +787,7 @@ async function cmdInit(args) {
778
787
  // Build env vars: proxy key + base URL. Keep provider key separate.
779
788
  const envVars = {
780
789
  CLAWZEMPIC_API_KEY: clawzempicKey,
781
- ANTHROPIC_BASE_URL: API_BASE,
790
+ LLM_BASE_URL: API_BASE,
782
791
  };
783
792
 
784
793
  // Show what we'll do
@@ -800,7 +809,7 @@ async function cmdInit(args) {
800
809
  return cleanup();
801
810
  }
802
811
 
803
- // Clean up v1.0.3 bug: it wrote Clawzempic keys into ANTHROPIC_API_KEY.
812
+ // Clean up legacy: remove Clawzempic keys from ANTHROPIC_API_KEY (v1.0.3 bug + old naming)
804
813
  if (existsSync(envPath)) {
805
814
  const existing = readFileSync(envPath, 'utf8');
806
815
  const badMatch = existing.match(/^ANTHROPIC_API_KEY\s*=\s*(.+)$/m);
@@ -809,9 +818,16 @@ async function cmdInit(args) {
809
818
  if (badVal.startsWith('sr_') || badVal.startsWith('sk-clwz-')) {
810
819
  const cleaned = existing.replace(/^ANTHROPIC_API_KEY\s*=\s*(?:sr_|sk-clwz-).+\n?/m, '');
811
820
  writeFileSync(envPath, cleaned, 'utf8');
812
- bullet(warn, `Removed stale ANTHROPIC_API_KEY (had a Clawzempic key from v1.0.3 bug)`);
821
+ bullet(warn, `Removed stale ANTHROPIC_API_KEY (had a Clawzempic key use CLAWZEMPIC_API_KEY instead)`);
813
822
  }
814
823
  }
824
+ // Also clean up old ANTHROPIC_BASE_URL pointing to clawzempic
825
+ const oldBaseMatch = existing.match(/^ANTHROPIC_BASE_URL\s*=\s*(.+)$/m);
826
+ if (oldBaseMatch && oldBaseMatch[1].includes('clawzempic.ai')) {
827
+ const cleaned2 = existing.replace(/^ANTHROPIC_BASE_URL\s*=\s*.+clawzempic\.ai.+\n?/m, '');
828
+ writeFileSync(envPath, cleaned2, 'utf8');
829
+ bullet(warn, `Migrated ANTHROPIC_BASE_URL → LLM_BASE_URL`);
830
+ }
815
831
  }
816
832
 
817
833
  // Apply
@@ -828,10 +844,15 @@ async function cmdInit(args) {
828
844
  // ── Test Connection ──────────────────────────────────────────────────────
829
845
 
830
846
  blank();
831
- const runTest = await confirm('Test the connection?');
832
- let testPassed = !runTest; // skip = assume ok
833
- if (runTest) {
834
- testPassed = await runConnectionTest(clawzempicKey);
847
+ let testPassed = true;
848
+ if (args.noTest) {
849
+ bullet(info, 'Skipping connection test (--no-test)');
850
+ } else {
851
+ const runTest = await confirm('Test the connection?');
852
+ testPassed = !runTest; // skip = assume ok
853
+ if (runTest) {
854
+ testPassed = await runConnectionTest(clawzempicKey);
855
+ }
835
856
  }
836
857
 
837
858
  // ── Done ─────────────────────────────────────────────────────────────────
@@ -1093,7 +1114,7 @@ async function cmdDoctor() {
1093
1114
 
1094
1115
  // 2. Check for Clawzempic config
1095
1116
  const content = readFileSync(envPath, 'utf8');
1096
- const keyMatch = content.match(/^(?:CLAWZEMPIC_API_KEY|ANTHROPIC_API_KEY)\s*=\s*(.+)$/m);
1117
+ const keyMatch = content.match(/^(?:CLAWZEMPIC_API_KEY|LLM_API_KEY|ANTHROPIC_API_KEY)\s*=\s*(.+)$/m);
1097
1118
  if (keyMatch && (keyMatch[1].startsWith('sk-clwz-') || keyMatch[1].startsWith('sr_'))) {
1098
1119
  bullet(ok, `Clawzempic API key found`);
1099
1120
  } else if (keyMatch) {
@@ -1104,14 +1125,14 @@ async function cmdDoctor() {
1104
1125
  return cleanup(1);
1105
1126
  }
1106
1127
 
1107
- // 3. Check base URL
1108
- const baseUrlMatch = content.match(/^ANTHROPIC_BASE_URL\s*=\s*(.+)$/m);
1128
+ // 3. Check base URL (check LLM_BASE_URL first, fall back to ANTHROPIC_BASE_URL)
1129
+ const baseUrlMatch = content.match(/^(?:LLM_BASE_URL|ANTHROPIC_BASE_URL)\s*=\s*(.+)$/m);
1109
1130
  if (baseUrlMatch && baseUrlMatch[1].includes('clawzempic.ai')) {
1110
1131
  bullet(ok, `Base URL pointing to Clawzempic`);
1111
1132
  } else if (baseUrlMatch) {
1112
1133
  bullet(warn, `Base URL set to ${baseUrlMatch[1]} — not pointing to Clawzempic`);
1113
1134
  } else {
1114
- bullet(fail, `ANTHROPIC_BASE_URL not set — requests go directly to Anthropic, bypassing Clawzempic`);
1135
+ bullet(fail, `LLM_BASE_URL not set — requests go directly to your provider, bypassing Clawzempic`);
1115
1136
  }
1116
1137
 
1117
1138
  // 4. Check framework
@@ -1189,13 +1210,15 @@ function cmdHelp() {
1189
1210
  // ── Arg Parsing ───────────────────────────────────────────────────────────────
1190
1211
 
1191
1212
  function parseArgs(argv) {
1192
- const args = { command: null, key: null, help: false, version: false };
1213
+ const args = { command: null, key: null, help: false, version: false, yes: false, noTest: false };
1193
1214
  const positional = [];
1194
1215
 
1195
1216
  for (let i = 2; i < argv.length; i++) {
1196
1217
  const arg = argv[i];
1197
1218
  if (arg === '--help' || arg === '-h') args.help = true;
1198
1219
  else if (arg === '--version' || arg === '-v') args.version = true;
1220
+ else if (arg === '--yes' || arg === '-y') args.yes = true;
1221
+ else if (arg === '--no-test') args.noTest = true;
1199
1222
  else if (arg === '--key' && argv[i + 1]) { args.key = argv[++i]; }
1200
1223
  else if (!arg.startsWith('-')) positional.push(arg);
1201
1224
  }
@@ -1222,38 +1245,48 @@ process.on('SIGINT', () => {
1222
1245
 
1223
1246
  // ── Main ──────────────────────────────────────────────────────────────────────
1224
1247
 
1225
- const args = parseArgs(process.argv);
1248
+ let globalArgs = null;
1226
1249
 
1227
- if (args.version) {
1228
- console.log(`clawzempic ${VERSION}`);
1229
- process.exit(0);
1230
- }
1250
+ async function main() {
1251
+ const args = parseArgs(process.argv);
1252
+ globalArgs = args;
1231
1253
 
1232
- if (args.help && !args.command) {
1233
- cmdHelp();
1234
- process.exit(0);
1235
- }
1254
+ if (args.version) {
1255
+ console.log(`clawzempic ${VERSION}`);
1256
+ process.exit(0);
1257
+ }
1236
1258
 
1237
- const command = args.command || 'init';
1238
-
1239
- switch (command) {
1240
- case 'init':
1241
- await cmdInit(args);
1242
- break;
1243
- case 'test':
1244
- await cmdTest(args);
1245
- break;
1246
- case 'status':
1247
- await cmdStatus(args);
1248
- break;
1249
- case 'doctor':
1250
- await cmdDoctor();
1251
- break;
1252
- case 'help':
1259
+ if (args.help && !args.command) {
1253
1260
  cmdHelp();
1254
1261
  process.exit(0);
1255
- break;
1256
- default:
1257
- console.error(`Unknown command: ${command}. Run 'npx clawzempic --help' for usage.`);
1258
- process.exit(1);
1262
+ }
1263
+
1264
+ const command = args.command || 'init';
1265
+
1266
+ switch (command) {
1267
+ case 'init':
1268
+ await cmdInit(args);
1269
+ break;
1270
+ case 'test':
1271
+ await cmdTest(args);
1272
+ break;
1273
+ case 'status':
1274
+ await cmdStatus(args);
1275
+ break;
1276
+ case 'doctor':
1277
+ await cmdDoctor();
1278
+ break;
1279
+ case 'help':
1280
+ cmdHelp();
1281
+ process.exit(0);
1282
+ break;
1283
+ default:
1284
+ console.error(`Unknown command: ${command}. Run 'npx clawzempic --help' for usage.`);
1285
+ process.exit(1);
1286
+ }
1259
1287
  }
1288
+
1289
+ main().catch(err => {
1290
+ console.error(`\n ${c.red}Fatal:${c.reset} ${err.message}\n`);
1291
+ process.exit(1);
1292
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawzempic",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Intelligent LLM API proxy — prompt caching, smart routing, memory. Drop-in replacement that cuts your Claude API costs 70-95%.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",