@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,281 @@
1
+ // ── report_stale_assets (T4, read-only) ──────────────────────────────
2
+ //
3
+ // Read-only distribution-insights tool. Identifies workspace assets that
4
+ // were once distributed (via share links) but have gone dormant — no
5
+ // fresh share link in the requested staleness window, or all covering
6
+ // share links are revoked/expired.
7
+ //
8
+ // Scope discipline:
9
+ // * `report_stale_assets` is DISTRIBUTION-scoped. Stale *collection*
10
+ // detection lives in the library audit spec; this tool is only about
11
+ // individual assets' share-link freshness.
12
+ // * "Once distributed" matters: an asset that was never shared is not
13
+ // a finding here — the activation/coverage gap is what
14
+ // `report_asset_activation` (T2) reports.
15
+ //
16
+ // Staleness signal:
17
+ // * `last_shared_at` per asset = max(share_link.created_at) across
18
+ // covering share links.
19
+ // * An asset is "stale" when `as_of - last_shared_at >= staleness_days`.
20
+ // * An asset is "all_revoked" when EVERY covering share link is
21
+ // `status: 'revoked' | 'expired'` — the asset's distribution has
22
+ // effectively ended even if `last_shared_at` is recent.
23
+ //
24
+ // Type discipline: never uses `any`. Mirrors the T1/T2/T3 factoring so a
25
+ // cache wrapper (T5) can plug in around `reportStaleAssets(...)` without
26
+ // touching the aggregation logic.
27
+ import { z } from 'zod';
28
+ import { createToolError } from '../../conventions/errors.js';
29
+ import { estimateTokens, HARD_CAP_TOKENS } from '../../conventions/response-budget.js';
30
+ // ── Tool description ────────────────────────────────────────────────
31
+ export const REPORT_STALE_ASSETS_DESCRIPTION = 'Read-only report on workspace assets whose distribution has gone ' +
32
+ 'dormant. Identifies assets that were once shared but have no fresh ' +
33
+ 'share link inside the staleness window, plus assets whose every ' +
34
+ 'covering share link is revoked or expired. Returns structured ' +
35
+ 'metrics — totals, top-N oldest-shared assets, and an age-bucket ' +
36
+ 'distribution. Filters: staleness_days (default 90), as_of (defaults ' +
37
+ 'to now), collection_id, top_n. Scope is per-asset distribution only; ' +
38
+ 'stale-collection detection lives in the library audit. No mutation, ' +
39
+ 'no AI prose.';
40
+ // ── Input schema ────────────────────────────────────────────────────
41
+ export const DEFAULT_TOP_N = 10;
42
+ export const MAX_TOP_N = 100;
43
+ export const DEFAULT_STALENESS_DAYS = 90;
44
+ export const MAX_STALENESS_DAYS = 3650; // 10 years
45
+ /**
46
+ * `as_of` is the reference point for the staleness window. Omit to use
47
+ * the current time. ISO-8601 date or datetime string; bare dates are
48
+ * interpreted as end-of-day in UTC (so "everything older than the end of
49
+ * 2026-04-01 by N days" is the same as "everything older than
50
+ * 2026-04-01T23:59:59.999Z by N days").
51
+ */
52
+ export const ReportStaleAssetsInputSchema = z
53
+ .object({
54
+ staleness_days: z
55
+ .number()
56
+ .int()
57
+ .min(1)
58
+ .max(MAX_STALENESS_DAYS)
59
+ .default(DEFAULT_STALENESS_DAYS),
60
+ as_of: z
61
+ .string()
62
+ .min(1)
63
+ .refine((v) => !Number.isNaN(Date.parse(v)), {
64
+ message: 'as_of must be a valid ISO-8601 date or datetime string',
65
+ })
66
+ .optional(),
67
+ collection_id: z.string().min(1).optional(),
68
+ top_n: z.number().int().min(1).max(MAX_TOP_N).default(DEFAULT_TOP_N),
69
+ })
70
+ .strict();
71
+ export class ReportStaleAssetsTool {
72
+ deps;
73
+ name = 'report_stale_assets';
74
+ description = REPORT_STALE_ASSETS_DESCRIPTION;
75
+ constructor(deps) {
76
+ this.deps = deps;
77
+ }
78
+ async run(rawInput = {}) {
79
+ let parsed;
80
+ try {
81
+ parsed = ReportStaleAssetsInputSchema.parse(rawInput);
82
+ }
83
+ catch (err) {
84
+ return {
85
+ ok: false,
86
+ error: createToolError('VALIDATION', err instanceof Error ? err.message : 'invalid input'),
87
+ };
88
+ }
89
+ const enumerated = await this.deps.enumerator.enumerate();
90
+ if (!enumerated.ok) {
91
+ return { ok: false, error: enumerated.error };
92
+ }
93
+ const report = buildReport(enumerated.rows, enumerated.truncated, parsed);
94
+ return { ok: true, report };
95
+ }
96
+ }
97
+ export function buildReportStaleAssetsTool(deps) {
98
+ return new ReportStaleAssetsTool(deps);
99
+ }
100
+ // ── Aggregation (pure) ──────────────────────────────────────────────
101
+ const MS_PER_DAY = 24 * 60 * 60 * 1000;
102
+ /**
103
+ * Build the stale-assets report from a flat list of share-link rows.
104
+ * Pure function, exported for direct test access.
105
+ */
106
+ export function buildReport(rows, enumeratorTruncated, input) {
107
+ // ── Resolve reference timestamp ──
108
+ const asOfMs = resolveAsOf(input.as_of);
109
+ const asOfIso = new Date(asOfMs).toISOString();
110
+ const stalenessThresholdMs = asOfMs - input.staleness_days * MS_PER_DAY;
111
+ // ── Pre-filter on collection scope only (we DO want pre-as_of rows here) ──
112
+ // Reason: staleness asks "when was this asset LAST shared?" — we must
113
+ // include older shares to find that maximum. We only exclude rows
114
+ // strictly newer than `as_of` (a future-dated row shouldn't make an
115
+ // asset look fresh from a backward-looking analysis).
116
+ const matching = rows.filter((row) => {
117
+ if (input.collection_id !== undefined) {
118
+ if (row.collection_id !== input.collection_id)
119
+ return false;
120
+ }
121
+ if (row.created_at === null)
122
+ return false;
123
+ const createdMs = Date.parse(row.created_at);
124
+ if (Number.isNaN(createdMs))
125
+ return false;
126
+ if (createdMs > asOfMs)
127
+ return false;
128
+ return true;
129
+ });
130
+ const assets = new Map();
131
+ for (const row of matching) {
132
+ if (row.created_at === null)
133
+ continue;
134
+ const createdMs = Date.parse(row.created_at);
135
+ if (Number.isNaN(createdMs))
136
+ continue;
137
+ for (const assetId of row.asset_ids) {
138
+ const existing = assets.get(assetId);
139
+ const isDead = isRevokedOrExpired(row.status);
140
+ if (existing === undefined) {
141
+ assets.set(assetId, {
142
+ first_shared_ms: createdMs,
143
+ first_shared_iso: row.created_at,
144
+ last_shared_ms: createdMs,
145
+ last_shared_iso: row.created_at,
146
+ share_link_count: 1,
147
+ revoked_or_expired_count: isDead ? 1 : 0,
148
+ title: row.title,
149
+ });
150
+ continue;
151
+ }
152
+ existing.share_link_count += 1;
153
+ if (isDead)
154
+ existing.revoked_or_expired_count += 1;
155
+ if (createdMs < existing.first_shared_ms) {
156
+ existing.first_shared_ms = createdMs;
157
+ existing.first_shared_iso = row.created_at;
158
+ }
159
+ if (createdMs >= existing.last_shared_ms) {
160
+ existing.last_shared_ms = createdMs;
161
+ existing.last_shared_iso = row.created_at;
162
+ // Prefer non-null titles from the most-recent row.
163
+ if (row.title !== null)
164
+ existing.title = row.title;
165
+ }
166
+ }
167
+ }
168
+ const classified = [];
169
+ for (const [id, state] of assets.entries()) {
170
+ const allDead = state.share_link_count > 0 &&
171
+ state.revoked_or_expired_count === state.share_link_count;
172
+ const daysSinceLastShare = Math.max(0, Math.floor((asOfMs - state.last_shared_ms) / MS_PER_DAY));
173
+ const isStaleByAge = state.last_shared_ms <= stalenessThresholdMs;
174
+ const isStale = isStaleByAge || allDead;
175
+ classified.push({
176
+ entry: {
177
+ id,
178
+ title: state.title,
179
+ last_shared_at: state.last_shared_iso,
180
+ first_shared_at: state.first_shared_iso,
181
+ days_since_last_share: daysSinceLastShare,
182
+ share_link_count: state.share_link_count,
183
+ all_shares_revoked_or_expired: allDead,
184
+ },
185
+ is_stale: isStale,
186
+ });
187
+ }
188
+ const staleEntries = classified.filter((c) => c.is_stale).map((c) => c.entry);
189
+ const allRevokedCount = classified.filter((c) => c.entry.all_shares_revoked_or_expired).length;
190
+ // ── Summary ──
191
+ const totalEverShared = assets.size;
192
+ const summary = {
193
+ total_ever_shared_assets: totalEverShared,
194
+ stale_assets: staleEntries.length,
195
+ fresh_assets: totalEverShared - staleEntries.length,
196
+ all_revoked_or_expired_assets: allRevokedCount,
197
+ staleness_rate: totalEverShared > 0 ? staleEntries.length / totalEverShared : null,
198
+ };
199
+ // ── Distribution buckets (over stale population) ──
200
+ const distribution = {
201
+ month_to_quarter: 0,
202
+ quarter_to_half_year: 0,
203
+ half_year_to_year: 0,
204
+ over_year: 0,
205
+ };
206
+ for (const e of staleEntries) {
207
+ const d = e.days_since_last_share;
208
+ if (d < 90)
209
+ distribution.month_to_quarter += 1;
210
+ else if (d < 180)
211
+ distribution.quarter_to_half_year += 1;
212
+ else if (d < 365)
213
+ distribution.half_year_to_year += 1;
214
+ else
215
+ distribution.over_year += 1;
216
+ }
217
+ // ── Top N stale (oldest-first; tie-break by share_link_count desc, then id asc) ──
218
+ const sortedStale = [...staleEntries].sort((a, b) => {
219
+ if (b.days_since_last_share !== a.days_since_last_share) {
220
+ return b.days_since_last_share - a.days_since_last_share;
221
+ }
222
+ if (b.share_link_count !== a.share_link_count) {
223
+ return b.share_link_count - a.share_link_count;
224
+ }
225
+ return a.id.localeCompare(b.id);
226
+ });
227
+ const topStale = sortedStale.slice(0, input.top_n);
228
+ const initial = {
229
+ filters: {
230
+ staleness_days: input.staleness_days,
231
+ as_of: asOfIso,
232
+ collection_id: input.collection_id ?? null,
233
+ top_n: input.top_n,
234
+ },
235
+ summary,
236
+ staleness_distribution: distribution,
237
+ top_stale_assets: topStale,
238
+ truncated: enumeratorTruncated,
239
+ };
240
+ if (enumeratorTruncated) {
241
+ initial.truncation_reason =
242
+ 'Share-link enumerator stopped at its internal cap; report reflects a partial dataset.';
243
+ }
244
+ return enforceResponseBudget(initial);
245
+ }
246
+ // ── Helpers ─────────────────────────────────────────────────────────
247
+ function isRevokedOrExpired(status) {
248
+ return status === 'revoked' || status === 'expired';
249
+ }
250
+ function resolveAsOf(rawAsOf) {
251
+ if (rawAsOf === undefined)
252
+ return Date.now();
253
+ // Bare YYYY-MM-DD → end-of-day in UTC, so "stale as of 2026-04-01"
254
+ // captures activity up through the close of that day.
255
+ if (/^\d{4}-\d{2}-\d{2}$/.test(rawAsOf)) {
256
+ return Date.parse(`${rawAsOf}T23:59:59.999Z`);
257
+ }
258
+ return Date.parse(rawAsOf);
259
+ }
260
+ // ── Response-budget enforcement ─────────────────────────────────────
261
+ const REDUCED_TOP_LIMIT = 10;
262
+ /**
263
+ * Aggregate reports tend to be small (totals + top-N + bucket counts).
264
+ * If the serialised report exceeds {@link HARD_CAP_TOKENS}, trim the
265
+ * top-asset list and mark `truncated: true`.
266
+ */
267
+ function enforceResponseBudget(report) {
268
+ if (estimateTokens(JSON.stringify(report)) <= HARD_CAP_TOKENS) {
269
+ return report;
270
+ }
271
+ const trimmed = {
272
+ ...report,
273
+ top_stale_assets: report.top_stale_assets.slice(0, REDUCED_TOP_LIMIT),
274
+ truncated: true,
275
+ truncation_reason: report.truncation_reason !== undefined
276
+ ? `${report.truncation_reason} Additionally, the top-stale-assets list was trimmed to fit the response budget.`
277
+ : 'Top-stale-assets list was trimmed to fit the response budget.',
278
+ };
279
+ return trimmed;
280
+ }
281
+ //# sourceMappingURL=report-stale-assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-stale-assets.js","sourceRoot":"","sources":["../../../src/tools/insights/report-stale-assets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
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_TOP_ASSETS_DESCRIPTION: string;
5
+ export declare const DEFAULT_TOP_N = 10;
6
+ export declare const MAX_TOP_N = 100;
7
+ /** Default look-back window when neither `date_from` nor `date_to` is set. */
8
+ export declare const DEFAULT_LOOKBACK_DAYS = 90;
9
+ export declare const SORT_BY_VALUES: readonly ["total_views", "share_link_count", "mean_views_per_share"];
10
+ export type ReportTopAssetsSortBy = (typeof SORT_BY_VALUES)[number];
11
+ /**
12
+ * `date_from` / `date_to` are inclusive ISO-8601 date or datetime
13
+ * strings. If only a date is supplied (e.g. `2026-04-14`) it is
14
+ * interpreted as the start (00:00:00Z) for `date_from` or the end
15
+ * (23:59:59.999Z) for `date_to`. When BOTH are omitted, the analyzer
16
+ * defaults to the last {@link DEFAULT_LOOKBACK_DAYS} days — wider than
17
+ * T2's 30-day default because "top performers" is more interesting over
18
+ * a quarter than a month.
19
+ */
20
+ export declare const ReportTopAssetsInputSchema: z.ZodObject<{
21
+ date_from: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
22
+ date_to: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
23
+ collection_id: z.ZodOptional<z.ZodString>;
24
+ created_by_user_id: z.ZodOptional<z.ZodString>;
25
+ sort_by: z.ZodDefault<z.ZodEnum<["total_views", "share_link_count", "mean_views_per_share"]>>;
26
+ top_n: z.ZodDefault<z.ZodNumber>;
27
+ }, "strict", z.ZodTypeAny, {
28
+ sort_by: "total_views" | "share_link_count" | "mean_views_per_share";
29
+ top_n: number;
30
+ collection_id?: string | undefined;
31
+ date_from?: string | undefined;
32
+ date_to?: string | undefined;
33
+ created_by_user_id?: string | undefined;
34
+ }, {
35
+ sort_by?: "total_views" | "share_link_count" | "mean_views_per_share" | undefined;
36
+ collection_id?: string | undefined;
37
+ date_from?: string | undefined;
38
+ date_to?: string | undefined;
39
+ created_by_user_id?: string | undefined;
40
+ top_n?: number | undefined;
41
+ }>;
42
+ export type ReportTopAssetsInput = z.input<typeof ReportTopAssetsInputSchema>;
43
+ export type ReportTopAssetsInputResolved = z.output<typeof ReportTopAssetsInputSchema>;
44
+ export interface TopAssetEntry {
45
+ id: string;
46
+ /** Best-effort title pulled from the most-recent share-link row covering this asset. */
47
+ title: string | null;
48
+ /** Sum of view counts across share links covering this asset. */
49
+ total_views: number;
50
+ /** Number of share links covering this asset within the matching range. */
51
+ share_link_count: number;
52
+ /** Number of distinct user ids that created share links covering this asset. */
53
+ distinct_creators_count: number;
54
+ /** Number of distinct collection ids whose shares covered this asset. */
55
+ distinct_collections_count: number;
56
+ /** Mean views per share link covering this asset (0 when share_link_count is 0 — guarded for callers iterating without the wrapping list). */
57
+ mean_views_per_share: number;
58
+ /** Earliest share-link `created_at` covering this asset (ISO-8601). */
59
+ first_shared_at: string | null;
60
+ /** Latest share-link `created_at` covering this asset (ISO-8601). */
61
+ last_shared_at: string | null;
62
+ }
63
+ export interface TopAssetsTotals {
64
+ /** Number of distinct assets with any matching share-link activity. */
65
+ matched_assets: number;
66
+ /** Sum of view counts across all matching share links. */
67
+ total_views: number;
68
+ /** Number of matching share-link rows. */
69
+ total_shares: number;
70
+ /** Mean total_views across matched assets (null when matched_assets === 0). */
71
+ mean_views_per_asset: number | null;
72
+ /** Median total_views across matched assets (null when matched_assets === 0). */
73
+ median_views_per_asset: number | null;
74
+ }
75
+ /**
76
+ * Tier counts using percentile thresholds across the matched-asset
77
+ * population's total_views distribution.
78
+ *
79
+ * Tier boundaries:
80
+ * * `high` — assets at or above the P80 threshold
81
+ * * `medium` — assets at or above P50 but below P80
82
+ * * `low` — assets below P50
83
+ *
84
+ * `thresholds` exposes the numeric boundary values used so the LLM can
85
+ * cite "top performers (≥ N views)" in natural language.
86
+ *
87
+ * `null` for both thresholds means there were no matched assets to
88
+ * derive tiers from.
89
+ */
90
+ export interface PerformanceBuckets {
91
+ high: number;
92
+ medium: number;
93
+ low: number;
94
+ thresholds: {
95
+ p80_views: number | null;
96
+ p50_views: number | null;
97
+ };
98
+ }
99
+ export interface TopAssetsReport {
100
+ /** Inputs as resolved (after defaults / filters applied). */
101
+ filters: {
102
+ date_from: string | null;
103
+ date_to: string | null;
104
+ collection_id: string | null;
105
+ created_by_user_id: string | null;
106
+ sort_by: ReportTopAssetsSortBy;
107
+ top_n: number;
108
+ };
109
+ totals: TopAssetsTotals;
110
+ performance_buckets: PerformanceBuckets;
111
+ top_assets: TopAssetEntry[];
112
+ /** True when the share-link enumerator hit its hard cap or the response was trimmed for budget. */
113
+ truncated: boolean;
114
+ truncation_reason?: string;
115
+ }
116
+ export interface ReportTopAssetsDeps {
117
+ enumerator: ShareLinkEnumerator;
118
+ }
119
+ export type ReportTopAssetsOutcome = {
120
+ ok: true;
121
+ report: TopAssetsReport;
122
+ } | {
123
+ ok: false;
124
+ error: McpToolError;
125
+ };
126
+ export declare class ReportTopAssetsTool {
127
+ private readonly deps;
128
+ readonly name = "report_top_assets";
129
+ readonly description: string;
130
+ constructor(deps: ReportTopAssetsDeps);
131
+ run(rawInput?: ReportTopAssetsInput): Promise<ReportTopAssetsOutcome>;
132
+ }
133
+ export declare function buildReportTopAssetsTool(deps: ReportTopAssetsDeps): ReportTopAssetsTool;
134
+ /**
135
+ * Build the top-assets report from a flat list of share-link rows. Pure
136
+ * function, exported for direct test access.
137
+ */
138
+ export declare function buildReport(rows: ReadonlyArray<ShareLinkRow>, enumeratorTruncated: boolean, input: ReportTopAssetsInputResolved): TopAssetsReport;
139
+ //# sourceMappingURL=report-top-assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-top-assets.d.ts","sourceRoot":"","sources":["../../../src/tools/insights/report-top-assets.ts"],"names":[],"mappings":"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"}