@skill-map/cli 0.14.0 → 0.14.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/dist/cli/guide/sm-guide.md +188 -78
- package/dist/cli.js +175 -32
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.js +1 -1
- package/dist/kernel/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -80,15 +80,17 @@ ls -A
|
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
**Items que ignorás** del listado al evaluar "vacío" (no cuentan
|
|
83
|
-
como contenido del usuario):
|
|
83
|
+
como contenido del usuario, son infraestructura del propio skill):
|
|
84
84
|
|
|
85
|
-
- `.claude` — infraestructura de skills/agents
|
|
86
|
-
|
|
87
|
-
- `
|
|
88
|
-
- `sm-guide.md` — copia del skill materializada por `sm guide`
|
|
89
|
-
(suelta en la raíz del cwd).
|
|
85
|
+
- `.claude` — infraestructura de skills/agents.
|
|
86
|
+
- `SKILL.md` — copia del skill suelta acá.
|
|
87
|
+
- `sm-guide.md` — copia del skill materializada por `sm guide`.
|
|
90
88
|
- `guide-state.yml` — modo resume (ver §Resume / restart).
|
|
91
89
|
|
|
90
|
+
La whitelist es **interna** — no se la enumerás al tester. Si todo
|
|
91
|
+
está OK le decís simplemente "Listo, el directorio está limpio.
|
|
92
|
+
Sigamos." sin paréntesis ni aclaraciones de qué items se ignoraron.
|
|
93
|
+
|
|
92
94
|
Reglas (después de filtrar los items ignorados):
|
|
93
95
|
|
|
94
96
|
- Listado vacío → el dir está vacío. **Seguís.**
|
|
@@ -167,51 +169,117 @@ Sugerí `node --version` y guialo.
|
|
|
167
169
|
|
|
168
170
|
### 3. Crear el fixture en el cwd
|
|
169
171
|
|
|
172
|
+
Cuatro nodos, uno por cada *kind* que skill-map reconoce — un skill,
|
|
173
|
+
un agente, un hook y una nota — todos linkeados entre sí para que el
|
|
174
|
+
grafo tenga forma. Más un `.skill-map-ignore` para que el escaneo no
|
|
175
|
+
levante archivos propios de la guía.
|
|
176
|
+
|
|
170
177
|
```
|
|
171
178
|
<cwd>/
|
|
172
|
-
├──
|
|
173
|
-
│ ├──
|
|
174
|
-
│ └──
|
|
179
|
+
├── .claude/
|
|
180
|
+
│ ├── skills/
|
|
181
|
+
│ │ └── demo-skill/
|
|
182
|
+
│ │ └── SKILL.md # kind: skill
|
|
183
|
+
│ ├── agents/
|
|
184
|
+
│ │ └── demo-agent.md # kind: agent
|
|
185
|
+
│ └── hooks/
|
|
186
|
+
│ └── demo-hook.md # kind: hook
|
|
175
187
|
├── notes/
|
|
176
|
-
│ └── todo.md
|
|
188
|
+
│ └── todo.md # kind: note (con link roto a propósito)
|
|
189
|
+
├── .skill-map-ignore
|
|
177
190
|
├── guide-state.yml
|
|
178
191
|
└── findings.md
|
|
179
192
|
```
|
|
180
193
|
|
|
181
|
-
|
|
194
|
+
`.claude/skills/demo-skill/SKILL.md`:
|
|
182
195
|
```markdown
|
|
183
196
|
---
|
|
184
|
-
|
|
185
|
-
|
|
197
|
+
name: demo-skill
|
|
198
|
+
description: |
|
|
199
|
+
Skill de ejemplo que muestra cómo skill-map detecta el frontmatter
|
|
200
|
+
y los links internos. Útil para inspeccionar el grafo en la UI.
|
|
201
|
+
inputs:
|
|
202
|
+
- name: target
|
|
203
|
+
type: path
|
|
204
|
+
description: Archivo a procesar.
|
|
205
|
+
required: true
|
|
206
|
+
outputs:
|
|
207
|
+
- name: report
|
|
208
|
+
type: string
|
|
209
|
+
description: Resumen en Markdown.
|
|
186
210
|
---
|
|
187
211
|
|
|
188
|
-
#
|
|
212
|
+
# demo-skill
|
|
213
|
+
|
|
214
|
+
Este skill recorre un archivo y devuelve un reporte. Cuando necesita
|
|
215
|
+
delegar trabajo pesado se apoya en el
|
|
216
|
+
[demo-agent](../../agents/demo-agent.md).
|
|
189
217
|
|
|
190
|
-
|
|
218
|
+
## Pasos
|
|
219
|
+
1. Leer el `target`.
|
|
220
|
+
2. Validar el frontmatter contra los schemas.
|
|
221
|
+
3. Generar el reporte.
|
|
191
222
|
```
|
|
192
223
|
|
|
193
|
-
|
|
224
|
+
`.claude/agents/demo-agent.md`:
|
|
194
225
|
```markdown
|
|
195
226
|
---
|
|
196
|
-
|
|
197
|
-
|
|
227
|
+
name: demo-agent
|
|
228
|
+
description: |
|
|
229
|
+
Agente de ejemplo que el demo-skill puede invocar para tareas de
|
|
230
|
+
lectura y ejecución de comandos.
|
|
231
|
+
tools: Read, Bash
|
|
232
|
+
model: sonnet
|
|
198
233
|
---
|
|
199
234
|
|
|
200
|
-
#
|
|
235
|
+
# demo-agent
|
|
236
|
+
|
|
237
|
+
Procesa entradas y, al cerrar la sesión, dispara el
|
|
238
|
+
[demo-hook](../hooks/demo-hook.md).
|
|
201
239
|
|
|
202
|
-
|
|
240
|
+
Reglas:
|
|
241
|
+
- Nunca correr comandos destructivos sin confirmación.
|
|
242
|
+
- Loggear cada acción a stderr.
|
|
203
243
|
```
|
|
204
244
|
|
|
205
|
-
|
|
245
|
+
`.claude/hooks/demo-hook.md`:
|
|
206
246
|
```markdown
|
|
207
247
|
---
|
|
208
|
-
|
|
209
|
-
|
|
248
|
+
event: SubagentStop
|
|
249
|
+
blocking: false
|
|
250
|
+
idempotent: true
|
|
210
251
|
---
|
|
211
252
|
|
|
212
|
-
#
|
|
253
|
+
# demo-hook
|
|
254
|
+
|
|
255
|
+
Hook que se dispara cuando un subagente termina. Marca el cierre y
|
|
256
|
+
deja una entrada en la lista de pendientes.
|
|
257
|
+
|
|
258
|
+
Ver [pendientes](../../notes/todo.md) para el contexto operativo.
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`notes/todo.md` (con link **roto a propósito** — sirve en la etapa
|
|
262
|
+
L4 del camino largo):
|
|
263
|
+
```markdown
|
|
264
|
+
---
|
|
265
|
+
title: Pendientes del demo
|
|
266
|
+
tags: [notes, demo]
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
# Pendientes
|
|
270
|
+
|
|
271
|
+
- [ ] Documentar el [diagrama de flujo](./missing-page.md) — link
|
|
272
|
+
roto a propósito, no toques.
|
|
273
|
+
- [ ] Pulir el prompt de [demo-skill](../.claude/skills/demo-skill/SKILL.md).
|
|
274
|
+
- [ ] Confirmar el `event` del [demo-hook](../.claude/hooks/demo-hook.md).
|
|
275
|
+
```
|
|
213
276
|
|
|
214
|
-
-
|
|
277
|
+
`.skill-map-ignore` (formato gitignore-like — evita que `sm scan`
|
|
278
|
+
levante archivos internos de la guía como nodos del grafo):
|
|
279
|
+
```
|
|
280
|
+
sm-guide.md
|
|
281
|
+
findings.md
|
|
282
|
+
guide-state.yml
|
|
215
283
|
```
|
|
216
284
|
|
|
217
285
|
`findings.md`:
|
|
@@ -366,11 +434,12 @@ sm
|
|
|
366
434
|
> El server queda corriendo. Abrí en el navegador la URL que muestra
|
|
367
435
|
> la salida (típicamente **http://127.0.0.1:4242**).
|
|
368
436
|
>
|
|
369
|
-
> Recorré las
|
|
370
|
-
> 1. **Grafo** — los nodos del fixture
|
|
371
|
-
>
|
|
372
|
-
>
|
|
373
|
-
>
|
|
437
|
+
> Recorré las 3 vistas:
|
|
438
|
+
> 1. **Grafo** — los 4 nodos del fixture (skill, agente, hook, nota)
|
|
439
|
+
> conectados por sus links internos.
|
|
440
|
+
> 2. **Lista** — tabla con paths, kind y metadata.
|
|
441
|
+
> 3. **Inspector** — clickeá un nodo para ver detalles (frontmatter,
|
|
442
|
+
> links in/out, issues).
|
|
374
443
|
>
|
|
375
444
|
> ¿Cargó todo bien? Si algo no se ve, registralo en findings.
|
|
376
445
|
|
|
@@ -382,25 +451,34 @@ la UI redibujarse sola.
|
|
|
382
451
|
|
|
383
452
|
Cambios que aplicás vos (con `Edit` y `Write`):
|
|
384
453
|
|
|
385
|
-
1. Editar
|
|
454
|
+
1. Editar `.claude/skills/demo-skill/SKILL.md` — agregar al final:
|
|
386
455
|
```markdown
|
|
387
|
-
|
|
456
|
+
Ver también [ejemplos](../../notes/examples.md).
|
|
388
457
|
```
|
|
389
|
-
2. Crear `
|
|
458
|
+
2. Crear `notes/examples.md`:
|
|
390
459
|
```markdown
|
|
391
460
|
---
|
|
392
|
-
title:
|
|
393
|
-
tags: [
|
|
461
|
+
title: Ejemplos del demo-skill
|
|
462
|
+
tags: [notes, examples, demo]
|
|
394
463
|
---
|
|
395
|
-
|
|
396
|
-
|
|
464
|
+
|
|
465
|
+
# Ejemplos
|
|
466
|
+
|
|
467
|
+
Casos típicos de uso del [demo-skill](../.claude/skills/demo-skill/SKILL.md):
|
|
468
|
+
|
|
469
|
+
- Procesar un único archivo `.md`.
|
|
470
|
+
- Validar frontmatter contra `note.schema.json`.
|
|
471
|
+
- Reportar links rotos detectados al pasar.
|
|
397
472
|
```
|
|
398
473
|
|
|
399
474
|
> Mirá el navegador. En 1-2 segundos deberías ver:
|
|
400
|
-
> - Un nodo nuevo (`examples.md`) en el grafo
|
|
401
|
-
>
|
|
402
|
-
>
|
|
403
|
-
>
|
|
475
|
+
> - Un nodo nuevo (`examples.md`, kind `note`) en el grafo.
|
|
476
|
+
> **Si no lo ves, hacé zoom con la rueda del mouse o el control de
|
|
477
|
+
> zoom de la UI** — los nodos nuevos a veces aparecen en un
|
|
478
|
+
> extremo del canvas.
|
|
479
|
+
> - Un conector nuevo: `demo-skill → examples.md`.
|
|
480
|
+
> - Eventos en el panel lateral tipo `scan.started` /
|
|
481
|
+
> `scan.completed`.
|
|
404
482
|
>
|
|
405
483
|
> ¿Lo viste moverse? Si no se actualizó, refrescá el navegador y
|
|
406
484
|
> decime.
|
|
@@ -464,35 +542,39 @@ que él puede hacer lo mismo desde su editor.
|
|
|
464
542
|
Pedile que vuelva a arrancar el server (`sm` desde el cwd de la guía)
|
|
465
543
|
y abra el navegador.
|
|
466
544
|
|
|
467
|
-
> Tu turno. Editá
|
|
468
|
-
> la línea que linkea a `
|
|
545
|
+
> Tu turno. Editá `.claude/skills/demo-skill/SKILL.md` con tu editor
|
|
546
|
+
> favorito y borrá la línea que linkea a `demo-agent.md`. Guardá.
|
|
547
|
+
> Mirá la UI.
|
|
469
548
|
>
|
|
470
|
-
> Esperado:
|
|
471
|
-
> `
|
|
472
|
-
>
|
|
549
|
+
> Esperado: el conector `demo-skill → demo-agent` desaparece. Si
|
|
550
|
+
> `demo-agent.md` queda sin nadie linkeándolo, aparece como huérfano
|
|
551
|
+
> (lo vamos a explotar en la etapa L4).
|
|
473
552
|
|
|
474
|
-
Verificás leyendo
|
|
475
|
-
aplicó. Cuando confirme, pedile **Ctrl+C** para
|
|
553
|
+
Verificás leyendo `.claude/skills/demo-skill/SKILL.md` para confirmar
|
|
554
|
+
que el cambio se aplicó. Cuando confirme, pedile **Ctrl+C** para
|
|
555
|
+
apagar el server.
|
|
476
556
|
|
|
477
557
|
### Etapa L2 — Browse CLI: list / show / check (~3 min)
|
|
478
558
|
|
|
479
559
|
```bash
|
|
480
560
|
sm list
|
|
481
|
-
sm list --kind
|
|
482
|
-
sm
|
|
561
|
+
sm list --kind skill
|
|
562
|
+
sm list --kind agent
|
|
563
|
+
sm show .claude/skills/demo-skill/SKILL.md
|
|
483
564
|
sm check
|
|
484
565
|
```
|
|
485
566
|
|
|
486
|
-
Esperado: ves los nodos del fixture listados; `check`
|
|
487
|
-
issue del link roto en `notes/todo.md` apuntando a
|
|
567
|
+
Esperado: ves los 4 nodos del fixture listados con su kind; `check`
|
|
568
|
+
reporta el issue del link roto en `notes/todo.md` apuntando a
|
|
569
|
+
`missing-page.md`.
|
|
488
570
|
|
|
489
571
|
### Etapa L3 — ASCII: graph + export (~3 min)
|
|
490
572
|
|
|
491
573
|
```bash
|
|
492
574
|
sm graph
|
|
493
|
-
sm graph --root
|
|
575
|
+
sm graph --root .claude/skills/demo-skill/SKILL.md
|
|
494
576
|
sm export --format md > export.md
|
|
495
|
-
sm export --format json --kind
|
|
577
|
+
sm export --format json --kind note > export-notes.json
|
|
496
578
|
ls -la export.*
|
|
497
579
|
```
|
|
498
580
|
|
|
@@ -516,16 +598,16 @@ sm orphans undo-rename --from <path-renombrado>
|
|
|
516
598
|
```
|
|
517
599
|
|
|
518
600
|
Para no romper nada, sugerí al tester apuntar el link roto de
|
|
519
|
-
`notes/todo.md` a un archivo existente (ej. `
|
|
601
|
+
`notes/todo.md` a un archivo existente (ej. `notes/examples.md`).
|
|
520
602
|
Es un test, no importa que la semántica sea fea.
|
|
521
603
|
|
|
522
604
|
### Etapa L5 — Delta + historia (~4 min)
|
|
523
605
|
|
|
524
606
|
```bash
|
|
525
607
|
sm export --format json > .skill-map/baseline.json
|
|
526
|
-
# editá algún .md (ej. agregá una línea en
|
|
608
|
+
# editá algún .md (ej. agregá una línea en notes/todo.md)
|
|
527
609
|
sm scan compare-with .skill-map/baseline.json
|
|
528
|
-
sm refresh -n
|
|
610
|
+
sm refresh -n notes/todo.md
|
|
529
611
|
sm refresh --stale
|
|
530
612
|
sm history
|
|
531
613
|
sm history --action scan
|
|
@@ -616,31 +698,58 @@ sm db reset --hard
|
|
|
616
698
|
|
|
617
699
|
## Cierre final
|
|
618
700
|
|
|
619
|
-
Cuando todo terminó (corto solo, o corto + largo)
|
|
701
|
+
Cuando todo terminó (corto solo, o corto + largo), **ofrecé generar
|
|
702
|
+
un archivo de reporte para enviarle a Pusher**:
|
|
620
703
|
|
|
621
|
-
|
|
622
|
-
|
|
704
|
+
> ¡Gracias! Llegamos al final. Antes de cerrar:
|
|
705
|
+
>
|
|
706
|
+
> ¿Querés que genere un **archivo de resultados** consolidado (resumen
|
|
707
|
+
> del recorrido + findings + entorno) listo para mandarle a
|
|
708
|
+
> **Pusher**? Lo guardo como `<cwd>/sm-guide-report.md`.
|
|
709
|
+
>
|
|
710
|
+
> 1. **Sí, generámelo**
|
|
711
|
+
> 2. **No, ya está**
|
|
623
712
|
|
|
624
|
-
|
|
625
|
-
- Tester: nivel <N> (si aplica)
|
|
626
|
-
- Directorio de la guía: <cwd>
|
|
627
|
-
- Pasos del corto: 4 / 4
|
|
628
|
-
- Etapas del largo: X / 9 (Y skipped) — si aplica
|
|
629
|
-
- Findings reportados: Z
|
|
630
|
-
- Tiempo total: ~<calculado de timestamps>
|
|
713
|
+
Si dice **1**, escribís `<cwd>/sm-guide-report.md` con esta plantilla:
|
|
631
714
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
715
|
+
```markdown
|
|
716
|
+
# sm-guide — reporte para Pusher
|
|
717
|
+
|
|
718
|
+
- **Fecha**: <ISO-8601>
|
|
719
|
+
- **Ruta**: <corto solo | corto + largo>
|
|
720
|
+
- **Tester**: nivel <N> (si aplica)
|
|
721
|
+
- **Directorio de la guía**: <cwd>
|
|
722
|
+
- **Pasos del corto**: 4 / 4
|
|
723
|
+
- **Etapas del largo**: X / 9 (Y skipped) — si aplica
|
|
724
|
+
- **Tiempo total**: ~<calculado de timestamps>
|
|
725
|
+
|
|
726
|
+
## Entorno
|
|
727
|
+
- `sm version`: <versión>
|
|
728
|
+
- Node: <versión>
|
|
729
|
+
- OS: <plataforma>
|
|
730
|
+
|
|
731
|
+
## Findings registrados
|
|
732
|
+
<volcar el contenido relevante de findings.md, sin el header genérico>
|
|
733
|
+
|
|
734
|
+
## Notas adicionales del tester
|
|
735
|
+
<si dejó comentarios libres>
|
|
736
|
+
```
|
|
635
737
|
|
|
636
|
-
|
|
738
|
+
Después le mostrás:
|
|
637
739
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
<cwd>/
|
|
641
|
-
|
|
740
|
+
> Listo. Te dejé el reporte en:
|
|
741
|
+
>
|
|
742
|
+
> <cwd>/sm-guide-report.md
|
|
743
|
+
>
|
|
744
|
+
> Mandámelo a Pusher cuando quieras (por el canal acordado).
|
|
745
|
+
>
|
|
746
|
+
> Para borrar todo lo que dejó la guía, si el cwd era un dir
|
|
747
|
+
> dedicado:
|
|
748
|
+
>
|
|
749
|
+
> cd ~ && rm -rf <cwd>
|
|
642
750
|
|
|
643
|
-
Si
|
|
751
|
+
Si dice **2**, le mostrás solo las instrucciones de borrado y
|
|
752
|
+
agradecés.
|
|
644
753
|
|
|
645
754
|
## Resume / restart
|
|
646
755
|
|
|
@@ -659,8 +768,9 @@ arrancás así (NO repetís pre-flight desde cero):
|
|
|
659
768
|
|
|
660
769
|
Si elige "empezar de cero", confirmás explícitamente. Solo después
|
|
661
770
|
borrás los archivos de la guía del cwd (`guide-state.yml`,
|
|
662
|
-
`findings.md`,
|
|
663
|
-
`export
|
|
771
|
+
`findings.md`, `.skill-map-ignore`, `.claude/`, `notes/`,
|
|
772
|
+
`.skill-map/`, y cualquier `export.*`, `dump.sql` o
|
|
773
|
+
`sm-guide-report.md` que haya quedado) y arrancás todo desde el
|
|
664
774
|
pre-flight.
|
|
665
775
|
|
|
666
776
|
## Edge cases
|
package/dist/cli.js
CHANGED
|
@@ -7363,7 +7363,7 @@ import { Command as Command8, Option as Option8 } from "clipanion";
|
|
|
7363
7363
|
// cli/i18n/guide.texts.ts
|
|
7364
7364
|
var GUIDE_TEXTS = {
|
|
7365
7365
|
// Success — written to stdout after `<cwd>/sm-guide.md` is created.
|
|
7366
|
-
written: 'Listo. sm-guide.md creado en {{cwd}}. Abr\xED Claude Code ac\xE1 y decile "
|
|
7366
|
+
written: 'Listo. sm-guide.md creado en {{cwd}}. Abr\xED Claude Code ac\xE1 y decile "ejecut\xE1 @sm-guide.md" para arrancar la gu\xEDa interactiva.\n',
|
|
7367
7367
|
// Refusal — `sm-guide.md` already exists and `--force` was not set.
|
|
7368
7368
|
// Goes to stderr, exit code 2 (operational error per spec § Exit codes).
|
|
7369
7369
|
alreadyExists: "sm guide: sm-guide.md ya existe en {{cwd}}. Us\xE1 `--force` para sobrescribir.\n",
|
|
@@ -7381,8 +7381,9 @@ var GuideCommand = class extends SmCommand {
|
|
|
7381
7381
|
description: "Materialize the interactive tester guide (sm-guide.md) in the current directory.",
|
|
7382
7382
|
details: `
|
|
7383
7383
|
Drops the canonical SKILL.md content as ./sm-guide.md so a tester
|
|
7384
|
-
can open Claude Code in the cwd and
|
|
7385
|
-
|
|
7384
|
+
can open Claude Code in the cwd and load the file as a skill by
|
|
7385
|
+
typing "ejecut\xE1 @sm-guide.md". Top-level only \u2014 no subdirectory
|
|
7386
|
+
is created.
|
|
7386
7387
|
|
|
7387
7388
|
Does NOT require an initialized .skill-map/ project. Refuses to
|
|
7388
7389
|
overwrite an existing sm-guide.md unless --force is passed.
|
|
@@ -7454,7 +7455,7 @@ import { Command as Command9, Option as Option9 } from "clipanion";
|
|
|
7454
7455
|
// package.json
|
|
7455
7456
|
var package_default = {
|
|
7456
7457
|
name: "@skill-map/cli",
|
|
7457
|
-
version: "0.14.
|
|
7458
|
+
version: "0.14.1",
|
|
7458
7459
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
7459
7460
|
license: "MIT",
|
|
7460
7461
|
type: "module",
|
|
@@ -9324,13 +9325,13 @@ async function writeDryRunGitignorePlan(stdout, scopeRoot) {
|
|
|
9324
9325
|
);
|
|
9325
9326
|
}
|
|
9326
9327
|
}
|
|
9327
|
-
async function runFirstScan(scopeRoot,
|
|
9328
|
+
async function runFirstScan(scopeRoot, homedir3, dbPath, strict, stdout, stderr) {
|
|
9328
9329
|
stdout.write(INIT_TEXTS.runningFirstScan);
|
|
9329
9330
|
const kernel = createKernel();
|
|
9330
9331
|
for (const manifest of listBuiltIns()) kernel.registry.register(manifest);
|
|
9331
9332
|
let cfg;
|
|
9332
9333
|
try {
|
|
9333
|
-
cfg = loadConfig({ scope: "project", cwd: scopeRoot, homedir:
|
|
9334
|
+
cfg = loadConfig({ scope: "project", cwd: scopeRoot, homedir: homedir3, strict }).effective;
|
|
9334
9335
|
} catch (err) {
|
|
9335
9336
|
const message = formatErrorMessage(err);
|
|
9336
9337
|
stderr.write(tx(INIT_TEXTS.configLoadFailure, { message }));
|
|
@@ -10582,9 +10583,9 @@ var PLUGINS_TEXTS = {
|
|
|
10582
10583
|
};
|
|
10583
10584
|
|
|
10584
10585
|
// cli/commands/plugins.ts
|
|
10585
|
-
function resolveSearchPaths2(opts, cwd,
|
|
10586
|
+
function resolveSearchPaths2(opts, cwd, homedir3) {
|
|
10586
10587
|
if (opts.pluginDir) return [resolve17(opts.pluginDir)];
|
|
10587
|
-
const ctx = { cwd, homedir:
|
|
10588
|
+
const ctx = { cwd, homedir: homedir3 };
|
|
10588
10589
|
const project = defaultProjectPluginsDir(ctx);
|
|
10589
10590
|
const user = defaultUserPluginsDir(ctx);
|
|
10590
10591
|
return opts.global ? [user] : [project, user];
|
|
@@ -10899,17 +10900,17 @@ function appendUnknownKindWarnings(out, extractorQualifiedId, applicableKinds, k
|
|
|
10899
10900
|
if (!knownKinds.has(k)) out.push({ extractorQualifiedId, unknownKind: k });
|
|
10900
10901
|
}
|
|
10901
10902
|
}
|
|
10902
|
-
function expandHome(p,
|
|
10903
|
-
if (p === "~") return
|
|
10904
|
-
if (p.startsWith("~/")) return join13(
|
|
10903
|
+
function expandHome(p, homedir3) {
|
|
10904
|
+
if (p === "~") return homedir3;
|
|
10905
|
+
if (p.startsWith("~/")) return join13(homedir3, p.slice(2));
|
|
10905
10906
|
return p;
|
|
10906
10907
|
}
|
|
10907
|
-
function collectExplorationDirWarnings(plugins,
|
|
10908
|
+
function collectExplorationDirWarnings(plugins, homedir3) {
|
|
10908
10909
|
const out = [];
|
|
10909
10910
|
forEachProviderInstance(plugins, ({ id, pluginId, instance }) => {
|
|
10910
10911
|
const dir = instance["explorationDir"];
|
|
10911
10912
|
if (typeof dir !== "string" || dir.length === 0) return;
|
|
10912
|
-
const resolved = expandHome(dir,
|
|
10913
|
+
const resolved = expandHome(dir, homedir3);
|
|
10913
10914
|
if (!existsSync14(resolved)) {
|
|
10914
10915
|
out.push({
|
|
10915
10916
|
providerQualifiedId: qualifiedExtensionId(pluginId, id),
|
|
@@ -13706,17 +13707,13 @@ function normalizeAddress(addr, fallbackHost, fallbackPort) {
|
|
|
13706
13707
|
|
|
13707
13708
|
// cli/i18n/serve.texts.ts
|
|
13708
13709
|
var SERVE_TEXTS = {
|
|
13709
|
-
//
|
|
13710
|
-
//
|
|
13711
|
-
//
|
|
13712
|
-
|
|
13713
|
-
//
|
|
13714
|
-
//
|
|
13715
|
-
//
|
|
13716
|
-
// Both end with the Ctrl+C reminder so the operational tail is
|
|
13717
|
-
// identical regardless of branch.
|
|
13718
|
-
bootOpening: "sm serve: opening http://{{host}}:{{port}}/ in your browser. Press Ctrl+C to stop.\n",
|
|
13719
|
-
bootVisitHint: "sm serve: visit http://{{host}}:{{port}}/ in your browser. Press Ctrl+C to stop.\n",
|
|
13710
|
+
// The boot banner (TTY box / flat-line fallback) is rendered by
|
|
13711
|
+
// `cli/util/serve-banner.ts` rather than templated through `tx` —
|
|
13712
|
+
// ANSI escapes + box-drawing aren't a good fit for the flat
|
|
13713
|
+
// `{{name}}` interpolation surface. The flat-mode strings live in
|
|
13714
|
+
// that helper and stay byte-equivalent to the pre-banner format so
|
|
13715
|
+
// existing pipes / redirects ('listening on <url>' scrapers) don't
|
|
13716
|
+
// break.
|
|
13720
13717
|
// Browser-open failure. Non-fatal — the URL is already printed; the
|
|
13721
13718
|
// user can open it manually.
|
|
13722
13719
|
openFailed: "sm serve: could not auto-open browser ({{message}}). Visit {{url}} manually.\n",
|
|
@@ -13740,6 +13737,146 @@ var SERVE_TEXTS = {
|
|
|
13740
13737
|
shutdown: "sm serve: shutdown complete.\n"
|
|
13741
13738
|
};
|
|
13742
13739
|
|
|
13740
|
+
// cli/util/serve-banner.ts
|
|
13741
|
+
import { homedir as homedir2 } from "os";
|
|
13742
|
+
import { relative as relative5, isAbsolute as isAbsolute6 } from "path";
|
|
13743
|
+
var ESC = {
|
|
13744
|
+
reset: "\x1B[0m",
|
|
13745
|
+
bold: "\x1B[1m",
|
|
13746
|
+
dim: "\x1B[2m",
|
|
13747
|
+
underline: "\x1B[4m",
|
|
13748
|
+
/** 256-color violet (xterm 141). */
|
|
13749
|
+
violet: "\x1B[38;5;141m",
|
|
13750
|
+
/** 256-color green (xterm 42). */
|
|
13751
|
+
green: "\x1B[38;5;42m"
|
|
13752
|
+
};
|
|
13753
|
+
var LOGO_LINES = [
|
|
13754
|
+
" ____ _ _ _ _ __ __ ",
|
|
13755
|
+
" / ___|| | _(_) | | | \\/ | __ _ _ __ ",
|
|
13756
|
+
" \\___ \\| |/ / | | | | |\\/| |/ _` | '_ \\ ",
|
|
13757
|
+
" ___) | <| | | | | | | | (_| | |_) |",
|
|
13758
|
+
" |____/|_|\\_\\_|_|_| |_| |_|\\__,_| .__/ ",
|
|
13759
|
+
" |_| "
|
|
13760
|
+
];
|
|
13761
|
+
var LOGO_WIDTH = 40;
|
|
13762
|
+
function renderBanner(input) {
|
|
13763
|
+
const url = `http://${input.host}:${input.port}`;
|
|
13764
|
+
const dbDisplay = formatDbPath(input.dbPath, input.cwd);
|
|
13765
|
+
const browserLine = input.openBrowser ? "Opening browser\u2026 Press Ctrl+C to stop." : `Visit ${url}/ in your browser. Press Ctrl+C to stop.`;
|
|
13766
|
+
if (!input.isTTY) {
|
|
13767
|
+
return renderFlat({
|
|
13768
|
+
host: input.host,
|
|
13769
|
+
port: input.port,
|
|
13770
|
+
scope: input.scope,
|
|
13771
|
+
dbPath: input.dbPath,
|
|
13772
|
+
openBrowser: input.openBrowser
|
|
13773
|
+
});
|
|
13774
|
+
}
|
|
13775
|
+
return renderFiglet({
|
|
13776
|
+
version: input.version,
|
|
13777
|
+
url,
|
|
13778
|
+
scope: input.scope,
|
|
13779
|
+
dbDisplay,
|
|
13780
|
+
pathDisplay: formatCwdPath(input.cwd),
|
|
13781
|
+
browserLine,
|
|
13782
|
+
colorEnabled: input.colorEnabled
|
|
13783
|
+
});
|
|
13784
|
+
}
|
|
13785
|
+
function resolveColorEnabled(opts) {
|
|
13786
|
+
if (opts.noColorFlag) return false;
|
|
13787
|
+
const noColor = opts.env["NO_COLOR"];
|
|
13788
|
+
if (noColor !== void 0 && noColor !== "") return false;
|
|
13789
|
+
const forceColor = opts.env["FORCE_COLOR"];
|
|
13790
|
+
if (forceColor !== void 0 && forceColor !== "") return true;
|
|
13791
|
+
return opts.isTTY;
|
|
13792
|
+
}
|
|
13793
|
+
function renderFlat(input) {
|
|
13794
|
+
const safeHost = sanitizeForTerminal(input.host);
|
|
13795
|
+
const safeDb = sanitizeForTerminal(input.dbPath);
|
|
13796
|
+
const url = `http://${safeHost}:${input.port}`;
|
|
13797
|
+
const linesOut = [];
|
|
13798
|
+
linesOut.push(`sm serve: listening on ${url} (scope=${input.scope}, db=${safeDb})`);
|
|
13799
|
+
if (input.openBrowser) {
|
|
13800
|
+
linesOut.push(`sm serve: opening ${url}/ in your browser. Press Ctrl+C to stop.`);
|
|
13801
|
+
} else {
|
|
13802
|
+
linesOut.push(`sm serve: visit ${url}/ in your browser. Press Ctrl+C to stop.`);
|
|
13803
|
+
}
|
|
13804
|
+
return linesOut.join("\n") + "\n";
|
|
13805
|
+
}
|
|
13806
|
+
function renderFiglet(input) {
|
|
13807
|
+
const {
|
|
13808
|
+
dimOpen,
|
|
13809
|
+
dimClose,
|
|
13810
|
+
greenUnderline,
|
|
13811
|
+
greenUnderlineClose,
|
|
13812
|
+
violetOpen,
|
|
13813
|
+
violetClose,
|
|
13814
|
+
greenOpen,
|
|
13815
|
+
greenClose
|
|
13816
|
+
} = resolveAnsi(input.colorEnabled);
|
|
13817
|
+
const logoLines = LOGO_LINES.map((line, i) => {
|
|
13818
|
+
const open = i < 3 ? violetOpen : greenOpen;
|
|
13819
|
+
const close = i < 3 ? violetClose : greenClose;
|
|
13820
|
+
return `${open}${line}${close}`;
|
|
13821
|
+
});
|
|
13822
|
+
const versionText = `v${input.version}`;
|
|
13823
|
+
const versionPad = Math.max(0, LOGO_WIDTH - versionText.length);
|
|
13824
|
+
const versionLine = `${" ".repeat(versionPad)}${dimOpen}${versionText}${dimClose}`;
|
|
13825
|
+
const lines = [];
|
|
13826
|
+
lines.push(...logoLines);
|
|
13827
|
+
lines.push("");
|
|
13828
|
+
lines.push(versionLine);
|
|
13829
|
+
lines.push("");
|
|
13830
|
+
lines.push(` ${dimOpen}Server${dimClose} ${greenUnderline}${input.url}${greenUnderlineClose}`);
|
|
13831
|
+
lines.push(` ${dimOpen}Scope${dimClose} ${input.scope}`);
|
|
13832
|
+
lines.push(` ${dimOpen}Path${dimClose} ${input.pathDisplay}`);
|
|
13833
|
+
lines.push(` ${dimOpen}DB${dimClose} ${input.dbDisplay}`);
|
|
13834
|
+
lines.push("");
|
|
13835
|
+
lines.push(` ${dimOpen}${input.browserLine}${dimClose}`);
|
|
13836
|
+
lines.push("");
|
|
13837
|
+
return lines.join("\n") + "\n";
|
|
13838
|
+
}
|
|
13839
|
+
var EMPTY_ANSI = {
|
|
13840
|
+
dimOpen: "",
|
|
13841
|
+
dimClose: "",
|
|
13842
|
+
greenUnderline: "",
|
|
13843
|
+
greenUnderlineClose: "",
|
|
13844
|
+
violetOpen: "",
|
|
13845
|
+
violetClose: "",
|
|
13846
|
+
greenOpen: "",
|
|
13847
|
+
greenClose: ""
|
|
13848
|
+
};
|
|
13849
|
+
var ENABLED_ANSI = {
|
|
13850
|
+
dimOpen: ESC.dim,
|
|
13851
|
+
dimClose: ESC.reset,
|
|
13852
|
+
greenUnderline: `${ESC.green}${ESC.underline}`,
|
|
13853
|
+
greenUnderlineClose: ESC.reset,
|
|
13854
|
+
violetOpen: ESC.violet,
|
|
13855
|
+
violetClose: ESC.reset,
|
|
13856
|
+
greenOpen: ESC.green,
|
|
13857
|
+
greenClose: ESC.reset
|
|
13858
|
+
};
|
|
13859
|
+
function resolveAnsi(colorEnabled) {
|
|
13860
|
+
return colorEnabled ? ENABLED_ANSI : EMPTY_ANSI;
|
|
13861
|
+
}
|
|
13862
|
+
function formatDbPath(dbPath, cwd) {
|
|
13863
|
+
const safe = sanitizeForTerminal(dbPath);
|
|
13864
|
+
if (!isAbsolute6(safe)) return safe;
|
|
13865
|
+
const rel = relative5(cwd, safe);
|
|
13866
|
+
if (rel === "" || rel.startsWith("..") || isAbsolute6(rel)) {
|
|
13867
|
+
return safe;
|
|
13868
|
+
}
|
|
13869
|
+
return rel;
|
|
13870
|
+
}
|
|
13871
|
+
function formatCwdPath(cwd) {
|
|
13872
|
+
const safe = sanitizeForTerminal(cwd);
|
|
13873
|
+
const home = homedir2();
|
|
13874
|
+
if (home && (safe === home || safe.startsWith(`${home}/`))) {
|
|
13875
|
+
return `~${safe.slice(home.length)}`;
|
|
13876
|
+
}
|
|
13877
|
+
return safe;
|
|
13878
|
+
}
|
|
13879
|
+
|
|
13743
13880
|
// cli/commands/serve.ts
|
|
13744
13881
|
var ServeCommand = class extends SmCommand {
|
|
13745
13882
|
static paths = [["serve"]];
|
|
@@ -13892,18 +14029,24 @@ var ServeCommand = class extends SmCommand {
|
|
|
13892
14029
|
);
|
|
13893
14030
|
return ExitCode.Error;
|
|
13894
14031
|
}
|
|
14032
|
+
const stderr = this.context.stderr;
|
|
14033
|
+
const isTTY = stderr.isTTY === true;
|
|
14034
|
+
const colorEnabled = resolveColorEnabled({
|
|
14035
|
+
isTTY,
|
|
14036
|
+
noColorFlag: this.noColor,
|
|
14037
|
+
env: process.env
|
|
14038
|
+
});
|
|
13895
14039
|
this.context.stderr.write(
|
|
13896
|
-
|
|
14040
|
+
renderBanner({
|
|
14041
|
+
version: VERSION,
|
|
13897
14042
|
host: sanitizeForTerminal(handle.address.host),
|
|
13898
14043
|
port: handle.address.port,
|
|
13899
14044
|
scope,
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
host: sanitizeForTerminal(handle.address.host),
|
|
13906
|
-
port: handle.address.port
|
|
14045
|
+
dbPath,
|
|
14046
|
+
cwd: runtimeCtx.cwd,
|
|
14047
|
+
openBrowser: validation.options.open,
|
|
14048
|
+
isTTY,
|
|
14049
|
+
colorEnabled
|
|
13907
14050
|
})
|
|
13908
14051
|
);
|
|
13909
14052
|
if (validation.options.open) {
|