@tokagent/tokagentos 2.0.33 → 2.0.34

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": "@tokagent/tokagentos",
3
- "version": "2.0.33",
3
+ "version": "2.0.34",
4
4
  "description": "tokagentOS CLI - Create and upgrade tokagentOS project templates",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Remove LLM provider API keys (OPENROUTER, ANTHROPIC, OPENAI, GOOGLE, GROQ)
4
+ * from the agents DB table. mergeDbSettings() in @elizaos/core loads
5
+ * agents.secrets and agents.settings.secrets into character.settings.secrets
6
+ * on every boot, and runtime.getSetting() checks character.settings.secrets
7
+ * BEFORE process.env — so a stale DB-stored key shadows the .env value
8
+ * forever. After running this, .env becomes the source of truth.
9
+ *
10
+ * Run with the agent STOPPED (`Ctrl-C` your `bun run dev`):
11
+ * bun run scripts/clear-db-llm-secrets.mjs
12
+ */
13
+ import path from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ import { existsSync } from "node:fs";
16
+
17
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
+ const PROJECT_ROOT = path.resolve(__dirname, "..");
19
+ const DB_DIR = path.join(PROJECT_ROOT, ".eliza", ".elizadb");
20
+
21
+ if (!existsSync(DB_DIR)) {
22
+ console.error(`PGLite directory not found at ${DB_DIR}`);
23
+ process.exit(1);
24
+ }
25
+
26
+ const LLM_KEYS = [
27
+ "OPENROUTER_API_KEY",
28
+ "ANTHROPIC_API_KEY",
29
+ "OPENAI_API_KEY",
30
+ "GOOGLE_GENERATIVE_AI_API_KEY",
31
+ "GOOGLE_API_KEY",
32
+ "GROQ_API_KEY",
33
+ ];
34
+
35
+ const { PGlite } = await import("@electric-sql/pglite");
36
+ const db = new PGlite(DB_DIR);
37
+ await db.waitReady;
38
+
39
+ const before = await db.query(
40
+ "SELECT id, name, secrets, settings FROM agents",
41
+ );
42
+ console.log(`Agents in DB: ${before.rows.length}`);
43
+ for (const row of before.rows) {
44
+ const id = row.id;
45
+ const name = row.name;
46
+ const topSecrets = row.secrets && typeof row.secrets === "object" ? row.secrets : {};
47
+ const settingsSecrets =
48
+ row.settings &&
49
+ typeof row.settings === "object" &&
50
+ row.settings.secrets &&
51
+ typeof row.settings.secrets === "object"
52
+ ? row.settings.secrets
53
+ : {};
54
+ const allKeys = new Set([
55
+ ...Object.keys(topSecrets),
56
+ ...Object.keys(settingsSecrets),
57
+ ]);
58
+ const llmKeysPresent = [...allKeys].filter((k) => LLM_KEYS.includes(k));
59
+ if (llmKeysPresent.length === 0) {
60
+ console.log(` ${name} (${id}): no LLM keys stored ✓`);
61
+ continue;
62
+ }
63
+ console.log(` ${name} (${id}): clearing ${llmKeysPresent.join(", ")}`);
64
+ const newTopSecrets = { ...topSecrets };
65
+ const newSettings =
66
+ row.settings && typeof row.settings === "object" ? { ...row.settings } : {};
67
+ const newSettingsSecrets = { ...settingsSecrets };
68
+ for (const k of llmKeysPresent) {
69
+ delete newTopSecrets[k];
70
+ delete newSettingsSecrets[k];
71
+ }
72
+ newSettings.secrets = newSettingsSecrets;
73
+ await db.query(
74
+ "UPDATE agents SET secrets = $1, settings = $2 WHERE id = $3",
75
+ [
76
+ JSON.stringify(newTopSecrets),
77
+ JSON.stringify(newSettings),
78
+ id,
79
+ ],
80
+ );
81
+ }
82
+
83
+ console.log("\nDone. Restart `bun run dev` — .env is now the source of truth.");
84
+ await db.close();
@@ -229,6 +229,87 @@ if (env.OPENROUTER_API_KEY) {
229
229
  }
230
230
  }
231
231
 
232
+ /**
233
+ * DB-shadow check.
234
+ *
235
+ * Failure mode observed in the field: an LLM key set during first-boot
236
+ * onboarding is persisted into the `agents` table (`secrets` and
237
+ * `settings.secrets` columns). On every restart, mergeDbSettings() in
238
+ * @elizaos/core copies it into character.settings.secrets, and
239
+ * runtime.getSetting() reads that BEFORE process.env. So rotating .env
240
+ * does nothing — the DB value wins forever, even after .env is changed.
241
+ *
242
+ * We open PGLite read-only, scan agents.secrets and agents.settings.secrets,
243
+ * and warn loudly if any LLM key differs from .env. We don't auto-mutate
244
+ * the DB — clearing secrets is a destructive operation that should be
245
+ * explicit (use scripts/clear-db-llm-secrets.mjs).
246
+ *
247
+ * Best-effort only: skipped if PGLite isn't installed, the DB dir doesn't
248
+ * exist (fresh project), or the `agents` table isn't there yet (pre-boot).
249
+ */
250
+ async function checkDbShadow() {
251
+ const dbDir = path.join(PROJECT_ROOT, ".eliza", ".elizadb");
252
+ if (!existsSync(dbDir)) return;
253
+ let PGlite;
254
+ try {
255
+ ({ PGlite } = await import("@electric-sql/pglite"));
256
+ } catch {
257
+ return;
258
+ }
259
+ let db;
260
+ try {
261
+ db = new PGlite(dbDir);
262
+ await db.waitReady;
263
+ } catch {
264
+ return;
265
+ }
266
+ try {
267
+ const result = await db.query(
268
+ "SELECT id, name, secrets, settings FROM agents",
269
+ );
270
+ for (const row of result.rows) {
271
+ const topSecrets =
272
+ row.secrets && typeof row.secrets === "object" ? row.secrets : {};
273
+ const settingsSecrets =
274
+ row.settings &&
275
+ typeof row.settings === "object" &&
276
+ row.settings.secrets &&
277
+ typeof row.settings.secrets === "object"
278
+ ? row.settings.secrets
279
+ : {};
280
+ for (const key of SHADOWED_KEYS) {
281
+ const dbValue = topSecrets[key] ?? settingsSecrets[key];
282
+ const dotenvValue = env[key];
283
+ if (!dbValue) continue;
284
+ if (!dotenvValue) {
285
+ // DB has it, .env doesn't. Probably set via onboarding UI and not
286
+ // mirrored. Not necessarily a bug — but flag it so the user knows.
287
+ continue;
288
+ }
289
+ if (dbValue !== dotenvValue) {
290
+ fail(
291
+ `${key} in PGLite database (agent "${row.name}") differs from .env.\n` +
292
+ ` db : ${String(dbValue).slice(0, 12)}…${String(dbValue).slice(-4)} (this is what the agent reads)\n` +
293
+ ` .env : ${String(dotenvValue).slice(0, 12)}…${String(dotenvValue).slice(-4)} (this is what you probably edited)\n` +
294
+ ` mergeDbSettings() in @elizaos/core loads the DB value into character.settings.secrets, and\n` +
295
+ ` runtime.getSetting() reads that BEFORE process.env. Editing .env doesn't help.\n` +
296
+ ` Fix: stop \`bun run dev\` and run \`bun run scripts/clear-db-llm-secrets.mjs\`,\n` +
297
+ ` then start again. .env will then be the source of truth.`,
298
+ );
299
+ }
300
+ }
301
+ }
302
+ } catch {
303
+ // agents table doesn't exist yet (fresh boot) — nothing to check.
304
+ } finally {
305
+ try {
306
+ await db.close();
307
+ } catch {}
308
+ }
309
+ }
310
+
311
+ await checkDbShadow();
312
+
232
313
  if (hadFailure) {
233
314
  console.error(
234
315
  "\n\x1b[31m[verify-llm-plugins]\x1b[0m One or more LLM-provider checks failed. Chat will not work until this is resolved.\n",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "1.0.0",
3
- "generatedAt": "2026-05-27T09:03:47.237Z",
3
+ "generatedAt": "2026-05-27T09:21:58.814Z",
4
4
  "repoUrl": "https://github.com/elizaos/eliza",
5
5
  "templates": [
6
6
  {