@verbex/filesystem 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.
@@ -0,0 +1,33 @@
1
+ import type { FSWatcher } from "node:fs";
2
+ import type { WorkspaceManager } from "./workspace/workspace-manager.js";
3
+ export interface DirectoryEntry {
4
+ name: string;
5
+ path: string;
6
+ isDirectory: boolean;
7
+ }
8
+ export declare class FileManager {
9
+ private readonly workspace;
10
+ constructor(workspace: WorkspaceManager);
11
+ read(inputPath: string): Promise<string>;
12
+ write(inputPath: string, content: string): Promise<void>;
13
+ append(inputPath: string, content: string): Promise<void>;
14
+ move(fromPath: string, toPath: string): Promise<void>;
15
+ copy(fromPath: string, toPath: string): Promise<void>;
16
+ delete(inputPath: string): Promise<void>;
17
+ mkdir(inputPath: string): Promise<void>;
18
+ list(inputPath?: string): Promise<DirectoryEntry[]>;
19
+ glob(pattern: string): Promise<string[]>;
20
+ exists(inputPath: string): Promise<boolean>;
21
+ searchContent(query: string, globPattern?: string): Promise<Array<{
22
+ path: string;
23
+ line: number;
24
+ text: string;
25
+ }>>;
26
+ watch(inputPath: string, listener: (event: string, filename: string) => void): FSWatcher;
27
+ stat(inputPath: string): Promise<{
28
+ size: number;
29
+ isDirectory: boolean;
30
+ mtime: Date;
31
+ }>;
32
+ }
33
+ //# sourceMappingURL=file-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-manager.d.ts","sourceRoot":"","sources":["../src/file-manager.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,gBAAgB;IAElD,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYxC,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAaxD,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASzD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvC,IAAI,CAAC,SAAS,GAAE,MAAY,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAgBxD,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAcxC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU3C,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAqBtH,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS;IASlF,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,IAAI,CAAA;KAAE,CAAC;CAa5F"}
@@ -0,0 +1,168 @@
1
+ import { readFile, writeFile, appendFile, rename, copyFile, unlink, mkdir, readdir, stat, access, } from "node:fs/promises";
2
+ import { watch } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { constants } from "node:fs";
5
+ import fg from "fast-glob";
6
+ import { FileError } from "@verbex/shared";
7
+ export class FileManager {
8
+ workspace;
9
+ constructor(workspace) {
10
+ this.workspace = workspace;
11
+ }
12
+ async read(inputPath) {
13
+ const path = this.workspace.resolvePath(inputPath);
14
+ if (this.workspace.isIgnored(path)) {
15
+ throw new FileError(`Cannot read ignored path: ${inputPath}`);
16
+ }
17
+ try {
18
+ return await readFile(path, "utf-8");
19
+ }
20
+ catch (error) {
21
+ throw new FileError(`Failed to read file: ${inputPath}`, error);
22
+ }
23
+ }
24
+ async write(inputPath, content) {
25
+ const path = this.workspace.resolvePath(inputPath);
26
+ if (this.workspace.isIgnored(path)) {
27
+ throw new FileError(`Cannot write to ignored path: ${inputPath}`);
28
+ }
29
+ try {
30
+ await mkdir(dirname(path), { recursive: true });
31
+ await writeFile(path, content, "utf-8");
32
+ }
33
+ catch (error) {
34
+ throw new FileError(`Failed to write file: ${inputPath}`, error);
35
+ }
36
+ }
37
+ async append(inputPath, content) {
38
+ const path = this.workspace.resolvePath(inputPath);
39
+ try {
40
+ await appendFile(path, content, "utf-8");
41
+ }
42
+ catch (error) {
43
+ throw new FileError(`Failed to append to file: ${inputPath}`, error);
44
+ }
45
+ }
46
+ async move(fromPath, toPath) {
47
+ const from = this.workspace.resolvePath(fromPath);
48
+ const to = this.workspace.resolvePath(toPath);
49
+ try {
50
+ await mkdir(dirname(to), { recursive: true });
51
+ await rename(from, to);
52
+ }
53
+ catch (error) {
54
+ throw new FileError(`Failed to move ${fromPath} to ${toPath}`, error);
55
+ }
56
+ }
57
+ async copy(fromPath, toPath) {
58
+ const from = this.workspace.resolvePath(fromPath);
59
+ const to = this.workspace.resolvePath(toPath);
60
+ try {
61
+ await mkdir(dirname(to), { recursive: true });
62
+ await copyFile(from, to);
63
+ }
64
+ catch (error) {
65
+ throw new FileError(`Failed to copy ${fromPath} to ${toPath}`, error);
66
+ }
67
+ }
68
+ async delete(inputPath) {
69
+ const path = this.workspace.resolvePath(inputPath);
70
+ try {
71
+ await unlink(path);
72
+ }
73
+ catch (error) {
74
+ throw new FileError(`Failed to delete file: ${inputPath}`, error);
75
+ }
76
+ }
77
+ async mkdir(inputPath) {
78
+ const path = this.workspace.resolvePath(inputPath);
79
+ try {
80
+ await mkdir(path, { recursive: true });
81
+ }
82
+ catch (error) {
83
+ throw new FileError(`Failed to create directory: ${inputPath}`, error);
84
+ }
85
+ }
86
+ async list(inputPath = ".") {
87
+ const path = this.workspace.resolvePath(inputPath);
88
+ try {
89
+ const entries = await readdir(path, { withFileTypes: true });
90
+ return entries
91
+ .filter((entry) => !this.workspace.isIgnored(`${inputPath}/${entry.name}`))
92
+ .map((entry) => ({
93
+ name: entry.name,
94
+ path: this.workspace.toRelative(`${path}/${entry.name}`),
95
+ isDirectory: entry.isDirectory(),
96
+ }));
97
+ }
98
+ catch (error) {
99
+ throw new FileError(`Failed to list directory: ${inputPath}`, error);
100
+ }
101
+ }
102
+ async glob(pattern) {
103
+ try {
104
+ const results = await fg(pattern, {
105
+ cwd: this.workspace.root,
106
+ absolute: false,
107
+ dot: false,
108
+ ignore: ["node_modules/**", "dist/**", "build/**", "coverage/**"],
109
+ });
110
+ return results.filter((p) => !this.workspace.isIgnored(p));
111
+ }
112
+ catch (error) {
113
+ throw new FileError(`Failed to glob pattern: ${pattern}`, error);
114
+ }
115
+ }
116
+ async exists(inputPath) {
117
+ const path = this.workspace.resolvePath(inputPath);
118
+ try {
119
+ await access(path, constants.F_OK);
120
+ return true;
121
+ }
122
+ catch {
123
+ return false;
124
+ }
125
+ }
126
+ async searchContent(query, globPattern = "**/*") {
127
+ const files = await this.glob(globPattern);
128
+ const results = [];
129
+ for (const file of files.slice(0, 200)) {
130
+ try {
131
+ const content = await this.read(file);
132
+ const lines = content.split("\n");
133
+ lines.forEach((text, index) => {
134
+ if (text.includes(query)) {
135
+ results.push({ path: file, line: index + 1, text: text.trim() });
136
+ }
137
+ });
138
+ }
139
+ catch {
140
+ // skip binary or unreadable files
141
+ }
142
+ }
143
+ return results;
144
+ }
145
+ watch(inputPath, listener) {
146
+ const path = this.workspace.resolvePath(inputPath);
147
+ return watch(path, { recursive: true }, (event, filename) => {
148
+ if (filename) {
149
+ listener(event, filename.toString());
150
+ }
151
+ });
152
+ }
153
+ async stat(inputPath) {
154
+ const path = this.workspace.resolvePath(inputPath);
155
+ try {
156
+ const info = await stat(path);
157
+ return {
158
+ size: info.size,
159
+ isDirectory: info.isDirectory(),
160
+ mtime: info.mtime,
161
+ };
162
+ }
163
+ catch (error) {
164
+ throw new FileError(`Failed to stat: ${inputPath}`, error);
165
+ }
166
+ }
167
+ }
168
+ //# sourceMappingURL=file-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-manager.js","sourceRoot":"","sources":["../src/file-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { FileManager } from "./file-manager.js";
2
+ export type { DirectoryEntry } from "./file-manager.js";
3
+ export { WorkspaceManager } from "./workspace/workspace-manager.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { FileManager } from "./file-manager.js";
2
+ export { WorkspaceManager } from "./workspace/workspace-manager.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { WorkspaceManager } from "./workspace-manager.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workspace/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { WorkspaceManager } from "./workspace-manager.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workspace/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare class WorkspaceManager {
2
+ readonly root: string;
3
+ private ig;
4
+ constructor(root: string);
5
+ initialize(): Promise<void>;
6
+ resolvePath(inputPath: string): string;
7
+ toRelative(absolutePath: string): string;
8
+ isWithinRoot(absolutePath: string): boolean;
9
+ isIgnored(inputPath: string): boolean;
10
+ }
11
+ //# sourceMappingURL=workspace-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-manager.d.ts","sourceRoot":"","sources":["../../src/workspace/workspace-manager.ts"],"names":[],"mappings":"AAaA,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,CAAS;gBAEP,IAAI,EAAE,MAAM;IAKlB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IActC,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAQxC,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAS3C,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;CAUtC"}
@@ -0,0 +1,62 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolve, relative, isAbsolute, normalize } from "node:path";
3
+ import ignore from "ignore";
4
+ import { FileError } from "@verbex/shared";
5
+ const HARDCODED_IGNORE = [
6
+ "node_modules",
7
+ "dist",
8
+ "build",
9
+ "coverage",
10
+ ".git",
11
+ ];
12
+ export class WorkspaceManager {
13
+ root;
14
+ ig;
15
+ constructor(root) {
16
+ this.root = resolve(root);
17
+ this.ig = ignore().add(HARDCODED_IGNORE);
18
+ }
19
+ async initialize() {
20
+ try {
21
+ const gitignorePath = resolve(this.root, ".gitignore");
22
+ const content = await readFile(gitignorePath, "utf-8");
23
+ this.ig.add(content);
24
+ }
25
+ catch {
26
+ // .gitignore is optional
27
+ }
28
+ }
29
+ resolvePath(inputPath) {
30
+ const absolute = isAbsolute(inputPath)
31
+ ? normalize(inputPath)
32
+ : resolve(this.root, inputPath);
33
+ if (!this.isWithinRoot(absolute)) {
34
+ throw new FileError(`Path "${inputPath}" resolves outside workspace root "${this.root}"`);
35
+ }
36
+ return absolute;
37
+ }
38
+ toRelative(absolutePath) {
39
+ const normalized = normalize(absolutePath);
40
+ if (!this.isWithinRoot(normalized)) {
41
+ throw new FileError(`Path "${absolutePath}" is outside workspace root`);
42
+ }
43
+ return relative(this.root, normalized) || ".";
44
+ }
45
+ isWithinRoot(absolutePath) {
46
+ const normalized = normalize(absolutePath);
47
+ const relativePath = relative(this.root, normalized);
48
+ return (relativePath === "" ||
49
+ (!relativePath.startsWith("..") && !isAbsolute(relativePath)));
50
+ }
51
+ isIgnored(inputPath) {
52
+ const absolute = isAbsolute(inputPath)
53
+ ? normalize(inputPath)
54
+ : resolve(this.root, inputPath);
55
+ const rel = relative(this.root, absolute);
56
+ if (!rel || rel.startsWith("..")) {
57
+ return true;
58
+ }
59
+ return this.ig.ignores(rel);
60
+ }
61
+ }
62
+ //# sourceMappingURL=workspace-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-manager.js","sourceRoot":"","sources":["../../src/workspace/workspace-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,MAAuB,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,gBAAgB,GAAG;IACvB,cAAc;IACd,MAAM;IACN,OAAO;IACP,UAAU;IACV,MAAM;CACP,CAAC;AAEF,MAAM,OAAO,gBAAgB;IAClB,IAAI,CAAS;IACd,EAAE,CAAS;IAEnB,YAAY,IAAY;QACtB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;YACvD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACvD,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;IACH,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC;YACpC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;YACtB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAElC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,SAAS,CACjB,SAAS,SAAS,sCAAsC,IAAI,CAAC,IAAI,GAAG,CACrE,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,UAAU,CAAC,YAAoB;QAC7B,MAAM,UAAU,GAAG,SAAS,CAAC,YAAY,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,SAAS,CAAC,SAAS,YAAY,6BAA6B,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,GAAG,CAAC;IAChD,CAAC;IAED,YAAY,CAAC,YAAoB;QAC/B,MAAM,UAAU,GAAG,SAAS,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACrD,OAAO,CACL,YAAY,KAAK,EAAE;YACnB,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAC9D,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,SAAiB;QACzB,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC;YACpC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;YACtB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=workspace-manager.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-manager.test.d.ts","sourceRoot":"","sources":["../../src/workspace/workspace-manager.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,24 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { WorkspaceManager } from "./workspace/workspace-manager.js";
3
+ import { FileError } from "@terminalai/shared";
4
+ describe("WorkspaceManager", () => {
5
+ it("resolves paths within root", () => {
6
+ const ws = new WorkspaceManager("/project");
7
+ expect(ws.resolvePath("src/index.ts")).toBe("/project/src/index.ts");
8
+ });
9
+ it("rejects path traversal outside root", () => {
10
+ const ws = new WorkspaceManager("/project");
11
+ expect(() => ws.resolvePath("../../etc/passwd")).toThrow(FileError);
12
+ });
13
+ it("detects paths within root", () => {
14
+ const ws = new WorkspaceManager("/project");
15
+ expect(ws.isWithinRoot("/project/src/file.ts")).toBe(true);
16
+ expect(ws.isWithinRoot("/other/file.ts")).toBe(false);
17
+ });
18
+ it("ignores node_modules", () => {
19
+ const ws = new WorkspaceManager("/project");
20
+ expect(ws.isIgnored("node_modules/pkg/index.js")).toBe(true);
21
+ expect(ws.isIgnored("src/index.ts")).toBe(false);
22
+ });
23
+ });
24
+ //# sourceMappingURL=workspace-manager.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-manager.test.js","sourceRoot":"","sources":["../../src/workspace/workspace-manager.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,EAAE,GAAG,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,EAAE,GAAG,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,EAAE,GAAG,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,EAAE,GAAG,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@verbex/filesystem",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": "./dist/index.js"
7
+ },
8
+ "dependencies": {
9
+ "fast-glob": "^3.3.3",
10
+ "ignore": "^7.0.3",
11
+ "@verbex/shared": "0.1.0"
12
+ },
13
+ "devDependencies": {
14
+ "typescript": "^5.7.3",
15
+ "vitest": "^3.0.5"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "engines": {
21
+ "node": ">=22.0.0"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public",
25
+ "registry": "https://registry.npmjs.org"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc -b",
29
+ "test": "vitest run",
30
+ "lint": "tsc -b --noEmit",
31
+ "clean": "rm -rf dist"
32
+ }
33
+ }