titan-agent 5.5.11 → 5.5.13

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.
@@ -5,13 +5,38 @@ const COMPONENT = "OrganismRouter";
5
5
  function createOrganismRouter() {
6
6
  const router = Router();
7
7
  router.get("/organism/history", async (_req, res) => {
8
- res.status(501).json({ error: "Not implemented" });
9
- });
10
- router.get("/organism/safety-trend", async (_req, res) => {
11
- res.status(501).json({ error: "Not implemented" });
8
+ try {
9
+ const { loadDriveHistory } = await import("../../organism/drives.js");
10
+ const persisted = loadDriveHistory();
11
+ if (!persisted) {
12
+ res.json({ history: [] });
13
+ return;
14
+ }
15
+ const history = persisted.history.map((h) => ({
16
+ timestamp: h.timestamp,
17
+ event: "drive-tick",
18
+ data: h.satisfactions
19
+ }));
20
+ res.json({ history });
21
+ } catch (e) {
22
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
23
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
24
+ }
12
25
  });
13
26
  router.get("/organism/safety-metrics", async (_req, res) => {
14
- res.status(501).json({ error: "Not implemented" });
27
+ try {
28
+ const { loadDriveHistory } = await import("../../organism/drives.js");
29
+ const persisted = loadDriveHistory();
30
+ const out = {};
31
+ if (persisted?.latest) {
32
+ for (const d of persisted.latest.drives) out[d.id] = d.satisfaction;
33
+ out.totalPressure = persisted.latest.totalPressure;
34
+ }
35
+ res.json(out);
36
+ } catch (e) {
37
+ logger.error(COMPONENT, `Endpoint error: ${e.message}`);
38
+ res.status(500).json({ error: "Something went wrong on our end. Please try again in a moment." });
39
+ }
15
40
  });
16
41
  router.get("/organism/alerts", async (_req, res) => {
17
42
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/gateway/routes/organism.ts"],"sourcesContent":["/**\n * Organism Router\n *\n * Extracted from gateway/server.ts.\n * Consolidates all /api/organism/* routes.\n */\n\nimport { Router } from 'express';\nimport logger from '../../utils/logger.js';\n\nconst COMPONENT = 'OrganismRouter';\n\nexport function createOrganismRouter(): Router {\n const router = Router();\n\n router.get('/organism/history', async (_req, res) => {\n res.status(501).json({ error: 'Not implemented' });\n });\n\n router.get('/organism/safety-trend', async (_req, res) => {\n res.status(501).json({ error: 'Not implemented' });\n });\n\n router.get('/organism/safety-metrics', async (_req, res) => {\n res.status(501).json({ error: 'Not implemented' });\n });\n\n router.get('/organism/alerts', async (_req, res) => {\n try {\n const { getAlerts } = await import('../../organism/alertsStore.js');\n res.json({ alerts: getAlerts() });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/organism/alerts/stats', async (_req, res) => {\n try {\n const { getAlertStats } = await import('../../organism/alertsStore.js');\n res.json(getAlertStats());\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/organism/alerts/config', async (_req, res) => {\n try {\n const { getAlertConfig } = await import('../../organism/alertsStore.js');\n res.json(getAlertConfig());\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/organism/alerts/config', async (_req, res) => {\n try {\n const { setAlertConfig } = await import('../../organism/alertsStore.js');\n setAlertConfig(_req.body || {});\n res.json({ success: true });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/organism/alerts/:id/acknowledge', async (req, res) => {\n try {\n const { acknowledgeAlert } = await import('../../organism/alertsStore.js');\n const ok = acknowledgeAlert(req.params.id);\n if (!ok) { res.status(404).json({ error: 'Alert not found' }); return; }\n res.json({ success: true });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.delete('/organism/alerts/old', async (_req, res) => {\n try {\n const { deleteOldAlerts } = await import('../../organism/alertsStore.js');\n const removed = deleteOldAlerts();\n res.json({ removed });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n return router;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/gateway/routes/organism.ts"],"sourcesContent":["/**\n * Organism Router\n *\n * Extracted from gateway/server.ts.\n * Consolidates all /api/organism/* routes.\n */\n\nimport { Router } from 'express';\nimport logger from '../../utils/logger.js';\n\nconst COMPONENT = 'OrganismRouter';\n\nexport function createOrganismRouter(): Router {\n const router = Router();\n\n // History: last ≤1440 drive ticks (24h at 60s cadence) from\n // ~/.titan/soma-drive-state.json. Returns the shape the UI client expects:\n // { history: [{ timestamp, event, data }] } where data is the per-drive\n // satisfactions for that tick.\n router.get('/organism/history', async (_req, res) => {\n try {\n const { loadDriveHistory } = await import('../../organism/drives.js');\n const persisted = loadDriveHistory();\n if (!persisted) { res.json({ history: [] }); return; }\n const history = persisted.history.map(h => ({\n timestamp: h.timestamp,\n event: 'drive-tick',\n data: h.satisfactions,\n }));\n res.json({ history });\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`);\n res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n // Safety metrics: drive satisfactions (0–1 each) from the most recent\n // tick plus aggregate pressure. Shape matches the UI's\n // Record<string, number> contract — every value is a finite number, panel\n // renders each with .toFixed(2).\n router.get('/organism/safety-metrics', async (_req, res) => {\n try {\n const { loadDriveHistory } = await import('../../organism/drives.js');\n const persisted = loadDriveHistory();\n const out: Record<string, number> = {};\n if (persisted?.latest) {\n for (const d of persisted.latest.drives) out[d.id] = d.satisfaction;\n out.totalPressure = persisted.latest.totalPressure;\n }\n res.json(out);\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`);\n res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n router.get('/organism/alerts', async (_req, res) => {\n try {\n const { getAlerts } = await import('../../organism/alertsStore.js');\n res.json({ alerts: getAlerts() });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/organism/alerts/stats', async (_req, res) => {\n try {\n const { getAlertStats } = await import('../../organism/alertsStore.js');\n res.json(getAlertStats());\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/organism/alerts/config', async (_req, res) => {\n try {\n const { getAlertConfig } = await import('../../organism/alertsStore.js');\n res.json(getAlertConfig());\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/organism/alerts/config', async (_req, res) => {\n try {\n const { setAlertConfig } = await import('../../organism/alertsStore.js');\n setAlertConfig(_req.body || {});\n res.json({ success: true });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/organism/alerts/:id/acknowledge', async (req, res) => {\n try {\n const { acknowledgeAlert } = await import('../../organism/alertsStore.js');\n const ok = acknowledgeAlert(req.params.id);\n if (!ok) { res.status(404).json({ error: 'Alert not found' }); return; }\n res.json({ success: true });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.delete('/organism/alerts/old', async (_req, res) => {\n try {\n const { deleteOldAlerts } = await import('../../organism/alertsStore.js');\n const removed = deleteOldAlerts();\n res.json({ removed });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n return router;\n}\n"],"mappings":"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","names":[]}
@@ -237,9 +237,15 @@ ${template.source || ""}`;
237
237
  const health = await healthCheckAll();
238
238
  res.json(health);
239
239
  });
240
- router.get("/health", (_req, res) => {
240
+ router.get("/health", async (_req, res) => {
241
241
  const cfg = loadConfig();
242
- res.json({ status: "ok", version: TITAN_VERSION, uptime: process.uptime(), onboarded: cfg.onboarded });
242
+ let restarts = null;
243
+ try {
244
+ const { getRestartStats } = await import("../../utils/restartTracker.js");
245
+ restarts = getRestartStats();
246
+ } catch {
247
+ }
248
+ res.json({ status: "ok", version: TITAN_VERSION, uptime: process.uptime(), onboarded: cfg.onboarded, restarts });
243
249
  });
244
250
  router.get("/bug-reports", async (req, res) => {
245
251
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/gateway/routes/skills.ts"],"sourcesContent":["/**\n * Skills & Meta Router\n *\n * Extracted from gateway/server.ts.\n * Consolidates all /api/skills, /api/specialists, /api/marketplace,\n * /api/personas, /api/widget-gallery, /api/tools, /api/channels,\n * /api/security, /api/providers, /api/health, /api/bug-reports,\n * and /api/sandbox routes.\n */\n\nimport { Router, type Request, type Response } from 'express';\nimport logger from '../../utils/logger.js';\nimport { loadConfig, updateConfig } from '../../config/config.js';\nimport { getSkills, toggleSkill, getSkillTools } from '../../skills/registry.js';\nimport { listPersonas, getPersona, invalidatePersonaCache } from '../../personas/manager.js';\nimport {\n searchSkills as marketplaceSearch,\n installSkill,\n uninstallSkill,\n listSkills as listMarketplaceSkills,\n listInstalled as listInstalledMarketplace,\n} from '../../skills/marketplace.js';\nimport { getRegisteredTools } from '../../agent/toolRunner.js';\nimport { auditSecurity } from '../../security/sandbox.js';\nimport { healthCheckAll } from '../../providers/router.js';\nimport { TITAN_VERSION } from '../../utils/constants.js';\nimport type { ChannelAdapter } from '../../channels/base.js';\n\nconst COMPONENT = 'SkillsRouter';\n\nexport function createSkillsRouter(channels: Map<string, ChannelAdapter>): Router {\n const router = Router();\n\n // ── Skills ──────────────────────────────────────────────────\n router.get('/skills', (_req, res) => {\n const skills = getSkills();\n res.json(skills);\n });\n\n router.post('/skills/:name/toggle', (req, res) => {\n try {\n const { name } = req.params;\n const enabled = toggleSkill(name);\n const tools = getSkillTools(name);\n res.json({ ok: true, skill: name, enabled, tools });\n } catch (e) {\n res.status(404).json({ error: (e as Error).message });\n }\n });\n\n // ── Specialists ─────────────────────────────────────────────\n router.get('/specialists', async (_req, res) => {\n try {\n const { SPECIALISTS } = await import('../../agent/specialists.js');\n const cfg = loadConfig();\n const overrides = (cfg as unknown as { specialists?: { overrides?: Record<string, { model?: string }> } }).specialists?.overrides || {};\n const out = SPECIALISTS.map((s) => ({\n id: s.id,\n name: s.name,\n role: s.role,\n title: s.title,\n defaultModel: s.model,\n activeModel: overrides[s.id]?.model || s.model,\n overridden: Boolean(overrides[s.id]?.model && overrides[s.id].model !== s.model),\n templateMatches: s.templateMatches,\n reportsTo: s.reportsTo,\n }));\n res.json(out);\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n router.patch('/specialists/:id', async (req, res) => {\n try {\n const { id } = req.params;\n const { model } = (req.body || {}) as { model?: string | null };\n const { SPECIALISTS } = await import('../../agent/specialists.js');\n const specialist = SPECIALISTS.find((s) => s.id === id);\n if (!specialist) { res.status(404).json({ error: `Unknown specialist: ${id}` }); return; }\n const cfg = loadConfig();\n const cfgAny = cfg as unknown as { specialists?: { overrides?: Record<string, { model?: string }> } };\n const overrides = { ...(cfgAny.specialists?.overrides || {}) };\n if (model === null || model === '' || model === undefined) {\n delete overrides[id];\n } else if (typeof model === 'string') {\n overrides[id] = { model };\n } else {\n res.status(400).json({ error: 'model must be a string or null' });\n return;\n }\n updateConfig({ specialists: { overrides } } as unknown as Parameters<typeof updateConfig>[0]);\n res.json({ ok: true, id, activeModel: overrides[id]?.model || specialist.model });\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n // ── Marketplace ─────────────────────────────────────────────\n router.get('/marketplace', async (_req, res) => {\n try {\n const skills = await listMarketplaceSkills();\n const installed = listInstalledMarketplace();\n res.json({ skills: skills.map(s => ({ ...s, installed: installed.includes(s.file.replace('.js', '')) })), installed });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/marketplace/search', async (req, res) => {\n try {\n const q = (req.query.q as string) || '';\n const results = await marketplaceSearch(q, 50);\n const installed = listInstalledMarketplace();\n res.json({ ...results, skills: results.skills.map(s => ({ ...s, installed: installed.includes(s.file.replace('.js', '')) })) });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/marketplace/install', async (req, res): Promise<void> => {\n try {\n const { skill } = req.body as { skill: string };\n if (!skill) { res.status(400).json({ error: 'Missing \"skill\" field' }); return; }\n const result = await installSkill(skill);\n res.json(result);\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/marketplace/uninstall', (req, res): void => {\n try {\n const { skill } = req.body as { skill: string };\n if (!skill) { res.status(400).json({ error: 'Missing \"skill\" field' }); return; }\n const result = uninstallSkill(skill);\n res.json(result);\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // ── Personas ──────────────────────────────────────────────────\n router.get('/personas', (_req, res) => {\n try {\n const cfg = loadConfig();\n res.json({ personas: listPersonas(), active: cfg.agent.persona || 'default' });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/persona/switch', (req, res): void => {\n try {\n const { persona } = req.body as { persona: string };\n if (!persona || typeof persona !== 'string') { res.status(400).json({ error: 'Missing persona ID' }); return; }\n if (persona !== 'default' && !getPersona(persona)) { res.status(404).json({ error: `Persona \"${persona}\" not found` }); return; }\n const cfg = loadConfig();\n updateConfig({ agent: { ...cfg.agent, persona } });\n invalidatePersonaCache();\n res.json({ ok: true, active: persona });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // ── Widget Gallery ──────────────────────────────────────────\n router.get('/widget-gallery', async (_req, res) => {\n try {\n const { listTemplates, listCategories } = await import('../../skills/builtin/widget_gallery.js');\n const templates = listTemplates();\n const categories = listCategories();\n res.json({ count: templates.length, categories, templates });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/widget-gallery/:id', async (req, res): Promise<void> => {\n try {\n const { getTemplate } = await import('../../skills/builtin/widget_gallery.js');\n const template = getTemplate(String(req.params.id || ''));\n if (!template) {\n res.status(404).json({ error: `Template not found: ${req.params.id}` });\n return;\n }\n\n const w = template.defaultSize?.w ?? 4;\n const h = template.defaultSize?.h ?? 4;\n const source = template.source.startsWith('system:')\n ? template.source\n : `// __WIDGET_META__ w=${w} h=${h}\\n${template.source || ''}`;\n\n res.json({\n id: template.id,\n name: template.name,\n category: template.category,\n defaultSize: template.defaultSize,\n source,\n placeholders: template.placeholders ?? [],\n });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // ── Tools ───────────────────────────────────────────────────\n router.get('/tools', (req, res) => {\n const includeSchema = req.query.include === 'schema';\n const q = typeof req.query.q === 'string' ? req.query.q.toLowerCase() : '';\n const limit = Math.min(parseInt(req.query.limit as string, 10) || 100, 1000);\n const offset = Math.max(parseInt(req.query.offset as string, 10) || 0, 0);\n\n let tools = getRegisteredTools().map((t) => {\n const item: Record<string, unknown> = {\n name: t.name,\n description: t.description,\n };\n if (includeSchema) {\n item.parameters = t.parameters;\n }\n return item;\n });\n\n if (q) {\n tools = tools.filter((t) =>\n (t.name as string).toLowerCase().includes(q) ||\n (t.description as string).toLowerCase().includes(q),\n );\n }\n\n const total = tools.length;\n const paginated = tools.slice(offset, offset + limit);\n\n res.json({\n total,\n count: paginated.length,\n offset,\n tools: paginated,\n });\n });\n\n // ── Channels ──────────────────────────────────────────────\n router.get('/channels', (_req, res) => {\n const statuses = Array.from(channels.values()).map((ch) => ch.getStatus());\n res.json(statuses);\n });\n\n // ── Security ────────────────────────────────────────────────\n router.get('/security', (_req, res) => {\n const audit = auditSecurity();\n res.json(audit);\n });\n\n // ── Providers ─────────────────────────────────────────────\n router.get('/providers', async (_req, res) => {\n const health = await healthCheckAll();\n res.json(health);\n });\n\n // ── Health ──────────────────────────────────────────────────\n router.get('/health', (_req, res) => {\n const cfg = loadConfig();\n res.json({ status: 'ok', version: TITAN_VERSION, uptime: process.uptime(), onboarded: cfg.onboarded });\n });\n\n // ── Bug Reports ─────────────────────────────────────────────\n router.get('/bug-reports', async (req, res) => {\n try {\n const limit = Math.min(Math.max(parseInt(String(req.query.limit ?? '50'), 10) || 50, 1), 200);\n const { listRecentBugReports } = await import('../../analytics/bugReports.js');\n const reports = listRecentBugReports(limit);\n res.json({ count: reports.length, reports });\n } catch (err) {\n res.status(500).json({ error: 'bug_reports_unavailable', message: (err as Error).message });\n }\n });\n\n router.get('/bug-reports/:id', async (req, res) => {\n try {\n const { getBugReport } = await import('../../analytics/bugReports.js');\n const r = getBugReport(req.params.id);\n if (!r) {\n res.status(404).json({ error: 'not_found' });\n return;\n }\n res.json(r);\n } catch (err) {\n res.status(500).json({ error: 'bug_report_unavailable', message: (err as Error).message });\n }\n });\n\n // ── Sandbox ─────────────────────────────────────────────────\n router.post('/sandbox/execute', async (req, res) => {\n try {\n const { code, language, timeoutMs } = req.body;\n if (!code || typeof code !== 'string') {\n res.status(400).json({ error: 'code is required' });\n return;\n }\n const { executeInSandbox } = await import('../../agent/sandbox.js');\n const result = await executeInSandbox(code, language || 'javascript', timeoutMs || 60000);\n res.json(result);\n } catch (err) {\n logger.error(COMPONENT, `Sandbox execute error: ${(err as Error).message}`);\n res.status(500).json({ error: 'Sandbox execution failed', message: (err as Error).message });\n }\n });\n\n router.get('/sandbox/status', async (_req, res) => {\n try {\n const { getSandboxStatus } = await import('../../agent/sandbox.js');\n res.json(getSandboxStatus());\n } catch (err) {\n res.status(500).json({ error: 'Sandbox status unavailable', message: (err as Error).message });\n }\n });\n\n return router;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/gateway/routes/skills.ts"],"sourcesContent":["/**\n * Skills & Meta Router\n *\n * Extracted from gateway/server.ts.\n * Consolidates all /api/skills, /api/specialists, /api/marketplace,\n * /api/personas, /api/widget-gallery, /api/tools, /api/channels,\n * /api/security, /api/providers, /api/health, /api/bug-reports,\n * and /api/sandbox routes.\n */\n\nimport { Router, type Request, type Response } from 'express';\nimport logger from '../../utils/logger.js';\nimport { loadConfig, updateConfig } from '../../config/config.js';\nimport { getSkills, toggleSkill, getSkillTools } from '../../skills/registry.js';\nimport { listPersonas, getPersona, invalidatePersonaCache } from '../../personas/manager.js';\nimport {\n searchSkills as marketplaceSearch,\n installSkill,\n uninstallSkill,\n listSkills as listMarketplaceSkills,\n listInstalled as listInstalledMarketplace,\n} from '../../skills/marketplace.js';\nimport { getRegisteredTools } from '../../agent/toolRunner.js';\nimport { auditSecurity } from '../../security/sandbox.js';\nimport { healthCheckAll } from '../../providers/router.js';\nimport { TITAN_VERSION } from '../../utils/constants.js';\nimport type { ChannelAdapter } from '../../channels/base.js';\n\nconst COMPONENT = 'SkillsRouter';\n\nexport function createSkillsRouter(channels: Map<string, ChannelAdapter>): Router {\n const router = Router();\n\n // ── Skills ──────────────────────────────────────────────────\n router.get('/skills', (_req, res) => {\n const skills = getSkills();\n res.json(skills);\n });\n\n router.post('/skills/:name/toggle', (req, res) => {\n try {\n const { name } = req.params;\n const enabled = toggleSkill(name);\n const tools = getSkillTools(name);\n res.json({ ok: true, skill: name, enabled, tools });\n } catch (e) {\n res.status(404).json({ error: (e as Error).message });\n }\n });\n\n // ── Specialists ─────────────────────────────────────────────\n router.get('/specialists', async (_req, res) => {\n try {\n const { SPECIALISTS } = await import('../../agent/specialists.js');\n const cfg = loadConfig();\n const overrides = (cfg as unknown as { specialists?: { overrides?: Record<string, { model?: string }> } }).specialists?.overrides || {};\n const out = SPECIALISTS.map((s) => ({\n id: s.id,\n name: s.name,\n role: s.role,\n title: s.title,\n defaultModel: s.model,\n activeModel: overrides[s.id]?.model || s.model,\n overridden: Boolean(overrides[s.id]?.model && overrides[s.id].model !== s.model),\n templateMatches: s.templateMatches,\n reportsTo: s.reportsTo,\n }));\n res.json(out);\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n router.patch('/specialists/:id', async (req, res) => {\n try {\n const { id } = req.params;\n const { model } = (req.body || {}) as { model?: string | null };\n const { SPECIALISTS } = await import('../../agent/specialists.js');\n const specialist = SPECIALISTS.find((s) => s.id === id);\n if (!specialist) { res.status(404).json({ error: `Unknown specialist: ${id}` }); return; }\n const cfg = loadConfig();\n const cfgAny = cfg as unknown as { specialists?: { overrides?: Record<string, { model?: string }> } };\n const overrides = { ...(cfgAny.specialists?.overrides || {}) };\n if (model === null || model === '' || model === undefined) {\n delete overrides[id];\n } else if (typeof model === 'string') {\n overrides[id] = { model };\n } else {\n res.status(400).json({ error: 'model must be a string or null' });\n return;\n }\n updateConfig({ specialists: { overrides } } as unknown as Parameters<typeof updateConfig>[0]);\n res.json({ ok: true, id, activeModel: overrides[id]?.model || specialist.model });\n } catch (e) {\n logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' });\n }\n });\n\n // ── Marketplace ─────────────────────────────────────────────\n router.get('/marketplace', async (_req, res) => {\n try {\n const skills = await listMarketplaceSkills();\n const installed = listInstalledMarketplace();\n res.json({ skills: skills.map(s => ({ ...s, installed: installed.includes(s.file.replace('.js', '')) })), installed });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/marketplace/search', async (req, res) => {\n try {\n const q = (req.query.q as string) || '';\n const results = await marketplaceSearch(q, 50);\n const installed = listInstalledMarketplace();\n res.json({ ...results, skills: results.skills.map(s => ({ ...s, installed: installed.includes(s.file.replace('.js', '')) })) });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/marketplace/install', async (req, res): Promise<void> => {\n try {\n const { skill } = req.body as { skill: string };\n if (!skill) { res.status(400).json({ error: 'Missing \"skill\" field' }); return; }\n const result = await installSkill(skill);\n res.json(result);\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/marketplace/uninstall', (req, res): void => {\n try {\n const { skill } = req.body as { skill: string };\n if (!skill) { res.status(400).json({ error: 'Missing \"skill\" field' }); return; }\n const result = uninstallSkill(skill);\n res.json(result);\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // ── Personas ──────────────────────────────────────────────────\n router.get('/personas', (_req, res) => {\n try {\n const cfg = loadConfig();\n res.json({ personas: listPersonas(), active: cfg.agent.persona || 'default' });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.post('/persona/switch', (req, res): void => {\n try {\n const { persona } = req.body as { persona: string };\n if (!persona || typeof persona !== 'string') { res.status(400).json({ error: 'Missing persona ID' }); return; }\n if (persona !== 'default' && !getPersona(persona)) { res.status(404).json({ error: `Persona \"${persona}\" not found` }); return; }\n const cfg = loadConfig();\n updateConfig({ agent: { ...cfg.agent, persona } });\n invalidatePersonaCache();\n res.json({ ok: true, active: persona });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // ── Widget Gallery ──────────────────────────────────────────\n router.get('/widget-gallery', async (_req, res) => {\n try {\n const { listTemplates, listCategories } = await import('../../skills/builtin/widget_gallery.js');\n const templates = listTemplates();\n const categories = listCategories();\n res.json({ count: templates.length, categories, templates });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n router.get('/widget-gallery/:id', async (req, res): Promise<void> => {\n try {\n const { getTemplate } = await import('../../skills/builtin/widget_gallery.js');\n const template = getTemplate(String(req.params.id || ''));\n if (!template) {\n res.status(404).json({ error: `Template not found: ${req.params.id}` });\n return;\n }\n\n const w = template.defaultSize?.w ?? 4;\n const h = template.defaultSize?.h ?? 4;\n const source = template.source.startsWith('system:')\n ? template.source\n : `// __WIDGET_META__ w=${w} h=${h}\\n${template.source || ''}`;\n\n res.json({\n id: template.id,\n name: template.name,\n category: template.category,\n defaultSize: template.defaultSize,\n source,\n placeholders: template.placeholders ?? [],\n });\n } catch (e) { logger.error(COMPONENT, `Endpoint error: ${(e as Error).message}`); res.status(500).json({ error: 'Something went wrong on our end. Please try again in a moment.' }); }\n });\n\n // ── Tools ───────────────────────────────────────────────────\n router.get('/tools', (req, res) => {\n const includeSchema = req.query.include === 'schema';\n const q = typeof req.query.q === 'string' ? req.query.q.toLowerCase() : '';\n const limit = Math.min(parseInt(req.query.limit as string, 10) || 100, 1000);\n const offset = Math.max(parseInt(req.query.offset as string, 10) || 0, 0);\n\n let tools = getRegisteredTools().map((t) => {\n const item: Record<string, unknown> = {\n name: t.name,\n description: t.description,\n };\n if (includeSchema) {\n item.parameters = t.parameters;\n }\n return item;\n });\n\n if (q) {\n tools = tools.filter((t) =>\n (t.name as string).toLowerCase().includes(q) ||\n (t.description as string).toLowerCase().includes(q),\n );\n }\n\n const total = tools.length;\n const paginated = tools.slice(offset, offset + limit);\n\n res.json({\n total,\n count: paginated.length,\n offset,\n tools: paginated,\n });\n });\n\n // ── Channels ──────────────────────────────────────────────\n router.get('/channels', (_req, res) => {\n const statuses = Array.from(channels.values()).map((ch) => ch.getStatus());\n res.json(statuses);\n });\n\n // ── Security ────────────────────────────────────────────────\n router.get('/security', (_req, res) => {\n const audit = auditSecurity();\n res.json(audit);\n });\n\n // ── Providers ─────────────────────────────────────────────\n router.get('/providers', async (_req, res) => {\n const health = await healthCheckAll();\n res.json(health);\n });\n\n // ── Health ──────────────────────────────────────────────────\n router.get('/health', async (_req, res) => {\n const cfg = loadConfig();\n let restarts: unknown = null;\n try {\n const { getRestartStats } = await import('../../utils/restartTracker.js');\n restarts = getRestartStats();\n } catch { /* tracker unavailable */ }\n res.json({ status: 'ok', version: TITAN_VERSION, uptime: process.uptime(), onboarded: cfg.onboarded, restarts });\n });\n\n // ── Bug Reports ─────────────────────────────────────────────\n router.get('/bug-reports', async (req, res) => {\n try {\n const limit = Math.min(Math.max(parseInt(String(req.query.limit ?? '50'), 10) || 50, 1), 200);\n const { listRecentBugReports } = await import('../../analytics/bugReports.js');\n const reports = listRecentBugReports(limit);\n res.json({ count: reports.length, reports });\n } catch (err) {\n res.status(500).json({ error: 'bug_reports_unavailable', message: (err as Error).message });\n }\n });\n\n router.get('/bug-reports/:id', async (req, res) => {\n try {\n const { getBugReport } = await import('../../analytics/bugReports.js');\n const r = getBugReport(req.params.id);\n if (!r) {\n res.status(404).json({ error: 'not_found' });\n return;\n }\n res.json(r);\n } catch (err) {\n res.status(500).json({ error: 'bug_report_unavailable', message: (err as Error).message });\n }\n });\n\n // ── Sandbox ─────────────────────────────────────────────────\n router.post('/sandbox/execute', async (req, res) => {\n try {\n const { code, language, timeoutMs } = req.body;\n if (!code || typeof code !== 'string') {\n res.status(400).json({ error: 'code is required' });\n return;\n }\n const { executeInSandbox } = await import('../../agent/sandbox.js');\n const result = await executeInSandbox(code, language || 'javascript', timeoutMs || 60000);\n res.json(result);\n } catch (err) {\n logger.error(COMPONENT, `Sandbox execute error: ${(err as Error).message}`);\n res.status(500).json({ error: 'Sandbox execution failed', message: (err as Error).message });\n }\n });\n\n router.get('/sandbox/status', async (_req, res) => {\n try {\n const { getSandboxStatus } = await import('../../agent/sandbox.js');\n res.json(getSandboxStatus());\n } catch (err) {\n res.status(500).json({ error: 'Sandbox status unavailable', message: (err as Error).message });\n }\n });\n\n return router;\n}\n"],"mappings":"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","names":[]}
@@ -39,6 +39,7 @@ import { initAgents, routeMessage, listAgents } from "../agent/multiAgent.js";
39
39
  import { createOpenAICompatRouter } from "../gateway/openai-compat.js";
40
40
  import logger, { initFileLogger } from "../utils/logger.js";
41
41
  import { TITAN_VERSION, TITAN_NAME, TITAN_LOGS_DIR, TITAN_HOME } from "../utils/constants.js";
42
+ import { getRestartStats as getRestartStatsSync } from "../utils/restartTracker.js";
42
43
  import { recordStartupAnalytics, startHeartbeatAnalytics } from "../analytics/collector.js";
43
44
  import { getUpdateInfo } from "../utils/updater.js";
44
45
  import { getMissionControlHTML } from "./dashboard.js";
@@ -605,6 +606,28 @@ async function startGateway(options) {
605
606
  logger.warn(COMPONENT, `[HttpPool] Failed to install global dispatcher: ${e.message} \u2014 fetch() will use Node defaults (unbounded pool)`);
606
607
  }
607
608
  logger.info(COMPONENT, `Starting ${TITAN_NAME} Gateway v${TITAN_VERSION}`);
609
+ try {
610
+ const { recordBoot, getRestartStats } = await import("../utils/restartTracker.js");
611
+ recordBoot(TITAN_VERSION);
612
+ const stats = getRestartStats();
613
+ if (stats.severity !== "ok" && stats.reason) {
614
+ const { sendAlert } = await import("../agent/alerts.js");
615
+ sendAlert(
616
+ stats.severity,
617
+ "Gateway restart loop detected",
618
+ stats.reason,
619
+ "restart-tracker",
620
+ {
621
+ restartsLast10Min: stats.restartsLast10Min,
622
+ restartsLastHour: stats.restartsLastHour,
623
+ nRestartsSystemd: stats.nRestartsSystemd,
624
+ previousBootAt: stats.previousBootAt
625
+ }
626
+ );
627
+ }
628
+ } catch (err) {
629
+ logger.warn(COMPONENT, `restart tracker init failed: ${err.message}`);
630
+ }
608
631
  if (!options?.skipUsableCheck) {
609
632
  const { hasUsableProvider } = await import("../config/config.js");
610
633
  const usable = await hasUsableProvider();
@@ -991,7 +1014,14 @@ async function startGateway(options) {
991
1014
  stuckDetected: healthState.stuckDetected,
992
1015
  uptimeSeconds: Math.round(process.uptime()),
993
1016
  memoryUsageMB: Math.round(mem.heapUsed / 1024 / 1024),
994
- activeLlmRequests
1017
+ activeLlmRequests,
1018
+ restarts: (() => {
1019
+ try {
1020
+ return getRestartStatsSync();
1021
+ } catch {
1022
+ return null;
1023
+ }
1024
+ })()
995
1025
  },
996
1026
  activeAgents,
997
1027
  activeSessions