// npm 패키지
@ikyyofc/gemini-cli
AI Agent CLI — native function calling · GEMINI.md context · extensions
버전
44
메인테이너
1
최초 publish
2026-04-21
publisher
ikyyofc
tarball
189,632 B
AUTO-PUBLISHED·1개 버전 인덱싱됨·최근 publish: 2026-05-26
// exfil path
what is read → where it shipssteals
- ○ home dir
- ○ fs recursive read
sends to
(no destination string extracted — payload may be dynamic / obfuscated)
evidence in excerpt
> import { exec } from "child_process";
> export const GLOBAL_DIR = path.join(os.homedir(), ".gemini");
> import { exec } from "child_process";
> export const AGENTS_DIR = path.join(os.homedir(), ".agents");// offending code· @5.0.3· 3 files flagged
llm: benign · 0.85→ 의심 전송지 없음, 원격 실행 형태 없음 — 1 known-vendor host(s).
- @5.0.3··AUTO-PUBLISHED·publisher: ikyyofcheuristic 75/100static flags 5llm benign (0.85) via ollamanew-publisher:7dmature-packageosv-flagged:MAL-2026-4394child-process-spawnreads-homedirfs-recursive-readreads-env-varspy-pip-install-runtime
→ 의심 전송지 없음, 원격 실행 형태 없음 — 1 known-vendor host(s).
// offending code· 3 files flaggedpatterns: 5
--- package/src/extensions.js (excerpt) --- // src/extensions.js — Extension manager (mirrors Gemini CLI extension system) import fs from "fs"; import path from "path"; import os from "os"; import { promisify } from "util"; import { exec } from "child_process"; import { GLOBAL_DIR, CONTEXT_FILENAME, readWithImports } from "./memory.js"; const execAsync = promisify(exec); const EXT_DIR = path.join(GLOBAL_DIR, "extensions"); const CMD_DIR = path.join(GLOBAL_DIR, "commands"); // ───────────────────────────────────────────────────────────────── // Extension manifest schema (gemini-extension.json) // { // "name": "my-ext", // "version": "1.0.0", // "description": "...", // "contextFileName": "GEMINI.md", // optional // "commands": { // optional custom commands // "cmd-name": { // "description": "...", // "prompt": "Do {{args}} for me" // } // }, // "enabled": true // } // ───────────────────────────────────────────────────────────────── export function getExtensionDir() { return EXT_DIR; } export function getCommandDir() { return CMD_DIR; } /** Load all enabled extensions, return their manifests + context dirs */ export function loadExtensions() { fs.mkdirSync(EXT_DIR, { recursive: true }); const extensions = []; for (const name of fs.readdirSync(EXT_DIR)) { const extPath = path.join(EXT_DIR, name); const manifest = path.join(extPath, "gemini-extension.json"); if (!fs.exists --- package/src/memory.js (excerpt) --- // src/memory.js — GEMINI.md hierarchical context loader (mirrors Gemini CLI) import fs from "fs"; import path from "path"; import os from "os"; export const CONTEXT_FILENAME = "GEMINI.md"; export const GLOBAL_DIR = path.join(os.homedir(), ".gemini"); export const GLOBAL_CONTEXT = path.join(GLOBAL_DIR, CONTEXT_FILENAME); /** * Load all GEMINI.md files in order (same as Gemini CLI): * 1. ~/.gemini/GEMINI.md — global user instructions * 2. Extensions' GEMINI.md — loaded separately by extensions.js * 3. Project root → CWD — walk up from CWD to .git root * * Supports @./path/to/other.md imports (recursive). */ export function loadMemory(extraDirs = []) { const loaded = []; // { file, content } // 1. Global if (fs.existsSync(GLOBAL_CONTEXT)) { loaded.push({ file: GLOBAL_CONTEXT, content: readWithImports(GLOBAL_CONTEXT) }); } // 2. Extra dirs (extensions inject their GEMINI.md here) for (const dir of extraDirs) { const p = path.join(dir, CONTEXT_FILENAME); if (fs.existsSync(p)) { loaded.push({ file: p, content: readWithImports(p) }); } } // 3. Walk from CWD up to git root (or filesystem root) const chain = walkUpToRoot(process.cwd()); // Reverse so parent-most context loads first, CWD context last (highest priority) for (const dir of chain.reverse()) { const p = path.join(dir, CONTEXT_FILENAME); if (fs.existsSync(p)) { --- package/src/skills.js (excerpt) --- // src/skills.js — Skills manager via npx skills CLI // Skills path: ~/.agents/skills/<slug>/SKILL.md import fs from "fs"; import path from "path"; import os from "os"; import { promisify } from "util"; import { exec } from "child_process"; const execAsync = promisify(exec); export const AGENTS_DIR = path.join(os.homedir(), ".agents"); export const SKILLS_DIR = path.join(AGENTS_DIR, "skills"); // npx skills default const KNOWN_AGENT_DIRS = [ ".gemini", ".gemini/skills", ".claude", ".cursor", ".codex", ".opencode", ".cline", ".aider", ]; export function ensureSkillsDirs() { fs.mkdirSync(SKILLS_DIR, { recursive: true }); } function scanForSkillMds(baseDir, maxDepth = 5) { const results = []; const SKIP = new Set(["node_modules", ".git", "dist", "build"]); const walk = (dir, depth) => { if (depth > maxDepth || !fs.existsSync(dir)) return; for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { if (SKIP.has(entry.name)) continue; const full = path.join(dir, entry.name); if (entry.isDirectory()) walk(full, depth + 1); else if (entry.name === "SKILL.md") results.push(full); } }; walk(baseDir, 0); return results; } async function npxSkills(args, cwd = process.cwd(), timeout = 120_000) { const cmd = `npx --yes skills ${args}`; try { const { stdout, stderr } = await execAsync(cmd, { cwd, timeout,
