@collage-dam/mcp-server 0.1.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 (306) hide show
  1. package/.env.example +56 -0
  2. package/CHANGELOG.md +90 -0
  3. package/LICENSE +21 -0
  4. package/README.md +512 -0
  5. package/dist/client.d.ts +497 -0
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +1162 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/conventions/confirmation.d.ts +89 -0
  10. package/dist/conventions/confirmation.d.ts.map +1 -0
  11. package/dist/conventions/confirmation.js +132 -0
  12. package/dist/conventions/confirmation.js.map +1 -0
  13. package/dist/conventions/dry-run/batch-executor.d.ts +36 -0
  14. package/dist/conventions/dry-run/batch-executor.d.ts.map +1 -0
  15. package/dist/conventions/dry-run/batch-executor.js +89 -0
  16. package/dist/conventions/dry-run/batch-executor.js.map +1 -0
  17. package/dist/conventions/dry-run/diff-renderer.d.ts +34 -0
  18. package/dist/conventions/dry-run/diff-renderer.d.ts.map +1 -0
  19. package/dist/conventions/dry-run/diff-renderer.js +158 -0
  20. package/dist/conventions/dry-run/diff-renderer.js.map +1 -0
  21. package/dist/conventions/dry-run/index.d.ts +13 -0
  22. package/dist/conventions/dry-run/index.d.ts.map +1 -0
  23. package/dist/conventions/dry-run/index.js +10 -0
  24. package/dist/conventions/dry-run/index.js.map +1 -0
  25. package/dist/conventions/dry-run/mutating-tool.d.ts +64 -0
  26. package/dist/conventions/dry-run/mutating-tool.d.ts.map +1 -0
  27. package/dist/conventions/dry-run/mutating-tool.js +88 -0
  28. package/dist/conventions/dry-run/mutating-tool.js.map +1 -0
  29. package/dist/conventions/dry-run/summary.d.ts +66 -0
  30. package/dist/conventions/dry-run/summary.d.ts.map +1 -0
  31. package/dist/conventions/dry-run/summary.js +185 -0
  32. package/dist/conventions/dry-run/summary.js.map +1 -0
  33. package/dist/conventions/dry-run/types.d.ts +597 -0
  34. package/dist/conventions/dry-run/types.d.ts.map +1 -0
  35. package/dist/conventions/dry-run/types.js +108 -0
  36. package/dist/conventions/dry-run/types.js.map +1 -0
  37. package/dist/conventions/dry-run/with-dry-run.d.ts +66 -0
  38. package/dist/conventions/dry-run/with-dry-run.d.ts.map +1 -0
  39. package/dist/conventions/dry-run/with-dry-run.js +219 -0
  40. package/dist/conventions/dry-run/with-dry-run.js.map +1 -0
  41. package/dist/conventions/env.d.ts +49 -0
  42. package/dist/conventions/env.d.ts.map +1 -0
  43. package/dist/conventions/env.js +84 -0
  44. package/dist/conventions/env.js.map +1 -0
  45. package/dist/conventions/errors.d.ts +68 -0
  46. package/dist/conventions/errors.d.ts.map +1 -0
  47. package/dist/conventions/errors.js +81 -0
  48. package/dist/conventions/errors.js.map +1 -0
  49. package/dist/conventions/logger.d.ts +28 -0
  50. package/dist/conventions/logger.d.ts.map +1 -0
  51. package/dist/conventions/logger.js +105 -0
  52. package/dist/conventions/logger.js.map +1 -0
  53. package/dist/conventions/pagination.d.ts +37 -0
  54. package/dist/conventions/pagination.d.ts.map +1 -0
  55. package/dist/conventions/pagination.js +53 -0
  56. package/dist/conventions/pagination.js.map +1 -0
  57. package/dist/conventions/rate-limiter.d.ts +54 -0
  58. package/dist/conventions/rate-limiter.d.ts.map +1 -0
  59. package/dist/conventions/rate-limiter.js +143 -0
  60. package/dist/conventions/rate-limiter.js.map +1 -0
  61. package/dist/conventions/response-budget.d.ts +66 -0
  62. package/dist/conventions/response-budget.d.ts.map +1 -0
  63. package/dist/conventions/response-budget.js +89 -0
  64. package/dist/conventions/response-budget.js.map +1 -0
  65. package/dist/conventions/schema-version.d.ts +27 -0
  66. package/dist/conventions/schema-version.d.ts.map +1 -0
  67. package/dist/conventions/schema-version.js +29 -0
  68. package/dist/conventions/schema-version.js.map +1 -0
  69. package/dist/conventions/state-store-redis.d.ts +32 -0
  70. package/dist/conventions/state-store-redis.d.ts.map +1 -0
  71. package/dist/conventions/state-store-redis.js +77 -0
  72. package/dist/conventions/state-store-redis.js.map +1 -0
  73. package/dist/conventions/state-store.d.ts +46 -0
  74. package/dist/conventions/state-store.d.ts.map +1 -0
  75. package/dist/conventions/state-store.js +105 -0
  76. package/dist/conventions/state-store.js.map +1 -0
  77. package/dist/index.d.ts +5 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +421 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/prompts/collection-audit.d.ts +13 -0
  82. package/dist/prompts/collection-audit.d.ts.map +1 -0
  83. package/dist/prompts/collection-audit.js +168 -0
  84. package/dist/prompts/collection-audit.js.map +1 -0
  85. package/dist/prompts/create-distribution.d.ts +15 -0
  86. package/dist/prompts/create-distribution.d.ts.map +1 -0
  87. package/dist/prompts/create-distribution.js +111 -0
  88. package/dist/prompts/create-distribution.js.map +1 -0
  89. package/dist/prompts/helpers.d.ts +20 -0
  90. package/dist/prompts/helpers.d.ts.map +1 -0
  91. package/dist/prompts/helpers.js +53 -0
  92. package/dist/prompts/helpers.js.map +1 -0
  93. package/dist/prompts/library-health-audit.d.ts +13 -0
  94. package/dist/prompts/library-health-audit.d.ts.map +1 -0
  95. package/dist/prompts/library-health-audit.js +131 -0
  96. package/dist/prompts/library-health-audit.js.map +1 -0
  97. package/dist/prompts/usage-insights.d.ts +13 -0
  98. package/dist/prompts/usage-insights.d.ts.map +1 -0
  99. package/dist/prompts/usage-insights.js +98 -0
  100. package/dist/prompts/usage-insights.js.map +1 -0
  101. package/dist/prompts/wrap-prompt-as-tool.d.ts +48 -0
  102. package/dist/prompts/wrap-prompt-as-tool.d.ts.map +1 -0
  103. package/dist/prompts/wrap-prompt-as-tool.js +61 -0
  104. package/dist/prompts/wrap-prompt-as-tool.js.map +1 -0
  105. package/dist/resources/asset-by-id.d.ts +4 -0
  106. package/dist/resources/asset-by-id.d.ts.map +1 -0
  107. package/dist/resources/asset-by-id.js +27 -0
  108. package/dist/resources/asset-by-id.js.map +1 -0
  109. package/dist/resources/collections.d.ts +5 -0
  110. package/dist/resources/collections.d.ts.map +1 -0
  111. package/dist/resources/collections.js +48 -0
  112. package/dist/resources/collections.js.map +1 -0
  113. package/dist/resources/custom-fields.d.ts +4 -0
  114. package/dist/resources/custom-fields.d.ts.map +1 -0
  115. package/dist/resources/custom-fields.js +30 -0
  116. package/dist/resources/custom-fields.js.map +1 -0
  117. package/dist/resources/folders.d.ts +5 -0
  118. package/dist/resources/folders.d.ts.map +1 -0
  119. package/dist/resources/folders.js +73 -0
  120. package/dist/resources/folders.js.map +1 -0
  121. package/dist/resources/helpers.d.ts +17 -0
  122. package/dist/resources/helpers.d.ts.map +1 -0
  123. package/dist/resources/helpers.js +59 -0
  124. package/dist/resources/helpers.js.map +1 -0
  125. package/dist/resources/portals.d.ts +5 -0
  126. package/dist/resources/portals.d.ts.map +1 -0
  127. package/dist/resources/portals.js +81 -0
  128. package/dist/resources/portals.js.map +1 -0
  129. package/dist/resources/recent-and-dashboard.d.ts +5 -0
  130. package/dist/resources/recent-and-dashboard.d.ts.map +1 -0
  131. package/dist/resources/recent-and-dashboard.js +42 -0
  132. package/dist/resources/recent-and-dashboard.js.map +1 -0
  133. package/dist/tools/asset-selection.d.ts +102 -0
  134. package/dist/tools/asset-selection.d.ts.map +1 -0
  135. package/dist/tools/asset-selection.js +133 -0
  136. package/dist/tools/asset-selection.js.map +1 -0
  137. package/dist/tools/audit/audit-folder-structure.d.ts +108 -0
  138. package/dist/tools/audit/audit-folder-structure.d.ts.map +1 -0
  139. package/dist/tools/audit/audit-folder-structure.js +260 -0
  140. package/dist/tools/audit/audit-folder-structure.js.map +1 -0
  141. package/dist/tools/audit/audit-naming-conventions.d.ts +83 -0
  142. package/dist/tools/audit/audit-naming-conventions.d.ts.map +1 -0
  143. package/dist/tools/audit/audit-naming-conventions.js +238 -0
  144. package/dist/tools/audit/audit-naming-conventions.js.map +1 -0
  145. package/dist/tools/audit/audit-tagging-hygiene.d.ts +77 -0
  146. package/dist/tools/audit/audit-tagging-hygiene.d.ts.map +1 -0
  147. package/dist/tools/audit/audit-tagging-hygiene.js +402 -0
  148. package/dist/tools/audit/audit-tagging-hygiene.js.map +1 -0
  149. package/dist/tools/audit/detect-duplicates.d.ts +62 -0
  150. package/dist/tools/audit/detect-duplicates.d.ts.map +1 -0
  151. package/dist/tools/audit/detect-duplicates.js +0 -0
  152. package/dist/tools/audit/detect-duplicates.js.map +1 -0
  153. package/dist/tools/audit/types.d.ts +526 -0
  154. package/dist/tools/audit/types.d.ts.map +1 -0
  155. package/dist/tools/audit/types.js +188 -0
  156. package/dist/tools/audit/types.js.map +1 -0
  157. package/dist/tools/bulk-move-assets.d.ts +78 -0
  158. package/dist/tools/bulk-move-assets.d.ts.map +1 -0
  159. package/dist/tools/bulk-move-assets.js +122 -0
  160. package/dist/tools/bulk-move-assets.js.map +1 -0
  161. package/dist/tools/bulk-normalize-filenames.d.ts +62 -0
  162. package/dist/tools/bulk-normalize-filenames.d.ts.map +1 -0
  163. package/dist/tools/bulk-normalize-filenames.js +237 -0
  164. package/dist/tools/bulk-normalize-filenames.js.map +1 -0
  165. package/dist/tools/bulk-rename-assets.d.ts +79 -0
  166. package/dist/tools/bulk-rename-assets.d.ts.map +1 -0
  167. package/dist/tools/bulk-rename-assets.js +139 -0
  168. package/dist/tools/bulk-rename-assets.js.map +1 -0
  169. package/dist/tools/bulk-tags.d.ts +107 -0
  170. package/dist/tools/bulk-tags.d.ts.map +1 -0
  171. package/dist/tools/bulk-tags.js +220 -0
  172. package/dist/tools/bulk-tags.js.map +1 -0
  173. package/dist/tools/client-adapters.d.ts +76 -0
  174. package/dist/tools/client-adapters.d.ts.map +1 -0
  175. package/dist/tools/client-adapters.js +648 -0
  176. package/dist/tools/client-adapters.js.map +1 -0
  177. package/dist/tools/collection-membership.d.ts +90 -0
  178. package/dist/tools/collection-membership.d.ts.map +1 -0
  179. package/dist/tools/collection-membership.js +195 -0
  180. package/dist/tools/collection-membership.js.map +1 -0
  181. package/dist/tools/create-collection.d.ts +63 -0
  182. package/dist/tools/create-collection.d.ts.map +1 -0
  183. package/dist/tools/create-collection.js +151 -0
  184. package/dist/tools/create-collection.js.map +1 -0
  185. package/dist/tools/create-folder.d.ts +46 -0
  186. package/dist/tools/create-folder.d.ts.map +1 -0
  187. package/dist/tools/create-folder.js +83 -0
  188. package/dist/tools/create-folder.js.map +1 -0
  189. package/dist/tools/create-share-link.d.ts +107 -0
  190. package/dist/tools/create-share-link.d.ts.map +1 -0
  191. package/dist/tools/create-share-link.js +239 -0
  192. package/dist/tools/create-share-link.js.map +1 -0
  193. package/dist/tools/get-asset-details.d.ts +401 -0
  194. package/dist/tools/get-asset-details.d.ts.map +1 -0
  195. package/dist/tools/get-asset-details.js +56 -0
  196. package/dist/tools/get-asset-details.js.map +1 -0
  197. package/dist/tools/get-collection.d.ts +126 -0
  198. package/dist/tools/get-collection.d.ts.map +1 -0
  199. package/dist/tools/get-collection.js +52 -0
  200. package/dist/tools/get-collection.js.map +1 -0
  201. package/dist/tools/get-embed-code.d.ts +195 -0
  202. package/dist/tools/get-embed-code.d.ts.map +1 -0
  203. package/dist/tools/get-embed-code.js +214 -0
  204. package/dist/tools/get-embed-code.js.map +1 -0
  205. package/dist/tools/insights/analyze-share-links.d.ts +159 -0
  206. package/dist/tools/insights/analyze-share-links.d.ts.map +1 -0
  207. package/dist/tools/insights/analyze-share-links.js +314 -0
  208. package/dist/tools/insights/analyze-share-links.js.map +1 -0
  209. package/dist/tools/insights/insight-cache.d.ts +36 -0
  210. package/dist/tools/insights/insight-cache.d.ts.map +1 -0
  211. package/dist/tools/insights/insight-cache.js +98 -0
  212. package/dist/tools/insights/insight-cache.js.map +1 -0
  213. package/dist/tools/insights/report-asset-activation.d.ts +149 -0
  214. package/dist/tools/insights/report-asset-activation.d.ts.map +1 -0
  215. package/dist/tools/insights/report-asset-activation.js +380 -0
  216. package/dist/tools/insights/report-asset-activation.js.map +1 -0
  217. package/dist/tools/insights/report-stale-assets.d.ts +120 -0
  218. package/dist/tools/insights/report-stale-assets.d.ts.map +1 -0
  219. package/dist/tools/insights/report-stale-assets.js +281 -0
  220. package/dist/tools/insights/report-stale-assets.js.map +1 -0
  221. package/dist/tools/insights/report-top-assets.d.ts +139 -0
  222. package/dist/tools/insights/report-top-assets.d.ts.map +1 -0
  223. package/dist/tools/insights/report-top-assets.js +407 -0
  224. package/dist/tools/insights/report-top-assets.js.map +1 -0
  225. package/dist/tools/list-categories.d.ts +127 -0
  226. package/dist/tools/list-categories.d.ts.map +1 -0
  227. package/dist/tools/list-categories.js +68 -0
  228. package/dist/tools/list-categories.js.map +1 -0
  229. package/dist/tools/list-collections.d.ts +127 -0
  230. package/dist/tools/list-collections.d.ts.map +1 -0
  231. package/dist/tools/list-collections.js +53 -0
  232. package/dist/tools/list-collections.js.map +1 -0
  233. package/dist/tools/list-custom-fields.d.ts +125 -0
  234. package/dist/tools/list-custom-fields.d.ts.map +1 -0
  235. package/dist/tools/list-custom-fields.js +51 -0
  236. package/dist/tools/list-custom-fields.js.map +1 -0
  237. package/dist/tools/list-share-links.d.ts +192 -0
  238. package/dist/tools/list-share-links.d.ts.map +1 -0
  239. package/dist/tools/list-share-links.js +92 -0
  240. package/dist/tools/list-share-links.js.map +1 -0
  241. package/dist/tools/list-workspaces.d.ts +88 -0
  242. package/dist/tools/list-workspaces.d.ts.map +1 -0
  243. package/dist/tools/list-workspaces.js +71 -0
  244. package/dist/tools/list-workspaces.js.map +1 -0
  245. package/dist/tools/move-asset.d.ts +48 -0
  246. package/dist/tools/move-asset.d.ts.map +1 -0
  247. package/dist/tools/move-asset.js +85 -0
  248. package/dist/tools/move-asset.js.map +1 -0
  249. package/dist/tools/rename-asset.d.ts +88 -0
  250. package/dist/tools/rename-asset.d.ts.map +1 -0
  251. package/dist/tools/rename-asset.js +100 -0
  252. package/dist/tools/rename-asset.js.map +1 -0
  253. package/dist/tools/rename-folder.d.ts +55 -0
  254. package/dist/tools/rename-folder.d.ts.map +1 -0
  255. package/dist/tools/rename-folder.js +101 -0
  256. package/dist/tools/rename-folder.js.map +1 -0
  257. package/dist/tools/revoke-share-link.d.ts +55 -0
  258. package/dist/tools/revoke-share-link.d.ts.map +1 -0
  259. package/dist/tools/revoke-share-link.js +77 -0
  260. package/dist/tools/revoke-share-link.js.map +1 -0
  261. package/dist/tools/search/facets.d.ts +34 -0
  262. package/dist/tools/search/facets.d.ts.map +1 -0
  263. package/dist/tools/search/facets.js +147 -0
  264. package/dist/tools/search/facets.js.map +1 -0
  265. package/dist/tools/search/filter-builder.d.ts +33 -0
  266. package/dist/tools/search/filter-builder.d.ts.map +1 -0
  267. package/dist/tools/search/filter-builder.js +111 -0
  268. package/dist/tools/search/filter-builder.js.map +1 -0
  269. package/dist/tools/search/search-assets.d.ts +41 -0
  270. package/dist/tools/search/search-assets.d.ts.map +1 -0
  271. package/dist/tools/search/search-assets.js +162 -0
  272. package/dist/tools/search/search-assets.js.map +1 -0
  273. package/dist/tools/search/search-collections.d.ts +35 -0
  274. package/dist/tools/search/search-collections.d.ts.map +1 -0
  275. package/dist/tools/search/search-collections.js +103 -0
  276. package/dist/tools/search/search-collections.js.map +1 -0
  277. package/dist/tools/search/types.d.ts +1047 -0
  278. package/dist/tools/search/types.d.ts.map +1 -0
  279. package/dist/tools/search/types.js +216 -0
  280. package/dist/tools/search/types.js.map +1 -0
  281. package/dist/tools/update-asset-metadata.d.ts +78 -0
  282. package/dist/tools/update-asset-metadata.d.ts.map +1 -0
  283. package/dist/tools/update-asset-metadata.js +203 -0
  284. package/dist/tools/update-asset-metadata.js.map +1 -0
  285. package/dist/tools/update-collection.d.ts +69 -0
  286. package/dist/tools/update-collection.d.ts.map +1 -0
  287. package/dist/tools/update-collection.js +142 -0
  288. package/dist/tools/update-collection.js.map +1 -0
  289. package/dist/tools/view-category-contents.d.ts +231 -0
  290. package/dist/tools/view-category-contents.d.ts.map +1 -0
  291. package/dist/tools/view-category-contents.js +97 -0
  292. package/dist/tools/view-category-contents.js.map +1 -0
  293. package/dist/types.d.ts +1326 -0
  294. package/dist/types.d.ts.map +1 -0
  295. package/dist/types.js +288 -0
  296. package/dist/types.js.map +1 -0
  297. package/dist/typesense.d.ts +84 -0
  298. package/dist/typesense.d.ts.map +1 -0
  299. package/dist/typesense.js +243 -0
  300. package/dist/typesense.js.map +1 -0
  301. package/docs/api-field-verification.md +244 -0
  302. package/docs/deployment-runbook.md +446 -0
  303. package/docs/security-review.md +195 -0
  304. package/docs/typesense-filter-schema.md +262 -0
  305. package/docs/verified-endpoints.md +38 -0
  306. package/package.json +72 -0
@@ -0,0 +1,314 @@
1
+ // ── analyze_share_links (T1, read-only) ──────────────────────────────
2
+ //
3
+ // Read-only distribution-insights tool. Aggregates share-link engagement
4
+ // metrics across the workspace by walking the existing
5
+ // `dashboard/list-share-assets-url` enumeration surface (already exposed
6
+ // to the MCP layer via `client.listShareLinks`).
7
+ //
8
+ // Output is purely structured metrics (totals, top-N, status
9
+ // distribution, creation time series, cohort breakdowns by creator). The
10
+ // client LLM is responsible for narrative synthesis on top — no prose is
11
+ // generated here. The companion `T6` task in this spec covers the
12
+ // AI-summary scaffolding separately.
13
+ //
14
+ // Caching is the next task (T5). This file is written so a cache wrapper
15
+ // can plug in around `analyzeShareLinks(...)` without touching the
16
+ // detection / aggregation logic.
17
+ //
18
+ // Type discipline: never uses `any`. The upstream `ShareLink` row carries
19
+ // loose / nullable fields (per the live `ShareLinkSchema` in `types.ts`),
20
+ // so this module defines a narrow projection (`ShareLinkRow`) that the
21
+ // enumerator adapter is responsible for producing.
22
+ import { z } from 'zod';
23
+ import { createToolError } from '../../conventions/errors.js';
24
+ import { estimateTokens, HARD_CAP_TOKENS } from '../../conventions/response-budget.js';
25
+ // ── Tool description ────────────────────────────────────────────────
26
+ export const ANALYZE_SHARE_LINKS_DESCRIPTION = 'Read-only analytics over share links in the workspace. Returns ' +
27
+ 'structured engagement metrics — totals, top-N most-viewed links, ' +
28
+ 'status distribution (active/expired/revoked), creation time series, ' +
29
+ 'and cohort breakdowns by creator and (if scoped) by collection. ' +
30
+ 'Filters: optional date range, collection scope, creator scope. ' +
31
+ 'Per-day view counts are NOT exposed by the upstream surface, so the ' +
32
+ 'time series only carries creation cadence; view metrics are reported ' +
33
+ 'as totals/aggregates only. No mutation, no AI prose.';
34
+ // ── Input schema ────────────────────────────────────────────────────
35
+ export const DEFAULT_TOP_N = 10;
36
+ export const MAX_TOP_N = 50;
37
+ export const ENUMERATOR_HARD_CAP = 5000;
38
+ /**
39
+ * `date_from` / `date_to` are inclusive ISO-8601 date or datetime strings.
40
+ * If only a date is supplied (e.g. `2026-04-14`), it is interpreted as
41
+ * the start (00:00:00Z) for `date_from` or the end (23:59:59.999Z) for
42
+ * `date_to`. Both bounds are optional — omit to leave that side
43
+ * unbounded.
44
+ */
45
+ export const AnalyzeShareLinksInputSchema = z
46
+ .object({
47
+ date_from: z
48
+ .string()
49
+ .min(1)
50
+ .refine((v) => !Number.isNaN(Date.parse(v)), {
51
+ message: 'date_from must be a valid ISO-8601 date or datetime string',
52
+ })
53
+ .optional(),
54
+ date_to: z
55
+ .string()
56
+ .min(1)
57
+ .refine((v) => !Number.isNaN(Date.parse(v)), {
58
+ message: 'date_to must be a valid ISO-8601 date or datetime string',
59
+ })
60
+ .optional(),
61
+ collection_id: z.string().min(1).optional(),
62
+ created_by_user_id: z.string().min(1).optional(),
63
+ top_n: z.number().int().min(1).max(MAX_TOP_N).default(DEFAULT_TOP_N),
64
+ })
65
+ .strict();
66
+ export class AnalyzeShareLinksTool {
67
+ deps;
68
+ name = 'analyze_share_links';
69
+ description = ANALYZE_SHARE_LINKS_DESCRIPTION;
70
+ constructor(deps) {
71
+ this.deps = deps;
72
+ }
73
+ async run(rawInput = {}) {
74
+ let parsed;
75
+ try {
76
+ parsed = AnalyzeShareLinksInputSchema.parse(rawInput);
77
+ }
78
+ catch (err) {
79
+ return {
80
+ ok: false,
81
+ error: createToolError('VALIDATION', err instanceof Error ? err.message : 'invalid input'),
82
+ };
83
+ }
84
+ // Cross-field validation: when both bounds are set, from <= to.
85
+ if (parsed.date_from !== undefined && parsed.date_to !== undefined) {
86
+ const fromMs = Date.parse(parsed.date_from);
87
+ const toMs = Date.parse(parsed.date_to);
88
+ if (fromMs > toMs) {
89
+ return {
90
+ ok: false,
91
+ error: createToolError('VALIDATION', 'date_from must be <= date_to'),
92
+ };
93
+ }
94
+ }
95
+ const enumerated = await this.deps.enumerator.enumerate();
96
+ if (!enumerated.ok) {
97
+ return { ok: false, error: enumerated.error };
98
+ }
99
+ const report = buildReport(enumerated.rows, enumerated.truncated, parsed);
100
+ return { ok: true, report };
101
+ }
102
+ }
103
+ export function buildAnalyzeShareLinksTool(deps) {
104
+ return new AnalyzeShareLinksTool(deps);
105
+ }
106
+ // ── Aggregation (pure) ──────────────────────────────────────────────
107
+ /**
108
+ * Build the analytics report from a flat list of rows. Pure function,
109
+ * exported for direct test access.
110
+ */
111
+ export function buildReport(rows, enumeratorTruncated, input) {
112
+ // ── Filter ──
113
+ const fromMs = parseLowerBound(input.date_from);
114
+ const toMs = parseUpperBound(input.date_to);
115
+ const matching = rows.filter((row) => {
116
+ if (input.collection_id !== undefined) {
117
+ if (row.collection_id !== input.collection_id)
118
+ return false;
119
+ }
120
+ if (input.created_by_user_id !== undefined) {
121
+ if (row.created_by_user_id !== input.created_by_user_id)
122
+ return false;
123
+ }
124
+ if (fromMs !== null || toMs !== null) {
125
+ const created = row.created_at;
126
+ if (created === null)
127
+ return false;
128
+ const createdMs = Date.parse(created);
129
+ if (Number.isNaN(createdMs))
130
+ return false;
131
+ if (fromMs !== null && createdMs < fromMs)
132
+ return false;
133
+ if (toMs !== null && createdMs > toMs)
134
+ return false;
135
+ }
136
+ return true;
137
+ });
138
+ // ── Totals ──
139
+ const viewCounts = matching.map((r) => r.view_count);
140
+ const totalViews = viewCounts.reduce((acc, v) => acc + v, 0);
141
+ const linkCount = matching.length;
142
+ const meanViews = linkCount === 0 ? null : totalViews / linkCount;
143
+ const medianViews = linkCount === 0 ? null : computeMedian(viewCounts);
144
+ // ── Status distribution ──
145
+ const statusDistribution = { active: 0, expired: 0, revoked: 0 };
146
+ for (const row of matching) {
147
+ statusDistribution[row.status] += 1;
148
+ }
149
+ // ── Top N (descending by view count, ties broken by created_at desc) ──
150
+ const sortedByViews = [...matching].sort((a, b) => {
151
+ if (b.view_count !== a.view_count)
152
+ return b.view_count - a.view_count;
153
+ const aMs = a.created_at === null ? 0 : Date.parse(a.created_at);
154
+ const bMs = b.created_at === null ? 0 : Date.parse(b.created_at);
155
+ return bMs - aMs;
156
+ });
157
+ const topLinks = sortedByViews
158
+ .slice(0, input.top_n)
159
+ .map((r) => ({
160
+ id: r.id,
161
+ title: r.title,
162
+ share_url: r.share_url,
163
+ view_count: r.view_count,
164
+ status: r.status,
165
+ created_at: r.created_at,
166
+ expires_at: r.expires_at,
167
+ }));
168
+ // ── Time series (creation cadence, daily) ──
169
+ const dayBuckets = new Map();
170
+ for (const row of matching) {
171
+ if (row.created_at === null)
172
+ continue;
173
+ const day = toIsoDay(row.created_at);
174
+ if (day === null)
175
+ continue;
176
+ dayBuckets.set(day, (dayBuckets.get(day) ?? 0) + 1);
177
+ }
178
+ const linksCreatedPerDay = [...dayBuckets.entries()]
179
+ .map(([date, count]) => ({ date, links_created: count }))
180
+ .sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));
181
+ // ── Cohorts ──
182
+ const byCreator = aggregateCohort(matching, (r) => r.created_by_user_id);
183
+ const byCollection = input.collection_id !== undefined
184
+ ? aggregateCohort(matching, (r) => r.collection_id)
185
+ : [];
186
+ const initial = {
187
+ filters: {
188
+ date_from: input.date_from ?? null,
189
+ date_to: input.date_to ?? null,
190
+ collection_id: input.collection_id ?? null,
191
+ created_by_user_id: input.created_by_user_id ?? null,
192
+ top_n: input.top_n,
193
+ },
194
+ totals: {
195
+ link_count: linkCount,
196
+ total_views: totalViews,
197
+ mean_views: meanViews,
198
+ median_views: medianViews,
199
+ },
200
+ status_distribution: statusDistribution,
201
+ top_links: topLinks,
202
+ time_series: {
203
+ links_created_per_day: linksCreatedPerDay,
204
+ views_per_day: null,
205
+ },
206
+ cohorts: {
207
+ by_creator: byCreator,
208
+ by_collection: byCollection,
209
+ },
210
+ truncated: enumeratorTruncated,
211
+ };
212
+ if (enumeratorTruncated) {
213
+ initial.truncation_reason =
214
+ `Enumerator stopped at the internal cap of ${ENUMERATOR_HARD_CAP} share links; report reflects a partial dataset.`;
215
+ }
216
+ return enforceResponseBudget(initial);
217
+ }
218
+ // ── Helpers ─────────────────────────────────────────────────────────
219
+ function parseLowerBound(value) {
220
+ if (value === undefined)
221
+ return null;
222
+ // Bare YYYY-MM-DD → start of day in UTC.
223
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
224
+ return Date.parse(`${value}T00:00:00.000Z`);
225
+ }
226
+ return Date.parse(value);
227
+ }
228
+ function parseUpperBound(value) {
229
+ if (value === undefined)
230
+ return null;
231
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
232
+ return Date.parse(`${value}T23:59:59.999Z`);
233
+ }
234
+ return Date.parse(value);
235
+ }
236
+ function toIsoDay(value) {
237
+ const ms = Date.parse(value);
238
+ if (Number.isNaN(ms))
239
+ return null;
240
+ return new Date(ms).toISOString().slice(0, 10);
241
+ }
242
+ function computeMedian(values) {
243
+ const sorted = [...values].sort((a, b) => a - b);
244
+ const n = sorted.length;
245
+ if (n === 0)
246
+ return 0;
247
+ const mid = Math.floor(n / 2);
248
+ if (n % 2 === 1)
249
+ return sorted[mid] ?? 0;
250
+ const left = sorted[mid - 1] ?? 0;
251
+ const right = sorted[mid] ?? 0;
252
+ return (left + right) / 2;
253
+ }
254
+ function aggregateCohort(rows, keyFn) {
255
+ const buckets = new Map();
256
+ for (const row of rows) {
257
+ const key = keyFn(row);
258
+ if (key === null)
259
+ continue;
260
+ let bucket = buckets.get(key);
261
+ if (bucket === undefined) {
262
+ bucket = { link_count: 0, view_count: 0 };
263
+ buckets.set(key, bucket);
264
+ }
265
+ bucket.link_count += 1;
266
+ bucket.view_count += row.view_count;
267
+ }
268
+ return [...buckets.entries()]
269
+ .map(([key, v]) => ({ key, link_count: v.link_count, view_count: v.view_count }))
270
+ .sort((a, b) => {
271
+ if (b.link_count !== a.link_count)
272
+ return b.link_count - a.link_count;
273
+ if (b.view_count !== a.view_count)
274
+ return b.view_count - a.view_count;
275
+ return a.key.localeCompare(b.key);
276
+ });
277
+ }
278
+ // ── Response-budget enforcement ─────────────────────────────────────
279
+ const REDUCED_TOP_LIMIT = 5;
280
+ const REDUCED_COHORT_LIMIT = 10;
281
+ const REDUCED_TIMESERIES_LIMIT = 30;
282
+ /**
283
+ * Aggregate reports tend to be small (totals, distribution, top-N), but a
284
+ * very wide creator cohort or a long date-range time series could push us
285
+ * over budget. If the serialised report exceeds {@link HARD_CAP_TOKENS},
286
+ * trim sample-heavy fields in priority order:
287
+ * 1. cap `top_links`, `cohorts.*`, and `time_series.links_created_per_day`
288
+ * to small limits;
289
+ * 2. if still over, mark `truncated: true` regardless of enumerator
290
+ * truncation and return.
291
+ */
292
+ function enforceResponseBudget(report) {
293
+ if (estimateTokens(JSON.stringify(report)) <= HARD_CAP_TOKENS) {
294
+ return report;
295
+ }
296
+ const trimmed = {
297
+ ...report,
298
+ top_links: report.top_links.slice(0, REDUCED_TOP_LIMIT),
299
+ time_series: {
300
+ ...report.time_series,
301
+ links_created_per_day: report.time_series.links_created_per_day.slice(-REDUCED_TIMESERIES_LIMIT),
302
+ },
303
+ cohorts: {
304
+ by_creator: report.cohorts.by_creator.slice(0, REDUCED_COHORT_LIMIT),
305
+ by_collection: report.cohorts.by_collection.slice(0, REDUCED_COHORT_LIMIT),
306
+ },
307
+ truncated: true,
308
+ truncation_reason: report.truncation_reason !== undefined
309
+ ? `${report.truncation_reason} Additionally, top/cohort/time-series lists were trimmed to fit the response budget.`
310
+ : 'Top, cohort, and time-series lists were trimmed to fit the response budget.',
311
+ };
312
+ return trimmed;
313
+ }
314
+ //# sourceMappingURL=analyze-share-links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-share-links.js","sourceRoot":"","sources":["../../../src/tools/insights/analyze-share-links.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { ShareLinkEnumerator } from './analyze-share-links.js';
2
+ /** Default cache lifetime per the spec — 10 minutes. */
3
+ export declare const DEFAULT_INSIGHT_CACHE_TTL_MS: number;
4
+ export interface InsightCacheOptions {
5
+ /** Cache lifetime in milliseconds. Defaults to {@link DEFAULT_INSIGHT_CACHE_TTL_MS}. */
6
+ ttlMs?: number;
7
+ /** Clock source. Defaults to `Date.now`; supply for deterministic tests. */
8
+ now?: () => number;
9
+ }
10
+ /**
11
+ * Diagnostic shape exposed for tests. Production callers should ignore
12
+ * the extra methods — they exist so unit tests can assert cache hit /
13
+ * miss behaviour without poking the closure.
14
+ */
15
+ export interface CachedEnumeratorWithStats extends ShareLinkEnumerator {
16
+ /** Returns true when a cached entry exists and is still fresh. */
17
+ hasFreshEntry(): boolean;
18
+ /** Force-expire the cached entry, if any. */
19
+ invalidate(): void;
20
+ }
21
+ /**
22
+ * Wrap a `ShareLinkEnumerator` with a 10-minute (default) in-memory
23
+ * cache. Multiple calls within the TTL window return the same cached
24
+ * result; concurrent calls during a fetch share the same in-flight
25
+ * promise. Errors are surfaced to every concurrent caller but are NOT
26
+ * cached — the next call after a failure will re-fetch.
27
+ *
28
+ * Pure function over the enumerator — does not mutate the input.
29
+ *
30
+ * The return shape exposes test-introspection methods
31
+ * ({@link CachedEnumeratorWithStats}) but assignment to a plain
32
+ * `ShareLinkEnumerator` is the production usage and discards them at
33
+ * the type level.
34
+ */
35
+ export declare function buildCachedShareLinkEnumerator(inner: ShareLinkEnumerator, options?: InsightCacheOptions): CachedEnumeratorWithStats;
36
+ //# sourceMappingURL=insight-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insight-cache.d.ts","sourceRoot":"","sources":["../../../src/tools/insights/insight-cache.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EACV,mBAAmB,EAEpB,MAAM,0BAA0B,CAAC;AAGlC,wDAAwD;AACxD,eAAO,MAAM,4BAA4B,QAAiB,CAAC;AAE3D,MAAM,WAAW,mBAAmB;IAClC,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAaD;;;;GAIG;AACH,MAAM,WAAW,yBAA0B,SAAQ,mBAAmB;IACpE,kEAAkE;IAClE,aAAa,IAAI,OAAO,CAAC;IACzB,6CAA6C;IAC7C,UAAU,IAAI,IAAI,CAAC;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,mBAAmB,EAC1B,OAAO,GAAE,mBAAwB,GAChC,yBAAyB,CAuD3B"}
@@ -0,0 +1,98 @@
1
+ // ── Insight Cache (T5) ──────────────────────────────────────────────
2
+ //
3
+ // In-memory TTL cache wrapper around the share-link enumerator. The four
4
+ // distribution-insight tools (analyze_share_links, report_asset_activation,
5
+ // report_top_assets, report_stale_assets) all enumerate the workspace's
6
+ // share-link list — three paginated GETs per status bucket per call.
7
+ // Without caching, four insight tool calls in the same conversation hit
8
+ // the upstream API up to 12 times. Caching the enumerator output for ten
9
+ // minutes drops that to one round-trip per ten-minute window, regardless
10
+ // of which (or how many) insight tools are called.
11
+ //
12
+ // Caching policy:
13
+ // * Cache LIFE: 10 minutes by default; configurable.
14
+ // * Cache KEY: implicit — each cache instance is per-workspace because
15
+ // the MCP server is single-workspace and a new server instance is
16
+ // created per stdio client. There is exactly one shared enumerator
17
+ // in `createServer()`.
18
+ // * Cache POLLUTION: failures are NOT cached. A bad upstream response
19
+ // should be retried, not memoised for ten minutes.
20
+ // * SINGLE-FLIGHT: concurrent callers during a fetch share the same
21
+ // in-flight promise. Without this, four insight tools booting at the
22
+ // same time would issue four parallel enumerations even though we
23
+ // intend to serve them all from one round-trip.
24
+ //
25
+ // Type discipline: never uses `any`. The cache only operates on the
26
+ // already-typed `ShareLinkEnumerator` surface — it does not need
27
+ // generics because the enumerator is the only memoisable boundary in
28
+ // the insight surface.
29
+ /** Default cache lifetime per the spec — 10 minutes. */
30
+ export const DEFAULT_INSIGHT_CACHE_TTL_MS = 10 * 60 * 1000;
31
+ /**
32
+ * Wrap a `ShareLinkEnumerator` with a 10-minute (default) in-memory
33
+ * cache. Multiple calls within the TTL window return the same cached
34
+ * result; concurrent calls during a fetch share the same in-flight
35
+ * promise. Errors are surfaced to every concurrent caller but are NOT
36
+ * cached — the next call after a failure will re-fetch.
37
+ *
38
+ * Pure function over the enumerator — does not mutate the input.
39
+ *
40
+ * The return shape exposes test-introspection methods
41
+ * ({@link CachedEnumeratorWithStats}) but assignment to a plain
42
+ * `ShareLinkEnumerator` is the production usage and discards them at
43
+ * the type level.
44
+ */
45
+ export function buildCachedShareLinkEnumerator(inner, options = {}) {
46
+ const ttlMs = options.ttlMs ?? DEFAULT_INSIGHT_CACHE_TTL_MS;
47
+ const now = options.now ?? Date.now;
48
+ let entry = null;
49
+ let inflight = null;
50
+ const tryRefresh = () => {
51
+ if (inflight !== null)
52
+ return inflight;
53
+ const fetchPromise = (async () => {
54
+ try {
55
+ const result = await inner.enumerate();
56
+ if (result.ok) {
57
+ entry = {
58
+ expires_at: now() + ttlMs,
59
+ // Defensive copy — the cache owns its rows independently of
60
+ // the caller, so external mutation of the returned array
61
+ // does not corrupt subsequent cache hits.
62
+ result: {
63
+ ok: true,
64
+ rows: [...result.rows],
65
+ truncated: result.truncated,
66
+ },
67
+ };
68
+ }
69
+ // Failures are intentionally NOT cached.
70
+ return result;
71
+ }
72
+ finally {
73
+ inflight = null;
74
+ }
75
+ })();
76
+ inflight = fetchPromise;
77
+ return fetchPromise;
78
+ };
79
+ return {
80
+ enumerate: async () => {
81
+ if (entry !== null && entry.expires_at > now()) {
82
+ // Return a fresh copy of the cached result so callers can
83
+ // mutate their local view without corrupting future cache hits.
84
+ return {
85
+ ok: true,
86
+ rows: [...entry.result.rows],
87
+ truncated: entry.result.truncated,
88
+ };
89
+ }
90
+ return tryRefresh();
91
+ },
92
+ hasFreshEntry: () => entry !== null && entry.expires_at > now(),
93
+ invalidate: () => {
94
+ entry = null;
95
+ },
96
+ };
97
+ }
98
+ //# sourceMappingURL=insight-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insight-cache.js","sourceRoot":"","sources":["../../../src/tools/insights/insight-cache.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,EAAE;AACF,yEAAyE;AACzE,4EAA4E;AAC5E,wEAAwE;AACxE,qEAAqE;AACrE,wEAAwE;AACxE,yEAAyE;AACzE,yEAAyE;AACzE,mDAAmD;AACnD,EAAE;AACF,kBAAkB;AAClB,uDAAuD;AACvD,yEAAyE;AACzE,sEAAsE;AACtE,uEAAuE;AACvE,2BAA2B;AAC3B,wEAAwE;AACxE,uDAAuD;AACvD,sEAAsE;AACtE,yEAAyE;AACzE,sEAAsE;AACtE,oDAAoD;AACpD,EAAE;AACF,oEAAoE;AACpE,iEAAiE;AACjE,qEAAqE;AACrE,uBAAuB;AAQvB,wDAAwD;AACxD,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAgC3D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,8BAA8B,CAC5C,KAA0B,EAC1B,UAA+B,EAAE;IAEjC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,4BAA4B,CAAC;IAC5D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IAEpC,IAAI,KAAK,GAAsB,IAAI,CAAC;IACpC,IAAI,QAAQ,GAAoC,IAAI,CAAC;IAErD,MAAM,UAAU,GAAG,GAA6B,EAAE;QAChD,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,QAAQ,CAAC;QAEvC,MAAM,YAAY,GAAG,CAAC,KAAK,IAA8B,EAAE;YACzD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE,CAAC;gBACvC,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;oBACd,KAAK,GAAG;wBACN,UAAU,EAAE,GAAG,EAAE,GAAG,KAAK;wBACzB,4DAA4D;wBAC5D,yDAAyD;wBACzD,0CAA0C;wBAC1C,MAAM,EAAE;4BACN,EAAE,EAAE,IAAI;4BACR,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;4BACtB,SAAS,EAAE,MAAM,CAAC,SAAS;yBAC5B;qBACF,CAAC;gBACJ,CAAC;gBACD,yCAAyC;gBACzC,OAAO,MAAM,CAAC;YAChB,CAAC;oBAAS,CAAC;gBACT,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QAEL,QAAQ,GAAG,YAAY,CAAC;QACxB,OAAO,YAAY,CAAC;IACtB,CAAC,CAAC;IAEF,OAAO;QACL,SAAS,EAAE,KAAK,IAA8B,EAAE;YAC9C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,GAAG,GAAG,EAAE,EAAE,CAAC;gBAC/C,0DAA0D;gBAC1D,gEAAgE;gBAChE,OAAO;oBACL,EAAE,EAAE,IAAI;oBACR,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;oBAC5B,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS;iBAClC,CAAC;YACJ,CAAC;YACD,OAAO,UAAU,EAAE,CAAC;QACtB,CAAC;QACD,aAAa,EAAE,GAAG,EAAE,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,GAAG,GAAG,EAAE;QAC/D,UAAU,EAAE,GAAG,EAAE;YACf,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,149 @@
1
+ import { z } from 'zod';
2
+ import { type McpToolError } from '../../conventions/errors.js';
3
+ import type { ShareLinkEnumerator, ShareLinkRow } from './analyze-share-links.js';
4
+ export declare const REPORT_ASSET_ACTIVATION_DESCRIPTION: string;
5
+ export declare const DEFAULT_TOP_N = 10;
6
+ export declare const MAX_TOP_N = 50;
7
+ /** Default look-back window when neither `date_from` nor `date_to` is set. */
8
+ export declare const DEFAULT_LOOKBACK_DAYS = 30;
9
+ /**
10
+ * `date_from` / `date_to` are inclusive ISO-8601 date or datetime
11
+ * strings. If only a date is supplied (e.g. `2026-04-14`) it is
12
+ * interpreted as the start (00:00:00Z) for `date_from` or the end
13
+ * (23:59:59.999Z) for `date_to`. When BOTH are omitted, the analyzer
14
+ * defaults to the last {@link DEFAULT_LOOKBACK_DAYS} days.
15
+ */
16
+ export declare const ReportAssetActivationInputSchema: z.ZodObject<{
17
+ date_from: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
18
+ date_to: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
19
+ collection_id: z.ZodOptional<z.ZodString>;
20
+ top_n: z.ZodDefault<z.ZodNumber>;
21
+ }, "strict", z.ZodTypeAny, {
22
+ top_n: number;
23
+ collection_id?: string | undefined;
24
+ date_from?: string | undefined;
25
+ date_to?: string | undefined;
26
+ }, {
27
+ collection_id?: string | undefined;
28
+ date_from?: string | undefined;
29
+ date_to?: string | undefined;
30
+ top_n?: number | undefined;
31
+ }>;
32
+ export type ReportAssetActivationInput = z.input<typeof ReportAssetActivationInputSchema>;
33
+ export type ReportAssetActivationInputResolved = z.output<typeof ReportAssetActivationInputSchema>;
34
+ /**
35
+ * Narrow shape consumed from `dashboard/common-data`. The upstream
36
+ * surface is opaque (`unknown` at the client layer), so the reader is
37
+ * responsible for parsing it via zod and returning `null` when the shape
38
+ * does not carry a usable `total_assets` count.
39
+ */
40
+ export interface DashboardSnapshot {
41
+ /** Total number of assets in the workspace. */
42
+ total_assets: number;
43
+ }
44
+ /**
45
+ * Read-only adapter for the workspace dashboard projection. Returns
46
+ * `ok: true` with a parsed snapshot, `ok: true` with `snapshot: null`
47
+ * when the upstream shape did not carry the fields we need (the report
48
+ * surfaces `total_assets: null` and `activation_rate: null` rather than
49
+ * crashing), or `ok: false` with a typed `McpToolError` on a transport
50
+ * failure.
51
+ */
52
+ export interface DashboardCommonDataReader {
53
+ read(): Promise<{
54
+ ok: true;
55
+ snapshot: DashboardSnapshot | null;
56
+ } | {
57
+ ok: false;
58
+ error: McpToolError;
59
+ }>;
60
+ }
61
+ export interface AssetActivationSummary {
62
+ /** Workspace-wide asset count. `null` when the dashboard reader could not parse the upstream shape. */
63
+ total_assets: number | null;
64
+ /** Number of distinct assets touched by share-link activity in the matching range. */
65
+ assets_with_distribution_activity: number;
66
+ /** Ratio in [0, 1]; `null` when `total_assets` is unknown. */
67
+ activation_rate: number | null;
68
+ /** `total_assets - assets_with_distribution_activity`; `null` when `total_assets` is unknown. */
69
+ dormant_count: number | null;
70
+ }
71
+ export interface AssetFirstSharedPoint {
72
+ /** ISO date (YYYY-MM-DD) bucket. */
73
+ date: string;
74
+ /** Number of assets that were first shared on this date (within the matching range). */
75
+ count: number;
76
+ }
77
+ export interface TopActivatedAsset {
78
+ id: string;
79
+ /** Best-effort title pulled from the most-recent share-link row covering this asset. */
80
+ title: string | null;
81
+ /** Number of share links covering this asset within the matching range. */
82
+ share_link_count: number;
83
+ /** Sum of view counts across those share links. */
84
+ total_views: number;
85
+ }
86
+ export interface ActivationCohortEntry {
87
+ /** User id for `by_user`, collection id for `by_collection`. */
88
+ user_id?: string;
89
+ collection_id?: string;
90
+ /** Number of distinct activated assets attributed to this cohort. */
91
+ activated_assets: number;
92
+ }
93
+ export interface AssetActivationReport {
94
+ /** Inputs as resolved (after defaults / filters applied). */
95
+ filters: {
96
+ date_from: string | null;
97
+ date_to: string | null;
98
+ collection_id: string | null;
99
+ top_n: number;
100
+ };
101
+ summary: AssetActivationSummary;
102
+ time_series: {
103
+ assets_first_shared_per_day: AssetFirstSharedPoint[];
104
+ };
105
+ top_activated_assets: TopActivatedAsset[];
106
+ cohort_breakdown: {
107
+ by_user: Array<{
108
+ user_id: string;
109
+ activated_assets: number;
110
+ }>;
111
+ by_collection: Array<{
112
+ collection_id: string;
113
+ activated_assets: number;
114
+ }>;
115
+ };
116
+ /** True when the share-link enumerator hit its hard cap or the response was trimmed for budget. */
117
+ truncated: boolean;
118
+ truncation_reason?: string;
119
+ }
120
+ export interface ReportAssetActivationDeps {
121
+ enumerator: ShareLinkEnumerator;
122
+ dashboard: DashboardCommonDataReader;
123
+ }
124
+ export type ReportAssetActivationOutcome = {
125
+ ok: true;
126
+ report: AssetActivationReport;
127
+ } | {
128
+ ok: false;
129
+ error: McpToolError;
130
+ };
131
+ export declare class ReportAssetActivationTool {
132
+ private readonly deps;
133
+ readonly name = "report_asset_activation";
134
+ readonly description: string;
135
+ constructor(deps: ReportAssetActivationDeps);
136
+ run(rawInput?: ReportAssetActivationInput): Promise<ReportAssetActivationOutcome>;
137
+ }
138
+ export declare function buildReportAssetActivationTool(deps: ReportAssetActivationDeps): ReportAssetActivationTool;
139
+ /**
140
+ * Build the asset-activation report from a flat list of share-link rows
141
+ * plus an optional workspace-snapshot denominator. Pure function,
142
+ * exported for direct test access.
143
+ *
144
+ * `dashboardSnapshot === null` means the workspace asset-count is
145
+ * unavailable; the report surfaces `total_assets`, `activation_rate`,
146
+ * and `dormant_count` as `null` per the degradation contract.
147
+ */
148
+ export declare function buildReport(rows: ReadonlyArray<ShareLinkRow>, enumeratorTruncated: boolean, dashboardSnapshot: DashboardSnapshot | null, input: ReportAssetActivationInputResolved): AssetActivationReport;
149
+ //# sourceMappingURL=report-asset-activation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-asset-activation.d.ts","sourceRoot":"","sources":["../../../src/tools/insights/report-asset-activation.ts"],"names":[],"mappings":"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"}