@vibe-agent-toolkit/agent-skills 0.2.0-rc.2 → 0.2.0-rc.4

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 (213) hide show
  1. package/dist/files-config.d.ts +34 -1
  2. package/dist/files-config.d.ts.map +1 -1
  3. package/dist/files-config.js +280 -36
  4. package/dist/files-config.js.map +1 -1
  5. package/dist/fs-attribution.d.ts +45 -0
  6. package/dist/fs-attribution.d.ts.map +1 -0
  7. package/dist/fs-attribution.js +57 -0
  8. package/dist/fs-attribution.js.map +1 -0
  9. package/dist/index.d.ts +6 -5
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +9 -3
  12. package/dist/index.js.map +1 -1
  13. package/dist/inventory/detectors/declared-but-missing.d.ts +1 -1
  14. package/dist/inventory/detectors/declared-but-missing.d.ts.map +1 -1
  15. package/dist/inventory/detectors/marketplace-source-missing.d.ts +1 -1
  16. package/dist/inventory/detectors/marketplace-source-missing.d.ts.map +1 -1
  17. package/dist/inventory/detectors/present-but-undeclared.d.ts +1 -1
  18. package/dist/inventory/detectors/present-but-undeclared.d.ts.map +1 -1
  19. package/dist/inventory/detectors/reference-target-missing.d.ts +1 -1
  20. package/dist/inventory/detectors/reference-target-missing.d.ts.map +1 -1
  21. package/dist/inventory/index.d.ts +1 -1
  22. package/dist/inventory/index.d.ts.map +1 -1
  23. package/dist/inventory/index.js +1 -1
  24. package/dist/inventory/index.js.map +1 -1
  25. package/dist/inventory/serialize.d.ts +4 -4
  26. package/dist/inventory/serialize.d.ts.map +1 -1
  27. package/dist/inventory/serialize.js +6 -6
  28. package/dist/inventory/serialize.js.map +1 -1
  29. package/dist/plugin-distribution-layout.d.ts.map +1 -1
  30. package/dist/plugin-distribution-layout.js +3 -1
  31. package/dist/plugin-distribution-layout.js.map +1 -1
  32. package/dist/post-build-checks.d.ts +1 -1
  33. package/dist/post-build-checks.d.ts.map +1 -1
  34. package/dist/post-build-checks.js.map +1 -1
  35. package/dist/projection/skill-extent.d.ts +247 -0
  36. package/dist/projection/skill-extent.d.ts.map +1 -0
  37. package/dist/projection/skill-extent.js +558 -0
  38. package/dist/projection/skill-extent.js.map +1 -0
  39. package/dist/schemas/agent-skill-frontmatter.js +1 -1
  40. package/dist/schemas/agent-skill-frontmatter.js.map +1 -1
  41. package/dist/skill-packager.d.ts +45 -7
  42. package/dist/skill-packager.d.ts.map +1 -1
  43. package/dist/skill-packager.js +123 -25
  44. package/dist/skill-packager.js.map +1 -1
  45. package/dist/skill-source/git-clone.d.ts +1 -1
  46. package/dist/skill-source/git-clone.d.ts.map +1 -1
  47. package/dist/skill-source/git-clone.js +10 -8
  48. package/dist/skill-source/git-clone.js.map +1 -1
  49. package/dist/skill-source/sources/url-source.d.ts.map +1 -1
  50. package/dist/skill-source/sources/url-source.js +2 -1
  51. package/dist/skill-source/sources/url-source.js.map +1 -1
  52. package/dist/skill-test/baseline-delta.d.ts +1575 -0
  53. package/dist/skill-test/baseline-delta.d.ts.map +1 -0
  54. package/dist/skill-test/baseline-delta.js +272 -0
  55. package/dist/skill-test/baseline-delta.js.map +1 -0
  56. package/dist/skill-test/baseline-integrity.d.ts +944 -0
  57. package/dist/skill-test/baseline-integrity.d.ts.map +1 -0
  58. package/dist/skill-test/baseline-integrity.js +3083 -0
  59. package/dist/skill-test/baseline-integrity.js.map +1 -0
  60. package/dist/skill-test/configure-writer.js +1 -1
  61. package/dist/skill-test/configure-writer.js.map +1 -1
  62. package/dist/skill-test/declared-env.d.ts.map +1 -1
  63. package/dist/skill-test/declared-env.js +2 -1
  64. package/dist/skill-test/declared-env.js.map +1 -1
  65. package/dist/skill-test/eval-executor.d.ts +20 -4
  66. package/dist/skill-test/eval-executor.d.ts.map +1 -1
  67. package/dist/skill-test/eval-executor.js +4 -4
  68. package/dist/skill-test/eval-executor.js.map +1 -1
  69. package/dist/skill-test/eval-fragment.d.ts +80 -6
  70. package/dist/skill-test/eval-fragment.d.ts.map +1 -1
  71. package/dist/skill-test/eval-fragment.js +61 -7
  72. package/dist/skill-test/eval-fragment.js.map +1 -1
  73. package/dist/skill-test/eval-grader.d.ts +1 -1
  74. package/dist/skill-test/eval-grader.d.ts.map +1 -1
  75. package/dist/skill-test/eval-grader.js +145 -8
  76. package/dist/skill-test/eval-grader.js.map +1 -1
  77. package/dist/skill-test/eval-inputs.d.ts +107 -6
  78. package/dist/skill-test/eval-inputs.d.ts.map +1 -1
  79. package/dist/skill-test/eval-inputs.js +173 -16
  80. package/dist/skill-test/eval-inputs.js.map +1 -1
  81. package/dist/skill-test/eval-lint.d.ts +13 -0
  82. package/dist/skill-test/eval-lint.d.ts.map +1 -1
  83. package/dist/skill-test/eval-lint.js +17 -4
  84. package/dist/skill-test/eval-lint.js.map +1 -1
  85. package/dist/skill-test/executor-prompt.d.ts +13 -5
  86. package/dist/skill-test/executor-prompt.d.ts.map +1 -1
  87. package/dist/skill-test/executor-prompt.js +8 -5
  88. package/dist/skill-test/executor-prompt.js.map +1 -1
  89. package/dist/skill-test/exit-codes.d.ts +53 -16
  90. package/dist/skill-test/exit-codes.d.ts.map +1 -1
  91. package/dist/skill-test/exit-codes.js +123 -40
  92. package/dist/skill-test/exit-codes.js.map +1 -1
  93. package/dist/skill-test/fragment-merge.d.ts +1 -18
  94. package/dist/skill-test/fragment-merge.d.ts.map +1 -1
  95. package/dist/skill-test/fragment-merge.js +63 -4
  96. package/dist/skill-test/fragment-merge.js.map +1 -1
  97. package/dist/skill-test/grader-prompt.d.ts +27 -7
  98. package/dist/skill-test/grader-prompt.d.ts.map +1 -1
  99. package/dist/skill-test/grader-prompt.js +253 -61
  100. package/dist/skill-test/grader-prompt.js.map +1 -1
  101. package/dist/skill-test/grader-text.d.ts +145 -0
  102. package/dist/skill-test/grader-text.d.ts.map +1 -0
  103. package/dist/skill-test/grader-text.js +410 -0
  104. package/dist/skill-test/grader-text.js.map +1 -0
  105. package/dist/skill-test/grading-adapter.d.ts +32 -0
  106. package/dist/skill-test/grading-adapter.d.ts.map +1 -1
  107. package/dist/skill-test/grading-adapter.js +50 -3
  108. package/dist/skill-test/grading-adapter.js.map +1 -1
  109. package/dist/skill-test/grading-schema.d.ts +160 -5
  110. package/dist/skill-test/grading-schema.d.ts.map +1 -1
  111. package/dist/skill-test/grading-schema.js +66 -7
  112. package/dist/skill-test/grading-schema.js.map +1 -1
  113. package/dist/skill-test/index.d.ts +1 -1
  114. package/dist/skill-test/index.d.ts.map +1 -1
  115. package/dist/skill-test/index.js +1 -1
  116. package/dist/skill-test/index.js.map +1 -1
  117. package/dist/skill-test/lock.d.ts +56 -0
  118. package/dist/skill-test/lock.d.ts.map +1 -1
  119. package/dist/skill-test/lock.js +75 -2
  120. package/dist/skill-test/lock.js.map +1 -1
  121. package/dist/skill-test/pipeline.d.ts +16 -0
  122. package/dist/skill-test/pipeline.d.ts.map +1 -1
  123. package/dist/skill-test/pipeline.js +16 -9
  124. package/dist/skill-test/pipeline.js.map +1 -1
  125. package/dist/skill-test/preflight.d.ts +1 -1
  126. package/dist/skill-test/preflight.d.ts.map +1 -1
  127. package/dist/skill-test/preflight.js +59 -15
  128. package/dist/skill-test/preflight.js.map +1 -1
  129. package/dist/skill-test/run-harness.d.ts +578 -35
  130. package/dist/skill-test/run-harness.d.ts.map +1 -1
  131. package/dist/skill-test/run-harness.js +1281 -148
  132. package/dist/skill-test/run-harness.js.map +1 -1
  133. package/dist/skill-test/staging.d.ts +8 -2
  134. package/dist/skill-test/staging.d.ts.map +1 -1
  135. package/dist/skill-test/staging.js +8 -4
  136. package/dist/skill-test/staging.js.map +1 -1
  137. package/dist/skill-test/tool-eval-schema.d.ts +6 -6
  138. package/dist/test-input.d.ts +57 -6
  139. package/dist/test-input.d.ts.map +1 -1
  140. package/dist/test-input.js +35 -12
  141. package/dist/test-input.js.map +1 -1
  142. package/dist/validators/agent-instruction-presence.d.ts +1 -1
  143. package/dist/validators/agent-instruction-presence.d.ts.map +1 -1
  144. package/dist/validators/agent-instruction-presence.js +2 -1
  145. package/dist/validators/agent-instruction-presence.js.map +1 -1
  146. package/dist/validators/bundled-resource-link-detection.d.ts +1 -1
  147. package/dist/validators/bundled-resource-link-detection.d.ts.map +1 -1
  148. package/dist/validators/bundled-resource-link-detection.js +1 -1
  149. package/dist/validators/bundled-resource-link-detection.js.map +1 -1
  150. package/dist/validators/compat-detectors.d.ts +1 -1
  151. package/dist/validators/compat-detectors.d.ts.map +1 -1
  152. package/dist/validators/compat-detectors.js +1 -1
  153. package/dist/validators/compat-detectors.js.map +1 -1
  154. package/dist/validators/cross-skill-dependency-detection.d.ts +1 -1
  155. package/dist/validators/cross-skill-dependency-detection.d.ts.map +1 -1
  156. package/dist/validators/cross-skill-dependency-detection.js +1 -1
  157. package/dist/validators/cross-skill-dependency-detection.js.map +1 -1
  158. package/dist/validators/description-style-detection.d.ts +1 -1
  159. package/dist/validators/description-style-detection.d.ts.map +1 -1
  160. package/dist/validators/description-style-detection.js +1 -1
  161. package/dist/validators/description-style-detection.js.map +1 -1
  162. package/dist/validators/frontmatter-validation.d.ts +1 -1
  163. package/dist/validators/frontmatter-validation.d.ts.map +1 -1
  164. package/dist/validators/frontmatter-validation.js +1 -1
  165. package/dist/validators/frontmatter-validation.js.map +1 -1
  166. package/dist/validators/imperative-body-detection.d.ts +1 -1
  167. package/dist/validators/imperative-body-detection.d.ts.map +1 -1
  168. package/dist/validators/imperative-body-detection.js +1 -1
  169. package/dist/validators/imperative-body-detection.js.map +1 -1
  170. package/dist/validators/index.d.ts +1 -1
  171. package/dist/validators/index.d.ts.map +1 -1
  172. package/dist/validators/kebab-case-detection.d.ts +1 -1
  173. package/dist/validators/kebab-case-detection.d.ts.map +1 -1
  174. package/dist/validators/kebab-case-detection.js +1 -1
  175. package/dist/validators/kebab-case-detection.js.map +1 -1
  176. package/dist/validators/marketplace-validator.js +1 -1
  177. package/dist/validators/marketplace-validator.js.map +1 -1
  178. package/dist/validators/packaging-validator.d.ts +96 -7
  179. package/dist/validators/packaging-validator.d.ts.map +1 -1
  180. package/dist/validators/packaging-validator.js +148 -21
  181. package/dist/validators/packaging-validator.js.map +1 -1
  182. package/dist/validators/plugin-hosted-shape.d.ts +1 -1
  183. package/dist/validators/plugin-hosted-shape.d.ts.map +1 -1
  184. package/dist/validators/plugin-hosted-shape.js +1 -1
  185. package/dist/validators/plugin-hosted-shape.js.map +1 -1
  186. package/dist/validators/plugin-recommended-fields.d.ts +1 -1
  187. package/dist/validators/plugin-recommended-fields.d.ts.map +1 -1
  188. package/dist/validators/plugin-recommended-fields.js +1 -1
  189. package/dist/validators/plugin-recommended-fields.js.map +1 -1
  190. package/dist/validators/registry-validator.js +1 -1
  191. package/dist/validators/registry-validator.js.map +1 -1
  192. package/dist/validators/rule-engine/rule-engine.d.ts +1 -1
  193. package/dist/validators/rule-engine/rule-engine.d.ts.map +1 -1
  194. package/dist/validators/rule-engine/rule-engine.js +20 -9
  195. package/dist/validators/rule-engine/rule-engine.js.map +1 -1
  196. package/dist/validators/skill-validator.d.ts.map +1 -1
  197. package/dist/validators/skill-validator.js +21 -3
  198. package/dist/validators/skill-validator.js.map +1 -1
  199. package/dist/validators/types.d.ts +1 -1
  200. package/dist/validators/types.d.ts.map +1 -1
  201. package/dist/validators/unified-validator.js +1 -1
  202. package/dist/validators/unified-validator.js.map +1 -1
  203. package/dist/validators/validation-rules.d.ts +1 -1
  204. package/dist/validators/validation-rules.d.ts.map +1 -1
  205. package/dist/validators/walker-to-issues.d.ts +7 -3
  206. package/dist/validators/walker-to-issues.d.ts.map +1 -1
  207. package/dist/validators/walker-to-issues.js +37 -8
  208. package/dist/validators/walker-to-issues.js.map +1 -1
  209. package/dist/walk-link-graph.d.ts +2 -1
  210. package/dist/walk-link-graph.d.ts.map +1 -1
  211. package/dist/walk-link-graph.js +37 -2
  212. package/dist/walk-link-graph.js.map +1 -1
  213. package/package.json +7 -7
@@ -0,0 +1,558 @@
1
+ /**
2
+ * The **skill** extent, expressed as the generic closure primitive plus a
3
+ * declaration — zones.md §7.3's adequacy test, run for real.
4
+ *
5
+ * §7.3 requires that *a built-in extent must be expressible the way a
6
+ * config-declared one would be*. A skill bundle is the hardest case VAT has,
7
+ * because a privileged walker (`walk-link-graph.ts`) already computes it, so
8
+ * this module is the falsification: it translates a `SkillPackagingConfig` into
9
+ * an {@link ExtentDeclaration} and hands it to `ClosureExtentContributor`. There
10
+ * is deliberately **no bespoke walker here**. A second walker that passed its
11
+ * own tests would prove nothing about the primitive — it would only prove that
12
+ * the skill contributor can stay privileged, which is the outcome §17 risk 3
13
+ * asks about.
14
+ *
15
+ * ## What the primitive expresses, measured against the shipped walker
16
+ *
17
+ * The equality experiment lives in `test/projection-skill-extent.test.ts`, and
18
+ * its result is that **membership** agrees exactly on a corpus whose every link
19
+ * target is an ordinary reachable file, and — since the primitive gained a
20
+ * labelled `refusals` cascade plus `admitPaths` — on three of the cascade
21
+ * discriminators that used to diverge, and now on their REASONS as well. What
22
+ * remains is listed below. Stated here rather than in a report, because a reader
23
+ * reaching for this translation needs the boundary, not the anecdote:
24
+ *
25
+ * | Walker feature | Verdict |
26
+ * |---|---|
27
+ * | `linkFollowDepth` *membership* | **expressible** — same union, same off-by-one (`depth < maxDepth`) |
28
+ * | `depth-exceeded` *the REASON* | **expressible** — and it moved out of the not-expressible list once the primitive stopped guarding ENUMERATION on `maxDepth` and started guarding only ADMISSION. A member at the bound now has its references resolved and judged, and one the budget alone turns away becomes a `CLOSURE_DEPTH_EXCEEDED` condition carrying the same provenance a refusal does. This is the one verdict a DECLARATION states directly rather than through a `refusals` rule, so it carries no label and `matchedPattern` is null — which is exactly what the walker's own row says (`makeExclusion` attaches `matchedRule` only for `pattern-matched`) |
29
+ * | `excludeReferencesFromBundle` *membership* | **expressible** — first-match-wins and any-match select the same file set; carried as ONE refusal rule per declared rule, in declared order, which selects the same set the flat union did |
30
+ * | `excludeReferencesFromBundle` *WHICH rule matched* | **expressible** — one refusal rule apiece means the primitive's first-match-wins scan is `excludeMatchers.find(...)`'s scan, and the winner's first pattern lands in `realization_conditions.matchedPattern`, the column `packaging-validator.ts` reads as `matchedRule.patterns[0]` |
31
+ * | `excludeReferencesFromBundle` *`template` payload* | **expressible** — carried verbatim in `ExtentRefusalRule.payload` (opaque to the primitive) and reported as `realization_conditions.matchedPayload`, beside the rule's declared index. ⚠️ Never MEASURED against the walker: no shipped config declares a `template`, so the corpus shadow synthesizes one to compare the two arms |
32
+ * | `excludeNavigationFiles` | **expressible** — a refusal rule over `NAVIGATION_FILE_PATTERNS`, gated on the knob exactly as `classifyExclusion` gates its branch |
33
+ * | `agent-instruction-file` *membership* | **expressible** — a refusal rule over `AGENT_INSTRUCTION_FILE_PATTERNS`, unconditionally, and the explicit-`files:` escape hatch becomes `admitPaths` (see {@link declaredAgentInstructionSources}) |
34
+ * | `directory-target` *membership* | **expressible** — a refusal rule over `kinds: ['directory']`, which reads `resources.kind`; a path glob cannot express it, because a directory's path is shaped like a file's |
35
+ * | the REASON of those four exclusions | **expressible** — each refusal rule carries a `label`, and the first-match-wins order is `classifyExclusion`'s own branch order, so the refusal reports `SKILL_REFUSED_DIRECTORY_TARGET` where the walker reports `directory-target`. Pinned by the corpus shadow's reason-mismatch bucket, not asserted here |
36
+ * | `deferredArtifacts` (`files:`) | **not expressible** — its three-way classification is keyed on filesystem existence and on gitignore, and the closure does no I/O by construction. Only the ONE fact `admitPaths` needs — which sources are explicit, non-glob agent-instruction files — is a pure function of the config, which is why that much survives the translation |
37
+ * | `gitignored` | **expressible, CONDITIONALLY** — a COLUMN match, not an oracle: `resource_realizations.gitignored` is a first-class boolean the registry crawl fills, and `ExtentRefusalRule.flags` reads boolean columns. Carried as `{ gitignored: true, exists: true }` — a CONJUNCTION, because `classifyGitignored` is existence-gated — and emitted only when the population has a `GitTracker`, since without one the column is `false` on every row. ⚠️ Two bounds: the WALKER needs no tracker (it spawns `git check-ignore`), so the arms diverge in the no-tracker state; and `classifyGitignoredTarget` turns a gitignored `files:` DEST into a `deferred` verdict rather than a refusal, which no declaration can say (`admitPaths` would make it a member) |
38
+ * | `skill-definition` | **expressible**, as two halves that were always two verdicts under one `if`. The cross-skill half is an ordinary `basenames: ['SKILL.md']` rule, sitting between the agent-instruction rule and the globs exactly where `classifyExclusion` puts it. The self-link half is the walker's `{ kind: 'skipped' }`, and it is not a rule: the PRIMITIVE now skips a reference resolving to `closureFrom`, because the root is a member by declaration in any closure — see `closure-extent.ts`'s `hopFor`. ⚠️ The walker compares the basename with `===`; `basenames` folds case, so `Skill.md` diverges — see {@link SKILL_DEFINITION_BASENAME} |
39
+ * | `outside-project` | **expressible as a REASON, not as a full row** — and it never needed an oracle: `relativize` states every path against the root, and one the root does not contain comes back `..`-prefixed. It was a LABELLING gap, not a knowledge gap; the closure knew, and reported `CLOSURE_REFERENCE_UNRESOLVED`, which is true and useless. It is now `CLOSURE_REFERENCE_OUTSIDE_ROOT`, naming the same target the walker's row names. ⚠️ `targetExists` stays null: the walker `stat`s the escaping path, a projection populated from one root observes nothing outside it |
40
+ * | `missing-target` | **not expressible** — and NOT for the reason the column suggests. `exists` is a real column and `flags` reads it, but no rule can ever fire on it here: a path that is not on disk is never ENUMERATED, so it has no realization for a candidate to be, and the reference resolves to nothing long before the cascade runs. The producer is structurally blind, so the matcher is dead. The fact is still reported — as `CLOSURE_REFERENCE_UNRESOLVED` — but that code conflates "absent" with "present and not enumerated by any contributor", and only a filesystem probe separates them |
41
+ * | routable vs non-routable | **not expressible** (reasoned, not measured — the corpus has no HTML), and the earlier reason given here was wrong. The declaration is not short of a COLUMN: `resource_realizations.ext` carries the extension and `blobs.contentKey` is literally `<parserKind>.<sha256>`. What it is short of is a VERDICT: `isRoutable` makes an HTML page a member that is not traversed THROUGH, and the primitive has no admit-but-do-not-traverse outcome — a refusal would drop a file the walker bundles. Expressing it means a new verdict in the primitive, not a new matcher |
42
+ * | `unreadable-target` | **not expressible** — the one genuine oracle left. It is `existsSync` true AND `statSync` throwing anyway, a read outcome no column records: `contentState: 'unreadable'` is a *different* fact (a BYTE read that threw) and is demand-driven besides, so a path nobody asked to hash reads `deferred` whether or not it is stattable |
43
+ * | a refusal's PROVENANCE (`sourcePath`, `sourceLine`, `linkHref`, `targetExists`, `matchedRule`) | **expressible** — `realization_conditions` gained the six columns (projection schema v4), the closure fills them at the refusal site, and every one of the five is compared field by field against the walker's own row by the corpus shadow's provenance bucket |
44
+ *
45
+ * Read the membership, reason and provenance rows together: the primitive now
46
+ * selects the same files for those causes, names the same cause, and carries the
47
+ * same `sourcePath`/`sourceLine`/`linkHref`/`targetExists`/matched-rule
48
+ * provenance the walker attaches to a refusal.
49
+ *
50
+ * ## The residue is TWO reasons, not six — and one of them is not an oracle problem
51
+ *
52
+ * The count above used to be six, and four of those six were stale. Three had
53
+ * gained the machinery to express them (`gitignored` became a boolean column of
54
+ * the realization row; `outside-project` was always path math the closure was
55
+ * already doing; `skill-definition` needed one basename rule plus a self-link
56
+ * rule the primitive owes every closure), and one — `missing-target` — was
57
+ * inexpressible for a completely different reason than "no oracle": its matcher
58
+ * exists and can never fire, because the producer never emits the row it would
59
+ * match.
60
+ *
61
+ * What is left is `unreadable-target`, a genuine filesystem read outcome, and
62
+ * routability, which needs a new VERDICT in the primitive rather than a new
63
+ * matcher. Both are stated above with the evidence for the claim, because a
64
+ * boundary list that is never re-derived is how four verdicts stayed wrong for
65
+ * three increments.
66
+ *
67
+ * ⚠️ **Neither new verdict is measured against the walker on the real corpus,
68
+ * and they are not equally unmeasured elsewhere. Stated per verdict, because an
69
+ * aggregate "verified" would be false for one of them.**
70
+ *
71
+ * - **`skill-definition` IS measured against the walker, at FIXTURE scale.**
72
+ * `projection-skill-extent.test.ts` builds a corpus containing a sibling
73
+ * `skills/tool-b/SKILL.md`, and that divergence — named there, as a
74
+ * one-element equality — closes when this rule lands.
75
+ * - **`gitignored` is reasoned, not measured against the walker anywhere.** The
76
+ * `flags` conjunction it is made of has its own falsifying case in
77
+ * `projection-closure-extent.test.ts` (including the `exists: false` control
78
+ * that separates AND from OR), but no fixture yet links a skill to a gitignored
79
+ * file with both arms running, so no two-arm comparison has ever exercised it.
80
+ *
81
+ * Neither is reachable on the REAL corpus, and that is asserted rather than
82
+ * assumed: the corpus shadow was green with both verdicts unexpressed, which is
83
+ * possible only if no declared skill links to a gitignored file or to another
84
+ * skill's SKILL.md, and both populations are now pinned at zero there. The day a
85
+ * link appears the test fails and the reader learns the corpus grew teeth
86
+ * ([[fixtures-that-cannot-distinguish]]).
87
+ *
88
+ * The `excludeNavigationFiles` row is the one worth reading twice, because the
89
+ * shape of its extension is the argument for why a rule needs a basename matcher
90
+ * and not a cleverer glob: `isNavigationBasename` matches a **case-insensitive
91
+ * basename set** (`README.md`, `index.md`, …), while `patterns` is picomatch
92
+ * over a root-relative path. A brace alternation over `README` / `readme` /
93
+ * `Readme` enumerates spellings a case-insensitive filesystem generates freely,
94
+ * so the approximation silently under-matches exactly where the walker's comment
95
+ * says it must not (`Claude.md` is loaded as instructions on APFS just as
96
+ * `CLAUDE.md` is). The honest extension was a declared basename set, and it is
97
+ * what `ExtentRefusalRule.basenames` is.
98
+ *
99
+ * ## `closureFrom` is stated in projection coordinates
100
+ *
101
+ * {@link skillExtentDeclaration} takes the SKILL.md path **relative to the
102
+ * corpus root**, the way `resource_realizations.path` spells it, because that is
103
+ * the only coordinate system `closureFrom` is resolved in. The packager works in
104
+ * absolute paths; converting is the caller's job precisely because the caller is
105
+ * the one holding the root.
106
+ */
107
+ import { basename } from 'node:path';
108
+ import { ClosureExtentContributor, ExtentDeclarationSchema, } from '@vibe-agent-toolkit/resources';
109
+ import { isGlob, safePath } from '@vibe-agent-toolkit/utils';
110
+ import { AGENT_INSTRUCTION_FILE_PATTERNS, NAVIGATION_FILE_PATTERNS, isAgentInstructionBasename, } from '../validators/validation-rules.js';
111
+ /**
112
+ * `zone_provenance.contributorId` prefix for a skill extent.
113
+ *
114
+ * **Per-skill, not fixed.** The plan specced a bare `builtin:skill`, which was
115
+ * written before anyone asked how many skills a corpus has:
116
+ * `ContributorRegistry.register` refuses a duplicate id, so a fixed id caps a
117
+ * population at **one** skill extent — and this repo alone ships thirteen. The
118
+ * extent ids were already distinct (the skill name is the within-root
119
+ * discriminator); only the contributor key space collided. Nothing schema-level
120
+ * objects: `zone_provenance.contributorId` is an open string.
121
+ */
122
+ export const SKILL_EXTENT_CONTRIBUTOR_ID_PREFIX = 'builtin:skill';
123
+ /**
124
+ * The `zone_provenance.contributorId` for one skill's extent.
125
+ *
126
+ * @param skillName - The skill's name
127
+ * @returns The contributor id, unique per skill
128
+ */
129
+ export function skillExtentContributorId(skillName) {
130
+ return `${SKILL_EXTENT_CONTRIBUTOR_ID_PREFIX}:${skillName}`;
131
+ }
132
+ /** The `resolution_contexts.kind` a skill extent has. */
133
+ export const SKILL_EXTENT_KIND = 'skill';
134
+ /**
135
+ * The hop budget a skill bundle gets when its config declares none.
136
+ *
137
+ * Two shipped sites spell this `?? 2` — `skill-packager.ts:580` and
138
+ * `packaging-validator.ts:484` — so the translation must default the same way or
139
+ * a config-less skill would project a different extent from the one it packages.
140
+ */
141
+ const DEFAULT_LINK_FOLLOW_DEPTH = 2;
142
+ /**
143
+ * The `resources.kind` a directory entity carries.
144
+ *
145
+ * Verified against the producers rather than assumed: both base contributors
146
+ * spell it the same way — `filesystem-extent.ts` and `git-extent.ts` each emit
147
+ * `kind: realization.isDirectory ? 'directory' : 'file'` — and
148
+ * `projection-filesystem-extent.test.ts` pins it ("kinds a directory row
149
+ * 'directory' and a file row 'file'"). That is what makes `excludeKinds` able to
150
+ * stand in for the walker's `classifyPathKind`, whose `directory-target` branch
151
+ * is the FIRST thing it refuses after the deferred check.
152
+ */
153
+ const DIRECTORY_KIND = 'directory';
154
+ /**
155
+ * The walker's default for `excludeNavigationFiles` when the config declares
156
+ * none — `skill-packager.ts:582` spells it `options.excludeNavigationFiles ?? true`.
157
+ */
158
+ const DEFAULT_EXCLUDE_NAVIGATION_FILES = true;
159
+ /**
160
+ * The refusal labels this translation supplies — **one per branch of the walker's
161
+ * exclusion cascade that a declaration can express**, and that property rather
162
+ * than a count is the definition: every `SKILL_REFUSED_*` constant below is a
163
+ * member, so adding a branch adds a member without falsifying this line. (The
164
+ * branches come from three classifiers, not one: `classifyExclusion`,
165
+ * `classifyPathKind` and `classifyGitignored` — each label's own doc line names
166
+ * which.)
167
+ *
168
+ * SCREAMING_SNAKE because they land in `realization_conditions.code`, whose two
169
+ * existing members (`CLOSURE_REFERENCE_UNRESOLVED`, `CLOSURE_ROOT_ABSENT`) set
170
+ * that convention. Prefixed `SKILL_REFUSED_` because that column is an OPEN
171
+ * vocabulary shared by every contributor in a population: a bare
172
+ * `DIRECTORY_TARGET` would not say whose cascade decided it.
173
+ *
174
+ * The walker reason each one stands for is in its own doc line, and that mapping
175
+ * is asserted end-to-end by the corpus shadow's reason-mismatch bucket rather
176
+ * than trusted — see `projection-skill-extent-corpus.integration.test.ts`.
177
+ */
178
+ /** `classifyPathKind`'s `directory-target`. */
179
+ export const SKILL_REFUSED_DIRECTORY_TARGET = 'SKILL_REFUSED_DIRECTORY_TARGET';
180
+ /** `classifyExclusion`'s `navigation-file`. */
181
+ export const SKILL_REFUSED_NAVIGATION_FILE = 'SKILL_REFUSED_NAVIGATION_FILE';
182
+ /** `classifyExclusion`'s `agent-instruction-file`. */
183
+ export const SKILL_REFUSED_AGENT_INSTRUCTION_FILE = 'SKILL_REFUSED_AGENT_INSTRUCTION_FILE';
184
+ /** `classifyExclusion`'s `pattern-matched`, from `excludeReferencesFromBundle`. */
185
+ export const SKILL_REFUSED_PATTERN_MATCHED = 'SKILL_REFUSED_PATTERN_MATCHED';
186
+ /**
187
+ * `classifyExclusion`'s `skill-definition` — ANOTHER skill's SKILL.md.
188
+ *
189
+ * Only the cross-skill half. The walker's branch is two verdicts wearing one
190
+ * `if`: a link to a *sibling's* SKILL.md is this refusal, and a link back to the
191
+ * walk's OWN `skillRootPath` is `{ kind: 'skipped' }` — recorded nowhere. The
192
+ * declaration expresses the first as an ordinary basename rule; the second is
193
+ * not a rule at all, and it is the primitive that supplies it, because a
194
+ * reference to `closureFrom` is a self-link in any closure and not a fact about
195
+ * skills (see `closure-extent.ts`'s `hopFor`).
196
+ */
197
+ export const SKILL_REFUSED_SKILL_DEFINITION = 'SKILL_REFUSED_SKILL_DEFINITION';
198
+ /** `classifyGitignored`'s `gitignored`, existence-gated exactly as that branch is. */
199
+ export const SKILL_REFUSED_GITIGNORED = 'SKILL_REFUSED_GITIGNORED';
200
+ /**
201
+ * The basename that makes a markdown file a skill DEFINITION rather than a
202
+ * resource — the whole content of `classifyExclusion`'s SKILL.md branch.
203
+ *
204
+ * ⚠️ The walker compares it with `===`, so `Skill.md` on a case-insensitive
205
+ * filesystem is a skill definition Claude Code loads and the walker bundles.
206
+ * `ExtentRefusalRule.basenames` folds case, deliberately and for the reason its
207
+ * schema states, so the declaration refuses the spelling the walker admits. That
208
+ * is a difference in the WALKER's favour on no real corpus: this repository
209
+ * declares fourteen skills and every one of them spells the file `SKILL.md`. It
210
+ * is recorded here rather than papered over with a case-sensitive matcher
211
+ * variant, which would be a primitive feature added to reproduce an
212
+ * inconsistency — the walker's own navigation and agent-instruction branches
213
+ * fold case, and its comment says why they must.
214
+ */
215
+ const SKILL_DEFINITION_BASENAME = 'SKILL.md';
216
+ /**
217
+ * The realization columns {@link SKILL_REFUSED_GITIGNORED} refuses on.
218
+ *
219
+ * A CONJUNCTION, and both halves are load-bearing: `classifyGitignored` returns
220
+ * early on `!facts.exists` because neither ignore oracle can be trusted about a
221
+ * path that is not there (a `GitTracker`'s active set holds only existing paths,
222
+ * so every typo'd link would read as "absent, therefore ignored"). Read
223
+ * disjunctively, `{ gitignored: true, exists: true }` would refuse every existing
224
+ * file in the corpus. Spelled as one object so the conjunction is visible at the
225
+ * site that depends on it — the same shape, for the same reason, as
226
+ * `inventory-extent.ts`'s `GITIGNORED_FLAGS`.
227
+ */
228
+ const GITIGNORED_FLAGS = { gitignored: true, exists: true };
229
+ /**
230
+ * This skill's refusal cascade, **in `classifyExclusion`'s own branch order**.
231
+ *
232
+ * ⚠️ The order is load-bearing now that a refusal carries a label: the primitive
233
+ * is first-match-wins, so a directory that also matches an
234
+ * `excludeReferencesFromBundle` pattern must be attributed to `directory-target`
235
+ * — which is what the walker does, and which the previous flat encoding got
236
+ * backwards (its glob matcher ran before its kind matcher, harmlessly, because
237
+ * no verdict carried a reason to get wrong).
238
+ *
239
+ * The six rules, and why each sits where it does:
240
+ *
241
+ * 1. **kinds `['directory']`** — `classifyPathKind` is the FIRST thing
242
+ * `classifyExclusion` consults after the deferred check, and no knob gates it.
243
+ * 2. **navigation basenames** — gated on `excludeNavigationFiles`, because
244
+ * `classifyExclusion`'s navigation branch is. Omitted entirely rather than
245
+ * emitted empty when the knob is off, so the declaration says "this branch
246
+ * does not run" rather than "it runs and catches nothing".
247
+ * 3. **agent-instruction basenames** — unconditional, and that is not an
248
+ * oversight: `refusesAgentInstructionFile` is deliberately NOT gated on
249
+ * `excludeNavigationFiles`, because that knob is about content granularity
250
+ * while these files are about distributability. Sitting AFTER navigation is
251
+ * what makes a `files:`-declared `README.md` report `navigation-file` — see
252
+ * {@link declaredAgentInstructionSources} for the other half of that rule.
253
+ * 4. **the `SKILL.md` basename** — `classifyExclusion`'s cross-skill branch,
254
+ * which sits exactly here: after the agent-instruction check and BEFORE the
255
+ * glob rules, so a sibling's SKILL.md that also matches a declared
256
+ * `excludeReferencesFromBundle` pattern reports `skill-definition`. Its other
257
+ * half — a link back to this skill's OWN SKILL.md — is not a rule and cannot
258
+ * be: the walker records nothing at all for it, and the primitive supplies
259
+ * that silence for every closure by skipping a reference to `closureFrom`.
260
+ * 5. **one rule per `excludeReferencesFromBundle` rule**, in declared order —
261
+ * see below.
262
+ * 6. **`gitignored ∧ exists`** — LAST, matching `classifyGitignored`'s position
263
+ * at the end of the cascade, and present only when the population can answer
264
+ * the question at all. `resource_realizations.gitignored` is filled by
265
+ * `FilesystemExtentContributor` only when the population was given a
266
+ * `GitTracker` (`realizations.ts` writes `false` on every row otherwise), so a
267
+ * rule emitted without one would CLAIM a branch it cannot run — the same
268
+ * dishonesty rule 2 avoids by omitting itself rather than emitting empty.
269
+ *
270
+ * ⚠️ **The gitignore rule is where the two arms stop being symmetric in the
271
+ * no-tracker state, and that is a fact about the WALKER.**
272
+ * `walkLinkGraph`'s branch needs no tracker: with none it spawns `git
273
+ * check-ignore` per target (`readGitignored`), so it refuses ignored targets
274
+ * anyway. The closure's only gitignore input is a column a tracker-less
275
+ * population never fills, so the two agree in that state only on a corpus with
276
+ * no gitignored link target.
277
+ *
278
+ * ## Why the exclude rules are ONE RULE EACH and not one flattened rule
279
+ *
280
+ * They used to flatten into a single refusal rule holding every rule's patterns,
281
+ * which selected the same files and reported the same label but could not say
282
+ * WHICH declared rule caught a file — so `LinkResolution.matchedRule`, which
283
+ * `packaging-validator.ts:1182` reads `patterns[0]` off, had no counterpart.
284
+ *
285
+ * Expanding them restores it **without touching the reported reason**: every
286
+ * expanded rule carries the SAME {@link SKILL_REFUSED_PATTERN_MATCHED} label, so
287
+ * `realization_conditions.code` is unchanged, while the primitive's
288
+ * first-match-wins scan over them is exactly `excludeMatchers.find(...)`'s scan
289
+ * over `options.excludeRules` — same order, same winner. A label is a REASON and
290
+ * reasons are shared; identity rides on the rule's position and its `payload`.
291
+ *
292
+ * ⚠️ They all stay in the glob branch's position, AFTER the basename rules: the
293
+ * expansion widens one cascade step into N, it does not reorder the cascade. And
294
+ * a config declaring no rules now contributes NO rule rather than one empty one —
295
+ * an empty pattern list never matched anything, and "one rule per declared rule"
296
+ * is a shape a reader can check against the config, which "always exactly one"
297
+ * was not.
298
+ *
299
+ * Each expanded rule's `payload` carries what the primitive has no column for:
300
+ * the rule's INDEX in the declared array (identity, when two rules share a first
301
+ * pattern) and its `template` (the walker's own `ExcludeRule.template`, which no
302
+ * `realization_conditions` column could hold without teaching the closure about
303
+ * skill packaging).
304
+ *
305
+ * Basename lists are imported from `validation-rules.ts`, never re-spelled: that
306
+ * module is explicit that ONE canonical spelling per name is the whole design,
307
+ * and a second copy here would be the enumeration it warns against.
308
+ *
309
+ * @param config - The skill's packaging block
310
+ * @param hasGitTracker - Whether the population was given a usable git oracle
311
+ * @returns The ordered refusal rules
312
+ */
313
+ function skillRefusals(config, hasGitTracker) {
314
+ const excludeNavigation = config.excludeNavigationFiles ?? DEFAULT_EXCLUDE_NAVIGATION_FILES;
315
+ return [
316
+ // `flags: {}` on every rule but the last: the empty record is the schema
317
+ // default and never matches, so spelling it declares "this rule refuses on
318
+ // no column" rather than leaving a reader to infer it from an absent key.
319
+ // Only the gitignore rule reads a column, and it reads two.
320
+ {
321
+ label: SKILL_REFUSED_DIRECTORY_TARGET,
322
+ patterns: [],
323
+ basenames: [],
324
+ kinds: [DIRECTORY_KIND],
325
+ flags: {},
326
+ payload: null,
327
+ },
328
+ ...(excludeNavigation
329
+ ? [{
330
+ label: SKILL_REFUSED_NAVIGATION_FILE,
331
+ patterns: [],
332
+ basenames: [...NAVIGATION_FILE_PATTERNS],
333
+ kinds: [],
334
+ flags: {},
335
+ payload: null,
336
+ }]
337
+ : []),
338
+ {
339
+ label: SKILL_REFUSED_AGENT_INSTRUCTION_FILE,
340
+ patterns: [],
341
+ basenames: [...AGENT_INSTRUCTION_FILE_PATTERNS],
342
+ kinds: [],
343
+ flags: {},
344
+ payload: null,
345
+ },
346
+ {
347
+ label: SKILL_REFUSED_SKILL_DEFINITION,
348
+ patterns: [],
349
+ basenames: [SKILL_DEFINITION_BASENAME],
350
+ kinds: [],
351
+ flags: {},
352
+ payload: null,
353
+ },
354
+ // `payload: null` above, a payload here: the first four rules ARE the
355
+ // walker's own branches, which carry no rule object for a consumer to read
356
+ // back (`makeExclusion` sets `matchedRule` only for `pattern-matched`).
357
+ ...(config.excludeReferencesFromBundle?.rules ?? []).map((rule, index) => ({
358
+ label: SKILL_REFUSED_PATTERN_MATCHED,
359
+ patterns: [...rule.patterns],
360
+ basenames: [],
361
+ kinds: [],
362
+ flags: {},
363
+ payload: excludeRulePayload(rule, index),
364
+ })),
365
+ ...(hasGitTracker
366
+ ? [{
367
+ label: SKILL_REFUSED_GITIGNORED,
368
+ patterns: [],
369
+ basenames: [],
370
+ kinds: [],
371
+ flags: { ...GITIGNORED_FLAGS },
372
+ payload: null,
373
+ }]
374
+ : []),
375
+ ];
376
+ }
377
+ /**
378
+ * One `excludeReferencesFromBundle` rule's identity, as opaque payload.
379
+ *
380
+ * `template` is the field the old flat encoding lost outright — the skill
381
+ * extent's own boundary table used to record it as "not expressible", and it is
382
+ * expressible now precisely because the payload is a channel the primitive never
383
+ * reads. `ruleIndex` is what distinguishes two rules that share a first pattern,
384
+ * which `matchedPattern` alone cannot.
385
+ *
386
+ * `template: null` rather than an omitted key, because the row this lands in is
387
+ * read as data: a consumer asking "did this rule declare a template" must not
388
+ * have to distinguish an absent key from a null one.
389
+ *
390
+ * @param rule - One declared exclude rule
391
+ * @param index - Its 0-based position in the declared array — first-match-wins order
392
+ * @returns The rule's payload, JSON-shaped
393
+ */
394
+ function excludeRulePayload(rule, index) {
395
+ return { ruleIndex: index, template: rule.template ?? null };
396
+ }
397
+ /**
398
+ * A `files:` source stated in projection coordinates — root-relative and
399
+ * forward-slashed, the way `resource_realizations.path` spells it.
400
+ *
401
+ * Mirrors `DeferredArtifacts.from`'s source normalization
402
+ * (`relative(projectRoot, resolve(join(projectRoot, source)))`), which strips a
403
+ * leading `./` and roots an absolute-looking source UNDER the project root. In
404
+ * projection coordinates the project root is the empty prefix, so that
405
+ * expression reduces to a normalizing join plus the leading-separator strip.
406
+ *
407
+ * @param source - A `files:` entry's `source`, authored relative to the project root
408
+ * @returns The same path, root-relative and forward-slashed
409
+ */
410
+ function rootRelativeSource(source) {
411
+ const joined = safePath.join(source);
412
+ return joined.startsWith('/') ? joined.slice(1) : joined;
413
+ }
414
+ /**
415
+ * The `files:`-declared agent-instruction files this skill's closure must admit
416
+ * despite {@link skillExcludeBasenames} refusing their basenames.
417
+ *
418
+ * ⚠️ **The asymmetry here is the walker's cascade ORDER, and it stays in this
419
+ * translation even though the primitive now has a cascade of its own.**
420
+ * `walk-link-graph.ts`'s `classifyExclusion` refuses `navigation-file` BEFORE it
421
+ * reaches the agent-instruction branch, and only the agent-instruction branch
422
+ * carries the explicit-`files:` escape hatch. A `files:`-declared `README.md`
423
+ * linked from a SKILL.md is therefore STILL excluded by the walker, as
424
+ * `navigation-file` — the hatch never gets a chance to run. {@link skillRefusals}
425
+ * reproduces the ORDER, so the reported reason is right; it cannot reproduce the
426
+ * hatch's POSITION, because `admitPaths` outranks the whole cascade rather than
427
+ * sitting inside one branch of it. So the positional fact is discharged HERE, by
428
+ * narrowing which declarations earn `admitPaths` at all — a per-branch escape
429
+ * hatch is a primitive feature nothing else has asked for.
430
+ *
431
+ * "Explicit" is EXACT membership in `DeferredArtifacts.sourcePaths`, which is
432
+ * why a GLOB source earns nothing: `DeferredArtifacts.from` registers a glob by
433
+ * its STATIC BASE (a directory), so a glob's matches are only ever prefix
434
+ * CHILDREN of what is in the set and the walker's exact-equality test refuses
435
+ * them. `refusesAgentInstructionFile` states the reasoning in full: naming a
436
+ * file is an unambiguous instruction to ship it, a glob is a net that never
437
+ * named the file it caught.
438
+ *
439
+ * ⚠️ **One narrowing the walker applies and this cannot.** Both walker lanes
440
+ * build their `DeferredArtifacts` from `partitionTestInputFileEntries(...).kept`
441
+ * (`skill-packager.ts:593`, `packaging-validator.ts:523`), so a `files:` entry
442
+ * whose source lives under a declared `test.evals` suite is dropped before it can
443
+ * earn the hatch. Reproducing that needs `resolveTestInputDirs`, which probes the
444
+ * filesystem and needs the project's whole skill list — neither of which a
445
+ * config→declaration translation has, by construction. A `test.evals`-resident
446
+ * `CLAUDE.md` declared in `files:` would therefore be admitted here and refused
447
+ * by the walker. Unreachable on the real corpus today: the corpus shadow test
448
+ * ("omitting the packager-only walk inputs changes no membership") measures the
449
+ * `test.evals` overlap across all fourteen declared skills and finds it empty.
450
+ *
451
+ * @param config - The skill's packaging block
452
+ * @returns Root-relative paths that outrank every refusal matcher
453
+ */
454
+ function declaredAgentInstructionSources(config) {
455
+ const admitted = [];
456
+ for (const entry of config.files ?? []) {
457
+ if (isGlob(entry.source))
458
+ continue;
459
+ const source = rootRelativeSource(entry.source);
460
+ if (isAgentInstructionBasename(basename(source)))
461
+ admitted.push(source);
462
+ }
463
+ return admitted;
464
+ }
465
+ /**
466
+ * Translate a skill's packaging config into a closure-extent declaration.
467
+ *
468
+ * This is the whole of the skill extent's behaviour: everything else is the
469
+ * generic contributor. `linkFollowDepth` becomes `maxDepth` unchanged (same
470
+ * `number | 'full'` union, same meaning of a hop), and {@link skillRefusals}
471
+ * becomes the cascade — one rule per `classifyExclusion` branch this translation
472
+ * can express, in that function's own order.
473
+ *
474
+ * ⚠️ This paragraph used to say the `excludeReferencesFromBundle` rules
475
+ * "flatten into ONE labelled refusal rule". They have not since the increment
476
+ * that restored `matchedRule`: they expand to one rule EACH, in declared order,
477
+ * which is what lets `realization_conditions.matchedPattern` name WHICH rule
478
+ * caught a file. The `template` it also said the primitive had "nowhere to put"
479
+ * rides in that rule's opaque `payload`.
480
+ *
481
+ * `follow` is left to the schema default (the three markdown forms), matching
482
+ * the walker: it processes only `isLocalFileLink` links off the markdown AST, so
483
+ * an `@`-prefixed or bare token is not an edge on either side.
484
+ *
485
+ * @param config - The skill's `skills.config.<name>` packaging block
486
+ * @param skillPath - The SKILL.md path **relative to the corpus root**, forward-slashed
487
+ * @param hasGitTracker - Whether the population this declaration will run in was
488
+ * given a usable git oracle. Not "should gitignored files be refused": the
489
+ * column that rule reads is unfilled without one, so declaring it anyway would
490
+ * claim a branch that cannot run. REQUIRED rather than defaulted, because a
491
+ * defaulted `false` would let a caller that does have a tracker silently ship a
492
+ * declaration missing the last rule of the cascade — a no-op wearing a fix
493
+ * @returns The declaration, schema-parsed so every default is materialized
494
+ * @throws When the resulting declaration is not schema-valid — e.g. an empty `skillPath`
495
+ */
496
+ export function skillExtentDeclaration(config, skillPath, hasGitTracker) {
497
+ return ExtentDeclarationSchema.parse({
498
+ kind: SKILL_EXTENT_KIND,
499
+ closureFrom: skillPath,
500
+ maxDepth: config.linkFollowDepth ?? DEFAULT_LINK_FOLLOW_DEPTH,
501
+ refusals: skillRefusals(config, hasGitTracker),
502
+ admitPaths: declaredAgentInstructionSources(config),
503
+ });
504
+ }
505
+ /**
506
+ * The skill extent — `ClosureExtentContributor` under a fixed id and kind.
507
+ *
508
+ * Delegation rather than inheritance, and the thinness is the finding: if this
509
+ * class needed to *do* anything, the closure primitive would have been
510
+ * inadequate and the skill contributor would have stayed privileged. It owns
511
+ * only the two things the registry reads before `contribute` runs — a stable
512
+ * `id` for `zone_provenance`, and the `kind` `ContributorRegistry.forKind`
513
+ * partitions on.
514
+ *
515
+ * **One instance per skill**, keyed by {@link skillExtentContributorId}. A fixed
516
+ * id would cap a population at one skill extent, because
517
+ * `ContributorRegistry.register` refuses a duplicate — see that function.
518
+ */
519
+ export class SkillExtentContributor {
520
+ id;
521
+ kind = SKILL_EXTENT_KIND;
522
+ stratum = 'closure';
523
+ /** The generic primitive this contributor is nothing but a naming of. */
524
+ #closure;
525
+ /**
526
+ * Delegated, never restated: this contributor's `contribute` is the
527
+ * delegate's, so whether it reads blob-keyed tables is the delegate's answer
528
+ * and a hard-coded `true` here would be a second copy free to drift.
529
+ */
530
+ get readsBlobs() {
531
+ return this.#closure.readsBlobs;
532
+ }
533
+ /**
534
+ * @param skillName - The skill's name. Discriminates both the contributor id
535
+ * and, through the delegate, the extent's within-root context id — one
536
+ * source for both, so the two cannot drift apart.
537
+ */
538
+ constructor(skillName) {
539
+ this.id = skillExtentContributorId(skillName);
540
+ this.#closure = new ClosureExtentContributor(skillName, SKILL_EXTENT_KIND);
541
+ }
542
+ /**
543
+ * Produce the skill extent by running the closure primitive.
544
+ *
545
+ * Not `async`: the delegate's promise is returned directly, so there is no
546
+ * second microtask and no place for this method to add behaviour.
547
+ *
548
+ * @param base - Everything merged so far — the realizations a reference can
549
+ * resolve to, and the `blob_references` rows that are the edges
550
+ * @param parameters - A {@link skillExtentDeclaration} result, arriving as
551
+ * config data exactly as a user-declared extent would
552
+ * @returns The extent's context, members, realizations and conditions
553
+ */
554
+ contribute(base, parameters) {
555
+ return this.#closure.contribute(base, parameters);
556
+ }
557
+ }
558
+ //# sourceMappingURL=skill-extent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-extent.js","sourceRoot":"","sources":["../../src/projection/skill-extent.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { SKILL_NAME_REGEX, SKILL_NAME_REGEX_MESSAGE } from '@vibe-agent-toolkit/agent-schema';
1
+ import { SKILL_NAME_REGEX, SKILL_NAME_REGEX_MESSAGE } from '@vibe-agent-toolkit/schema';
2
2
  import { z } from 'zod';
3
3
  import { zodToJsonSchema } from 'zod-to-json-schema';
4
4
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"agent-skill-frontmatter.js","sourceRoot":"","sources":["../../src/schemas/agent-skill-frontmatter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-skill-frontmatter.js","sourceRoot":"","sources":["../../src/schemas/agent-skill-frontmatter.ts"],"names":[],"mappings":"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"}