Governed substrate for autonomous agents: scoped identity (passports), audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
193 lines
5.9 KiB
JavaScript
193 lines
5.9 KiB
JavaScript
/**
|
|
* Briefing — Data Fetchers
|
|
*
|
|
* Functions that query CRM tables for calendar events, tasks, health, medications, etc.
|
|
*/
|
|
|
|
import { dbAll, dbGet, safeJsonParse } from '../../database/connection.js';
|
|
import {
|
|
log, TABLE_IDS, WELLNESS_SCHEDULE_TABLE, ATOMIC_HABITS_TABLE,
|
|
getOptionLabels, resolveTaskFields, extractTime,
|
|
} from './constants.js';
|
|
|
|
// =============================================================================
|
|
// DATA FETCHERS
|
|
// =============================================================================
|
|
|
|
export async function fetchTodayEvents(todayStr) {
|
|
try {
|
|
const rows = await dbAll(
|
|
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at DESC',
|
|
[TABLE_IDS.CALENDAR_EVENTS]
|
|
);
|
|
const events = [];
|
|
for (const row of rows) {
|
|
const data = safeJsonParse(row.data) || {};
|
|
const startDt = data.start_datetime || '';
|
|
if (startDt.startsWith(todayStr)) {
|
|
events.push({
|
|
id: row.id,
|
|
title: data.title || data.summary || '\u0411\u0435\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f',
|
|
start_datetime: startDt,
|
|
end_datetime: data.end_datetime || '',
|
|
location: data.location || '',
|
|
time: extractTime(startDt),
|
|
});
|
|
}
|
|
}
|
|
events.sort((a, b) => a.start_datetime.localeCompare(b.start_datetime));
|
|
return events;
|
|
} catch (err) {
|
|
log.error({ err }, 'Failed to fetch calendar events');
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function fetchSprintTasks() {
|
|
try {
|
|
const opts = await getOptionLabels();
|
|
const rows = await dbAll(
|
|
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at DESC',
|
|
[TABLE_IDS.SPRINT_TASKS]
|
|
);
|
|
const tasks = [];
|
|
for (const row of rows) {
|
|
const data = safeJsonParse(row.data) || {};
|
|
const { title, stateLabel, priorityLabel, isDone } = resolveTaskFields(data, opts);
|
|
if (!isDone) {
|
|
tasks.push({
|
|
id: row.id,
|
|
title,
|
|
state: stateLabel,
|
|
priority: priorityLabel,
|
|
assigned_to: data.assigned_to || '',
|
|
});
|
|
}
|
|
}
|
|
const priorityOrder = { p0: 0, p1: 1, urgent: 1, high: 1, critical: 0, p2: 2, medium: 2, normal: 2, p3: 3, low: 3, p4: 4 };
|
|
tasks.sort((a, b) => {
|
|
const pa = priorityOrder[String(a.priority).toLowerCase()] ?? 5;
|
|
const pb = priorityOrder[String(b.priority).toLowerCase()] ?? 5;
|
|
return pa - pb;
|
|
});
|
|
return tasks;
|
|
} catch (err) {
|
|
log.error({ err }, 'Failed to fetch sprint tasks');
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function fetchHealthMetrics() {
|
|
try {
|
|
const row = await dbGet(
|
|
'SELECT id, data, created_at FROM table_rows WHERE table_id = ? ORDER BY created_at DESC LIMIT 1',
|
|
[TABLE_IDS.HEALTH_METRICS]
|
|
);
|
|
if (!row) return null;
|
|
return { id: row.id, ...safeJsonParse(row.data), _recorded_at: row.created_at };
|
|
} catch (err) {
|
|
log.error({ err }, 'Failed to fetch health metrics');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function fetchMedications() {
|
|
try {
|
|
const rows = await dbAll(
|
|
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at ASC',
|
|
[TABLE_IDS.MEDICATIONS]
|
|
);
|
|
return rows.map(row => {
|
|
const data = safeJsonParse(row.data) || {};
|
|
return {
|
|
id: row.id,
|
|
name: data.name || data.title || 'Unknown',
|
|
dosage: data.dosage || '',
|
|
time_of_day: data.time_of_day || data.schedule || data.time || 'any',
|
|
notes: data.notes || '',
|
|
};
|
|
});
|
|
} catch (err) {
|
|
log.error({ err }, 'Failed to fetch medications');
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function fetchCompletedToday(todayStr) {
|
|
try {
|
|
const opts = await getOptionLabels();
|
|
const rows = await dbAll(
|
|
'SELECT id, data, updated_at FROM table_rows WHERE table_id = ? ORDER BY updated_at DESC',
|
|
[TABLE_IDS.SPRINT_TASKS]
|
|
);
|
|
const completed = [];
|
|
for (const row of rows) {
|
|
const data = safeJsonParse(row.data) || {};
|
|
const { title, stateLabel, priorityLabel, isDone } = resolveTaskFields(data, opts);
|
|
const rawUpdated = row.updated_at || '';
|
|
const updatedAt = rawUpdated instanceof Date ? rawUpdated.toISOString() : String(rawUpdated);
|
|
if (isDone && updatedAt.startsWith(todayStr)) {
|
|
completed.push({
|
|
id: row.id,
|
|
title,
|
|
state: stateLabel,
|
|
priority: priorityLabel,
|
|
});
|
|
}
|
|
}
|
|
return completed;
|
|
} catch (err) {
|
|
log.error({ err }, 'Failed to fetch completed tasks');
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch wellness schedule blocks from CRM table.
|
|
*/
|
|
export async function fetchWellnessSchedule() {
|
|
try {
|
|
const rows = await dbAll(
|
|
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at ASC',
|
|
[WELLNESS_SCHEDULE_TABLE]
|
|
);
|
|
return rows.map(row => {
|
|
const data = safeJsonParse(row.data) || {};
|
|
return {
|
|
id: row.id,
|
|
time_start: data.time_start || data.start_time || '',
|
|
time_end: data.time_end || data.end_time || '',
|
|
block_name: data.block_name || data.name || data.title || '',
|
|
category: data.category || data.type || '',
|
|
details: data.details || data.description || '',
|
|
};
|
|
});
|
|
} catch (err) {
|
|
log.error({ err }, 'Failed to fetch wellness schedule');
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch atomic habit stacks from CRM table.
|
|
*/
|
|
export async function fetchAtomicHabits() {
|
|
try {
|
|
const rows = await dbAll(
|
|
'SELECT id, data FROM table_rows WHERE table_id = ? ORDER BY created_at ASC',
|
|
[ATOMIC_HABITS_TABLE]
|
|
);
|
|
return rows.map(row => {
|
|
const data = safeJsonParse(row.data) || {};
|
|
return {
|
|
id: row.id,
|
|
trigger: data.trigger || data.cue || '',
|
|
habit: data.habit || data.micro_habit || data.name || '',
|
|
duration: data.duration || data.time || '',
|
|
};
|
|
});
|
|
} catch (err) {
|
|
log.error({ err }, 'Failed to fetch atomic habits');
|
|
return [];
|
|
}
|
|
}
|