@archildata/just-bash 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.
package/dist/index.cjs ADDED
@@ -0,0 +1,532 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // src/ArchilFs.ts
34
+ var ArchilFs_exports = {};
35
+ __export(ArchilFs_exports, {
36
+ ArchilFs: () => ArchilFs
37
+ });
38
+ var import_debug, debug, ArchilFs;
39
+ var init_ArchilFs = __esm({
40
+ "src/ArchilFs.ts"() {
41
+ "use strict";
42
+ import_debug = __toESM(require("debug"), 1);
43
+ debug = (0, import_debug.default)("archil:fs");
44
+ ArchilFs = class {
45
+ client;
46
+ user;
47
+ rootInodeId = 1;
48
+ /**
49
+ * Create a new ArchilFs adapter
50
+ *
51
+ * @param client - Connected ArchilClient instance
52
+ * @param options - Optional configuration
53
+ * @param options.user - Unix user context for permission checks
54
+ */
55
+ constructor(client, options) {
56
+ this.client = client;
57
+ this.user = options?.user;
58
+ }
59
+ // ========================================================================
60
+ // Path Resolution
61
+ // ========================================================================
62
+ /**
63
+ * Normalize a path (remove . and .., ensure leading /)
64
+ */
65
+ normalizePath(path) {
66
+ if (!path || path === "") {
67
+ return "/";
68
+ }
69
+ if (!path.startsWith("/")) {
70
+ path = "/" + path;
71
+ }
72
+ const parts = path.split("/").filter((p) => p !== "" && p !== ".");
73
+ const result = [];
74
+ for (const part of parts) {
75
+ if (part === "..") {
76
+ result.pop();
77
+ } else {
78
+ result.push(part);
79
+ }
80
+ }
81
+ return "/" + result.join("/");
82
+ }
83
+ /**
84
+ * Resolve a path to its inode ID, walking the directory tree
85
+ */
86
+ async resolve(path) {
87
+ const normalizedPath = this.normalizePath(path);
88
+ const parts = normalizedPath.split("/").filter((p) => p !== "");
89
+ let currentInodeId = this.rootInodeId;
90
+ for (const part of parts) {
91
+ const response = await this.client.lookupInode(currentInodeId, part, this.user);
92
+ if (response.inodeId === -1) {
93
+ throw new Error(`ENOENT: no such file or directory, '${path}'`);
94
+ }
95
+ currentInodeId = response.inodeId;
96
+ }
97
+ const attributes = await this.client.getAttributes(currentInodeId, this.user);
98
+ return { inodeId: currentInodeId, attributes };
99
+ }
100
+ /**
101
+ * Resolve parent directory and get child name
102
+ */
103
+ async resolveParent(path) {
104
+ debug("resolveParent raw path=%j (bytes: %o)", path, Buffer.from(path));
105
+ const normalizedPath = this.normalizePath(path);
106
+ const lastSlash = normalizedPath.lastIndexOf("/");
107
+ const parentPath = lastSlash === 0 ? "/" : normalizedPath.substring(0, lastSlash);
108
+ const name = normalizedPath.substring(lastSlash + 1);
109
+ debug("resolveParent extracted name=%j (bytes: %o)", name, Buffer.from(name));
110
+ const { inodeId: parentInodeId } = await this.resolve(parentPath);
111
+ return { parentInodeId, name };
112
+ }
113
+ /**
114
+ * Convert InodeAttributes to FsStat
115
+ */
116
+ toStat(attrs) {
117
+ return {
118
+ isFile: attrs.inodeType === "File",
119
+ isDirectory: attrs.inodeType === "Directory",
120
+ isSymlink: attrs.inodeType === "Symlink",
121
+ mode: attrs.mode,
122
+ size: Number(attrs.size),
123
+ mtime: new Date(attrs.mtimeMs)
124
+ };
125
+ }
126
+ // ========================================================================
127
+ // IFileSystem Implementation - Read Operations
128
+ // ========================================================================
129
+ resolvePath(base, ...paths) {
130
+ debug("resolvePath base=%s paths=%o", base, paths);
131
+ let result = base;
132
+ for (const p of paths) {
133
+ if (p.startsWith("/")) {
134
+ result = p;
135
+ } else {
136
+ result = result.endsWith("/") ? result + p : result + "/" + p;
137
+ }
138
+ }
139
+ const normalized = this.normalizePath(result);
140
+ debug("resolvePath result=%s", normalized);
141
+ return normalized;
142
+ }
143
+ async readFile(path, encoding) {
144
+ debug("readFile path=%s encoding=%s", path, encoding);
145
+ try {
146
+ const buffer = await this.readFileBuffer(path);
147
+ debug("readFile got buffer length=%d", buffer.length);
148
+ const decoderEncoding = encoding === "binary" ? "latin1" : encoding || "utf-8";
149
+ debug("readFile using decoder encoding=%s", decoderEncoding);
150
+ const decoder = new TextDecoder(decoderEncoding);
151
+ const result = decoder.decode(buffer);
152
+ debug("readFile decoded to string length=%d", result.length);
153
+ return result;
154
+ } catch (err) {
155
+ debug("readFile FAILED: %O", err);
156
+ throw err;
157
+ }
158
+ }
159
+ async readFileBuffer(path) {
160
+ debug("readFileBuffer path=%s", path);
161
+ const { inodeId, attributes } = await this.resolve(path);
162
+ debug("readFileBuffer resolved inodeId=%d type=%s size=%d", inodeId, attributes.inodeType, attributes.size);
163
+ if (attributes.inodeType !== "File") {
164
+ throw new Error(`EISDIR: illegal operation on a directory, read '${path}'`);
165
+ }
166
+ const size = Number(attributes.size);
167
+ if (size === 0) {
168
+ debug("readFileBuffer file is empty, returning empty buffer");
169
+ return new Uint8Array(0);
170
+ }
171
+ const MAX_CHUNK = 4 * 1024 * 1024;
172
+ if (size <= MAX_CHUNK) {
173
+ const buffer = await this.client.readInode(inodeId, 0, size, this.user);
174
+ return new Uint8Array(buffer);
175
+ }
176
+ const result = new Uint8Array(size);
177
+ let offset = 0;
178
+ while (offset < size) {
179
+ const chunkSize = Math.min(MAX_CHUNK, size - offset);
180
+ const chunk = await this.client.readInode(inodeId, offset, chunkSize, this.user);
181
+ result.set(new Uint8Array(chunk), offset);
182
+ offset += chunkSize;
183
+ }
184
+ return result;
185
+ }
186
+ async readdir(path) {
187
+ debug("readdir path=%s", path);
188
+ const { inodeId, attributes } = await this.resolve(path);
189
+ if (attributes.inodeType !== "Directory") {
190
+ throw new Error(`ENOTDIR: not a directory, scandir '${path}'`);
191
+ }
192
+ const entries = await this.client.readDirectory(inodeId, void 0, void 0, this.user);
193
+ for (const e of entries) {
194
+ debug("readdir entry name=%j (bytes: %o)", e.name, Buffer.from(e.name));
195
+ }
196
+ return entries.map((e) => e.name).filter((name) => name !== "." && name !== "..");
197
+ }
198
+ async readdirWithFileTypes(path) {
199
+ const { inodeId, attributes } = await this.resolve(path);
200
+ if (attributes.inodeType !== "Directory") {
201
+ throw new Error(`ENOTDIR: not a directory, scandir '${path}'`);
202
+ }
203
+ const entries = await this.client.readDirectory(inodeId, void 0, void 0, this.user);
204
+ return entries.filter((e) => e.name !== "." && e.name !== "..").map((e) => ({
205
+ name: e.name,
206
+ isFile: e.inodeType === "File",
207
+ isDirectory: e.inodeType === "Directory",
208
+ isSymlink: e.inodeType === "Symlink"
209
+ }));
210
+ }
211
+ async stat(path) {
212
+ debug("stat path=%s", path);
213
+ const { attributes } = await this.resolve(path);
214
+ if (attributes.inodeType === "Symlink" && attributes.symlinkTarget) {
215
+ const targetPath = attributes.symlinkTarget.startsWith("/") ? attributes.symlinkTarget : this.resolvePath(path, "..", attributes.symlinkTarget);
216
+ return this.stat(targetPath);
217
+ }
218
+ return this.toStat(attributes);
219
+ }
220
+ async lstat(path) {
221
+ debug("lstat path=%s", path);
222
+ const { attributes } = await this.resolve(path);
223
+ return this.toStat(attributes);
224
+ }
225
+ async exists(path) {
226
+ debug("exists path=%s", path);
227
+ try {
228
+ await this.resolve(path);
229
+ debug("exists path=%s -> true", path);
230
+ return true;
231
+ } catch {
232
+ debug("exists path=%s -> false", path);
233
+ return false;
234
+ }
235
+ }
236
+ async readlink(path) {
237
+ const { attributes } = await this.resolve(path);
238
+ if (attributes.inodeType !== "Symlink") {
239
+ throw new Error(`EINVAL: invalid argument, readlink '${path}'`);
240
+ }
241
+ return attributes.symlinkTarget || "";
242
+ }
243
+ async realpath(path) {
244
+ const normalizedPath = this.normalizePath(path);
245
+ const parts = normalizedPath.split("/").filter((p) => p !== "");
246
+ let resolvedPath = "/";
247
+ let currentInodeId = this.rootInodeId;
248
+ for (const part of parts) {
249
+ const response = await this.client.lookupInode(currentInodeId, part, this.user);
250
+ if (response.inodeId === -1) {
251
+ throw new Error(`ENOENT: no such file or directory, realpath '${path}'`);
252
+ }
253
+ const attrs = response.attributes;
254
+ if (attrs.inodeType === "Symlink" && attrs.symlinkTarget) {
255
+ const targetPath = attrs.symlinkTarget.startsWith("/") ? attrs.symlinkTarget : this.resolvePath(resolvedPath, attrs.symlinkTarget);
256
+ const resolved = await this.realpath(targetPath);
257
+ resolvedPath = resolved;
258
+ const { inodeId } = await this.resolve(resolved);
259
+ currentInodeId = inodeId;
260
+ } else {
261
+ resolvedPath = resolvedPath === "/" ? "/" + part : resolvedPath + "/" + part;
262
+ currentInodeId = response.inodeId;
263
+ }
264
+ }
265
+ return resolvedPath;
266
+ }
267
+ // ========================================================================
268
+ // IFileSystem Implementation - Write Operations
269
+ // ========================================================================
270
+ async writeFile(path, content) {
271
+ debug("writeFile path=%s contentLength=%d", path, content.length);
272
+ const data = typeof content === "string" ? new TextEncoder().encode(content) : content;
273
+ let inodeId;
274
+ try {
275
+ const resolved = await this.resolve(path);
276
+ inodeId = resolved.inodeId;
277
+ debug("writeFile resolved existing file path=%s inodeId=%d", path, inodeId);
278
+ if (resolved.attributes.inodeType !== "File") {
279
+ throw new Error(`EISDIR: illegal operation on a directory, write '${path}'`);
280
+ }
281
+ } catch (err) {
282
+ if (err instanceof Error && err.message.includes("EISDIR")) {
283
+ throw err;
284
+ }
285
+ debug("writeFile file doesn't exist, creating: %s", path);
286
+ const { parentInodeId, name } = await this.resolveParent(path);
287
+ debug("writeFile resolved parent parentInodeId=%d name=%s", parentInodeId, name);
288
+ const now = Date.now();
289
+ debug("writeFile calling create parent=%d name=%s", parentInodeId, name);
290
+ try {
291
+ inodeId = await this.client.create(
292
+ parentInodeId,
293
+ name,
294
+ {
295
+ inodeId: 0,
296
+ // Will be assigned by the filesystem
297
+ inodeType: "File",
298
+ size: 0,
299
+ uid: this.user?.uid ?? 0,
300
+ gid: this.user?.gid ?? 0,
301
+ mode: 420,
302
+ nlink: 1,
303
+ ctimeMs: now,
304
+ atimeMs: now,
305
+ mtimeMs: now,
306
+ btimeMs: now,
307
+ rdev: void 0,
308
+ symlinkTarget: void 0
309
+ },
310
+ this.user
311
+ );
312
+ debug("writeFile create succeeded inodeId=%d", inodeId);
313
+ } catch (createErr) {
314
+ debug("writeFile create FAILED: %O", createErr);
315
+ throw createErr;
316
+ }
317
+ }
318
+ debug("writeFile writing %d bytes to inodeId=%d", data.length, inodeId);
319
+ await this.client.writeData(inodeId, 0, Buffer.from(data), this.user);
320
+ debug("writeFile write succeeded");
321
+ }
322
+ async appendFile(path, content) {
323
+ let existing;
324
+ try {
325
+ existing = await this.readFileBuffer(path);
326
+ } catch {
327
+ existing = new Uint8Array(0);
328
+ }
329
+ const data = typeof content === "string" ? new TextEncoder().encode(content) : content;
330
+ const combined = new Uint8Array(existing.length + data.length);
331
+ combined.set(existing, 0);
332
+ combined.set(data, existing.length);
333
+ await this.writeFile(path, combined);
334
+ }
335
+ async mkdir(path, options) {
336
+ const normalizedPath = this.normalizePath(path);
337
+ if (options?.recursive) {
338
+ const parts = normalizedPath.split("/").filter((p) => p !== "");
339
+ let currentPath = "";
340
+ for (const part of parts) {
341
+ currentPath += "/" + part;
342
+ const exists = await this.exists(currentPath);
343
+ if (exists) {
344
+ continue;
345
+ }
346
+ await this.mkdirSingle(currentPath);
347
+ }
348
+ } else {
349
+ await this.mkdirSingle(normalizedPath);
350
+ }
351
+ }
352
+ async mkdirSingle(path) {
353
+ const { parentInodeId, name } = await this.resolveParent(path);
354
+ const now = Date.now();
355
+ await this.client.create(
356
+ parentInodeId,
357
+ name,
358
+ {
359
+ inodeId: 0,
360
+ // Will be assigned by the filesystem
361
+ inodeType: "Directory",
362
+ size: 4096,
363
+ uid: this.user?.uid ?? 0,
364
+ gid: this.user?.gid ?? 0,
365
+ mode: 493,
366
+ nlink: 2,
367
+ ctimeMs: now,
368
+ atimeMs: now,
369
+ mtimeMs: now,
370
+ btimeMs: now,
371
+ rdev: void 0,
372
+ symlinkTarget: void 0
373
+ },
374
+ this.user
375
+ );
376
+ }
377
+ async rm(path, options) {
378
+ let resolved;
379
+ try {
380
+ resolved = await this.resolve(path);
381
+ } catch {
382
+ if (options?.force) {
383
+ return;
384
+ }
385
+ throw new Error(`ENOENT: no such file or directory, rm '${path}'`);
386
+ }
387
+ if (resolved.attributes.inodeType === "Directory") {
388
+ if (!options?.recursive) {
389
+ throw new Error(`EISDIR: illegal operation on a directory, rm '${path}'`);
390
+ }
391
+ const entries = await this.readdir(path);
392
+ for (const entry of entries) {
393
+ await this.rm(this.resolvePath(path, entry), options);
394
+ }
395
+ }
396
+ const { parentInodeId, name } = await this.resolveParent(path);
397
+ await this.client.unlink(parentInodeId, name, this.user);
398
+ }
399
+ async cp(src, dest, options) {
400
+ const srcResolved = await this.resolve(src);
401
+ if (srcResolved.attributes.inodeType === "Directory") {
402
+ if (!options?.recursive) {
403
+ throw new Error(`EISDIR: illegal operation on a directory, cp '${src}'`);
404
+ }
405
+ await this.mkdir(dest, { recursive: true });
406
+ const entries = await this.readdir(src);
407
+ for (const entry of entries) {
408
+ await this.cp(
409
+ this.resolvePath(src, entry),
410
+ this.resolvePath(dest, entry),
411
+ options
412
+ );
413
+ }
414
+ } else {
415
+ const content = await this.readFileBuffer(src);
416
+ await this.writeFile(dest, content);
417
+ }
418
+ }
419
+ async mv(src, dest) {
420
+ const { parentInodeId: srcParentInodeId, name: srcName } = await this.resolveParent(src);
421
+ const { parentInodeId: destParentInodeId, name: destName } = await this.resolveParent(dest);
422
+ await this.client.rename(
423
+ srcParentInodeId,
424
+ srcName,
425
+ destParentInodeId,
426
+ destName,
427
+ this.user
428
+ );
429
+ }
430
+ async symlink(target, path) {
431
+ const { parentInodeId, name } = await this.resolveParent(path);
432
+ const now = Date.now();
433
+ await this.client.create(
434
+ parentInodeId,
435
+ name,
436
+ {
437
+ inodeId: 0,
438
+ // Will be assigned by the filesystem
439
+ inodeType: "Symlink",
440
+ size: target.length,
441
+ uid: this.user?.uid ?? 0,
442
+ gid: this.user?.gid ?? 0,
443
+ mode: 511,
444
+ nlink: 1,
445
+ ctimeMs: now,
446
+ atimeMs: now,
447
+ mtimeMs: now,
448
+ btimeMs: now,
449
+ rdev: void 0,
450
+ symlinkTarget: target
451
+ },
452
+ this.user
453
+ );
454
+ }
455
+ async link(existingPath, newPath) {
456
+ throw new Error(
457
+ "Hard link operations not yet implemented. The archil-node bindings need to expose link for hard links."
458
+ );
459
+ }
460
+ async chmod(path, mode) {
461
+ const { inodeId } = await this.resolve(path);
462
+ await this.client.setattr(
463
+ inodeId,
464
+ { mode },
465
+ this.user ?? { uid: 0, gid: 0 }
466
+ );
467
+ }
468
+ async utimes(path, atime, mtime) {
469
+ debug("utimes path=%s atime=%d mtime=%d", path, atime, mtime);
470
+ const { inodeId } = await this.resolve(path);
471
+ debug("utimes resolved path=%s inodeId=%d", path, inodeId);
472
+ const atimeMs = atime === -1 ? -1 : Math.floor(atime * 1e3);
473
+ const mtimeMs = mtime === -1 ? -1 : Math.floor(mtime * 1e3);
474
+ debug("utimes calling setattr inodeId=%d atimeMs=%d mtimeMs=%d", inodeId, atimeMs, mtimeMs);
475
+ await this.client.setattr(
476
+ inodeId,
477
+ { atimeMs, mtimeMs },
478
+ this.user ?? { uid: 0, gid: 0 }
479
+ );
480
+ debug("utimes setattr succeeded inodeId=%d", inodeId);
481
+ }
482
+ // ========================================================================
483
+ // Utility Methods
484
+ // ========================================================================
485
+ async getAllPaths() {
486
+ const paths = [];
487
+ const walk = async (dirPath) => {
488
+ paths.push(dirPath);
489
+ try {
490
+ const entries = await this.readdirWithFileTypes(dirPath);
491
+ for (const entry of entries) {
492
+ const fullPath = this.resolvePath(dirPath, entry.name);
493
+ if (entry.isDirectory) {
494
+ await walk(fullPath);
495
+ } else {
496
+ paths.push(fullPath);
497
+ }
498
+ }
499
+ } catch {
500
+ }
501
+ };
502
+ await walk("/");
503
+ return paths;
504
+ }
505
+ /**
506
+ * Resolve a path to its inode ID (public wrapper for delegation operations)
507
+ */
508
+ async resolveInodeId(path) {
509
+ const { inodeId } = await this.resolve(path);
510
+ return inodeId;
511
+ }
512
+ };
513
+ }
514
+ });
515
+
516
+ // src/index.ts
517
+ var index_exports = {};
518
+ __export(index_exports, {
519
+ ArchilFs: () => ArchilFs,
520
+ createArchilFs: () => createArchilFs
521
+ });
522
+ module.exports = __toCommonJS(index_exports);
523
+ init_ArchilFs();
524
+ function createArchilFs(client, options) {
525
+ const { ArchilFs: ArchilFs2 } = (init_ArchilFs(), __toCommonJS(ArchilFs_exports));
526
+ return new ArchilFs2(client, options);
527
+ }
528
+ // Annotate the CommonJS export names for ESM import in node:
529
+ 0 && (module.exports = {
530
+ ArchilFs,
531
+ createArchilFs
532
+ });
@@ -0,0 +1,171 @@
1
+ import * as _archildata_client from '@archildata/client';
2
+ import { ArchilClient, UnixUser } from '@archildata/client';
3
+
4
+ /**
5
+ * Archil filesystem adapter for just-bash
6
+ *
7
+ * Implements the IFileSystem interface from just-bash using the ArchilClient
8
+ * from @archildata/client for direct protocol access to Archil distributed filesystems.
9
+ */
10
+
11
+ type BufferEncoding = "utf8" | "utf-8" | "ascii" | "binary" | "base64" | "hex" | "latin1";
12
+ type FileContent = string | Uint8Array;
13
+ interface FsStat {
14
+ isFile: boolean;
15
+ isDirectory: boolean;
16
+ isSymlink: boolean;
17
+ mode: number;
18
+ size: number;
19
+ mtime: Date;
20
+ }
21
+ interface DirentEntry {
22
+ name: string;
23
+ isFile: boolean;
24
+ isDirectory: boolean;
25
+ isSymlink: boolean;
26
+ }
27
+ interface IFileSystem {
28
+ readFile(path: string, encoding?: BufferEncoding): Promise<string>;
29
+ readFileBuffer(path: string): Promise<Uint8Array>;
30
+ readdir(path: string): Promise<string[]>;
31
+ readdirWithFileTypes?(path: string): Promise<DirentEntry[]>;
32
+ stat(path: string): Promise<FsStat>;
33
+ lstat(path: string): Promise<FsStat>;
34
+ exists(path: string): Promise<boolean>;
35
+ readlink(path: string): Promise<string>;
36
+ realpath(path: string): Promise<string>;
37
+ writeFile(path: string, content: FileContent): Promise<void>;
38
+ appendFile(path: string, content: FileContent): Promise<void>;
39
+ mkdir(path: string, options?: {
40
+ recursive?: boolean;
41
+ }): Promise<void>;
42
+ rm(path: string, options?: {
43
+ recursive?: boolean;
44
+ force?: boolean;
45
+ }): Promise<void>;
46
+ cp(src: string, dest: string, options?: {
47
+ recursive?: boolean;
48
+ }): Promise<void>;
49
+ mv(src: string, dest: string): Promise<void>;
50
+ symlink(target: string, path: string): Promise<void>;
51
+ link(existingPath: string, newPath: string): Promise<void>;
52
+ chmod(path: string, mode: number): Promise<void>;
53
+ utimes(path: string, atime: number, mtime: number): Promise<void>;
54
+ resolvePath(base: string, ...paths: string[]): string;
55
+ getAllPaths?(): Promise<string[]>;
56
+ }
57
+ /**
58
+ * ArchilFs implements the just-bash IFileSystem interface using Archil protocol.
59
+ *
60
+ * This adapter provides:
61
+ * - Path-to-inode resolution
62
+ * - Full filesystem operations via Archil protocol
63
+ * - Optional user context for permission checks
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * import { ArchilClient } from '@archildata/client';
68
+ * import { ArchilFs } from '@archildata/just-bash';
69
+ *
70
+ * const client = await ArchilClient.connect({
71
+ * region: 'aws-us-east-1',
72
+ * diskName: 'myaccount/mydisk',
73
+ * authToken: 'adt_xxx',
74
+ * });
75
+ *
76
+ * const fs = new ArchilFs(client);
77
+ *
78
+ * // Use with just-bash
79
+ * import { Bash } from 'just-bash';
80
+ * const bash = new Bash({ fs });
81
+ * await bash.run('ls -la /');
82
+ * ```
83
+ */
84
+ declare class ArchilFs implements IFileSystem {
85
+ private client;
86
+ private user?;
87
+ private rootInodeId;
88
+ /**
89
+ * Create a new ArchilFs adapter
90
+ *
91
+ * @param client - Connected ArchilClient instance
92
+ * @param options - Optional configuration
93
+ * @param options.user - Unix user context for permission checks
94
+ */
95
+ constructor(client: ArchilClient, options?: {
96
+ user?: UnixUser;
97
+ });
98
+ /**
99
+ * Normalize a path (remove . and .., ensure leading /)
100
+ */
101
+ private normalizePath;
102
+ /**
103
+ * Resolve a path to its inode ID, walking the directory tree
104
+ */
105
+ private resolve;
106
+ /**
107
+ * Resolve parent directory and get child name
108
+ */
109
+ private resolveParent;
110
+ /**
111
+ * Convert InodeAttributes to FsStat
112
+ */
113
+ private toStat;
114
+ resolvePath(base: string, ...paths: string[]): string;
115
+ readFile(path: string, encoding?: BufferEncoding): Promise<string>;
116
+ readFileBuffer(path: string): Promise<Uint8Array>;
117
+ readdir(path: string): Promise<string[]>;
118
+ readdirWithFileTypes(path: string): Promise<DirentEntry[]>;
119
+ stat(path: string): Promise<FsStat>;
120
+ lstat(path: string): Promise<FsStat>;
121
+ exists(path: string): Promise<boolean>;
122
+ readlink(path: string): Promise<string>;
123
+ realpath(path: string): Promise<string>;
124
+ writeFile(path: string, content: FileContent): Promise<void>;
125
+ appendFile(path: string, content: FileContent): Promise<void>;
126
+ mkdir(path: string, options?: {
127
+ recursive?: boolean;
128
+ }): Promise<void>;
129
+ private mkdirSingle;
130
+ rm(path: string, options?: {
131
+ recursive?: boolean;
132
+ force?: boolean;
133
+ }): Promise<void>;
134
+ cp(src: string, dest: string, options?: {
135
+ recursive?: boolean;
136
+ }): Promise<void>;
137
+ mv(src: string, dest: string): Promise<void>;
138
+ symlink(target: string, path: string): Promise<void>;
139
+ link(existingPath: string, newPath: string): Promise<void>;
140
+ chmod(path: string, mode: number): Promise<void>;
141
+ utimes(path: string, atime: number, mtime: number): Promise<void>;
142
+ getAllPaths(): Promise<string[]>;
143
+ /**
144
+ * Resolve a path to its inode ID (public wrapper for delegation operations)
145
+ */
146
+ resolveInodeId(path: string): Promise<number>;
147
+ }
148
+
149
+ /**
150
+ * Create an ArchilFs instance from an existing client
151
+ *
152
+ * This is a convenience function for creating the filesystem adapter.
153
+ *
154
+ * @param client - Connected ArchilClient instance
155
+ * @param options - Optional configuration
156
+ * @returns Configured ArchilFs instance
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * import { ArchilClient } from '@archildata/client';
161
+ * import { createArchilFs } from '@archildata/just-bash';
162
+ *
163
+ * const client = await ArchilClient.connectAuthenticated({...});
164
+ * const fs = createArchilFs(client, { user: { uid: 1000, gid: 1000 } });
165
+ * ```
166
+ */
167
+ declare function createArchilFs(client: _archildata_client.ArchilClient, options?: {
168
+ user?: _archildata_client.UnixUser;
169
+ }): ArchilFs;
170
+
171
+ export { ArchilFs, type BufferEncoding, type DirentEntry, type FileContent, type FsStat, type IFileSystem, createArchilFs };