agenr 0.8.2 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.8.4]
4
+
5
+ ### Added
6
+ - feat(openclaw-plugin): project scoping via config.project in openclaw.json; all session-start recall and store calls are scoped to the configured project when set (issue #71)
7
+ - feat(openclaw-plugin): optional subject field in agenr_store schema; agents can now pass an explicit subject per entry rather than always relying on inference (issue #86)
8
+ - feat(openclaw-plugin): platform normalization and source_file format warnings in runStoreTool; platform is inferred from source when missing, invalid values are warned and dropped, freeform source strings trigger a format hint (issue #145)
9
+
10
+ ### Fixed
11
+ - fix(recall): cap final recall scores at 1.0 after FTS bonus; Math.min(1.0) applied in scoreEntryWithBreakdown (issue #64)
12
+ - fix(mcp): correct misleading retire tool message; retired entries are hidden from all recall paths (issue #143)
13
+ - fix(mcp): inferSubject now splits on punctuation followed by whitespace only, preventing truncation on file path periods (e.g. .ts, .js)
14
+ - fix(openclaw-plugin): subject inference in runStoreTool processedEntries now uses the same safe regex as inferSubject
15
+
16
+ ### Changed
17
+ - chore(openclaw-plugin): remove openclaw.plugin.json version field; package.json is now the single source of truth (issue #91)
18
+ - chore(openclaw-plugin): remove formatRecallAsSummary dead code; writeAgenrMd was already removed, this cleans up the last orphaned export (issue #77)
19
+
20
+ ## [0.8.3]
21
+
22
+ ### Fixed
23
+ - setup: custom model aliases (gpt-4.1-nano, gpt-4.1-mini) now appear in
24
+ the model picker when using openai-api-key auth (issue #136)
25
+ - setup: revert hint null-normalization regression (details?.name ?? undefined)
26
+ - setup: warn user when empty credential is entered during key rotation
27
+ - setup: note that updated credential is saved but not re-validated
28
+ - setup: openai-api-key now prioritizes gpt-4.1-nano, gpt-4.1-mini, and
29
+ gpt-5-nano in preferred model selection, and adds gpt-5-nano alias
30
+ resolution for OpenAI model lookup
31
+ - setup: reconfigure now offers to update stored API key even when existing
32
+ credential is valid (issue #13)
33
+ - embeddings: EmbeddingCache is now bounded with LRU eviction (default
34
+ max 5000 entries) to prevent unbounded heap growth during large ingests
35
+ (issue #57)
36
+ - embeddings: EmbeddingCache constructor throws RangeError for maxSize < 1
37
+
3
38
  ## [0.8.2] - 2026-02-22
4
39
 
5
40
  ### Added
package/README.md CHANGED
@@ -12,7 +12,7 @@ One local database. Your memory stays on your machine.
12
12
 
13
13
  AGENR uses embeddings to make your memory searchable. The best setup we've found: an **OpenAI API key** with `text-embedding-3-small`. Embeddings cost fractions of a penny per operation - a full ingestion of 100+ session transcripts runs about $0.10 total.
14
14
 
15
- AGENR also supports **OpenAI Pro subscriptions** and **Anthropic Claude subscriptions** (no API key needed) for the LLM extraction step. But for the best balance of speed, accuracy, and cost, we recommend `gpt-4o-mini` with an API key. `agenr setup` walks you through all of this.
15
+ AGENR also supports **OpenAI Pro subscriptions** and **Anthropic Claude subscriptions** (no API key needed) for the LLM extraction step. But for the best balance of speed, accuracy, and cost, we recommend `gpt-4.1-nano` with an API key. `agenr setup` walks you through all of this.
16
16
 
17
17
  ```bash
18
18
  export OPENAI_API_KEY=sk-... # for embeddings + extraction
package/dist/cli-main.js CHANGED
@@ -43,7 +43,8 @@ var MODEL_ALIASES = {
43
43
  "gpt-codex": "gpt-5.2-codex",
44
44
  "gpt-4.1-nano": "openai/gpt-4.1-nano",
45
45
  "gpt-4.1-mini": "openai/gpt-4.1-mini",
46
- "gpt-4.1": "openai/gpt-4.1"
46
+ "gpt-4.1": "openai/gpt-4.1",
47
+ "gpt-5-nano": "openai/gpt-5-nano"
47
48
  },
48
49
  "openai-codex": {
49
50
  codex: "gpt-5.3-codex",
@@ -138,7 +139,7 @@ var AUTH_METHOD_DEFINITIONS = [
138
139
  provider: "openai",
139
140
  title: "OpenAI -- API key",
140
141
  setupDescription: "Standard API key from platform.openai.com. Pay per token.",
141
- preferredModels: ["gpt-4o", "openai/gpt-4.1-nano", "gpt-4o-mini"]
142
+ preferredModels: ["gpt-4.1-nano", "gpt-4.1-mini", "gpt-5-nano"]
142
143
  }
143
144
  ];
144
145
  var AUTH_METHOD_SET = new Set(AUTH_METHOD_DEFINITIONS.map((item) => item.id));
@@ -3847,7 +3848,8 @@ function scoreEntryWithBreakdown(entry, vectorSim, ftsMatch, now, freshnessNow =
3847
3848
  const memoryStrength = Math.min(Math.max(imp, spacedRecallBase) * fresh, 1);
3848
3849
  const todoPenalty = entry.type === "todo" ? todoStaleness(entry, now) : 1;
3849
3850
  const contradictionPenalty = entry.contradictions >= 2 ? 0.8 : 1;
3850
- const score = sim * (0.3 + 0.7 * rec) * memoryStrength * todoPenalty * contradictionPenalty + fts;
3851
+ const rawScore = sim * (0.3 + 0.7 * rec) * memoryStrength * todoPenalty * contradictionPenalty + fts;
3852
+ const score = Math.min(1, rawScore);
3851
3853
  return {
3852
3854
  score,
3853
3855
  scores: {
@@ -3857,6 +3859,7 @@ function scoreEntryWithBreakdown(entry, vectorSim, ftsMatch, now, freshnessNow =
3857
3859
  recall: recallBase,
3858
3860
  freshness: fresh,
3859
3861
  todoPenalty,
3862
+ // FTS bonus component before the final score is capped at 1.0.
3860
3863
  fts,
3861
3864
  spacing: spacingFactor
3862
3865
  }
@@ -4533,12 +4536,75 @@ async function retireEntries(opts) {
4533
4536
 
4534
4537
  // src/embeddings/cache.ts
4535
4538
  var EmbeddingCache = class {
4536
- embeddings = /* @__PURE__ */ new Map();
4539
+ maxSize;
4540
+ map = /* @__PURE__ */ new Map();
4541
+ head = null;
4542
+ // most recently used key
4543
+ tail = null;
4544
+ // least recently used key
4545
+ constructor(maxSize = 5e3) {
4546
+ if (!(maxSize >= 1)) {
4547
+ throw new RangeError(`EmbeddingCache maxSize must be at least 1. Received: ${String(maxSize)}.`);
4548
+ }
4549
+ this.maxSize = maxSize;
4550
+ }
4537
4551
  get(text2) {
4538
- return this.embeddings.get(text2);
4552
+ const node = this.map.get(text2);
4553
+ if (!node) return void 0;
4554
+ this.moveToHead(text2, node);
4555
+ return node.value;
4539
4556
  }
4540
4557
  set(text2, embedding) {
4541
- this.embeddings.set(text2, embedding);
4558
+ if (this.map.has(text2)) {
4559
+ const node2 = this.map.get(text2);
4560
+ node2.value = embedding;
4561
+ this.moveToHead(text2, node2);
4562
+ return;
4563
+ }
4564
+ if (this.map.size >= this.maxSize) {
4565
+ this.evictTail();
4566
+ }
4567
+ const node = { value: embedding, prev: null, next: this.head };
4568
+ this.map.set(text2, node);
4569
+ if (this.head !== null) {
4570
+ this.map.get(this.head).prev = text2;
4571
+ }
4572
+ this.head = text2;
4573
+ if (this.tail === null) {
4574
+ this.tail = text2;
4575
+ }
4576
+ }
4577
+ get size() {
4578
+ return this.map.size;
4579
+ }
4580
+ moveToHead(key, node) {
4581
+ if (this.head === key) return;
4582
+ if (node.prev !== null) {
4583
+ this.map.get(node.prev).next = node.next;
4584
+ }
4585
+ if (node.next !== null) {
4586
+ this.map.get(node.next).prev = node.prev;
4587
+ } else {
4588
+ this.tail = node.prev;
4589
+ }
4590
+ node.prev = null;
4591
+ node.next = this.head;
4592
+ if (this.head !== null) {
4593
+ this.map.get(this.head).prev = key;
4594
+ }
4595
+ this.head = key;
4596
+ }
4597
+ evictTail() {
4598
+ if (this.tail === null) return;
4599
+ const tailKey = this.tail;
4600
+ const tailNode = this.map.get(tailKey);
4601
+ this.tail = tailNode.prev;
4602
+ if (this.tail !== null) {
4603
+ this.map.get(this.tail).next = null;
4604
+ } else {
4605
+ this.head = null;
4606
+ }
4607
+ this.map.delete(tailKey);
4542
4608
  }
4543
4609
  };
4544
4610
 
@@ -15285,10 +15351,15 @@ function inferSubject(content) {
15285
15351
  if (!trimmed) {
15286
15352
  return "memory";
15287
15353
  }
15288
- const firstClause = trimmed.split(/[.!?]/)[0] ?? trimmed;
15289
- const words = firstClause.split(/\s+/).filter((word) => word.length > 0).slice(0, 6);
15290
- const candidate = words.join(" ");
15291
- return candidate.slice(0, 80) || "memory";
15354
+ const firstClause = trimmed.split(/[.!?:;]\s/)[0].trim();
15355
+ if (!firstClause) {
15356
+ return "memory";
15357
+ }
15358
+ if (firstClause.length <= 80) {
15359
+ return firstClause;
15360
+ }
15361
+ const cut = firstClause.lastIndexOf(" ", 80);
15362
+ return cut > 0 ? firstClause.slice(0, cut) : firstClause.slice(0, 80);
15292
15363
  }
15293
15364
  function parseStoreEntries(rawEntries) {
15294
15365
  if (!Array.isArray(rawEntries)) {
@@ -15753,7 +15824,7 @@ function createMcpServer(options = {}, deps = {}) {
15753
15824
  if (retired.count === 0) {
15754
15825
  throw new RpcError(JSON_RPC_INVALID_PARAMS, `No active entry found with id: ${entryId}`);
15755
15826
  }
15756
- const messageBase = `Retired: ${subject} (type: ${type}). Entry is hidden from session-start recall but can still be found with explicit queries.`;
15827
+ const messageBase = `Retired: ${subject} (type: ${type}). Entry is hidden from all recall (session-start and explicit queries).`;
15757
15828
  const text2 = persist ? `${messageBase} Retirement will survive database re-ingest.` : messageBase;
15758
15829
  return text2;
15759
15830
  }
@@ -18131,7 +18202,14 @@ function promptToEnterCredential(auth) {
18131
18202
  function modelChoicesForAuth(auth, provider) {
18132
18203
  const definition = getAuthMethodDefinition(auth);
18133
18204
  const allModels = getModels(provider).map((model) => model.id);
18134
- const preferred = definition.preferredModels.filter((modelId) => allModels.includes(modelId));
18205
+ const preferred = definition.preferredModels.filter((modelId) => {
18206
+ try {
18207
+ resolveModel(provider, modelId);
18208
+ return true;
18209
+ } catch {
18210
+ return false;
18211
+ }
18212
+ });
18135
18213
  const fallback = allModels.filter((modelId) => !preferred.includes(modelId));
18136
18214
  if (provider === "openai") {
18137
18215
  const prioritizedFallback = fallback.filter(
@@ -18194,9 +18272,9 @@ async function runSetup(env = process.env) {
18194
18272
  storedCredentials: working.credentials,
18195
18273
  env
18196
18274
  });
18275
+ const credentialKey = credentialKeyForAuth(auth);
18197
18276
  if (!probe.available) {
18198
18277
  clack11.log.warn(probe.guidance);
18199
- const credentialKey = credentialKeyForAuth(auth);
18200
18278
  if (credentialKey) {
18201
18279
  const shouldEnterNow = await clack11.confirm({
18202
18280
  message: "Enter the credential now?",
@@ -18225,6 +18303,36 @@ async function runSetup(env = process.env) {
18225
18303
  }
18226
18304
  }
18227
18305
  }
18306
+ } else if (existing && credentialKey) {
18307
+ const updateKey = await clack11.confirm({
18308
+ message: "Update stored credential?",
18309
+ initialValue: false
18310
+ });
18311
+ if (clack11.isCancel(updateKey)) {
18312
+ clack11.cancel("Setup cancelled.");
18313
+ return;
18314
+ }
18315
+ if (updateKey) {
18316
+ const entered = await clack11.password({
18317
+ message: promptToEnterCredential(auth)
18318
+ });
18319
+ if (clack11.isCancel(entered)) {
18320
+ clack11.cancel("Setup cancelled.");
18321
+ return;
18322
+ }
18323
+ const normalized = entered.trim();
18324
+ if (normalized) {
18325
+ working = setStoredCredential(working, credentialKey, normalized);
18326
+ probe = probeCredentials({
18327
+ auth,
18328
+ storedCredentials: working.credentials,
18329
+ env
18330
+ });
18331
+ clack11.log.info("Credential updated.");
18332
+ } else {
18333
+ clack11.log.warn("Credential not updated - empty input.");
18334
+ }
18335
+ }
18228
18336
  }
18229
18337
  const modelChoices = modelChoicesForAuth(auth, provider);
18230
18338
  if (modelChoices.length === 0) {
@@ -30,7 +30,7 @@ function buildSpawnArgs(agenrPath) {
30
30
  }
31
31
  return { cmd: agenrPath, args: [] };
32
32
  }
33
- async function runRecall(agenrPath, budget) {
33
+ async function runRecall(agenrPath, budget, project) {
34
34
  return await new Promise((resolve) => {
35
35
  let stdout = "";
36
36
  let settled = false;
@@ -42,11 +42,13 @@ async function runRecall(agenrPath, budget) {
42
42
  settled = true;
43
43
  resolve(value);
44
44
  }
45
- const child = spawn(
46
- spawnArgs.cmd,
47
- [...spawnArgs.args, "recall", "--context", "session-start", "--budget", String(budget), "--json"],
48
- { stdio: ["ignore", "pipe", "ignore"] }
49
- );
45
+ const args = ["recall", "--context", "session-start", "--budget", String(budget), "--json"];
46
+ if (project) {
47
+ args.push("--project", project);
48
+ }
49
+ const child = spawn(spawnArgs.cmd, [...spawnArgs.args, ...args], {
50
+ stdio: ["ignore", "pipe", "ignore"]
51
+ });
50
52
  const timer = setTimeout(() => {
51
53
  child.kill("SIGTERM");
52
54
  finish(null);
@@ -245,6 +247,9 @@ import { tmpdir } from "os";
245
247
  import { join } from "path";
246
248
  var TOOL_TIMEOUT_MS = 1e4;
247
249
  var EXTRACT_TIMEOUT_MS = 6e4;
250
+ var KNOWN_PLATFORMS = /* @__PURE__ */ new Set(["openclaw", "codex", "claude-code", "plaud"]);
251
+ var RECOMMENDED_SOURCE_PREFIXES = ["mcp:", "file:", "cli:", "session:", "conversation"];
252
+ var SOURCE_FORMAT_WARNING = "agenr_store: source_file does not follow recommended format (mcp:, file:, cli:, session:, conversation). Storing as-is.";
248
253
  function asString(value) {
249
254
  if (typeof value !== "string") {
250
255
  return void 0;
@@ -264,6 +269,54 @@ function asNumber(value) {
264
269
  }
265
270
  return void 0;
266
271
  }
272
+ function resolveWarn(pluginConfig) {
273
+ const logger = pluginConfig?.logger;
274
+ if (logger && typeof logger === "object") {
275
+ const warn = logger.warn;
276
+ if (typeof warn === "function") {
277
+ return (message) => {
278
+ warn(message);
279
+ };
280
+ }
281
+ }
282
+ return (message) => {
283
+ console.warn(message);
284
+ };
285
+ }
286
+ function sourceStringFromEntry(entry) {
287
+ if (typeof entry.source === "string") {
288
+ return entry.source;
289
+ }
290
+ if (entry.source && typeof entry.source === "object") {
291
+ const sourceFile = asString(entry.source.file);
292
+ if (sourceFile) {
293
+ return sourceFile;
294
+ }
295
+ }
296
+ return void 0;
297
+ }
298
+ function inferPlatformFromEntries(entries) {
299
+ for (const entry of entries) {
300
+ const source = sourceStringFromEntry(entry);
301
+ if (!source) {
302
+ continue;
303
+ }
304
+ const normalizedSource = source.toLowerCase();
305
+ if (normalizedSource.includes("codex")) {
306
+ return "codex";
307
+ }
308
+ if (normalizedSource.includes("claude")) {
309
+ return "claude-code";
310
+ }
311
+ if (normalizedSource.includes("openclaw")) {
312
+ return "openclaw";
313
+ }
314
+ if (normalizedSource.includes("plaud")) {
315
+ return "plaud";
316
+ }
317
+ }
318
+ return void 0;
319
+ }
267
320
  async function runAgenrCommand(agenrPath, args, stdinPayload, timeoutMs = TOOL_TIMEOUT_MS) {
268
321
  return await new Promise((resolve) => {
269
322
  const resolvedAgenrPath = agenrPath.trim() || resolveAgenrPath();
@@ -306,7 +359,7 @@ async function runAgenrCommand(agenrPath, args, stdinPayload, timeoutMs = TOOL_T
306
359
  child.stdin.end();
307
360
  });
308
361
  }
309
- async function runRecallTool(agenrPath, params) {
362
+ async function runRecallTool(agenrPath, params, defaultProject) {
310
363
  const args = ["recall", "--json"];
311
364
  const query = asString(params.query);
312
365
  const context = asString(params.context);
@@ -315,7 +368,7 @@ async function runRecallTool(agenrPath, params) {
315
368
  const since = asString(params.since);
316
369
  const until = asString(params.until);
317
370
  const platform = asString(params.platform);
318
- const project = asString(params.project);
371
+ const project = asString(params.project) || defaultProject;
319
372
  if (query) {
320
373
  args.push(query);
321
374
  }
@@ -377,10 +430,44 @@ async function runRecallTool(agenrPath, params) {
377
430
  };
378
431
  }
379
432
  }
380
- async function runStoreTool(agenrPath, params, pluginConfig) {
433
+ async function runStoreTool(agenrPath, params, pluginConfig, defaultProject) {
381
434
  const entries = Array.isArray(params.entries) ? params.entries : [];
382
- const platform = asString(params.platform);
383
- const project = asString(params.project);
435
+ const project = asString(params.project) || defaultProject;
436
+ const warn = resolveWarn(pluginConfig);
437
+ const processedEntries = entries.map((e) => {
438
+ const entry = e && typeof e === "object" ? e : {};
439
+ if (!entry.subject && typeof entry.content === "string") {
440
+ entry.subject = entry.content.slice(0, 60).replace(/[.!?:;]\s[\s\S]*$/, "").trim() || entry.content.slice(0, 40);
441
+ }
442
+ return entry;
443
+ });
444
+ const explicitPlatform = asString(params.platform);
445
+ const normalizedPlatform = explicitPlatform?.toLowerCase();
446
+ let platform;
447
+ if (explicitPlatform) {
448
+ if (normalizedPlatform && KNOWN_PLATFORMS.has(normalizedPlatform)) {
449
+ platform = normalizedPlatform;
450
+ } else {
451
+ warn(
452
+ `agenr_store: invalid platform "${explicitPlatform}". Expected one of: openclaw, codex, claude-code, plaud. Omitting --platform.`
453
+ );
454
+ }
455
+ } else {
456
+ platform = inferPlatformFromEntries(processedEntries);
457
+ }
458
+ for (const entry of processedEntries) {
459
+ if (typeof entry.source !== "string") {
460
+ continue;
461
+ }
462
+ const normalizedSource = entry.source.toLowerCase();
463
+ const hasKnownPrefix = RECOMMENDED_SOURCE_PREFIXES.some(
464
+ (prefix) => normalizedSource.startsWith(prefix)
465
+ );
466
+ if (!hasKnownPrefix) {
467
+ warn(SOURCE_FORMAT_WARNING);
468
+ break;
469
+ }
470
+ }
384
471
  const storeArgs = ["store"];
385
472
  if (platform) {
386
473
  storeArgs.push("--platform", platform);
@@ -388,13 +475,6 @@ async function runStoreTool(agenrPath, params, pluginConfig) {
388
475
  if (project) {
389
476
  storeArgs.push("--project", project);
390
477
  }
391
- const processedEntries = entries.map((e) => {
392
- const entry = e && typeof e === "object" ? e : {};
393
- if (!entry.subject && typeof entry.content === "string") {
394
- entry.subject = entry.content.slice(0, 60).replace(/[.!?][\s\S]*$/, "").trim() || entry.content.slice(0, 40);
395
- }
396
- return entry;
397
- });
398
478
  const dedupConfig = pluginConfig?.dedup;
399
479
  if (dedupConfig?.aggressive === true) {
400
480
  storeArgs.push("--aggressive");
@@ -654,7 +734,8 @@ var plugin = {
654
734
  }
655
735
  const agenrPath = resolveAgenrPath(config);
656
736
  const budget = resolveBudget(config);
657
- const recallResult = await runRecall(agenrPath, budget);
737
+ const project = config?.project?.trim() || void 0;
738
+ const recallResult = await runRecall(agenrPath, budget, project);
658
739
  if (recallResult) {
659
740
  const formatted = formatRecallAsMarkdown(recallResult);
660
741
  if (formatted.trim()) {
@@ -731,7 +812,8 @@ var plugin = {
731
812
  return makeDisabledToolResult();
732
813
  }
733
814
  const agenrPath = resolveAgenrPath(runtimeConfig);
734
- return runRecallTool(agenrPath, params);
815
+ const defaultProject = runtimeConfig?.project?.trim() || void 0;
816
+ return runRecallTool(agenrPath, params, defaultProject);
735
817
  }
736
818
  }
737
819
  );
@@ -744,6 +826,11 @@ var plugin = {
744
826
  entries: Type.Array(
745
827
  Type.Object({
746
828
  content: Type.String({ description: "What to remember." }),
829
+ subject: Type.Optional(
830
+ Type.String({
831
+ description: "Short subject label. Inferred from content if omitted."
832
+ })
833
+ ),
747
834
  type: Type.Unsafe({
748
835
  type: "string",
749
836
  enum: [...KNOWLEDGE_TYPES],
@@ -780,7 +867,17 @@ var plugin = {
780
867
  return makeDisabledToolResult();
781
868
  }
782
869
  const agenrPath = resolveAgenrPath(runtimeConfig);
783
- return runStoreTool(agenrPath, params, runtimeConfig);
870
+ const defaultProject = runtimeConfig?.project?.trim() || void 0;
871
+ const toolConfig = {
872
+ ...runtimeConfig,
873
+ logger: api.logger
874
+ };
875
+ return runStoreTool(
876
+ agenrPath,
877
+ params,
878
+ toolConfig,
879
+ defaultProject
880
+ );
784
881
  }
785
882
  }
786
883
  );
@@ -2,7 +2,6 @@
2
2
  "id": "agenr",
3
3
  "name": "agenr Memory",
4
4
  "description": "Local memory layer - injects agenr context at session start",
5
- "version": "0.8.2",
6
5
  "skills": [
7
6
  "skills"
8
7
  ],
@@ -18,6 +17,10 @@
18
17
  "type": "number",
19
18
  "description": "Token budget for session-start recall. Default: 2000."
20
19
  },
20
+ "project": {
21
+ "type": "string",
22
+ "description": "Project scope for recall and store. Omit for global (default)."
23
+ },
21
24
  "enabled": {
22
25
  "type": "boolean",
23
26
  "description": "Set false to disable memory injection without uninstalling."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenr",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "openclaw": {
5
5
  "extensions": [
6
6
  "dist/openclaw-plugin/index.js"
@@ -11,13 +11,6 @@
11
11
  "bin": {
12
12
  "agenr": "dist/cli.js"
13
13
  },
14
- "scripts": {
15
- "build": "tsup src/cli.ts src/cli-main.ts src/openclaw-plugin/index.ts --format esm --dts",
16
- "dev": "tsup src/cli.ts src/cli-main.ts --format esm --watch",
17
- "test": "vitest run",
18
- "test:watch": "vitest",
19
- "typecheck": "tsc --noEmit"
20
- },
21
14
  "dependencies": {
22
15
  "@clack/prompts": "^1.0.1",
23
16
  "@libsql/client": "^0.17.0",
@@ -61,9 +54,11 @@
61
54
  "README.md"
62
55
  ],
63
56
  "author": "agenr-ai",
64
- "pnpm": {
65
- "overrides": {
66
- "fast-xml-parser": "^5.3.6"
67
- }
57
+ "scripts": {
58
+ "build": "tsup src/cli.ts src/cli-main.ts src/openclaw-plugin/index.ts --format esm --dts",
59
+ "dev": "tsup src/cli.ts src/cli-main.ts --format esm --watch",
60
+ "test": "vitest run",
61
+ "test:watch": "vitest",
62
+ "typecheck": "tsc --noEmit"
68
63
  }
69
- }
64
+ }