@interactive-inc/docs-client 1.0.18 → 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
@@ -4255,11 +4255,23 @@ var DocDirectoryReference = class _DocDirectoryReference {
4255
4255
  get config() {
4256
4256
  return this.props.config;
4257
4257
  }
4258
- get relativePath() {
4258
+ get path() {
4259
4259
  return this.props.path;
4260
4260
  }
4261
+ /**
4262
+ * @deprecated
4263
+ */
4264
+ get relativePath() {
4265
+ return this.path;
4266
+ }
4267
+ get fullPath() {
4268
+ return this.pathSystem.join(this.basePath, this.path);
4269
+ }
4270
+ /**
4271
+ * @deprecated
4272
+ */
4261
4273
  get absolutePath() {
4262
- return this.pathSystem.join(this.basePath, this.relativePath);
4274
+ return this.fullPath;
4263
4275
  }
4264
4276
  get indexFileName() {
4265
4277
  return this.props.indexFileName;
@@ -4275,7 +4287,7 @@ var DocDirectoryReference = class _DocDirectoryReference {
4275
4287
  return this.props.archiveDirectoryName;
4276
4288
  }
4277
4289
  get name() {
4278
- return this.pathSystem.basename(this.relativePath);
4290
+ return this.pathSystem.basename(this.path);
4279
4291
  }
4280
4292
  async fileNames() {
4281
4293
  const filePaths = await this.fileSystem.readDirectoryFilePaths(
@@ -5126,9 +5138,9 @@ var DocClient = class {
5126
5138
  }
5127
5139
  };
5128
5140
 
5129
- // lib/doc-file-system.ts
5141
+ // lib/doc-file-system-read.ts
5130
5142
  import * as fs from "fs/promises";
5131
- var DocFileSystem = class {
5143
+ var DocFileSystemRead = class {
5132
5144
  basePath;
5133
5145
  pathSystem;
5134
5146
  constructor(props) {
@@ -5148,32 +5160,6 @@ var DocFileSystem = class {
5148
5160
  return error instanceof Error ? error : new Error(`Failed to read file at ${relativePath}`);
5149
5161
  }
5150
5162
  }
5151
- /**
5152
- * Write content to file at the specified path (creates directory if needed)
5153
- */
5154
- async writeFile(relativePath, content) {
5155
- try {
5156
- const fullPath = this.pathSystem.join(this.basePath, relativePath);
5157
- const dirPath = this.pathSystem.dirname(fullPath);
5158
- await fs.mkdir(dirPath, { recursive: true });
5159
- await fs.writeFile(fullPath, content, "utf-8");
5160
- return null;
5161
- } catch (error) {
5162
- return error instanceof Error ? error : new Error(`Failed to write file at ${relativePath}`);
5163
- }
5164
- }
5165
- /**
5166
- * Delete file at the specified path
5167
- */
5168
- async deleteFile(relativePath) {
5169
- try {
5170
- const fullPath = this.pathSystem.join(this.basePath, relativePath);
5171
- await fs.unlink(fullPath);
5172
- return null;
5173
- } catch (error) {
5174
- return new Error(`Failed to delete file at ${relativePath}: ${error}`);
5175
- }
5176
- }
5177
5163
  /**
5178
5164
  * Get file name from path
5179
5165
  */
@@ -5277,27 +5263,90 @@ var DocFileSystem = class {
5277
5263
  return this.pathSystem.join(this.basePath, relativePath);
5278
5264
  }
5279
5265
  /**
5280
- * Create directory
5266
+ * Get file size in bytes
5281
5267
  */
5282
- async createDirectory(relativePath) {
5268
+ async getFileSize(relativePath) {
5283
5269
  try {
5284
5270
  const fullPath = this.pathSystem.join(this.basePath, relativePath);
5285
- await fs.mkdir(fullPath, { recursive: true });
5286
- return null;
5271
+ const stats = await fs.stat(fullPath);
5272
+ return stats.size;
5287
5273
  } catch (error) {
5288
- 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}`);
5289
5275
  }
5290
5276
  }
5291
5277
  /**
5292
- * Get file size in bytes
5278
+ * Get file last modified time
5293
5279
  */
5294
- async getFileSize(relativePath) {
5280
+ async getFileModifiedTime(relativePath) {
5295
5281
  try {
5296
5282
  const fullPath = this.pathSystem.join(this.basePath, relativePath);
5297
5283
  const stats = await fs.stat(fullPath);
5298
- return stats.size;
5284
+ return stats.mtime;
5299
5285
  } catch (error) {
5300
- 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}`);
5301
5350
  }
5302
5351
  }
5303
5352
  /**
@@ -5305,12 +5354,16 @@ var DocFileSystem = class {
5305
5354
  */
5306
5355
  async ensureDirectoryExists(relativePath) {
5307
5356
  try {
5308
- if (!await this.exists(relativePath)) {
5309
- const result = await this.createDirectory(relativePath);
5310
- if (result instanceof Error) {
5311
- return result;
5357
+ if (this.reader) {
5358
+ const exists = await this.reader.exists(relativePath);
5359
+ if (exists) {
5360
+ return null;
5312
5361
  }
5313
5362
  }
5363
+ const result = await this.createDirectory(relativePath);
5364
+ if (result instanceof Error) {
5365
+ return result;
5366
+ }
5314
5367
  return null;
5315
5368
  } catch (error) {
5316
5369
  return error instanceof Error ? error : new Error(`Failed to ensure directory exists at ${relativePath}`);
@@ -5323,7 +5376,7 @@ var DocFileSystem = class {
5323
5376
  try {
5324
5377
  const sourceFullPath = this.pathSystem.join(this.basePath, sourcePath);
5325
5378
  const destFullPath = this.pathSystem.join(this.basePath, destinationPath);
5326
- await fs.copyFile(sourceFullPath, destFullPath);
5379
+ await fs2.copyFile(sourceFullPath, destFullPath);
5327
5380
  return null;
5328
5381
  } catch (error) {
5329
5382
  return error instanceof Error ? error : new Error(
@@ -5338,7 +5391,7 @@ var DocFileSystem = class {
5338
5391
  try {
5339
5392
  const sourceFullPath = this.pathSystem.join(this.basePath, sourcePath);
5340
5393
  const destFullPath = this.pathSystem.join(this.basePath, destinationPath);
5341
- await fs.rename(sourceFullPath, destFullPath);
5394
+ await fs2.rename(sourceFullPath, destFullPath);
5342
5395
  return null;
5343
5396
  } catch (error) {
5344
5397
  return error instanceof Error ? error : new Error(
@@ -5346,144 +5399,776 @@ var DocFileSystem = class {
5346
5399
  );
5347
5400
  }
5348
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
+ }
5349
5423
  /**
5350
- * Get file last modified time
5424
+ * Read file content at the specified path
5351
5425
  */
5352
- async getFileModifiedTime(relativePath) {
5353
- try {
5354
- const fullPath = this.pathSystem.join(this.basePath, relativePath);
5355
- const stats = await fs.stat(fullPath);
5356
- return stats.mtime;
5357
- } catch (error) {
5358
- return error instanceof Error ? error : new Error(`Failed to get file modified time at ${relativePath}`);
5359
- }
5426
+ async readFile(relativePath) {
5427
+ return this.reader.readFile(relativePath);
5360
5428
  }
5361
5429
  /**
5362
- * Get file creation time
5430
+ * Write content to file at the specified path (creates directory if needed)
5363
5431
  */
5364
- async getFileCreatedTime(relativePath) {
5365
- try {
5366
- const fullPath = this.pathSystem.join(this.basePath, relativePath);
5367
- const stats = await fs.stat(fullPath);
5368
- return stats.birthtime;
5369
- } catch (error) {
5370
- return error instanceof Error ? error : new Error(`Failed to get file created time at ${relativePath}`);
5371
- }
5432
+ async writeFile(relativePath, content) {
5433
+ return this.writer.writeFile(relativePath, content);
5372
5434
  }
5373
- };
5374
-
5375
- // lib/doc-file-system-mock.ts
5376
- var mockDirectoryData = {
5377
- "docs/index.md": `---
5378
- icon: \u{1F4DA}
5379
- ---
5380
-
5381
- # Documentation
5382
-
5383
- Welcome to the documentation!`,
5384
- "docs/guide/index.md": `---
5385
- icon: \u{1F4D6}
5386
- ---
5387
-
5388
- # Guide
5389
-
5390
- This is a guide.`,
5391
- "docs/guide/getting-started.md": `# Getting Started
5392
-
5393
- Let's get started!`,
5394
- "docs/guide/advanced.md": `# Advanced
5395
-
5396
- Advanced topics here.`,
5397
- "docs/api/index.md": `---
5398
- icon: \u{1F527}
5399
- ---
5400
-
5401
- # API
5402
-
5403
- API documentation.`,
5404
- "docs/api/reference.md": `# API Reference
5405
-
5406
- Complete API reference.`
5407
- };
5408
- var DocFileSystemMock = class _DocFileSystemMock extends DocFileSystem {
5409
- files = /* @__PURE__ */ new Map();
5410
- _pathSystem;
5411
- _basePath;
5412
- constructor(props) {
5413
- super(props);
5414
- this._pathSystem = props.pathSystem;
5415
- this._basePath = props.basePath.endsWith("/") ? props.basePath.slice(0, -1) : props.basePath;
5416
- if (!props.skipDefaultFiles) {
5417
- this.setupTestFiles(mockDirectoryData);
5418
- }
5419
- Object.freeze(this);
5435
+ /**
5436
+ * Delete file at the specified path
5437
+ */
5438
+ async deleteFile(relativePath) {
5439
+ return this.writer.deleteFile(relativePath);
5420
5440
  }
5421
5441
  /**
5422
- * PathSystem accessor (for testing)
5442
+ * Get file name from path
5423
5443
  */
5424
- getPathSystem() {
5425
- return this._pathSystem;
5444
+ readFileName(relativePath) {
5445
+ return this.reader.readFileName(relativePath);
5426
5446
  }
5427
5447
  /**
5428
- * Normalize path using basePath
5448
+ * Get file extension from path
5429
5449
  */
5430
- normalizePath(filePath) {
5431
- if (filePath.startsWith(this._basePath)) {
5432
- return filePath;
5433
- }
5434
- const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
5435
- return `${this._basePath}/${cleanPath}`;
5450
+ readFileExtension(relativePath) {
5451
+ return this.reader.readFileExtension(relativePath);
5436
5452
  }
5437
5453
  /**
5438
- * Create instance (mock data is automatically loaded)
5454
+ * Get directory path where the file exists
5439
5455
  */
5440
- static create(basePath = "/test") {
5441
- const pathSystem = new DocPathSystem();
5442
- return new _DocFileSystemMock({ basePath, pathSystem });
5456
+ readFileDirectory(relativePath) {
5457
+ return this.reader.readFileDirectory(relativePath);
5443
5458
  }
5444
5459
  /**
5445
- * Factory method for testing
5460
+ * Get list of entries in directory
5446
5461
  */
5447
- static createWithFiles(props) {
5448
- const pathSystem = new DocPathSystem();
5449
- const basePath = props.basePath ?? "/test";
5450
- const fileSystem = new _DocFileSystemMock({
5451
- basePath,
5452
- pathSystem,
5453
- skipDefaultFiles: true
5454
- });
5455
- if (props.fileContents) {
5456
- const now = /* @__PURE__ */ new Date();
5457
- for (const [path, content] of Object.entries(props.fileContents)) {
5458
- const cleanPath = path.startsWith("/") ? path.slice(1) : path;
5459
- const normalizedPath = path.startsWith(basePath) ? path : `${basePath}/${cleanPath}`;
5460
- fileSystem.files.set(normalizedPath, {
5461
- content,
5462
- modifiedTime: now,
5463
- createdTime: now,
5464
- size: new TextEncoder().encode(content).length
5465
- });
5466
- }
5467
- }
5468
- return fileSystem;
5462
+ async readDirectoryFileNames(relativePath = "") {
5463
+ return this.reader.readDirectoryFileNames(relativePath);
5469
5464
  }
5470
- async readFile(filePath) {
5471
- try {
5472
- const normalizedPath = this.normalizePath(filePath);
5473
- const file = this.files.get(normalizedPath);
5474
- return file ? file.content : null;
5475
- } catch (error) {
5476
- return error instanceof Error ? error : new Error(`Failed to read file at ${filePath}`);
5477
- }
5465
+ async readDirectoryFilePaths(relativePath) {
5466
+ return this.reader.readDirectoryFilePaths(relativePath);
5478
5467
  }
5479
- async writeFile(filePath, content) {
5480
- try {
5481
- const normalizedPath = this.normalizePath(filePath);
5482
- const now = /* @__PURE__ */ new Date();
5483
- const existing = this.files.get(normalizedPath);
5484
- this.files.set(normalizedPath, {
5485
- content,
5486
- modifiedTime: now,
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,
5487
6172
  createdTime: existing?.createdTime ?? now,
5488
6173
  size: new TextEncoder().encode(content).length
5489
6174
  });
@@ -5609,64 +6294,288 @@ var DocFileSystemMock = class _DocFileSystemMock extends DocFileSystem {
5609
6294
  return error instanceof Error ? error : new Error(`Failed to get file size at ${filePath}`);
5610
6295
  }
5611
6296
  }
5612
- 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 = "") {
5613
6498
  try {
5614
- const normalizedPath = this.normalizePath(filePath);
5615
- const file = this.files.get(normalizedPath);
5616
- if (!file) {
5617
- 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);
5618
6508
  }
5619
- return file.modifiedTime;
6509
+ return new Error(`Path ${relativePath} is not a directory`);
5620
6510
  } catch (error) {
5621
- 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}`);
5622
6512
  }
5623
6513
  }
5624
- async getFileCreatedTime(filePath) {
6514
+ /**
6515
+ * Get list of file paths in directory
6516
+ */
6517
+ async readDirectoryFilePaths(relativePath) {
5625
6518
  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}`);
6519
+ const fileNames = await this.readDirectoryFileNames(relativePath);
6520
+ if (fileNames instanceof Error) {
6521
+ return fileNames;
5630
6522
  }
5631
- return file.createdTime;
6523
+ return fileNames.map(
6524
+ (fileName) => this.pathSystem.join(relativePath, fileName)
6525
+ );
5632
6526
  } catch (error) {
5633
- 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}`);
5634
6528
  }
5635
6529
  }
6530
+ /**
6531
+ * Check if path is a directory
6532
+ */
5636
6533
  async isDirectory(relativePath) {
5637
- const normalizedPath = this.normalizePath(relativePath);
5638
- const dirPath = normalizedPath.endsWith("/") ? normalizedPath : `${normalizedPath}/`;
5639
- for (const path of this.files.keys()) {
5640
- if (path.startsWith(dirPath)) {
5641
- return true;
5642
- }
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;
5643
6545
  }
5644
- return false;
5645
6546
  }
6547
+ /**
6548
+ * Check if path is a file
6549
+ */
5646
6550
  async isFile(relativePath) {
5647
- const normalizedPath = this.normalizePath(relativePath);
5648
- 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
+ }
5649
6563
  }
5650
6564
  /**
5651
- * Get list of entries in directory
6565
+ * Check if file or directory exists
5652
6566
  */
5653
- async readDirectoryFileNames(directoryPath = "") {
6567
+ async exists(relativePath) {
5654
6568
  try {
5655
- const normalizedDir = directoryPath === "" ? this._basePath : this.normalizePath(directoryPath);
5656
- const dirPath = normalizedDir.endsWith("/") ? normalizedDir : `${normalizedDir}/`;
5657
- const entries = /* @__PURE__ */ new Set();
5658
- for (const path of this.files.keys()) {
5659
- if (path.startsWith(dirPath)) {
5660
- const relativePath = path.slice(dirPath.length);
5661
- const firstSegment = relativePath.split("/")[0];
5662
- if (firstSegment) {
5663
- entries.add(firstSegment);
5664
- }
5665
- }
5666
- }
5667
- return Array.from(entries).sort();
5668
- } catch (error) {
5669
- 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;
5670
6579
  }
5671
6580
  }
5672
6581
  /**
@@ -5682,62 +6591,303 @@ var DocFileSystemMock = class _DocFileSystemMock extends DocFileSystem {
5682
6591
  return this.isFile(relativePath);
5683
6592
  }
5684
6593
  /**
5685
- * Create directory if it doesn't exist
6594
+ * Get base path
5686
6595
  */
5687
- async ensureDirectoryExists(_relativePath) {
5688
- return null;
6596
+ getBasePath() {
6597
+ return this.basePath;
5689
6598
  }
5690
6599
  /**
5691
- * Clear all files
6600
+ * Convert relative path to absolute path
5692
6601
  */
5693
- clear() {
5694
- this.files.clear();
6602
+ resolve(relativePath) {
6603
+ return this.pathSystem.join(this.basePath, relativePath);
5695
6604
  }
5696
6605
  /**
5697
- * Check file existence (for testing)
6606
+ * Get file size in bytes
5698
6607
  */
5699
- hasFile(filePath) {
5700
- const normalizedPath = this.normalizePath(filePath);
5701
- 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
+ }
5702
6628
  }
5703
6629
  /**
5704
- * Get file content (sync version, for testing)
6630
+ * Get file last modified time
5705
6631
  */
5706
- getFileContent(filePath) {
5707
- const normalizedPath = this.normalizePath(filePath);
5708
- 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
+ }
5709
6648
  }
5710
6649
  /**
5711
- * Get all file paths (for testing)
6650
+ * Get file creation time (first commit)
5712
6651
  */
5713
- getAllFilePaths() {
5714
- return Array.from(this.files.keys()).map((path) => {
5715
- return path.startsWith(`${this._basePath}/`) ? path.slice(this._basePath.length + 1) : path;
5716
- }).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
+ }
5717
6668
  }
5718
6669
  /**
5719
- * Get file count (for testing)
6670
+ * Get cached SHA for a file
5720
6671
  */
5721
- getFileCount() {
5722
- 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);
5723
6697
  }
5724
6698
  /**
5725
- * Setup test data
6699
+ * Write content to file in GitHub repository
5726
6700
  */
5727
- setupTestFiles(files) {
5728
- const now = /* @__PURE__ */ new Date();
5729
- for (const [path, content] of Object.entries(files)) {
5730
- const normalizedPath = this.normalizePath(path);
5731
- this.files.set(normalizedPath, {
5732
- content,
5733
- modifiedTime: now,
5734
- createdTime: now,
5735
- 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
5736
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
+ );
5737
6841
  }
5738
6842
  }
5739
6843
  };
5740
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
+
5741
6891
  // lib/doc-path-system-mock.ts
5742
6892
  var DocPathSystemMock = class _DocPathSystemMock extends DocPathSystem {
5743
6893
  _separator;
@@ -6378,7 +7528,15 @@ export {
6378
7528
  DocFilePathValue,
6379
7529
  DocFileRelationReference,
6380
7530
  DocFileSystem,
7531
+ DocFileSystemJson,
7532
+ DocFileSystemJsonRead,
7533
+ DocFileSystemJsonWrite,
6381
7534
  DocFileSystemMock,
7535
+ DocFileSystemOctokit,
7536
+ DocFileSystemOctokitRead,
7537
+ DocFileSystemOctokitWrite,
7538
+ DocFileSystemRead,
7539
+ DocFileSystemWrite,
6382
7540
  DocFileTreeSystem,
6383
7541
  DocFileUnknownEntity,
6384
7542
  DocFileUnknownReference,