@dogsbay/format-astro 0.2.0-beta.5 → 0.2.0-beta.50

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.
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * Single source of truth for the `basePath` URL prefix.
3
3
  *
4
- * `basePath` is the path-under-host where docs are served. By default
5
- * it's `/docs` (every existing dogsbay site uses this); set
6
- * `site.basePath: ""` in `dogsbay.config.yml` to serve at the host
7
- * root, or `"/handbook"` (etc.) for any other prefix.
4
+ * `basePath` is the path-under-host where docs are served. The default
5
+ * is `""` (host root, matching every other SSG); set
6
+ * `site.basePath: "/docs"` in `dogsbay.config.yml` for the legacy
7
+ * "docs nested under marketing site" shape, or `"/handbook"` (etc.)
8
+ * for any other prefix. See plans/default-basepath-root.md for the
9
+ * rationale behind the default flip in v0.3.
8
10
  *
9
11
  * Every emitter that builds URLs, file paths, or rewrites links
10
12
  * reads from `AstroProjectOptions.basePath` and runs it through
@@ -22,8 +24,18 @@
22
24
  *
23
25
  * See plans/configurable-base-path.md.
24
26
  */
25
- /** Default `basePath` when no override is supplied. */
26
- export declare const DEFAULT_BASE_PATH = "/docs";
27
+ /**
28
+ * Default `basePath` when no override is supplied.
29
+ *
30
+ * Changed in v0.3 from `"/docs"` to `""` (host root) so the default
31
+ * matches the plurality of doc-site deployments (GH Pages project
32
+ * sites, `docs.acme.com` subdomains, standalone wikis) and aligns
33
+ * with peer SSGs (Astro, Next, MkDocs, Docusaurus). The `cli`'s
34
+ * `site build` emits a one-shot migration warning when this default
35
+ * is hit so users from the `/docs` era can opt in to either value
36
+ * explicitly. See plans/default-basepath-root.md.
37
+ */
38
+ export declare const DEFAULT_BASE_PATH = "";
27
39
  /**
28
40
  * Normalize a user-supplied `basePath` to canonical form.
29
41
  *
@@ -33,7 +45,7 @@ export declare const DEFAULT_BASE_PATH = "/docs";
33
45
  * non-empty prefix.
34
46
  *
35
47
  * Examples:
36
- * - `undefined` → `"/docs"` (default)
48
+ * - `undefined` → `""` (default in v0.3+; was `"/docs"` previously)
37
49
  * - `""` → `""`
38
50
  * - `"/"` → `""`
39
51
  * - `"docs"` → `"/docs"`
@@ -68,6 +80,92 @@ export declare function basePathSegments(basePath: string): string[];
68
80
  * - `joinBaseUrl("", undefined, "")` → `"/"`
69
81
  */
70
82
  export declare function joinBaseUrl(basePath: string, section: string | undefined, slug: string): string;
83
+ /**
84
+ * Prepend the normalized `basePath` onto a raw config-supplied
85
+ * `indexPath` (e.g. `/tags` from `taxonomies.tags.indexPath`),
86
+ * producing the URL prefix that components use to compose hrefs.
87
+ *
88
+ * Different from `joinBaseUrl` because it preserves absolute paths
89
+ * with internal `/` segments and does NOT add a trailing slash —
90
+ * downstream consumers do `${out}/<term>/` themselves.
91
+ *
92
+ * - `withBasePath("/docs", "/tags")` → `"/docs/tags"`
93
+ * - `withBasePath("/docs", "tags")` → `"/docs/tags"`
94
+ * - `withBasePath("", "/tags")` → `"/tags"`
95
+ * - `withBasePath("/docs", "/by-type")` → `"/docs/by-type"`
96
+ *
97
+ * Used for the URL-bearing `indexPath` baked into the taxonomy data
98
+ * file and the `tagsIndexPath` / `taxonomyIndexPaths` Astro props,
99
+ * so components like `<TagList>`, `<TaxonomyIndex>`, `<TaxonomyTerm>`,
100
+ * and `<TypeBadge>` produce hrefs that resolve under the configured
101
+ * site base. Without this prefix, taxonomy navigation 404s on any
102
+ * site with `site.basePath` set.
103
+ */
104
+ export declare function withBasePath(basePath: string, indexPath: string): string;
105
+ /**
106
+ * Parse `site.url` into its origin and path-component parts. The
107
+ * path component (if any) becomes the **urlBase** — the prefix the
108
+ * host serves dist/ at, distinct from `basePath` (which is the
109
+ * filesystem position of content within that served space).
110
+ *
111
+ * Used by emitters that need to (a) emit Astro's `base` config
112
+ * (= urlBase), (b) produce absolute URLs in sitemap / canonical /
113
+ * llms.txt (= origin + combined prefix + slug), or (c) build the
114
+ * combined prefix that internal hrefs need (`combinePrefix` below).
115
+ *
116
+ * Returns `origin` undefined when `siteUrl` is missing or unparseable
117
+ * — the caller then degrades to relative URLs (existing behavior).
118
+ *
119
+ * - `undefined` → `{ origin: undefined, urlBase: "" }`
120
+ * - `"https://example.com"` → `{ origin: "https://example.com", urlBase: "" }`
121
+ * - `"https://example.com/"` → `{ origin: "https://example.com", urlBase: "" }`
122
+ * - `"https://example.com/docs"` → `{ origin: "https://example.com", urlBase: "/docs" }`
123
+ * - `"https://example.com/docs/"` → `{ origin: "https://example.com", urlBase: "/docs" }`
124
+ * - `"https://user.github.io/dogsbay-docs"` → `{ origin: "https://user.github.io", urlBase: "/dogsbay-docs" }`
125
+ * - `"/relative-path"` → `{ origin: undefined, urlBase: "" }` (not a full URL)
126
+ *
127
+ * See plans/astro-base-from-site-url.md.
128
+ */
129
+ export declare function parseSiteUrl(siteUrl: string | undefined): {
130
+ origin: string | undefined;
131
+ urlBase: string;
132
+ };
133
+ /**
134
+ * Combine a urlBase (host subpath, from `site.url`) with a
135
+ * basePath (filesystem layout prefix, from `site.basePath`) into the
136
+ * single prefix that nav hrefs, sitemap URLs, llms.txt, and the
137
+ * link rewriter all need.
138
+ *
139
+ * Both inputs MUST already be normalized (output of `normalizeBasePath`
140
+ * or `parseSiteUrl`): empty string OR a single leading slash with no
141
+ * trailing slash. The output respects the same shape.
142
+ *
143
+ * - `combinePrefix("", "")` → `""`
144
+ * - `combinePrefix("", "/docs")` → `"/docs"`
145
+ * - `combinePrefix("/repo", "")` → `"/repo"`
146
+ * - `combinePrefix("/repo", "/docs")` → `"/repo/docs"`
147
+ * - `combinePrefix("/handbook", "/team-docs")` → `"/handbook/team-docs"`
148
+ *
149
+ * See plans/astro-base-from-site-url.md.
150
+ */
151
+ export declare function combinePrefix(urlBase: string, basePath: string): string;
152
+ /**
153
+ * One-shot resolver: given the user's `site.url` + `site.basePath`,
154
+ * return everything emitters need. Convenience wrapper around
155
+ * `parseSiteUrl` + `normalizeBasePath` + `combinePrefix` so callers
156
+ * only do the math once.
157
+ *
158
+ * Used at the boundary in cli/site-build and cli/site-init to compute
159
+ * the effective prefixes before threading them into the emit tier.
160
+ *
161
+ * See plans/astro-base-from-site-url.md.
162
+ */
163
+ export declare function resolvePrefixes(siteUrl: string | undefined, basePath: string | undefined): {
164
+ origin: string | undefined;
165
+ urlBase: string;
166
+ basePath: string;
167
+ combined: string;
168
+ };
71
169
  /**
72
170
  * Build the `currentPath` value embedded in generated `.astro` pages
73
171
  * for `getPagination` lookups. No trailing slash so it matches the
@@ -1 +1 @@
1
- {"version":3,"file":"base-path.d.ts","sourceRoot":"","sources":["../src/base-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKnE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAMR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAMR"}
1
+ {"version":3,"file":"base-path.d.ts","sourceRoot":"","sources":["../src/base-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKnE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAMR;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGxE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG;IACzD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB,CAiBA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B;IACD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CASA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAMR"}
package/dist/base-path.js CHANGED
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * Single source of truth for the `basePath` URL prefix.
3
3
  *
4
- * `basePath` is the path-under-host where docs are served. By default
5
- * it's `/docs` (every existing dogsbay site uses this); set
6
- * `site.basePath: ""` in `dogsbay.config.yml` to serve at the host
7
- * root, or `"/handbook"` (etc.) for any other prefix.
4
+ * `basePath` is the path-under-host where docs are served. The default
5
+ * is `""` (host root, matching every other SSG); set
6
+ * `site.basePath: "/docs"` in `dogsbay.config.yml` for the legacy
7
+ * "docs nested under marketing site" shape, or `"/handbook"` (etc.)
8
+ * for any other prefix. See plans/default-basepath-root.md for the
9
+ * rationale behind the default flip in v0.3.
8
10
  *
9
11
  * Every emitter that builds URLs, file paths, or rewrites links
10
12
  * reads from `AstroProjectOptions.basePath` and runs it through
@@ -22,8 +24,18 @@
22
24
  *
23
25
  * See plans/configurable-base-path.md.
24
26
  */
25
- /** Default `basePath` when no override is supplied. */
26
- export const DEFAULT_BASE_PATH = "/docs";
27
+ /**
28
+ * Default `basePath` when no override is supplied.
29
+ *
30
+ * Changed in v0.3 from `"/docs"` to `""` (host root) so the default
31
+ * matches the plurality of doc-site deployments (GH Pages project
32
+ * sites, `docs.acme.com` subdomains, standalone wikis) and aligns
33
+ * with peer SSGs (Astro, Next, MkDocs, Docusaurus). The `cli`'s
34
+ * `site build` emits a one-shot migration warning when this default
35
+ * is hit so users from the `/docs` era can opt in to either value
36
+ * explicitly. See plans/default-basepath-root.md.
37
+ */
38
+ export const DEFAULT_BASE_PATH = "";
27
39
  /**
28
40
  * Normalize a user-supplied `basePath` to canonical form.
29
41
  *
@@ -33,7 +45,7 @@ export const DEFAULT_BASE_PATH = "/docs";
33
45
  * non-empty prefix.
34
46
  *
35
47
  * Examples:
36
- * - `undefined` → `"/docs"` (default)
48
+ * - `undefined` → `""` (default in v0.3+; was `"/docs"` previously)
37
49
  * - `""` → `""`
38
50
  * - `"/"` → `""`
39
51
  * - `"docs"` → `"/docs"`
@@ -86,6 +98,123 @@ export function joinBaseUrl(basePath, section, slug) {
86
98
  parts.push(slug);
87
99
  return parts.length === 0 ? "/" : `/${parts.join("/")}/`;
88
100
  }
101
+ /**
102
+ * Prepend the normalized `basePath` onto a raw config-supplied
103
+ * `indexPath` (e.g. `/tags` from `taxonomies.tags.indexPath`),
104
+ * producing the URL prefix that components use to compose hrefs.
105
+ *
106
+ * Different from `joinBaseUrl` because it preserves absolute paths
107
+ * with internal `/` segments and does NOT add a trailing slash —
108
+ * downstream consumers do `${out}/<term>/` themselves.
109
+ *
110
+ * - `withBasePath("/docs", "/tags")` → `"/docs/tags"`
111
+ * - `withBasePath("/docs", "tags")` → `"/docs/tags"`
112
+ * - `withBasePath("", "/tags")` → `"/tags"`
113
+ * - `withBasePath("/docs", "/by-type")` → `"/docs/by-type"`
114
+ *
115
+ * Used for the URL-bearing `indexPath` baked into the taxonomy data
116
+ * file and the `tagsIndexPath` / `taxonomyIndexPaths` Astro props,
117
+ * so components like `<TagList>`, `<TaxonomyIndex>`, `<TaxonomyTerm>`,
118
+ * and `<TypeBadge>` produce hrefs that resolve under the configured
119
+ * site base. Without this prefix, taxonomy navigation 404s on any
120
+ * site with `site.basePath` set.
121
+ */
122
+ export function withBasePath(basePath, indexPath) {
123
+ const cleanIndex = indexPath.startsWith("/") ? indexPath : `/${indexPath}`;
124
+ return basePath ? `${basePath}${cleanIndex}` : cleanIndex;
125
+ }
126
+ /**
127
+ * Parse `site.url` into its origin and path-component parts. The
128
+ * path component (if any) becomes the **urlBase** — the prefix the
129
+ * host serves dist/ at, distinct from `basePath` (which is the
130
+ * filesystem position of content within that served space).
131
+ *
132
+ * Used by emitters that need to (a) emit Astro's `base` config
133
+ * (= urlBase), (b) produce absolute URLs in sitemap / canonical /
134
+ * llms.txt (= origin + combined prefix + slug), or (c) build the
135
+ * combined prefix that internal hrefs need (`combinePrefix` below).
136
+ *
137
+ * Returns `origin` undefined when `siteUrl` is missing or unparseable
138
+ * — the caller then degrades to relative URLs (existing behavior).
139
+ *
140
+ * - `undefined` → `{ origin: undefined, urlBase: "" }`
141
+ * - `"https://example.com"` → `{ origin: "https://example.com", urlBase: "" }`
142
+ * - `"https://example.com/"` → `{ origin: "https://example.com", urlBase: "" }`
143
+ * - `"https://example.com/docs"` → `{ origin: "https://example.com", urlBase: "/docs" }`
144
+ * - `"https://example.com/docs/"` → `{ origin: "https://example.com", urlBase: "/docs" }`
145
+ * - `"https://user.github.io/dogsbay-docs"` → `{ origin: "https://user.github.io", urlBase: "/dogsbay-docs" }`
146
+ * - `"/relative-path"` → `{ origin: undefined, urlBase: "" }` (not a full URL)
147
+ *
148
+ * See plans/astro-base-from-site-url.md.
149
+ */
150
+ export function parseSiteUrl(siteUrl) {
151
+ if (!siteUrl)
152
+ return { origin: undefined, urlBase: "" };
153
+ // Only accept absolute http(s) URLs as full site URLs. Anything else
154
+ // (relative paths, mailto:, tel:, …) yields no origin — emitters
155
+ // fall back to whatever they do today when site.url is missing.
156
+ if (!/^https?:\/\//i.test(siteUrl)) {
157
+ return { origin: undefined, urlBase: "" };
158
+ }
159
+ let parsed;
160
+ try {
161
+ parsed = new URL(siteUrl);
162
+ }
163
+ catch {
164
+ return { origin: undefined, urlBase: "" };
165
+ }
166
+ const origin = `${parsed.protocol}//${parsed.host}`;
167
+ const urlBase = normalizeBasePath(parsed.pathname);
168
+ return { origin, urlBase };
169
+ }
170
+ /**
171
+ * Combine a urlBase (host subpath, from `site.url`) with a
172
+ * basePath (filesystem layout prefix, from `site.basePath`) into the
173
+ * single prefix that nav hrefs, sitemap URLs, llms.txt, and the
174
+ * link rewriter all need.
175
+ *
176
+ * Both inputs MUST already be normalized (output of `normalizeBasePath`
177
+ * or `parseSiteUrl`): empty string OR a single leading slash with no
178
+ * trailing slash. The output respects the same shape.
179
+ *
180
+ * - `combinePrefix("", "")` → `""`
181
+ * - `combinePrefix("", "/docs")` → `"/docs"`
182
+ * - `combinePrefix("/repo", "")` → `"/repo"`
183
+ * - `combinePrefix("/repo", "/docs")` → `"/repo/docs"`
184
+ * - `combinePrefix("/handbook", "/team-docs")` → `"/handbook/team-docs"`
185
+ *
186
+ * See plans/astro-base-from-site-url.md.
187
+ */
188
+ export function combinePrefix(urlBase, basePath) {
189
+ // Both already normalized — concatenation is safe; no double slashes
190
+ // appear because each is empty OR starts with `/` and has no trailing.
191
+ if (!urlBase)
192
+ return basePath;
193
+ if (!basePath)
194
+ return urlBase;
195
+ return `${urlBase}${basePath}`;
196
+ }
197
+ /**
198
+ * One-shot resolver: given the user's `site.url` + `site.basePath`,
199
+ * return everything emitters need. Convenience wrapper around
200
+ * `parseSiteUrl` + `normalizeBasePath` + `combinePrefix` so callers
201
+ * only do the math once.
202
+ *
203
+ * Used at the boundary in cli/site-build and cli/site-init to compute
204
+ * the effective prefixes before threading them into the emit tier.
205
+ *
206
+ * See plans/astro-base-from-site-url.md.
207
+ */
208
+ export function resolvePrefixes(siteUrl, basePath) {
209
+ const { origin, urlBase } = parseSiteUrl(siteUrl);
210
+ const normalizedBasePath = normalizeBasePath(basePath);
211
+ return {
212
+ origin,
213
+ urlBase,
214
+ basePath: normalizedBasePath,
215
+ combined: combinePrefix(urlBase, normalizedBasePath),
216
+ };
217
+ }
89
218
  /**
90
219
  * Build the `currentPath` value embedded in generated `.astro` pages
91
220
  * for `getPagination` lookups. No trailing slash so it matches the
@@ -1 +1 @@
1
- {"version":3,"file":"base-path.js","sourceRoot":"","sources":["../src/base-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,uDAAuD;AACvD,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAyB;IACzD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,iBAAiB,CAAC;IAClD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,OAAO,IAAI,OAAO,EAAE,CAAC;AACvB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CACzB,QAAgB,EAChB,OAA2B,EAC3B,IAAY;IAEZ,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9D,IAAI,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,IAAI,IAAI,IAAI,KAAK,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAAgB,EAChB,OAA2B,EAC3B,IAAY;IAEZ,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9D,IAAI,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3B,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAC1D,CAAC"}
1
+ {"version":3,"file":"base-path.js","sourceRoot":"","sources":["../src/base-path.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,11 +2,13 @@ export { treeToAstro, escapeExpr, escapeAttr, escapeTemplate } from "./serialize
2
2
  export { detectLeadingNodes } from "./lead.js";
3
3
  export type { LeadingNodeInfo } from "./lead.js";
4
4
  export type { AstroGenResult, AstroGenOptions, AstroRenderMode } from "./serialize.js";
5
- export { DEFAULT_BASE_PATH, normalizeBasePath, basePathSegments, joinBaseUrl, buildCurrentPath, } from "./base-path.js";
5
+ export { DEFAULT_BASE_PATH, normalizeBasePath, basePathSegments, joinBaseUrl, buildCurrentPath, parseSiteUrl, combinePrefix, resolvePrefixes, } from "./base-path.js";
6
6
  export { buildLlmsTxt, buildSectionLlmsTxt, buildLlmsFullTxt, extractFirstParagraph, } from "./llms-txt.js";
7
7
  export type { BuildLlmsTxtOptions, BuildLlmsFullTxtOptions, } from "./llms-txt.js";
8
- export { exportAstroProject, emitSiteScaffold, emitSiteConfig, emitAstroPages, emitConfigDerivedFiles, emitAgentReadinessFiles, emitSwitcherMap, emitMissingTranslationStubs, } from "./project.js";
9
- export type { AstroProjectOptions, SwitcherMap } from "./project.js";
8
+ export { buildSitemap, buildSitemapIndex } from "./sitemap.js";
9
+ export type { BuildSitemapOptions } from "./sitemap.js";
10
+ export { exportAstroProject, emitSiteScaffold, emitSiteConfig, emitAstroPages, emitConfigDerivedFiles, emitAgentReadinessFiles, emitSwitcherMap, emitMissingTranslationStubs, emitPassthroughAstroPages, emitDeployArtifacts, } from "./project.js";
11
+ export type { AstroProjectOptions, SwitcherMap, PassthroughCopy, } from "./project.js";
10
12
  export { emitPluginRuntime } from "./plugins.js";
11
13
  export type { EmitPluginRuntimeOptions, PluginClientModulesGroup, PluginStylesGroup, PluginClientConfig, } from "./plugins.js";
12
14
  export { buildTaxonomyData, emitTaxonomyForName, emitTaxonomyRoutes, getPageTerms, } from "./taxonomy.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKvF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAavB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAKrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,YAAY,GACb,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKvF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAaxD,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,2BAA2B,EAC3B,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,eAAe,GAChB,MAAM,cAAc,CAAC;AAKtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,YAAY,GACb,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -8,9 +8,11 @@ export { detectLeadingNodes } from "./lead.js";
8
8
  // Base-path helpers — single source of truth for the `basePath` URL
9
9
  // prefix shared across project / nav / llms-txt / taxonomy emitters.
10
10
  // See plans/configurable-base-path.md.
11
- export { DEFAULT_BASE_PATH, normalizeBasePath, basePathSegments, joinBaseUrl, buildCurrentPath, } from "./base-path.js";
11
+ export { DEFAULT_BASE_PATH, normalizeBasePath, basePathSegments, joinBaseUrl, buildCurrentPath, parseSiteUrl, combinePrefix, resolvePrefixes, } from "./base-path.js";
12
12
  // llms.txt + llms-full.txt builders (LLM discovery files)
13
13
  export { buildLlmsTxt, buildSectionLlmsTxt, buildLlmsFullTxt, extractFirstParagraph, } from "./llms-txt.js";
14
+ // Sitemap builders (per-mount, sitemaps.org 0.9)
15
+ export { buildSitemap, buildSitemapIndex } from "./sitemap.js";
14
16
  // Project export — orchestrator + per-tier emitters
15
17
  //
16
18
  // `exportAstroProject` is the high-level entry: generates a complete
@@ -22,7 +24,7 @@ export { buildLlmsTxt, buildSectionLlmsTxt, buildLlmsFullTxt, extractFirstParagr
22
24
  // alone; `dogsbay site build` calls `emitAstroPages` +
23
25
  // `emitConfigDerivedFiles` + `emitAgentReadinessFiles`. Pure
24
26
  // `dogsbay convert --to astro` (Step 7) calls only `emitAstroPages`.
25
- export { exportAstroProject, emitSiteScaffold, emitSiteConfig, emitAstroPages, emitConfigDerivedFiles, emitAgentReadinessFiles, emitSwitcherMap, emitMissingTranslationStubs, } from "./project.js";
27
+ export { exportAstroProject, emitSiteScaffold, emitSiteConfig, emitAstroPages, emitConfigDerivedFiles, emitAgentReadinessFiles, emitSwitcherMap, emitMissingTranslationStubs, emitPassthroughAstroPages, emitDeployArtifacts, } from "./project.js";
26
28
  // Plugin runtime codegen — emits the entry, virtual config modules,
27
29
  // stylesheets, and Vite alias file each plugin needs to participate
28
30
  // in the Astro / Vite build. See plans/plugin-api.md.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErF,gEAAgE;AAChE,kEAAkE;AAClE,kEAAkE;AAClE,0BAA0B;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAI/C,oEAAoE;AACpE,qEAAqE;AACrE,uCAAuC;AACvC,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,0DAA0D;AAC1D,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAMvB,oDAAoD;AACpD,EAAE;AACF,qEAAqE;AACrE,kEAAkE;AAClE,mBAAmB;AACnB,EAAE;AACF,gEAAgE;AAChE,sEAAsE;AACtE,uDAAuD;AACvD,6DAA6D;AAC7D,qEAAqE;AACrE,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AAGtB,oEAAoE;AACpE,oEAAoE;AACpE,sDAAsD;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAQjD,kEAAkE;AAClE,uEAAuE;AACvE,0DAA0D;AAC1D,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,GACb,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErF,gEAAgE;AAChE,kEAAkE;AAClE,kEAAkE;AAClE,0BAA0B;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAI/C,oEAAoE;AACpE,qEAAqE;AACrE,uCAAuC;AACvC,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB,0DAA0D;AAC1D,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAMvB,iDAAiD;AACjD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAG/D,oDAAoD;AACpD,EAAE;AACF,qEAAqE;AACrE,kEAAkE;AAClE,mBAAmB;AACnB,EAAE;AACF,gEAAgE;AAChE,sEAAsE;AACtE,uDAAuD;AACvD,6DAA6D;AAC7D,qEAAqE;AACrE,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,2BAA2B,EAC3B,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAOtB,oEAAoE;AACpE,oEAAoE;AACpE,sDAAsD;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAQjD,kEAAkE;AAClE,uEAAuE;AACvE,0DAA0D;AAC1D,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,GACb,MAAM,eAAe,CAAC"}
@@ -35,6 +35,14 @@ export interface BuildLlmsTxtOptions {
35
35
  * Default: "Documentation".
36
36
  */
37
37
  topLevelLabel?: string;
38
+ /**
39
+ * Label for pages that exist in `pages` but are not reachable via
40
+ * `nav`. They're appended under a final section so agents see the
41
+ * full content surface even when nav curates a subset for human
42
+ * sidebars. Default: "Other pages". Set to `false` to suppress
43
+ * orphan emission entirely (matches pre-decoupling behavior).
44
+ */
45
+ otherPagesLabel?: string | false;
38
46
  }
39
47
  export interface BuildLlmsFullTxtOptions extends BuildLlmsTxtOptions {
40
48
  /**
@@ -56,8 +64,11 @@ export interface BuildLlmsFullTxtOptions extends BuildLlmsTxtOptions {
56
64
  * Layout:
57
65
  * - One `## {label}` section per top-level nav group with children.
58
66
  * - Top-level leaf nav items collected into a single
59
- * `## {topLevelLabel}` block at the end.
60
- * - External hrefs and pages not in nav are skipped.
67
+ * `## {topLevelLabel}` block.
68
+ * - Pages reachable in `pages` but absent from `nav` appended under
69
+ * a final `## {otherPagesLabel}` section. Set `otherPagesLabel`
70
+ * to `false` to suppress (e.g. when nav is the publish list).
71
+ * - External hrefs are skipped.
61
72
  */
62
73
  export declare function buildLlmsTxt(siteConfig: Pick<SiteConfig, "siteName" | "description" | "siteUrl">, nav: NavItem[], pages: ExportPage[], options?: BuildLlmsTxtOptions): string;
63
74
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"llms-txt.d.ts","sourceRoot":"","sources":["../src/llms-txt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EACV,UAAU,EAEV,OAAO,EACP,UAAU,EACV,QAAQ,EACT,MAAM,gBAAgB,CAAC;AAUxB,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IACjC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC;CAC9C;AAID;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC,EACpE,GAAG,EAAE,OAAO,EAAE,EACd,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,mBAAwB,GAChC,MAAM,CAoDR;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC,EACpD,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,mBAAwB,GAChC,MAAM,CAqBR;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC,EACpE,GAAG,EAAE,OAAO,EAAE,EACd,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,uBAA4B,GACpC,MAAM,CA8CR;AAsGD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAO9D"}
1
+ {"version":3,"file":"llms-txt.d.ts","sourceRoot":"","sources":["../src/llms-txt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EACV,UAAU,EAEV,OAAO,EACP,UAAU,EACV,QAAQ,EACT,MAAM,gBAAgB,CAAC;AAWxB,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAClC;AAED,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IACjC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC;CAC9C;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC,EACpE,GAAG,EAAE,OAAO,EAAE,EACd,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,mBAAwB,GAChC,MAAM,CA6ER;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC,EACpD,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,mBAAwB,GAChC,MAAM,CAqBR;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC,EACpE,GAAG,EAAE,OAAO,EAAE,EACd,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,uBAA4B,GACpC,MAAM,CAyDR;AAmJD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAO9D"}
package/dist/llms-txt.js CHANGED
@@ -2,6 +2,7 @@ import { DEFAULT_BASE_PATH } from "./base-path.js";
2
2
  const EXTERNAL_HREF_RE = /^(?:https?:\/\/|mailto:|tel:|#)/i;
3
3
  const DEFAULT_DESCRIPTION_LIMIT = 160;
4
4
  const DEFAULT_TOP_LEVEL_LABEL = "Documentation";
5
+ const DEFAULT_OTHER_PAGES_LABEL = "Other pages";
5
6
  // ── Public builders ─────────────────────────────────────────────
6
7
  /**
7
8
  * Build the top-level llms.txt index for a site.
@@ -9,15 +10,22 @@ const DEFAULT_TOP_LEVEL_LABEL = "Documentation";
9
10
  * Layout:
10
11
  * - One `## {label}` section per top-level nav group with children.
11
12
  * - Top-level leaf nav items collected into a single
12
- * `## {topLevelLabel}` block at the end.
13
- * - External hrefs and pages not in nav are skipped.
13
+ * `## {topLevelLabel}` block.
14
+ * - Pages reachable in `pages` but absent from `nav` appended under
15
+ * a final `## {otherPagesLabel}` section. Set `otherPagesLabel`
16
+ * to `false` to suppress (e.g. when nav is the publish list).
17
+ * - External hrefs are skipped.
14
18
  */
15
19
  export function buildLlmsTxt(siteConfig, nav, pages, options = {}) {
16
20
  const hrefPrefix = options.hrefPrefix ?? DEFAULT_BASE_PATH;
17
21
  const siteUrl = options.siteUrl ?? siteConfig.siteUrl;
18
22
  const descLimit = options.descriptionLimit ?? DEFAULT_DESCRIPTION_LIMIT;
19
23
  const topLevelLabel = options.topLevelLabel ?? DEFAULT_TOP_LEVEL_LABEL;
24
+ const otherPagesLabel = options.otherPagesLabel === undefined
25
+ ? DEFAULT_OTHER_PAGES_LABEL
26
+ : options.otherPagesLabel;
20
27
  const slugIndex = indexPagesBySlug(pages);
28
+ const emittedSlugs = new Set();
21
29
  const out = [];
22
30
  out.push(`# ${siteConfig.siteName}`);
23
31
  out.push("");
@@ -34,11 +42,11 @@ export function buildLlmsTxt(siteConfig, nav, pages, options = {}) {
34
42
  lines.push("");
35
43
  // Group's own landing page first, if it has one
36
44
  if (item.href && !EXTERNAL_HREF_RE.test(item.href)) {
37
- const entry = renderEntry(item, slugIndex, hrefPrefix, siteUrl, descLimit);
45
+ const entry = renderEntry(item, slugIndex, hrefPrefix, siteUrl, descLimit, emittedSlugs);
38
46
  if (entry)
39
47
  lines.push(entry);
40
48
  }
41
- collectEntries(item.children, slugIndex, hrefPrefix, siteUrl, descLimit, lines);
49
+ collectEntries(item.children, slugIndex, hrefPrefix, siteUrl, descLimit, lines, emittedSlugs);
42
50
  lines.push("");
43
51
  groupSections.push(lines);
44
52
  }
@@ -50,7 +58,7 @@ export function buildLlmsTxt(siteConfig, nav, pages, options = {}) {
50
58
  out.push(`## ${topLevelLabel}`);
51
59
  out.push("");
52
60
  for (const leaf of topLevelLeaves) {
53
- const entry = renderEntry(leaf, slugIndex, hrefPrefix, siteUrl, descLimit);
61
+ const entry = renderEntry(leaf, slugIndex, hrefPrefix, siteUrl, descLimit, emittedSlugs);
54
62
  if (entry)
55
63
  out.push(entry);
56
64
  }
@@ -59,6 +67,19 @@ export function buildLlmsTxt(siteConfig, nav, pages, options = {}) {
59
67
  for (const section of groupSections) {
60
68
  out.push(...section);
61
69
  }
70
+ // Orphan pass — pages that exist in `pages` but were never hit by
71
+ // the nav walk. Emit so agents see the full surface even when nav
72
+ // curates a subset (the common case: a sidebar trims internal /
73
+ // sub-utility pages, but agents still want to find them).
74
+ if (otherPagesLabel !== false) {
75
+ const orphans = collectOrphanEntries(pages, emittedSlugs, hrefPrefix, siteUrl, descLimit);
76
+ if (orphans.length > 0) {
77
+ out.push(`## ${otherPagesLabel}`);
78
+ out.push("");
79
+ out.push(...orphans);
80
+ out.push("");
81
+ }
82
+ }
62
83
  return out.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
63
84
  }
64
85
  /**
@@ -100,6 +121,16 @@ export function buildLlmsFullTxt(siteConfig, nav, pages, options = {}) {
100
121
  }
101
122
  const slugIndex = indexPagesBySlug(pages);
102
123
  const navOrder = flattenNavToSlugs(nav, hrefPrefix);
124
+ // Append page slugs not reachable from nav (sorted for stable
125
+ // output). Same rationale as buildLlmsTxt's orphan pass: the bundle
126
+ // is for agents, and curated nav usually trims internal pages that
127
+ // agents still want to read.
128
+ const seen = new Set(navOrder);
129
+ const orphanSlugs = pages
130
+ .map((p) => p.slug || "index")
131
+ .filter((s) => !seen.has(s))
132
+ .sort((a, b) => a.localeCompare(b));
133
+ const allSlugs = [...navOrder, ...orphanSlugs];
103
134
  const out = [];
104
135
  out.push(`# ${siteConfig.siteName}`);
105
136
  out.push("");
@@ -108,7 +139,7 @@ export function buildLlmsFullTxt(siteConfig, nav, pages, options = {}) {
108
139
  out.push("");
109
140
  }
110
141
  let firstPage = true;
111
- for (const slug of navOrder) {
142
+ for (const slug of allSlugs) {
112
143
  const page = slugIndex.get(slug);
113
144
  if (!page)
114
145
  continue;
@@ -133,19 +164,19 @@ export function buildLlmsFullTxt(siteConfig, nav, pages, options = {}) {
133
164
  return out.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
134
165
  }
135
166
  // ── Internals: nav walking + entry rendering ────────────────────
136
- function collectEntries(items, slugIndex, hrefPrefix, siteUrl, descLimit, out) {
167
+ function collectEntries(items, slugIndex, hrefPrefix, siteUrl, descLimit, out, emitted) {
137
168
  for (const item of items) {
138
169
  if (item.href && !EXTERNAL_HREF_RE.test(item.href)) {
139
- const entry = renderEntry(item, slugIndex, hrefPrefix, siteUrl, descLimit);
170
+ const entry = renderEntry(item, slugIndex, hrefPrefix, siteUrl, descLimit, emitted);
140
171
  if (entry)
141
172
  out.push(entry);
142
173
  }
143
174
  if (item.children) {
144
- collectEntries(item.children, slugIndex, hrefPrefix, siteUrl, descLimit, out);
175
+ collectEntries(item.children, slugIndex, hrefPrefix, siteUrl, descLimit, out, emitted);
145
176
  }
146
177
  }
147
178
  }
148
- function renderEntry(item, slugIndex, hrefPrefix, siteUrl, descLimit) {
179
+ function renderEntry(item, slugIndex, hrefPrefix, siteUrl, descLimit, emitted) {
149
180
  if (!item.href)
150
181
  return null;
151
182
  const slug = hrefToSlug(item.href, hrefPrefix);
@@ -155,10 +186,33 @@ function renderEntry(item, slugIndex, hrefPrefix, siteUrl, descLimit) {
155
186
  const label = item.label || page?.title || slug;
156
187
  const description = page ? getPageDescription(page, descLimit) : "";
157
188
  const url = absoluteUrl(`${item.href.replace(/\/$/, "")}.md`, siteUrl);
189
+ if (emitted && page)
190
+ emitted.add(slug);
158
191
  return description
159
192
  ? `- [${label}](${url}): ${description}`
160
193
  : `- [${label}](${url})`;
161
194
  }
195
+ /**
196
+ * Render entries for pages that exist but weren't reached during the
197
+ * nav walk. Sorted alphabetically by slug for stable output (nav
198
+ * order isn't meaningful for these — they're not in nav).
199
+ */
200
+ function collectOrphanEntries(pages, emitted, hrefPrefix, siteUrl, descLimit) {
201
+ const orphans = [];
202
+ const sorted = pages
203
+ .filter((p) => !emitted.has(p.slug || "index"))
204
+ .sort((a, b) => (a.slug || "index").localeCompare(b.slug || "index"));
205
+ for (const page of sorted) {
206
+ const slug = page.slug || "index";
207
+ const label = page.title || slug;
208
+ const description = getPageDescription(page, descLimit);
209
+ const url = absoluteUrl(slugToHref(slug, hrefPrefix), siteUrl);
210
+ orphans.push(description
211
+ ? `- [${label}](${url}): ${description}`
212
+ : `- [${label}](${url})`);
213
+ }
214
+ return orphans;
215
+ }
162
216
  function flattenNavToSlugs(nav, hrefPrefix) {
163
217
  const slugs = [];
164
218
  const seen = new Set();
@@ -204,8 +258,21 @@ function slugToHref(slug, hrefPrefix) {
204
258
  function absoluteUrl(path, siteUrl) {
205
259
  if (!siteUrl)
206
260
  return path;
207
- const base = siteUrl.replace(/\/$/, "");
208
- return path.startsWith("/") ? `${base}${path}` : `${base}/${path}`;
261
+ // Strip the path component from siteUrl. With the two-prefix
262
+ // model (urlBase from site.url's path drives Astro's `base`,
263
+ // basePath stays as filesystem prefix), `path` already carries
264
+ // the combined prefix. Concatenating siteUrl-with-path would
265
+ // double-count. Use only the origin.
266
+ // See plans/astro-base-from-site-url.md.
267
+ let origin;
268
+ try {
269
+ const u = new URL(siteUrl);
270
+ origin = `${u.protocol}//${u.host}`;
271
+ }
272
+ catch {
273
+ origin = siteUrl.replace(/\/$/, "");
274
+ }
275
+ return path.startsWith("/") ? `${origin}${path}` : `${origin}/${path}`;
209
276
  }
210
277
  // ── Internals: description + plain-text extraction ──────────────
211
278
  function getPageDescription(page, limit) {