feat: modelo por defecto por proyecto con selector y orden /modelo-proyecto

This commit is contained in:
sargatxet committed 2026-10-18 14:03:22 +02:00
1 parent b35bc7a607
commit f6d2870635
12 files changed
+372 -22

No files matched your search

+24
View File
@@ -12,6 +12,30 @@ y el proyecto usa [Versionado Semántico](https://semver.org/lang/es/).
- Fijar las reglas de modelo y de funcionamiento que la skill escribirá en el - Fijar las reglas de modelo y de funcionamiento que la skill escribirá en el
`AGENTS.md` de cada proyecto generado (hoy quedan como `PENDIENTE`). `AGENTS.md` de cada proyecto generado (hoy quedan como `PENDIENTE`).
## [0.2.0] - 2026-10-18
### Añadido
- Extensión `extensions/modelo-proyecto.ts`:
- orden `/modelo-proyecto [proveedor/id]`: elige, de entre los modelos
disponibles, el modelo por defecto del proyecto actual, lo guarda en
`.pi/settings.json` (fusionando con el resto de ajustes) y lo activa;
- herramienta `elegir_modelo_proyecto`: muestra el selector al crear un
proyecto y guarda la elección en `<ruta>/.pi/settings.json`.
- `new-project.sh --modelo proveedor/id` para fijar el modelo sin pi.
- Paso obligatorio en la skill: el usuario elige el modelo del proyecto.
### Cambiado
- `AGENTS.md` generado: la sección *Reglas de modelo* documenta el modelo por
defecto y cómo cambiarlo; el criterio por tarea sigue `PENDIENTE`.
- Plantillas de `README.md` y `TODO.md` mencionan `.pi/settings.json`.
### Corregido
- `new-project.sh`: una opción sin valor (`--nombre` al final) terminaba sin
mensaje; ahora informa del error.
## [0.1.0] - 2026-10-18 ## [0.1.0] - 2026-10-18
### Añadido ### Añadido
+26 -1
View File
@@ -26,7 +26,8 @@ O desde git/npm cuando se publique:
pi install git:github.com/<usuario>/pi-new-project@v0.1.0 pi install git:github.com/<usuario>/pi-new-project@v0.1.0
``` ```
Comprueba con `pi list` y arranca pi: la skill aparecerá como `new-project`. Comprueba con `pi list` y arranca pi: la skill aparecerá como `new-project` y
estará disponible la orden `/modelo-proyecto`.
Para una prueba puntual sin instalarlo: `pi -e ./pi-new-project`. Para una prueba puntual sin instalarlo: `pi -e ./pi-new-project`.
## 3. Opción B — copiar la skill ## 3. Opción B — copiar la skill
@@ -46,6 +47,15 @@ ln -s "$PWD/pi-new-project/skills/new-project" ~/.agents/skills/new-project
Rutas equivalentes: `~/.pi/agent/skills/` y, por proyecto, `.agents/skills/`. Rutas equivalentes: `~/.pi/agent/skills/` y, por proyecto, `.agents/skills/`.
La skill sola no incluye la orden `/modelo-proyecto` ni la herramienta
`elegir_modelo_proyecto`; cópialas también (o la skill usará el plan B,
`pi --list-models` + `--modelo`):
```bash
mkdir -p ~/.pi/agent/extensions
cp pi-new-project/extensions/modelo-proyecto.ts ~/.pi/agent/extensions/
```
## 4. Opción C — exportar a otro ordenador ## 4. Opción C — exportar a otro ordenador
No hay más que copiar el directorio; no tiene dependencias. No hay más que copiar el directorio; no tiene dependencias.
@@ -76,6 +86,17 @@ ls -A /tmp/demo
Deben aparecer `AGENTS.md`, `README.md`, `CHANGELOG.md`, `TODO.md`, `INSTALL.md` Deben aparecer `AGENTS.md`, `README.md`, `CHANGELOG.md`, `TODO.md`, `INSTALL.md`
y `.gitignore`, sin marcadores `{{...}}` pendientes. y `.gitignore`, sin marcadores `{{...}}` pendientes.
Modelo por defecto:
```bash
pi-new-project/skills/new-project/scripts/new-project.sh \
--nombre Demo --modelo anthropic/claude-sonnet-4-5 /tmp/demo2
cat /tmp/demo2/.pi/settings.json
```
En pi, dentro de `/tmp/demo2`, `/modelo-proyecto` debe mostrar el selector de
modelos y actualizar `.pi/settings.json`.
## 6. Actualización ## 6. Actualización
```bash ```bash
@@ -88,6 +109,7 @@ pi update --extensions # si se instaló como paquete
```bash ```bash
pi remove ./pi-new-project # si se instaló como paquete pi remove ./pi-new-project # si se instaló como paquete
rm -rf ~/.agents/skills/new-project # si se copió o enlazó rm -rf ~/.agents/skills/new-project # si se copió o enlazó
rm -f ~/.pi/agent/extensions/modelo-proyecto.ts
``` ```
La skill no deja estado propio: no hay caché ni configuración que limpiar. La skill no deja estado propio: no hay caché ni configuración que limpiar.
@@ -100,3 +122,6 @@ La skill no deja estado propio: no hay caché ni configuración que limpiar.
| `no encuentro las plantillas` | Falta `templates/` | Reinstala el paquete completo, no solo el script. | | `no encuentro las plantillas` | Falta `templates/` | Reinstala el paquete completo, no solo el script. |
| `no puedo deducir el nombre` | Destino `.` o `/` | Pasa `--nombre`. | | `no puedo deducir el nombre` | Destino `.` o `/` | Pasa `--nombre`. |
| No sobreescribe mis ficheros | Protección por defecto | Usa `--force` tras revisar `--dry-run`. | | No sobreescribe mis ficheros | Protección por defecto | Usa `--force` tras revisar `--dry-run`. |
| El proyecto no arranca con su modelo | Proyecto no confiado: pi ignora `.pi/settings.json` | Ejecuta `/trust` en el proyecto. |
| `/modelo-proyecto` no existe | Solo se copió la skill | Instala el paquete o copia `extensions/modelo-proyecto.ts`. |
| El selector sale vacío | Ningún proveedor con credenciales | `/login` o configura la API key del proveedor. |
+24 -2
View File
@@ -3,7 +3,9 @@
Paquete de [pi](https://pi.dev) que genera la base documental de un proyecto Paquete de [pi](https://pi.dev) que genera la base documental de un proyecto
nuevo: `AGENTS.md`, `README.md`, `CHANGELOG.md`, `TODO.md`, `INSTALL.md` y nuevo: `AGENTS.md`, `README.md`, `CHANGELOG.md`, `TODO.md`, `INSTALL.md` y
`.gitignore`, listos para versionar y con las secciones de reglas reservadas `.gitignore`, listos para versionar y con las secciones de reglas reservadas
para acordarlas después. para acordarlas después. Al crear el proyecto, el usuario elige el **modelo por
defecto** de entre los disponibles; se guarda en `.pi/settings.json` y se puede
cambiar en cualquier momento con la orden `/modelo-proyecto`.
## Contenido ## Contenido
@@ -14,6 +16,8 @@ pi-new-project/
├── INSTALL.md # instalación en otro ordenador ├── INSTALL.md # instalación en otro ordenador
├── CHANGELOG.md ├── CHANGELOG.md
├── TODO.md ├── TODO.md
├── extensions/
│ └── modelo-proyecto.ts # orden /modelo-proyecto y herramienta elegir_modelo_proyecto
└── skills/ └── skills/
└── new-project/ └── new-project/
├── SKILL.md # instrucciones para el agente ├── SKILL.md # instrucciones para el agente
@@ -41,6 +45,20 @@ skills/new-project/scripts/new-project.sh \
--git ~/src/gestor-gastos --git ~/src/gestor-gastos
``` ```
### Modelo por defecto del proyecto
- **Al crear el proyecto**: la skill llama a la herramienta
`elegir_modelo_proyecto`, que muestra los modelos disponibles (los que tienen
credenciales en pi) para que elijas uno.
- **Dónde se guarda**: en `<proyecto>/.pi/settings.json` (`defaultProvider` y
`defaultModel`). pi lo aplica en cada sesión nueva iniciada en ese
directorio, siempre que el proyecto sea de confianza (`/trust`).
- **Para cambiarlo**: dentro del proyecto, `/modelo-proyecto` abre el selector;
`/modelo-proyecto proveedor/id` lo fija directamente (con autocompletado).
Conserva los demás ajustes del fichero y activa el modelo en la sesión actual.
- **Sin pi**: `new-project.sh --modelo proveedor/id destino` (lista con
`pi --list-models`).
El script nunca sobreescribe ficheros existentes salvo con `--force`, y admite El script nunca sobreescribe ficheros existentes salvo con `--force`, y admite
`--dry-run` para revisar antes. `--dry-run` para revisar antes.
@@ -48,8 +66,12 @@ El script nunca sobreescribe ficheros existentes salvo con `--force`, y admite
Ver [`INSTALL.md`](INSTALL.md). Resumen: copia (o enlaza) el directorio en Ver [`INSTALL.md`](INSTALL.md). Resumen: copia (o enlaza) el directorio en
`~/.pi/agent/skills/` o instálalo como paquete con `pi install ./pi-new-project`. `~/.pi/agent/skills/` o instálalo como paquete con `pi install ./pi-new-project`.
La orden `/modelo-proyecto` solo está disponible al instalarlo como paquete (o
copiando también `extensions/`).
## Requisitos ## Requisitos
- pi 1.3.0+ (la extensión usa la API de extensiones y `typebox`, incluidos en pi).
- `bash` 4+ y `git` (opcional, solo para `--git` y el autor por defecto). - `bash` 4+ y `git` (opcional, solo para `--git` y el autor por defecto).
- No usa Python, Node ni dependencias externas: es `bash` con biblioteca estándar. - El script no usa Python, Node ni dependencias externas: es `bash` con
biblioteca estándar.
+4 -2
View File
@@ -6,8 +6,8 @@
## Pendiente ## Pendiente
- [ ] Definir las **reglas de modelo** (modelo, contexto, criterio de selección) - [ ] Definir el resto de **reglas de modelo** (contexto, criterio de selección
y volcarlas en `templates/AGENTS.md.tmpl`. por tarea) y volcarlas en `templates/AGENTS.md.tmpl`.
- [ ] Definir las **reglas de funcionamiento** comunes y volcarlas en - [ ] Definir las **reglas de funcionamiento** comunes y volcarlas en
`templates/AGENTS.md.tmpl`. `templates/AGENTS.md.tmpl`.
- [ ] Decidir si las reglas se configuran por parámetros del script - [ ] Decidir si las reglas se configuran por parámetros del script
@@ -20,5 +20,7 @@
## Hecho ## Hecho
- [x] 2026-10-18 — modelo por defecto por proyecto: selector al crear y orden
`/modelo-proyecto` para cambiarlo.
- [x] 2026-10-18 — estructura del paquete, skill, script y plantillas. - [x] 2026-10-18 — estructura del paquete, skill, script y plantillas.
- [x] 2026-10-18 — `INSTALL.md` con exportación a otro ordenador. - [x] 2026-10-18 — `INSTALL.md` con exportación a otro ordenador.
+199
View File
@@ -0,0 +1,199 @@
/**
* modelo-proyecto — modelo por defecto de un proyecto.
*
* Guarda el modelo elegido en `<proyecto>/.pi/settings.json` (`defaultProvider`
* y `defaultModel`), que pi aplica al iniciar cualquier sesión nueva en ese
* proyecto (una vez concedida la confianza del proyecto).
*
* - Orden `/modelo-proyecto [proveedor/modelo]`: muestra los modelos
* disponibles para elegir (o usa el indicado), lo guarda en el proyecto del
* directorio actual y lo activa en la sesión en curso.
* - Herramienta `elegir_modelo_proyecto`: la usa la skill `new-project` para
* que el usuario elija el modelo al crear un proyecto en otra ruta.
*/
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
import { join, resolve } from "node:path";
import type { Api, Model } from "@earendil-works/pi-ai";
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
const SETTINGS_REL = join(".pi", "settings.json");
function clave(m: Model<Api>): string {
return `${m.provider}/${m.id}`;
}
function kilos(n: number | undefined): string {
if (!n) return "?";
return n >= 1_000_000 ? `${(n / 1_000_000).toFixed(1)}M` : `${Math.round(n / 1000)}K`;
}
function etiqueta(m: Model<Api>, actual?: string): string {
const marca = actual === clave(m) ? " ← actual del proyecto" : "";
return `${clave(m)} (${m.name ?? m.id}, ctx ${kilos(m.contextWindow)})${marca}`;
}
function disponibles(ctx: ExtensionContext): Model<Api>[] {
return [...ctx.modelRegistry.getAvailable()].sort((a, b) => clave(a).localeCompare(clave(b)));
}
function leerSettings(proyecto: string): Record<string, unknown> {
const ruta = join(proyecto, SETTINGS_REL);
if (!existsSync(ruta)) return {};
const texto = readFileSync(ruta, "utf-8").trim();
if (!texto) return {};
const datos = JSON.parse(texto);
if (typeof datos !== "object" || datos === null || Array.isArray(datos)) {
throw new Error(`${ruta} no contiene un objeto JSON`);
}
return datos as Record<string, unknown>;
}
export function modeloDelProyecto(proyecto: string): string | undefined {
try {
const s = leerSettings(proyecto);
if (typeof s.defaultProvider === "string" && typeof s.defaultModel === "string") {
return `${s.defaultProvider}/${s.defaultModel}`;
}
} catch {
// settings ilegible: se trata como sin modelo
}
return undefined;
}
/** Fusiona defaultProvider/defaultModel en .pi/settings.json sin tocar el resto. */
function guardarModelo(proyecto: string, m: Model<Api>): string {
const ruta = join(proyecto, SETTINGS_REL);
const datos = leerSettings(proyecto);
datos.defaultProvider = m.provider;
datos.defaultModel = m.id;
mkdirSync(join(proyecto, ".pi"), { recursive: true });
const tmp = `${ruta}.tmp`;
writeFileSync(tmp, `${JSON.stringify(datos, null, 2)}\n`, "utf-8");
renameSync(tmp, ruta);
return ruta;
}
function buscar(ctx: ExtensionContext, texto: string): Model<Api> | undefined {
const t = texto.trim();
const lista = disponibles(ctx);
return (
lista.find((m) => clave(m) === t) ??
(t.includes("/") ? undefined : lista.filter((m) => m.id === t).at(0))
);
}
async function elegir(ctx: ExtensionContext, proyecto: string): Promise<Model<Api> | undefined> {
const lista = disponibles(ctx);
if (lista.length === 0) throw new Error("no hay modelos disponibles (¿falta /login o credenciales?)");
const actual = modeloDelProyecto(proyecto);
const opciones = lista.map((m) => etiqueta(m, actual));
const elegido = await ctx.ui.select(`Modelo por defecto del proyecto (${proyecto})`, opciones);
if (!elegido) return undefined;
return lista[opciones.indexOf(elegido)];
}
export default function (pi: ExtensionAPI) {
// Lista para autocompletar (getArgumentCompletions no recibe ctx).
let cache: string[] = [];
pi.on("session_start", (_event, ctx) => {
try {
cache = disponibles(ctx).map(clave);
} catch {
cache = [];
}
});
pi.registerCommand("modelo-proyecto", {
description: "Elige el modelo por defecto de este proyecto (se guarda en .pi/settings.json)",
getArgumentCompletions: (prefijo) => {
const p = prefijo.trim().toLowerCase();
const items = cache.filter((k) => k.toLowerCase().includes(p)).map((k) => ({ value: k, label: k }));
return items.length ? items : null;
},
handler: async (args, ctx) => {
const proyecto = ctx.cwd;
let modelo: Model<Api> | undefined;
try {
if (args.trim()) {
modelo = buscar(ctx, args);
if (!modelo) {
ctx.ui.notify(`Modelo "${args.trim()}" no disponible. Usa /modelo-proyecto sin argumentos para elegir.`, "error");
return;
}
} else {
if (!ctx.hasUI) {
ctx.ui.notify("Sin interfaz: indica el modelo, /modelo-proyecto proveedor/modelo", "error");
return;
}
modelo = await elegir(ctx, proyecto);
if (!modelo) {
ctx.ui.notify("Sin cambios: no se eligió modelo.", "info");
return;
}
}
const ruta = guardarModelo(proyecto, modelo);
const activo = await pi.setModel(modelo);
ctx.ui.notify(
`Modelo del proyecto: ${clave(modelo)} (guardado en ${ruta})` +
(activo ? "; activado en esta sesión." : "; no se pudo activar ahora (¿credenciales?)."),
activo ? "info" : "warning",
);
} catch (err) {
ctx.ui.notify(`modelo-proyecto: ${(err as Error).message}`, "error");
}
},
});
pi.registerTool({
name: "elegir_modelo_proyecto",
label: "Elegir modelo del proyecto",
description:
"Muestra al usuario la lista de modelos disponibles para que elija el modelo por defecto de un proyecto " +
"y lo guarda en <ruta>/.pi/settings.json (defaultProvider/defaultModel), que pi usará en las nuevas sesiones " +
"de ese proyecto. Úsala al crear un proyecto. No elijas tú el modelo: deja que el usuario lo seleccione. " +
"Pasa 'modelo' (proveedor/id) solo si el usuario ya lo ha dicho explícitamente.",
parameters: Type.Object({
ruta: Type.String({ description: "Directorio raíz del proyecto" }),
modelo: Type.Optional(
Type.String({ description: "proveedor/id ya indicado por el usuario; si falta se muestra el selector" }),
),
}),
async execute(_id, params, _signal, _onUpdate, ctx) {
const proyecto = resolve(ctx.cwd, params.ruta.replace(/^~(?=$|\/)/, process.env.HOME ?? "~"));
let modelo: Model<Api> | undefined;
if (params.modelo) {
modelo = buscar(ctx, params.modelo);
if (!modelo) {
const lista = disponibles(ctx).map(clave).join(", ");
throw new Error(`modelo "${params.modelo}" no disponible. Disponibles: ${lista}`);
}
} else {
if (!ctx.hasUI) {
const lista = disponibles(ctx).map(clave).join("\n");
throw new Error(
`sin interfaz para mostrar el selector. Pregunta al usuario y vuelve a llamar con 'modelo'. Disponibles:\n${lista}`,
);
}
modelo = await elegir(ctx, proyecto);
if (!modelo) {
return {
content: [{ type: "text", text: "El usuario canceló la elección; no se guardó modelo. Pregúntale si quiere elegir uno." }],
details: { proyecto, modelo: null },
};
}
}
const ruta = guardarModelo(proyecto, modelo);
return {
content: [
{
type: "text",
text: `Modelo por defecto del proyecto: ${clave(modelo)}. Guardado en ${ruta}. Se cambia con /modelo-proyecto.`,
},
],
details: { proyecto, modelo: clave(modelo), ruta },
};
},
});
}
+5 -2
View File
@@ -1,12 +1,15 @@
{ {
"name": "pi-new-project", "name": "pi-new-project",
"version": "0.1.0", "version": "0.2.0",
"private": true, "private": true,
"description": "Paquete de pi con la skill new-project: genera la base documental de un proyecto (AGENTS.md, README, CHANGELOG, TODO, INSTALL).", "description": "Paquete de pi con la skill new-project (base documental de un proyecto) y la orden /modelo-proyecto (modelo por defecto del proyecto).",
"keywords": [ "keywords": [
"pi-package" "pi-package"
], ],
"pi": { "pi": {
"extensions": [
"./extensions"
],
"skills": [ "skills": [
"./skills" "./skills"
] ]
+23 -6
View File
@@ -1,6 +1,6 @@
--- ---
name: new-project name: new-project
description: Genera la base documental de un proyecto nuevo (AGENTS.md, README.md, CHANGELOG.md, TODO.md, INSTALL.md y .gitignore) a partir de plantillas. Úsala cuando el usuario pida crear un proyecto, repositorio o directorio nuevo, inicializar su documentación o "montar el esqueleto" de un repo. description: Genera la base documental de un proyecto nuevo (AGENTS.md, README.md, CHANGELOG.md, TODO.md, INSTALL.md y .gitignore) a partir de plantillas, y deja que el usuario elija el modelo por defecto del proyecto. Úsala cuando el usuario pida crear un proyecto, repositorio o directorio nuevo, inicializar su documentación o "montar el esqueleto" de un repo.
license: MIT license: MIT
--- ---
@@ -28,22 +28,37 @@ Genera el esqueleto documental de un proyecto. Todas las plantillas están en
El script no sobreescribe ficheros existentes salvo con `--force` y muestra El script no sobreescribe ficheros existentes salvo con `--force` y muestra
un resumen de lo creado. Usa `--dry-run` para revisar antes. un resumen de lo creado. Usa `--dry-run` para revisar antes.
3. **Revisa el resultado**: abre `README.md` y `AGENTS.md` del proyecto generado 3. **Modelo por defecto del proyecto** (obligatorio): el usuario elige el modelo
de entre los existentes; tú no lo eliges.
- Llama a la herramienta `elegir_modelo_proyecto` con `ruta` = destino del
proyecto. Muestra al usuario el selector con los modelos disponibles y
guarda su elección en `<ruta>/.pi/settings.json` (`defaultProvider` y
`defaultModel`). pi lo usará en todas las sesiones nuevas del proyecto.
- Si la herramienta no existe o no hay interfaz: ejecuta `pi --list-models`,
enséñale la lista al usuario, pregúntale cuál quiere y guárdalo con
`scripts/new-project.sh --modelo proveedor/id <destino>` (solo crea
`.pi/settings.json` si no existe).
- Si el usuario cancela, déjalo sin fijar e indícale que puede hacerlo más
tarde con `/modelo-proyecto`.
4. **Revisa el resultado**: abre `README.md` y `AGENTS.md` del proyecto generado
y completa lo que quede como `PENDIENTE` (objetivos, stack, comandos de y completa lo que quede como `PENDIENTE` (objetivos, stack, comandos de
verificación reales). No dejes marcadores de plantilla ni secciones vacías. verificación reales). No dejes marcadores de plantilla ni secciones vacías.
4. **Ajusta** `INSTALL.md` con los requisitos y pasos reales del stack elegido. 5. **Ajusta** `INSTALL.md` con los requisitos y pasos reales del stack elegido.
5. **Commit inicial** si se creó repo git: 6. **Commit inicial** si se creó repo git (incluye `.pi/settings.json`):
```bash ```bash
git add -A && git commit -m "docs: base documental inicial" git add -A && git commit -m "docs: base documental inicial"
``` ```
6. Informa al usuario de la ruta creada, los ficheros y del commit. 7. Informa al usuario de la ruta creada, los ficheros, el modelo elegido, el
commit y de que puede cambiar el modelo en cualquier momento con
`/modelo-proyecto` dentro del proyecto.
## Reglas ## Reglas
- No ejecutes el script sobre un directorio que ya tiene `AGENTS.md` o `README.md` - No ejecutes el script sobre un directorio que ya tiene `AGENTS.md` o `README.md`
sin avisar y confirmar (usaría `--force`). sin avisar y confirmar (usaría `--force`).
- Las secciones `## Reglas de modelo` y `## Reglas de funcionamiento` de - Las secciones `## Reglas de modelo` (salvo el modelo por defecto, que gestiona
`/modelo-proyecto`) y `## Reglas de funcionamiento` de
`AGENTS.md` se dejan como `PENDIENTE` a propósito: se acuerdan después, por `AGENTS.md` se dejan como `PENDIENTE` a propósito: se acuerdan después, por
proyecto. No las rellenes con suposiciones. proyecto. No las rellenes con suposiciones.
- Idioma de los documentos generados: español. - Idioma de los documentos generados: español.
@@ -52,6 +67,8 @@ Genera el esqueleto documental de un proyecto. Todas las plantillas están en
## Referencia ## Referencia
- `scripts/new-project.sh --help` — todas las opciones. - `scripts/new-project.sh --help` — todas las opciones.
- `/modelo-proyecto [proveedor/id]` — cambia el modelo por defecto del proyecto
del directorio actual (sin argumento, muestra el selector).
- `templates/` — plantillas con marcadores `{{PROYECTO}}`, `{{DESCRIPCION}}`, - `templates/` — plantillas con marcadores `{{PROYECTO}}`, `{{DESCRIPCION}}`,
`{{AUTOR}}`, `{{FECHA}}`, `{{FECHA_ISO}}`. `{{AUTOR}}`, `{{FECHA}}`, `{{FECHA_ISO}}`.
- `references/plantillas.md` — qué contiene cada documento y cuándo tocarlo. - `references/plantillas.md` — qué contiene cada documento y cuándo tocarlo.
+12 -1
View File
@@ -10,6 +10,7 @@ Qué genera `new-project.sh` y cuándo hay que tocar cada documento.
| `CHANGELOG.md` | Historial *Keep a Changelog*: `Añadido` / `Cambiado` / `Corregido` / `Eliminado`. | En cada cambio, sin excepción. | | `CHANGELOG.md` | Historial *Keep a Changelog*: `Añadido` / `Cambiado` / `Corregido` / `Eliminado`. | En cada cambio, sin excepción. |
| `TODO.md` | Tareas en curso, pendientes y hechas, incluida la deuda técnica. | Al abrir o cerrar tareas. | | `TODO.md` | Tareas en curso, pendientes y hechas, incluida la deuda técnica. | Al abrir o cerrar tareas. |
| `.gitignore` | Exclusiones básicas: secretos, dependencias descargadas, artefactos de build, logs. | Al detectar ficheros que no deben versionarse. | | `.gitignore` | Exclusiones básicas: secretos, dependencias descargadas, artefactos de build, logs. | Al detectar ficheros que no deben versionarse. |
| `.pi/settings.json` | Modelo por defecto de pi para el proyecto (`defaultProvider`, `defaultModel`). Lo crea `elegir_modelo_proyecto` o `--modelo`. | Solo con `/modelo-proyecto`, a petición del usuario. |
## Marcadores ## Marcadores
@@ -26,7 +27,17 @@ El script sustituye estos marcadores en todas las plantillas:
`AGENTS.md` incluye a propósito dos secciones con `PENDIENTE`: `AGENTS.md` incluye a propósito dos secciones con `PENDIENTE`:
- `## Reglas de modelo` — modelo de pi, contexto y criterio de selección. - `## Reglas de modelo` — explica dónde está el modelo por defecto y cómo
cambiarlo; el criterio de selección por tarea queda `PENDIENTE`.
- `## Reglas de funcionamiento` — estándares, ramas, revisión y automatización. - `## Reglas de funcionamiento` — estándares, ramas, revisión y automatización.
No se rellenan al generar el proyecto: se acuerdan después, proyecto a proyecto. No se rellenan al generar el proyecto: se acuerdan después, proyecto a proyecto.
## Modelo por defecto
- Al crear el proyecto, el usuario elige el modelo en el selector de la
herramienta `elegir_modelo_proyecto` (alternativa: `--modelo proveedor/id`).
- Se guarda en `<proyecto>/.pi/settings.json`; pi lo aplica en cada sesión nueva
del proyecto si éste es de confianza.
- Se cambia en cualquier momento con `/modelo-proyecto`, que fusiona el valor con
el resto de ajustes del fichero y activa el modelo en la sesión actual.
+32 -3
View File
@@ -13,6 +13,7 @@ PROYECTO=""
DESCRIPCION="" DESCRIPCION=""
AUTOR="" AUTOR=""
DESTINO="" DESTINO=""
MODELO=""
INIT_GIT=0 INIT_GIT=0
FORCE=0 FORCE=0
DRY_RUN=0 DRY_RUN=0
@@ -28,6 +29,10 @@ Opciones:
-n, --nombre NOMBRE Nombre del proyecto (por defecto: nombre del directorio). -n, --nombre NOMBRE Nombre del proyecto (por defecto: nombre del directorio).
-d, --descripcion TEXTO Descripción en una frase (por defecto: PENDIENTE). -d, --descripcion TEXTO Descripción en una frase (por defecto: PENDIENTE).
-a, --autor NOMBRE Autor (por defecto: git config user.name). -a, --autor NOMBRE Autor (por defecto: git config user.name).
-m, --modelo PROV/ID Modelo por defecto del proyecto; se guarda en
.pi/settings.json (lista: pi --list-models).
En pi es preferible la herramienta
elegir_modelo_proyecto o la orden /modelo-proyecto.
-g, --git Inicializa un repositorio git en el destino. -g, --git Inicializa un repositorio git en el destino.
-f, --force Sobreescribe ficheros que ya existan. -f, --force Sobreescribe ficheros que ya existan.
--dry-run Muestra lo que haría sin escribir nada. --dry-run Muestra lo que haría sin escribir nada.
@@ -37,12 +42,14 @@ EOF
die() { printf 'error: %s\n' "$*" >&2; exit 1; } die() { printf 'error: %s\n' "$*" >&2; exit 1; }
aviso() { printf 'aviso: %s\n' "$*" >&2; } aviso() { printf 'aviso: %s\n' "$*" >&2; }
requiere() { [[ $# -ge 2 && -n "$2" && "$2" != -* ]] || die "$1 necesita un valor"; }
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
-n | --nombre) PROYECTO="${2:-}"; shift 2 ;; -n | --nombre) requiere "$@"; PROYECTO="$2"; shift 2 ;;
-d | --descripcion) DESCRIPCION="${2:-}"; shift 2 ;; -d | --descripcion) requiere "$@"; DESCRIPCION="$2"; shift 2 ;;
-a | --autor) AUTOR="${2:-}"; shift 2 ;; -a | --autor) requiere "$@"; AUTOR="$2"; shift 2 ;;
-m | --modelo) requiere "$@"; MODELO="$2"; shift 2 ;;
-g | --git) INIT_GIT=1; shift ;; -g | --git) INIT_GIT=1; shift ;;
-f | --force) FORCE=1; shift ;; -f | --force) FORCE=1; shift ;;
--dry-run) DRY_RUN=1; shift ;; --dry-run) DRY_RUN=1; shift ;;
@@ -74,6 +81,11 @@ if [[ -z "$AUTOR" ]]; then
[[ -n "$AUTOR" ]] || AUTOR="PENDIENTE" [[ -n "$AUTOR" ]] || AUTOR="PENDIENTE"
fi fi
if [[ -n "$MODELO" ]]; then
[[ "$MODELO" =~ ^[^/[:space:]\"]+/[^[:space:]\"]+$ ]] \
|| die "--modelo debe tener la forma proveedor/id (p. ej. anthropic/claude-sonnet-4-5)"
fi
FICHEROS=(AGENTS.md README.md CHANGELOG.md TODO.md INSTALL.md .gitignore) FICHEROS=(AGENTS.md README.md CHANGELOG.md TODO.md INSTALL.md .gitignore)
render() { render() {
@@ -109,6 +121,22 @@ for fichero in "${FICHEROS[@]}"; do
creados+=("$fichero") creados+=("$fichero")
done done
if [[ -n "$MODELO" ]]; then
settings="$DESTINO/.pi/settings.json"
if [[ -e "$settings" && $FORCE -eq 0 ]]; then
omitidos+=(".pi/settings.json")
aviso ".pi/settings.json ya existe; se omite (usa /modelo-proyecto en pi para cambiar el modelo sin perder otros ajustes)"
elif [[ $DRY_RUN -eq 1 ]]; then
printf 'dry-run: escribiría %s (modelo %s)\n' "$settings" "$MODELO"
creados+=(".pi/settings.json")
else
mkdir -p -- "$DESTINO/.pi"
printf '{\n "defaultProvider": "%s",\n "defaultModel": "%s"\n}\n' \
"${MODELO%%/*}" "${MODELO#*/}" > "$settings"
creados+=(".pi/settings.json")
fi
fi
if [[ $INIT_GIT -eq 1 && $DRY_RUN -eq 0 ]]; then if [[ $INIT_GIT -eq 1 && $DRY_RUN -eq 0 ]]; then
if [[ -d "$DESTINO/.git" ]]; then if [[ -d "$DESTINO/.git" ]]; then
aviso "$DESTINO ya es un repositorio git" aviso "$DESTINO ya es un repositorio git"
@@ -120,6 +148,7 @@ fi
printf '\nproyecto: %s\n' "$PROYECTO" printf '\nproyecto: %s\n' "$PROYECTO"
printf 'destino: %s\n' "$destino_abs" printf 'destino: %s\n' "$destino_abs"
printf 'modelo: %s\n' "${MODELO:-sin fijar (elígelo con /modelo-proyecto)}"
printf 'creados: %s\n' "${creados[*]:-ninguno}" printf 'creados: %s\n' "${creados[*]:-ninguno}"
[[ ${#omitidos[@]} -eq 0 ]] || printf 'omitidos: %s\n' "${omitidos[*]}" [[ ${#omitidos[@]} -eq 0 ]] || printf 'omitidos: %s\n' "${omitidos[*]}"
[[ $DRY_RUN -eq 1 ]] || printf 'siguiente: revisa README.md, INSTALL.md y las secciones PENDIENTE de AGENTS.md\n' [[ $DRY_RUN -eq 1 ]] || printf 'siguiente: revisa README.md, INSTALL.md y las secciones PENDIENTE de AGENTS.md\n'
+18 -3
View File
@@ -16,13 +16,28 @@ Léela antes de tocar cualquier fichero y respétala en cada cambio.
| `INSTALL.md` | Instalación detallada y dependencias. | | `INSTALL.md` | Instalación detallada y dependencias. |
| `CHANGELOG.md` | Historial de cambios (*Keep a Changelog*). | | `CHANGELOG.md` | Historial de cambios (*Keep a Changelog*). |
| `TODO.md` | Tareas pendientes y deuda técnica. | | `TODO.md` | Tareas pendientes y deuda técnica. |
| `.pi/settings.json` | Ajustes de pi del proyecto: modelo por defecto. |
| _(completar)_ | Añade aquí el código y los recursos del proyecto. | | _(completar)_ | Añade aquí el código y los recursos del proyecto. |
## Reglas de modelo ## Reglas de modelo
PENDIENTE: definir qué modelo de pi se usa en este proyecto, con qué contexto y ### Modelo por defecto
con qué criterio de selección (coste, VRAM, ventana, velocidad). Se acuerda
tarea por tarea; hasta entonces, no fijar valores aquí. El modelo por defecto del proyecto se guarda en `.pi/settings.json`
(`defaultProvider` y `defaultModel`) y pi lo aplica al iniciar cada sesión nueva
en este directorio (requiere haber confiado en el proyecto: `/trust`).
- Para cambiarlo: `/modelo-proyecto` (muestra los modelos disponibles) o
`/modelo-proyecto proveedor/id`.
- No edites a mano ni cambies ese modelo sin que lo pida el usuario.
- `.pi/settings.json` se versiona; un cambio de modelo se commitea como
cualquier otro cambio.
### Otras reglas
PENDIENTE: definir el contexto y el criterio de selección de modelos por tarea
(coste, VRAM, ventana, velocidad). Se acuerda tarea por tarea; hasta entonces,
no fijar valores aquí.
## Reglas de funcionamiento ## Reglas de funcionamiento
+3 -1
View File
@@ -39,7 +39,9 @@ PENDIENTE: ejemplo mínimo de uso o de arranque.
├── README.md # este documento ├── README.md # este documento
├── INSTALL.md # instalación y dependencias ├── INSTALL.md # instalación y dependencias
├── CHANGELOG.md # historial de cambios ├── CHANGELOG.md # historial de cambios
└── TODO.md # tareas pendientes ├── TODO.md # tareas pendientes
└── .pi/
└── settings.json # modelo por defecto de pi (cambiar con /modelo-proyecto)
``` ```
## Documentación ## Documentación
+2 -1
View File
@@ -9,7 +9,8 @@ anota el cambio en `CHANGELOG.md`.
## Pendiente ## Pendiente
- [ ] Definir las **reglas de modelo** del proyecto en `AGENTS.md`. - [ ] Definir las **reglas de modelo** del proyecto en `AGENTS.md` (criterio por
tarea; el modelo por defecto se cambia con `/modelo-proyecto`).
- [ ] Definir las **reglas de funcionamiento** del proyecto en `AGENTS.md`. - [ ] Definir las **reglas de funcionamiento** del proyecto en `AGENTS.md`.
- [ ] Completar los `PENDIENTE` de `README.md` e `INSTALL.md`. - [ ] Completar los `PENDIENTE` de `README.md` e `INSTALL.md`.
- [ ] Fijar los comandos de verificación reales en `AGENTS.md`. - [ ] Fijar los comandos de verificación reales en `AGENTS.md`.