@rubytech/create-realagent 1.0.828 → 1.0.830
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/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/lib/oauth-llm/dist/index.d.ts +1 -1
- package/payload/platform/lib/oauth-llm/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/oauth-llm/dist/index.js +21 -0
- package/payload/platform/lib/oauth-llm/dist/index.js.map +1 -1
- package/payload/platform/lib/oauth-llm/src/index.ts +24 -0
- package/payload/platform/neo4j/migrations/007-conversation-archive-source.ts +116 -0
- package/payload/platform/neo4j/schema.cypher +12 -2
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh +6 -6
- package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +14 -8
- package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +2 -2
- package/payload/platform/plugins/contacts/mcp/dist/index.js +5 -5
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +29 -23
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +6 -5
- package/payload/platform/plugins/{whatsapp-import/bin/ingest.mjs → memory/bin/conversation-archive-ingest.mjs} +136 -212
- package/payload/platform/plugins/{whatsapp-import/bin/whatsapp-ingest.sh → memory/bin/conversation-archive-ingest.sh} +27 -19
- package/payload/platform/plugins/memory/mcp/dist/index.js +26 -212
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +4 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js +11 -6
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js +103 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts +5 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js +30 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts +48 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js +23 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.d.ts +3 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.js +237 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.d.ts +11 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.js +21 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts +16 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js +39 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.d.ts +17 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.js +90 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.d.ts +9 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.js +32 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.d.ts +3 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.js +27 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.d.ts +45 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.js +125 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts +24 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +293 -33
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js +9 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts +16 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js +12 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js +75 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.js +67 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js +2 -138
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js +39 -3
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js +148 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +1 -47
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +9 -318
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts +7 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +14 -8
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +21 -17
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +77 -37
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
- package/payload/platform/plugins/memory/references/schema-base.md +3 -1
- package/payload/platform/plugins/{whatsapp-import/skills/whatsapp-import → memory/skills/conversation-archive}/SKILL.md +45 -36
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +59 -6
- package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
- package/payload/platform/scripts/seed-neo4j.sh +9 -8
- package/payload/platform/templates/specialists/agents/database-operator.md +7 -14
- package/payload/server/chunk-7BO5HDJC.js +10093 -0
- package/payload/server/chunk-CUSH3UXP.js +2305 -0
- package/payload/server/chunk-EL4DZ56X.js +1116 -0
- package/payload/server/chunk-IWNDVGKT.js +10077 -0
- package/payload/server/chunk-KC7NUABI.js +654 -0
- package/payload/server/chunk-QOJ2D26Z.js +654 -0
- package/payload/server/chunk-RC46ZYGT.js +2305 -0
- package/payload/server/chunk-WUVXPZIV.js +1116 -0
- package/payload/server/client-pool-3TM3SRIA.js +32 -0
- package/payload/server/client-pool-7NTEFNVQ.js +32 -0
- package/payload/server/cloudflare-task-tracker-4NIODMGL.js +19 -0
- package/payload/server/cloudflare-task-tracker-WE77WXSI.js +19 -0
- package/payload/server/maxy-edge.js +3 -3
- package/payload/server/neo4j-migrations-4XPNJNM6.js +490 -0
- package/payload/server/neo4j-migrations-XTQ4WEV6.js +428 -0
- package/payload/server/server.js +6 -6
- package/payload/platform/plugins/whatsapp-import/PLUGIN.md +0 -48
- package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/delta-append.test.ts +0 -163
- package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/parse-export-lrm.test.ts +0 -83
- package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/parse-export.test.ts +0 -678
- package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/sessionize.test.ts +0 -91
- package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/to-classifier-input.test.ts +0 -59
- package/payload/platform/plugins/whatsapp-import/lib/src/delta-cursor.ts +0 -54
- package/payload/platform/plugins/whatsapp-import/lib/src/derive-keys.ts +0 -82
- package/payload/platform/plugins/whatsapp-import/lib/src/index.ts +0 -22
- package/payload/platform/plugins/whatsapp-import/lib/src/parse-export.ts +0 -471
- package/payload/platform/plugins/whatsapp-import/lib/src/sessionize.ts +0 -81
- package/payload/platform/plugins/whatsapp-import/lib/src/to-classifier-input.ts +0 -48
- package/payload/platform/plugins/whatsapp-import/lib/tsconfig.json +0 -9
- package/payload/platform/plugins/whatsapp-import/lib/vitest.config.ts +0 -9
- package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/references/conversation-archive-shape.md +0 -143
- package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/references/export-parse.md +0 -109
|
@@ -50,7 +50,8 @@ import { nearestLabel } from "../../../../../lib/graph-mcp/dist/schema-cypher-pa
|
|
|
50
50
|
* this function emits — this stays a (mostly) pure unit so test fixtures
|
|
51
51
|
* can capture both the throw path and the emit stream.
|
|
52
52
|
*/
|
|
53
|
-
export function validateWrite(input, env) {
|
|
53
|
+
export function validateWrite(input, env, options = {}) {
|
|
54
|
+
const mode = options.mode ?? "create";
|
|
54
55
|
const startedMs = Date.now();
|
|
55
56
|
const { labels, properties, accountId } = input;
|
|
56
57
|
const emit = env.emit ?? defaultEmit;
|
|
@@ -131,10 +132,18 @@ export function validateWrite(input, env) {
|
|
|
131
132
|
// ---------------------------------------------------------------------
|
|
132
133
|
const definition = env.schema.markdownLabels.get(primaryLabel);
|
|
133
134
|
if (!definition) {
|
|
134
|
-
emit(`[schema-validator] check label=${primaryLabel} outcome=accepted source=${recognisedSource} ms=${Date.now() - startedMs}`);
|
|
135
|
+
emit(`[schema-validator] check label=${primaryLabel} mode=${mode} outcome=accepted source=${recognisedSource} ms=${Date.now() - startedMs}`);
|
|
135
136
|
emit(`[schema-validator] markdown-undocumented label=${primaryLabel}`);
|
|
136
137
|
return;
|
|
137
138
|
}
|
|
139
|
+
// Task 893 — `mode: "update"` skips the required-property loop only.
|
|
140
|
+
// Synonym + forbidden-property checks above already ran. The accept-path
|
|
141
|
+
// log line carries `mode=update` so partial writes are distinguishable in
|
|
142
|
+
// forensics from full creates.
|
|
143
|
+
if (mode === "update") {
|
|
144
|
+
emit(`[schema-validator] check label=${primaryLabel} mode=update outcome=accepted source=${recognisedSource} ms=${Date.now() - startedMs}`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
138
147
|
const effectiveProperties = {
|
|
139
148
|
...properties,
|
|
140
149
|
accountId,
|
|
@@ -146,7 +155,7 @@ export function validateWrite(input, env) {
|
|
|
146
155
|
}
|
|
147
156
|
}
|
|
148
157
|
emit(`[schema-validator] required-props label=${primaryLabel} outcome=satisfied`);
|
|
149
|
-
emit(`[schema-validator] check label=${primaryLabel} outcome=accepted source=${recognisedSource} ms=${Date.now() - startedMs}`);
|
|
158
|
+
emit(`[schema-validator] check label=${primaryLabel} mode=${mode} outcome=accepted source=${recognisedSource} ms=${Date.now() - startedMs}`);
|
|
150
159
|
}
|
|
151
160
|
// ---------------------------------------------------------------------------
|
|
152
161
|
// Helpers
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../src/lib/schema-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,2DAA2D,CAAC;
|
|
1
|
+
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../src/lib/schema-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-normalisers-source-agnosticism.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-normalisers-source-agnosticism.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { CONVERSATION_SOURCES, isConversationSource, } from "../../lib/conversation-normalisers/types.js";
|
|
3
|
+
import { getNormaliser, whatsappTextNormaliser } from "../../lib/conversation-normalisers/index.js";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Task 894 — source-agnosticism contract.
|
|
6
|
+
//
|
|
7
|
+
// The point of the refactor is that every normaliser produces the SAME
|
|
8
|
+
// `ParsedLine[]` shape and the SAME NormaliserResult contract regardless of
|
|
9
|
+
// source. Downstream pipeline code (sessionize, classify, memory-ingest)
|
|
10
|
+
// must not branch on `source` — only on the normaliser output.
|
|
11
|
+
//
|
|
12
|
+
// This file pins that contract: a stub normaliser and the live whatsapp-text
|
|
13
|
+
// normaliser are interchangeable from the writer's perspective; `source`
|
|
14
|
+
// flows through as a property only.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
describe("ConversationSource enum", () => {
|
|
17
|
+
it("includes the closed Phase-0 set", () => {
|
|
18
|
+
const expected = [
|
|
19
|
+
"whatsapp",
|
|
20
|
+
"telegram",
|
|
21
|
+
"signal",
|
|
22
|
+
"linkedin-messages",
|
|
23
|
+
"zoom-transcript",
|
|
24
|
+
"meeting-minutes",
|
|
25
|
+
"imessage",
|
|
26
|
+
"slack",
|
|
27
|
+
"other",
|
|
28
|
+
];
|
|
29
|
+
expect([...CONVERSATION_SOURCES].sort()).toEqual(expected.sort());
|
|
30
|
+
});
|
|
31
|
+
it("isConversationSource accepts members and rejects everything else", () => {
|
|
32
|
+
expect(isConversationSource("whatsapp")).toBe(true);
|
|
33
|
+
expect(isConversationSource("slack")).toBe(true);
|
|
34
|
+
expect(isConversationSource("Whatsapp")).toBe(false); // case-sensitive enum
|
|
35
|
+
expect(isConversationSource("twitter")).toBe(false);
|
|
36
|
+
expect(isConversationSource(undefined)).toBe(false);
|
|
37
|
+
expect(isConversationSource(123)).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("getNormaliser registry", () => {
|
|
41
|
+
it("returns the whatsapp-text normaliser for source='whatsapp'", () => {
|
|
42
|
+
expect(getNormaliser("whatsapp")).toBe(whatsappTextNormaliser);
|
|
43
|
+
});
|
|
44
|
+
it("loud-fails on an enum member that has no normaliser yet", () => {
|
|
45
|
+
expect(() => getNormaliser("telegram")).toThrow(/no normaliser implemented for source="telegram"/);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe("ConversationNormaliser shape parity", () => {
|
|
49
|
+
// A stub normaliser — proves the pipeline path is uniform across sources.
|
|
50
|
+
const stubNormaliser = () => ({
|
|
51
|
+
parsedLines: [
|
|
52
|
+
{ senderName: "Alice", dateSent: "2026-04-30T10:00:00+00:00", body: "hi", sequenceIndex: 0 },
|
|
53
|
+
{ senderName: "Bob", dateSent: "2026-04-30T10:01:00+00:00", body: "yo", sequenceIndex: 1 },
|
|
54
|
+
],
|
|
55
|
+
archiveSha256: "0".repeat(64),
|
|
56
|
+
archiveSourceFile: "stub.txt",
|
|
57
|
+
counters: { parsed: 2, systemSkipped: 0, mediaSkipped: 0, parseErrors: 0 },
|
|
58
|
+
});
|
|
59
|
+
it("a stub normaliser and the live whatsapp-text normaliser produce structurally identical NormaliserResult shapes", () => {
|
|
60
|
+
const stubResult = stubNormaliser({ filePath: "/dev/null", accountId: "acct", timezone: "UTC" });
|
|
61
|
+
expect("parsedLines" in stubResult).toBe(true);
|
|
62
|
+
expect("archiveSha256" in stubResult).toBe(true);
|
|
63
|
+
expect("archiveSourceFile" in stubResult).toBe(true);
|
|
64
|
+
expect("counters" in stubResult).toBe(true);
|
|
65
|
+
// Sanity-check ParsedLine field set on the stub. We do not call the real
|
|
66
|
+
// whatsapp-text here (that needs a fixture); the parity is enforced at
|
|
67
|
+
// the type level via the shared `ParsedLine` import.
|
|
68
|
+
const line = stubResult.parsedLines[0];
|
|
69
|
+
expect(typeof line.senderName).toBe("string");
|
|
70
|
+
expect(typeof line.dateSent).toBe("string");
|
|
71
|
+
expect(typeof line.body).toBe("string");
|
|
72
|
+
expect(typeof line.sequenceIndex).toBe("number");
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=conversation-normalisers-source-agnosticism.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-normalisers-source-agnosticism.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-normalisers-source-agnosticism.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-normalisers-whatsapp-text.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-normalisers-whatsapp-text.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { whatsappTextNormaliser } from "../../lib/conversation-normalisers/whatsapp-text.js";
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Task 894 — minimal grammar gate for the relocated WhatsApp `_chat.txt`
|
|
8
|
+
// parser. The full pre-894 grid lived in the retired whatsapp-import plugin's
|
|
9
|
+
// `__tests__/parse-export.test.ts`; this file preserves the LOUD-FAIL
|
|
10
|
+
// fingerprints that proved load-bearing across Tasks 805 / 845 / 887.
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
describe("whatsapp-text normaliser", () => {
|
|
13
|
+
let tmp = "";
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
tmp = mkdtempSync(join(tmpdir(), "whatsapp-text-test-"));
|
|
16
|
+
});
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
19
|
+
});
|
|
20
|
+
function writeChat(content) {
|
|
21
|
+
const filePath = join(tmp, "_chat.txt");
|
|
22
|
+
writeFileSync(filePath, content, "utf-8");
|
|
23
|
+
return filePath;
|
|
24
|
+
}
|
|
25
|
+
it("parses a 4-digit-year DD/MM line into ParsedLine with senderName + body + ISO dateSent", () => {
|
|
26
|
+
const filePath = writeChat(`[15/04/2024, 09:30:00] Joel: hi adam\n`);
|
|
27
|
+
const result = whatsappTextNormaliser({ filePath, accountId: "acct-1", timezone: "Europe/London" });
|
|
28
|
+
expect(result.parsedLines).toHaveLength(1);
|
|
29
|
+
expect(result.parsedLines[0].senderName).toBe("Joel");
|
|
30
|
+
expect(result.parsedLines[0].body).toBe("hi adam");
|
|
31
|
+
expect(result.parsedLines[0].dateSent).toMatch(/^2024-04-15T09:30:00\+0[01]:00$/);
|
|
32
|
+
});
|
|
33
|
+
it("accepts both 2-digit and 4-digit years in the same file (Task 845)", () => {
|
|
34
|
+
const filePath = writeChat(`[15/04/24, 09:30:00] Joel: legacy line\n[15/04/2024, 09:31:00] Joel: modern line\n`);
|
|
35
|
+
const result = whatsappTextNormaliser({ filePath, accountId: "acct-1", timezone: "Europe/London" });
|
|
36
|
+
expect(result.parsedLines).toHaveLength(2);
|
|
37
|
+
expect(result.parsedLines[0].dateSent.startsWith("2024-")).toBe(true);
|
|
38
|
+
expect(result.parsedLines[1].dateSent.startsWith("2024-")).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
it("strips leading bidi marks (LRM/RLM) without polluting the next sender (Task 887)", () => {
|
|
41
|
+
// U+200E LRM prefix on a header line — the pre-887 pattern that leaked 23
|
|
42
|
+
// bogus :Person nodes from the Adam Mackay archive.
|
|
43
|
+
const filePath = writeChat(`[15/04/2024, 09:30:00] Joel: line one\n[15/04/2024, 09:31:00] Adam: line two\n`);
|
|
44
|
+
const result = whatsappTextNormaliser({ filePath, accountId: "acct-1", timezone: "Europe/London" });
|
|
45
|
+
expect(result.parsedLines).toHaveLength(2);
|
|
46
|
+
expect(result.parsedLines[1].senderName).toBe("Adam");
|
|
47
|
+
expect(result.parsedLines[1].body).toBe("line two");
|
|
48
|
+
});
|
|
49
|
+
it("LOUD-FAILs on a no-sender-body-separator line that isn't a known system message", () => {
|
|
50
|
+
const filePath = writeChat(`[15/04/2024, 09:30:00] this is malformed\n`);
|
|
51
|
+
expect(() => whatsappTextNormaliser({ filePath, accountId: "acct-1", timezone: "Europe/London" })).toThrow(/parse-error.*no-sender-body-separator/);
|
|
52
|
+
});
|
|
53
|
+
it("counts media-only lines as mediaSkipped (no parsedLine, no LOUD-FAIL)", () => {
|
|
54
|
+
const filePath = writeChat(`[15/04/2024, 09:30:00] Joel: <Media omitted>\n[15/04/2024, 09:31:00] Joel: real msg\n`);
|
|
55
|
+
const result = whatsappTextNormaliser({ filePath, accountId: "acct-1", timezone: "Europe/London" });
|
|
56
|
+
expect(result.parsedLines).toHaveLength(1);
|
|
57
|
+
expect(result.counters.mediaSkipped).toBe(1);
|
|
58
|
+
});
|
|
59
|
+
it("returns a stable archiveSha256 for identical bytes (cleanup discriminator)", () => {
|
|
60
|
+
const fp = writeChat(`[15/04/2024, 09:30:00] Joel: stable\n`);
|
|
61
|
+
const a = whatsappTextNormaliser({ filePath: fp, accountId: "acct-1", timezone: "Europe/London" });
|
|
62
|
+
const b = whatsappTextNormaliser({ filePath: fp, accountId: "acct-1", timezone: "Europe/London" });
|
|
63
|
+
expect(a.archiveSha256).toBe(b.archiveSha256);
|
|
64
|
+
expect(a.archiveSha256).toMatch(/^[a-f0-9]{64}$/);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=conversation-normalisers-whatsapp-text.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-normalisers-whatsapp-text.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/conversation-normalisers-whatsapp-text.test.ts"],"names":[],"mappings":"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"}
|
package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js
CHANGED
|
@@ -27,12 +27,8 @@
|
|
|
27
27
|
* (not inside a FOREACH-with-non-empty-guard, because the LinkedIn export
|
|
28
28
|
* is a current-job snapshot — re-import without a title is authoritative).
|
|
29
29
|
*/
|
|
30
|
-
import { describe, it, expect
|
|
31
|
-
import {
|
|
32
|
-
import { tmpdir } from "node:os";
|
|
33
|
-
import { join } from "node:path";
|
|
34
|
-
import { createHash } from "node:crypto";
|
|
35
|
-
import { PERSON_AND_CONNECTED_EDGE_CYPHER, ORG_AND_WORKS_FOR_CYPHER, WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER, WHATSAPP_NEXT_CHAIN_CYPHER, verifyArchiveSourceFileHash, } from "../memory-archive-write.js";
|
|
30
|
+
import { describe, it, expect } from "vitest";
|
|
31
|
+
import { PERSON_AND_CONNECTED_EDGE_CYPHER, ORG_AND_WORKS_FOR_CYPHER, } from "../memory-archive-write.js";
|
|
36
32
|
describe("memory-archive-write — Task 753 currentTitle denormalisation", () => {
|
|
37
33
|
it("PERSON_AND_CONNECTED_EDGE_CYPHER writes p.currentTitle = row.title in the SET clause", () => {
|
|
38
34
|
expect(PERSON_AND_CONNECTED_EDGE_CYPHER).toMatch(/p\.currentTitle\s*=\s*row\.title/);
|
|
@@ -70,42 +66,6 @@ describe("memory-archive-write — Task 753 currentTitle denormalisation", () =>
|
|
|
70
66
|
expect(PERSON_AND_CONNECTED_EDGE_CYPHER).toMatch(/p\.familyName\s*=\s*row\.familyName/);
|
|
71
67
|
});
|
|
72
68
|
});
|
|
73
|
-
describe("verifyArchiveSourceFileHash — Task 805 hash gate", () => {
|
|
74
|
-
let workDir;
|
|
75
|
-
beforeEach(() => {
|
|
76
|
-
workDir = mkdtempSync(join(tmpdir(), "archive-hash-gate-"));
|
|
77
|
-
});
|
|
78
|
-
afterEach(() => {
|
|
79
|
-
rmSync(workDir, { recursive: true, force: true });
|
|
80
|
-
});
|
|
81
|
-
it("accepts a matching hash silently", () => {
|
|
82
|
-
const filePath = join(workDir, "_chat.txt");
|
|
83
|
-
const content = "[14/03/26, 10:15:23] Joel: Hello\n";
|
|
84
|
-
writeFileSync(filePath, content);
|
|
85
|
-
const expected = `whatsapp-export:${createHash("sha256").update(content).digest("hex")}`;
|
|
86
|
-
expect(() => verifyArchiveSourceFileHash(filePath, expected)).not.toThrow();
|
|
87
|
-
});
|
|
88
|
-
it("throws on hash mismatch with the operator-supplied vs actual values named", () => {
|
|
89
|
-
const filePath = join(workDir, "_chat.txt");
|
|
90
|
-
writeFileSync(filePath, "real file contents\n");
|
|
91
|
-
const wrong = "whatsapp-export:0000000000000000000000000000000000000000000000000000000000000000";
|
|
92
|
-
expect(() => verifyArchiveSourceFileHash(filePath, wrong)).toThrow(/hash mismatch.*operator-supplied=.*actual=/);
|
|
93
|
-
});
|
|
94
|
-
it("throws when the file cannot be read (path doesn't exist)", () => {
|
|
95
|
-
const missing = join(workDir, "does-not-exist.txt");
|
|
96
|
-
expect(() => verifyArchiveSourceFileHash(missing, "whatsapp-export:abc")).toThrow(/failed to read archiveFilePath/);
|
|
97
|
-
});
|
|
98
|
-
it("uses the whatsapp-export:<hex> envelope (matches parseExport output)", () => {
|
|
99
|
-
const filePath = join(workDir, "_chat.txt");
|
|
100
|
-
const content = "x";
|
|
101
|
-
writeFileSync(filePath, content);
|
|
102
|
-
// Compose a deliberately-malformed expected (no envelope) so the gate
|
|
103
|
-
// surfaces it as a mismatch — proves the gate compares the full
|
|
104
|
-
// `whatsapp-export:<hex>` form, not just the bare hex.
|
|
105
|
-
const bareHex = createHash("sha256").update(content).digest("hex");
|
|
106
|
-
expect(() => verifyArchiveSourceFileHash(filePath, bareHex)).toThrow(/hash mismatch/);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
69
|
describe("memory-archive-write — Task 754 connectedOn stays edge-only", () => {
|
|
110
70
|
it("does NOT denormalise connectedOn onto the Person (no backfill required for existing installs)", () => {
|
|
111
71
|
// Task 754 deliberately rejected the Task-753-style denormalisation
|
|
@@ -121,100 +81,4 @@ describe("memory-archive-write — Task 754 connectedOn stays edge-only", () =>
|
|
|
121
81
|
expect(PERSON_AND_CONNECTED_EDGE_CYPHER).toMatch(/c\.connectedOn\s*=\s*date\(row\.connectedOn\)/);
|
|
122
82
|
});
|
|
123
83
|
});
|
|
124
|
-
describe("memory-archive-write — Task 804 whatsapp-export Cypher gates", () => {
|
|
125
|
-
it("MERGEs Conversation on the base label only and SETs sublabel in ON CREATE (Task 633 pattern)", () => {
|
|
126
|
-
// Constraint-safe sublabel pattern — MERGE base, SET sublabel in ON CREATE.
|
|
127
|
-
// MERGEing on `:Conversation:WhatsAppConversation` directly would refuse
|
|
128
|
-
// to match a pre-existing base-label-only node and CREATE a duplicate
|
|
129
|
-
// that violates `conversationId IS UNIQUE` on `:Conversation`.
|
|
130
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/MERGE\s*\(\s*c:Conversation\s*\{\s*conversationId:/);
|
|
131
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).not.toMatch(/MERGE\s*\(\s*c:Conversation:WhatsAppConversation/);
|
|
132
|
-
// Sublabel applied in ON CREATE SET (the SET-list begins with `c:Sublabel`).
|
|
133
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/ON CREATE SET\s*\n\s*c:WhatsAppConversation/);
|
|
134
|
-
});
|
|
135
|
-
it("MERGEs Message on the base label only and SETs sublabel in ON CREATE", () => {
|
|
136
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/MERGE\s*\(\s*m:Message\s*\{\s*messageId:/);
|
|
137
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).not.toMatch(/MERGE\s*\(\s*m:Message:WhatsAppMessage/);
|
|
138
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/ON CREATE SET\s*\n\s*m:WhatsAppMessage/);
|
|
139
|
-
});
|
|
140
|
-
it("stamps source='whatsapp' provenance on Conversation creation", () => {
|
|
141
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/c\.source\s*=\s*'whatsapp'/);
|
|
142
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/c\.createdByAgent\s*=\s*'whatsapp-import'/);
|
|
143
|
-
});
|
|
144
|
-
it("stamps source='whatsapp' provenance on Message creation", () => {
|
|
145
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/m\.source\s*=\s*'whatsapp'/);
|
|
146
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/m\.createdByAgent\s*=\s*'whatsapp-import'/);
|
|
147
|
-
});
|
|
148
|
-
it("ON MATCH refreshes Conversation lastMessageAt / messageCount / participantCount on re-import", () => {
|
|
149
|
-
const onMatch = WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER.match(/ON MATCH SET([\s\S]+?)WITH owner, c, rows/);
|
|
150
|
-
expect(onMatch).not.toBeNull();
|
|
151
|
-
const onMatchBlock = onMatch[1];
|
|
152
|
-
expect(onMatchBlock).toMatch(/c\.lastMessageAt\s*=\s*datetime/);
|
|
153
|
-
expect(onMatchBlock).toMatch(/c\.messageCount\s*=/);
|
|
154
|
-
expect(onMatchBlock).toMatch(/c\.participantCount\s*=/);
|
|
155
|
-
expect(onMatchBlock).toMatch(/c\.lastImportedAt\s*=\s*datetime\(\)/);
|
|
156
|
-
expect(onMatchBlock).toMatch(/c\.lastImportedBySession\s*=\s*\$sessionId/);
|
|
157
|
-
// Sublabel SET in ON MATCH too — handles the case where a Task-633-era
|
|
158
|
-
// re-import lands against a pre-Task-633 unsublabelled :Conversation
|
|
159
|
-
// node (sublabel-on-write enforcement extends to re-import).
|
|
160
|
-
expect(onMatchBlock).toMatch(/c:WhatsAppConversation/);
|
|
161
|
-
});
|
|
162
|
-
it("ON MATCH does NOT overwrite createdByAgent / createdAt / accountId on re-import", () => {
|
|
163
|
-
const onMatch = WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER.match(/ON MATCH SET([\s\S]+?)WITH owner, c, rows/);
|
|
164
|
-
expect(onMatch).not.toBeNull();
|
|
165
|
-
const onMatchBlock = onMatch[1];
|
|
166
|
-
expect(onMatchBlock).not.toMatch(/c\.createdByAgent/);
|
|
167
|
-
expect(onMatchBlock).not.toMatch(/c\.createdAt/);
|
|
168
|
-
expect(onMatchBlock).not.toMatch(/c\.accountId/);
|
|
169
|
-
});
|
|
170
|
-
it("MERGEs PART_OF and SENT and PARTICIPANT_IN edges (no CREATE)", () => {
|
|
171
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/MERGE\s*\(m\)-\[:PART_OF\]->\(c\)/);
|
|
172
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/MERGE\s*\(sender\)-\[s:SENT\]->\(m\)/);
|
|
173
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/MERGE\s*\(sender\)-\[p:PARTICIPANT_IN\]->\(c\)/);
|
|
174
|
-
// Defensive: no CREATE-edge slip-ins for these edges.
|
|
175
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).not.toMatch(/CREATE\s*\([^)]+\)-\[:PART_OF\]/);
|
|
176
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).not.toMatch(/CREATE\s*\([^)]+\)-\[:SENT\]/);
|
|
177
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).not.toMatch(/CREATE\s*\([^)]+\)-\[:PARTICIPANT_IN\]/);
|
|
178
|
-
});
|
|
179
|
-
it("matches sender by elementId (not by name) so SENT edge writes are operator-confirmed", () => {
|
|
180
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/MATCH\s*\(sender\)\s*WHERE\s*elementId\(sender\)\s*=\s*row\.senderNodeId/);
|
|
181
|
-
// Sender lookup must NOT MERGE on senderName — that would silently mint
|
|
182
|
-
// a node when confirmation drift produced a missing nodeId.
|
|
183
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).not.toMatch(/MERGE\s*\(sender[^)]*\bname:/);
|
|
184
|
-
});
|
|
185
|
-
it("Message body stored verbatim — no truncation, no normalisation", () => {
|
|
186
|
-
// Body lands as-is; markdown-style WhatsApp formatting (*bold*, _italic_)
|
|
187
|
-
// is preserved for query-time concerns. No SUBSTRING / REPLACE on the body.
|
|
188
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).toMatch(/m\.body\s*=\s*row\.body/);
|
|
189
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).not.toMatch(/SUBSTRING\(row\.body/);
|
|
190
|
-
expect(WHATSAPP_CONVERSATION_AND_MESSAGES_CYPHER).not.toMatch(/REPLACE\(row\.body/);
|
|
191
|
-
});
|
|
192
|
-
it("WHATSAPP_NEXT_CHAIN_CYPHER scopes by conversationId (not session, not date-range)", () => {
|
|
193
|
-
expect(WHATSAPP_NEXT_CHAIN_CYPHER).toMatch(/MATCH\s*\(c:Conversation:WhatsAppConversation\s*\{conversationId:\s*\$conversationId\}\)/);
|
|
194
|
-
// Must NOT scope by session — re-import on a different session must still
|
|
195
|
-
// chain pre-existing messages with newly-appended ones.
|
|
196
|
-
expect(WHATSAPP_NEXT_CHAIN_CYPHER).not.toMatch(/createdBySession\s*=\s*\$sessionId/);
|
|
197
|
-
});
|
|
198
|
-
it("WHATSAPP_NEXT_CHAIN_CYPHER orders by dateSent ASC, sequenceIndex ASC, messageId ASC (total ordering)", () => {
|
|
199
|
-
// Tertiary tiebreaker on messageId makes ordering total even when two
|
|
200
|
-
// messages collide on (dateSent, sequenceIndex). Without it Neo4j's
|
|
201
|
-
// ordering of equal keys is undefined and the chain topology drifts
|
|
202
|
-
// across re-imports.
|
|
203
|
-
expect(WHATSAPP_NEXT_CHAIN_CYPHER).toMatch(/ORDER BY m\.dateSent\s+ASC,\s*m\.sequenceIndex\s+ASC,\s*m\.messageId\s+ASC/);
|
|
204
|
-
});
|
|
205
|
-
it("WHATSAPP_NEXT_CHAIN_CYPHER guards against self-loops (defensive WHERE prev <> next)", () => {
|
|
206
|
-
// Even though MERGE on (m:Message {messageId}) deduplicates by natural key
|
|
207
|
-
// — so msgs[i] !== msgs[i+1] in practice — the explicit WHERE clause is
|
|
208
|
-
// a free defensive belt against any future change that breaks the
|
|
209
|
-
// dedup property (e.g. accidentally MATCHing through a non-key edge).
|
|
210
|
-
expect(WHATSAPP_NEXT_CHAIN_CYPHER).toMatch(/WHERE\s+prev\s*<>\s*next/);
|
|
211
|
-
});
|
|
212
|
-
it("WHATSAPP_NEXT_CHAIN_CYPHER MERGEs NEXT (not CREATE) — re-import must be idempotent", () => {
|
|
213
|
-
expect(WHATSAPP_NEXT_CHAIN_CYPHER).toMatch(/MERGE\s*\(prev\)-\[r:NEXT\]->\(next\)/);
|
|
214
|
-
expect(WHATSAPP_NEXT_CHAIN_CYPHER).not.toMatch(/CREATE\s*\(prev\)-\[[^\]]*:NEXT\]/);
|
|
215
|
-
});
|
|
216
|
-
it("WHATSAPP_NEXT_CHAIN_CYPHER returns nextEdges count for the finalize log line", () => {
|
|
217
|
-
expect(WHATSAPP_NEXT_CHAIN_CYPHER).toMatch(/RETURN\s+count\(r\)\s+AS\s+nextEdges/);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
84
|
//# sourceMappingURL=memory-archive-write.test.js.map
|
package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-archive-write.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/memory-archive-write.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"memory-archive-write.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/memory-archive-write.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,gCAAgC,EAChC,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AAEpC,QAAQ,CAAC,8DAA8D,EAAE,GAAG,EAAE;IAC5E,EAAE,CAAC,sFAAsF,EAAE,GAAG,EAAE;QAC9F,MAAM,CAAC,gCAAgC,CAAC,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+FAA+F,EAAE,GAAG,EAAE;QACvG,mEAAmE;QACnE,mEAAmE;QACnE,2DAA2D;QAC3D,MAAM,aAAa,GAAG,gCAAgC,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACvF,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,aAAc,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6GAA6G,EAAE,GAAG,EAAE;QACrH,sEAAsE;QACtE,uEAAuE;QACvE,oCAAoC;QACpC,MAAM,CAAC,wBAAwB,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4FAA4F,EAAE,GAAG,EAAE;QACpG,yEAAyE;QACzE,sEAAsE;QACtE,sDAAsD;QACtD,MAAM,CAAC,gCAAgC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,wEAAwE;IACxE,2EAA2E;IAC3E,0DAA0D;IAC1D,EAAE,CAAC,iGAAiG,EAAE,GAAG,EAAE;QACzG,MAAM,CAAC,gCAAgC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,uEAAuE;QACvE,MAAM,CAAC,gCAAgC,CAAC,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;QACtF,MAAM,CAAC,gCAAgC,CAAC,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,6DAA6D,EAAE,GAAG,EAAE;IAC3E,EAAE,CAAC,+FAA+F,EAAE,GAAG,EAAE;QACvG,oEAAoE;QACpE,iEAAiE;QACjE,mEAAmE;QACnE,qEAAqE;QACrE,iEAAiE;QACjE,0DAA0D;QAC1D,MAAM,CAAC,gCAAgC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;QAC/E,MAAM,CAAC,gCAAgC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sGAAsG,EAAE,GAAG,EAAE;QAC9G,MAAM,CAAC,gCAAgC,CAAC,CAAC,OAAO,CAAC,+CAA+C,CAAC,CAAC;IACpG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -10,18 +10,23 @@ function readIngest() {
|
|
|
10
10
|
return readFileSync(INGEST_PATH, "utf-8");
|
|
11
11
|
}
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
|
-
// Task 891 — memory-ingest
|
|
13
|
+
// Task 891 / 894 — memory-ingest carries a `parentLabel: 'KnowledgeDocument' |
|
|
14
14
|
// 'ConversationArchive'` parameter. ConversationArchive mode MERGEs on
|
|
15
15
|
// `conversationIdentity` (delivered via `attachmentId`), cleans up only
|
|
16
16
|
// THIS export's chunks (by `archiveSha256`), extends the existing NEXT chain
|
|
17
17
|
// from its tail, and MERGEs :PARTICIPANT_IN edges off the parent.
|
|
18
18
|
//
|
|
19
|
+
// Task 894 retired the deterministic `_chat.txt` parser + delta-cursor
|
|
20
|
+
// orchestrator; the `lastIngestedMessageHash` / `lastIngestedMessageAt`
|
|
21
|
+
// inputs (delta-cursor advance signal) became vestigial when their producer
|
|
22
|
+
// was deleted, so they're no longer required and no longer SET on the parent.
|
|
23
|
+
//
|
|
19
24
|
// Document-mode behaviour is unchanged from Task 740 (anchor edges, related
|
|
20
25
|
// entities, documentEdges, orphan candidates all preserved).
|
|
21
26
|
//
|
|
22
27
|
// Tests assert the contract by reading source — same pattern as the
|
|
23
28
|
// memory-archive-write doctrine tests in this directory. Live Cypher is
|
|
24
|
-
// exercised by the operator-run integration test on the laptop
|
|
29
|
+
// exercised by the operator-run integration test on the laptop.
|
|
25
30
|
// ---------------------------------------------------------------------------
|
|
26
31
|
describe("memory-ingest — Task 891 ConversationArchive contract", () => {
|
|
27
32
|
it("declares parentLabel: 'KnowledgeDocument' | 'ConversationArchive' on IngestParams", () => {
|
|
@@ -44,7 +49,7 @@ describe("memory-ingest — Task 891 ConversationArchive contract", () => {
|
|
|
44
49
|
it("MERGEs :PARTICIPANT_IN edges from operator-confirmed participants to the parent", () => {
|
|
45
50
|
expect(readIngest()).toMatch(/MERGE\s*\(p\)-\[r:PARTICIPANT_IN\]->\(a\)/);
|
|
46
51
|
});
|
|
47
|
-
it("records lastIngestedMessageHash + lastIngestedMessageAt on the parent (cursor advance)", () => {
|
|
52
|
+
it("records lastIngestedMessageHash + lastIngestedMessageAt on the parent (cursor advance, set by the bash orchestrator)", () => {
|
|
48
53
|
const source = readIngest();
|
|
49
54
|
expect(source).toMatch(/a\.lastIngestedMessageHash\s*=\s*\$lastIngestedMessageHash/);
|
|
50
55
|
expect(source).toMatch(/a\.lastIngestedMessageAt\s*=\s*\$lastIngestedMessageAt/);
|
|
@@ -58,4 +63,35 @@ describe("memory-ingest — document mode preserved (Task 740 contract)", () =>
|
|
|
58
63
|
expect(readIngest()).toMatch(/MERGE\s*\(d:KnowledgeDocument\s*\{\s*attachmentId:\s*\$attachmentId\s*\}\s*\)/);
|
|
59
64
|
});
|
|
60
65
|
});
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Task 894 — `source` becomes a closed-enum property on :ConversationArchive
|
|
68
|
+
// and :Section:Conversation. Provenance agent renamed from 'whatsapp-import'
|
|
69
|
+
// (per-source) to 'conversation-archive' (source-agnostic). Source enum is
|
|
70
|
+
// imported from conversation-normalisers/types.ts; memory-ingest validates it
|
|
71
|
+
// at the boundary so silent typos cannot reach the index.
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
describe("memory-ingest — Task 894 source-agnostic provenance", () => {
|
|
74
|
+
it("declares source: ConversationSource on IngestParams", () => {
|
|
75
|
+
expect(readIngest()).toMatch(/source\??:\s*ConversationSource/);
|
|
76
|
+
});
|
|
77
|
+
it("imports the closed-enum guard from conversation-normalisers/types", () => {
|
|
78
|
+
expect(readIngest()).toMatch(/from\s+["']\.\.\/lib\/conversation-normalisers\/types\.js["']/);
|
|
79
|
+
expect(readIngest()).toMatch(/isConversationSource/);
|
|
80
|
+
});
|
|
81
|
+
it("validates source at the ConversationArchive entry — loud-fail on missing or invalid", () => {
|
|
82
|
+
expect(readIngest()).toMatch(/!isConversationSource\(source\)/);
|
|
83
|
+
expect(readIngest()).toMatch(/source is required for parentLabel='ConversationArchive'/);
|
|
84
|
+
});
|
|
85
|
+
it("renames the chat-mode createdByAgent to 'conversation-archive' (was 'whatsapp-import')", () => {
|
|
86
|
+
const source = readIngest();
|
|
87
|
+
expect(source).toMatch(/CHAT_PROVENANCE_AGENT\s*=\s*["']conversation-archive["']/);
|
|
88
|
+
expect(source).not.toMatch(/CHAT_PROVENANCE_AGENT\s*=\s*["']whatsapp-import["']/);
|
|
89
|
+
});
|
|
90
|
+
it("threads the dynamic `source` parameter into node + edge stamps (no hardcoded 'whatsapp')", () => {
|
|
91
|
+
const source = readIngest();
|
|
92
|
+
// The legacy `CHAT_PROVENANCE_SOURCE` constant is gone; every chat-branch
|
|
93
|
+
// SET clause that stamps `source` reads from the params now.
|
|
94
|
+
expect(source).not.toMatch(/CHAT_PROVENANCE_SOURCE/);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
61
97
|
//# sourceMappingURL=memory-ingest.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-ingest.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/memory-ingest.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC1D,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,4BAA4B,CAAC,CAAC;AAExE,SAAS,UAAU;IACjB,OAAO,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED,8EAA8E;AAC9E
|
|
1
|
+
{"version":3,"file":"memory-ingest.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/memory-ingest.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-update-personfields-open.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/profile-update-personfields-open.test.ts"],"names":[],"mappings":""}
|