Add 5 pi extensions: pi-subagents, pi-crew, rpiv-pi, pi-interactive-shell, pi-intercom

This commit is contained in:
2026-05-08 15:59:25 +10:00
parent d0d1d9b045
commit 31b4110c87
457 changed files with 85157 additions and 0 deletions

View File

@@ -0,0 +1,184 @@
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
type Params = Record<string, string | number>;
const namespace = "pi-crew";
const TEMPLATE_RE = /\{(\w+)\}/g;
const fallback = {
"agent.requiresPrompt": "Agent requires prompt.",
"agent.started": "Agent {state}.",
"agent.id": "Agent ID: {id}",
"agent.type": "Type: {type}",
"agent.description": "Description: {description}",
"agent.retrieveHint": "Use get_subagent_result to retrieve output. Do not duplicate this agent's work.",
"agent.foregroundStatus": "Agent {id} {status}.",
"agent.noOutput": "No output.",
"result.requiresAgentId": "get_subagent_result requires agent_id.",
"result.notFound": "Agent not found: {id}",
"result.unrecoverable": "Subagent was interrupted before its durable run id was recorded; it cannot be recovered after restart.",
"result.waitAborted": "Waiting for subagent result was aborted.",
"result.waitTimeout": "Timed out waiting for subagent result.",
"result.stillRunning": "Agent is still running. Use wait=true or check again later.",
"steer.noted": "Steering request noted for {id}.",
"steer.unavailable": "Current default pi-crew backend is child-process, so mid-turn session.steer is not available yet.",
"steer.cancelHint": "Use team cancel runId={runId} if the agent must be interrupted.",
} as const;
type Key = keyof typeof fallback;
/** Map of locale → partial translations. Keys not present fall back to English. */
const translations: Record<string, Partial<Record<Key, string>>> = {
es: {
"agent.requiresPrompt": "Agent requiere prompt.",
"agent.started": "Agent {state}.",
"agent.id": "ID del agente: {id}",
"agent.type": "Tipo: {type}",
"agent.description": "Descripción: {description}",
"agent.retrieveHint": "Usa get_subagent_result para recuperar la salida. No dupliques el trabajo de este agente.",
"agent.foregroundStatus": "Agent {id} {status}.",
"agent.noOutput": "Sin salida.",
"result.requiresAgentId": "get_subagent_result requiere agent_id.",
"result.notFound": "Agente no encontrado: {id}",
"result.unrecoverable": "El subagente fue interrumpido antes de registrar su ID de ejecución duradero; no se puede recuperar tras reiniciar.",
"result.waitAborted": "Se canceló la espera del resultado del subagente.",
"result.waitTimeout": "Se agotó el tiempo de espera del resultado del subagente.",
"result.stillRunning": "El agente sigue ejecutándose. Usa wait=true o vuelve a comprobar más tarde.",
"steer.noted": "Solicitud de dirección registrada para {id}.",
"steer.unavailable": "El backend predeterminado actual de pi-crew es child-process, así que session.steer a mitad de turno aún no está disponible.",
"steer.cancelHint": "Usa team cancel runId={runId} si hay que interrumpir el agente.",
},
fr: {
"agent.requiresPrompt": "Agent nécessite un prompt.",
"agent.started": "Agent {state}.",
"agent.id": "ID de l'agent : {id}",
"agent.type": "Type : {type}",
"agent.description": "Description : {description}",
"agent.retrieveHint": "Utilisez get_subagent_result pour récupérer la sortie. Ne dupliquez pas le travail de cet agent.",
"agent.foregroundStatus": "Agent {id} {status}.",
"agent.noOutput": "Aucune sortie.",
"result.requiresAgentId": "get_subagent_result nécessite agent_id.",
"result.notFound": "Agent introuvable : {id}",
"result.unrecoverable": "Le sous-agent a été interrompu avant l'enregistrement de son ID d'exécution durable ; il ne peut pas être récupéré après redémarrage.",
"result.waitAborted": "L'attente du résultat du sous-agent a été annulée.",
"result.waitTimeout": "Délai d'attente du résultat du sous-agent dépassé.",
"result.stillRunning": "L'agent est toujours en cours d'exécution. Utilisez wait=true ou réessayez plus tard.",
"steer.noted": "Demande de pilotage enregistrée pour {id}.",
"steer.unavailable": "Le backend pi-crew par défaut actuel est child-process, donc session.steer en milieu de tour n'est pas encore disponible.",
"steer.cancelHint": "Utilisez team cancel runId={runId} si l'agent doit être interrompu.",
},
"pt-BR": {
"agent.requiresPrompt": "Agent requer prompt.",
"agent.started": "Agent {state}.",
"agent.id": "ID do agente: {id}",
"agent.type": "Tipo: {type}",
"agent.description": "Descrição: {description}",
"agent.retrieveHint": "Use get_subagent_result para recuperar a saída. Não duplique o trabalho deste agente.",
"agent.foregroundStatus": "Agent {id} {status}.",
"agent.noOutput": "Sem saída.",
"result.requiresAgentId": "get_subagent_result requer agent_id.",
"result.notFound": "Agente não encontrado: {id}",
"result.unrecoverable": "O subagente foi interrompido antes que seu ID de execução durável fosse registrado; ele não pode ser recuperado após reiniciar.",
"result.waitAborted": "A espera pelo resultado do subagente foi abortada.",
"result.waitTimeout": "Tempo limite de espera pelo resultado do subagente esgotado.",
"result.stillRunning": "O agente ainda está em execução. Use wait=true ou verifique novamente mais tarde.",
"steer.noted": "Solicitação de orientação registrada para {id}.",
"steer.unavailable": "O backend padrão atual do pi-crew é child-process, então session.steer no meio do turno ainda não está disponível.",
"steer.cancelHint": "Use team cancel runId={runId} se o agente precisar ser interrompido.",
},
};
// --- Runtime state ---
let currentLocale: string | undefined;
const warnedMissing = new Set<string>();
// --- Helpers ---
function format(template: string, params: Params = {}): string {
return template.replace(TEMPLATE_RE, (_match, key) => String(params[key] ?? `{${key}}`));
}
function warnOnce(key: string): void {
const tag = `${currentLocale}:${key}`;
if (warnedMissing.has(tag)) return;
warnedMissing.add(tag);
process.stderr.write(`[pi-crew] i18n: missing "${key}" in locale "${currentLocale}" — using English\n`);
}
// --- Public API ---
/**
* Translate a key for the currently active locale.
* Falls back to English, then to the raw key as a last resort.
*/
export function t(key: Key, params?: Params): string {
if (currentLocale && translations[currentLocale]) {
const template = translations[currentLocale]?.[key];
if (template) return format(template, params);
warnOnce(key);
}
return format(fallback[key] ?? key, params);
}
/**
* Register or extend translations for a locale at runtime.
* Useful for contributors adding new language bundles without modifying i18n.ts.
*
* @example
* addTranslations("vi", { "agent.requiresPrompt": "Agent cần prompt." })
*/
export function addTranslations(locale: string, bundle: Partial<Record<Key, string>>): void {
if (!locale) return;
const existing = translations[locale];
if (existing) {
Object.assign(existing, bundle);
} else {
translations[locale] = { ...bundle };
}
}
/**
* Returns the list of currently registered locales (excluding English, which is always available).
*/
export function listLocales(): string[] {
return Object.keys(translations);
}
// --- Initialization ---
export function initI18n(pi: ExtensionAPI): () => void {
try {
pi.events?.emit?.("pi-core/i18n/registerBundle", { namespace, defaultLocale: "en", fallback, translations });
} catch {
// Non-critical.
}
const unsubscribe = pi.events?.on?.("pi-core/i18n/localeChanged", (event: unknown) => {
if (!event || typeof event !== "object") return;
const raw = String((event as { locale?: unknown }).locale ?? "").trim();
currentLocale = raw && translations[raw] ? raw : undefined;
});
try {
pi.events?.emit?.("pi-core/i18n/requestApi", { namespace, onApi(api: { getLocale?: () => string | undefined }) {
const raw = api.getLocale?.()?.trim();
if (raw && translations[raw]) currentLocale = raw;
} });
} catch {
// Non-critical.
}
return () => {
currentLocale = undefined;
unsubscribe?.();
};
}
// --- Test helpers ---
export function __test__resetI18n(): void {
currentLocale = undefined;
warnedMissing.clear();
// Clear runtime-added translations but keep built-in ones.
for (const key of Object.keys(translations)) {
if (!["es", "fr", "pt-BR"].includes(key)) delete translations[key];
}
}