@remnic/core 9.6.17 → 9.6.19

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.
Files changed (90) hide show
  1. package/dist/access-admin-ops-surface.js +9 -9
  2. package/dist/access-boundary.js +10 -10
  3. package/dist/access-cli.js +37 -36
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.js +16 -16
  6. package/dist/access-identity-continuity-surface.js +9 -9
  7. package/dist/access-lcm-surface.js +9 -9
  8. package/dist/access-mcp.js +15 -15
  9. package/dist/access-observe-write-surface.js +9 -9
  10. package/dist/access-operations-batch.js +12 -12
  11. package/dist/access-operations.js +14 -14
  12. package/dist/access-recall-surface.js +9 -9
  13. package/dist/access-schema.js +5 -5
  14. package/dist/access-service.js +9 -9
  15. package/dist/{capsule-crypto-RAARDY3M.js → capsule-crypto-CZJSLEFG.js} +2 -2
  16. package/dist/{chunk-EEIROWEG.js → chunk-2BFLDH5F.js} +2 -2
  17. package/dist/{chunk-UPSAT4PY.js → chunk-2MR3MFQB.js} +2 -2
  18. package/dist/{chunk-LNQUAJNC.js → chunk-437S3G37.js} +1 -1
  19. package/dist/{chunk-JZKR6ZAV.js → chunk-4Q2XWAHZ.js} +2 -2
  20. package/dist/{chunk-HR4NACR7.js → chunk-A2OFRQ5B.js} +5 -5
  21. package/dist/{chunk-D3YEDDCC.js → chunk-ARDRBJHD.js} +4 -4
  22. package/dist/{chunk-U4CWMKN6.js → chunk-B4LPRAWL.js} +2 -2
  23. package/dist/{chunk-L6NW2XSU.js → chunk-D3D677BV.js} +4 -4
  24. package/dist/{chunk-7WSLR2CU.js → chunk-DE6ENYLG.js} +2 -2
  25. package/dist/{chunk-DEG5ULFJ.js → chunk-DQ2CJYUM.js} +2 -2
  26. package/dist/{chunk-KTULX4YO.js → chunk-FLVL4L3L.js} +4 -4
  27. package/dist/{chunk-KJ3QGI63.js → chunk-GXLFDLX2.js} +6 -6
  28. package/dist/{chunk-MGN7VHWQ.js → chunk-HHAA35A3.js} +120 -7
  29. package/dist/chunk-HHAA35A3.js.map +1 -0
  30. package/dist/chunk-I6WYQSX4.js +99 -0
  31. package/dist/chunk-I6WYQSX4.js.map +1 -0
  32. package/dist/{chunk-JCEFF346.js → chunk-KEY3FEMP.js} +18 -18
  33. package/dist/{chunk-PYHOAXTI.js → chunk-LRGSLV7M.js} +4 -4
  34. package/dist/{chunk-CYWCKFCL.js → chunk-M5QKGHCR.js} +5 -5
  35. package/dist/{chunk-RSS3CZV7.js → chunk-MRQN5Q3I.js} +2 -2
  36. package/dist/{chunk-HLN7RROI.js → chunk-SFHI7JBE.js} +4 -4
  37. package/dist/{chunk-5TYS6NTK.js → chunk-XMNVHYI6.js} +84 -35
  38. package/dist/chunk-XMNVHYI6.js.map +1 -0
  39. package/dist/{chunk-ZZYLM6KQ.js → chunk-YDF4HL3W.js} +4 -4
  40. package/dist/cli.js +25 -25
  41. package/dist/contradiction/index.js +4 -4
  42. package/dist/{first-start-migration-VBJQL6OI.js → first-start-migration-4I3VDSYS.js} +4 -4
  43. package/dist/index.js +46 -45
  44. package/dist/lcm/index.js +3 -3
  45. package/dist/namespaces/migrate.js +4 -4
  46. package/dist/namespaces/search.js +3 -3
  47. package/dist/operator-toolkit.js +5 -5
  48. package/dist/orchestrator.js +39 -38
  49. package/dist/retrieval-agents.js +2 -2
  50. package/dist/search/factory.js +2 -2
  51. package/dist/search/index.js +4 -4
  52. package/dist/temporal-index.d.ts +42 -7
  53. package/dist/temporal-index.js +3 -1
  54. package/dist/temporal-timeline-recall.d.ts +24 -0
  55. package/dist/temporal-timeline-recall.js +8 -0
  56. package/dist/temporal-timeline-recall.js.map +1 -0
  57. package/dist/transfer/backup.js +3 -3
  58. package/dist/transfer/capsule-export.js +4 -4
  59. package/dist/transfer/capsule-import.js +3 -3
  60. package/dist/transfer/import-sqlite.js +2 -2
  61. package/package.json +2 -2
  62. package/src/lifecycle/tombstones.test.ts +78 -5
  63. package/src/orchestration/persistence-index.ts +15 -2
  64. package/src/orchestration/recall-internal.ts +77 -35
  65. package/src/temporal-index.test.ts +157 -0
  66. package/src/temporal-index.ts +211 -7
  67. package/src/temporal-timeline-recall.test.ts +70 -0
  68. package/src/temporal-timeline-recall.ts +111 -0
  69. package/dist/chunk-5TYS6NTK.js.map +0 -1
  70. package/dist/chunk-MGN7VHWQ.js.map +0 -1
  71. /package/dist/{capsule-crypto-RAARDY3M.js.map → capsule-crypto-CZJSLEFG.js.map} +0 -0
  72. /package/dist/{chunk-EEIROWEG.js.map → chunk-2BFLDH5F.js.map} +0 -0
  73. /package/dist/{chunk-UPSAT4PY.js.map → chunk-2MR3MFQB.js.map} +0 -0
  74. /package/dist/{chunk-LNQUAJNC.js.map → chunk-437S3G37.js.map} +0 -0
  75. /package/dist/{chunk-JZKR6ZAV.js.map → chunk-4Q2XWAHZ.js.map} +0 -0
  76. /package/dist/{chunk-HR4NACR7.js.map → chunk-A2OFRQ5B.js.map} +0 -0
  77. /package/dist/{chunk-D3YEDDCC.js.map → chunk-ARDRBJHD.js.map} +0 -0
  78. /package/dist/{chunk-U4CWMKN6.js.map → chunk-B4LPRAWL.js.map} +0 -0
  79. /package/dist/{chunk-L6NW2XSU.js.map → chunk-D3D677BV.js.map} +0 -0
  80. /package/dist/{chunk-7WSLR2CU.js.map → chunk-DE6ENYLG.js.map} +0 -0
  81. /package/dist/{chunk-DEG5ULFJ.js.map → chunk-DQ2CJYUM.js.map} +0 -0
  82. /package/dist/{chunk-KTULX4YO.js.map → chunk-FLVL4L3L.js.map} +0 -0
  83. /package/dist/{chunk-KJ3QGI63.js.map → chunk-GXLFDLX2.js.map} +0 -0
  84. /package/dist/{chunk-JCEFF346.js.map → chunk-KEY3FEMP.js.map} +0 -0
  85. /package/dist/{chunk-PYHOAXTI.js.map → chunk-LRGSLV7M.js.map} +0 -0
  86. /package/dist/{chunk-CYWCKFCL.js.map → chunk-M5QKGHCR.js.map} +0 -0
  87. /package/dist/{chunk-RSS3CZV7.js.map → chunk-MRQN5Q3I.js.map} +0 -0
  88. /package/dist/{chunk-HLN7RROI.js.map → chunk-SFHI7JBE.js.map} +0 -0
  89. /package/dist/{chunk-ZZYLM6KQ.js.map → chunk-YDF4HL3W.js.map} +0 -0
  90. /package/dist/{first-start-migration-VBJQL6OI.js.map → first-start-migration-4I3VDSYS.js.map} +0 -0
@@ -0,0 +1,70 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { buildTemporalTimelineRecallSection, type TemporalTimelineRecallItem } from "./temporal-timeline-recall.js";
5
+ import type { MemoryFile } from "./types.js";
6
+
7
+ function item(
8
+ id: string,
9
+ content: string,
10
+ eventAt: string,
11
+ sessionKey?: string,
12
+ ): TemporalTimelineRecallItem {
13
+ const memory: MemoryFile = {
14
+ path: `/memory/${id}.md`,
15
+ content,
16
+ frontmatter: {
17
+ id,
18
+ category: "fact",
19
+ created: "2026-07-01T00:00:00.000Z",
20
+ updated: "2026-07-01T00:00:00.000Z",
21
+ source: "test",
22
+ confidence: 0.9,
23
+ confidenceTier: "explicit",
24
+ tags: ["trip"],
25
+ },
26
+ };
27
+ return { memory, eventAt, ...(sessionKey ? { sessionKey } : {}) };
28
+ }
29
+
30
+ test("timeline selects query-relevant evidence then restores cross-session chronology", () => {
31
+ const output = buildTemporalTimelineRecallSection({
32
+ query: "Which trip happened first, Paris or Rome?",
33
+ maxChars: 4_000,
34
+ maxItems: 2,
35
+ items: [
36
+ item("rome", "Visited Rome in spring.", "2026-05-10T00:00:00.000Z", "session-b"),
37
+ item("noise", "Changed the database pool size.", "2026-01-01T00:00:00.000Z", "session-c"),
38
+ item("paris", "Visited Paris in winter.", "2026-03-04T00:00:00.000Z", "session-a"),
39
+ ],
40
+ });
41
+
42
+ assert.doesNotMatch(output, /database pool/);
43
+ assert.ok(output.indexOf("Visited Paris") < output.indexOf("Visited Rome"));
44
+ assert.match(output, /session=session-a/);
45
+ assert.match(output, /session=session-b/);
46
+ });
47
+
48
+ test("timeline dedupes replayed memory ids and uses a stable tie-break", () => {
49
+ const output = buildTemporalTimelineRecallSection({
50
+ query: "What happened first?",
51
+ maxChars: 4_000,
52
+ maxItems: 10,
53
+ items: [
54
+ item("b", "Second stable item.", "2026-03-04T00:00:00.000Z"),
55
+ item("a", "First stable item.", "2026-03-04T00:00:00.000Z"),
56
+ item("a", "REPLAY_MUST_NOT_SURFACE.", "2026-04-04T00:00:00.000Z"),
57
+ ],
58
+ });
59
+
60
+ assert.ok(output.indexOf("First stable item") < output.indexOf("Second stable item"));
61
+ assert.doesNotMatch(output, /REPLAY_MUST_NOT_SURFACE/);
62
+ });
63
+
64
+ test("timeline respects zero limits and clips within its character budget", () => {
65
+ const items = [item("a", "A long temporal event body.", "2026-03-04T00:00:00.000Z")];
66
+ assert.equal(buildTemporalTimelineRecallSection({ query: "when", maxChars: 0, maxItems: 1, items }), "");
67
+ assert.equal(buildTemporalTimelineRecallSection({ query: "when", maxChars: 100, maxItems: 0, items }), "");
68
+ const clipped = buildTemporalTimelineRecallSection({ query: "when", maxChars: 40, maxItems: 1, items });
69
+ assert.ok(clipped.length <= 40);
70
+ });
@@ -0,0 +1,111 @@
1
+ import type { MemoryFile } from "./types.js";
2
+
3
+ export interface TemporalTimelineRecallItem {
4
+ memory: MemoryFile;
5
+ eventAt: string;
6
+ observedAt?: string;
7
+ sessionKey?: string;
8
+ validUntil?: string;
9
+ }
10
+
11
+ export interface TemporalTimelineRecallOptions {
12
+ items: readonly TemporalTimelineRecallItem[];
13
+ query: string;
14
+ maxChars: number;
15
+ maxItems: number;
16
+ title?: string;
17
+ }
18
+
19
+ const QUERY_STOPWORDS = new Set([
20
+ "a", "an", "and", "did", "do", "first", "happened", "how", "i", "in",
21
+ "is", "it", "last", "many", "most", "my", "of", "on", "or", "recent",
22
+ "recently", "the", "to", "was", "what", "when", "which", "who", "with",
23
+ ]);
24
+
25
+ function queryTerms(query: string): string[] {
26
+ return [...new Set(
27
+ query
28
+ .toLowerCase()
29
+ .match(/[\p{L}\p{N}][\p{L}\p{N}'_-]*/gu)
30
+ ?.filter((term) => term.length > 1 && !QUERY_STOPWORDS.has(term)) ?? [],
31
+ )];
32
+ }
33
+
34
+ function relevanceScore(item: TemporalTimelineRecallItem, terms: readonly string[]): number {
35
+ if (terms.length === 0) return 1;
36
+ const haystack = `${item.memory.content} ${(item.memory.frontmatter.tags ?? []).join(" ")} ${item.memory.frontmatter.entityRef ?? ""}`.toLowerCase();
37
+ let score = 0;
38
+ for (const term of terms) {
39
+ if (haystack.includes(term)) score += 1;
40
+ }
41
+ return score;
42
+ }
43
+
44
+ function compareChronology(
45
+ left: TemporalTimelineRecallItem,
46
+ right: TemporalTimelineRecallItem,
47
+ ): number {
48
+ const eventOrder = left.eventAt.localeCompare(right.eventAt);
49
+ if (eventOrder !== 0) return eventOrder;
50
+ const observedOrder = (left.observedAt ?? "").localeCompare(right.observedAt ?? "");
51
+ if (observedOrder !== 0) return observedOrder;
52
+ return left.memory.frontmatter.id.localeCompare(right.memory.frontmatter.id);
53
+ }
54
+
55
+ function clip(text: string, maxChars: number): string {
56
+ if (text.length <= maxChars) return text;
57
+ if (maxChars <= 1) return text.slice(0, maxChars);
58
+ return `${text.slice(0, maxChars - 1).trimEnd()}…`;
59
+ }
60
+
61
+ /**
62
+ * Build a query-focused timeline from ingest-indexed memory primitives.
63
+ * Selection is relevance-first; presentation is always event-time ordered.
64
+ */
65
+ export function buildTemporalTimelineRecallSection(
66
+ options: TemporalTimelineRecallOptions,
67
+ ): string {
68
+ const maxChars = Number.isFinite(options.maxChars) ? Math.floor(options.maxChars) : 0;
69
+ const maxItems = Number.isFinite(options.maxItems) ? Math.floor(options.maxItems) : 0;
70
+ if (maxChars <= 0 || maxItems <= 0 || options.items.length === 0) return "";
71
+
72
+ const terms = queryTerms(options.query);
73
+ const uniqueById = new Map<string, TemporalTimelineRecallItem>();
74
+ for (const item of options.items) {
75
+ const id = item.memory.frontmatter.id;
76
+ const current = uniqueById.get(id);
77
+ if (!current || compareChronology(item, current) < 0) uniqueById.set(id, item);
78
+ }
79
+
80
+ const scored = [...uniqueById.values()].map((item) => ({
81
+ item,
82
+ score: relevanceScore(item, terms),
83
+ }));
84
+ const relevant = scored.some(({ score }) => score > 0)
85
+ ? scored.filter(({ score }) => score > 0)
86
+ : scored;
87
+ const selected = relevant
88
+ .sort((left, right) => {
89
+ if (right.score !== left.score) return right.score - left.score;
90
+ return compareChronology(left.item, right.item);
91
+ })
92
+ .slice(0, maxItems)
93
+ .map(({ item }) => item)
94
+ .sort(compareChronology);
95
+
96
+ const title = options.title ?? "Cross-session temporal timeline";
97
+ const lines = [
98
+ `## ${title}`,
99
+ "Ordered by event time across source sessions; event time is distinct from ingest time.",
100
+ ];
101
+ for (const item of selected) {
102
+ const provenance = [
103
+ `event=${item.eventAt}`,
104
+ item.validUntil ? `until<${item.validUntil}` : "",
105
+ item.observedAt ? `observed=${item.observedAt}` : "",
106
+ item.sessionKey ? `session=${item.sessionKey}` : "",
107
+ ].filter(Boolean).join(", ");
108
+ lines.push(`- [${provenance}] ${item.memory.content.trim()}`);
109
+ }
110
+ return clip(lines.join("\n"), maxChars);
111
+ }