agenr 0.9.79 → 0.9.81

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,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.81] - 2026-03-08
4
+
5
+ ### Added
6
+
7
+ - Added in-place entry metadata updates for memory hygiene, starting with `importance`, via the new `agenr update --id <id> --importance <n>` CLI command.
8
+ - Added the `agenr_update` MCP tool and native OpenClaw plugin tool so agents can demote stale-but-still-true entries without retiring them.
9
+ - Added focused coverage for CLI and MCP update flows plus OpenClaw plugin tool wiring.
10
+
11
+ ### Fixed
12
+
13
+ - Added startup-only `SQLITE_BUSY` retry/backoff for OpenClaw session-start browse and memory-index reads, reducing transient lock-induced degradation immediately after handoff recovery.
14
+ - Session-start browse now logs explicit retry and unavailable states instead of collapsing lock failures into the ordinary `browse returned 0 entries` path.
15
+ - Preserved existing startup fail-open rendering behavior by continuing to omit unavailable browse or memory-index sections while still completing session-start with the remaining recovered context.
16
+ - Added focused regression coverage for strict startup browse execution, compatibility preservation in `runRecall()`, and session-start retry/degradation logging for browse and memory-index lock contention.
17
+
3
18
  ## [0.9.79] - 2026-03-08
4
19
 
5
20
  ### Fixed
package/README.md CHANGED
@@ -56,7 +56,7 @@ export OPENAI_API_KEY=sk-... # for embeddings + extraction
56
56
 
57
57
  ### OpenClaw (recommended)
58
58
 
59
- `agenr init` auto-detects OpenClaw, installs the native plugin, and restarts the gateway. The plugin handles everything automatically: session-start context injection (recent turns, core recall, browse recall, and a memory index), mid-session signals when important entries arrive, cross-session handoff summaries, and native `agenr_recall`, `agenr_store`, `agenr_extract`, `agenr_retire`, and session-project tools.
59
+ `agenr init` auto-detects OpenClaw, installs the native plugin, and restarts the gateway. The plugin handles everything automatically: session-start context injection (recent turns, core recall, browse recall, and a memory index), mid-session signals when important entries arrive, cross-session handoff summaries, and native `agenr_recall`, `agenr_store`, `agenr_extract`, `agenr_retire`, `agenr_update`, and session-project tools.
60
60
 
61
61
  No AGENTS.md edits needed. No MCP config needed. The bundled SKILL.md loads automatically and instructs the agent when to call `agenr_store` proactively.
62
62
 
@@ -127,7 +127,7 @@ Adds instructions to `~/.codeium/windsurf/memories/global_rules.md` and wires `.
127
127
  agenr init # auto-detects platform, falls back to generic AGENTS.md
128
128
  ```
129
129
 
130
- Or start `agenr mcp` as a stdio MCP server and configure it in your tool's MCP settings manually. Your agent gets `agenr_recall`, `agenr_store`, `agenr_extract`, and `agenr_retire` as tools.
130
+ Or start `agenr mcp` as a stdio MCP server and configure it in your tool's MCP settings manually. Your agent gets `agenr_recall`, `agenr_store`, `agenr_extract`, `agenr_retire`, and `agenr_update` as tools.
131
131
 
132
132
  ## How Memory Works
133
133
 
@@ -236,7 +236,7 @@ If you prefer manual MCP setup over `agenr init`, start the stdio server:
236
236
  agenr mcp
237
237
  ```
238
238
 
239
- This exposes four tools: `agenr_recall`, `agenr_store`, `agenr_extract`, `agenr_retire`. Configure it in your tool's MCP settings as a stdio server.
239
+ This exposes five tools: `agenr_recall`, `agenr_store`, `agenr_extract`, `agenr_retire`, `agenr_update`. Configure it in your tool's MCP settings as a stdio server.
240
240
 
241
241
  ## Commands
242
242
 
@@ -252,6 +252,7 @@ This exposes four tools: `agenr_recall`, `agenr_store`, `agenr_extract`, `agenr_
252
252
  | `agenr store [files...]` | Store entries with semantic dedup |
253
253
  | `agenr recall [query]` | Semantic + memory-aware recall. Use `--since`/`--until` for date ranges, `--around` for target-date ranking, `--browse` for temporal mode. |
254
254
  | `agenr retire [subject]` | Retire a stale entry (hidden, not deleted). Match by subject or `--id`. |
255
+ | `agenr update --id <id> --importance <n>` | Update an entry in place. Currently supports importance only. |
255
256
  | `agenr watch [file]` | Live-watch files/directories, auto-extract knowledge |
256
257
  | `agenr watcher install` | Install background watch daemon (macOS launchd) |
257
258
  | `agenr watcher status` | Show daemon status (running/stopped, pid, watched file, recent logs) |
@@ -6289,6 +6289,112 @@ async function executeRetire(request, deps) {
6289
6289
  }
6290
6290
  }
6291
6291
 
6292
+ // src/app/update-service.ts
6293
+ function validateEntryId(id) {
6294
+ const entryId = id?.trim() ?? "";
6295
+ if (!entryId) {
6296
+ throw new Error("id is required");
6297
+ }
6298
+ return entryId;
6299
+ }
6300
+ function normalizeImportance(value) {
6301
+ const parsed = typeof value === "number" ? value : Number(value);
6302
+ if (!Number.isInteger(parsed) || parsed < IMPORTANCE_MIN || parsed > IMPORTANCE_MAX) {
6303
+ throw new Error(`importance must be an integer between ${IMPORTANCE_MIN} and ${IMPORTANCE_MAX}`);
6304
+ }
6305
+ return parsed;
6306
+ }
6307
+ async function queryById2(db, id) {
6308
+ const result = await db.execute({
6309
+ sql: `
6310
+ SELECT id, type, subject, importance, content
6311
+ FROM entries
6312
+ WHERE retired = 0 AND id = ?
6313
+ LIMIT 1
6314
+ `,
6315
+ args: [id]
6316
+ });
6317
+ const row = result.rows[0];
6318
+ if (!row) {
6319
+ return null;
6320
+ }
6321
+ return {
6322
+ id: toStringValue(row.id),
6323
+ type: toStringValue(row.type),
6324
+ subject: toStringValue(row.subject),
6325
+ importance: toNumber(row.importance),
6326
+ content: toStringValue(row.content)
6327
+ };
6328
+ }
6329
+ async function lookupUpdateCandidate(request, deps) {
6330
+ const resolvedDeps = {
6331
+ readConfigFn: deps?.readConfigFn ?? readConfig,
6332
+ getDbFn: deps?.getDbFn ?? getDb,
6333
+ initDbFn: deps?.initDbFn ?? initDb,
6334
+ closeDbFn: deps?.closeDbFn ?? closeDb
6335
+ };
6336
+ const runtimeEnv = request.env ?? process.env;
6337
+ const id = validateEntryId(request.id);
6338
+ const config = resolvedDeps.readConfigFn(runtimeEnv);
6339
+ const db = resolvedDeps.getDbFn(request.dbPath?.trim() || config?.db?.path);
6340
+ try {
6341
+ await resolvedDeps.initDbFn(db);
6342
+ return { candidate: await queryById2(db, id) };
6343
+ } finally {
6344
+ resolvedDeps.closeDbFn(db);
6345
+ }
6346
+ }
6347
+ async function executeUpdate(request, deps) {
6348
+ const resolvedDeps = {
6349
+ readConfigFn: deps?.readConfigFn ?? readConfig,
6350
+ getDbFn: deps?.getDbFn ?? getDb,
6351
+ initDbFn: deps?.initDbFn ?? initDb,
6352
+ closeDbFn: deps?.closeDbFn ?? closeDb
6353
+ };
6354
+ const runtimeEnv = request.env ?? process.env;
6355
+ const id = validateEntryId(request.id);
6356
+ const importance = normalizeImportance(request.importance);
6357
+ const config = resolvedDeps.readConfigFn(runtimeEnv);
6358
+ const db = resolvedDeps.getDbFn(request.dbPath?.trim() || config?.db?.path);
6359
+ try {
6360
+ await resolvedDeps.initDbFn(db);
6361
+ const existing = await queryById2(db, id);
6362
+ if (!existing) {
6363
+ return { id, previousImportance: importance, importance, updated: false };
6364
+ }
6365
+ if (existing.importance === importance) {
6366
+ return { id, previousImportance: existing.importance, importance, updated: true };
6367
+ }
6368
+ const now = (/* @__PURE__ */ new Date()).toISOString();
6369
+ const result = await db.execute({
6370
+ sql: `
6371
+ UPDATE entries
6372
+ SET importance = ?,
6373
+ updated_at = ?
6374
+ WHERE id = ?
6375
+ AND retired = 0
6376
+ `,
6377
+ args: [importance, now, id]
6378
+ });
6379
+ if (toRowsAffected(result.rowsAffected) === 0) {
6380
+ return {
6381
+ id,
6382
+ previousImportance: existing.importance,
6383
+ importance: existing.importance,
6384
+ updated: false
6385
+ };
6386
+ }
6387
+ return {
6388
+ id,
6389
+ previousImportance: existing.importance,
6390
+ importance,
6391
+ updated: true
6392
+ };
6393
+ } finally {
6394
+ resolvedDeps.closeDbFn(db);
6395
+ }
6396
+ }
6397
+
6292
6398
  // src/app/store-service.ts
6293
6399
  var KNOWLEDGE_TYPE_SET = new Set(KNOWLEDGE_TYPES);
6294
6400
  var EXPIRY_LEVEL_SET = new Set(EXPIRY_LEVELS);
@@ -6325,7 +6431,7 @@ function normalizeCanonicalKey(value) {
6325
6431
  }
6326
6432
  return normalized;
6327
6433
  }
6328
- function normalizeImportance(value) {
6434
+ function normalizeImportance2(value) {
6329
6435
  const importanceRaw = typeof value === "number" ? value : Number(value);
6330
6436
  return Number.isInteger(importanceRaw) && importanceRaw >= IMPORTANCE_MIN && importanceRaw <= IMPORTANCE_MAX ? importanceRaw : 5;
6331
6437
  }
@@ -6358,7 +6464,7 @@ function normalizeStoreJsonEntry(raw, fallbackFile) {
6358
6464
  subject,
6359
6465
  canonical_key: normalizeCanonicalKey(record.canonical_key),
6360
6466
  content,
6361
- importance: normalizeImportance(record.importance),
6467
+ importance: normalizeImportance2(record.importance),
6362
6468
  expiry: normalizeExpiry(record.expiry),
6363
6469
  tags: normalizeTags(record.tags),
6364
6470
  created_at: normalizeCreatedAt(record.created_at),
@@ -6485,7 +6591,7 @@ function normalizeStoreToolPayload(params, fallbackSourceFile, warn = () => void
6485
6591
  type,
6486
6592
  subject,
6487
6593
  content,
6488
- importance: normalizeImportance(entry.importance),
6594
+ importance: normalizeImportance2(entry.importance),
6489
6595
  expiry: normalizedExpiry,
6490
6596
  tags: normalizeTags(entry.tags),
6491
6597
  source: {
@@ -6702,6 +6808,8 @@ export {
6702
6808
  recallSectionOrder,
6703
6809
  lookupRetireCandidates,
6704
6810
  executeRetire,
6811
+ lookupUpdateCandidate,
6812
+ executeUpdate,
6705
6813
  parseStoreJsonInput,
6706
6814
  normalizeStoreToolPayload,
6707
6815
  buildVirtualStoreBatch,
package/dist/cli-main.js CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  deduplicateEntries,
9
9
  ensurePluginDbTables,
10
10
  executeRetire,
11
+ executeUpdate,
11
12
  expandInputFiles,
12
13
  extractKnowledgeFromChunks,
13
14
  extractTextEntries,
@@ -27,6 +28,7 @@ import {
27
28
  getPendingReviews,
28
29
  isProjectWorthyOpenClawStoreEntry,
29
30
  lookupRetireCandidates,
31
+ lookupUpdateCandidate,
30
32
  normalizeKnowledgePlatform,
31
33
  parseStoreJsonInput,
32
34
  parseTranscriptFile,
@@ -39,7 +41,7 @@ import {
39
41
  runStoreService,
40
42
  runTraceService,
41
43
  ui
42
- } from "./chunk-JJZHOS4U.js";
44
+ } from "./chunk-CEPFOYOL.js";
43
45
  import {
44
46
  ConflictAlreadyResolvedError,
45
47
  REVIEW_QUEUE_PATH,
@@ -64,6 +66,8 @@ import {
64
66
  ENTRY_SELECT_COLUMNS_WITH_EMBEDDING,
65
67
  EXPIRY_LEVELS,
66
68
  EmbeddingCache,
69
+ IMPORTANCE_MAX,
70
+ IMPORTANCE_MIN,
67
71
  KNOWLEDGE_PLATFORMS,
68
72
  KNOWLEDGE_TYPES,
69
73
  SCOPE_LEVELS,
@@ -170,7 +174,7 @@ import {
170
174
  } from "./chunk-UGIJJOPV.js";
171
175
 
172
176
  // src/cli-main.ts
173
- import * as clack18 from "@clack/prompts";
177
+ import * as clack19 from "@clack/prompts";
174
178
  import { Command } from "commander";
175
179
 
176
180
  // src/auth-status.ts
@@ -6066,10 +6070,10 @@ function renderTextReport(stats, dryRun) {
6066
6070
  function createLogger2(jsonMode) {
6067
6071
  const useClack = process.stderr.isTTY && !jsonMode;
6068
6072
  if (!useClack) {
6069
- const log22 = createLogger("consolidate-cmd");
6073
+ const log23 = createLogger("consolidate-cmd");
6070
6074
  return {
6071
- info: (message) => log22.info(message),
6072
- warn: (message) => log22.warn(message)
6075
+ info: (message) => log23.info(message),
6076
+ warn: (message) => log23.warn(message)
6073
6077
  };
6074
6078
  }
6075
6079
  const clackOutput = { output: process.stderr };
@@ -14010,6 +14014,27 @@ var TOOL_DEFINITIONS = [
14010
14014
  }
14011
14015
  }
14012
14016
  }
14017
+ },
14018
+ {
14019
+ name: "agenr_update",
14020
+ description: "Update an existing memory entry in place. Currently supports importance only.",
14021
+ inputSchema: {
14022
+ type: "object",
14023
+ additionalProperties: false,
14024
+ required: ["entry_id", "importance"],
14025
+ properties: {
14026
+ entry_id: {
14027
+ type: "string",
14028
+ description: "Entry id to update."
14029
+ },
14030
+ importance: {
14031
+ type: "integer",
14032
+ description: "New importance score.",
14033
+ minimum: 1,
14034
+ maximum: 10
14035
+ }
14036
+ }
14037
+ }
14013
14038
  }
14014
14039
  ];
14015
14040
  function hasOwn(record, key) {
@@ -14259,12 +14284,12 @@ function createMcpServer(options = {}, deps = {}) {
14259
14284
  let dbInitPromise = null;
14260
14285
  let isStopped = false;
14261
14286
  let lineReader = null;
14262
- function log22(line) {
14287
+ function log23(line) {
14263
14288
  errorOutput.write(`${line}
14264
14289
  `);
14265
14290
  }
14266
14291
  if (!scopedProjectDir) {
14267
- log22("warn: AGENR_PROJECT_DIR not set -- recall will return global (unscoped) results. Run agenr init to configure project scoping.");
14292
+ log23("warn: AGENR_PROJECT_DIR not set -- recall will return global (unscoped) results. Run agenr init to configure project scoping.");
14268
14293
  }
14269
14294
  async function ensureDb() {
14270
14295
  if (!dbClient) {
@@ -14513,6 +14538,41 @@ function createMcpServer(options = {}, deps = {}) {
14513
14538
  const text4 = persist ? `${messageBase} Retirement will survive database re-ingest.` : messageBase;
14514
14539
  return text4;
14515
14540
  }
14541
+ async function callUpdateTool(args) {
14542
+ const entryId = typeof args.entry_id === "string" ? args.entry_id.trim() : "";
14543
+ if (!entryId) {
14544
+ throw new RpcError(JSON_RPC_INVALID_PARAMS, "entry_id is required");
14545
+ }
14546
+ const rawImportance = typeof args.importance === "number" ? args.importance : Number(args.importance);
14547
+ if (!Number.isInteger(rawImportance) || rawImportance < 1 || rawImportance > 10) {
14548
+ throw new RpcError(JSON_RPC_INVALID_PARAMS, "importance must be an integer between 1 and 10");
14549
+ }
14550
+ const db = await ensureDb();
14551
+ const updateDeps = {
14552
+ readConfigFn: resolvedDeps.readConfigFn,
14553
+ getDbFn: () => db,
14554
+ initDbFn: async () => void 0,
14555
+ closeDbFn: () => void 0
14556
+ };
14557
+ const lookup = await lookupUpdateCandidate({
14558
+ id: entryId,
14559
+ dbPath: options.dbPath,
14560
+ env
14561
+ }, updateDeps);
14562
+ if (!lookup.candidate) {
14563
+ throw new RpcError(JSON_RPC_INVALID_PARAMS, `No active entry found with id: ${entryId}`);
14564
+ }
14565
+ const updated = await executeUpdate({
14566
+ id: entryId,
14567
+ importance: rawImportance,
14568
+ dbPath: options.dbPath,
14569
+ env
14570
+ }, updateDeps);
14571
+ if (!updated.updated) {
14572
+ return `Not updated: ${lookup.candidate.subject} (type: ${lookup.candidate.type}) is no longer active.`;
14573
+ }
14574
+ return updated.previousImportance === updated.importance ? `Entry ${entryId} already has importance ${updated.importance}.` : `Updated: ${lookup.candidate.subject} (type: ${lookup.candidate.type}) importance ${updated.previousImportance} -> ${updated.importance}.`;
14575
+ }
14516
14576
  async function dispatchToolCall(params) {
14517
14577
  try {
14518
14578
  if (params.name === "agenr_recall") {
@@ -14537,6 +14597,11 @@ function createMcpServer(options = {}, deps = {}) {
14537
14597
  content: [{ type: "text", text: await callRetireTool(params.args) }]
14538
14598
  };
14539
14599
  }
14600
+ if (params.name === "agenr_update") {
14601
+ return {
14602
+ content: [{ type: "text", text: await callUpdateTool(params.args) }]
14603
+ };
14604
+ }
14540
14605
  throw new RpcError(JSON_RPC_INVALID_PARAMS, `Unknown tool: ${params.name}`);
14541
14606
  } catch (error) {
14542
14607
  if (error instanceof RpcError) {
@@ -14588,9 +14653,9 @@ function createMcpServer(options = {}, deps = {}) {
14588
14653
  const startupConfig = await resolvedDeps.readConfigFn();
14589
14654
  resolvedDeps.resolveEmbeddingApiKeyFn(startupConfig, env);
14590
14655
  } catch {
14591
- log22("[mcp] ERROR: OPENAI_API_KEY is required for embeddings but was not found.");
14592
- log22("[mcp] Set it via environment variable or run: agenr setup");
14593
- log22("[mcp] If using MCP, add it to your MCP server config env block.");
14656
+ log23("[mcp] ERROR: OPENAI_API_KEY is required for embeddings but was not found.");
14657
+ log23("[mcp] Set it via environment variable or run: agenr setup");
14658
+ log23("[mcp] If using MCP, add it to your MCP server config env block.");
14594
14659
  process.exitCode = 1;
14595
14660
  return;
14596
14661
  }
@@ -14611,7 +14676,7 @@ function createMcpServer(options = {}, deps = {}) {
14611
14676
  continue;
14612
14677
  }
14613
14678
  if (verbose) {
14614
- log22(`[mcp] <= ${trimmed}`);
14679
+ log23(`[mcp] <= ${trimmed}`);
14615
14680
  }
14616
14681
  let parsedJson;
14617
14682
  try {
@@ -14620,7 +14685,7 @@ function createMcpServer(options = {}, deps = {}) {
14620
14685
  const parseError = makeErrorResponse(null, JSON_RPC_PARSE_ERROR, "Parse error");
14621
14686
  await writeLine(output, parseError);
14622
14687
  if (verbose) {
14623
- log22(`[mcp] => ${JSON.stringify(parseError)}`);
14688
+ log23(`[mcp] => ${JSON.stringify(parseError)}`);
14624
14689
  }
14625
14690
  continue;
14626
14691
  }
@@ -14632,13 +14697,13 @@ function createMcpServer(options = {}, deps = {}) {
14632
14697
  }
14633
14698
  await writeLine(output, response);
14634
14699
  if (verbose) {
14635
- log22(`[mcp] => ${JSON.stringify(response)}`);
14700
+ log23(`[mcp] => ${JSON.stringify(response)}`);
14636
14701
  }
14637
14702
  } catch (error) {
14638
14703
  const normalized = error instanceof RpcError ? makeErrorResponse(idForError, error.code, error.message) : makeErrorResponse(idForError, JSON_RPC_INTERNAL_ERROR, "Internal error");
14639
14704
  await writeLine(output, normalized);
14640
14705
  if (verbose) {
14641
- log22(`[mcp] => ${JSON.stringify(normalized)}`);
14706
+ log23(`[mcp] => ${JSON.stringify(normalized)}`);
14642
14707
  }
14643
14708
  }
14644
14709
  }
@@ -15767,11 +15832,83 @@ function registerTraceCommand(program) {
15767
15832
  );
15768
15833
  }
15769
15834
 
15835
+ // src/commands/update.ts
15836
+ import * as clack17 from "@clack/prompts";
15837
+ async function runUpdateCommand(options) {
15838
+ const entryId = options.id?.trim() ?? "";
15839
+ if (!entryId) {
15840
+ throw new Error("id is required");
15841
+ }
15842
+ const importance = options.importance;
15843
+ if (!Number.isInteger(importance) || importance < IMPORTANCE_MIN || importance > IMPORTANCE_MAX) {
15844
+ throw new Error(`importance must be an integer between ${IMPORTANCE_MIN} and ${IMPORTANCE_MAX}`);
15845
+ }
15846
+ const clackOutput = { output: process.stderr };
15847
+ clack17.intro(banner(), clackOutput);
15848
+ const lookup = await lookupUpdateCandidate({
15849
+ id: entryId,
15850
+ dbPath: options.db
15851
+ });
15852
+ if (!lookup.candidate) {
15853
+ clack17.log.warn(`No active entry found with id: ${entryId}`, clackOutput);
15854
+ clack17.outro(void 0, clackOutput);
15855
+ return { exitCode: 1 };
15856
+ }
15857
+ const candidate = lookup.candidate;
15858
+ clack17.log.info(
15859
+ `Entry: ${candidate.type} (importance: ${candidate.importance}) "${candidate.subject}"`,
15860
+ clackOutput
15861
+ );
15862
+ if (options.force !== true) {
15863
+ const confirmed = await clack17.confirm({
15864
+ message: `Update importance from ${candidate.importance} to ${importance}?`
15865
+ });
15866
+ if (confirmed !== true) {
15867
+ clack17.log.warn("Update canceled.", clackOutput);
15868
+ clack17.outro(void 0, clackOutput);
15869
+ return { exitCode: 1 };
15870
+ }
15871
+ }
15872
+ const updated = await executeUpdate({
15873
+ id: entryId,
15874
+ importance,
15875
+ dbPath: options.db
15876
+ });
15877
+ if (!updated.updated) {
15878
+ clack17.log.warn(`No active entry found with id: ${entryId}`, clackOutput);
15879
+ clack17.outro(void 0, clackOutput);
15880
+ return { exitCode: 1 };
15881
+ }
15882
+ if (updated.previousImportance === updated.importance) {
15883
+ clack17.log.success(`Entry ${entryId} already has importance ${updated.importance}.`, clackOutput);
15884
+ } else {
15885
+ clack17.log.success(
15886
+ `Updated entry ${entryId} importance: ${updated.previousImportance} -> ${updated.importance}.`,
15887
+ clackOutput
15888
+ );
15889
+ }
15890
+ clack17.outro(void 0, clackOutput);
15891
+ return { exitCode: 0 };
15892
+ }
15893
+
15894
+ // src/cli/update.ts
15895
+ function registerUpdateCommand(program) {
15896
+ program.command("update").description("Update mutable entry metadata in place").requiredOption("--id <id>", "Update a specific entry by its ID").requiredOption("--importance <n>", "New importance: 1-10").option("--force", "Skip confirmation prompt").option("--db <path>", "Path to database file").action(async (opts) => {
15897
+ const result = await runUpdateCommand({
15898
+ id: opts.id,
15899
+ importance: Number(opts.importance),
15900
+ force: opts.force === true,
15901
+ db: opts.db
15902
+ });
15903
+ process.exitCode = result.exitCode;
15904
+ });
15905
+ }
15906
+
15770
15907
  // src/commands/watch.ts
15771
15908
  import fs26 from "fs/promises";
15772
15909
  import os12 from "os";
15773
15910
  import path25 from "path";
15774
- import * as clack17 from "@clack/prompts";
15911
+ import * as clack18 from "@clack/prompts";
15775
15912
 
15776
15913
  // src/watch/watcher.ts
15777
15914
  import { watch as watchFs } from "fs";
@@ -16425,7 +16562,7 @@ async function runWatcher(options, deps) {
16425
16562
  }
16426
16563
 
16427
16564
  // src/commands/watch.ts
16428
- var log20 = createLogger("watch");
16565
+ var log21 = createLogger("watch");
16429
16566
  function formatBytes2(value) {
16430
16567
  return value.toLocaleString("en-US");
16431
16568
  }
@@ -16697,11 +16834,11 @@ async function runWatchCommand(file, options, deps) {
16697
16834
  const clackOutput = { output: process.stderr };
16698
16835
  warnIfLocked();
16699
16836
  installSignalHandlers();
16700
- clack17.intro(banner(), clackOutput);
16837
+ clack18.intro(banner(), clackOutput);
16701
16838
  try {
16702
16839
  await resolvedDeps.writeWatcherPidFn();
16703
16840
  } catch (error) {
16704
- clack17.log.error(
16841
+ clack18.log.error(
16705
16842
  formatError(`Failed to write watcher PID file: ${toErrorMessage(error)}`),
16706
16843
  clackOutput
16707
16844
  );
@@ -16736,7 +16873,7 @@ async function runWatchCommand(file, options, deps) {
16736
16873
  return { version: 1, files: {} };
16737
16874
  });
16738
16875
  if (stateWarning) {
16739
- clack17.log.warn(formatWarn(stateWarning), clackOutput);
16876
+ clack18.log.warn(formatWarn(stateWarning), clackOutput);
16740
16877
  await resolvedDeps.saveWatchStateFn(state);
16741
16878
  }
16742
16879
  const fileState = modeConfig.filePath ? getFileState(state, modeConfig.filePath) : void 0;
@@ -16744,11 +16881,11 @@ async function runWatchCommand(file, options, deps) {
16744
16881
  const config = resolvedDeps.readConfigFn(process.env);
16745
16882
  const dbPath = options.db?.trim() || config?.db?.path || "~/.agenr/knowledge.db";
16746
16883
  if (modeConfig.mode === "file") {
16747
- clack17.log.info(formatLabel("Watching", modeConfig.filePath ?? "(unknown)"), clackOutput);
16884
+ clack18.log.info(formatLabel("Watching", modeConfig.filePath ?? "(unknown)"), clackOutput);
16748
16885
  } else if (modeConfig.mode === "dir") {
16749
- clack17.log.info(formatLabel("Watching directory", modeConfig.sessionsDir ?? "(unknown)"), clackOutput);
16750
- clack17.log.info(formatLabel("Platform", modeConfig.platform ?? "mtime"), clackOutput);
16751
- clack17.log.info(
16886
+ clack18.log.info(formatLabel("Watching directory", modeConfig.sessionsDir ?? "(unknown)"), clackOutput);
16887
+ clack18.log.info(formatLabel("Platform", modeConfig.platform ?? "mtime"), clackOutput);
16888
+ clack18.log.info(
16752
16889
  formatLabel(
16753
16890
  "Active file",
16754
16891
  modeConfig.filePath ? formatSwitchLabel(modeConfig.filePath) : "(waiting for session file)"
@@ -16756,22 +16893,22 @@ async function runWatchCommand(file, options, deps) {
16756
16893
  clackOutput
16757
16894
  );
16758
16895
  }
16759
- clack17.log.info(
16896
+ clack18.log.info(
16760
16897
  `${formatLabel("Interval", formatInterval(intervalMs))} | ${formatLabel("Min chunk", `${minChunkChars} chars`)}`,
16761
16898
  clackOutput
16762
16899
  );
16763
- clack17.log.info(
16900
+ clack18.log.info(
16764
16901
  `${formatLabel("Offset", `${formatBytes2(offset)} bytes (${fileState ? "resume" : "fresh"})`)} | ${formatLabel("DB", dbPath)}`,
16765
16902
  clackOutput
16766
16903
  );
16767
- clack17.log.info("", clackOutput);
16768
- clack17.log.info("Waiting for changes...", clackOutput);
16904
+ clack18.log.info("", clackOutput);
16905
+ clack18.log.info("Waiting for changes...", clackOutput);
16769
16906
  const emitWatchWarning = (message) => {
16770
16907
  if (message.startsWith("Filtered:")) {
16771
- clack17.log.info(message, clackOutput);
16908
+ clack18.log.info(message, clackOutput);
16772
16909
  return;
16773
16910
  }
16774
- clack17.log.warn(formatWarn(message), clackOutput);
16911
+ clack18.log.warn(formatWarn(message), clackOutput);
16775
16912
  };
16776
16913
  let cycleCount = 0;
16777
16914
  let contextChain = Promise.resolve();
@@ -16799,7 +16936,7 @@ async function runWatchCommand(file, options, deps) {
16799
16936
  onSwitch: (from, to, platform) => {
16800
16937
  const fromLabel = from ? formatSwitchLabel(from) : "(none)";
16801
16938
  const platformLabel = platform ? ` [${platform}]` : "";
16802
- clack17.log.info(`Switched watch file${platformLabel}: ${fromLabel} -> ${formatSwitchLabel(to)}`, clackOutput);
16939
+ clack18.log.info(`Switched watch file${platformLabel}: ${fromLabel} -> ${formatSwitchLabel(to)}`, clackOutput);
16803
16940
  },
16804
16941
  onCycle: (result, ctx) => {
16805
16942
  cycleCount += 1;
@@ -16811,29 +16948,29 @@ async function runWatchCommand(file, options, deps) {
16811
16948
  `);
16812
16949
  }
16813
16950
  if (result.error) {
16814
- clack17.log.warn(formatWarn(`[${timestamp}] Cycle ${cycleCount}: ${result.error}${fileLabel}`), clackOutput);
16951
+ clack18.log.warn(formatWarn(`[${timestamp}] Cycle ${cycleCount}: ${result.error}${fileLabel}`), clackOutput);
16815
16952
  return;
16816
16953
  }
16817
16954
  if (result.skipped) {
16818
16955
  if (result.bytesRead > 0) {
16819
- clack17.log.info(
16956
+ clack18.log.info(
16820
16957
  `[${timestamp}] Cycle ${cycleCount}: +${formatBytes2(result.bytesRead)} bytes (below threshold, skipping)${fileLabel}`,
16821
16958
  clackOutput
16822
16959
  );
16823
16960
  } else if (once2 || verbose) {
16824
- clack17.log.info(`[${timestamp}] Cycle ${cycleCount}: no new content${fileLabel}`, clackOutput);
16961
+ clack18.log.info(`[${timestamp}] Cycle ${cycleCount}: no new content${fileLabel}`, clackOutput);
16825
16962
  }
16826
16963
  return;
16827
16964
  }
16828
16965
  if (dryRun) {
16829
- clack17.log.info(
16966
+ clack18.log.info(
16830
16967
  `[${timestamp}] Cycle ${cycleCount}: +${formatBytes2(result.bytesRead)} bytes | ${result.entriesExtracted} entries extracted (dry-run)${fileLabel}`,
16831
16968
  clackOutput
16832
16969
  );
16833
16970
  return;
16834
16971
  }
16835
16972
  const deduped = Math.max(0, result.entriesExtracted - result.entriesStored);
16836
- clack17.log.info(
16973
+ clack18.log.info(
16837
16974
  `[${timestamp}] Cycle ${cycleCount}: +${formatBytes2(result.bytesRead)} bytes | ${result.entriesExtracted} entries extracted | ${result.entriesStored} stored, ${deduped} deduped${fileLabel}`,
16838
16975
  clackOutput
16839
16976
  );
@@ -16885,11 +17022,11 @@ async function runWatchCommand(file, options, deps) {
16885
17022
  emitWatchWarning(`Context DB close failed: ${toErrorMessage(error)}`);
16886
17023
  }
16887
17024
  }
16888
- clack17.log.info(
17025
+ clack18.log.info(
16889
17026
  `Summary: ${summary.cycles} cycles | ${summary.entriesStored} entries stored | watched for ${formatDuration(summary.durationMs)}`,
16890
17027
  clackOutput
16891
17028
  );
16892
- clack17.outro(void 0, clackOutput);
17029
+ clack18.outro(void 0, clackOutput);
16893
17030
  return {
16894
17031
  exitCode: 0,
16895
17032
  cycles: summary.cycles,
@@ -16912,7 +17049,7 @@ async function runWatchCommand(file, options, deps) {
16912
17049
  }
16913
17050
  } else {
16914
17051
  const forceExitTimer = setTimeout(() => {
16915
- log20.warn("Force exit after timeout");
17052
+ log21.warn("Force exit after timeout");
16916
17053
  resolvedDeps.exitProcessFn(1);
16917
17054
  }, resolvedDeps.shutdownTimeoutMs);
16918
17055
  forceExitTimer.unref();
@@ -16983,12 +17120,12 @@ function createProgram() {
16983
17120
  program.enablePositionalOptions();
16984
17121
  program.name("agenr").description("Memory infrastructure for AI agents").version(APP_VERSION).action(async () => {
16985
17122
  const quick = getQuickStatus(process.env);
16986
- clack18.intro(banner());
17123
+ clack19.intro(banner());
16987
17124
  if (!quick.configured) {
16988
- clack18.note("Not configured", "Status");
16989
- clack18.log.warn("Run " + ui.bold("agenr setup") + " to get started.");
17125
+ clack19.note("Not configured", "Status");
17126
+ clack19.log.warn("Run " + ui.bold("agenr setup") + " to get started.");
16990
17127
  } else if (quick.credentialAvailable) {
16991
- clack18.note(
17128
+ clack19.note(
16992
17129
  [
16993
17130
  formatLabel("Provider", quick.provider ?? "(not set)"),
16994
17131
  formatLabel("Model", quick.model ?? "(not set)"),
@@ -16998,7 +17135,7 @@ function createProgram() {
16998
17135
  "Ready"
16999
17136
  );
17000
17137
  } else {
17001
- clack18.note(
17138
+ clack19.note(
17002
17139
  [
17003
17140
  formatLabel("Provider", quick.provider ?? "(not set)"),
17004
17141
  formatLabel("Model", quick.model ?? "(not set)"),
@@ -17006,16 +17143,17 @@ function createProgram() {
17006
17143
  ].join("\n"),
17007
17144
  "Not authenticated"
17008
17145
  );
17009
- clack18.log.warn(quick.guidance);
17146
+ clack19.log.warn(quick.guidance);
17010
17147
  }
17011
17148
  program.outputHelp();
17012
- clack18.outro(ui.dim("https://agenr.ai"));
17149
+ clack19.outro(ui.dim("https://agenr.ai"));
17013
17150
  });
17014
17151
  registerExtractCommand(program);
17015
17152
  registerStoreCommand(program);
17016
17153
  registerRecallCommand(program);
17017
17154
  registerRetireCommand(program);
17018
17155
  registerTraceCommand(program);
17156
+ registerUpdateCommand(program);
17019
17157
  registerReviewCommand(program);
17020
17158
  registerEdgesCommand(program);
17021
17159
  registerSyntheticCommand(program);
@@ -5,17 +5,19 @@ import {
5
5
  clearSessionProject,
6
6
  ensurePluginDb,
7
7
  executeRetire,
8
+ executeUpdate,
8
9
  extractTextEntries,
9
10
  getSessionProject,
10
11
  getSessionProjectState,
11
12
  lookupRetireCandidates,
13
+ lookupUpdateCandidate,
12
14
  normalizeStoreToolPayload,
13
15
  resolveProjectWorthySessionProject,
14
16
  runRecallService,
15
17
  runStoreService,
16
18
  runTraceService,
17
19
  setSessionProject
18
- } from "../chunk-JJZHOS4U.js";
20
+ } from "../chunk-CEPFOYOL.js";
19
21
  import {
20
22
  KNOWLEDGE_TYPES,
21
23
  SCOPE_LEVELS,
@@ -635,7 +637,8 @@ __export(recall_exports, {
635
637
  resolveAgenrPath: () => resolveAgenrPath,
636
638
  resolveBudget: () => resolveBudget,
637
639
  runMemoryIndex: () => runMemoryIndex,
638
- runRecall: () => runRecall
640
+ runRecall: () => runRecall,
641
+ runRecallStrict: () => runRecallStrict
639
642
  });
640
643
  import path from "path";
641
644
  import { fileURLToPath } from "url";
@@ -773,34 +776,45 @@ function buildSpawnArgs(agenrPath) {
773
776
  }
774
777
  return { cmd: agenrPath, args: [] };
775
778
  }
776
- async function runRecall(_agenrPath, budget, project, query, options, dbPath) {
779
+ function buildRecallServiceRequest(budget, project, query, options, dbPath) {
780
+ const isBrowse = options?.context === "browse";
781
+ const trimmedQuery = query?.trim() ?? "";
782
+ const truncatedQuery = trimmedQuery.length > RECALL_QUERY_MAX_CHARS ? trimmedQuery.slice(0, RECALL_QUERY_MAX_CHARS) : trimmedQuery;
783
+ return {
784
+ queryInput: isBrowse ? void 0 : truncatedQuery || void 0,
785
+ context: isBrowse ? "browse" : "session-start",
786
+ browse: isBrowse,
787
+ since: isBrowse ? options?.since ?? "1d" : void 0,
788
+ limit: options?.limit,
789
+ minImportance: options?.minImportance,
790
+ expiry: options?.expiry,
791
+ universalOnly: options?.nullProjectOnly === true || options?.universalOnly === true,
792
+ project: options?.nullProjectOnly || options?.universalOnly || !project ? void 0 : [project],
793
+ projectStrict: Boolean(project && !options?.nullProjectOnly && !options?.universalOnly),
794
+ budget: isBrowse ? void 0 : budget,
795
+ dbPath,
796
+ metadataMode: "non-browse"
797
+ };
798
+ }
799
+ function shapeRecallResult(result) {
800
+ return {
801
+ query: result.payload.query,
802
+ results: result.payload.results.map((item) => ({
803
+ entry: item.entry,
804
+ score: item.score,
805
+ category: item.category
806
+ }))
807
+ };
808
+ }
809
+ async function runRecallStrict(_agenrPath, budget, project, query, options, dbPath) {
810
+ const result = await runRecallService(
811
+ buildRecallServiceRequest(budget, project, query, options, dbPath)
812
+ );
813
+ return shapeRecallResult(result);
814
+ }
815
+ async function runRecall(agenrPath, budget, project, query, options, dbPath) {
777
816
  try {
778
- const isBrowse = options?.context === "browse";
779
- const trimmedQuery = query?.trim() ?? "";
780
- const truncatedQuery = trimmedQuery.length > RECALL_QUERY_MAX_CHARS ? trimmedQuery.slice(0, RECALL_QUERY_MAX_CHARS) : trimmedQuery;
781
- const result = await runRecallService({
782
- queryInput: isBrowse ? void 0 : truncatedQuery || void 0,
783
- context: isBrowse ? "browse" : "session-start",
784
- browse: isBrowse,
785
- since: isBrowse ? options?.since ?? "1d" : void 0,
786
- limit: options?.limit,
787
- minImportance: options?.minImportance,
788
- expiry: options?.expiry,
789
- universalOnly: options?.nullProjectOnly === true || options?.universalOnly === true,
790
- project: options?.nullProjectOnly || options?.universalOnly || !project ? void 0 : [project],
791
- projectStrict: Boolean(project && !options?.nullProjectOnly && !options?.universalOnly),
792
- budget: isBrowse ? void 0 : budget,
793
- dbPath,
794
- metadataMode: "non-browse"
795
- });
796
- return {
797
- query: result.payload.query,
798
- results: result.payload.results.map((item) => ({
799
- entry: item.entry,
800
- score: item.score,
801
- category: item.category
802
- }))
803
- };
817
+ return await runRecallStrict(agenrPath, budget, project, query, options, dbPath);
804
818
  } catch {
805
819
  return null;
806
820
  }
@@ -1668,6 +1682,53 @@ async function runRetireTool(_agenrPath, params, dbPath) {
1668
1682
  };
1669
1683
  }
1670
1684
  }
1685
+ async function runUpdateTool(_agenrPath, params, dbPath) {
1686
+ try {
1687
+ const entryId = asString(params.entry_id);
1688
+ const importance = asNumber(params.importance);
1689
+ if (!entryId) {
1690
+ return {
1691
+ content: [{ type: "text", text: "agenr_update failed: entry_id is required" }]
1692
+ };
1693
+ }
1694
+ if (!Number.isInteger(importance) || importance < 1 || importance > 10) {
1695
+ return {
1696
+ content: [{ type: "text", text: "agenr_update failed: importance must be an integer between 1 and 10" }]
1697
+ };
1698
+ }
1699
+ const lookup = await lookupUpdateCandidate({
1700
+ id: entryId,
1701
+ dbPath
1702
+ });
1703
+ if (!lookup.candidate) {
1704
+ return {
1705
+ content: [{ type: "text", text: `agenr_update failed: No active entry found with id: ${entryId}` }]
1706
+ };
1707
+ }
1708
+ const updated = await executeUpdate({
1709
+ id: entryId,
1710
+ importance,
1711
+ dbPath
1712
+ });
1713
+ if (!updated.updated) {
1714
+ return {
1715
+ content: [{ type: "text", text: `Entry ${entryId} was not updated because it is no longer active.` }]
1716
+ };
1717
+ }
1718
+ return {
1719
+ content: [
1720
+ {
1721
+ type: "text",
1722
+ text: updated.previousImportance === updated.importance ? `Entry ${entryId} already has importance ${updated.importance}.` : `Updated entry ${entryId} importance: ${updated.previousImportance} -> ${updated.importance}.`
1723
+ }
1724
+ ]
1725
+ };
1726
+ } catch (error) {
1727
+ return {
1728
+ content: [{ type: "text", text: `agenr_update failed: ${toErrorMessage(error)}` }]
1729
+ };
1730
+ }
1731
+ }
1671
1732
  async function runTraceTool(_agenrPath, params, dbPath) {
1672
1733
  try {
1673
1734
  const entryId = asString(params.entry_id);
@@ -4592,6 +4653,7 @@ function diversifySessionStartBrowseCandidates(browseResult, limit = SESSION_STA
4592
4653
 
4593
4654
  // src/openclaw-plugin/hooks/before-prompt-build-session-start-recall.ts
4594
4655
  var SESSION_START_BROWSE_SINCE = "30d";
4656
+ var SQLITE_BUSY_RETRY_DELAYS_MS = [100, 200, 400];
4595
4657
  var sessionStartLog3 = createLogger("session-start");
4596
4658
  function formatConfiguredCoreProjects(coreProjects) {
4597
4659
  return `[${coreProjects.join(",")}]`;
@@ -4611,6 +4673,59 @@ function describeMemoryIndexResult(result) {
4611
4673
  return "memory index unavailable: invalid response";
4612
4674
  }
4613
4675
  }
4676
+ function isSqliteBusyMessage(message) {
4677
+ return message.toUpperCase().includes("SQLITE_BUSY");
4678
+ }
4679
+ async function sleepMs(ms) {
4680
+ await new Promise((resolve) => setTimeout(resolve, ms));
4681
+ }
4682
+ async function loadSessionStartBrowseWithRetry(params, project, options) {
4683
+ for (let attempt = 0; ; attempt += 1) {
4684
+ try {
4685
+ return await runRecallStrict(
4686
+ params.agenrPath,
4687
+ params.budget,
4688
+ project,
4689
+ void 0,
4690
+ options,
4691
+ params.config?.dbPath
4692
+ );
4693
+ } catch (error) {
4694
+ const message = toErrorMessage(error);
4695
+ const isBusy = isSqliteBusyMessage(message);
4696
+ if (!isBusy || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) {
4697
+ sessionStartLog3.warn(`browse unavailable: ${message}`);
4698
+ return null;
4699
+ }
4700
+ const delayMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt] ?? 400;
4701
+ sessionStartLog3.warn(
4702
+ `browse hit SQLITE_BUSY, retrying in ${delayMs}ms (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1})`
4703
+ );
4704
+ await sleepMs(delayMs);
4705
+ }
4706
+ }
4707
+ }
4708
+ async function loadMemoryIndexWithRetry(params) {
4709
+ for (let attempt = 0; ; attempt += 1) {
4710
+ const result = await runMemoryIndex(
4711
+ params.agenrPath,
4712
+ params.config?.dbPath
4713
+ );
4714
+ const message = result.status === "error" ? result.error : "";
4715
+ const isBusy = result.status === "error" && isSqliteBusyMessage(message);
4716
+ if (!isBusy || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) {
4717
+ if (result.status !== "ok") {
4718
+ sessionStartLog3.warn(describeMemoryIndexResult(result));
4719
+ }
4720
+ return result;
4721
+ }
4722
+ const delayMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt] ?? 400;
4723
+ sessionStartLog3.warn(
4724
+ `memory index hit SQLITE_BUSY, retrying in ${delayMs}ms (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1})`
4725
+ );
4726
+ await sleepMs(delayMs);
4727
+ }
4728
+ }
4614
4729
  async function fetchSessionStartRecallData(currentSessionProjectKey, params) {
4615
4730
  const coreProjects = params.config?.coreProjects ?? [];
4616
4731
  const sessionStartBrowseProject = await resolveSessionStartBrowseProject(
@@ -4629,18 +4744,8 @@ async function fetchSessionStartRecallData(currentSessionProjectKey, params) {
4629
4744
  }
4630
4745
  const [coreSettled, browseSettled, memoryIndexSettled] = await Promise.allSettled([
4631
4746
  fetchCoreEntries(params.agenrPath, coreProjects, params.config?.dbPath),
4632
- runRecall(
4633
- params.agenrPath,
4634
- params.budget,
4635
- sessionStartBrowseProject,
4636
- void 0,
4637
- browseRecallOptions,
4638
- params.config?.dbPath
4639
- ),
4640
- runMemoryIndex(
4641
- params.agenrPath,
4642
- params.config?.dbPath
4643
- )
4747
+ loadSessionStartBrowseWithRetry(params, sessionStartBrowseProject, browseRecallOptions),
4748
+ loadMemoryIndexWithRetry(params)
4644
4749
  ]);
4645
4750
  if (coreSettled.status === "rejected") {
4646
4751
  sessionStartLog3.error(`core recall failed: ${toErrorMessage(coreSettled.reason)}`);
@@ -4660,12 +4765,16 @@ async function fetchSessionStartRecallData(currentSessionProjectKey, params) {
4660
4765
  "session-start",
4661
4766
  `core recall returned ${coreResult?.results.length ?? 0} entries (configured coreProjects=${formatConfiguredCoreProjects(coreProjects)})`
4662
4767
  );
4663
- debugLog(params.debug, "session-start", `browse returned ${browseResult?.results.length ?? 0} entries`);
4664
- debugLog(
4665
- params.debug,
4666
- "session-start",
4667
- describeMemoryIndexResult(memoryIndexResult)
4668
- );
4768
+ if (browseResult) {
4769
+ debugLog(params.debug, "session-start", `browse returned ${browseResult.results.length} entries`);
4770
+ }
4771
+ if (memoryIndexResult?.status === "ok") {
4772
+ debugLog(
4773
+ params.debug,
4774
+ "session-start",
4775
+ describeMemoryIndexResult(memoryIndexResult)
4776
+ );
4777
+ }
4669
4778
  return {
4670
4779
  coreResult,
4671
4780
  browseResult,
@@ -6279,6 +6388,26 @@ function registerAgenrTools(api, params) {
6279
6388
  }
6280
6389
  }
6281
6390
  );
6391
+ api.registerTool(
6392
+ {
6393
+ name: "agenr_update",
6394
+ label: "Agenr Update",
6395
+ description: "Update an existing memory entry in place. Currently supports importance only.",
6396
+ parameters: Type.Object({
6397
+ entry_id: Type.String({ description: "Entry ID to update." }),
6398
+ importance: Type.Integer({ minimum: 1, maximum: 10, description: "New importance score." })
6399
+ }),
6400
+ async execute(_toolCallId, toolParams) {
6401
+ const runtimeConfig = api.pluginConfig;
6402
+ if (runtimeConfig?.enabled === false) {
6403
+ return makeDisabledToolResult();
6404
+ }
6405
+ const agenrPath = resolveAgenrPath(runtimeConfig);
6406
+ const dbPath = runtimeConfig?.dbPath;
6407
+ return runUpdateTool(agenrPath, toolParams, dbPath);
6408
+ }
6409
+ }
6410
+ );
6282
6411
  api.registerTool(
6283
6412
  {
6284
6413
  name: "agenr_trace",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenr",
3
- "version": "0.9.79",
3
+ "version": "0.9.81",
4
4
  "openclaw": {
5
5
  "extensions": [
6
6
  "dist/openclaw-plugin/index.js"
@@ -11,19 +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 --clean",
16
- "check": "pnpm format:check && pnpm lint && pnpm typecheck && pnpm test",
17
- "dev": "tsup src/cli.ts src/cli-main.ts --format esm --watch",
18
- "lint": "eslint .",
19
- "format": "prettier --write .",
20
- "format:check": "prettier --check .",
21
- "test": "vitest run",
22
- "test:watch": "vitest",
23
- "typecheck": "tsc --noEmit",
24
- "verify:dist": "node scripts/verify-dist.js",
25
- "prepack": "pnpm build && pnpm verify:dist"
26
- },
27
14
  "dependencies": {
28
15
  "@clack/prompts": "^1.0.1",
29
16
  "@libsql/client": "^0.17.0",
@@ -72,9 +59,16 @@
72
59
  "README.md"
73
60
  ],
74
61
  "author": "agenr-ai",
75
- "pnpm": {
76
- "overrides": {
77
- "fast-xml-parser": "^5.3.6"
78
- }
62
+ "scripts": {
63
+ "build": "tsup src/cli.ts src/cli-main.ts src/openclaw-plugin/index.ts --format esm --dts --clean",
64
+ "check": "pnpm format:check && pnpm lint && pnpm typecheck && pnpm test",
65
+ "dev": "tsup src/cli.ts src/cli-main.ts --format esm --watch",
66
+ "lint": "eslint .",
67
+ "format": "prettier --write .",
68
+ "format:check": "prettier --check .",
69
+ "test": "vitest run",
70
+ "test:watch": "vitest",
71
+ "typecheck": "tsc --noEmit",
72
+ "verify:dist": "node scripts/verify-dist.js"
79
73
  }
80
- }
74
+ }