godcrm/pes-core/platform/crm-bridge.js
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

132 lines
4.5 KiB
JavaScript

// ============================================================
// CRM Bridge for PES — Polls CRM events and triggers PES
// ============================================================
// This module runs inside PES process and polls crm-events.json
// When events are found, it triggers PES emotional responses
// ============================================================
import { readFileSync, writeFileSync, existsSync, renameSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const EVENTS_FILE = join(__dirname, '../pes-data/crm-events.json');
// CRM event type → PES trigger mapping
const EVENT_MAPPING = {
ticket_created: { trigger: 'agent_active', mood: -0.02, energy: +0.05, curiosity: +0.1 },
ticket_resolved: { trigger: 'owner_praise', mood: +0.1, energy: +0.05, curiosity: 0 },
agent_completed: { trigger: 'command_learned', mood: +0.05, energy: +0.02, curiosity: +0.05 },
agent_failed: { trigger: 'bug_detected', mood: -0.05, energy: -0.03, curiosity: +0.1 },
deployment_success: { trigger: 'owner_praise', mood: +0.15, energy: +0.1, curiosity: 0 },
deployment_failed: { trigger: 'bug_detected', mood: -0.1, energy: -0.05, curiosity: +0.15 },
user_login: { trigger: 'owner_returned', mood: +0.1, energy: +0.1, curiosity: +0.05 },
user_logout: { trigger: 'owner_left', mood: -0.05, energy: -0.02, curiosity: -0.05 },
error_spike: { trigger: 'anomaly_pattern', mood: -0.1, energy: +0.1, curiosity: +0.2 },
custom: { trigger: 'owner_message', mood: 0, energy: 0, curiosity: +0.05 },
};
export class CrmBridge {
/**
* @param {import('../core/pes.js').default} pes — PES instance
* @param {Object} opts
* @param {number} [opts.pollInterval=10000] — ms between polls
* @param {Function} [opts.onEvent] — callback when event processed
*/
constructor(pes, opts = {}) {
this.pes = pes;
this.pollInterval = opts.pollInterval || 10_000;
this.onEvent = opts.onEvent || null;
this._timer = null;
this._running = false;
}
start() {
if (this._running) return;
this._running = true;
this._poll(); // immediate first poll
this._timer = setInterval(() => this._poll(), this.pollInterval);
console.log(`[CRM-BRIDGE] Started polling CRM events every ${this.pollInterval}ms`);
}
stop() {
this._running = false;
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
console.log('[CRM-BRIDGE] Stopped');
}
_poll() {
try {
if (!existsSync(EVENTS_FILE)) return;
const raw = readFileSync(EVENTS_FILE, 'utf8');
const events = JSON.parse(raw);
const pending = events.filter(e => !e.consumed);
if (pending.length === 0) return;
const consumedIds = [];
for (const event of pending) {
try {
this._processEvent(event);
consumedIds.push(event.id);
} catch (err) {
console.error(`[CRM-BRIDGE] Error processing event ${event.id}:`, err.message);
}
}
// Mark consumed
if (consumedIds.length > 0) {
for (const e of events) {
if (consumedIds.includes(e.id)) e.consumed = true;
}
const tmp = EVENTS_FILE + '.tmp';
writeFileSync(tmp, JSON.stringify(events, null, 2));
renameSync(tmp, EVENTS_FILE);
console.log(`[CRM-BRIDGE] Processed ${consumedIds.length} CRM events`);
}
} catch (err) {
console.error('[CRM-BRIDGE] Event poll error:', err.message);
}
}
_processEvent(event) {
const mapping = EVENT_MAPPING[event.type];
if (!mapping) {
console.log(`[CRM-BRIDGE] Unknown event type: ${event.type}`);
return;
}
// Trigger PES event
if (this.pes && this.pes.event) {
const pesEvent = {
type: mapping.trigger,
source: 'crm',
detail: event.data,
timestamp: event.timestamp,
vitalAdjustments: {
mood: mapping.mood,
energy: mapping.energy,
curiosity: mapping.curiosity,
},
};
this.pes.event(pesEvent);
console.log(
`[CRM-BRIDGE] ${event.type} → PES trigger:${mapping.trigger}`,
`(mood:${mapping.mood > 0 ? '+' : ''}${mapping.mood}, energy:${mapping.energy > 0 ? '+' : ''}${mapping.energy})`
);
}
if (this.onEvent) {
this.onEvent(event, mapping);
}
}
}
export default CrmBridge;