@procedures/fs 0.0.0-stage → 0.2.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.
- package/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +895 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +22 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +203 -0
- package/dist/module.js.map +1 -0
- package/dist/procedures/fs/copy.d.ts +11 -0
- package/dist/procedures/fs/copy.d.ts.map +1 -0
- package/dist/procedures/fs/copy.js +21 -0
- package/dist/procedures/fs/copy.js.map +1 -0
- package/dist/procedures/fs/exists.d.ts +11 -0
- package/dist/procedures/fs/exists.d.ts.map +1 -0
- package/dist/procedures/fs/exists.js +20 -0
- package/dist/procedures/fs/exists.js.map +1 -0
- package/dist/procedures/fs/glob.d.ts +17 -0
- package/dist/procedures/fs/glob.d.ts.map +1 -0
- package/dist/procedures/fs/glob.js +85 -0
- package/dist/procedures/fs/glob.js.map +1 -0
- package/dist/procedures/fs/index.d.ts +12 -0
- package/dist/procedures/fs/index.d.ts.map +1 -0
- package/dist/procedures/fs/index.js +12 -0
- package/dist/procedures/fs/index.js.map +1 -0
- package/dist/procedures/fs/json.d.ts +11 -0
- package/dist/procedures/fs/json.d.ts.map +1 -0
- package/dist/procedures/fs/json.js +16 -0
- package/dist/procedures/fs/json.js.map +1 -0
- package/dist/procedures/fs/mkdir.d.ts +11 -0
- package/dist/procedures/fs/mkdir.d.ts.map +1 -0
- package/dist/procedures/fs/mkdir.js +39 -0
- package/dist/procedures/fs/mkdir.js.map +1 -0
- package/dist/procedures/fs/move.d.ts +11 -0
- package/dist/procedures/fs/move.d.ts.map +1 -0
- package/dist/procedures/fs/move.js +46 -0
- package/dist/procedures/fs/move.js.map +1 -0
- package/dist/procedures/fs/read.d.ts +11 -0
- package/dist/procedures/fs/read.d.ts.map +1 -0
- package/dist/procedures/fs/read.js +21 -0
- package/dist/procedures/fs/read.js.map +1 -0
- package/dist/procedures/fs/readdir.d.ts +11 -0
- package/dist/procedures/fs/readdir.d.ts.map +1 -0
- package/dist/procedures/fs/readdir.js +38 -0
- package/dist/procedures/fs/readdir.js.map +1 -0
- package/dist/procedures/fs/rm.d.ts +11 -0
- package/dist/procedures/fs/rm.d.ts.map +1 -0
- package/dist/procedures/fs/rm.js +30 -0
- package/dist/procedures/fs/rm.js.map +1 -0
- package/dist/procedures/fs/stat.d.ts +11 -0
- package/dist/procedures/fs/stat.d.ts.map +1 -0
- package/dist/procedures/fs/stat.js +29 -0
- package/dist/procedures/fs/stat.js.map +1 -0
- package/dist/procedures/fs/write.d.ts +11 -0
- package/dist/procedures/fs/write.d.ts.map +1 -0
- package/dist/procedures/fs/write.js +24 -0
- package/dist/procedures/fs/write.js.map +1 -0
- package/dist/procedures/fs.d.ts +5 -0
- package/dist/procedures/fs.d.ts.map +1 -0
- package/dist/procedures/fs.js +5 -0
- package/dist/procedures/fs.js.map +1 -0
- package/dist/register.d.ts +7 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +9 -0
- package/dist/register.js.map +1 -0
- package/dist/types.d.ts +187 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +197 -0
- package/dist/types.js.map +1 -0
- package/package.json +77 -3
- package/src/index.ts +17 -0
- package/src/module.ts +265 -0
- package/src/procedures/fs/copy.ts +24 -0
- package/src/procedures/fs/exists.ts +20 -0
- package/src/procedures/fs/glob.ts +92 -0
- package/src/procedures/fs/index.ts +11 -0
- package/src/procedures/fs/json.ts +21 -0
- package/src/procedures/fs/mkdir.ts +43 -0
- package/src/procedures/fs/move.ts +47 -0
- package/src/procedures/fs/read.ts +23 -0
- package/src/procedures/fs/readdir.ts +44 -0
- package/src/procedures/fs/rm.ts +31 -0
- package/src/procedures/fs/stat.ts +30 -0
- package/src/procedures/fs/write.ts +27 -0
- package/src/procedures/fs.ts +5 -0
- package/src/register.ts +11 -0
- package/src/types.ts +407 -0
package/README.md
CHANGED
|
@@ -1,3 +1,896 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @procedures/fs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@procedures/fs)
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
|
|
9
|
+
File system operations as RPC procedures. Read, write, copy, move, glob files and directories via `client.call()`.
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
`client-fs` provides comprehensive file system access through the client procedure ecosystem with:
|
|
14
|
+
- **File operations**: Read, write, stat, exists, remove
|
|
15
|
+
- **Directory operations**: Create, list, copy, move
|
|
16
|
+
- **Pattern matching**: Glob file search via the Node.js `fs.glob` API (`node:fs/promises`, requires Node >= 22)
|
|
17
|
+
- **JSON utilities**: Read and parse JSON files
|
|
18
|
+
- **Zod validation**: Runtime type safety on all inputs
|
|
19
|
+
|
|
20
|
+
The package has 11 procedures. Its register entry (`import "@procedures/fs/register"`) registers them:
|
|
21
|
+
`fs.read`, `fs.write`, `fs.exists`, `fs.stat`, `fs.mkdir`, `fs.rm`, `fs.readdir`, `fs.copy`, `fs.move`, `fs.glob`, `fs.read.json`
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
```mermaid
|
|
26
|
+
graph TB
|
|
27
|
+
subgraph "Client Ecosystem"
|
|
28
|
+
Client["@procedures/client"]
|
|
29
|
+
Registry["Procedure Registry"]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
subgraph "client-fs Package"
|
|
33
|
+
Register["register.ts<br/>(Auto-registers procedures)"]
|
|
34
|
+
Types["types.ts<br/>(Zod Schemas + Types)"]
|
|
35
|
+
|
|
36
|
+
subgraph "Procedure Categories"
|
|
37
|
+
FileOps["File Operations<br/>read, write, exists, stat, rm"]
|
|
38
|
+
DirOps["Directory Operations<br/>mkdir, readdir, copy, move"]
|
|
39
|
+
PatternOps["Pattern Operations<br/>glob, read.json"]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
subgraph "Node.js Modules"
|
|
44
|
+
NodeFs["node:fs/promises"]
|
|
45
|
+
NodePath["node:path"]
|
|
46
|
+
NodeGlob["node:fs/promises glob<br/>(Node >= 22)"]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
subgraph "File System"
|
|
50
|
+
FS["Local File System"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
Register --> Client
|
|
54
|
+
Register --> Registry
|
|
55
|
+
|
|
56
|
+
FileOps --> NodeFs
|
|
57
|
+
DirOps --> NodeFs
|
|
58
|
+
PatternOps --> NodeGlob
|
|
59
|
+
|
|
60
|
+
NodeFs --> NodePath
|
|
61
|
+
NodeFs --> FS
|
|
62
|
+
NodeGlob --> FS
|
|
63
|
+
|
|
64
|
+
Types -.validates.-> FileOps
|
|
65
|
+
Types -.validates.-> DirOps
|
|
66
|
+
Types -.validates.-> PatternOps
|
|
67
|
+
|
|
68
|
+
style Register fill:#e1f5ff
|
|
69
|
+
style Types fill:#f0f0f0
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Package Dependency Flow
|
|
73
|
+
|
|
74
|
+
```mermaid
|
|
75
|
+
graph LR
|
|
76
|
+
App["Your Application"]
|
|
77
|
+
ClientFs["@procedures/fs"]
|
|
78
|
+
Client["@procedures/client"]
|
|
79
|
+
Zod["zod"]
|
|
80
|
+
NodeModules["node:fs/promises<br/>(glob: Node >= 22)"]
|
|
81
|
+
|
|
82
|
+
App --> ClientFs
|
|
83
|
+
ClientFs --> Client
|
|
84
|
+
ClientFs --> Zod
|
|
85
|
+
ClientFs --> NodeModules
|
|
86
|
+
|
|
87
|
+
App -.client.call.-> Client
|
|
88
|
+
Client -.executes.-> ClientFs
|
|
89
|
+
ClientFs -.validates.-> Zod
|
|
90
|
+
ClientFs -.file ops.-> NodeModules
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Installation
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install @procedures/fs
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Peer Dependencies
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"@procedures/client": "github:mark1russell7/client#main",
|
|
104
|
+
"zod": "^3.24.0"
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## API Reference
|
|
109
|
+
|
|
110
|
+
### File Operations
|
|
111
|
+
|
|
112
|
+
#### `fs.read`
|
|
113
|
+
|
|
114
|
+
Read file contents as a string.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const result = await client.exec(
|
|
118
|
+
["fs", "read"],
|
|
119
|
+
{
|
|
120
|
+
path: "./config.json",
|
|
121
|
+
encoding: "utf8"
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
console.log(result.content);
|
|
126
|
+
console.log(result.stats.size);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Input:**
|
|
130
|
+
```typescript
|
|
131
|
+
interface ReadInput {
|
|
132
|
+
path: string; // File path (absolute or relative)
|
|
133
|
+
encoding?: string; // Default: "utf8"
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Output:**
|
|
138
|
+
```typescript
|
|
139
|
+
interface ReadOutput {
|
|
140
|
+
content: string; // File contents
|
|
141
|
+
path: string; // Resolved absolute path
|
|
142
|
+
stats: StatOutput; // File statistics
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### `fs.write`
|
|
147
|
+
|
|
148
|
+
Write content to a file.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
await client.exec(
|
|
152
|
+
["fs", "write"],
|
|
153
|
+
{
|
|
154
|
+
path: "./output.txt",
|
|
155
|
+
content: "Hello, World!",
|
|
156
|
+
mode: "write" // or "append"
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Input:**
|
|
162
|
+
```typescript
|
|
163
|
+
interface WriteInput {
|
|
164
|
+
path: string; // File path
|
|
165
|
+
content: string; // Content to write
|
|
166
|
+
encoding?: string; // Default: "utf8"
|
|
167
|
+
mode?: "write" | "append"; // Default: "write"
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Output:**
|
|
172
|
+
```typescript
|
|
173
|
+
interface WriteOutput {
|
|
174
|
+
path: string; // Written file path
|
|
175
|
+
bytesWritten: number; // Number of bytes written
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### `fs.exists`
|
|
180
|
+
|
|
181
|
+
Check if a path exists and get its type.
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
const result = await client.exec(
|
|
185
|
+
["fs", "exists"],
|
|
186
|
+
{ path: "./my-file.txt" }
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (result.exists) {
|
|
190
|
+
console.log(`Path exists and is a ${result.stats.type}`);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Input:**
|
|
195
|
+
```typescript
|
|
196
|
+
interface ExistsInput {
|
|
197
|
+
path: string;
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Output:**
|
|
202
|
+
```typescript
|
|
203
|
+
type ExistsOutput =
|
|
204
|
+
| { exists: false }
|
|
205
|
+
| { exists: true; stats: StatOutput };
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### `fs.stat`
|
|
209
|
+
|
|
210
|
+
Get file or directory statistics.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const result = await client.exec(
|
|
214
|
+
["fs", "stat"],
|
|
215
|
+
{ path: "./my-directory" }
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
console.log(result.type); // "file" | "directory" | "other"
|
|
219
|
+
console.log(result.size); // Size in bytes
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Input:**
|
|
223
|
+
```typescript
|
|
224
|
+
interface StatInput {
|
|
225
|
+
path: string;
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Output:**
|
|
230
|
+
```typescript
|
|
231
|
+
interface StatOutput {
|
|
232
|
+
path: string;
|
|
233
|
+
type: FileType; // "file" | "directory" | "other"
|
|
234
|
+
size: number; // Size in bytes
|
|
235
|
+
mtime: string; // Modified time (ISO)
|
|
236
|
+
ctime: string; // Created time (ISO)
|
|
237
|
+
atime: string; // Accessed time (ISO)
|
|
238
|
+
mode: number; // Unix permissions
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
enum FileType {
|
|
242
|
+
File = "file",
|
|
243
|
+
Directory = "directory",
|
|
244
|
+
Other = "other"
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### `fs.rm`
|
|
249
|
+
|
|
250
|
+
Remove a file or directory.
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
// Remove file
|
|
254
|
+
await client.exec(
|
|
255
|
+
["fs", "rm"],
|
|
256
|
+
{ path: "./old-file.txt" }
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
// Remove directory recursively
|
|
260
|
+
await client.exec(
|
|
261
|
+
["fs", "rm"],
|
|
262
|
+
{
|
|
263
|
+
path: "./old-directory",
|
|
264
|
+
recursive: true,
|
|
265
|
+
force: true
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Input:**
|
|
271
|
+
```typescript
|
|
272
|
+
interface RmInput {
|
|
273
|
+
path: string;
|
|
274
|
+
recursive?: boolean; // Default: false
|
|
275
|
+
force?: boolean; // Ignore if doesn't exist (default: false)
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Output:**
|
|
280
|
+
```typescript
|
|
281
|
+
interface RmOutput {
|
|
282
|
+
path: string;
|
|
283
|
+
removed: boolean; // false if didn't exist with force=true
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Directory Operations
|
|
288
|
+
|
|
289
|
+
#### `fs.mkdir`
|
|
290
|
+
|
|
291
|
+
Create a directory.
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
await client.exec(
|
|
295
|
+
["fs", "mkdir"],
|
|
296
|
+
{
|
|
297
|
+
path: "./new/nested/directory",
|
|
298
|
+
recursive: true // Create parents if needed
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Input:**
|
|
304
|
+
```typescript
|
|
305
|
+
interface MkdirInput {
|
|
306
|
+
path: string;
|
|
307
|
+
recursive?: boolean; // Default: true
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Output:**
|
|
312
|
+
```typescript
|
|
313
|
+
interface MkdirOutput {
|
|
314
|
+
path: string;
|
|
315
|
+
created: boolean; // false if already existed
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### `fs.readdir`
|
|
320
|
+
|
|
321
|
+
List directory contents.
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
const result = await client.exec(
|
|
325
|
+
["fs", "readdir"],
|
|
326
|
+
{
|
|
327
|
+
path: "./src",
|
|
328
|
+
recursive: true,
|
|
329
|
+
includeStats: true
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
result.entries.forEach(entry => {
|
|
334
|
+
console.log(`${entry.type}: ${entry.path}`);
|
|
335
|
+
if (entry.stats) {
|
|
336
|
+
console.log(` Size: ${entry.stats.size} bytes`);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Input:**
|
|
342
|
+
```typescript
|
|
343
|
+
interface ReaddirInput {
|
|
344
|
+
path: string;
|
|
345
|
+
recursive?: boolean; // Default: false
|
|
346
|
+
includeStats?: boolean; // Default: false
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**Output:**
|
|
351
|
+
```typescript
|
|
352
|
+
interface ReaddirOutput {
|
|
353
|
+
path: string;
|
|
354
|
+
entries: ReaddirEntry[];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
interface ReaddirEntry {
|
|
358
|
+
name: string; // Entry name
|
|
359
|
+
path: string; // Full path
|
|
360
|
+
type: FileType; // "file" | "directory" | "other"
|
|
361
|
+
stats?: StatOutput; // If includeStats=true
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
#### `fs.copy`
|
|
366
|
+
|
|
367
|
+
Copy a file or directory.
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
// Copy file
|
|
371
|
+
await client.exec(
|
|
372
|
+
["fs", "copy"],
|
|
373
|
+
{
|
|
374
|
+
src: "./source.txt",
|
|
375
|
+
dest: "./destination.txt",
|
|
376
|
+
overwrite: true
|
|
377
|
+
}
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
// Copy directory recursively
|
|
381
|
+
await client.exec(
|
|
382
|
+
["fs", "copy"],
|
|
383
|
+
{
|
|
384
|
+
src: "./src-dir",
|
|
385
|
+
dest: "./dest-dir",
|
|
386
|
+
recursive: true
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Input:**
|
|
392
|
+
```typescript
|
|
393
|
+
interface CopyInput {
|
|
394
|
+
src: string;
|
|
395
|
+
dest: string;
|
|
396
|
+
recursive?: boolean; // Default: true
|
|
397
|
+
overwrite?: boolean; // Default: false
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Output:**
|
|
402
|
+
```typescript
|
|
403
|
+
interface CopyOutput {
|
|
404
|
+
src: string;
|
|
405
|
+
dest: string;
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
#### `fs.move`
|
|
410
|
+
|
|
411
|
+
Move or rename a file or directory.
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
await client.exec(
|
|
415
|
+
["fs", "move"],
|
|
416
|
+
{
|
|
417
|
+
src: "./old-name.txt",
|
|
418
|
+
dest: "./new-name.txt",
|
|
419
|
+
overwrite: false
|
|
420
|
+
}
|
|
421
|
+
);
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Input:**
|
|
425
|
+
```typescript
|
|
426
|
+
interface MoveInput {
|
|
427
|
+
src: string;
|
|
428
|
+
dest: string;
|
|
429
|
+
overwrite?: boolean; // Default: false
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**Output:**
|
|
434
|
+
```typescript
|
|
435
|
+
interface MoveOutput {
|
|
436
|
+
src: string;
|
|
437
|
+
dest: string;
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Pattern Matching Operations
|
|
442
|
+
|
|
443
|
+
#### `fs.glob`
|
|
444
|
+
|
|
445
|
+
Find files matching a glob pattern using the Node.js `fs.glob` API (`node:fs/promises`, requires Node >= 22).
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
const result = await client.exec(
|
|
449
|
+
["fs", "glob"],
|
|
450
|
+
{
|
|
451
|
+
pattern: "src/**/*.{ts,tsx}",
|
|
452
|
+
cwd: "/my/project",
|
|
453
|
+
absolute: true,
|
|
454
|
+
dot: false
|
|
455
|
+
}
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
console.log(result.matches);
|
|
459
|
+
// ["/my/project/src/index.ts", "/my/project/src/components/App.tsx", ...]
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
**Input:**
|
|
463
|
+
```typescript
|
|
464
|
+
interface GlobInput {
|
|
465
|
+
pattern: string; // Glob pattern (e.g., "**/*.ts")
|
|
466
|
+
cwd?: string; // Base directory (default: process.cwd())
|
|
467
|
+
absolute?: boolean; // Return absolute paths (default: false)
|
|
468
|
+
dot?: boolean; // Include dotfiles (default: false)
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
**Output:**
|
|
473
|
+
```typescript
|
|
474
|
+
interface GlobOutput {
|
|
475
|
+
pattern: string;
|
|
476
|
+
matches: string[]; // Matching file paths
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
**Glob Pattern Examples:**
|
|
481
|
+
```typescript
|
|
482
|
+
// All TypeScript files
|
|
483
|
+
"**/*.ts"
|
|
484
|
+
|
|
485
|
+
// All files in src directory
|
|
486
|
+
"src/**/*"
|
|
487
|
+
|
|
488
|
+
// TypeScript and JavaScript files
|
|
489
|
+
"**/*.{ts,js}"
|
|
490
|
+
|
|
491
|
+
// Note: node:fs/promises glob does NOT exclude node_modules by default;
|
|
492
|
+
// pass an `exclude` pattern or scope the pattern (e.g. "src/**/*.ts")
|
|
493
|
+
"src/**/*.ts"
|
|
494
|
+
|
|
495
|
+
// Include test files
|
|
496
|
+
"**/*.{test,spec}.ts"
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
#### `fs.read.json`
|
|
500
|
+
|
|
501
|
+
Read and parse a JSON file.
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
const result = await client.exec(
|
|
505
|
+
["fs", "read.json"],
|
|
506
|
+
{ path: "./package.json" }
|
|
507
|
+
);
|
|
508
|
+
|
|
509
|
+
console.log(result.data); // Parsed JSON object
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**Input:**
|
|
513
|
+
```typescript
|
|
514
|
+
interface ReadJsonInput {
|
|
515
|
+
path: string;
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**Output:**
|
|
520
|
+
```typescript
|
|
521
|
+
interface ReadJsonOutput {
|
|
522
|
+
path: string;
|
|
523
|
+
data: unknown; // Parsed JSON (cast to your type)
|
|
524
|
+
stats: StatOutput;
|
|
525
|
+
}
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
**Type-safe example:**
|
|
529
|
+
```typescript
|
|
530
|
+
interface PackageJson {
|
|
531
|
+
name: string;
|
|
532
|
+
version: string;
|
|
533
|
+
dependencies: Record<string, string>;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const result = await client.exec(
|
|
537
|
+
["fs", "read.json"],
|
|
538
|
+
{ path: "./package.json" }
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
const pkg = result.data as PackageJson;
|
|
542
|
+
console.log(pkg.name, pkg.version);
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
## Usage Examples
|
|
546
|
+
|
|
547
|
+
### Basic File Operations
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
import { Client, LocalTransport, PROCEDURE_REGISTRY } from "@procedures/client";
|
|
551
|
+
import "@procedures/fs/register"; // registers its procedures
|
|
552
|
+
|
|
553
|
+
const client = new Client(new LocalTransport({ registry: PROCEDURE_REGISTRY }));
|
|
554
|
+
|
|
555
|
+
// Read a file
|
|
556
|
+
const { content } = await client.exec(
|
|
557
|
+
["fs", "read"],
|
|
558
|
+
{ path: "./README.md" }
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
// Write to a file
|
|
562
|
+
await client.exec(
|
|
563
|
+
["fs", "write"],
|
|
564
|
+
{
|
|
565
|
+
path: "./output.txt",
|
|
566
|
+
content: "Generated content\n",
|
|
567
|
+
mode: "write"
|
|
568
|
+
}
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
// Append to a file
|
|
572
|
+
await client.exec(
|
|
573
|
+
["fs", "write"],
|
|
574
|
+
{
|
|
575
|
+
path: "./log.txt",
|
|
576
|
+
content: `[${new Date().toISOString()}] Log entry\n`,
|
|
577
|
+
mode: "append"
|
|
578
|
+
}
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
// Check if file exists
|
|
582
|
+
const exists = await client.exec(
|
|
583
|
+
["fs", "exists"],
|
|
584
|
+
{ path: "./config.json" }
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
if (exists.exists) {
|
|
588
|
+
// Get file stats
|
|
589
|
+
const stats = await client.exec(
|
|
590
|
+
["fs", "stat"],
|
|
591
|
+
{ path: "./config.json" }
|
|
592
|
+
);
|
|
593
|
+
console.log(`File size: ${stats.size} bytes`);
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
### Directory Operations
|
|
598
|
+
|
|
599
|
+
```typescript
|
|
600
|
+
// Create nested directories
|
|
601
|
+
await client.exec(
|
|
602
|
+
["fs", "mkdir"],
|
|
603
|
+
{
|
|
604
|
+
path: "./build/assets/images",
|
|
605
|
+
recursive: true
|
|
606
|
+
}
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
// List directory contents
|
|
610
|
+
const { entries } = await client.exec(
|
|
611
|
+
["fs", "readdir"],
|
|
612
|
+
{
|
|
613
|
+
path: "./src",
|
|
614
|
+
includeStats: true
|
|
615
|
+
}
|
|
616
|
+
);
|
|
617
|
+
|
|
618
|
+
entries.forEach(entry => {
|
|
619
|
+
if (entry.type === "file") {
|
|
620
|
+
console.log(`File: ${entry.name} (${entry.stats?.size} bytes)`);
|
|
621
|
+
} else {
|
|
622
|
+
console.log(`Directory: ${entry.name}`);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
// Recursive directory listing
|
|
627
|
+
const { entries: allFiles } = await client.exec(
|
|
628
|
+
["fs", "readdir"],
|
|
629
|
+
{
|
|
630
|
+
path: "./src",
|
|
631
|
+
recursive: true
|
|
632
|
+
}
|
|
633
|
+
);
|
|
634
|
+
|
|
635
|
+
console.log(`Total items: ${allFiles.length}`);
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
### Copy and Move Operations
|
|
639
|
+
|
|
640
|
+
```typescript
|
|
641
|
+
// Backup a file
|
|
642
|
+
await client.exec(
|
|
643
|
+
["fs", "copy"],
|
|
644
|
+
{
|
|
645
|
+
src: "./important-data.json",
|
|
646
|
+
dest: "./backups/important-data.backup.json"
|
|
647
|
+
}
|
|
648
|
+
);
|
|
649
|
+
|
|
650
|
+
// Copy entire directory
|
|
651
|
+
await client.exec(
|
|
652
|
+
["fs", "copy"],
|
|
653
|
+
{
|
|
654
|
+
src: "./templates",
|
|
655
|
+
dest: "./build/templates",
|
|
656
|
+
recursive: true,
|
|
657
|
+
overwrite: true
|
|
658
|
+
}
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
// Rename a file
|
|
662
|
+
await client.exec(
|
|
663
|
+
["fs", "move"],
|
|
664
|
+
{
|
|
665
|
+
src: "./old-name.txt",
|
|
666
|
+
dest: "./new-name.txt"
|
|
667
|
+
}
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
// Move to different directory
|
|
671
|
+
await client.exec(
|
|
672
|
+
["fs", "move"],
|
|
673
|
+
{
|
|
674
|
+
src: "./temp/file.txt",
|
|
675
|
+
dest: "./archive/file.txt",
|
|
676
|
+
overwrite: false
|
|
677
|
+
}
|
|
678
|
+
);
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Pattern Matching with Glob
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
// Find all TypeScript files
|
|
685
|
+
const { matches: tsFiles } = await client.exec(
|
|
686
|
+
["fs", "glob"],
|
|
687
|
+
{
|
|
688
|
+
pattern: "**/*.ts",
|
|
689
|
+
cwd: "./src",
|
|
690
|
+
absolute: true
|
|
691
|
+
}
|
|
692
|
+
);
|
|
693
|
+
|
|
694
|
+
console.log(`Found ${tsFiles.length} TypeScript files`);
|
|
695
|
+
|
|
696
|
+
// Find test files
|
|
697
|
+
const { matches: testFiles } = await client.exec(
|
|
698
|
+
["fs", "glob"],
|
|
699
|
+
{
|
|
700
|
+
pattern: "**/*.{test,spec}.{ts,js}",
|
|
701
|
+
cwd: "."
|
|
702
|
+
}
|
|
703
|
+
);
|
|
704
|
+
|
|
705
|
+
// Find config files
|
|
706
|
+
const { matches: configs } = await client.exec(
|
|
707
|
+
["fs", "glob"],
|
|
708
|
+
{
|
|
709
|
+
pattern: "**/*.config.{js,ts,json}",
|
|
710
|
+
dot: true // Include dotfiles like .eslintrc.json
|
|
711
|
+
}
|
|
712
|
+
);
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
### JSON File Operations
|
|
716
|
+
|
|
717
|
+
```typescript
|
|
718
|
+
// Read package.json
|
|
719
|
+
const { data: pkg } = await client.exec(
|
|
720
|
+
["fs", "read.json"],
|
|
721
|
+
{ path: "./package.json" }
|
|
722
|
+
);
|
|
723
|
+
|
|
724
|
+
console.log(`Package: ${pkg.name}@${pkg.version}`);
|
|
725
|
+
|
|
726
|
+
// Read tsconfig.json
|
|
727
|
+
const { data: tsconfig } = await client.exec(
|
|
728
|
+
["fs", "read.json"],
|
|
729
|
+
{ path: "./tsconfig.json" }
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
console.log("Compiler options:", tsconfig.compilerOptions);
|
|
733
|
+
|
|
734
|
+
// Read and modify JSON
|
|
735
|
+
const { data: config } = await client.exec(
|
|
736
|
+
["fs", "read.json"],
|
|
737
|
+
{ path: "./config.json" }
|
|
738
|
+
);
|
|
739
|
+
|
|
740
|
+
config.lastUpdated = new Date().toISOString();
|
|
741
|
+
|
|
742
|
+
await client.exec(
|
|
743
|
+
["fs", "write"],
|
|
744
|
+
{
|
|
745
|
+
path: "./config.json",
|
|
746
|
+
content: JSON.stringify(config, null, 2)
|
|
747
|
+
}
|
|
748
|
+
);
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
### Build Script Example
|
|
752
|
+
|
|
753
|
+
```typescript
|
|
754
|
+
// Clean build directory
|
|
755
|
+
await client.exec(
|
|
756
|
+
["fs", "rm"],
|
|
757
|
+
{
|
|
758
|
+
path: "./dist",
|
|
759
|
+
recursive: true,
|
|
760
|
+
force: true
|
|
761
|
+
}
|
|
762
|
+
);
|
|
763
|
+
|
|
764
|
+
// Create build directory
|
|
765
|
+
await client.exec(
|
|
766
|
+
["fs", "mkdir"],
|
|
767
|
+
{ path: "./dist" }
|
|
768
|
+
);
|
|
769
|
+
|
|
770
|
+
// Find all source files
|
|
771
|
+
const { matches: sourceFiles } = await client.exec(
|
|
772
|
+
["fs", "glob"],
|
|
773
|
+
{
|
|
774
|
+
pattern: "src/**/*.ts",
|
|
775
|
+
absolute: true
|
|
776
|
+
}
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
// Process each file...
|
|
780
|
+
for (const file of sourceFiles) {
|
|
781
|
+
const { content } = await client.exec(
|
|
782
|
+
["fs", "read"],
|
|
783
|
+
{ path: file }
|
|
784
|
+
);
|
|
785
|
+
|
|
786
|
+
// Transform content...
|
|
787
|
+
const transformed = content.replace(/\.ts$/, ".js");
|
|
788
|
+
|
|
789
|
+
await client.exec(
|
|
790
|
+
["fs", "write"],
|
|
791
|
+
{
|
|
792
|
+
path: file.replace("src/", "dist/").replace(".ts", ".js"),
|
|
793
|
+
content: transformed
|
|
794
|
+
}
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// Copy assets
|
|
799
|
+
await client.exec(
|
|
800
|
+
["fs", "copy"],
|
|
801
|
+
{
|
|
802
|
+
src: "./public",
|
|
803
|
+
dest: "./dist/public",
|
|
804
|
+
recursive: true
|
|
805
|
+
}
|
|
806
|
+
);
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
## Integration with Ecosystem
|
|
810
|
+
|
|
811
|
+
### Bundle Packages
|
|
812
|
+
|
|
813
|
+
`client-fs` can be included in bundle packages:
|
|
814
|
+
|
|
815
|
+
```typescript
|
|
816
|
+
// In bundle-dev/src/register.ts
|
|
817
|
+
import "@procedures/fs/register"; // registers its procedures
|
|
818
|
+
import "@procedures/shell/register"; // registers its procedures
|
|
819
|
+
import "@procedures/cli-run/register"; // registers its procedures
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
## Dependencies
|
|
823
|
+
|
|
824
|
+
### Runtime Dependencies
|
|
825
|
+
|
|
826
|
+
- **@procedures/client** - Core client procedure system
|
|
827
|
+
- **zod** (^3.24.0) - Runtime type validation
|
|
828
|
+
|
|
829
|
+
### Implicit Dependencies
|
|
830
|
+
|
|
831
|
+
- **node:fs/promises** - Node.js file system promises API
|
|
832
|
+
- **node:path** - Node.js path utilities
|
|
833
|
+
- **node:fs/promises `glob`** - Glob pattern matching (used by the `fs.glob` procedure; requires Node >= 22)
|
|
834
|
+
|
|
835
|
+
### Development Dependencies
|
|
836
|
+
|
|
837
|
+
- **@mark1russell7/cue** - Configuration and type utilities
|
|
838
|
+
- **typescript** (^5.9.3) - TypeScript compiler
|
|
839
|
+
- **@types/node** (^22.0.0) - Node.js type definitions
|
|
840
|
+
|
|
841
|
+
## Package Structure
|
|
842
|
+
|
|
843
|
+
```
|
|
844
|
+
client-fs/
|
|
845
|
+
├── src/
|
|
846
|
+
│ ├── types.ts # Zod schemas + TypeScript types
|
|
847
|
+
│ ├── register.ts # Auto-registration
|
|
848
|
+
│ ├── index.ts # Main entry point
|
|
849
|
+
│ ├── procedures/
|
|
850
|
+
│ │ ├── fs.ts # Barrel export
|
|
851
|
+
│ │ └── fs/
|
|
852
|
+
│ │ ├── index.ts # Procedure exports
|
|
853
|
+
│ │ ├── read.ts # fs.read
|
|
854
|
+
│ │ ├── write.ts # fs.write
|
|
855
|
+
│ │ ├── exists.ts # fs.exists
|
|
856
|
+
│ │ ├── stat.ts # fs.stat
|
|
857
|
+
│ │ ├── mkdir.ts # fs.mkdir
|
|
858
|
+
│ │ ├── rm.ts # fs.rm
|
|
859
|
+
│ │ ├── readdir.ts # fs.readdir
|
|
860
|
+
│ │ ├── copy.ts # fs.copy
|
|
861
|
+
│ │ ├── move.ts # fs.move
|
|
862
|
+
│ │ ├── glob.ts # fs.glob
|
|
863
|
+
│ │ └── json.ts # fs.read.json
|
|
864
|
+
├── dist/ # Compiled output
|
|
865
|
+
├── package.json
|
|
866
|
+
├── tsconfig.json
|
|
867
|
+
└── README.md
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
## Development
|
|
871
|
+
|
|
872
|
+
### Build
|
|
873
|
+
|
|
874
|
+
```bash
|
|
875
|
+
npm run build
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
### Type Check
|
|
879
|
+
|
|
880
|
+
```bash
|
|
881
|
+
npm run typecheck
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
### Clean
|
|
885
|
+
|
|
886
|
+
```bash
|
|
887
|
+
npm run clean
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
## License
|
|
891
|
+
|
|
892
|
+
MIT
|
|
893
|
+
|
|
894
|
+
## Author
|
|
895
|
+
|
|
896
|
+
Mark Russell <marktheprogrammer17@gmail.com>
|