@remnic/plugin-openclaw 9.69.53 → 9.69.54

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/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  import { loadDaySummaryPrompt } from "@remnic/core/day-summary";
18
18
  import OpenAI from "openai";
19
19
  import { createRequire } from "module";
20
- import { createHash as createHash4 } from "crypto";
20
+ import { createHash as createHash3 } from "crypto";
21
21
  import { parseConfig } from "@remnic/core/config";
22
22
  import { initLogger, log as log8 } from "@remnic/core/logger";
23
23
  import {
@@ -31,9 +31,9 @@ import {
31
31
  import { beginCodexSubscriptionShutdown, getCodexSubscriptionRunnerForOwner, terminateActiveCodexSubscriptionChildren } from "@remnic/core";
32
32
 
33
33
  // ../../src/tools.ts
34
- import { createHash as createHash2 } from "crypto";
34
+ import { createHash } from "crypto";
35
35
  import { Type as Type2 } from "@sinclair/typebox";
36
- import { indexMemoryAsync as indexMemoryAsync2, indexesExistAsync as indexesExistAsync2 } from "@remnic/core/temporal-index";
36
+ import { indexMemoryAsync, indexesExistAsync } from "@remnic/core/temporal-index";
37
37
 
38
38
  // ../../src/explicit-capture.ts
39
39
  import {
@@ -59,105 +59,8 @@ function mergeInlineCaptureDedupeKeys(messageKeys, fallbackDedupeKeys = []) {
59
59
 
60
60
  // ../../src/tools.ts
61
61
  import { log } from "@remnic/core/logger";
62
- import { composeSalvagedEnvelope as composeSalvagedEnvelope2 } from "@remnic/core/salvage-envelope";
63
-
64
- // ../../src/memory-promote.ts
65
- import { createHash } from "crypto";
66
62
  import { composeSalvagedEnvelope } from "@remnic/core/salvage-envelope";
67
- import {
68
- STRUCTURED_ATTRIBUTE_LIMITS,
69
- TAG_LIMITS
70
- } from "@remnic/core/write-envelope";
71
- import { stripAttributesSuffix } from "@remnic/core/storage";
72
- import { isSupportPassportPrivateMemory } from "@remnic/core/support-passport";
73
- import { displayErrorDetail } from "@remnic/core/runtime/better-sqlite";
74
- import { isSafeRouteNamespace } from "@remnic/core/routing/engine";
75
- import { indexMemoryAsync, indexesExistAsync } from "@remnic/core/temporal-index";
76
- function buildPromotionOrigin(srcNamespace, memoryId) {
77
- const memoryIdHash = createHash("sha256").update(memoryId).digest("hex");
78
- const fullTag = `promotedFrom:${srcNamespace}:${memoryId}`;
79
- return {
80
- tag: fullTag.length <= TAG_LIMITS.maxTagLength ? fullTag : `promotedFromHash:${memoryIdHash}`,
81
- structuredAttributes: {
82
- promotedFromNamespace: srcNamespace,
83
- promotedFromMemoryIdHash: memoryIdHash,
84
- ...memoryId.length <= STRUCTURED_ATTRIBUTE_LIMITS.maxValueLength ? { promotedFromMemoryId: memoryId } : {}
85
- }
86
- };
87
- }
88
- async function executeMemoryPromote(orchestrator, params) {
89
- const { memoryId, fromNamespace, toNamespace, note } = params;
90
- if (typeof memoryId !== "string" || memoryId.length === 0) {
91
- return `Invalid memoryId: ${JSON.stringify(memoryId)} \u2014 expected a non-empty memory ID.`;
92
- }
93
- for (const [name, value] of [
94
- ["fromNamespace", fromNamespace],
95
- ["toNamespace", toNamespace]
96
- ]) {
97
- if (value !== void 0 && value !== null && (typeof value !== "string" || !isSafeRouteNamespace(value))) {
98
- return `Invalid ${name}: ${JSON.stringify(value)} \u2014 expected a path-safe namespace name.`;
99
- }
100
- }
101
- const srcNs = fromNamespace ?? orchestrator.config.defaultNamespace;
102
- const dstNs = toNamespace ?? orchestrator.config.sharedNamespace;
103
- const src = await orchestrator.getStorage(srcNs);
104
- const mem = await src.getMemoryById(memoryId);
105
- if (!mem || isSupportPassportPrivateMemory(mem)) {
106
- return `Memory not found in ${srcNs}: ${memoryId}`;
107
- }
108
- const dst = await orchestrator.getStorage(dstNs);
109
- const promotionOrigin = buildPromotionOrigin(srcNs, memoryId);
110
- const promoteEnvelope = composeSalvagedEnvelope(
111
- "promote",
112
- {
113
- content: mem.frontmatter.structuredAttributes ? stripAttributesSuffix(mem.content) : mem.content,
114
- category: mem.frontmatter.category,
115
- confidence: mem.frontmatter.confidence,
116
- tags: (() => {
117
- const promotionTags = [
118
- "promoted",
119
- promotionOrigin.tag,
120
- ...note ? [`note:${note}`] : []
121
- ];
122
- const sourceTags = mem.frontmatter.tags ?? [];
123
- return Array.from(/* @__PURE__ */ new Set([...promotionTags, ...sourceTags])).slice(
124
- 0,
125
- TAG_LIMITS.maxTags
126
- );
127
- })(),
128
- structuredAttributes: promotionOrigin.structuredAttributes,
129
- entityRef: mem.frontmatter.entityRef
130
- },
131
- { source: "promote" }
132
- );
133
- const { id: newId, tombstoneBlocked } = await dst.writeSealedMemory(
134
- promoteEnvelope,
135
- {
136
- importance: mem.frontmatter.importance,
137
- supersedes: mem.frontmatter.supersedes,
138
- links: mem.frontmatter.links
139
- }
140
- );
141
- if (tombstoneBlocked) {
142
- return `Promotion of ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} is queued for review (tombstone-blocked): no active promoted copy was created.`;
143
- }
144
- try {
145
- if (orchestrator.config.queryAwareIndexingEnabled && await indexesExistAsync(orchestrator.config.memoryDir)) {
146
- const promoted = await dst.getMemoryById(newId).catch(() => null);
147
- if (promoted?.path && promoted.frontmatter?.created) {
148
- await indexMemoryAsync(
149
- orchestrator.config.memoryDir,
150
- promoted.path,
151
- promoted.frontmatter.created,
152
- promoted.frontmatter.tags ?? []
153
- );
154
- }
155
- }
156
- } catch (err) {
157
- return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} (index refresh failed \u2014 recall picks it up on the next maintenance pass: ${displayErrorDetail(err)})`;
158
- }
159
- return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId}`;
160
- }
63
+ import { executeMemoryPromote } from "@remnic/plugin-openclaw/plugin/memory-promote";
161
64
 
162
65
  // ../../src/shared-context-tools.ts
163
66
  import { Type } from "@sinclair/typebox";
@@ -372,49 +275,11 @@ import { wrapWorkLayerContext } from "@remnic/core/work/boundary";
372
275
  import { VALID_MEMORY_CATEGORIES } from "@remnic/core/config";
373
276
  import { formatProfileTraceAscii } from "@remnic/core/profiling";
374
277
  import { runMemoryGovernance } from "@remnic/core/maintenance/memory-governance";
375
-
376
- // ../../src/memory-action-target.ts
377
- import { isSupportPassportPrivateMemory as isSupportPassportPrivateMemory2 } from "@remnic/core";
378
- function clampUnitInterval(value, fallback) {
379
- if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
380
- if (value < 0) return 0;
381
- if (value > 1) return 1;
382
- return value;
383
- }
384
- function normalizeEligibilitySource(value) {
385
- switch (value) {
386
- case "extraction":
387
- case "consolidation":
388
- case "replay":
389
- case "manual":
390
- return value;
391
- default:
392
- return "unknown";
393
- }
394
- }
395
- function deriveMemoryActionPolicyEligibility(memory) {
396
- if (!memory) return void 0;
397
- const frontmatter = memory.frontmatter;
398
- return {
399
- confidence: clampUnitInterval(frontmatter.confidence, 0),
400
- lifecycleState: frontmatter.status === "archived" ? "archived" : frontmatter.lifecycleState ?? "candidate",
401
- importance: clampUnitInterval(frontmatter.importance?.score, 0),
402
- source: normalizeEligibilitySource(frontmatter.source)
403
- };
404
- }
405
- async function readReferencedMemoryForPolicyEligibility(storage, memoryId) {
406
- if (!memoryId) return void 0;
407
- const direct = await storage.getMemoryById?.(memoryId);
408
- if (direct) return direct;
409
- const active = (await storage.readAllMemories?.())?.find((memory) => memory.frontmatter.id === memoryId);
410
- if (active) return active;
411
- return (await storage.readArchivedMemories?.())?.find((memory) => memory.frontmatter.id === memoryId);
412
- }
413
- function blocksSupportPassportMutation(action, memory) {
414
- return (action === "update_note" || action === "discard" || action === "link_graph") && Boolean(memory && isSupportPassportPrivateMemory2(memory));
415
- }
416
-
417
- // ../../src/tools.ts
278
+ import {
279
+ blocksSupportPassportMutation,
280
+ deriveMemoryActionPolicyEligibility,
281
+ readReferencedMemoryForPolicyEligibility
282
+ } from "@remnic/plugin-openclaw/plugin/memory-action-target";
418
283
  function toolResult2(text) {
419
284
  return { content: [{ type: "text", text }], details: void 0 };
420
285
  }
@@ -599,7 +464,7 @@ function registerTools(api, orchestrator, hostRuntimeAgentId) {
599
464
  const actionTypeSet = new Set(actionTypes);
600
465
  function promptHashForTelemetry(input) {
601
466
  if (typeof input !== "string" || input.trim().length === 0) return void 0;
602
- return createHash2("sha256").update(input).digest("hex").slice(0, 16);
467
+ return createHash("sha256").update(input).digest("hex").slice(0, 16);
603
468
  }
604
469
  function normalizeMemoryCategory(value, fallback) {
605
470
  const normalized = asNonEmptyString(value);
@@ -654,11 +519,11 @@ function registerTools(api, orchestrator, hostRuntimeAgentId) {
654
519
  Content: ${candidate.content}`
655
520
  );
656
521
  }
657
- if (!result.duplicateOf && orchestrator.config.queryAwareIndexingEnabled && await indexesExistAsync2(orchestrator.config.memoryDir)) {
522
+ if (!result.duplicateOf && orchestrator.config.queryAwareIndexingEnabled && await indexesExistAsync(orchestrator.config.memoryDir)) {
658
523
  const storage = await orchestrator.getStorage(candidate.namespace);
659
524
  const mem = await storage.getMemoryById(result.id).catch(() => null);
660
525
  if (mem?.path && mem.frontmatter?.created) {
661
- await indexMemoryAsync2(orchestrator.config.memoryDir, mem.path, mem.frontmatter.created, mem.frontmatter.tags ?? []);
526
+ await indexMemoryAsync(orchestrator.config.memoryDir, mem.path, mem.frontmatter.created, mem.frontmatter.tags ?? []);
662
527
  }
663
528
  }
664
529
  orchestrator.requestQmdMaintenanceForTool(maintenanceReason);
@@ -1832,7 +1697,7 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
1832
1697
  let queuedForReview = false;
1833
1698
  switch (action) {
1834
1699
  case "store_episode": {
1835
- const episodeEnvelope = composeSalvagedEnvelope2(
1700
+ const episodeEnvelope = composeSalvagedEnvelope(
1836
1701
  "memory-action",
1837
1702
  { content: contentValue, category: normalizedCategory ?? "fact" },
1838
1703
  { source: "memory_action_apply" }
@@ -1851,7 +1716,7 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
1851
1716
  break;
1852
1717
  }
1853
1718
  case "store_note": {
1854
- const noteEnvelope = composeSalvagedEnvelope2(
1719
+ const noteEnvelope = composeSalvagedEnvelope(
1855
1720
  "memory-action",
1856
1721
  { content: contentValue, category: normalizedCategory ?? "fact" },
1857
1722
  { source: "memory_action_apply" }
@@ -1909,7 +1774,7 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
1909
1774
  break;
1910
1775
  }
1911
1776
  case "summarize_node": {
1912
- const summaryEnvelope = composeSalvagedEnvelope2(
1777
+ const summaryEnvelope = composeSalvagedEnvelope(
1913
1778
  "memory-action",
1914
1779
  { content: contentValue, category: normalizedCategory ?? "fact" },
1915
1780
  { source: "memory_action_apply" }
@@ -3165,7 +3030,7 @@ import path11 from "path";
3165
3030
  import os from "os";
3166
3031
  import { createOpikExporter } from "@remnic/core/opik-exporter";
3167
3032
  import { readEnvVar, resolveHomeDir as resolveHomeDir3 } from "@remnic/core/runtime/env";
3168
- import { displayErrorDetail as displayErrorDetail2 } from "@remnic/core/runtime/better-sqlite";
3033
+ import { displayErrorDetail } from "@remnic/core/runtime/better-sqlite";
3169
3034
  import { migrateFromEngram } from "@remnic/core/migrate/from-engram";
3170
3035
 
3171
3036
  // ../../src/user-message-cleaning.ts
@@ -3434,7 +3299,7 @@ function buildMemorySearchTool(orchestrator, options = {}) {
3434
3299
  }
3435
3300
 
3436
3301
  // src/runtime-surfaces.ts
3437
- import { composeSalvagedEnvelope as composeSalvagedEnvelope3 } from "@remnic/core/salvage-envelope";
3302
+ import { composeSalvagedEnvelope as composeSalvagedEnvelope2 } from "@remnic/core/salvage-envelope";
3438
3303
  import {
3439
3304
  gatewayTaskChainOptions
3440
3305
  } from "@remnic/core/fallback-llm";
@@ -3647,7 +3512,7 @@ async function syncDreamSurfaceEntries(params) {
3647
3512
  const existing = findSurfaceMemoryByAttribute(memories, DREAM_ENTRY_ID_KEY, entry.id);
3648
3513
  if (!existing) {
3649
3514
  const { id: memoryId } = await storage.writeSealedMemory(
3650
- composeSalvagedEnvelope3(
3515
+ composeSalvagedEnvelope2(
3651
3516
  "dreams-surface",
3652
3517
  { content, category: "moment", confidence: 0.85, tags, structuredAttributes },
3653
3518
  { source: "dreams.md" }
@@ -3707,7 +3572,7 @@ async function syncHeartbeatSurfaceEntries(params) {
3707
3572
  const existing = findSurfaceMemoryByAttribute(memories, HEARTBEAT_ENTRY_ID_KEY, entry.id) ?? findUniqueSurfaceMemoryBySlug(memories, HEARTBEAT_SURFACE_TYPE, entry.slug);
3708
3573
  if (!existing) {
3709
3574
  const { id: memoryId } = await storage.writeSealedMemory(
3710
- composeSalvagedEnvelope3(
3575
+ composeSalvagedEnvelope2(
3711
3576
  "heartbeat-surface",
3712
3577
  { content, category: "principle", confidence: 0.95, tags, structuredAttributes },
3713
3578
  { source: "heartbeat.md" }
@@ -4213,7 +4078,7 @@ function validateSlotSelection(ctx) {
4213
4078
 
4214
4079
  // ../../src/openclaw-flush-plan-lifecycle.ts
4215
4080
  import path2 from "path";
4216
- import { createHash as createHash3, randomUUID } from "crypto";
4081
+ import { createHash as createHash2, randomUUID } from "crypto";
4217
4082
  import {
4218
4083
  lstat as lstat2,
4219
4084
  mkdir,
@@ -4346,7 +4211,7 @@ function isPathInsideOrEqual(parentPath, childPath) {
4346
4211
  return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
4347
4212
  }
4348
4213
  function hashContent(content) {
4349
- return createHash3("sha256").update(content, "utf8").digest("hex");
4214
+ return createHash2("sha256").update(content, "utf8").digest("hex");
4350
4215
  }
4351
4216
  function utf8PrefixByByteLength(content, byteLength) {
4352
4217
  const buffer = Buffer.from(content, "utf8");
@@ -8913,7 +8778,7 @@ function buildTurnFingerprint(input) {
8913
8778
  import { planRecallMode } from "@remnic/core/intent";
8914
8779
  import {
8915
8780
  expandTildePath as expandTildePath3,
8916
- isSupportPassportPrivateMemory as isSupportPassportPrivateMemory3,
8781
+ isSupportPassportPrivateMemory,
8917
8782
  renderMemoryContextPrompt as renderSharedMemoryContextPrompt,
8918
8783
  resolveAgentAccessAuthToken,
8919
8784
  resolvePrincipal,
@@ -9633,7 +9498,7 @@ function stableOpenClawConfigSignature(value, seen = /* @__PURE__ */ new WeakSet
9633
9498
  return JSON.stringify(String(value));
9634
9499
  }
9635
9500
  function openClawHostEmbeddingConfigSignature(cfg, apiConfig, workspaceDir) {
9636
- return `sha256:${createHash4("sha256").update(JSON.stringify({
9501
+ return `sha256:${createHash3("sha256").update(JSON.stringify({
9637
9502
  enabled: cfg.hostEmbeddingProviderEnabled !== false,
9638
9503
  memoryDir: cfg.memoryDir,
9639
9504
  providerId: cfg.hostEmbeddingProviderId ?? "",
@@ -10031,7 +9896,7 @@ var pluginDefinition = {
10031
9896
  );
10032
9897
  }
10033
9898
  } catch (error) {
10034
- const detail = displayErrorDetail2(error) || "unknown error";
9899
+ const detail = displayErrorDetail(error) || "unknown error";
10035
9900
  log8.warn(`OpenClaw flush-plan processing failed: ${detail}`);
10036
9901
  }
10037
9902
  }
@@ -12174,7 +12039,7 @@ Keep the reflection grounded in the evidence below.
12174
12039
  const resolved = await readMemoryByLookup(lookup, agentSessionKey);
12175
12040
  if (!resolved) return null;
12176
12041
  const { memory, displayPath } = resolved;
12177
- if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) || isSupportPassportPrivateMemory3(memory)) {
12042
+ if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) || isSupportPassportPrivateMemory(memory)) {
12178
12043
  return null;
12179
12044
  }
12180
12045
  const allLines = memory.content.split(/\r?\n/);
@@ -12569,7 +12434,7 @@ function buildOpenClawInboundContentFingerprint(content, message, event, ctx, se
12569
12434
  normalizeThreadId(message.threadId) ?? normalizeThreadId(event.threadId) ?? normalizeThreadId(ctx.threadId) ?? "",
12570
12435
  512
12571
12436
  );
12572
- const contentHash = createHash4("sha256").update(normalizedContent).digest("hex");
12437
+ const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
12573
12438
  return [
12574
12439
  sessionPart,
12575
12440
  "content",
@@ -12583,7 +12448,7 @@ function buildOpenClawSparseInboundContentFingerprint(content, sessionKey) {
12583
12448
  const normalizedContent = content.trim();
12584
12449
  if (!normalizedContent) return null;
12585
12450
  const sessionPart = truncateMetadataValue(sessionKey || "default", 512);
12586
- const contentHash = createHash4("sha256").update(normalizedContent).digest("hex");
12451
+ const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
12587
12452
  return `${sessionPart}\0sparse-content\0${contentHash}`;
12588
12453
  }
12589
12454
  function withReplyExtractionHint(content, metadata) {
@@ -0,0 +1,11 @@
1
+ import { MemoryActionType, MemoryFile, MemoryActionEligibilityContext } from '@remnic/core/types';
2
+
3
+ declare function deriveMemoryActionPolicyEligibility(memory: Pick<MemoryFile, "frontmatter"> | null | undefined): MemoryActionEligibilityContext | undefined;
4
+ declare function readReferencedMemoryForPolicyEligibility(storage: {
5
+ getMemoryById?: (id: string) => Promise<MemoryFile | null>;
6
+ readAllMemories?: () => Promise<MemoryFile[]>;
7
+ readArchivedMemories?: () => Promise<MemoryFile[]>;
8
+ }, memoryId: string | undefined): Promise<MemoryFile | null | undefined>;
9
+ declare function blocksSupportPassportMutation(action: MemoryActionType, memory: Pick<MemoryFile, "frontmatter"> | null | undefined): boolean;
10
+
11
+ export { blocksSupportPassportMutation, deriveMemoryActionPolicyEligibility, readReferencedMemoryForPolicyEligibility };
@@ -0,0 +1,47 @@
1
+ import "../chunk-I2KLQ2HA.js";
2
+
3
+ // src/plugin/memory-action-target.ts
4
+ import { isSupportPassportPrivateMemory } from "@remnic/core";
5
+ function clampUnitInterval(value, fallback) {
6
+ if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
7
+ if (value < 0) return 0;
8
+ if (value > 1) return 1;
9
+ return value;
10
+ }
11
+ function normalizeEligibilitySource(value) {
12
+ switch (value) {
13
+ case "extraction":
14
+ case "consolidation":
15
+ case "replay":
16
+ case "manual":
17
+ return value;
18
+ default:
19
+ return "unknown";
20
+ }
21
+ }
22
+ function deriveMemoryActionPolicyEligibility(memory) {
23
+ if (!memory) return void 0;
24
+ const frontmatter = memory.frontmatter;
25
+ return {
26
+ confidence: clampUnitInterval(frontmatter.confidence, 0),
27
+ lifecycleState: frontmatter.status === "archived" ? "archived" : frontmatter.lifecycleState ?? "candidate",
28
+ importance: clampUnitInterval(frontmatter.importance?.score, 0),
29
+ source: normalizeEligibilitySource(frontmatter.source)
30
+ };
31
+ }
32
+ async function readReferencedMemoryForPolicyEligibility(storage, memoryId) {
33
+ if (!memoryId) return void 0;
34
+ const direct = await storage.getMemoryById?.(memoryId);
35
+ if (direct) return direct;
36
+ const active = (await storage.readAllMemories?.())?.find((memory) => memory.frontmatter.id === memoryId);
37
+ if (active) return active;
38
+ return (await storage.readArchivedMemories?.())?.find((memory) => memory.frontmatter.id === memoryId);
39
+ }
40
+ function blocksSupportPassportMutation(action, memory) {
41
+ return (action === "update_note" || action === "discard" || action === "link_graph") && Boolean(memory && isSupportPassportPrivateMemory(memory));
42
+ }
43
+ export {
44
+ blocksSupportPassportMutation,
45
+ deriveMemoryActionPolicyEligibility,
46
+ readReferencedMemoryForPolicyEligibility
47
+ };
@@ -0,0 +1,10 @@
1
+ import { Orchestrator } from '@remnic/core/orchestrator';
2
+
3
+ declare function executeMemoryPromote(orchestrator: Orchestrator, params: {
4
+ memoryId: string;
5
+ fromNamespace?: string;
6
+ toNamespace?: string;
7
+ note?: string;
8
+ }): Promise<string>;
9
+
10
+ export { executeMemoryPromote };
@@ -0,0 +1,102 @@
1
+ import "../chunk-I2KLQ2HA.js";
2
+
3
+ // src/plugin/memory-promote.ts
4
+ import { createHash } from "crypto";
5
+ import { composeSalvagedEnvelope } from "@remnic/core/salvage-envelope";
6
+ import {
7
+ STRUCTURED_ATTRIBUTE_LIMITS,
8
+ TAG_LIMITS
9
+ } from "@remnic/core/write-envelope";
10
+ import { stripAttributesSuffix } from "@remnic/core/storage";
11
+ import { isSupportPassportPrivateMemory } from "@remnic/core/support-passport";
12
+ import { displayErrorDetail } from "@remnic/core/runtime/better-sqlite";
13
+ import { isSafeRouteNamespace } from "@remnic/core/routing/engine";
14
+ import { indexMemoryAsync, indexesExistAsync } from "@remnic/core/temporal-index";
15
+ function buildPromotionOrigin(srcNamespace, memoryId) {
16
+ const memoryIdHash = createHash("sha256").update(memoryId).digest("hex");
17
+ const fullTag = `promotedFrom:${srcNamespace}:${memoryId}`;
18
+ return {
19
+ tag: fullTag.length <= TAG_LIMITS.maxTagLength ? fullTag : `promotedFromHash:${memoryIdHash}`,
20
+ structuredAttributes: {
21
+ promotedFromNamespace: srcNamespace,
22
+ promotedFromMemoryIdHash: memoryIdHash,
23
+ ...memoryId.length <= STRUCTURED_ATTRIBUTE_LIMITS.maxValueLength ? { promotedFromMemoryId: memoryId } : {}
24
+ }
25
+ };
26
+ }
27
+ async function executeMemoryPromote(orchestrator, params) {
28
+ const { memoryId, fromNamespace, toNamespace, note } = params;
29
+ if (typeof memoryId !== "string" || memoryId.length === 0) {
30
+ return `Invalid memoryId: ${JSON.stringify(memoryId)} \u2014 expected a non-empty memory ID.`;
31
+ }
32
+ for (const [name, value] of [
33
+ ["fromNamespace", fromNamespace],
34
+ ["toNamespace", toNamespace]
35
+ ]) {
36
+ if (value !== void 0 && value !== null && (typeof value !== "string" || !isSafeRouteNamespace(value))) {
37
+ return `Invalid ${name}: ${JSON.stringify(value)} \u2014 expected a path-safe namespace name.`;
38
+ }
39
+ }
40
+ const srcNs = fromNamespace ?? orchestrator.config.defaultNamespace;
41
+ const dstNs = toNamespace ?? orchestrator.config.sharedNamespace;
42
+ const src = await orchestrator.getStorage(srcNs);
43
+ const mem = await src.getMemoryById(memoryId);
44
+ if (!mem || isSupportPassportPrivateMemory(mem)) {
45
+ return `Memory not found in ${srcNs}: ${memoryId}`;
46
+ }
47
+ const dst = await orchestrator.getStorage(dstNs);
48
+ const promotionOrigin = buildPromotionOrigin(srcNs, memoryId);
49
+ const promoteEnvelope = composeSalvagedEnvelope(
50
+ "promote",
51
+ {
52
+ content: mem.frontmatter.structuredAttributes ? stripAttributesSuffix(mem.content) : mem.content,
53
+ category: mem.frontmatter.category,
54
+ confidence: mem.frontmatter.confidence,
55
+ tags: (() => {
56
+ const promotionTags = [
57
+ "promoted",
58
+ promotionOrigin.tag,
59
+ ...note ? [`note:${note}`] : []
60
+ ];
61
+ const sourceTags = mem.frontmatter.tags ?? [];
62
+ return Array.from(/* @__PURE__ */ new Set([...promotionTags, ...sourceTags])).slice(
63
+ 0,
64
+ TAG_LIMITS.maxTags
65
+ );
66
+ })(),
67
+ structuredAttributes: promotionOrigin.structuredAttributes,
68
+ entityRef: mem.frontmatter.entityRef
69
+ },
70
+ { source: "promote" }
71
+ );
72
+ const { id: newId, tombstoneBlocked } = await dst.writeSealedMemory(
73
+ promoteEnvelope,
74
+ {
75
+ importance: mem.frontmatter.importance,
76
+ supersedes: mem.frontmatter.supersedes,
77
+ links: mem.frontmatter.links
78
+ }
79
+ );
80
+ if (tombstoneBlocked) {
81
+ return `Promotion of ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} is queued for review (tombstone-blocked): no active promoted copy was created.`;
82
+ }
83
+ try {
84
+ if (orchestrator.config.queryAwareIndexingEnabled && await indexesExistAsync(orchestrator.config.memoryDir)) {
85
+ const promoted = await dst.getMemoryById(newId).catch(() => null);
86
+ if (promoted?.path && promoted.frontmatter?.created) {
87
+ await indexMemoryAsync(
88
+ orchestrator.config.memoryDir,
89
+ promoted.path,
90
+ promoted.frontmatter.created,
91
+ promoted.frontmatter.tags ?? []
92
+ );
93
+ }
94
+ }
95
+ } catch (err) {
96
+ return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId} (index refresh failed \u2014 recall picks it up on the next maintenance pass: ${displayErrorDetail(err)})`;
97
+ }
98
+ return `Promoted ${srcNs}:${memoryId} \u2192 ${dstNs}:${newId}`;
99
+ }
100
+ export {
101
+ executeMemoryPromote
102
+ };