agenr 0.9.17 → 0.9.18

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,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.18 (2026-02-28)
4
+
5
+ ### Features
6
+ - OpenClaw plugin: subsequent-turn auto-recall with heuristic message
7
+ classifier. Messages are classified as trivial (skip), normal (5 results),
8
+ or complex (8 results) based on entity detection, temporal references,
9
+ and explicit recall phrases. Queries built from a sliding window of
10
+ recent messages with Jaccard similarity dedup. Recalled entries are
11
+ deduplicated against session-start context. Configurable via
12
+ midSessionRecall plugin config.
13
+
14
+ ### Bug Fixes
15
+ - MCP: fix stdout corruption during store and contradiction checks.
16
+ Diagnostic logs in db/store.ts and db/contradiction.ts were writing to
17
+ stdout via console.log, corrupting MCP JSON-RPC framing. Routed all
18
+ diagnostic logging to stderr via console.error.
19
+
20
+ ### Changed
21
+ - Removed agenr_store tool from MCP server. Coding agents should rely on
22
+ Watcher for knowledge ingest from session transcripts. Reduces MCP
23
+ surface area and eliminates stdout corruption risk.
24
+ - Removed store option from agenr_extract MCP tool. Extract now returns
25
+ extracted entries without storing them.
26
+
27
+ ### Tests
28
+ - 16-case message classifier test suite
29
+ - Query builder, similarity check, and state management tests
30
+ - Integration tests for mid-session recall in before_prompt_build
31
+ - MCP stdout corruption test
32
+ - Updated MCP server tests for removed store tool and extract store option
33
+
3
34
  ## 0.9.17 - 2026-02-27
4
35
 
5
36
  ### Changed
package/dist/cli-main.js CHANGED
@@ -5604,14 +5604,14 @@ async function classifyConflict(llmClient, newEntry, existing, model, config) {
5604
5604
  verbose: false
5605
5605
  });
5606
5606
  if (response.stopReason === "error" || response.errorMessage) {
5607
- console.warn(
5607
+ console.error(
5608
5608
  `[contradiction] LLM judge error: ${response.errorMessage ?? "unknown stop reason"}`
5609
5609
  );
5610
5610
  return llmErrorResult();
5611
5611
  }
5612
5612
  const parsed = extractJudgeArgs(response);
5613
5613
  if (!parsed) {
5614
- console.warn("[contradiction] LLM judge returned unparseable response");
5614
+ console.error("[contradiction] LLM judge returned unparseable response");
5615
5615
  return llmErrorResult();
5616
5616
  }
5617
5617
  return {
@@ -5620,7 +5620,7 @@ async function classifyConflict(llmClient, newEntry, existing, model, config) {
5620
5620
  explanation: parsed.explanation
5621
5621
  };
5622
5622
  } catch (err) {
5623
- console.warn(
5623
+ console.error(
5624
5624
  `[contradiction] LLM judge call failed: ${err instanceof Error ? err.message : String(err)}`
5625
5625
  );
5626
5626
  return llmErrorResult();
@@ -5724,7 +5724,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
5724
5724
  conflict.result.confidence,
5725
5725
  "coexist"
5726
5726
  );
5727
- console.log(
5727
+ console.error(
5728
5728
  `[contradiction] resolution: coexist (events are immutable) entry=${conflict.existingEntryId.slice(0, 8)}`
5729
5729
  );
5730
5730
  return { action: "coexist", reason: "events are immutable" };
@@ -5753,7 +5753,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
5753
5753
  conflict.result.confidence,
5754
5754
  "auto-superseded"
5755
5755
  );
5756
- console.log(
5756
+ console.error(
5757
5757
  `[contradiction] resolution: auto-superseded entry=${conflict.existingEntryId.slice(0, 8)} (${conflict.existingType} confidence=${conflict.result.confidence.toFixed(2)})`
5758
5758
  );
5759
5759
  return {
@@ -5770,7 +5770,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
5770
5770
  conflict.result.confidence,
5771
5771
  "pending"
5772
5772
  );
5773
- console.log(
5773
+ console.error(
5774
5774
  `[contradiction] resolution: flagged for review entry=${conflict.existingEntryId.slice(0, 8)} (${conflict.result.relation} confidence=${conflict.result.confidence.toFixed(2)})`
5775
5775
  );
5776
5776
  return { action: "flagged", reason: "needs human review" };
@@ -5784,7 +5784,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
5784
5784
  conflict.result.confidence,
5785
5785
  "pending"
5786
5786
  );
5787
- console.log(
5787
+ console.error(
5788
5788
  `[contradiction] resolution: flagged for review entry=${conflict.existingEntryId.slice(0, 8)} (high-confidence supersedes blocked by importance)`
5789
5789
  );
5790
5790
  return { action: "flagged", reason: "high-confidence supersession blocked by importance" };
@@ -5797,7 +5797,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
5797
5797
  conflict.result.confidence,
5798
5798
  "coexist"
5799
5799
  );
5800
- console.log(
5800
+ console.error(
5801
5801
  `[contradiction] resolution: coexist entry=${conflict.existingEntryId.slice(0, 8)}`
5802
5802
  );
5803
5803
  return { action: "coexist", reason: "entries can coexist" };
@@ -7474,7 +7474,7 @@ async function storeEntries(db, entries, apiKey, options = {}) {
7474
7474
  }
7475
7475
  if (!entityHintsPromise) {
7476
7476
  entityHintsPromise = getDistinctEntities(db).catch((err) => {
7477
- console.warn(
7477
+ console.error(
7478
7478
  `[store] entity hints lookup failed, proceeding without hints: ${err instanceof Error ? err.message : String(err)}`
7479
7479
  );
7480
7480
  return [];
@@ -7679,7 +7679,7 @@ async function storeEntries(db, entries, apiKey, options = {}) {
7679
7679
  }
7680
7680
  if ((processed.mutation.kind === "add" || processed.mutation.kind === "add_related") && options.llmClient && options.contradictionEnabled !== false && processed.mutation.embedding) {
7681
7681
  await contradictionSubjectIndex.ensureInitialized(db);
7682
- console.log(
7682
+ console.error(
7683
7683
  `[contradiction] checking entry: type=${normalizedEntry.type} subject="${normalizedEntry.subject}" subjectKey=${normalizedEntry.subjectKey ?? "none"}`
7684
7684
  );
7685
7685
  const conflicts = await detectContradictions(
@@ -7700,11 +7700,11 @@ async function storeEntries(db, entries, apiKey, options = {}) {
7700
7700
  }
7701
7701
  );
7702
7702
  if (conflicts.length === 0) {
7703
- console.log("[contradiction] no conflicts detected");
7703
+ console.error("[contradiction] no conflicts detected");
7704
7704
  } else {
7705
- console.log(`[contradiction] found ${conflicts.length} conflict(s):`);
7705
+ console.error(`[contradiction] found ${conflicts.length} conflict(s):`);
7706
7706
  for (const c of conflicts) {
7707
- console.log(
7707
+ console.error(
7708
7708
  `[contradiction] vs entry=${c.existingEntryId.slice(0, 8)} relation=${c.result.relation} confidence=${c.result.confidence.toFixed(2)} explanation="${c.result.explanation.slice(0, 80)}"`
7709
7709
  );
7710
7710
  }
@@ -20756,15 +20756,13 @@ function normalizeSlugList(value) {
20756
20756
  function isPlatform(value) {
20757
20757
  return PLATFORM_VALUES.includes(value);
20758
20758
  }
20759
- function buildSystemPromptBlock(projectSlug) {
20759
+ function buildSystemPromptBlock(_projectSlug) {
20760
20760
  return [
20761
- "You have access to agenr_recall and agenr_store for persistent memory across sessions.",
20761
+ "You have access to agenr_recall for persistent memory across sessions.",
20762
20762
  "",
20763
20763
  'On session start, call agenr_recall with context="session-start" to load prior knowledge for this project. Mid-session, call agenr_recall with a query when you need context you do not have.',
20764
20764
  "",
20765
- `After any decision, user preference, lesson learned, or important event, immediately call agenr_store. Do not ask - just store it. Each entry needs: type (fact|decision|preference|todo|lesson|event), content (what and why), importance (1-10, default 7, use 9 for critical, 10 sparingly), project="${projectSlug}".`,
20766
- "",
20767
- "Do not store: secrets/credentials, temporary state, verbatim conversation, or information already in files."
20765
+ "Do NOT call agenr_store. That tool has been removed. Your session transcript is automatically ingested by the Watcher, which extracts valuable knowledge after the session ends. Focus on your task - the memory system captures insights for you."
20768
20766
  ].join("\n");
20769
20767
  }
20770
20768
  async function pathExists(targetPath) {
@@ -22427,7 +22425,6 @@ var RpcError = class extends Error {
22427
22425
  }
22428
22426
  };
22429
22427
  var KNOWLEDGE_TYPE_SET2 = new Set(KNOWLEDGE_TYPES);
22430
- var SCOPE_LEVEL_SET = new Set(SCOPE_LEVELS);
22431
22428
  var TOOL_DEFINITIONS = [
22432
22429
  {
22433
22430
  name: "agenr_recall",
@@ -22491,56 +22488,6 @@ var TOOL_DEFINITIONS = [
22491
22488
  }
22492
22489
  }
22493
22490
  },
22494
- {
22495
- name: "agenr_store",
22496
- description: "Store new knowledge entries in the database.",
22497
- inputSchema: {
22498
- type: "object",
22499
- additionalProperties: false,
22500
- required: ["entries"],
22501
- properties: {
22502
- platform: {
22503
- type: "string",
22504
- description: "Optional platform tag for all entries: openclaw, claude-code, codex."
22505
- },
22506
- project: {
22507
- type: "string",
22508
- description: "Optional project tag for all entries (lowercase)."
22509
- },
22510
- entries: {
22511
- type: "array",
22512
- items: {
22513
- type: "object",
22514
- additionalProperties: false,
22515
- required: ["content", "type"],
22516
- properties: {
22517
- content: { type: "string", minLength: 1 },
22518
- type: {
22519
- type: "string",
22520
- enum: [...KNOWLEDGE_TYPES]
22521
- },
22522
- importance: {
22523
- type: "integer",
22524
- minimum: 1,
22525
- maximum: 10,
22526
- default: 7
22527
- },
22528
- source: { type: "string" },
22529
- tags: {
22530
- type: "array",
22531
- items: { type: "string" }
22532
- },
22533
- scope: {
22534
- type: "string",
22535
- enum: [...SCOPE_LEVELS],
22536
- default: "personal"
22537
- }
22538
- }
22539
- }
22540
- }
22541
- }
22542
- }
22543
- },
22544
22491
  {
22545
22492
  name: "agenr_extract",
22546
22493
  description: "Extract knowledge entries from raw text.",
@@ -22554,11 +22501,6 @@ var TOOL_DEFINITIONS = [
22554
22501
  minLength: 1,
22555
22502
  description: "Raw text to extract knowledge from."
22556
22503
  },
22557
- store: {
22558
- type: "boolean",
22559
- default: false,
22560
- description: "Whether to store extracted entries."
22561
- },
22562
22504
  source: {
22563
22505
  type: "string",
22564
22506
  description: "Optional source label for extracted entries."
@@ -22717,95 +22659,6 @@ function parseCsvProjects(input) {
22717
22659
  }
22718
22660
  return parsed;
22719
22661
  }
22720
- function normalizeTags3(value) {
22721
- if (!Array.isArray(value)) {
22722
- return [];
22723
- }
22724
- return Array.from(
22725
- new Set(
22726
- value.filter((item) => typeof item === "string").map((item) => item.trim().toLowerCase()).filter((item) => item.length > 0)
22727
- )
22728
- );
22729
- }
22730
- function parseScope(value) {
22731
- if (value === void 0 || value === null || String(value).trim().length === 0) {
22732
- return "personal";
22733
- }
22734
- if (typeof value !== "string") {
22735
- throw new RpcError(JSON_RPC_INVALID_PARAMS, "scope must be a string");
22736
- }
22737
- const normalized = value.trim().toLowerCase();
22738
- if (!SCOPE_LEVEL_SET.has(normalized)) {
22739
- throw new RpcError(JSON_RPC_INVALID_PARAMS, `Invalid scope: ${value}`);
22740
- }
22741
- return normalized;
22742
- }
22743
- function normalizeImportance2(value) {
22744
- const parsed = value === void 0 ? 7 : Number(value);
22745
- if (!Number.isInteger(parsed) || parsed < 1 || parsed > 10) {
22746
- throw new RpcError(JSON_RPC_INVALID_PARAMS, "importance must be an integer between 1 and 10");
22747
- }
22748
- return parsed;
22749
- }
22750
- function inferSubject(content) {
22751
- const trimmed = content.trim();
22752
- if (!trimmed) {
22753
- return "memory";
22754
- }
22755
- const firstClause = trimmed.split(/[.!?:;]\s/)[0].trim();
22756
- if (!firstClause) {
22757
- return "memory";
22758
- }
22759
- if (firstClause.length <= 80) {
22760
- return firstClause;
22761
- }
22762
- const cut = firstClause.lastIndexOf(" ", 80);
22763
- return cut > 0 ? firstClause.slice(0, cut) : firstClause.slice(0, 80);
22764
- }
22765
- function parseStoreEntries(rawEntries) {
22766
- if (!Array.isArray(rawEntries)) {
22767
- throw new RpcError(JSON_RPC_INVALID_PARAMS, "entries must be an array");
22768
- }
22769
- return rawEntries.map((raw, index) => {
22770
- if (!isRecord2(raw)) {
22771
- throw new RpcError(JSON_RPC_INVALID_PARAMS, `entries[${index}] must be an object`);
22772
- }
22773
- const type = typeof raw.type === "string" ? raw.type.trim().toLowerCase() : "";
22774
- if (!type || !KNOWLEDGE_TYPE_SET2.has(type)) {
22775
- throw new RpcError(JSON_RPC_INVALID_PARAMS, `entries[${index}].type is invalid`);
22776
- }
22777
- const content = typeof raw.content === "string" ? raw.content.trim() : "";
22778
- if (!content) {
22779
- throw new RpcError(JSON_RPC_INVALID_PARAMS, `entries[${index}].content is required`);
22780
- }
22781
- const importance = (() => {
22782
- try {
22783
- return normalizeImportance2(raw.importance);
22784
- } catch {
22785
- throw new RpcError(
22786
- JSON_RPC_INVALID_PARAMS,
22787
- `entries[${index}].importance must be an integer between 1 and 10`
22788
- );
22789
- }
22790
- })();
22791
- const source = typeof raw.source === "string" && raw.source.trim().length > 0 ? raw.source.trim() : "mcp:agenr_store";
22792
- const subject = typeof raw.subject === "string" && raw.subject.trim().length > 0 ? raw.subject.trim() : inferSubject(content);
22793
- const scope = parseScope(raw.scope);
22794
- return {
22795
- type,
22796
- subject,
22797
- content,
22798
- importance,
22799
- expiry: "temporary",
22800
- tags: normalizeTags3(raw.tags),
22801
- scope,
22802
- source: {
22803
- file: source,
22804
- context: "stored via MCP tool"
22805
- }
22806
- };
22807
- });
22808
- }
22809
22662
  function formatDate(value) {
22810
22663
  if (!value) {
22811
22664
  return "unknown-date";
@@ -22857,15 +22710,7 @@ function formatBrowseText(results) {
22857
22710
  }
22858
22711
  return lines.join("\n");
22859
22712
  }
22860
- function formatStoreSummary(result) {
22861
- const total = result.added + result.updated + result.skipped + result.superseded;
22862
- const parts = [`${result.added} new`, `${result.updated} updated`, `${result.skipped} duplicates skipped`];
22863
- if (result.superseded > 0) {
22864
- parts.push(`${result.superseded} superseded`);
22865
- }
22866
- return `Stored ${total} entries (${parts.join(", ")}).`;
22867
- }
22868
- function formatExtractedText(entries, stored) {
22713
+ function formatExtractedText(entries) {
22869
22714
  const lines = [`Extracted ${entries.length} entries from text:`, ""];
22870
22715
  for (let i = 0; i < entries.length; i += 1) {
22871
22716
  const entry = entries[i];
@@ -22874,12 +22719,6 @@ function formatExtractedText(entries, stored) {
22874
22719
  }
22875
22720
  lines.push(`[${i + 1}] (${entry.type}) ${entry.content}`);
22876
22721
  }
22877
- if (stored) {
22878
- lines.push("");
22879
- lines.push(
22880
- `Stored: ${stored.added} new, ${stored.updated} updated, ${stored.skipped} duplicates skipped, ${stored.superseded} superseded.`
22881
- );
22882
- }
22883
22722
  return lines.join("\n");
22884
22723
  }
22885
22724
  function extractIdForError(raw) {
@@ -22919,7 +22758,6 @@ function createMcpServer(options = {}, deps = {}) {
22919
22758
  closeDbFn: deps.closeDbFn ?? closeDb,
22920
22759
  recallFn: deps.recallFn ?? recall,
22921
22760
  updateRecallMetadataFn: deps.updateRecallMetadataFn ?? updateRecallMetadata,
22922
- storeEntriesFn: deps.storeEntriesFn ?? storeEntries,
22923
22761
  retireEntriesFn: deps.retireEntriesFn ?? retireEntries,
22924
22762
  parseTranscriptFileFn: deps.parseTranscriptFileFn ?? parseTranscriptFile,
22925
22763
  extractKnowledgeFromChunksFn: deps.extractKnowledgeFromChunksFn ?? extractKnowledgeFromChunks,
@@ -23153,56 +22991,11 @@ function createMcpServer(options = {}, deps = {}) {
23153
22991
  }
23154
22992
  return formatRecallText(query || context, filtered);
23155
22993
  }
23156
- async function callStoreTool(args) {
23157
- if (!hasOwn(args, "entries")) {
23158
- throw new RpcError(JSON_RPC_INVALID_PARAMS, "entries is required");
23159
- }
23160
- const platformRaw = typeof args.platform === "string" ? args.platform.trim() : "";
23161
- const platform = platformRaw ? normalizeKnowledgePlatform(platformRaw) : null;
23162
- if (platformRaw && !platform) {
23163
- throw new RpcError(
23164
- JSON_RPC_INVALID_PARAMS,
23165
- `platform must be one of: ${KNOWLEDGE_PLATFORMS.join(", ")}`
23166
- );
23167
- }
23168
- const projectRaw = typeof args.project === "string" ? args.project.trim() : "";
23169
- const explicitProject = projectRaw ? normalizeProject(projectRaw) : null;
23170
- if (projectRaw && !explicitProject) {
23171
- throw new RpcError(JSON_RPC_INVALID_PARAMS, "project must be a non-empty string");
23172
- }
23173
- const scoped = !explicitProject ? await loadScopedProjectConfig() : null;
23174
- const project = explicitProject ?? scoped?.project ?? null;
23175
- const parsed = parseStoreEntries(args.entries);
23176
- const entries = platform || project ? parsed.map((entry) => ({
23177
- ...entry,
23178
- ...platform ? { platform } : {},
23179
- ...project ? { project } : {}
23180
- })) : parsed;
23181
- const db = await ensureDb();
23182
- const config = resolvedDeps.readConfigFn(env);
23183
- const aggressiveDedup = config?.dedup?.aggressive === true;
23184
- const configDedupThreshold = typeof config?.dedup?.threshold === "number" ? config.dedup.threshold : void 0;
23185
- const contradictionEnabled = config?.contradiction?.enabled !== false;
23186
- const dedupClient = resolvedDeps.createLlmClientFn({ config, env });
23187
- const apiKey = resolvedDeps.resolveEmbeddingApiKeyFn(config, env);
23188
- const result = await resolvedDeps.storeEntriesFn(db, entries, apiKey, {
23189
- sourceFile: "mcp:agenr_store",
23190
- onlineDedup: true,
23191
- llmClient: dedupClient,
23192
- aggressiveDedup,
23193
- dedupThreshold: configDedupThreshold,
23194
- contradictionEnabled,
23195
- config: config ?? void 0,
23196
- dbPath: options.dbPath
23197
- });
23198
- return formatStoreSummary(result);
23199
- }
23200
22994
  async function callExtractTool(args) {
23201
22995
  const text4 = typeof args.text === "string" ? args.text : "";
23202
22996
  if (!text4.trim()) {
23203
22997
  throw new RpcError(JSON_RPC_INVALID_PARAMS, "text is required");
23204
22998
  }
23205
- const shouldStore = args.store === true;
23206
22999
  const sourceLabel = typeof args.source === "string" && args.source.trim().length > 0 ? args.source.trim() : void 0;
23207
23000
  const tempDir = await resolvedDeps.mkdtempFn(path31.join(resolvedDeps.tmpdirFn(), "agenr-mcp-"));
23208
23001
  const tempFile = path31.join(tempDir, "input.txt");
@@ -23226,32 +23019,7 @@ function createMcpServer(options = {}, deps = {}) {
23226
23019
  context: entry.source.context
23227
23020
  }
23228
23021
  }));
23229
- let stored;
23230
- if (shouldStore && extractedEntries.length > 0) {
23231
- const db = await ensureDb();
23232
- const apiKey = resolvedDeps.resolveEmbeddingApiKeyFn(config, env);
23233
- const contradictionEnabled = config?.contradiction?.enabled !== false;
23234
- stored = await resolvedDeps.storeEntriesFn(db, extractedEntries, apiKey, {
23235
- sourceFile: sourceLabel ?? "mcp:agenr_extract",
23236
- onlineDedup: true,
23237
- llmClient: client,
23238
- contradictionEnabled,
23239
- config: config ?? void 0,
23240
- dbPath: options.dbPath
23241
- });
23242
- } else if (shouldStore) {
23243
- stored = {
23244
- added: 0,
23245
- updated: 0,
23246
- skipped: 0,
23247
- superseded: 0,
23248
- llm_dedup_calls: 0,
23249
- relations_created: 0,
23250
- total_entries: 0,
23251
- duration_ms: 0
23252
- };
23253
- }
23254
- return formatExtractedText(extractedEntries, stored);
23022
+ return formatExtractedText(extractedEntries);
23255
23023
  } finally {
23256
23024
  await resolvedDeps.rmFn(tempDir, { recursive: true, force: true });
23257
23025
  }
@@ -23310,22 +23078,6 @@ function createMcpServer(options = {}, deps = {}) {
23310
23078
  content: [{ type: "text", text: result }]
23311
23079
  };
23312
23080
  }
23313
- if (params.name === "agenr_store") {
23314
- const result = await callStoreTool(params.args);
23315
- const storeArgsEntries = Array.isArray(params.args.entries) ? params.args.entries : [];
23316
- const firstEntry = storeArgsEntries[0];
23317
- await appendMcpLog({
23318
- tool: "agenr_store",
23319
- count: storeArgsEntries.length,
23320
- firstType: typeof firstEntry?.type === "string" ? firstEntry.type : void 0,
23321
- firstSubject: typeof firstEntry?.subject === "string" ? firstEntry.subject.slice(0, 80) : void 0,
23322
- firstImportance: typeof firstEntry?.importance === "number" ? firstEntry.importance : void 0,
23323
- project: typeof params.args.project === "string" ? params.args.project : void 0
23324
- });
23325
- return {
23326
- content: [{ type: "text", text: result }]
23327
- };
23328
- }
23329
23081
  if (params.name === "agenr_extract") {
23330
23082
  return {
23331
23083
  content: [{ type: "text", text: await callExtractTool(params.args) }]
@@ -23783,8 +23535,8 @@ async function runRecallCommand(queryInput, options, deps) {
23783
23535
  budget,
23784
23536
  nonCoreLimit: limit
23785
23537
  });
23786
- finalResults = grouped.results;
23787
- budgetUsed = grouped.budgetUsed;
23538
+ finalResults = grouped.results.slice(0, limit);
23539
+ budgetUsed = finalResults.reduce((sum, item) => sum + estimateEntryTokens(item), 0);
23788
23540
  } else {
23789
23541
  const baseResults = await resolvedDeps.recallFn(db, queryForRecall, apiKey);
23790
23542
  if (budget === void 0) {
@@ -24187,7 +23939,7 @@ function readStdin() {
24187
23939
  process.stdin.on("error", reject);
24188
23940
  });
24189
23941
  }
24190
- function normalizeTags4(value) {
23942
+ function normalizeTags3(value) {
24191
23943
  if (!Array.isArray(value)) {
24192
23944
  return [];
24193
23945
  }
@@ -24248,7 +24000,7 @@ function normalizeEntry(raw, fallbackFile) {
24248
24000
  content,
24249
24001
  importance,
24250
24002
  expiry,
24251
- tags: normalizeTags4(record.tags),
24003
+ tags: normalizeTags3(record.tags),
24252
24004
  created_at: normalizeCreatedAt2(record.created_at),
24253
24005
  source: {
24254
24006
  file: sourceFile,
@@ -92,7 +92,7 @@ declare function capTranscriptLength(params: {
92
92
  currentSurface: string;
93
93
  maxChars: number;
94
94
  }): string;
95
- declare function summarizeSessionForHandoff(currentRawMessages: BeforeResetEvent["messages"], sessionsDir: string, currentSessionFile: string, logger: PluginApi["logger"], includeBackground: boolean, streamSimpleImpl?: StreamSimpleFn, logEnabled?: boolean, logDir?: string): Promise<string | null>;
95
+ declare function summarizeSessionForHandoff(currentRawMessages: BeforeResetEvent["messages"], sessionsDir: string, currentSessionFile: string, logger: PluginApi["logger"], includeBackground: boolean, streamSimpleImpl?: StreamSimpleFn, logEnabled?: boolean, logDir?: string, debugEnabled?: boolean): Promise<string | null>;
96
96
  declare function runHandoffForSession(opts: {
97
97
  messages: unknown[];
98
98
  sessionFile: string | null;
@@ -107,6 +107,7 @@ declare function runHandoffForSession(opts: {
107
107
  includeBackground?: boolean;
108
108
  logEnabled?: boolean;
109
109
  logDir?: string;
110
+ debugEnabled?: boolean;
110
111
  logger: PluginLogger | undefined;
111
112
  source: "before_reset" | "command" | "session_start";
112
113
  dbPath?: string;