shilo-cli 0.7.0 → 0.9.0
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/README.md +338 -255
- package/bin/shilo.js +211 -165
- package/package.json +1 -1
- package/src/ShiloClient.js +1066 -837
- package/src/args.js +32 -8
- package/src/checks.js +57 -0
- package/src/commands/deploys.js +105 -0
- package/src/commands/diff.js +19 -3
- package/src/commands/export.js +226 -0
- package/src/commands/init.js +8 -0
- package/src/commands/log.js +4 -0
- package/src/commands/pull.js +86 -2
- package/src/commands/push.js +668 -69
- package/src/commands/review.js +101 -0
- package/src/commands/status.js +148 -14
- package/src/exportgit.js +417 -0
- package/src/gitobjects.js +532 -0
- package/src/projectconfig.js +76 -0
- package/src/safelist.js +101 -0
- package/src/secrets.js +75 -9
- package/src/sync.js +56 -5
- package/src/walk.js +30 -0
package/README.md
CHANGED
|
@@ -1,255 +1,338 @@
|
|
|
1
|
-
# shilo-cli
|
|
2
|
-
|
|
3
|
-
CLI para subir carpetas locales a repositorios de [Shilo](https://www.shilo.city),
|
|
4
|
-
con una experiencia tipo git: `shilo login` una vez y después `shilo push`.
|
|
5
|
-
|
|
6
|
-
> **Estado:** Fase 5 (colaboración asíncrona). Disponibles `login`, `whoami`, `logout`,
|
|
7
|
-
> `init`, `push`, `pull`, `status`, `log`, `diff`.
|
|
8
|
-
> Ciclo completo: `shilo status` → `shilo pull` → trabajar local → `shilo push`.
|
|
9
|
-
|
|
10
|
-
## Requisitos
|
|
11
|
-
|
|
12
|
-
- Node.js **>= 18** (usa `fetch` y `crypto` nativos; sin dependencias de runtime).
|
|
13
|
-
|
|
14
|
-
## Instalación (local, durante desarrollo)
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
cd cli
|
|
18
|
-
npm link # expone el comando `shilo` global
|
|
19
|
-
# o, sin link:
|
|
20
|
-
node bin/shilo.js <comando>
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Uso
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
shilo login # pregunta email y contraseña (oculta)
|
|
27
|
-
shilo login --email you@example.com
|
|
28
|
-
shilo whoami # muestra la sesión activa
|
|
29
|
-
shilo logout # borra las credenciales locales
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Subir una carpeta (flujo tipo git)
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
cd mi-carpeta
|
|
36
|
-
shilo init --project <uuid> # ata la carpeta al repo (escribe .shilo.json)
|
|
37
|
-
shilo push # sube: crea/actualiza + commit
|
|
38
|
-
shilo push -m "mi mensaje" # con mensaje de commit
|
|
39
|
-
shilo push --
|
|
40
|
-
shilo push --
|
|
41
|
-
shilo push --
|
|
42
|
-
shilo push --
|
|
43
|
-
shilo push --
|
|
44
|
-
shilo push
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
shilo
|
|
138
|
-
shilo
|
|
139
|
-
shilo
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
shilo
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
1
|
+
# shilo-cli
|
|
2
|
+
|
|
3
|
+
CLI para subir carpetas locales a repositorios de [Shilo](https://www.shilo.city),
|
|
4
|
+
con una experiencia tipo git: `shilo login` una vez y después `shilo push`.
|
|
5
|
+
|
|
6
|
+
> **Estado:** Fase 5 (colaboración asíncrona). Disponibles `login`, `whoami`, `logout`,
|
|
7
|
+
> `init`, `push`, `pull`, `status`, `log`, `diff`.
|
|
8
|
+
> Ciclo completo: `shilo status` → `shilo pull` → trabajar local → `shilo push`.
|
|
9
|
+
|
|
10
|
+
## Requisitos
|
|
11
|
+
|
|
12
|
+
- Node.js **>= 18** (usa `fetch` y `crypto` nativos; sin dependencias de runtime).
|
|
13
|
+
|
|
14
|
+
## Instalación (local, durante desarrollo)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
cd cli
|
|
18
|
+
npm link # expone el comando `shilo` global
|
|
19
|
+
# o, sin link:
|
|
20
|
+
node bin/shilo.js <comando>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Uso
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
shilo login # pregunta email y contraseña (oculta)
|
|
27
|
+
shilo login --email you@example.com
|
|
28
|
+
shilo whoami # muestra la sesión activa
|
|
29
|
+
shilo logout # borra las credenciales locales
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Subir una carpeta (flujo tipo git)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
cd mi-carpeta
|
|
36
|
+
shilo init --project <uuid> # ata la carpeta al repo (escribe .shilo.json)
|
|
37
|
+
shilo push # sube: crea/actualiza + commit
|
|
38
|
+
shilo push -m "mi mensaje" # con mensaje de commit
|
|
39
|
+
shilo push --deploy prod # este push despliega a producción ("[deploy: prod]")
|
|
40
|
+
shilo push --dry-run # muestra qué haría sin subir
|
|
41
|
+
shilo push --card ABC-123 # agrega "[card: ABC-123]" al mensaje del commit
|
|
42
|
+
shilo push --agent claude-code --model claude-opus-5 # lo escribió un agente, y queda anotado
|
|
43
|
+
shilo push --agent claude-code --prompt-file pedido.md # guarda además el pedido que lo originó
|
|
44
|
+
shilo push --yes # sin pedir confirmación
|
|
45
|
+
shilo push --verbose # lista archivo por archivo en vez de resumir
|
|
46
|
+
shilo push --concurrency 4 # requests en paralelo (1-32, default 8)
|
|
47
|
+
shilo push ./otra-carpeta --project <uuid> # sin init, proyecto explícito
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Sólo se suben archivos de **texto**; binarios, oversize (>25 MB) y nombres con
|
|
51
|
+
caracteres no permitidos se saltan con aviso. Los archivos sin cambios no se
|
|
52
|
+
re-suben.
|
|
53
|
+
|
|
54
|
+
Los nombres aceptan **espacios, acentos y Unicode** (`Notas Metrónomo.txt`, `日本語.md`):
|
|
55
|
+
sólo se rechaza lo que rompe una ruta o no es portable — `/ \ : * ? " < > |`, bytes de
|
|
56
|
+
control, `.`/`..`, nombres de dispositivo de Windows (`CON`, `NUL`, `COM1`…) y el punto
|
|
57
|
+
final. Los nombres se normalizan a NFC, igual que el backend, para que el mismo archivo
|
|
58
|
+
subido desde macOS y desde Windows sea uno solo.
|
|
59
|
+
|
|
60
|
+
Guardar es **proponer**: el push manda todo lo que cambió como una propuesta que parte
|
|
61
|
+
de la versión que esta carpeta vio por última vez (`base` en `.shilo.json`, que
|
|
62
|
+
`pull` y `push` van anotando). El servidor la aplica solo si combina limpio con la
|
|
63
|
+
versión actual. Si otra persona cambió alguno de los **mismos archivos** desde esa
|
|
64
|
+
base, la propuesta **queda abierta y no se pisa nada**: el CLI dice qué archivos son,
|
|
65
|
+
tus cambios quedan guardados en esa propuesta para que el dueño decida, y vos podés
|
|
66
|
+
traer la versión actual con `shilo pull`, ajustar y volver a `push`. Un push nuevo
|
|
67
|
+
reemplaza tus propuestas abiertas anteriores.
|
|
68
|
+
|
|
69
|
+
El texto viaja inline (hasta 500 archivos o 4 MB por propuesta; más que eso son varias
|
|
70
|
+
propuestas de la misma base); los binarios y los textos de más de 1 MB se suben por URL
|
|
71
|
+
firmada y entran por su identificador de contenido. Contra un servidor anterior a las
|
|
72
|
+
propuestas, el CLI avisa y cae al camino viejo (escribir + commit), que sí puede pisar.
|
|
73
|
+
|
|
74
|
+
#### Subir sólo una parte (`--only`)
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
shilo push --only Documentacion/decisiones.md --only LEEME.md -m "decisiones de la semana"
|
|
78
|
+
shilo push --only Documentacion/ # un prefijo de carpeta también vale
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`--only` es repetible y recorta **qué se sube**, no qué se revisa: los ignores y el
|
|
82
|
+
escaneo de secretos corren igual sobre toda la carpeta. Como el push nunca borra
|
|
83
|
+
archivos remotos, subir un subconjunto es seguro por construcción.
|
|
84
|
+
|
|
85
|
+
Un selector que **no matchea nada es un error** (código 1) y no sube nada: nunca vas a
|
|
86
|
+
pedir dos archivos y terminar subiendo el repo entero. Al final, el resumen dice
|
|
87
|
+
cuántos archivos con cambios locales quedaron fuera, para que "una pieza = una tarjeta"
|
|
88
|
+
no se convierta en trabajo olvidado. El índice local no se poda con la selección: el
|
|
89
|
+
push completo siguiente sigue siendo rápido.
|
|
90
|
+
|
|
91
|
+
#### Qué se ignora
|
|
92
|
+
|
|
93
|
+
`push` respeta **`.gitignore` y `.shiloignore`**, incluidos los de subcarpetas (una
|
|
94
|
+
regla de `src/.gitignore` sólo alcanza a `src/`). `.shiloignore` se lee último, así que
|
|
95
|
+
podés re-incluir con `!` algo que git ignora. Por defecto ya se saltean `.git/`,
|
|
96
|
+
`node_modules/`, `.shilo/`, `.vercel/`, `.DS_Store` y `Thumbs.db`.
|
|
97
|
+
|
|
98
|
+
También se poda cualquier carpeta que **tenga forma de repo git** (`HEAD` + `objects/`
|
|
99
|
+
+ `refs/`), aunque no se llame `.git`: un `.git-ORIGINAL-BACKUP/` trae todo el
|
|
100
|
+
historial, incluidos secretos de commits ya borrados del árbol de trabajo.
|
|
101
|
+
|
|
102
|
+
> **Limitación conocida:** la negación `!` se evalúa por regla, no por directorio. Como
|
|
103
|
+
> en git, `!` no puede re-incluir un archivo si su carpeta padre ya está excluida
|
|
104
|
+
> (`dist/` + `!dist/keep.txt` no funciona); excluí el contenido en vez de la carpeta
|
|
105
|
+
> (`dist/*` + `!dist/keep.txt`).
|
|
106
|
+
|
|
107
|
+
Lo salteado se reporta **agrupado por motivo** (binario, ilegible, symlink, nombre
|
|
108
|
+
inválido, profundidad) con unos pocos ejemplos; si una carpeta concentra muchos
|
|
109
|
+
descartes, el CLI sugiere la línea de `.shiloignore` que la cubre. Con `--verbose` ves
|
|
110
|
+
la lista completa.
|
|
111
|
+
|
|
112
|
+
#### Escaneo de secretos
|
|
113
|
+
|
|
114
|
+
Antes de tocar la red, `push` revisa nombres sospechosos (`.env`, `id_rsa`,
|
|
115
|
+
`*.pem`, credenciales de service account…) y los primeros 8 KB de cada archivo
|
|
116
|
+
buscando patrones de claves (AWS, JWT de Supabase, tokens de GitHub, claves privadas
|
|
117
|
+
PEM…). Si encuentra algo, **no sube nada** y sale con código 1, indicando archivo y
|
|
118
|
+
línea — nunca el valor detectado. Salidas: agregarlo a `.shiloignore`, sacar el
|
|
119
|
+
secreto, o `--allow-secrets` si es un falso positivo.
|
|
120
|
+
|
|
121
|
+
#### Índice local
|
|
122
|
+
|
|
123
|
+
`push` guarda un índice en `.shilo/index.json` (tamaño + mtime + hash de lo último
|
|
124
|
+
subido). Los archivos que no cambiaron se resuelven sin bajar el contenido remoto,
|
|
125
|
+
que es lo que hace rápido el segundo push de una carpeta grande. Se puede ignorar con
|
|
126
|
+
`--no-index` para recomparar todo contra el servidor. Agregá `.shilo/` a tu
|
|
127
|
+
`.gitignore` (el CLI ya no lo sube).
|
|
128
|
+
|
|
129
|
+
`--dry-run` lista qué se crearía y qué se actualizaría, sin tocar la red más que para
|
|
130
|
+
leer el árbol. Ya no hace falta adivinar si vas a pisar a alguien: eso lo decide el
|
|
131
|
+
servidor con la base exacta, y si pasa, no pisa.
|
|
132
|
+
|
|
133
|
+
### ¿Estoy desactualizado? (status)
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
shilo status # compara local vs remoto SIN bajar contenido
|
|
137
|
+
shilo status --short # sólo rutas
|
|
138
|
+
shilo status --show-ignored # lista los archivos del remoto ignorados localmente
|
|
139
|
+
shilo status --json # para scripts
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Es el comando barato: usa sólo listados de carpeta (una request por carpeta, cero
|
|
143
|
+
descargas de contenido) y compara por **ruta + tamaño**. Informa qué tiene el remoto
|
|
144
|
+
que vos no (con autor y fecha del último commit de cada archivo), qué tenés local sin
|
|
145
|
+
subir, y marca aparte los archivos que cambiaron **de los dos lados** — el caso
|
|
146
|
+
peligroso. **Exit code 2** = estás atrasado respecto del remoto, útil en scripts.
|
|
147
|
+
|
|
148
|
+
**Los ignores valen en los dos sentidos.** Un archivo que existe en el remoto pero
|
|
149
|
+
está ignorado localmente (un `.env.ejemplo`, un `settings.local.json` que alguien subió
|
|
150
|
+
desde otra máquina) **no cuenta como "atrás"**: se informa en una línea aparte —con
|
|
151
|
+
`--show-ignored` para verlos, y en el campo `ignoredRemote` del `--json`— pero no
|
|
152
|
+
enciende el exit code 2. Antes quedaba en "faltan localmente" para siempre y la señal
|
|
153
|
+
que debería frenarte era ruido permanente.
|
|
154
|
+
|
|
155
|
+
Compensación consciente: dos archivos del mismo tamaño se reportan como iguales
|
|
156
|
+
aunque difieran byte a byte. `shilo diff` y `shilo push` sí comparan contenido.
|
|
157
|
+
|
|
158
|
+
La comparación con "desde la última vez que sincronicé" se apoya en `lastSync`, que
|
|
159
|
+
`push` y los `pull` completos escriben en `.shilo.json`. Si nunca sincronizaste desde
|
|
160
|
+
esta carpeta, no hay línea de base y los cambios remotos se reportan igual.
|
|
161
|
+
|
|
162
|
+
### Historial (log)
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
shilo log # últimos commits del proyecto
|
|
166
|
+
shilo log src/app.js # sólo los commits que tocaron ese archivo
|
|
167
|
+
shilo log -n 50 --files # más commits, listando archivos de cada uno
|
|
168
|
+
shilo log --json
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
La paginación es **por commit**, no por archivo: si un archivo no aparece, subí `-n`.
|
|
172
|
+
|
|
173
|
+
### Deploys a Vercel (deploys)
|
|
174
|
+
|
|
175
|
+
Si el owner conectó el proyecto con Vercel (pestaña **Deploys** en la web), cada
|
|
176
|
+
push que cambia algo dispara un deploy: por defecto a **preview**. Producción sólo
|
|
177
|
+
si se pide explícitamente.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
shilo push --deploy prod # este push va a producción
|
|
181
|
+
shilo push --deploy off # este push no despliega
|
|
182
|
+
shilo deploys # destino y últimos deploys, con estado y URL
|
|
183
|
+
shilo deploys -n 20 --json
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`--deploy` sólo agrega el trailer `[deploy: …]` al mensaje; escribirlo a mano en
|
|
187
|
+
`-m` da lo mismo.
|
|
188
|
+
|
|
189
|
+
### Diferencias (diff)
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
shilo diff # resumen de todo lo que difiere (sólo metadata)
|
|
193
|
+
shilo diff src/app.js # diff de contenido línea a línea
|
|
194
|
+
shilo diff src/app.js --context 6
|
|
195
|
+
shilo diff --stat
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
El diff usa el remoto como base (`---`) y tu copia local como destino (`+++`), o sea
|
|
199
|
+
que las líneas `+` son lo que un `push` agregaría. **Exit code 1** = hay diferencias.
|
|
200
|
+
|
|
201
|
+
### Bajar un proyecto (pull)
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
shilo pull ./mi-carpeta --project <uuid> # baja el repo a una carpeta local
|
|
205
|
+
shilo pull --dry-run # muestra qué cambiaría localmente, sin bajar nada
|
|
206
|
+
shilo pull --yes # sin pedir confirmación
|
|
207
|
+
shilo pull --force # sobrescribe también los archivos que difieren
|
|
208
|
+
shilo pull --include-ignored # baja también lo ignorado localmente
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`pull` recorre el árbol remoto (carpeta por carpeta), baja los archivos de texto
|
|
212
|
+
y deja `.shilo.json` listo para un `push` posterior sin `--project`.
|
|
213
|
+
|
|
214
|
+
Protección del trabajo local sin guardar: **no pisa** un archivo local que difiera del
|
|
215
|
+
remoto salvo con `--force`. Sin `--force` no aborta el pull entero — baja lo que es
|
|
216
|
+
seguro, deja afuera los conflictivos y sale con código 1 para que decidas (mirá
|
|
217
|
+
`shilo diff <archivo>`). Los archivos que sólo existen localmente nunca se tocan: el
|
|
218
|
+
pull no borra. `--dry-run` muestra el impacto sobre tu disco (nuevo / sobrescribe /
|
|
219
|
+
se conserva), no el árbol remoto crudo.
|
|
220
|
+
|
|
221
|
+
**Respaldo automático con `--force`.** Antes de pisar un archivo local que difería, el
|
|
222
|
+
pull guarda tu versión en `.shilo/respaldo/<fecha-ISO>/<ruta>` y te dice la carpeta al
|
|
223
|
+
terminar. Va dentro de `.shilo/` —ignorado por defecto— y no como un `<archivo>.local`
|
|
224
|
+
al lado, que el push siguiente subiría: cambiaríamos "perder trabajo" por "publicar tu
|
|
225
|
+
versión en conflicto". Al ir por fecha, dos pulls seguidos no se pisan entre sí.
|
|
226
|
+
|
|
227
|
+
**Lo ignorado localmente no se baja.** Si `.env.*` está en tu `.shiloignore`, que
|
|
228
|
+
alguien haya subido un `.env.ejemplo` desde otra máquina no lo hace aparecer acá: se
|
|
229
|
+
cuenta aparte como "ignorados (no se bajan)", y con `--include-ignored` se bajan igual.
|
|
230
|
+
Esto también arregla el conteo, que antes prometía más archivos de los que escribía.
|
|
231
|
+
|
|
232
|
+
También bloquea nombres que intenten escribir fuera de la carpeta destino (path
|
|
233
|
+
traversal) y saltea binarios con aviso (volverían corruptos). Espejo de `push`:
|
|
234
|
+
`--project` pisa a `.shilo.json`. Con `shilo init --pull` se ata y baja en un solo paso.
|
|
235
|
+
|
|
236
|
+
### Exportar a Git (export)
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
shilo export ../mi-repo --project <uuid> # la historia entera, como repositorio Git
|
|
240
|
+
shilo export ../mi-repo # otra vez: trae sólo lo nuevo
|
|
241
|
+
git -C ../mi-repo push <remoto> main
|
|
242
|
+
git -C ../mi-repo push <remoto> +refs/notes/shilo
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Escribe todos los puntos de guardado de `main` como commits de Git, con su autor y
|
|
246
|
+
su fecha, y la procedencia (agente, tarjeta, propuesta) al pie de cada mensaje y
|
|
247
|
+
completa en `refs/notes/shilo`. Es de sólo lectura para el proyecto. Necesita `git`
|
|
248
|
+
en el PATH; un proyecto público se exporta sin sesión.
|
|
249
|
+
|
|
250
|
+
- **La primera vez**, la carpeta tiene que estar vacía o no existir. Después, repetir
|
|
251
|
+
el comando sobre la misma carpeta baja sólo los archivos nuevos
|
|
252
|
+
(`.git/shilo/mapa` recuerda lo exportado) y exige que lo viejo dé los mismos SHA-1.
|
|
253
|
+
- **Determinístico:** el mismo proyecto da los mismos SHA-1 en cualquier máquina. Los
|
|
254
|
+
commits firman con el nombre congelado de cada persona y
|
|
255
|
+
`<usuario>@users.noreply.shilo.city`, nunca con su correo real.
|
|
256
|
+
- **No pisa trabajo ajeno:** si `main` tiene commits que no salieron de Shilo, o hay
|
|
257
|
+
cambios sin guardar, se niega y no toca nada.
|
|
258
|
+
- **Git no guarda carpetas vacías:** quedan afuera y el informe las lista.
|
|
259
|
+
- La ref de notas se rehace entera en cada exportación: por eso el `+` en su push.
|
|
260
|
+
|
|
261
|
+
### Servidor alternativo
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
shilo login --base-url https://mi-shilo.vercel.app
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Credenciales
|
|
268
|
+
|
|
269
|
+
Se guardan en `~/.shilo/config.json` (override con `SHILO_CONFIG_DIR`), **cifradas**
|
|
270
|
+
con AES-256-CBC y con permisos `0600`.
|
|
271
|
+
|
|
272
|
+
- Por defecto la clave de cifrado se deriva de la máquina (hostname + usuario).
|
|
273
|
+
Esto es **ofuscación en reposo**, no secreto fuerte.
|
|
274
|
+
- Para cifrado fuerte, exportá `SHILO_ENCRYPTION_KEY` (una passphrase propia) antes
|
|
275
|
+
de `shilo login`; necesitarás la misma variable para futuras ejecuciones.
|
|
276
|
+
|
|
277
|
+
Se almacena el JWT, el refresh token, la expiración y el email; **no** se guarda la
|
|
278
|
+
contraseña.
|
|
279
|
+
|
|
280
|
+
### Tokens de acceso personal (PAT)
|
|
281
|
+
|
|
282
|
+
Un token pasado como `--token abc123` queda en el historial del shell y en la lista de
|
|
283
|
+
procesos (`ps` lo muestra a cualquier usuario de la máquina). El CLI lo acepta —es la
|
|
284
|
+
forma que se copia desde la web— pero avisa. Alternativas:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
cat pat.txt | shilo login --token - # lee el token de stdin
|
|
288
|
+
SHILO_TOKEN=<pat> shilo init --project <uuid> # variable de entorno (lo natural en CI)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Variables de entorno
|
|
292
|
+
|
|
293
|
+
| Variable | Efecto |
|
|
294
|
+
| ----------------------- | ------------------------------------------------------------- |
|
|
295
|
+
| `SHILO_CONFIG_DIR` | Directorio de config (default `~/.shilo`). |
|
|
296
|
+
| `SHILO_ENCRYPTION_KEY` | Passphrase para cifrar credenciales (recomendado). |
|
|
297
|
+
| `SHILO_TOKEN` | Token de acceso personal (evita pasarlo por `--token`). |
|
|
298
|
+
| `SHILO_CONCURRENCY` | Requests en paralelo del push (1-32, default 8). |
|
|
299
|
+
| `NO_COLOR` | Desactiva colores ANSI. |
|
|
300
|
+
|
|
301
|
+
## Roadmap
|
|
302
|
+
|
|
303
|
+
- **Fase 1 — auth** *(hecho)*: `login`, `whoami`, `logout` + config cifrada.
|
|
304
|
+
- **Fase 2 — motor** *(hecho)*: cliente de archivos (`list`/`getMeta`/`create`/`write`/
|
|
305
|
+
`ensurePath`/`commit`) + recorrido de árbol (`.shiloignore`) + detección de binarios.
|
|
306
|
+
- **Fase 3 — push** *(hecho)*: `shilo init` + `shilo push` (crea/actualiza + commit,
|
|
307
|
+
detección de cambios, `.shiloignore`, `--dry-run`).
|
|
308
|
+
- **Fase 4 — pull** *(hecho)*: `shilo pull` (recorrido del árbol remoto con pool,
|
|
309
|
+
guarda anti path-traversal, salto de binarios, colisiones, binding `.shilo.json`,
|
|
310
|
+
`--dry-run`). Cierra el ciclo `pull → trabajar local → push`.
|
|
311
|
+
- **Fase 5 — colaboración asíncrona** *(hecho)*: `status` (comparación barata local vs
|
|
312
|
+
remoto + exit code 2), `log` (historial por proyecto o archivo), `diff` (comparación
|
|
313
|
+
de contenido + exit code 1), atribución de autor en `push --dry-run`, `pull` que
|
|
314
|
+
resuelve conflictos por archivo en vez de abortar, `lastSync` en `.shilo.json` y
|
|
315
|
+
`push --card <id>` para cruzar commits con un tablero externo (Metrónomo).
|
|
316
|
+
- **Fase 6 — robustez del push** *(hecho)*: `.gitignore` (incluidos los anidados),
|
|
317
|
+
poda de repos git por forma, escaneo de secretos con corte del push, preflight
|
|
318
|
+
100 % offline antes de tocar la red, planificación con un recorrido del árbol
|
|
319
|
+
remoto (una request por carpeta en vez de una por archivo), índice local
|
|
320
|
+
`.shilo/index.json`, lectura perezosa del contenido, reintentos con backoff ante
|
|
321
|
+
429/5xx, concurrencia adaptativa, barra de progreso y confirmación real en
|
|
322
|
+
`init --push`.
|
|
323
|
+
- **Fase 7 — propuestas** *(hecho)*: `push` deja de escribir archivo por archivo y
|
|
324
|
+
manda una propuesta con la base exacta; el servidor la combina con la versión actual
|
|
325
|
+
y nunca pisa un archivo que otra persona cambió. `base` en `.shilo.json`,
|
|
326
|
+
`registerBlob` para binarios, camino viejo sólo como reserva.
|
|
327
|
+
- **Fase 8 — deploys** *(hecho)*: `push --deploy <prod|preview|off>` y
|
|
328
|
+
`shilo deploys` para el deploy automático a Vercel (PLAN_DEPLOY_VERCEL).
|
|
329
|
+
|
|
330
|
+
## Exit codes
|
|
331
|
+
|
|
332
|
+
| Comando | Código | Significado |
|
|
333
|
+
| -------- | ------ | -------------------------------------------- |
|
|
334
|
+
| `status` | 2 | El remoto tiene cambios que no tenés. |
|
|
335
|
+
| `diff` | 1 | Hay diferencias entre local y remoto. |
|
|
336
|
+
| `pull` | 1 | Quedaron conflictos sin bajar (o fallas). |
|
|
337
|
+
| `push` | 1 | Se detectaron posibles secretos (nada subido). |
|
|
338
|
+
| cualquiera | 1 | Error. |
|