@caelo-cms/shared 0.10.22 → 0.10.24

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 (249) hide show
  1. package/dist/ai-tools.d.ts +289 -273
  2. package/dist/ai-tools.d.ts.map +1 -1
  3. package/dist/ai-tools.js +342 -323
  4. package/dist/ai-tools.js.map +1 -1
  5. package/dist/auth-forms.d.ts.map +1 -1
  6. package/dist/auth-forms.js +4 -1
  7. package/dist/auth-forms.js.map +1 -1
  8. package/dist/base-css.d.ts +35 -0
  9. package/dist/base-css.d.ts.map +1 -0
  10. package/dist/base-css.js +40 -0
  11. package/dist/base-css.js.map +1 -0
  12. package/dist/build-page.d.ts +330 -0
  13. package/dist/build-page.d.ts.map +1 -0
  14. package/dist/build-page.js +282 -0
  15. package/dist/build-page.js.map +1 -0
  16. package/dist/content.d.ts +322 -9
  17. package/dist/content.d.ts.map +1 -1
  18. package/dist/content.js +354 -11
  19. package/dist/content.js.map +1 -1
  20. package/dist/css-gradient-scan.d.ts +14 -0
  21. package/dist/css-gradient-scan.d.ts.map +1 -0
  22. package/dist/css-gradient-scan.js +81 -0
  23. package/dist/css-gradient-scan.js.map +1 -0
  24. package/dist/css-var-scan.d.ts +56 -0
  25. package/dist/css-var-scan.d.ts.map +1 -0
  26. package/dist/css-var-scan.js +97 -0
  27. package/dist/css-var-scan.js.map +1 -0
  28. package/dist/design-draft-shell.d.ts +21 -0
  29. package/dist/design-draft-shell.d.ts.map +1 -0
  30. package/dist/design-draft-shell.js +81 -0
  31. package/dist/design-draft-shell.js.map +1 -0
  32. package/dist/design-manifest.d.ts +36 -0
  33. package/dist/design-manifest.d.ts.map +1 -0
  34. package/dist/design-manifest.js +90 -0
  35. package/dist/design-manifest.js.map +1 -0
  36. package/dist/fonts.d.ts +89 -0
  37. package/dist/fonts.d.ts.map +1 -0
  38. package/dist/fonts.js +241 -0
  39. package/dist/fonts.js.map +1 -0
  40. package/dist/genesis-inventory.d.ts +32 -0
  41. package/dist/genesis-inventory.d.ts.map +1 -0
  42. package/dist/genesis-inventory.js +186 -0
  43. package/dist/genesis-inventory.js.map +1 -0
  44. package/dist/genesis.d.ts +102 -0
  45. package/dist/genesis.d.ts.map +1 -0
  46. package/dist/genesis.js +145 -0
  47. package/dist/genesis.js.map +1 -0
  48. package/dist/i18n.d.ts +29 -36
  49. package/dist/i18n.d.ts.map +1 -1
  50. package/dist/i18n.js +53 -128
  51. package/dist/i18n.js.map +1 -1
  52. package/dist/index.d.ts +28 -1
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +28 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/interactions.d.ts +23 -0
  57. package/dist/interactions.d.ts.map +1 -0
  58. package/dist/interactions.js +44 -0
  59. package/dist/interactions.js.map +1 -0
  60. package/dist/media.d.ts +101 -16
  61. package/dist/media.d.ts.map +1 -1
  62. package/dist/media.js +126 -15
  63. package/dist/media.js.map +1 -1
  64. package/dist/page-log.d.ts +94 -0
  65. package/dist/page-log.d.ts.map +1 -0
  66. package/dist/page-log.js +111 -0
  67. package/dist/page-log.js.map +1 -0
  68. package/dist/preview-compose.d.ts +85 -12
  69. package/dist/preview-compose.d.ts.map +1 -1
  70. package/dist/preview-compose.js +157 -67
  71. package/dist/preview-compose.js.map +1 -1
  72. package/dist/proposal-status.d.ts +40 -0
  73. package/dist/proposal-status.d.ts.map +1 -0
  74. package/dist/proposal-status.js +34 -0
  75. package/dist/proposal-status.js.map +1 -0
  76. package/dist/responsive-images.d.ts +64 -0
  77. package/dist/responsive-images.d.ts.map +1 -0
  78. package/dist/responsive-images.js +98 -0
  79. package/dist/responsive-images.js.map +1 -0
  80. package/dist/safe-keys.d.ts +9 -0
  81. package/dist/safe-keys.d.ts.map +1 -0
  82. package/dist/safe-keys.js +20 -0
  83. package/dist/safe-keys.js.map +1 -0
  84. package/dist/seo.d.ts +11 -16
  85. package/dist/seo.d.ts.map +1 -1
  86. package/dist/seo.js +7 -23
  87. package/dist/seo.js.map +1 -1
  88. package/dist/skills.d.ts +14 -68
  89. package/dist/skills.d.ts.map +1 -1
  90. package/dist/skills.js +19 -113
  91. package/dist/skills.js.map +1 -1
  92. package/dist/strip-cdata.d.ts +7 -0
  93. package/dist/strip-cdata.d.ts.map +1 -0
  94. package/dist/strip-cdata.js +48 -0
  95. package/dist/strip-cdata.js.map +1 -0
  96. package/dist/structured-sets.d.ts +6 -52
  97. package/dist/structured-sets.d.ts.map +1 -1
  98. package/dist/structured-sets.js +6 -68
  99. package/dist/structured-sets.js.map +1 -1
  100. package/dist/subagents.d.ts +105 -3
  101. package/dist/subagents.d.ts.map +1 -1
  102. package/dist/subagents.js +224 -41
  103. package/dist/subagents.js.map +1 -1
  104. package/dist/template-engine.d.ts +85 -0
  105. package/dist/template-engine.d.ts.map +1 -0
  106. package/dist/template-engine.js +403 -0
  107. package/dist/template-engine.js.map +1 -0
  108. package/dist/theme-importers/auto-detect.d.ts +26 -0
  109. package/dist/theme-importers/auto-detect.d.ts.map +1 -0
  110. package/dist/theme-importers/auto-detect.js +42 -0
  111. package/dist/theme-importers/auto-detect.js.map +1 -0
  112. package/dist/theme-importers/css-comments.d.ts +12 -0
  113. package/dist/theme-importers/css-comments.d.ts.map +1 -0
  114. package/dist/theme-importers/css-comments.js +15 -0
  115. package/dist/theme-importers/css-comments.js.map +1 -0
  116. package/dist/theme-importers/dtcg.d.ts +46 -0
  117. package/dist/theme-importers/dtcg.d.ts.map +1 -0
  118. package/dist/theme-importers/dtcg.js +111 -0
  119. package/dist/theme-importers/dtcg.js.map +1 -0
  120. package/dist/theme-importers/loose.d.ts +3 -0
  121. package/dist/theme-importers/loose.d.ts.map +1 -0
  122. package/dist/theme-importers/loose.js +76 -0
  123. package/dist/theme-importers/loose.js.map +1 -0
  124. package/dist/theme-importers/shadcn.d.ts +24 -0
  125. package/dist/theme-importers/shadcn.d.ts.map +1 -0
  126. package/dist/theme-importers/shadcn.js +135 -0
  127. package/dist/theme-importers/shadcn.js.map +1 -0
  128. package/dist/theme-importers/style-dictionary.d.ts +17 -0
  129. package/dist/theme-importers/style-dictionary.d.ts.map +1 -0
  130. package/dist/theme-importers/style-dictionary.js +125 -0
  131. package/dist/theme-importers/style-dictionary.js.map +1 -0
  132. package/dist/theme-importers/tailwind.d.ts +3 -0
  133. package/dist/theme-importers/tailwind.d.ts.map +1 -0
  134. package/dist/theme-importers/tailwind.js +218 -0
  135. package/dist/theme-importers/tailwind.js.map +1 -0
  136. package/dist/theme-literal-binding.d.ts +37 -0
  137. package/dist/theme-literal-binding.d.ts.map +1 -0
  138. package/dist/theme-literal-binding.js +138 -0
  139. package/dist/theme-literal-binding.js.map +1 -0
  140. package/dist/theme-normalize.d.ts +31 -0
  141. package/dist/theme-normalize.d.ts.map +1 -0
  142. package/dist/theme-normalize.js +587 -0
  143. package/dist/theme-normalize.js.map +1 -0
  144. package/dist/theme-ramp.d.ts +55 -0
  145. package/dist/theme-ramp.d.ts.map +1 -0
  146. package/dist/theme-ramp.js +149 -0
  147. package/dist/theme-ramp.js.map +1 -0
  148. package/dist/theme-render.d.ts +105 -0
  149. package/dist/theme-render.d.ts.map +1 -0
  150. package/dist/theme-render.js +441 -0
  151. package/dist/theme-render.js.map +1 -0
  152. package/dist/themes-errors.d.ts +109 -0
  153. package/dist/themes-errors.d.ts.map +1 -0
  154. package/dist/themes-errors.js +170 -0
  155. package/dist/themes-errors.js.map +1 -0
  156. package/dist/themes.d.ts +343 -0
  157. package/dist/themes.d.ts.map +1 -0
  158. package/dist/themes.js +697 -0
  159. package/dist/themes.js.map +1 -0
  160. package/dist/version.d.ts +7 -4
  161. package/dist/version.d.ts.map +1 -1
  162. package/dist/version.js +6 -3
  163. package/dist/version.js.map +1 -1
  164. package/package.json +10 -2
  165. package/src/__tests__/redos-hardening.test.ts +160 -0
  166. package/src/ai-tools-add-module-modes.test.ts +106 -0
  167. package/src/ai-tools-position.test.ts +134 -0
  168. package/src/ai-tools.test.ts +81 -0
  169. package/src/ai-tools.ts +1105 -0
  170. package/src/auth-forms.ts +36 -0
  171. package/src/base-css.ts +42 -0
  172. package/src/build-page.test.ts +228 -0
  173. package/src/build-page.ts +319 -0
  174. package/src/cap-failures.ts +67 -0
  175. package/src/content.test.ts +170 -0
  176. package/src/content.ts +620 -0
  177. package/src/context.ts +43 -0
  178. package/src/css-gradient-scan.ts +88 -0
  179. package/src/css-var-scan.test.ts +96 -0
  180. package/src/css-var-scan.ts +144 -0
  181. package/src/derive-module-type.test.ts +80 -0
  182. package/src/design-draft-shell.test.ts +85 -0
  183. package/src/design-draft-shell.ts +109 -0
  184. package/src/design-manifest.ts +93 -0
  185. package/src/fonts.test.ts +157 -0
  186. package/src/fonts.ts +296 -0
  187. package/src/genesis-inventory.test.ts +86 -0
  188. package/src/genesis-inventory.ts +215 -0
  189. package/src/genesis-sanitize.test.ts +35 -0
  190. package/src/genesis.ts +158 -0
  191. package/src/i18n.test.ts +58 -0
  192. package/src/i18n.ts +91 -0
  193. package/src/index.test.ts +10 -0
  194. package/src/index.ts +59 -0
  195. package/src/interactions.ts +48 -0
  196. package/src/logger.ts +147 -0
  197. package/src/media.test.ts +160 -0
  198. package/src/media.ts +355 -0
  199. package/src/page-log.test.ts +163 -0
  200. package/src/page-log.ts +124 -0
  201. package/src/preview-compose.test.ts +637 -0
  202. package/src/preview-compose.ts +656 -0
  203. package/src/preview-scanner.test.ts +96 -0
  204. package/src/preview-scanner.ts +214 -0
  205. package/src/proposal-status.test.ts +69 -0
  206. package/src/proposal-status.ts +40 -0
  207. package/src/responsive-images.test.ts +104 -0
  208. package/src/responsive-images.ts +151 -0
  209. package/src/result.ts +29 -0
  210. package/src/safe-keys.ts +21 -0
  211. package/src/seo.test.ts +194 -0
  212. package/src/seo.ts +233 -0
  213. package/src/skills.ts +48 -0
  214. package/src/snapshots.test.ts +80 -0
  215. package/src/snapshots.ts +81 -0
  216. package/src/strip-cdata.test.ts +41 -0
  217. package/src/strip-cdata.ts +50 -0
  218. package/src/structured-sets.ts +114 -0
  219. package/src/subagents.test.ts +262 -0
  220. package/src/subagents.ts +432 -0
  221. package/src/template-engine.test.ts +379 -0
  222. package/src/template-engine.ts +520 -0
  223. package/src/theme-gradient.test.ts +92 -0
  224. package/src/theme-importers/__tests__/proto-pollution.test.ts +54 -0
  225. package/src/theme-importers/auto-detect.ts +84 -0
  226. package/src/theme-importers/css-comments.ts +15 -0
  227. package/src/theme-importers/dtcg.ts +106 -0
  228. package/src/theme-importers/loose.ts +76 -0
  229. package/src/theme-importers/shadcn.ts +133 -0
  230. package/src/theme-importers/style-dictionary.ts +125 -0
  231. package/src/theme-importers/tailwind.ts +217 -0
  232. package/src/theme-literal-binding.test.ts +71 -0
  233. package/src/theme-literal-binding.ts +159 -0
  234. package/src/theme-motion.test.ts +115 -0
  235. package/src/theme-normalize-envelope.test.ts +43 -0
  236. package/src/theme-normalize-gradient.test.ts +135 -0
  237. package/src/theme-normalize.ts +661 -0
  238. package/src/theme-ramp.ts +187 -0
  239. package/src/theme-render-sanitize.test.ts +45 -0
  240. package/src/theme-render.test.ts +119 -0
  241. package/src/theme-render.ts +487 -0
  242. package/src/theme-shadow.test.ts +56 -0
  243. package/src/themes-errors.ts +199 -0
  244. package/src/themes.ts +842 -0
  245. package/src/version.ts +66 -0
  246. package/dist/translation.d.ts +0 -127
  247. package/dist/translation.d.ts.map +0 -1
  248. package/dist/translation.js +0 -208
  249. package/dist/translation.js.map +0 -1
@@ -0,0 +1,44 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * issue #160 — the vetted interaction baseline (epic #149).
4
+ *
5
+ * A header without a working mobile menu reads as broken, not minimal
6
+ * — and hand-rolled per-module JS gets focus/aria handling wrong more
7
+ * often than right. This module carries the FUNCTIONAL (non-aesthetic)
8
+ * CSS + JS for the built-in nav renderer: hamburger toggle under the
9
+ * mobile breakpoint, `aria-expanded` bookkeeping, escape-to-close.
10
+ * All colors/spacing stay the module/theme's business — these rules
11
+ * only govern show/hide behaviour, so they don't violate the
12
+ * no-global-look re-scope (#151).
13
+ *
14
+ * The composer includes each asset ONCE per page when at least one
15
+ * nav-menu module rendered (natural dedup, same rule as #158).
16
+ */
17
+ /** Functional-only rules: collapse/expand mechanics, zero aesthetics. */
18
+ export const NAV_FUNCTIONAL_CSS = ".caelo-nav-menu .caelo-nav-toggle{display:none;background:none;border:0;cursor:pointer;padding:0.5rem;color:inherit;font:inherit}" +
19
+ ".caelo-nav-menu .caelo-nav-toggle .caelo-nav-bar{display:block;width:1.25em;height:2px;background:currentColor;margin:0.25em 0}" +
20
+ "@media (max-width: 720px){" +
21
+ ".caelo-nav-menu .caelo-nav-toggle{display:inline-block}" +
22
+ ".caelo-nav-menu > ul{display:none}" +
23
+ '.caelo-nav-menu[data-nav-open="true"] > ul{display:block}' +
24
+ "}";
25
+ /**
26
+ * Toggle behaviour. Runs deferred; idempotent per element via the
27
+ * data attribute; closes on Escape and returns focus to the toggle.
28
+ */
29
+ export const NAV_TOGGLE_JS = "(function(){" +
30
+ "document.querySelectorAll('.caelo-nav-menu').forEach(function(nav){" +
31
+ "var btn=nav.querySelector('.caelo-nav-toggle');if(!btn)return;" +
32
+ "btn.addEventListener('click',function(){" +
33
+ "var open=nav.getAttribute('data-nav-open')==='true';" +
34
+ "nav.setAttribute('data-nav-open',String(!open));" +
35
+ "btn.setAttribute('aria-expanded',String(!open));" +
36
+ "});" +
37
+ "nav.addEventListener('keydown',function(e){" +
38
+ "if(e.key==='Escape'&&nav.getAttribute('data-nav-open')==='true'){" +
39
+ "nav.setAttribute('data-nav-open','false');" +
40
+ "btn.setAttribute('aria-expanded','false');btn.focus();" +
41
+ "}});" +
42
+ "});" +
43
+ "})();";
44
+ //# sourceMappingURL=interactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactions.js","sourceRoot":"","sources":["../src/interactions.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;;;;;;GAcG;AAEH,yEAAyE;AACzE,MAAM,CAAC,MAAM,kBAAkB,GAC7B,mIAAmI;IACnI,iIAAiI;IACjI,4BAA4B;IAC5B,yDAAyD;IACzD,oCAAoC;IACpC,2DAA2D;IAC3D,GAAG,CAAC;AAEN;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GACxB,cAAc;IACd,qEAAqE;IACrE,gEAAgE;IAChE,0CAA0C;IAC1C,sDAAsD;IACtD,kDAAkD;IAClD,kDAAkD;IAClD,KAAK;IACL,6CAA6C;IAC7C,mEAAmE;IACnE,4CAA4C;IAC5C,wDAAwD;IACxD,MAAM;IACN,KAAK;IACL,OAAO,CAAC"}
package/dist/media.d.ts CHANGED
@@ -15,7 +15,7 @@ import { z } from "zod";
15
15
  * pipeline strips `<script>` and event-handler attributes before
16
16
  * persisting (see {@link sanitizeSvg} in admin-core).
17
17
  */
18
- export declare const MEDIA_ALLOWED_MIMES: readonly ["image/jpeg", "image/png", "image/webp", "image/avif", "image/gif", "image/svg+xml", "application/pdf", "video/mp4"];
18
+ export declare const MEDIA_ALLOWED_MIMES: readonly ["image/jpeg", "image/png", "image/webp", "image/avif", "image/gif", "image/svg+xml", "application/pdf", "video/mp4", "font/woff2", "font/woff", "font/ttf", "font/otf"];
19
19
  export type MediaMime = (typeof MEDIA_ALLOWED_MIMES)[number];
20
20
  /** Per-MIME size caps (bytes). Server enforces; client display only. */
21
21
  export declare const MEDIA_SIZE_CAPS: Record<MediaMime, number>;
@@ -37,33 +37,65 @@ export declare const MEDIA_VARIANT_WIDTHS: Record<Exclude<MediaVariantTag, "orig
37
37
  * shape; the static generator rewrites to `/_assets/...` (or a CDN
38
38
  * URL) at deploy time.
39
39
  *
40
- * Format: `/_caelo/media/<asset-id>/<variant>`. The asset id, not the
41
- * sha, so URLs survive a re-upload of the same content under a new id.
40
+ * Format (current): `/_caelo/media/<slug>` for the orig variant,
41
+ * `/_caelo/media/<slug>/<variant>` for a named variant (webp/crops). The
42
+ * `<slug>` is `media_assets.slug` — a human-meaningful name (e.g.
43
+ * `searchviu-logo`); the UUID id stays internal. The static generator
44
+ * rewrites these to `/_assets/<slug>.<ext>` (orig) / `/_assets/<slug>/<variant>.<ext>`.
45
+ *
46
+ * Legacy form `/_caelo/media/<uuid>/<variant>` is still PARSED (existing
47
+ * persisted embeds keep resolving), but never newly EMITTED.
42
48
  */
43
49
  export declare const MEDIA_URL_PREFIX = "/_caelo/media";
44
- export declare function buildMediaUrl(assetId: string, variant: MediaVariantTag): string;
45
50
  /**
46
- * Extract every (assetId, variant) pair referenced in an HTML string.
47
- * Used by the post-write usage-tracker and by the static-generator
48
- * media-pass. Returns a deduped list to keep callers' work proportional
49
- * to unique assets, not raw match count.
51
+ * Build the media URL for an asset SLUG + variant. The orig variant is
52
+ * flat (`/_caelo/media/<slug>`) so a plain image reads as a name, not a
53
+ * path; named variants (srcset webp / focal crops) nest under the slug.
54
+ * Widened to `| string` (run #10 D4): pickAiImageVariant returns whichever
55
+ * variant tag actually exists.
56
+ */
57
+ export declare function buildMediaUrl(slug: string, variant: MediaVariantTag | string): string;
58
+ /**
59
+ * Turn a human/asset label into a URL-safe media slug: lowercase ascii,
60
+ * kebab-case, extension + junk stripped, capped at 60 chars. NOT
61
+ * uniquified — the caller resolves collisions against the live library
62
+ * (append `-2`/`-3`…); see `resolveUniqueMediaSlug` in admin-core.
50
63
  */
51
- export declare function extractMediaRefs(html: string): {
52
- assetId: string;
53
- variant: string;
54
- }[];
64
+ export declare function slugifyMediaName(name: string): string;
65
+ /**
66
+ * One media reference parsed from HTML. `ref` is either an asset SLUG
67
+ * (`isSlug: true`) or a legacy UUID id (`isSlug: false`); callers resolve
68
+ * a slug ref to an asset id before touching the DB. `variant` defaults to
69
+ * `orig` for the flat slug form.
70
+ */
71
+ export interface MediaRef {
72
+ readonly ref: string;
73
+ readonly isSlug: boolean;
74
+ readonly variant: string;
75
+ }
76
+ /**
77
+ * Extract every media reference in an HTML string (deduped). Used by the
78
+ * post-write usage-tracker and the static-generator media-pass. Handles
79
+ * both the current slug form and the legacy `<uuid>/<variant>` form.
80
+ */
81
+ export declare function extractMediaRefs(html: string): MediaRef[];
55
82
  export declare const mediaUploadInputSchema: z.ZodObject<{
56
83
  sha256: z.ZodString;
57
84
  originalName: z.ZodString;
85
+ name: z.ZodOptional<z.ZodString>;
58
86
  mime: z.ZodEnum<{
59
- "image/jpeg": "image/jpeg";
60
87
  "image/png": "image/png";
88
+ "image/jpeg": "image/jpeg";
61
89
  "image/webp": "image/webp";
62
- "image/avif": "image/avif";
63
90
  "image/gif": "image/gif";
91
+ "image/avif": "image/avif";
64
92
  "image/svg+xml": "image/svg+xml";
65
93
  "application/pdf": "application/pdf";
66
94
  "video/mp4": "video/mp4";
95
+ "font/woff2": "font/woff2";
96
+ "font/woff": "font/woff";
97
+ "font/ttf": "font/ttf";
98
+ "font/otf": "font/otf";
67
99
  }>;
68
100
  sizeBytes: z.ZodNumber;
69
101
  width: z.ZodNullable<z.ZodNumber>;
@@ -71,6 +103,14 @@ export declare const mediaUploadInputSchema: z.ZodObject<{
71
103
  alt: z.ZodDefault<z.ZodString>;
72
104
  storageKey: z.ZodString;
73
105
  storageProvider: z.ZodDefault<z.ZodString>;
106
+ sourceKind: z.ZodOptional<z.ZodEnum<{
107
+ upload: "upload";
108
+ ai_generated: "ai_generated";
109
+ imported: "imported";
110
+ external: "external";
111
+ }>>;
112
+ sourceDetail: z.ZodOptional<z.ZodString>;
113
+ license: z.ZodOptional<z.ZodString>;
74
114
  variants: z.ZodArray<z.ZodObject<{
75
115
  variant: z.ZodString;
76
116
  format: z.ZodString;
@@ -84,14 +124,18 @@ export type MediaUploadInput = z.infer<typeof mediaUploadInputSchema>;
84
124
  export declare const mediaListInputSchema: z.ZodObject<{
85
125
  query: z.ZodOptional<z.ZodString>;
86
126
  mime: z.ZodOptional<z.ZodEnum<{
87
- "image/jpeg": "image/jpeg";
88
127
  "image/png": "image/png";
128
+ "image/jpeg": "image/jpeg";
89
129
  "image/webp": "image/webp";
90
- "image/avif": "image/avif";
91
130
  "image/gif": "image/gif";
131
+ "image/avif": "image/avif";
92
132
  "image/svg+xml": "image/svg+xml";
93
133
  "application/pdf": "application/pdf";
94
134
  "video/mp4": "video/mp4";
135
+ "font/woff2": "font/woff2";
136
+ "font/woff": "font/woff";
137
+ "font/ttf": "font/ttf";
138
+ "font/otf": "font/otf";
95
139
  }>>;
96
140
  sort: z.ZodDefault<z.ZodEnum<{
97
141
  recent: "recent";
@@ -106,6 +150,24 @@ export declare const mediaUpdateAltInputSchema: z.ZodObject<{
106
150
  alt: z.ZodString;
107
151
  }, z.core.$strict>;
108
152
  export type MediaUpdateAltInput = z.infer<typeof mediaUpdateAltInputSchema>;
153
+ /**
154
+ * media.set_source (0181) — record/patch an asset's provenance after it
155
+ * exists. COALESCE semantics at the handler: omitted fields stay
156
+ * unchanged, so this both sets provenance the first time and patches a
157
+ * single field (e.g. a licence the operator states later).
158
+ */
159
+ export declare const mediaSetSourceInputSchema: z.ZodObject<{
160
+ assetId: z.ZodString;
161
+ sourceKind: z.ZodOptional<z.ZodEnum<{
162
+ upload: "upload";
163
+ ai_generated: "ai_generated";
164
+ imported: "imported";
165
+ external: "external";
166
+ }>>;
167
+ sourceDetail: z.ZodOptional<z.ZodString>;
168
+ license: z.ZodOptional<z.ZodString>;
169
+ }, z.core.$strict>;
170
+ export type MediaSetSourceInput = z.infer<typeof mediaSetSourceInputSchema>;
109
171
  export declare const mediaDeleteInputSchema: z.ZodObject<{
110
172
  assetId: z.ZodString;
111
173
  force: z.ZodDefault<z.ZodBoolean>;
@@ -138,6 +200,29 @@ export interface MediaStorageAdapter {
138
200
  /** Bytes-on-disk for capacity reporting. */
139
201
  totalSizeBytes(): Promise<number>;
140
202
  }
203
+ /**
204
+ * Object-store prefix for images the AI produced during a chat (screenshots
205
+ * of a page, of an external site, of a crawled source page).
206
+ *
207
+ * They are NOT media assets. The operator's library is their own curated
208
+ * space; filling it with machine screenshots would make it useless, and these
209
+ * images have no life outside the conversation that produced them. They live
210
+ * under their own prefix instead, and a scheduled sweep removes the ones whose
211
+ * conversations have aged out (see `chat_images.gc`).
212
+ *
213
+ * The key is `chat-images/<UTC day>/<sha256>.<ext>`:
214
+ * - the day segment makes age the first thing you can see in a key, so a
215
+ * sweep never has to open a file to decide;
216
+ * - the content hash means re-shooting an unchanged page writes the SAME
217
+ * key. That is not just a storage saving — an identical key keeps the
218
+ * message history byte-identical, so the provider's prompt cache survives
219
+ * a re-screenshot of something that did not change.
220
+ */
221
+ export declare const CHAT_IMAGE_PREFIX = "chat-images";
222
+ /** Build the storage key for a chat image. `day` is `YYYY-MM-DD` (UTC). */
223
+ export declare function buildChatImageKey(day: string, sha256: string, ext: string): string;
224
+ /** True for keys under the chat-image prefix — the sweep's safety check. */
225
+ export declare function isChatImageKey(key: string): boolean;
141
226
  /** Build the canonical storage key for a given asset variant. */
142
227
  export declare function buildStorageKey(sha256: string, variant: MediaVariantTag | string, ext: string): string;
143
228
  //# sourceMappingURL=media.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,gIAStB,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,wEAAwE;AACxE,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CASrD,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,QAAmB,CAAC;AAEvD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,qEAMrB,CAAC;AACX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,oDAAoD;AACpD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,OAAO,CAAC,eAAe,EAAE,MAAM,CAAC,EAAE,MAAM,CAKjF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAEhD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAE/E;AAWD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAUrF;AAQD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAyBxB,CAAC;AACZ,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;kBAQtB,CAAC;AACZ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,yBAAyB;;;kBAK3B,CAAC;AACZ,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,sBAAsB;;;kBAKxB,CAAC;AAEZ,eAAO,MAAM,2BAA2B;;kBAK7B,CAAC;AACZ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,2BAA2B;;kBAI7B,CAAC;AAEZ,eAAO,MAAM,sBAAsB;;;kBAKxB,CAAC;AACZ,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAOtE;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,4CAA4C;IAC5C,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,iEAAiE;AACjE,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,eAAe,GAAG,MAAM,EACjC,GAAG,EAAE,MAAM,GACV,MAAM,CAER"}
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"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"}
package/dist/media.js CHANGED
@@ -25,6 +25,14 @@ export const MEDIA_ALLOWED_MIMES = [
25
25
  "image/svg+xml",
26
26
  "application/pdf",
27
27
  "video/mp4",
28
+ // issue #249 — webfonts. Migrated sites reference their own font
29
+ // files from replayed CSS; the media-migration pass downloads them
30
+ // into the library so the rebuilt site survives the source host
31
+ // going away. Stored as-is (no derived variants).
32
+ "font/woff2",
33
+ "font/woff",
34
+ "font/ttf",
35
+ "font/otf",
28
36
  ];
29
37
  /** Per-MIME size caps (bytes). Server enforces; client display only. */
30
38
  export const MEDIA_SIZE_CAPS = {
@@ -36,6 +44,10 @@ export const MEDIA_SIZE_CAPS = {
36
44
  "image/svg+xml": 1 * 1024 * 1024,
37
45
  "application/pdf": 20 * 1024 * 1024,
38
46
  "video/mp4": 50 * 1024 * 1024,
47
+ "font/woff2": 5 * 1024 * 1024,
48
+ "font/woff": 5 * 1024 * 1024,
49
+ "font/ttf": 5 * 1024 * 1024,
50
+ "font/otf": 5 * 1024 * 1024,
39
51
  };
40
52
  /** Hard ceiling on the multipart body. Per-MIME caps narrow further. */
41
53
  export const MEDIA_HARD_LIMIT_BYTES = 50 * 1024 * 1024;
@@ -65,33 +77,74 @@ export const MEDIA_VARIANT_WIDTHS = {
65
77
  * shape; the static generator rewrites to `/_assets/...` (or a CDN
66
78
  * URL) at deploy time.
67
79
  *
68
- * Format: `/_caelo/media/<asset-id>/<variant>`. The asset id, not the
69
- * sha, so URLs survive a re-upload of the same content under a new id.
80
+ * Format (current): `/_caelo/media/<slug>` for the orig variant,
81
+ * `/_caelo/media/<slug>/<variant>` for a named variant (webp/crops). The
82
+ * `<slug>` is `media_assets.slug` — a human-meaningful name (e.g.
83
+ * `searchviu-logo`); the UUID id stays internal. The static generator
84
+ * rewrites these to `/_assets/<slug>.<ext>` (orig) / `/_assets/<slug>/<variant>.<ext>`.
85
+ *
86
+ * Legacy form `/_caelo/media/<uuid>/<variant>` is still PARSED (existing
87
+ * persisted embeds keep resolving), but never newly EMITTED.
70
88
  */
71
89
  export const MEDIA_URL_PREFIX = "/_caelo/media";
72
- export function buildMediaUrl(assetId, variant) {
73
- return `${MEDIA_URL_PREFIX}/${assetId}/${variant}`;
90
+ /** Full-uuid shape — used to tell a legacy id ref from a slug ref. */
91
+ const MEDIA_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
92
+ /**
93
+ * Build the media URL for an asset SLUG + variant. The orig variant is
94
+ * flat (`/_caelo/media/<slug>`) so a plain image reads as a name, not a
95
+ * path; named variants (srcset webp / focal crops) nest under the slug.
96
+ * Widened to `| string` (run #10 D4): pickAiImageVariant returns whichever
97
+ * variant tag actually exists.
98
+ */
99
+ export function buildMediaUrl(slug, variant) {
100
+ return variant === "orig"
101
+ ? `${MEDIA_URL_PREFIX}/${slug}`
102
+ : `${MEDIA_URL_PREFIX}/${slug}/${variant}`;
74
103
  }
75
- // Variant token: `orig`, `webp-<width>`, or `<crop-name>-<width>`. We
76
- // accept any kebab-case slug so focal-point crop fan-outs like
77
- // `square-800` and `wide-1200` (added by P7 optimization #2) round-trip
78
- // without a regex update per crop name.
79
- const mediaUrlPattern = new RegExp(`${MEDIA_URL_PREFIX}/([0-9a-f-]{36})/([a-z][a-z0-9-]{0,63})`, "g");
80
104
  /**
81
- * Extract every (assetId, variant) pair referenced in an HTML string.
82
- * Used by the post-write usage-tracker and by the static-generator
83
- * media-pass. Returns a deduped list to keep callers' work proportional
84
- * to unique assets, not raw match count.
105
+ * Turn a human/asset label into a URL-safe media slug: lowercase ascii,
106
+ * kebab-case, extension + junk stripped, capped at 60 chars. NOT
107
+ * uniquified — the caller resolves collisions against the live library
108
+ * (append `-2`/`-3`…); see `resolveUniqueMediaSlug` in admin-core.
109
+ */
110
+ export function slugifyMediaName(name) {
111
+ const noExt = name.replace(/\.[a-z0-9]{1,8}$/i, "");
112
+ const slug = noExt
113
+ .normalize("NFKD")
114
+ .replace(/[̀-ͯ]/g, "") // strip combining accents
115
+ .toLowerCase()
116
+ .replace(/[^a-z0-9]+/g, "-")
117
+ .replace(/^-+|-+$/g, "")
118
+ .slice(0, 60)
119
+ .replace(/-+$/g, "");
120
+ return slug.length > 0 ? slug : "image";
121
+ }
122
+ // Segment token: a slug or uuid (`[a-z0-9-]`) optionally followed by a
123
+ // variant. `orig`, `webp-<width>`, `<crop-name>-<width>` all round-trip
124
+ // without a per-crop regex update.
125
+ const mediaUrlPattern = new RegExp(`${MEDIA_URL_PREFIX}/([a-z0-9][a-z0-9-]{0,63})(?:/([a-z][a-z0-9-]{0,63}))?`, "g");
126
+ /**
127
+ * Extract every media reference in an HTML string (deduped). Used by the
128
+ * post-write usage-tracker and the static-generator media-pass. Handles
129
+ * both the current slug form and the legacy `<uuid>/<variant>` form.
85
130
  */
86
131
  export function extractMediaRefs(html) {
87
132
  const seen = new Set();
88
133
  const out = [];
89
134
  for (const m of html.matchAll(mediaUrlPattern)) {
90
- const key = `${m[1]}/${m[2]}`;
135
+ const seg1 = m[1];
136
+ const seg2 = m[2];
137
+ // A full-uuid first segment with a trailing variant is the legacy id
138
+ // form; everything else is a slug (orig when no explicit variant).
139
+ const isLegacyId = MEDIA_UUID_RE.test(seg1) && seg2 !== undefined;
140
+ const ref = seg1;
141
+ const isSlug = !isLegacyId;
142
+ const variant = seg2 ?? "orig";
143
+ const key = `${isSlug ? "s" : "i"}:${ref}/${variant}`;
91
144
  if (seen.has(key))
92
145
  continue;
93
146
  seen.add(key);
94
- out.push({ assetId: m[1], variant: m[2] });
147
+ out.push({ ref, isSlug, variant });
95
148
  }
96
149
  return out;
97
150
  }
@@ -103,6 +156,13 @@ export const mediaUploadInputSchema = z
103
156
  .object({
104
157
  sha256: sha256Schema,
105
158
  originalName: z.string().min(1).max(512),
159
+ /**
160
+ * Meaningful, human-facing label for the asset (e.g. "SearchVIU logo").
161
+ * The handler slugifies + uniquifies it into `media_assets.slug`, which
162
+ * becomes the public URL (`/_assets/<slug>.<ext>`); the id stays internal.
163
+ * Optional: falls back to `alt` → `originalName` → "image".
164
+ */
165
+ name: z.string().max(200).optional(),
106
166
  mime: z.enum(MEDIA_ALLOWED_MIMES),
107
167
  sizeBytes: z.number().int().positive(),
108
168
  width: z.number().int().positive().nullable(),
@@ -111,6 +171,16 @@ export const mediaUploadInputSchema = z
111
171
  storageKey: z.string().min(1),
112
172
  /** P7 optimization #3 — stamped by the upload endpoint via getMediaStorageProvider(). */
113
173
  storageProvider: z.string().min(1).max(64).default("local"),
174
+ /**
175
+ * Media provenance (0181). Where the asset came from + its licence
176
+ * when known. All optional — a plain human upload may leave them
177
+ * unset. `sourceDetail` is the origin: source URL for imported /
178
+ * external, "<provider>/<model>" for ai_generated, filename/NULL for
179
+ * a plain upload.
180
+ */
181
+ sourceKind: z.enum(["upload", "ai_generated", "imported", "external"]).optional(),
182
+ sourceDetail: z.string().max(2048).optional(),
183
+ license: z.string().max(200).optional(),
114
184
  variants: z
115
185
  .array(z.object({
116
186
  variant: z.string().min(1).max(64),
@@ -138,6 +208,20 @@ export const mediaUpdateAltInputSchema = z
138
208
  alt: z.string().max(2048),
139
209
  })
140
210
  .strict();
211
+ /**
212
+ * media.set_source (0181) — record/patch an asset's provenance after it
213
+ * exists. COALESCE semantics at the handler: omitted fields stay
214
+ * unchanged, so this both sets provenance the first time and patches a
215
+ * single field (e.g. a licence the operator states later).
216
+ */
217
+ export const mediaSetSourceInputSchema = z
218
+ .object({
219
+ assetId: z.string().uuid(),
220
+ sourceKind: z.enum(["upload", "ai_generated", "imported", "external"]).optional(),
221
+ sourceDetail: z.string().max(2048).optional(),
222
+ license: z.string().max(200).optional(),
223
+ })
224
+ .strict();
141
225
  export const mediaDeleteInputSchema = z
142
226
  .object({
143
227
  assetId: z.string().uuid(),
@@ -161,6 +245,33 @@ export const mediaSetCdnInputSchema = z
161
245
  threshold: z.number().int().min(1).max(10000),
162
246
  })
163
247
  .strict();
248
+ /**
249
+ * Object-store prefix for images the AI produced during a chat (screenshots
250
+ * of a page, of an external site, of a crawled source page).
251
+ *
252
+ * They are NOT media assets. The operator's library is their own curated
253
+ * space; filling it with machine screenshots would make it useless, and these
254
+ * images have no life outside the conversation that produced them. They live
255
+ * under their own prefix instead, and a scheduled sweep removes the ones whose
256
+ * conversations have aged out (see `chat_images.gc`).
257
+ *
258
+ * The key is `chat-images/<UTC day>/<sha256>.<ext>`:
259
+ * - the day segment makes age the first thing you can see in a key, so a
260
+ * sweep never has to open a file to decide;
261
+ * - the content hash means re-shooting an unchanged page writes the SAME
262
+ * key. That is not just a storage saving — an identical key keeps the
263
+ * message history byte-identical, so the provider's prompt cache survives
264
+ * a re-screenshot of something that did not change.
265
+ */
266
+ export const CHAT_IMAGE_PREFIX = "chat-images";
267
+ /** Build the storage key for a chat image. `day` is `YYYY-MM-DD` (UTC). */
268
+ export function buildChatImageKey(day, sha256, ext) {
269
+ return `${CHAT_IMAGE_PREFIX}/${day}/${sha256}.${ext}`;
270
+ }
271
+ /** True for keys under the chat-image prefix — the sweep's safety check. */
272
+ export function isChatImageKey(key) {
273
+ return key.startsWith(`${CHAT_IMAGE_PREFIX}/`);
274
+ }
164
275
  /** Build the canonical storage key for a given asset variant. */
165
276
  export function buildStorageKey(sha256, variant, ext) {
166
277
  return `${sha256}/${variant}.${ext}`;
package/dist/media.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * issue #264 — the per-page edit LOG: durable, append-only work history so a
3
+ * later chat or a fresh subagent that touches a page knows WHY it was edited,
4
+ * what decisions were taken, and which operator answers shaped it — without
5
+ * dragging the originating chat's full transcript through its context.
6
+ *
7
+ * This is FACT (what happened), not learned BEHAVIOUR — so, unlike
8
+ * `site_ai_memory`, it is ungated: any actor appends directly. The shared
9
+ * Zod schemas here are the single source of truth for the `page_log.append`
10
+ * op input, the `log_page_edit` tool schema, and the `page_log.list` output.
11
+ * `formatPageLogBlock` renders the `## Page log` context block the AI reads
12
+ * before touching a page.
13
+ */
14
+ import { z } from "zod";
15
+ /**
16
+ * The kinds of log entry, in the order the AI should reach for them:
17
+ * - `edited` — a substantive content/module change was made.
18
+ * - `decision` — a design/structure call the AI made and its rationale.
19
+ * - `operator_answer` — an answer the operator gave that shaped the page.
20
+ * - `open_question` — something still unresolved a future turn must settle.
21
+ * - `rebuilt` — the page was rebuilt from scratch (e.g. migration rebuild).
22
+ * - `note` — anything else worth preserving for a future editor.
23
+ */
24
+ export declare const pageLogEntryKinds: readonly ["edited", "decision", "operator_answer", "open_question", "rebuilt", "note"];
25
+ export declare const pageLogEntryKindSchema: z.ZodEnum<{
26
+ decision: "decision";
27
+ edited: "edited";
28
+ operator_answer: "operator_answer";
29
+ open_question: "open_question";
30
+ rebuilt: "rebuilt";
31
+ note: "note";
32
+ }>;
33
+ export type PageLogEntryKind = (typeof pageLogEntryKinds)[number];
34
+ /**
35
+ * Optional structured context beyond the one-line summary — an OBJECT, never
36
+ * a bare scalar or array, so the jsonb column stores queryable keys (chosen
37
+ * option, operator's exact words, affected module ids). Writes go through
38
+ * `jsonbParam()` in the op handler to avoid the double-encode trap (issue
39
+ * #68).
40
+ */
41
+ export declare const pageLogDetailSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
42
+ export type PageLogDetail = z.infer<typeof pageLogDetailSchema>;
43
+ /** Input shape shared by `page_log.append` and the `log_page_edit` tool. */
44
+ export declare const pageLogAppendInputSchema: z.ZodObject<{
45
+ pageId: z.ZodString;
46
+ entryKind: z.ZodEnum<{
47
+ decision: "decision";
48
+ edited: "edited";
49
+ operator_answer: "operator_answer";
50
+ open_question: "open_question";
51
+ rebuilt: "rebuilt";
52
+ note: "note";
53
+ }>;
54
+ summary: z.ZodString;
55
+ detail: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
56
+ }, z.core.$strict>;
57
+ export type PageLogAppendInput = z.infer<typeof pageLogAppendInputSchema>;
58
+ /** One row as returned by `page_log.list`. */
59
+ export declare const pageLogEntrySchema: z.ZodObject<{
60
+ id: z.ZodString;
61
+ pageId: z.ZodString;
62
+ chatSessionId: z.ZodNullable<z.ZodString>;
63
+ actorKind: z.ZodEnum<{
64
+ system: "system";
65
+ human: "human";
66
+ ai: "ai";
67
+ plugin: "plugin";
68
+ }>;
69
+ entryKind: z.ZodEnum<{
70
+ decision: "decision";
71
+ edited: "edited";
72
+ operator_answer: "operator_answer";
73
+ open_question: "open_question";
74
+ rebuilt: "rebuilt";
75
+ note: "note";
76
+ }>;
77
+ summary: z.ZodString;
78
+ detail: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
79
+ createdAt: z.ZodString;
80
+ }, z.core.$strict>;
81
+ export type PageLogEntry = z.infer<typeof pageLogEntrySchema>;
82
+ /**
83
+ * Render the `## Page log` context block for a single page's recent entries
84
+ * (newest first). Returns `null` when there is nothing to show, so the
85
+ * caller omits the header entirely (CLAUDE.md §11 — render only when
86
+ * non-empty). Kept well under 2 KB: entries are capped and each summary is
87
+ * clamped, because the block rides in the system prompt on every turn that
88
+ * touches the page.
89
+ *
90
+ * @param entries page log rows, expected newest-first (as `page_log.list`
91
+ * returns them). The renderer does not re-sort.
92
+ */
93
+ export declare function formatPageLogBlock(entries: readonly PageLogEntry[]): string | null;
94
+ //# sourceMappingURL=page-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-log.d.ts","sourceRoot":"","sources":["../src/page-log.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,wFAOpB,CAAC;AAEX,eAAO,MAAM,sBAAsB;;;;;;;EAA4B,CAAC;AAChE,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,wCAAoC,CAAC;AACrE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,4EAA4E;AAC5E,eAAO,MAAM,wBAAwB;;;;;;;;;;;;kBAO1B,CAAC;AACZ,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,8CAA8C;AAC9C,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;kBAepB,CAAC;AACZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAS9D;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,GAAG,IAAI,CAyBlF"}