@interactive-inc/docs-client 1.0.19 → 1.0.20

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.
package/build/index.js CHANGED
@@ -5138,9 +5138,9 @@ var DocClient = class {
5138
5138
  }
5139
5139
  };
5140
5140
 
5141
- // lib/doc-file-system.ts
5141
+ // lib/doc-file-system-read.ts
5142
5142
  import * as fs from "fs/promises";
5143
- var DocFileSystem = class {
5143
+ var DocFileSystemRead = class {
5144
5144
  basePath;
5145
5145
  pathSystem;
5146
5146
  constructor(props) {
@@ -5160,32 +5160,6 @@ var DocFileSystem = class {
5160
5160
  return error instanceof Error ? error : new Error(`Failed to read file at ${relativePath}`);
5161
5161
  }
5162
5162
  }
5163
- /**
5164
- * Write content to file at the specified path (creates directory if needed)
5165
- */
5166
- async writeFile(relativePath, content) {
5167
- try {
5168
- const fullPath = this.pathSystem.join(this.basePath, relativePath);
5169
- const dirPath = this.pathSystem.dirname(fullPath);
5170
- await fs.mkdir(dirPath, { recursive: true });
5171
- await fs.writeFile(fullPath, content, "utf-8");
5172
- return null;
5173
- } catch (error) {
5174
- return error instanceof Error ? error : new Error(`Failed to write file at ${relativePath}`);
5175
- }
5176
- }
5177
- /**
5178
- * Delete file at the specified path
5179
- */
5180
- async deleteFile(relativePath) {
5181
- try {
5182
- const fullPath = this.pathSystem.join(this.basePath, relativePath);
5183
- await fs.unlink(fullPath);
5184
- return null;
5185
- } catch (error) {
5186
- return new Error(`Failed to delete file at ${relativePath}: ${error}`);
5187
- }
5188
- }
5189
5163
  /**
5190
5164
  * Get file name from path
5191
5165
  */
@@ -5289,27 +5263,90 @@ var DocFileSystem = class {
5289
5263
  return this.pathSystem.join(this.basePath, relativePath);
5290
5264
  }
5291
5265
  /**
5292
- * Create directory
5266
+ * Get file size in bytes
5293
5267
  */
5294
- async createDirectory(relativePath) {
5268
+ async getFileSize(relativePath) {
5295
5269
  try {
5296
5270
  const fullPath = this.pathSystem.join(this.basePath, relativePath);
5297
- await fs.mkdir(fullPath, { recursive: true });
5298
- return null;
5271
+ const stats = await fs.stat(fullPath);
5272
+ return stats.size;
5299
5273
  } catch (error) {
5300
- return error instanceof Error ? error : new Error(`Failed to create directory at ${relativePath}`);
5274
+ return error instanceof Error ? error : new Error(`Failed to get file size at ${relativePath}`);
5301
5275
  }
5302
5276
  }
5303
5277
  /**
5304
- * Get file size in bytes
5278
+ * Get file last modified time
5305
5279
  */
5306
- async getFileSize(relativePath) {
5280
+ async getFileModifiedTime(relativePath) {
5307
5281
  try {
5308
5282
  const fullPath = this.pathSystem.join(this.basePath, relativePath);
5309
5283
  const stats = await fs.stat(fullPath);
5310
- return stats.size;
5284
+ return stats.mtime;
5311
5285
  } catch (error) {
5312
- return error instanceof Error ? error : new Error(`Failed to get file size at ${relativePath}`);
5286
+ return error instanceof Error ? error : new Error(`Failed to get file modified time at ${relativePath}`);
5287
+ }
5288
+ }
5289
+ /**
5290
+ * Get file creation time
5291
+ */
5292
+ async getFileCreatedTime(relativePath) {
5293
+ try {
5294
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
5295
+ const stats = await fs.stat(fullPath);
5296
+ return stats.birthtime;
5297
+ } catch (error) {
5298
+ return error instanceof Error ? error : new Error(`Failed to get file created time at ${relativePath}`);
5299
+ }
5300
+ }
5301
+ };
5302
+
5303
+ // lib/doc-file-system-write.ts
5304
+ import * as fs2 from "fs/promises";
5305
+ var DocFileSystemWrite = class {
5306
+ basePath;
5307
+ pathSystem;
5308
+ reader;
5309
+ constructor(props) {
5310
+ this.basePath = props.basePath;
5311
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
5312
+ this.reader = props.reader;
5313
+ }
5314
+ /**
5315
+ * Write content to file at the specified path (creates directory if needed)
5316
+ */
5317
+ async writeFile(relativePath, content) {
5318
+ try {
5319
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
5320
+ const dirPath = this.pathSystem.dirname(fullPath);
5321
+ await fs2.mkdir(dirPath, { recursive: true });
5322
+ await fs2.writeFile(fullPath, content, "utf-8");
5323
+ return null;
5324
+ } catch (error) {
5325
+ return error instanceof Error ? error : new Error(`Failed to write file at ${relativePath}`);
5326
+ }
5327
+ }
5328
+ /**
5329
+ * Delete file at the specified path
5330
+ */
5331
+ async deleteFile(relativePath) {
5332
+ try {
5333
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
5334
+ await fs2.unlink(fullPath);
5335
+ return null;
5336
+ } catch (error) {
5337
+ return new Error(`Failed to delete file at ${relativePath}: ${error}`);
5338
+ }
5339
+ }
5340
+ /**
5341
+ * Create directory
5342
+ */
5343
+ async createDirectory(relativePath) {
5344
+ try {
5345
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
5346
+ await fs2.mkdir(fullPath, { recursive: true });
5347
+ return null;
5348
+ } catch (error) {
5349
+ return error instanceof Error ? error : new Error(`Failed to create directory at ${relativePath}`);
5313
5350
  }
5314
5351
  }
5315
5352
  /**
@@ -5317,12 +5354,16 @@ var DocFileSystem = class {
5317
5354
  */
5318
5355
  async ensureDirectoryExists(relativePath) {
5319
5356
  try {
5320
- if (!await this.exists(relativePath)) {
5321
- const result = await this.createDirectory(relativePath);
5322
- if (result instanceof Error) {
5323
- return result;
5357
+ if (this.reader) {
5358
+ const exists = await this.reader.exists(relativePath);
5359
+ if (exists) {
5360
+ return null;
5324
5361
  }
5325
5362
  }
5363
+ const result = await this.createDirectory(relativePath);
5364
+ if (result instanceof Error) {
5365
+ return result;
5366
+ }
5326
5367
  return null;
5327
5368
  } catch (error) {
5328
5369
  return error instanceof Error ? error : new Error(`Failed to ensure directory exists at ${relativePath}`);
@@ -5335,7 +5376,7 @@ var DocFileSystem = class {
5335
5376
  try {
5336
5377
  const sourceFullPath = this.pathSystem.join(this.basePath, sourcePath);
5337
5378
  const destFullPath = this.pathSystem.join(this.basePath, destinationPath);
5338
- await fs.copyFile(sourceFullPath, destFullPath);
5379
+ await fs2.copyFile(sourceFullPath, destFullPath);
5339
5380
  return null;
5340
5381
  } catch (error) {
5341
5382
  return error instanceof Error ? error : new Error(
@@ -5350,7 +5391,7 @@ var DocFileSystem = class {
5350
5391
  try {
5351
5392
  const sourceFullPath = this.pathSystem.join(this.basePath, sourcePath);
5352
5393
  const destFullPath = this.pathSystem.join(this.basePath, destinationPath);
5353
- await fs.rename(sourceFullPath, destFullPath);
5394
+ await fs2.rename(sourceFullPath, destFullPath);
5354
5395
  return null;
5355
5396
  } catch (error) {
5356
5397
  return error instanceof Error ? error : new Error(
@@ -5358,151 +5399,783 @@ var DocFileSystem = class {
5358
5399
  );
5359
5400
  }
5360
5401
  }
5402
+ };
5403
+
5404
+ // lib/doc-file-system.ts
5405
+ var DocFileSystem = class {
5406
+ reader;
5407
+ writer;
5408
+ basePath;
5409
+ pathSystem;
5410
+ constructor(props) {
5411
+ this.basePath = props.basePath;
5412
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
5413
+ this.reader = props.reader ?? new DocFileSystemRead({
5414
+ basePath: this.basePath,
5415
+ pathSystem: this.pathSystem
5416
+ });
5417
+ this.writer = props.writer ?? new DocFileSystemWrite({
5418
+ basePath: this.basePath,
5419
+ pathSystem: this.pathSystem,
5420
+ reader: this.reader
5421
+ });
5422
+ }
5361
5423
  /**
5362
- * Get file last modified time
5424
+ * Read file content at the specified path
5363
5425
  */
5364
- async getFileModifiedTime(relativePath) {
5365
- try {
5366
- const fullPath = this.pathSystem.join(this.basePath, relativePath);
5367
- const stats = await fs.stat(fullPath);
5368
- return stats.mtime;
5369
- } catch (error) {
5370
- return error instanceof Error ? error : new Error(`Failed to get file modified time at ${relativePath}`);
5371
- }
5426
+ async readFile(relativePath) {
5427
+ return this.reader.readFile(relativePath);
5372
5428
  }
5373
5429
  /**
5374
- * Get file creation time
5430
+ * Write content to file at the specified path (creates directory if needed)
5375
5431
  */
5376
- async getFileCreatedTime(relativePath) {
5377
- try {
5378
- const fullPath = this.pathSystem.join(this.basePath, relativePath);
5379
- const stats = await fs.stat(fullPath);
5380
- return stats.birthtime;
5381
- } catch (error) {
5382
- return error instanceof Error ? error : new Error(`Failed to get file created time at ${relativePath}`);
5383
- }
5432
+ async writeFile(relativePath, content) {
5433
+ return this.writer.writeFile(relativePath, content);
5384
5434
  }
5385
- };
5386
-
5387
- // lib/doc-file-system-mock.ts
5388
- var mockDirectoryData = {
5389
- "docs/index.md": `---
5390
- icon: \u{1F4DA}
5391
- ---
5392
-
5393
- # Documentation
5394
-
5395
- Welcome to the documentation!`,
5396
- "docs/guide/index.md": `---
5397
- icon: \u{1F4D6}
5398
- ---
5399
-
5400
- # Guide
5401
-
5402
- This is a guide.`,
5403
- "docs/guide/getting-started.md": `# Getting Started
5404
-
5405
- Let's get started!`,
5406
- "docs/guide/advanced.md": `# Advanced
5407
-
5408
- Advanced topics here.`,
5409
- "docs/api/index.md": `---
5410
- icon: \u{1F527}
5411
- ---
5412
-
5413
- # API
5414
-
5415
- API documentation.`,
5416
- "docs/api/reference.md": `# API Reference
5417
-
5418
- Complete API reference.`
5419
- };
5420
- var DocFileSystemMock = class _DocFileSystemMock extends DocFileSystem {
5421
- files = /* @__PURE__ */ new Map();
5422
- _pathSystem;
5423
- _basePath;
5424
- constructor(props) {
5425
- super(props);
5426
- this._pathSystem = props.pathSystem;
5427
- this._basePath = props.basePath.endsWith("/") ? props.basePath.slice(0, -1) : props.basePath;
5428
- if (!props.skipDefaultFiles) {
5429
- this.setupTestFiles(mockDirectoryData);
5430
- }
5431
- Object.freeze(this);
5435
+ /**
5436
+ * Delete file at the specified path
5437
+ */
5438
+ async deleteFile(relativePath) {
5439
+ return this.writer.deleteFile(relativePath);
5432
5440
  }
5433
5441
  /**
5434
- * PathSystem accessor (for testing)
5442
+ * Get file name from path
5435
5443
  */
5436
- getPathSystem() {
5437
- return this._pathSystem;
5444
+ readFileName(relativePath) {
5445
+ return this.reader.readFileName(relativePath);
5438
5446
  }
5439
5447
  /**
5440
- * Normalize path using basePath
5448
+ * Get file extension from path
5441
5449
  */
5442
- normalizePath(filePath) {
5443
- if (filePath.startsWith(this._basePath)) {
5444
- return filePath;
5445
- }
5446
- const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
5447
- return `${this._basePath}/${cleanPath}`;
5450
+ readFileExtension(relativePath) {
5451
+ return this.reader.readFileExtension(relativePath);
5448
5452
  }
5449
5453
  /**
5450
- * Create instance (mock data is automatically loaded)
5454
+ * Get directory path where the file exists
5451
5455
  */
5452
- static create(basePath = "/test") {
5453
- const pathSystem = new DocPathSystem();
5454
- return new _DocFileSystemMock({ basePath, pathSystem });
5456
+ readFileDirectory(relativePath) {
5457
+ return this.reader.readFileDirectory(relativePath);
5455
5458
  }
5456
5459
  /**
5457
- * Factory method for testing
5460
+ * Get list of entries in directory
5458
5461
  */
5459
- static createWithFiles(props) {
5460
- const pathSystem = new DocPathSystem();
5461
- const basePath = props.basePath ?? "/test";
5462
- const fileSystem = new _DocFileSystemMock({
5463
- basePath,
5464
- pathSystem,
5465
- skipDefaultFiles: true
5466
- });
5467
- if (props.fileContents) {
5468
- const now = /* @__PURE__ */ new Date();
5469
- for (const [path, content] of Object.entries(props.fileContents)) {
5470
- const cleanPath = path.startsWith("/") ? path.slice(1) : path;
5471
- const normalizedPath = path.startsWith(basePath) ? path : `${basePath}/${cleanPath}`;
5472
- fileSystem.files.set(normalizedPath, {
5473
- content,
5474
- modifiedTime: now,
5475
- createdTime: now,
5476
- size: new TextEncoder().encode(content).length
5477
- });
5478
- }
5479
- }
5480
- return fileSystem;
5462
+ async readDirectoryFileNames(relativePath = "") {
5463
+ return this.reader.readDirectoryFileNames(relativePath);
5481
5464
  }
5482
- async readFile(filePath) {
5483
- try {
5484
- const normalizedPath = this.normalizePath(filePath);
5485
- const file = this.files.get(normalizedPath);
5486
- return file ? file.content : null;
5487
- } catch (error) {
5488
- return error instanceof Error ? error : new Error(`Failed to read file at ${filePath}`);
5489
- }
5465
+ async readDirectoryFilePaths(relativePath) {
5466
+ return this.reader.readDirectoryFilePaths(relativePath);
5490
5467
  }
5491
- async writeFile(filePath, content) {
5492
- try {
5493
- const normalizedPath = this.normalizePath(filePath);
5494
- const now = /* @__PURE__ */ new Date();
5495
- const existing = this.files.get(normalizedPath);
5496
- this.files.set(normalizedPath, {
5497
- content,
5498
- modifiedTime: now,
5499
- createdTime: existing?.createdTime ?? now,
5500
- size: new TextEncoder().encode(content).length
5501
- });
5502
- return null;
5503
- } catch (error) {
5504
- return error instanceof Error ? error : new Error(`Failed to write file at ${filePath}`);
5505
- }
5468
+ /**
5469
+ * Check if path is a directory
5470
+ */
5471
+ async isDirectory(relativePath) {
5472
+ return this.reader.isDirectory(relativePath);
5473
+ }
5474
+ /**
5475
+ * Check if path is a file
5476
+ */
5477
+ async isFile(relativePath) {
5478
+ return this.reader.isFile(relativePath);
5479
+ }
5480
+ /**
5481
+ * Check if file or directory exists
5482
+ */
5483
+ async exists(relativePath) {
5484
+ return this.reader.exists(relativePath);
5485
+ }
5486
+ /**
5487
+ * Check if directory exists
5488
+ */
5489
+ async directoryExists(relativePath) {
5490
+ return this.reader.directoryExists(relativePath);
5491
+ }
5492
+ /**
5493
+ * Check if file exists
5494
+ */
5495
+ async fileExists(relativePath) {
5496
+ return this.reader.fileExists(relativePath);
5497
+ }
5498
+ /**
5499
+ * Get base path
5500
+ */
5501
+ getBasePath() {
5502
+ return this.reader.getBasePath();
5503
+ }
5504
+ /**
5505
+ * Convert relative path to absolute path
5506
+ */
5507
+ resolve(relativePath) {
5508
+ return this.reader.resolve(relativePath);
5509
+ }
5510
+ /**
5511
+ * Create directory
5512
+ */
5513
+ async createDirectory(relativePath) {
5514
+ return this.writer.createDirectory(relativePath);
5515
+ }
5516
+ /**
5517
+ * Get file size in bytes
5518
+ */
5519
+ async getFileSize(relativePath) {
5520
+ return this.reader.getFileSize(relativePath);
5521
+ }
5522
+ /**
5523
+ * Create directory if it doesn't exist
5524
+ */
5525
+ async ensureDirectoryExists(relativePath) {
5526
+ return this.writer.ensureDirectoryExists(relativePath);
5527
+ }
5528
+ /**
5529
+ * Copy file
5530
+ */
5531
+ async copyFile(sourcePath, destinationPath) {
5532
+ return this.writer.copyFile(sourcePath, destinationPath);
5533
+ }
5534
+ /**
5535
+ * Move file
5536
+ */
5537
+ async moveFile(sourcePath, destinationPath) {
5538
+ return this.writer.moveFile(sourcePath, destinationPath);
5539
+ }
5540
+ /**
5541
+ * Get file last modified time
5542
+ */
5543
+ async getFileModifiedTime(relativePath) {
5544
+ return this.reader.getFileModifiedTime(relativePath);
5545
+ }
5546
+ /**
5547
+ * Get file creation time
5548
+ */
5549
+ async getFileCreatedTime(relativePath) {
5550
+ return this.reader.getFileCreatedTime(relativePath);
5551
+ }
5552
+ };
5553
+
5554
+ // lib/doc-file-system-json.ts
5555
+ import { z as z4 } from "zod";
5556
+
5557
+ // lib/doc-file-system-json-read.ts
5558
+ import { z as z2 } from "zod";
5559
+ var zJsonDocumentData = z2.record(z2.string(), z2.string());
5560
+ function parseJsonDocumentData(data) {
5561
+ try {
5562
+ return zJsonDocumentData.parse(data);
5563
+ } catch (error) {
5564
+ return error instanceof Error ? error : new Error("Failed to parse JSON document data");
5565
+ }
5566
+ }
5567
+ var DocFileSystemJsonRead = class {
5568
+ data;
5569
+ basePath;
5570
+ pathSystem;
5571
+ constructor(props) {
5572
+ const parsed = parseJsonDocumentData(props.data);
5573
+ if (parsed instanceof Error) {
5574
+ throw parsed;
5575
+ }
5576
+ this.data = parsed;
5577
+ this.basePath = props.basePath ?? "json://";
5578
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
5579
+ Object.freeze(this);
5580
+ }
5581
+ /**
5582
+ * Read file content from JSON data
5583
+ */
5584
+ async readFile(relativePath) {
5585
+ try {
5586
+ const normalizedPath = this.normalizePath(relativePath);
5587
+ const content = this.data[normalizedPath];
5588
+ return content ?? null;
5589
+ } catch (error) {
5590
+ return error instanceof Error ? error : new Error(`Failed to read file at ${relativePath}`);
5591
+ }
5592
+ }
5593
+ /**
5594
+ * Get file name from path
5595
+ */
5596
+ readFileName(relativePath) {
5597
+ return this.pathSystem.basename(relativePath);
5598
+ }
5599
+ /**
5600
+ * Get file extension from path
5601
+ */
5602
+ readFileExtension(relativePath) {
5603
+ return this.pathSystem.extname(relativePath);
5604
+ }
5605
+ /**
5606
+ * Get directory path where the file exists
5607
+ */
5608
+ readFileDirectory(relativePath) {
5609
+ return this.pathSystem.dirname(relativePath);
5610
+ }
5611
+ /**
5612
+ * Get list of file names in directory
5613
+ */
5614
+ async readDirectoryFileNames(relativePath = "") {
5615
+ try {
5616
+ const normalizedDir = this.normalizePath(relativePath);
5617
+ const fileNames = /* @__PURE__ */ new Set();
5618
+ for (const filePath of Object.keys(this.data)) {
5619
+ if (this.isFileInDirectory(filePath, normalizedDir)) {
5620
+ const relativePart = this.getRelativePartFromDirectory(
5621
+ filePath,
5622
+ normalizedDir
5623
+ );
5624
+ const segments = relativePart.split("/").filter(Boolean);
5625
+ if (segments.length > 0) {
5626
+ fileNames.add(segments[0]);
5627
+ }
5628
+ }
5629
+ }
5630
+ return Array.from(fileNames).sort();
5631
+ } catch (error) {
5632
+ return error instanceof Error ? error : new Error(`Failed to read directory at ${relativePath}`);
5633
+ }
5634
+ }
5635
+ /**
5636
+ * Get list of file paths in directory
5637
+ */
5638
+ async readDirectoryFilePaths(relativePath) {
5639
+ try {
5640
+ const fileNames = await this.readDirectoryFileNames(relativePath);
5641
+ if (fileNames instanceof Error) {
5642
+ return fileNames;
5643
+ }
5644
+ return fileNames.map(
5645
+ (fileName) => this.pathSystem.join(relativePath, fileName)
5646
+ );
5647
+ } catch (error) {
5648
+ return error instanceof Error ? error : new Error(`Failed to read directory file paths at ${relativePath}`);
5649
+ }
5650
+ }
5651
+ /**
5652
+ * Check if path is a directory
5653
+ */
5654
+ async isDirectory(relativePath) {
5655
+ try {
5656
+ const normalizedPath = this.normalizePath(relativePath);
5657
+ for (const filePath of Object.keys(this.data)) {
5658
+ if (filePath.startsWith(`${normalizedPath}/`)) {
5659
+ return true;
5660
+ }
5661
+ }
5662
+ return false;
5663
+ } catch {
5664
+ return false;
5665
+ }
5666
+ }
5667
+ /**
5668
+ * Check if path is a file
5669
+ */
5670
+ async isFile(relativePath) {
5671
+ try {
5672
+ const normalizedPath = this.normalizePath(relativePath);
5673
+ return normalizedPath in this.data;
5674
+ } catch {
5675
+ return false;
5676
+ }
5677
+ }
5678
+ /**
5679
+ * Check if file or directory exists
5680
+ */
5681
+ async exists(relativePath) {
5682
+ const isFile = await this.isFile(relativePath);
5683
+ if (isFile) return true;
5684
+ const isDir = await this.isDirectory(relativePath);
5685
+ return isDir;
5686
+ }
5687
+ /**
5688
+ * Check if directory exists
5689
+ */
5690
+ async directoryExists(relativePath) {
5691
+ return this.isDirectory(relativePath);
5692
+ }
5693
+ /**
5694
+ * Check if file exists
5695
+ */
5696
+ async fileExists(relativePath) {
5697
+ return this.isFile(relativePath);
5698
+ }
5699
+ /**
5700
+ * Get base path
5701
+ */
5702
+ getBasePath() {
5703
+ return this.basePath;
5704
+ }
5705
+ /**
5706
+ * Convert relative path to absolute path
5707
+ */
5708
+ resolve(relativePath) {
5709
+ return this.pathSystem.join(this.basePath, relativePath);
5710
+ }
5711
+ /**
5712
+ * Get file size in bytes
5713
+ */
5714
+ async getFileSize(relativePath) {
5715
+ try {
5716
+ const content = await this.readFile(relativePath);
5717
+ if (content instanceof Error) {
5718
+ return content;
5719
+ }
5720
+ if (content === null) {
5721
+ return new Error(`File not found: ${relativePath}`);
5722
+ }
5723
+ return Buffer.byteLength(content, "utf8");
5724
+ } catch (error) {
5725
+ return error instanceof Error ? error : new Error(`Failed to get file size at ${relativePath}`);
5726
+ }
5727
+ }
5728
+ /**
5729
+ * Get file last modified time (not available for JSON data)
5730
+ */
5731
+ async getFileModifiedTime(_relativePath) {
5732
+ return new Error("File modified time not available for JSON data");
5733
+ }
5734
+ /**
5735
+ * Get file creation time (not available for JSON data)
5736
+ */
5737
+ async getFileCreatedTime(_relativePath) {
5738
+ return new Error("File creation time not available for JSON data");
5739
+ }
5740
+ /**
5741
+ * Get all file paths in the JSON data
5742
+ */
5743
+ getAllFilePaths() {
5744
+ return Object.keys(this.data);
5745
+ }
5746
+ /**
5747
+ * Get the raw JSON data
5748
+ */
5749
+ getRawData() {
5750
+ return { ...this.data };
5751
+ }
5752
+ /**
5753
+ * Normalize path by removing leading/trailing slashes
5754
+ */
5755
+ normalizePath(path) {
5756
+ return path.replace(/^\/+|\/+$/g, "");
5757
+ }
5758
+ /**
5759
+ * Check if a file path is within a directory
5760
+ */
5761
+ isFileInDirectory(filePath, dirPath) {
5762
+ if (dirPath === "") {
5763
+ return true;
5764
+ }
5765
+ return filePath.startsWith(`${dirPath}/`) || filePath === dirPath;
5766
+ }
5767
+ /**
5768
+ * Get the relative part of a file path from a directory
5769
+ */
5770
+ getRelativePartFromDirectory(filePath, dirPath) {
5771
+ if (dirPath === "") {
5772
+ return filePath;
5773
+ }
5774
+ if (filePath.startsWith(`${dirPath}/`)) {
5775
+ return filePath.slice(dirPath.length + 1);
5776
+ }
5777
+ return "";
5778
+ }
5779
+ };
5780
+
5781
+ // lib/doc-file-system-json-write.ts
5782
+ import { z as z3 } from "zod";
5783
+ var zJsonDocumentData2 = z3.record(z3.string(), z3.string());
5784
+ function parseJsonDocumentData2(data) {
5785
+ try {
5786
+ return zJsonDocumentData2.parse(data);
5787
+ } catch (error) {
5788
+ return error instanceof Error ? error : new Error("Failed to parse JSON document data");
5789
+ }
5790
+ }
5791
+ var DocFileSystemJsonWrite = class {
5792
+ data;
5793
+ basePath;
5794
+ pathSystem;
5795
+ reader;
5796
+ onDataChange;
5797
+ constructor(props = {}) {
5798
+ if (props.data !== void 0) {
5799
+ const parsed = parseJsonDocumentData2(props.data);
5800
+ if (parsed instanceof Error) {
5801
+ throw parsed;
5802
+ }
5803
+ this.data = parsed;
5804
+ } else {
5805
+ this.data = {};
5806
+ }
5807
+ this.basePath = props.basePath ?? "json://";
5808
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
5809
+ this.reader = props.reader;
5810
+ this.onDataChange = props.onDataChange;
5811
+ }
5812
+ /**
5813
+ * Write content to JSON data
5814
+ */
5815
+ async writeFile(relativePath, content) {
5816
+ try {
5817
+ const normalizedPath = this.normalizePath(relativePath);
5818
+ this.data[normalizedPath] = content;
5819
+ this.notifyDataChange();
5820
+ return null;
5821
+ } catch (error) {
5822
+ return error instanceof Error ? error : new Error(`Failed to write file at ${relativePath}`);
5823
+ }
5824
+ }
5825
+ /**
5826
+ * Delete file from JSON data
5827
+ */
5828
+ async deleteFile(relativePath) {
5829
+ try {
5830
+ const normalizedPath = this.normalizePath(relativePath);
5831
+ if (!(normalizedPath in this.data)) {
5832
+ return new Error(`File not found: ${relativePath}`);
5833
+ }
5834
+ delete this.data[normalizedPath];
5835
+ this.notifyDataChange();
5836
+ return null;
5837
+ } catch (error) {
5838
+ return error instanceof Error ? error : new Error(`Failed to delete file at ${relativePath}`);
5839
+ }
5840
+ }
5841
+ /**
5842
+ * Create directory (creates a placeholder entry)
5843
+ */
5844
+ async createDirectory(relativePath) {
5845
+ try {
5846
+ const normalizedPath = this.normalizePath(relativePath);
5847
+ const gitkeepPath = this.pathSystem.join(normalizedPath, ".gitkeep");
5848
+ const normalizedGitkeepPath = this.normalizePath(gitkeepPath);
5849
+ this.data[normalizedGitkeepPath] = "";
5850
+ this.notifyDataChange();
5851
+ return null;
5852
+ } catch (error) {
5853
+ return error instanceof Error ? error : new Error(`Failed to create directory at ${relativePath}`);
5854
+ }
5855
+ }
5856
+ /**
5857
+ * Create directory if it doesn't exist
5858
+ */
5859
+ async ensureDirectoryExists(relativePath) {
5860
+ try {
5861
+ if (this.reader) {
5862
+ const exists = await this.reader.exists(relativePath);
5863
+ if (exists) {
5864
+ return null;
5865
+ }
5866
+ } else {
5867
+ if (await this.directoryExistsInData(relativePath)) {
5868
+ return null;
5869
+ }
5870
+ }
5871
+ return await this.createDirectory(relativePath);
5872
+ } catch (error) {
5873
+ return error instanceof Error ? error : new Error(`Failed to ensure directory exists at ${relativePath}`);
5874
+ }
5875
+ }
5876
+ /**
5877
+ * Copy file within JSON data
5878
+ */
5879
+ async copyFile(sourcePath, destinationPath) {
5880
+ try {
5881
+ const normalizedSourcePath = this.normalizePath(sourcePath);
5882
+ const normalizedDestPath = this.normalizePath(destinationPath);
5883
+ if (this.reader) {
5884
+ const content = await this.reader.readFile(sourcePath);
5885
+ if (content instanceof Error) {
5886
+ return content;
5887
+ }
5888
+ if (content === null) {
5889
+ return new Error(`Source file not found: ${sourcePath}`);
5890
+ }
5891
+ this.data[normalizedDestPath] = content;
5892
+ } else {
5893
+ if (!(normalizedSourcePath in this.data)) {
5894
+ return new Error(`Source file not found: ${sourcePath}`);
5895
+ }
5896
+ this.data[normalizedDestPath] = this.data[normalizedSourcePath];
5897
+ }
5898
+ this.notifyDataChange();
5899
+ return null;
5900
+ } catch (error) {
5901
+ return error instanceof Error ? error : new Error(
5902
+ `Failed to copy file from ${sourcePath} to ${destinationPath}`
5903
+ );
5904
+ }
5905
+ }
5906
+ /**
5907
+ * Move file within JSON data
5908
+ */
5909
+ async moveFile(sourcePath, destinationPath) {
5910
+ try {
5911
+ const copyResult = await this.copyFile(sourcePath, destinationPath);
5912
+ if (copyResult !== null) {
5913
+ return copyResult;
5914
+ }
5915
+ return await this.deleteFile(sourcePath);
5916
+ } catch (error) {
5917
+ return error instanceof Error ? error : new Error(
5918
+ `Failed to move file from ${sourcePath} to ${destinationPath}`
5919
+ );
5920
+ }
5921
+ }
5922
+ /**
5923
+ * Get the current JSON data
5924
+ */
5925
+ getData() {
5926
+ return { ...this.data };
5927
+ }
5928
+ /**
5929
+ * Update the entire JSON data
5930
+ */
5931
+ setData(data) {
5932
+ try {
5933
+ const parsed = parseJsonDocumentData2(data);
5934
+ if (parsed instanceof Error) {
5935
+ return parsed;
5936
+ }
5937
+ this.data = parsed;
5938
+ this.notifyDataChange();
5939
+ return null;
5940
+ } catch (error) {
5941
+ return error instanceof Error ? error : new Error("Failed to set JSON data");
5942
+ }
5943
+ }
5944
+ /**
5945
+ * Clear all data
5946
+ */
5947
+ clear() {
5948
+ this.data = {};
5949
+ this.notifyDataChange();
5950
+ }
5951
+ /**
5952
+ * Get all file paths in the JSON data
5953
+ */
5954
+ getAllFilePaths() {
5955
+ return Object.keys(this.data);
5956
+ }
5957
+ /**
5958
+ * Normalize path by removing leading/trailing slashes
5959
+ */
5960
+ normalizePath(path) {
5961
+ return path.replace(/^\/+|\/+$/g, "");
5962
+ }
5963
+ /**
5964
+ * Check if directory exists in data
5965
+ */
5966
+ async directoryExistsInData(relativePath) {
5967
+ const normalizedPath = this.normalizePath(relativePath);
5968
+ for (const filePath of Object.keys(this.data)) {
5969
+ if (filePath.startsWith(`${normalizedPath}/`)) {
5970
+ return true;
5971
+ }
5972
+ }
5973
+ return false;
5974
+ }
5975
+ /**
5976
+ * Notify data change callback
5977
+ */
5978
+ notifyDataChange() {
5979
+ if (this.onDataChange) {
5980
+ this.onDataChange({ ...this.data });
5981
+ }
5982
+ }
5983
+ };
5984
+
5985
+ // lib/doc-file-system-json.ts
5986
+ var zJsonDocumentData3 = z4.record(z4.string(), z4.string());
5987
+ var DocFileSystemJson = class _DocFileSystemJson extends DocFileSystem {
5988
+ jsonReader;
5989
+ jsonWriter;
5990
+ constructor(props = {}) {
5991
+ const reader = new DocFileSystemJsonRead({
5992
+ data: props.data,
5993
+ basePath: props.basePath,
5994
+ pathSystem: props.pathSystem
5995
+ });
5996
+ const writer = new DocFileSystemJsonWrite({
5997
+ data: props.data,
5998
+ basePath: props.basePath,
5999
+ pathSystem: props.pathSystem,
6000
+ reader,
6001
+ onDataChange: props.onDataChange
6002
+ });
6003
+ super({
6004
+ basePath: props.basePath ?? "json://",
6005
+ pathSystem: props.pathSystem,
6006
+ reader,
6007
+ writer
6008
+ });
6009
+ this.jsonReader = reader;
6010
+ this.jsonWriter = writer;
6011
+ Object.freeze(this);
6012
+ }
6013
+ /**
6014
+ * Get the current JSON data
6015
+ */
6016
+ getData() {
6017
+ return this.jsonWriter.getData();
6018
+ }
6019
+ /**
6020
+ * Update the entire JSON data
6021
+ */
6022
+ setData(data) {
6023
+ return this.jsonWriter.setData(data);
6024
+ }
6025
+ /**
6026
+ * Clear all data
6027
+ */
6028
+ clear() {
6029
+ this.jsonWriter.clear();
6030
+ }
6031
+ /**
6032
+ * Get all file paths in the JSON data
6033
+ */
6034
+ getAllFilePaths() {
6035
+ return this.jsonReader.getAllFilePaths();
6036
+ }
6037
+ /**
6038
+ * Get the raw JSON data (read-only copy)
6039
+ */
6040
+ getRawData() {
6041
+ return this.jsonReader.getRawData();
6042
+ }
6043
+ /**
6044
+ * Create from docs-to-json format
6045
+ */
6046
+ static fromDocsToJson(data, options = {}) {
6047
+ return new _DocFileSystemJson({
6048
+ ...options,
6049
+ data
6050
+ });
6051
+ }
6052
+ /**
6053
+ * Export to docs-to-json format
6054
+ */
6055
+ toDocsToJson() {
6056
+ return this.getData();
6057
+ }
6058
+ };
6059
+
6060
+ // lib/doc-file-system-mock.ts
6061
+ var mockDirectoryData = {
6062
+ "docs/index.md": `---
6063
+ icon: \u{1F4DA}
6064
+ ---
6065
+
6066
+ # Documentation
6067
+
6068
+ Welcome to the documentation!`,
6069
+ "docs/guide/index.md": `---
6070
+ icon: \u{1F4D6}
6071
+ ---
6072
+
6073
+ # Guide
6074
+
6075
+ This is a guide.`,
6076
+ "docs/guide/getting-started.md": `# Getting Started
6077
+
6078
+ Let's get started!`,
6079
+ "docs/guide/advanced.md": `# Advanced
6080
+
6081
+ Advanced topics here.`,
6082
+ "docs/api/index.md": `---
6083
+ icon: \u{1F527}
6084
+ ---
6085
+
6086
+ # API
6087
+
6088
+ API documentation.`,
6089
+ "docs/api/reference.md": `# API Reference
6090
+
6091
+ Complete API reference.`
6092
+ };
6093
+ var DocFileSystemMock = class _DocFileSystemMock extends DocFileSystem {
6094
+ files = /* @__PURE__ */ new Map();
6095
+ _pathSystem;
6096
+ _basePath;
6097
+ constructor(props) {
6098
+ super(props);
6099
+ this._pathSystem = props.pathSystem;
6100
+ this._basePath = props.basePath.endsWith("/") ? props.basePath.slice(0, -1) : props.basePath;
6101
+ if (!props.skipDefaultFiles) {
6102
+ this.setupTestFiles(mockDirectoryData);
6103
+ }
6104
+ Object.freeze(this);
6105
+ }
6106
+ /**
6107
+ * PathSystem accessor (for testing)
6108
+ */
6109
+ getPathSystem() {
6110
+ return this._pathSystem;
6111
+ }
6112
+ /**
6113
+ * Normalize path using basePath
6114
+ */
6115
+ normalizePath(filePath) {
6116
+ if (filePath.startsWith(this._basePath)) {
6117
+ return filePath;
6118
+ }
6119
+ const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
6120
+ return `${this._basePath}/${cleanPath}`;
6121
+ }
6122
+ /**
6123
+ * Create instance (mock data is automatically loaded)
6124
+ */
6125
+ static create(basePath = "/test") {
6126
+ const pathSystem = new DocPathSystem();
6127
+ return new _DocFileSystemMock({ basePath, pathSystem });
6128
+ }
6129
+ /**
6130
+ * Factory method for testing
6131
+ */
6132
+ static createWithFiles(props) {
6133
+ const pathSystem = new DocPathSystem();
6134
+ const basePath = props.basePath ?? "/test";
6135
+ const fileSystem = new _DocFileSystemMock({
6136
+ basePath,
6137
+ pathSystem,
6138
+ skipDefaultFiles: true
6139
+ });
6140
+ if (props.fileContents) {
6141
+ const now = /* @__PURE__ */ new Date();
6142
+ for (const [path, content] of Object.entries(props.fileContents)) {
6143
+ const cleanPath = path.startsWith("/") ? path.slice(1) : path;
6144
+ const normalizedPath = path.startsWith(basePath) ? path : `${basePath}/${cleanPath}`;
6145
+ fileSystem.files.set(normalizedPath, {
6146
+ content,
6147
+ modifiedTime: now,
6148
+ createdTime: now,
6149
+ size: new TextEncoder().encode(content).length
6150
+ });
6151
+ }
6152
+ }
6153
+ return fileSystem;
6154
+ }
6155
+ async readFile(filePath) {
6156
+ try {
6157
+ const normalizedPath = this.normalizePath(filePath);
6158
+ const file = this.files.get(normalizedPath);
6159
+ return file ? file.content : null;
6160
+ } catch (error) {
6161
+ return error instanceof Error ? error : new Error(`Failed to read file at ${filePath}`);
6162
+ }
6163
+ }
6164
+ async writeFile(filePath, content) {
6165
+ try {
6166
+ const normalizedPath = this.normalizePath(filePath);
6167
+ const now = /* @__PURE__ */ new Date();
6168
+ const existing = this.files.get(normalizedPath);
6169
+ this.files.set(normalizedPath, {
6170
+ content,
6171
+ modifiedTime: now,
6172
+ createdTime: existing?.createdTime ?? now,
6173
+ size: new TextEncoder().encode(content).length
6174
+ });
6175
+ return null;
6176
+ } catch (error) {
6177
+ return error instanceof Error ? error : new Error(`Failed to write file at ${filePath}`);
6178
+ }
5506
6179
  }
5507
6180
  async deleteFile(filePath) {
5508
6181
  try {
@@ -5621,64 +6294,288 @@ var DocFileSystemMock = class _DocFileSystemMock extends DocFileSystem {
5621
6294
  return error instanceof Error ? error : new Error(`Failed to get file size at ${filePath}`);
5622
6295
  }
5623
6296
  }
5624
- async getFileModifiedTime(filePath) {
6297
+ async getFileModifiedTime(filePath) {
6298
+ try {
6299
+ const normalizedPath = this.normalizePath(filePath);
6300
+ const file = this.files.get(normalizedPath);
6301
+ if (!file) {
6302
+ return new Error(`File not found: ${normalizedPath}`);
6303
+ }
6304
+ return file.modifiedTime;
6305
+ } catch (error) {
6306
+ return error instanceof Error ? error : new Error(`Failed to get file modified time at ${filePath}`);
6307
+ }
6308
+ }
6309
+ async getFileCreatedTime(filePath) {
6310
+ try {
6311
+ const normalizedPath = this.normalizePath(filePath);
6312
+ const file = this.files.get(normalizedPath);
6313
+ if (!file) {
6314
+ return new Error(`File not found: ${normalizedPath}`);
6315
+ }
6316
+ return file.createdTime;
6317
+ } catch (error) {
6318
+ return error instanceof Error ? error : new Error(`Failed to get file created time at ${filePath}`);
6319
+ }
6320
+ }
6321
+ async isDirectory(relativePath) {
6322
+ const normalizedPath = this.normalizePath(relativePath);
6323
+ const dirPath = normalizedPath.endsWith("/") ? normalizedPath : `${normalizedPath}/`;
6324
+ for (const path of this.files.keys()) {
6325
+ if (path.startsWith(dirPath)) {
6326
+ return true;
6327
+ }
6328
+ }
6329
+ return false;
6330
+ }
6331
+ async isFile(relativePath) {
6332
+ const normalizedPath = this.normalizePath(relativePath);
6333
+ return this.files.has(normalizedPath);
6334
+ }
6335
+ /**
6336
+ * Get list of entries in directory
6337
+ */
6338
+ async readDirectoryFileNames(directoryPath = "") {
6339
+ try {
6340
+ const normalizedDir = directoryPath === "" ? this._basePath : this.normalizePath(directoryPath);
6341
+ const dirPath = normalizedDir.endsWith("/") ? normalizedDir : `${normalizedDir}/`;
6342
+ const entries = /* @__PURE__ */ new Set();
6343
+ for (const path of this.files.keys()) {
6344
+ if (path.startsWith(dirPath)) {
6345
+ const relativePath = path.slice(dirPath.length);
6346
+ const firstSegment = relativePath.split("/")[0];
6347
+ if (firstSegment) {
6348
+ entries.add(firstSegment);
6349
+ }
6350
+ }
6351
+ }
6352
+ return Array.from(entries).sort();
6353
+ } catch (error) {
6354
+ return error instanceof Error ? error : new Error(`Failed to read directory at ${directoryPath}`);
6355
+ }
6356
+ }
6357
+ /**
6358
+ * Check if directory exists
6359
+ */
6360
+ async directoryExists(relativePath) {
6361
+ return this.isDirectory(relativePath);
6362
+ }
6363
+ /**
6364
+ * Check if file exists
6365
+ */
6366
+ async fileExists(relativePath) {
6367
+ return this.isFile(relativePath);
6368
+ }
6369
+ /**
6370
+ * Create directory if it doesn't exist
6371
+ */
6372
+ async ensureDirectoryExists(_relativePath) {
6373
+ return null;
6374
+ }
6375
+ /**
6376
+ * Clear all files
6377
+ */
6378
+ clear() {
6379
+ this.files.clear();
6380
+ }
6381
+ /**
6382
+ * Check file existence (for testing)
6383
+ */
6384
+ hasFile(filePath) {
6385
+ const normalizedPath = this.normalizePath(filePath);
6386
+ return this.files.has(normalizedPath);
6387
+ }
6388
+ /**
6389
+ * Get file content (sync version, for testing)
6390
+ */
6391
+ getFileContent(filePath) {
6392
+ const normalizedPath = this.normalizePath(filePath);
6393
+ return this.files.get(normalizedPath)?.content;
6394
+ }
6395
+ /**
6396
+ * Get all file paths (for testing)
6397
+ */
6398
+ getAllFilePaths() {
6399
+ return Array.from(this.files.keys()).map((path) => {
6400
+ return path.startsWith(`${this._basePath}/`) ? path.slice(this._basePath.length + 1) : path;
6401
+ }).sort();
6402
+ }
6403
+ /**
6404
+ * Get file count (for testing)
6405
+ */
6406
+ getFileCount() {
6407
+ return this.files.size;
6408
+ }
6409
+ /**
6410
+ * Setup test data
6411
+ */
6412
+ setupTestFiles(files) {
6413
+ const now = /* @__PURE__ */ new Date();
6414
+ for (const [path, content] of Object.entries(files)) {
6415
+ const normalizedPath = this.normalizePath(path);
6416
+ this.files.set(normalizedPath, {
6417
+ content,
6418
+ modifiedTime: now,
6419
+ createdTime: now,
6420
+ size: new TextEncoder().encode(content).length
6421
+ });
6422
+ }
6423
+ }
6424
+ };
6425
+
6426
+ // lib/doc-file-system-octokit-read.ts
6427
+ import { Octokit } from "@octokit/rest";
6428
+ var DocFileSystemOctokitRead = class {
6429
+ octokit;
6430
+ owner;
6431
+ repo;
6432
+ branch;
6433
+ pathSystem;
6434
+ basePath;
6435
+ fileCache = /* @__PURE__ */ new Map();
6436
+ constructor(props) {
6437
+ this.owner = props.owner;
6438
+ this.repo = props.repo;
6439
+ this.branch = props.branch ?? "main";
6440
+ this.basePath = props.basePath;
6441
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
6442
+ this.octokit = new Octokit({ auth: props.token });
6443
+ Object.freeze(this);
6444
+ }
6445
+ /**
6446
+ * Read file content from GitHub repository
6447
+ */
6448
+ async readFile(relativePath) {
6449
+ try {
6450
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
6451
+ const response = await this.octokit.repos.getContent({
6452
+ owner: this.owner,
6453
+ repo: this.repo,
6454
+ path: fullPath,
6455
+ ref: this.branch
6456
+ });
6457
+ if ("type" in response.data && response.data.type === "file") {
6458
+ const content = Buffer.from(response.data.content, "base64").toString(
6459
+ "utf-8"
6460
+ );
6461
+ this.fileCache.set(fullPath, {
6462
+ sha: response.data.sha,
6463
+ content,
6464
+ size: response.data.size
6465
+ });
6466
+ return content;
6467
+ }
6468
+ return new Error(`Path ${relativePath} is not a file`);
6469
+ } catch (error) {
6470
+ if (error && typeof error === "object" && "status" in error && error.status === 404) {
6471
+ return null;
6472
+ }
6473
+ return error instanceof Error ? error : new Error(`Failed to read file at ${relativePath}`);
6474
+ }
6475
+ }
6476
+ /**
6477
+ * Get file name from path
6478
+ */
6479
+ readFileName(relativePath) {
6480
+ return this.pathSystem.basename(relativePath);
6481
+ }
6482
+ /**
6483
+ * Get file extension from path
6484
+ */
6485
+ readFileExtension(relativePath) {
6486
+ return this.pathSystem.extname(relativePath);
6487
+ }
6488
+ /**
6489
+ * Get directory path where the file exists
6490
+ */
6491
+ readFileDirectory(relativePath) {
6492
+ return this.pathSystem.dirname(relativePath);
6493
+ }
6494
+ /**
6495
+ * Get list of file names in directory
6496
+ */
6497
+ async readDirectoryFileNames(relativePath = "") {
5625
6498
  try {
5626
- const normalizedPath = this.normalizePath(filePath);
5627
- const file = this.files.get(normalizedPath);
5628
- if (!file) {
5629
- return new Error(`File not found: ${normalizedPath}`);
6499
+ const fullPath = relativePath ? this.pathSystem.join(this.basePath, relativePath) : this.basePath;
6500
+ const response = await this.octokit.repos.getContent({
6501
+ owner: this.owner,
6502
+ repo: this.repo,
6503
+ path: fullPath,
6504
+ ref: this.branch
6505
+ });
6506
+ if (Array.isArray(response.data)) {
6507
+ return response.data.map((item) => item.name);
5630
6508
  }
5631
- return file.modifiedTime;
6509
+ return new Error(`Path ${relativePath} is not a directory`);
5632
6510
  } catch (error) {
5633
- return error instanceof Error ? error : new Error(`Failed to get file modified time at ${filePath}`);
6511
+ return error instanceof Error ? error : new Error(`Failed to read directory at ${relativePath}`);
5634
6512
  }
5635
6513
  }
5636
- async getFileCreatedTime(filePath) {
6514
+ /**
6515
+ * Get list of file paths in directory
6516
+ */
6517
+ async readDirectoryFilePaths(relativePath) {
5637
6518
  try {
5638
- const normalizedPath = this.normalizePath(filePath);
5639
- const file = this.files.get(normalizedPath);
5640
- if (!file) {
5641
- return new Error(`File not found: ${normalizedPath}`);
6519
+ const fileNames = await this.readDirectoryFileNames(relativePath);
6520
+ if (fileNames instanceof Error) {
6521
+ return fileNames;
5642
6522
  }
5643
- return file.createdTime;
6523
+ return fileNames.map(
6524
+ (fileName) => this.pathSystem.join(relativePath, fileName)
6525
+ );
5644
6526
  } catch (error) {
5645
- return error instanceof Error ? error : new Error(`Failed to get file created time at ${filePath}`);
6527
+ return error instanceof Error ? error : new Error(`Failed to read directory file paths at ${relativePath}`);
5646
6528
  }
5647
6529
  }
6530
+ /**
6531
+ * Check if path is a directory
6532
+ */
5648
6533
  async isDirectory(relativePath) {
5649
- const normalizedPath = this.normalizePath(relativePath);
5650
- const dirPath = normalizedPath.endsWith("/") ? normalizedPath : `${normalizedPath}/`;
5651
- for (const path of this.files.keys()) {
5652
- if (path.startsWith(dirPath)) {
5653
- return true;
5654
- }
6534
+ try {
6535
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
6536
+ const response = await this.octokit.repos.getContent({
6537
+ owner: this.owner,
6538
+ repo: this.repo,
6539
+ path: fullPath,
6540
+ ref: this.branch
6541
+ });
6542
+ return Array.isArray(response.data);
6543
+ } catch {
6544
+ return false;
5655
6545
  }
5656
- return false;
5657
6546
  }
6547
+ /**
6548
+ * Check if path is a file
6549
+ */
5658
6550
  async isFile(relativePath) {
5659
- const normalizedPath = this.normalizePath(relativePath);
5660
- return this.files.has(normalizedPath);
6551
+ try {
6552
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
6553
+ const response = await this.octokit.repos.getContent({
6554
+ owner: this.owner,
6555
+ repo: this.repo,
6556
+ path: fullPath,
6557
+ ref: this.branch
6558
+ });
6559
+ return !Array.isArray(response.data) && response.data.type === "file";
6560
+ } catch {
6561
+ return false;
6562
+ }
5661
6563
  }
5662
6564
  /**
5663
- * Get list of entries in directory
6565
+ * Check if file or directory exists
5664
6566
  */
5665
- async readDirectoryFileNames(directoryPath = "") {
6567
+ async exists(relativePath) {
5666
6568
  try {
5667
- const normalizedDir = directoryPath === "" ? this._basePath : this.normalizePath(directoryPath);
5668
- const dirPath = normalizedDir.endsWith("/") ? normalizedDir : `${normalizedDir}/`;
5669
- const entries = /* @__PURE__ */ new Set();
5670
- for (const path of this.files.keys()) {
5671
- if (path.startsWith(dirPath)) {
5672
- const relativePath = path.slice(dirPath.length);
5673
- const firstSegment = relativePath.split("/")[0];
5674
- if (firstSegment) {
5675
- entries.add(firstSegment);
5676
- }
5677
- }
5678
- }
5679
- return Array.from(entries).sort();
5680
- } catch (error) {
5681
- return error instanceof Error ? error : new Error(`Failed to read directory at ${directoryPath}`);
6569
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
6570
+ await this.octokit.repos.getContent({
6571
+ owner: this.owner,
6572
+ repo: this.repo,
6573
+ path: fullPath,
6574
+ ref: this.branch
6575
+ });
6576
+ return true;
6577
+ } catch {
6578
+ return false;
5682
6579
  }
5683
6580
  }
5684
6581
  /**
@@ -5694,62 +6591,303 @@ var DocFileSystemMock = class _DocFileSystemMock extends DocFileSystem {
5694
6591
  return this.isFile(relativePath);
5695
6592
  }
5696
6593
  /**
5697
- * Create directory if it doesn't exist
6594
+ * Get base path
5698
6595
  */
5699
- async ensureDirectoryExists(_relativePath) {
5700
- return null;
6596
+ getBasePath() {
6597
+ return this.basePath;
5701
6598
  }
5702
6599
  /**
5703
- * Clear all files
6600
+ * Convert relative path to absolute path
5704
6601
  */
5705
- clear() {
5706
- this.files.clear();
6602
+ resolve(relativePath) {
6603
+ return this.pathSystem.join(this.basePath, relativePath);
5707
6604
  }
5708
6605
  /**
5709
- * Check file existence (for testing)
6606
+ * Get file size in bytes
5710
6607
  */
5711
- hasFile(filePath) {
5712
- const normalizedPath = this.normalizePath(filePath);
5713
- return this.files.has(normalizedPath);
6608
+ async getFileSize(relativePath) {
6609
+ try {
6610
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
6611
+ const cached = this.fileCache.get(fullPath);
6612
+ if (cached) {
6613
+ return cached.size;
6614
+ }
6615
+ const response = await this.octokit.repos.getContent({
6616
+ owner: this.owner,
6617
+ repo: this.repo,
6618
+ path: fullPath,
6619
+ ref: this.branch
6620
+ });
6621
+ if ("size" in response.data) {
6622
+ return response.data.size;
6623
+ }
6624
+ return new Error(`Cannot get size for ${relativePath}`);
6625
+ } catch (error) {
6626
+ return error instanceof Error ? error : new Error(`Failed to get file size at ${relativePath}`);
6627
+ }
5714
6628
  }
5715
6629
  /**
5716
- * Get file content (sync version, for testing)
6630
+ * Get file last modified time
5717
6631
  */
5718
- getFileContent(filePath) {
5719
- const normalizedPath = this.normalizePath(filePath);
5720
- return this.files.get(normalizedPath)?.content;
6632
+ async getFileModifiedTime(relativePath) {
6633
+ try {
6634
+ const commits = await this.octokit.repos.listCommits({
6635
+ owner: this.owner,
6636
+ repo: this.repo,
6637
+ path: relativePath,
6638
+ sha: this.branch,
6639
+ per_page: 1
6640
+ });
6641
+ if (commits.data.length > 0 && commits.data[0].commit.author?.date) {
6642
+ return new Date(commits.data[0].commit.author.date);
6643
+ }
6644
+ return new Error(`No commits found for ${relativePath}`);
6645
+ } catch (error) {
6646
+ return error instanceof Error ? error : new Error(`Failed to get file modified time at ${relativePath}`);
6647
+ }
5721
6648
  }
5722
6649
  /**
5723
- * Get all file paths (for testing)
6650
+ * Get file creation time (first commit)
5724
6651
  */
5725
- getAllFilePaths() {
5726
- return Array.from(this.files.keys()).map((path) => {
5727
- return path.startsWith(`${this._basePath}/`) ? path.slice(this._basePath.length + 1) : path;
5728
- }).sort();
6652
+ async getFileCreatedTime(relativePath) {
6653
+ try {
6654
+ const commits = await this.octokit.repos.listCommits({
6655
+ owner: this.owner,
6656
+ repo: this.repo,
6657
+ path: relativePath,
6658
+ sha: this.branch
6659
+ });
6660
+ const lastCommit = commits.data[commits.data.length - 1];
6661
+ if (lastCommit?.commit.author?.date) {
6662
+ return new Date(lastCommit.commit.author.date);
6663
+ }
6664
+ return new Error(`No commits found for ${relativePath}`);
6665
+ } catch (error) {
6666
+ return error instanceof Error ? error : new Error(`Failed to get file created time at ${relativePath}`);
6667
+ }
5729
6668
  }
5730
6669
  /**
5731
- * Get file count (for testing)
6670
+ * Get cached SHA for a file
5732
6671
  */
5733
- getFileCount() {
5734
- return this.files.size;
6672
+ getCachedSha(relativePath) {
6673
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
6674
+ return this.fileCache.get(fullPath)?.sha;
6675
+ }
6676
+ };
6677
+
6678
+ // lib/doc-file-system-octokit-write.ts
6679
+ import { Octokit as Octokit2 } from "@octokit/rest";
6680
+ var DocFileSystemOctokitWrite = class {
6681
+ octokit;
6682
+ owner;
6683
+ repo;
6684
+ basePath;
6685
+ branch;
6686
+ pathSystem;
6687
+ reader;
6688
+ constructor(props) {
6689
+ this.owner = props.owner;
6690
+ this.repo = props.repo;
6691
+ this.basePath = props.basePath;
6692
+ this.branch = props.branch ?? "main";
6693
+ this.pathSystem = props.pathSystem ?? new DocPathSystem();
6694
+ this.octokit = new Octokit2({ auth: props.token });
6695
+ this.reader = props.reader;
6696
+ Object.freeze(this);
5735
6697
  }
5736
6698
  /**
5737
- * Setup test data
6699
+ * Write content to file in GitHub repository
5738
6700
  */
5739
- setupTestFiles(files) {
5740
- const now = /* @__PURE__ */ new Date();
5741
- for (const [path, content] of Object.entries(files)) {
5742
- const normalizedPath = this.normalizePath(path);
5743
- this.files.set(normalizedPath, {
5744
- content,
5745
- modifiedTime: now,
5746
- createdTime: now,
5747
- size: new TextEncoder().encode(content).length
6701
+ async writeFile(relativePath, content) {
6702
+ try {
6703
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
6704
+ const encodedContent = Buffer.from(content).toString("base64");
6705
+ let sha;
6706
+ if (this.reader && "getCachedSha" in this.reader) {
6707
+ sha = this.reader.getCachedSha(
6708
+ relativePath
6709
+ );
6710
+ }
6711
+ if (!sha) {
6712
+ try {
6713
+ const existing = await this.octokit.repos.getContent({
6714
+ owner: this.owner,
6715
+ repo: this.repo,
6716
+ path: fullPath,
6717
+ ref: this.branch
6718
+ });
6719
+ if ("sha" in existing.data) {
6720
+ sha = existing.data.sha;
6721
+ }
6722
+ } catch {
6723
+ }
6724
+ }
6725
+ await this.octokit.repos.createOrUpdateFileContents({
6726
+ owner: this.owner,
6727
+ repo: this.repo,
6728
+ path: fullPath,
6729
+ message: `Update ${fullPath}`,
6730
+ content: encodedContent,
6731
+ branch: this.branch,
6732
+ sha
6733
+ });
6734
+ return null;
6735
+ } catch (error) {
6736
+ return error instanceof Error ? error : new Error(`Failed to write file at ${relativePath}`);
6737
+ }
6738
+ }
6739
+ /**
6740
+ * Delete file from GitHub repository
6741
+ */
6742
+ async deleteFile(relativePath) {
6743
+ try {
6744
+ const fullPath = this.pathSystem.join(this.basePath, relativePath);
6745
+ let sha;
6746
+ if (this.reader && "getCachedSha" in this.reader) {
6747
+ sha = this.reader.getCachedSha(
6748
+ relativePath
6749
+ );
6750
+ }
6751
+ if (!sha) {
6752
+ const existing = await this.octokit.repos.getContent({
6753
+ owner: this.owner,
6754
+ repo: this.repo,
6755
+ path: fullPath,
6756
+ ref: this.branch
6757
+ });
6758
+ if ("sha" in existing.data) {
6759
+ sha = existing.data.sha;
6760
+ }
6761
+ }
6762
+ if (!sha) {
6763
+ return new Error(`Cannot delete file at ${relativePath}: SHA not found`);
6764
+ }
6765
+ await this.octokit.repos.deleteFile({
6766
+ owner: this.owner,
6767
+ repo: this.repo,
6768
+ path: fullPath,
6769
+ message: `Delete ${fullPath}`,
6770
+ sha,
6771
+ branch: this.branch
5748
6772
  });
6773
+ return null;
6774
+ } catch (error) {
6775
+ return error instanceof Error ? error : new Error(`Failed to delete file at ${relativePath}`);
6776
+ }
6777
+ }
6778
+ /**
6779
+ * Create directory by creating a .gitkeep file
6780
+ */
6781
+ async createDirectory(relativePath) {
6782
+ try {
6783
+ const gitkeepPath = this.pathSystem.join(relativePath, ".gitkeep");
6784
+ return await this.writeFile(gitkeepPath, "");
6785
+ } catch (error) {
6786
+ return error instanceof Error ? error : new Error(`Failed to create directory at ${relativePath}`);
6787
+ }
6788
+ }
6789
+ /**
6790
+ * Create directory if it doesn't exist
6791
+ */
6792
+ async ensureDirectoryExists(relativePath) {
6793
+ try {
6794
+ if (this.reader) {
6795
+ const exists = await this.reader.exists(relativePath);
6796
+ if (exists) {
6797
+ return null;
6798
+ }
6799
+ }
6800
+ return await this.createDirectory(relativePath);
6801
+ } catch (error) {
6802
+ return error instanceof Error ? error : new Error(`Failed to ensure directory exists at ${relativePath}`);
6803
+ }
6804
+ }
6805
+ /**
6806
+ * Copy file to new location
6807
+ */
6808
+ async copyFile(sourcePath, destinationPath) {
6809
+ try {
6810
+ if (!this.reader) {
6811
+ return new Error("Reader is required for copy operation");
6812
+ }
6813
+ const content = await this.reader.readFile(sourcePath);
6814
+ if (content instanceof Error) {
6815
+ return content;
6816
+ }
6817
+ if (content === null) {
6818
+ return new Error(`Source file ${sourcePath} does not exist`);
6819
+ }
6820
+ return await this.writeFile(destinationPath, content);
6821
+ } catch (error) {
6822
+ return error instanceof Error ? error : new Error(
6823
+ `Failed to copy file from ${sourcePath} to ${destinationPath}`
6824
+ );
6825
+ }
6826
+ }
6827
+ /**
6828
+ * Move file to new location
6829
+ */
6830
+ async moveFile(sourcePath, destinationPath) {
6831
+ try {
6832
+ const copyResult = await this.copyFile(sourcePath, destinationPath);
6833
+ if (copyResult !== null) {
6834
+ return copyResult;
6835
+ }
6836
+ return await this.deleteFile(sourcePath);
6837
+ } catch (error) {
6838
+ return error instanceof Error ? error : new Error(
6839
+ `Failed to move file from ${sourcePath} to ${destinationPath}`
6840
+ );
5749
6841
  }
5750
6842
  }
5751
6843
  };
5752
6844
 
6845
+ // lib/doc-file-system-octokit.ts
6846
+ var DocFileSystemOctokit = class extends DocFileSystem {
6847
+ owner;
6848
+ repo;
6849
+ branch;
6850
+ constructor(props) {
6851
+ const reader = new DocFileSystemOctokitRead({
6852
+ owner: props.owner,
6853
+ repo: props.repo,
6854
+ basePath: props.basePath,
6855
+ branch: props.branch,
6856
+ token: props.token,
6857
+ pathSystem: props.pathSystem
6858
+ });
6859
+ const writer = new DocFileSystemOctokitWrite({
6860
+ owner: props.owner,
6861
+ repo: props.repo,
6862
+ basePath: props.basePath,
6863
+ branch: props.branch,
6864
+ token: props.token,
6865
+ pathSystem: props.pathSystem,
6866
+ reader
6867
+ });
6868
+ super({
6869
+ basePath: props.basePath,
6870
+ pathSystem: props.pathSystem,
6871
+ reader,
6872
+ writer
6873
+ });
6874
+ this.owner = props.owner;
6875
+ this.repo = props.repo;
6876
+ this.branch = props.branch ?? "main";
6877
+ Object.freeze(this);
6878
+ }
6879
+ /**
6880
+ * Get repository information
6881
+ */
6882
+ getRepositoryInfo() {
6883
+ return {
6884
+ owner: this.owner,
6885
+ repo: this.repo,
6886
+ branch: this.branch
6887
+ };
6888
+ }
6889
+ };
6890
+
5753
6891
  // lib/doc-path-system-mock.ts
5754
6892
  var DocPathSystemMock = class _DocPathSystemMock extends DocPathSystem {
5755
6893
  _separator;
@@ -6390,7 +7528,15 @@ export {
6390
7528
  DocFilePathValue,
6391
7529
  DocFileRelationReference,
6392
7530
  DocFileSystem,
7531
+ DocFileSystemJson,
7532
+ DocFileSystemJsonRead,
7533
+ DocFileSystemJsonWrite,
6393
7534
  DocFileSystemMock,
7535
+ DocFileSystemOctokit,
7536
+ DocFileSystemOctokitRead,
7537
+ DocFileSystemOctokitWrite,
7538
+ DocFileSystemRead,
7539
+ DocFileSystemWrite,
6394
7540
  DocFileTreeSystem,
6395
7541
  DocFileUnknownEntity,
6396
7542
  DocFileUnknownReference,