@skill-map/cli 0.39.0 → 0.40.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.
@@ -81,10 +81,6 @@ Then narrate, one file at a time:
81
81
  > - `specCompat` / `catalogCompat`: which `sm` and plugin catalog
82
82
  > version your plugin targets.
83
83
  >
84
- > - `granularity`: `'bundle'` (whole plugin enables/disables as one)
85
- > or `'extension'` (each extension toggles independently). The
86
- > scaffold picks `'bundle'`, the right default for 95% of plugins.
87
- >
88
84
  > - `settings`: user-configurable knobs. The scaffold ships
89
85
  > `keywords`, a `string-list` defaulting to `["TODO", "FIXME"]`.
90
86
  > Browse other input types with `sm plugins slots list`.
@@ -553,6 +553,12 @@ tutorial-state.yml
553
553
  # clean up (sm export, sm db dump).
554
554
  export.*
555
555
  dump.sql
556
+
557
+ # Step 14 spawns a self-contained sub-project under link-validation/hijoA
558
+ # with its own .skill-map/. Excluded here so that, if the tester
559
+ # relaunches `sm` from the tutorial root after Step 14, the nested
560
+ # project does not leak into the main demo graph.
561
+ link-validation/
556
562
  ```
557
563
 
558
564
  ### 4. Generate `tutorial-state.yml`
@@ -612,7 +618,7 @@ long_steps:
612
618
  - id: "11-issues"
613
619
  title: "Issues: broken refs"
614
620
  status: "pending"
615
- verbs: ["sm check", "sm check --analyzers broken-ref",
621
+ verbs: ["sm check", "sm check --analyzers reference-broken",
616
622
  "sm check --json"]
617
623
  - id: "12-plugins"
618
624
  title: "Plugins"
@@ -624,6 +630,10 @@ long_steps:
624
630
  title: "Annotations and the .sm consent prompt"
625
631
  status: "pending"
626
632
  verbs: ["sm sidecar annotate"]
633
+ - id: "14-reference-paths"
634
+ title: "Validate links to folders outside the scan scope"
635
+ status: "pending"
636
+ verbs: ["sm config set scan.referencePaths", "sm scan", "sm check"]
627
637
  findings_file: "./findings.md"
628
638
  ```
629
639
 
@@ -1283,20 +1293,20 @@ captures the notes folder regardless of the catch-all kind.
1283
1293
 
1284
1294
  ### Step 11: Issues: broken refs (~3 min)
1285
1295
 
1286
- `broken-ref` is one of the deterministic rules `sm check` runs.
1296
+ `reference-broken` is one of the deterministic rules `sm check` runs.
1287
1297
  We'll plant one and watch it surface, that's the easiest way to
1288
1298
  internalise that it is an **issue** on a node, NOT a graph
1289
1299
  connector and NOT the same thing as an "orphan".
1290
1300
 
1291
- > ℹ️ `broken-ref` is one of ~16 built-in rules. Others surface
1292
- > different families: `core/reserved-name` (a file shadows a vendor
1293
- > built-in like `/help`), `core/self-loop` (a node links to itself),
1294
- > `core/redundant-target-reference` (two surfaces in the same body
1301
+ > ℹ️ `reference-broken` is one of ~16 built-in rules. Others surface
1302
+ > different families: `core/name-reserved` (a file shadows a vendor
1303
+ > built-in like `/help`), `core/link-self-loop` (a node links to itself),
1304
+ > `core/reference-redundant` (two surfaces in the same body
1295
1305
  > point at the same target), `core/signal-collision` (two extractors
1296
1306
  > detected the SAME byte range with different interpretations, the
1297
1307
  > resolver picked one and the warning explains who lost and why).
1298
1308
  > Same `sm check --analyzers <id>` pattern works for any of them.
1299
- > We will not plant fixtures for the rest, the broken-ref demo
1309
+ > We will not plant fixtures for the rest, the reference-broken demo
1300
1310
  > covers the mechanics.
1301
1311
 
1302
1312
  Ask the tester to **append one bullet** to `notes/todo.md`:
@@ -1312,7 +1322,7 @@ checking:
1312
1322
  ```bash
1313
1323
  sm scan
1314
1324
  sm check
1315
- sm check --analyzers broken-ref
1325
+ sm check --analyzers reference-broken
1316
1326
  sm check --json
1317
1327
  ```
1318
1328
 
@@ -1428,6 +1438,195 @@ goes through silently). On a CI / non-interactive session, pass
1428
1438
  If the tester asks about `sm bump` vs `sm sidecar annotate` vs
1429
1439
  `sm sidecar refresh`, see §Scope clarifications.
1430
1440
 
1441
+ ### Step 14: Validate links to folders outside the scan scope (~4 min)
1442
+
1443
+ **Context**: until now the graph saw only files inside the cwd. In
1444
+ real projects a repo often links to files in a sibling repo (a specs
1445
+ project, a sibling package in a monorepo). Skill-map only scans from
1446
+ its cwd downwards, so a link to `../sibling/file.md` shows up as
1447
+ broken. The fix is to declare the external folders in
1448
+ `scan.referencePaths`, which lets the `reference-broken` analyzer
1449
+ validate path-style links against those extra roots **without
1450
+ indexing their files as nodes**. The folders are checked, not walked
1451
+ as part of the graph.
1452
+
1453
+ **Setup (you, silent)**: write the fixture under the tutorial cwd
1454
+ so both sub-projects are siblings of each other but children of the
1455
+ tutorial root. The agent does this with `Write`, no confirmation
1456
+ beat needed, the tester learns about the files in the next message.
1457
+
1458
+ ```
1459
+ link-validation/
1460
+ ├── hijoA/
1461
+ │ └── note-with-external-link.md ← contains [spec](../hijoB/spec.md)
1462
+ └── hijoB/
1463
+ └── spec.md ← the real target file
1464
+ ```
1465
+
1466
+ `link-validation/hijoA/note-with-external-link.md`:
1467
+ ```markdown
1468
+ ---
1469
+ name: note-with-external-link
1470
+ description: |
1471
+ Demo note that links out to a sibling project (hijoB) sitting
1472
+ next to this one. Used to teach scan.referencePaths.
1473
+ tags: [demo, link-validation]
1474
+ ---
1475
+
1476
+ # Note with external link
1477
+
1478
+ See the [spec](../hijoB/spec.md) for the agreed format.
1479
+ ```
1480
+
1481
+ `link-validation/hijoB/spec.md`:
1482
+ ```markdown
1483
+ ---
1484
+ name: spec
1485
+ description: |
1486
+ Target of the cross-folder link. Lives outside hijoA's scan
1487
+ scope on purpose: that is precisely what scan.referencePaths
1488
+ is designed to bridge.
1489
+ tags: [demo, link-validation]
1490
+ ---
1491
+
1492
+ # External spec
1493
+
1494
+ Anything that hijoA points at lives here.
1495
+ ```
1496
+
1497
+ Once the files are in place, tell the tester:
1498
+
1499
+ > Acabo de dejar dos carpetas hermanas dentro del cwd del tutorial:
1500
+ >
1501
+ > ```
1502
+ > link-validation/
1503
+ > ├── hijoA/
1504
+ > │ └── note-with-external-link.md ← contiene [spec](../hijoB/spec.md)
1505
+ > └── hijoB/
1506
+ > └── spec.md ← el archivo target real
1507
+ > ```
1508
+ >
1509
+ > Para este paso vas a cambiar de carpeta momentáneamente, así `sm`
1510
+ > trata a `hijoA/` como un proyecto separado (cwd nuevo, scope
1511
+ > acotado al subárbol). Al final del paso te indico cómo volver.
1512
+ >
1513
+ > Si quedó algún `sm` corriendo de un paso anterior, ciérralo con
1514
+ > Ctrl+C así el puerto queda libre para el de este paso. Después,
1515
+ > en tu segundo terminal:
1516
+
1517
+ ```bash
1518
+ cd link-validation/hijoA
1519
+ sm init
1520
+ sm check
1521
+ ```
1522
+
1523
+ > Vas a ver un warning del analyzer (regla que detecta problemas)
1524
+ > `reference-broken` apuntando al link `../hijoB/spec.md`. Para
1525
+ > skill-map ese archivo no existe, porque `hijoB/` queda afuera
1526
+ > del scope (alcance) que `sm` está escaneando desde `hijoA/`:
1527
+ > cada proyecto tiene su propio `.skill-map/` y solo recorre
1528
+ > desde su cwd hacia abajo, nunca para "arriba" ni hacia carpetas
1529
+ > hermanas.
1530
+ >
1531
+ > Pásame la salida (o un OK) y seguimos con el fix.
1532
+
1533
+ Wait for confirmation before showing the fix. Mark the warning
1534
+ landed as expected; if the tester reports `✓ No issues` instead,
1535
+ the most likely cause is that they ran `sm check` from the
1536
+ tutorial root by mistake (the root scan still sees both folders).
1537
+ Have them re-check that the cwd of their second terminal is
1538
+ `link-validation/hijoA/` (`pwd`) and rerun.
1539
+
1540
+ After they confirm the broken-ref warning, present the fix:
1541
+
1542
+ > Para resolver el link sin tener que mover `hijoB/` dentro de
1543
+ > `hijoA/`, agregas `../hijoB` al setting `scan.referencePaths`.
1544
+ > Le dice al analyzer "si un link path-style cae acá, valídalo
1545
+ > también contra estas carpetas extra". Los archivos NO se
1546
+ > agregan al grafo (no aparecen como nodos), solo se consultan
1547
+ > para resolver referencias salientes desde `hijoA/`.
1548
+ >
1549
+ > En tu segundo terminal (todavía dentro de `link-validation/hijoA/`):
1550
+
1551
+ ```bash
1552
+ sm config set scan.referencePaths '["../hijoB"]' --yes
1553
+ sm scan
1554
+ sm check
1555
+ ```
1556
+
1557
+ > El flag `--yes` confirma el privacy gate (control de privacidad):
1558
+ > estás autorizando que skill-map lea archivos fuera del project
1559
+ > root, así que pide tu OK explícito. Sin `--yes` el verb se aborta
1560
+ > y te pregunta en interactivo. Después del scan, `sm check`
1561
+ > debería imprimir `✓ No issues`: el warning desapareció y `hijoB/`
1562
+ > sigue sin entrar al grafo como nodo.
1563
+ >
1564
+ > Pásame la salida y vemos cómo quedó persistido.
1565
+
1566
+ Wait for confirmation. After they paste the clean `sm check`
1567
+ output, show where the value lives on disk:
1568
+
1569
+ > Mira cómo quedó guardado el cambio:
1570
+
1571
+ ```bash
1572
+ cat .skill-map/settings.local.json
1573
+ ```
1574
+
1575
+ > Vas a ver algo así:
1576
+ >
1577
+ > ```json
1578
+ > {
1579
+ > "scan": {
1580
+ > "referencePaths": ["../hijoB"]
1581
+ > }
1582
+ > }
1583
+ > ```
1584
+ >
1585
+ > Vive en `settings.local.json` (gitignored, no viaja por git),
1586
+ > NO en el `settings.json` que sí se commitea. La razón: los
1587
+ > paths a carpetas hermanas suelen depender del layout local de
1588
+ > tu máquina (no todos los contribuidores tienen el mismo árbol
1589
+ > de proyectos en disco), por eso skill-map fuerza este setting
1590
+ > al layer local.
1591
+
1592
+ Now the UI half. The tester needs `sm` running with `hijoA/` as
1593
+ cwd to see the matching panel:
1594
+
1595
+ > Lo mismo desde la UI. En el mismo terminal, levanta el servidor
1596
+ > desde `hijoA/`:
1597
+
1598
+ ```bash
1599
+ sm
1600
+ ```
1601
+
1602
+ > Abre la URL que imprime el comando en el browser. Arriba a la
1603
+ > derecha está el icono ⚙ (gear), haz clic ahí, en el modal ve al
1604
+ > tab **Project** y baja hasta la sección **Folders for link
1605
+ > validation**. Vas a ver `../hijoB` listado, con botones para
1606
+ > agregar o sacar paths. La CLI y la UI escriben al mismo archivo:
1607
+ > si agregas uno desde la UI, aparece en el JSON, y viceversa.
1608
+ >
1609
+ > Cuando termines de mirar, Ctrl+C en el terminal para cerrar el
1610
+ > servidor.
1611
+
1612
+ Wait for confirmation that they saw the panel and closed the
1613
+ server. If the `sm` launch fails with a port-in-use error, an old
1614
+ `sm` is still bound to the default port from an earlier step;
1615
+ follow the §Edge cases recipe (`sm serve --port 4243`).
1616
+
1617
+ Finally, return the tester to the tutorial root so any wrap-up
1618
+ work runs against the original cwd:
1619
+
1620
+ > Último detalle: vuelve al cwd raíz del tutorial:
1621
+
1622
+ ```bash
1623
+ cd ../..
1624
+ ```
1625
+
1626
+ > Confirma cuando estés de vuelta.
1627
+
1628
+ Mark `14-reference-paths: done`.
1629
+
1431
1630
  ---
1432
1631
 
1433
1632
  ## Scope clarifications (on demand)
@@ -1460,24 +1659,30 @@ extension table to spot the one you queried.
1460
1659
 
1461
1660
  ### IDs for `plugins disable` / `plugins enable`
1462
1661
 
1463
- Those verbs accept either a **bundle id** (e.g. `claude`, which
1464
- toggles every Claude extension at once) or a **qualified extension
1465
- id** `<bundle>/<ext-id>` (e.g. `core/external-url-counter`). The
1466
- display format you see in `plugins list`
1662
+ Those verbs accept either a **qualified extension id**
1663
+ `<bundle>/<ext-id>` (e.g. `core/external-url-counter`,
1664
+ `claude/at-directive`) or a **bare bundle id** (e.g. `claude`,
1665
+ `core`) which the CLI treats as a macro that fans the toggle out
1666
+ across every extension inside the bundle. The display format you
1667
+ see in `plugins list`
1467
1668
  (`extractor:core/external-url-counter@1.0.0`) includes the kind
1468
1669
  prefix and the version for readability, strip both when passing
1469
- the id to `disable` / `enable`. Per-extension toggles only work on
1470
- extension-granularity bundles like `core`; the `claude` bundle is
1471
- bundle-granularity and only accepts the bundle id.
1670
+ the id to `disable` / `enable`.
1671
+
1672
+ Single-extension bundles (`openai`, `antigravity`,
1673
+ `agent-skills`) flip without prompting because the macro is a
1674
+ 1-1 mapping. Multi-extension bundles (`claude`, `core`,
1675
+ multi-extension user plugins) need `--yes` OR an interactive TTY
1676
+ confirm; pipe / CI contexts always need `--yes` to avoid an
1677
+ accidental cascade.
1472
1678
 
1473
1679
  **Multiple ids in one call**: both verbs accept any number of ids
1474
1680
  in a single invocation, e.g. `sm plugins disable antigravity openai
1475
- agent-skills` or `sm plugins enable claude core/external-url-counter`.
1476
- Batches are all-or-nothing: if any id is unknown or
1477
- granularity-mismatched the entire call aborts before any
1478
- `config_plugins` write, so the user never lands in a partial state.
1479
- Repeated ids are deduped; locked plugins inside a batch are
1480
- silently skipped (matching `--all` semantics).
1681
+ agent-skills` or `sm plugins enable claude/at-directive core/external-url-counter`.
1682
+ Batches are all-or-nothing: if any id is unknown the entire call
1683
+ aborts before any `config_plugins` write, so the user never lands
1684
+ in a partial state. Repeated ids are deduped; locked extensions
1685
+ inside a batch are silently skipped (matching `--all` semantics).
1481
1686
 
1482
1687
  ### Reserved names (e.g. `commands/help.md`)
1483
1688
 
@@ -1526,14 +1731,59 @@ sm tutorial master
1526
1731
  > That drops `sm-master.md` in the cwd. Then load it from your
1527
1732
  > agent (e.g. `ejecutá @sm-master.md` in Claude Code, or the
1528
1733
  > equivalent `@`-mention in Antigravity CLI) and the deep-dive starts.
1529
- >
1530
- > To delete everything THIS tutorial left behind, if the cwd was a
1531
- > dedicated dir:
1734
+
1735
+ **Cleanup, choose ONE of the two paths**. Decide programmatically
1736
+ before showing the closing message: list the cwd (`ls -A <cwd>`)
1737
+ and compare against the set of paths this tutorial owns. If the
1738
+ ONLY entries are tutorial-owned, the cwd looks dedicated and the
1739
+ bulk path is safe. If there are unrelated entries (git repo,
1740
+ unrelated source, the tester's day-to-day work), use the per-file
1741
+ path instead. **Never recommend `rm -rf <cwd>` when the cwd
1742
+ contains any path skill-map did not put there**, the tester might
1743
+ be running the tutorial inside their actual work dir (a frequent
1744
+ finding from real sessions).
1745
+
1746
+ If the cwd is dedicated, render:
1747
+
1748
+ > To delete everything THIS tutorial left behind:
1532
1749
  >
1533
1750
  > cd ~ && rm -rf <cwd>
1534
1751
  >
1535
1752
  > Thanks for testing skill-map!
1536
1753
 
1754
+ If the cwd is NOT dedicated, render the exact per-file list
1755
+ (substituting `<provider_dir>` per the saved `tutorial.provider`
1756
+ and dropping rows the provider did not create, same shape as
1757
+ the "start over" branch below):
1758
+
1759
+ > Your cwd has unrelated files, so removing it would also delete
1760
+ > work that is not mine. To delete only what THIS tutorial left
1761
+ > behind, remove these specific paths from `<cwd>`:
1762
+ >
1763
+ > ```
1764
+ > tutorial-state.yml
1765
+ > findings.md
1766
+ > .skillmapignore
1767
+ > .skill-map/
1768
+ > <provider_dir>/agents/demo-agent.md (claude only)
1769
+ > <provider_dir>/commands/demo-command.md (claude only)
1770
+ > <provider_dir>/skills/demo-skill/ (both providers)
1771
+ > notes/todo.md
1772
+ > notes/demo-guideline.md
1773
+ > notes/private-credentials.md
1774
+ > link-validation/ (if Step 14 ran)
1775
+ > export.* (if present)
1776
+ > dump.sql (if present)
1777
+ > ```
1778
+ >
1779
+ > Do NOT `rm -rf <provider_dir>/` or `notes/` as directories,
1780
+ > remove only the tutorial-owned files inside in case you have
1781
+ > unrelated files there. `link-validation/` IS safe to remove as
1782
+ > a whole directory, the agent created it from scratch in Step 14
1783
+ > and nothing else lives inside it.
1784
+ >
1785
+ > Thanks for testing skill-map!
1786
+
1537
1787
  ## Resume / restart
1538
1788
 
1539
1789
  When the skill is re-invoked and `tutorial-state.yml` already exists in
@@ -1582,6 +1832,7 @@ anything**:
1582
1832
  > notes/todo.md
1583
1833
  > notes/demo-guideline.md
1584
1834
  > notes/private-credentials.md
1835
+ > link-validation/ (if Step 14 ran)
1585
1836
  > export.* (if present)
1586
1837
  > dump.sql (if present)
1587
1838
  > ```
@@ -1600,8 +1851,10 @@ anything**:
1600
1851
  `rmdir` the per-provider subdirs that actually exist
1601
1852
  (`<provider_dir>/agents`, `<provider_dir>/commands`,
1602
1853
  `<provider_dir>/skills`), then `notes/` and `<provider_dir>/`,
1603
- each one only if empty (silent failure if not). Then start
1604
- everything from pre-flight.
1854
+ each one only if empty (silent failure if not). `link-validation/`
1855
+ IS safe to remove recursively when present, the agent created it
1856
+ from scratch in Step 14 and nothing else lives inside it. Then
1857
+ start everything from pre-flight.
1605
1858
 
1606
1859
  ## Edge cases
1607
1860