@vltpkg/query 1.0.0-rc.32 → 1.0.0-rc.34

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.
Files changed (215) hide show
  1. package/dist/index.js +10 -6
  2. package/dist/parser.js +2 -1
  3. package/dist/pseudo/hostname.js +3 -1
  4. package/dist/pseudo/malware.d.ts +3 -16
  5. package/dist/pseudo/malware.js +11 -171
  6. package/dist/pseudo/scripts.js +1 -1
  7. package/dist/pseudo/vuln.d.ts +22 -0
  8. package/dist/pseudo/vuln.js +220 -0
  9. package/dist/pseudo.js +3 -3
  10. package/dist/types.d.ts +3 -2
  11. package/package.json +19 -10
  12. package/skills/dss-query/REFERENCE.md +123 -0
  13. package/skills/dss-query/SKILL.md +190 -0
  14. package/skills/dss-query/evals/README.md +79 -0
  15. package/skills/dss-query/evals/evals.json +89 -0
  16. package/skills/dss-query/evals/grade.mjs +480 -0
  17. package/src/attribute.ts +186 -0
  18. package/src/combinator.ts +132 -0
  19. package/src/id.ts +46 -0
  20. package/src/index.ts +620 -0
  21. package/src/parser.ts +122 -0
  22. package/src/pseudo/abandoned.ts +9 -0
  23. package/src/pseudo/attr.ts +92 -0
  24. package/src/pseudo/built.ts +19 -0
  25. package/src/pseudo/confused.ts +29 -0
  26. package/src/pseudo/cve.ts +93 -0
  27. package/src/pseudo/cwe.ts +97 -0
  28. package/src/pseudo/debug.ts +9 -0
  29. package/src/pseudo/deprecated.ts +9 -0
  30. package/src/pseudo/dev.ts +18 -0
  31. package/src/pseudo/diff.ts +90 -0
  32. package/src/pseudo/dist.ts +144 -0
  33. package/src/pseudo/dynamic.ts +9 -0
  34. package/src/pseudo/empty.ts +15 -0
  35. package/src/pseudo/entropic.ts +9 -0
  36. package/src/pseudo/env.ts +6 -0
  37. package/src/pseudo/eval.ts +9 -0
  38. package/src/pseudo/fs.ts +9 -0
  39. package/src/pseudo/helpers.ts +106 -0
  40. package/src/pseudo/host.ts +111 -0
  41. package/src/pseudo/hostname.ts +156 -0
  42. package/src/pseudo/license.ts +134 -0
  43. package/src/pseudo/link.ts +30 -0
  44. package/src/pseudo/malware.ts +41 -0
  45. package/src/pseudo/minified.ts +9 -0
  46. package/src/pseudo/missing.ts +16 -0
  47. package/src/pseudo/native.ts +9 -0
  48. package/src/pseudo/network.ts +9 -0
  49. package/src/pseudo/obfuscated.ts +9 -0
  50. package/src/pseudo/optional.ts +18 -0
  51. package/src/pseudo/outdated.ts +305 -0
  52. package/src/pseudo/overridden.ts +20 -0
  53. package/src/pseudo/path.ts +146 -0
  54. package/src/pseudo/peer.ts +18 -0
  55. package/src/pseudo/prerelease.ts +47 -0
  56. package/src/pseudo/private.ts +19 -0
  57. package/src/pseudo/prod.ts +18 -0
  58. package/src/pseudo/published.ts +248 -0
  59. package/src/pseudo/registry.ts +29 -0
  60. package/src/pseudo/root.ts +19 -0
  61. package/src/pseudo/scanned.ts +20 -0
  62. package/src/pseudo/score.ts +186 -0
  63. package/src/pseudo/scripts.ts +54 -0
  64. package/src/pseudo/semver.ts +320 -0
  65. package/src/pseudo/severity.ts +231 -0
  66. package/src/pseudo/shell.ts +9 -0
  67. package/src/pseudo/shrinkwrap.ts +9 -0
  68. package/src/pseudo/spec.ts +131 -0
  69. package/src/pseudo/squat.ts +225 -0
  70. package/src/pseudo/suspicious.ts +9 -0
  71. package/src/pseudo/tracker.ts +9 -0
  72. package/src/pseudo/trivial.ts +9 -0
  73. package/src/pseudo/type.ts +26 -0
  74. package/src/pseudo/undesirable.ts +9 -0
  75. package/src/pseudo/unknown.ts +9 -0
  76. package/src/pseudo/unmaintained.ts +9 -0
  77. package/src/pseudo/unpopular.ts +9 -0
  78. package/src/pseudo/unstable.ts +9 -0
  79. package/src/pseudo/vuln.ts +273 -0
  80. package/src/pseudo/workspace.ts +22 -0
  81. package/src/pseudo.ts +413 -0
  82. package/src/types.ts +165 -0
  83. package/tap-snapshots/test/attribute.ts.test.cjs +304 -0
  84. package/tap-snapshots/test/combinator.ts.test.cjs +333 -0
  85. package/tap-snapshots/test/id.ts.test.cjs +118 -0
  86. package/tap-snapshots/test/parser.ts.test.cjs +344 -0
  87. package/tap-snapshots/test/pseudo/abandoned.ts.test.cjs +18 -0
  88. package/tap-snapshots/test/pseudo/attr.ts.test.cjs +161 -0
  89. package/tap-snapshots/test/pseudo/built.ts.test.cjs +70 -0
  90. package/tap-snapshots/test/pseudo/confused.ts.test.cjs +32 -0
  91. package/tap-snapshots/test/pseudo/cve.ts.test.cjs +49 -0
  92. package/tap-snapshots/test/pseudo/cwe.ts.test.cjs +49 -0
  93. package/tap-snapshots/test/pseudo/debug.ts.test.cjs +18 -0
  94. package/tap-snapshots/test/pseudo/deprecated.ts.test.cjs +18 -0
  95. package/tap-snapshots/test/pseudo/dist.ts.test.cjs +30 -0
  96. package/tap-snapshots/test/pseudo/dynamic.ts.test.cjs +18 -0
  97. package/tap-snapshots/test/pseudo/empty.ts.test.cjs +50 -0
  98. package/tap-snapshots/test/pseudo/entropic.ts.test.cjs +18 -0
  99. package/tap-snapshots/test/pseudo/env.ts.test.cjs +18 -0
  100. package/tap-snapshots/test/pseudo/eval.ts.test.cjs +18 -0
  101. package/tap-snapshots/test/pseudo/fs.ts.test.cjs +18 -0
  102. package/tap-snapshots/test/pseudo/helpers.ts.test.cjs +18 -0
  103. package/tap-snapshots/test/pseudo/hostname.ts.test.cjs +148 -0
  104. package/tap-snapshots/test/pseudo/license.ts.test.cjs +41 -0
  105. package/tap-snapshots/test/pseudo/link.ts.test.cjs +36 -0
  106. package/tap-snapshots/test/pseudo/malware.ts.test.cjs +22 -0
  107. package/tap-snapshots/test/pseudo/minified.ts.test.cjs +18 -0
  108. package/tap-snapshots/test/pseudo/missing.ts.test.cjs +30 -0
  109. package/tap-snapshots/test/pseudo/native.ts.test.cjs +18 -0
  110. package/tap-snapshots/test/pseudo/network.ts.test.cjs +18 -0
  111. package/tap-snapshots/test/pseudo/obfuscated.ts.test.cjs +18 -0
  112. package/tap-snapshots/test/pseudo/outdated.ts.test.cjs +130 -0
  113. package/tap-snapshots/test/pseudo/overridden.ts.test.cjs +75 -0
  114. package/tap-snapshots/test/pseudo/prerelease.ts.test.cjs +101 -0
  115. package/tap-snapshots/test/pseudo/private.ts.test.cjs +38 -0
  116. package/tap-snapshots/test/pseudo/published.ts.test.cjs +171 -0
  117. package/tap-snapshots/test/pseudo/registry.ts.test.cjs +68 -0
  118. package/tap-snapshots/test/pseudo/root.ts.test.cjs +24 -0
  119. package/tap-snapshots/test/pseudo/scanned.ts.test.cjs +18 -0
  120. package/tap-snapshots/test/pseudo/score.ts.test.cjs +239 -0
  121. package/tap-snapshots/test/pseudo/scripts.ts.test.cjs +61 -0
  122. package/tap-snapshots/test/pseudo/semver.ts.test.cjs +575 -0
  123. package/tap-snapshots/test/pseudo/severity.ts.test.cjs +95 -0
  124. package/tap-snapshots/test/pseudo/shell.ts.test.cjs +18 -0
  125. package/tap-snapshots/test/pseudo/shrinkwrap.ts.test.cjs +18 -0
  126. package/tap-snapshots/test/pseudo/spec.ts.test.cjs +148 -0
  127. package/tap-snapshots/test/pseudo/squat.ts.test.cjs +129 -0
  128. package/tap-snapshots/test/pseudo/suspicious.ts.test.cjs +18 -0
  129. package/tap-snapshots/test/pseudo/tracker.ts.test.cjs +18 -0
  130. package/tap-snapshots/test/pseudo/trivial.ts.test.cjs +18 -0
  131. package/tap-snapshots/test/pseudo/type.ts.test.cjs +51 -0
  132. package/tap-snapshots/test/pseudo/undesirable.ts.test.cjs +18 -0
  133. package/tap-snapshots/test/pseudo/unknown.ts.test.cjs +18 -0
  134. package/tap-snapshots/test/pseudo/unmaintained.ts.test.cjs +18 -0
  135. package/tap-snapshots/test/pseudo/unpopular.ts.test.cjs +18 -0
  136. package/tap-snapshots/test/pseudo/unstable.ts.test.cjs +18 -0
  137. package/tap-snapshots/test/pseudo/vuln.ts.test.cjs +208 -0
  138. package/tap-snapshots/test/pseudo/vulnerable.ts.test.cjs +20 -0
  139. package/tap-snapshots/test/pseudo/workspace.ts.test.cjs +19 -0
  140. package/tap-snapshots/test/pseudo.ts.test.cjs +1247 -0
  141. package/test/attribute.ts +266 -0
  142. package/test/combinator.ts +168 -0
  143. package/test/fixtures/graph.ts +999 -0
  144. package/test/fixtures/selector.ts +103 -0
  145. package/test/fixtures/types.ts +7 -0
  146. package/test/id.ts +102 -0
  147. package/test/index.ts +1000 -0
  148. package/test/parser.ts +117 -0
  149. package/test/pseudo/abandoned.ts +98 -0
  150. package/test/pseudo/attr.ts +298 -0
  151. package/test/pseudo/built.ts +214 -0
  152. package/test/pseudo/confused.ts +160 -0
  153. package/test/pseudo/cve.ts +249 -0
  154. package/test/pseudo/cwe.ts +255 -0
  155. package/test/pseudo/debug.ts +98 -0
  156. package/test/pseudo/deprecated.ts +98 -0
  157. package/test/pseudo/dev.ts +61 -0
  158. package/test/pseudo/diff.ts +417 -0
  159. package/test/pseudo/dist.ts +215 -0
  160. package/test/pseudo/dynamic.ts +98 -0
  161. package/test/pseudo/empty.ts +108 -0
  162. package/test/pseudo/entropic.ts +101 -0
  163. package/test/pseudo/env.ts +98 -0
  164. package/test/pseudo/eval.ts +98 -0
  165. package/test/pseudo/fs.ts +98 -0
  166. package/test/pseudo/helpers.ts +370 -0
  167. package/test/pseudo/host-context.ts +276 -0
  168. package/test/pseudo/hostname.ts +314 -0
  169. package/test/pseudo/license.ts +265 -0
  170. package/test/pseudo/link.ts +94 -0
  171. package/test/pseudo/malware.ts +184 -0
  172. package/test/pseudo/minified.ts +98 -0
  173. package/test/pseudo/missing.ts +111 -0
  174. package/test/pseudo/native.ts +98 -0
  175. package/test/pseudo/network.ts +98 -0
  176. package/test/pseudo/obfuscated.ts +98 -0
  177. package/test/pseudo/optional.ts +73 -0
  178. package/test/pseudo/outdated.ts +331 -0
  179. package/test/pseudo/overridden.ts +317 -0
  180. package/test/pseudo/path.ts +680 -0
  181. package/test/pseudo/peer.ts +101 -0
  182. package/test/pseudo/prerelease.ts +279 -0
  183. package/test/pseudo/private.ts +108 -0
  184. package/test/pseudo/prod.ts +61 -0
  185. package/test/pseudo/published.ts +557 -0
  186. package/test/pseudo/registry.ts +122 -0
  187. package/test/pseudo/root.ts +66 -0
  188. package/test/pseudo/scanned.ts +78 -0
  189. package/test/pseudo/score.ts +591 -0
  190. package/test/pseudo/scripts.ts +294 -0
  191. package/test/pseudo/semver.ts +822 -0
  192. package/test/pseudo/severity.ts +310 -0
  193. package/test/pseudo/shell.ts +98 -0
  194. package/test/pseudo/shrinkwrap.ts +98 -0
  195. package/test/pseudo/spec.ts +525 -0
  196. package/test/pseudo/squat.ts +565 -0
  197. package/test/pseudo/suspicious.ts +98 -0
  198. package/test/pseudo/tracker.ts +98 -0
  199. package/test/pseudo/trivial.ts +98 -0
  200. package/test/pseudo/type.ts +105 -0
  201. package/test/pseudo/undesirable.ts +98 -0
  202. package/test/pseudo/unknown.ts +98 -0
  203. package/test/pseudo/unmaintained.ts +98 -0
  204. package/test/pseudo/unpopular.ts +98 -0
  205. package/test/pseudo/unstable.ts +98 -0
  206. package/test/pseudo/vuln.ts +625 -0
  207. package/test/pseudo/vulnerable.ts +137 -0
  208. package/test/pseudo/workspace.ts +111 -0
  209. package/test/pseudo.ts +558 -0
  210. package/tsconfig.json +3 -0
  211. package/tsconfig.publish.json +19 -0
  212. package/tsconfig.publish.tsbuildinfo +1 -0
  213. package/typedoc.mjs +2 -0
  214. package/dist/pseudo/vulnerable.d.ts +0 -8
  215. package/dist/pseudo/vulnerable.js +0 -17
@@ -0,0 +1,123 @@
1
+ # DSS Reference
2
+
3
+ Compiled from https://docs.vlt.io/cli/selectors/ (source:
4
+ `www/docs/src/content/docs/cli/selectors/`). When in doubt, check
5
+ those docs — they are canonical.
6
+
7
+ ## Attribute selectors
8
+
9
+ Match against `package.json` fields.
10
+
11
+ | Selector | Meaning |
12
+ | ---------------- | ------------------------------------------------ |
13
+ | `[attr]` | has the property |
14
+ | `[attr=value]` | equals |
15
+ | `[attr^=value]` | starts with |
16
+ | `[attr$=value]` | ends with |
17
+ | `[attr*=value]` | contains |
18
+ | `[attr~=value]` | whitespace-separated list contains |
19
+ | `[attr\|=value]` | equals value or starts with `value-` |
20
+ | `[attr=value i]` | case-insensitive (`s` = case-sensitive, default) |
21
+
22
+ Nested fields (e.g. `engines.node`) need `:attr()`:
23
+ `:attr(engines, [node])`,
24
+ `:attr(peerDependenciesMeta, foo, [optional=true])`.
25
+
26
+ `#foo` is shorthand for `[name=foo]`.
27
+
28
+ ## Combinators
29
+
30
+ | Combinator | Meaning |
31
+ | ---------- | -------------------------------------------------------------------- |
32
+ | `A > B` | B is a **direct** dependency of A (chain for depth: `:root > * > *`) |
33
+ | `A B` | B is a direct **or transitive** dependency of A |
34
+ | `A ~ B` | B shares a parent with A (sibling) |
35
+
36
+ ## Pseudo-states (no arguments)
37
+
38
+ Graph structure:
39
+
40
+ | Selector | Matches |
41
+ | ------------ | --------------------------------------- |
42
+ | `:root` | top-level package.json node |
43
+ | `:project` | root + all workspaces ("your code") |
44
+ | `:workspace` | workspaces from vlt.json |
45
+ | `:scope` | current selector scope (with `--scope`) |
46
+
47
+ Dependency type:
48
+
49
+ | Selector | Matches |
50
+ | ---------------------------------------- | ------------------------------------------------------ |
51
+ | `:prod` / `:dev` / `:optional` / `:peer` | by dependency type |
52
+ | `:missing` | declared but not installed (**edges only, not nodes**) |
53
+ | `:overridden` | has an override applied |
54
+
55
+ Package properties:
56
+
57
+ | Selector | Matches |
58
+ | ------------- | -------------------------------------------- |
59
+ | `:private` | `"private": true` |
60
+ | `:empty` | no dependencies |
61
+ | `:link` | linked packages |
62
+ | `:prerelease` | version has prerelease part (`1.0.0-beta.1`) |
63
+ | `:built` | built during reify |
64
+ | `:scanned` | has Socket security metadata |
65
+
66
+ ## Pseudo-classes (take arguments)
67
+
68
+ | Selector | Meaning | Example |
69
+ | ------------------- | --------------------------------------- | ---------------------------------------------- |
70
+ | `:attr(...)` | nested package.json property | `:attr(engines, [node])` |
71
+ | `:dist(tag)` | registry dist-tag | `:dist(latest)` |
72
+ | `:has(sel)` | has matching descendant | `:has(.peer[name=react])` |
73
+ | `:host(name)` | switch graph context to another project | `:host(local) :malware` |
74
+ | `:is(a, b)` | any of (forgiving list) | `:is([name=a], [name=b])` |
75
+ | `:not(sel)` | negation | `:not([license=MIT])` |
76
+ | `:outdated(kind?)` | newer version exists | `:outdated(major)` |
77
+ | `:published(range)` | by publish date | `:published(">2024")` |
78
+ | `:semver(range)` | semver comparison on installed version | `:semver(^1.0.0)` |
79
+ | `:spec(spec)` | by declared specifier (edge) | `:spec(^1.0.0)` |
80
+ | `:path(glob)` | workspace/file packages by path | `:path("packages/**")` |
81
+ | `:type(kind)` | package type | `:type(git)`, `:type(registry)`, `:type(file)` |
82
+ | `:diff(ref)` | files changed vs git ref | `:diff(main)` |
83
+ | `:hostname(host)` | upstream hostname | `:hostname(github.com)` |
84
+ | `:registry(name)` | configured registry name | `:registry(npm)` |
85
+
86
+ ## Security insights (Socket-powered, network call)
87
+
88
+ Severity args accept names or numbers (`critical`/`0`, `high`/`1`,
89
+ `medium`/`2`, `low`/`3`) and comparators: `:severity(">=medium")`.
90
+
91
+ Threats: `:malware` (binary, no params), `:squat(sev?)`,
92
+ `:suspicious`, `:confused`.
93
+
94
+ Vulnerabilities: `:vuln(sev?)` (alias `:vulnerable`),
95
+ `:cve(CVE-2023-1234)`, `:cve(*)`, `:cwe(CWE-79)`, `:severity(level)`.
96
+ `:vuln` without params matches severity ≥ medium; `:vuln(critical)`
97
+ exact-matches; `:vuln(">=high")` uses comparators. Also matches alerts
98
+ carrying a `cveId` prop.
99
+
100
+ Licensing: `:license(type)` — types: `unlicensed`, `misc`,
101
+ `restricted`, `ambiguous`, `copyleft`, `unknown`, `none`, `exception`.
102
+
103
+ Code behavior: `:eval`, `:network`, `:fs`, `:env`, `:shell`,
104
+ `:scripts` (install scripts), `:debug`, `:dynamic`.
105
+
106
+ Obfuscation: `:obfuscated`, `:minified`, `:entropic`, `:native`,
107
+ `:shrinkwrap`.
108
+
109
+ Health: `:deprecated`, `:unmaintained` (5+ years stale), `:unpopular`,
110
+ `:trivial` (<10 LOC), `:abandoned`, `:unknown`, `:unstable`.
111
+
112
+ Other: `:tracker` (telemetry), `:undesirable`, `:score(rate, kind?)` —
113
+ kinds: `overall` (default), `license`, `maintenance`, `quality`,
114
+ `supplyChain`, `vulnerability`; e.g. `:score("<=0.5", "maintenance")`.
115
+
116
+ ## Audit query starters
117
+
118
+ ```bash
119
+ vlt query ':malware, :vuln(critical), :cve(*), :obfuscated' # critical issues
120
+ vlt query ':abandoned, :unmaintained, :unknown' # supply chain risk
121
+ vlt query ':license(copyleft), :license(unlicensed)' # license compliance
122
+ vlt query ':eval, :shell, :network, :fs' # behavior audit
123
+ ```
@@ -0,0 +1,190 @@
1
+ ---
2
+ name: dss-query
3
+ description:
4
+ Explain and compose vlt Dependency Selector Syntax (DSS) queries —
5
+ CSS-selector-like strings for filtering packages in a dependency
6
+ graph, including Socket-powered security auditing. Use when the user
7
+ asks about DSS, `vlt query`, dependency selectors, wants to
8
+ find/filter packages (e.g. "find outdated deps", "select all
9
+ workspaces"), or wants to security-audit dependencies ("which
10
+ packages have CVEs", "check for malware/typosquats", "what can run
11
+ shell commands or hit the network").
12
+ allowed-tools: [Read, Grep]
13
+ context: fork
14
+ ---
15
+
16
+ # DSS Query Helper
17
+
18
+ Run DSS queries via `vlt query '<selector>'`.
19
+
20
+ ## Response style
21
+
22
+ **Be concise, but teach one thing.** Give the query first, then a
23
+ one-line explanation. No long preambles, no exhaustive alternatives —
24
+ but don't dead-end either: close with a short **Examples** tail of 1–2
25
+ adjacent queries (one step broader, narrower, or a sibling concept).
26
+ Users learn DSS through adjacent examples, and each answer is a chance
27
+ to build that intuition cheaply. Keep the tail bare — a query plus a
28
+ few-word label, no surrounding prose; the whole answer should still
29
+ read in seconds.
30
+
31
+ Two more rules:
32
+
33
+ - **Gloss jargon in place.** Readers may not know DSS terms — on first
34
+ use, give a 2–4 word parenthetical instead of assuming: "`:root`
35
+ anchors the match (starts it) at your project root", "`>` (direct
36
+ deps only)". Never a terminology lecture, just the aside.
37
+ - **End with a docs deep link** so the answer has a "learn more" exit.
38
+ Use the verified map in [Full reference](#full-reference) below —
39
+ link the section relevant to the query, not the docs homepage.
40
+
41
+ Example answer shape:
42
+
43
+ > ```
44
+ > vlt query ':root > :outdated(major)'
45
+ > ```
46
+ >
47
+ > Direct dependencies with a newer major version available.
48
+ >
49
+ > Examples:
50
+ >
51
+ > - `vlt query ':root > :outdated'` — any newer version, not just
52
+ > major
53
+ > - `vlt query ':outdated(major)'` — whole graph, not just direct
54
+ >
55
+ > Add `--view=json` for machine-readable output. More:
56
+ > <https://docs.vlt.io/cli/selectors/>
57
+
58
+ ## Workflow
59
+
60
+ 1. **Clarify intent first** if the goal is ambiguous — ask 1–2 short
61
+ questions, never a survey. Pin down:
62
+ - **What to match**: which packages? Whole graph or just direct
63
+ deps? Everywhere, or only under a specific workspace/package?
64
+ - **Expected outcome**: what does the result set look like if the
65
+ query works — a handful of known offenders, every workspace, one
66
+ package? What will they do with it (audit, remove, report)? Skip
67
+ this when the request is already specific — don't interrogate
68
+ someone who said "direct deps of root with an MIT license".
69
+ 2. **Compose the query** with the steps below. Then:
70
+ - Show the query.
71
+ - Explain each piece in one short sentence.
72
+ - State what the results should look like, so the user can tell
73
+ whether it worked.
74
+ - Close with the **Examples** tail (1–2 adjacent queries).
75
+ 3. **"What does this query do?"**: decompose left to right, one line
76
+ per segment. Offer 1–2 example queries the user could try next.
77
+ 4. **Correcting a mistaken query?** Add one line on _why_ it was
78
+ wrong, not just the fix — e.g. combinators point from dependent to
79
+ dependency (parent `>` child), so `#x > *` selects x's
80
+ dependencies, not its dependents. The rule transfers; the fix alone
81
+ doesn't.
82
+ 5. **Uncertain match?** Offer to run it: `vlt query '<selector>'`
83
+ (always single-quote the selector in the shell). Output format:
84
+ `--view=human|json|mermaid|svg|png|count` — defaults to human (json
85
+ when piped).
86
+ 6. **Iterate**: compare results against the expected outcome from step
87
+ 1 — too broad/narrow means refine one piece at a time (add a
88
+ combinator, a pseudo-state, or `:not()`).
89
+
90
+ ## Composing a query from a goal
91
+
92
+ Build left to right, in this order — each step is optional:
93
+
94
+ 1. **Anchor** — where in the graph? `:root` (top level), `:workspace`,
95
+ `:project`, `#pkg-name`, or nothing (whole graph).
96
+ 2. **Traverse** — what relationship? `>` direct deps, ` ` (space)
97
+ anything beneath, `~` siblings. Skip to filter the anchor itself.
98
+ 3. **Filter** — chain conditions with no space = AND: attribute
99
+ (`[license=MIT]`), state (`:dev`), functional (`:outdated(major)`),
100
+ negation (`:not(...)`).
101
+ 4. **Union** — need OR? Join complete selectors with commas.
102
+ 5. **Invert direction** — "what depends on X?" flips traversal: use
103
+ `:has(> #x)` (dependents of x), not `#x > *` (dependencies of x).
104
+
105
+ Worked example — "prod deps of my workspaces with a copyleft license":
106
+ `:workspace` (anchor) + `>` (direct) + `:prod:license(copyleft)`
107
+ (filters) → `vlt query ':workspace > :prod:license(copyleft)'`
108
+
109
+ ## Core syntax (mental model: CSS, but nodes are packages)
110
+
111
+ | Piece | Meaning | Example |
112
+ | ----------------------------------- | ------------------------------------------- | ------------------------ |
113
+ | `[name=foo]` / `#foo` | match by package.json field / name shortcut | `[version^=2]`, `#react` |
114
+ | `>` | direct dependency | `:root > *` |
115
+ | ` ` (space) | any transitive dependency | `:root [name=js-tokens]` |
116
+ | `~` | sibling (shares a parent) | `[name=react] ~ *` |
117
+ | `:root` `:project` `:workspace` | graph anchors | `:workspace > :dev` |
118
+ | `:prod` `:dev` `:optional` `:peer` | dependency type | `:dev:outdated` |
119
+ | `:has()` `:not()` `:is()` | structural filters | `:has(> :cve(*))` |
120
+ | `:outdated()` `:semver()` `:type()` | functional filters | `:outdated(major)` |
121
+ | `:malware` `:cve()` `:license()` | security (Socket data, network call) | `:license(copyleft)` |
122
+ | `,` | OR — union of selectors | `:dev, :optional` |
123
+
124
+ Chaining without spaces is AND: `:workspace:private` = workspace AND
125
+ private.
126
+
127
+ ## Common recipes
128
+
129
+ ```bash
130
+ vlt query ':root > *' # direct dependencies
131
+ vlt query ':workspace' # select all workspaces
132
+ vlt query ':root > :outdated' # outdated direct deps
133
+ vlt query '[name=react] *' # everything react pulls in
134
+ vlt query ':has(> #react)' # packages that directly depend on react
135
+ vlt query ':dev:eval' # dev deps using eval()
136
+ vlt query ':malware, :cve(*)' # malware or any CVE
137
+ ```
138
+
139
+ ## Security auditing (Socket-powered)
140
+
141
+ DSS's sharpest feature: nodes are enriched with Socket insight data,
142
+ so the dependency graph doubles as a security scanner. Selectors group
143
+ into four families — compose them with anchors and combinators like
144
+ any other filter:
145
+
146
+ | Family | Selectors | Ask |
147
+ | --------------- | -------------------------------------------------------------------------------- | -------------------------------------- |
148
+ | Threats | `:malware` `:squat` `:obfuscated` `:suspicious` | is anything actively hostile? |
149
+ | Vulnerabilities | `:vuln(critical)` `:cve(CVE-…)` `:cve(*)` `:cwe(CWE-79)` `:severity(">=medium")` | known CVEs / vulns, filter by severity |
150
+ | Capabilities | `:eval` `:network` `:fs` `:shell` `:env` | what _can_ this code do? |
151
+ | Hygiene | `:abandoned` `:unmaintained` `:deprecated` `:score("<=0.5", "maintenance")` | will this rot on us? |
152
+
153
+ Audit recipes:
154
+
155
+ ```bash
156
+ vlt query ':malware, :vuln(critical), :squat, :obfuscated' # supply-chain sweep
157
+ vlt query ':workspace > :prod:severity(">=high")' # release blockers
158
+ vlt query ':dev:shell, :dev:network' # dev deps that spawn/phone home
159
+ ```
160
+
161
+ All of these fetch Socket data over the network — expect latency on
162
+ first run.
163
+
164
+ ## Gotchas
165
+
166
+ - `:workspace` matches workspaces declared in `vlt.json` — yarn/pnpm/
167
+ bun-style workspace configs aren't read unless mirrored there.
168
+ - `:license(x)` takes a category (`copyleft`, `unlicensed`, `none`,
169
+ …), never a license ID — for a specific license use the attribute
170
+ form `[license=MIT]`.
171
+ - `:missing` matches edges (declarations), not nodes — no package
172
+ output.
173
+ - Quote values with special chars: `[name^="@vltpkg"]`.
174
+
175
+ ## Full reference
176
+
177
+ Selector-by-selector detail (all pseudo-classes, security insights,
178
+ operators): see [REFERENCE.md](REFERENCE.md).
179
+
180
+ Canonical docs — deep-link the section that matches the query
181
+ (verified anchors; don't invent others):
182
+
183
+ | Query topic | Link |
184
+ | ----------------------------------------- | ------------------------------------------------------------ |
185
+ | syntax, composition, anything structural | <https://docs.vlt.io/cli/selectors/> |
186
+ | malware / typosquats / obfuscation | <https://docs.vlt.io/cli/security#malware-detection> |
187
+ | CVEs / CWEs / severity | <https://docs.vlt.io/cli/security#vulnerability-detection> |
188
+ | capabilities (`:eval` `:network` `:fs` …) | <https://docs.vlt.io/cli/security#behavioral-security-risks> |
189
+ | license compliance | <https://docs.vlt.io/cli/security#license-compliance> |
190
+ | security scores | <https://docs.vlt.io/cli/security#security-scoring> |
@@ -0,0 +1,79 @@
1
+ # dss-query skill evals
2
+
3
+ How we evaluate the [dss-query](../SKILL.md) agent skill:
4
+
5
+ Claude's skill-creator plugin "Evaluate a skill" decomposes into three
6
+ different measurements with different levels of rigor
7
+
8
+ | Layer | Question | Method | LLM involved? | CI-gateable? |
9
+ | ---------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------- | ------------------------------------------- |
10
+ | 1. Content correctness | Are the skill's documented selectors valid and current? | Extract selectors from SKILL.md/REFERENCE.md, parse + execute against the real query engine | No | Yes — deterministic |
11
+ | 2. Content efficacy | Does the skill make model output measurably better? | With-skill vs baseline differential, graded deterministically | As subject, not judge | Not as a hard gate (single-sample variance) |
12
+ | 3. Trigger efficacy | Does the skill activate when it should? | Repeated trigger-rate sampling on the production model | Yes, unavoidably | No — probabilistic, monitor only |
13
+
14
+ Two principles behind this split, learned the hard way:
15
+
16
+ - **Never use an LLM as the judge of a skill written for that LLM** —
17
+ grade with deterministic checks (parse, execute, regex). The LLM may
18
+ be the _subject_ of an eval, never its grader.
19
+ - **A skill's value is its lift over baseline.** A strong model may
20
+ already know the domain (correctness lift ≈ 0) while the skill still
21
+ earns its keep on response style, concision, and latency. Only a
22
+ with/without differential reveals which.
23
+
24
+ ## Layer 2: the efficacy differential (primary loop)
25
+
26
+ Lives in [`../../dss-query-workspace/`](../../dss-query-workspace/)
27
+ (gitignored). Test prompts + deterministic assertions are defined in
28
+ [evals.json](evals.json). Each iteration:
29
+
30
+ 1. For every eval, spawn two subagents in the same turn: one told to
31
+ read and follow the live SKILL.md (**force-loaded** — this removes
32
+ the trigger confound, see below), one baseline (no skill, or a
33
+ snapshot of the pre-edit skill when iterating).
34
+ 2. Grade every answer with [grade.mjs](grade.mjs) (run from
35
+ `src/query`:
36
+ `node skills/dss-query/evals/grade.mjs <iteration-dir>`) — no LLM:
37
+ - extract selectors from the answer (`vlt query '…'` and bare
38
+ code-block selectors);
39
+ - every selector must **parse** via `@vltpkg/dss-parser`;
40
+ - structural selectors must **execute** via `Query.search()`
41
+ against the in-memory fixture graph
42
+ (`src/query/test/fixtures/graph.ts`). Selectors using `:outdated`
43
+ (registry fetch) or security pseudo-selectors (need the Socket
44
+ archive) are parse-checked only, so grading stays offline.
45
+ Comma-separated selectors are split at the top level first —
46
+ multi-selector lists enable the engine's loose mode, which
47
+ silently swallows invalid segments;
48
+ - per-eval regex assertions (expected shape, style contract,
49
+ required caveats).
50
+ 3. Aggregate with skill-creator's `aggregate_benchmark` and review
51
+ outputs in its eval viewer; human feedback drives the next skill
52
+ edit, then re-run with the pre-edit snapshot as baseline.
53
+
54
+ Read the benchmark honestly: pass-rate delta is the skill's
55
+ correctness lift; time/token deltas are its efficiency cost/benefit;
56
+ assertions that pass in **both** configs are non-discriminating — they
57
+ can't detect skill regressions on that model (but may on weaker ones).
58
+
59
+ ## Layer 1: doc-selector validation
60
+
61
+ Machinery exists in [grade.mjs](grade.mjs) (parse + offline execute);
62
+ a standalone sweep that extracts every selector from
63
+ SKILL.md/REFERENCE.md and validates it the same way is the natural CI
64
+ gate — it catches the regression that actually bites: the query engine
65
+ changes and the skill's documented examples silently go stale.
66
+
67
+ ## Adding cases
68
+
69
+ Add to [evals.json](evals.json). Prefer deterministic assertions
70
+ (selector parses, executes, matches shape) over prose matching; make
71
+ prompts realistic (casual phrasing, a wrong attempt to correct,
72
+ project context) rather than textbook questions; and verify any
73
+ factual claim an assertion encodes against the engine source first —
74
+ e.g. `:license()` takes only category kinds, so an eval expecting
75
+ `:license(mit)` would grade correct answers as failures.
76
+
77
+ This directory is excluded from the published `@vltpkg/query` package
78
+ (see the `files` field in `package.json`) — it's repo tooling, not
79
+ part of the skill consumers receive.
@@ -0,0 +1,89 @@
1
+ {
2
+ "skill_name": "dss-query",
3
+ "evals": [
4
+ {
5
+ "id": 0,
6
+ "prompt": "How do I find outdated direct dependencies of my project root with vlt?",
7
+ "expected_output": "A vlt query using ':root > :outdated' (optionally with a specifier like major), with a one-line explanation. Concise — query first, no long preamble.",
8
+ "files": [],
9
+ "assertions": [
10
+ "proposes-root-outdated-selector: at least one extracted selector matches /:root\\s*>\\s*:outdated/",
11
+ "all-selectors-parse: every `vlt query '<sel>'` selector in the answer parses via @vltpkg/dss-parser",
12
+ "selector-executes-on-fixture-graph: the primary (structural) selector runs through Query.search() against the in-memory fixture graph without throwing",
13
+ "query-first-style: a fenced code block containing the vlt query appears before any multi-sentence explanation"
14
+ ]
15
+ },
16
+ {
17
+ "id": 1,
18
+ "prompt": "Write a DSS query for prod dependencies of my workspaces that have a MIT license.",
19
+ "expected_output": "A vlt query like ':workspace > :prod[license=MIT]' — workspace anchor, direct-dep combinator, prod filter chained with the [license=MIT] attribute. Must NOT suggest ':license(mit)': the :license() pseudo only accepts category kinds (copyleft, unlicensed, none, ...), so specific license IDs require the attribute form.",
20
+ "files": [],
21
+ "assertions": [
22
+ "uses-license-attribute-form: a selector matches /\\[license\\^?=\\s*['\"]?MIT/i (attribute form for a specific license ID)",
23
+ "avoids-invalid-license-pseudo: the answer does NOT propose :license(mit) — :license() only accepts category kinds, so this would throw 'Expected a valid license kind'",
24
+ "workspace-prod-anchored: a selector matches /:workspace\\s*>\\s*:prod/",
25
+ "all-selectors-parse: every extracted selector parses via @vltpkg/dss-parser"
26
+ ]
27
+ },
28
+ {
29
+ "id": 2,
30
+ "prompt": "What vlt query shows me which packages directly depend on react? I keep writing '#react > *' and getting the wrong thing.",
31
+ "expected_output": "Inverted-direction query using ':has(> #react)' (dependents), correcting the user's '#react > *' (which selects react's dependencies, not its dependents).",
32
+ "files": [],
33
+ "assertions": [
34
+ "uses-has-inversion: a selector matches /:has\\(\\s*>\\s*(#react|\\[name=react\\])\\s*\\)/",
35
+ "corrects-direction-mistake: states that '#react > *' selects react's DEPENDENCIES (children), i.e. wrong direction for finding dependents (grader quotes evidence)",
36
+ "does-not-present-wrong-selector-as-answer: '#react > *' is not offered as the solution",
37
+ "all-selectors-parse: every extracted selector parses via @vltpkg/dss-parser"
38
+ ]
39
+ },
40
+ {
41
+ "id": 3,
42
+ "prompt": "What does the vlt query ':workspace > :prod:cve(*)' do?",
43
+ "expected_output": "Left-to-right decomposition: workspaces anchor, direct dependencies, production type, has any CVE. Should mention security selectors hit the network (Socket data).",
44
+ "files": [],
45
+ "assertions": [
46
+ "covers-workspace-anchor: explanation mentions workspaces as the starting set (/workspace/i)",
47
+ "covers-direct-prod-segment: explanation mentions direct AND production dependencies (/direct/i and /prod/i)",
48
+ "covers-cve-segment: explanation says it matches packages with any known CVE (/cve/i)",
49
+ "mentions-security-data-source: notes that :cve() uses Socket security data / a network call (/socket|network/i)"
50
+ ]
51
+ },
52
+ {
53
+ "id": 4,
54
+ "prompt": "We just got a supply-chain security alert at work. What vlt queries should I run to audit our dependency graph for malware, typosquats, and obfuscated code?",
55
+ "expected_output": "A supply-chain sweep using threat selectors — e.g. ':malware(critical), :squat, :obfuscated' (union or separate queries). Notes Socket data / network latency. Offers scoping or follow-up queries.",
56
+ "files": [],
57
+ "assertions": [
58
+ "uses-threat-selectors: selectors include :malware AND at least one of :squat / :obfuscated / :suspicious",
59
+ "all-selectors-parse: every extracted selector parses via @vltpkg/dss-parser",
60
+ "mentions-security-data-source: notes Socket data / network fetch (/socket|network/i)",
61
+ "offers-related-queries: at least 2 distinct selectors offered"
62
+ ]
63
+ },
64
+ {
65
+ "id": 5,
66
+ "prompt": "Which of my dev dependencies can run shell commands or hit the network? We're locking down CI.",
67
+ "expected_output": "Capability query composing :dev with :shell and :network — e.g. ':dev:shell, :dev:network' (chained AND, comma OR). Explains capabilities = what the code can do (Socket static analysis).",
68
+ "files": [],
69
+ "assertions": [
70
+ "uses-capability-selectors: a selector chains :dev with :shell or :network (e.g. :dev:shell)",
71
+ "covers-both-capabilities: both shell and network are queried (union or two queries)",
72
+ "all-selectors-parse: every extracted selector parses via @vltpkg/dss-parser",
73
+ "explains-capability-meaning: explains these match what code CAN do / Socket analysis (/socket|static|capab|can /i)"
74
+ ]
75
+ },
76
+ {
77
+ "id": 6,
78
+ "prompt": "Before our release I want to check whether any prod deps of our workspaces have high or critical severity vulnerabilities. What's the vlt query?",
79
+ "expected_output": "Severity-filtered composition anchored at workspaces — e.g. ':workspace > :prod:severity(\">=high\")' (or union of severity(high), severity(critical)). Explains the comparator and mentions Socket/network.",
80
+ "files": [],
81
+ "assertions": [
82
+ "uses-severity-filter: a selector uses :severity(...) or :sev(...)",
83
+ "anchors-workspace-prod: a selector matches /:workspace\\s*>\\s*:prod/",
84
+ "all-selectors-parse: every extracted selector parses via @vltpkg/dss-parser",
85
+ "mentions-security-data-source: notes Socket data / network fetch (/socket|network/i)"
86
+ ]
87
+ }
88
+ ]
89
+ }