mdrip 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +137 -0
  2. package/dist/commands/clean.d.ts +6 -0
  3. package/dist/commands/clean.d.ts.map +1 -0
  4. package/dist/commands/clean.js +49 -0
  5. package/dist/commands/clean.js.map +1 -0
  6. package/dist/commands/fetch.d.ts +9 -0
  7. package/dist/commands/fetch.d.ts.map +1 -0
  8. package/dist/commands/fetch.js +163 -0
  9. package/dist/commands/fetch.js.map +1 -0
  10. package/dist/commands/list.d.ts +6 -0
  11. package/dist/commands/list.d.ts.map +1 -0
  12. package/dist/commands/list.js +55 -0
  13. package/dist/commands/list.js.map +1 -0
  14. package/dist/commands/remove.d.ts +5 -0
  15. package/dist/commands/remove.d.ts.map +1 -0
  16. package/dist/commands/remove.js +53 -0
  17. package/dist/commands/remove.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +74 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/lib/agents.d.ts +10 -0
  23. package/dist/lib/agents.d.ts.map +1 -0
  24. package/dist/lib/agents.js +129 -0
  25. package/dist/lib/agents.js.map +1 -0
  26. package/dist/lib/cloudflare.d.ts +17 -0
  27. package/dist/lib/cloudflare.d.ts.map +1 -0
  28. package/dist/lib/cloudflare.js +74 -0
  29. package/dist/lib/cloudflare.js.map +1 -0
  30. package/dist/lib/cloudflare.test.d.ts +2 -0
  31. package/dist/lib/cloudflare.test.d.ts.map +1 -0
  32. package/dist/lib/cloudflare.test.js +59 -0
  33. package/dist/lib/cloudflare.test.js.map +1 -0
  34. package/dist/lib/gitignore.d.ts +3 -0
  35. package/dist/lib/gitignore.d.ts.map +1 -0
  36. package/dist/lib/gitignore.js +42 -0
  37. package/dist/lib/gitignore.js.map +1 -0
  38. package/dist/lib/html-to-markdown.d.ts +3 -0
  39. package/dist/lib/html-to-markdown.d.ts.map +1 -0
  40. package/dist/lib/html-to-markdown.js +312 -0
  41. package/dist/lib/html-to-markdown.js.map +1 -0
  42. package/dist/lib/html-to-markdown.test.d.ts +2 -0
  43. package/dist/lib/html-to-markdown.test.d.ts.map +1 -0
  44. package/dist/lib/html-to-markdown.test.js +54 -0
  45. package/dist/lib/html-to-markdown.test.js.map +1 -0
  46. package/dist/lib/prompt.d.ts +5 -0
  47. package/dist/lib/prompt.d.ts.map +1 -0
  48. package/dist/lib/prompt.js +47 -0
  49. package/dist/lib/prompt.js.map +1 -0
  50. package/dist/lib/settings.d.ts +9 -0
  51. package/dist/lib/settings.d.ts.map +1 -0
  52. package/dist/lib/settings.js +42 -0
  53. package/dist/lib/settings.js.map +1 -0
  54. package/dist/lib/storage.d.ts +11 -0
  55. package/dist/lib/storage.d.ts.map +1 -0
  56. package/dist/lib/storage.js +87 -0
  57. package/dist/lib/storage.js.map +1 -0
  58. package/dist/lib/tsconfig.d.ts +4 -0
  59. package/dist/lib/tsconfig.d.ts.map +1 -0
  60. package/dist/lib/tsconfig.js +49 -0
  61. package/dist/lib/tsconfig.js.map +1 -0
  62. package/dist/lib/url.d.ts +5 -0
  63. package/dist/lib/url.d.ts.map +1 -0
  64. package/dist/lib/url.js +73 -0
  65. package/dist/lib/url.js.map +1 -0
  66. package/dist/lib/url.test.d.ts +2 -0
  67. package/dist/lib/url.test.d.ts.map +1 -0
  68. package/dist/lib/url.test.js +41 -0
  69. package/dist/lib/url.test.js.map +1 -0
  70. package/dist/types.d.ts +28 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +2 -0
  73. package/dist/types.js.map +1 -0
  74. package/package.json +58 -0
@@ -0,0 +1,129 @@
1
+ import { readFile, writeFile, rm } from "fs/promises";
2
+ import { join } from "path";
3
+ import { existsSync } from "fs";
4
+ import { ensureMdripDir } from "./settings.js";
5
+ const AGENTS_FILE = "AGENTS.md";
6
+ const MDRIP_DIR = "mdrip";
7
+ const SOURCES_FILE = "sources.json";
8
+ const SECTION_TITLE = "## Website Markdown Reference";
9
+ const SECTION_MARKER = "<!-- mdrip:start -->";
10
+ const SECTION_END_MARKER = "<!-- mdrip:end -->";
11
+ function getSectionContent() {
12
+ return `${SECTION_MARKER}
13
+
14
+ ${SECTION_TITLE}
15
+
16
+ Markdown snapshots of web pages are available in \`mdrip/\` for deeper implementation context in AI workflows.
17
+
18
+ See \`mdrip/sources.json\` for the list of available pages and metadata such as token estimates.
19
+
20
+ Use these snapshots when your agent needs structured page content instead of raw HTML.
21
+
22
+ ### Fetching Additional Pages
23
+
24
+ To fetch markdown for one or more pages, run:
25
+
26
+ \`\`\`bash
27
+ npx mdrip <url>
28
+ npx mdrip https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/
29
+ \`\`\`
30
+
31
+ ${SECTION_END_MARKER}`;
32
+ }
33
+ function getSourcesPath(cwd) {
34
+ return join(cwd, MDRIP_DIR, SOURCES_FILE);
35
+ }
36
+ function extractSection(content) {
37
+ const startIdx = content.indexOf(SECTION_MARKER);
38
+ const endIdx = content.indexOf(SECTION_END_MARKER);
39
+ if (startIdx === -1 || endIdx === -1) {
40
+ return null;
41
+ }
42
+ return content.slice(startIdx, endIdx + SECTION_END_MARKER.length);
43
+ }
44
+ export async function updatePageIndex(sources, cwd = process.cwd()) {
45
+ await ensureMdripDir(cwd);
46
+ const sourcesPath = getSourcesPath(cwd);
47
+ if (sources.pages.length === 0) {
48
+ if (existsSync(sourcesPath)) {
49
+ await rm(sourcesPath, { force: true });
50
+ }
51
+ return;
52
+ }
53
+ const index = {
54
+ updatedAt: new Date().toISOString(),
55
+ pages: sources.pages.map((page) => ({ ...page })),
56
+ };
57
+ await writeFile(sourcesPath, JSON.stringify(index, null, 2) + "\n", "utf-8");
58
+ }
59
+ export async function ensureAgentsMd(cwd = process.cwd()) {
60
+ const agentsPath = join(cwd, AGENTS_FILE);
61
+ const newSection = getSectionContent();
62
+ if (existsSync(agentsPath)) {
63
+ const content = await readFile(agentsPath, "utf-8");
64
+ if (content.includes(SECTION_MARKER)) {
65
+ const existingSection = extractSection(content);
66
+ if (existingSection === newSection) {
67
+ return false;
68
+ }
69
+ const startIdx = content.indexOf(SECTION_MARKER);
70
+ const endIdx = content.indexOf(SECTION_END_MARKER);
71
+ const before = content.slice(0, startIdx);
72
+ const after = content.slice(endIdx + SECTION_END_MARKER.length);
73
+ await writeFile(agentsPath, before + newSection + after, "utf-8");
74
+ return true;
75
+ }
76
+ let newContent = content;
77
+ if (newContent.length > 0 && !newContent.endsWith("\n")) {
78
+ newContent += "\n";
79
+ }
80
+ newContent += "\n" + newSection;
81
+ await writeFile(agentsPath, newContent, "utf-8");
82
+ return true;
83
+ }
84
+ const content = `# AGENTS.md
85
+
86
+ Instructions for AI coding agents working with this codebase.
87
+
88
+ ${newSection}
89
+ `;
90
+ await writeFile(agentsPath, content, "utf-8");
91
+ return true;
92
+ }
93
+ export async function removeMdripSection(cwd = process.cwd()) {
94
+ const agentsPath = join(cwd, AGENTS_FILE);
95
+ if (!existsSync(agentsPath)) {
96
+ return false;
97
+ }
98
+ try {
99
+ const content = await readFile(agentsPath, "utf-8");
100
+ if (!content.includes(SECTION_MARKER)) {
101
+ return false;
102
+ }
103
+ const startIdx = content.indexOf(SECTION_MARKER);
104
+ const endIdx = content.indexOf(SECTION_END_MARKER);
105
+ if (startIdx === -1 || endIdx === -1) {
106
+ return false;
107
+ }
108
+ const before = content.slice(0, startIdx).trimEnd();
109
+ const after = content.slice(endIdx + SECTION_END_MARKER.length).trimStart();
110
+ let newContent = before;
111
+ if (after) {
112
+ newContent += "\n\n" + after;
113
+ }
114
+ newContent = newContent.replace(/\n{3,}/g, "\n\n").trim() + "\n";
115
+ await writeFile(agentsPath, newContent, "utf-8");
116
+ return true;
117
+ }
118
+ catch {
119
+ return false;
120
+ }
121
+ }
122
+ export async function updateAgentsMd(sources, cwd = process.cwd()) {
123
+ await updatePageIndex(sources, cwd);
124
+ if (sources.pages.length > 0) {
125
+ return ensureAgentsMd(cwd);
126
+ }
127
+ return removeMdripSection(cwd);
128
+ }
129
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/lib/agents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface FetchMarkdownOptions {
2
+ timeoutMs?: number;
3
+ userAgent?: string;
4
+ htmlFallback?: boolean;
5
+ fetchImpl?: typeof fetch;
6
+ }
7
+ export interface MarkdownResponse {
8
+ markdown: string;
9
+ status: number;
10
+ contentType: string;
11
+ resolvedUrl: string;
12
+ markdownTokens?: number;
13
+ contentSignal?: string;
14
+ source: "cloudflare-markdown" | "html-fallback";
15
+ }
16
+ export declare function fetchMarkdownPage(url: string, options?: FetchMarkdownOptions): Promise<MarkdownResponse>;
17
+ //# sourceMappingURL=cloudflare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/lib/cloudflare.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,qBAAqB,GAAG,eAAe,CAAC;CACjD;AAWD,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,CAAC,CA4E3B"}
@@ -0,0 +1,74 @@
1
+ import { convertHtmlToMarkdown, estimateTokenCount } from "./html-to-markdown.js";
2
+ const DEFAULT_TIMEOUT_MS = 30_000;
3
+ const DEFAULT_ACCEPT = "text/markdown, text/html;q=0.9, */*;q=0.1";
4
+ function parseTokenHeader(value) {
5
+ if (!value) {
6
+ return undefined;
7
+ }
8
+ const parsed = Number.parseInt(value, 10);
9
+ return Number.isFinite(parsed) ? parsed : undefined;
10
+ }
11
+ export async function fetchMarkdownPage(url, options = {}) {
12
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
13
+ const htmlFallback = options.htmlFallback ?? true;
14
+ const controller = new AbortController();
15
+ const fetchImpl = options.fetchImpl ?? fetch;
16
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
17
+ try {
18
+ const response = await fetchImpl(url, {
19
+ method: "GET",
20
+ headers: {
21
+ Accept: DEFAULT_ACCEPT,
22
+ "User-Agent": options.userAgent ?? "mdrip-cli",
23
+ },
24
+ redirect: "follow",
25
+ signal: controller.signal,
26
+ });
27
+ if (!response.ok) {
28
+ throw new Error(`Request failed: ${response.status} ${response.statusText}`);
29
+ }
30
+ const contentType = response.headers.get("content-type") || "";
31
+ const normalizedType = contentType.toLowerCase();
32
+ if (normalizedType.includes("text/markdown")) {
33
+ const markdown = await response.text();
34
+ return {
35
+ markdown,
36
+ status: response.status,
37
+ contentType,
38
+ resolvedUrl: response.url || url,
39
+ markdownTokens: parseTokenHeader(response.headers.get("x-markdown-tokens")),
40
+ contentSignal: response.headers.get("content-signal") || undefined,
41
+ source: "cloudflare-markdown",
42
+ };
43
+ }
44
+ const isHtmlResponse = normalizedType.includes("text/html") ||
45
+ normalizedType.includes("application/xhtml+xml");
46
+ if (isHtmlResponse && htmlFallback) {
47
+ const html = await response.text();
48
+ const markdown = convertHtmlToMarkdown(html, response.url || url);
49
+ return {
50
+ markdown,
51
+ status: response.status,
52
+ contentType,
53
+ resolvedUrl: response.url || url,
54
+ markdownTokens: estimateTokenCount(markdown),
55
+ contentSignal: response.headers.get("content-signal") || undefined,
56
+ source: "html-fallback",
57
+ };
58
+ }
59
+ if (isHtmlResponse && !htmlFallback) {
60
+ throw new Error(`Expected text/markdown but received "${contentType || "unknown"}". Use HTML fallback (default) or remove --no-html-fallback.`);
61
+ }
62
+ throw new Error(`Expected text/markdown but received "${contentType || "unknown"}". Response type is not convertible by HTML fallback.`);
63
+ }
64
+ catch (err) {
65
+ if (err instanceof Error && err.name === "AbortError") {
66
+ throw new Error(`Request timed out after ${timeoutMs}ms`);
67
+ }
68
+ throw err;
69
+ }
70
+ finally {
71
+ clearTimeout(timeout);
72
+ }
73
+ }
74
+ //# sourceMappingURL=cloudflare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.js","sourceRoot":"","sources":["../../src/lib/cloudflare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cloudflare.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.test.d.ts","sourceRoot":"","sources":["../../src/lib/cloudflare.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { fetchMarkdownPage } from "./cloudflare.js";
3
+ describe("fetchMarkdownPage", () => {
4
+ it("uses Cloudflare markdown response when available", async () => {
5
+ const mockFetch = async () => new Response("# Hello", {
6
+ status: 200,
7
+ headers: {
8
+ "content-type": "text/markdown; charset=utf-8",
9
+ "x-markdown-tokens": "22",
10
+ "content-signal": "ai-input=yes",
11
+ },
12
+ });
13
+ const result = await fetchMarkdownPage("https://example.com", {
14
+ fetchImpl: mockFetch,
15
+ });
16
+ expect(result.source).toBe("cloudflare-markdown");
17
+ expect(result.markdown).toBe("# Hello");
18
+ expect(result.markdownTokens).toBe(22);
19
+ expect(result.contentSignal).toBe("ai-input=yes");
20
+ });
21
+ it("falls back to HTML conversion when markdown is not returned", async () => {
22
+ const mockFetch = async () => new Response("<html><body><main><h1>Welcome</h1><p>Page</p></main></body></html>", {
23
+ status: 200,
24
+ headers: {
25
+ "content-type": "text/html; charset=utf-8",
26
+ },
27
+ });
28
+ const result = await fetchMarkdownPage("https://example.com", {
29
+ fetchImpl: mockFetch,
30
+ });
31
+ expect(result.source).toBe("html-fallback");
32
+ expect(result.markdown).toContain("# Welcome");
33
+ expect(result.markdownTokens).toBeGreaterThan(0);
34
+ });
35
+ it("errors on HTML when fallback is disabled", async () => {
36
+ const mockFetch = async () => new Response("<html><body>test</body></html>", {
37
+ status: 200,
38
+ headers: {
39
+ "content-type": "text/html; charset=utf-8",
40
+ },
41
+ });
42
+ await expect(fetchMarkdownPage("https://example.com", {
43
+ fetchImpl: mockFetch,
44
+ htmlFallback: false,
45
+ })).rejects.toThrow(/Expected text\/markdown/);
46
+ });
47
+ it("errors on unsupported non-markdown content types", async () => {
48
+ const mockFetch = async () => new Response('{"ok":true}', {
49
+ status: 200,
50
+ headers: {
51
+ "content-type": "application/json",
52
+ },
53
+ });
54
+ await expect(fetchMarkdownPage("https://example.com", {
55
+ fetchImpl: mockFetch,
56
+ })).rejects.toThrow(/not convertible by HTML fallback/);
57
+ });
58
+ });
59
+ //# sourceMappingURL=cloudflare.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.test.js","sourceRoot":"","sources":["../../src/lib/cloudflare.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,SAAS,GAAiB,KAAK,IAAI,EAAE,CACzC,IAAI,QAAQ,CAAC,SAAS,EAAE;YACtB,MAAM,EAAE,GAAG;YACX,OAAO,EAAE;gBACP,cAAc,EAAE,8BAA8B;gBAC9C,mBAAmB,EAAE,IAAI;gBACzB,gBAAgB,EAAE,cAAc;aACjC;SACF,CAAC,CAAC;QAEL,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,qBAAqB,EAAE;YAC5D,SAAS,EAAE,SAAS;SACrB,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,SAAS,GAAiB,KAAK,IAAI,EAAE,CACzC,IAAI,QAAQ,CAAC,oEAAoE,EAAE;YACjF,MAAM,EAAE,GAAG;YACX,OAAO,EAAE;gBACP,cAAc,EAAE,0BAA0B;aAC3C;SACF,CAAC,CAAC;QAEL,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,qBAAqB,EAAE;YAC5D,SAAS,EAAE,SAAS;SACrB,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,SAAS,GAAiB,KAAK,IAAI,EAAE,CACzC,IAAI,QAAQ,CAAC,gCAAgC,EAAE;YAC7C,MAAM,EAAE,GAAG;YACX,OAAO,EAAE;gBACP,cAAc,EAAE,0BAA0B;aAC3C;SACF,CAAC,CAAC;QAEL,MAAM,MAAM,CACV,iBAAiB,CAAC,qBAAqB,EAAE;YACvC,SAAS,EAAE,SAAS;YACpB,YAAY,EAAE,KAAK;SACpB,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,SAAS,GAAiB,KAAK,IAAI,EAAE,CACzC,IAAI,QAAQ,CAAC,aAAa,EAAE;YAC1B,MAAM,EAAE,GAAG;YACX,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;SACF,CAAC,CAAC;QAEL,MAAM,MAAM,CACV,iBAAiB,CAAC,qBAAqB,EAAE;YACvC,SAAS,EAAE,SAAS;SACrB,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function hasMdripEntry(cwd?: string): Promise<boolean>;
2
+ export declare function ensureGitignore(cwd?: string): Promise<boolean>;
3
+ //# sourceMappingURL=gitignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../src/lib/gitignore.ts"],"names":[],"mappings":"AAOA,wBAAsB,aAAa,CACjC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAkBlB;AAED,wBAAsB,eAAe,CACnC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAuBlB"}
@@ -0,0 +1,42 @@
1
+ import { readFile, writeFile } from "fs/promises";
2
+ import { join } from "path";
3
+ import { existsSync } from "fs";
4
+ const MDRIP_ENTRY = "mdrip/";
5
+ const MARKER_COMMENT = "# mdrip - markdown snapshots for agents";
6
+ export async function hasMdripEntry(cwd = process.cwd()) {
7
+ const gitignorePath = join(cwd, ".gitignore");
8
+ if (!existsSync(gitignorePath)) {
9
+ return false;
10
+ }
11
+ try {
12
+ const content = await readFile(gitignorePath, "utf-8");
13
+ const lines = content.split("\n");
14
+ return lines.some((line) => {
15
+ const trimmed = line.trim();
16
+ return trimmed === MDRIP_ENTRY || trimmed === "mdrip";
17
+ });
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ }
23
+ export async function ensureGitignore(cwd = process.cwd()) {
24
+ const gitignorePath = join(cwd, ".gitignore");
25
+ if (await hasMdripEntry(cwd)) {
26
+ return false;
27
+ }
28
+ let content = "";
29
+ if (existsSync(gitignorePath)) {
30
+ content = await readFile(gitignorePath, "utf-8");
31
+ if (content.length > 0 && !content.endsWith("\n")) {
32
+ content += "\n";
33
+ }
34
+ if (content.trim().length > 0) {
35
+ content += "\n";
36
+ }
37
+ }
38
+ content += `${MARKER_COMMENT}\n${MDRIP_ENTRY}\n`;
39
+ await writeFile(gitignorePath, content, "utf-8");
40
+ return true;
41
+ }
42
+ //# sourceMappingURL=gitignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../../src/lib/gitignore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAEhC,MAAM,WAAW,GAAG,QAAQ,CAAC;AAC7B,MAAM,cAAc,GAAG,yCAAyC,CAAC;AAEjE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAE9C,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAElC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,OAAO,CAAC;QACxD,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAE9C,IAAI,MAAM,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,GAAG,EAAE,CAAC;IAEjB,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACjD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAClD,OAAO,IAAI,IAAI,CAAC;QAClB,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO,IAAI,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,GAAG,cAAc,KAAK,WAAW,IAAI,CAAC;IAEjD,MAAM,SAAS,CAAC,aAAa,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function estimateTokenCount(markdown: string): number;
2
+ export declare function convertHtmlToMarkdown(html: string, baseUrl?: string): string;
3
+ //# sourceMappingURL=html-to-markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-to-markdown.d.ts","sourceRoot":"","sources":["../../src/lib/html-to-markdown.ts"],"names":[],"mappings":"AA2XA,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO3D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAiB5E"}