@hagicode/hagilight 0.9.5 → 0.9.7-dev.111.1.899dd08

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.
package/README.md CHANGED
@@ -49,6 +49,30 @@ The values come from `HAGILIGHT_BUILD_BRANCH` and `HAGILIGHT_BUILD_COMMIT`, then
49
49
 
50
50
  `github.head_ref` is set on pull requests and `github.ref_name` on pushes. A shallow clone still reports its commit, because `git rev-parse HEAD` reads the checkout.
51
51
 
52
+ ## llms.txt
53
+
54
+ `hagilight()` writes `/llms.txt` after the build, following the [llms.txt](https://llmstxt.org/) layout: the site name as the H1, the home page description as a blockquote summary, and one H2 section of links per top-level path segment. It is generated from the built HTML, so it works for plain Astro and Starlight sites alike and needs no content collection.
55
+
56
+ - Only one language is listed: the Astro `i18n.defaultLocale`, then the home page language. The home pages of the other languages go under `## Optional`.
57
+ - Pages are left out when they are `noindex`, instant redirects, 404 pages, or declare a canonical URL for another page.
58
+ - Each link carries the page's meta description. A description repeated on three or more pages is treated as a site-wide default and left out of the links.
59
+ - Section order is Overview first, then by page count. A section lists 12 links (Overview 36) and the file lists at most 120.
60
+ - An `llms.txt` that the site already provides, as a public file or a page, is never overwritten. `hagilight({ enabled: false })` skips generation too.
61
+
62
+ ```js
63
+ hagilight({
64
+ llms: {
65
+ title: 'Example Docs', // default: the home page og:site_name
66
+ summary: 'What this site is.', // default: the home page description
67
+ lang: 'en-US', // default: i18n.defaultLocale
68
+ maxLinksPerSection: 60, // default: 12
69
+ maxLinks: 200, // default: 120
70
+ },
71
+ });
72
+ ```
73
+
74
+ Pass `llms: false` (or `{ enabled: false }`) to opt out. The file is only as good as the page titles and descriptions it reads, so write a real `description` for important pages.
75
+
52
76
  ## Body images
53
77
 
54
78
  `hagilight()` registers the content-image plugin from `@hagicode/hagilight-core/content-images`. Markdown and MDX body images then get `loading="lazy"`, `decoding="async"`, and the class `hagilight-content-image`, with the author's values kept. This registration does not depend on `enabled`, so `hagilight({ enabled: false })` still registers the plugin.
@@ -21,6 +21,26 @@ export interface HagilightOptions {
21
21
  * Independent of `enabled`, which controls only sitemap and robots.
22
22
  */
23
23
  contentImages?: boolean | HagilightContentImagesOptions;
24
+ /**
25
+ * Generate `/llms.txt` after the build from the built pages. Defaults to `true`; `false` or
26
+ * `{ enabled: false }` opts out. A site-provided `llms.txt` (public file or page) is never
27
+ * overwritten. It also follows `enabled`: `hagilight({ enabled: false })` skips it.
28
+ */
29
+ llms?: boolean | HagilightLlmsOptions;
30
+ }
31
+ export interface HagilightLlmsOptions {
32
+ /** Defaults to `true`. */
33
+ enabled?: boolean;
34
+ /** Site name for the H1. Defaults to the home page `og:site_name` or title. */
35
+ title?: string;
36
+ /** Summary blockquote. Defaults to the home page description. */
37
+ summary?: string;
38
+ /** Language to list, for example `en-US`. Defaults to the Astro default locale, then the home page language. */
39
+ lang?: string;
40
+ /** Maximum links per section. Defaults to 12. */
41
+ maxLinksPerSection?: number;
42
+ /** Maximum links in total. Defaults to 120. */
43
+ maxLinks?: number;
24
44
  }
25
45
  export interface HagilightContentImagesOptions {
26
46
  /** Defaults to `true`. */
@@ -39,6 +59,6 @@ export type HagilightFaviconOptions = FaviconOptions;
39
59
  * owns sitemap generation, a consumer-owned robots page or public file takes
40
60
  * precedence, and an enabled Starlight Hagilight integration owns RSS feeds.
41
61
  */
42
- export declare function hagilight({ enabled, rss, contentImages }?: HagilightOptions): AstroIntegration;
62
+ export declare function hagilight({ enabled, rss, contentImages, llms }?: HagilightOptions): AstroIntegration;
43
63
  /** Inject the bundled HagiCode favicon unless the site head already declares an icon. */
44
64
  export declare function hagilightFavicon(options?: HagilightFaviconOptions): AstroIntegration;
@@ -1,12 +1,13 @@
1
- import { existsSync, readdirSync, statSync } from 'node:fs';
1
+ import { existsSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
2
  import { fileURLToPath } from 'node:url';
3
- import { extname, isAbsolute, resolve, win32 } from 'node:path';
3
+ import { extname, isAbsolute, join, resolve, win32 } from 'node:path';
4
4
  import sitemap from '@astrojs/sitemap';
5
5
  import { resolveBuildInfo } from '@hagicode/hagilight-core/build-info-resolver';
6
6
  import { checkContentImageRegistration, registerContentImages } from '@hagicode/hagilight-core/content-images';
7
7
  import { resolveFaviconHeadEntry } from '@hagicode/hagilight-core/favicon';
8
8
  import { resolveRssLocales } from '@hagicode/hagilight-core/rss';
9
9
  import { resolvePlainAstroRssOwner } from '@hagicode/hagilight-core/rss-ownership';
10
+ import { buildLlmsTxt, parsePageMeta } from './llms.js';
10
11
  const VIRTUAL_RSS_CONFIG = 'virtual:hagilight/rss-config';
11
12
  const VIRTUAL_RSS_CONFIG_RESOLVED = `\0${VIRTUAL_RSS_CONFIG}`;
12
13
  const VIRTUAL_BUILD_INFO = 'virtual:hagilight/build-info';
@@ -51,7 +52,7 @@ const BUILTIN_RSS_FEED_SOURCE = BUILTIN_RSS_FEED.toString();
51
52
  * owns sitemap generation, a consumer-owned robots page or public file takes
52
53
  * precedence, and an enabled Starlight Hagilight integration owns RSS feeds.
53
54
  */
54
- export function hagilight({ enabled = true, rss, contentImages } = {}) {
55
+ export function hagilight({ enabled = true, rss, contentImages, llms } = {}) {
55
56
  if (typeof enabled !== 'boolean') {
56
57
  throw new TypeError('Hagilight sitemap and robots enabled option must be a boolean.');
57
58
  }
@@ -61,6 +62,7 @@ export function hagilight({ enabled = true, rss, contentImages } = {}) {
61
62
  if (isRecord(contentImages) && contentImages.enabled !== undefined && typeof contentImages.enabled !== 'boolean') {
62
63
  throw new TypeError('Hagilight content images enabled option must be a boolean.');
63
64
  }
65
+ const llmsOptions = resolveLlmsOptions(llms);
64
66
  const contentImagesEnabled = typeof contentImages === 'boolean' ? contentImages : contentImages?.enabled !== false;
65
67
  if (rss !== undefined && typeof rss !== 'boolean' && !isRecord(rss)) {
66
68
  throw new TypeError('Hagilight RSS option must be a boolean or an options object.');
@@ -73,6 +75,7 @@ export function hagilight({ enabled = true, rss, contentImages } = {}) {
73
75
  throw new TypeError('Hagilight RSS getFeed must be a non-empty module path.');
74
76
  }
75
77
  }
78
+ let resolvedConfig;
76
79
  return {
77
80
  name: '@hagicode/hagilight:discovery',
78
81
  hooks: {
@@ -130,11 +133,79 @@ export function hagilight({ enabled = true, rss, contentImages } = {}) {
130
133
  });
131
134
  },
132
135
  'astro:config:done'({ config, logger }) {
136
+ resolvedConfig = config;
133
137
  checkContentImageRegistration({ config, logger, enabled: contentImagesEnabled });
134
138
  },
139
+ 'astro:build:done'({ dir, pages, logger }) {
140
+ if (!enabled || !llmsOptions.enabled || !resolvedConfig)
141
+ return;
142
+ writeLlmsTxt({ config: resolvedConfig, dir, pages, options: llmsOptions, logger });
143
+ },
135
144
  },
136
145
  };
137
146
  }
147
+ function resolveLlmsOptions(llms) {
148
+ if (llms !== undefined && typeof llms !== 'boolean' && !isRecord(llms)) {
149
+ throw new TypeError('Hagilight llms option must be a boolean or an options object.');
150
+ }
151
+ if (typeof llms === 'boolean')
152
+ return { enabled: llms };
153
+ const options = llms ?? {};
154
+ if (options.enabled !== undefined && typeof options.enabled !== 'boolean') {
155
+ throw new TypeError('Hagilight llms enabled option must be a boolean.');
156
+ }
157
+ for (const key of ['title', 'summary', 'lang']) {
158
+ if (options[key] !== undefined && (typeof options[key] !== 'string' || !options[key].trim())) {
159
+ throw new TypeError(`Hagilight llms ${key} must be a non-empty string.`);
160
+ }
161
+ }
162
+ for (const key of ['maxLinksPerSection', 'maxLinks']) {
163
+ if (options[key] !== undefined && (!Number.isInteger(options[key]) || options[key] < 1)) {
164
+ throw new TypeError(`Hagilight llms ${key} must be a positive integer.`);
165
+ }
166
+ }
167
+ return { ...options, enabled: options.enabled !== false };
168
+ }
169
+ function writeLlmsTxt({ config, dir, pages, options, logger }) {
170
+ const outDir = fileURLToPath(dir);
171
+ const target = join(outDir, 'llms.txt');
172
+ if (existsSync(target)) {
173
+ logger.info('llms.txt already exists in the build output; leaving it untouched.');
174
+ return;
175
+ }
176
+ const base = `${config.base || '/'}`.replace(/\/?$/u, '/');
177
+ const siteBase = new URL(base, config.site);
178
+ const i18n = config.i18n;
179
+ const entries = [];
180
+ for (const { pathname } of pages) {
181
+ const relative = pathname.replace(/^\/+/u, '');
182
+ const candidates = relative === '' || relative.endsWith('/')
183
+ ? [join(outDir, relative, 'index.html')]
184
+ : [join(outDir, relative, 'index.html'), join(outDir, `${relative}.html`)];
185
+ const file = candidates.find((candidate) => existsSync(candidate) && statSync(candidate).isFile());
186
+ if (!file)
187
+ continue;
188
+ const url = new URL(relative, siteBase).href;
189
+ const meta = parsePageMeta(readFileSync(file, 'utf8'), url);
190
+ if (!meta)
191
+ continue;
192
+ entries.push({ path: new URL(url).pathname.slice(siteBase.pathname.length - 1), url, lang: meta.lang, title: meta.title, description: meta.description, siteName: meta.siteName });
193
+ }
194
+ const body = buildLlmsTxt({
195
+ pages: entries,
196
+ title: options.title,
197
+ summary: options.summary,
198
+ lang: options.lang ?? i18n?.defaultLocale,
199
+ maxLinksPerSection: options.maxLinksPerSection,
200
+ maxLinks: options.maxLinks,
201
+ });
202
+ if (!body) {
203
+ logger.warn('No indexable pages were found, so llms.txt was not generated.');
204
+ return;
205
+ }
206
+ writeFileSync(target, body, 'utf8');
207
+ logger.info(`Generated llms.txt from ${entries.length} page(s).`);
208
+ }
138
209
  function deriveRssLocales(locales, config) {
139
210
  if (locales !== undefined)
140
211
  return locales;
package/dist/llms.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * `llms.txt` generation. The file is derived from the built HTML so it works for every site
3
+ * type (plain Astro, Starlight) without depending on content collections: each indexable page
4
+ * contributes its `<title>` and meta description, grouped by its first path segment.
5
+ * Format: https://llmstxt.org/ (H1 name, blockquote summary, H2 link sections).
6
+ */
7
+ export interface LlmsPage {
8
+ /** Path relative to the site root, with a leading slash, for example `/guides/install/`. */
9
+ path: string;
10
+ url: string;
11
+ lang: string | undefined;
12
+ title: string;
13
+ description: string | undefined;
14
+ /** The page's `og:site_name`, used to name the site and to strip the title suffix. */
15
+ siteName?: string | undefined;
16
+ }
17
+ export interface LlmsPageMeta {
18
+ lang: string | undefined;
19
+ title: string;
20
+ description: string | undefined;
21
+ siteName: string | undefined;
22
+ }
23
+ export interface BuildLlmsTxtOptions {
24
+ pages: readonly LlmsPage[];
25
+ /** Overrides the site name taken from the home page. */
26
+ title?: string;
27
+ /** Overrides the summary taken from the home page description. */
28
+ summary?: string;
29
+ /** Preferred language, for example the Astro default locale. Falls back to the home page language. */
30
+ lang?: string;
31
+ maxLinksPerSection?: number;
32
+ maxLinks?: number;
33
+ }
34
+ export declare const DEFAULT_MAX_LINKS_PER_SECTION = 12;
35
+ export declare const DEFAULT_MAX_LINKS = 120;
36
+ /**
37
+ * Read the facts `llms.txt` needs from one built page. Returns `undefined` for pages that should
38
+ * not be listed: `noindex`, instant redirects, 404 pages, and pages whose canonical URL points
39
+ * somewhere else.
40
+ */
41
+ export declare function parsePageMeta(html: string, pageUrl: string): LlmsPageMeta | undefined;
42
+ /** Build the `llms.txt` body. Returns `undefined` when there is nothing to list. */
43
+ export declare function buildLlmsTxt(options: BuildLlmsTxtOptions): string | undefined;
package/dist/llms.js ADDED
@@ -0,0 +1,183 @@
1
+ /**
2
+ * `llms.txt` generation. The file is derived from the built HTML so it works for every site
3
+ * type (plain Astro, Starlight) without depending on content collections: each indexable page
4
+ * contributes its `<title>` and meta description, grouped by its first path segment.
5
+ * Format: https://llmstxt.org/ (H1 name, blockquote summary, H2 link sections).
6
+ */
7
+ export const DEFAULT_MAX_LINKS_PER_SECTION = 12;
8
+ export const DEFAULT_MAX_LINKS = 120;
9
+ const OVERVIEW_LIMIT_FACTOR = 3;
10
+ const GENERIC_DESCRIPTION_MIN_PAGES = 3;
11
+ const LOCALE_SEGMENT = /^[a-z]{2,3}(?:-[a-z0-9]{2,8})?$/iu;
12
+ const ENTITIES = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", nbsp: ' ' };
13
+ function decodeEntities(value) {
14
+ return value.replace(/&(?:#(\d+)|#x([0-9a-f]+)|([a-z]+));/giu, (match, dec, hex, name) => {
15
+ if (dec)
16
+ return String.fromCodePoint(Number(dec));
17
+ if (hex)
18
+ return String.fromCodePoint(parseInt(hex, 16));
19
+ return ENTITIES[String(name).toLowerCase()] ?? match;
20
+ });
21
+ }
22
+ function attributes(tag) {
23
+ const result = {};
24
+ for (const [, name, double, single] of tag.matchAll(/([a-zA-Z_:][-a-zA-Z0-9_:.]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/gu)) {
25
+ result[name.toLowerCase()] = decodeEntities(double ?? single ?? '');
26
+ }
27
+ return result;
28
+ }
29
+ function clean(value) {
30
+ const text = value?.replace(/\s+/gu, ' ').trim();
31
+ return text ? text : undefined;
32
+ }
33
+ function normalizeUrl(href, base) {
34
+ try {
35
+ const url = new URL(href, base);
36
+ url.hash = '';
37
+ url.search = '';
38
+ return url.href.replace(/\/index\.html$/u, '/');
39
+ }
40
+ catch {
41
+ return undefined;
42
+ }
43
+ }
44
+ /**
45
+ * Read the facts `llms.txt` needs from one built page. Returns `undefined` for pages that should
46
+ * not be listed: `noindex`, instant redirects, 404 pages, and pages whose canonical URL points
47
+ * somewhere else.
48
+ */
49
+ export function parsePageMeta(html, pageUrl) {
50
+ const headEnd = html.indexOf('</head>');
51
+ const head = headEnd === -1 ? html : html.slice(0, headEnd);
52
+ const metas = [...head.matchAll(/<meta\b[^>]*>/giu)].map(([tag]) => attributes(tag));
53
+ const named = (name) => metas.find((meta) => meta.name?.toLowerCase() === name)?.content;
54
+ const property = (name) => metas.find((meta) => meta.property?.toLowerCase() === name)?.content;
55
+ if (/noindex/iu.test(named('robots') ?? ''))
56
+ return undefined;
57
+ if (metas.some((meta) => meta['http-equiv']?.toLowerCase() === 'refresh'))
58
+ return undefined;
59
+ const canonicalTag = [...head.matchAll(/<link\b[^>]*>/giu)]
60
+ .map(([tag]) => attributes(tag))
61
+ .find((link) => link.rel?.toLowerCase().split(/\s+/u).includes('canonical'));
62
+ if (canonicalTag?.href) {
63
+ const canonical = normalizeUrl(canonicalTag.href, pageUrl);
64
+ const own = normalizeUrl(pageUrl, pageUrl);
65
+ // A trailing-slash difference is a site setting, not a different page.
66
+ if (canonical && own && canonical.replace(/\/$/u, '') !== own.replace(/\/$/u, ''))
67
+ return undefined;
68
+ }
69
+ const title = clean(decodeEntities(head.match(/<title[^>]*>([\s\S]*?)<\/title>/iu)?.[1] ?? ''));
70
+ if (!title || /^(?:404\b|page not found)/iu.test(title))
71
+ return undefined;
72
+ const htmlTag = html.match(/<html\b[^>]*>/iu)?.[0];
73
+ const lang = clean(htmlTag ? attributes(htmlTag).lang : undefined);
74
+ return {
75
+ lang,
76
+ title,
77
+ description: clean(named('description') ?? property('og:description')),
78
+ siteName: clean(property('og:site_name')),
79
+ };
80
+ }
81
+ function sameLanguage(a, b) {
82
+ if (!a || !b)
83
+ return false;
84
+ const x = a.toLowerCase();
85
+ const y = b.toLowerCase();
86
+ return x === y || x.startsWith(`${y}-`) || y.startsWith(`${x}-`);
87
+ }
88
+ function segmentsOf(page) {
89
+ const segments = page.path.split('/').filter(Boolean);
90
+ if (segments.length > 0 && LOCALE_SEGMENT.test(segments[0]) && (sameLanguage(segments[0], page.lang) || segments.length === 1)) {
91
+ segments.shift();
92
+ }
93
+ return segments;
94
+ }
95
+ function humanize(segment) {
96
+ const text = decodeURIComponent(segment).replace(/[-_]+/gu, ' ').trim();
97
+ return text.replace(/\b[a-z]/gu, (letter) => letter.toUpperCase());
98
+ }
99
+ function stripSiteSuffix(title, siteName) {
100
+ if (!siteName)
101
+ return title;
102
+ const escaped = siteName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
103
+ const stripped = title.replace(new RegExp(`\\s*[|•·–—-]\\s*${escaped}$`, 'iu'), '').trim();
104
+ return stripped || title;
105
+ }
106
+ function mostCommonLanguage(pages) {
107
+ const counts = new Map();
108
+ for (const page of pages)
109
+ if (page.lang)
110
+ counts.set(page.lang, (counts.get(page.lang) ?? 0) + 1);
111
+ return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))[0]?.[0];
112
+ }
113
+ function mostCommonSiteName(pages) {
114
+ const counts = new Map();
115
+ for (const page of pages)
116
+ if (page.siteName)
117
+ counts.set(page.siteName, (counts.get(page.siteName) ?? 0) + 1);
118
+ return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))[0]?.[0];
119
+ }
120
+ function linkLine(page, siteName, generic) {
121
+ const title = stripSiteSuffix(page.title, siteName).replace(/[[\]]/gu, '');
122
+ return page.description && !generic.has(page.description) ? `- [${title}](${page.url}): ${page.description}` : `- [${title}](${page.url})`;
123
+ }
124
+ /** Build the `llms.txt` body. Returns `undefined` when there is nothing to list. */
125
+ export function buildLlmsTxt(options) {
126
+ const maxPerSection = options.maxLinksPerSection ?? DEFAULT_MAX_LINKS_PER_SECTION;
127
+ const maxLinks = options.maxLinks ?? DEFAULT_MAX_LINKS;
128
+ const all = [...options.pages].sort((a, b) => a.path.localeCompare(b.path));
129
+ if (all.length === 0)
130
+ return undefined;
131
+ const shallowest = (candidates) => [...candidates].sort((a, b) => segmentsOf(a).length - segmentsOf(b).length || a.path.length - b.path.length)[0];
132
+ let lang = options.lang && all.some((page) => sameLanguage(page.lang, options.lang))
133
+ ? options.lang
134
+ : shallowest(all.filter((page) => segmentsOf(page).length === 0))?.lang ?? mostCommonLanguage(all);
135
+ if (!all.some((page) => sameLanguage(page.lang, lang)))
136
+ lang = mostCommonLanguage(all);
137
+ const inLanguage = all.filter((page) => lang === undefined || sameLanguage(page.lang, lang));
138
+ const home = shallowest(inLanguage.filter((page) => segmentsOf(page).length === 0)) ?? shallowest(inLanguage);
139
+ const siteName = clean(options.title) ?? home?.siteName ?? mostCommonSiteName(inLanguage) ?? home?.title;
140
+ const summary = clean(options.summary) ?? home?.description;
141
+ const sections = new Map();
142
+ const hasChildren = (segment) => inLanguage.some((other) => {
143
+ const parts = segmentsOf(other);
144
+ return parts[0] === segment && parts.length > 1;
145
+ });
146
+ for (const page of inLanguage) {
147
+ const segments = segmentsOf(page);
148
+ // Top-level pages without children (for example /about/) go to Overview; /guides/... goes to Guides.
149
+ const key = segments.length === 0 || (segments.length === 1 && !hasChildren(segments[0]))
150
+ ? 'Overview'
151
+ : humanize(segments[0]);
152
+ sections.set(key, [...(sections.get(key) ?? []), page]);
153
+ }
154
+ // A description repeated across pages is a site-wide default, not information about the page.
155
+ const descriptionCounts = new Map();
156
+ for (const page of inLanguage)
157
+ if (page.description)
158
+ descriptionCounts.set(page.description, (descriptionCounts.get(page.description) ?? 0) + 1);
159
+ const generic = new Set([...descriptionCounts].filter(([, count]) => count >= GENERIC_DESCRIPTION_MIN_PAGES).map(([text]) => text));
160
+ const lines = [`# ${siteName ?? 'Site'}`];
161
+ if (summary)
162
+ lines.push('', `> ${summary}`);
163
+ let remaining = maxLinks;
164
+ const ordered = [...sections.entries()].sort(([a, pa], [b, pb]) => (a === 'Overview' ? -1 : 0) - (b === 'Overview' ? -1 : 0) || pb.length - pa.length || a.localeCompare(b));
165
+ for (const [name, pages] of ordered) {
166
+ if (remaining <= 0)
167
+ break;
168
+ // Flat sites keep most pages under Overview, so it gets a larger share than a topical section.
169
+ const limit = name === 'Overview' ? maxPerSection * OVERVIEW_LIMIT_FACTOR : maxPerSection;
170
+ const picked = [...pages]
171
+ .sort((a, b) => segmentsOf(a).length - segmentsOf(b).length || a.path.localeCompare(b.path))
172
+ .slice(0, Math.min(limit, remaining));
173
+ remaining -= picked.length;
174
+ lines.push('', `## ${name}`, '', ...picked.map((page) => linkLine(page, siteName, generic)));
175
+ }
176
+ const alternates = all
177
+ .filter((page) => lang !== undefined && page.lang && !sameLanguage(page.lang, lang) && segmentsOf(page).length === 0)
178
+ .sort((a, b) => (a.lang ?? '').localeCompare(b.lang ?? ''));
179
+ if (alternates.length > 0) {
180
+ lines.push('', '## Optional', '', ...alternates.map((page) => `- [${page.lang}](${page.url})`));
181
+ }
182
+ return `${lines.join('\n')}\n`;
183
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hagicode/hagilight",
3
- "version": "0.9.5",
3
+ "version": "0.9.7-dev.111.1.899dd08",
4
4
  "type": "module",
5
5
  "description": "Astro integrations and components for HagiCode sites",
6
6
  "repository": {
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@astrojs/sitemap": "^3.7.4",
43
- "@hagicode/hagilight-core": "0.9.5"
43
+ "@hagicode/hagilight-core": "0.9.7-dev.111.1.899dd08"
44
44
  },
45
45
  "keywords": [
46
46
  "astro-component",