@remnic/plugin-openclaw 9.69.53 → 9.69.55

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");
@@ -5379,9 +5244,10 @@ import { log as log2 } from "@remnic/core/logger";
5379
5244
  // src/bridge.ts
5380
5245
  import fs3 from "fs";
5381
5246
  import path6 from "path";
5382
- import { isIPv4, isIPv6 } from "net";
5247
+ import { isIPv6 } from "net";
5383
5248
  import { Worker } from "worker_threads";
5384
5249
  import { configPathCandidates, readCompatEnv } from "@remnic/core";
5250
+ import { isLoopbackHost } from "@remnic/core/runtime/http-transport.js";
5385
5251
 
5386
5252
  // src/bridge-health-worker.ts
5387
5253
  function runHealthWorker(request, data) {
@@ -6183,17 +6049,8 @@ function isDaemonRunning() {
6183
6049
  }
6184
6050
  function isLoopbackDaemonHost(host) {
6185
6051
  const normalized = host.trim().toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
6186
- if (normalized === "localhost") return true;
6187
6052
  if (loopbackForWildcardBind(normalized) !== void 0) return true;
6188
- const ipv6 = canonicalIPv6(normalized);
6189
- if (ipv6 !== void 0) {
6190
- if (ipv6 === "::1") return true;
6191
- const mappedHex = /^::ffff:([0-9a-f]{1,4}):[0-9a-f]{1,4}$/.exec(ipv6);
6192
- if (mappedHex !== null) return Number.parseInt(mappedHex[1], 16) >> 8 === 127;
6193
- const mappedDotted = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(ipv6);
6194
- return mappedDotted !== null && isIPv4(mappedDotted[1]) && mappedDotted[1].split(".")[0] === "127";
6195
- }
6196
- return isIPv4(normalized) && normalized.split(".")[0] === "127";
6053
+ return isLoopbackHost(normalized);
6197
6054
  }
6198
6055
  function canonicalIPv6(value) {
6199
6056
  if (!isIPv6(value)) return void 0;
@@ -8913,7 +8770,7 @@ function buildTurnFingerprint(input) {
8913
8770
  import { planRecallMode } from "@remnic/core/intent";
8914
8771
  import {
8915
8772
  expandTildePath as expandTildePath3,
8916
- isSupportPassportPrivateMemory as isSupportPassportPrivateMemory3,
8773
+ isSupportPassportPrivateMemory,
8917
8774
  renderMemoryContextPrompt as renderSharedMemoryContextPrompt,
8918
8775
  resolveAgentAccessAuthToken,
8919
8776
  resolvePrincipal,
@@ -9633,7 +9490,7 @@ function stableOpenClawConfigSignature(value, seen = /* @__PURE__ */ new WeakSet
9633
9490
  return JSON.stringify(String(value));
9634
9491
  }
9635
9492
  function openClawHostEmbeddingConfigSignature(cfg, apiConfig, workspaceDir) {
9636
- return `sha256:${createHash4("sha256").update(JSON.stringify({
9493
+ return `sha256:${createHash3("sha256").update(JSON.stringify({
9637
9494
  enabled: cfg.hostEmbeddingProviderEnabled !== false,
9638
9495
  memoryDir: cfg.memoryDir,
9639
9496
  providerId: cfg.hostEmbeddingProviderId ?? "",
@@ -10031,7 +9888,7 @@ var pluginDefinition = {
10031
9888
  );
10032
9889
  }
10033
9890
  } catch (error) {
10034
- const detail = displayErrorDetail2(error) || "unknown error";
9891
+ const detail = displayErrorDetail(error) || "unknown error";
10035
9892
  log8.warn(`OpenClaw flush-plan processing failed: ${detail}`);
10036
9893
  }
10037
9894
  }
@@ -12174,7 +12031,7 @@ Keep the reflection grounded in the evidence below.
12174
12031
  const resolved = await readMemoryByLookup(lookup, agentSessionKey);
12175
12032
  if (!resolved) return null;
12176
12033
  const { memory, displayPath } = resolved;
12177
- if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) || isSupportPassportPrivateMemory3(memory)) {
12034
+ if (isMemoryArtifactPath(displayPath) || isMemoryArtifactPath(memory.path) || isSupportPassportPrivateMemory(memory)) {
12178
12035
  return null;
12179
12036
  }
12180
12037
  const allLines = memory.content.split(/\r?\n/);
@@ -12569,7 +12426,7 @@ function buildOpenClawInboundContentFingerprint(content, message, event, ctx, se
12569
12426
  normalizeThreadId(message.threadId) ?? normalizeThreadId(event.threadId) ?? normalizeThreadId(ctx.threadId) ?? "",
12570
12427
  512
12571
12428
  );
12572
- const contentHash = createHash4("sha256").update(normalizedContent).digest("hex");
12429
+ const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
12573
12430
  return [
12574
12431
  sessionPart,
12575
12432
  "content",
@@ -12583,7 +12440,7 @@ function buildOpenClawSparseInboundContentFingerprint(content, sessionKey) {
12583
12440
  const normalizedContent = content.trim();
12584
12441
  if (!normalizedContent) return null;
12585
12442
  const sessionPart = truncateMetadataValue(sessionKey || "default", 512);
12586
- const contentHash = createHash4("sha256").update(normalizedContent).digest("hex");
12443
+ const contentHash = createHash3("sha256").update(normalizedContent).digest("hex");
12587
12444
  return `${sessionPart}\0sparse-content\0${contentHash}`;
12588
12445
  }
12589
12446
  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
+ };