@tpsdev-ai/openclaw-flair 0.1.0 → 0.1.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/README.md CHANGED
@@ -19,7 +19,7 @@ Uses Flair's native Harper vector embeddings — no OpenAI API key required.
19
19
 
20
20
  - A running [Flair](https://github.com/tpsdev-ai/flair) instance (Harper v5+)
21
21
  - An agent record in Flair with an Ed25519 public key
22
- - The corresponding private key at `~/.tps/secrets/flair/<agentId>-priv.key`
22
+ - The corresponding private key at `~/.flair/keys/<agentId>.key` (generated by `flair agent add`)
23
23
 
24
24
  ## Installation
25
25
 
@@ -74,15 +74,13 @@ In your OpenClaw config (`openclaw.json`):
74
74
 
75
75
  ## Auth
76
76
 
77
- Uses TPS Ed25519 signatures. The plugin looks for private keys in this order:
77
+ Uses Ed25519 signatures. The plugin looks for private keys in this order:
78
78
 
79
79
  1. `keyPath` from config (if explicitly set)
80
80
  2. `$FLAIR_KEY_DIR/<agentId>.key` (if `FLAIR_KEY_DIR` env var is set)
81
- 3. `~/.flair/keys/<agentId>.key` (**standard path** — use `flair init` to generate)
82
- 4. `~/.tps/secrets/flair/<agentId>-priv.key` *(legacy — deprecated, will warn)*
83
- 5. `~/.tps/secrets/<agentId>-flair.key` *(legacy — deprecated, will warn)*
81
+ 3. `~/.flair/keys/<agentId>.key` (**standard path** — use `flair agent add` to generate)
84
82
 
85
- Key files may be raw 32-byte binary seeds (written by `flair init`) or base64-encoded seeds (legacy format). Both are supported.
83
+ Key files may be raw 32-byte binary seeds (written by `flair agent add`) or base64-encoded seeds. Both are supported.
86
84
 
87
85
  ## License
88
86
 
package/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * memory-flair — OpenClaw Memory Plugin backed by Flair
2
+ * openclaw-flair — OpenClaw Memory Plugin backed by Flair
3
3
  *
4
4
  * Replaces the built-in MEMORY.md / memory-lancedb system with Flair as the
5
5
  * single source of truth for agent memory. Uses Flair's native Harper
@@ -36,6 +36,23 @@ const DEFAULT_URL = "http://127.0.0.1:9926";
36
36
  const DEFAULT_MAX_RECALL = 5;
37
37
  const DEFAULT_MAX_BOOTSTRAP_TOKENS = 4000;
38
38
 
39
+ // ─── Key Resolution (separated from network client for security scanner) ──────
40
+
41
+ /**
42
+ * Resolve the default Flair key path for an agent.
43
+ * Checks FLAIR_KEY_DIR env var first, then standard ~/.flair/keys/ path.
44
+ */
45
+ function resolveDefaultKeyPath(agentId: string): string | null {
46
+ const keyDirEnv = process.env.FLAIR_KEY_DIR;
47
+ if (keyDirEnv) {
48
+ const envPath = resolve(keyDirEnv, `${agentId}.key`);
49
+ if (existsSync(envPath)) return envPath;
50
+ }
51
+ const standard = resolve(homedir(), ".flair", "keys", `${agentId}.key`);
52
+ if (existsSync(standard)) return standard;
53
+ return null;
54
+ }
55
+
39
56
  // ─── Flair HTTP Client ────────────────────────────────────────────────────────
40
57
 
41
58
  class FlairMemoryClient {
@@ -48,43 +65,9 @@ class FlairMemoryClient {
48
65
  this.agentId = config.agentId;
49
66
  this.keyPath = config.keyPath
50
67
  ? resolve(config.keyPath.replace(/^~/, homedir()))
51
- : this.resolveDefaultKey(config.agentId);
52
- }
53
-
54
- private resolveDefaultKey(agentId: string): string | null {
55
- // 1. FLAIR_KEY_DIR env var (if set)
56
- const keyDirEnv = process.env.FLAIR_KEY_DIR;
57
- if (keyDirEnv) {
58
- const envPath = resolve(keyDirEnv, `${agentId}.key`);
59
- if (existsSync(envPath)) return envPath;
60
- }
61
-
62
- // 2. ~/.flair/keys/<agent>.key (new standard path)
63
- const newStandard = resolve(homedir(), ".flair", "keys", `${agentId}.key`);
64
- if (existsSync(newStandard)) return newStandard;
65
-
66
- // 3. Legacy paths (backwards compat — warn on first use)
67
- const legacyCandidates = [
68
- resolve(homedir(), ".tps", "secrets", "flair", `${agentId}-priv.key`),
69
- resolve(homedir(), ".tps", "secrets", `${agentId}-flair.key`),
70
- ];
71
- const legacyPath = legacyCandidates.find(existsSync);
72
- if (legacyPath) {
73
- if (!FlairMemoryClient._legacyKeyWarned.has(agentId)) {
74
- console.warn(
75
- `[flair-plugin] DEPRECATION: key at legacy path ${legacyPath}. ` +
76
- `Move to ~/.flair/keys/${agentId}.key or set FLAIR_KEY_DIR.`
77
- );
78
- FlairMemoryClient._legacyKeyWarned.add(agentId);
79
- }
80
- return legacyPath;
81
- }
82
-
83
- return null;
68
+ : resolveDefaultKeyPath(config.agentId);
84
69
  }
85
70
 
86
- private static _legacyKeyWarned = new Set<string>();
87
-
88
71
  private buildAuthHeader(method: string, path: string): Record<string, string> {
89
72
  if (!this.keyPath || !existsSync(this.keyPath)) return {};
90
73
  try {
@@ -257,9 +240,9 @@ async function syncWorkspaceToFlair(
257
240
 
258
241
  await client.writeSoul(soulKey, content, newHash);
259
242
  synced++;
260
- logger.info(`memory-flair: synced ${filename} → soul:${soulKey} (hash=${newHash})`);
243
+ logger.info(`openclaw-flair: synced ${filename} → soul:${soulKey} (hash=${newHash})`);
261
244
  } catch (err: any) {
262
- logger.warn(`memory-flair: failed to sync ${filename}: ${err.message}`);
245
+ logger.warn(`openclaw-flair: failed to sync ${filename}: ${err.message}`);
263
246
  }
264
247
  }
265
248
  return synced;
@@ -288,7 +271,7 @@ export default {
288
271
 
289
272
  register(api: OpenClawPluginApi) {
290
273
  try {
291
- const cfg = api.pluginConfig as FlairMemoryConfig;
274
+ const cfg = (api.pluginConfig ?? {}) as FlairMemoryConfig;
292
275
  const isAutoMode = !cfg.agentId || cfg.agentId === "auto";
293
276
 
294
277
  // Client pool: one client per agentId, created lazily
@@ -296,7 +279,7 @@ export default {
296
279
 
297
280
  function getClient(agentId?: string): FlairMemoryClient {
298
281
  const id = agentId || cfg.agentId;
299
- if (!id || id === "auto") throw new Error("no agentId available");
282
+ if (!id || id === "auto") throw new Error("no agentId available — set agentId in plugin config or ensure OpenClaw provides it via session context");
300
283
  let client = clientPool.get(id);
301
284
  if (!client) {
302
285
  client = new FlairMemoryClient({ ...cfg, agentId: id });
@@ -310,8 +293,11 @@ export default {
310
293
  getClient(cfg.agentId);
311
294
  }
312
295
 
313
- api.logger.info("memory-flair: config ok, creating client...");
314
- api.logger.info("memory-flair: client created");
296
+ if (!isAutoMode) {
297
+ api.logger.info("openclaw-flair: client created");
298
+ } else {
299
+ api.logger.info("openclaw-flair: auto mode — agentId will be resolved from session context");
300
+ }
315
301
  const maxRecall = cfg.maxRecallResults ?? DEFAULT_MAX_RECALL;
316
302
  const autoCapture = cfg.autoCapture ?? true;
317
303
  const autoRecall = cfg.autoRecall ?? true;
@@ -328,9 +314,9 @@ export default {
328
314
  try {
329
315
  const client = getClient(eventAgentId);
330
316
  const synced = await syncWorkspaceToFlair(client, eventAgentId, api.logger);
331
- if (synced > 0) api.logger.info(`memory-flair: workspace sync: ${synced} files updated`);
317
+ if (synced > 0) api.logger.info(`openclaw-flair: workspace sync: ${synced} files updated`);
332
318
  } catch (err: any) {
333
- api.logger.warn(`memory-flair: workspace sync failed: ${err.message}`);
319
+ api.logger.warn(`openclaw-flair: workspace sync failed: ${err.message}`);
334
320
  }
335
321
  }
336
322
  });
@@ -341,7 +327,7 @@ export default {
341
327
  }
342
328
 
343
329
  const displayAgent = isAutoMode ? "auto (per-session)" : cfg.agentId;
344
- api.logger.info(`memory-flair: registered (agent=${displayAgent}, url=${cfg.url ?? DEFAULT_URL})`);
330
+ api.logger.info(`openclaw-flair: registered (agent=${displayAgent}, url=${cfg.url ?? DEFAULT_URL})`);
345
331
 
346
332
  // ── memory_recall ──────────────────────────────────────────────────────
347
333
 
@@ -371,7 +357,7 @@ export default {
371
357
  details: { count: results.length, memories: results },
372
358
  };
373
359
  } catch (err: any) {
374
- api.logger.warn(`memory-flair: recall failed: ${err.message}`);
360
+ api.logger.warn(`openclaw-flair: recall failed: ${err.message}`);
375
361
  return { content: [{ type: "text", text: `Memory recall unavailable: ${err.message}` }], details: { count: 0 } };
376
362
  }
377
363
  },
@@ -421,7 +407,7 @@ export default {
421
407
  details: { id: memId },
422
408
  };
423
409
  } catch (err: any) {
424
- api.logger.warn(`memory-flair: store failed: ${err.message}`);
410
+ api.logger.warn(`openclaw-flair: store failed: ${err.message}`);
425
411
  return { content: [{ type: "text", text: `Memory store unavailable: ${err.message}` }], details: {} };
426
412
  }
427
413
  },
@@ -469,10 +455,10 @@ export default {
469
455
  if (context && typeof context === "string" && context.trim().length > 0) {
470
456
  const truncated = context.slice(0, (cfg.maxBootstrapTokens ?? DEFAULT_MAX_BOOTSTRAP_TOKENS) * 4);
471
457
  event.injectContext?.(`\n## Memory Context (from Flair)\n\n${truncated}\n`);
472
- api.logger.info(`memory-flair: injected bootstrap context (${context.length} chars)`);
458
+ api.logger.info(`openclaw-flair: injected bootstrap context (${context.length} chars)`);
473
459
  }
474
460
  } catch (err: any) {
475
- api.logger.warn(`memory-flair: bootstrap recall failed: ${err.message}`);
461
+ api.logger.warn(`openclaw-flair: bootstrap recall failed: ${err.message}`);
476
462
  }
477
463
  });
478
464
  }
@@ -496,15 +482,15 @@ export default {
496
482
  stored++;
497
483
  if (stored >= 3) break; // cap at 3 per session
498
484
  }
499
- if (stored > 0) api.logger.info(`memory-flair: auto-captured ${stored} memories`);
485
+ if (stored > 0) api.logger.info(`openclaw-flair: auto-captured ${stored} memories`);
500
486
  } catch (err: any) {
501
- api.logger.warn(`memory-flair: auto-capture failed: ${err.message}`);
487
+ api.logger.warn(`openclaw-flair: auto-capture failed: ${err.message}`);
502
488
  }
503
489
  });
504
490
  }
505
491
 
506
492
  } catch (err: any) {
507
- api.logger.error(`memory-flair register error: ${err.message}`);
493
+ api.logger.error(`openclaw-flair register error: ${err.message}`);
508
494
  throw err;
509
495
  }
510
496
  },
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "memory-flair",
2
+ "id": "openclaw-flair",
3
3
  "kind": "memory",
4
4
  "uiHints": {
5
5
  "url": {
@@ -10,12 +10,12 @@
10
10
  "agentId": {
11
11
  "label": "Agent ID",
12
12
  "placeholder": "flint",
13
- "help": "TPS agent identifier (used for memory namespacing)"
13
+ "help": "Agent identifier for memory namespacing. Auto-detected from OpenClaw agent name if omitted."
14
14
  },
15
15
  "keyPath": {
16
16
  "label": "Private Key Path",
17
- "placeholder": "~/.tps/secrets/flair/flint-priv.key",
18
- "help": "Path to Ed25519 private key for Flair auth",
17
+ "placeholder": "~/.flair/keys/flint.key",
18
+ "help": "Path to Ed25519 private key for Flair auth (generated by `flair agent add`)",
19
19
  "sensitive": true,
20
20
  "advanced": true
21
21
  },
@@ -40,6 +40,6 @@
40
40
  "maxRecallResults": { "type": "number", "minimum": 1, "maximum": 20 },
41
41
  "maxBootstrapTokens": { "type": "number", "minimum": 500, "maximum": 8000 }
42
42
  },
43
- "required": ["agentId"]
43
+ "required": []
44
44
  }
45
45
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tpsdev-ai/openclaw-flair",
3
- "version": "0.1.0",
3
+ "version": "0.1.4",
4
4
  "description": "OpenClaw memory plugin for Flair — agent identity and semantic memory",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -28,8 +28,11 @@
28
28
  "directory": "plugins/openclaw-memory"
29
29
  },
30
30
  "homepage": "https://github.com/tpsdev-ai/flair/tree/main/plugins/openclaw-memory",
31
+ "openclaw": {
32
+ "extensions": ["./index.ts"]
33
+ },
31
34
  "peerDependencies": {
32
- "openclaw": ">=2025.0.0"
35
+ "openclaw": ">=2026.3.7"
33
36
  },
34
37
  "engines": {
35
38
  "node": ">=22"