mcard-js 2.1.49 → 2.1.51

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 (109) hide show
  1. package/dist/CardCollection-EMSBVZP3.js +10 -0
  2. package/dist/CardCollection-KQWR4PCV.js +10 -0
  3. package/dist/CardCollection-ORGE2XBG.js +10 -0
  4. package/dist/EngineRegistry-ABZXHZWO.js +17 -0
  5. package/dist/EngineRegistry-EIOT4MUZ.js +17 -0
  6. package/dist/EngineRegistry-IQ6EVO72.js +17 -0
  7. package/dist/EngineRegistry-PHRFXEOE.js +17 -0
  8. package/dist/IndexedDBEngine-EWA3SLAO.js +12 -0
  9. package/dist/IndexedDBEngine-FXAD42F3.js +12 -0
  10. package/dist/IndexedDBEngine-RD4447IS.js +12 -0
  11. package/dist/LLMRuntime-ARUWOX52.js +17 -0
  12. package/dist/LLMRuntime-C3XCO7WF.js +17 -0
  13. package/dist/LLMRuntime-CQ7X43QR.js +17 -0
  14. package/dist/LLMRuntime-PD45COKE.js +17 -0
  15. package/dist/LLMRuntime-QOUMLT33.js +17 -0
  16. package/dist/LLMRuntime-SZNLTHD7.js +17 -0
  17. package/dist/LLMRuntime-TVJGK2BG.js +17 -0
  18. package/dist/LambdaRuntime-25GMEJCU.js +19 -0
  19. package/dist/LambdaRuntime-7KQUMHPI.js +19 -0
  20. package/dist/LambdaRuntime-DRT7ODPC.js +19 -0
  21. package/dist/LambdaRuntime-HSREEYQG.js +19 -0
  22. package/dist/LambdaRuntime-IH7NVG6Z.js +19 -0
  23. package/dist/LambdaRuntime-MPG27FM2.js +19 -0
  24. package/dist/LambdaRuntime-ODSWIMNM.js +19 -0
  25. package/dist/LambdaRuntime-PHGRZYAW.js +19 -0
  26. package/dist/LambdaRuntime-QOEYR37L.js +19 -0
  27. package/dist/LambdaRuntime-RT33TFN2.js +19 -0
  28. package/dist/LambdaRuntime-W6TQBP5O.js +19 -0
  29. package/dist/Loader-35WSUC53.js +14 -0
  30. package/dist/Loader-STS3G4OQ.js +16 -0
  31. package/dist/Loader-W22AEM6F.js +12 -0
  32. package/dist/Loader-YBPWP43S.js +12 -0
  33. package/dist/Loader-ZYSS7B4D.js +12 -0
  34. package/dist/NetworkRuntime-KR2QITXV.js +987 -0
  35. package/dist/NetworkRuntime-S6V2CMZV.js +1575 -0
  36. package/dist/OllamaProvider-2ANW6EB2.js +9 -0
  37. package/dist/OllamaProvider-5QFJKYAC.js +9 -0
  38. package/dist/OllamaProvider-6QXJGR7V.js +9 -0
  39. package/dist/OllamaProvider-ABEEFX7M.js +9 -0
  40. package/dist/OllamaProvider-Z2CGY5LY.js +9 -0
  41. package/dist/VCard-225X42W7.js +25 -0
  42. package/dist/chunk-2APJYBH4.js +368 -0
  43. package/dist/chunk-4DFTWDRB.js +497 -0
  44. package/dist/chunk-4PBRTFSY.js +112 -0
  45. package/dist/chunk-4T3H25AP.js +299 -0
  46. package/dist/chunk-5DFXPIRL.js +42 -0
  47. package/dist/chunk-5HRZV4R3.js +217 -0
  48. package/dist/chunk-6ZRJXVJ3.js +529 -0
  49. package/dist/chunk-7N7JYGN2.js +364 -0
  50. package/dist/chunk-7QTJUGYQ.js +74 -0
  51. package/dist/chunk-7TXIPJI2.js +2360 -0
  52. package/dist/chunk-BFJUD527.js +2369 -0
  53. package/dist/chunk-CHXIVTQV.js +364 -0
  54. package/dist/chunk-DM2ABCA4.js +497 -0
  55. package/dist/chunk-DTPHGTBQ.js +275 -0
  56. package/dist/chunk-EDAJ5FO6.js +405 -0
  57. package/dist/chunk-ETJWXHKZ.js +246 -0
  58. package/dist/chunk-FLYGNPUC.js +2369 -0
  59. package/dist/chunk-FSDRDWOP.js +34 -0
  60. package/dist/chunk-GIKMCG4D.js +497 -0
  61. package/dist/chunk-IJKS3LGK.js +428 -0
  62. package/dist/chunk-JUQ2VQZA.js +428 -0
  63. package/dist/chunk-JVW4J7BY.js +2369 -0
  64. package/dist/chunk-JWTRVEC3.js +2369 -0
  65. package/dist/chunk-KJM4C65U.js +299 -0
  66. package/dist/chunk-KMC566CN.js +591 -0
  67. package/dist/chunk-KMNP6DBL.js +455 -0
  68. package/dist/chunk-LVU7O5IY.js +597 -0
  69. package/dist/chunk-M4C6RWLA.js +373 -0
  70. package/dist/chunk-NAAAKSEO.js +541 -0
  71. package/dist/chunk-NKIXLPHL.js +373 -0
  72. package/dist/chunk-NOEDMK7I.js +428 -0
  73. package/dist/chunk-NOPYSBOQ.js +2360 -0
  74. package/dist/chunk-P4G42QCY.js +2369 -0
  75. package/dist/chunk-PKLONZCF.js +253 -0
  76. package/dist/chunk-PNGECWPN.js +597 -0
  77. package/dist/chunk-PYP6T64W.js +217 -0
  78. package/dist/chunk-QFT3COE2.js +217 -0
  79. package/dist/chunk-QFZFXMNX.js +275 -0
  80. package/dist/chunk-QZGRQRJP.js +2369 -0
  81. package/dist/chunk-R3XRBAM7.js +253 -0
  82. package/dist/chunk-RYP66UMH.js +74 -0
  83. package/dist/chunk-RZIZYRLF.js +112 -0
  84. package/dist/chunk-T43V44RS.js +2369 -0
  85. package/dist/chunk-UCNVX5BZ.js +74 -0
  86. package/dist/chunk-UDF7HS4V.js +368 -0
  87. package/dist/chunk-VJPXJVEH.js +299 -0
  88. package/dist/chunk-VW3KBDK5.js +74 -0
  89. package/dist/chunk-X72XIYSN.js +364 -0
  90. package/dist/chunk-XETU7TV4.js +112 -0
  91. package/dist/chunk-Y4BT6LHA.js +368 -0
  92. package/dist/chunk-YQGB6BIA.js +2369 -0
  93. package/dist/chunk-ZEQPO3XV.js +217 -0
  94. package/dist/chunk-ZKRKWXEQ.js +2369 -0
  95. package/dist/chunk-ZMK2HTZ5.js +275 -0
  96. package/dist/constants-CLB7B6MN.js +101 -0
  97. package/dist/constants-O343SMHL.js +103 -0
  98. package/dist/constants-YPGDEX5X.js +103 -0
  99. package/dist/index.browser.cjs +11 -5
  100. package/dist/index.browser.js +12 -12
  101. package/dist/index.cjs +2358 -1896
  102. package/dist/index.d.cts +934 -776
  103. package/dist/index.d.ts +934 -776
  104. package/dist/index.js +1353 -1271
  105. package/dist/storage/SqliteNodeEngine.cjs +12 -6
  106. package/dist/storage/SqliteNodeEngine.js +4 -4
  107. package/dist/storage/SqliteWasmEngine.cjs +11 -5
  108. package/dist/storage/SqliteWasmEngine.js +4 -4
  109. package/package.json +5 -3
@@ -0,0 +1,275 @@
1
+ import {
2
+ createPage
3
+ } from "./chunk-3EIBJPNF.js";
4
+ import {
5
+ MCard
6
+ } from "./chunk-GGQCF7ZK.js";
7
+ import {
8
+ init_Handle,
9
+ validateHandle
10
+ } from "./chunk-ADV52544.js";
11
+ import {
12
+ DEFAULT_PAGE_SIZE,
13
+ INDEXEDDB_DEFAULT_DB_NAME,
14
+ INDEXEDDB_DEFAULT_DB_VERSION
15
+ } from "./chunk-PKLONZCF.js";
16
+
17
+ // src/storage/engines/IndexedDBEngine.ts
18
+ import { openDB } from "idb";
19
+ init_Handle();
20
+ var IndexedDBEngine = class {
21
+ db = null;
22
+ dbName;
23
+ constructor(dbName = INDEXEDDB_DEFAULT_DB_NAME) {
24
+ this.dbName = dbName;
25
+ }
26
+ /**
27
+ * Initialize the database connection
28
+ */
29
+ async init() {
30
+ this.db = await openDB(this.dbName, INDEXEDDB_DEFAULT_DB_VERSION, {
31
+ upgrade(db) {
32
+ if (!db.objectStoreNames.contains("cards")) {
33
+ db.createObjectStore("cards", { keyPath: "hash" });
34
+ }
35
+ if (!db.objectStoreNames.contains("handles")) {
36
+ const handleStore = db.createObjectStore("handles", { keyPath: "handle" });
37
+ handleStore.createIndex("by-hash", "currentHash");
38
+ }
39
+ if (!db.objectStoreNames.contains("handleHistory")) {
40
+ const historyStore = db.createObjectStore("handleHistory", {
41
+ keyPath: "id",
42
+ autoIncrement: true
43
+ });
44
+ historyStore.createIndex("by-handle", "handle");
45
+ }
46
+ }
47
+ });
48
+ }
49
+ ensureDb() {
50
+ if (!this.db) {
51
+ throw new Error("Database not initialized. Call init() first.");
52
+ }
53
+ return this.db;
54
+ }
55
+ // =========== Card Operations ===========
56
+ async add(card) {
57
+ const db = this.ensureDb();
58
+ await db.put("cards", {
59
+ hash: card.hash,
60
+ content: card.content,
61
+ g_time: card.g_time
62
+ });
63
+ return card.hash;
64
+ }
65
+ async get(hash) {
66
+ const db = this.ensureDb();
67
+ const record = await db.get("cards", hash);
68
+ if (!record) return null;
69
+ return MCard.fromData(record.content, record.hash, record.g_time);
70
+ }
71
+ async delete(hash) {
72
+ const db = this.ensureDb();
73
+ await db.delete("cards", hash);
74
+ }
75
+ async getPage(pageNumber, pageSize = DEFAULT_PAGE_SIZE) {
76
+ const db = this.ensureDb();
77
+ const totalItems = await db.count("cards");
78
+ const allCards = await db.getAll("cards");
79
+ const start = (pageNumber - 1) * pageSize;
80
+ const pageRecords = allCards.slice(start, start + pageSize);
81
+ const items = pageRecords.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
82
+ return createPage(items, totalItems, pageNumber, pageSize);
83
+ }
84
+ async count() {
85
+ const db = this.ensureDb();
86
+ return db.count("cards");
87
+ }
88
+ async searchByHash(hashPrefix) {
89
+ const db = this.ensureDb();
90
+ const start = hashPrefix;
91
+ const end = hashPrefix + "\uFFFF";
92
+ const range = IDBKeyRange.bound(start, end);
93
+ const records = await db.getAll("cards", range);
94
+ return records.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
95
+ }
96
+ async search(query, pageNumber, pageSize = DEFAULT_PAGE_SIZE) {
97
+ const db = this.ensureDb();
98
+ const records = await db.getAll("cards");
99
+ const decoder = new TextDecoder();
100
+ const filtered = records.filter((r) => {
101
+ try {
102
+ const text = decoder.decode(r.content);
103
+ return text.includes(query);
104
+ } catch {
105
+ return false;
106
+ }
107
+ });
108
+ const totalItems = filtered.length;
109
+ const start = (pageNumber - 1) * pageSize;
110
+ const pageItems = filtered.slice(start, start + pageSize).map((r) => MCard.fromData(r.content, r.hash, r.g_time));
111
+ return createPage(pageItems, totalItems, pageNumber, pageSize);
112
+ }
113
+ async getAll() {
114
+ const db = this.ensureDb();
115
+ const records = await db.getAll("cards");
116
+ return records.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
117
+ }
118
+ async clear() {
119
+ const db = this.ensureDb();
120
+ await db.clear("cards");
121
+ await db.clear("handles");
122
+ await db.clear("handleHistory");
123
+ }
124
+ // =========== Handle Operations ===========
125
+ async registerHandle(handle, hash) {
126
+ const db = this.ensureDb();
127
+ const normalized = validateHandle(handle);
128
+ const existing = await db.get("handles", normalized);
129
+ if (existing) {
130
+ throw new Error(`Handle '${handle}' already exists.`);
131
+ }
132
+ const now = (/* @__PURE__ */ new Date()).toISOString();
133
+ await db.put("handles", {
134
+ handle: normalized,
135
+ currentHash: hash,
136
+ createdAt: now,
137
+ updatedAt: now
138
+ });
139
+ }
140
+ async resolveHandle(handle) {
141
+ const db = this.ensureDb();
142
+ const normalized = validateHandle(handle);
143
+ const record = await db.get("handles", normalized);
144
+ return record?.currentHash ?? null;
145
+ }
146
+ async getByHandle(handle) {
147
+ const hash = await this.resolveHandle(handle);
148
+ if (!hash) return null;
149
+ return this.get(hash);
150
+ }
151
+ async updateHandle(handle, newHash) {
152
+ const db = this.ensureDb();
153
+ const normalized = validateHandle(handle);
154
+ const existing = await db.get("handles", normalized);
155
+ if (!existing) {
156
+ throw new Error(`Handle '${handle}' not found.`);
157
+ }
158
+ const previousHash = existing.currentHash;
159
+ const now = (/* @__PURE__ */ new Date()).toISOString();
160
+ await db.add("handleHistory", {
161
+ handle: normalized,
162
+ previousHash,
163
+ changedAt: now
164
+ });
165
+ await db.put("handles", {
166
+ ...existing,
167
+ currentHash: newHash,
168
+ updatedAt: now
169
+ });
170
+ return previousHash;
171
+ }
172
+ async getHandleHistory(handle) {
173
+ const db = this.ensureDb();
174
+ const normalized = validateHandle(handle);
175
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
176
+ return records.map((r) => ({ previousHash: r.previousHash, changedAt: r.changedAt })).reverse();
177
+ }
178
+ async pruneHandleHistory(handle, options = {}) {
179
+ const db = this.ensureDb();
180
+ const normalized = validateHandle(handle);
181
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
182
+ let toDelete;
183
+ if (options.deleteAll) {
184
+ toDelete = records;
185
+ } else if (options.olderThan) {
186
+ toDelete = records.filter((r) => r.changedAt < options.olderThan);
187
+ } else {
188
+ return 0;
189
+ }
190
+ const tx = db.transaction("handleHistory", "readwrite");
191
+ for (const record of toDelete) {
192
+ await tx.store.delete(record.id);
193
+ }
194
+ await tx.done;
195
+ return toDelete.length;
196
+ }
197
+ // =========== Handle Management Operations ===========
198
+ async getAllHandles() {
199
+ const db = this.ensureDb();
200
+ const records = await db.getAll("handles");
201
+ return records.map((r) => ({ handle: r.handle, hash: r.currentHash }));
202
+ }
203
+ async removeHandle(handle) {
204
+ const db = this.ensureDb();
205
+ const normalized = validateHandle(handle);
206
+ const keysToTry = normalized !== handle.trim() ? [normalized, handle.trim()] : [normalized];
207
+ const tx = db.transaction(["handles", "handleHistory"], "readwrite");
208
+ const handleStore = tx.objectStore("handles");
209
+ const historyStore = tx.objectStore("handleHistory");
210
+ for (const key of keysToTry) {
211
+ await handleStore.delete(key);
212
+ }
213
+ const historyIndex = historyStore.index("by-handle");
214
+ for (const key of keysToTry) {
215
+ let cursor = await historyIndex.openCursor(key);
216
+ while (cursor) {
217
+ await cursor.delete();
218
+ cursor = await cursor.continue();
219
+ }
220
+ }
221
+ await tx.done;
222
+ }
223
+ async renameHandle(oldHandle, newHandle) {
224
+ const db = this.ensureDb();
225
+ const normalizedOld = validateHandle(oldHandle);
226
+ const normalizedNew = validateHandle(newHandle);
227
+ if (normalizedOld === normalizedNew) return;
228
+ const oldEntry = await db.get("handles", normalizedOld);
229
+ if (!oldEntry) throw new Error(`Handle '${oldHandle}' not found.`);
230
+ const newEntry = await db.get("handles", normalizedNew);
231
+ if (newEntry) throw new Error(`Handle '${newHandle}' already exists.`);
232
+ const tx = db.transaction(["handles", "handleHistory"], "readwrite");
233
+ const handleStore = tx.objectStore("handles");
234
+ const historyStore = tx.objectStore("handleHistory");
235
+ const now = (/* @__PURE__ */ new Date()).toISOString();
236
+ await handleStore.put({
237
+ ...oldEntry,
238
+ handle: normalizedNew,
239
+ updatedAt: now
240
+ });
241
+ await handleStore.delete(normalizedOld);
242
+ const historyIndex = historyStore.index("by-handle");
243
+ let cursor = await historyIndex.openCursor(normalizedOld);
244
+ while (cursor) {
245
+ const record = cursor.value;
246
+ record.handle = normalizedNew;
247
+ await cursor.update(record);
248
+ cursor = await cursor.continue();
249
+ }
250
+ await tx.done;
251
+ }
252
+ async deleteHistoryEntry(handle, previousHash) {
253
+ const db = this.ensureDb();
254
+ const normalized = validateHandle(handle);
255
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
256
+ const entries = records.sort((a, b) => a.id - b.id);
257
+ const targetIdx = entries.findIndex((e) => e.previousHash === previousHash);
258
+ if (targetIdx === -1) return;
259
+ const target = entries[targetIdx];
260
+ const successor = entries[targetIdx + 1];
261
+ const tx = db.transaction("handleHistory", "readwrite");
262
+ const store = tx.objectStore("handleHistory");
263
+ if (successor && targetIdx > 0) {
264
+ const predecessor = entries[targetIdx - 1];
265
+ successor.previousHash = predecessor.previousHash;
266
+ await store.put(successor);
267
+ }
268
+ await store.delete(target.id);
269
+ await tx.done;
270
+ }
271
+ };
272
+
273
+ export {
274
+ IndexedDBEngine
275
+ };
@@ -0,0 +1,405 @@
1
+ import {
2
+ ContentTypeInterpreter,
3
+ MCard
4
+ } from "./chunk-GGQCF7ZK.js";
5
+ import {
6
+ MAX_FILE_SIZE,
7
+ READ_TIMEOUT_MS
8
+ } from "./chunk-R3XRBAM7.js";
9
+ import {
10
+ __export
11
+ } from "./chunk-PNKVD2UK.js";
12
+
13
+ // src/Loader.ts
14
+ var Loader_exports = {};
15
+ __export(Loader_exports, {
16
+ exportCollectionToDirectory: () => exportCollectionToDirectory,
17
+ loadFileToCollection: () => loadFileToCollection,
18
+ processAndStoreFile: () => processAndStoreFile
19
+ });
20
+ import * as fs2 from "fs/promises";
21
+ import * as path2 from "path";
22
+
23
+ // src/FileIO.ts
24
+ var FileIO_exports = {};
25
+ __export(FileIO_exports, {
26
+ getTreeHashes: () => getTreeHashes,
27
+ isProblematicFile: () => isProblematicFile,
28
+ listFiles: () => listFiles,
29
+ processFileContent: () => processFileContent,
30
+ readFileSafely: () => readFileSafely,
31
+ streamReadNormalizedText: () => streamReadNormalizedText
32
+ });
33
+ import * as crypto from "crypto";
34
+ import * as fs from "fs/promises";
35
+ import * as path from "path";
36
+ async function streamReadNormalizedText(filePath, options) {
37
+ const { byteCap, wrapWidth } = options;
38
+ const sha = crypto.createHash("sha256");
39
+ let totalSize = 0;
40
+ let producedText = "";
41
+ let currentLen = 0;
42
+ const handle = await fs.open(filePath, "r");
43
+ try {
44
+ const buffer = new Uint8Array(8192);
45
+ let remaining = byteCap;
46
+ const decoder = new TextDecoder("utf-8", { fatal: false });
47
+ let position = 0;
48
+ while (remaining > 0) {
49
+ const { bytesRead } = await handle.read(buffer, 0, Math.min(buffer.length, remaining), position);
50
+ if (bytesRead === 0) break;
51
+ position += bytesRead;
52
+ const chunk = buffer.subarray(0, bytesRead);
53
+ sha.update(chunk);
54
+ totalSize += bytesRead;
55
+ remaining -= bytesRead;
56
+ const s2 = decoder.decode(chunk, { stream: true });
57
+ for (const ch of s2) {
58
+ if (ch === "\r") continue;
59
+ producedText += ch;
60
+ if (ch === "\n") {
61
+ currentLen = 0;
62
+ } else {
63
+ currentLen++;
64
+ if (wrapWidth > 0 && currentLen >= wrapWidth) {
65
+ producedText += "\n";
66
+ currentLen = 0;
67
+ }
68
+ }
69
+ }
70
+ }
71
+ const s = decoder.decode();
72
+ for (const ch of s) {
73
+ if (ch === "\r") continue;
74
+ producedText += ch;
75
+ if (ch === "\n") {
76
+ currentLen = 0;
77
+ } else {
78
+ currentLen++;
79
+ if (wrapWidth > 0 && currentLen >= wrapWidth) {
80
+ producedText += "\n";
81
+ currentLen = 0;
82
+ }
83
+ }
84
+ }
85
+ } finally {
86
+ await handle.close();
87
+ }
88
+ return {
89
+ text: producedText,
90
+ originalSize: totalSize,
91
+ originalSha256Prefix: sha.digest("hex").substring(0, 16)
92
+ };
93
+ }
94
+ var MAX_FILE_SIZE2 = MAX_FILE_SIZE;
95
+ var READ_TIMEOUT_MS2 = READ_TIMEOUT_MS;
96
+ async function isProblematicFile(filePath) {
97
+ try {
98
+ const stats = await fs.stat(filePath);
99
+ if (stats.size === 0) return false;
100
+ if (path.basename(filePath).startsWith(".")) return true;
101
+ if (stats.size > MAX_FILE_SIZE2) return true;
102
+ const ext = path.extname(filePath);
103
+ const isKnownType = ContentTypeInterpreter.isKnownLongLineExtension(ext);
104
+ if (isKnownType && stats.size > 1024 * 1024) return true;
105
+ const handle = await fs.open(filePath, "r");
106
+ try {
107
+ const buffer = new Uint8Array(32 * 1024);
108
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
109
+ const sample = buffer.subarray(0, bytesRead);
110
+ if (ContentTypeInterpreter.isUnstructuredBinary(sample)) return true;
111
+ if (ContentTypeInterpreter.hasPathologicalLines(sample, isKnownType)) return true;
112
+ } finally {
113
+ await handle.close();
114
+ }
115
+ return false;
116
+ } catch {
117
+ return true;
118
+ }
119
+ }
120
+ async function readFileSafely(filePath, options = {}) {
121
+ const stats = await fs.stat(filePath);
122
+ if (stats.size > MAX_FILE_SIZE2) throw new Error(`File too large: ${stats.size}`);
123
+ const controller = new AbortController();
124
+ const timeout = setTimeout(() => controller.abort(), READ_TIMEOUT_MS2);
125
+ try {
126
+ const handle = await fs.open(filePath, "r");
127
+ try {
128
+ const buffer = new Uint8Array(stats.size);
129
+ await handle.read(buffer, 0, stats.size, 0);
130
+ return buffer;
131
+ } finally {
132
+ await handle.close();
133
+ }
134
+ } catch (e) {
135
+ const error = e;
136
+ if (error.name === "AbortError") throw new Error(`Read timeout for ${filePath}`);
137
+ throw e;
138
+ } finally {
139
+ clearTimeout(timeout);
140
+ }
141
+ }
142
+ async function listFiles(dirPath, recursive = false) {
143
+ let files = [];
144
+ try {
145
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
146
+ for (const entry of entries) {
147
+ const fullPath = path.join(dirPath, entry.name);
148
+ if (entry.name.startsWith(".")) continue;
149
+ if (entry.isDirectory()) {
150
+ if (recursive) {
151
+ files = files.concat(await listFiles(fullPath, true));
152
+ }
153
+ } else if (entry.isFile()) {
154
+ if (!await isProblematicFile(fullPath)) {
155
+ files.push(fullPath);
156
+ }
157
+ }
158
+ }
159
+ } catch (e) {
160
+ console.warn(`Error listing directory ${dirPath}:`, e);
161
+ }
162
+ return files;
163
+ }
164
+ async function processFileContent(filePath, options = {}) {
165
+ const rawContent = await readFileSafely(filePath, { allowPathological: options.allowPathological, maxBytes: options.maxBytes });
166
+ const sample = rawContent.subarray(0, 1024 * 1024);
167
+ const detection = ContentTypeInterpreter.detectContentType(sample, path.extname(filePath));
168
+ let isBinary = ContentTypeInterpreter.isBinaryContent(sample, detection.mimeType);
169
+ if (options.forceBinary) isBinary = true;
170
+ let content = rawContent;
171
+ if (!isBinary) {
172
+ try {
173
+ content = new TextDecoder("utf-8", { fatal: true }).decode(rawContent);
174
+ } catch {
175
+ content = new TextDecoder("utf-8", { fatal: false }).decode(rawContent);
176
+ }
177
+ }
178
+ return {
179
+ content,
180
+ filename: path.basename(filePath),
181
+ mimeType: detection.mimeType,
182
+ extension: detection.extension,
183
+ isBinary,
184
+ size: rawContent.length
185
+ };
186
+ }
187
+ async function getTreeHashes(dirPath) {
188
+ const hashes = {};
189
+ const files = await listFiles(dirPath, true);
190
+ for (const filePath of files) {
191
+ const relPath = path.relative(dirPath, filePath);
192
+ try {
193
+ const result = await processFileContent(filePath);
194
+ const sha = crypto.createHash("sha256");
195
+ if (typeof result.content === "string") {
196
+ sha.update(result.content, "utf-8");
197
+ } else {
198
+ sha.update(result.content);
199
+ }
200
+ hashes[relPath] = sha.digest("hex");
201
+ } catch (e) {
202
+ console.warn(`Failed to hash ${filePath}:`, e);
203
+ }
204
+ }
205
+ return hashes;
206
+ }
207
+
208
+ // src/Loader.ts
209
+ var DEFAULT_MAX_PROBLEM_BYTES = 2 * 1024 * 1024;
210
+ var WRAP_WIDTH_KNOWN = 1e3;
211
+ var WRAP_WIDTH_DEFAULT = 80;
212
+ var Logger = {
213
+ info: (...args) => console.log("[Loader]", ...args),
214
+ warn: (...args) => console.warn("[Loader]", ...args),
215
+ error: (...args) => console.error("[Loader]", ...args),
216
+ debug: (...args) => {
217
+ if (process.env.DEBUG) console.log("[Loader]", ...args);
218
+ }
219
+ };
220
+ async function processAndStoreFile(filePath, collection, options = {}) {
221
+ const {
222
+ allowProblematic = false,
223
+ maxBytesOnProblem = DEFAULT_MAX_PROBLEM_BYTES,
224
+ metadataOnly = false,
225
+ rootPath
226
+ } = options;
227
+ try {
228
+ let fileInfo;
229
+ if (await isProblematicFile(filePath)) {
230
+ if (!allowProblematic) {
231
+ Logger.warn(`Skipping problematic file: ${filePath}`);
232
+ return null;
233
+ }
234
+ const extension = path2.extname(filePath).toLowerCase();
235
+ const isKnownType = ContentTypeInterpreter.isKnownLongLineExtension(extension);
236
+ const wrapWidth = isKnownType ? WRAP_WIDTH_KNOWN : WRAP_WIDTH_DEFAULT;
237
+ Logger.warn(`Problematic file detected, processing as safe text: ${filePath}`);
238
+ try {
239
+ const streamed = await streamReadNormalizedText(filePath, {
240
+ byteCap: maxBytesOnProblem,
241
+ wrapWidth
242
+ });
243
+ fileInfo = {
244
+ content: streamed.text,
245
+ filename: path2.basename(filePath),
246
+ mimeType: "text/plain",
247
+ extension,
248
+ isBinary: false,
249
+ size: streamed.text.length,
250
+ originalSize: streamed.originalSize,
251
+ originalSha256Prefix: streamed.originalSha256Prefix,
252
+ normalized: true,
253
+ wrapWidth
254
+ };
255
+ } catch (e) {
256
+ Logger.warn(`Safe text processing failed, falling back to capped binary: ${filePath}`, e);
257
+ fileInfo = await processFileContent(filePath, {
258
+ forceBinary: true,
259
+ allowPathological: true,
260
+ maxBytes: maxBytesOnProblem
261
+ });
262
+ }
263
+ } else {
264
+ Logger.info(`Processing file: ${filePath}`);
265
+ fileInfo = await processFileContent(filePath);
266
+ }
267
+ if (!fileInfo) return null;
268
+ const content = fileInfo.content;
269
+ if (!content || typeof content === "string" && content.length === 0 || content instanceof Uint8Array && content.length === 0) {
270
+ Logger.debug(`Skipping empty file: ${filePath} (empty files cannot be stored as MCards)`);
271
+ return {
272
+ hash: "",
273
+ contentType: fileInfo.mimeType,
274
+ isBinary: fileInfo.isBinary,
275
+ filename: fileInfo.filename,
276
+ size: 0,
277
+ filePath
278
+ };
279
+ }
280
+ let mcard = null;
281
+ const isProblematic = await isProblematicFile(filePath);
282
+ if (metadataOnly && isProblematic) {
283
+ mcard = null;
284
+ } else {
285
+ mcard = await MCard.create(fileInfo.content);
286
+ const handle = path2.basename(filePath);
287
+ try {
288
+ await collection.addWithHandle(mcard, handle);
289
+ } catch (e) {
290
+ let registered = false;
291
+ if (rootPath) {
292
+ const relPath = path2.relative(rootPath, filePath);
293
+ if (relPath !== handle) {
294
+ try {
295
+ await collection.addWithHandle(mcard, relPath);
296
+ registered = true;
297
+ } catch (e2) {
298
+ Logger.debug(
299
+ `Handle name '${handle}' already in use (common for files like README.md, LICENSE). MCard stored successfully with hash ${mcard.hash.slice(0, 8)}... (accessible by hash, not by handle)`
300
+ );
301
+ }
302
+ }
303
+ }
304
+ if (!registered) {
305
+ try {
306
+ await collection.add(mcard);
307
+ } catch (e3) {
308
+ Logger.warn(`Hash fallback also failed for ${handle}:`, e3);
309
+ }
310
+ }
311
+ }
312
+ }
313
+ const result = {
314
+ hash: mcard ? mcard.hash : "METADATA_ONLY",
315
+ contentType: fileInfo.mimeType,
316
+ isBinary: fileInfo.isBinary,
317
+ filename: fileInfo.filename,
318
+ size: fileInfo.size,
319
+ filePath
320
+ };
321
+ if (fileInfo.originalSize !== void 0) result.originalSize = fileInfo.originalSize;
322
+ if (fileInfo.originalSha256Prefix) result.originalSha256Prefix = fileInfo.originalSha256Prefix;
323
+ if (metadataOnly && isProblematic) result.metadataOnly = true;
324
+ return result;
325
+ } catch (e) {
326
+ Logger.error(`Error processing ${filePath}:`, e);
327
+ return null;
328
+ }
329
+ }
330
+ async function loadFileToCollection(targetPath, collection, options = {}) {
331
+ const {
332
+ recursive = false,
333
+ includeProblematic = false,
334
+ maxBytesOnProblem = DEFAULT_MAX_PROBLEM_BYTES,
335
+ metadataOnly = false
336
+ } = options;
337
+ const resolvedPath = path2.resolve(targetPath);
338
+ const stats = await fs2.stat(resolvedPath);
339
+ const results = [];
340
+ let files = [];
341
+ let rootPath = resolvedPath;
342
+ if (stats.isFile()) {
343
+ files = [resolvedPath];
344
+ rootPath = path2.dirname(resolvedPath);
345
+ } else if (stats.isDirectory()) {
346
+ files = await listFiles(resolvedPath, recursive);
347
+ rootPath = resolvedPath;
348
+ } else {
349
+ throw new Error(`Path ${targetPath} is not a file or directory`);
350
+ }
351
+ const uniqueDirs = /* @__PURE__ */ new Set();
352
+ let maxDepth = 0;
353
+ for (const file of files) {
354
+ const dir = path2.dirname(file);
355
+ if (dir.startsWith(rootPath)) {
356
+ uniqueDirs.add(dir);
357
+ const rel = path2.relative(rootPath, file);
358
+ const parts = rel.split(path2.sep);
359
+ const depth = parts.length - 1;
360
+ if (depth > maxDepth) maxDepth = depth;
361
+ }
362
+ }
363
+ const metrics = {
364
+ filesCount: files.length,
365
+ directoriesCount: uniqueDirs.size,
366
+ directoryLevels: maxDepth
367
+ };
368
+ Logger.info(`About to process ${files.length} files`);
369
+ for (const file of files) {
370
+ const result = await processAndStoreFile(file, collection, {
371
+ allowProblematic: includeProblematic,
372
+ maxBytesOnProblem,
373
+ metadataOnly,
374
+ rootPath
375
+ });
376
+ if (result) results.push(result);
377
+ }
378
+ return { metrics, results };
379
+ }
380
+ async function exportCollectionToDirectory(collection, targetDir) {
381
+ let exportedCount = 0;
382
+ let bytesWritten = 0;
383
+ const handles = await collection.getAllHandles();
384
+ for (const h of handles) {
385
+ const handlePath = h.handle;
386
+ const card = await collection.get(h.hash);
387
+ if (card) {
388
+ const absolutePath = path2.join(targetDir, handlePath);
389
+ await fs2.mkdir(path2.dirname(absolutePath), { recursive: true });
390
+ await fs2.writeFile(absolutePath, card.content);
391
+ bytesWritten += card.content.length;
392
+ exportedCount++;
393
+ }
394
+ }
395
+ return { exportedCount, bytesWritten };
396
+ }
397
+
398
+ export {
399
+ getTreeHashes,
400
+ FileIO_exports,
401
+ processAndStoreFile,
402
+ loadFileToCollection,
403
+ exportCollectionToDirectory,
404
+ Loader_exports
405
+ };