docs-ready 0.4.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/core/scanner.ts
4
+ import fs from "fs/promises";
5
+ import path from "path";
6
+ import matter from "gray-matter";
7
+ import { glob } from "glob";
8
+ async function scanDocs(docsDir, options) {
9
+ const resolvedDir = path.resolve(docsDir);
10
+ const allFiles = [];
11
+ for (const pattern of options.include) {
12
+ const matches = await glob(pattern, {
13
+ cwd: resolvedDir,
14
+ ignore: options.exclude,
15
+ nodir: true,
16
+ absolute: false
17
+ });
18
+ allFiles.push(...matches);
19
+ }
20
+ const uniqueFiles = [...new Set(allFiles)];
21
+ const pages = [];
22
+ for (const relativePath of uniqueFiles) {
23
+ const filePath = path.join(resolvedDir, relativePath);
24
+ const raw = await fs.readFile(filePath, "utf-8");
25
+ const { data: frontmatter, content } = matter(raw);
26
+ const title = resolveTitle(frontmatter, content, relativePath);
27
+ const description = frontmatter.description ?? null;
28
+ pages.push({
29
+ filePath,
30
+ relativePath: relativePath.replace(/\\/g, "/"),
31
+ title,
32
+ description,
33
+ frontmatter,
34
+ content
35
+ });
36
+ }
37
+ pages.sort((a, b) => {
38
+ const posA = a.frontmatter.sidebar_position ?? Infinity;
39
+ const posB = b.frontmatter.sidebar_position ?? Infinity;
40
+ if (posA !== posB) return posA - posB;
41
+ return a.relativePath.localeCompare(b.relativePath);
42
+ });
43
+ return pages;
44
+ }
45
+ function resolveTitle(frontmatter, content, relativePath) {
46
+ if (typeof frontmatter.title === "string" && frontmatter.title.trim()) {
47
+ return frontmatter.title.trim();
48
+ }
49
+ const h1Match = content.match(/^#\s+(.+)$/m);
50
+ if (h1Match) {
51
+ return h1Match[1].trim();
52
+ }
53
+ const basename = path.basename(relativePath, path.extname(relativePath));
54
+ return basename.charAt(0).toUpperCase() + basename.slice(1).replace(/[-_]/g, " ");
55
+ }
56
+
57
+ // src/utils/tokens.ts
58
+ function estimateTokens(content) {
59
+ return Math.ceil(content.length / 4);
60
+ }
61
+ function formatTokens(count) {
62
+ if (count >= 1e3) {
63
+ return `~${(count / 1e3).toFixed(1)}K tokens`;
64
+ }
65
+ return `~${count} tokens`;
66
+ }
67
+
68
+ export {
69
+ scanDocs,
70
+ estimateTokens,
71
+ formatTokens
72
+ };
73
+ //# sourceMappingURL=chunk-4NYEWEU2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/scanner.ts","../src/utils/tokens.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport matter from \"gray-matter\";\nimport { glob } from \"glob\";\n\nexport interface ScannedPage {\n filePath: string;\n relativePath: string;\n title: string;\n description: string | null;\n frontmatter: Record<string, unknown>;\n content: string;\n}\n\nexport interface ScanOptions {\n include: string[];\n exclude: string[];\n}\n\nexport async function scanDocs(docsDir: string, options: ScanOptions): Promise<ScannedPage[]> {\n const resolvedDir = path.resolve(docsDir);\n const allFiles: string[] = [];\n\n for (const pattern of options.include) {\n const matches = await glob(pattern, {\n cwd: resolvedDir,\n ignore: options.exclude,\n nodir: true,\n absolute: false,\n });\n allFiles.push(...matches);\n }\n\n const uniqueFiles = [...new Set(allFiles)];\n const pages: ScannedPage[] = [];\n\n for (const relativePath of uniqueFiles) {\n const filePath = path.join(resolvedDir, relativePath);\n const raw = await fs.readFile(filePath, \"utf-8\");\n const { data: frontmatter, content } = matter(raw);\n\n const title = resolveTitle(frontmatter, content, relativePath);\n const description = (frontmatter.description as string) ?? null;\n\n pages.push({\n filePath,\n relativePath: relativePath.replace(/\\\\/g, \"/\"),\n title,\n description,\n frontmatter,\n content,\n });\n }\n\n pages.sort((a, b) => {\n const posA = (a.frontmatter.sidebar_position as number) ?? Infinity;\n const posB = (b.frontmatter.sidebar_position as number) ?? Infinity;\n if (posA !== posB) return posA - posB;\n return a.relativePath.localeCompare(b.relativePath);\n });\n\n return pages;\n}\n\nfunction resolveTitle(\n frontmatter: Record<string, unknown>,\n content: string,\n relativePath: string\n): string {\n if (typeof frontmatter.title === \"string\" && frontmatter.title.trim()) {\n return frontmatter.title.trim();\n }\n\n const h1Match = content.match(/^#\\s+(.+)$/m);\n if (h1Match) {\n return h1Match[1].trim();\n }\n\n const basename = path.basename(relativePath, path.extname(relativePath));\n return basename.charAt(0).toUpperCase() + basename.slice(1).replace(/[-_]/g, \" \");\n}\n","/**\n * Estimate token count using chars/4 heuristic.\n * Accurate within ~15% for English technical documentation.\n */\nexport function estimateTokens(content: string): number {\n return Math.ceil(content.length / 4);\n}\n\n/**\n * Format token count for display (e.g. \"~12.5K tokens\")\n */\nexport function formatTokens(count: number): string {\n if (count >= 1000) {\n return `~${(count / 1000).toFixed(1)}K tokens`;\n }\n return `~${count} tokens`;\n}\n"],"mappings":";;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,YAAY;AACnB,SAAS,YAAY;AAgBrB,eAAsB,SAAS,SAAiB,SAA8C;AAC5F,QAAM,cAAc,KAAK,QAAQ,OAAO;AACxC,QAAM,WAAqB,CAAC;AAE5B,aAAW,WAAW,QAAQ,SAAS;AACrC,UAAM,UAAU,MAAM,KAAK,SAAS;AAAA,MAClC,KAAK;AAAA,MACL,QAAQ,QAAQ;AAAA,MAChB,OAAO;AAAA,MACP,UAAU;AAAA,IACZ,CAAC;AACD,aAAS,KAAK,GAAG,OAAO;AAAA,EAC1B;AAEA,QAAM,cAAc,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;AACzC,QAAM,QAAuB,CAAC;AAE9B,aAAW,gBAAgB,aAAa;AACtC,UAAM,WAAW,KAAK,KAAK,aAAa,YAAY;AACpD,UAAM,MAAM,MAAM,GAAG,SAAS,UAAU,OAAO;AAC/C,UAAM,EAAE,MAAM,aAAa,QAAQ,IAAI,OAAO,GAAG;AAEjD,UAAM,QAAQ,aAAa,aAAa,SAAS,YAAY;AAC7D,UAAM,cAAe,YAAY,eAA0B;AAE3D,UAAM,KAAK;AAAA,MACT;AAAA,MACA,cAAc,aAAa,QAAQ,OAAO,GAAG;AAAA,MAC7C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,KAAK,CAAC,GAAG,MAAM;AACnB,UAAM,OAAQ,EAAE,YAAY,oBAA+B;AAC3D,UAAM,OAAQ,EAAE,YAAY,oBAA+B;AAC3D,QAAI,SAAS,KAAM,QAAO,OAAO;AACjC,WAAO,EAAE,aAAa,cAAc,EAAE,YAAY;AAAA,EACpD,CAAC;AAED,SAAO;AACT;AAEA,SAAS,aACP,aACA,SACA,cACQ;AACR,MAAI,OAAO,YAAY,UAAU,YAAY,YAAY,MAAM,KAAK,GAAG;AACrE,WAAO,YAAY,MAAM,KAAK;AAAA,EAChC;AAEA,QAAM,UAAU,QAAQ,MAAM,aAAa;AAC3C,MAAI,SAAS;AACX,WAAO,QAAQ,CAAC,EAAE,KAAK;AAAA,EACzB;AAEA,QAAM,WAAW,KAAK,SAAS,cAAc,KAAK,QAAQ,YAAY,CAAC;AACvE,SAAO,SAAS,OAAO,CAAC,EAAE,YAAY,IAAI,SAAS,MAAM,CAAC,EAAE,QAAQ,SAAS,GAAG;AAClF;;;AC5EO,SAAS,eAAe,SAAyB;AACtD,SAAO,KAAK,KAAK,QAAQ,SAAS,CAAC;AACrC;AAKO,SAAS,aAAa,OAAuB;AAClD,MAAI,SAAS,KAAM;AACjB,WAAO,KAAK,QAAQ,KAAM,QAAQ,CAAC,CAAC;AAAA,EACtC;AACA,SAAO,IAAI,KAAK;AAClB;","names":[]}
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/http.ts
4
+ async function fetchWithTimeout(url, options = {}) {
5
+ const { timeout = 1e4, headers = {} } = options;
6
+ const controller = new AbortController();
7
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
8
+ try {
9
+ const response = await fetch(url, {
10
+ signal: controller.signal,
11
+ headers
12
+ });
13
+ return response;
14
+ } finally {
15
+ clearTimeout(timeoutId);
16
+ }
17
+ }
18
+ function githubHeaders() {
19
+ const headers = {
20
+ Accept: "application/vnd.github.v3+json"
21
+ };
22
+ const token = process.env.GITHUB_TOKEN;
23
+ if (token) {
24
+ headers.Authorization = `Bearer ${token}`;
25
+ }
26
+ return headers;
27
+ }
28
+
29
+ export {
30
+ fetchWithTimeout,
31
+ githubHeaders
32
+ };
33
+ //# sourceMappingURL=chunk-5XFC7QYB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/http.ts"],"sourcesContent":["export interface FetchOptions {\n timeout?: number;\n headers?: Record<string, string>;\n}\n\nexport async function fetchWithTimeout(\n url: string,\n options: FetchOptions = {}\n): Promise<Response> {\n const { timeout = 10000, headers = {} } = options;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n signal: controller.signal,\n headers,\n });\n return response;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nexport function githubHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github.v3+json\",\n };\n const token = process.env.GITHUB_TOKEN;\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n return headers;\n}\n"],"mappings":";;;AAKA,eAAsB,iBACpB,KACA,UAAwB,CAAC,GACN;AACnB,QAAM,EAAE,UAAU,KAAO,UAAU,CAAC,EAAE,IAAI;AAC1C,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO;AAE9D,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ,WAAW;AAAA,MACnB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT,UAAE;AACA,iBAAa,SAAS;AAAA,EACxB;AACF;AAEO,SAAS,gBAAwC;AACtD,QAAM,UAAkC;AAAA,IACtC,QAAQ;AAAA,EACV;AACA,QAAM,QAAQ,QAAQ,IAAI;AAC1B,MAAI,OAAO;AACT,YAAQ,gBAAgB,UAAU,KAAK;AAAA,EACzC;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/logger.ts
4
+ import chalk from "chalk";
5
+ import ora from "ora";
6
+ var currentLevel = "normal";
7
+ function setLogLevel(level) {
8
+ currentLevel = level;
9
+ }
10
+ var log = {
11
+ info: (msg) => {
12
+ if (currentLevel !== "quiet") console.log(chalk.blue("\u2139"), msg);
13
+ },
14
+ success: (msg) => {
15
+ if (currentLevel !== "quiet") console.log(chalk.green("\u2714"), msg);
16
+ },
17
+ warn: (msg) => {
18
+ console.log(chalk.yellow("\u26A0"), msg);
19
+ },
20
+ error: (msg) => {
21
+ console.error(chalk.red("\u2716"), msg);
22
+ },
23
+ dim: (msg) => {
24
+ if (currentLevel !== "quiet") console.log(chalk.dim(msg));
25
+ },
26
+ debug: (msg) => {
27
+ if (currentLevel === "verbose") console.log(chalk.gray("[debug]"), msg);
28
+ }
29
+ };
30
+ function spinner(text) {
31
+ if (currentLevel === "quiet") {
32
+ return { start: () => ({}), stop: () => ({}), succeed: () => ({}), fail: () => ({}) };
33
+ }
34
+ return ora({ text, color: "cyan" });
35
+ }
36
+
37
+ export {
38
+ setLogLevel,
39
+ log,
40
+ spinner
41
+ };
42
+ //# sourceMappingURL=chunk-PXQN4E6K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/logger.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport ora, { type Ora } from \"ora\";\n\nexport type LogLevel = \"quiet\" | \"normal\" | \"verbose\";\n\nlet currentLevel: LogLevel = \"normal\";\n\nexport function setLogLevel(level: LogLevel): void {\n currentLevel = level;\n}\n\nexport const log = {\n info: (msg: string) => {\n if (currentLevel !== \"quiet\") console.log(chalk.blue(\"ℹ\"), msg);\n },\n success: (msg: string) => {\n if (currentLevel !== \"quiet\") console.log(chalk.green(\"✔\"), msg);\n },\n warn: (msg: string) => {\n console.log(chalk.yellow(\"⚠\"), msg);\n },\n error: (msg: string) => {\n console.error(chalk.red(\"✖\"), msg);\n },\n dim: (msg: string) => {\n if (currentLevel !== \"quiet\") console.log(chalk.dim(msg));\n },\n debug: (msg: string) => {\n if (currentLevel === \"verbose\") console.log(chalk.gray(\"[debug]\"), msg);\n },\n};\n\nexport function spinner(text: string): Ora {\n if (currentLevel === \"quiet\") {\n // Return a no-op spinner\n return { start: () => ({} as Ora), stop: () => ({} as Ora), succeed: () => ({} as Ora), fail: () => ({} as Ora) } as unknown as Ora;\n }\n return ora({ text, color: \"cyan\" });\n}\n"],"mappings":";;;AAAA,OAAO,WAAW;AAClB,OAAO,SAAuB;AAI9B,IAAI,eAAyB;AAEtB,SAAS,YAAY,OAAuB;AACjD,iBAAe;AACjB;AAEO,IAAM,MAAM;AAAA,EACjB,MAAM,CAAC,QAAgB;AACrB,QAAI,iBAAiB,QAAS,SAAQ,IAAI,MAAM,KAAK,QAAG,GAAG,GAAG;AAAA,EAChE;AAAA,EACA,SAAS,CAAC,QAAgB;AACxB,QAAI,iBAAiB,QAAS,SAAQ,IAAI,MAAM,MAAM,QAAG,GAAG,GAAG;AAAA,EACjE;AAAA,EACA,MAAM,CAAC,QAAgB;AACrB,YAAQ,IAAI,MAAM,OAAO,QAAG,GAAG,GAAG;AAAA,EACpC;AAAA,EACA,OAAO,CAAC,QAAgB;AACtB,YAAQ,MAAM,MAAM,IAAI,QAAG,GAAG,GAAG;AAAA,EACnC;AAAA,EACA,KAAK,CAAC,QAAgB;AACpB,QAAI,iBAAiB,QAAS,SAAQ,IAAI,MAAM,IAAI,GAAG,CAAC;AAAA,EAC1D;AAAA,EACA,OAAO,CAAC,QAAgB;AACtB,QAAI,iBAAiB,UAAW,SAAQ,IAAI,MAAM,KAAK,SAAS,GAAG,GAAG;AAAA,EACxE;AACF;AAEO,SAAS,QAAQ,MAAmB;AACzC,MAAI,iBAAiB,SAAS;AAE5B,WAAO,EAAE,OAAO,OAAO,CAAC,IAAW,MAAM,OAAO,CAAC,IAAW,SAAS,OAAO,CAAC,IAAW,MAAM,OAAO,CAAC,GAAU;AAAA,EAClH;AACA,SAAO,IAAI,EAAE,MAAM,OAAO,OAAO,CAAC;AACpC;","names":[]}
@@ -1,72 +1,23 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ estimateTokens,
4
+ formatTokens,
5
+ scanDocs
6
+ } from "./chunk-4NYEWEU2.js";
2
7
  import {
3
8
  loadConfig
4
9
  } from "./chunk-QI2AROM3.js";
5
10
  import {
6
11
  log,
7
12
  spinner
8
- } from "./chunk-7YN54Y4Y.js";
13
+ } from "./chunk-PXQN4E6K.js";
9
14
 
10
15
  // src/cli/commands/generate.ts
11
- import fs2 from "fs/promises";
12
- import path4 from "path";
13
-
14
- // src/core/scanner.ts
15
16
  import fs from "fs/promises";
16
- import path from "path";
17
- import matter from "gray-matter";
18
- import { glob } from "glob";
19
- async function scanDocs(docsDir, options) {
20
- const resolvedDir = path.resolve(docsDir);
21
- const allFiles = [];
22
- for (const pattern of options.include) {
23
- const matches = await glob(pattern, {
24
- cwd: resolvedDir,
25
- ignore: options.exclude,
26
- nodir: true,
27
- absolute: false
28
- });
29
- allFiles.push(...matches);
30
- }
31
- const uniqueFiles = [...new Set(allFiles)];
32
- const pages = [];
33
- for (const relativePath of uniqueFiles) {
34
- const filePath = path.join(resolvedDir, relativePath);
35
- const raw = await fs.readFile(filePath, "utf-8");
36
- const { data: frontmatter, content } = matter(raw);
37
- const title = resolveTitle(frontmatter, content, relativePath);
38
- const description = frontmatter.description ?? null;
39
- pages.push({
40
- filePath,
41
- relativePath: relativePath.replace(/\\/g, "/"),
42
- title,
43
- description,
44
- frontmatter,
45
- content
46
- });
47
- }
48
- pages.sort((a, b) => {
49
- const posA = a.frontmatter.sidebar_position ?? Infinity;
50
- const posB = b.frontmatter.sidebar_position ?? Infinity;
51
- if (posA !== posB) return posA - posB;
52
- return a.relativePath.localeCompare(b.relativePath);
53
- });
54
- return pages;
55
- }
56
- function resolveTitle(frontmatter, content, relativePath) {
57
- if (typeof frontmatter.title === "string" && frontmatter.title.trim()) {
58
- return frontmatter.title.trim();
59
- }
60
- const h1Match = content.match(/^#\s+(.+)$/m);
61
- if (h1Match) {
62
- return h1Match[1].trim();
63
- }
64
- const basename = path.basename(relativePath, path.extname(relativePath));
65
- return basename.charAt(0).toUpperCase() + basename.slice(1).replace(/[-_]/g, " ");
66
- }
17
+ import path3 from "path";
67
18
 
68
19
  // src/generate/llms-txt.ts
69
- import path3 from "path";
20
+ import path2 from "path";
70
21
 
71
22
  // node_modules/balanced-match/dist/esm/index.js
72
23
  var balanced = (a, b, str) => {
@@ -312,9 +263,9 @@ var posixClasses = {
312
263
  var braceEscape = (s) => s.replace(/[[\]\\-]/g, "\\$&");
313
264
  var regexpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
314
265
  var rangesToString = (ranges) => ranges.join("");
315
- var parseClass = (glob2, position) => {
266
+ var parseClass = (glob, position) => {
316
267
  const pos = position;
317
- if (glob2.charAt(pos) !== "[") {
268
+ if (glob.charAt(pos) !== "[") {
318
269
  throw new Error("not in a brace expression");
319
270
  }
320
271
  const ranges = [];
@@ -326,8 +277,8 @@ var parseClass = (glob2, position) => {
326
277
  let negate = false;
327
278
  let endPos = pos;
328
279
  let rangeStart = "";
329
- WHILE: while (i < glob2.length) {
330
- const c = glob2.charAt(i);
280
+ WHILE: while (i < glob.length) {
281
+ const c = glob.charAt(i);
331
282
  if ((c === "!" || c === "^") && i === pos + 1) {
332
283
  negate = true;
333
284
  i++;
@@ -347,9 +298,9 @@ var parseClass = (glob2, position) => {
347
298
  }
348
299
  if (c === "[" && !escaping) {
349
300
  for (const [cls, [unip, u, neg]] of Object.entries(posixClasses)) {
350
- if (glob2.startsWith(cls, i)) {
301
+ if (glob.startsWith(cls, i)) {
351
302
  if (rangeStart) {
352
- return ["$.", false, glob2.length - pos, true];
303
+ return ["$.", false, glob.length - pos, true];
353
304
  }
354
305
  i += cls.length;
355
306
  if (neg)
@@ -372,12 +323,12 @@ var parseClass = (glob2, position) => {
372
323
  i++;
373
324
  continue;
374
325
  }
375
- if (glob2.startsWith("-]", i + 1)) {
326
+ if (glob.startsWith("-]", i + 1)) {
376
327
  ranges.push(braceEscape(c + "-"));
377
328
  i += 2;
378
329
  continue;
379
330
  }
380
- if (glob2.startsWith("-", i + 1)) {
331
+ if (glob.startsWith("-", i + 1)) {
381
332
  rangeStart = c;
382
333
  i += 2;
383
334
  continue;
@@ -389,7 +340,7 @@ var parseClass = (glob2, position) => {
389
340
  return ["", false, 0, false];
390
341
  }
391
342
  if (!ranges.length && !negs.length) {
392
- return ["$.", false, glob2.length - pos, true];
343
+ return ["$.", false, glob.length - pos, true];
393
344
  }
394
345
  if (negs.length === 0 && ranges.length === 1 && /^\\?.$/.test(ranges[0]) && !negate) {
395
346
  const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0];
@@ -797,16 +748,16 @@ var AST = class {
797
748
  toMMPattern() {
798
749
  if (this !== this.#root)
799
750
  return this.#root.toMMPattern();
800
- const glob2 = this.toString();
751
+ const glob = this.toString();
801
752
  const [re, body, hasMagic, uflag] = this.toRegExpSource();
802
- const anyMagic = hasMagic || this.#hasMagic || this.#options.nocase && !this.#options.nocaseMagicOnly && glob2.toUpperCase() !== glob2.toLowerCase();
753
+ const anyMagic = hasMagic || this.#hasMagic || this.#options.nocase && !this.#options.nocaseMagicOnly && glob.toUpperCase() !== glob.toLowerCase();
803
754
  if (!anyMagic) {
804
755
  return body;
805
756
  }
806
757
  const flags = (this.#options.nocase ? "i" : "") + (uflag ? "u" : "");
807
758
  return Object.assign(new RegExp(`^${re}$`, flags), {
808
759
  _src: re,
809
- _glob: glob2
760
+ _glob: glob
810
761
  });
811
762
  }
812
763
  get options() {
@@ -1001,13 +952,13 @@ var AST = class {
1001
952
  return re;
1002
953
  }).filter((p) => !(this.isStart() && this.isEnd()) || !!p).join("|");
1003
954
  }
1004
- static #parseGlob(glob2, hasMagic, noEmpty = false) {
955
+ static #parseGlob(glob, hasMagic, noEmpty = false) {
1005
956
  let escaping = false;
1006
957
  let re = "";
1007
958
  let uflag = false;
1008
959
  let inStar = false;
1009
- for (let i = 0; i < glob2.length; i++) {
1010
- const c = glob2.charAt(i);
960
+ for (let i = 0; i < glob.length; i++) {
961
+ const c = glob.charAt(i);
1011
962
  if (escaping) {
1012
963
  escaping = false;
1013
964
  re += (reSpecials.has(c) ? "\\" : "") + c;
@@ -1017,14 +968,14 @@ var AST = class {
1017
968
  if (inStar)
1018
969
  continue;
1019
970
  inStar = true;
1020
- re += noEmpty && /^[*]+$/.test(glob2) ? starNoEmpty : star;
971
+ re += noEmpty && /^[*]+$/.test(glob) ? starNoEmpty : star;
1021
972
  hasMagic = true;
1022
973
  continue;
1023
974
  } else {
1024
975
  inStar = false;
1025
976
  }
1026
977
  if (c === "\\") {
1027
- if (i === glob2.length - 1) {
978
+ if (i === glob.length - 1) {
1028
979
  re += "\\\\";
1029
980
  } else {
1030
981
  escaping = true;
@@ -1032,7 +983,7 @@ var AST = class {
1032
983
  continue;
1033
984
  }
1034
985
  if (c === "[") {
1035
- const [src, needUflag, consumed, magic] = parseClass(glob2, i);
986
+ const [src, needUflag, consumed, magic] = parseClass(glob, i);
1036
987
  if (consumed) {
1037
988
  re += src;
1038
989
  uflag = uflag || needUflag;
@@ -1048,7 +999,7 @@ var AST = class {
1048
999
  }
1049
1000
  re += regExpEscape(c);
1050
1001
  }
1051
- return [re, unescape(glob2), !!hasMagic, uflag];
1002
+ return [re, unescape(glob), !!hasMagic, uflag];
1052
1003
  }
1053
1004
  };
1054
1005
  _a = AST;
@@ -1120,11 +1071,11 @@ var qmarksTestNoExtDot = ([$0]) => {
1120
1071
  return (f) => f.length === len && f !== "." && f !== "..";
1121
1072
  };
1122
1073
  var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
1123
- var path2 = {
1074
+ var path = {
1124
1075
  win32: { sep: "\\" },
1125
1076
  posix: { sep: "/" }
1126
1077
  };
1127
- var sep = defaultPlatform === "win32" ? path2.win32.sep : path2.posix.sep;
1078
+ var sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
1128
1079
  minimatch.sep = sep;
1129
1080
  var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
1130
1081
  minimatch.GLOBSTAR = GLOBSTAR;
@@ -1945,7 +1896,7 @@ function extractFirstParagraph(content) {
1945
1896
  function groupByDirectory(pages) {
1946
1897
  const groups = /* @__PURE__ */ new Map();
1947
1898
  for (const page of pages) {
1948
- const dir = path3.dirname(page.relativePath);
1899
+ const dir = path2.dirname(page.relativePath);
1949
1900
  const topDir = dir === "." ? "." : dir.split("/")[0];
1950
1901
  if (!groups.has(topDir)) {
1951
1902
  groups.set(topDir, []);
@@ -1986,24 +1937,13 @@ ${cleaned}`);
1986
1937
  return sections.join("\n\n").trimEnd() + "\n";
1987
1938
  }
1988
1939
 
1989
- // src/utils/tokens.ts
1990
- function estimateTokens(content) {
1991
- return Math.ceil(content.length / 4);
1992
- }
1993
- function formatTokens(count) {
1994
- if (count >= 1e3) {
1995
- return `~${(count / 1e3).toFixed(1)}K tokens`;
1996
- }
1997
- return `~${count} tokens`;
1998
- }
1999
-
2000
1940
  // src/cli/commands/generate.ts
2001
1941
  async function generateCommand(options = {}) {
2002
1942
  const cwd = process.cwd();
2003
1943
  const config = await loadConfig(cwd);
2004
1944
  const spin = spinner("Scanning documentation...");
2005
1945
  spin.start();
2006
- const docsDir = path4.resolve(cwd, config.docs.dir);
1946
+ const docsDir = path3.resolve(cwd, config.docs.dir);
2007
1947
  const pages = await scanDocs(docsDir, {
2008
1948
  include: config.docs.include,
2009
1949
  exclude: config.docs.exclude
@@ -2014,7 +1954,7 @@ async function generateCommand(options = {}) {
2014
1954
  return;
2015
1955
  }
2016
1956
  log.info(`Found ${pages.length} documentation pages`);
2017
- const outputDir = path4.resolve(cwd, config.generate.output_dir);
1957
+ const outputDir = path3.resolve(cwd, config.generate.output_dir);
2018
1958
  if (config.generate.llms_txt && options.only !== "llms-full") {
2019
1959
  const llmsTxt = generateLlmsTxt(pages, {
2020
1960
  title: config.title,
@@ -2026,8 +1966,8 @@ async function generateCommand(options = {}) {
2026
1966
  log.info("[dry-run] Would write llms.txt");
2027
1967
  log.dim(` ${llmsTxt.length} chars, ${formatTokens(estimateTokens(llmsTxt))}`);
2028
1968
  } else {
2029
- await fs2.mkdir(outputDir, { recursive: true });
2030
- await fs2.writeFile(path4.join(outputDir, "llms.txt"), llmsTxt, "utf-8");
1969
+ await fs.mkdir(outputDir, { recursive: true });
1970
+ await fs.writeFile(path3.join(outputDir, "llms.txt"), llmsTxt, "utf-8");
2031
1971
  log.success(`Generated llms.txt (${formatTokens(estimateTokens(llmsTxt))})`);
2032
1972
  }
2033
1973
  }
@@ -2037,8 +1977,8 @@ async function generateCommand(options = {}) {
2037
1977
  log.info("[dry-run] Would write llms-full.txt");
2038
1978
  log.dim(` ${llmsFullTxt.length} chars, ${formatTokens(estimateTokens(llmsFullTxt))}`);
2039
1979
  } else {
2040
- await fs2.mkdir(outputDir, { recursive: true });
2041
- await fs2.writeFile(path4.join(outputDir, "llms-full.txt"), llmsFullTxt, "utf-8");
1980
+ await fs.mkdir(outputDir, { recursive: true });
1981
+ await fs.writeFile(path3.join(outputDir, "llms-full.txt"), llmsFullTxt, "utf-8");
2042
1982
  log.success(`Generated llms-full.txt (${formatTokens(estimateTokens(llmsFullTxt))})`);
2043
1983
  }
2044
1984
  }
@@ -2059,13 +1999,27 @@ async function generateCommand(options = {}) {
2059
1999
  log.info("[dry-run] Would write ai-context.md");
2060
2000
  log.dim(` ${aiContext.length} chars, ${formatTokens(estimateTokens(aiContext))}`);
2061
2001
  } else {
2062
- await fs2.mkdir(outputDir, { recursive: true });
2063
- await fs2.writeFile(path4.join(outputDir, "ai-context.md"), aiContext, "utf-8");
2002
+ await fs.mkdir(outputDir, { recursive: true });
2003
+ await fs.writeFile(path3.join(outputDir, "ai-context.md"), aiContext, "utf-8");
2064
2004
  log.success(`Generated ai-context.md (${formatTokens(estimateTokens(aiContext))})`);
2065
2005
  }
2066
2006
  }
2007
+ if (options.watch) {
2008
+ log.info("Watching for changes... (press Ctrl+C to stop)");
2009
+ const { watchDocs } = await import("./watcher-TAYSGKGV.js");
2010
+ watchDocs({
2011
+ dir: docsDir,
2012
+ patterns: config.docs.include,
2013
+ onChange: async () => {
2014
+ log.info("Changes detected, regenerating...");
2015
+ await generateCommand({ ...options, watch: false });
2016
+ }
2017
+ });
2018
+ await new Promise(() => {
2019
+ });
2020
+ }
2067
2021
  }
2068
2022
  export {
2069
2023
  generateCommand
2070
2024
  };
2071
- //# sourceMappingURL=generate-N54SEQ7E.js.map
2025
+ //# sourceMappingURL=generate-2KF6X5GF.js.map