- Inicio
- Documentation
- Configuración
- Migración desde pi-mono: Una guía práctica de merge
Migración desde pi-mono: Una guía práctica de merge
Esta guía es una lista de verificación repetible para portar cambios desde pi-mono a este repositorio. Úsela para cualquier merge: un solo archivo, rama de funcionalidad o sincronización de versión completa.
Último punto de sincronización
Sección titulada «Último punto de sincronización»Commit: b21b42d032919de2f2e6920a76fa9a37c3920c0a
Fecha: 2026-03-22
Actualice esta sección después de cada sincronización; no reutilice el rango anterior.
Al iniciar una nueva sincronización, genere los parches desde este commit en adelante:
git format-patch b21b42d032919de2f2e6920a76fa9a37c3920c0a..HEAD --stdout > changes.patch0) Definir el alcance
Sección titulada «0) Definir el alcance»- Identifique la referencia upstream (commit, tag o PR).
- Liste los paquetes o carpetas que planea modificar.
- Decida qué funcionalidades están dentro del alcance y cuáles se omiten intencionalmente.
1) Traer el código de forma segura
Sección titulada «1) Traer el código de forma segura»- Prefiera un diff limpio y enfocado en lugar de una copia al por mayor.
- Evite copiar artefactos compilados o archivos generados.
- Si upstream agregó nuevos archivos, agréguelos explícitamente y revise su contenido.
2) Seguir las convenciones de extensión en imports
Sección titulada «2) Seguir las convenciones de extensión en imports»La mayoría de los archivos TypeScript de tiempo de ejecución omiten .js en los imports internos, pero algunos entrypoints de test/bench mantienen .js para compatibilidad con ESM en tiempo de ejecución. Siga el estilo existente del paquete local; no elimine extensiones de forma indiscriminada.
- En los archivos de tiempo de ejecución de
packages/coding-agent, mantenga los imports internos sin extensión a menos que importe recursos no-TS. - En
packages/tui/testypackages/natives/bench, mantenga.jsdonde los archivos circundantes ya lo usan. - Mantenga las extensiones de archivo reales cuando las herramientas lo requieran (por ejemplo,
.json,.css, embeds de texto.md). - Ejemplo:
import { x } from "./foo.js";→import { x } from "./foo";(solo cuando la convención del paquete es sin extensión).
3) Reemplazar los scopes de imports
Sección titulada «3) Reemplazar los scopes de imports»Upstream usa diferentes scopes de paquetes. Reemplácelos de manera consistente.
- Reemplace los scopes antiguos con el scope local usado aquí.
- Ejemplos (ajuste para que coincidan con los paquetes reales que está portando):
@mariozechner/pi-coding-agent→@f5-sales-demo/xcsh@mariozechner/pi-agent-core→@f5-sales-demo/pi-agent-core@mariozechner/pi-tui→@f5-sales-demo/pi-tui@mariozechner/pi-ai→@f5-sales-demo/pi-ai
4) Usar APIs de Bun cuando mejoren respecto a Node
Sección titulada «4) Usar APIs de Bun cuando mejoren respecto a Node»Ejecutamos sobre Bun. Reemplace las APIs de Node solo cuando Bun proporcione una alternativa mejor.
SÍ reemplazar:
- Ejecución de procesos:
child_process.spawn→ Bun Shell$para comandos simples,Bun.spawn/Bun.spawnSyncpara streaming o trabajo de larga duración - E/S de archivos:
fs.readFileSync→Bun.file().text()/Bun.write() - Clientes HTTP:
node-fetch,axios→fetchnativo - Hashing criptográfico:
node:crypto→ Web Crypto oBun.hash - SQLite:
better-sqlite3→bun:sqlite - Carga de variables de entorno:
dotenv→ Bun carga.envautomáticamente
NO reemplazar (estos funcionan correctamente en Bun):
os.homedir()— NO reemplazar conBun.env.HOME,Bun.env.HOMEo el literal"~"os.tmpdir()— NO reemplazar conBun.env.TMPDIR || "/tmp"o rutas hardcodeadasfs.mkdtempSync()— NO reemplazar con construcción manual de rutaspath.join(),path.resolve(), etc. — estos están bien
Estilo de import: Use el prefijo node: con imports de namespace únicamente (sin imports con nombre desde node:fs o node:path).
Convenciones adicionales de Bun:
- Prefiera Bun Shell
$para comandos cortos sin streaming; useBun.spawnsolo cuando necesite streaming de E/S o control de procesos. - Use
Bun.file()/Bun.write()para archivos ynode:fs/promisespara directorios. - Evite verificaciones con
Bun.file().exists(); use manejo conisEnoenten try/catch. - Prefiera
Bun.sleep(ms)sobre wrappers desetTimeout.
Incorrecto:
// BROKEN: env vars may be undefined, "~" is not expandedconst home = Bun.env.HOME || "~";const tmp = Bun.env.TMPDIR || "/tmp";Correcto:
import * as os from "node:os";import * as fs from "node:fs";import * as path from "node:path";
const configDir = path.join(os.homedir(), ".config", "myapp");const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "myapp-"));5) Preferir embeds de Bun (sin copiar)
Sección titulada «5) Preferir embeds de Bun (sin copiar)»No copie assets de tiempo de ejecución ni archivos de vendor en tiempo de compilación.
- Si upstream copia assets a una carpeta dist, reemplace con embeds compatibles con Bun.
- Los prompts son archivos
.mdestáticos; use imports de texto de Bun (with { type: "text" }) y Handlebars en lugar de cadenas de prompt inline. - Use
import.meta.dir+Bun.filepara cargar recursos adyacentes que no sean texto. - Mantenga los assets en el repositorio y deje que el bundler los incluya.
- Elimine los scripts de copia a menos que el usuario los solicite explícitamente.
- Si upstream lee un archivo fallback empaquetado en tiempo de ejecución, reemplace las lecturas del sistema de archivos con un import de texto embed de Bun.
- Ejemplo (fallback de instrucciones de Codex):
const FALLBACK_PROMPT_PATH = join(import.meta.dir, "codex-instructions.md");-> eliminadoimport FALLBACK_INSTRUCTIONS from "./codex-instructions.md" with { type: "text" };- Use
return FALLBACK_INSTRUCTIONS;en lugar dereadFileSync(FALLBACK_PROMPT_PATH, "utf8")
- Ejemplo (fallback de instrucciones de Codex):
6) Portar package.json con cuidado
Sección titulada «6) Portar package.json con cuidado»Trate package.json como un contrato. Haga el merge de forma intencional.
- Mantenga los valores existentes de
name,version,type,exportsybina menos que el port lo requiera. - Reemplace los scripts de npm/node con equivalentes de Bun (por ejemplo,
bun check,bun test). - Asegúrese de que las dependencias usen el scope correcto.
- No rebaje versiones de dependencias para corregir errores de tipos; actualice en su lugar.
- Valide los enlaces de paquetes del workspace y
peerDependencies.
7) Alinear estilo de código y herramientas
Sección titulada «7) Alinear estilo de código y herramientas»- Mantenga las convenciones de formato existentes.
- No introduzca
anya menos que sea necesario. - Evite imports dinámicos e imports de tipos inline; use solo imports de nivel superior.
- Nunca construya prompts en código; los prompts son archivos
.mdestáticos renderizados con Handlebars. - En coding-agent, nunca use
console.log/console.warn/console.error; useloggerde@f5-sales-demo/pi-utils. - Use
Promise.withResolvers()en lugar denew Promise((resolve, reject) => ...). - No use las palabras clave
private/protected/publicen campos o métodos de clase. Use campos privados ES#para encapsulación; deje los miembros accesibles sin palabra clave. La única excepción son las propiedades de parámetros del constructor (constructor(private readonly x: T)), donde la palabra clave es requerida por TypeScript. Al portar código upstream que usaprivate foooprotected bar, convierta a#foo(privado) obarsin modificador (accesible). - Prefiera helpers y utilidades existentes sobre código ad-hoc nuevo.
- Preserve los cambios de infraestructura Bun-first ya realizados en este repositorio:
- El runtime es Bun (sin entry points de Node).
- El gestor de paquetes es Bun (sin lockfiles de npm).
- Las APIs pesadas de Node (
child_process,readline) están reemplazadas con equivalentes de Bun. - Las APIs ligeras de Node (
os.homedir,os.tmpdir,fs.mkdtempSync,path.*) se mantienen. - Los shebangs de CLI usan
bun(nonode, notsx). - Los paquetes usan archivos fuente directamente (sin paso de compilación de TypeScript).
- Los workflows de CI ejecutan Bun para install/check/test.
8) Eliminar capas de compatibilidad antiguas
Sección titulada «8) Eliminar capas de compatibilidad antiguas»A menos que se solicite, elimine los shims de compatibilidad de upstream.
- Elimine las APIs antiguas que fueron reemplazadas.
- Actualice todos los sitios de llamada a la nueva API directamente.
- No mantenga versiones
*_v2ni paralelas.
9) Actualizar documentación y referencias
Sección titulada «9) Actualizar documentación y referencias»- Reemplace los enlaces al repositorio pi-mono donde sea apropiado.
- Actualice los ejemplos para usar Bun y los scopes de paquetes correctos.
- Asegúrese de que las instrucciones del README aún coincidan con el comportamiento actual del repositorio.
10) Validar el port
Sección titulada «10) Validar el port»Ejecute las verificaciones estándar después de los cambios:
bun check
Si el repositorio ya tiene verificaciones fallando no relacionadas con sus cambios, repórtelo.
Las pruebas usan el runner de Bun (no Vitest), pero solo ejecute bun test cuando se solicite explícitamente.
11) Proteger funcionalidades mejoradas (lista de trampas de regresión)
Sección titulada «11) Proteger funcionalidades mejoradas (lista de trampas de regresión)»Si ya mejoró el comportamiento localmente, trate esas mejoras como no negociables. Antes de portar, documente las mejoras y agregue verificaciones explícitas para que no se pierdan en el merge.
- Congele el comportamiento esperado: agregue una nota breve de “antes/después” para cada mejora (entradas, salidas, valores por defecto, casos límite). Esto previene reversiones silenciosas.
- Mapee APIs antiguas → nuevas: si upstream renombró conceptos (hooks → extensions, custom tools → tools, etc.), asegúrese de que cada punto de entrada antiguo aún se conecte correctamente. Un flag o export omitido equivale a funcionalidad perdida.
- Verifique los exports: revise los
exportsdepackage.json, tipos públicos y archivos barrel. Los ports de upstream a menudo olvidan re-exportar adiciones locales. - Cubra los caminos no felices: si corrigió manejo de errores, timeouts o lógica de fallback, agregue una prueba o al menos una lista de verificación manual que ejercite esos caminos.
- Verifique valores por defecto y orden de merge de configuración: las mejoras a menudo residen en los valores por defecto. Confirme que los nuevos valores por defecto no se revirtieron (por ejemplo, nueva precedencia de configuración, funcionalidades deshabilitadas, listas de herramientas).
- Audite el comportamiento de env/shell: si corrigió la ejecución o el sandboxing, verifique que el nuevo camino aún use su env sanitizado y no reintroduzca overrides de alias/funciones.
- Re-ejecute muestras específicas: mantenga un conjunto mínimo de ejemplos “known good” y ejecútelos después del port (flags de CLI, registro de extensiones, ejecución de herramientas).
12) Detectar y manejar código refactorizado
Sección titulada «12) Detectar y manejar código refactorizado»Antes de portar un archivo, verifique si upstream lo refactorizó significativamente:
# Compare the file you're about to port against what you have locallygit diff HEAD upstream/main -- path/to/file.tsSi el diff muestra que el archivo fue refactorizado (no solo parcheado):
- Nuevas abstracciones, conceptos renombrados, módulos fusionados, flujo de datos cambiado
Entonces debe leer la nueva implementación completamente antes de portar. El merge a ciegas de código refactorizado pierde funcionalidad porque:
Nota: el modo interactivo fue recientemente dividido en controllers/utils/types. Al retroportar cambios relacionados, porte las actualizaciones a los archivos individuales que creamos y asegúrese de que el cableado de interactive-mode.ts se mantenga sincronizado.
-
Los valores por defecto cambian silenciosamente - Una nueva variable
defaultFoo = [a, b]puede reemplazar un antiguogetAllFoo()que retornaba[a, b, c, d, e]. -
Las opciones de API se eliminan - Cuando los sistemas se fusionan (por ejemplo,
hooks+customTools→extensions), las opciones antiguas pueden no conectarse a la nueva implementación. -
Los caminos de código quedan obsoletos - Un concepto renombrado (por ejemplo,
hookMessage→custom) necesita actualizaciones en cada switch statement, type guard y handler, no solo en la definición. -
El contexto/capacidades se reducen - Las APIs antiguas pueden haber expuesto
{ logger, typebox, pi }que las nuevas APIs olvidaron incluir.
Proceso de porteo semántico
Sección titulada «Proceso de porteo semántico»Cuando upstream refactorizó un módulo:
-
Lea la implementación antigua - Entienda qué hacía, qué opciones aceptaba, qué exponía.
-
Lea la implementación nueva - Entienda las nuevas abstracciones y cómo se mapean al comportamiento anterior.
-
Verifique la paridad de funcionalidades - Para cada capacidad del código antiguo, confirme que el código nuevo la preserva o la elimina explícitamente.
-
Busque remanentes - Busque nombres/conceptos antiguos que puedan haberse omitido en switch statements, handlers, componentes de UI.
-
Pruebe los límites - Flags de CLI, opciones del SDK, event handlers, valores por defecto: aquí es donde se esconden las regresiones.
Verificaciones rápidas
Sección titulada «Verificaciones rápidas»# Find all uses of an old concept that may need updatingrg "oldConceptName" --type ts
# Compare default values between versionsgit show upstream/main:path/to/file.ts | rg "default|DEFAULT"
# Check if all enum/union values have handlersrg "case \"" path/to/file.ts13) Lista de verificación de auditoría rápida
Sección titulada «13) Lista de verificación de auditoría rápida»Use esto como una pasada final antes de terminar:
14) Formato de mensajes de commit
Sección titulada «14) Formato de mensajes de commit»Al hacer commit de un backport, siga el formato del repositorio <type>(scope): <descripción en pasado> y mantenga el
rango de commits en el título.
fix(coding-agent): backported pi-mono changes (<from>..<to>)
packages/<package>:- <type>: <description>- <type>: <description> (#<issue> by @<contributor>)
packages/<other-package>:- <type>: <description>Ejemplo:
fix(coding-agent): backported pi-mono changes (9f3eef65f..52532c7c0)
packages/ai:- fix: handle "sensitive" stop reason from Anthropic API- fix: normalize tool call IDs with special characters for Responses API- fix: add overflow detection for Bedrock, MiniMax, Kimi providers- fix: 429 status is rate limiting, not context overflow
packages/tui:- fix: refactored autocomplete state tracking- fix: file autocomplete should not trigger on empty text- fix: configurable autocomplete max visible items- fix: improved table column width calculation with word-aware wrapping
packages/coding-agent:- fix: preserve external config.yml edits on save (#1046 by @nicobailonMD)- fix: resolve macOS NFD and curly quote variants in file pathsReglas:
- Agrupe los cambios por paquete
- Use tipos de commit convencionales (
fix,feat,refactor,perf,docs) - Incluya números de issue/PR de upstream y atribución del contribuidor para contribuciones externas
- El rango de commits en el título ayuda a rastrear los puntos de sincronización
15) Divergencias intencionales
Sección titulada «15) Divergencias intencionales»Nuestro fork tiene decisiones arquitectónicas que difieren de upstream. No porte estos patrones de upstream:
Arquitectura de UI
Sección titulada «Arquitectura de UI»| Upstream | Nuestro fork | Razón |
|---|---|---|
Clase FooterDataProvider | StatusLineComponent | Línea de estado más simple e integrada |
ctx.ui.setHeader() / ctx.ui.setFooter() | Stub en modos no-TUI | Implementado en TUI, no-op en otros casos |
ctx.ui.setEditorComponent() | Stub en modos no-TUI | Implementado en TUI, no-op en otros casos |
Objeto de opciones InteractiveModeOptions | Args posicionales en constructor (el tipo de opciones aún se exporta) | Mantener la firma del constructor; actualizar el tipo cuando upstream agregue campos |
Nombres de componentes
Sección titulada «Nombres de componentes»| Upstream | Nuestro fork |
|---|---|
extension-input.ts | hook-input.ts |
extension-selector.ts | hook-selector.ts |
ExtensionInputComponent | HookInputComponent |
ExtensionSelectorComponent | HookSelectorComponent |
Nombres de API
Sección titulada «Nombres de API»| Upstream | Nuestro fork | Notas |
|---|---|---|
sessionManager.appendSessionInfo(name) | sessionManager.setSessionName(name) | Usamos sessionName en todo el código |
sessionManager.getSessionName() | sessionManager.getSessionName() | Igual (unificamos para coincidir con el RPC de upstream) |
agent.sessionName / setSessionName() | agent.sessionName / setSessionName() | Igual |
Consolidación de archivos
Sección titulada «Consolidación de archivos»| Upstream | Nuestro fork | Razón |
|---|---|---|
clipboard.ts + clipboard-image.ts (archivos de tool) | Módulo clipboard de @f5-sales-demo/pi-natives | Fusionado en implementación nativa N-API |
Framework de pruebas
Sección titulada «Framework de pruebas»| Upstream | Nuestro fork |
|---|---|
vitest con vi.mock() | bun:test con vi de bun |
Aserciones de node:test | Matchers expect() |
Arquitectura de herramientas
Sección titulada «Arquitectura de herramientas»| Upstream | Nuestro fork | Notas |
|---|---|---|
createTool(cwd: string, options?) | createTools(session: ToolSession) vía registro BUILTIN_TOOLS | Las factorías de tools aceptan ToolSession y pueden retornar null |
Interfaces *Operations por tool | Las interfaces por tool se mantienen (FindOperations, GrepOperations) | Usadas para overrides SSH/remotos |
fs/promises de Node.js en todos lados | Bun.file()/Bun.write() para archivos; node:fs/promises para directorios | Preferir APIs de Bun cuando simplifiquen |
Almacenamiento de autenticación
Sección titulada «Almacenamiento de autenticación»| Upstream | Nuestro fork | Notas |
|---|---|---|
proper-lockfile + auth.json | agent.db (bun:sqlite) | Credenciales almacenadas exclusivamente en agent.db |
| Una sola credencial por proveedor | Multi-credencial con selección round-robin | Lógica de afinidad de sesión y backoff preservada |
Extensiones
Sección titulada «Extensiones»| Upstream | Nuestro fork |
|---|---|
jiti para carga de TypeScript | import() nativo de Bun |
Campo de manifiesto pkg.pi | pkg.xcsh ?? pkg.pi (preferir nuestro namespace) |
Omitir estas funcionalidades de upstream
Sección titulada «Omitir estas funcionalidades de upstream»Al portar, omita estos archivos/funcionalidades por completo:
footer-data-provider.ts— usamos StatusLineComponentclipboard-image.ts— el clipboard está en el módulo N-API de@f5-sales-demo/pi-natives- Archivos de workflow de GitHub — tenemos nuestro propio CI
models.generated.ts— auto-generado, regenerar localmente (como models.json en su lugar)
Funcionalidades que agregamos (preservar estas)
Sección titulada «Funcionalidades que agregamos (preservar estas)»Estas existen en nuestro fork pero no en upstream. Nunca sobrescribir:
StatusLineComponenten modo interactivo- Autenticación multi-credencial con afinidad de sesión
- Sistema de descubrimiento basado en capacidades (
defineCapability,registerProvider,loadCapability,skillCapability, etc.) - Integraciones MCP/Exa/SSH
- Writethrough LSP para format-on-save
- Intercepción de Bash (
checkBashInterception) - Sugerencias de rutas difusas en la herramienta read