widgettdc-api / scripts /run_ingestion_verify.cjs
Kraft102's picture
fix: sql.js Docker/Alpine compatibility layer for PatternMemory and FailureMemory
5a81b95
const { randomUUID } = require('crypto');
const neo4j = require('neo4j-driver');
const fs = require('fs');
const path = require('path');
const OWNER_UID = 'executive_claus';
const mockEmails = [
{
id: randomUUID(),
from: 'cto@example.com',
to: ['claus@example.com'],
subject: 'Weekly status',
body: 'Reminder: prepare the Twin status deck.',
receivedAt: new Date().toISOString(),
},
{
id: randomUUID(),
from: 'coach@example.com',
to: ['claus@example.com'],
subject: 'Fodboldtræning flyttet',
body: 'Træningen er flyttet til 17:00 pga. vejr.',
receivedAt: new Date(Date.now() - 3600_000).toISOString(),
},
];
const now = Date.now();
const mockEvents = [
{
id: randomUUID(),
title: 'Wingman weekly sync',
start: new Date(now + 2 * 3_600_000).toISOString(),
end: new Date(now + 3 * 3_600_000).toISOString(),
location: 'Zoom',
source: 'google',
},
{
id: randomUUID(),
title: 'Børnenes fodboldkamp',
start: new Date(now + 24 * 3_600_000).toISOString(),
end: new Date(now + 26 * 3_600_000).toISOString(),
location: 'KampKlar',
source: 'ics',
},
];
const emailToNode = (item) => ({
labels: ['Email', 'Communication', 'Private'],
properties: {
externalId: item.id,
from: item.from,
to: item.to,
subject: item.subject,
bodyPreview: item.body.slice(0, 140),
receivedAt: item.receivedAt,
belongsTo: OWNER_UID,
},
ownerUid: OWNER_UID,
});
const eventToNode = (item) => ({
labels: ['CalendarEvent', 'Schedule', 'Private'],
properties: {
externalId: item.id,
title: item.title,
start: item.start,
end: item.end,
location: item.location ?? 'unspecified',
source: item.source ?? 'mock',
belongsTo: OWNER_UID,
},
ownerUid: OWNER_UID,
});
const persistNodes = async (session, nodes) => {
const persisted = [];
for (const node of nodes) {
const labels = node.labels?.length ? node.labels : ['Private'];
const labelString = labels.map((l) => `:${l.replace(/[^A-Za-z0-9_]/g, '')}`).join('');
const props = { ...(node.properties || {}) };
if (!props.externalId) props.externalId = randomUUID();
const cypher = `
MERGE (n${labelString} {externalId: $props.externalId})
SET n += $props
WITH n, $ownerUid AS ownerUid
OPTIONAL MATCH (u:User {uid: ownerUid})
WITH n, ownerUid, u
FOREACH (_ IN CASE WHEN ownerUid IS NULL THEN [] ELSE [1] END |
MERGE (u:User {uid: ownerUid})
ON CREATE SET u.name = 'Claus', u.role = 'Executive', u.access_level = 'god_mode'
MERGE (n)-[:BELONGS_TO]->(u)
)
RETURN n.externalId AS externalId
`;
const res = await session.run(cypher, { props, ownerUid: node.ownerUid ?? null });
const rec = res.records[0];
if (rec) persisted.push(rec.get('externalId'));
}
return persisted;
};
const loadEnvIfNeeded = () => {
if (process.env.NEO4J_URI && process.env.NEO4J_USERNAME && process.env.NEO4J_PASSWORD) return;
const envPath = path.join(__dirname, '..', 'apps', 'backend', '.env');
if (fs.existsSync(envPath)) {
const lines = fs.readFileSync(envPath, 'utf-8').split(/\r?\n/);
for (const line of lines) {
const m = line.match(/^([A-Z0-9_]+)=(.*)$/);
if (m) {
const [, k, v] = m;
if (!process.env[k]) process.env[k] = v;
}
}
}
};
const main = async () => {
loadEnvIfNeeded();
const uri = process.env.NEO4J_URI;
const user = process.env.NEO4J_USERNAME;
const password = process.env.NEO4J_PASSWORD;
if (!uri || !user || !password) {
console.error('Missing NEO4J_URI/NEO4J_USERNAME/NEO4J_PASSWORD');
process.exit(1);
}
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password));
const session = driver.session();
try {
const emailNodes = mockEmails.map(emailToNode);
const calendarNodes = mockEvents.map(eventToNode);
await persistNodes(session, emailNodes);
await persistNodes(session, calendarNodes);
const res = await session.run(
'MATCH (u:User)-[r:BELONGS_TO]-(n:Private) RETURN u.uid AS uid, type(r) AS rel, labels(n) AS labels, coalesce(n.title, n.subject, n.bodyPreview) AS title LIMIT 5'
);
const output = res.records.map((rec) => ({
uid: rec.get('uid'),
rel: rec.get('rel'),
labels: rec.get('labels'),
title: rec.get('title'),
}));
console.log(JSON.stringify(output, null, 2));
} finally {
await session.close();
await driver.close();
}
};
main().catch((err) => {
console.error(err);
process.exit(1);
});