@skillsmith/core 0.11.4 → 0.11.6

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 (240) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +10 -7
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/src/api/client.d.ts.map +1 -1
  5. package/dist/src/api/client.js +20 -5
  6. package/dist/src/api/client.js.map +1 -1
  7. package/dist/src/api/client.private-registry.d.ts +80 -0
  8. package/dist/src/api/client.private-registry.d.ts.map +1 -0
  9. package/dist/src/api/client.private-registry.js +97 -0
  10. package/dist/src/api/client.private-registry.js.map +1 -0
  11. package/dist/src/api/client.private-registry.test.d.ts +9 -0
  12. package/dist/src/api/client.private-registry.test.d.ts.map +1 -0
  13. package/dist/src/api/client.private-registry.test.js +127 -0
  14. package/dist/src/api/client.private-registry.test.js.map +1 -0
  15. package/dist/src/api/client.test.js +39 -0
  16. package/dist/src/api/client.test.js.map +1 -1
  17. package/dist/src/api/client.toSkill.test.d.ts +25 -0
  18. package/dist/src/api/client.toSkill.test.d.ts.map +1 -0
  19. package/dist/src/api/client.toSkill.test.js +97 -0
  20. package/dist/src/api/client.toSkill.test.js.map +1 -0
  21. package/dist/src/api/client.token-refresh.d.ts +8 -0
  22. package/dist/src/api/client.token-refresh.d.ts.map +1 -1
  23. package/dist/src/api/client.token-refresh.js +26 -0
  24. package/dist/src/api/client.token-refresh.js.map +1 -1
  25. package/dist/src/api/client.token-refresh.test.js +82 -0
  26. package/dist/src/api/client.token-refresh.test.js.map +1 -1
  27. package/dist/src/api/index.d.ts +2 -0
  28. package/dist/src/api/index.d.ts.map +1 -1
  29. package/dist/src/api/index.js +9 -0
  30. package/dist/src/api/index.js.map +1 -1
  31. package/dist/src/api/security-summary.d.ts +73 -0
  32. package/dist/src/api/security-summary.d.ts.map +1 -0
  33. package/dist/src/api/security-summary.js +88 -0
  34. package/dist/src/api/security-summary.js.map +1 -0
  35. package/dist/src/api/security-summary.test.d.ts +9 -0
  36. package/dist/src/api/security-summary.test.d.ts.map +1 -0
  37. package/dist/src/api/security-summary.test.js +94 -0
  38. package/dist/src/api/security-summary.test.js.map +1 -0
  39. package/dist/src/compatibility/slugs.d.ts +7 -3
  40. package/dist/src/compatibility/slugs.d.ts.map +1 -1
  41. package/dist/src/compatibility/slugs.js +11 -4
  42. package/dist/src/compatibility/slugs.js.map +1 -1
  43. package/dist/src/config/config-atomic-write.d.ts +30 -10
  44. package/dist/src/config/config-atomic-write.d.ts.map +1 -1
  45. package/dist/src/config/config-atomic-write.js +33 -80
  46. package/dist/src/config/config-atomic-write.js.map +1 -1
  47. package/dist/src/config/config-atomic-write.test.d.ts +8 -0
  48. package/dist/src/config/config-atomic-write.test.d.ts.map +1 -1
  49. package/dist/src/config/config-atomic-write.test.js +64 -12
  50. package/dist/src/config/config-atomic-write.test.js.map +1 -1
  51. package/dist/src/config/owned-lock.acquire.d.ts +53 -0
  52. package/dist/src/config/owned-lock.acquire.d.ts.map +1 -0
  53. package/dist/src/config/owned-lock.acquire.js +140 -0
  54. package/dist/src/config/owned-lock.acquire.js.map +1 -0
  55. package/dist/src/config/owned-lock.claim.d.ts +84 -0
  56. package/dist/src/config/owned-lock.claim.d.ts.map +1 -0
  57. package/dist/src/config/owned-lock.claim.js +310 -0
  58. package/dist/src/config/owned-lock.claim.js.map +1 -0
  59. package/dist/src/config/owned-lock.d.ts +113 -0
  60. package/dist/src/config/owned-lock.d.ts.map +1 -0
  61. package/dist/src/config/owned-lock.js +121 -0
  62. package/dist/src/config/owned-lock.js.map +1 -0
  63. package/dist/src/config/owned-lock.test.d.ts +12 -0
  64. package/dist/src/config/owned-lock.test.d.ts.map +1 -0
  65. package/dist/src/config/owned-lock.test.js +412 -0
  66. package/dist/src/config/owned-lock.test.js.map +1 -0
  67. package/dist/src/config/owned-lock.types.d.ts +78 -0
  68. package/dist/src/config/owned-lock.types.d.ts.map +1 -0
  69. package/dist/src/config/owned-lock.types.js +30 -0
  70. package/dist/src/config/owned-lock.types.js.map +1 -0
  71. package/dist/src/db/createDatabase.d.ts.map +1 -1
  72. package/dist/src/db/createDatabase.js +19 -7
  73. package/dist/src/db/createDatabase.js.map +1 -1
  74. package/dist/src/db/drivers/sqljsDriver.d.ts +8 -0
  75. package/dist/src/db/drivers/sqljsDriver.d.ts.map +1 -1
  76. package/dist/src/db/drivers/sqljsDriver.js +24 -2
  77. package/dist/src/db/drivers/sqljsDriver.js.map +1 -1
  78. package/dist/src/db/migration-runner.d.ts.map +1 -1
  79. package/dist/src/db/migration-runner.js +23 -2
  80. package/dist/src/db/migration-runner.js.map +1 -1
  81. package/dist/src/db/schema.d.ts.map +1 -1
  82. package/dist/src/db/schema.js +29 -3
  83. package/dist/src/db/schema.js.map +1 -1
  84. package/dist/src/embeddings/hnsw-store.exports.d.ts +11 -0
  85. package/dist/src/embeddings/hnsw-store.exports.d.ts.map +1 -0
  86. package/dist/src/embeddings/hnsw-store.exports.js +10 -0
  87. package/dist/src/embeddings/hnsw-store.exports.js.map +1 -0
  88. package/dist/src/embeddings/index.d.ts +1 -2
  89. package/dist/src/embeddings/index.d.ts.map +1 -1
  90. package/dist/src/embeddings/index.js +17 -3
  91. package/dist/src/embeddings/index.js.map +1 -1
  92. package/dist/src/embeddings/probe.d.ts.map +1 -1
  93. package/dist/src/embeddings/probe.js +4 -8
  94. package/dist/src/embeddings/probe.js.map +1 -1
  95. package/dist/src/exports/services.d.ts +5 -1
  96. package/dist/src/exports/services.d.ts.map +1 -1
  97. package/dist/src/exports/services.js +27 -0
  98. package/dist/src/exports/services.js.map +1 -1
  99. package/dist/src/index.d.ts +3 -3
  100. package/dist/src/index.d.ts.map +1 -1
  101. package/dist/src/index.js +9 -3
  102. package/dist/src/index.js.map +1 -1
  103. package/dist/src/install/index.d.ts +2 -2
  104. package/dist/src/install/index.d.ts.map +1 -1
  105. package/dist/src/install/index.js +1 -1
  106. package/dist/src/install/index.js.map +1 -1
  107. package/dist/src/install/paths.d.ts +165 -1
  108. package/dist/src/install/paths.d.ts.map +1 -1
  109. package/dist/src/install/paths.js +254 -1
  110. package/dist/src/install/paths.js.map +1 -1
  111. package/dist/src/install/paths.test.js +174 -2
  112. package/dist/src/install/paths.test.js.map +1 -1
  113. package/dist/src/security/scanner/multiline-category-closure.test.d.ts +80 -0
  114. package/dist/src/security/scanner/multiline-category-closure.test.d.ts.map +1 -0
  115. package/dist/src/security/scanner/multiline-category-closure.test.js +287 -0
  116. package/dist/src/security/scanner/multiline-category-closure.test.js.map +1 -0
  117. package/dist/src/services/context-words.d.ts +40 -0
  118. package/dist/src/services/context-words.d.ts.map +1 -0
  119. package/dist/src/services/context-words.js +178 -0
  120. package/dist/src/services/context-words.js.map +1 -0
  121. package/dist/src/services/context-words.test.d.ts +2 -0
  122. package/dist/src/services/context-words.test.d.ts.map +1 -0
  123. package/dist/src/services/context-words.test.js +94 -0
  124. package/dist/src/services/context-words.test.js.map +1 -0
  125. package/dist/src/services/recommend-guard.d.ts +28 -0
  126. package/dist/src/services/recommend-guard.d.ts.map +1 -0
  127. package/dist/src/services/recommend-guard.js +34 -0
  128. package/dist/src/services/recommend-guard.js.map +1 -0
  129. package/dist/src/services/recommend-guard.test.d.ts +2 -0
  130. package/dist/src/services/recommend-guard.test.d.ts.map +1 -0
  131. package/dist/src/services/recommend-guard.test.js +28 -0
  132. package/dist/src/services/recommend-guard.test.js.map +1 -0
  133. package/dist/src/services/skill-installation.content.d.ts +96 -0
  134. package/dist/src/services/skill-installation.content.d.ts.map +1 -0
  135. package/dist/src/services/skill-installation.content.js +319 -0
  136. package/dist/src/services/skill-installation.content.js.map +1 -0
  137. package/dist/src/services/skill-installation.helpers.d.ts +32 -1
  138. package/dist/src/services/skill-installation.helpers.d.ts.map +1 -1
  139. package/dist/src/services/skill-installation.helpers.js +62 -7
  140. package/dist/src/services/skill-installation.helpers.js.map +1 -1
  141. package/dist/src/services/skill-installation.helpers.test.js +108 -2
  142. package/dist/src/services/skill-installation.helpers.test.js.map +1 -1
  143. package/dist/src/services/skill-installation.io.d.ts +22 -1
  144. package/dist/src/services/skill-installation.io.d.ts.map +1 -1
  145. package/dist/src/services/skill-installation.io.js +110 -6
  146. package/dist/src/services/skill-installation.io.js.map +1 -1
  147. package/dist/src/services/skill-installation.service.d.ts +22 -1
  148. package/dist/src/services/skill-installation.service.d.ts.map +1 -1
  149. package/dist/src/services/skill-installation.service.js +30 -5
  150. package/dist/src/services/skill-installation.service.js.map +1 -1
  151. package/dist/src/services/skill-installation.types.d.ts +42 -1
  152. package/dist/src/services/skill-installation.types.d.ts.map +1 -1
  153. package/dist/src/services/skill-installation.types.js.map +1 -1
  154. package/dist/src/services/skill-manifest.d.ts +21 -0
  155. package/dist/src/services/skill-manifest.d.ts.map +1 -1
  156. package/dist/src/services/skill-manifest.js +51 -6
  157. package/dist/src/services/skill-manifest.js.map +1 -1
  158. package/dist/src/services/skill-manifest.test.d.ts +2 -0
  159. package/dist/src/services/skill-manifest.test.d.ts.map +1 -0
  160. package/dist/src/services/skill-manifest.test.js +202 -0
  161. package/dist/src/services/skill-manifest.test.js.map +1 -0
  162. package/dist/src/services/skill-resolution.d.ts +67 -0
  163. package/dist/src/services/skill-resolution.d.ts.map +1 -0
  164. package/dist/src/services/skill-resolution.js +67 -0
  165. package/dist/src/services/skill-resolution.js.map +1 -0
  166. package/dist/src/services/skill-resolution.test.d.ts +2 -0
  167. package/dist/src/services/skill-resolution.test.d.ts.map +1 -0
  168. package/dist/src/services/skill-resolution.test.js +143 -0
  169. package/dist/src/services/skill-resolution.test.js.map +1 -0
  170. package/dist/src/types/skill.d.ts +10 -0
  171. package/dist/src/types/skill.d.ts.map +1 -1
  172. package/dist/src/types.d.ts +9 -5
  173. package/dist/src/types.d.ts.map +1 -1
  174. package/dist/src/utils/index.d.ts +1 -0
  175. package/dist/src/utils/index.d.ts.map +1 -1
  176. package/dist/src/utils/index.js +4 -0
  177. package/dist/src/utils/index.js.map +1 -1
  178. package/dist/src/utils/quiet-mode.d.ts +21 -0
  179. package/dist/src/utils/quiet-mode.d.ts.map +1 -0
  180. package/dist/src/utils/quiet-mode.js +26 -0
  181. package/dist/src/utils/quiet-mode.js.map +1 -0
  182. package/dist/tests/EmbeddingService.test.js +58 -1
  183. package/dist/tests/EmbeddingService.test.js.map +1 -1
  184. package/dist/tests/SecurityScanner.performance.test.js +5 -2
  185. package/dist/tests/SecurityScanner.performance.test.js.map +1 -1
  186. package/dist/tests/db/database-abstraction.test.js +45 -1
  187. package/dist/tests/db/database-abstraction.test.js.map +1 -1
  188. package/dist/tests/db/migration-runner-race.test.d.ts +2 -0
  189. package/dist/tests/db/migration-runner-race.test.d.ts.map +1 -0
  190. package/dist/tests/db/migration-runner-race.test.js +75 -0
  191. package/dist/tests/db/migration-runner-race.test.js.map +1 -0
  192. package/dist/tests/db/schema-async.test.js +37 -1
  193. package/dist/tests/db/schema-async.test.js.map +1 -1
  194. package/dist/tests/db/sqljsDriver.test.js +63 -1
  195. package/dist/tests/db/sqljsDriver.test.js.map +1 -1
  196. package/dist/tests/helpers/deterministic-dead-pid.d.ts +13 -0
  197. package/dist/tests/helpers/deterministic-dead-pid.d.ts.map +1 -0
  198. package/dist/tests/helpers/deterministic-dead-pid.js +31 -0
  199. package/dist/tests/helpers/deterministic-dead-pid.js.map +1 -0
  200. package/dist/tests/integration/owned-lock-lost-update.test.d.ts +12 -0
  201. package/dist/tests/integration/owned-lock-lost-update.test.d.ts.map +1 -0
  202. package/dist/tests/integration/owned-lock-lost-update.test.js +52 -0
  203. package/dist/tests/integration/owned-lock-lost-update.test.js.map +1 -0
  204. package/dist/tests/integration/owned-lock-reclaim-race.test.d.ts +19 -0
  205. package/dist/tests/integration/owned-lock-reclaim-race.test.d.ts.map +1 -0
  206. package/dist/tests/integration/owned-lock-reclaim-race.test.js +177 -0
  207. package/dist/tests/integration/owned-lock-reclaim-race.test.js.map +1 -0
  208. package/dist/tests/schema.test.js +43 -1
  209. package/dist/tests/schema.test.js.map +1 -1
  210. package/dist/tests/unit/services/skill-installation.content.test.d.ts +10 -0
  211. package/dist/tests/unit/services/skill-installation.content.test.d.ts.map +1 -0
  212. package/dist/tests/unit/services/skill-installation.content.test.js +290 -0
  213. package/dist/tests/unit/services/skill-installation.content.test.js.map +1 -0
  214. package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.d.ts +34 -0
  215. package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.d.ts.map +1 -0
  216. package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.js +246 -0
  217. package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.js.map +1 -0
  218. package/dist/tests/unit/services/skill-installation.io.symlink.test.d.ts +8 -0
  219. package/dist/tests/unit/services/skill-installation.io.symlink.test.d.ts.map +1 -0
  220. package/dist/tests/unit/services/skill-installation.io.symlink.test.js +72 -0
  221. package/dist/tests/unit/services/skill-installation.io.symlink.test.js.map +1 -0
  222. package/dist/tests/unit/services/skill-installation.service.companion-basedir.test.d.ts +17 -0
  223. package/dist/tests/unit/services/skill-installation.service.companion-basedir.test.d.ts.map +1 -0
  224. package/dist/tests/unit/services/skill-installation.service.companion-basedir.test.js +112 -0
  225. package/dist/tests/unit/services/skill-installation.service.companion-basedir.test.js.map +1 -0
  226. package/dist/tests/unit/services/skill-installation.service.error-codes.test.d.ts +15 -0
  227. package/dist/tests/unit/services/skill-installation.service.error-codes.test.d.ts.map +1 -0
  228. package/dist/tests/unit/services/skill-installation.service.error-codes.test.js +190 -0
  229. package/dist/tests/unit/services/skill-installation.service.error-codes.test.js.map +1 -0
  230. package/dist/tests/unit/services/skill-installation.service.multi-client.test.d.ts +17 -0
  231. package/dist/tests/unit/services/skill-installation.service.multi-client.test.d.ts.map +1 -0
  232. package/dist/tests/unit/services/skill-installation.service.multi-client.test.js +126 -0
  233. package/dist/tests/unit/services/skill-installation.service.multi-client.test.js.map +1 -0
  234. package/dist/tests/unit/services/skill-installation.service.test.js +7 -112
  235. package/dist/tests/unit/services/skill-installation.service.test.js.map +1 -1
  236. package/dist/tests/utils/quiet-mode.test.d.ts +12 -0
  237. package/dist/tests/utils/quiet-mode.test.d.ts.map +1 -0
  238. package/dist/tests/utils/quiet-mode.test.js +42 -0
  239. package/dist/tests/utils/quiet-mode.test.js.map +1 -0
  240. package/package.json +17 -5
@@ -0,0 +1,97 @@
1
+ /**
2
+ * SMI-5897 (C-15): Unit coverage for `SkillsmithApiClient.toSkill()`'s
3
+ * security-status field derivation.
4
+ *
5
+ * Previously `toSkill()` hardcoded `riskScore: null, securityFindingsCount: 0,
6
+ * securityScannedAt: null, securityPassed: null` for every API-sourced skill,
7
+ * discarding the real `security_score`/`quarantined`/`last_scanned_at`/
8
+ * `security_findings` fields already present on the `ApiSearchResult` it
9
+ * received — this is why CLI `info`/`search` (which both route through
10
+ * `toSkill()`) could show "Not scanned" for a skill MCP correctly reported
11
+ * as passed. `toSkill()` now derives these fields via the same shared
12
+ * `deriveSecuritySummaryFromApiSkill()` MCP's tools use, so the two surfaces
13
+ * can't re-diverge (see `api/security-summary.test.ts` for derivation-logic
14
+ * coverage — this file only asserts `toSkill()` wires it through correctly).
15
+ *
16
+ * SMI-5897 (Wave 4 fix): imports `ApiSearchResult` from `./client.types.js` —
17
+ * `toSkill()`'s ACTUAL parameter type — not `./types.js`, which declares a
18
+ * different, same-named type (a pre-existing naming collision elsewhere in
19
+ * this codebase, not something fixed globally here). Importing the wrong
20
+ * type, combined with the `as ApiSearchResult` cast this fix also removes,
21
+ * meant the fixture below was never actually type-checked against
22
+ * `toSkill()`'s real input contract.
23
+ */
24
+ import { describe, it, expect } from 'vitest';
25
+ import { SkillsmithApiClient } from './client.js';
26
+ function makeApiSearchResult(overrides = {}) {
27
+ return {
28
+ id: 'skill-1',
29
+ name: 'commit',
30
+ description: 'A commit skill',
31
+ author: 'anthropic',
32
+ repo_url: 'https://github.com/anthropic/commit',
33
+ quality_score: 90,
34
+ trust_tier: 'verified',
35
+ tags: ['git'],
36
+ stars: 10,
37
+ created_at: '2026-01-01T00:00:00.000Z',
38
+ updated_at: '2026-01-02T00:00:00.000Z',
39
+ installable: true,
40
+ ...overrides,
41
+ };
42
+ }
43
+ describe('SkillsmithApiClient.toSkill() — security field derivation (SMI-5897 C-15)', () => {
44
+ it('reports "not scanned" (all-null security fields) when last_scanned_at is null', () => {
45
+ const result = makeApiSearchResult({
46
+ last_scanned_at: null,
47
+ quarantined: false,
48
+ security_score: null,
49
+ security_findings: null,
50
+ });
51
+ const skill = SkillsmithApiClient.toSkill(result);
52
+ expect(skill.securityScannedAt).toBeNull();
53
+ expect(skill.securityPassed).toBeNull();
54
+ expect(skill.riskScore).toBeNull();
55
+ expect(skill.securityFindingsCount).toBe(0);
56
+ });
57
+ it('reports a real passing scan status instead of a hardcoded "not scanned"', () => {
58
+ const result = makeApiSearchResult({
59
+ last_scanned_at: '2026-06-01T00:00:00.000Z',
60
+ quarantined: false,
61
+ security_score: 0,
62
+ security_findings: [],
63
+ });
64
+ const skill = SkillsmithApiClient.toSkill(result);
65
+ // Pre-fix this was unconditionally { securityPassed: null, ... } —
66
+ // the exact CLI/MCP status-mismatch bug (C-15).
67
+ expect(skill.securityPassed).toBe(true);
68
+ expect(skill.securityScannedAt).toBe('2026-06-01T00:00:00.000Z');
69
+ expect(skill.riskScore).toBe(0);
70
+ expect(skill.securityFindingsCount).toBe(0);
71
+ });
72
+ it('reports a failing scan status (quarantined) instead of a hardcoded "not scanned"', () => {
73
+ const result = makeApiSearchResult({
74
+ last_scanned_at: '2026-06-01T00:00:00.000Z',
75
+ quarantined: true,
76
+ security_score: 10,
77
+ security_findings: [{ rule: 'a' }, { rule: 'b' }],
78
+ });
79
+ const skill = SkillsmithApiClient.toSkill(result);
80
+ expect(skill.securityPassed).toBe(false);
81
+ expect(skill.securityFindingsCount).toBe(2);
82
+ expect(skill.riskScore).toBe(10);
83
+ });
84
+ it('preserves riskScore: null (never fabricates 0) for a scanned-but-unscored skill', () => {
85
+ const result = makeApiSearchResult({
86
+ last_scanned_at: '2026-06-01T00:00:00.000Z',
87
+ quarantined: false,
88
+ security_score: null,
89
+ security_findings: null,
90
+ });
91
+ const skill = SkillsmithApiClient.toSkill(result);
92
+ expect(skill.securityPassed).toBeNull();
93
+ expect(skill.riskScore).toBeNull();
94
+ expect(skill.securityScannedAt).toBe('2026-06-01T00:00:00.000Z');
95
+ });
96
+ });
97
+ //# sourceMappingURL=client.toSkill.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.toSkill.test.js","sourceRoot":"","sources":["../../../src/api/client.toSkill.test.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,11 @@
1
1
  export declare function tryRefreshToken(): Promise<string | null>;
2
2
  export declare function loadStoredAccessToken(): Promise<string | null>;
3
+ /**
4
+ * Resolve the signed-in user's Supabase access token, refreshing it if it has
5
+ * expired (or is within `TOKEN_EXPIRY_SKEW_MS` of expiring).
6
+ *
7
+ * @returns the access token, or null when no credentials are stored on this
8
+ * machine (or the stored refresh token is no longer valid).
9
+ */
10
+ export declare function resolveFreshAccessToken(): Promise<string | null>;
3
11
  //# sourceMappingURL=client.token-refresh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.token-refresh.d.ts","sourceRoot":"","sources":["../../../src/api/client.token-refresh.ts"],"names":[],"mappings":"AAOA,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS9D;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIpE"}
1
+ {"version":3,"file":"client.token-refresh.d.ts","sourceRoot":"","sources":["../../../src/api/client.token-refresh.ts"],"names":[],"mappings":"AAOA,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS9D;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIpE;AAcD;;;;;;GAMG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKtE"}
@@ -16,4 +16,30 @@ export async function loadStoredAccessToken() {
16
16
  return null;
17
17
  return creds.accessToken;
18
18
  }
19
+ /**
20
+ * SMI-5905 Wave 1: refresh a token this many ms before its recorded expiry.
21
+ *
22
+ * Extracted from `packages/mcp-server/src/tools/team-resolver.ts`'s
23
+ * `resolveUserAccessToken()` (originally SMI-4292) so a 2nd consumer (the
24
+ * CLI, via a future private-registry command) can resolve "the signed-in
25
+ * user's fresh access token" without depending on mcp-server. team-resolver.ts
26
+ * now delegates to `resolveFreshAccessToken()` below — same skew constant,
27
+ * same refresh-or-null fallback, no behavior change for its existing callers.
28
+ */
29
+ const TOKEN_EXPIRY_SKEW_MS = 60_000;
30
+ /**
31
+ * Resolve the signed-in user's Supabase access token, refreshing it if it has
32
+ * expired (or is within `TOKEN_EXPIRY_SKEW_MS` of expiring).
33
+ *
34
+ * @returns the access token, or null when no credentials are stored on this
35
+ * machine (or the stored refresh token is no longer valid).
36
+ */
37
+ export async function resolveFreshAccessToken() {
38
+ const creds = await loadCredentials();
39
+ if (!creds)
40
+ return null;
41
+ if (Date.now() < creds.expiresAt - TOKEN_EXPIRY_SKEW_MS)
42
+ return creds.accessToken;
43
+ return tryRefreshToken();
44
+ }
19
45
  //# sourceMappingURL=client.token-refresh.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.token-refresh.js","sourceRoot":"","sources":["../../../src/api/client.token-refresh.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,gCAAgC,CAAA;AAEvC,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAA;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAEvB,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IAC9D,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAA;IAE3B,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAA;IACjC,OAAO,SAAS,CAAC,WAAW,CAAA;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAA;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,KAAK,CAAC,WAAW,CAAA;AAC1B,CAAC"}
1
+ {"version":3,"file":"client.token-refresh.js","sourceRoot":"","sources":["../../../src/api/client.token-refresh.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,gCAAgC,CAAA;AAEvC,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAA;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAEvB,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IAC9D,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAA;IAE3B,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAA;IACjC,OAAO,SAAS,CAAC,WAAW,CAAA;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAA;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,KAAK,CAAC,WAAW,CAAA;AAC1B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,oBAAoB,GAAG,MAAM,CAAA;AAEnC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC3C,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAA;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,oBAAoB;QAAE,OAAO,KAAK,CAAC,WAAW,CAAA;IACjF,OAAO,eAAe,EAAE,CAAA;AAC1B,CAAC"}
@@ -70,4 +70,86 @@ describe('client.token-refresh', () => {
70
70
  expect(result).toBeNull();
71
71
  });
72
72
  });
73
+ // SMI-5905 Wave 1: resolveFreshAccessToken() — extracted from team-resolver.ts's
74
+ // resolveUserAccessToken() (TOKEN_EXPIRY_SKEW_MS=60s). team-resolver.ts now delegates to this
75
+ // function unchanged, so these cases are the authoritative coverage for the skew logic.
76
+ describe('resolveFreshAccessToken (SMI-5905)', () => {
77
+ beforeEach(() => {
78
+ vi.clearAllMocks();
79
+ });
80
+ it('RFT-1: returns accessToken directly when well within expiry (no refresh)', async () => {
81
+ const { loadCredentials, refreshAccessToken } = await import('../config/token-credentials.js');
82
+ const { resolveFreshAccessToken } = await import('./client.token-refresh.js');
83
+ vi.mocked(loadCredentials).mockResolvedValue({
84
+ accessToken: 'fresh_at',
85
+ refreshToken: 'fresh_rt',
86
+ expiresAt: Date.now() + 3_600_000, // 1h out — far outside the 60s skew window
87
+ version: 2,
88
+ });
89
+ const result = await resolveFreshAccessToken();
90
+ expect(result).toBe('fresh_at');
91
+ expect(refreshAccessToken).not.toHaveBeenCalled();
92
+ });
93
+ it('RFT-2: returns null when no credentials are stored (no refresh attempted)', async () => {
94
+ const { loadCredentials, refreshAccessToken } = await import('../config/token-credentials.js');
95
+ const { resolveFreshAccessToken } = await import('./client.token-refresh.js');
96
+ vi.mocked(loadCredentials).mockResolvedValue(null);
97
+ const result = await resolveFreshAccessToken();
98
+ expect(result).toBeNull();
99
+ expect(refreshAccessToken).not.toHaveBeenCalled();
100
+ });
101
+ it('RFT-3: expiry-skew boundary — refreshes within the 60s skew window', async () => {
102
+ const { loadCredentials, refreshAccessToken, storeCredentials } = await import('../config/token-credentials.js');
103
+ const { resolveFreshAccessToken } = await import('./client.token-refresh.js');
104
+ vi.mocked(loadCredentials).mockResolvedValue({
105
+ accessToken: 'about_to_expire_at',
106
+ refreshToken: 'still_valid_rt',
107
+ expiresAt: Date.now() + 30_000, // 30s out — inside the 60s skew window
108
+ version: 2,
109
+ });
110
+ vi.mocked(refreshAccessToken).mockResolvedValue({
111
+ accessToken: 'refreshed_at',
112
+ refreshToken: 'refreshed_rt',
113
+ expiresAt: Date.now() + 3_600_000,
114
+ version: 2,
115
+ });
116
+ vi.mocked(storeCredentials).mockResolvedValue(undefined);
117
+ const result = await resolveFreshAccessToken();
118
+ expect(result).toBe('refreshed_at');
119
+ expect(refreshAccessToken).toHaveBeenCalledWith('still_valid_rt');
120
+ expect(storeCredentials).toHaveBeenCalledWith(expect.objectContaining({ accessToken: 'refreshed_at' }));
121
+ });
122
+ it('RFT-4: an already-expired token also refreshes (not just the skew window)', async () => {
123
+ const { loadCredentials, refreshAccessToken, storeCredentials } = await import('../config/token-credentials.js');
124
+ const { resolveFreshAccessToken } = await import('./client.token-refresh.js');
125
+ vi.mocked(loadCredentials).mockResolvedValue({
126
+ accessToken: 'expired_at',
127
+ refreshToken: 'expired_rt',
128
+ expiresAt: Date.now() - 1_000,
129
+ version: 2,
130
+ });
131
+ vi.mocked(refreshAccessToken).mockResolvedValue({
132
+ accessToken: 'new_at',
133
+ refreshToken: 'new_rt',
134
+ expiresAt: Date.now() + 3_600_000,
135
+ version: 2,
136
+ });
137
+ vi.mocked(storeCredentials).mockResolvedValue(undefined);
138
+ const result = await resolveFreshAccessToken();
139
+ expect(result).toBe('new_at');
140
+ });
141
+ it('RFT-5: returns null when the refresh token itself is no longer valid', async () => {
142
+ const { loadCredentials, refreshAccessToken } = await import('../config/token-credentials.js');
143
+ const { resolveFreshAccessToken } = await import('./client.token-refresh.js');
144
+ vi.mocked(loadCredentials).mockResolvedValue({
145
+ accessToken: 'about_to_expire_at',
146
+ refreshToken: 'dead_rt',
147
+ expiresAt: Date.now() + 30_000,
148
+ version: 2,
149
+ });
150
+ vi.mocked(refreshAccessToken).mockResolvedValue(null);
151
+ const result = await resolveFreshAccessToken();
152
+ expect(result).toBeNull();
153
+ });
154
+ });
73
155
  //# sourceMappingURL=client.token-refresh.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.token-refresh.test.js","sourceRoot":"","sources":["../../../src/api/client.token-refresh.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.token-refresh.test.js","sourceRoot":"","sources":["../../../src/api/client.token-refresh.test.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,9 @@
7
7
  * SMI-1300: API types matching OpenAPI spec
8
8
  */
9
9
  export { SkillsmithApiClient, createApiClient, generateAnonymousId, ApiClientError, type ApiClientConfig, type ApiResponse, type ApiErrorResponse, type ApiSearchResult, type RecommendationRequest, type TelemetryEvent, } from './client.js';
10
+ export { getPrivateRegistrySkillContent, type PrivateRegistrySkillContent, type PrivateRegistryGetErrorCode, type PrivateRegistryGetResult, type GetPrivateRegistrySkillContentParams, } from './client.private-registry.js';
10
11
  export { EventBatcher, createEventBatcher, type EventBatcherOptions, type BatchFlushFn, } from './event-batcher.js';
12
+ export { deriveSecuritySummaryFromApiSkill, deriveSecuritySummaryFromSkillRow, } from './security-summary.js';
11
13
  export { ApiCache, createCache, getGlobalCache, DEFAULT_TTL, type CacheConfig, type CacheStats, } from './cache.js';
12
14
  export { API_TRUST_TIERS, API_CATEGORIES } from './types.js';
13
15
  export type { ApiTrustTier, ApiCategory, ApiProjectType, ApiSkill, ApiSearchResult as OpenApiSearchResult, RecommendedSkill, SearchParams, SearchResponse, SearchResponseMeta, RecommendParams, RecommendResponse, RecommendResponseMeta, SkillResponse, HealthStatus, TelemetryEventType, TelemetryMetadata, TelemetryEventPayload, TelemetryResponse, ApiErrorResponse as OpenApiErrorResponse, RateLimitInfo, ApiClientOptions, ApiResponse as OpenApiResponse, } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,GACpB,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,YAAY,GAClB,MAAM,oBAAoB,CAAA;AAM3B,OAAO,EACL,QAAQ,EACR,WAAW,EACX,cAAc,EACd,WAAW,EACX,KAAK,WAAW,EAChB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAA;AAMnB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE5D,YAAY,EAEV,YAAY,EACZ,WAAW,EACX,cAAc,EAEd,QAAQ,EACR,eAAe,IAAI,mBAAmB,EACtC,gBAAgB,EAEhB,YAAY,EACZ,cAAc,EACd,kBAAkB,EAElB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EAErB,aAAa,EAEb,YAAY,EAEZ,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EAEjB,gBAAgB,IAAI,oBAAoB,EAExC,aAAa,EAEb,gBAAgB,EAEhB,WAAW,IAAI,eAAe,GAC/B,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,GACpB,MAAM,aAAa,CAAA;AAIpB,OAAO,EACL,8BAA8B,EAC9B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,KAAK,oCAAoC,GAC1C,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,YAAY,GAClB,MAAM,oBAAoB,CAAA;AAO3B,OAAO,EACL,iCAAiC,EACjC,iCAAiC,GAClC,MAAM,uBAAuB,CAAA;AAM9B,OAAO,EACL,QAAQ,EACR,WAAW,EACX,cAAc,EACd,WAAW,EACX,KAAK,WAAW,EAChB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAA;AAMnB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE5D,YAAY,EAEV,YAAY,EACZ,WAAW,EACX,cAAc,EAEd,QAAQ,EACR,eAAe,IAAI,mBAAmB,EACtC,gBAAgB,EAEhB,YAAY,EACZ,cAAc,EACd,kBAAkB,EAElB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EAErB,aAAa,EAEb,YAAY,EAEZ,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EAEjB,gBAAgB,IAAI,oBAAoB,EAExC,aAAa,EAEb,gBAAgB,EAEhB,WAAW,IAAI,eAAe,GAC/B,MAAM,YAAY,CAAA"}
@@ -10,8 +10,17 @@
10
10
  // API Client
11
11
  // ============================================================================
12
12
  export { SkillsmithApiClient, createApiClient, generateAnonymousId, ApiClientError, } from './client.js';
13
+ // SMI-5905 Wave 4: private-registry content fetch — the CLI's only transport
14
+ // to `private_registry_skills.content` (see client.private-registry.ts header).
15
+ export { getPrivateRegistrySkillContent, } from './client.private-registry.js';
13
16
  // SMI-4119: Event batching
14
17
  export { EventBatcher, createEventBatcher, } from './event-batcher.js';
18
+ // SMI-5897 (C-15): shared security-summary derivation — CLI (`toSkill()`)
19
+ // and MCP tool call sites both import this instead of independently
20
+ // reconstructing the passed/riskScore/findingsCount/scannedAt logic.
21
+ // SMI-5897 (Wave 4 fix): sibling `deriveSecuritySummaryFromSkillRow()` for
22
+ // the local-DB-shaped (pre-computed field) call sites.
23
+ export { deriveSecuritySummaryFromApiSkill, deriveSecuritySummaryFromSkillRow, } from './security-summary.js';
15
24
  // ============================================================================
16
25
  // API Cache
17
26
  // ============================================================================
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,cAAc,GAOf,MAAM,aAAa,CAAA;AAEpB,2BAA2B;AAC3B,OAAO,EACL,YAAY,EACZ,kBAAkB,GAGnB,MAAM,oBAAoB,CAAA;AAE3B,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,OAAO,EACL,QAAQ,EACR,WAAW,EACX,cAAc,EACd,WAAW,GAGZ,MAAM,YAAY,CAAA;AAEnB,+EAA+E;AAC/E,8BAA8B;AAC9B,+EAA+E;AAE/E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,cAAc,GAOf,MAAM,aAAa,CAAA;AAEpB,6EAA6E;AAC7E,gFAAgF;AAChF,OAAO,EACL,8BAA8B,GAK/B,MAAM,8BAA8B,CAAA;AAErC,2BAA2B;AAC3B,OAAO,EACL,YAAY,EACZ,kBAAkB,GAGnB,MAAM,oBAAoB,CAAA;AAE3B,0EAA0E;AAC1E,oEAAoE;AACpE,qEAAqE;AACrE,2EAA2E;AAC3E,uDAAuD;AACvD,OAAO,EACL,iCAAiC,EACjC,iCAAiC,GAClC,MAAM,uBAAuB,CAAA;AAE9B,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,OAAO,EACL,QAAQ,EACR,WAAW,EACX,cAAc,EACd,WAAW,GAGZ,MAAM,YAAY,CAAA;AAEnB,+EAA+E;AAC/E,8BAA8B;AAC9B,+EAA+E;AAE/E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @fileoverview Shared derivation of a `SecuritySummary` from an API skill row,
3
+ * and from a pre-computed local-DB-shaped skill row.
4
+ * @module @skillsmith/core/api/security-summary
5
+ * @see SMI-4240: original inline derivation in mcp-server's get-skill.ts
6
+ * @see SMI-5562: extracted to mcp-server's utils/security-summary.ts so
7
+ * get-skill.ts, recommend.ts, and search.ts share a single implementation
8
+ * instead of triplicating the logic.
9
+ * @see SMI-5897 (C-15): moved here from mcp-server so `SkillsmithApiClient.toSkill()`
10
+ * (CLI path) can share the exact same derivation instead of hardcoding
11
+ * `riskScore: null, securityFindingsCount: 0, securityScannedAt: null,
12
+ * securityPassed: null` for every API-sourced skill — which caused CLI
13
+ * `info`/`search` to show "Not scanned" for skills MCP correctly reported
14
+ * as passed. Both `toSkill()` and mcp-server's tool call sites now import
15
+ * this one function, so the two surfaces cannot re-diverge.
16
+ * @see SMI-5897 (Wave 4 fix): `deriveSecuritySummaryFromSkillRow()` added
17
+ * alongside `deriveSecuritySummaryFromApiSkill()` — the local-DB-path
18
+ * sibling for the SAME undefined-when-never-scanned contract, but over the
19
+ * pre-computed `securityPassed`/`riskScore`/`securityFindingsCount`/
20
+ * `securityScannedAt` field shape (as opposed to the raw API row's
21
+ * `last_scanned_at`/`quarantined`/`security_score`/`security_findings`
22
+ * columns). `recommend.helpers.ts`'s `buildDbFallbackRecommendation` had
23
+ * this exact ternary inline already; `search.helpers.ts`'s
24
+ * `mapLocalSkillToSearchResult` and `get-skill.ts`'s local-DB branch built
25
+ * the security object unconditionally, violating the contract for a
26
+ * never-scanned skill. All three now share this one function.
27
+ */
28
+ import type { ApiSkill } from './types.js';
29
+ import type { SecuritySummary } from '../types.js';
30
+ /**
31
+ * Derive a `SecuritySummary` from an API skill row's flat security columns.
32
+ *
33
+ * Returns `undefined` when the skill has never been scanned
34
+ * (`last_scanned_at == null`) — never scanned is a distinct state from
35
+ * "scanned but no verdict" and callers must not conflate the two by
36
+ * shipping a placeholder `{ passed: null, ... }` object for skills that
37
+ * were never scanned at all.
38
+ *
39
+ * `security_findings_count` is not a stored column — `findingsCount` is
40
+ * always derived from the length of the `security_findings` jsonb array
41
+ * (defensively 0 when the value is missing or not an array).
42
+ *
43
+ * @param apiSkill - Object carrying the flat security columns from an
44
+ * `ApiSkill`/`ApiSearchResult` row (registry API response shape).
45
+ * @returns The derived summary, or `undefined` when never scanned.
46
+ */
47
+ export declare function deriveSecuritySummaryFromApiSkill(apiSkill: Pick<ApiSkill, 'last_scanned_at' | 'quarantined' | 'security_score' | 'security_findings'>): SecuritySummary | undefined;
48
+ /**
49
+ * Derive a `SecuritySummary` from a local-DB-shaped skill row's PRE-COMPUTED
50
+ * flat security fields (`securityPassed`/`riskScore`/`securityFindingsCount`/
51
+ * `securityScannedAt` — a different shape from {@link deriveSecuritySummaryFromApiSkill}'s
52
+ * raw API-row columns).
53
+ *
54
+ * Same contract as {@link deriveSecuritySummaryFromApiSkill}: returns
55
+ * `undefined` when the skill has never been scanned (`securityScannedAt ==
56
+ * null`) — never scanned is a distinct state from "scanned but no verdict"
57
+ * and callers must not conflate the two by shipping a placeholder
58
+ * `{ passed: null, ... }` object for skills that were never scanned at all.
59
+ * `passed`/`riskScore` pass through RAW — never coerce/default to a
60
+ * fabricated value, which would misread as "confirmed clean/scanned."
61
+ *
62
+ * @param skill - Object carrying the pre-computed flat security fields
63
+ * present on both a local `Skill` repository row and `SkillData`
64
+ * (mcp-server's recommend matcher shape).
65
+ * @returns The derived summary, or `undefined` when never scanned.
66
+ */
67
+ export declare function deriveSecuritySummaryFromSkillRow(skill: {
68
+ securityPassed: boolean | null;
69
+ riskScore: number | null;
70
+ securityFindingsCount: number;
71
+ securityScannedAt: string | null;
72
+ }): SecuritySummary | undefined;
73
+ //# sourceMappingURL=security-summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-summary.d.ts","sourceRoot":"","sources":["../../../src/api/security-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,IAAI,CACZ,QAAQ,EACR,iBAAiB,GAAG,aAAa,GAAG,gBAAgB,GAAG,mBAAmB,CAC3E,GACA,eAAe,GAAG,SAAS,CAa7B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iCAAiC,CAAC,KAAK,EAAE;IACvD,cAAc,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC,GAAG,eAAe,GAAG,SAAS,CAW9B"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @fileoverview Shared derivation of a `SecuritySummary` from an API skill row,
3
+ * and from a pre-computed local-DB-shaped skill row.
4
+ * @module @skillsmith/core/api/security-summary
5
+ * @see SMI-4240: original inline derivation in mcp-server's get-skill.ts
6
+ * @see SMI-5562: extracted to mcp-server's utils/security-summary.ts so
7
+ * get-skill.ts, recommend.ts, and search.ts share a single implementation
8
+ * instead of triplicating the logic.
9
+ * @see SMI-5897 (C-15): moved here from mcp-server so `SkillsmithApiClient.toSkill()`
10
+ * (CLI path) can share the exact same derivation instead of hardcoding
11
+ * `riskScore: null, securityFindingsCount: 0, securityScannedAt: null,
12
+ * securityPassed: null` for every API-sourced skill — which caused CLI
13
+ * `info`/`search` to show "Not scanned" for skills MCP correctly reported
14
+ * as passed. Both `toSkill()` and mcp-server's tool call sites now import
15
+ * this one function, so the two surfaces cannot re-diverge.
16
+ * @see SMI-5897 (Wave 4 fix): `deriveSecuritySummaryFromSkillRow()` added
17
+ * alongside `deriveSecuritySummaryFromApiSkill()` — the local-DB-path
18
+ * sibling for the SAME undefined-when-never-scanned contract, but over the
19
+ * pre-computed `securityPassed`/`riskScore`/`securityFindingsCount`/
20
+ * `securityScannedAt` field shape (as opposed to the raw API row's
21
+ * `last_scanned_at`/`quarantined`/`security_score`/`security_findings`
22
+ * columns). `recommend.helpers.ts`'s `buildDbFallbackRecommendation` had
23
+ * this exact ternary inline already; `search.helpers.ts`'s
24
+ * `mapLocalSkillToSearchResult` and `get-skill.ts`'s local-DB branch built
25
+ * the security object unconditionally, violating the contract for a
26
+ * never-scanned skill. All three now share this one function.
27
+ */
28
+ /**
29
+ * Derive a `SecuritySummary` from an API skill row's flat security columns.
30
+ *
31
+ * Returns `undefined` when the skill has never been scanned
32
+ * (`last_scanned_at == null`) — never scanned is a distinct state from
33
+ * "scanned but no verdict" and callers must not conflate the two by
34
+ * shipping a placeholder `{ passed: null, ... }` object for skills that
35
+ * were never scanned at all.
36
+ *
37
+ * `security_findings_count` is not a stored column — `findingsCount` is
38
+ * always derived from the length of the `security_findings` jsonb array
39
+ * (defensively 0 when the value is missing or not an array).
40
+ *
41
+ * @param apiSkill - Object carrying the flat security columns from an
42
+ * `ApiSkill`/`ApiSearchResult` row (registry API response shape).
43
+ * @returns The derived summary, or `undefined` when never scanned.
44
+ */
45
+ export function deriveSecuritySummaryFromApiSkill(apiSkill) {
46
+ if (apiSkill.last_scanned_at == null) {
47
+ return undefined;
48
+ }
49
+ return {
50
+ passed: apiSkill.quarantined === true ? false : apiSkill.security_score == null ? null : true,
51
+ riskScore: apiSkill.security_score ?? null,
52
+ findingsCount: Array.isArray(apiSkill.security_findings)
53
+ ? apiSkill.security_findings.length
54
+ : 0,
55
+ scannedAt: apiSkill.last_scanned_at,
56
+ };
57
+ }
58
+ /**
59
+ * Derive a `SecuritySummary` from a local-DB-shaped skill row's PRE-COMPUTED
60
+ * flat security fields (`securityPassed`/`riskScore`/`securityFindingsCount`/
61
+ * `securityScannedAt` — a different shape from {@link deriveSecuritySummaryFromApiSkill}'s
62
+ * raw API-row columns).
63
+ *
64
+ * Same contract as {@link deriveSecuritySummaryFromApiSkill}: returns
65
+ * `undefined` when the skill has never been scanned (`securityScannedAt ==
66
+ * null`) — never scanned is a distinct state from "scanned but no verdict"
67
+ * and callers must not conflate the two by shipping a placeholder
68
+ * `{ passed: null, ... }` object for skills that were never scanned at all.
69
+ * `passed`/`riskScore` pass through RAW — never coerce/default to a
70
+ * fabricated value, which would misread as "confirmed clean/scanned."
71
+ *
72
+ * @param skill - Object carrying the pre-computed flat security fields
73
+ * present on both a local `Skill` repository row and `SkillData`
74
+ * (mcp-server's recommend matcher shape).
75
+ * @returns The derived summary, or `undefined` when never scanned.
76
+ */
77
+ export function deriveSecuritySummaryFromSkillRow(skill) {
78
+ if (skill.securityScannedAt == null) {
79
+ return undefined;
80
+ }
81
+ return {
82
+ passed: skill.securityPassed,
83
+ riskScore: skill.riskScore,
84
+ findingsCount: skill.securityFindingsCount,
85
+ scannedAt: skill.securityScannedAt,
86
+ };
87
+ }
88
+ //# sourceMappingURL=security-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-summary.js","sourceRoot":"","sources":["../../../src/api/security-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,iCAAiC,CAC/C,QAGC;IAED,IAAI,QAAQ,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC;QACrC,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;QAC7F,SAAS,EAAE,QAAQ,CAAC,cAAc,IAAI,IAAI;QAC1C,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YACtD,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM;YACnC,CAAC,CAAC,CAAC;QACL,SAAS,EAAE,QAAQ,CAAC,eAAe;KACpC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,iCAAiC,CAAC,KAKjD;IACC,IAAI,KAAK,CAAC,iBAAiB,IAAI,IAAI,EAAE,CAAC;QACpC,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,cAAc;QAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,aAAa,EAAE,KAAK,CAAC,qBAAqB;QAC1C,SAAS,EAAE,KAAK,CAAC,iBAAiB;KACnC,CAAA;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * SMI-5562: Unit coverage for the shared security-summary derivation helper,
3
+ * extracted from get-skill.ts's inline derivation (SMI-4240).
4
+ * SMI-5897 (C-15): moved from packages/mcp-server/src/utils/security-summary.test.ts
5
+ * to packages/core so the CLI (`SkillsmithApiClient.toSkill()`) and MCP tool
6
+ * call sites share and test one implementation.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=security-summary.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-summary.test.d.ts","sourceRoot":"","sources":["../../../src/api/security-summary.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * SMI-5562: Unit coverage for the shared security-summary derivation helper,
3
+ * extracted from get-skill.ts's inline derivation (SMI-4240).
4
+ * SMI-5897 (C-15): moved from packages/mcp-server/src/utils/security-summary.test.ts
5
+ * to packages/core so the CLI (`SkillsmithApiClient.toSkill()`) and MCP tool
6
+ * call sites share and test one implementation.
7
+ */
8
+ import { describe, it, expect } from 'vitest';
9
+ import { deriveSecuritySummaryFromApiSkill } from './security-summary.js';
10
+ describe('deriveSecuritySummaryFromApiSkill', () => {
11
+ it('returns undefined when the skill has never been scanned (last_scanned_at null)', () => {
12
+ const result = deriveSecuritySummaryFromApiSkill({
13
+ last_scanned_at: null,
14
+ quarantined: false,
15
+ security_score: null,
16
+ security_findings: null,
17
+ });
18
+ expect(result).toBeUndefined();
19
+ });
20
+ it('returns undefined when last_scanned_at is undefined', () => {
21
+ const result = deriveSecuritySummaryFromApiSkill({
22
+ last_scanned_at: undefined,
23
+ quarantined: undefined,
24
+ security_score: undefined,
25
+ security_findings: undefined,
26
+ });
27
+ expect(result).toBeUndefined();
28
+ });
29
+ it('returns passed: false when quarantined, regardless of security_score', () => {
30
+ const result = deriveSecuritySummaryFromApiSkill({
31
+ last_scanned_at: '2026-06-01T00:00:00.000Z',
32
+ quarantined: true,
33
+ // A low score would otherwise read as "clean" — quarantined must win.
34
+ security_score: 0,
35
+ security_findings: [],
36
+ });
37
+ expect(result?.passed).toBe(false);
38
+ });
39
+ it('returns passed: null when scanned but no security_score is recorded yet', () => {
40
+ const result = deriveSecuritySummaryFromApiSkill({
41
+ last_scanned_at: '2026-06-01T00:00:00.000Z',
42
+ quarantined: false,
43
+ security_score: null,
44
+ security_findings: null,
45
+ });
46
+ expect(result?.passed).toBeNull();
47
+ expect(result?.riskScore).toBeNull();
48
+ });
49
+ it('returns passed: true for a clean scanned skill with a recorded score', () => {
50
+ const result = deriveSecuritySummaryFromApiSkill({
51
+ last_scanned_at: '2026-06-01T00:00:00.000Z',
52
+ quarantined: false,
53
+ security_score: 0,
54
+ security_findings: [],
55
+ });
56
+ expect(result).toEqual({
57
+ passed: true,
58
+ riskScore: 0,
59
+ findingsCount: 0,
60
+ scannedAt: '2026-06-01T00:00:00.000Z',
61
+ });
62
+ });
63
+ it('derives findingsCount from the security_findings array length', () => {
64
+ const result = deriveSecuritySummaryFromApiSkill({
65
+ last_scanned_at: '2026-06-01T00:00:00.000Z',
66
+ quarantined: false,
67
+ security_score: 42,
68
+ security_findings: [{ rule: 'a' }, { rule: 'b' }, { rule: 'c' }],
69
+ });
70
+ expect(result?.findingsCount).toBe(3);
71
+ });
72
+ it('defaults findingsCount to 0 when security_findings is not an array', () => {
73
+ const result = deriveSecuritySummaryFromApiSkill({
74
+ last_scanned_at: '2026-06-01T00:00:00.000Z',
75
+ quarantined: false,
76
+ security_score: 10,
77
+ // Defensive non-array case — should never happen at runtime (jsonb column),
78
+ // but the derivation must not throw or miscount.
79
+ security_findings: undefined,
80
+ });
81
+ expect(result?.findingsCount).toBe(0);
82
+ });
83
+ it('passes riskScore through as null (never a fabricated 0) when unscored', () => {
84
+ const result = deriveSecuritySummaryFromApiSkill({
85
+ last_scanned_at: '2026-06-01T00:00:00.000Z',
86
+ quarantined: false,
87
+ security_score: null,
88
+ security_findings: [{ rule: 'pending-review' }],
89
+ });
90
+ expect(result?.riskScore).toBeNull();
91
+ expect(result?.findingsCount).toBe(1);
92
+ });
93
+ });
94
+ //# sourceMappingURL=security-summary.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-summary.test.js","sourceRoot":"","sources":["../../../src/api/security-summary.test.ts"],"names":[],"mappings":"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"}
@@ -16,9 +16,13 @@ export type CompatibilitySlug = (typeof COMPATIBILITY_SLUGS)[number];
16
16
  export declare const COMPATIBILITY_LABELS: Record<CompatibilitySlug, string>;
17
17
  /**
18
18
  * Slugs that are filterable/browsable but have NO install target yet — the
19
- * install-client enum (`install/paths.ts` `ClientId`) lacks them. Adding
20
- * `antigravity`/`gemini` ClientIds + auto-detect is Phase 2c (SMI-5179). Until
21
- * then the UI labels these "browse-only" rather than implying installability.
19
+ * install-client enum (`install/paths.ts` `ClientId`) lacks them.
20
+ * `antigravity` was un-deferred (SMI-5982 Wave 6) — it now has a real
21
+ * `ClientId` + `CLIENT_NATIVE_PATHS` entry, so it moved out of this list.
22
+ * `gemini` has no install target (it names a model family, not a distinct
23
+ * install client) and remains browse-only; adding it (if ever justified) is
24
+ * still Phase 2c (SMI-5179). Until then the UI labels `gemini` "browse-only"
25
+ * rather than implying installability.
22
26
  */
23
27
  export declare const BROWSE_ONLY_SLUGS: readonly CompatibilitySlug[];
24
28
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"slugs.d.ts","sourceRoot":"","sources":["../../../src/compatibility/slugs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,6FAQtB,CAAA;AAEV,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpE,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAQlE,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,iBAAiB,EAA8B,CAAA;AAExF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAM1E,CAAA;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD"}
1
+ {"version":3,"file":"slugs.d.ts","sourceRoot":"","sources":["../../../src/compatibility/slugs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,6FAQtB,CAAA;AAEV,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpE,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAQlE,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,iBAAiB,EAAe,CAAA;AAEzE;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAS1E,CAAA;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD"}