@interactive-inc/docs-client 1.0.20 → 1.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.
@@ -0,0 +1,1043 @@
1
+ // lib/modules/file-system/doc-file-system-json.ts
2
+ import { z as z3 } from "zod";
3
+
4
+ // lib/modules/path-system/doc-path-system.ts
5
+ var DocPathSystem = class {
6
+ separator = "/";
7
+ /**
8
+ * Join paths
9
+ */
10
+ join(...paths) {
11
+ const parts = [];
12
+ for (const path of paths) {
13
+ if (path === "") continue;
14
+ const segments = path.split(this.separator).filter(Boolean);
15
+ parts.push(...segments);
16
+ }
17
+ if (parts.length === 0) {
18
+ return ".";
19
+ }
20
+ const isAbsolute = paths[0]?.startsWith(this.separator);
21
+ const joined = parts.join(this.separator);
22
+ return isAbsolute ? `${this.separator}${joined}` : joined;
23
+ }
24
+ /**
25
+ * Get filename with extension
26
+ */
27
+ basename(path, ext) {
28
+ const segments = path.split(this.separator);
29
+ const filename = segments[segments.length - 1] || "";
30
+ if (ext && filename.endsWith(ext)) {
31
+ return filename.slice(0, -ext.length);
32
+ }
33
+ return filename;
34
+ }
35
+ /**
36
+ * Get directory name
37
+ */
38
+ dirname(path) {
39
+ const segments = path.split(this.separator);
40
+ if (segments.length <= 1) {
41
+ return ".";
42
+ }
43
+ segments.pop();
44
+ const dir = segments.join(this.separator);
45
+ return dir || ".";
46
+ }
47
+ /**
48
+ * Get extension
49
+ */
50
+ extname(path) {
51
+ const basename = this.basename(path);
52
+ const lastDot = basename.lastIndexOf(".");
53
+ if (lastDot <= 0) {
54
+ return "";
55
+ }
56
+ return basename.slice(lastDot);
57
+ }
58
+ /**
59
+ * Calculate relative path
60
+ */
61
+ relative(from, to) {
62
+ const fromSegments = from.split(this.separator).filter(Boolean);
63
+ const toSegments = to.split(this.separator).filter(Boolean);
64
+ let commonLength = 0;
65
+ for (let i = 0; i < Math.min(fromSegments.length, toSegments.length); i++) {
66
+ if (fromSegments[i] === toSegments[i]) {
67
+ commonLength++;
68
+ } else {
69
+ break;
70
+ }
71
+ }
72
+ const upCount = fromSegments.length - commonLength;
73
+ const upSegments = Array(upCount).fill("..");
74
+ const downSegments = toSegments.slice(commonLength);
75
+ const segments = [...upSegments, ...downSegments];
76
+ return segments.length > 0 ? segments.join(this.separator) : ".";
77
+ }
78
+ /**
79
+ * Convert to absolute path
80
+ */
81
+ resolve(...paths) {
82
+ let resolved = "";
83
+ for (const path of paths) {
84
+ if (path.startsWith(this.separator)) {
85
+ resolved = path;
86
+ } else if (path !== "") {
87
+ resolved = resolved ? this.join(resolved, path) : path;
88
+ }
89
+ }
90
+ return resolved || ".";
91
+ }
92
+ /**
93
+ * Normalize path
94
+ */
95
+ normalize(path) {
96
+ const isAbsolute = path.startsWith(this.separator);
97
+ const segments = path.split(this.separator).filter(Boolean);
98
+ const normalized = [];
99
+ for (const segment of segments) {
100
+ if (segment === "..") {
101
+ if (normalized.length > 0 && normalized[normalized.length - 1] !== "..") {
102
+ normalized.pop();
103
+ } else if (!isAbsolute) {
104
+ normalized.push("..");
105
+ }
106
+ } else if (segment !== ".") {
107
+ normalized.push(segment);
108
+ }
109
+ }
110
+ if (normalized.length === 0) {
111
+ return isAbsolute ? this.separator : ".";
112
+ }
113
+ const result = normalized.join(this.separator);
114
+ return isAbsolute ? `${this.separator}${result}` : result;
115
+ }
116
+ /**
117
+ * Check if path is absolute
118
+ */
119
+ isAbsolute(path) {
120
+ return path.startsWith(this.separator);
121
+ }
122
+ };
123
+
124
+ // lib/modules/file-system/doc-file-system-read.ts
125
+ import * as fs from "fs/promises";
126
+ var DocFileSystemRead = class {
127
+ basePath;
128
+ pathSystem;
129
+ constructor(props) {
130
+ this.basePath = props.basePath;
131
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
132
+ }
133
+ /**
134
+ * Read file content at the specified path
135
+ */
136
+ async readFile(relativePath) {
137
+ try {
138
+ const exists = await this.exists(relativePath);
139
+ if (!exists) return null;
140
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
141
+ return await fs.readFile(fullPath, "utf-8");
142
+ } catch (error) {
143
+ return error instanceof Error ? error : new Error(`Failed to read file at ${relativePath}`);
144
+ }
145
+ }
146
+ /**
147
+ * Get file name from path
148
+ */
149
+ readFileName(relativePath) {
150
+ return this.pathSystem.basename(relativePath);
151
+ }
152
+ /**
153
+ * Get file extension from path
154
+ */
155
+ readFileExtension(relativePath) {
156
+ return this.pathSystem.extname(relativePath);
157
+ }
158
+ /**
159
+ * Get directory path where the file exists
160
+ */
161
+ readFileDirectory(relativePath) {
162
+ return this.pathSystem.dirname(relativePath);
163
+ }
164
+ /**
165
+ * Get list of entries in directory
166
+ */
167
+ async readDirectoryFileNames(relativePath = "") {
168
+ try {
169
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
170
+ return await fs.readdir(fullPath);
171
+ } catch (error) {
172
+ return error instanceof Error ? error : new Error(`Failed to read directory at ${relativePath}`);
173
+ }
174
+ }
175
+ async readDirectoryFilePaths(relativePath) {
176
+ try {
177
+ const fileNames = await this.readDirectoryFileNames(relativePath);
178
+ if (fileNames instanceof Error) {
179
+ return fileNames;
180
+ }
181
+ return fileNames.map(
182
+ (fileName) => this.pathSystem.join(relativePath, fileName)
183
+ );
184
+ } catch (error) {
185
+ return error instanceof Error ? error : new Error(`Failed to read directory file paths at ${relativePath}`);
186
+ }
187
+ }
188
+ /**
189
+ * Check if path is a directory
190
+ */
191
+ async isDirectory(relativePath) {
192
+ try {
193
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
194
+ const stats = await fs.stat(fullPath);
195
+ return stats.isDirectory();
196
+ } catch {
197
+ return false;
198
+ }
199
+ }
200
+ /**
201
+ * Check if path is a file
202
+ */
203
+ async isFile(relativePath) {
204
+ try {
205
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
206
+ const stats = await fs.stat(fullPath);
207
+ return stats.isFile();
208
+ } catch {
209
+ return false;
210
+ }
211
+ }
212
+ /**
213
+ * Check if file or directory exists
214
+ */
215
+ async exists(relativePath) {
216
+ try {
217
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
218
+ await fs.access(fullPath);
219
+ return true;
220
+ } catch {
221
+ return false;
222
+ }
223
+ }
224
+ /**
225
+ * Check if directory exists
226
+ */
227
+ async directoryExists(relativePath) {
228
+ return this.isDirectory(relativePath);
229
+ }
230
+ /**
231
+ * Check if file exists
232
+ */
233
+ async fileExists(relativePath) {
234
+ return this.isFile(relativePath);
235
+ }
236
+ /**
237
+ * Get base path
238
+ */
239
+ getBasePath() {
240
+ return this.basePath;
241
+ }
242
+ /**
243
+ * Convert relative path to absolute path
244
+ */
245
+ resolve(relativePath) {
246
+ return this.pathSystem.join(this.basePath, relativePath);
247
+ }
248
+ /**
249
+ * Get file size in bytes
250
+ */
251
+ async getFileSize(relativePath) {
252
+ try {
253
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
254
+ const stats = await fs.stat(fullPath);
255
+ return stats.size;
256
+ } catch (error) {
257
+ return error instanceof Error ? error : new Error(`Failed to get file size at ${relativePath}`);
258
+ }
259
+ }
260
+ /**
261
+ * Get file last modified time
262
+ */
263
+ async getFileModifiedTime(relativePath) {
264
+ try {
265
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
266
+ const stats = await fs.stat(fullPath);
267
+ return stats.mtime;
268
+ } catch (error) {
269
+ return error instanceof Error ? error : new Error(`Failed to get file modified time at ${relativePath}`);
270
+ }
271
+ }
272
+ /**
273
+ * Get file creation time
274
+ */
275
+ async getFileCreatedTime(relativePath) {
276
+ try {
277
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
278
+ const stats = await fs.stat(fullPath);
279
+ return stats.birthtime;
280
+ } catch (error) {
281
+ return error instanceof Error ? error : new Error(`Failed to get file created time at ${relativePath}`);
282
+ }
283
+ }
284
+ };
285
+
286
+ // lib/modules/file-system/doc-file-system-write.ts
287
+ import * as fs2 from "fs/promises";
288
+ var DocFileSystemWrite = class {
289
+ basePath;
290
+ pathSystem;
291
+ reader;
292
+ constructor(props) {
293
+ this.basePath = props.basePath;
294
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
295
+ this.reader = props.reader;
296
+ }
297
+ /**
298
+ * Write content to file at the specified path (creates directory if needed)
299
+ */
300
+ async writeFile(relativePath, content) {
301
+ try {
302
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
303
+ const dirPath = this.pathSystem.dirname(fullPath);
304
+ await fs2.mkdir(dirPath, { recursive: true });
305
+ await fs2.writeFile(fullPath, content, "utf-8");
306
+ return null;
307
+ } catch (error) {
308
+ return error instanceof Error ? error : new Error(`Failed to write file at ${relativePath}`);
309
+ }
310
+ }
311
+ /**
312
+ * Delete file at the specified path
313
+ */
314
+ async deleteFile(relativePath) {
315
+ try {
316
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
317
+ await fs2.unlink(fullPath);
318
+ return null;
319
+ } catch (error) {
320
+ return new Error(`Failed to delete file at ${relativePath}: ${error}`);
321
+ }
322
+ }
323
+ /**
324
+ * Create directory
325
+ */
326
+ async createDirectory(relativePath) {
327
+ try {
328
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
329
+ await fs2.mkdir(fullPath, { recursive: true });
330
+ return null;
331
+ } catch (error) {
332
+ return error instanceof Error ? error : new Error(`Failed to create directory at ${relativePath}`);
333
+ }
334
+ }
335
+ /**
336
+ * Create directory if it doesn't exist
337
+ */
338
+ async ensureDirectoryExists(relativePath) {
339
+ try {
340
+ if (this.reader) {
341
+ const exists = await this.reader.exists(relativePath);
342
+ if (exists) {
343
+ return null;
344
+ }
345
+ }
346
+ const result = await this.createDirectory(relativePath);
347
+ if (result instanceof Error) {
348
+ return result;
349
+ }
350
+ return null;
351
+ } catch (error) {
352
+ return error instanceof Error ? error : new Error(`Failed to ensure directory exists at ${relativePath}`);
353
+ }
354
+ }
355
+ /**
356
+ * Copy file
357
+ */
358
+ async copyFile(sourcePath, destinationPath) {
359
+ try {
360
+ const sourceFullPath = this.pathSystem.join(this.basePath, sourcePath);
361
+ const destFullPath = this.pathSystem.join(this.basePath, destinationPath);
362
+ await fs2.copyFile(sourceFullPath, destFullPath);
363
+ return null;
364
+ } catch (error) {
365
+ return error instanceof Error ? error : new Error(
366
+ `Failed to copy file from ${sourcePath} to ${destinationPath}`
367
+ );
368
+ }
369
+ }
370
+ /**
371
+ * Move file
372
+ */
373
+ async moveFile(sourcePath, destinationPath) {
374
+ try {
375
+ const sourceFullPath = this.pathSystem.join(this.basePath, sourcePath);
376
+ const destFullPath = this.pathSystem.join(this.basePath, destinationPath);
377
+ await fs2.rename(sourceFullPath, destFullPath);
378
+ return null;
379
+ } catch (error) {
380
+ return error instanceof Error ? error : new Error(
381
+ `Failed to move file from ${sourcePath} to ${destinationPath}`
382
+ );
383
+ }
384
+ }
385
+ };
386
+
387
+ // lib/modules/file-system/doc-file-system.ts
388
+ var DocFileSystem = class {
389
+ reader;
390
+ writer;
391
+ basePath;
392
+ pathSystem;
393
+ constructor(props) {
394
+ this.basePath = props.basePath;
395
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
396
+ this.reader = props.reader ?? new DocFileSystemRead({
397
+ basePath: this.basePath,
398
+ pathSystem: this.pathSystem
399
+ });
400
+ this.writer = props.writer ?? new DocFileSystemWrite({
401
+ basePath: this.basePath,
402
+ pathSystem: this.pathSystem,
403
+ reader: this.reader
404
+ });
405
+ }
406
+ /**
407
+ * Read file content at the specified path
408
+ */
409
+ async readFile(relativePath) {
410
+ return this.reader.readFile(relativePath);
411
+ }
412
+ /**
413
+ * Write content to file at the specified path (creates directory if needed)
414
+ */
415
+ async writeFile(relativePath, content) {
416
+ return this.writer.writeFile(relativePath, content);
417
+ }
418
+ /**
419
+ * Delete file at the specified path
420
+ */
421
+ async deleteFile(relativePath) {
422
+ return this.writer.deleteFile(relativePath);
423
+ }
424
+ /**
425
+ * Get file name from path
426
+ */
427
+ readFileName(relativePath) {
428
+ return this.reader.readFileName(relativePath);
429
+ }
430
+ /**
431
+ * Get file extension from path
432
+ */
433
+ readFileExtension(relativePath) {
434
+ return this.reader.readFileExtension(relativePath);
435
+ }
436
+ /**
437
+ * Get directory path where the file exists
438
+ */
439
+ readFileDirectory(relativePath) {
440
+ return this.reader.readFileDirectory(relativePath);
441
+ }
442
+ /**
443
+ * Get list of entries in directory
444
+ */
445
+ async readDirectoryFileNames(relativePath = "") {
446
+ return this.reader.readDirectoryFileNames(relativePath);
447
+ }
448
+ async readDirectoryFilePaths(relativePath) {
449
+ return this.reader.readDirectoryFilePaths(relativePath);
450
+ }
451
+ /**
452
+ * Check if path is a directory
453
+ */
454
+ async isDirectory(relativePath) {
455
+ return this.reader.isDirectory(relativePath);
456
+ }
457
+ /**
458
+ * Check if path is a file
459
+ */
460
+ async isFile(relativePath) {
461
+ return this.reader.isFile(relativePath);
462
+ }
463
+ /**
464
+ * Check if file or directory exists
465
+ */
466
+ async exists(relativePath) {
467
+ return this.reader.exists(relativePath);
468
+ }
469
+ /**
470
+ * Check if directory exists
471
+ */
472
+ async directoryExists(relativePath) {
473
+ return this.reader.directoryExists(relativePath);
474
+ }
475
+ /**
476
+ * Check if file exists
477
+ */
478
+ async fileExists(relativePath) {
479
+ return this.reader.fileExists(relativePath);
480
+ }
481
+ /**
482
+ * Get base path
483
+ */
484
+ getBasePath() {
485
+ return this.reader.getBasePath();
486
+ }
487
+ /**
488
+ * Convert relative path to absolute path
489
+ */
490
+ resolve(relativePath) {
491
+ return this.reader.resolve(relativePath);
492
+ }
493
+ /**
494
+ * Create directory
495
+ */
496
+ async createDirectory(relativePath) {
497
+ return this.writer.createDirectory(relativePath);
498
+ }
499
+ /**
500
+ * Get file size in bytes
501
+ */
502
+ async getFileSize(relativePath) {
503
+ return this.reader.getFileSize(relativePath);
504
+ }
505
+ /**
506
+ * Create directory if it doesn't exist
507
+ */
508
+ async ensureDirectoryExists(relativePath) {
509
+ return this.writer.ensureDirectoryExists(relativePath);
510
+ }
511
+ /**
512
+ * Copy file
513
+ */
514
+ async copyFile(sourcePath, destinationPath) {
515
+ return this.writer.copyFile(sourcePath, destinationPath);
516
+ }
517
+ /**
518
+ * Move file
519
+ */
520
+ async moveFile(sourcePath, destinationPath) {
521
+ return this.writer.moveFile(sourcePath, destinationPath);
522
+ }
523
+ /**
524
+ * Get file last modified time
525
+ */
526
+ async getFileModifiedTime(relativePath) {
527
+ return this.reader.getFileModifiedTime(relativePath);
528
+ }
529
+ /**
530
+ * Get file creation time
531
+ */
532
+ async getFileCreatedTime(relativePath) {
533
+ return this.reader.getFileCreatedTime(relativePath);
534
+ }
535
+ };
536
+
537
+ // lib/modules/file-system/doc-file-system-json-read.ts
538
+ import { z } from "zod";
539
+ var zJsonDocumentData = z.record(z.string(), z.string());
540
+ function parseJsonDocumentData(data) {
541
+ try {
542
+ return zJsonDocumentData.parse(data);
543
+ } catch (error) {
544
+ return error instanceof Error ? error : new Error("Failed to parse JSON document data");
545
+ }
546
+ }
547
+ var DocFileSystemJsonRead = class {
548
+ data;
549
+ basePath;
550
+ pathSystem;
551
+ constructor(props) {
552
+ const parsed = parseJsonDocumentData(props.data);
553
+ if (parsed instanceof Error) {
554
+ throw parsed;
555
+ }
556
+ this.data = parsed;
557
+ this.basePath = props.basePath ?? "docs";
558
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
559
+ Object.freeze(this);
560
+ }
561
+ /**
562
+ * Read file content from JSON data
563
+ */
564
+ async readFile(relativePath) {
565
+ try {
566
+ const normalizedPath = this.normalizePath(relativePath);
567
+ const content = this.data[normalizedPath];
568
+ return content ?? null;
569
+ } catch (error) {
570
+ return error instanceof Error ? error : new Error(`Failed to read file at ${relativePath}`);
571
+ }
572
+ }
573
+ /**
574
+ * Get file name from path
575
+ */
576
+ readFileName(relativePath) {
577
+ return this.pathSystem.basename(relativePath);
578
+ }
579
+ /**
580
+ * Get file extension from path
581
+ */
582
+ readFileExtension(relativePath) {
583
+ return this.pathSystem.extname(relativePath);
584
+ }
585
+ /**
586
+ * Get directory path where the file exists
587
+ */
588
+ readFileDirectory(relativePath) {
589
+ return this.pathSystem.dirname(relativePath);
590
+ }
591
+ /**
592
+ * Get list of file names in directory
593
+ */
594
+ async readDirectoryFileNames(relativePath = "") {
595
+ try {
596
+ const normalizedDir = this.normalizePath(relativePath);
597
+ const fileNames = /* @__PURE__ */ new Set();
598
+ for (const filePath of Object.keys(this.data)) {
599
+ if (this.isFileInDirectory(filePath, normalizedDir)) {
600
+ const relativePart = this.getRelativePartFromDirectory(
601
+ filePath,
602
+ normalizedDir
603
+ );
604
+ const segments = relativePart.split("/").filter(Boolean);
605
+ if (segments.length > 0) {
606
+ fileNames.add(segments[0]);
607
+ }
608
+ }
609
+ }
610
+ return Array.from(fileNames).sort();
611
+ } catch (error) {
612
+ return error instanceof Error ? error : new Error(`Failed to read directory at ${relativePath}`);
613
+ }
614
+ }
615
+ /**
616
+ * Get list of file paths in directory
617
+ */
618
+ async readDirectoryFilePaths(relativePath) {
619
+ try {
620
+ const fileNames = await this.readDirectoryFileNames(relativePath);
621
+ if (fileNames instanceof Error) {
622
+ return fileNames;
623
+ }
624
+ return fileNames.map(
625
+ (fileName) => this.pathSystem.join(relativePath, fileName)
626
+ );
627
+ } catch (error) {
628
+ return error instanceof Error ? error : new Error(`Failed to read directory file paths at ${relativePath}`);
629
+ }
630
+ }
631
+ /**
632
+ * Check if path is a directory
633
+ */
634
+ async isDirectory(relativePath) {
635
+ try {
636
+ const normalizedPath = this.normalizePath(relativePath);
637
+ for (const filePath of Object.keys(this.data)) {
638
+ if (filePath.startsWith(`${normalizedPath}/`)) {
639
+ return true;
640
+ }
641
+ }
642
+ return false;
643
+ } catch {
644
+ return false;
645
+ }
646
+ }
647
+ /**
648
+ * Check if path is a file
649
+ */
650
+ async isFile(relativePath) {
651
+ try {
652
+ const normalizedPath = this.normalizePath(relativePath);
653
+ return normalizedPath in this.data;
654
+ } catch {
655
+ return false;
656
+ }
657
+ }
658
+ /**
659
+ * Check if file or directory exists
660
+ */
661
+ async exists(relativePath) {
662
+ const isFile = await this.isFile(relativePath);
663
+ if (isFile) return true;
664
+ const isDir = await this.isDirectory(relativePath);
665
+ return isDir;
666
+ }
667
+ /**
668
+ * Check if directory exists
669
+ */
670
+ async directoryExists(relativePath) {
671
+ return this.isDirectory(relativePath);
672
+ }
673
+ /**
674
+ * Check if file exists
675
+ */
676
+ async fileExists(relativePath) {
677
+ return this.isFile(relativePath);
678
+ }
679
+ /**
680
+ * Get base path
681
+ */
682
+ getBasePath() {
683
+ return this.basePath;
684
+ }
685
+ /**
686
+ * Convert relative path to absolute path
687
+ */
688
+ resolve(relativePath) {
689
+ return this.pathSystem.join(this.basePath, relativePath);
690
+ }
691
+ /**
692
+ * Get file size in bytes
693
+ */
694
+ async getFileSize(relativePath) {
695
+ try {
696
+ const content = await this.readFile(relativePath);
697
+ if (content instanceof Error) {
698
+ return content;
699
+ }
700
+ if (content === null) {
701
+ return new Error(`File not found: ${relativePath}`);
702
+ }
703
+ return Buffer.byteLength(content, "utf8");
704
+ } catch (error) {
705
+ return error instanceof Error ? error : new Error(`Failed to get file size at ${relativePath}`);
706
+ }
707
+ }
708
+ /**
709
+ * Get file last modified time (not available for JSON data)
710
+ */
711
+ async getFileModifiedTime(_relativePath) {
712
+ return new Error("File modified time not available for JSON data");
713
+ }
714
+ /**
715
+ * Get file creation time (not available for JSON data)
716
+ */
717
+ async getFileCreatedTime(_relativePath) {
718
+ return new Error("File creation time not available for JSON data");
719
+ }
720
+ /**
721
+ * Get all file paths in the JSON data
722
+ */
723
+ getAllFilePaths() {
724
+ return Object.keys(this.data);
725
+ }
726
+ /**
727
+ * Get the raw JSON data
728
+ */
729
+ getRawData() {
730
+ return { ...this.data };
731
+ }
732
+ /**
733
+ * Normalize path by removing leading/trailing slashes
734
+ */
735
+ normalizePath(path) {
736
+ return path.replace(/^\/+|\/+$/g, "");
737
+ }
738
+ /**
739
+ * Check if a file path is within a directory
740
+ */
741
+ isFileInDirectory(filePath, dirPath) {
742
+ if (dirPath === "") {
743
+ return true;
744
+ }
745
+ return filePath.startsWith(`${dirPath}/`) || filePath === dirPath;
746
+ }
747
+ /**
748
+ * Get the relative part of a file path from a directory
749
+ */
750
+ getRelativePartFromDirectory(filePath, dirPath) {
751
+ if (dirPath === "") {
752
+ return filePath;
753
+ }
754
+ if (filePath.startsWith(`${dirPath}/`)) {
755
+ return filePath.slice(dirPath.length + 1);
756
+ }
757
+ return "";
758
+ }
759
+ };
760
+
761
+ // lib/modules/file-system/doc-file-system-json-write.ts
762
+ import { z as z2 } from "zod";
763
+ var zJsonDocumentData2 = z2.record(z2.string(), z2.string());
764
+ function parseJsonDocumentData2(data) {
765
+ try {
766
+ return zJsonDocumentData2.parse(data);
767
+ } catch (error) {
768
+ return error instanceof Error ? error : new Error("Failed to parse JSON document data");
769
+ }
770
+ }
771
+ var DocFileSystemJsonWrite = class {
772
+ data;
773
+ basePath;
774
+ pathSystem;
775
+ reader;
776
+ onDataChange;
777
+ constructor(props = {}) {
778
+ if (props.data !== void 0) {
779
+ const parsed = parseJsonDocumentData2(props.data);
780
+ if (parsed instanceof Error) {
781
+ throw parsed;
782
+ }
783
+ this.data = parsed;
784
+ } else {
785
+ this.data = {};
786
+ }
787
+ this.basePath = props.basePath ?? "docs";
788
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
789
+ this.reader = props.reader;
790
+ this.onDataChange = props.onDataChange;
791
+ }
792
+ /**
793
+ * Write content to JSON data
794
+ */
795
+ async writeFile(relativePath, content) {
796
+ try {
797
+ const normalizedPath = this.normalizePath(relativePath);
798
+ this.data[normalizedPath] = content;
799
+ this.notifyDataChange();
800
+ return null;
801
+ } catch (error) {
802
+ return error instanceof Error ? error : new Error(`Failed to write file at ${relativePath}`);
803
+ }
804
+ }
805
+ /**
806
+ * Delete file from JSON data
807
+ */
808
+ async deleteFile(relativePath) {
809
+ try {
810
+ const normalizedPath = this.normalizePath(relativePath);
811
+ if (!(normalizedPath in this.data)) {
812
+ return new Error(`File not found: ${relativePath}`);
813
+ }
814
+ delete this.data[normalizedPath];
815
+ this.notifyDataChange();
816
+ return null;
817
+ } catch (error) {
818
+ return error instanceof Error ? error : new Error(`Failed to delete file at ${relativePath}`);
819
+ }
820
+ }
821
+ /**
822
+ * Create directory (creates a placeholder entry)
823
+ */
824
+ async createDirectory(relativePath) {
825
+ try {
826
+ const normalizedPath = this.normalizePath(relativePath);
827
+ const gitkeepPath = this.pathSystem.join(normalizedPath, ".gitkeep");
828
+ const normalizedGitkeepPath = this.normalizePath(gitkeepPath);
829
+ this.data[normalizedGitkeepPath] = "";
830
+ this.notifyDataChange();
831
+ return null;
832
+ } catch (error) {
833
+ return error instanceof Error ? error : new Error(`Failed to create directory at ${relativePath}`);
834
+ }
835
+ }
836
+ /**
837
+ * Create directory if it doesn't exist
838
+ */
839
+ async ensureDirectoryExists(relativePath) {
840
+ try {
841
+ if (this.reader) {
842
+ const exists = await this.reader.exists(relativePath);
843
+ if (exists) {
844
+ return null;
845
+ }
846
+ } else {
847
+ if (await this.directoryExistsInData(relativePath)) {
848
+ return null;
849
+ }
850
+ }
851
+ return await this.createDirectory(relativePath);
852
+ } catch (error) {
853
+ return error instanceof Error ? error : new Error(`Failed to ensure directory exists at ${relativePath}`);
854
+ }
855
+ }
856
+ /**
857
+ * Copy file within JSON data
858
+ */
859
+ async copyFile(sourcePath, destinationPath) {
860
+ try {
861
+ const normalizedSourcePath = this.normalizePath(sourcePath);
862
+ const normalizedDestPath = this.normalizePath(destinationPath);
863
+ if (this.reader) {
864
+ const content = await this.reader.readFile(sourcePath);
865
+ if (content instanceof Error) {
866
+ return content;
867
+ }
868
+ if (content === null) {
869
+ return new Error(`Source file not found: ${sourcePath}`);
870
+ }
871
+ this.data[normalizedDestPath] = content;
872
+ } else {
873
+ if (!(normalizedSourcePath in this.data)) {
874
+ return new Error(`Source file not found: ${sourcePath}`);
875
+ }
876
+ this.data[normalizedDestPath] = this.data[normalizedSourcePath];
877
+ }
878
+ this.notifyDataChange();
879
+ return null;
880
+ } catch (error) {
881
+ return error instanceof Error ? error : new Error(
882
+ `Failed to copy file from ${sourcePath} to ${destinationPath}`
883
+ );
884
+ }
885
+ }
886
+ /**
887
+ * Move file within JSON data
888
+ */
889
+ async moveFile(sourcePath, destinationPath) {
890
+ try {
891
+ const copyResult = await this.copyFile(sourcePath, destinationPath);
892
+ if (copyResult !== null) {
893
+ return copyResult;
894
+ }
895
+ return await this.deleteFile(sourcePath);
896
+ } catch (error) {
897
+ return error instanceof Error ? error : new Error(
898
+ `Failed to move file from ${sourcePath} to ${destinationPath}`
899
+ );
900
+ }
901
+ }
902
+ /**
903
+ * Get the current JSON data
904
+ */
905
+ getData() {
906
+ return { ...this.data };
907
+ }
908
+ /**
909
+ * Update the entire JSON data
910
+ */
911
+ setData(data) {
912
+ try {
913
+ const parsed = parseJsonDocumentData2(data);
914
+ if (parsed instanceof Error) {
915
+ return parsed;
916
+ }
917
+ this.data = parsed;
918
+ this.notifyDataChange();
919
+ return null;
920
+ } catch (error) {
921
+ return error instanceof Error ? error : new Error("Failed to set JSON data");
922
+ }
923
+ }
924
+ /**
925
+ * Clear all data
926
+ */
927
+ clear() {
928
+ this.data = {};
929
+ this.notifyDataChange();
930
+ }
931
+ /**
932
+ * Get all file paths in the JSON data
933
+ */
934
+ getAllFilePaths() {
935
+ return Object.keys(this.data);
936
+ }
937
+ /**
938
+ * Normalize path by removing leading/trailing slashes
939
+ */
940
+ normalizePath(path) {
941
+ return path.replace(/^\/+|\/+$/g, "");
942
+ }
943
+ /**
944
+ * Check if directory exists in data
945
+ */
946
+ async directoryExistsInData(relativePath) {
947
+ const normalizedPath = this.normalizePath(relativePath);
948
+ for (const filePath of Object.keys(this.data)) {
949
+ if (filePath.startsWith(`${normalizedPath}/`)) {
950
+ return true;
951
+ }
952
+ }
953
+ return false;
954
+ }
955
+ /**
956
+ * Notify data change callback
957
+ */
958
+ notifyDataChange() {
959
+ if (this.onDataChange) {
960
+ this.onDataChange({ ...this.data });
961
+ }
962
+ }
963
+ };
964
+
965
+ // lib/modules/file-system/doc-file-system-json.ts
966
+ var zJsonDocumentData3 = z3.record(z3.string(), z3.string());
967
+ var DocFileSystemJson = class _DocFileSystemJson extends DocFileSystem {
968
+ jsonReader;
969
+ jsonWriter;
970
+ constructor(props = {}) {
971
+ const reader = new DocFileSystemJsonRead({
972
+ data: props.data,
973
+ basePath: props.basePath,
974
+ pathSystem: props.pathSystem
975
+ });
976
+ const writer = new DocFileSystemJsonWrite({
977
+ data: props.data,
978
+ basePath: props.basePath,
979
+ pathSystem: props.pathSystem,
980
+ reader,
981
+ onDataChange: props.onDataChange
982
+ });
983
+ super({
984
+ basePath: props.basePath ?? "docs",
985
+ pathSystem: props.pathSystem,
986
+ reader,
987
+ writer
988
+ });
989
+ this.jsonReader = reader;
990
+ this.jsonWriter = writer;
991
+ Object.freeze(this);
992
+ }
993
+ /**
994
+ * Get the current JSON data
995
+ */
996
+ getData() {
997
+ return this.jsonWriter.getData();
998
+ }
999
+ /**
1000
+ * Update the entire JSON data
1001
+ */
1002
+ setData(data) {
1003
+ return this.jsonWriter.setData(data);
1004
+ }
1005
+ /**
1006
+ * Clear all data
1007
+ */
1008
+ clear() {
1009
+ this.jsonWriter.clear();
1010
+ }
1011
+ /**
1012
+ * Get all file paths in the JSON data
1013
+ */
1014
+ getAllFilePaths() {
1015
+ return this.jsonReader.getAllFilePaths();
1016
+ }
1017
+ /**
1018
+ * Get the raw JSON data (read-only copy)
1019
+ */
1020
+ getRawData() {
1021
+ return this.jsonReader.getRawData();
1022
+ }
1023
+ /**
1024
+ * Create from docs-to-json format
1025
+ */
1026
+ static fromDocsToJson(data, options = {}) {
1027
+ return new _DocFileSystemJson({
1028
+ ...options,
1029
+ data
1030
+ });
1031
+ }
1032
+ /**
1033
+ * Export to docs-to-json format
1034
+ */
1035
+ toDocsToJson() {
1036
+ return this.getData();
1037
+ }
1038
+ };
1039
+ export {
1040
+ DocFileSystemJson,
1041
+ DocFileSystemJsonRead,
1042
+ DocFileSystemJsonWrite
1043
+ };