agenr 0.9.81 → 0.9.83

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,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.83] - 2026-03-08
4
+
5
+ ### Fixed
6
+
7
+ - Hardened OpenClaw session-start startup reads by preserving the `initDbForStartupReads` export in test mocks, updating startup-read assertion shapes to match the current read-safe API, aligning deferred handoff timing coverage with the current lifecycle, and eliminating a real startup PRAGMA vs `BEGIN IMMEDIATE` contention race in regression coverage.
8
+
9
+ ## [0.9.82] - 2026-03-08
10
+
11
+ ### Added
12
+
13
+ - Added a GitHub Actions `Validate` workflow that runs on pull requests and `master` pushes, installs dependencies, runs `pnpm typecheck`, and then runs the full `pnpm check` gate.
14
+
15
+ ### Changed
16
+
17
+ - Documented `pnpm check` as the canonical local validation command and called out `pnpm typecheck` as the minimum fast sanity check before trusting passing tests.
18
+ - Hardened update-path validation and regression coverage so validation-gate checks no longer depend on ambient host project config or local previous-session state.
19
+
3
20
  ## [0.9.81] - 2026-03-08
4
21
 
5
22
  ### Added
@@ -37,7 +37,7 @@ import {
37
37
  toErrorMessage,
38
38
  updateRecallMetadata,
39
39
  walCheckpoint
40
- } from "./chunk-3NGXMER3.js";
40
+ } from "./chunk-LXLOBT4V.js";
41
41
  import {
42
42
  toNumber,
43
43
  toRowsAffected,
@@ -6716,8 +6716,10 @@ async function runStoreService(request, deps) {
6716
6716
  dedupThreshold: dedupThreshold ?? configDedupThreshold,
6717
6717
  llmClient,
6718
6718
  claimExtractionEnabled,
6719
+ skipClaimExtraction: request.skipClaimExtraction === true,
6719
6720
  claimExtractionModel,
6720
6721
  contradictionEnabled,
6722
+ skipContradiction: request.skipContradiction === true,
6721
6723
  config: config ?? void 0,
6722
6724
  dbPath,
6723
6725
  sourceFile: batch.sourceFile,
@@ -2507,7 +2507,18 @@ var walInitByClient = /* @__PURE__ */ new WeakMap();
2507
2507
  var didWarnVectorIndexCorruption = false;
2508
2508
  var WAL_CHECKPOINT_MAX_ATTEMPTS = 5;
2509
2509
  var WAL_CHECKPOINT_RETRY_MS = 50;
2510
+ var DEFAULT_BUSY_TIMEOUT_MS = 3e3;
2510
2511
  var log = createLogger("db");
2512
+ async function awaitClientStartupPragmas(client, options = {}) {
2513
+ const walInit = walInitByClient.get(client);
2514
+ if (!walInit) {
2515
+ return;
2516
+ }
2517
+ await walInit;
2518
+ if (options.setWalAutoCheckpoint === true) {
2519
+ await client.execute("PRAGMA wal_autocheckpoint=1000");
2520
+ }
2521
+ }
2511
2522
  function resolveDbPath(dbPath) {
2512
2523
  if (dbPath === ":memory:") {
2513
2524
  return dbPath;
@@ -2539,8 +2550,10 @@ function buildBackupPath(dbPath) {
2539
2550
  `${path4.basename(resolvedDbPath)}.backup-pre-reset-${timestamp2}Z`
2540
2551
  );
2541
2552
  }
2542
- function getDb(dbPath) {
2553
+ function getDb(dbPath, options = {}) {
2543
2554
  const rawPath = dbPath?.trim() ? dbPath.trim() : DEFAULT_DB_PATH;
2555
+ const busyTimeoutMs = Number.isFinite(options.busyTimeoutMs) ? Math.max(0, Math.floor(options.busyTimeoutMs)) : DEFAULT_BUSY_TIMEOUT_MS;
2556
+ const ensureWalMode = options.ensureWalMode !== false;
2544
2557
  if (rawPath === ":memory:") {
2545
2558
  return createClient({ url: ":memory:" });
2546
2559
  }
@@ -2548,7 +2561,12 @@ function getDb(dbPath) {
2548
2561
  const client2 = createClient({ url: rawPath });
2549
2562
  walInitByClient.set(
2550
2563
  client2,
2551
- client2.execute("PRAGMA journal_mode=WAL").then(() => client2.execute("PRAGMA busy_timeout=3000")).then(() => void 0)
2564
+ (async () => {
2565
+ if (ensureWalMode) {
2566
+ await client2.execute("PRAGMA journal_mode=WAL");
2567
+ }
2568
+ await client2.execute(`PRAGMA busy_timeout=${busyTimeoutMs}`);
2569
+ })()
2552
2570
  );
2553
2571
  return client2;
2554
2572
  }
@@ -2556,7 +2574,12 @@ function getDb(dbPath) {
2556
2574
  const client = createClient({ url: `file:${resolvedPath}` });
2557
2575
  walInitByClient.set(
2558
2576
  client,
2559
- client.execute("PRAGMA journal_mode=WAL").then(() => client.execute("PRAGMA busy_timeout=3000")).then(() => void 0)
2577
+ (async () => {
2578
+ if (ensureWalMode) {
2579
+ await client.execute("PRAGMA journal_mode=WAL");
2580
+ }
2581
+ await client.execute(`PRAGMA busy_timeout=${busyTimeoutMs}`);
2582
+ })()
2560
2583
  );
2561
2584
  return client;
2562
2585
  }
@@ -2622,12 +2645,11 @@ async function checkAndRecoverBulkIngest(client) {
2622
2645
  throw error;
2623
2646
  }
2624
2647
  }
2648
+ async function initDbForStartupReads(client) {
2649
+ await awaitClientStartupPragmas(client);
2650
+ }
2625
2651
  async function initDb(client, opts) {
2626
- const walInit = walInitByClient.get(client);
2627
- if (walInit) {
2628
- await walInit;
2629
- await client.execute("PRAGMA wal_autocheckpoint=1000");
2630
- }
2652
+ await awaitClientStartupPragmas(client, { setWalAutoCheckpoint: true });
2631
2653
  await initSchema(client);
2632
2654
  if (opts?.checkBulkRecovery === true) {
2633
2655
  try {
@@ -2641,23 +2663,25 @@ async function initDb(client, opts) {
2641
2663
  );
2642
2664
  }
2643
2665
  }
2644
- try {
2645
- const hasEntries = await client.execute(
2646
- "SELECT 1 FROM entries WHERE embedding IS NOT NULL LIMIT 1"
2647
- );
2648
- if (hasEntries.rows.length > 0) {
2649
- await client.execute(`
2650
- SELECT count(*) FROM vector_top_k(
2651
- 'idx_entries_embedding',
2652
- (SELECT embedding FROM entries WHERE embedding IS NOT NULL LIMIT 1),
2653
- 1
2654
- )
2655
- `);
2656
- }
2657
- } catch {
2658
- if (!didWarnVectorIndexCorruption) {
2659
- didWarnVectorIndexCorruption = true;
2660
- log.warn("\u26A0\uFE0F Vector index may be corrupted. Run `agenr db rebuild-index` to fix.");
2666
+ if (opts?.skipVectorHealthCheck !== true) {
2667
+ try {
2668
+ const hasEntries = await client.execute(
2669
+ "SELECT 1 FROM entries WHERE embedding IS NOT NULL LIMIT 1"
2670
+ );
2671
+ if (hasEntries.rows.length > 0) {
2672
+ await client.execute(`
2673
+ SELECT count(*) FROM vector_top_k(
2674
+ 'idx_entries_embedding',
2675
+ (SELECT embedding FROM entries WHERE embedding IS NOT NULL LIMIT 1),
2676
+ 1
2677
+ )
2678
+ `);
2679
+ }
2680
+ } catch {
2681
+ if (!didWarnVectorIndexCorruption) {
2682
+ didWarnVectorIndexCorruption = true;
2683
+ log.warn("\u26A0\uFE0F Vector index may be corrupted. Run `agenr db rebuild-index` to fix.");
2684
+ }
2661
2685
  }
2662
2686
  }
2663
2687
  }
@@ -3378,6 +3402,107 @@ async function retireEntries(opts) {
3378
3402
  return { count };
3379
3403
  }
3380
3404
 
3405
+ // src/utils/injected-context.ts
3406
+ var OPENCLAW_TIMESTAMP_PREFIX_PATTERN = /\[(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun) \d{4}-\d{2}-\d{2} \d{2}:\d{2} (?:[A-Z]{2,5}|GMT[+-]\d{1,2})\] /g;
3407
+ var UNTRUSTED_METADATA_PATTERN = /(?:^|\r?\n)\s*(?:Conversation info|Sender) \(untrusted metadata\):\s*(?:(?:\r?\n|\s+)```(?:json)?\s*[\s\S]*?\r?\n\s*```|(?:\r?\n|\s+)\{[\s\S]*?\})(?:\s*(?=\r?\n|$))?/gim;
3408
+ var SECTION_HEADER_PATTERN = /^## (?:Session project state(?: \(authoritative\))?|Recent session|Recent memory|Relevant memory|agenr Memory Context)\b/i;
3409
+ var PREFIXED_SECTION_HEADER_PATTERN = /^(?:U:|A:|\[(?:user|assistant)\]:)\s*## (?:Session project state(?: \(authoritative\))?|Recent session|Recent memory|Relevant memory|agenr Memory Context)\b/i;
3410
+ var HANDOFF_BACKGROUND_MARKER = "=== BACKGROUND CONTEXT (DO NOT SUMMARIZE) ===";
3411
+ var HANDOFF_SUMMARIZE_MARKER = "=== SUMMARIZE THIS SESSION ONLY ===";
3412
+ var STARTUP_BOILERPLATE_PATTERN = /^(?:A new session was started via \/new or \/reset|Execute your Session Startup sequence now)\b/i;
3413
+ var SIGNAL_PATTERN = /^AGENR SIGNAL:/i;
3414
+ var SIGNAL_BULLET_PATTERN = /^\s*-\s*\[[^\n]*/i;
3415
+ var STRUCTURAL_BOUNDARY_PATTERN = /^(?:## |(?:Conversation info|Sender) \(untrusted metadata\):|=== |U:|A:|\[(?:user|assistant)\]:)/i;
3416
+ function normalizeRemainingWhitespace(text) {
3417
+ return text.replace(/\r\n/g, "\n").replace(/[ \t]+\n/g, "\n").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
3418
+ }
3419
+ function flattenForDisplay(text) {
3420
+ return text.split(/\r?\n+/).map((line) => line.trim()).filter((line) => line.length > 0).join(" | ").trim();
3421
+ }
3422
+ function stripStructuredLineBlocks(text) {
3423
+ const lines = text.split(/\r?\n/);
3424
+ const kept = [];
3425
+ let skipSection = false;
3426
+ let skipSignalBullets = false;
3427
+ let skipHandoffBackground = false;
3428
+ for (const line of lines) {
3429
+ const trimmed = line.trim();
3430
+ if (skipHandoffBackground) {
3431
+ if (trimmed === HANDOFF_SUMMARIZE_MARKER) {
3432
+ skipHandoffBackground = false;
3433
+ }
3434
+ continue;
3435
+ }
3436
+ if (skipSection) {
3437
+ if (!trimmed) {
3438
+ skipSection = false;
3439
+ continue;
3440
+ }
3441
+ if (trimmed && STRUCTURAL_BOUNDARY_PATTERN.test(trimmed)) {
3442
+ skipSection = false;
3443
+ } else {
3444
+ continue;
3445
+ }
3446
+ }
3447
+ if (skipSignalBullets) {
3448
+ if (trimmed && SIGNAL_BULLET_PATTERN.test(trimmed)) {
3449
+ continue;
3450
+ }
3451
+ skipSignalBullets = false;
3452
+ }
3453
+ if (!trimmed) {
3454
+ kept.push(line);
3455
+ continue;
3456
+ }
3457
+ if (trimmed === HANDOFF_BACKGROUND_MARKER) {
3458
+ skipHandoffBackground = true;
3459
+ continue;
3460
+ }
3461
+ if (trimmed === HANDOFF_SUMMARIZE_MARKER) {
3462
+ continue;
3463
+ }
3464
+ if (SECTION_HEADER_PATTERN.test(trimmed) || PREFIXED_SECTION_HEADER_PATTERN.test(trimmed)) {
3465
+ skipSection = true;
3466
+ continue;
3467
+ }
3468
+ if (SIGNAL_PATTERN.test(trimmed)) {
3469
+ skipSignalBullets = true;
3470
+ continue;
3471
+ }
3472
+ if (STARTUP_BOILERPLATE_PATTERN.test(trimmed)) {
3473
+ continue;
3474
+ }
3475
+ kept.push(line);
3476
+ }
3477
+ return kept.join("\n");
3478
+ }
3479
+ function hasMeaningfulSanitizedText(text) {
3480
+ const tokens = text.match(/[A-Za-z0-9]+/g) ?? [];
3481
+ if (tokens.length >= 2) {
3482
+ return true;
3483
+ }
3484
+ return tokens.join("").length >= 8;
3485
+ }
3486
+ function stripInjectedContext(text) {
3487
+ if (!text) {
3488
+ return "";
3489
+ }
3490
+ let cleaned = text.replace(OPENCLAW_TIMESTAMP_PREFIX_PATTERN, "");
3491
+ cleaned = cleaned.replace(UNTRUSTED_METADATA_PATTERN, "\n");
3492
+ cleaned = stripStructuredLineBlocks(cleaned);
3493
+ return normalizeRemainingWhitespace(cleaned);
3494
+ }
3495
+ function sanitizeInjectedContextText(text, options = {}) {
3496
+ const baseline = normalizeRemainingWhitespace(text.replace(OPENCLAW_TIMESTAMP_PREFIX_PATTERN, ""));
3497
+ const stripped = stripInjectedContext(text);
3498
+ const normalized = options.flatten ? flattenForDisplay(stripped) : stripped;
3499
+ return {
3500
+ text: normalized,
3501
+ removed: stripped !== baseline,
3502
+ meaningful: hasMeaningfulSanitizedText(normalized)
3503
+ };
3504
+ }
3505
+
3381
3506
  // src/utils/async.ts
3382
3507
  function sleep(ms) {
3383
3508
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -9765,7 +9890,7 @@ async function storeEntries(db, entries, apiKey, options = {}) {
9765
9890
  throw new Error("storeEntries does not support dryRun with externalTransaction.");
9766
9891
  }
9767
9892
  const preBatchEmbedChunkSize = typeof options.preBatchEmbedChunkSize === "number" && Number.isFinite(options.preBatchEmbedChunkSize) && options.preBatchEmbedChunkSize > 0 ? Math.floor(options.preBatchEmbedChunkSize) : DEFAULT_PRE_BATCH_EMBED_CHUNK_SIZE;
9768
- const shouldUseEntityHints = Boolean(options.llmClient) && options.claimExtractionEnabled !== false;
9893
+ const shouldUseEntityHints = Boolean(options.llmClient) && options.claimExtractionEnabled !== false && options.skipClaimExtraction !== true;
9769
9894
  let entityHintsPromise = null;
9770
9895
  const getBatchEntityHints = async () => {
9771
9896
  if (!shouldUseEntityHints) {
@@ -9786,6 +9911,26 @@ async function storeEntries(db, entries, apiKey, options = {}) {
9786
9911
  let relationsCreated = 0;
9787
9912
  let llmDedupCalls = 0;
9788
9913
  const pendingConflictsMap = /* @__PURE__ */ new Map();
9914
+ const sanitizedEntries = [];
9915
+ for (const entry of entries) {
9916
+ const sanitized = sanitizeInjectedContextText(entry.content);
9917
+ if (sanitized.removed && !sanitized.meaningful) {
9918
+ skipped += 1;
9919
+ options.onDecision?.({
9920
+ entry,
9921
+ action: "skipped",
9922
+ reason: "operational injected context"
9923
+ });
9924
+ continue;
9925
+ }
9926
+ sanitizedEntries.push(
9927
+ sanitized.text === entry.content ? entry : {
9928
+ ...entry,
9929
+ content: sanitized.text
9930
+ }
9931
+ );
9932
+ }
9933
+ entries = sanitizedEntries;
9789
9934
  if (!options.force && !onlineDedup) {
9790
9935
  const seen = /* @__PURE__ */ new Map();
9791
9936
  for (let i = 0; i < entries.length; i += 1) {
@@ -9969,13 +10114,15 @@ async function storeEntries(db, entries, apiKey, options = {}) {
9969
10114
  llmDedupCalls += 1;
9970
10115
  }
9971
10116
  });
9972
- if ((processed.mutation.kind === "add" || processed.mutation.kind === "add_related") && options.llmClient && options.claimExtractionEnabled !== false) {
10117
+ const shouldRunClaimExtraction = (processed.mutation.kind === "add" || processed.mutation.kind === "add_related") && Boolean(options.llmClient) && options.claimExtractionEnabled !== false && options.skipClaimExtraction !== true;
10118
+ const llmClient = options.llmClient;
10119
+ if (shouldRunClaimExtraction && llmClient) {
9973
10120
  const entityHints = await getBatchEntityHints();
9974
10121
  const claim = await extractClaim(
9975
10122
  normalizedEntry.content,
9976
10123
  normalizedEntry.type,
9977
10124
  normalizedEntry.subject,
9978
- options.llmClient,
10125
+ llmClient,
9979
10126
  {
9980
10127
  model: options.claimExtractionModel,
9981
10128
  config: options.config,
@@ -10004,7 +10151,9 @@ async function storeEntries(db, entries, apiKey, options = {}) {
10004
10151
  };
10005
10152
  }
10006
10153
  }
10007
- if ((processed.mutation.kind === "add" || processed.mutation.kind === "add_related") && options.llmClient && options.contradictionEnabled !== false && processed.mutation.embedding) {
10154
+ const shouldRunContradictionChecks = (processed.mutation.kind === "add" || processed.mutation.kind === "add_related") && Boolean(options.llmClient) && options.contradictionEnabled !== false && options.skipContradiction !== true && Boolean(processed.mutation.embedding);
10155
+ const mutationEmbedding = processed.mutation.embedding;
10156
+ if (shouldRunContradictionChecks && llmClient && mutationEmbedding) {
10008
10157
  await contradictionSubjectIndex.ensureInitialized(db);
10009
10158
  contradictionLog.info(
10010
10159
  `checking entry: type=${normalizedEntry.type} subject="${normalizedEntry.subject}" subjectKey=${normalizedEntry.subjectKey ?? "none"}`
@@ -10018,9 +10167,9 @@ async function storeEntries(db, entries, apiKey, options = {}) {
10018
10167
  subjectKey: normalizedEntry.subjectKey,
10019
10168
  importance: normalizedEntry.importance
10020
10169
  },
10021
- processed.mutation.embedding,
10170
+ mutationEmbedding,
10022
10171
  contradictionSubjectIndex,
10023
- options.llmClient,
10172
+ llmClient,
10024
10173
  {
10025
10174
  model: options.contradictionModel,
10026
10175
  config: options.config
@@ -10078,7 +10227,7 @@ async function storeEntries(db, entries, apiKey, options = {}) {
10078
10227
  }
10079
10228
  pendingConflictsMap.delete(entryIndex);
10080
10229
  }
10081
- if (options.contradictionEnabled !== false && normalizedEntry.subjectKey && applied.newEntryId) {
10230
+ if (options.contradictionEnabled !== false && options.skipContradiction !== true && normalizedEntry.subjectKey && applied.newEntryId) {
10082
10231
  contradictionSubjectIndex.add(normalizedEntry.subjectKey, applied.newEntryId);
10083
10232
  }
10084
10233
  return applied;
@@ -10237,6 +10386,7 @@ export {
10237
10386
  DEFAULT_DB_PATH,
10238
10387
  buildBackupPath,
10239
10388
  getDb,
10389
+ initDbForStartupReads,
10240
10390
  initDb,
10241
10391
  walCheckpoint,
10242
10392
  backupDb,
@@ -10312,6 +10462,8 @@ export {
10312
10462
  resolveHigherExpiry,
10313
10463
  resolveHighestExpiry,
10314
10464
  resolveSameSubject,
10465
+ stripInjectedContext,
10466
+ sanitizeInjectedContextText,
10315
10467
  storeEntries,
10316
10468
  isRecord,
10317
10469
  evolveQualityScores,
@@ -23,7 +23,7 @@ import {
23
23
  runSimpleStream,
24
24
  toErrorMessage,
25
25
  walCheckpoint
26
- } from "./chunk-3NGXMER3.js";
26
+ } from "./chunk-LXLOBT4V.js";
27
27
  import {
28
28
  MILLISECONDS_PER_DAY,
29
29
  parseDaysBetween,
@@ -284,10 +284,16 @@ declare function writeOutput(params: {
284
284
 
285
285
  declare function deduplicateEntries(entries: KnowledgeEntry[]): KnowledgeEntry[];
286
286
 
287
- declare function getDb(dbPath?: string): Client;
288
- declare function initDb(client: Client, opts?: {
287
+ interface GetDbOptions {
288
+ busyTimeoutMs?: number;
289
+ ensureWalMode?: boolean;
290
+ }
291
+ interface InitDbOptions {
289
292
  checkBulkRecovery?: boolean;
290
- }): Promise<void>;
293
+ skipVectorHealthCheck?: boolean;
294
+ }
295
+ declare function getDb(dbPath?: string, options?: GetDbOptions): Client;
296
+ declare function initDb(client: Client, opts?: InitDbOptions): Promise<void>;
291
297
  declare function closeDb(client: Client): void;
292
298
 
293
299
  declare function resolveEmbeddingApiKey(config: AgenrConfig | null | undefined, env?: NodeJS.ProcessEnv): string;
package/dist/cli-main.js CHANGED
@@ -41,7 +41,7 @@ import {
41
41
  runStoreService,
42
42
  runTraceService,
43
43
  ui
44
- } from "./chunk-CEPFOYOL.js";
44
+ } from "./chunk-E4QJJSZI.js";
45
45
  import {
46
46
  ConflictAlreadyResolvedError,
47
47
  REVIEW_QUEUE_PATH,
@@ -56,7 +56,7 @@ import {
56
56
  showFlaggedMerges,
57
57
  toConflictLogRow,
58
58
  toRecord
59
- } from "./chunk-WT6HSCSO.js";
59
+ } from "./chunk-TCIOL7ZL.js";
60
60
  import {
61
61
  APP_VERSION,
62
62
  DEFAULT_AROUND_RADIUS_DAYS,
@@ -150,6 +150,7 @@ import {
150
150
  retireEntries,
151
151
  runShutdownHandlers,
152
152
  runSimpleStream,
153
+ sanitizeInjectedContextText,
153
154
  scoreEntry,
154
155
  scoreEntryWithBreakdown,
155
156
  sessionStartRecall,
@@ -163,7 +164,7 @@ import {
163
164
  walCheckpoint,
164
165
  warnIfLocked,
165
166
  writeConfig
166
- } from "./chunk-3NGXMER3.js";
167
+ } from "./chunk-LXLOBT4V.js";
167
168
  import {
168
169
  getCoRecallNeighbors,
169
170
  getTopCoRecallEdges,
@@ -6197,6 +6198,8 @@ async function runConsolidateCommand(options, deps = {}) {
6197
6198
  getDbFn: deps.getDbFn ?? getDb,
6198
6199
  closeDbFn: deps.closeDbFn ?? closeDb,
6199
6200
  initSchemaFn: deps.initSchemaFn ?? initSchema,
6201
+ acquireDbLockFn: deps.acquireDbLockFn ?? acquireDbLock,
6202
+ releaseDbLockFn: deps.releaseDbLockFn ?? releaseDbLock,
6200
6203
  createLlmClientFn: deps.createLlmClientFn ?? createLlmClient,
6201
6204
  resolveEmbeddingApiKeyFn: deps.resolveEmbeddingApiKeyFn ?? resolveEmbeddingApiKey,
6202
6205
  showFlaggedMergesFn: deps.showFlaggedMergesFn ?? showFlaggedMerges,
@@ -6237,9 +6240,9 @@ async function runConsolidateCommand(options, deps = {}) {
6237
6240
  if (dbFilePath === ":memory:") {
6238
6241
  throw new Error("Consolidation requires a file-backed database so a backup can be created.");
6239
6242
  }
6240
- acquireDbLock();
6243
+ resolvedDeps.acquireDbLockFn();
6241
6244
  onShutdown(async () => {
6242
- releaseDbLock();
6245
+ resolvedDeps.releaseDbLockFn();
6243
6246
  });
6244
6247
  const db = resolvedDeps.getDbFn(configuredPath);
6245
6248
  try {
@@ -13781,12 +13784,12 @@ function registerMaintainCommand(program) {
13781
13784
  "--only <tasks>",
13782
13785
  "Comma-separated task names: quality,edge-decay,clusters,conflicts,consolidation,retirement,reflection"
13783
13786
  ).option("--prune-edges", "When edge decay runs, delete edges below the configured decay floor").option("--verbose", "Show detailed per-task output").action(async (opts) => {
13784
- const { runMaintainCommand } = await import("./maintain-S6ROD7SF.js");
13787
+ const { runMaintainCommand } = await import("./maintain-YECEJSXO.js");
13785
13788
  const result = await runMaintainCommand(opts);
13786
13789
  process.exitCode = result.exitCode;
13787
13790
  });
13788
13791
  maintainCommand.command("history").description("Show past maintenance runs").option("--db <path>", "Database path override").option("--limit <n>", "Max runs to show (default: 10)", parseIntOption).option("--json", "Output as JSON").action(async (opts) => {
13789
- const { runMaintainHistoryCommand } = await import("./maintain-S6ROD7SF.js");
13792
+ const { runMaintainHistoryCommand } = await import("./maintain-YECEJSXO.js");
13790
13793
  const result = await runMaintainHistoryCommand(opts);
13791
13794
  process.exitCode = result.exitCode;
13792
13795
  });
@@ -15840,7 +15843,7 @@ async function runUpdateCommand(options) {
15840
15843
  throw new Error("id is required");
15841
15844
  }
15842
15845
  const importance = options.importance;
15843
- if (!Number.isInteger(importance) || importance < IMPORTANCE_MIN || importance > IMPORTANCE_MAX) {
15846
+ if (typeof importance !== "number" || !Number.isInteger(importance) || importance < IMPORTANCE_MIN || importance > IMPORTANCE_MAX) {
15844
15847
  throw new Error(`importance must be an integer between ${IMPORTANCE_MIN} and ${IMPORTANCE_MAX}`);
15845
15848
  }
15846
15849
  const clackOutput = { output: process.stderr };
@@ -16307,8 +16310,20 @@ async function runWatcher(options, deps) {
16307
16310
  ...entry,
16308
16311
  platform: entry.platform ?? platformTag
16309
16312
  })) : attributedEntries;
16310
- cycleResult.entriesExtracted += taggedEntries.length;
16311
- const deduped = resolvedDeps.deduplicateEntriesFn(taggedEntries);
16313
+ const sanitizedEntries = taggedEntries.flatMap((entry) => {
16314
+ const sanitized = sanitizeInjectedContextText(entry.content);
16315
+ if (sanitized.removed && !sanitized.meaningful) {
16316
+ return [];
16317
+ }
16318
+ return [
16319
+ sanitized.text === entry.content ? entry : {
16320
+ ...entry,
16321
+ content: sanitized.text
16322
+ }
16323
+ ];
16324
+ });
16325
+ cycleResult.entriesExtracted += sanitizedEntries.length;
16326
+ const deduped = resolvedDeps.deduplicateEntriesFn(sanitizedEntries);
16312
16327
  if (options.dryRun || deduped.length === 0) {
16313
16328
  return;
16314
16329
  }
@@ -17,7 +17,7 @@ import {
17
17
  resolveConflict,
18
18
  runConsolidationOrchestrator,
19
19
  toRecord
20
- } from "./chunk-WT6HSCSO.js";
20
+ } from "./chunk-TCIOL7ZL.js";
21
21
  import {
22
22
  DEFAULT_DB_PATH,
23
23
  DEFAULT_TASK_MODEL,
@@ -43,7 +43,7 @@ import {
43
43
  resolveModelForLlmClient,
44
44
  runSimpleStream,
45
45
  walCheckpoint
46
- } from "./chunk-3NGXMER3.js";
46
+ } from "./chunk-LXLOBT4V.js";
47
47
  import {
48
48
  decayCoRecallEdges,
49
49
  getLastRecallActivity,
@@ -71,12 +71,13 @@ type PluginApi = {
71
71
  };
72
72
  };
73
73
 
74
+ declare function stripInjectedContext(text: string): string;
75
+
74
76
  type HandoffMessage = {
75
77
  role: "user" | "assistant";
76
78
  content: string;
77
79
  timestamp: string;
78
80
  };
79
- declare function stripInjectedContext(text: string): string;
80
81
  declare function getBaseSessionPath(filePath: string): string;
81
82
  declare function readSessionsJson(sessionsDir: string): Promise<Record<string, unknown>>;
82
83
  declare function readAndParseSessionJsonl(sessionFile: string): Promise<unknown[]>;