@vibe-agent-toolkit/agent-skills 0.2.0-rc.10 → 0.2.0-rc.12

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 (230) hide show
  1. package/README.md +31 -13
  2. package/dist/builder.d.ts +24 -0
  3. package/dist/builder.d.ts.map +1 -1
  4. package/dist/builder.js +135 -62
  5. package/dist/builder.js.map +1 -1
  6. package/dist/bundle-copy.d.ts +31 -0
  7. package/dist/bundle-copy.d.ts.map +1 -0
  8. package/dist/bundle-copy.js +50 -0
  9. package/dist/bundle-copy.js.map +1 -0
  10. package/dist/evidence/derive-observations.d.ts +2 -2
  11. package/dist/evidence/derive-observations.d.ts.map +1 -1
  12. package/dist/evidence/derive-observations.js +4 -4
  13. package/dist/evidence/derive-observations.js.map +1 -1
  14. package/dist/evidence/types.d.ts +2 -2
  15. package/dist/evidence/types.d.ts.map +1 -1
  16. package/dist/files-config.d.ts +9 -2
  17. package/dist/files-config.d.ts.map +1 -1
  18. package/dist/files-config.js +116 -109
  19. package/dist/files-config.js.map +1 -1
  20. package/dist/import.d.ts +21 -2
  21. package/dist/import.d.ts.map +1 -1
  22. package/dist/import.js +46 -31
  23. package/dist/import.js.map +1 -1
  24. package/dist/index.d.ts +13 -8
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +15 -7
  27. package/dist/index.js.map +1 -1
  28. package/dist/inventory/index.d.ts +2 -1
  29. package/dist/inventory/index.d.ts.map +1 -1
  30. package/dist/inventory/index.js +1 -1
  31. package/dist/inventory/index.js.map +1 -1
  32. package/dist/inventory/serialize.d.ts +5796 -22
  33. package/dist/inventory/serialize.d.ts.map +1 -1
  34. package/dist/inventory/serialize.js +145 -33
  35. package/dist/inventory/serialize.js.map +1 -1
  36. package/dist/inventory/types.d.ts +3 -3
  37. package/dist/inventory/types.d.ts.map +1 -1
  38. package/dist/packaging-errors.d.ts +73 -0
  39. package/dist/packaging-errors.d.ts.map +1 -0
  40. package/dist/packaging-errors.js +96 -0
  41. package/dist/packaging-errors.js.map +1 -0
  42. package/dist/plugin-distribution-layout.d.ts +9 -3
  43. package/dist/plugin-distribution-layout.d.ts.map +1 -1
  44. package/dist/plugin-distribution-layout.js +19 -8
  45. package/dist/plugin-distribution-layout.js.map +1 -1
  46. package/dist/post-build-checks.d.ts +1 -1
  47. package/dist/post-build-checks.d.ts.map +1 -1
  48. package/dist/post-build-checks.js +36 -30
  49. package/dist/post-build-checks.js.map +1 -1
  50. package/dist/projection/skill-extent.d.ts +2 -2
  51. package/dist/projection/skill-extent.js +2 -2
  52. package/dist/skill-packager.d.ts +188 -8
  53. package/dist/skill-packager.d.ts.map +1 -1
  54. package/dist/skill-packager.js +688 -351
  55. package/dist/skill-packager.js.map +1 -1
  56. package/dist/skill-source/content-hash.d.ts +1 -0
  57. package/dist/skill-source/content-hash.d.ts.map +1 -1
  58. package/dist/skill-source/content-hash.js +16 -9
  59. package/dist/skill-source/content-hash.js.map +1 -1
  60. package/dist/skill-source/fetch-cache.d.ts +7 -1
  61. package/dist/skill-source/fetch-cache.d.ts.map +1 -1
  62. package/dist/skill-source/fetch-cache.js +54 -27
  63. package/dist/skill-source/fetch-cache.js.map +1 -1
  64. package/dist/skill-source/git-clone.d.ts +18 -0
  65. package/dist/skill-source/git-clone.d.ts.map +1 -1
  66. package/dist/skill-source/git-clone.js +207 -24
  67. package/dist/skill-source/git-clone.js.map +1 -1
  68. package/dist/skill-source/resolve-skill-source.d.ts +15 -0
  69. package/dist/skill-source/resolve-skill-source.d.ts.map +1 -1
  70. package/dist/skill-source/resolve-skill-source.js +23 -1
  71. package/dist/skill-source/resolve-skill-source.js.map +1 -1
  72. package/dist/skill-source/source-errors.d.ts +40 -0
  73. package/dist/skill-source/source-errors.d.ts.map +1 -0
  74. package/dist/skill-source/source-errors.js +47 -0
  75. package/dist/skill-source/source-errors.js.map +1 -0
  76. package/dist/skill-source/sources/npm-source.d.ts +25 -3
  77. package/dist/skill-source/sources/npm-source.d.ts.map +1 -1
  78. package/dist/skill-source/sources/npm-source.js +76 -19
  79. package/dist/skill-source/sources/npm-source.js.map +1 -1
  80. package/dist/skill-source/sources/path-source.js +1 -1
  81. package/dist/skill-source/sources/path-source.js.map +1 -1
  82. package/dist/skill-source/sources/url-source.d.ts +10 -4
  83. package/dist/skill-source/sources/url-source.d.ts.map +1 -1
  84. package/dist/skill-source/sources/url-source.js +107 -45
  85. package/dist/skill-source/sources/url-source.js.map +1 -1
  86. package/dist/skill-source/sources/vendored-source.js +1 -1
  87. package/dist/skill-source/sources/vendored-source.js.map +1 -1
  88. package/dist/skill-source/sources/workspace-source.d.ts.map +1 -1
  89. package/dist/skill-source/sources/workspace-source.js +6 -11
  90. package/dist/skill-source/sources/workspace-source.js.map +1 -1
  91. package/dist/skill-source/stage.d.ts +12 -0
  92. package/dist/skill-source/stage.d.ts.map +1 -1
  93. package/dist/skill-source/stage.js +65 -34
  94. package/dist/skill-source/stage.js.map +1 -1
  95. package/dist/skill-source/types.d.ts +7 -0
  96. package/dist/skill-source/types.d.ts.map +1 -1
  97. package/dist/skill-test/baseline-delta.d.ts +27 -27
  98. package/dist/skill-test/baseline-integrity.d.ts +9 -9
  99. package/dist/skill-test/build-hook.d.ts +8 -1
  100. package/dist/skill-test/build-hook.d.ts.map +1 -1
  101. package/dist/skill-test/build-hook.js +3 -2
  102. package/dist/skill-test/build-hook.js.map +1 -1
  103. package/dist/skill-test/eval-fragment.d.ts +19 -6
  104. package/dist/skill-test/eval-fragment.d.ts.map +1 -1
  105. package/dist/skill-test/eval-fragment.js +5 -4
  106. package/dist/skill-test/eval-fragment.js.map +1 -1
  107. package/dist/skill-test/eval-grader.d.ts.map +1 -1
  108. package/dist/skill-test/eval-grader.js +6 -3
  109. package/dist/skill-test/eval-grader.js.map +1 -1
  110. package/dist/skill-test/eval-inputs.d.ts +10 -4
  111. package/dist/skill-test/eval-inputs.d.ts.map +1 -1
  112. package/dist/skill-test/eval-inputs.js +93 -42
  113. package/dist/skill-test/eval-inputs.js.map +1 -1
  114. package/dist/skill-test/eval-suite-isolation.d.ts +1 -1
  115. package/dist/skill-test/eval-suite-isolation.d.ts.map +1 -1
  116. package/dist/skill-test/eval-suite-isolation.js +30 -9
  117. package/dist/skill-test/eval-suite-isolation.js.map +1 -1
  118. package/dist/skill-test/evals-template.d.ts.map +1 -1
  119. package/dist/skill-test/evals-template.js +4 -3
  120. package/dist/skill-test/evals-template.js.map +1 -1
  121. package/dist/skill-test/failure-reason.d.ts +83 -2
  122. package/dist/skill-test/failure-reason.d.ts.map +1 -1
  123. package/dist/skill-test/failure-reason.js +93 -4
  124. package/dist/skill-test/failure-reason.js.map +1 -1
  125. package/dist/skill-test/friction-schema.d.ts +53 -10
  126. package/dist/skill-test/friction-schema.d.ts.map +1 -1
  127. package/dist/skill-test/friction-schema.js +28 -2
  128. package/dist/skill-test/friction-schema.js.map +1 -1
  129. package/dist/skill-test/grader-text.d.ts +1 -1
  130. package/dist/skill-test/grader-text.js +2 -2
  131. package/dist/skill-test/harness-location.d.ts +14 -3
  132. package/dist/skill-test/harness-location.d.ts.map +1 -1
  133. package/dist/skill-test/harness-location.js +41 -15
  134. package/dist/skill-test/harness-location.js.map +1 -1
  135. package/dist/skill-test/index.d.ts +2 -2
  136. package/dist/skill-test/index.d.ts.map +1 -1
  137. package/dist/skill-test/index.js +2 -2
  138. package/dist/skill-test/index.js.map +1 -1
  139. package/dist/skill-test/lock.d.ts +15 -21
  140. package/dist/skill-test/lock.d.ts.map +1 -1
  141. package/dist/skill-test/lock.js +29 -42
  142. package/dist/skill-test/lock.js.map +1 -1
  143. package/dist/skill-test/pipeline.d.ts.map +1 -1
  144. package/dist/skill-test/pipeline.js +30 -29
  145. package/dist/skill-test/pipeline.js.map +1 -1
  146. package/dist/skill-test/plugin-layout.d.ts +4 -3
  147. package/dist/skill-test/plugin-layout.d.ts.map +1 -1
  148. package/dist/skill-test/plugin-layout.js +4 -3
  149. package/dist/skill-test/plugin-layout.js.map +1 -1
  150. package/dist/skill-test/preflight.d.ts +20 -3
  151. package/dist/skill-test/preflight.d.ts.map +1 -1
  152. package/dist/skill-test/preflight.js +49 -15
  153. package/dist/skill-test/preflight.js.map +1 -1
  154. package/dist/skill-test/run-harness.d.ts +68 -34
  155. package/dist/skill-test/run-harness.d.ts.map +1 -1
  156. package/dist/skill-test/run-harness.js +244 -116
  157. package/dist/skill-test/run-harness.js.map +1 -1
  158. package/dist/skill-test/staging.d.ts +6 -0
  159. package/dist/skill-test/staging.d.ts.map +1 -1
  160. package/dist/skill-test/staging.js +56 -29
  161. package/dist/skill-test/staging.js.map +1 -1
  162. package/dist/skill-test/vendor-manifest.d.ts.map +1 -1
  163. package/dist/skill-test/vendor-manifest.js +7 -5
  164. package/dist/skill-test/vendor-manifest.js.map +1 -1
  165. package/dist/skill-zip-layout.d.ts +45 -0
  166. package/dist/skill-zip-layout.d.ts.map +1 -0
  167. package/dist/skill-zip-layout.js +64 -0
  168. package/dist/skill-zip-layout.js.map +1 -0
  169. package/dist/test-input.d.ts.map +1 -1
  170. package/dist/test-input.js +4 -3
  171. package/dist/test-input.js.map +1 -1
  172. package/dist/validators/agent-instruction-presence.d.ts +4 -1
  173. package/dist/validators/agent-instruction-presence.d.ts.map +1 -1
  174. package/dist/validators/agent-instruction-presence.js +8 -4
  175. package/dist/validators/agent-instruction-presence.js.map +1 -1
  176. package/dist/validators/bundled-resource-link-detection.d.ts +4 -1
  177. package/dist/validators/bundled-resource-link-detection.d.ts.map +1 -1
  178. package/dist/validators/bundled-resource-link-detection.js +16 -8
  179. package/dist/validators/bundled-resource-link-detection.js.map +1 -1
  180. package/dist/validators/compat-detectors.js +1 -1
  181. package/dist/validators/compat-detectors.js.map +1 -1
  182. package/dist/validators/describe-issues.d.ts +18 -0
  183. package/dist/validators/describe-issues.d.ts.map +1 -0
  184. package/dist/validators/describe-issues.js +40 -0
  185. package/dist/validators/describe-issues.js.map +1 -0
  186. package/dist/validators/format-detection.d.ts.map +1 -1
  187. package/dist/validators/format-detection.js +31 -23
  188. package/dist/validators/format-detection.js.map +1 -1
  189. package/dist/validators/frontmatter-validation.d.ts +7 -0
  190. package/dist/validators/frontmatter-validation.d.ts.map +1 -1
  191. package/dist/validators/frontmatter-validation.js +249 -11
  192. package/dist/validators/frontmatter-validation.js.map +1 -1
  193. package/dist/validators/marketplace-validator.d.ts +25 -0
  194. package/dist/validators/marketplace-validator.d.ts.map +1 -1
  195. package/dist/validators/marketplace-validator.js +62 -21
  196. package/dist/validators/marketplace-validator.js.map +1 -1
  197. package/dist/validators/packaged-size-limit.d.ts +6 -9
  198. package/dist/validators/packaged-size-limit.d.ts.map +1 -1
  199. package/dist/validators/packaged-size-limit.js +2 -2
  200. package/dist/validators/packaged-size-limit.js.map +1 -1
  201. package/dist/validators/packaging-validator.d.ts +37 -12
  202. package/dist/validators/packaging-validator.d.ts.map +1 -1
  203. package/dist/validators/packaging-validator.js +107 -41
  204. package/dist/validators/packaging-validator.js.map +1 -1
  205. package/dist/validators/plugin-hosted-shape.d.ts.map +1 -1
  206. package/dist/validators/plugin-hosted-shape.js +6 -5
  207. package/dist/validators/plugin-hosted-shape.js.map +1 -1
  208. package/dist/validators/referenced-path-missing.d.ts +1 -1
  209. package/dist/validators/referenced-path-missing.d.ts.map +1 -1
  210. package/dist/validators/referenced-path-missing.js +12 -8
  211. package/dist/validators/referenced-path-missing.js.map +1 -1
  212. package/dist/validators/registry-validator.d.ts.map +1 -1
  213. package/dist/validators/registry-validator.js +21 -25
  214. package/dist/validators/registry-validator.js.map +1 -1
  215. package/dist/validators/skill-validator.d.ts.map +1 -1
  216. package/dist/validators/skill-validator.js +49 -18
  217. package/dist/validators/skill-validator.js.map +1 -1
  218. package/dist/validators/types.d.ts +28 -14
  219. package/dist/validators/types.d.ts.map +1 -1
  220. package/dist/validators/unified-validator.d.ts.map +1 -1
  221. package/dist/validators/unified-validator.js +5 -6
  222. package/dist/validators/unified-validator.js.map +1 -1
  223. package/dist/walk-link-graph.js +3 -1
  224. package/dist/walk-link-graph.js.map +1 -1
  225. package/package.json +7 -7
  226. package/schemas/friction-report.json +3 -3
  227. package/dist/fs-attribution.d.ts +0 -45
  228. package/dist/fs-attribution.d.ts.map +0 -1
  229. package/dist/fs-attribution.js +0 -57
  230. package/dist/fs-attribution.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"derive-observations.js","sourceRoot":"","sources":["../../src/evidence/derive-observations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"derive-observations.js","sourceRoot":"","sources":["../../src/evidence/derive-observations.ts"],"names":[],"mappings":"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"}
@@ -40,8 +40,8 @@ export interface PatternDefinition {
40
40
  export interface Observation {
41
41
  /** Validation code (e.g. 'CAPABILITY_LOCAL_SHELL'). */
42
42
  code: string;
43
- /** Human-readable claim. */
44
- summary: string;
43
+ /** Human-readable claim, one sentence. Never `summary`: that name always means severity counts. */
44
+ description: string;
45
45
  /** Payload specific to the observation code. */
46
46
  payload?: Record<string, unknown>;
47
47
  /** patternId[] of evidence records that support this observation. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/evidence/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,oCAAoC;AACpC,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,IAAI,CAAC;AAE3C,mDAAmD;AACnD,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,cAAc,CAAC;IACvB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,kBAAkB,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,qEAAqE;IACrE,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/evidence/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,oCAAoC;AACpC,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,IAAI,CAAC;AAE3C,mDAAmD;AACnD,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,cAAc,CAAC;IACvB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,kBAAkB,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,qEAAqE;IACrE,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B"}
@@ -53,7 +53,7 @@ export interface AppliedFilesConfig {
53
53
  *
54
54
  * Returned rather than written to a `warn` sink because a file vanishing from
55
55
  * a bundle is a build FINDING, not a log line: it has to reach the structured
56
- * report (`issueCounts`), or a CI consumer reads `warnings: 0` for a build
56
+ * report's counts (`summary`), or a CI consumer reads `warnings: 0` for a build
57
57
  * that silently shipped less than the config asked for.
58
58
  */
59
59
  dropped: DroppedGlobMatch[];
@@ -184,8 +184,15 @@ export interface ApplyFilesConfigOptions {
184
184
  * missing dest. Intended to be called after a copy operation to assert the
185
185
  * copy was faithful. Exported so it can be tested directly without running a
186
186
  * full applyFilesConfig round-trip.
187
+ *
188
+ * The check reads BOTH trees, so each read is guarded as the side it touches: a
189
+ * source the OS will not read is the skill's refusal, a dest it will not stat or
190
+ * read is the output's. One guard over the whole pair coded a dest-side errno as
191
+ * the skill's, with a remedy pointing at the source.
192
+ *
193
+ * @param subject - The `files:` entry, phrased for the refusal's message
187
194
  */
188
- export declare function verifyFilesIntegrity(pairs: {
195
+ export declare function verifyFilesIntegrity(subject: string, pairs: {
189
196
  absSource: string;
190
197
  absDest: string;
191
198
  }[]): void;
@@ -1 +1 @@
1
- {"version":3,"file":"files-config.d.ts","sourceRoot":"","sources":["../src/files-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"files-config.d.ts","sourceRoot":"","sources":["../src/files-config.ts"],"names":[],"mappings":"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"}
@@ -7,13 +7,12 @@
7
7
  * - Computing deferred paths for validation
8
8
  * - Copying declared build artifacts into a skill output dir (every build path)
9
9
  */
10
- import { statSync } from 'node:fs';
11
- import { copyFile, lstat, mkdir, stat } from 'node:fs/promises';
12
- import { dirname } from 'node:path';
13
- import { fileContentHash, globMagicRemainder, hasParentTraversalSegment, isFilesystemAccessError, isGlob, issueLocation, safePath, staticGlobBase, toForwardSlash, toForwardSlashAnyPlatform, } from '@vibe-agent-toolkit/utils';
10
+ import { lstat } from 'node:fs/promises';
11
+ import { classifyFsFault, fileContentHash, followedKind, followedStatSync, fsFaultOf, globMagicRemainder, hasParentTraversalSegment, isGlob, isLinkChainRefusedError, forEachInOrder, issueLocation, mapWithConcurrency, safePath, staticGlobBase, toForwardSlash, toForwardSlashAnyPlatform, withFsFault, withFsFaultSync, } from '@vibe-agent-toolkit/utils';
14
12
  import { glob } from 'glob';
15
13
  import picomatch from 'picomatch';
16
- import { withFsAttribution } from './fs-attribution.js';
14
+ import { copyIntoBundle } from './bundle-copy.js';
15
+ import { packagingInputError } from './packaging-errors.js';
17
16
  import { materializeIssue } from './validators/rule-engine/index.js';
18
17
  import { isNeverPackagedBasename } from './validators/validation-rules.js';
19
18
  /**
@@ -75,10 +74,10 @@ async function partitionRegularFiles(matches, absoluteBase) {
75
74
  // caller's sorted order regardless of completion order — `droppedRel` and
76
75
  // `nonRegularRel` are rendered into error messages an adopter reads, and a set
77
76
  // that reshuffles between runs is a diff for no reason.
78
- const copyable = await mapWithConcurrency(matches, STAT_CONCURRENCY, (rel) =>
77
+ const copyable = await mapWithConcurrency(matches, (rel) =>
79
78
  // joinUnderRoot asserts the match stays under absoluteBase, the same guard the
80
79
  // copy loop applies before reading it.
81
- isCopyableFile(safePath.joinUnderRoot(absoluteBase, rel)));
80
+ isCopyableFile(safePath.joinUnderRoot(absoluteBase, rel), absoluteBase));
82
81
  const regular = [];
83
82
  const nonRegular = [];
84
83
  for (const [i, rel] of matches.entries()) {
@@ -86,25 +85,6 @@ async function partitionRegularFiles(matches, absoluteBase) {
86
85
  }
87
86
  return { regular, nonRegular };
88
87
  }
89
- /**
90
- * Enough parallelism to hide per-call latency, low enough to stay far from the
91
- * default file-descriptor ceiling even with several skills building at once.
92
- */
93
- const STAT_CONCURRENCY = 16;
94
- /** `Promise.all`-shaped, but with at most `limit` calls in flight. Order preserved. */
95
- async function mapWithConcurrency(items, limit, fn) {
96
- const results = Array.from({ length: items.length });
97
- let next = 0;
98
- const worker = async () => {
99
- while (next < items.length) {
100
- const i = next++;
101
- // Non-null: `i` is always a valid index, guarded by the loop condition.
102
- results[i] = await fn(items[i]);
103
- }
104
- };
105
- await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
106
- return results;
107
- }
108
88
  /**
109
89
  * Whether `copyFile` can read this path as a stream of bytes.
110
90
  *
@@ -114,17 +94,25 @@ async function mapWithConcurrency(items, limit, fn) {
114
94
  * would move. A dangling link, or one resolving to a directory, throws from `stat`
115
95
  * and is reported as not copyable rather than escaping as the build's whole
116
96
  * explanation.
97
+ *
98
+ * The link is followed only once its chain is read beneath `within` (the glob's
99
+ * base, in the operator's project): a chain VAT will not hand the kernel — a link
100
+ * to a network or device path — is a refusal on the source side, thrown, never a
101
+ * quiet "not copyable".
117
102
  */
118
- async function isCopyableFile(absPath) {
103
+ async function isCopyableFile(absPath, within) {
119
104
  try {
120
105
  const linkStat = await lstat(absPath);
121
106
  if (linkStat.isFile())
122
107
  return true;
123
108
  if (!linkStat.isSymbolicLink())
124
109
  return false;
125
- return (await stat(absPath)).isFile();
110
+ return (await followedKind(absPath, within)) === 'file';
126
111
  }
127
112
  catch (error) {
113
+ if (isLinkChainRefusedError(error)) {
114
+ throw classifyFsFault(error, { side: 'source', origin: 'content', action: `examine ${absPath}` });
115
+ }
128
116
  // Unreadable or dangling. Not copyable is the honest answer, and the caller
129
117
  // reports it as a named finding — which is strictly more than the raw errno
130
118
  // this replaces ever gave.
@@ -132,9 +120,14 @@ async function isCopyableFile(absPath) {
132
120
  // Narrowed to filesystem errors on purpose: a bare `catch {}` here would
133
121
  // answer "not a regular file" to a bug in our own code, silently converting a
134
122
  // defect into a routine skip. Same predicate the audit walk uses, from one
135
- // shared source so the two cannot drift.
136
- if (!isFilesystemAccessError(error))
123
+ // shared source so the two cannot drift. A machine that ran out (`exhausted`,
124
+ // `busy`) says nothing about the match: thrown, classified, never a skip.
125
+ const faultClass = fsFaultOf(error)?.faultClass;
126
+ if (faultClass === undefined)
137
127
  throw error;
128
+ if (faultClass === 'exhausted' || faultClass === 'busy') {
129
+ throw classifyFsFault(error, { side: 'source', origin: 'content', action: `examine ${absPath}` });
130
+ }
138
131
  return false;
139
132
  }
140
133
  }
@@ -155,8 +148,16 @@ async function isCopyableFile(absPath) {
155
148
  * text is kept verbatim inside it, because it is what distinguishes a permission
156
149
  * problem from a full disk from a vanished mount.
157
150
  */
158
- async function attributed(entry, absPath, projectRoot, work, action) {
159
- return withFsAttribution(`files: source '${entry.source}' resolved to ${anchoredPath(absPath, projectRoot)}`, work, action);
151
+ function attributed(entry, absPath, projectRoot, work) {
152
+ return withFsFault({ side: 'source', origin: 'content', action: `read ${entrySubject(entry, absPath, projectRoot)}` }, () => Promise.resolve(work()));
153
+ }
154
+ /** How a failure names a `files:` entry: the `source:` the author wrote, and where it resolved. */
155
+ function entrySubject(entry, absPath, projectRoot) {
156
+ return `files: source '${entry.source}' resolved to ${anchoredPath(absPath, projectRoot)}`;
157
+ }
158
+ /** Copy one file a `files:` entry names into the bundle, each side's refusal coded as that side's. */
159
+ function copyEntryFile(entry, absSource, bundle, projectRoot) {
160
+ return copyIntoBundle(entrySubject(entry, absSource, projectRoot), absSource, bundle.root, bundle.dest);
160
161
  }
161
162
  /**
162
163
  * Turn never-package drops into reportable findings.
@@ -217,7 +218,7 @@ function globMatchesToIssues(matches, locationRoot, code) {
217
218
  *
218
219
  * Load-bearing for every THROWN message in this module, not only for issue
219
220
  * locations: `applyFilesConfig`'s throws reach `vat skills build`'s stdout
220
- * verbatim as `failedSkills[].message`, so an absolute path there publishes the
221
+ * verbatim as a `SKILL_PACKAGING_FAILED` finding's `message`, so an absolute path there publishes the
221
222
  * developer's home directory into whatever issue or CI log the report is pasted
222
223
  * into. Build-report messages are project-relative, never absolute.
223
224
  */
@@ -311,7 +312,7 @@ export function mergeFilesConfig(defaults, perSkill) {
311
312
  for (const entry of perSkill) {
312
313
  const normalized = normalizeRelPath(entry.dest);
313
314
  if (destSet.has(normalized)) {
314
- throw new Error(`Duplicate dest in per-skill files config: '${entry.dest}'. ` +
315
+ throw packagingInputError(`Duplicate dest in per-skill files config: '${entry.dest}'. ` +
315
316
  `Each dest must be unique within a skill's files configuration.`);
316
317
  }
317
318
  destSet.add(normalized);
@@ -369,30 +370,38 @@ export function explicitFilesConfigDests(files) {
369
370
  * missing dest. Intended to be called after a copy operation to assert the
370
371
  * copy was faithful. Exported so it can be tested directly without running a
371
372
  * full applyFilesConfig round-trip.
373
+ *
374
+ * The check reads BOTH trees, so each read is guarded as the side it touches: a
375
+ * source the OS will not read is the skill's refusal, a dest it will not stat or
376
+ * read is the output's. One guard over the whole pair coded a dest-side errno as
377
+ * the skill's, with a remedy pointing at the source.
378
+ *
379
+ * @param subject - The `files:` entry, phrased for the refusal's message
372
380
  */
373
- export function verifyFilesIntegrity(pairs) {
381
+ export function verifyFilesIntegrity(subject, pairs) {
374
382
  for (const { absSource, absDest } of pairs) {
375
- // `statSync` in a guard rather than `existsSync`, because `existsSync`
376
- // answers FALSE for a file that is present but unreadable — so a permissions
377
- // problem on the dest was reported as "dest file missing", sending the author
378
- // to look for a file that is sitting right there. Only a real ENOENT is
379
- // missing; anything else is the filesystem refusing the path, and is rethrown
380
- // for the caller to attribute to the `files:` entry.
381
- try {
382
- statSync(absDest);
383
- }
384
- catch (error) {
385
- if (error.code !== 'ENOENT')
386
- throw error;
387
- throw new Error(`files: integrity check failed — dest file missing: ${toForwardSlash(absDest)}`);
388
- }
389
- const srcHash = fileContentHash(absSource);
390
- const dstHash = fileContentHash(absDest);
383
+ const srcHash = withFsFaultSync({ side: 'source', origin: 'content', action: `read ${subject} for verification` }, () => fileContentHash(absSource));
384
+ const dstHash = withFsFaultSync({ side: 'destination', shapeFromSource: true, action: `verify ${subject} in the bundle` }, () => destContentHash(absDest));
391
385
  if (srcHash !== dstHash) {
392
386
  throw new Error(`files: integrity check failed — content mismatch at dest: ${toForwardSlash(absDest)}`);
393
387
  }
394
388
  }
395
389
  }
390
+ /**
391
+ * The dest's content hash. A followed `stat` in a guard rather than `existsSync`,
392
+ * because `existsSync` answers FALSE for a file that is present but unreadable —
393
+ * so a permissions problem on the dest was reported as "dest file missing",
394
+ * sending the author to look for a file that is sitting right there. Only
395
+ * resolving to nothing is missing; anything else is the filesystem refusing the
396
+ * path, and is rethrown for the caller's guard to code.
397
+ */
398
+ function destContentHash(absDest) {
399
+ // The dest is the file this build just wrote — VAT's own path, so it is its own tree.
400
+ if (followedStatSync(absDest, absDest) === undefined) {
401
+ throw new Error(`files: integrity check failed — dest file missing: ${toForwardSlash(absDest)}`);
402
+ }
403
+ return fileContentHash(absDest);
404
+ }
396
405
  /**
397
406
  * Verify that the on-disk contents of a glob entry's dest subtree EXACTLY match
398
407
  * the set of rel paths the copy step intended to write — no missing, no extra.
@@ -449,31 +458,36 @@ export async function verifyDestSet(destDir, expectedRel, source) {
449
458
  * Throws on missing source or if source is a directory.
450
459
  */
451
460
  async function copyNonGlobEntry(entry, absoluteSource, projectRoot, skillOutputDir) {
452
- // `statSync` in a guard, not `existsSync`: `existsSync` swallows EACCES and
461
+ // A followed `stat` in a guard, not `existsSync`: `existsSync` swallows EACCES and
453
462
  // answers FALSE, so a source the process merely cannot REACH — one under a
454
463
  // directory it lacks permission to traverse — was reported as "does not exist".
455
464
  // For a `dist/` source that also appended `buildArtifactHint`, telling the
456
465
  // author to run a build that would not have helped: a confidently wrong
457
- // diagnosis plus a confidently wrong remedy. Only ENOENT is absence; anything
458
- // else is the filesystem refusing the path, and `attributed` at the call site
459
- // names the entry.
460
- let sourceStat;
461
- try {
462
- sourceStat = statSync(absoluteSource);
463
- }
464
- catch (error) {
465
- if (error.code !== 'ENOENT')
466
- throw error;
467
- throw new Error(`files: source '${entry.source}' does not exist (resolved to ${anchoredPath(absoluteSource, projectRoot)}).${buildArtifactHint(entry.source)}`);
468
- }
469
- if (sourceStat.isDirectory()) {
470
- throw new Error(`files: source '${entry.source}' is a directory; use a glob like '${entry.source}/**/*' to copy its contents.`);
471
- }
466
+ // diagnosis plus a confidently wrong remedy. Only resolving to nothing is absence; anything
467
+ // else is the filesystem refusing the path, and `attributed` names the entry.
468
+ //
469
+ // The source's `stat` is guarded as well as its copy. Guarding the copy alone
470
+ // left a source under a directory the process cannot traverse escaping as a bare
471
+ // errno — and an EXPLICIT entry is the spelling that unambiguously says "ship
472
+ // this file", so the build owes its author an error that names it back. (The two
473
+ // deliberate errors below carry no errno, so `attributed` passes them through.)
474
+ //
475
+ // The source is crawled beneath the project root: its link chain is read by its
476
+ // text before the kernel follows it, and a chain VAT will not hand the kernel is
477
+ // a refusal `attributed` names, never "does not exist".
478
+ await attributed(entry, absoluteSource, projectRoot, () => {
479
+ const sourceStat = followedStatSync(absoluteSource, projectRoot);
480
+ if (sourceStat === undefined) {
481
+ throw packagingInputError(`files: source '${entry.source}' does not exist (resolved to ${anchoredPath(absoluteSource, projectRoot)}).${buildArtifactHint(entry.source)}`);
482
+ }
483
+ if (sourceStat.isDirectory()) {
484
+ throw packagingInputError(`files: source '${entry.source}' is a directory; use a glob like '${entry.source}/**/*' to copy its contents.`);
485
+ }
486
+ });
472
487
  // joinUnderRoot rejects a dest that escapes the skill output dir (absolute /
473
488
  // drive-letter / '..'), defense-in-depth beyond the schema refine.
474
489
  const absoluteDest = safePath.joinUnderRoot(skillOutputDir, entry.dest);
475
- await mkdir(dirname(absoluteDest), { recursive: true });
476
- await copyFile(absoluteSource, absoluteDest);
490
+ await copyEntryFile(entry, absoluteSource, { root: skillOutputDir, dest: absoluteDest }, projectRoot);
477
491
  return { relDest: normalizeRelPath(entry.dest), absSource: absoluteSource, absDest: absoluteDest };
478
492
  }
479
493
  /**
@@ -497,7 +511,7 @@ async function copyNonGlobEntry(entry, absoluteSource, projectRoot, skillOutputD
497
511
  async function expandGlobEntry(entry, projectRoot) {
498
512
  const remainder = globMagicRemainder(entry.source);
499
513
  if (hasParentTraversalSegment(remainder)) {
500
- throw new Error(`files: source '${entry.source}' (glob) has a '..' segment in its glob portion ('${remainder}'); ` +
514
+ throw packagingInputError(`files: source '${entry.source}' (glob) has a '..' segment in its glob portion ('${remainder}'); ` +
501
515
  `parent-directory traversal is not allowed after the static base.`);
502
516
  }
503
517
  const absoluteBase = safePath.resolve(safePath.join(projectRoot, staticGlobBase(entry.source)));
@@ -550,17 +564,17 @@ async function expandGlobEntry(entry, projectRoot) {
550
564
  async function copyGlobEntry(entry, projectRoot, skillOutputDir) {
551
565
  const { absoluteBase, allMatches, kept: matches, droppedRel, dropped, nonRegularRel, nonRegular, } = await expandGlobEntry(entry, projectRoot);
552
566
  // Project-relative in both throws below: these messages are published verbatim
553
- // as `failedSkills[].message` (see {@link anchoredPath}).
567
+ // as a `SKILL_PACKAGING_FAILED` finding's `message` (see {@link anchoredPath}).
554
568
  const reportedBase = anchoredPath(absoluteBase, projectRoot);
555
569
  if (allMatches.length === 0) {
556
- throw new Error(`files: source '${entry.source}' (glob) matched no files under ${reportedBase} — has your build run?`);
570
+ throw packagingInputError(`files: source '${entry.source}' (glob) matched no files under ${reportedBase} — has your build run?`);
557
571
  }
558
572
  // Ordered BEFORE the never-package throw because it is the more specific
559
573
  // diagnosis: if the entry nets nothing shippable and nothing it netted was even
560
574
  // a file, "all of them are never packaged" names the wrong cause and its
561
575
  // remediation ("declare an explicit source: entry") would not work if followed.
562
576
  if (matches.length === 0 && droppedRel.length === 0) {
563
- throw new Error(`files: source '${entry.source}' (glob) matched ${allMatches.length} path(s) under ${reportedBase}, ` +
577
+ throw packagingInputError(`files: source '${entry.source}' (glob) matched ${allMatches.length} path(s) under ${reportedBase}, ` +
564
578
  `but none of them is a regular file (a symlink to a directory, a FIFO, a socket or a device node ` +
565
579
  `cannot be packaged): ${nonRegularRel.join(', ')}. ` +
566
580
  `Point the glob at files, or replace the link with the directory it targets.`);
@@ -578,7 +592,7 @@ async function copyGlobEntry(entry, projectRoot, skillOutputDir) {
578
592
  ? ''
579
593
  : ` A further ${nonRegularRel.length.toString()} match(es) are not regular files and could not ` +
580
594
  `be packaged either: ${nonRegularRel.join(', ')}.`;
581
- throw new Error(`files: source '${entry.source}' (glob) matched ${allMatches.length} file(s) under ${reportedBase}, ` +
595
+ throw packagingInputError(`files: source '${entry.source}' (glob) matched ${allMatches.length} file(s) under ${reportedBase}, ` +
582
596
  `but all of them are never packaged into a skill bundle: ${droppedRel.join(', ')}. ` +
583
597
  // NOT "widen the glob": the filter is on basename and applies at any width, so a
584
598
  // wider glob clears this error while still shipping none of these files — advice
@@ -593,7 +607,8 @@ async function copyGlobEntry(entry, projectRoot, skillOutputDir) {
593
607
  // which equals the matched `rel` for files actually copied — the expected set
594
608
  // verifyDestSet diffs the on-disk subtree against.
595
609
  const rels = [];
596
- for (const rel of matches) {
610
+ // In order: bundle writes, where the first failure names the first match.
611
+ await forEachInOrder(matches, async (rel) => {
597
612
  // joinUnderRoot asserts each matched file stays under absoluteBase (read) and
598
613
  // that the rebased dest stays under the skill output dir (write) — H1/H2
599
614
  // defense-in-depth against a traversal that slipped past earlier guards.
@@ -611,14 +626,11 @@ async function copyGlobEntry(entry, projectRoot, skillOutputDir) {
611
626
  // the author DECLARED and expects in the bundle, so shipping silently without
612
627
  // it would change the artifact behind their back. A non-regular match can
613
628
  // never be packaged at all, which is why that one degrades instead.
614
- await attributed(entry, absSource, projectRoot, async () => {
615
- await mkdir(dirname(absDest), { recursive: true });
616
- await copyFile(absSource, absDest);
617
- });
629
+ await copyEntryFile(entry, absSource, { root: skillOutputDir, dest: absDest }, projectRoot);
618
630
  copied.push(relDest);
619
631
  pairs.push({ absSource, absDest });
620
632
  rels.push(toForwardSlash(rel));
621
- }
633
+ });
622
634
  return { copied, pairs, rels, dropped, skipped: nonRegular };
623
635
  }
624
636
  /**
@@ -666,9 +678,10 @@ export async function collectPreBuildGlobFindings(filesConfig, projectRoot) {
666
678
  const allRefused = [];
667
679
  const unmatched = [];
668
680
  const skipped = [];
669
- for (const entry of filesConfig) {
681
+ // In order: `expandGlobEntry`'s throws must fire in `copyGlobEntry`'s order.
682
+ await forEachInOrder(filesConfig, async (entry) => {
670
683
  if (!isGlob(entry.source))
671
- continue;
684
+ return;
672
685
  // A '..' segment in the magic remainder is a malformed pattern that
673
686
  // `expandGlobEntry` refuses to expand. It is the BUILD's error to raise (and
674
687
  // `copyGlobEntry` does); a pre-build gate asking "what would this do?" must not
@@ -683,7 +696,7 @@ export async function collectPreBuildGlobFindings(filesConfig, projectRoot) {
683
696
  // pattern in `SkillFileEntrySchema.source` the way `dest` already is — at which
684
697
  // point this line becomes defense-in-depth against a config that cannot load.
685
698
  if (hasParentTraversalSegment(globMagicRemainder(entry.source)))
686
- continue;
699
+ return;
687
700
  const expansion = await expandGlobEntry(entry, projectRoot);
688
701
  const absBase = toForwardSlash(expansion.absoluteBase);
689
702
  // The two predicates below are `copyGlobEntry`'s two throws, in its order and
@@ -694,7 +707,7 @@ export async function collectPreBuildGlobFindings(filesConfig, projectRoot) {
694
707
  // exactly the misdirection the second error was written to avoid.
695
708
  if (expansion.allMatches.length === 0) {
696
709
  unmatched.push({ source: entry.source, absBase });
697
- continue;
710
+ return;
698
711
  }
699
712
  // Reported for EVERY entry that has them, including ones that go on to be
700
713
  // `allRefused` below — unlike the per-file drops, which that verdict
@@ -706,7 +719,7 @@ export async function collectPreBuildGlobFindings(filesConfig, projectRoot) {
706
719
  // Matched only non-files. `allRefused` would name the never-package list as
707
720
  // the cause, which is not what happened, and its remediation would not work.
708
721
  // The `skipped` findings just pushed carry this entry on their own.
709
- continue;
722
+ return;
710
723
  }
711
724
  if (expansion.kept.length === 0) {
712
725
  // Supersedes this entry's per-file drops rather than adding to them: the
@@ -718,10 +731,10 @@ export async function collectPreBuildGlobFindings(filesConfig, projectRoot) {
718
731
  absBase,
719
732
  absRefused: expansion.dropped.map((d) => d.absFile),
720
733
  });
721
- continue;
734
+ return;
722
735
  }
723
736
  dropped.push(...expansion.dropped.filter((d) => !shippedDests.has(normalizeRelPath(d.dest))));
724
- }
737
+ });
725
738
  return { dropped, allRefused, unmatched, skipped };
726
739
  }
727
740
  /**
@@ -798,7 +811,7 @@ function assertFileShapedDest(entry) {
798
811
  while (base.endsWith('/'))
799
812
  base = base.slice(0, -1);
800
813
  const suggested = `${base}/${entry.source.slice(entry.source.lastIndexOf('/') + 1)}`;
801
- throw new Error(`files: dest '${entry.dest}' names a directory, but a non-glob entry copies ONE file to ONE path. ` +
814
+ throw packagingInputError(`files: dest '${entry.dest}' names a directory, but a non-glob entry copies ONE file to ONE path. ` +
802
815
  `Name the output file itself (e.g. dest: '${normalizeRelPath(suggested)}'), ` +
803
816
  `or use a glob source to copy a whole subtree.`);
804
817
  }
@@ -831,15 +844,7 @@ async function applyNonGlobFileEntry(fileEntry, opts, bundledFileSet) {
831
844
  : undefined,
832
845
  };
833
846
  }
834
- // The WHOLE entry's filesystem work is guarded, not just its copy. Guarding the
835
- // copy alone left the source `statSync` outside — so a source under a directory
836
- // the process cannot traverse still escaped as a bare errno, which is the same
837
- // defect one call earlier. An EXPLICIT entry is the spelling that unambiguously
838
- // says "ship this file", so a bare errno here is if anything worse than on a
839
- // glob: the author named the path, and the build owes them an error that names
840
- // it back. (`copyNonGlobEntry`'s own deliberate errors — "does not exist", "is a
841
- // directory" — carry no errno, so `attributed` passes them through untouched.)
842
- const { relDest, absSource, absDest } = await attributed(fileEntry, absoluteSource, opts.projectRoot, () => copyNonGlobEntry(fileEntry, absoluteSource, opts.projectRoot, opts.skillOutputDir));
847
+ const { relDest, absSource, absDest } = await copyNonGlobEntry(fileEntry, absoluteSource, opts.projectRoot, opts.skillOutputDir);
843
848
  return {
844
849
  dests: [relDest],
845
850
  dropped: [],
@@ -869,17 +874,16 @@ function relUnderDest(destRoot, dest) {
869
874
  * rather than being weakened into a permissive one.
870
875
  */
871
876
  async function runDeferredIntegrity(pending, allDests, skillOutputDir, projectRoot) {
872
- for (const { entry, pairs, rels } of pending) {
873
- // Through the same attribution point as the copy. `verifyFilesIntegrity`
874
- // hashes both sides, so an unreadable source or dest surfaces here as a raw
875
- // errno carrying an absolute path and no entry name — the same defect the
876
- // copy loop had, in the one lane that had not been routed through the guard.
877
+ // In order: the first refusal is named in config order.
878
+ await forEachInOrder(pending, async ({ entry, pairs, rels }) => {
877
879
  // Anchored at the ENTRY, not at `pairs[0]`: any of the entry's files can be
878
880
  // the one that failed, and naming the first while the errno names another is
879
- // worse than naming none. The errno itself carries the offending path.
880
- await attributed(entry, safePath.resolve(safePath.join(projectRoot, entry.source)), projectRoot, async () => { verifyFilesIntegrity(pairs); }, 'verified');
881
+ // worse than naming none. The errno itself carries the offending path, and
882
+ // each read is coded by the tree it touched (see `verifyFilesIntegrity`).
883
+ const subject = entrySubject(entry, safePath.resolve(safePath.join(projectRoot, entry.source)), projectRoot);
884
+ verifyFilesIntegrity(subject, pairs);
881
885
  if (rels === undefined)
882
- continue;
886
+ return;
883
887
  const destRoot = normalizeRelPath(entry.dest);
884
888
  const expected = new Set(rels);
885
889
  for (const dest of allDests) {
@@ -887,8 +891,10 @@ async function runDeferredIntegrity(pending, allDests, skillOutputDir, projectRo
887
891
  if (rel !== null && rel !== '')
888
892
  expected.add(rel);
889
893
  }
890
- await verifyDestSet(safePath.joinUnderRoot(skillOutputDir, entry.dest), [...expected], entry.source);
891
- }
894
+ const destDir = safePath.joinUnderRoot(skillOutputDir, entry.dest);
895
+ // Lists the bundle the build just wrote: a refusal is the output's.
896
+ await withFsFault({ side: 'destination', shapeFromSource: true, action: `verify ${subject} in the bundle` }, () => verifyDestSet(destDir, [...expected], entry.source));
897
+ });
892
898
  }
893
899
  export async function applyFilesConfig(opts) {
894
900
  const bundledFileSet = new Set((opts.bundledFiles ?? []).map((f) => toForwardSlash(f)));
@@ -896,7 +902,8 @@ export async function applyFilesConfig(opts) {
896
902
  const dropped = [];
897
903
  const skipped = [];
898
904
  const pending = [];
899
- for (const fileEntry of opts.filesConfig) {
905
+ // In order: ordered writes — a later entry may overwrite an earlier dest, and the last one wins.
906
+ await forEachInOrder(opts.filesConfig, async (fileEntry) => {
900
907
  const outcome = isGlob(fileEntry.source)
901
908
  ? await applyGlobFileEntry(fileEntry, opts)
902
909
  : await applyNonGlobFileEntry(fileEntry, opts, bundledFileSet);
@@ -905,7 +912,7 @@ export async function applyFilesConfig(opts) {
905
912
  skipped.push(...outcome.skipped);
906
913
  if (outcome.pending)
907
914
  pending.push(outcome.pending);
908
- }
915
+ });
909
916
  await runDeferredIntegrity(pending, dests, opts.skillOutputDir, opts.projectRoot);
910
917
  // A drop is only worth reporting if the file genuinely did not ship. In the
911
918
  // escape-hatch config the guide prescribes — a glob over a subtree plus an