overmind-mcp
Version:
Orchestrateur universel agents IA multi-modeles via MCP. Inclut le protocole 'Custom-Nickname' pour identifier vos agents avec des surnoms originaux (The Chaos Prophet, Shadow Sniper, etc.), l'isolation mémoire (Private Memory Context) et le support pour
152 lines • 6.84 kB
JavaScript
/**
* ╔══════════════════════════════════════════════════════════════════════╗
* ║ OVERMIND BRIDGE — PromptSource (Multi-Input Prompt Resolver) ║
* ║ ║
* ║ Résout un prompt depuis 8 sources différentes : ║
* ║ 1. --prompt "..." (string literal) ║
* ║ 2. --prompt-file path.txt (fichier local) ║
* ║ 3. --prompt-stdin (lit stdin si pipe) ║
* ║ 4. --prompt-base64 "..." (binaire décodé) ║
* ║ 5. --prompt-url "https://" (fetch HTTP/HTTPS) ║
* ║ 6. --prompt-file-base64 b (fichier binaire décodé) ║
* ║ 7. --prompt-json '{"k":"v"}' (objet JSON, reformaté) ║
* ║ 8. --prompt-template t (template avec ${var} interpolation) ║
* ║ ║
* ║ Ordre de priorité (1er match gagne) : ║
* ║ 1. --prompt (literal) ║
* ║ 2. --prompt-file ║
* ║ 3. --prompt-stdin (si TTY absent) ║
* ║ 4. --prompt-base64 ║
* ║ 5. --prompt-url ║
* ╚══════════════════════════════════════════════════════════════════════╝
*/
import fs from 'node:fs/promises';
import { hasStdinData, readStdin } from './ArgParser.js';
/**
* Résout le prompt depuis la première source valide.
* Throw si aucune source ne fournit du contenu.
*/
export async function resolvePrompt(opts) {
// 1. Literal
if (opts.prompt !== undefined && opts.prompt !== '') {
return makeResolved(opts.prompt, 'literal', 'utf-8', 'arg:prompt');
}
// 2. File
if (opts.promptFile) {
const text = await fs.readFile(opts.promptFile, 'utf-8');
const final = interpolate(text, opts.vars);
return makeResolved(final, 'file', 'utf-8', `file:${opts.promptFile}`);
}
// 3. Stdin (auto si TTY absent)
if (opts.promptStdin || (opts.promptStdin === undefined && hasStdinData())) {
const text = await readStdin();
if (text.length > 0) {
const final = interpolate(text, opts.vars);
return makeResolved(final, 'stdin', 'utf-8', 'stdin');
}
}
// 4. Base64 literal
if (opts.promptBase64) {
const decoded = Buffer.from(opts.promptBase64, 'base64').toString('utf-8');
return makeResolved(decoded, 'base64', 'utf-8', 'arg:base64');
}
// 5. Base64 from file
if (opts.promptFileBase64) {
const buf = await fs.readFile(opts.promptFileBase64);
const text = buf.toString('utf-8');
return makeResolved(text, 'file-base64', 'utf-8', `file:${opts.promptFileBase64}`);
}
// 6. URL
if (opts.promptUrl) {
const res = await fetch(opts.promptUrl, {
signal: AbortSignal.timeout(30_000),
});
if (!res.ok) {
throw new Error(`Failed to fetch prompt URL ${opts.promptUrl}: HTTP ${res.status}`);
}
const text = await res.text();
return makeResolved(text, 'url', 'utf-8', `url:${opts.promptUrl}`);
}
// 7. JSON object → reformaté
if (opts.promptJson) {
const obj = JSON.parse(opts.promptJson);
const text = jsonToText(obj);
return makeResolved(text, 'json', 'utf-8', 'arg:json');
}
// 8. Template avec vars
if (opts.promptTemplate) {
const text = interpolate(opts.promptTemplate, opts.vars);
return makeResolved(text, 'template', 'utf-8', 'arg:template');
}
throw new Error('No prompt source provided. Use one of: --prompt, --prompt-file, --prompt-stdin, --prompt-base64, --prompt-file-base64, --prompt-url, --prompt-json, --prompt-template');
}
// ─── Vars parsing ──────────────────────────────────────────────────────────
/**
* Parse les --var key=value passés en argv.
* Ex: --var name=Monde --var lang=fr → { name: 'Monde', lang: 'fr' }
*/
export function parseVars(values) {
if (!values)
return {};
const arr = Array.isArray(values) ? values : [values];
const vars = {};
for (const v of arr) {
const eqIdx = v.indexOf('=');
if (eqIdx === -1) {
vars[v] = ''; // --var foo (vide)
}
else {
const key = v.slice(0, eqIdx).trim();
const value = v.slice(eqIdx + 1);
if (key)
vars[key] = value;
}
}
return vars;
}
// ─── Helpers ───────────────────────────────────────────────────────────────
function makeResolved(text, source, encoding, origin) {
return {
text,
source,
meta: {
bytes: Buffer.byteLength(text, 'utf-8'),
encoding,
origin,
},
};
}
/**
* Interpolation ${var} dans un template.
* Supporte ${var} et $var (simple).
*/
function interpolate(text, vars) {
if (!vars || Object.keys(vars).length === 0)
return text;
return text.replace(/\$\{([a-zA-Z0-9_]+)\}/g, (_, key) => vars[key] ?? `\${${key}}`);
}
/**
* Convertit un objet JSON en texte lisible (clé: valeur, récursif).
* Utile pour les prompts de type "voici les données à analyser".
*/
function jsonToText(obj, indent = 0) {
const pad = ' '.repeat(indent);
if (obj === null || obj === undefined)
return `${pad}null`;
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') {
return `${pad}${obj}`;
}
if (Array.isArray(obj)) {
if (obj.length === 0)
return `${pad}[]`;
return obj.map((v) => jsonToText(v, indent + 1)).join('\n');
}
if (typeof obj === 'object') {
const entries = Object.entries(obj);
if (entries.length === 0)
return `${pad}{}`;
return entries.map(([k, v]) => `${pad}${k}:\n${jsonToText(v, indent + 1)}`).join('\n');
}
return `${pad}${String(obj)}`;
}
//# sourceMappingURL=PromptSource.js.map