grix-connector
Version:
Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.
3 lines (2 loc) • 3.58 kB
JavaScript
import{readdirSync as y,readFileSync as g,existsSync as d,statSync as S}from"node:fs";import{dirname as w,join as r,resolve as b}from"node:path";import{homedir as F}from"node:os";import{log as O}from"../../core/log/index.js";function D(t){const e=t.trim();if(!e.startsWith("---"))return{name:"",description:""};const i=e.indexOf("---",3);if(i===-1)return{name:"",description:""};const s=e.slice(3,i).trim();let n="",c="",f;for(const a of s.split(`
`)){const u=a.indexOf(":");if(u===-1)continue;const p=a.slice(0,u).trim();let o=a.slice(u+1).trim();(o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'"))&&(o=o.slice(1,-1)),p==="name"?n=o:p==="description"?c=o:p==="trigger"&&(f=o)}return{name:n,description:c,trigger:f}}function W(t,e,i){if(!d(t))return[];const s=[];try{for(const n of y(t,{withFileTypes:!0})){const c=r(t,n.name);if(!j(n,c)||n.name.startsWith("."))continue;const f=r(c,"SKILL.md");if(d(f))try{const a=g(f,"utf-8"),u=D(a);u.name&&s.push({name:u.name,description:u.description,trigger:u.trigger,source:e,pluginName:i})}catch{}}}catch{}return s}function l(t,e,i){if(!d(t))return[];const s=i?.maxDepth??6,n=i?.includeHiddenDirs??!1,c=[],f=(a,u)=>{if(u>s)return;let p;try{p=y(a,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(const o of p){const m=r(a,o.name);if(!j(o,m)||!n&&o.name.startsWith("."))continue;const h=r(m,"SKILL.md");if(d(h))try{const x=g(h,"utf-8"),k=D(x);k.name&&c.push({name:k.name,description:k.description,trigger:k.trigger,source:e,pluginName:i?.pluginName})}catch{}f(m,u+1)}};return f(t,0),c}function j(t,e){if(t.isDirectory())return!0;if(!t.isSymbolicLink())return!1;try{return S(e).isDirectory()}catch{return!1}}function L(t){const e=[],i=new Set;for(const s of t){const n=s.name.trim().toLowerCase();i.has(n)||(i.add(n),e.push(s))}return e}function H(t){const e=[],i=new Set;let s=b(t);for(;;){i.has(s)||(e.push(s),i.add(s));const n=w(s);if(n===s)break;s=n}return e}function I(t){const e=r(t,".claude","plugins","installed_plugins.json");if(!d(e))return[];const i=[];try{const s=g(e,"utf-8"),c=JSON.parse(s)?.plugins;if(!c||typeof c!="object")return i;for(const[f,a]of Object.entries(c))if(Array.isArray(a))for(const u of a){const p=u?.installPath;if(!p||!d(p))continue;const o=r(p,"skills"),m=f.split("@")[0],h=W(o,"plugin",m);i.push(...h)}}catch{}return i}function K(t){const e=[],i=t.homeDir??F();switch(t.mode){case"claude":{const n=r(i,".claude","skills");e.push(...l(n,"global")),t.projectDir&&e.push(...l(r(t.projectDir,".claude","skills"),"project")),e.push(...I(i));break}case"codex":{const n=process.env.CODEX_HOME?.trim()||r(i,".codex");if(t.projectDir)for(const c of H(t.projectDir))e.push(...l(r(c,".agents","skills"),"project")),e.push(...l(r(c,".codex","skills"),"project"));e.push(...l(r(i,".agents","skills"),"codex")),e.push(...l(r(n,"skills"),"codex")),e.push(...l(r(n,"skills",".system"),"codex"));break}case"gemini":{e.push(...l(r(i,".gemini","skills"),"gemini")),e.push(...l(r(i,".agents","skills"),"gemini")),t.projectDir&&(e.push(...l(r(t.projectDir,".gemini","skills"),"project")),e.push(...l(r(t.projectDir,".agents","skills"),"project")));break}case"pi":{e.push(...l(r(i,".pi","agent","skills"),"pi")),t.projectDir&&e.push(...l(r(t.projectDir,".pi","skills"),"project"));break}case"kiro":{e.push(...l(r(i,".kiro","skills"),"kiro")),t.projectDir&&e.push(...l(r(t.projectDir,".kiro","skills"),"project"));break}}const s=L(e);return O.info("skill-scanner",`Scanned skills: mode=${t.mode} count=${s.length}`),s}export{L as dedupeSkills,D as parseSkillFrontmatter,l as scanSkillTree,K as scanSkills};