@caplab/read 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +189 -0
  3. package/dist/cjs/errors/structured.d.ts +12 -0
  4. package/dist/cjs/errors/structured.d.ts.map +1 -0
  5. package/dist/cjs/errors/structured.js +124 -0
  6. package/dist/cjs/errors/structured.js.map +1 -0
  7. package/dist/cjs/factory.d.ts +3 -0
  8. package/dist/cjs/factory.d.ts.map +1 -0
  9. package/dist/cjs/factory.js +92 -0
  10. package/dist/cjs/factory.js.map +1 -0
  11. package/dist/cjs/fs/binary.d.ts +4 -0
  12. package/dist/cjs/fs/binary.d.ts.map +1 -0
  13. package/dist/cjs/fs/binary.js +116 -0
  14. package/dist/cjs/fs/binary.js.map +1 -0
  15. package/dist/cjs/fs/directory.d.ts +3 -0
  16. package/dist/cjs/fs/directory.d.ts.map +1 -0
  17. package/dist/cjs/fs/directory.js +163 -0
  18. package/dist/cjs/fs/directory.js.map +1 -0
  19. package/dist/cjs/fs/reader.d.ts +3 -0
  20. package/dist/cjs/fs/reader.d.ts.map +1 -0
  21. package/dist/cjs/fs/reader.js +145 -0
  22. package/dist/cjs/fs/reader.js.map +1 -0
  23. package/dist/cjs/index.d.ts +3 -0
  24. package/dist/cjs/index.d.ts.map +1 -0
  25. package/dist/cjs/index.js +7 -0
  26. package/dist/cjs/index.js.map +1 -0
  27. package/dist/cjs/output/formatter.d.ts +4 -0
  28. package/dist/cjs/output/formatter.d.ts.map +1 -0
  29. package/dist/cjs/output/formatter.js +26 -0
  30. package/dist/cjs/output/formatter.js.map +1 -0
  31. package/dist/cjs/output/truncation.d.ts +5 -0
  32. package/dist/cjs/output/truncation.d.ts.map +1 -0
  33. package/dist/cjs/output/truncation.js +10 -0
  34. package/dist/cjs/output/truncation.js.map +1 -0
  35. package/dist/cjs/package.json +1 -0
  36. package/dist/cjs/path/guard.d.ts +5 -0
  37. package/dist/cjs/path/guard.d.ts.map +1 -0
  38. package/dist/cjs/path/guard.js +91 -0
  39. package/dist/cjs/path/guard.js.map +1 -0
  40. package/dist/cjs/path/normalizer.d.ts +3 -0
  41. package/dist/cjs/path/normalizer.d.ts.map +1 -0
  42. package/dist/cjs/path/normalizer.js +47 -0
  43. package/dist/cjs/path/normalizer.js.map +1 -0
  44. package/dist/cjs/path/resolver.d.ts +5 -0
  45. package/dist/cjs/path/resolver.d.ts.map +1 -0
  46. package/dist/cjs/path/resolver.js +73 -0
  47. package/dist/cjs/path/resolver.js.map +1 -0
  48. package/dist/cjs/read/encoding.d.ts +5 -0
  49. package/dist/cjs/read/encoding.d.ts.map +1 -0
  50. package/dist/cjs/read/encoding.js +29 -0
  51. package/dist/cjs/read/encoding.js.map +1 -0
  52. package/dist/cjs/read/multi-file.d.ts +4 -0
  53. package/dist/cjs/read/multi-file.d.ts.map +1 -0
  54. package/dist/cjs/read/multi-file.js +293 -0
  55. package/dist/cjs/read/multi-file.js.map +1 -0
  56. package/dist/cjs/search/adapter.d.ts +3 -0
  57. package/dist/cjs/search/adapter.d.ts.map +1 -0
  58. package/dist/cjs/search/adapter.js +34 -0
  59. package/dist/cjs/search/adapter.js.map +1 -0
  60. package/dist/cjs/types/internal.d.ts +24 -0
  61. package/dist/cjs/types/internal.d.ts.map +1 -0
  62. package/dist/cjs/types/internal.js +4 -0
  63. package/dist/cjs/types/internal.js.map +1 -0
  64. package/dist/cjs/types/public.d.ts +87 -0
  65. package/dist/cjs/types/public.d.ts.map +1 -0
  66. package/dist/cjs/types/public.js +4 -0
  67. package/dist/cjs/types/public.js.map +1 -0
  68. package/dist/errors/structured.d.ts +12 -0
  69. package/dist/errors/structured.d.ts.map +1 -0
  70. package/dist/errors/structured.js +79 -0
  71. package/dist/errors/structured.js.map +1 -0
  72. package/dist/factory.d.ts +3 -0
  73. package/dist/factory.d.ts.map +1 -0
  74. package/dist/factory.js +89 -0
  75. package/dist/factory.js.map +1 -0
  76. package/dist/fs/binary.d.ts +4 -0
  77. package/dist/fs/binary.d.ts.map +1 -0
  78. package/dist/fs/binary.js +79 -0
  79. package/dist/fs/binary.js.map +1 -0
  80. package/dist/fs/directory.d.ts +3 -0
  81. package/dist/fs/directory.d.ts.map +1 -0
  82. package/dist/fs/directory.js +127 -0
  83. package/dist/fs/directory.js.map +1 -0
  84. package/dist/fs/reader.d.ts +3 -0
  85. package/dist/fs/reader.d.ts.map +1 -0
  86. package/dist/fs/reader.js +109 -0
  87. package/dist/fs/reader.js.map +1 -0
  88. package/dist/index.d.ts +3 -0
  89. package/dist/index.d.ts.map +1 -0
  90. package/dist/index.js +3 -0
  91. package/dist/index.js.map +1 -0
  92. package/dist/output/formatter.d.ts +4 -0
  93. package/dist/output/formatter.d.ts.map +1 -0
  94. package/dist/output/formatter.js +22 -0
  95. package/dist/output/formatter.js.map +1 -0
  96. package/dist/output/truncation.d.ts +5 -0
  97. package/dist/output/truncation.d.ts.map +1 -0
  98. package/dist/output/truncation.js +7 -0
  99. package/dist/output/truncation.js.map +1 -0
  100. package/dist/path/guard.d.ts +5 -0
  101. package/dist/path/guard.d.ts.map +1 -0
  102. package/dist/path/guard.js +55 -0
  103. package/dist/path/guard.js.map +1 -0
  104. package/dist/path/normalizer.d.ts +3 -0
  105. package/dist/path/normalizer.d.ts.map +1 -0
  106. package/dist/path/normalizer.js +10 -0
  107. package/dist/path/normalizer.js.map +1 -0
  108. package/dist/path/resolver.d.ts +5 -0
  109. package/dist/path/resolver.d.ts.map +1 -0
  110. package/dist/path/resolver.js +35 -0
  111. package/dist/path/resolver.js.map +1 -0
  112. package/dist/read/encoding.d.ts +5 -0
  113. package/dist/read/encoding.d.ts.map +1 -0
  114. package/dist/read/encoding.js +26 -0
  115. package/dist/read/encoding.js.map +1 -0
  116. package/dist/read/multi-file.d.ts +4 -0
  117. package/dist/read/multi-file.d.ts.map +1 -0
  118. package/dist/read/multi-file.js +257 -0
  119. package/dist/read/multi-file.js.map +1 -0
  120. package/dist/search/adapter.d.ts +3 -0
  121. package/dist/search/adapter.d.ts.map +1 -0
  122. package/dist/search/adapter.js +31 -0
  123. package/dist/search/adapter.js.map +1 -0
  124. package/dist/types/internal.d.ts +24 -0
  125. package/dist/types/internal.d.ts.map +1 -0
  126. package/dist/types/internal.js +3 -0
  127. package/dist/types/internal.js.map +1 -0
  128. package/dist/types/public.d.ts +87 -0
  129. package/dist/types/public.d.ts.map +1 -0
  130. package/dist/types/public.js +3 -0
  131. package/dist/types/public.js.map +1 -0
  132. package/package.json +62 -0
@@ -0,0 +1,79 @@
1
+ import * as path from 'node:path';
2
+ export function createFileNotFoundResult(filePath, workspaceRoot) {
3
+ return {
4
+ success: false,
5
+ error: 'file_not_found',
6
+ path: filePath,
7
+ relativePath: path.relative(workspaceRoot, filePath),
8
+ };
9
+ }
10
+ export function createPermissionDeniedResult(filePath, workspaceRoot) {
11
+ return {
12
+ success: false,
13
+ error: 'permission_denied',
14
+ path: filePath,
15
+ relativePath: path.relative(workspaceRoot, filePath),
16
+ };
17
+ }
18
+ export function createBinaryFileResult(filePath, workspaceRoot) {
19
+ return {
20
+ success: false,
21
+ error: 'binary_file',
22
+ path: filePath,
23
+ relativePath: path.relative(workspaceRoot, filePath),
24
+ };
25
+ }
26
+ export function createUnsupportedEncodingResult(filePath, workspaceRoot) {
27
+ return {
28
+ success: false,
29
+ error: 'unsupported_encoding',
30
+ path: filePath,
31
+ relativePath: path.relative(workspaceRoot, filePath),
32
+ };
33
+ }
34
+ export function createPathOutsideWorkspaceResult(filePath, workspaceRoot) {
35
+ return {
36
+ success: false,
37
+ error: 'path_outside_workspace',
38
+ path: filePath,
39
+ relativePath: path.relative(workspaceRoot, filePath),
40
+ };
41
+ }
42
+ export function createSkippedDueToBudgetResult(filePath, workspaceRoot) {
43
+ return {
44
+ success: false,
45
+ error: 'skipped_due_to_budget',
46
+ path: filePath,
47
+ relativePath: path.relative(workspaceRoot, filePath),
48
+ };
49
+ }
50
+ export function createSkippedDueToMaxFilesResult(filePath, workspaceRoot) {
51
+ return {
52
+ success: false,
53
+ error: 'skipped_due_to_max_files',
54
+ path: filePath,
55
+ relativePath: path.relative(workspaceRoot, filePath),
56
+ };
57
+ }
58
+ export function createDirectoryNotFoundResult(dirPath) {
59
+ return {
60
+ success: false,
61
+ error: 'path_not_found',
62
+ path: dirPath,
63
+ };
64
+ }
65
+ export function createDirectoryPermissionDeniedResult(dirPath) {
66
+ return {
67
+ success: false,
68
+ error: 'permission_denied',
69
+ path: dirPath,
70
+ };
71
+ }
72
+ export function createDirectoryOutsideWorkspaceResult(dirPath) {
73
+ return {
74
+ success: false,
75
+ error: 'path_outside_workspace',
76
+ path: dirPath,
77
+ };
78
+ }
79
+ //# sourceMappingURL=structured.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured.js","sourceRoot":"","sources":["../../src/errors/structured.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,UAAU,wBAAwB,CAAC,QAAgB,EAAE,aAAqB;IAC9E,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,gBAAgB;QACvB,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,QAAgB,EAAE,aAAqB;IAClF,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,mBAAmB;QAC1B,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,QAAgB,EAAE,aAAqB;IAC5E,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,aAAa;QACpB,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,QAAgB,EAAE,aAAqB;IACrF,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,sBAAsB;QAC7B,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gCAAgC,CAAC,QAAgB,EAAE,aAAqB;IACtF,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,wBAAwB;QAC/B,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,QAAgB,EAAE,aAAqB;IACpF,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,uBAAuB;QAC9B,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gCAAgC,CAAC,QAAgB,EAAE,aAAqB;IACtF,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,0BAA0B;QACjC,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,OAAe;IAC3D,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,gBAAgB;QACvB,IAAI,EAAE,OAAO;KACd,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qCAAqC,CAAC,OAAe;IACnE,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,mBAAmB;QAC1B,IAAI,EAAE,OAAO;KACd,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qCAAqC,CAAC,OAAe;IACnE,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,wBAAwB;QAC/B,IAAI,EAAE,OAAO;KACd,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { WorkspaceReader, WorkspaceReaderOptions } from './types/public.js';
2
+ export declare function createWorkspaceReader(options: WorkspaceReaderOptions): Promise<WorkspaceReader>;
3
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAsF,MAAM,mBAAmB,CAAC;AASrK,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CA2FrG"}
@@ -0,0 +1,89 @@
1
+ import { validateWorkspaceRoot, resolvePath, getRelativePath } from './path/resolver.js';
2
+ import { validatePathBoundary } from './path/guard.js';
3
+ import { listDirectory as listDirectoryImpl } from './fs/directory.js';
4
+ import { readFileWithBudget } from './fs/reader.js';
5
+ import { readMultipleFiles } from './read/multi-file.js';
6
+ import { fileSearch as fileSearchImpl } from './search/adapter.js';
7
+ export async function createWorkspaceReader(options) {
8
+ const config = await validateWorkspaceRoot(options.workspaceRoot);
9
+ if (!config) {
10
+ throw new Error('Invalid workspace root: path does not exist or is not a directory');
11
+ }
12
+ // Apply overrides from options
13
+ const workspaceConfig = {
14
+ ...config,
15
+ maxBytes: options.maxBytes ?? config.maxBytes,
16
+ maxLines: options.maxLines ?? config.maxLines,
17
+ maxFiles: options.maxFiles ?? config.maxFiles,
18
+ maxTotalBytes: options.maxTotalBytes ?? config.maxTotalBytes,
19
+ maxEntries: options.maxEntries ?? config.maxEntries,
20
+ maxSearchResults: options.maxSearchResults ?? config.maxSearchResults,
21
+ };
22
+ return {
23
+ async listDirectory(path, options) {
24
+ const absolutePath = resolvePath(path, workspaceConfig.workspaceRoot);
25
+ const boundaryCheck = await validatePathBoundary(absolutePath, workspaceConfig.workspaceRoot);
26
+ if (!boundaryCheck.valid) {
27
+ if (boundaryCheck.error === 'not_found') {
28
+ return {
29
+ success: false,
30
+ error: 'path_not_found',
31
+ path: absolutePath,
32
+ };
33
+ }
34
+ if (boundaryCheck.error === 'permission_denied') {
35
+ return {
36
+ success: false,
37
+ error: 'permission_denied',
38
+ path: absolutePath,
39
+ };
40
+ }
41
+ return {
42
+ success: false,
43
+ error: 'path_outside_workspace',
44
+ path: absolutePath,
45
+ };
46
+ }
47
+ return listDirectoryImpl(absolutePath, workspaceConfig.workspaceRoot, options ?? {});
48
+ },
49
+ async readFile(path, options) {
50
+ const absolutePath = resolvePath(path, workspaceConfig.workspaceRoot);
51
+ const boundaryCheck = await validatePathBoundary(absolutePath, workspaceConfig.workspaceRoot);
52
+ if (!boundaryCheck.valid) {
53
+ if (boundaryCheck.error === 'not_found') {
54
+ return {
55
+ success: false,
56
+ error: 'file_not_found',
57
+ path: absolutePath,
58
+ relativePath: getRelativePath(absolutePath, workspaceConfig.workspaceRoot),
59
+ };
60
+ }
61
+ if (boundaryCheck.error === 'permission_denied') {
62
+ return {
63
+ success: false,
64
+ error: 'permission_denied',
65
+ path: absolutePath,
66
+ relativePath: getRelativePath(absolutePath, workspaceConfig.workspaceRoot),
67
+ };
68
+ }
69
+ return {
70
+ success: false,
71
+ error: 'path_outside_workspace',
72
+ path: absolutePath,
73
+ relativePath: getRelativePath(absolutePath, workspaceConfig.workspaceRoot),
74
+ };
75
+ }
76
+ const maxBytes = options?.maxBytes ?? workspaceConfig.maxBytes;
77
+ const maxLines = options?.maxLines ?? workspaceConfig.maxLines;
78
+ const encoding = options?.encoding;
79
+ return readFileWithBudget(absolutePath, maxBytes, maxLines, encoding, workspaceConfig.workspaceRoot);
80
+ },
81
+ async readMultipleFiles(paths, options) {
82
+ return readMultipleFiles(paths, workspaceConfig, options ?? {});
83
+ },
84
+ fileSearch(query, options) {
85
+ return fileSearchImpl(query, workspaceConfig, options ?? {});
86
+ },
87
+ };
88
+ }
89
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { EncodingDetectionResult } from '../types/internal.js';
2
+ export declare function detectEncoding(filePath: string): Promise<EncodingDetectionResult>;
3
+ export declare function isBinaryFile(filePath: string, encoding: 'utf-8' | 'utf-16le' | 'utf-16be'): Promise<boolean>;
4
+ //# sourceMappingURL=binary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binary.d.ts","sourceRoot":"","sources":["../../src/fs/binary.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAIpE,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAYvF;AA2CD,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAiClH"}
@@ -0,0 +1,79 @@
1
+ import * as fs from 'node:fs/promises';
2
+ const SNIFF_CHUNK_SIZE = 8192;
3
+ export async function detectEncoding(filePath) {
4
+ try {
5
+ const handle = await fs.open(filePath, 'r');
6
+ const buffer = Buffer.alloc(SNIFF_CHUNK_SIZE);
7
+ const { bytesRead } = await handle.read(buffer, 0, SNIFF_CHUNK_SIZE, 0);
8
+ await handle.close();
9
+ const data = buffer.subarray(0, bytesRead);
10
+ return detectEncodingFromBuffer(data);
11
+ }
12
+ catch {
13
+ return { encoding: 'unknown', bom: false };
14
+ }
15
+ }
16
+ function detectEncodingFromBuffer(buffer) {
17
+ if (buffer.length < 2) {
18
+ return { encoding: 'utf-8', bom: false };
19
+ }
20
+ // Check for BOM
21
+ if (buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
22
+ return { encoding: 'utf-8', bom: true };
23
+ }
24
+ if (buffer[0] === 0xFF && buffer[1] === 0xFE) {
25
+ return { encoding: 'utf-16le', bom: true };
26
+ }
27
+ if (buffer[0] === 0xFE && buffer[1] === 0xFF) {
28
+ return { encoding: 'utf-16be', bom: true };
29
+ }
30
+ // Detect UTF-16 without BOM by looking for null bytes
31
+ let nullByteCount = 0;
32
+ for (let i = 0; i < Math.min(buffer.length, 100); i++) {
33
+ if (buffer[i] === 0) {
34
+ nullByteCount++;
35
+ }
36
+ }
37
+ // If we see many null bytes, it's likely UTF-16
38
+ if (nullByteCount > 10) {
39
+ // Determine LE vs BE by looking at pattern
40
+ if (buffer[0] === 0 && buffer[1] !== 0) {
41
+ return { encoding: 'utf-16be', bom: false };
42
+ }
43
+ if (buffer[0] !== 0 && buffer[1] === 0) {
44
+ return { encoding: 'utf-16le', bom: false };
45
+ }
46
+ }
47
+ // Default to UTF-8
48
+ return { encoding: 'utf-8', bom: false };
49
+ }
50
+ export async function isBinaryFile(filePath, encoding) {
51
+ try {
52
+ const handle = await fs.open(filePath, 'r');
53
+ const buffer = Buffer.alloc(SNIFF_CHUNK_SIZE);
54
+ const { bytesRead } = await handle.read(buffer, 0, SNIFF_CHUNK_SIZE, 0);
55
+ await handle.close();
56
+ const data = buffer.subarray(0, bytesRead);
57
+ if (encoding === 'utf-8' || encoding === 'utf-16le' || encoding === 'utf-16be') {
58
+ // For supported encodings, decode and check for null bytes in decoded text space
59
+ const decoder = new TextDecoder(encoding, { fatal: false });
60
+ const decoded = decoder.decode(data, { stream: true });
61
+ // Check for null bytes in decoded text
62
+ if (decoded.includes('\0')) {
63
+ return true;
64
+ }
65
+ return false;
66
+ }
67
+ // For unsupported encodings, use null-byte heuristic on raw bytes
68
+ for (let i = 0; i < data.length; i++) {
69
+ if (data[i] === 0) {
70
+ return true;
71
+ }
72
+ }
73
+ return false;
74
+ }
75
+ catch {
76
+ return true;
77
+ }
78
+ }
79
+ //# sourceMappingURL=binary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binary.js","sourceRoot":"","sources":["../../src/fs/binary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { DirectoryResult, ListDirectoryOptions } from '../types/public.js';
2
+ export declare function listDirectory(dirPath: string, workspaceRoot: string, options?: ListDirectoryOptions): Promise<DirectoryResult>;
3
+ //# sourceMappingURL=directory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/fs/directory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAkB,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAahG,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,eAAe,CAAC,CA6H1B"}
@@ -0,0 +1,127 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { normalizePath } from '../path/normalizer.js';
4
+ function minimatch(str, pattern) {
5
+ // Simple glob pattern matcher supporting * and ?
6
+ const regexPattern = pattern
7
+ .replace(/\./g, '\\.')
8
+ .replace(/\*/g, '.*')
9
+ .replace(/\?/g, '.');
10
+ const regex = new RegExp(`^${regexPattern}$`);
11
+ return regex.test(str);
12
+ }
13
+ export async function listDirectory(dirPath, workspaceRoot, options = {}) {
14
+ try {
15
+ const stats = await fs.stat(dirPath);
16
+ if (!stats.isDirectory()) {
17
+ return {
18
+ success: false,
19
+ error: 'path_not_found',
20
+ path: dirPath,
21
+ };
22
+ }
23
+ const entries = [];
24
+ const maxDepth = options.maxDepth ?? Infinity;
25
+ const includeHidden = options.includeHidden ?? false;
26
+ const includePatterns = options.include ?? [];
27
+ const excludePatterns = options.exclude ?? [];
28
+ const maxEntries = options.maxEntries ?? 1000;
29
+ async function collectEntries(currentPath, currentDepth) {
30
+ if (currentDepth > maxDepth) {
31
+ return;
32
+ }
33
+ try {
34
+ const dirents = await fs.readdir(currentPath, { withFileTypes: true });
35
+ for (const dirent of dirents) {
36
+ const fullPath = path.join(currentPath, dirent.name);
37
+ const relativePath = path.relative(workspaceRoot, fullPath);
38
+ const normalizedRelativePath = normalizePath(relativePath);
39
+ // Skip hidden files unless includeHidden is true
40
+ if (!includeHidden && dirent.name.startsWith('.')) {
41
+ continue;
42
+ }
43
+ // Apply exclude patterns (apply to both files and directories)
44
+ if (excludePatterns.length > 0) {
45
+ const matchesExclude = excludePatterns.some(pattern => minimatch(normalizedRelativePath, pattern));
46
+ if (matchesExclude) {
47
+ continue;
48
+ }
49
+ }
50
+ // For files, apply include patterns
51
+ if (dirent.isFile()) {
52
+ if (includePatterns.length > 0) {
53
+ const matchesInclude = includePatterns.some(pattern => minimatch(normalizedRelativePath, pattern));
54
+ if (!matchesInclude) {
55
+ continue;
56
+ }
57
+ }
58
+ const entry = {
59
+ path: normalizePath(fullPath),
60
+ relativePath: normalizedRelativePath,
61
+ type: 'file',
62
+ };
63
+ // Get size for files
64
+ try {
65
+ const fileStats = await fs.stat(fullPath);
66
+ entry.size = fileStats.size;
67
+ }
68
+ catch {
69
+ // Ignore stat errors
70
+ }
71
+ entries.push(entry);
72
+ }
73
+ // Always recurse into directories to find nested files
74
+ if (dirent.isDirectory()) {
75
+ // Add directory entry if it matches include patterns or if no include patterns
76
+ if (includePatterns.length === 0 || includePatterns.some(pattern => minimatch(normalizedRelativePath, pattern))) {
77
+ const entry = {
78
+ path: normalizePath(fullPath),
79
+ relativePath: normalizedRelativePath,
80
+ type: 'directory',
81
+ };
82
+ entries.push(entry);
83
+ }
84
+ await collectEntries(fullPath, currentDepth + 1);
85
+ }
86
+ }
87
+ }
88
+ catch (error) {
89
+ if (error.code === 'EACCES' || error.code === 'EPERM') {
90
+ // Skip directories we can't access
91
+ }
92
+ else {
93
+ throw error;
94
+ }
95
+ }
96
+ }
97
+ await collectEntries(dirPath, 0);
98
+ // Sort by normalized path (deterministic)
99
+ entries.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
100
+ // Cap to maxEntries
101
+ const truncated = entries.length > maxEntries;
102
+ const finalEntries = entries.slice(0, maxEntries);
103
+ return {
104
+ success: true,
105
+ entries: finalEntries,
106
+ truncated,
107
+ };
108
+ }
109
+ catch (error) {
110
+ if (error.code === 'ENOENT') {
111
+ return {
112
+ success: false,
113
+ error: 'path_not_found',
114
+ path: dirPath,
115
+ };
116
+ }
117
+ if (error.code === 'EACCES' || error.code === 'EPERM') {
118
+ return {
119
+ success: false,
120
+ error: 'permission_denied',
121
+ path: dirPath,
122
+ };
123
+ }
124
+ throw error;
125
+ }
126
+ }
127
+ //# sourceMappingURL=directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.js","sourceRoot":"","sources":["../../src/fs/directory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { FileReadResult } from '../types/public.js';
2
+ export declare function readFileWithBudget(filePath: string, maxBytes: number, maxLines: number, encoding?: 'utf-8' | 'utf-16le' | 'utf-16be' | 'auto', workspaceRoot?: string): Promise<FileReadResult>;
3
+ //# sourceMappingURL=reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/fs/reader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,EACrD,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,cAAc,CAAC,CA8GzB"}
@@ -0,0 +1,109 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { detectEncoding, isBinaryFile } from './binary.js';
4
+ export async function readFileWithBudget(filePath, maxBytes, maxLines, encoding, workspaceRoot) {
5
+ const getRelativePath = () => {
6
+ if (workspaceRoot) {
7
+ const relative = path.relative(workspaceRoot, filePath);
8
+ // Normalize to forward slashes for consistency
9
+ return relative.split(path.sep).join('/');
10
+ }
11
+ return path.basename(filePath);
12
+ };
13
+ try {
14
+ const stats = await fs.stat(filePath);
15
+ if (!stats.isFile()) {
16
+ return {
17
+ success: false,
18
+ error: 'file_not_found',
19
+ path: filePath,
20
+ relativePath: getRelativePath(),
21
+ };
22
+ }
23
+ // Detect encoding if auto
24
+ let finalEncoding;
25
+ if (encoding === 'auto' || !encoding) {
26
+ const detection = await detectEncoding(filePath);
27
+ if (detection.encoding === 'unknown') {
28
+ return {
29
+ success: false,
30
+ error: 'unsupported_encoding',
31
+ path: filePath,
32
+ relativePath: getRelativePath(),
33
+ };
34
+ }
35
+ finalEncoding = detection.encoding;
36
+ }
37
+ else {
38
+ finalEncoding = encoding;
39
+ }
40
+ // Check if binary
41
+ const isBinary = await isBinaryFile(filePath, finalEncoding);
42
+ if (isBinary) {
43
+ return {
44
+ success: false,
45
+ error: 'binary_file',
46
+ path: filePath,
47
+ relativePath: getRelativePath(),
48
+ };
49
+ }
50
+ // Read file with budgets
51
+ const handle = await fs.open(filePath, 'r');
52
+ const buffer = Buffer.alloc(maxBytes);
53
+ const { bytesRead } = await handle.read(buffer, 0, maxBytes, 0);
54
+ await handle.close();
55
+ const data = buffer.subarray(0, bytesRead);
56
+ // Use fatal: true when reading full file to catch encoding errors
57
+ // Use fatal: false when truncated to handle multibyte sequence cuts
58
+ const decoder = new TextDecoder(finalEncoding, { fatal: bytesRead === stats.size });
59
+ let content;
60
+ try {
61
+ content = decoder.decode(data);
62
+ }
63
+ catch (decodeError) {
64
+ return {
65
+ success: false,
66
+ error: 'unsupported_encoding',
67
+ path: filePath,
68
+ relativePath: getRelativePath(),
69
+ };
70
+ }
71
+ // Count lines and apply line limit
72
+ const lines = content.split('\n');
73
+ const truncatedLines = lines.length > maxLines;
74
+ const finalContent = truncatedLines ? lines.slice(0, maxLines).join('\n') : content;
75
+ const linesRead = Math.min(lines.length, maxLines);
76
+ const truncatedBytes = bytesRead === maxBytes && stats.size > maxBytes;
77
+ return {
78
+ success: true,
79
+ path: filePath,
80
+ relativePath: getRelativePath(),
81
+ content: finalContent,
82
+ encoding: finalEncoding,
83
+ truncatedBytes,
84
+ truncatedLines,
85
+ bytesRead,
86
+ linesRead,
87
+ };
88
+ }
89
+ catch (error) {
90
+ if (error.code === 'ENOENT') {
91
+ return {
92
+ success: false,
93
+ error: 'file_not_found',
94
+ path: filePath,
95
+ relativePath: getRelativePath(),
96
+ };
97
+ }
98
+ if (error.code === 'EACCES' || error.code === 'EPERM') {
99
+ return {
100
+ success: false,
101
+ error: 'permission_denied',
102
+ path: filePath,
103
+ relativePath: getRelativePath(),
104
+ };
105
+ }
106
+ throw error;
107
+ }
108
+ }
109
+ //# sourceMappingURL=reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/fs/reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export type { WorkspaceReaderOptions, ListDirectoryOptions, DirectoryResult, DirectoryEntry, ReadFileOptions, FileReadResult, ReadMultipleFilesOptions, MultiFileResult, FileSearchOptions, WorkspaceReader, } from "./types/public.js";
2
+ export { createWorkspaceReader } from "./factory.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACX,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,wBAAwB,EACxB,eAAe,EACf,iBAAiB,EACjB,eAAe,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ // Public API exports for @caplab/read
2
+ export { createWorkspaceReader } from "./factory.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAetC,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { FileReadResult, DirectoryEntry } from '../types/public.js';
2
+ export declare function formatFileReadResult(path: string, relativePath: string, content: string, encoding: string, truncatedBytes: boolean, truncatedLines: boolean, bytesRead: number, linesRead: number): FileReadResult;
3
+ export declare function formatDirectoryEntry(path: string, relativePath: string, type: 'file' | 'directory', size?: number): DirectoryEntry;
4
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/output/formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzE,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,OAAO,EACvB,cAAc,EAAE,OAAO,EACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,cAAc,CAYhB;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,IAAI,CAAC,EAAE,MAAM,GACZ,cAAc,CAOhB"}
@@ -0,0 +1,22 @@
1
+ export function formatFileReadResult(path, relativePath, content, encoding, truncatedBytes, truncatedLines, bytesRead, linesRead) {
2
+ return {
3
+ success: true,
4
+ path,
5
+ relativePath,
6
+ content,
7
+ encoding,
8
+ truncatedBytes,
9
+ truncatedLines,
10
+ bytesRead,
11
+ linesRead,
12
+ };
13
+ }
14
+ export function formatDirectoryEntry(path, relativePath, type, size) {
15
+ return {
16
+ path,
17
+ relativePath,
18
+ type,
19
+ size,
20
+ };
21
+ }
22
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/output/formatter.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,YAAoB,EACpB,OAAe,EACf,QAAgB,EAChB,cAAuB,EACvB,cAAuB,EACvB,SAAiB,EACjB,SAAiB;IAEjB,OAAO;QACL,OAAO,EAAE,IAAI;QACb,IAAI;QACJ,YAAY;QACZ,OAAO;QACP,QAAQ;QACR,cAAc;QACd,cAAc;QACd,SAAS;QACT,SAAS;KACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,YAAoB,EACpB,IAA0B,EAC1B,IAAa;IAEb,OAAO;QACL,IAAI;QACJ,YAAY;QACZ,IAAI;QACJ,IAAI;KACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function markTruncation(content: string, maxBytes: number, maxLines: number, bytesRead: number, fileSize: number): {
2
+ truncatedBytes: boolean;
3
+ truncatedLines: boolean;
4
+ };
5
+ //# sourceMappingURL=truncation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncation.d.ts","sourceRoot":"","sources":["../../src/output/truncation.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,CAOtD"}
@@ -0,0 +1,7 @@
1
+ export function markTruncation(content, maxBytes, maxLines, bytesRead, fileSize) {
2
+ const truncatedBytes = bytesRead === maxBytes && fileSize > maxBytes;
3
+ const lines = content.split('\n');
4
+ const truncatedLines = lines.length > maxLines;
5
+ return { truncatedBytes, truncatedLines };
6
+ }
7
+ //# sourceMappingURL=truncation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncation.js","sourceRoot":"","sources":["../../src/output/truncation.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,QAAgB,EAChB,QAAgB,EAChB,SAAiB,EACjB,QAAgB;IAEhB,MAAM,cAAc,GAAG,SAAS,KAAK,QAAQ,IAAI,QAAQ,GAAG,QAAQ,CAAC;IAErE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC;IAE/C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function validatePathBoundary(absolutePath: string, workspaceRoot: string): Promise<{
2
+ valid: boolean;
3
+ error?: 'not_found' | 'permission_denied';
4
+ }>;
5
+ //# sourceMappingURL=guard.d.ts.map