@rubytech/create-maxy-code 0.1.373 → 0.1.375
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/__tests__/cgroup-memory-controller-install-flow.test.js +41 -0
- package/dist/__tests__/cgroup-memory-controller.test.js +32 -0
- package/dist/cgroup-memory-controller.js +33 -0
- package/dist/index.js +54 -0
- package/package.json +1 -1
- package/payload/platform/neo4j/schema.cypher +9 -4
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +7 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +43 -8
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.js +50 -2
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +17 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +40 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +1 -4
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js +18 -36
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/ics-graph-ingest.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/ics-graph-ingest.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/ics-graph-ingest.test.js +153 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/ics-graph-ingest.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-write.test.js +11 -19
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-write.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +0 -2
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +10 -17
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.d.ts +13 -7
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js +38 -33
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.js +13 -19
- package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.js.map +1 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +6 -4
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +31 -15
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/scripts/migrate-whatsapp-to-disk.mjs +115 -0
- package/payload/platform/scripts/rss-sampler.sh +18 -2
- package/payload/platform/scripts/seed-neo4j.sh +17 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +34 -14
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +2 -2
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +19 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +42 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +10 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +25 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-cap-audit.d.ts +75 -4
- package/payload/platform/services/claude-session-manager/dist/session-cap-audit.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-cap-audit.js +138 -15
- package/payload/platform/services/claude-session-manager/dist/session-cap-audit.js.map +1 -1
- package/payload/server/public/assets/AdminLoginScreens-3vFueaZy.js +1 -0
- package/payload/server/public/assets/AdminShell-DvczcTdp.js +1 -0
- package/payload/server/public/assets/{Checkbox-BagcrE4Q.js → Checkbox-KbEWQEVU.js} +1 -1
- package/payload/server/public/assets/{admin-CodAEpgQ.js → admin-Cm1tZXbf.js} +1 -1
- package/payload/server/public/assets/{browser-CRTlI7ck.js → browser-C38YYs28.js} +1 -1
- package/payload/server/public/assets/{calendar-BBEivUAw.js → calendar-CCN9px9o.js} +1 -1
- package/payload/server/public/assets/chat-fj5J5aKV.js +1 -0
- package/payload/server/public/assets/data-D1EXeX7P.js +1 -0
- package/payload/server/public/assets/{graph-HoHcI7qv.js → graph-DGXKuRbL.js} +3 -3
- package/payload/server/public/assets/{graph-labels-BJfK0tbH.js → graph-labels-DYRDEL2l.js} +1 -1
- package/payload/server/public/assets/{operator-5wtImBoF.js → operator-Bhtayf9U.js} +1 -1
- package/payload/server/public/assets/{page-CzTgPTp3.js → page-BSMtFFmx.js} +5 -5
- package/payload/server/public/assets/{public-CUopv7Ro.js → public-DO_OqjJa.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-DttFB1nY.js → rotate-ccw-DQfsmjLr.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-CSCcvysa.css +1 -0
- package/payload/server/public/assets/useSubAccountSwitcher-z8xhukFw.js +9 -0
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +4 -4
- package/payload/server/public/chat.html +6 -6
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +7 -7
- package/payload/server/public/index.html +6 -6
- package/payload/server/public/operator.html +8 -8
- package/payload/server/public/public.html +6 -6
- package/payload/server/server.js +1169 -964
- package/payload/server/public/assets/AdminLoginScreens-CGTA9noi.js +0 -1
- package/payload/server/public/assets/AdminShell-CNwb23_A.js +0 -1
- package/payload/server/public/assets/OperatorConversations-BX9t3jgm.css +0 -1
- package/payload/server/public/assets/OperatorConversations-CivR0bnD.js +0 -9
- package/payload/server/public/assets/chat-r1qKuzHk.js +0 -1
- package/payload/server/public/assets/data-BkY0bFYS.js +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Task 1023. Real MERGE idempotency is a live-Neo4j property; these tests pin
|
|
2
2
|
// the contract the JS owns: a deterministic (accountId, uid) content-hash key,
|
|
3
|
-
// the :Meeting MERGE shape, the PART_OF provenance link, and the attendee
|
|
4
|
-
// (
|
|
3
|
+
// the :Meeting MERGE shape, the PART_OF provenance link, and the attendee
|
|
4
|
+
// branch (accountId-scoped email link — Task 1304 — vs. resolved nodeId vs.
|
|
5
|
+
// name-only).
|
|
5
6
|
import { describe, it, expect, vi } from "vitest";
|
|
6
7
|
import { writeMeeting, meetingUid } from "../meeting-write.js";
|
|
7
8
|
const base = {
|
|
@@ -12,9 +13,8 @@ const base = {
|
|
|
12
13
|
createdBy: { agent: "personal-assistant", session: "sess-1", tool: "schedule-event" },
|
|
13
14
|
};
|
|
14
15
|
// Fake session that routes each run() by the cypher it sees, capturing cyphers +
|
|
15
|
-
// params. `created` controls the meeting MERGE; `
|
|
16
|
-
//
|
|
17
|
-
// whether a nodeId attendee resolved under this account.
|
|
16
|
+
// params. `created` controls the meeting MERGE; `nodeIdLinks` controls whether a
|
|
17
|
+
// nodeId attendee resolved under this account.
|
|
18
18
|
function makeSession(opts) {
|
|
19
19
|
const cyphers = [];
|
|
20
20
|
const params = [];
|
|
@@ -24,10 +24,6 @@ function makeSession(opts) {
|
|
|
24
24
|
if (cypher.includes("MERGE (m:Meeting")) {
|
|
25
25
|
return { records: [{ get: (k) => (k === "created" ? opts.created ?? true : "el-meeting-1") }] };
|
|
26
26
|
}
|
|
27
|
-
if (cypher.includes("MERGE (p:Person {email:")) {
|
|
28
|
-
const linked = opts.personOwner === undefined || opts.personOwner === p.accountId;
|
|
29
|
-
return { records: [{ get: () => linked }] };
|
|
30
|
-
}
|
|
31
27
|
if (cypher.includes("MATCH (p:Person) WHERE elementId(p)")) {
|
|
32
28
|
// The real query's same-account MATCH yields a row only when the Person
|
|
33
29
|
// resolves under this account; a foreign/missing nodeId returns zero rows.
|
|
@@ -73,22 +69,18 @@ describe("writeMeeting", () => {
|
|
|
73
69
|
await writeMeeting(session, base);
|
|
74
70
|
expect(cyphers.some((c) => c.includes("PART_OF"))).toBe(false);
|
|
75
71
|
});
|
|
76
|
-
it("links
|
|
77
|
-
const { session, cyphers, params } = makeSession({ created: true
|
|
72
|
+
it("links an email counterparty via an accountId-scoped Person MERGE", async () => {
|
|
73
|
+
const { session, cyphers, params } = makeSession({ created: true });
|
|
78
74
|
const r = await writeMeeting(session, { ...base, attendees: [{ email: "Josh@Goff.com", name: "Josh" }] });
|
|
79
75
|
expect(r.attendeesLinked).toBe(1);
|
|
80
76
|
expect(r.crossAccountSkipped).toBe(0);
|
|
77
|
+
expect(cyphers.some((c) => c.includes("MERGE (p:Person {email: $email, accountId: $accountId})"))).toBe(true);
|
|
81
78
|
expect(cyphers.some((c) => c.includes("MERGE (p)-[r:ATTENDED]->(m)"))).toBe(true);
|
|
82
79
|
// email is lowercased before the MERGE.
|
|
83
|
-
const
|
|
80
|
+
const personCallIndex = cyphers.findIndex((c) => c.includes("MERGE (p:Person"));
|
|
81
|
+
const personCall = params[personCallIndex];
|
|
84
82
|
expect(personCall?.email).toBe("josh@goff.com");
|
|
85
|
-
|
|
86
|
-
it("skips a cross-account email counterparty but still lands the meeting", async () => {
|
|
87
|
-
const { session } = makeSession({ created: true, personOwner: "other-account" });
|
|
88
|
-
const r = await writeMeeting(session, { ...base, attendees: [{ email: "foreign@x.com" }] });
|
|
89
|
-
expect(r.created).toBe(true);
|
|
90
|
-
expect(r.attendeesLinked).toBe(0);
|
|
91
|
-
expect(r.crossAccountSkipped).toBe(1);
|
|
83
|
+
expect(personCall?.accountId).toBe("acct-1");
|
|
92
84
|
});
|
|
93
85
|
it("links a resolved same-account nodeId counterparty", async () => {
|
|
94
86
|
const { session } = makeSession({ created: true, nodeIdLinks: true });
|
package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-write.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meeting-write.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/meeting-write.test.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+EAA+E;AAC/E,
|
|
1
|
+
{"version":3,"file":"meeting-write.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/meeting-write.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,8 +10,6 @@ export interface BookingRow {
|
|
|
10
10
|
export interface ReconcileResult {
|
|
11
11
|
created: boolean;
|
|
12
12
|
meetingId: string;
|
|
13
|
-
personLinked: boolean;
|
|
14
|
-
crossAccountSkipped: boolean;
|
|
15
13
|
}
|
|
16
14
|
export declare function bookingUid(bookingId: string): string;
|
|
17
15
|
export declare function reconcileOne(session: Session, accountId: string, booking: BookingRow): Promise<ReconcileResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"booking-reconcile.d.ts","sourceRoot":"","sources":["../../src/lib/booking-reconcile.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"booking-reconcile.d.ts","sourceRoot":"","sources":["../../src/lib/booking-reconcile.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,eAAe,CAAC,CAqD1B;AAED,MAAM,WAAW,WAAW;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,WAAW,CAAC,CAWtB"}
|
|
@@ -32,26 +32,19 @@ export async function reconcileOne(session, accountId, booking) {
|
|
|
32
32
|
});
|
|
33
33
|
const created = meetingRes.records[0].get("created");
|
|
34
34
|
const meetingId = meetingRes.records[0].get("meetingId");
|
|
35
|
-
// Resolve the booker in one atomic statement
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const personRes = await session.run(`MATCH (m:Meeting) WHERE elementId(m) = $meetingId
|
|
43
|
-
MERGE (p:Person {email: $email})
|
|
44
|
-
ON CREATE SET p.accountId = $accountId,
|
|
45
|
-
p.displayName = $name,
|
|
35
|
+
// Resolve the booker in one atomic statement. The MERGE key includes
|
|
36
|
+
// accountId, so this account always gets or keeps its own Person for the
|
|
37
|
+
// booking email — the merge can never match, relabel, or link a foreign
|
|
38
|
+
// account's Person.
|
|
39
|
+
await session.run(`MATCH (m:Meeting) WHERE elementId(m) = $meetingId
|
|
40
|
+
MERGE (p:Person {email: $email, accountId: $accountId})
|
|
41
|
+
ON CREATE SET p.displayName = $name,
|
|
46
42
|
p.scope = 'booking',
|
|
47
43
|
p.source = 'booking-reconcile',
|
|
48
44
|
p.createdAt = datetime()
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
RETURN p.accountId = $accountId AS linked`, { meetingId, email: booking.email, accountId, name: booking.name });
|
|
53
|
-
const linked = personRes.records[0]?.get("linked") === true;
|
|
54
|
-
return { created, meetingId, personLinked: linked, crossAccountSkipped: !linked };
|
|
45
|
+
MERGE (p)-[r:ATTENDED]->(m)
|
|
46
|
+
ON CREATE SET r.role = 'booker', r.createdAt = datetime(), r.createdBySource = 'booking-reconcile'`, { meetingId, email: booking.email, accountId, name: booking.name });
|
|
47
|
+
return { created, meetingId };
|
|
55
48
|
}
|
|
56
49
|
/**
|
|
57
50
|
* Compare D1's accepted booking ids against the account's booking :Meeting set.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"booking-reconcile.js","sourceRoot":"","sources":["../../src/lib/booking-reconcile.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"booking-reconcile.js","sourceRoot":"","sources":["../../src/lib/booking-reconcile.ts"],"names":[],"mappings":"AAyBA,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,OAAO,WAAW,SAAS,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAgB,EAChB,SAAiB,EACjB,OAAmB;IAEnB,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAE1C,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAClC;;;;;;;;;;;;;;;;;;+CAkB2C,EAC3C;QACE,SAAS;QACT,GAAG;QACH,KAAK,EAAE,YAAY,OAAO,CAAC,IAAI,EAAE;QACjC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE;KACzB,CACF,CAAC;IACF,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAY,CAAC;IAChE,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAW,CAAC;IAEnE,qEAAqE;IACrE,yEAAyE;IACzE,wEAAwE;IACxE,oBAAoB;IACpB,MAAM,OAAO,CAAC,GAAG,CACf;;;;;;;0GAOsG,EACtG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CACnE,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAChC,CAAC;AAOD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAgB,EAChB,SAAiB,EACjB,aAAuB;IAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAC3B,4FAA4F,EAC5F,EAAE,SAAS,EAAE,CACd,CAAC;IACF,MAAM,IAAI,GAAa,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACzD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;IACrC,MAAM,mBAAmB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7F,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7F,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,CAAC;AACjD,CAAC"}
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* via `[:IMPORTED]`, resolves attendees to `:Person` by lowercased email, and
|
|
8
8
|
* MERGEs `[:ATTENDED]` edges with role + partstat.
|
|
9
9
|
*
|
|
10
|
-
* Cross-account
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
10
|
+
* Cross-account rule (Task 1304): `Person.email` is unique per account, not
|
|
11
|
+
* globally. When an attendee email already exists under a different
|
|
12
|
+
* accountId, this account still gets its own new Person stub and
|
|
13
|
+
* `:ATTENDED` edge — the two accounts' Person nodes are never linked,
|
|
14
|
+
* merged, or relabelled. Nothing is skipped; there is no
|
|
15
|
+
* `skippedCrossAccountPerson` outcome.
|
|
16
16
|
*/
|
|
17
17
|
import { Session } from "neo4j-driver";
|
|
18
18
|
import { type ParsedAttendee } from "./ics.js";
|
|
@@ -31,6 +31,13 @@ export interface IcsIngestParams {
|
|
|
31
31
|
export interface AttendeePreviewEntry {
|
|
32
32
|
address: string;
|
|
33
33
|
displayName?: string;
|
|
34
|
+
/**
|
|
35
|
+
* "existing-cross-account" (Task 1304) does NOT mean this attendee will
|
|
36
|
+
* be skipped — a different account already holding this email/telephone
|
|
37
|
+
* no longer blocks anything. It means commit will create a brand-new
|
|
38
|
+
* same-account Person stub for it, same as "will-create". The status is
|
|
39
|
+
* kept distinct purely so the operator can see the overlap.
|
|
40
|
+
*/
|
|
34
41
|
status: "existing-same-account" | "existing-cross-account" | "will-create" | "non-mailto";
|
|
35
42
|
/** Set when status is existing-*. */
|
|
36
43
|
existingDisplayName?: string;
|
|
@@ -70,7 +77,6 @@ export interface IcsIngestCommitResult {
|
|
|
70
77
|
organizers: number;
|
|
71
78
|
skippedNoUid: number;
|
|
72
79
|
skippedNoStartTime: number;
|
|
73
|
-
skippedCrossAccountPerson: number;
|
|
74
80
|
parseErrors: string[];
|
|
75
81
|
ms: number;
|
|
76
82
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ics-graph-ingest.d.ts","sourceRoot":"","sources":["../../src/lib/ics-graph-ingest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAA8B,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAO3E,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EACF,uBAAuB,GACvB,wBAAwB,GACxB,aAAa,GACb,YAAY,CAAC;IACjB,qCAAqC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kCAAkC;IAClC,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,mBAAmB,EAAE,MAAM,CAAC;QAC5B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,uFAAuF;IACvF,eAAe,EAAE,oBAAoB,EAAE,CAAC;IACxC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"ics-graph-ingest.d.ts","sourceRoot":"","sources":["../../src/lib/ics-graph-ingest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAA8B,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAO3E,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,MAAM,EACF,uBAAuB,GACvB,wBAAwB,GACxB,aAAa,GACb,YAAY,CAAC;IACjB,qCAAqC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kCAAkC;IAClC,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,mBAAmB,EAAE,MAAM,CAAC;QAC5B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,uFAAuF;IACvF,eAAe,EAAE,oBAAoB,EAAE,CAAC;IACxC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,eAAe,GAAG,qBAAqB,GAAG,qBAAqB,CAAC;AAM5E,wBAAsB,SAAS,CAC7B,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,eAAe,CAAC,CA8D1B;AAsZD,YAAY,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* via `[:IMPORTED]`, resolves attendees to `:Person` by lowercased email, and
|
|
8
8
|
* MERGEs `[:ATTENDED]` edges with role + partstat.
|
|
9
9
|
*
|
|
10
|
-
* Cross-account
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
10
|
+
* Cross-account rule (Task 1304): `Person.email` is unique per account, not
|
|
11
|
+
* globally. When an attendee email already exists under a different
|
|
12
|
+
* accountId, this account still gets its own new Person stub and
|
|
13
|
+
* `:ATTENDED` edge — the two accounts' Person nodes are never linked,
|
|
14
|
+
* merged, or relabelled. Nothing is skipped; there is no
|
|
15
|
+
* `skippedCrossAccountPerson` outcome.
|
|
16
16
|
*/
|
|
17
17
|
import { randomUUID } from "node:crypto";
|
|
18
18
|
import { parseICS } from "./ics.js";
|
|
@@ -108,16 +108,26 @@ async function dryRunPreview(ctx) {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
// One round-trip to classify every unique address against the live graph.
|
|
111
|
+
// Two accountId-partitioned lookups (Task 1304 — Person.email is unique
|
|
112
|
+
// per account, not globally): same-account existence decides the preview
|
|
113
|
+
// bucket; foreign-account existence is informational only (both buckets
|
|
114
|
+
// now get their own same-account stub at commit time).
|
|
111
115
|
const existing = new Map();
|
|
112
116
|
if (addressOrder.length > 0) {
|
|
113
117
|
const result = await ctx.session.run(`
|
|
114
118
|
UNWIND $emails AS email
|
|
115
|
-
MATCH (
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
OPTIONAL MATCH (same:Person {email: email, accountId: $accountId})
|
|
120
|
+
OPTIONAL MATCH (foreign:Person {email: email})
|
|
121
|
+
WHERE foreign.accountId <> $accountId
|
|
122
|
+
RETURN email,
|
|
123
|
+
same IS NOT NULL AS hasSameAccount,
|
|
124
|
+
foreign IS NOT NULL AS hasForeignAccount,
|
|
125
|
+
coalesce(same.displayName, foreign.displayName) AS displayName
|
|
126
|
+
`, { emails: addressOrder, accountId: ctx.accountId });
|
|
118
127
|
for (const rec of result.records) {
|
|
119
128
|
existing.set(rec.get("email"), {
|
|
120
|
-
|
|
129
|
+
hasSameAccount: rec.get("hasSameAccount") === true,
|
|
130
|
+
hasForeignAccount: rec.get("hasForeignAccount") === true,
|
|
121
131
|
displayName: rec.get("displayName") ?? null,
|
|
122
132
|
});
|
|
123
133
|
}
|
|
@@ -131,22 +141,22 @@ async function dryRunPreview(ctx) {
|
|
|
131
141
|
const hit = existing.get(address);
|
|
132
142
|
let status;
|
|
133
143
|
let existingDisplayName;
|
|
134
|
-
if (
|
|
135
|
-
willCreate++;
|
|
136
|
-
status = "will-create";
|
|
137
|
-
}
|
|
138
|
-
else if (hit.accountId === ctx.accountId) {
|
|
144
|
+
if (hit?.hasSameAccount) {
|
|
139
145
|
existingSameAccount++;
|
|
140
146
|
status = "existing-same-account";
|
|
141
147
|
if (hit.displayName)
|
|
142
148
|
existingDisplayName = hit.displayName;
|
|
143
149
|
}
|
|
144
|
-
else {
|
|
150
|
+
else if (hit?.hasForeignAccount) {
|
|
145
151
|
existingCrossAccount++;
|
|
146
152
|
status = "existing-cross-account";
|
|
147
153
|
if (hit.displayName)
|
|
148
154
|
existingDisplayName = hit.displayName;
|
|
149
155
|
}
|
|
156
|
+
else {
|
|
157
|
+
willCreate++;
|
|
158
|
+
status = "will-create";
|
|
159
|
+
}
|
|
150
160
|
if (sample.length < SAMPLE_CAP) {
|
|
151
161
|
const entry = { address, status };
|
|
152
162
|
const dn = addressDisplayName.get(address);
|
|
@@ -216,7 +226,6 @@ async function commit(ctx) {
|
|
|
216
226
|
let meetingsUpdated = 0;
|
|
217
227
|
let peopleCreated = 0;
|
|
218
228
|
let existingPersonsLinked = 0;
|
|
219
|
-
let skippedCrossAccountPerson = 0;
|
|
220
229
|
let attendees = 0;
|
|
221
230
|
let organizers = 0;
|
|
222
231
|
// One transaction per meeting keeps the blast radius small — if attendee
|
|
@@ -307,17 +316,16 @@ async function commit(ctx) {
|
|
|
307
316
|
process.stderr.write(`[graph-write] warn reason=embed-failed labels=Person agent=ics-ingest detail=${err instanceof Error ? err.message : String(err)}\n`);
|
|
308
317
|
}
|
|
309
318
|
const personResult = await ctx.session.executeWrite(async (tx) => {
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (existingAccountId === ctx.accountId) {
|
|
319
|
+
// Same-account existence check (Task 1304 — Person.email is unique
|
|
320
|
+
// per account, not globally): whether another account also holds
|
|
321
|
+
// this email is irrelevant here, since this account always gets or
|
|
322
|
+
// keeps its own Person for it.
|
|
323
|
+
const lookup = await tx.run(`MATCH (p:Person {email: $email, accountId: $accountId}) RETURN elementId(p) AS id LIMIT 1`, { email: att.address, accountId: ctx.accountId });
|
|
324
|
+
const existingSameAccount = lookup.records.length > 0;
|
|
325
|
+
if (existingSameAccount) {
|
|
318
326
|
// Same-account Person: link without overwriting their identity.
|
|
319
327
|
await tx.run(`
|
|
320
|
-
MATCH (p:Person {email: $email})
|
|
328
|
+
MATCH (p:Person {email: $email, accountId: $accountId})
|
|
321
329
|
MATCH (m:Meeting) WHERE elementId(m) = $meetingId
|
|
322
330
|
MERGE (p)-[r:ATTENDED]->(m)
|
|
323
331
|
ON CREATE SET r.role = $role, r.partstat = $partstat,
|
|
@@ -329,6 +337,7 @@ async function commit(ctx) {
|
|
|
329
337
|
)
|
|
330
338
|
`, {
|
|
331
339
|
email: att.address,
|
|
340
|
+
accountId: ctx.accountId,
|
|
332
341
|
meetingId: meetingResult.meetingId,
|
|
333
342
|
role: att.role,
|
|
334
343
|
partstat: att.partstat ?? null,
|
|
@@ -336,7 +345,8 @@ async function commit(ctx) {
|
|
|
336
345
|
});
|
|
337
346
|
return { outcome: "linked-existing" };
|
|
338
347
|
}
|
|
339
|
-
// Brand new Person stub under the importer's account
|
|
348
|
+
// Brand new Person stub under the importer's account — created
|
|
349
|
+
// regardless of whether another account already holds this email.
|
|
340
350
|
await tx.run(`
|
|
341
351
|
MATCH (m:Meeting) WHERE elementId(m) = $meetingId
|
|
342
352
|
CREATE (p:Person {
|
|
@@ -369,10 +379,7 @@ async function commit(ctx) {
|
|
|
369
379
|
});
|
|
370
380
|
return { outcome: "person-created" };
|
|
371
381
|
});
|
|
372
|
-
if (personResult.outcome === "
|
|
373
|
-
skippedCrossAccountPerson++;
|
|
374
|
-
}
|
|
375
|
-
else if (personResult.outcome === "linked-existing") {
|
|
382
|
+
if (personResult.outcome === "linked-existing") {
|
|
376
383
|
existingPersonsLinked++;
|
|
377
384
|
}
|
|
378
385
|
else {
|
|
@@ -386,7 +393,6 @@ async function commit(ctx) {
|
|
|
386
393
|
`meetingsCreated=${meetingsCreated} meetingsUpdated=${meetingsUpdated} ` +
|
|
387
394
|
`peopleCreated=${peopleCreated} existingPersonsLinked=${existingPersonsLinked} ` +
|
|
388
395
|
`attendees=${attendees} organizers=${organizers} ` +
|
|
389
|
-
`skippedCrossAccountPerson=${skippedCrossAccountPerson} ` +
|
|
390
396
|
`skippedNoUid=${ctx.skippedNoUid} skippedNoStartTime=${ctx.skippedNoStartTime} ` +
|
|
391
397
|
`ms=${ms}\n`);
|
|
392
398
|
return {
|
|
@@ -402,7 +408,6 @@ async function commit(ctx) {
|
|
|
402
408
|
organizers,
|
|
403
409
|
skippedNoUid: ctx.skippedNoUid,
|
|
404
410
|
skippedNoStartTime: ctx.skippedNoStartTime,
|
|
405
|
-
skippedCrossAccountPerson,
|
|
406
411
|
parseErrors: ctx.parseErrors,
|
|
407
412
|
ms,
|
|
408
413
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ics-graph-ingest.js","sourceRoot":"","sources":["../../src/lib/ics-graph-ingest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAyC,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,KAAK,EAAE,MAAM,+CAA+C,CAAC;
|
|
1
|
+
{"version":3,"file":"ics-graph-ingest.js","sourceRoot":"","sources":["../../src/lib/ics-graph-ingest.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meeting-write.d.ts","sourceRoot":"","sources":["../../src/lib/meeting-write.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"meeting-write.d.ts","sourceRoot":"","sources":["../../src/lib/meeting-write.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGrF;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,kBAAkB,CAAC,CA2G7B"}
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
// where uid is a deterministic content hash of (accountId, title, startDate), so
|
|
5
5
|
// re-running the identical request writes no duplicate.
|
|
6
6
|
//
|
|
7
|
-
// Attendee linkage
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
7
|
+
// Attendee linkage: nodeId attendees carry an explicit same-account guard in
|
|
8
|
+
// their MATCH (a foreign-account nodeId resolves to zero rows, so it is
|
|
9
|
+
// skipped and counted in crossAccountSkipped). Email attendees resolve via an
|
|
10
|
+
// accountId-scoped MERGE (Task 1304 — Person.email is unique per account, not
|
|
11
|
+
// globally): this account always gets or keeps its own Person for that email,
|
|
12
|
+
// so the email branch never touches a foreign account's node and has no skip
|
|
13
|
+
// path. A name-only attendee carries no link.
|
|
13
14
|
import { createHash } from "node:crypto";
|
|
14
15
|
/**
|
|
15
16
|
* Deterministic uid for a conversationally-booked meeting. ICS uses the VEVENT
|
|
@@ -98,22 +99,15 @@ export async function writeMeeting(session, params) {
|
|
|
98
99
|
continue;
|
|
99
100
|
}
|
|
100
101
|
if (email) {
|
|
101
|
-
|
|
102
|
-
MERGE (p:Person {email: $email})
|
|
103
|
-
ON CREATE SET p.
|
|
104
|
-
p.displayName = $name,
|
|
102
|
+
await session.run(`MATCH (m:Meeting) WHERE elementId(m) = $meetingId
|
|
103
|
+
MERGE (p:Person {email: $email, accountId: $accountId})
|
|
104
|
+
ON CREATE SET p.displayName = $name,
|
|
105
105
|
p.scope = 'admin',
|
|
106
106
|
p.source = 'schedule-event',
|
|
107
107
|
p.createdAt = datetime()
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
RETURN p.accountId = $accountId AS linked`, { meetingId, email: email.toLowerCase(), accountId, name: attendee.name ?? email });
|
|
112
|
-
const linked = res.records[0]?.get("linked") === true;
|
|
113
|
-
if (linked)
|
|
114
|
-
attendeesLinked++;
|
|
115
|
-
else
|
|
116
|
-
crossAccountSkipped++;
|
|
108
|
+
MERGE (p)-[r:ATTENDED]->(m)
|
|
109
|
+
ON CREATE SET r.role = 'attendee', r.createdAt = datetime(), r.createdBySource = 'schedule-event'`, { meetingId, email: email.toLowerCase(), accountId, name: attendee.name ?? email });
|
|
110
|
+
attendeesLinked++;
|
|
117
111
|
continue;
|
|
118
112
|
}
|
|
119
113
|
// name-only attendee: informational, no link.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meeting-write.js","sourceRoot":"","sources":["../../src/lib/meeting-write.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,+EAA+E;AAC/E,4EAA4E;AAC5E,iFAAiF;AACjF,wDAAwD;AACxD,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"meeting-write.js","sourceRoot":"","sources":["../../src/lib/meeting-write.ts"],"names":[],"mappings":"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"}
|
|
@@ -70,13 +70,13 @@ Activate when the user asks about WhatsApp — connecting, linking, checking sta
|
|
|
70
70
|
|
|
71
71
|
## Conversation Browsing
|
|
72
72
|
|
|
73
|
-
Four tools for reading WhatsApp conversation context. The first two read from the in-memory ring buffer (recent inbound, ~500 per JID, ephemeral). `whatsapp-conversation-graph-state` reads the durable
|
|
73
|
+
Four tools for reading WhatsApp conversation context. The first two read from the in-memory ring buffer (recent inbound, ~500 per JID, ephemeral). `whatsapp-conversation-graph-state` reads the durable on-disk store — the read logic lives in the platform route so the agent never composes its own query. `whatsapp-group-info` queries the live WhatsApp servers.
|
|
74
74
|
|
|
75
75
|
| Tool | Returns |
|
|
76
76
|
|------|---------|
|
|
77
77
|
| `whatsapp-conversations` | JIDs with recent message activity, conversation type (group/DM), last message timestamp, message count |
|
|
78
78
|
| `whatsapp-messages` | In-memory ring-buffer messages for a specific JID — sender, body, timestamp, reply context. Supports optional `limit` for most recent N messages |
|
|
79
|
-
| `whatsapp-conversation-graph-state` | Persisted
|
|
79
|
+
| `whatsapp-conversation-graph-state` | Persisted WhatsApp messages from the on-disk store (no longer Neo4j). Pass `jid` for one conversation (plus the resolved `sessionId` and a divergence header vs in-memory count). Omit `jid` for every sender across the account in one call, each resolved to its `:Person` name. Use when the question is "what got persisted" or "who has messaged us that never got a reply session" |
|
|
80
80
|
| `whatsapp-group-info` | Group metadata from WhatsApp servers — subject, description, participants with admin flags, creation date. Requires active connection |
|
|
81
81
|
|
|
82
82
|
## Group access — observation-only
|
|
@@ -99,9 +99,11 @@ The agent links as a companion device on the operator's own WhatsApp account, so
|
|
|
99
99
|
|
|
100
100
|
## Live persistence
|
|
101
101
|
|
|
102
|
-
Every `messages.upsert` event (both `notify` and `append`, both `fromMe` directions)
|
|
102
|
+
Every `messages.upsert` event (both `notify` and `append`, both `fromMe` directions) is captured at a single site in `platform/ui/app/lib/whatsapp/manager.ts` and split two ways: the sender's `:Person` node is MERGEd in Neo4j (identity linkage, shared with the rest of the platform's People model — unchanged from before), and the message content itself is appended to an on-disk JSONL store at `~/.<brand>/data/whatsapp-messages/<platformAccountId>/<remoteJid>.jsonl` — one file per conversation, one line per message. `:Message:WhatsAppMessage` nodes and their `:PART_OF`/`:SENT`/`:NEXT` edges no longer exist; message ordering is a `dateSent` sort at read time instead of a graph edge. `:Conversation` nodes are unaffected — they remain the shared session anchor for the agent-path `:UserMessage`/`:AssistantMessage` writer too. `messageId` namespace is unchanged: `whatsapp-live:<waName>:<remoteJid>:<msg.key.id>`. Persist failures are loud (`[whatsapp-persist] FAIL …`) and never block dispatch.
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
**Search coverage tradeoff.** `/graph`'s BM25/vector search no longer covers WhatsApp message bodies (`graph-search.ts`'s `MESSAGE_FAMILY_LABELS` dropped `WhatsAppMessage`) — this is an accepted, documented consequence of the storage move, not a bug. Every persisted message remains readable via `whatsapp-conversation-graph-state` (all-senders mode) and the `/whatsapp` reader panel's persisted-only rows.
|
|
105
|
+
|
|
106
|
+
**`accountId` contract.** Unchanged for `:Person` (see below); the on-disk store is keyed by the same platform-side UUID.
|
|
105
107
|
|
|
106
108
|
## Skills
|
|
107
109
|
|