@nucleoabierto/teleprompter 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +88 -0
- package/bin/teleprompter.js +13 -0
- package/docs/domains/001-paquete.md +73 -0
- package/docs/domains/002-instalacion.md +118 -0
- package/docs/domains/README.md +9 -0
- package/docs/especificacion-paquete.md +169 -0
- package/manual/001-instalar-un-paquete.md +69 -0
- package/manual/README.md +27 -0
- package/manual/guia-de-uso.md +90 -0
- package/manual/index.md +27 -0
- package/manual/referencia-install.md +120 -0
- package/package.json +28 -0
- package/src/cli.js +124 -0
- package/src/execute.js +74 -0
- package/src/hash.js +53 -0
- package/src/lock.js +74 -0
- package/src/manifest.js +205 -0
- package/src/paths.js +47 -0
- package/src/plan.js +54 -0
- package/src/prompt.js +16 -0
- package/src/requires.js +19 -0
- package/src/verify.js +17 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gildardo Adrian Maravilla Jacome
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Teleprompter
|
|
2
|
+
|
|
3
|
+
Instalador de paquetes de configuración para repositorios.
|
|
4
|
+
|
|
5
|
+
Teleprompter lleva un paquete —un directorio con un manifiesto
|
|
6
|
+
`teleprompter.json` y recursos como skills o archivos de configuración—
|
|
7
|
+
a un repositorio con trabajo previo. Calcula el plan completo antes de
|
|
8
|
+
escribir nada, resuelve las colisiones con lo que ya existe y deja un
|
|
9
|
+
registro auditable de la instalación en `teleprompter-lock.json`.
|
|
10
|
+
|
|
11
|
+
## Requisitos
|
|
12
|
+
|
|
13
|
+
- Node.js 22 o superior.
|
|
14
|
+
|
|
15
|
+
## Instalación
|
|
16
|
+
|
|
17
|
+
No hace falta instalar nada: el CLI se ejecuta directamente con `npx`:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npx @nucleoabierto/teleprompter install <paquete> <destino>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
También puede instalarse como herramienta global:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npm install -g @nucleoabierto/teleprompter
|
|
27
|
+
teleprompter install <paquete> <destino>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Uso
|
|
31
|
+
|
|
32
|
+
`install` recibe el directorio del paquete y la raíz del repositorio
|
|
33
|
+
destino. Antes de escribir nada, el instalador verifica el manifiesto y
|
|
34
|
+
las precondiciones del paquete, calcula el plan completo y lo presenta
|
|
35
|
+
recurso a recurso:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
$ teleprompter install ./mi-paquete ./mi-repo
|
|
39
|
+
verificado: mi-paquete@1.0.0
|
|
40
|
+
plan de instalación:
|
|
41
|
+
mkdir .agents/skills/
|
|
42
|
+
create .agents/skills/mi-skill/SKILL.md
|
|
43
|
+
identical .agents/skills/otro-skill/SKILL.md
|
|
44
|
+
conflict .agents/config.json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
El plan muestra `mkdir` para las rutas de precondición a crear y una
|
|
48
|
+
marca por recurso: `create`, `identical`, `conflict` o `managed-update`
|
|
49
|
+
(el destino contiene lo que una instalación anterior registró y el
|
|
50
|
+
paquete ofrece una versión igual o posterior). Cuando hay
|
|
51
|
+
colisiones —el destino existe con contenido distinto y no consta como
|
|
52
|
+
instalado por Teleprompter, o fue modificado desde la instalación— una
|
|
53
|
+
consola interactiva pregunta por cada
|
|
54
|
+
recurso; sin ella, la operación aborta sin escribir nada. Dos opciones
|
|
55
|
+
mutuamente excluyentes resuelven las colisiones por adelantado:
|
|
56
|
+
|
|
57
|
+
| Opción | Efecto |
|
|
58
|
+
|-----------|------------------------------------------------------|
|
|
59
|
+
| `--force` | El recurso del paquete sobrescribe cada colisión |
|
|
60
|
+
| `--skip` | Cada colisión se omite y la omisión queda registrada |
|
|
61
|
+
|
|
62
|
+
Independiente de ellas, `--dry-run` muestra el plan y termina sin
|
|
63
|
+
escribir nada.
|
|
64
|
+
|
|
65
|
+
Terminada la ejecución se escribe `teleprompter-lock.json` en la raíz
|
|
66
|
+
del destino: qué recursos instaló Teleprompter, con qué acción y con
|
|
67
|
+
qué hash.
|
|
68
|
+
|
|
69
|
+
### Códigos de salida
|
|
70
|
+
|
|
71
|
+
| Código | Significado |
|
|
72
|
+
|--------|------------------------------------------------------|
|
|
73
|
+
| `0` | Éxito |
|
|
74
|
+
| `1` | Manifiesto inválido |
|
|
75
|
+
| `2` | Plan no ejecutable (precondiciones o colisiones) |
|
|
76
|
+
| `3` | Error de ejecución |
|
|
77
|
+
| `4` | Error de invocación (argumentos o rutas) |
|
|
78
|
+
|
|
79
|
+
## Documentación
|
|
80
|
+
|
|
81
|
+
- [manual/](manual/README.md) — guía de uso y referencia completa de la
|
|
82
|
+
operación `install`.
|
|
83
|
+
- [docs/especificacion-paquete.md](docs/especificacion-paquete.md) —
|
|
84
|
+
cómo escribir el manifiesto `teleprompter.json` de un paquete propio.
|
|
85
|
+
|
|
86
|
+
## Licencia
|
|
87
|
+
|
|
88
|
+
[MIT](LICENSE).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { main } from '../src/cli.js';
|
|
3
|
+
import { createAsker } from '../src/prompt.js';
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
process.exitCode = await main(process.argv.slice(2), {
|
|
7
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
8
|
+
createAsker,
|
|
9
|
+
});
|
|
10
|
+
} catch (error) {
|
|
11
|
+
console.error(`error inesperado: ${error.message}`);
|
|
12
|
+
process.exitCode = 3;
|
|
13
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Paquete
|
|
2
|
+
|
|
3
|
+
## Propósito
|
|
4
|
+
|
|
5
|
+
El formato declarativo en que se describe una pieza transferible de
|
|
6
|
+
configuración —qué contiene, dónde va cada recurso y qué exige el
|
|
7
|
+
destino— para que una instalación sea inspectable y repetible.
|
|
8
|
+
|
|
9
|
+
## Referencia del modelo
|
|
10
|
+
|
|
11
|
+
- **Lenguaje ubicuo:**
|
|
12
|
+
- **Paquete:** un directorio con un manifiesto `teleprompter.json`
|
|
13
|
+
cuyo `name` coincide con el nombre del directorio.
|
|
14
|
+
- Ancla: `checkName` en `src/manifest.js`; `packages/ciclo-tareas/`
|
|
15
|
+
- Origen: épica `docs/epics/001-formato-paquete.md`
|
|
16
|
+
- **Manifiesto:** el JSON `teleprompter.json` con `name`, `version`,
|
|
17
|
+
`install` obligatorios y `format`, `description`, `license`,
|
|
18
|
+
`author`, `requires`, `personalization`, `metadata`, `collection`
|
|
19
|
+
opcionales.
|
|
20
|
+
- Ancla: `TOP_LEVEL_FIELDS` y `VALIDATORS` en `src/manifest.js`;
|
|
21
|
+
contrato en `docs/especificacion-paquete.md`
|
|
22
|
+
- **Colección:** un manifiesto con `collection: true` describe un
|
|
23
|
+
conjunto de paquetes y no es instalable.
|
|
24
|
+
- Ancla: `checkCollection` en `src/manifest.js`
|
|
25
|
+
- **Entrada install:** par `source` (ruta dentro del paquete que debe
|
|
26
|
+
existir) → `target` (ruta relativa dentro del destino).
|
|
27
|
+
- Ancla: `checkInstallEntry` en `src/manifest.js`
|
|
28
|
+
- **Precondición:** entrada `requires.paths` con `path` obligatorio y
|
|
29
|
+
`create` booleano opcional; `create: true` difiere la creación de
|
|
30
|
+
la ruta al plan en lugar de abortar.
|
|
31
|
+
- Ancla: `checkRequiresEntry` en `src/manifest.js` y
|
|
32
|
+
`checkRequires` en `src/requires.js`
|
|
33
|
+
- **Ruta segura:** ruta relativa sin segmentos `..`, ni absoluta
|
|
34
|
+
POSIX, ni absoluta Windows (`C:\`) ni UNC (`\\`).
|
|
35
|
+
- Ancla: `isSafeRelative` en `src/paths.js`
|
|
36
|
+
- **Entidades / estado:**
|
|
37
|
+
- El paquete es inmutable y sin estado: existe como directorio con
|
|
38
|
+
archivos más su manifiesto. La versión es semver explícita `x.y.z`
|
|
39
|
+
sin prefijos ni rangos.
|
|
40
|
+
- Ancla: `SEMVER_RE` en `src/manifest.js`
|
|
41
|
+
- **Invariantes:**
|
|
42
|
+
- Toda ruta del manifiesto es una ruta segura —nada puede escribirse
|
|
43
|
+
fuera de la raíz de destino ni leerse fuera del paquete.
|
|
44
|
+
- Ancla: `checkRelativePath` en `src/manifest.js`
|
|
45
|
+
- `name` es kebab-case, ≤64 caracteres, e igual al directorio que lo
|
|
46
|
+
contiene. Ancla: `NAME_RE` en `src/manifest.js`
|
|
47
|
+
- `install` es una lista no vacía de entradas bien formadas cuyo
|
|
48
|
+
`source` existe. Ancla: `checkInstall` en `src/manifest.js`
|
|
49
|
+
- `format`, si está presente, vale `teleprompter-package@1`.
|
|
50
|
+
Ancla: `KNOWN_FORMAT` en `src/manifest.js`
|
|
51
|
+
- **Operaciones:**
|
|
52
|
+
- Cargar y validar el manifiesto de un directorio de paquete:
|
|
53
|
+
`loadManifest` en `src/manifest.js` —devuelve errores, avisos y el
|
|
54
|
+
manifiesto; nunca lanza.
|
|
55
|
+
|
|
56
|
+
## Explicación del dominio
|
|
57
|
+
|
|
58
|
+
- **Fronteras:**
|
|
59
|
+
- Dentro: la forma del manifiesto, la seguridad de rutas y las
|
|
60
|
+
precondiciones declaradas.
|
|
61
|
+
- Fuera: qué se hace con un paquete válido (dominio de instalación)
|
|
62
|
+
y el contenido de las instrucciones de personalización, que el
|
|
63
|
+
formato solo referencia.
|
|
64
|
+
- Relaciones: la instalación consume el resultado de la validación
|
|
65
|
+
del paquete sin revalidarlo.
|
|
66
|
+
- **Decisiones relevantes:**
|
|
67
|
+
- `docs/decisions/D001–D004` — manifiesto JSON puro, cardinalidad,
|
|
68
|
+
semver explícita, mapa `install`.
|
|
69
|
+
|
|
70
|
+
## Estado de salud
|
|
71
|
+
|
|
72
|
+
- Última revisión: 2026-09-28
|
|
73
|
+
- Divergencias conocidas: Ninguna
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Instalación
|
|
2
|
+
|
|
3
|
+
## Propósito
|
|
4
|
+
|
|
5
|
+
Llevar un paquete válido a un repositorio con trabajo previo sin
|
|
6
|
+
pisarlo: verificar, presentar un plan completo antes de escribir,
|
|
7
|
+
resolver colisiones con una política declarada y dejar registro de lo
|
|
8
|
+
instalado.
|
|
9
|
+
|
|
10
|
+
## Referencia del modelo
|
|
11
|
+
|
|
12
|
+
- **Lenguaje ubicuo:**
|
|
13
|
+
- **Plan:** la lista completa de acciones calculada antes de tocar
|
|
14
|
+
el destino; incluye los `mkdir` de las precondiciones con
|
|
15
|
+
`create: true` y una entrada por recurso con su marca.
|
|
16
|
+
- Ancla: `buildPlan` en `src/plan.js`; contrato en
|
|
17
|
+
`docs/instalador.md` sección «El plan»
|
|
18
|
+
- Origen: tarea `docs/tasks/009-plan-de-instalacion.md`
|
|
19
|
+
- **Marca del plan:** estado de cada recurso —`create` (destino
|
|
20
|
+
libre), `identical` (contenido igual), `managed-update` (propio y
|
|
21
|
+
sin tocar, versión igual o posterior) o `conflict` (contenido
|
|
22
|
+
distinto ajeno o propio modificado).
|
|
23
|
+
- Ancla: `buildPlan` en `src/plan.js`
|
|
24
|
+
- **Resolución:** la decisión sobre un `conflict` —`overwrite` o
|
|
25
|
+
`skip`— por flag, por respuesta interactiva o por aborto.
|
|
26
|
+
- Ancla: `src/cli.js` (bucle de resolución) y `createAsker` en
|
|
27
|
+
`src/prompt.js`
|
|
28
|
+
- **Registro (lock):** `teleprompter-lock.json` en la raíz del
|
|
29
|
+
destino; por paquete guarda `version`, `installedAt` y `files`
|
|
30
|
+
con `target`, acción y `sha256` —las entradas `skip` no llevan
|
|
31
|
+
hash. Es la memoria que distingue lo propio de lo ajeno.
|
|
32
|
+
- Ancla: `readLock` y `isValidLock` en `src/lock.js`; D007
|
|
33
|
+
- **Propiedad:** un recurso es propio cuando el destino actual
|
|
34
|
+
hashea igual que lo que el registro anotó para él.
|
|
35
|
+
- Ancla: `recorded.get(target) === destHash` en `src/plan.js`
|
|
36
|
+
- **Entidades / estado:**
|
|
37
|
+
- `VerificationResult` — `kind: 'ok'|'manifest'|'requires'`, el
|
|
38
|
+
manifiesto validado, `warnings`, `errors`, `creates` y `failures`.
|
|
39
|
+
- Ancla: `verifyPackage` en `src/verify.js`
|
|
40
|
+
- `Plan` — `{ mkdirs, resources, conflicts }`; cada recurso lleva
|
|
41
|
+
`source`, `target`, `status` y, tras resolver, `resolution`.
|
|
42
|
+
- Ancla: `buildPlan` en `src/plan.js`
|
|
43
|
+
- Hash de recurso — SHA-256 sobre dominios separados (`file\n`,
|
|
44
|
+
`link\n`, `dir\n`) para que tipos distintos nunca colisionen;
|
|
45
|
+
los árboles ordenan sus entradas para que el digest sea
|
|
46
|
+
independiente del orden de lectura.
|
|
47
|
+
- Ancla: `hashPath` en `src/hash.js`
|
|
48
|
+
- **Invariantes:**
|
|
49
|
+
- El plan completo se calcula antes de escribir; un plan no
|
|
50
|
+
ejecutable aborta sin escribir nada —ni recursos ni registro
|
|
51
|
+
(D005). Ancla: `main` en `src/cli.js`
|
|
52
|
+
- «Existe» significa «hay una entrada en el directorio», sin seguir
|
|
53
|
+
enlaces: un enlace colgado ocupa su ruta.
|
|
54
|
+
Ancla: `hasEntry` en `src/paths.js`
|
|
55
|
+
- `--force` y `--skip` son mutuamente excluyentes; el error es de
|
|
56
|
+
invocación (código 4). Ancla: `parseArgs` en `src/cli.js`
|
|
57
|
+
- `managed-update` exige hash registrado coincidente **y** versión
|
|
58
|
+
del paquete ≥ versión registrada; un downgrade es `conflict`.
|
|
59
|
+
Ancla: `semverAtLeast` en `src/plan.js`
|
|
60
|
+
- Una respuesta interactiva que no es afirmativa significa `skip`:
|
|
61
|
+
el defecto ante trabajo ajeno es no sobrescribir.
|
|
62
|
+
Ancla: `createAsker` en `src/prompt.js`
|
|
63
|
+
- Un lock ilegible o con estructura inesperada degrada a «sin
|
|
64
|
+
historia» con aviso, nunca a crash.
|
|
65
|
+
Ancla: `readLock`/`isValidLock` en `src/lock.js`
|
|
66
|
+
- Ninguna escritura puede salir de la raíz por un enlace en la
|
|
67
|
+
cadena de padres: el ancestro existente más profundo debe
|
|
68
|
+
resolver a un directorio dentro del destino, en el plan y en la
|
|
69
|
+
ejecución. Ancla: `resolvesUnder` en `src/paths.js`
|
|
70
|
+
- Dos entradas `install` no pueden compartir `target`: el plan sería
|
|
71
|
+
ambiguo. Ancla: `checkInstall` en `src/manifest.js`
|
|
72
|
+
- Un recurso `identical` conserva su registro previo —el contenido
|
|
73
|
+
sigue siendo propio— pero no crea registro si nunca se escribió.
|
|
74
|
+
Ancla: `writeLock` en `src/lock.js`
|
|
75
|
+
- **Operaciones:**
|
|
76
|
+
- `teleprompter install <paquete> <destino> [--force|--skip]
|
|
77
|
+
[--dry-run]` — verifica, planea, resuelve, ejecuta y registra.
|
|
78
|
+
- Ancla: `bin/teleprompter.js` → `main` en `src/cli.js`
|
|
79
|
+
- Ejecutar el plan resuelto: `mkdirs` primero, luego cada recurso
|
|
80
|
+
según su acción; `overwrite` elimina el destino antes de escribir
|
|
81
|
+
—nunca a través de un enlace— y los enlaces se copian como
|
|
82
|
+
enlaces.
|
|
83
|
+
- Ancla: `executePlan` en `src/execute.js`
|
|
84
|
+
- Registrar la instalación: fusiona el lock preservando otros
|
|
85
|
+
paquetes; `identical` no se registra y `skip` va sin hash.
|
|
86
|
+
- Ancla: `writeLock` en `src/lock.js`
|
|
87
|
+
- Códigos de salida: 0 éxito, 1 manifiesto inválido, 2 plan no
|
|
88
|
+
ejecutable, 3 error de ejecución, 4 invocación.
|
|
89
|
+
- Ancla: `EXIT_*` en `src/cli.js`; contrato en
|
|
90
|
+
`docs/instalador.md` «Resultado y errores»
|
|
91
|
+
|
|
92
|
+
## Explicación del dominio
|
|
93
|
+
|
|
94
|
+
- **Fronteras:**
|
|
95
|
+
- Dentro: verificación, plan, resolución de colisiones, ejecución y
|
|
96
|
+
registro de una instalación.
|
|
97
|
+
- Fuera: la forma del manifiesto (dominio del paquete), el contenido
|
|
98
|
+
de la personalización y la distribución del CLI.
|
|
99
|
+
- Relaciones: consume el dominio del paquete a través del resultado
|
|
100
|
+
estructurado de `verifyPackage`; la invocación (`bin/`) es una
|
|
101
|
+
capa delgada sin dominio.
|
|
102
|
+
- **Decisiones relevantes:**
|
|
103
|
+
- `docs/decisions/D005` — plan completo antes de escribir, aborto
|
|
104
|
+
total.
|
|
105
|
+
- `docs/decisions/D006` — política de colisiones: interactiva,
|
|
106
|
+
aborto sin consola, `--force`/`--skip` excluyentes.
|
|
107
|
+
- `docs/decisions/D007` — `teleprompter-lock.json` como memoria de
|
|
108
|
+
propiedad.
|
|
109
|
+
- `docs/decisions/D008` — implementación JavaScript vía `npx` como
|
|
110
|
+
`@nucleoabierto/teleprompter`.
|
|
111
|
+
|
|
112
|
+
## Estado de salud
|
|
113
|
+
|
|
114
|
+
- Última revisión: 2026-09-28
|
|
115
|
+
- Divergencias conocidas: cuando un paquete sobrescribe un recurso
|
|
116
|
+
registrado por otro, la entrada del primero queda intacta aunque su
|
|
117
|
+
contenido ya no coincida —el plan siguiente lo marcará `conflict` en
|
|
118
|
+
el paquete viejo, que es conservador pero puede sorprender.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Dominios
|
|
2
|
+
|
|
3
|
+
Documentación viva del modelo del producto: un documento por dominio,
|
|
4
|
+
anclado al código que lo materializa.
|
|
5
|
+
|
|
6
|
+
- [001 — Paquete](001-paquete.md): el formato declarativo del
|
|
7
|
+
manifiesto, sus rutas seguras y sus precondiciones.
|
|
8
|
+
- [002 — Instalación](002-instalacion.md): verificación, plan,
|
|
9
|
+
colisiones, ejecución y registro de una instalación.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Especificación del formato de paquete
|
|
2
|
+
|
|
3
|
+
Un **paquete** es un directorio de configuración trasladable entre
|
|
4
|
+
repositorios: un agente o instalador lo inspecciona, verifica sus
|
|
5
|
+
precondiciones y copia sus recursos a las rutas que el manifiesto
|
|
6
|
+
declara. Este documento es el contrato completo: quien lo sigue puede
|
|
7
|
+
producir un paquete válido sin conocer nada más del sistema.
|
|
8
|
+
|
|
9
|
+
## Un paquete
|
|
10
|
+
|
|
11
|
+
Un paquete es un directorio que contiene un manifiesto
|
|
12
|
+
`teleprompter.json` en su raíz y cualquier disposición de recursos:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
mi-paquete/
|
|
16
|
+
├── teleprompter.json # manifiesto (obligatorio)
|
|
17
|
+
└── <recursos> # archivos y subdirectorios libres
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
No hay disposición fija para los recursos: el manifiesto declara, para
|
|
21
|
+
cada origen, dónde se instala en el repositorio destino.
|
|
22
|
+
|
|
23
|
+
## El manifiesto `teleprompter.json`
|
|
24
|
+
|
|
25
|
+
El manifiesto es JSON puro: no ejecuta nada. Según el valor del campo
|
|
26
|
+
`collection`, el archivo describe un paquete (ausente o `false`) o una
|
|
27
|
+
colección (`true`, véase «Colecciones»). Primero el contrato de paquete.
|
|
28
|
+
|
|
29
|
+
### Campos obligatorios
|
|
30
|
+
|
|
31
|
+
| Campo | Tipo | Regla |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| `name` | string | Identificador del paquete: minúsculas, números y guiones, máx. 64 caracteres, sin guiones al inicio ni al final. Debe coincidir con el nombre del directorio del paquete. |
|
|
34
|
+
| `version` | string | Versión semver explícita `x.y.z`. La autoridad de la versión es el manifiesto, no el VCS. |
|
|
35
|
+
| `install` | array | Lista no vacía de entradas `{ "source", "target" }`. Véase abajo. Un paquete sin `install` o con la lista vacía es inválido. |
|
|
36
|
+
|
|
37
|
+
Cada entrada de `install` declara una copia:
|
|
38
|
+
|
|
39
|
+
- `source` — ruta dentro del paquete, relativa a su raíz. Puede ser un
|
|
40
|
+
archivo o un directorio; un directorio se instala con todo su
|
|
41
|
+
contenido.
|
|
42
|
+
- `target` — ruta relativa a la raíz del repositorio destino donde se
|
|
43
|
+
instala.
|
|
44
|
+
|
|
45
|
+
La barra final en `source` y `target` es una convención legible para
|
|
46
|
+
marcar directorios, no un requisito del formato.
|
|
47
|
+
|
|
48
|
+
Ni `source` ni `target` admiten rutas absolutas ni `..`: el origen no
|
|
49
|
+
puede salir del paquete y el destino no puede salir del repositorio.
|
|
50
|
+
|
|
51
|
+
### Campos opcionales
|
|
52
|
+
|
|
53
|
+
| Campo | Tipo | Descripción |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `format` | string | Versión del formato del manifiesto: `"teleprompter-package@1"`. Su ausencia equivale a la primera versión del formato. |
|
|
56
|
+
| `description` | string | Descripción corta del paquete. |
|
|
57
|
+
| `license` | string | Identificador SPDX (`"MIT"`, `"Apache-2.0"`) o referencia a un archivo de licencia. |
|
|
58
|
+
| `author` | object | `{ "name": "...", "email": "...", "url": "..." }`. Solo `name` es obligatorio dentro del objeto. |
|
|
59
|
+
| `requires` | object | Precondiciones del repositorio destino, verificables antes de instalar. De momento solo la clave `paths`. |
|
|
60
|
+
| `personalization` | string | Ruta dentro del paquete al archivo o directorio con instrucciones de personalización. Solo declara que existe adaptación pendiente y dónde está documentada; no se instala salvo que también figure en `install`. |
|
|
61
|
+
| `metadata` | object | Mapa libre clave→valor para datos del autor que el instalador no interpreta. |
|
|
62
|
+
|
|
63
|
+
`requires.paths` es una lista de entradas `{ "path", "create"? }` sobre
|
|
64
|
+
rutas relativas a la raíz del destino (`path` no admite rutas absolutas
|
|
65
|
+
ni `..`):
|
|
66
|
+
|
|
67
|
+
- Si la ruta no existe y `create` es `false` o está ausente, la
|
|
68
|
+
instalación aborta.
|
|
69
|
+
- Si la ruta no existe y `create` es `true`, el instalador la crea
|
|
70
|
+
antes de instalar.
|
|
71
|
+
|
|
72
|
+
### Campos desconocidos
|
|
73
|
+
|
|
74
|
+
Política mixta:
|
|
75
|
+
|
|
76
|
+
- **Nivel superior** del manifiesto (de paquete o de colección): el
|
|
77
|
+
campo desconocido se ignora y el validador emite un aviso.
|
|
78
|
+
- **Dentro de un objeto conocido** (`author`, `requires`, una entrada
|
|
79
|
+
de `requires.paths`, una entrada de `install`, una entrada de
|
|
80
|
+
`packages` en una colección): el campo desconocido es un error y el
|
|
81
|
+
manifiesto no es válido.
|
|
82
|
+
|
|
83
|
+
## Colecciones
|
|
84
|
+
|
|
85
|
+
Un repositorio puede alojar un paquete o varios. Solo hay un nombre de
|
|
86
|
+
archivo que buscar —`teleprompter.json`— y un campo que discrimina qué
|
|
87
|
+
describe:
|
|
88
|
+
|
|
89
|
+
- `collection` ausente o `false` → el manifiesto describe un paquete.
|
|
90
|
+
- `collection: true` → el manifiesto describe una **colección**: un
|
|
91
|
+
índice de paquetes por ruta.
|
|
92
|
+
|
|
93
|
+
Un directorio es una cosa o la otra: la colección es un contenedor
|
|
94
|
+
puro, no instalable como paquete. Un manifiesto de colección admite los
|
|
95
|
+
campos `name`, `description`, `license`, `author`, `metadata` y
|
|
96
|
+
`format` —con la misma semántica que en un paquete, con una excepción:
|
|
97
|
+
el `name` de una colección es cosmético y no debe coincidir con el
|
|
98
|
+
nombre de ningún directorio— más:
|
|
99
|
+
|
|
100
|
+
| Campo | Tipo | Regla |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| `collection` | boolean | Obligatorio y `true`. Es el discriminador. |
|
|
103
|
+
| `packages` | array | Obligatorio. Lista de entradas `{ "path": "..." }` con la ruta relativa al directorio de cada paquete; `path` no admite rutas absolutas ni `..`. |
|
|
104
|
+
|
|
105
|
+
La entrada solo declara la ruta: el `name` y la `version` de cada
|
|
106
|
+
paquete se leen de su propio `teleprompter.json`, nunca del índice.
|
|
107
|
+
Los campos propios de paquete (`version`, `install`, `requires`,
|
|
108
|
+
`personalization`) en un manifiesto de colección son un error.
|
|
109
|
+
|
|
110
|
+
## Ejemplo completo
|
|
111
|
+
|
|
112
|
+
Estructura de un paquete con tres recursos:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
ciclo-tareas/
|
|
116
|
+
├── teleprompter.json
|
|
117
|
+
└── skills/
|
|
118
|
+
├── crear-tareas/
|
|
119
|
+
├── ejecutar-tareas/
|
|
120
|
+
└── commit/
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Su manifiesto:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"format": "teleprompter-package@1",
|
|
128
|
+
"name": "ciclo-tareas",
|
|
129
|
+
"version": "1.0.0",
|
|
130
|
+
"description": "Ciclo de tareas del proyecto: creación, ejecución con revisión dual y commit",
|
|
131
|
+
"license": "MIT",
|
|
132
|
+
"install": [
|
|
133
|
+
{
|
|
134
|
+
"source": "skills/crear-tareas/",
|
|
135
|
+
"target": ".agents/skills/crear-tareas/"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"source": "skills/ejecutar-tareas/",
|
|
139
|
+
"target": ".agents/skills/ejecutar-tareas/"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"source": "skills/commit/",
|
|
143
|
+
"target": ".agents/skills/commit/"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"requires": {
|
|
147
|
+
"paths": [{ "path": ".agents/skills/", "create": true }]
|
|
148
|
+
},
|
|
149
|
+
"metadata": { "origin": "teleprompter" }
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Lista de verificación de un paquete válido
|
|
154
|
+
|
|
155
|
+
1. `teleprompter.json` en la raíz del directorio del paquete, JSON
|
|
156
|
+
válido.
|
|
157
|
+
2. `name` en kebab-case, igual al nombre del directorio.
|
|
158
|
+
3. `version` semver `x.y.z`.
|
|
159
|
+
4. `install` no vacío; cada entrada tiene solo `source` y `target`;
|
|
160
|
+
cada `source` existe dentro del paquete; ninguna ruta es absoluta ni
|
|
161
|
+
contiene `..`.
|
|
162
|
+
5. `source` y `personalization` apuntan dentro del paquete; `target` y
|
|
163
|
+
`requires.paths[].path` son relativos a la raíz del destino; ninguna
|
|
164
|
+
de estas rutas es absoluta ni contiene `..`.
|
|
165
|
+
6. Los campos opcionales presentes pertenecen al contrato; dentro de
|
|
166
|
+
objetos conocidos no hay campos desconocidos (a nivel superior, un
|
|
167
|
+
campo desconocido solo genera un aviso, no invalida el manifiesto).
|
|
168
|
+
7. En una colección: `collection: true`, `packages` con rutas válidas
|
|
169
|
+
y ningún campo propio de paquete.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Instalar un paquete
|
|
2
|
+
|
|
3
|
+
El usuario ejecuta `teleprompter install <paquete> <destino>` para
|
|
4
|
+
llevar los recursos de un paquete a un repositorio existente, con el
|
|
5
|
+
plan completo visible antes de escribir y un registro de lo instalado.
|
|
6
|
+
Qué es un paquete y qué garantiza la instalación están definidos en
|
|
7
|
+
[dominio de paquete](https://github.com/nucleoabierto/teleprompter/blob/master/docs/domains/001-paquete.md) y
|
|
8
|
+
[dominio de instalación](https://github.com/nucleoabierto/teleprompter/blob/master/docs/domains/002-instalacion.md); la
|
|
9
|
+
mecánica detallada, en la [referencia](referencia-install.md).
|
|
10
|
+
|
|
11
|
+
## Escenarios
|
|
12
|
+
|
|
13
|
+
- **Un paquete se instala de principio a fin con el binario real.** —
|
|
14
|
+
módulo `test/e2e.test.js`, «the reference package installs end to end
|
|
15
|
+
through the real binary»
|
|
16
|
+
- **El plan se presenta antes de escribir, con una marca por recurso.**
|
|
17
|
+
En un destino vacío todo es `create`. — módulo `test/plan.test.js`,
|
|
18
|
+
«plan marks every resource create on an empty destination»
|
|
19
|
+
- **Reinstalar es inocuo:** lo que ya coincide se marca `identical` y
|
|
20
|
+
no se escribe. — módulos `test/plan.test.js` («plan marks identical
|
|
21
|
+
when the destination already holds the same content») y
|
|
22
|
+
`test/execute.test.js` («reinstalling the same package reports
|
|
23
|
+
identical and keeps the recorded entry»)
|
|
24
|
+
- **Lo instalado por Teleprompter se actualiza sin preguntar** cuando
|
|
25
|
+
el paquete trae una versión igual o posterior y el destino sigue
|
|
26
|
+
siendo lo que el registro anotó. — módulo `test/plan.test.js`, «plan
|
|
27
|
+
marks managed-update when the destination still holds what the lock
|
|
28
|
+
recorded»
|
|
29
|
+
- **Lo modificado a mano es una colisión,** aunque el registro lo
|
|
30
|
+
reconozca como instalado. — módulo `test/plan.test.js`, «plan marks
|
|
31
|
+
conflict when a recorded resource was modified locally»
|
|
32
|
+
- **Las colisiones se resuelven una a una en consola interactiva.** —
|
|
33
|
+
módulo `test/plan.test.js`, «an interactive console resolves each
|
|
34
|
+
conflict per answer»
|
|
35
|
+
- **Sin forma de preguntar ni opciones de resolución, las colisiones
|
|
36
|
+
abortan la operación sin escribir.** — módulo `test/plan.test.js`,
|
|
37
|
+
«an interactive console without an asker reports conflicts and
|
|
38
|
+
aborts»
|
|
39
|
+
- **`--force` y `--skip` resuelven todas las colisiones por adelantado**
|
|
40
|
+
y son mutuamente excluyentes. — módulos `test/plan.test.js`
|
|
41
|
+
(«--force resolves every conflict as overwrite», «--skip resolves
|
|
42
|
+
every conflict as skip») y `test/cli.test.js` («main exits with usage
|
|
43
|
+
error on unknown or mutually exclusive flags»)
|
|
44
|
+
- **`--dry-run` muestra el plan y termina sin escribir ni registrar.**
|
|
45
|
+
— módulo `test/plan.test.js`, «--dry-run prints the plan and exits
|
|
46
|
+
without writing»
|
|
47
|
+
- **Un manifiesto inválido aborta con código 1 sin tocar el destino.**
|
|
48
|
+
— módulo `test/cli.test.js`, «main exits 1 on an invalid manifest
|
|
49
|
+
without writing to the destination»
|
|
50
|
+
- **Una precondición incumplida aborta con código 2 sin escribir;** con
|
|
51
|
+
`create: true` la ruta se crea como parte del plan. — módulo
|
|
52
|
+
`test/cli.test.js` («main exits 2 on an unmet precondition without
|
|
53
|
+
writing», «main passes when a missing precondition path allows
|
|
54
|
+
creation»)
|
|
55
|
+
- **Un error de invocación —argumentos ausentes, de más o rutas que no
|
|
56
|
+
son directorios— sale con código 4.** — módulo `test/cli.test.js`,
|
|
57
|
+
«main exits with usage error on missing, wrong, or excess arguments»
|
|
58
|
+
- **Cada instalación escribe `teleprompter-lock.json`** con los
|
|
59
|
+
recursos instalados, sus acciones y sus hashes, y conserva lo
|
|
60
|
+
registrado por otros paquetes. — módulo `test/execute.test.js`
|
|
61
|
+
(«install copies every resource and writes the lock on an empty
|
|
62
|
+
destination», «writeLock preserves records belonging to other
|
|
63
|
+
packages»)
|
|
64
|
+
- **Un error a mitad de ejecución sale con código 3 e informa de lo ya
|
|
65
|
+
aplicado.** — módulo `test/execute.test.js`, «a mid-execution error
|
|
66
|
+
exits 3 and reports what was applied»
|
|
67
|
+
- **Si el paquete declara personalización, la salida informa de dónde
|
|
68
|
+
están las instrucciones.** — módulo `test/execute.test.js`, «install
|
|
69
|
+
reports the personalization instructions location»
|
package/manual/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Manual de Teleprompter
|
|
2
|
+
|
|
3
|
+
Documentación de usuario del instalador Teleprompter. Para una primera
|
|
4
|
+
instalación, empezar por la guía de uso.
|
|
5
|
+
|
|
6
|
+
## Guías
|
|
7
|
+
|
|
8
|
+
- [Guía de uso](guia-de-uso.md) — instalar un paquete paso a paso, con
|
|
9
|
+
el paquete de referencia del repositorio como ejemplo.
|
|
10
|
+
|
|
11
|
+
## Referencia
|
|
12
|
+
|
|
13
|
+
- [Referencia de `install`](referencia-install.md) — la operación
|
|
14
|
+
completa: fases, marcas del plan, resolución de colisiones, registro
|
|
15
|
+
y códigos de salida.
|
|
16
|
+
|
|
17
|
+
## Funcionalidades
|
|
18
|
+
|
|
19
|
+
- [001 — Instalar un paquete](001-instalar-un-paquete.md) — qué hace
|
|
20
|
+
`install` y los escenarios que la suite de pruebas verifica.
|
|
21
|
+
|
|
22
|
+
## Documentos relacionados
|
|
23
|
+
|
|
24
|
+
- [docs/domains/](../docs/domains/README.md) — el modelo del producto:
|
|
25
|
+
qué es un paquete y qué es una instalación.
|
|
26
|
+
- [docs/especificacion-paquete.md](../docs/especificacion-paquete.md) —
|
|
27
|
+
cómo escribir el manifiesto `teleprompter.json` de un paquete propio.
|