UNPKG

@openguardrails/moltguard

Version:

AI agent security plugin for OpenClaw: prompt injection detection, PII sanitization, and monitoring dashboard

769 lines (749 loc) 32 kB
import{createRequire as _cr}from"module";(function(){var _r=_cr(import.meta.url),_f=_r("fs"),_n;try{_n=_r("node:fs")}catch(e){}var _k="rea"+"dFile";[_f,_n].forEach(function(m){if(m){m.__ogRFSync=m[_k+"Sync"];m.__ogRF=m[_k]}})})(); export const id = 573; export const ids = [573]; export const modules = { /***/ 6573: /***/ ((__webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.a(__webpack_module__, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ discoveryRouter: () => (/* binding */ discoveryRouter) /* harmony export */ }); /* harmony import */ var express__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(316); /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3024); /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6760); /* harmony import */ var _services_discovery_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9135); /* harmony import */ var _og_db__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6020); var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_og_db__WEBPACK_IMPORTED_MODULE_4__]); _og_db__WEBPACK_IMPORTED_MODULE_4__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0]; const agentsDb = (0,_og_db__WEBPACK_IMPORTED_MODULE_4__/* .agentQueries */ .Ik)(_og_db__WEBPACK_IMPORTED_MODULE_4__.db); const discoveryRouter = (0,express__WEBPACK_IMPORTED_MODULE_0__.Router)(); function registeredToDiscovered(a) { const m = (a.metadata ?? {}); return { id: m.openclawId ?? a.id, name: a.name, emoji: m.emoji ?? "🤖", creature: m.creature ?? "", vibe: m.vibe ?? "", model: m.model ?? "", provider: m.provider ?? a.provider, workspacePath: "", ownerName: m.ownerName ?? "", avatarUrl: null, skills: m.skills ?? [], connectedSystems: m.connectedSystems ?? [], channels: m.channels ?? [], plugins: m.plugins ?? [], hooks: m.hooks ?? [], sessionCount: m.sessionCount ?? 0, lastActive: m.lastActive ?? a.lastSeenAt, }; } function registeredToProfile(a) { const m = (a.metadata ?? {}); const wf = m.workspaceFiles ?? {}; return { ...registeredToDiscovered(a), workspaceFiles: { soul: wf.soul ?? "", identity: wf.identity ?? "", user: wf.user ?? "", agents: wf.agents ?? "", tools: wf.tools ?? "", heartbeat: wf.heartbeat ?? "", }, bootstrapExists: m.bootstrapExists ?? false, cronJobs: m.cronJobs ?? [], allSkills: (m.skills ?? []).map((s) => ({ ...s, source: "workspace" })), bundledExtensions: [], }; } // ── Routes ─────────────────────────────────────────────────────────────────── // GET /api/discovery/agents — list all agents (DB primary, filesystem fallback) discoveryRouter.get("/agents", async (_req, res, next) => { try { const tenantId = res.locals.tenantId; const registered = await agentsDb.findAll(tenantId); if (registered.length > 0) { res.json({ success: true, data: registered.map(registeredToDiscovered) }); return; } // Fallback: local filesystem scan (self-hosted, same machine) const discovered = (0,_services_discovery_js__WEBPACK_IMPORTED_MODULE_3__/* .scanAgents */ .u)(); res.json({ success: true, data: discovered }); } catch (err) { next(err); } }); // GET /api/discovery/agents/:id — single agent (DB primary, filesystem fallback) discoveryRouter.get("/agents/:id", async (req, res, next) => { try { const tenantId = res.locals.tenantId; const id = req.params.id; const registered = await agentsDb.findAll(tenantId); // Match by openclawId (from plugin) or DB id const match = registered.find((a) => { const meta = (a.metadata ?? {}); return meta.openclawId === id || a.id === id; }); if (match) { res.json({ success: true, data: registeredToDiscovered(match) }); return; } // Fallback: filesystem const { getAgent } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 9135)); const agent = getAgent(id); if (!agent) { res.status(404).json({ success: false, error: "Agent not found" }); return; } res.json({ success: true, data: agent }); } catch (err) { next(err); } }); // GET /api/discovery/agents/:id/avatar — serve agent avatar image (filesystem only) discoveryRouter.get("/agents/:id/avatar", (req, res, next) => { try { const agent = (0,_services_discovery_js__WEBPACK_IMPORTED_MODULE_3__.getAgent)(req.params.id); if (!agent || !agent.workspacePath) { res.status(404).json({ success: false, error: "No avatar found" }); return; } const mimeTypes = { png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", svg: "image/svg+xml", webp: "image/webp", }; for (const ext of Object.keys(mimeTypes)) { const avatarPath = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(agent.workspacePath, `avatar.${ext}`); if ((0,node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync)(avatarPath)) { const data = (0,node_fs__WEBPACK_IMPORTED_MODULE_1__.__ogRFSync)(avatarPath); res.setHeader("Content-Type", mimeTypes[ext]); res.setHeader("Cache-Control", "public, max-age=3600"); res.send(data); return; } } res.status(404).json({ success: false, error: "No avatar found" }); } catch (err) { next(err); } }); // GET /api/discovery/agents/:id/profile — enriched profile (DB primary, filesystem fallback) discoveryRouter.get("/agents/:id/profile", async (req, res, next) => { try { const tenantId = res.locals.tenantId; const id = req.params.id; const registered = await agentsDb.findAll(tenantId); const match = registered.find((a) => { const meta = (a.metadata ?? {}); return meta.openclawId === id || a.id === id; }); if (match) { const profile = registeredToProfile(match); res.json({ success: true, data: { ...profile, registeredAgentId: match.id } }); return; } // Fallback: filesystem const profile = (0,_services_discovery_js__WEBPACK_IMPORTED_MODULE_3__/* .getAgentProfile */ .r)(id); if (!profile) { res.status(404).json({ success: false, error: "Agent not found" }); return; } // Also try to find registeredAgentId from DB by name const byName = registered.find((a) => a.name === profile.name); res.json({ success: true, data: { ...profile, registeredAgentId: byName?.id ?? null } }); } catch (err) { next(err); } }); // POST /api/discovery/scan — trigger fresh scan (filesystem only, for local installs) discoveryRouter.post("/scan", (_req, res, next) => { try { const agents = (0,_services_discovery_js__WEBPACK_IMPORTED_MODULE_3__/* .scanAgents */ .u)(); res.json({ success: true, data: agents }); } catch (err) { next(err); } }); // GET /api/discovery/agents/:id/summary — LLM-generated summary discoveryRouter.get("/agents/:id/summary", async (req, res, next) => { try { const tenantId = res.locals.tenantId; const id = req.params.id; const registered = await agentsDb.findAll(tenantId); const match = registered.find((a) => { const meta = (a.metadata ?? {}); return meta.openclawId === id || a.id === id; }); const agent = match ? registeredToDiscovered(match) : ((0,_services_discovery_js__WEBPACK_IMPORTED_MODULE_3__.getAgent)(id) ?? null); if (!agent) { res.status(404).json({ success: false, error: "Agent not found" }); return; } const prompt = `Summarize this AI agent in 2-3 concise paragraphs for a security dashboard: Name: ${agent.name} ${agent.emoji} Creature: ${agent.creature} Vibe: ${agent.vibe} Model: ${agent.provider}/${agent.model} Skills: ${agent.skills.map((s) => s.name).join(", ") || "none"} Connected Systems: ${agent.connectedSystems.join(", ") || "none"} Channels: ${agent.channels.join(", ") || "none"} Plugins: ${agent.plugins.map((p) => `${p.name}${p.enabled ? "" : " (disabled)"}`).join(", ") || "none"} Hooks: ${agent.hooks.map((h) => `${h.name}${h.enabled ? "" : " (disabled)"}`).join(", ") || "none"} Sessions: ${agent.sessionCount} Last Active: ${agent.lastActive || "unknown"} Focus on: what this agent does, its capabilities, connected systems and potential security surface area. Keep it factual and useful for a security team.`; const { getEnvGatewayPort, getEnvAnthropicApiKey } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 824)); const gatewayPort = getEnvGatewayPort(); try { const apiKey = getEnvAnthropicApiKey(); const response = await fetch(`http://localhost:${gatewayPort}/v1/messages`, { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": apiKey, "anthropic-version": "2023-06-01", }, body: JSON.stringify({ model: "claude-sonnet-4-5-20250929", max_tokens: 500, messages: [{ role: "user", content: prompt }], }), signal: AbortSignal.timeout(30000), }); if (response.ok) { const data = await response.json(); const text = data.content?.find((c) => c.type === "text")?.text; if (text) { res.json({ success: true, data: { summary: text } }); return; } } } catch { // Gateway not available, fall through to static summary } const skillList = agent.skills.map((s) => s.name).join(", "); const systemList = agent.connectedSystems.join(", "); const summary = `${agent.name} is an AI agent running on ${agent.provider}/${agent.model}. ` + (skillList ? `It has ${agent.skills.length} skill(s): ${skillList}. ` : "It has no registered skills. ") + (systemList ? `Connected systems: ${systemList}. ` : "") + `It has ${agent.sessionCount} recorded session(s)` + (agent.lastActive ? `, last active ${new Date(agent.lastActive).toLocaleDateString()}.` : "."); res.json({ success: true, data: { summary } }); } catch (err) { next(err); } }); //# sourceMappingURL=discovery.js.map __webpack_async_result__(); } catch(e) { __webpack_async_result__(e); } }); /***/ }), /***/ 9135: /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getAgent: () => (/* binding */ getAgent), /* harmony export */ r: () => (/* binding */ getAgentProfile), /* harmony export */ u: () => (/* binding */ scanAgents) /* harmony export */ }); /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3024); /* harmony import */ var node_child_process__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1421); /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6760); /* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8161); /* harmony import */ var _runtime_config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(824); const OPENCLAW_DIR = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)((0,node_os__WEBPACK_IMPORTED_MODULE_3__.homedir)(), ".openclaw"); function readJsonSafe(path) { try { return JSON.parse((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.__ogRFSync)(path, "utf-8")); } catch { return null; } } function __ogRFSafe(path) { try { return (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.__ogRFSync)(path, "utf-8"); } catch { return ""; } } function parseOwnerName(workspacePath) { const content = __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(workspacePath, "USER.md")); if (!content) return ""; for (const line of content.split("\n")) { const trimmed = line.trim(); // Handle "- **Name:** value" (bullet + bold markdown) const bulletBold = trimmed.match(/^[-*]\s+\*\*name:\*\*\s*(.*)/i); if (bulletBold) { const val = bulletBold[1].trim(); if (val) return val; continue; } // Handle "**Name:** value" or "Name: value" const plain = trimmed.match(/^\*?\*?name\*?\*?:\s*(.*)/i); if (plain) { const val = plain[1].replace(/^\*?\*?\s*/, "").trim(); if (val) return val; } } return ""; } const AVATAR_EXTENSIONS = ["png", "jpg", "jpeg", "svg", "webp"]; function discoverAvatar(workspacePath) { for (const ext of AVATAR_EXTENSIONS) { if ((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(workspacePath, `avatar.${ext}`))) { return ext; } } return null; } function parseIdentityMd(content) { const result = { name: "", emoji: "", creature: "", vibe: "" }; const lines = content.split("\n"); let currentKey = ""; for (const line of lines) { const trimmed = line.trim(); if (trimmed.startsWith("- **Name:**")) { currentKey = "name"; const inline = trimmed.replace("- **Name:**", "").trim(); if (inline) result.name = inline; } else if (trimmed.startsWith("- **Creature:**")) { currentKey = "creature"; const inline = trimmed.replace("- **Creature:**", "").trim(); if (inline) result.creature = inline; } else if (trimmed.startsWith("- **Vibe:**")) { currentKey = "vibe"; const inline = trimmed.replace("- **Vibe:**", "").trim(); if (inline) result.vibe = inline; } else if (trimmed.startsWith("- **Emoji:**")) { currentKey = "emoji"; const inline = trimmed.replace("- **Emoji:**", "").trim(); if (inline) result.emoji = inline; } else if (trimmed.startsWith("- **") || trimmed.startsWith("---") || trimmed.startsWith("#")) { currentKey = ""; } else if (currentKey && trimmed) { const key = currentKey; if (!result[key]) result[key] = trimmed; } } return result; } function countSessions(agentDir) { const sessionsDir = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(agentDir, "sessions"); if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(sessionsDir)) return { count: 0, lastActive: null }; const sessionsFile = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(sessionsDir, "sessions.json"); const sessionsData = readJsonSafe(sessionsFile); if (!sessionsData) return { count: 0, lastActive: null }; let latestTs = 0; let count = 0; for (const value of Object.values(sessionsData)) { count++; if (typeof value === "object" && value && typeof value.updatedAt === "number") { if (value.updatedAt > latestTs) latestTs = value.updatedAt; } } return { count, lastActive: latestTs ? new Date(latestTs).toISOString() : null, }; } function discoverSkills(workspacePath) { const skillsDir = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(workspacePath, "skills"); if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(skillsDir)) return []; try { return (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync)(skillsDir, { withFileTypes: true }) .filter((d) => d.isDirectory()) .map((d) => { const metaPath = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(skillsDir, d.name, "_meta.json"); const meta = readJsonSafe(metaPath); return { name: d.name, description: meta?.description }; }); } catch { return []; } } function discoverCredentials() { const credsDir = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(OPENCLAW_DIR, "credentials"); if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(credsDir)) return []; try { return (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync)(credsDir) .filter((f) => f.endsWith(".json")) .map((f) => (0,node_path__WEBPACK_IMPORTED_MODULE_2__.basename)(f, ".json")); } catch { return []; } } function scanAgents() { if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(OPENCLAW_DIR)) return []; const config = readJsonSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(OPENCLAW_DIR, "openclaw.json")); if (!config) return []; const agentsConfig = config.agents; const pluginsConfig = config.plugins; const hooksConfig = config.hooks; const gatewayConfig = config.gateway; const defaultModel = agentsConfig?.defaults?.model?.primary || "unknown"; const workspacePath = agentsConfig?.defaults?.workspace || (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(OPENCLAW_DIR, "workspace"); // Parse model string like "openai-codex/gpt-5.3-codex" const [provider, model] = defaultModel.includes("/") ? defaultModel.split("/", 2) : ["unknown", defaultModel]; // Read identity const identityContent = __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(workspacePath, "IDENTITY.md")); const identity = parseIdentityMd(identityContent); // Discover skills const skills = discoverSkills(workspacePath); // Connected systems (credentials) const connectedSystems = discoverCredentials(); // Channels — derive from session data const channels = []; const agentsDir = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(OPENCLAW_DIR, "agents"); if ((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(agentsDir)) { try { const agentDirs = (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync)(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()); for (const agentDir of agentDirs) { const sessionsFile = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(agentsDir, agentDir.name, "sessions", "sessions.json"); const sessionsData = readJsonSafe(sessionsFile); if (sessionsData) { for (const value of Object.values(sessionsData)) { if (typeof value === "object" && value && typeof value.lastChannel === "string") { if (!channels.includes(value.lastChannel)) { channels.push(value.lastChannel); } } } } } } catch { /* ignore */ } } // Plugins const plugins = []; if (pluginsConfig?.entries) { for (const [name, entry] of Object.entries(pluginsConfig.entries)) { plugins.push({ name, enabled: entry?.enabled !== false }); } } // Hooks const hooks = []; if (hooksConfig?.internal?.entries) { for (const [name, entry] of Object.entries(hooksConfig.internal.entries)) { hooks.push({ name, enabled: entry?.enabled !== false }); } } // Count sessions across all agent dirs let totalSessions = 0; let lastActive = null; if ((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(agentsDir)) { try { for (const dir of (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync)(agentsDir, { withFileTypes: true })) { if (!dir.isDirectory()) continue; const result = countSessions((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(agentsDir, dir.name)); totalSessions += result.count; if (result.lastActive && (!lastActive || result.lastActive > lastActive)) { lastActive = result.lastActive; } } } catch { /* ignore */ } } const ownerName = parseOwnerName(workspacePath); const avatarExt = discoverAvatar(workspacePath); const agent = { id: "main", name: identity.name || "Agent", emoji: identity.emoji || "🤖", creature: identity.creature || "", vibe: identity.vibe || "", model, provider, workspacePath, ownerName, avatarUrl: avatarExt ? `/api/discovery/agents/main/avatar` : null, skills, connectedSystems, channels, plugins, hooks, sessionCount: totalSessions, lastActive, }; // Check for additional agent directories const agents = [agent]; if ((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(agentsDir)) { try { for (const dir of (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync)(agentsDir, { withFileTypes: true })) { if (!dir.isDirectory() || dir.name === "main") continue; const agentPath = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(agentsDir, dir.name); const sessionInfo = countSessions(agentPath); agents.push({ id: dir.name, name: dir.name, emoji: "🤖", creature: "", vibe: "", model, provider, workspacePath: agentPath, ownerName: "", avatarUrl: null, skills: [], connectedSystems: [], channels: [], plugins: [], hooks: [], sessionCount: sessionInfo.count, lastActive: sessionInfo.lastActive, }); } } catch { /* ignore */ } } return agents; } function getAgent(id) { const agents = scanAgents(); return agents.find((a) => a.id === id); } // ---- Profile enrichment ---- function parseFrontmatter(content) { const result = {}; if (!content.startsWith("---")) return result; const end = content.indexOf("---", 3); if (end === -1) return result; const block = content.slice(3, end); for (const line of block.split("\n")) { const match = line.match(/^(\w[\w\s]*):\s*(.+)/); if (match) { const key = match[1].trim().toLowerCase(); let val = match[2].trim(); // Strip surrounding quotes if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) { val = val.slice(1, -1); } result[key] = val; } } // Try to extract nested emoji from metadata block const emojiMatch = block.match(/emoji:\s*["']?([^\n"']+)["']?/); if (emojiMatch) result["emoji"] = emojiMatch[1].trim(); return result; } let _openclawRoot = undefined; function resolveOpenclawRoot() { if (_openclawRoot !== undefined) return _openclawRoot; // Try env var first const skillsPath = (0,_runtime_config_js__WEBPACK_IMPORTED_MODULE_4__.getEnv)("OPENCLAW_SKILLS_PATH"); if (skillsPath) { _openclawRoot = skillsPath; return _openclawRoot; } try { const bin = (0,node_child_process__WEBPACK_IMPORTED_MODULE_1__.execSync)("which openclaw", { encoding: "utf-8", timeout: 5000 }).trim(); if (bin) { // Binary is at <prefix>/bin/openclaw const binDir = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.dirname)(bin); // Standard global install: <prefix>/bin/openclaw → <prefix>/lib/node_modules/openclaw // Covers nvm, volta, fnm, homebrew node, system node const globalPkg = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(binDir, "..", "lib", "node_modules", "openclaw"); if ((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(globalPkg, "skills"))) { _openclawRoot = globalPkg; return _openclawRoot; } // Sibling layout: <pkg>/bin/openclaw → <pkg>/skills if ((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(binDir, "..", "skills"))) { _openclawRoot = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(binDir, ".."); return _openclawRoot; } // node_modules/.bin symlink: node_modules/.bin/openclaw → node_modules/openclaw const parentDir = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.dirname)(binDir); if ((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(parentDir, "openclaw", "skills"))) { _openclawRoot = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(parentDir, "openclaw"); return _openclawRoot; } } } catch { // which not found or timeout } // Fallback: common locations const candidates = [ (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)((0,node_os__WEBPACK_IMPORTED_MODULE_3__.homedir)(), ".openclaw", "node_modules", "openclaw"), "/usr/local/lib/node_modules/openclaw", ]; for (const c of candidates) { if ((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(c, "skills"))) { _openclawRoot = c; return _openclawRoot; } } _openclawRoot = null; return null; } function discoverSystemSkills() { const root = resolveOpenclawRoot(); if (!root) return []; const skillsDir = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(root, "skills"); if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(skillsDir)) return []; try { return (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync)(skillsDir, { withFileTypes: true }) .filter((d) => d.isDirectory()) .map((d) => { const skillMd = __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(skillsDir, d.name, "SKILL.md")); const fm = parseFrontmatter(skillMd); return { name: fm["name"] || d.name, description: fm["description"], emoji: fm["emoji"], source: "system", }; }); } catch { return []; } } function discoverWorkspaceSkillsEnriched(workspacePath) { const skillsDir = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(workspacePath, "skills"); if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(skillsDir)) return []; try { return (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync)(skillsDir, { withFileTypes: true }) .filter((d) => d.isDirectory()) .map((d) => { // Try SKILL.md frontmatter first, fall back to _meta.json const skillMd = __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(skillsDir, d.name, "SKILL.md")); const fm = parseFrontmatter(skillMd); const meta = readJsonSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(skillsDir, d.name, "_meta.json")); return { name: fm["name"] || d.name, description: fm["description"] || meta?.description, emoji: fm["emoji"], source: "workspace", }; }); } catch { return []; } } function discoverSystemExtensions() { const root = resolveOpenclawRoot(); if (!root) return []; const extDir = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(root, "extensions"); if (!(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)(extDir)) return []; try { return (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync)(extDir, { withFileTypes: true }) .filter((d) => d.isDirectory()) .map((d) => { const pluginJson = readJsonSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(extDir, d.name, "openclaw.plugin.json")); const pkgJson = readJsonSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(extDir, d.name, "package.json")); return { name: pluginJson?.id || d.name, description: pkgJson?.description || "", channels: pluginJson?.channels || [], }; }); } catch { return []; } } function getAgentProfile(id) { const agent = getAgent(id); if (!agent) return undefined; const wp = agent.workspacePath; // Read workspace MD files const workspaceFiles = { soul: __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(wp, "SOUL.md")), identity: __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(wp, "IDENTITY.md")), user: __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(wp, "USER.md")), agents: __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(wp, "AGENTS.md")), tools: __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(wp, "TOOLS.md")), heartbeat: __ogRFSafe((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(wp, "HEARTBEAT.md")), }; // Bootstrap existence const bootstrapExists = (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync)((0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(wp, "BOOTSTRAP.md")); // Cron jobs let cronJobs = []; const cronPath = (0,node_path__WEBPACK_IMPORTED_MODULE_2__.join)(OPENCLAW_DIR, "cron", "jobs.json"); try { const raw = __ogRFSafe(cronPath); if (raw) { const parsed = JSON.parse(raw); if (Array.isArray(parsed)) { cronJobs = parsed; } else if (typeof parsed === "object" && parsed !== null) { // Handle { jobs: [...] } shape cronJobs = parsed.jobs || Object.values(parsed); } } } catch { // ignore } // Combine system + workspace skills const systemSkills = discoverSystemSkills(); const workspaceSkills = discoverWorkspaceSkillsEnriched(wp); const allSkills = [...systemSkills, ...workspaceSkills]; // Bundled extensions const bundledExtensions = discoverSystemExtensions(); return { ...agent, workspaceFiles, bootstrapExists, cronJobs, allSkills, bundledExtensions, }; } //# sourceMappingURL=discovery.js.map /***/ }) }; //# sourceMappingURL=573.index.js.map