@skillsmith/core 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts +23 -0
  4. package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts.map +1 -1
  5. package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js +137 -0
  6. package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js.map +1 -1
  7. package/dist/src/analysis/tree-sitter/pythonIncremental.js +83 -10
  8. package/dist/src/analysis/tree-sitter/pythonIncremental.js.map +1 -1
  9. package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js +6 -1
  10. package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js.map +1 -1
  11. package/dist/src/api/client.d.ts.map +1 -1
  12. package/dist/src/api/client.js +6 -0
  13. package/dist/src/api/client.js.map +1 -1
  14. package/dist/src/api/client.test.d.ts +9 -0
  15. package/dist/src/api/client.test.d.ts.map +1 -0
  16. package/dist/src/api/client.test.js +81 -0
  17. package/dist/src/api/client.test.js.map +1 -0
  18. package/dist/src/config/audit-notify-state.d.ts +46 -0
  19. package/dist/src/config/audit-notify-state.d.ts.map +1 -0
  20. package/dist/src/config/audit-notify-state.js +55 -0
  21. package/dist/src/config/audit-notify-state.js.map +1 -0
  22. package/dist/src/config/audit-notify-state.test.d.ts +9 -0
  23. package/dist/src/config/audit-notify-state.test.d.ts.map +1 -0
  24. package/dist/src/config/audit-notify-state.test.js +63 -0
  25. package/dist/src/config/audit-notify-state.test.js.map +1 -0
  26. package/dist/src/config/index.d.ts +10 -0
  27. package/dist/src/config/index.d.ts.map +1 -1
  28. package/dist/src/config/index.js.map +1 -1
  29. package/dist/src/exports/services.d.ts +3 -1
  30. package/dist/src/exports/services.d.ts.map +1 -1
  31. package/dist/src/exports/services.js +9 -1
  32. package/dist/src/exports/services.js.map +1 -1
  33. package/dist/src/index.d.ts +6 -3
  34. package/dist/src/index.d.ts.map +1 -1
  35. package/dist/src/index.js +11 -2
  36. package/dist/src/index.js.map +1 -1
  37. package/dist/src/install/agent-config-merge.json-array.d.ts +29 -0
  38. package/dist/src/install/agent-config-merge.json-array.d.ts.map +1 -0
  39. package/dist/src/install/agent-config-merge.json-array.js +100 -0
  40. package/dist/src/install/agent-config-merge.json-array.js.map +1 -0
  41. package/dist/src/install/agent-config-merge.json.d.ts +37 -0
  42. package/dist/src/install/agent-config-merge.json.d.ts.map +1 -0
  43. package/dist/src/install/agent-config-merge.json.js +134 -0
  44. package/dist/src/install/agent-config-merge.json.js.map +1 -0
  45. package/dist/src/install/agent-config-merge.toml-block.d.ts +48 -0
  46. package/dist/src/install/agent-config-merge.toml-block.d.ts.map +1 -0
  47. package/dist/src/install/agent-config-merge.toml-block.js +107 -0
  48. package/dist/src/install/agent-config-merge.toml-block.js.map +1 -0
  49. package/dist/src/install/agent-config-merge.types.d.ts +87 -0
  50. package/dist/src/install/agent-config-merge.types.d.ts.map +1 -0
  51. package/dist/src/install/agent-config-merge.types.js +83 -0
  52. package/dist/src/install/agent-config-merge.types.js.map +1 -0
  53. package/dist/src/install/agent-config-merge.yaml.d.ts +46 -0
  54. package/dist/src/install/agent-config-merge.yaml.d.ts.map +1 -0
  55. package/dist/src/install/agent-config-merge.yaml.js +133 -0
  56. package/dist/src/install/agent-config-merge.yaml.js.map +1 -0
  57. package/dist/src/install/agent-config-merge.yaml.test.d.ts +2 -0
  58. package/dist/src/install/agent-config-merge.yaml.test.d.ts.map +1 -0
  59. package/dist/src/install/agent-config-merge.yaml.test.js +210 -0
  60. package/dist/src/install/agent-config-merge.yaml.test.js.map +1 -0
  61. package/dist/src/install/agent-harness-targets.d.ts +98 -0
  62. package/dist/src/install/agent-harness-targets.d.ts.map +1 -0
  63. package/dist/src/install/agent-harness-targets.js +154 -0
  64. package/dist/src/install/agent-harness-targets.js.map +1 -0
  65. package/dist/src/install/agent-home-relocate.d.ts +29 -0
  66. package/dist/src/install/agent-home-relocate.d.ts.map +1 -0
  67. package/dist/src/install/agent-home-relocate.js +38 -0
  68. package/dist/src/install/agent-home-relocate.js.map +1 -0
  69. package/dist/src/install/agent-manifest-path-guard.d.ts +55 -0
  70. package/dist/src/install/agent-manifest-path-guard.d.ts.map +1 -0
  71. package/dist/src/install/agent-manifest-path-guard.js +109 -0
  72. package/dist/src/install/agent-manifest-path-guard.js.map +1 -0
  73. package/dist/src/install/agent-manifest-path-guard.test.d.ts +2 -0
  74. package/dist/src/install/agent-manifest-path-guard.test.d.ts.map +1 -0
  75. package/dist/src/install/agent-manifest-path-guard.test.js +72 -0
  76. package/dist/src/install/agent-manifest-path-guard.test.js.map +1 -0
  77. package/dist/src/install/agent-manifest.d.ts +58 -0
  78. package/dist/src/install/agent-manifest.d.ts.map +1 -0
  79. package/dist/src/install/agent-manifest.js +103 -0
  80. package/dist/src/install/agent-manifest.js.map +1 -0
  81. package/dist/src/install/agent-pack-installer.d.ts +39 -0
  82. package/dist/src/install/agent-pack-installer.d.ts.map +1 -0
  83. package/dist/src/install/agent-pack-installer.entry.d.ts +55 -0
  84. package/dist/src/install/agent-pack-installer.entry.d.ts.map +1 -0
  85. package/dist/src/install/agent-pack-installer.entry.js +90 -0
  86. package/dist/src/install/agent-pack-installer.entry.js.map +1 -0
  87. package/dist/src/install/agent-pack-installer.fs-helpers.d.ts +33 -0
  88. package/dist/src/install/agent-pack-installer.fs-helpers.d.ts.map +1 -0
  89. package/dist/src/install/agent-pack-installer.fs-helpers.js +59 -0
  90. package/dist/src/install/agent-pack-installer.fs-helpers.js.map +1 -0
  91. package/dist/src/install/agent-pack-installer.harness.d.ts +66 -0
  92. package/dist/src/install/agent-pack-installer.harness.d.ts.map +1 -0
  93. package/dist/src/install/agent-pack-installer.harness.js +310 -0
  94. package/dist/src/install/agent-pack-installer.harness.js.map +1 -0
  95. package/dist/src/install/agent-pack-installer.js +221 -0
  96. package/dist/src/install/agent-pack-installer.js.map +1 -0
  97. package/dist/src/install/agent-pack-installer.preserve.test.d.ts +11 -0
  98. package/dist/src/install/agent-pack-installer.preserve.test.d.ts.map +1 -0
  99. package/dist/src/install/agent-pack-installer.preserve.test.js +72 -0
  100. package/dist/src/install/agent-pack-installer.preserve.test.js.map +1 -0
  101. package/dist/src/install/agent-pack-installer.test.d.ts +2 -0
  102. package/dist/src/install/agent-pack-installer.test.d.ts.map +1 -0
  103. package/dist/src/install/agent-pack-installer.test.js +350 -0
  104. package/dist/src/install/agent-pack-installer.test.js.map +1 -0
  105. package/dist/src/install/agent-pack-installer.types.d.ts +51 -0
  106. package/dist/src/install/agent-pack-installer.types.d.ts.map +1 -0
  107. package/dist/src/install/agent-pack-installer.types.js +16 -0
  108. package/dist/src/install/agent-pack-installer.types.js.map +1 -0
  109. package/dist/src/install/agent-pack-uninstaller.d.ts +43 -0
  110. package/dist/src/install/agent-pack-uninstaller.d.ts.map +1 -0
  111. package/dist/src/install/agent-pack-uninstaller.js +113 -0
  112. package/dist/src/install/agent-pack-uninstaller.js.map +1 -0
  113. package/dist/src/install/agent-pack-uninstaller.test.d.ts +2 -0
  114. package/dist/src/install/agent-pack-uninstaller.test.d.ts.map +1 -0
  115. package/dist/src/install/agent-pack-uninstaller.test.js +212 -0
  116. package/dist/src/install/agent-pack-uninstaller.test.js.map +1 -0
  117. package/dist/src/install/index.d.ts +7 -0
  118. package/dist/src/install/index.d.ts.map +1 -1
  119. package/dist/src/install/index.js +7 -0
  120. package/dist/src/install/index.js.map +1 -1
  121. package/dist/src/install/paths.d.ts +1 -1
  122. package/dist/src/install/paths.d.ts.map +1 -1
  123. package/dist/src/install/paths.js +4 -0
  124. package/dist/src/install/paths.js.map +1 -1
  125. package/dist/src/install/paths.test.js +15 -0
  126. package/dist/src/install/paths.test.js.map +1 -1
  127. package/dist/src/journal/hash.d.ts +13 -0
  128. package/dist/src/journal/hash.d.ts.map +1 -0
  129. package/dist/src/journal/hash.js +16 -0
  130. package/dist/src/journal/hash.js.map +1 -0
  131. package/dist/src/journal/index.d.ts +15 -0
  132. package/dist/src/journal/index.d.ts.map +1 -0
  133. package/dist/src/journal/index.js +15 -0
  134. package/dist/src/journal/index.js.map +1 -0
  135. package/dist/src/journal/journal.test.d.ts +16 -0
  136. package/dist/src/journal/journal.test.d.ts.map +1 -0
  137. package/dist/src/journal/journal.test.js +171 -0
  138. package/dist/src/journal/journal.test.js.map +1 -0
  139. package/dist/src/journal/path.d.ts +44 -0
  140. package/dist/src/journal/path.d.ts.map +1 -0
  141. package/dist/src/journal/path.js +61 -0
  142. package/dist/src/journal/path.js.map +1 -0
  143. package/dist/src/journal/reader.d.ts +38 -0
  144. package/dist/src/journal/reader.d.ts.map +1 -0
  145. package/dist/src/journal/reader.js +93 -0
  146. package/dist/src/journal/reader.js.map +1 -0
  147. package/dist/src/journal/types.d.ts +87 -0
  148. package/dist/src/journal/types.d.ts.map +1 -0
  149. package/dist/src/journal/types.js +21 -0
  150. package/dist/src/journal/types.js.map +1 -0
  151. package/dist/src/journal/writer.d.ts +52 -0
  152. package/dist/src/journal/writer.d.ts.map +1 -0
  153. package/dist/src/journal/writer.js +125 -0
  154. package/dist/src/journal/writer.js.map +1 -0
  155. package/dist/src/logging/context.d.ts +58 -0
  156. package/dist/src/logging/context.d.ts.map +1 -0
  157. package/dist/src/logging/context.js +62 -0
  158. package/dist/src/logging/context.js.map +1 -0
  159. package/dist/src/logging/context.test.d.ts +14 -0
  160. package/dist/src/logging/context.test.d.ts.map +1 -0
  161. package/dist/src/logging/context.test.js +88 -0
  162. package/dist/src/logging/context.test.js.map +1 -0
  163. package/dist/src/logging/index.d.ts +13 -0
  164. package/dist/src/logging/index.d.ts.map +1 -0
  165. package/dist/src/logging/index.js +12 -0
  166. package/dist/src/logging/index.js.map +1 -0
  167. package/dist/src/logging/logger.d.ts +71 -0
  168. package/dist/src/logging/logger.d.ts.map +1 -0
  169. package/dist/src/logging/logger.js +264 -0
  170. package/dist/src/logging/logger.js.map +1 -0
  171. package/dist/src/logging/logger.test.d.ts +9 -0
  172. package/dist/src/logging/logger.test.d.ts.map +1 -0
  173. package/dist/src/logging/logger.test.js +320 -0
  174. package/dist/src/logging/logger.test.js.map +1 -0
  175. package/dist/src/logging/redact.d.ts +35 -0
  176. package/dist/src/logging/redact.d.ts.map +1 -0
  177. package/dist/src/logging/redact.js +152 -0
  178. package/dist/src/logging/redact.js.map +1 -0
  179. package/dist/src/logging/redact.test.d.ts +8 -0
  180. package/dist/src/logging/redact.test.d.ts.map +1 -0
  181. package/dist/src/logging/redact.test.js +330 -0
  182. package/dist/src/logging/redact.test.js.map +1 -0
  183. package/dist/src/logging/rotation.d.ts +75 -0
  184. package/dist/src/logging/rotation.d.ts.map +1 -0
  185. package/dist/src/logging/rotation.js +284 -0
  186. package/dist/src/logging/rotation.js.map +1 -0
  187. package/dist/src/logging/rotation.test.d.ts +11 -0
  188. package/dist/src/logging/rotation.test.d.ts.map +1 -0
  189. package/dist/src/logging/rotation.test.js +132 -0
  190. package/dist/src/logging/rotation.test.js.map +1 -0
  191. package/dist/src/logging/types.d.ts +69 -0
  192. package/dist/src/logging/types.d.ts.map +1 -0
  193. package/dist/src/logging/types.js +9 -0
  194. package/dist/src/logging/types.js.map +1 -0
  195. package/dist/src/paywall-triggers/index.d.ts +13 -0
  196. package/dist/src/paywall-triggers/index.d.ts.map +1 -0
  197. package/dist/src/paywall-triggers/index.js +13 -0
  198. package/dist/src/paywall-triggers/index.js.map +1 -0
  199. package/dist/src/paywall-triggers/path.d.ts +47 -0
  200. package/dist/src/paywall-triggers/path.d.ts.map +1 -0
  201. package/dist/src/paywall-triggers/path.js +73 -0
  202. package/dist/src/paywall-triggers/path.js.map +1 -0
  203. package/dist/src/paywall-triggers/store.d.ts +75 -0
  204. package/dist/src/paywall-triggers/store.d.ts.map +1 -0
  205. package/dist/src/paywall-triggers/store.js +122 -0
  206. package/dist/src/paywall-triggers/store.js.map +1 -0
  207. package/dist/src/paywall-triggers/store.test.d.ts +2 -0
  208. package/dist/src/paywall-triggers/store.test.d.ts.map +1 -0
  209. package/dist/src/paywall-triggers/store.test.js +121 -0
  210. package/dist/src/paywall-triggers/store.test.js.map +1 -0
  211. package/dist/src/paywall-triggers/types.d.ts +24 -0
  212. package/dist/src/paywall-triggers/types.d.ts.map +1 -0
  213. package/dist/src/paywall-triggers/types.js +13 -0
  214. package/dist/src/paywall-triggers/types.js.map +1 -0
  215. package/dist/src/security/index.d.ts +2 -0
  216. package/dist/src/security/index.d.ts.map +1 -1
  217. package/dist/src/security/index.js +4 -0
  218. package/dist/src/security/index.js.map +1 -1
  219. package/dist/src/security/scanner/SecurityScanner.compound.d.ts +13 -0
  220. package/dist/src/security/scanner/SecurityScanner.compound.d.ts.map +1 -0
  221. package/dist/src/security/scanner/SecurityScanner.compound.js +127 -0
  222. package/dist/src/security/scanner/SecurityScanner.compound.js.map +1 -0
  223. package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
  224. package/dist/src/security/scanner/SecurityScanner.hostile-update.d.ts +46 -0
  225. package/dist/src/security/scanner/SecurityScanner.hostile-update.d.ts.map +1 -0
  226. package/dist/src/security/scanner/SecurityScanner.hostile-update.js +209 -0
  227. package/dist/src/security/scanner/SecurityScanner.hostile-update.js.map +1 -0
  228. package/dist/src/security/scanner/SecurityScanner.js +10 -1
  229. package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
  230. package/dist/src/security/scanner/SecurityScanner.pii.d.ts +23 -0
  231. package/dist/src/security/scanner/SecurityScanner.pii.d.ts.map +1 -0
  232. package/dist/src/security/scanner/SecurityScanner.pii.js +152 -0
  233. package/dist/src/security/scanner/SecurityScanner.pii.js.map +1 -0
  234. package/dist/src/security/scanner/SecurityScanner.scanners.d.ts +5 -12
  235. package/dist/src/security/scanner/SecurityScanner.scanners.d.ts.map +1 -1
  236. package/dist/src/security/scanner/SecurityScanner.scanners.js +63 -137
  237. package/dist/src/security/scanner/SecurityScanner.scanners.js.map +1 -1
  238. package/dist/src/security/scanner/index.d.ts +2 -1
  239. package/dist/src/security/scanner/index.d.ts.map +1 -1
  240. package/dist/src/security/scanner/index.js +2 -0
  241. package/dist/src/security/scanner/index.js.map +1 -1
  242. package/dist/src/security/scanner/patterns.d.ts +2 -0
  243. package/dist/src/security/scanner/patterns.d.ts.map +1 -1
  244. package/dist/src/security/scanner/patterns.js +79 -11
  245. package/dist/src/security/scanner/patterns.js.map +1 -1
  246. package/dist/src/security/scanner/types.d.ts +23 -0
  247. package/dist/src/security/scanner/types.d.ts.map +1 -1
  248. package/dist/src/services/agent-pack/agent-pack.test.d.ts +18 -0
  249. package/dist/src/services/agent-pack/agent-pack.test.d.ts.map +1 -0
  250. package/dist/src/services/agent-pack/agent-pack.test.js +344 -0
  251. package/dist/src/services/agent-pack/agent-pack.test.js.map +1 -0
  252. package/dist/src/services/agent-pack/hooks.d.ts +29 -0
  253. package/dist/src/services/agent-pack/hooks.d.ts.map +1 -0
  254. package/dist/src/services/agent-pack/hooks.js +139 -0
  255. package/dist/src/services/agent-pack/hooks.js.map +1 -0
  256. package/dist/src/services/agent-pack/index.d.ts +26 -0
  257. package/dist/src/services/agent-pack/index.d.ts.map +1 -0
  258. package/dist/src/services/agent-pack/index.js +109 -0
  259. package/dist/src/services/agent-pack/index.js.map +1 -0
  260. package/dist/src/services/agent-pack/prompt-source.d.ts +47 -0
  261. package/dist/src/services/agent-pack/prompt-source.d.ts.map +1 -0
  262. package/dist/src/services/agent-pack/prompt-source.js +182 -0
  263. package/dist/src/services/agent-pack/prompt-source.js.map +1 -0
  264. package/dist/src/services/agent-pack/shims.d.ts +40 -0
  265. package/dist/src/services/agent-pack/shims.d.ts.map +1 -0
  266. package/dist/src/services/agent-pack/shims.js +96 -0
  267. package/dist/src/services/agent-pack/shims.js.map +1 -0
  268. package/dist/src/services/agent-pack/skill-md.d.ts +35 -0
  269. package/dist/src/services/agent-pack/skill-md.d.ts.map +1 -0
  270. package/dist/src/services/agent-pack/skill-md.js +89 -0
  271. package/dist/src/services/agent-pack/skill-md.js.map +1 -0
  272. package/dist/src/services/agent-pack/types.d.ts +118 -0
  273. package/dist/src/services/agent-pack/types.d.ts.map +1 -0
  274. package/dist/src/services/agent-pack/types.js +61 -0
  275. package/dist/src/services/agent-pack/types.js.map +1 -0
  276. package/dist/src/services/agent-tool-profile.d.ts +59 -0
  277. package/dist/src/services/agent-tool-profile.d.ts.map +1 -0
  278. package/dist/src/services/agent-tool-profile.js +76 -0
  279. package/dist/src/services/agent-tool-profile.js.map +1 -0
  280. package/dist/src/services/agent-tool-profile.test.d.ts +2 -0
  281. package/dist/src/services/agent-tool-profile.test.d.ts.map +1 -0
  282. package/dist/src/services/agent-tool-profile.test.js +28 -0
  283. package/dist/src/services/agent-tool-profile.test.js.map +1 -0
  284. package/dist/src/services/bundled-sibling-scan.d.ts +111 -0
  285. package/dist/src/services/bundled-sibling-scan.d.ts.map +1 -0
  286. package/dist/src/services/bundled-sibling-scan.js +170 -0
  287. package/dist/src/services/bundled-sibling-scan.js.map +1 -0
  288. package/dist/src/services/skill-installation.io.d.ts +16 -5
  289. package/dist/src/services/skill-installation.io.d.ts.map +1 -1
  290. package/dist/src/services/skill-installation.io.js +63 -22
  291. package/dist/src/services/skill-installation.io.js.map +1 -1
  292. package/dist/src/services/skill-installation.policy.d.ts +96 -0
  293. package/dist/src/services/skill-installation.policy.d.ts.map +1 -0
  294. package/dist/src/services/skill-installation.policy.js +144 -0
  295. package/dist/src/services/skill-installation.policy.js.map +1 -0
  296. package/dist/src/services/skill-installation.service.d.ts.map +1 -1
  297. package/dist/src/services/skill-installation.service.js +9 -3
  298. package/dist/src/services/skill-installation.service.js.map +1 -1
  299. package/dist/src/sources/index.d.ts +1 -0
  300. package/dist/src/sources/index.d.ts.map +1 -1
  301. package/dist/src/sources/index.js +4 -0
  302. package/dist/src/sources/index.js.map +1 -1
  303. package/dist/src/sync/access-token.d.ts +27 -0
  304. package/dist/src/sync/access-token.d.ts.map +1 -0
  305. package/dist/src/sync/access-token.js +40 -0
  306. package/dist/src/sync/access-token.js.map +1 -0
  307. package/dist/src/sync/audit-notify-client.d.ts +83 -0
  308. package/dist/src/sync/audit-notify-client.d.ts.map +1 -0
  309. package/dist/src/sync/audit-notify-client.js +126 -0
  310. package/dist/src/sync/audit-notify-client.js.map +1 -0
  311. package/dist/src/sync/audit-notify-client.test.d.ts +14 -0
  312. package/dist/src/sync/audit-notify-client.test.d.ts.map +1 -0
  313. package/dist/src/sync/audit-notify-client.test.js +133 -0
  314. package/dist/src/sync/audit-notify-client.test.js.map +1 -0
  315. package/dist/src/sync/index.d.ts +2 -1
  316. package/dist/src/sync/index.d.ts.map +1 -1
  317. package/dist/src/sync/index.js +3 -1
  318. package/dist/src/sync/index.js.map +1 -1
  319. package/dist/src/sync/inventory-client.d.ts +16 -0
  320. package/dist/src/sync/inventory-client.d.ts.map +1 -1
  321. package/dist/src/sync/inventory-client.js +59 -16
  322. package/dist/src/sync/inventory-client.js.map +1 -1
  323. package/dist/src/sync/inventory-client.test.js +67 -1
  324. package/dist/src/sync/inventory-client.test.js.map +1 -1
  325. package/dist/src/sync/inventory-collector.d.ts.map +1 -1
  326. package/dist/src/sync/inventory-collector.js +32 -5
  327. package/dist/src/sync/inventory-collector.js.map +1 -1
  328. package/dist/src/sync/inventory-collector.test.js +50 -1
  329. package/dist/src/sync/inventory-collector.test.js.map +1 -1
  330. package/dist/src/sync/inventory-types.d.ts +9 -0
  331. package/dist/src/sync/inventory-types.d.ts.map +1 -1
  332. package/dist/src/sync/inventory-types.js +3 -0
  333. package/dist/src/sync/inventory-types.js.map +1 -1
  334. package/dist/src/telemetry/agent-marker.d.ts +137 -0
  335. package/dist/src/telemetry/agent-marker.d.ts.map +1 -0
  336. package/dist/src/telemetry/agent-marker.js +242 -0
  337. package/dist/src/telemetry/agent-marker.js.map +1 -0
  338. package/dist/src/telemetry/agent-marker.test.d.ts +13 -0
  339. package/dist/src/telemetry/agent-marker.test.d.ts.map +1 -0
  340. package/dist/src/telemetry/agent-marker.test.js +202 -0
  341. package/dist/src/telemetry/agent-marker.test.js.map +1 -0
  342. package/dist/src/telemetry/index.d.ts +2 -1
  343. package/dist/src/telemetry/index.d.ts.map +1 -1
  344. package/dist/src/telemetry/index.js +6 -1
  345. package/dist/src/telemetry/index.js.map +1 -1
  346. package/dist/src/telemetry/posthog.d.ts +25 -0
  347. package/dist/src/telemetry/posthog.d.ts.map +1 -1
  348. package/dist/src/telemetry/posthog.js +10 -1
  349. package/dist/src/telemetry/posthog.js.map +1 -1
  350. package/dist/src/telemetry/wrap.bench.js +5 -0
  351. package/dist/src/telemetry/wrap.bench.js.map +1 -1
  352. package/dist/src/telemetry/wrap.correlation.test.d.ts +20 -0
  353. package/dist/src/telemetry/wrap.correlation.test.d.ts.map +1 -0
  354. package/dist/src/telemetry/wrap.correlation.test.js +174 -0
  355. package/dist/src/telemetry/wrap.correlation.test.js.map +1 -0
  356. package/dist/src/telemetry/wrap.d.ts +28 -7
  357. package/dist/src/telemetry/wrap.d.ts.map +1 -1
  358. package/dist/src/telemetry/wrap.gate.test.d.ts +22 -0
  359. package/dist/src/telemetry/wrap.gate.test.d.ts.map +1 -0
  360. package/dist/src/telemetry/wrap.gate.test.js +202 -0
  361. package/dist/src/telemetry/wrap.gate.test.js.map +1 -0
  362. package/dist/src/telemetry/wrap.js +196 -52
  363. package/dist/src/telemetry/wrap.js.map +1 -1
  364. package/dist/src/telemetry/wrap.marker.test.d.ts +16 -0
  365. package/dist/src/telemetry/wrap.marker.test.d.ts.map +1 -0
  366. package/dist/src/telemetry/wrap.marker.test.js +190 -0
  367. package/dist/src/telemetry/wrap.marker.test.js.map +1 -0
  368. package/dist/src/telemetry/wrap.test.js +14 -0
  369. package/dist/src/telemetry/wrap.test.js.map +1 -1
  370. package/dist/src/types.d.ts +6 -0
  371. package/dist/src/types.d.ts.map +1 -1
  372. package/dist/tests/SecurityScanner.exec.test.js +60 -0
  373. package/dist/tests/SecurityScanner.exec.test.js.map +1 -1
  374. package/dist/tests/security/ContinuousSecurity.test.js +10 -4
  375. package/dist/tests/security/ContinuousSecurity.test.js.map +1 -1
  376. package/dist/tests/security/SecurityScanner.chmod-evasion.test.d.ts +2 -0
  377. package/dist/tests/security/SecurityScanner.chmod-evasion.test.d.ts.map +1 -0
  378. package/dist/tests/security/SecurityScanner.chmod-evasion.test.js +126 -0
  379. package/dist/tests/security/SecurityScanner.chmod-evasion.test.js.map +1 -0
  380. package/dist/tests/security/chmod-compound.test.d.ts +2 -0
  381. package/dist/tests/security/chmod-compound.test.d.ts.map +1 -0
  382. package/dist/tests/security/chmod-compound.test.js +188 -0
  383. package/dist/tests/security/chmod-compound.test.js.map +1 -0
  384. package/dist/tests/security/pii-detection.test.js +24 -0
  385. package/dist/tests/security/pii-detection.test.js.map +1 -1
  386. package/dist/tests/security/scanner-regression-guard.test.d.ts +23 -7
  387. package/dist/tests/security/scanner-regression-guard.test.d.ts.map +1 -1
  388. package/dist/tests/security/scanner-regression-guard.test.js +206 -12
  389. package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
  390. package/dist/tests/security/sensitive-path-fp.test.d.ts +2 -0
  391. package/dist/tests/security/sensitive-path-fp.test.d.ts.map +1 -0
  392. package/dist/tests/security/sensitive-path-fp.test.js +142 -0
  393. package/dist/tests/security/sensitive-path-fp.test.js.map +1 -0
  394. package/dist/tests/services/bundled-sibling-scan.test.d.ts +2 -0
  395. package/dist/tests/services/bundled-sibling-scan.test.d.ts.map +1 -0
  396. package/dist/tests/services/bundled-sibling-scan.test.js +139 -0
  397. package/dist/tests/services/bundled-sibling-scan.test.js.map +1 -0
  398. package/dist/tests/unit/services/skill-installation.io.test.js +166 -0
  399. package/dist/tests/unit/services/skill-installation.io.test.js.map +1 -1
  400. package/dist/tests/unit/services/skill-installation.policy.test.d.ts +8 -0
  401. package/dist/tests/unit/services/skill-installation.policy.test.d.ts.map +1 -0
  402. package/dist/tests/unit/services/skill-installation.policy.test.js +151 -0
  403. package/dist/tests/unit/services/skill-installation.policy.test.js.map +1 -0
  404. package/package.json +28 -3
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Trigger-state file layout (SMI-5456 Wave 1 Step 5, QD-3).
3
+ *
4
+ * `~/.skillsmith/paywall-triggers/<triggerId>.json` — one file per trigger,
5
+ * mirroring the per-resource-directory convention already used by
6
+ * `journal/path.ts` (`~/.skillsmith/journal/`) and
7
+ * `telemetry/agent-marker.ts` (`~/.skillsmith/agent-markers/`). Named
8
+ * `paywall-triggers` (not `triggers`) both in the module path and the
9
+ * on-disk directory to avoid any collision with the PRE-EXISTING, unrelated
10
+ * `packages/core/src/triggers/` module (`TriggerDetector`/`ContextScorer` —
11
+ * proactive skill-suggestion detection, nothing to do with PRD §8.1's T1-T4
12
+ * paywall triggers).
13
+ *
14
+ * Format compatibility with the SessionStart hook's nudge cooldown
15
+ * (the per-harness `hooks/<harness>/session-start.sh` script, generated by
16
+ * the — locked for this step — `agent-pack/hooks.ts`): that hook writes a
17
+ * PLAIN epoch-seconds integer to
18
+ * `~/.skillsmith/agent-nudge.state` (`SKILLSMITH_AGENT_NUDGE_STATE`
19
+ * override), because it is self-contained POSIX sh with no JSON tooling
20
+ * available. This module's {@link getNudgeCooldownState} reads that EXACT
21
+ * file/format/override so a future consumer (a report, a diagnostic) can
22
+ * inspect the onboarding-nudge cooldown through the same TS surface as the
23
+ * T1-T4 paywall triggers, without asking the hook to change its wire format.
24
+ * The T1-T4 trigger files themselves are independent, JSON-shaped, and own
25
+ * their own directory — see the module header of `store.ts` for why.
26
+ *
27
+ * @module @skillsmith/core/paywall-triggers/path
28
+ */
29
+ import { existsSync, readFileSync } from 'node:fs';
30
+ import { join } from 'node:path';
31
+ import { getConfigDir } from '../config/index.js';
32
+ /** Env var overriding the trigger-state directory (test isolation). */
33
+ export const TRIGGER_STATE_DIR_ENV_VAR = 'SKILLSMITH_TRIGGER_STATE_DIR';
34
+ function getTriggerStateDir() {
35
+ const override = process.env[TRIGGER_STATE_DIR_ENV_VAR];
36
+ return override && override.length > 0 ? override : join(getConfigDir(), 'paywall-triggers');
37
+ }
38
+ export function getTriggerStateFilePath(triggerId) {
39
+ return join(getTriggerStateDir(), `${triggerId}.json`);
40
+ }
41
+ export function getTriggerStateDirForTests() {
42
+ return getTriggerStateDir();
43
+ }
44
+ /**
45
+ * Read the onboarding SessionStart hook's nudge-cooldown stamp — the SAME
46
+ * file (`~/.skillsmith/agent-nudge.state`, override
47
+ * `SKILLSMITH_AGENT_NUDGE_STATE`) `hooks.ts`'s `renderSessionStartHook`
48
+ * writes a bare epoch-seconds integer into. Read-only: this module never
49
+ * writes this file — that stays the hook's job.
50
+ *
51
+ * @returns the last-nudge epoch-seconds, or null if the file is absent,
52
+ * empty, or not a valid non-negative integer (matches the hook's own
53
+ * tolerant `case "" | *[!0-9]*) last=0` parsing — malformed content is
54
+ * treated as "no prior nudge", never an error).
55
+ */
56
+ export function getNudgeCooldownState() {
57
+ const override = process.env.SKILLSMITH_AGENT_NUDGE_STATE;
58
+ const path = override && override.length > 0 ? override : join(getConfigDir(), 'agent-nudge.state');
59
+ if (!existsSync(path))
60
+ return null;
61
+ let raw;
62
+ try {
63
+ raw = readFileSync(path, 'utf-8').trim();
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ if (!/^[0-9]+$/.test(raw))
69
+ return null;
70
+ const value = Number(raw);
71
+ return Number.isSafeInteger(value) ? value : null;
72
+ }
73
+ //# sourceMappingURL=path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../../src/paywall-triggers/path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGjD,uEAAuE;AACvE,MAAM,CAAC,MAAM,yBAAyB,GAAG,8BAA8B,CAAA;AAEvE,SAAS,kBAAkB;IACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAA;IACvD,OAAO,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,kBAAkB,CAAC,CAAA;AAC9F,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,SAAoB;IAC1D,OAAO,IAAI,CAAC,kBAAkB,EAAE,EAAE,GAAG,SAAS,OAAO,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO,kBAAkB,EAAE,CAAA;AAC7B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAA;IACzD,MAAM,IAAI,GACR,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,mBAAmB,CAAC,CAAA;IACxF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAClC,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;IACzB,OAAO,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;AACnD,CAAC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Paywall trigger-state store (SMI-5456 Wave 1 Step 5, QD-3).
3
+ *
4
+ * PRD §8.1 defines four paywall triggers (T1 version currency, T2 quota
5
+ * forecast, T3 sharing, T4 security-depth disclosure) with two frequency
6
+ * rules: at most one upgrade prompt per session, and two dismissals of the
7
+ * same trigger suppress it for 30 days. This module persists the state those
8
+ * rules need — per-trigger last-shown session id, dismissal count, and mute
9
+ * expiry — under `~/.skillsmith/paywall-triggers/` (deliberately NOT
10
+ * `~/.skillsmith/triggers/` — see `path.ts`'s header for the pre-existing,
11
+ * unrelated `packages/core/src/triggers/` module this avoids colliding with).
12
+ *
13
+ * WAVE-1 SCOPE LIMITATION (read before wiring this into anything):
14
+ * The trigger RULES live in the pack's prompt wording (PRD §6 change 6) —
15
+ * the agent, running inside whatever harness's model, decides in
16
+ * conversation whether to mention a trigger, and the user's response
17
+ * ("no thanks") is plain conversational text the agent sees, not a
18
+ * structured tool call. There is currently NO MCP tool or CLI command that
19
+ * reports a T1/T2/T4 dismissal from that conversation into this store — no
20
+ * Wave-1 exclusion-9 tool covers it (PRD §10 exclusion 9's only two
21
+ * acknowledged exceptions are the undo tool and the Wave-2 stats surface).
22
+ * That means: {@link recordTriggerDismissal} is real, tested infrastructure
23
+ * with NO live caller in Wave 1. This is intentional staged infrastructure
24
+ * (the same shape the change-journal module shipped in — Step 3, before the
25
+ * apply tools became its first real caller in a later step) — NOT an
26
+ * "unconsumed dismissal-recording pathway" in the house anti-pattern sense,
27
+ * because nothing in this codebase currently calls it as if dismissals were
28
+ * being captured. Do not present in-conversation dismissal tracking as a
29
+ * shipped product behavior (docs, marketing copy, the eval-matrix report)
30
+ * until a real consumer exists. What DOES already work end-to-end in Wave 1:
31
+ * the session-cap half via {@link canShowTrigger}/{@link recordImpression} —
32
+ * though even that has no live caller yet either, since trigger *display*
33
+ * also currently lives entirely in the pack's prompt wording. Both halves
34
+ * are ready for whichever surface (a future tool, or a CLI diagnostic) needs
35
+ * them; the eval-matrix worker (Step 6) should treat "trigger frequency cap
36
+ * enforced server-side" as NOT YET TRUE for the published Tier badges.
37
+ *
38
+ * Single-writer-per-trigger-file note: like the journal (P-5), each trigger
39
+ * file is read-modify-written directly (not append-only, since there's only
40
+ * ever one live state per trigger, not a growing log) — concurrent writers
41
+ * to the SAME trigger id are not expected in Wave 1 (no live caller), so no
42
+ * write-queue serialization is implemented here; add one if/when a consumer
43
+ * with real concurrency (e.g. two parallel MCP requests) lands.
44
+ *
45
+ * @module @skillsmith/core/paywall-triggers/store
46
+ */
47
+ import { type TriggerId, type TriggerState } from './types.js';
48
+ /** Load a trigger's persisted state, or a fresh empty state if none exists or it is corrupt. */
49
+ export declare function loadTriggerState(triggerId: TriggerId): TriggerState;
50
+ /**
51
+ * Is `triggerId` currently muted (30-day suppression after
52
+ * {@link TRIGGER_DISMISSAL_THRESHOLD} dismissals)?
53
+ *
54
+ * @param now - injectable clock for tests.
55
+ */
56
+ export declare function isTriggerMuted(state: TriggerState, now?: number): boolean;
57
+ /**
58
+ * P-5 "one prompt per session enforced from persisted state, not memory":
59
+ * true when `triggerId` has NOT already been shown in `sessionId` AND is not
60
+ * currently muted. Concurrent sessions may each independently see `true` and
61
+ * both prompt once — accepted, documented (P-5 table).
62
+ */
63
+ export declare function canShowTrigger(triggerId: TriggerId, sessionId: string, now?: number): boolean;
64
+ /** Record that `triggerId` was shown in `sessionId` (persisted — the session cap). */
65
+ export declare function recordImpression(triggerId: TriggerId, sessionId: string): TriggerState;
66
+ /**
67
+ * Record a dismissal. On reaching {@link TRIGGER_DISMISSAL_THRESHOLD}
68
+ * dismissals, sets a {@link TRIGGER_MUTE_DAYS}-day mute from `now`.
69
+ *
70
+ * See the module header: no Wave-1 caller reports a real in-conversation
71
+ * dismissal today. This function is correct, tested library code — not an
72
+ * inert stub — for whichever surface becomes that caller.
73
+ */
74
+ export declare function recordTriggerDismissal(triggerId: TriggerId, now?: number): TriggerState;
75
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/paywall-triggers/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAMH,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,YAAY,CAAA;AAInB,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,YAAY,CAiBnE;AAQD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,GAAE,MAAmB,GAAG,OAAO,CAErF;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAmB,GACvB,OAAO,CAIT;AAED,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,CAKtF;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,SAAS,EACpB,GAAG,GAAE,MAAmB,GACvB,YAAY,CAQd"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Paywall trigger-state store (SMI-5456 Wave 1 Step 5, QD-3).
3
+ *
4
+ * PRD §8.1 defines four paywall triggers (T1 version currency, T2 quota
5
+ * forecast, T3 sharing, T4 security-depth disclosure) with two frequency
6
+ * rules: at most one upgrade prompt per session, and two dismissals of the
7
+ * same trigger suppress it for 30 days. This module persists the state those
8
+ * rules need — per-trigger last-shown session id, dismissal count, and mute
9
+ * expiry — under `~/.skillsmith/paywall-triggers/` (deliberately NOT
10
+ * `~/.skillsmith/triggers/` — see `path.ts`'s header for the pre-existing,
11
+ * unrelated `packages/core/src/triggers/` module this avoids colliding with).
12
+ *
13
+ * WAVE-1 SCOPE LIMITATION (read before wiring this into anything):
14
+ * The trigger RULES live in the pack's prompt wording (PRD §6 change 6) —
15
+ * the agent, running inside whatever harness's model, decides in
16
+ * conversation whether to mention a trigger, and the user's response
17
+ * ("no thanks") is plain conversational text the agent sees, not a
18
+ * structured tool call. There is currently NO MCP tool or CLI command that
19
+ * reports a T1/T2/T4 dismissal from that conversation into this store — no
20
+ * Wave-1 exclusion-9 tool covers it (PRD §10 exclusion 9's only two
21
+ * acknowledged exceptions are the undo tool and the Wave-2 stats surface).
22
+ * That means: {@link recordTriggerDismissal} is real, tested infrastructure
23
+ * with NO live caller in Wave 1. This is intentional staged infrastructure
24
+ * (the same shape the change-journal module shipped in — Step 3, before the
25
+ * apply tools became its first real caller in a later step) — NOT an
26
+ * "unconsumed dismissal-recording pathway" in the house anti-pattern sense,
27
+ * because nothing in this codebase currently calls it as if dismissals were
28
+ * being captured. Do not present in-conversation dismissal tracking as a
29
+ * shipped product behavior (docs, marketing copy, the eval-matrix report)
30
+ * until a real consumer exists. What DOES already work end-to-end in Wave 1:
31
+ * the session-cap half via {@link canShowTrigger}/{@link recordImpression} —
32
+ * though even that has no live caller yet either, since trigger *display*
33
+ * also currently lives entirely in the pack's prompt wording. Both halves
34
+ * are ready for whichever surface (a future tool, or a CLI diagnostic) needs
35
+ * them; the eval-matrix worker (Step 6) should treat "trigger frequency cap
36
+ * enforced server-side" as NOT YET TRUE for the published Tier badges.
37
+ *
38
+ * Single-writer-per-trigger-file note: like the journal (P-5), each trigger
39
+ * file is read-modify-written directly (not append-only, since there's only
40
+ * ever one live state per trigger, not a growing log) — concurrent writers
41
+ * to the SAME trigger id are not expected in Wave 1 (no live caller), so no
42
+ * write-queue serialization is implemented here; add one if/when a consumer
43
+ * with real concurrency (e.g. two parallel MCP requests) lands.
44
+ *
45
+ * @module @skillsmith/core/paywall-triggers/store
46
+ */
47
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
48
+ import { dirname } from 'node:path';
49
+ import { getTriggerStateFilePath } from './path.js';
50
+ import { TRIGGER_DISMISSAL_THRESHOLD, TRIGGER_MUTE_DAYS, emptyTriggerState, } from './types.js';
51
+ const MUTE_DURATION_MS = TRIGGER_MUTE_DAYS * 24 * 60 * 60 * 1000;
52
+ /** Load a trigger's persisted state, or a fresh empty state if none exists or it is corrupt. */
53
+ export function loadTriggerState(triggerId) {
54
+ const path = getTriggerStateFilePath(triggerId);
55
+ if (!existsSync(path))
56
+ return emptyTriggerState(triggerId);
57
+ try {
58
+ const parsed = JSON.parse(readFileSync(path, 'utf-8'));
59
+ if (parsed.triggerId !== triggerId)
60
+ return emptyTriggerState(triggerId);
61
+ return {
62
+ schema: 1,
63
+ triggerId,
64
+ lastSessionShown: typeof parsed.lastSessionShown === 'string' ? parsed.lastSessionShown : null,
65
+ dismissalCount: typeof parsed.dismissalCount === 'number' ? parsed.dismissalCount : 0,
66
+ mutedUntil: typeof parsed.mutedUntil === 'number' ? parsed.mutedUntil : null,
67
+ };
68
+ }
69
+ catch {
70
+ return emptyTriggerState(triggerId);
71
+ }
72
+ }
73
+ function saveTriggerState(state) {
74
+ const path = getTriggerStateFilePath(state.triggerId);
75
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
76
+ writeFileSync(path, JSON.stringify(state, null, 2) + '\n', { mode: 0o600 });
77
+ }
78
+ /**
79
+ * Is `triggerId` currently muted (30-day suppression after
80
+ * {@link TRIGGER_DISMISSAL_THRESHOLD} dismissals)?
81
+ *
82
+ * @param now - injectable clock for tests.
83
+ */
84
+ export function isTriggerMuted(state, now = Date.now()) {
85
+ return state.mutedUntil !== null && now < state.mutedUntil;
86
+ }
87
+ /**
88
+ * P-5 "one prompt per session enforced from persisted state, not memory":
89
+ * true when `triggerId` has NOT already been shown in `sessionId` AND is not
90
+ * currently muted. Concurrent sessions may each independently see `true` and
91
+ * both prompt once — accepted, documented (P-5 table).
92
+ */
93
+ export function canShowTrigger(triggerId, sessionId, now = Date.now()) {
94
+ const state = loadTriggerState(triggerId);
95
+ if (isTriggerMuted(state, now))
96
+ return false;
97
+ return state.lastSessionShown !== sessionId;
98
+ }
99
+ /** Record that `triggerId` was shown in `sessionId` (persisted — the session cap). */
100
+ export function recordImpression(triggerId, sessionId) {
101
+ const state = loadTriggerState(triggerId);
102
+ const next = { ...state, lastSessionShown: sessionId };
103
+ saveTriggerState(next);
104
+ return next;
105
+ }
106
+ /**
107
+ * Record a dismissal. On reaching {@link TRIGGER_DISMISSAL_THRESHOLD}
108
+ * dismissals, sets a {@link TRIGGER_MUTE_DAYS}-day mute from `now`.
109
+ *
110
+ * See the module header: no Wave-1 caller reports a real in-conversation
111
+ * dismissal today. This function is correct, tested library code — not an
112
+ * inert stub — for whichever surface becomes that caller.
113
+ */
114
+ export function recordTriggerDismissal(triggerId, now = Date.now()) {
115
+ const state = loadTriggerState(triggerId);
116
+ const dismissalCount = state.dismissalCount + 1;
117
+ const mutedUntil = dismissalCount >= TRIGGER_DISMISSAL_THRESHOLD ? now + MUTE_DURATION_MS : state.mutedUntil;
118
+ const next = { ...state, dismissalCount, mutedUntil };
119
+ saveTriggerState(next);
120
+ return next;
121
+ }
122
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/paywall-triggers/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AACnD,OAAO,EACL,2BAA2B,EAC3B,iBAAiB,EACjB,iBAAiB,GAGlB,MAAM,YAAY,CAAA;AAEnB,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;AAEhE,gGAAgG;AAChG,MAAM,UAAU,gBAAgB,CAAC,SAAoB;IACnD,MAAM,IAAI,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAA;IAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAA;IAC1D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAA0B,CAAA;QAC/E,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS;YAAE,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAA;QACvE,OAAO;YACL,MAAM,EAAE,CAAC;YACT,SAAS;YACT,gBAAgB,EACd,OAAO,MAAM,CAAC,gBAAgB,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI;YAC9E,cAAc,EAAE,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;YACrF,UAAU,EAAE,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;SAC7E,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAA;IACrC,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAmB;IAC3C,MAAM,IAAI,GAAG,uBAAuB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACrD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1D,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;AAC7E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAmB,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;IAC1E,OAAO,KAAK,CAAC,UAAU,KAAK,IAAI,IAAI,GAAG,GAAG,KAAK,CAAC,UAAU,CAAA;AAC5D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,SAAoB,EACpB,SAAiB,EACjB,MAAc,IAAI,CAAC,GAAG,EAAE;IAExB,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAA;IACzC,IAAI,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC;QAAE,OAAO,KAAK,CAAA;IAC5C,OAAO,KAAK,CAAC,gBAAgB,KAAK,SAAS,CAAA;AAC7C,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,gBAAgB,CAAC,SAAoB,EAAE,SAAiB;IACtE,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAA;IACzC,MAAM,IAAI,GAAiB,EAAE,GAAG,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAA;IACpE,gBAAgB,CAAC,IAAI,CAAC,CAAA;IACtB,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CACpC,SAAoB,EACpB,MAAc,IAAI,CAAC,GAAG,EAAE;IAExB,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAA;IACzC,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,GAAG,CAAC,CAAA;IAC/C,MAAM,UAAU,GACd,cAAc,IAAI,2BAA2B,CAAC,CAAC,CAAC,GAAG,GAAG,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAA;IAC3F,MAAM,IAAI,GAAiB,EAAE,GAAG,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,CAAA;IACnE,gBAAgB,CAAC,IAAI,CAAC,CAAA;IACtB,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=store.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.test.d.ts","sourceRoot":"","sources":["../../../src/paywall-triggers/store.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * @fileoverview Tests for the paywall trigger-state store (SMI-5456 Wave 1
3
+ * Step 5, QD-3). Covers the P-5 "Trigger state" invariant:
4
+ * "One prompt per session enforced from persisted state, not
5
+ * memory" (cap) + "30-day mute expiry" test.
6
+ * @module @skillsmith/core/paywall-triggers/store.test
7
+ */
8
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
9
+ import { tmpdir } from 'node:os';
10
+ import { join } from 'node:path';
11
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
12
+ import { canShowTrigger, getNudgeCooldownState, isTriggerMuted, loadTriggerState, recordImpression, recordTriggerDismissal, TRIGGER_DISMISSAL_THRESHOLD, TRIGGER_MUTE_DAYS, TRIGGER_STATE_DIR_ENV_VAR, } from './index.js';
13
+ let stateDir;
14
+ let prevEnv;
15
+ let prevNudgeEnv;
16
+ beforeEach(() => {
17
+ stateDir = mkdtempSync(join(tmpdir(), 'skillsmith-paywall-triggers-'));
18
+ prevEnv = process.env[TRIGGER_STATE_DIR_ENV_VAR];
19
+ process.env[TRIGGER_STATE_DIR_ENV_VAR] = stateDir;
20
+ prevNudgeEnv = process.env.SKILLSMITH_AGENT_NUDGE_STATE;
21
+ });
22
+ afterEach(() => {
23
+ rmSync(stateDir, { recursive: true, force: true });
24
+ if (prevEnv !== undefined)
25
+ process.env[TRIGGER_STATE_DIR_ENV_VAR] = prevEnv;
26
+ else
27
+ delete process.env[TRIGGER_STATE_DIR_ENV_VAR];
28
+ if (prevNudgeEnv !== undefined)
29
+ process.env.SKILLSMITH_AGENT_NUDGE_STATE = prevNudgeEnv;
30
+ else
31
+ delete process.env.SKILLSMITH_AGENT_NUDGE_STATE;
32
+ });
33
+ describe('session cap (persisted, not memory)', () => {
34
+ it('allows showing a trigger the first time in a session', () => {
35
+ expect(canShowTrigger('T1', 'session-a')).toBe(true);
36
+ });
37
+ it('blocks a second impression of the same trigger in the same session', () => {
38
+ recordImpression('T1', 'session-a');
39
+ expect(canShowTrigger('T1', 'session-a')).toBe(false);
40
+ });
41
+ it('the cap is read from persisted state, not in-memory — a fresh loadTriggerState call after recordImpression reflects it', () => {
42
+ recordImpression('T2', 'session-x');
43
+ const state = loadTriggerState('T2');
44
+ expect(state.lastSessionShown).toBe('session-x');
45
+ });
46
+ it('allows the SAME trigger again in a DIFFERENT session (documented: concurrent sessions may each prompt once)', () => {
47
+ recordImpression('T1', 'session-a');
48
+ expect(canShowTrigger('T1', 'session-b')).toBe(true);
49
+ });
50
+ it('caps are independent per trigger id', () => {
51
+ recordImpression('T1', 'session-a');
52
+ expect(canShowTrigger('T3', 'session-a')).toBe(true);
53
+ });
54
+ });
55
+ describe('30-day mute expiry', () => {
56
+ it('does not mute after one dismissal', () => {
57
+ const state = recordTriggerDismissal('T4');
58
+ expect(state.dismissalCount).toBe(1);
59
+ expect(isTriggerMuted(state)).toBe(false);
60
+ });
61
+ it(`mutes after ${TRIGGER_DISMISSAL_THRESHOLD} dismissals`, () => {
62
+ recordTriggerDismissal('T4');
63
+ const state = recordTriggerDismissal('T4');
64
+ expect(state.dismissalCount).toBe(TRIGGER_DISMISSAL_THRESHOLD);
65
+ expect(isTriggerMuted(state)).toBe(true);
66
+ });
67
+ it('a muted trigger cannot be shown, even in a session it was never shown in', () => {
68
+ recordTriggerDismissal('T1');
69
+ recordTriggerDismissal('T1');
70
+ expect(canShowTrigger('T1', 'brand-new-session')).toBe(false);
71
+ });
72
+ it(`is still muted 1ms before ${TRIGGER_MUTE_DAYS} days elapse`, () => {
73
+ const now = 1_000_000;
74
+ recordTriggerDismissal('T2', now);
75
+ recordTriggerDismissal('T2', now);
76
+ const almostExpired = now + TRIGGER_MUTE_DAYS * 24 * 60 * 60 * 1000 - 1;
77
+ const state = loadTriggerState('T2');
78
+ expect(isTriggerMuted(state, almostExpired)).toBe(true);
79
+ });
80
+ it(`the mute has expired exactly at ${TRIGGER_MUTE_DAYS} days`, () => {
81
+ const now = 1_000_000;
82
+ recordTriggerDismissal('T2', now);
83
+ recordTriggerDismissal('T2', now);
84
+ const exactlyExpired = now + TRIGGER_MUTE_DAYS * 24 * 60 * 60 * 1000;
85
+ const state = loadTriggerState('T2');
86
+ expect(isTriggerMuted(state, exactlyExpired)).toBe(false);
87
+ });
88
+ it('canShowTrigger allows the trigger again once the mute has expired', () => {
89
+ const now = 1_000_000;
90
+ recordTriggerDismissal('T3', now);
91
+ recordTriggerDismissal('T3', now);
92
+ const afterMute = now + TRIGGER_MUTE_DAYS * 24 * 60 * 60 * 1000 + 1;
93
+ expect(canShowTrigger('T3', 'any-session', afterMute)).toBe(true);
94
+ });
95
+ it('dismissal count keeps accumulating past the threshold (never resets)', () => {
96
+ recordTriggerDismissal('T1');
97
+ recordTriggerDismissal('T1');
98
+ const state = recordTriggerDismissal('T1');
99
+ expect(state.dismissalCount).toBe(3);
100
+ });
101
+ });
102
+ describe('getNudgeCooldownState — format compatibility with the SessionStart hook', () => {
103
+ it('returns null when the nudge-state file does not exist', () => {
104
+ const nudgeFile = join(stateDir, 'agent-nudge.state');
105
+ process.env.SKILLSMITH_AGENT_NUDGE_STATE = nudgeFile;
106
+ expect(getNudgeCooldownState()).toBeNull();
107
+ });
108
+ it('reads a plain epoch-seconds integer written by the hook (no JSON, no wrapper)', () => {
109
+ const nudgeFile = join(stateDir, 'agent-nudge.state');
110
+ process.env.SKILLSMITH_AGENT_NUDGE_STATE = nudgeFile;
111
+ writeFileSync(nudgeFile, '1735689600');
112
+ expect(getNudgeCooldownState()).toBe(1735689600);
113
+ });
114
+ it('treats malformed content as "no prior nudge" (matches the hook\'s own tolerant parsing)', () => {
115
+ const nudgeFile = join(stateDir, 'agent-nudge.state');
116
+ process.env.SKILLSMITH_AGENT_NUDGE_STATE = nudgeFile;
117
+ writeFileSync(nudgeFile, 'not-a-number');
118
+ expect(getNudgeCooldownState()).toBeNull();
119
+ });
120
+ });
121
+ //# sourceMappingURL=store.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.test.js","sourceRoot":"","sources":["../../../src/paywall-triggers/store.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Trigger-state types (SMI-5456 Wave 1 Step 5, QD-3).
3
+ *
4
+ * @module @skillsmith/core/paywall-triggers/types
5
+ */
6
+ /** Paywall trigger IDs from PRD §8.1 (T1 version currency, T2 quota forecast, T3 sharing, T4 security depth). */
7
+ export type TriggerId = 'T1' | 'T2' | 'T3' | 'T4';
8
+ /** Days a trigger stays muted after its dismissal threshold is reached (PRD §8.1 principle 2). */
9
+ export declare const TRIGGER_MUTE_DAYS = 30;
10
+ /** Dismissals before a trigger is muted (PRD §8.1: "two dismissals... suppress it for 30 days"). */
11
+ export declare const TRIGGER_DISMISSAL_THRESHOLD = 2;
12
+ /** On-disk per-trigger state (`~/.skillsmith/paywall-triggers/<id>.json`). */
13
+ export interface TriggerState {
14
+ schema: 1;
15
+ triggerId: TriggerId;
16
+ /** Session id of the last session this trigger was shown in, or null. */
17
+ lastSessionShown: string | null;
18
+ /** Total dismissal count (never resets, even after a mute expires). */
19
+ dismissalCount: number;
20
+ /** Epoch-ms the mute lifts, or null when not currently muted. */
21
+ mutedUntil: number | null;
22
+ }
23
+ export declare function emptyTriggerState(triggerId: TriggerId): TriggerState;
24
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/paywall-triggers/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iHAAiH;AACjH,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAEjD,kGAAkG;AAClG,eAAO,MAAM,iBAAiB,KAAK,CAAA;AAEnC,oGAAoG;AACpG,eAAO,MAAM,2BAA2B,IAAI,CAAA;AAE5C,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,CAAC,CAAA;IACT,SAAS,EAAE,SAAS,CAAA;IACpB,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,uEAAuE;IACvE,cAAc,EAAE,MAAM,CAAA;IACtB,iEAAiE;IACjE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,YAAY,CAEpE"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Trigger-state types (SMI-5456 Wave 1 Step 5, QD-3).
3
+ *
4
+ * @module @skillsmith/core/paywall-triggers/types
5
+ */
6
+ /** Days a trigger stays muted after its dismissal threshold is reached (PRD §8.1 principle 2). */
7
+ export const TRIGGER_MUTE_DAYS = 30;
8
+ /** Dismissals before a trigger is muted (PRD §8.1: "two dismissals... suppress it for 30 days"). */
9
+ export const TRIGGER_DISMISSAL_THRESHOLD = 2;
10
+ export function emptyTriggerState(triggerId) {
11
+ return { schema: 1, triggerId, lastSessionShown: null, dismissalCount: 0, mutedUntil: null };
12
+ }
13
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/paywall-triggers/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,kGAAkG;AAClG,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAA;AAEnC,oGAAoG;AACpG,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAA;AAc5C,MAAM,UAAU,iBAAiB,CAAC,SAAoB;IACpD,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA;AAC9F,CAAC"}
@@ -9,6 +9,8 @@
9
9
  */
10
10
  export { SecurityScanner } from './scanner/index.js';
11
11
  export type { SecurityFinding, SecurityFindingType, SecuritySeverity, ScanReport, ScannerOptions, RiskScoreBreakdown, } from './scanner/index.js';
12
+ export { compareScanReports, DEFAULT_RISK_THRESHOLD } from './scanner/index.js';
13
+ export type { HostileUpdateVerdict } from './scanner/index.js';
12
14
  export { sanitizeHtml, sanitizeFileName, sanitizePath, sanitizeUrl, sanitizeText, isValidStripeId, sanitizeStripeCustomerId, sanitizeStripeSubscriptionId, sanitizeStripePriceId, sanitizeStripeInvoiceId, sanitizeStripeEventId, } from './sanitization.js';
13
15
  export { validateDbPath, validateDbPathOrThrow, isPathSafe, DEFAULT_ALLOWED_DIRS, } from './pathValidation.js';
14
16
  export type { PathValidationOptions, PathValidationResult } from './pathValidation.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/security/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,YAAY,EAEZ,eAAe,EACf,wBAAwB,EACxB,4BAA4B,EAC5B,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,UAAU,EACV,oBAAoB,GACrB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAGtF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,YAAY,EACV,aAAa,EACb,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,GACX,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,WAAW,EACX,wBAAwB,EACxB,kBAAkB,EAClB,2BAA2B,EAC3B,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGtD,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACtF,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/security/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAI3B,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAC/E,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAG9D,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,YAAY,EAEZ,eAAe,EACf,wBAAwB,EACxB,4BAA4B,EAC5B,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,UAAU,EACV,oBAAoB,GACrB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAGtF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,YAAY,EACV,aAAa,EACb,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,GACX,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,WAAW,EACX,wBAAwB,EACxB,kBAAkB,EAClB,2BAA2B,EAC3B,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGtD,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACtF,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA"}
@@ -9,6 +9,10 @@
9
9
  */
10
10
  // Scanner module
11
11
  export { SecurityScanner } from './scanner/index.js';
12
+ // SMI-5535 R0 Wave 2A: the hostile-update (rug-pull) comparator is a public
13
+ // feature; surface it (+ its default threshold + verdict type) through the
14
+ // security barrel so it is reachable from `@skillsmith/core`.
15
+ export { compareScanReports, DEFAULT_RISK_THRESHOLD } from './scanner/index.js';
12
16
  // Sanitization
13
17
  export { sanitizeHtml, sanitizeFileName, sanitizePath, sanitizeUrl, sanitizeText,
14
18
  // SMI-1062: Stripe ID validators
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/security/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iBAAiB;AACjB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAUpD,eAAe;AACf,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,YAAY;AACZ,iCAAiC;AACjC,eAAe,EACf,wBAAwB,EACxB,4BAA4B,EAC5B,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAE1B,kBAAkB;AAClB,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,UAAU,EACV,oBAAoB,GACrB,MAAM,qBAAqB,CAAA;AAG5B,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAU9C,sBAAsB;AACtB,OAAO,EACL,WAAW,EACX,wBAAwB,EACxB,kBAAkB,EAClB,2BAA2B,EAC3B,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,yBAAyB,CAAA;AAQhC,iCAAiC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGjD,0CAA0C;AAC1C,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/security/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iBAAiB;AACjB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AASpD,4EAA4E;AAC5E,2EAA2E;AAC3E,8DAA8D;AAC9D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAG/E,eAAe;AACf,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,YAAY;AACZ,iCAAiC;AACjC,eAAe,EACf,wBAAwB,EACxB,4BAA4B,EAC5B,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAE1B,kBAAkB;AAClB,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,UAAU,EACV,oBAAoB,GACrB,MAAM,qBAAqB,CAAA;AAG5B,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAU9C,sBAAsB;AACtB,OAAO,EACL,WAAW,EACX,wBAAwB,EACxB,kBAAkB,EAClB,2BAA2B,EAC3B,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,yBAAyB,CAAA;AAQhC,iCAAiC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGjD,0CAA0C;AAC1C,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Security Scanner — compound chmod+fetch signal detector
3
+ * @module @skillsmith/core/security/scanner/SecurityScanner.compound
4
+ *
5
+ * SMI-5434: Section 2 of SecurityScanner.scanners.ts extracted so that the
6
+ * upcoming SMI-5433 regex widening (~40 lines) can land without breaching the
7
+ * 500-line audit:standards gate. Pure functions of (content, alreadyFlaggedLines,
8
+ * lineContexts) — no scanner instance state.
9
+ */
10
+ import type { SecurityFinding } from './types.js';
11
+ import type { LineContext } from './SecurityScanner.helpers.js';
12
+ export declare function scanChmodFetchCompound(content: string, alreadyFlaggedLines: ReadonlySet<number>, lineContexts?: LineContext[]): SecurityFinding[];
13
+ //# sourceMappingURL=SecurityScanner.compound.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecurityScanner.compound.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.compound.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAiE/D,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,mBAAmB,EAAE,WAAW,CAAC,MAAM,CAAC,EACxC,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,eAAe,EAAE,CAyDnB"}