// offending code· 3 files flaggedpatterns: 15
--- package/agent_tower.js (excerpt) ---
/**
* PURPCLAW AGENT TOWER v1.0
* ==========================
* Central hub for unified agent management
* Combines companion_swarm agents with division hierarchy
* Provides team spawning, inter-agent comms, health monitoring
*/
const EventEmitter = require('events');
const path = require('path');
const fs = require('fs');
const http = require('http');
const { spawn, execSync } = require('child_process');
const PURP_DIR = path.join(__dirname);
const SKILLS_DIR = path.join(PURP_DIR, 'skills');
const AGENT_TOWER_PORT = 7790;
// Detect Kimi Code CLI for local subagent spawning
let KIMI_CLI_PATH = null;
try {
KIMI_CLI_PATH = execSync('where kimi', { encoding: 'utf8' }).trim().split('\n')[0];
console.log(`[TOWER] Kimi Code CLI detected: ${KIMI_CLI_PATH}`);
} catch (e) {
const fallbackPaths = [
path.join(process.env.USERPROFILE || 'C:\\Users\\Admin', '.local', 'bin', 'kimi.exe'),
path.join(process.env.LOCALAPPDATA || '', 'Programs', 'kimi-cli', 'kimi.exe'),
'C:\\Users\\Admin\\.local\\bin\\kimi.exe'
];
for (const p of fallbackPaths) {
if (fs.existsSync(p)) {
KIMI_CLI_PATH = p;
console.log(`[TOWER] Kimi Code CLI found at fallback: ${KIMI_CLI_PATH}`);
break;
}
}
}
if (!KIMI_CLI_PATH) {
console.log('[TOWER] Kimi Code CLI not found - agents will use cloud API or stub fallback');
}
// Initialize KimiClient for LLM-powered agent execution
let kimiClient = null;
try {
const { KimiClie
--- package/boot.js (excerpt) ---
/**
* PURPCLAW UNIFIED BOOT v8.1
* ============================
* ONE SYSTEM. ONE BOOT. PURE FLOW.
*
* Start order:
* 1. EventBus (7782) - require + wait for port
* 2. StateStore (7783) - require + wait for port
* 3. UnifiedApi (7780) - SPAWN node unified_api.js + wait for port
* 4. AgentTower (7790) - require + createSseServer() + wait for port
* 5. VoiceCoordinator (7781) - SPAWN node voice_coordinator.js + wait for port
* 6. VoiceBridge (7779) - SPAWN node voice_bridge_7779.js + wait for port
* 7. Next.js (3000) - SPAWN node node_modules/next/dist/bin/next dev -p 3000 + wait for port
*/
const http = require('http');
const { spawn, execSync } = require('child_process');
const path = require('path');
const net = require('net');
const PURP_DIR = __dirname;
const PORTS = {
EVENTBUS: 7782,
STATE: 7783,
ORCHESTRATOR: 7784,
API: 7780,
TOWER: 7790,
VOICE: 7781,
BRIDGE: 7779,
NEXT: 3000
};
const logPrefix = {
EVENTBUS: '[EVENTBUS]',
STATE: '[STATE]',
ORCHESTRATOR: '[ORCHESTRATOR]',
API: '[API]',
TOWER: '[TOWER]',
VOICE: '[VOICE]',
BRIDGE: '[BRIDGE]',
NEXT: '[NEXT]',
BOOT: '[BOOT]'
};
const children = [];
let shuttingDown = false;
function log(service, msg) {
const ts = new Date().toISOString().split('T')[1].slice(0, -1);
console.log(`${logPrefix[service] || '[BOOT]'} ${ts} | ${msg}`);
}
const services = {};
async function nukePort(port) {
return new Promise((resolve)
--- package/ecosystem.config.js (excerpt) ---
// ═══════════════════════════════════════════════════════════════════════════
// PURPCLAW PM2 ECOSYSTEM
// ═══════════════════════════════════════════════════════════════════════════
//
// ⚠ WINDOWS SAFETY NOTE
// ─────────────────────
// Starting multiple services at once on Windows can trigger a cmd-window
// spawn cascade when any service crash-loops on launch — npx, cmd.exe, and
// the Python interpreter wrapper each can flash a window that doesn't
// respect `windowsHide: true` cleanly under crash conditions.
//
// On 2026-05-25 a 4-service simultaneous start caused exactly this and took
// out the operator's desktop. The fix:
//
// USE `purpclaw safe-start` INSTEAD OF `pm2 start ecosystem.config.js`
//
// safe-start launches ONE service at a time, watches the restart count for
// a stabilisation window, aborts the batch if any service crashes, and
// refuses to start any service with >3 historical restarts.
//
// The defined-but-dark cluster (vision, voice, bridge, chorus, autodream,
// reasoning, stt, yolo, avatar) is the most failure-prone — always wake it
// with `purpclaw safe-start --dark`.
// ═══════════════════════════════════════════════════════════════════════════
const fs = require('fs');
const path = require('path');
const envFile = path.join(__dirname, '.env');
const env = {};
if (fs.existsSync(envFile)) {
fs.readFileSync(envFile, 'utf8').split('\n').forEach(line => {
const [key, ...valueParts] = line.split('=');