@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,171 @@
1
+ /**
2
+ * @fileoverview Unit tests for the change-journal writer + reader
3
+ * (SMI-5456 Wave 1 Step 3 / SMI-5470).
4
+ * @module @skillsmith/core/journal/journal.test
5
+ *
6
+ * Covers two of the three P-5 invariants named in
7
+ * docs/internal/implementation/smi-5456-skillsmith-agent-wave1.md's
8
+ * "Shared-State / Coordination Audit" table for `~/.skillsmith/journal`:
9
+ * - "journal module: concurrent-apply serialization test" (below)
10
+ * - "journal module: chain-verification test" (below)
11
+ * The third (undo round-trip / refusal / scope fence) lives in
12
+ * `@skillsmith/mcp-server`'s `tests/unit/undo-apply.test.ts`, since it
13
+ * needs the mcp-server apply-family tools to produce a realistic changeset.
14
+ */
15
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
16
+ import * as fs from 'node:fs';
17
+ import * as os from 'node:os';
18
+ import * as path from 'node:path';
19
+ import { appendJournalRecord, isCorruptTailError } from './writer.js';
20
+ import { verifyJournalChain } from './reader.js';
21
+ import { getJournalFilePath, resetJournalSessionIdForTests } from './path.js';
22
+ let TEST_DIR;
23
+ let PREV_OVERRIDE;
24
+ beforeEach(() => {
25
+ TEST_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'skillsmith-journal-'));
26
+ PREV_OVERRIDE = process.env['SKILLSMITH_JOURNAL_DIR'];
27
+ process.env['SKILLSMITH_JOURNAL_DIR'] = TEST_DIR;
28
+ resetJournalSessionIdForTests();
29
+ });
30
+ afterEach(() => {
31
+ if (PREV_OVERRIDE !== undefined)
32
+ process.env['SKILLSMITH_JOURNAL_DIR'] = PREV_OVERRIDE;
33
+ else
34
+ delete process.env['SKILLSMITH_JOURNAL_DIR'];
35
+ if (TEST_DIR && fs.existsSync(TEST_DIR))
36
+ fs.rmSync(TEST_DIR, { recursive: true, force: true });
37
+ resetJournalSessionIdForTests();
38
+ });
39
+ function fixtureRecord(suggestionId) {
40
+ return {
41
+ schema: 1,
42
+ ts: Date.now(),
43
+ session_id: 'test-session',
44
+ tool: 'apply_namespace_rename',
45
+ action: 'apply',
46
+ suggestion_id: suggestionId,
47
+ target_path: `/tmp/skill-${suggestionId}.md`,
48
+ before_hash: 'before-hash',
49
+ after_hash: 'after-hash',
50
+ approval: 'apply',
51
+ backup_ref: '/tmp/backup',
52
+ detail: null,
53
+ };
54
+ }
55
+ describe('journal chain verification', () => {
56
+ it('a valid chain (multiple sequential appends) passes verification', async () => {
57
+ await appendJournalRecord(fixtureRecord('a'));
58
+ await appendJournalRecord(fixtureRecord('b'));
59
+ await appendJournalRecord(fixtureRecord('c'));
60
+ const result = await verifyJournalChain();
61
+ expect(result.valid).toBe(true);
62
+ expect(result.records).toHaveLength(3);
63
+ expect(result.breakAt).toBeUndefined();
64
+ // The chain is genuinely linked, not just three independent records.
65
+ expect(result.records[1].prev_hash).toBe(result.records[0].record_hash);
66
+ expect(result.records[2].prev_hash).toBe(result.records[1].record_hash);
67
+ });
68
+ it('an empty / never-written journal is a valid, empty chain (never throws)', async () => {
69
+ const result = await verifyJournalChain();
70
+ expect(result).toEqual({ valid: true, records: [] });
71
+ });
72
+ it('a tampered middle record breaks the chain at the correct index', async () => {
73
+ await appendJournalRecord(fixtureRecord('a'));
74
+ await appendJournalRecord(fixtureRecord('b'));
75
+ await appendJournalRecord(fixtureRecord('c'));
76
+ const filePath = getJournalFilePath();
77
+ const lines = fs
78
+ .readFileSync(filePath, 'utf-8')
79
+ .split('\n')
80
+ .filter((l) => l.length > 0);
81
+ const tampered = JSON.parse(lines[1]);
82
+ tampered.suggestion_id = 'TAMPERED';
83
+ lines[1] = JSON.stringify(tampered);
84
+ fs.writeFileSync(filePath, lines.join('\n') + '\n', 'utf-8');
85
+ const result = await verifyJournalChain();
86
+ expect(result.valid).toBe(false);
87
+ expect(result.breakAt).toBe(1);
88
+ // Everything before the tamper is still reported as verified evidence.
89
+ expect(result.records).toHaveLength(1);
90
+ expect(result.records[0].suggestion_id).toBe('a');
91
+ });
92
+ it('a corrupt tail line is reported via breakAt, never thrown', async () => {
93
+ await appendJournalRecord(fixtureRecord('a'));
94
+ await appendJournalRecord(fixtureRecord('b'));
95
+ const filePath = getJournalFilePath();
96
+ fs.appendFileSync(filePath, 'this is not json\n', 'utf-8');
97
+ const outcome = await verifyJournalChain();
98
+ expect(outcome.valid).toBe(false);
99
+ expect(outcome.breakAt).toBe(2);
100
+ expect(outcome.records).toHaveLength(2);
101
+ });
102
+ });
103
+ describe('journal writer refuses to append past a corrupt tail (governance follow-up, SMI-5456)', () => {
104
+ it('rejects with a typed isCorruptTailError when the last line is unparseable', async () => {
105
+ await appendJournalRecord(fixtureRecord('a'));
106
+ const filePath = getJournalFilePath();
107
+ fs.appendFileSync(filePath, 'this is not json\n', 'utf-8');
108
+ let caught;
109
+ try {
110
+ await appendJournalRecord(fixtureRecord('b'));
111
+ }
112
+ catch (err) {
113
+ caught = err;
114
+ }
115
+ expect(caught).toBeDefined();
116
+ expect(isCorruptTailError(caught)).toBe(true);
117
+ expect(caught.message).toMatch(/corrupt|unverifiable/);
118
+ // The writer never wrote 'b' past the corrupt tail — the file still
119
+ // has exactly the original record plus the corrupt line.
120
+ const lines = fs
121
+ .readFileSync(filePath, 'utf-8')
122
+ .split('\n')
123
+ .filter((l) => l.length > 0);
124
+ expect(lines).toHaveLength(2);
125
+ });
126
+ it('does not wedge the write queue for subsequent callers — a fixed tail lets the next append through', async () => {
127
+ await appendJournalRecord(fixtureRecord('a'));
128
+ const filePath = getJournalFilePath();
129
+ fs.appendFileSync(filePath, 'this is not json\n', 'utf-8');
130
+ await expect(appendJournalRecord(fixtureRecord('b'))).rejects.toSatisfy(isCorruptTailError);
131
+ // Repair the tail (what a real operator/future recovery tool would do)
132
+ // and prove the queue moved forward rather than staying wedged on the
133
+ // rejected promise.
134
+ const lines = fs
135
+ .readFileSync(filePath, 'utf-8')
136
+ .split('\n')
137
+ .filter((l) => l.length > 0);
138
+ lines.pop();
139
+ fs.writeFileSync(filePath, lines.join('\n') + '\n', 'utf-8');
140
+ const record = await appendJournalRecord(fixtureRecord('c'));
141
+ expect(record.suggestion_id).toBe('c');
142
+ const result = await verifyJournalChain();
143
+ expect(result.valid).toBe(true);
144
+ expect(result.records.map((r) => r.suggestion_id)).toEqual(['a', 'c']);
145
+ });
146
+ });
147
+ describe('journal concurrent-apply serialization (P-5 single-writer invariant)', () => {
148
+ it('N concurrent journal writes produce N well-formed, correctly-chained records with no interleaved/torn lines', async () => {
149
+ const N = 25;
150
+ // Fire all N appends without awaiting between them — simulates
151
+ // apply_namespace_rename and apply_recommended_edit racing inside the
152
+ // same server process.
153
+ await Promise.all(Array.from({ length: N }, (_, i) => appendJournalRecord(fixtureRecord(`concurrent-${i}`))));
154
+ const filePath = getJournalFilePath();
155
+ const raw = fs.readFileSync(filePath, 'utf-8');
156
+ const lines = raw.split('\n').filter((l) => l.length > 0);
157
+ // No torn/interleaved lines: every line parses as JSON on its own.
158
+ expect(lines).toHaveLength(N);
159
+ for (const line of lines) {
160
+ expect(() => JSON.parse(line)).not.toThrow();
161
+ }
162
+ const result = await verifyJournalChain();
163
+ expect(result.valid).toBe(true);
164
+ expect(result.records).toHaveLength(N);
165
+ // Every suggestion_id we wrote shows up exactly once — no lost or
166
+ // duplicated writes from the race.
167
+ const seen = new Set(result.records.map((r) => r.suggestion_id));
168
+ expect(seen.size).toBe(N);
169
+ });
170
+ });
171
+ //# sourceMappingURL=journal.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.test.js","sourceRoot":"","sources":["../../../src/journal/journal.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @fileoverview Journal file-layout + process session-id resolution
3
+ * (SMI-5456 Wave 1 Step 3 / SMI-5470).
4
+ * @module @skillsmith/core/journal/path
5
+ *
6
+ * File layout: `<configDir>/journal/journal.jsonl` — JSON Lines (one JSON
7
+ * object per line), append-only. Chosen over a single JSON array because:
8
+ * - Appends are O(1) — no read-modify-rewrite of the whole file, unlike
9
+ * `audit/namespace-overrides.ts`'s ledger (appropriate there because
10
+ * that file is small, mutable config, not an ever-growing log).
11
+ * - A line is the unit of both a write and a crash boundary: fsync'ing
12
+ * one appended line can't corrupt any earlier line, so a torn last
13
+ * write degrades to "one unreadable tail line" rather than an
14
+ * unparseable whole file — exactly what `reader.ts`'s
15
+ * "corrupt tail = report, never throw" contract needs.
16
+ * - It's streamable / greppable for ad-hoc forensics without a parser.
17
+ *
18
+ * `SKILLSMITH_JOURNAL_DIR` overrides the default, mirroring
19
+ * `SKILLSMITH_AGENT_MARKER_DIR` (`../telemetry/agent-marker.ts`) — needed
20
+ * because macOS `os.homedir()` resolves via `getpwuid()` and ignores
21
+ * `process.env.HOME` mutations in tests.
22
+ */
23
+ /** Env var overriding the journal directory (test isolation). */
24
+ export declare const JOURNAL_DIR_ENV_VAR = "SKILLSMITH_JOURNAL_DIR";
25
+ /** Absolute path to the journal file. Read-time resolved (not memoised) so
26
+ * tests can flip `SKILLSMITH_JOURNAL_DIR` between cases. */
27
+ export declare function getJournalFilePath(): string;
28
+ /**
29
+ * Process-lifetime session id shared by every journal record this server
30
+ * process writes, and by the in-process undo stack
31
+ * (`@skillsmith/mcp-server`'s `tools/apply-session.helpers.ts`) that keys
32
+ * "session-scoped undo" off the same lifetime: restarting the MCP server
33
+ * both mints a new session id here AND resets the undo stack (a fresh
34
+ * module load), so the two always agree without explicit coordination.
35
+ */
36
+ export declare function getJournalSessionId(): string;
37
+ /**
38
+ * Test-only reset. The session id is memoised for the process lifetime by
39
+ * design, but a single Vitest process runs many logically-independent
40
+ * "sessions" (test cases) — call this in `afterEach`/`beforeEach` to avoid
41
+ * cross-test bleed.
42
+ */
43
+ export declare function resetJournalSessionIdForTests(): void;
44
+ //# sourceMappingURL=path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/journal/path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,2BAA2B,CAAA;AAO3D;4DAC4D;AAC5D,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAID;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @fileoverview Journal file-layout + process session-id resolution
3
+ * (SMI-5456 Wave 1 Step 3 / SMI-5470).
4
+ * @module @skillsmith/core/journal/path
5
+ *
6
+ * File layout: `<configDir>/journal/journal.jsonl` — JSON Lines (one JSON
7
+ * object per line), append-only. Chosen over a single JSON array because:
8
+ * - Appends are O(1) — no read-modify-rewrite of the whole file, unlike
9
+ * `audit/namespace-overrides.ts`'s ledger (appropriate there because
10
+ * that file is small, mutable config, not an ever-growing log).
11
+ * - A line is the unit of both a write and a crash boundary: fsync'ing
12
+ * one appended line can't corrupt any earlier line, so a torn last
13
+ * write degrades to "one unreadable tail line" rather than an
14
+ * unparseable whole file — exactly what `reader.ts`'s
15
+ * "corrupt tail = report, never throw" contract needs.
16
+ * - It's streamable / greppable for ad-hoc forensics without a parser.
17
+ *
18
+ * `SKILLSMITH_JOURNAL_DIR` overrides the default, mirroring
19
+ * `SKILLSMITH_AGENT_MARKER_DIR` (`../telemetry/agent-marker.ts`) — needed
20
+ * because macOS `os.homedir()` resolves via `getpwuid()` and ignores
21
+ * `process.env.HOME` mutations in tests.
22
+ */
23
+ import { randomUUID } from 'node:crypto';
24
+ import { join } from 'node:path';
25
+ import { getConfigDir } from '../config/index.js';
26
+ /** Env var overriding the journal directory (test isolation). */
27
+ export const JOURNAL_DIR_ENV_VAR = 'SKILLSMITH_JOURNAL_DIR';
28
+ function getJournalDir() {
29
+ const override = process.env[JOURNAL_DIR_ENV_VAR];
30
+ return override && override.length > 0 ? override : join(getConfigDir(), 'journal');
31
+ }
32
+ /** Absolute path to the journal file. Read-time resolved (not memoised) so
33
+ * tests can flip `SKILLSMITH_JOURNAL_DIR` between cases. */
34
+ export function getJournalFilePath() {
35
+ return join(getJournalDir(), 'journal.jsonl');
36
+ }
37
+ let processSessionId;
38
+ /**
39
+ * Process-lifetime session id shared by every journal record this server
40
+ * process writes, and by the in-process undo stack
41
+ * (`@skillsmith/mcp-server`'s `tools/apply-session.helpers.ts`) that keys
42
+ * "session-scoped undo" off the same lifetime: restarting the MCP server
43
+ * both mints a new session id here AND resets the undo stack (a fresh
44
+ * module load), so the two always agree without explicit coordination.
45
+ */
46
+ export function getJournalSessionId() {
47
+ if (processSessionId === undefined) {
48
+ processSessionId = randomUUID();
49
+ }
50
+ return processSessionId;
51
+ }
52
+ /**
53
+ * Test-only reset. The session id is memoised for the process lifetime by
54
+ * design, but a single Vitest process runs many logically-independent
55
+ * "sessions" (test cases) — call this in `afterEach`/`beforeEach` to avoid
56
+ * cross-test bleed.
57
+ */
58
+ export function resetJournalSessionIdForTests() {
59
+ processSessionId = undefined;
60
+ }
61
+ //# sourceMappingURL=path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../../src/journal/path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,iEAAiE;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,wBAAwB,CAAA;AAE3D,SAAS,aAAa;IACpB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;IACjD,OAAO,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,SAAS,CAAC,CAAA;AACrF,CAAC;AAED;4DAC4D;AAC5D,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE,eAAe,CAAC,CAAA;AAC/C,CAAC;AAED,IAAI,gBAAoC,CAAA;AAExC;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB;IACjC,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACnC,gBAAgB,GAAG,UAAU,EAAE,CAAA;IACjC,CAAC;IACD,OAAO,gBAAgB,CAAA;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B;IAC3C,gBAAgB,GAAG,SAAS,CAAA;AAC9B,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @fileoverview Change-journal reader — hash-chain verification
3
+ * (SMI-5456 Wave 1 Step 3 / SMI-5470).
4
+ * @module @skillsmith/core/journal/reader
5
+ *
6
+ * Never throws. The journal exists to be evidence (PRD §7 / §10 exclusion
7
+ * 1); a reader that raises on the first bad byte can't produce that
8
+ * evidence when it matters most (after a tamper or a crash mid-write). A
9
+ * missing file is a valid, empty chain. A corrupt or tampered line is
10
+ * reported via `breakAt` — the caller (e.g. `undo_apply`, or a future audit
11
+ * surface) decides what to do with a break, but the reader never decides
12
+ * for them by throwing.
13
+ */
14
+ import type { JournalRecord } from './types.js';
15
+ export interface ChainVerificationResult {
16
+ /** `true` iff every line parsed, chained, and hash-verified cleanly. */
17
+ valid: boolean;
18
+ /** Records verified so far — the full chain when `valid` is `true`, or
19
+ * every record BEFORE the break when `valid` is `false`. */
20
+ records: JournalRecord[];
21
+ /** 0-based line index of the first unparseable / malformed / tampered
22
+ * record. Present iff `valid` is `false`. */
23
+ breakAt?: number;
24
+ }
25
+ /**
26
+ * Verify the journal's hash chain line-by-line: each record's `prev_hash`
27
+ * must equal the previous record's `record_hash` (or `JOURNAL_GENESIS_HASH`
28
+ * for the first line), and each record's own `record_hash` must match a
29
+ * fresh recomputation from its other fields (SMI-5456 §7 tamper signal).
30
+ *
31
+ * @param filePath - Override for tests; defaults to the resolved journal path.
32
+ */
33
+ export declare function verifyJournalChain(filePath?: string): Promise<ChainVerificationResult>;
34
+ /** Convenience wrapper: the verified records, or as many as verified before
35
+ * a break. Callers that need the break position should use
36
+ * `verifyJournalChain` directly. */
37
+ export declare function readJournalRecords(filePath?: string): Promise<JournalRecord[]>;
38
+ //# sourceMappingURL=reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../../src/journal/reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,KAAK,EAAE,OAAO,CAAA;IACd;gEAC4D;IAC5D,OAAO,EAAE,aAAa,EAAE,CAAA;IACxB;iDAC6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAwBD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA6C5F;AAED;;oCAEoC;AACpC,wBAAsB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAGpF"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @fileoverview Change-journal reader — hash-chain verification
3
+ * (SMI-5456 Wave 1 Step 3 / SMI-5470).
4
+ * @module @skillsmith/core/journal/reader
5
+ *
6
+ * Never throws. The journal exists to be evidence (PRD §7 / §10 exclusion
7
+ * 1); a reader that raises on the first bad byte can't produce that
8
+ * evidence when it matters most (after a tamper or a crash mid-write). A
9
+ * missing file is a valid, empty chain. A corrupt or tampered line is
10
+ * reported via `breakAt` — the caller (e.g. `undo_apply`, or a future audit
11
+ * surface) decides what to do with a break, but the reader never decides
12
+ * for them by throwing.
13
+ */
14
+ import { readFile } from 'node:fs/promises';
15
+ import { getJournalFilePath } from './path.js';
16
+ import { computeRecordHash } from './writer.js';
17
+ import { JOURNAL_GENESIS_HASH } from './hash.js';
18
+ /** Narrow an arbitrary parsed JSON value down to the `JournalRecord` shape. */
19
+ function isJournalRecordShape(value) {
20
+ if (!value || typeof value !== 'object')
21
+ return false;
22
+ const r = value;
23
+ return (typeof r.schema === 'number' &&
24
+ typeof r.ts === 'number' &&
25
+ typeof r.session_id === 'string' &&
26
+ typeof r.tool === 'string' &&
27
+ (r.action === 'apply' || r.action === 'error' || r.action === 'undo') &&
28
+ (r.suggestion_id === null || typeof r.suggestion_id === 'string') &&
29
+ (r.target_path === null || typeof r.target_path === 'string') &&
30
+ (r.before_hash === null || typeof r.before_hash === 'string') &&
31
+ (r.after_hash === null || typeof r.after_hash === 'string') &&
32
+ (r.approval === null || typeof r.approval === 'string') &&
33
+ (r.backup_ref === null || typeof r.backup_ref === 'string') &&
34
+ (r.detail === null || typeof r.detail === 'string') &&
35
+ typeof r.prev_hash === 'string' &&
36
+ typeof r.record_hash === 'string');
37
+ }
38
+ /**
39
+ * Verify the journal's hash chain line-by-line: each record's `prev_hash`
40
+ * must equal the previous record's `record_hash` (or `JOURNAL_GENESIS_HASH`
41
+ * for the first line), and each record's own `record_hash` must match a
42
+ * fresh recomputation from its other fields (SMI-5456 §7 tamper signal).
43
+ *
44
+ * @param filePath - Override for tests; defaults to the resolved journal path.
45
+ */
46
+ export async function verifyJournalChain(filePath) {
47
+ const path = filePath ?? getJournalFilePath();
48
+ let raw;
49
+ try {
50
+ raw = await readFile(path, 'utf-8');
51
+ }
52
+ catch {
53
+ // Missing file (never written yet) — a valid, empty chain.
54
+ return { valid: true, records: [] };
55
+ }
56
+ const lines = raw.split('\n').filter((line) => line.trim().length > 0);
57
+ const records = [];
58
+ let expectedPrevHash = JOURNAL_GENESIS_HASH;
59
+ for (let i = 0; i < lines.length; i++) {
60
+ let parsed;
61
+ try {
62
+ parsed = JSON.parse(lines[i]);
63
+ }
64
+ catch {
65
+ // Corrupt/torn line (e.g. a crash mid-append) — report, don't throw.
66
+ return { valid: false, records, breakAt: i };
67
+ }
68
+ if (!isJournalRecordShape(parsed)) {
69
+ return { valid: false, records, breakAt: i };
70
+ }
71
+ if (parsed.prev_hash !== expectedPrevHash) {
72
+ // Chain discontinuity — a record was deleted, reordered, or its
73
+ // neighbor was tampered.
74
+ return { valid: false, records, breakAt: i };
75
+ }
76
+ const { record_hash, ...rest } = parsed;
77
+ if (computeRecordHash(rest) !== record_hash) {
78
+ // The record's own content was edited after the fact.
79
+ return { valid: false, records, breakAt: i };
80
+ }
81
+ records.push(parsed);
82
+ expectedPrevHash = record_hash;
83
+ }
84
+ return { valid: true, records };
85
+ }
86
+ /** Convenience wrapper: the verified records, or as many as verified before
87
+ * a break. Callers that need the break position should use
88
+ * `verifyJournalChain` directly. */
89
+ export async function readJournalRecords(filePath) {
90
+ const result = await verifyJournalChain(filePath);
91
+ return result.records;
92
+ }
93
+ //# sourceMappingURL=reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.js","sourceRoot":"","sources":["../../../src/journal/reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @fileoverview Change-journal record shape (SMI-5456 Wave 1 Step 3 / SMI-5470).
3
+ * @module @skillsmith/core/journal/types
4
+ *
5
+ * The journal is the trust-loop evidence base described in
6
+ * docs/internal/product/prd-skillsmith-agent.md §7: an append-only,
7
+ * hash-chained record of every mutation the apply-family MCP tools make
8
+ * (`apply_namespace_rename`, `apply_recommended_edit`) plus the `undo_apply`
9
+ * tool that reverses them. It is the substrate PRD §10 exclusion 1 points at
10
+ * before autonomy can ever be relaxed ("90 days of journal data shows ≥95%
11
+ * suggestion-acceptance and zero rollback incidents").
12
+ *
13
+ * Field naming is snake_case (not the package's usual camelCase) because the
14
+ * journal is a durable on-disk wire format, not an in-memory TS shape — it
15
+ * mirrors the telemetry wire format's convention (SMI-5012) for the same
16
+ * reason: an on-disk/over-the-wire record should read the same regardless of
17
+ * which language eventually parses it.
18
+ */
19
+ /** Bump on a breaking shape change to `JournalRecord`. */
20
+ export declare const JOURNAL_SCHEMA_VERSION = 1;
21
+ /**
22
+ * `'apply'` — an apply-family tool successfully mutated a file.
23
+ * `'error'` — an apply-family tool attempted a mutation and it failed
24
+ * (the `detail` field carries the typed error kind).
25
+ * `'undo'` — `undo_apply` successfully reversed a prior `'apply'` record.
26
+ */
27
+ export type JournalAction = 'apply' | 'error' | 'undo';
28
+ /**
29
+ * Every field the caller supplies. The writer (`writer.ts`) fills in
30
+ * `prev_hash` + `record_hash` to complete a `JournalRecord`.
31
+ *
32
+ * Field semantics:
33
+ * - `suggestion_id` — the `collisionId` the mutation was applied for.
34
+ * - `target_path` — the on-disk file whose CONTENT the record's hashes
35
+ * describe. For a single-file mutation (prose edit, command/agent rename)
36
+ * this is the mutated file itself. For a skill-directory rename
37
+ * (`rename_skill_dir_and_frontmatter`) this is `<newSkillDir>/SKILL.md` —
38
+ * the one file whose bytes actually changed; the directory rename itself
39
+ * is not content-hashable and is intentionally out of this record's scope
40
+ * (see `tools/apply-journal.helpers.ts` header in `@skillsmith/mcp-server`
41
+ * for the full rationale).
42
+ * - `before_hash` / `after_hash` — sha256 of `target_path`'s content
43
+ * immediately before / after the mutation. `null` where not applicable
44
+ * (e.g. an `'error'` record where the mutation never reached a
45
+ * content-changing step, so there is no "after" state to hash).
46
+ * - `approval` — the caller-supplied approval mode that authorized the
47
+ * mutation, e.g. `'apply'` / `'custom'` (namespace rename) or
48
+ * `'apply_with_confirmation'` (recommended edit). Always non-null for
49
+ * `'apply'`/`'error'` records (the confirmation gate ran); `'undo'` for
50
+ * undo records.
51
+ * - `backup_ref` — absolute path to the apply tool's own pre-mutation
52
+ * backup directory (from `createSkillBackup` / `createProseBackup`).
53
+ * `null` for `'error'` and `'undo'` records — an error may not have
54
+ * reached the backup step, and an undo record documents a restore that
55
+ * already happened rather than creating a new backup.
56
+ * - `detail` — free-text elaboration. Populated with the typed error
57
+ * `kind` (e.g. `'namespace.rename.backup_failed'`) on `'error'` records;
58
+ * `null` otherwise.
59
+ */
60
+ export interface JournalRecordFields {
61
+ schema: number;
62
+ ts: number;
63
+ session_id: string;
64
+ tool: string;
65
+ action: JournalAction;
66
+ suggestion_id: string | null;
67
+ target_path: string | null;
68
+ before_hash: string | null;
69
+ after_hash: string | null;
70
+ approval: string | null;
71
+ backup_ref: string | null;
72
+ detail: string | null;
73
+ }
74
+ /** Input to `appendJournalRecord` — the writer computes the rest. */
75
+ export type JournalRecordInput = JournalRecordFields;
76
+ /**
77
+ * A fully-formed, on-disk journal record (one JSON-Lines row). `prev_hash`
78
+ * chains to the previous record's `record_hash` (or `JOURNAL_GENESIS_HASH`
79
+ * for the first record); `record_hash` commits to every other field
80
+ * INCLUDING `prev_hash`, so any single-record tamper is detectable by
81
+ * recomputing it — see `reader.ts:verifyJournalChain`.
82
+ */
83
+ export interface JournalRecord extends JournalRecordFields {
84
+ prev_hash: string;
85
+ record_hash: string;
86
+ }
87
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/journal/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,0DAA0D;AAC1D,eAAO,MAAM,sBAAsB,IAAI,CAAA;AAEvC;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAA;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,aAAa,CAAA;IACrB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED,qEAAqE;AACrE,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,CAAA;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,aAAc,SAAQ,mBAAmB;IACxD,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;CACpB"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @fileoverview Change-journal record shape (SMI-5456 Wave 1 Step 3 / SMI-5470).
3
+ * @module @skillsmith/core/journal/types
4
+ *
5
+ * The journal is the trust-loop evidence base described in
6
+ * docs/internal/product/prd-skillsmith-agent.md §7: an append-only,
7
+ * hash-chained record of every mutation the apply-family MCP tools make
8
+ * (`apply_namespace_rename`, `apply_recommended_edit`) plus the `undo_apply`
9
+ * tool that reverses them. It is the substrate PRD §10 exclusion 1 points at
10
+ * before autonomy can ever be relaxed ("90 days of journal data shows ≥95%
11
+ * suggestion-acceptance and zero rollback incidents").
12
+ *
13
+ * Field naming is snake_case (not the package's usual camelCase) because the
14
+ * journal is a durable on-disk wire format, not an in-memory TS shape — it
15
+ * mirrors the telemetry wire format's convention (SMI-5012) for the same
16
+ * reason: an on-disk/over-the-wire record should read the same regardless of
17
+ * which language eventually parses it.
18
+ */
19
+ /** Bump on a breaking shape change to `JournalRecord`. */
20
+ export const JOURNAL_SCHEMA_VERSION = 1;
21
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/journal/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,0DAA0D;AAC1D,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAA"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @fileoverview Change-journal writer — single-writer, fsync'd, hash-chained
3
+ * append (SMI-5456 Wave 1 Step 3 / SMI-5470).
4
+ * @module @skillsmith/core/journal/writer
5
+ *
6
+ * P-5 single-writer invariant (docs/internal/implementation/smi-5456-skillsmith-agent-wave1.md
7
+ * "Shared-State / Coordination Audit"): the journal file is written by the
8
+ * apply-family MCP tools ONLY, and every writer in this process funnels
9
+ * through `appendJournalRecord`, which serializes behind ONE module-scoped
10
+ * promise queue. That queue — not any per-caller locking — is what makes
11
+ * concurrent `apply_namespace_rename` / `apply_recommended_edit` / `undo_apply`
12
+ * calls in the same server process produce well-formed, correctly-chained
13
+ * lines instead of interleaved/torn writes.
14
+ *
15
+ * Durability: each append opens the file, writes the line, calls
16
+ * `FileHandle.sync()` (fsync), then closes — so a record that returns
17
+ * successfully is durable on disk before the caller's apply/undo response
18
+ * goes out, matching the "fsync'd appends" requirement in the plan's P-5
19
+ * table.
20
+ */
21
+ import type { JournalRecord, JournalRecordInput } from './types.js';
22
+ /**
23
+ * Recompute a record's `record_hash` from its other fields. Exported so the
24
+ * reader can independently verify each line without duplicating the
25
+ * canonicalization logic (drift between writer and reader would silently
26
+ * break every chain-verification call).
27
+ */
28
+ export declare function computeRecordHash(record: Omit<JournalRecord, 'record_hash'>): string;
29
+ /**
30
+ * Error thrown when the journal's last line cannot be parsed as a valid
31
+ * record — the writer cannot safely determine the chain head to append
32
+ * after. This is distinct from the reader's "corrupt tail = report, never
33
+ * throw" contract: a reader is producing evidence about the past and must
34
+ * degrade gracefully; a writer is about to create NEW evidence and silently
35
+ * starting a fresh chain over a corrupt/tampered tail would hide exactly
36
+ * the tamper signal the chain exists to surface.
37
+ */
38
+ export interface JournalCorruptTailError extends Error {
39
+ kind: 'journal.write.corrupt_tail';
40
+ }
41
+ export declare function isCorruptTailError(err: unknown): err is JournalCorruptTailError;
42
+ /**
43
+ * Append a record to the journal. Serialized behind the module-scoped
44
+ * write queue and fsync'd before the returned promise resolves.
45
+ *
46
+ * Callers (the apply-family tools) should treat a rejection as fail-soft —
47
+ * the journal is an evidence trail, not a gate on the user's mutation —
48
+ * and log rather than propagate. See `tools/apply-journal.helpers.ts` in
49
+ * `@skillsmith/mcp-server` for the call-site convention.
50
+ */
51
+ export declare function appendJournalRecord(input: JournalRecordInput): Promise<JournalRecord>;
52
+ //# sourceMappingURL=writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../../src/journal/writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AA4BnE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,GAAG,MAAM,CAEpF;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAwB,SAAQ,KAAK;IACpD,IAAI,EAAE,4BAA4B,CAAA;CACnC;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,uBAAuB,CAK/E;AAkCD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAQrF"}