@archildata/just-bash 0.8.18 → 0.8.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-zhIdm_Vq.mjs","names":[],"sources":["../src/ArchilFs.ts","../src/commands.ts","../src/index.ts"],"sourcesContent":["/**\n * Archil filesystem adapter for just-bash\n *\n * Implements the IFileSystem interface from just-bash using the ArchilClient\n * from @archildata/native for direct protocol access to Archil distributed filesystems.\n */\n\nimport createDebug from \"debug\";\nimport { MAXIMUM_READ_SIZE } from \"@archildata/native\";\nimport type { ArchilClient, DirectoryEntry, InodeAttributes, UnixUser } from \"@archildata/native\";\n\nconst debug = createDebug(\"archil:fs\");\n\n// Types from just-bash interface (we define them here to avoid hard dependency)\nexport type BufferEncoding =\n | \"utf8\"\n | \"utf-8\"\n | \"ascii\"\n | \"binary\"\n | \"base64\"\n | \"hex\"\n | \"latin1\";\n\nexport type FileContent = string | Uint8Array;\n\nexport interface FsStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n mode: number;\n size: number;\n mtime: Date;\n}\n\nexport interface DirentEntry {\n name: string;\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n}\n\nexport interface IFileSystem {\n // Read operations\n readFile(path: string, encoding?: BufferEncoding): Promise<string>;\n readFileBuffer(path: string): Promise<Uint8Array>;\n readdir(path: string): Promise<string[]>;\n readdirWithFileTypes?(path: string): Promise<DirentEntry[]>;\n stat(path: string): Promise<FsStat>;\n lstat(path: string): Promise<FsStat>;\n exists(path: string): Promise<boolean>;\n readlink(path: string): Promise<string>;\n realpath(path: string): Promise<string>;\n\n // Write operations\n writeFile(path: string, content: FileContent): Promise<void>;\n appendFile(path: string, content: FileContent): Promise<void>;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>;\n cp(src: string, dest: string, options?: { recursive?: boolean }): Promise<void>;\n mv(src: string, dest: string): Promise<void>;\n symlink(target: string, path: string): Promise<void>;\n link(existingPath: string, newPath: string): Promise<void>;\n chmod(path: string, mode: number): Promise<void>;\n utimes(path: string, atime: Date, mtime: Date): Promise<void>;\n\n // Utility\n resolvePath(base: string, ...paths: string[]): string;\n getAllPaths?(): string[];\n}\n\n/**\n * Path resolution result containing both the inode ID and attributes\n */\ninterface ResolvedPath {\n inodeId: number;\n attributes: InodeAttributes;\n}\n\n/**\n * ArchilFs implements the just-bash IFileSystem interface using Archil protocol.\n *\n * This adapter provides:\n * - Path-to-inode resolution\n * - Full filesystem operations via Archil protocol\n * - Optional user context for permission checks\n *\n * @example\n * ```typescript\n * import { ArchilClient } from '@archildata/native';\n * import { ArchilFs } from '@archildata/just-bash';\n *\n * const client = await ArchilClient.connect({\n * region: 'aws-us-east-1',\n * diskName: 'myaccount/mydisk',\n * authToken: 'adt_xxx',\n * });\n *\n * const fs = await ArchilFs.create(client);\n *\n * // Use with just-bash\n * import { Bash } from 'just-bash';\n * const bash = new Bash({ fs });\n * await bash.run('ls -la /');\n * ```\n */\nexport class ArchilFs implements IFileSystem {\n private client: ArchilClient;\n private user?: UnixUser;\n private rootInodeId: number = 1;\n\n private constructor(\n client: ArchilClient,\n options?: {\n user?: UnixUser;\n }\n ) {\n this.client = client;\n this.user = options?.user;\n }\n\n /**\n * Create an ArchilFs adapter, optionally rooted at a subdirectory.\n *\n * The subdirectory path is resolved eagerly: if any component does not\n * exist or is not a directory, this method throws immediately.\n *\n * @param client - Connected ArchilClient instance\n * @param options - Optional configuration\n * @param options.user - Unix user context for permission checks\n * @param options.subdirectory - Subdirectory to treat as the root of the filesystem\n */\n static async create(\n client: ArchilClient,\n options?: {\n user?: UnixUser;\n subdirectory?: string;\n }\n ): Promise<ArchilFs> {\n const fs = new ArchilFs(client, { user: options?.user });\n\n if (options?.subdirectory) {\n const resolved = await fs.resolveFollow(options.subdirectory);\n if (resolved.attributes.inodeType !== \"Directory\") {\n throw new Error(`ENOTDIR: subdirectory '${options.subdirectory}' is not a directory`);\n }\n fs.rootInodeId = resolved.inodeId;\n debug(\"resolved subdirectory '%s' to inode %d\", options.subdirectory, fs.rootInodeId);\n }\n\n return fs;\n }\n\n // ========================================================================\n // Path Resolution\n // ========================================================================\n\n /**\n * Normalize a path (remove . and .., ensure leading /)\n */\n private normalizePath(path: string): string {\n // Handle empty path\n if (!path || path === \"\") {\n return \"/\";\n }\n\n // Ensure absolute path\n if (!path.startsWith(\"/\")) {\n path = \"/\" + path;\n }\n\n // Split and process components\n const parts = path.split(\"/\").filter((p) => p !== \"\" && p !== \".\");\n const result: string[] = [];\n\n for (const part of parts) {\n if (part === \"..\") {\n result.pop();\n } else {\n result.push(part);\n }\n }\n\n return \"/\" + result.join(\"/\");\n }\n\n private static readonly MAX_SYMLINKS = 40;\n\n /**\n * Resolve a path to its inode ID, walking the directory tree.\n * Follows symlinks on intermediate components but NOT on the final\n * component (matching lstat/readlink semantics).\n */\n private async resolve(path: string, symlinkDepth: number = 0): Promise<ResolvedPath> {\n const normalizedPath = this.normalizePath(path);\n\n const parts = normalizedPath.split(\"/\").filter((p) => p !== \"\");\n let currentInodeId = this.rootInodeId;\n let resolvedPath = \"/\";\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const response = await this.client.lookupInode(currentInodeId, part, { user: this.user });\n\n if (response === null) {\n throw new Error(`ENOENT: no such file or directory, '${path}'`);\n }\n\n const isLast = i === parts.length - 1;\n\n // Follow symlinks on intermediate components\n if (!isLast && response.attributes.inodeType === \"Symlink\" && response.attributes.symlinkTarget) {\n if (symlinkDepth >= ArchilFs.MAX_SYMLINKS) {\n throw new Error(`ELOOP: too many levels of symbolic links, '${path}'`);\n }\n const targetPath = response.attributes.symlinkTarget.startsWith(\"/\")\n ? response.attributes.symlinkTarget\n : this.resolvePath(resolvedPath, response.attributes.symlinkTarget);\n // Resolve the symlink target, then continue with remaining components\n const remaining = parts.slice(i + 1).join(\"/\");\n const fullPath = remaining ? targetPath + \"/\" + remaining : targetPath;\n return this.resolve(fullPath, symlinkDepth + 1);\n }\n\n resolvedPath = resolvedPath === \"/\" ? \"/\" + part : resolvedPath + \"/\" + part;\n currentInodeId = response.inodeId;\n }\n\n const attributes = await this.client.getAttributes(currentInodeId, { user: this.user });\n return { inodeId: currentInodeId, attributes };\n }\n\n /**\n * Resolve a path, following symlinks on ALL components including the\n * final one (like stat(2)). Use resolve() when you need lstat semantics.\n */\n private async resolveFollow(path: string, symlinkDepth: number = 0): Promise<ResolvedPath> {\n if (symlinkDepth >= ArchilFs.MAX_SYMLINKS) {\n throw new Error(`ELOOP: too many levels of symbolic links, '${path}'`);\n }\n const resolved = await this.resolve(path, symlinkDepth);\n if (resolved.attributes.inodeType === \"Symlink\" && resolved.attributes.symlinkTarget) {\n const targetPath = resolved.attributes.symlinkTarget.startsWith(\"/\")\n ? resolved.attributes.symlinkTarget\n : this.resolvePath(path, \"..\", resolved.attributes.symlinkTarget);\n return this.resolveFollow(targetPath, symlinkDepth + 1);\n }\n return resolved;\n }\n\n /**\n * Resolve parent directory and get child name\n */\n private async resolveParent(path: string): Promise<{ parentInodeId: number; name: string }> {\n debug(\"resolveParent raw path=%j (bytes: %o)\", path, Buffer.from(path));\n const normalizedPath = this.normalizePath(path);\n const lastSlash = normalizedPath.lastIndexOf(\"/\");\n const parentPath = lastSlash === 0 ? \"/\" : normalizedPath.substring(0, lastSlash);\n const name = normalizedPath.substring(lastSlash + 1);\n debug(\"resolveParent extracted name=%j (bytes: %o)\", name, Buffer.from(name));\n\n const { inodeId: parentInodeId } = await this.resolve(parentPath);\n return { parentInodeId, name };\n }\n\n /**\n * Convert InodeAttributes to FsStat\n */\n private toStat(attrs: InodeAttributes): FsStat {\n return {\n isFile: attrs.inodeType === \"File\",\n isDirectory: attrs.inodeType === \"Directory\",\n isSymbolicLink: attrs.inodeType === \"Symlink\",\n mode: attrs.mode,\n size: Number(attrs.size),\n mtime: new Date(attrs.mtimeMs),\n };\n }\n\n private static readonly DIR_PAGE_SIZE = 1000;\n\n /**\n * Read all directory entries using the paginated API.\n */\n private async readAllDirectoryEntries(inodeId: number): Promise<DirectoryEntry[]> {\n const handle = await this.client.openDirectory(inodeId, { user: this.user });\n try {\n const allEntries: DirectoryEntry[] = [];\n let cursor: string | undefined;\n\n for (;;) {\n const page = await this.client.readDirectory(\n inodeId,\n handle,\n ArchilFs.DIR_PAGE_SIZE,\n cursor,\n { user: this.user }\n );\n allEntries.push(...page.entries);\n if (!page.nextCursor) break;\n cursor = page.nextCursor;\n }\n\n return allEntries;\n } finally {\n this.client.closeDirectory(inodeId, handle);\n }\n }\n\n // ========================================================================\n // IFileSystem Implementation - Read Operations\n // ========================================================================\n\n resolvePath(base: string, ...paths: string[]): string {\n debug(\"resolvePath base=%s paths=%o\", base, paths);\n let result = base;\n for (const p of paths) {\n if (p.startsWith(\"/\")) {\n result = p;\n } else {\n result = result.endsWith(\"/\") ? result + p : result + \"/\" + p;\n }\n }\n const normalized = this.normalizePath(result);\n debug(\"resolvePath result=%s\", normalized);\n return normalized;\n }\n\n async readFile(path: string, encoding?: BufferEncoding): Promise<string> {\n debug(\"readFile path=%s encoding=%s\", path, encoding);\n try {\n const buffer = await this.readFileBuffer(path);\n debug(\"readFile got buffer length=%d\", buffer.length);\n // \"base64\", \"hex\", and \"binary\" are Node Buffer encodings not supported\n // by TextDecoder — use Buffer.toString() for those.\n const enc = encoding || \"utf-8\";\n let result: string;\n if (enc === \"base64\" || enc === \"hex\" || enc === \"binary\") {\n result = Buffer.from(buffer).toString(enc);\n } else {\n result = new TextDecoder(enc).decode(buffer);\n }\n debug(\"readFile decoded to string length=%d\", result.length);\n return result;\n } catch (err) {\n debug(\"readFile FAILED: %O\", err);\n throw err;\n }\n }\n\n async readFileBuffer(path: string): Promise<Uint8Array> {\n debug(\"readFileBuffer path=%s\", path);\n const { inodeId, attributes } = await this.resolveFollow(path);\n debug(\"readFileBuffer resolved inodeId=%d type=%s size=%d\", inodeId, attributes.inodeType, attributes.size);\n\n if (attributes.inodeType !== \"File\") {\n throw new Error(`EISDIR: illegal operation on a directory, read '${path}'`);\n }\n\n const size = Number(attributes.size);\n if (size === 0) {\n debug(\"readFileBuffer file is empty, returning empty buffer\");\n return new Uint8Array(0);\n }\n\n if (size <= MAXIMUM_READ_SIZE) {\n const buffer = await this.client.readInode(inodeId, 0, size, { user: this.user });\n return new Uint8Array(buffer);\n }\n\n // Read large files in chunks\n const result = new Uint8Array(size);\n let offset = 0;\n while (offset < size) {\n const chunkSize = Math.min(MAXIMUM_READ_SIZE, size - offset);\n const chunk = await this.client.readInode(inodeId, offset, chunkSize, { user: this.user });\n result.set(new Uint8Array(chunk), offset);\n offset += chunkSize;\n }\n return result;\n }\n\n async readdir(path: string): Promise<string[]> {\n debug(\"readdir path=%s\", path);\n const { inodeId, attributes } = await this.resolveFollow(path);\n\n if (attributes.inodeType !== \"Directory\") {\n throw new Error(`ENOTDIR: not a directory, scandir '${path}'`);\n }\n\n const entries = await this.readAllDirectoryEntries(inodeId);\n for (const e of entries) {\n debug(\"readdir entry name=%j (bytes: %o)\", e.name, Buffer.from(e.name));\n }\n return entries\n .map((e) => e.name)\n .filter((name) => name !== \".\" && name !== \"..\");\n }\n\n async readdirWithFileTypes(path: string): Promise<DirentEntry[]> {\n const { inodeId, attributes } = await this.resolveFollow(path);\n\n if (attributes.inodeType !== \"Directory\") {\n throw new Error(`ENOTDIR: not a directory, scandir '${path}'`);\n }\n\n const entries = await this.readAllDirectoryEntries(inodeId);\n\n return entries\n .filter((e) => e.name !== \".\" && e.name !== \"..\")\n .map((e) => ({\n name: e.name,\n isFile: e.inodeType === \"File\",\n isDirectory: e.inodeType === \"Directory\",\n isSymbolicLink: e.inodeType === \"Symlink\",\n }));\n }\n\n async stat(path: string): Promise<FsStat> {\n debug(\"stat path=%s\", path);\n const { attributes } = await this.resolveFollow(path);\n return this.toStat(attributes);\n }\n\n async lstat(path: string): Promise<FsStat> {\n debug(\"lstat path=%s\", path);\n const { attributes } = await this.resolve(path);\n return this.toStat(attributes);\n }\n\n async exists(path: string): Promise<boolean> {\n debug(\"exists path=%s\", path);\n try {\n await this.resolve(path);\n debug(\"exists path=%s -> true\", path);\n return true;\n } catch {\n debug(\"exists path=%s -> false\", path);\n return false;\n }\n }\n\n async readlink(path: string): Promise<string> {\n const { attributes } = await this.resolve(path);\n\n if (attributes.inodeType !== \"Symlink\") {\n throw new Error(`EINVAL: invalid argument, readlink '${path}'`);\n }\n\n return attributes.symlinkTarget || \"\";\n }\n\n async realpath(path: string, symlinkDepth: number = 0): Promise<string> {\n const normalizedPath = this.normalizePath(path);\n\n const parts = normalizedPath.split(\"/\").filter((p) => p !== \"\");\n let resolvedPath = \"/\";\n let currentInodeId = this.rootInodeId;\n\n for (const part of parts) {\n const response = await this.client.lookupInode(currentInodeId, part, { user: this.user });\n\n if (response === null) {\n throw new Error(`ENOENT: no such file or directory, realpath '${path}'`);\n }\n\n const attrs = response.attributes;\n\n if (attrs.inodeType === \"Symlink\" && attrs.symlinkTarget) {\n if (symlinkDepth >= ArchilFs.MAX_SYMLINKS) {\n throw new Error(`ELOOP: too many levels of symbolic links, '${path}'`);\n }\n const targetPath = attrs.symlinkTarget.startsWith(\"/\")\n ? attrs.symlinkTarget\n : this.resolvePath(resolvedPath, attrs.symlinkTarget);\n const resolved = await this.realpath(targetPath, symlinkDepth + 1);\n resolvedPath = resolved;\n const { inodeId } = await this.resolve(resolved);\n currentInodeId = inodeId;\n } else {\n resolvedPath = resolvedPath === \"/\" ? \"/\" + part : resolvedPath + \"/\" + part;\n currentInodeId = response.inodeId;\n }\n }\n\n return resolvedPath;\n }\n\n // ========================================================================\n // IFileSystem Implementation - Write Operations\n // ========================================================================\n\n async writeFile(path: string, content: FileContent): Promise<void> {\n debug(\"writeFile path=%s contentLength=%d\", path, content.length);\n const data = typeof content === \"string\" ? new TextEncoder().encode(content) : content;\n\n // Try to resolve existing file — only this call can produce a\n // legitimate ENOENT (file doesn't exist yet). Everything after it\n // must propagate errors, not fall through to the create path.\n let resolved: ResolvedPath | null;\n try {\n resolved = await this.resolveFollow(path);\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"ENOENT\")) {\n resolved = null;\n } else {\n throw err;\n }\n }\n\n if (resolved !== null) {\n debug(\"writeFile resolved existing file path=%s inodeId=%d\", path, resolved.inodeId);\n\n if (resolved.attributes.inodeType !== \"File\") {\n throw new Error(`EISDIR: illegal operation on a directory, write '${path}'`);\n }\n\n // Atomic overwrite: write to a temp file, then rename over the original.\n // This ensures readers never see partial content or stale trailing bytes.\n // Use realpath so we target the actual file, not a symlink entry.\n const realPath = await this.realpath(path);\n const { parentInodeId, name } = await this.resolveParent(realPath);\n const tmpName = `.~tmp-${Math.random().toString(36).slice(2)}`;\n debug(\"writeFile atomic overwrite via temp=%s\", tmpName);\n\n const tmpResult = await this.client.create(\n parentInodeId,\n tmpName,\n {\n inodeType: \"File\",\n uid: resolved.attributes.uid,\n gid: resolved.attributes.gid,\n mode: resolved.attributes.mode,\n },\n { user: this.user }\n );\n\n try {\n await this.client.writeData(tmpResult.inodeId, 0, Buffer.from(data), { user: this.user });\n await this.client.rename(parentInodeId, tmpName, parentInodeId, name, { user: this.user });\n debug(\"writeFile atomic overwrite succeeded\");\n } catch (writeErr) {\n // Best-effort cleanup of temp file\n try { await this.client.unlink(parentInodeId, tmpName, { user: this.user }); } catch { /* ignore */ }\n throw writeErr;\n }\n\n return;\n }\n\n debug(\"writeFile file doesn't exist, creating: %s\", path);\n const { parentInodeId, name } = await this.resolveParent(path);\n debug(\"writeFile resolved parent parentInodeId=%d name=%s\", parentInodeId, name);\n\n const result = await this.client.create(\n parentInodeId,\n name,\n {\n inodeType: \"File\",\n uid: this.user?.uid ?? 0,\n gid: this.user?.gid ?? 0,\n mode: 0o644,\n },\n { user: this.user }\n );\n debug(\"writeFile create succeeded inodeId=%d\", result.inodeId);\n\n await this.client.writeData(result.inodeId, 0, Buffer.from(data), { user: this.user });\n debug(\"writeFile write succeeded\");\n }\n\n async appendFile(path: string, content: FileContent): Promise<void> {\n const data = typeof content === \"string\" ? new TextEncoder().encode(content) : content;\n\n let inodeId: number;\n let size: number;\n try {\n const resolved = await this.resolveFollow(path);\n if (resolved.attributes.inodeType !== \"File\") {\n throw new Error(`EISDIR: illegal operation on a directory, write '${path}'`);\n }\n inodeId = resolved.inodeId;\n size = Number(resolved.attributes.size);\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"ENOENT\")) {\n // File doesn't exist — create and write from offset 0\n await this.writeFile(path, data);\n return;\n }\n throw err;\n }\n\n await this.client.writeData(inodeId, size, Buffer.from(data), { user: this.user });\n }\n\n async mkdir(path: string, options?: { recursive?: boolean }): Promise<void> {\n const normalizedPath = this.normalizePath(path);\n\n if (options?.recursive) {\n // Create all directories in the path\n const parts = normalizedPath.split(\"/\").filter((p) => p !== \"\");\n let currentPath = \"\";\n\n for (const part of parts) {\n currentPath += \"/\" + part;\n\n // Check if exists\n const exists = await this.exists(currentPath);\n if (exists) {\n continue;\n }\n\n // Create this directory\n await this.mkdirSingle(currentPath);\n }\n } else {\n await this.mkdirSingle(normalizedPath);\n }\n }\n\n private async mkdirSingle(path: string): Promise<void> {\n const { parentInodeId, name } = await this.resolveParent(path);\n\n await this.client.create(\n parentInodeId,\n name,\n {\n inodeType: \"Directory\",\n uid: this.user?.uid ?? 0,\n gid: this.user?.gid ?? 0,\n mode: 0o755,\n },\n { user: this.user }\n );\n }\n\n async rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void> {\n let resolved: ResolvedPath;\n try {\n resolved = await this.resolve(path);\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"ENOENT\")) {\n if (options?.force) {\n return;\n }\n throw err;\n }\n throw err;\n }\n\n if (resolved.attributes.inodeType === \"Directory\") {\n if (!options?.recursive) {\n throw new Error(`EISDIR: illegal operation on a directory, rm '${path}'`);\n }\n\n // Recursively delete contents first\n const entries = await this.readdir(path);\n for (const entry of entries) {\n await this.rm(this.resolvePath(path, entry), options);\n }\n }\n\n // Unlink the file/directory from its parent\n const { parentInodeId, name } = await this.resolveParent(path);\n await this.client.unlink(parentInodeId, name, { user: this.user });\n }\n\n async cp(src: string, dest: string, options?: { recursive?: boolean }): Promise<void> {\n const srcResolved = await this.resolveFollow(src);\n\n if (srcResolved.attributes.inodeType === \"Directory\") {\n if (!options?.recursive) {\n throw new Error(`EISDIR: illegal operation on a directory, cp '${src}'`);\n }\n\n // Create destination directory\n await this.mkdir(dest, { recursive: true });\n\n // Copy contents\n const entries = await this.readdir(src);\n for (const entry of entries) {\n await this.cp(\n this.resolvePath(src, entry),\n this.resolvePath(dest, entry),\n options\n );\n }\n } else {\n // Copy file\n const content = await this.readFileBuffer(src);\n await this.writeFile(dest, content);\n }\n }\n\n async mv(src: string, dest: string): Promise<void> {\n // Use atomic rename operation\n const { parentInodeId: srcParentInodeId, name: srcName } = await this.resolveParent(src);\n const { parentInodeId: destParentInodeId, name: destName } = await this.resolveParent(dest);\n\n await this.client.rename(\n srcParentInodeId,\n srcName,\n destParentInodeId,\n destName,\n { user: this.user }\n );\n }\n\n async symlink(target: string, path: string): Promise<void> {\n const { parentInodeId, name } = await this.resolveParent(path);\n\n await this.client.create(\n parentInodeId,\n name,\n {\n inodeType: \"Symlink\",\n uid: this.user?.uid ?? 0,\n gid: this.user?.gid ?? 0,\n mode: 0o777,\n symlinkTarget: target,\n },\n { user: this.user }\n );\n }\n\n async link(existingPath: string, newPath: string): Promise<void> {\n // Hard links require special handling\n // TODO: Implement when archil-node exposes link operation\n throw new Error(\n \"Hard link operations not yet implemented. \" +\n \"The archil-node bindings need to expose link for hard links.\"\n );\n }\n\n async chmod(path: string, mode: number): Promise<void> {\n const { inodeId } = await this.resolveFollow(path);\n await this.client.setattr(inodeId, { mode }, { user: this.user ?? { uid: 0, gid: 0 } });\n }\n\n async utimes(path: string, atime: Date, mtime: Date): Promise<void> {\n debug(\"utimes path=%s atime=%s mtime=%s\", path, atime.toISOString(), mtime.toISOString());\n\n const { inodeId } = await this.resolveFollow(path);\n debug(\"utimes resolved path=%s inodeId=%d\", path, inodeId);\n\n const atimeMs = atime.getTime();\n const mtimeMs = mtime.getTime();\n\n debug(\"utimes calling setattr inodeId=%d atimeMs=%d mtimeMs=%d\", inodeId, atimeMs, mtimeMs);\n await this.client.setattr(\n inodeId,\n { atimeMs, mtimeMs },\n { user: this.user ?? { uid: 0, gid: 0 } }\n );\n debug(\"utimes setattr succeeded inodeId=%d\", inodeId);\n }\n\n // ========================================================================\n // Utility Methods\n // ========================================================================\n\n getAllPaths(): string[] {\n return [];\n }\n\n /**\n * Resolve a path to its inode ID (public wrapper for delegation operations)\n */\n async resolveInodeId(path: string): Promise<number> {\n const { inodeId } = await this.resolve(path);\n return inodeId;\n }\n}\n","import { defineCommand } from \"just-bash\";\nimport type { ExecResult } from \"just-bash\";\nimport type { ArchilClient } from \"@archildata/native\";\nimport type { ArchilFs } from \"./ArchilFs.js\";\n\n/**\n * Create the `archil` custom command for use with just-bash.\n *\n * Provides checkout/checkin delegation management, delegation listing, and\n * cache control (invalidate-cache, set-cache-expiry) as a shell command that\n * works in scripts, pipes, and interactive use.\n *\n * @example\n * ```typescript\n * import { Bash } from 'just-bash';\n * import { ArchilFs, createArchilCommand } from '@archildata/just-bash';\n *\n * const fs = await ArchilFs.create(client);\n * const bash = new Bash({\n * fs,\n * customCommands: [createArchilCommand(client, fs)],\n * });\n *\n * await bash.exec('archil checkout /mydir');\n * await bash.exec('echo \"hello\" > /mydir/file.txt');\n * await bash.exec('archil checkin /mydir');\n * ```\n */\nexport function createArchilCommand(client: ArchilClient, fs: ArchilFs) {\n return defineCommand(\"archil\", async (args, ctx) => {\n const ok = (stdout: string): ExecResult => ({ stdout, stderr: \"\", exitCode: 0 });\n const fail = (stderr: string): ExecResult => ({ stdout: \"\", stderr, exitCode: 1 });\n\n const subcommand = args[0];\n\n if (subcommand === \"checkout\") {\n const rest = args.slice(1);\n const force = rest.includes(\"--force\") || rest.includes(\"-f\");\n const pathArg = rest.find((a) => !a.startsWith(\"-\"));\n if (!pathArg) {\n return fail(\"Usage: archil checkout [--force|-f] <path>\\n\");\n }\n const fullPath = fs.resolvePath(ctx.cwd, pathArg);\n try {\n const inodeId = await fs.resolveInodeId(fullPath);\n await client.checkout(inodeId, { force });\n return ok(`Checked out: ${fullPath} (inode ${inodeId})${force ? \" (forced)\" : \"\"}\\n`);\n } catch (err) {\n return fail(`Failed to checkout ${fullPath}: ${err instanceof Error ? err.message : err}\\n`);\n }\n }\n\n if (subcommand === \"checkin\") {\n const pathArg = args[1];\n if (!pathArg) {\n return fail(\"Usage: archil checkin <path>\\n\");\n }\n const fullPath = fs.resolvePath(ctx.cwd, pathArg);\n try {\n const inodeId = await fs.resolveInodeId(fullPath);\n await client.checkin(inodeId);\n return ok(`Checked in: ${fullPath} (inode ${inodeId})\\n`);\n } catch (err) {\n return fail(`Failed to checkin ${fullPath}: ${err instanceof Error ? err.message : err}\\n`);\n }\n }\n\n if (subcommand === \"list-delegations\" || subcommand === \"delegations\") {\n try {\n const delegations = client.listDelegations();\n if (delegations.length === 0) {\n return ok(\"No delegations held\\n\");\n }\n const lines = delegations.map((d) => ` inode ${d.inodeId}: ${d.state}`);\n return ok(\"Delegations:\\n\" + lines.join(\"\\n\") + \"\\n\");\n } catch (err) {\n return fail(`Failed to list delegations: ${err instanceof Error ? err.message : err}\\n`);\n }\n }\n\n if (subcommand === \"invalidate-cache\") {\n // Path is accepted for parity with the FUSE CLI (`archil invalidate-cache <path>`),\n // but the Node binding's invalidateCache() is mount-wide — there is exactly\n // one client per shell session, so any path on this filesystem is equivalent\n // to \"invalidate everything\". We resolve it only to validate it exists and to\n // include it in the success message for operator clarity.\n const pathArg = args.slice(1).find((a) => !a.startsWith(\"-\"));\n let scopeLabel = \"(mount-wide)\";\n if (pathArg) {\n const fullPath = fs.resolvePath(ctx.cwd, pathArg);\n try {\n await fs.resolveInodeId(fullPath);\n scopeLabel = `(via ${fullPath})`;\n } catch (err) {\n return fail(`Failed to resolve ${fullPath}: ${err instanceof Error ? err.message : err}\\n`);\n }\n }\n try {\n const stats = client.invalidateCache();\n return ok(\n `Invalidated cache ${scopeLabel}: ${stats.totalEvictedInodes} inodes evicted ` +\n `(attr=${stats.attribute}, xattr=${stats.extendedAttribute}, ` +\n `dirent=${stats.dirent}, file=${stats.fileData})\\n`\n );\n } catch (err) {\n return fail(`Failed to invalidate cache: ${err instanceof Error ? err.message : err}\\n`);\n }\n }\n\n if (subcommand === \"set-cache-expiry\") {\n const rest = args.slice(1);\n const flagIdx = rest.indexOf(\"--readdir-expiry\");\n if (flagIdx === -1 || flagIdx === rest.length - 1) {\n return fail(\"Usage: archil set-cache-expiry <path> --readdir-expiry <seconds>\\n\");\n }\n const flagValueIdx = flagIdx + 1;\n const expirySeconds = Number(rest[flagValueIdx]);\n if (!Number.isInteger(expirySeconds) || expirySeconds < 0) {\n return fail(\"--readdir-expiry must be a non-negative integer (seconds)\\n\");\n }\n const pathArg = rest.find((a, i) => i !== flagIdx && i !== flagValueIdx && !a.startsWith(\"-\"));\n if (!pathArg) {\n return fail(\"Usage: archil set-cache-expiry <path> --readdir-expiry <seconds>\\n\");\n }\n const fullPath = fs.resolvePath(ctx.cwd, pathArg);\n try {\n const inodeId = await fs.resolveInodeId(fullPath);\n client.setCacheExpiry(inodeId, expirySeconds);\n return ok(`Set readdir cache expiry for ${fullPath} (inode ${inodeId}) to ${expirySeconds}s\\n`);\n } catch (err) {\n return fail(`Failed to set cache expiry for ${fullPath}: ${err instanceof Error ? err.message : err}\\n`);\n }\n }\n\n if (subcommand === \"help\" || !subcommand) {\n return ok(\n \"Archil commands:\\n\" +\n \" archil checkout [--force|-f] <path> - Acquire write delegation\\n\" +\n \" archil checkin <path> - Release write delegation\\n\" +\n \" archil list-delegations - Show held delegations\\n\" +\n \" archil invalidate-cache [<path>] - Drop every evictable cache entry\\n\" +\n \" archil set-cache-expiry <path> --readdir-expiry <secs>\\n\" +\n \" - Set readdir cache TTL on a directory\\n\" +\n \" archil help - Show this help message\\n\" +\n \"\\n\" +\n \"The --force flag revokes any existing delegation from other clients.\\n\"\n );\n }\n\n return fail(`Unknown archil command: ${subcommand}\\nRun 'archil help' for available commands\\n`);\n });\n}\n","/**\n * @archildata/just-bash - Archil filesystem adapter for just-bash\n *\n * This package provides a filesystem adapter that allows just-bash to use\n * Archil distributed filesystems as a backend.\n *\n * @example\n * ```typescript\n * import { ArchilClient } from '@archildata/native';\n * import { ArchilFs } from '@archildata/just-bash';\n * import { Bash } from 'just-bash';\n *\n * // Connect to Archil\n * const client = await ArchilClient.connect({\n * region: 'aws-us-east-1',\n * diskName: 'myaccount/mydisk',\n * authToken: 'adt_xxx',\n * });\n *\n * // Create filesystem adapter\n * const fs = await ArchilFs.create(client);\n *\n * // Use with just-bash\n * const bash = new Bash({ fs });\n * const result = await bash.run('ls -la /');\n * console.log(result.stdout);\n * ```\n *\n * @packageDocumentation\n */\n\nimport { ArchilFs } from \"./ArchilFs.js\";\nexport { ArchilFs };\n\nexport type {\n IFileSystem,\n FsStat,\n DirentEntry,\n BufferEncoding,\n FileContent,\n} from \"./ArchilFs.js\";\n\nexport { createArchilCommand } from \"./commands.js\";\n\n/**\n * Create an ArchilFs instance, optionally rooted at a subdirectory.\n *\n * @param client - Connected ArchilClient instance\n * @param options - Optional configuration\n * @returns Configured ArchilFs instance\n *\n * @example\n * ```typescript\n * import { ArchilClient } from '@archildata/native';\n * import { createArchilFs } from '@archildata/just-bash';\n *\n * const client = await ArchilClient.connectAuthenticated({...});\n * const fs = await createArchilFs(client, { user: { uid: 1000, gid: 1000 } });\n * ```\n */\nexport async function createArchilFs(\n client: import(\"@archildata/native\").ArchilClient,\n options?: { user?: import(\"@archildata/native\").UnixUser; subdirectory?: string }\n): Promise<ArchilFs> {\n return ArchilFs.create(client, options);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,44 +1,38 @@
1
1
  {
2
2
  "name": "@archildata/just-bash",
3
- "version": "0.8.18",
3
+ "version": "0.8.20",
4
4
  "description": "Archil filesystem adapter for just-bash",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
7
- "types": "dist/index.d.ts",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.mts",
8
9
  "exports": {
9
10
  ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js",
11
+ "types": "./dist/index.d.mts",
12
+ "import": "./dist/index.mjs",
12
13
  "require": "./dist/index.cjs"
13
14
  }
14
15
  },
15
16
  "bin": {
16
- "archil-shell": "./dist/shell.js"
17
+ "archil-shell": "./dist/shell.mjs"
17
18
  },
18
19
  "files": [
19
20
  "dist"
20
21
  ],
21
- "scripts": {
22
- "build": "tsup src/index.ts --format cjs,esm --dts && tsup bin/shell.ts --format esm --outDir dist --no-splitting --external @archildata/just-bash",
23
- "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
24
- "lint": "eslint src/",
25
- "typecheck": "tsc --noEmit",
26
- "shell": "tsx bin/shell.ts"
27
- },
28
22
  "dependencies": {
29
23
  "@archildata/native": "^0.8.18",
30
24
  "commander": "^14.0.3",
31
25
  "debug": "^4.3.4",
32
- "disk": "^0.8.18",
33
- "just-bash": "^2.7.0"
26
+ "just-bash": "^2.7.0",
27
+ "disk": "0.8.20"
34
28
  },
35
29
  "devDependencies": {
36
30
  "@types/debug": "^4.1.12",
37
31
  "@types/node": "^20.0.0",
38
32
  "ts-node": "^10.9.2",
39
- "tsup": "^8.0.0",
33
+ "tsdown": "^0.22.3",
40
34
  "tsx": "^4.21.0",
41
- "typescript": "^5.9.3"
35
+ "typescript": "^6.0.3"
42
36
  },
43
37
  "keywords": [
44
38
  "archil",
@@ -47,5 +41,12 @@
47
41
  "bash",
48
42
  "ai-agents"
49
43
  ],
50
- "license": "MIT"
51
- }
44
+ "license": "MIT",
45
+ "scripts": {
46
+ "build": "tsdown",
47
+ "dev": "tsdown --watch",
48
+ "lint": "eslint src/",
49
+ "typecheck": "tsc --noEmit",
50
+ "shell": "tsx bin/shell.ts"
51
+ }
52
+ }
package/dist/index.d.ts DELETED
@@ -1,215 +0,0 @@
1
- import * as _archildata_native from '@archildata/native';
2
- import { ArchilClient, UnixUser } from '@archildata/native';
3
- import * as just_bash from 'just-bash';
4
-
5
- /**
6
- * Archil filesystem adapter for just-bash
7
- *
8
- * Implements the IFileSystem interface from just-bash using the ArchilClient
9
- * from @archildata/native for direct protocol access to Archil distributed filesystems.
10
- */
11
-
12
- type BufferEncoding = "utf8" | "utf-8" | "ascii" | "binary" | "base64" | "hex" | "latin1";
13
- type FileContent = string | Uint8Array;
14
- interface FsStat {
15
- isFile: boolean;
16
- isDirectory: boolean;
17
- isSymbolicLink: boolean;
18
- mode: number;
19
- size: number;
20
- mtime: Date;
21
- }
22
- interface DirentEntry {
23
- name: string;
24
- isFile: boolean;
25
- isDirectory: boolean;
26
- isSymbolicLink: boolean;
27
- }
28
- interface IFileSystem {
29
- readFile(path: string, encoding?: BufferEncoding): Promise<string>;
30
- readFileBuffer(path: string): Promise<Uint8Array>;
31
- readdir(path: string): Promise<string[]>;
32
- readdirWithFileTypes?(path: string): Promise<DirentEntry[]>;
33
- stat(path: string): Promise<FsStat>;
34
- lstat(path: string): Promise<FsStat>;
35
- exists(path: string): Promise<boolean>;
36
- readlink(path: string): Promise<string>;
37
- realpath(path: string): Promise<string>;
38
- writeFile(path: string, content: FileContent): Promise<void>;
39
- appendFile(path: string, content: FileContent): Promise<void>;
40
- mkdir(path: string, options?: {
41
- recursive?: boolean;
42
- }): Promise<void>;
43
- rm(path: string, options?: {
44
- recursive?: boolean;
45
- force?: boolean;
46
- }): Promise<void>;
47
- cp(src: string, dest: string, options?: {
48
- recursive?: boolean;
49
- }): Promise<void>;
50
- mv(src: string, dest: string): Promise<void>;
51
- symlink(target: string, path: string): Promise<void>;
52
- link(existingPath: string, newPath: string): Promise<void>;
53
- chmod(path: string, mode: number): Promise<void>;
54
- utimes(path: string, atime: Date, mtime: Date): Promise<void>;
55
- resolvePath(base: string, ...paths: string[]): string;
56
- getAllPaths?(): string[];
57
- }
58
- /**
59
- * ArchilFs implements the just-bash IFileSystem interface using Archil protocol.
60
- *
61
- * This adapter provides:
62
- * - Path-to-inode resolution
63
- * - Full filesystem operations via Archil protocol
64
- * - Optional user context for permission checks
65
- *
66
- * @example
67
- * ```typescript
68
- * import { ArchilClient } from '@archildata/native';
69
- * import { ArchilFs } from '@archildata/just-bash';
70
- *
71
- * const client = await ArchilClient.connect({
72
- * region: 'aws-us-east-1',
73
- * diskName: 'myaccount/mydisk',
74
- * authToken: 'adt_xxx',
75
- * });
76
- *
77
- * const fs = await ArchilFs.create(client);
78
- *
79
- * // Use with just-bash
80
- * import { Bash } from 'just-bash';
81
- * const bash = new Bash({ fs });
82
- * await bash.run('ls -la /');
83
- * ```
84
- */
85
- declare class ArchilFs implements IFileSystem {
86
- private client;
87
- private user?;
88
- private rootInodeId;
89
- private constructor();
90
- /**
91
- * Create an ArchilFs adapter, optionally rooted at a subdirectory.
92
- *
93
- * The subdirectory path is resolved eagerly: if any component does not
94
- * exist or is not a directory, this method throws immediately.
95
- *
96
- * @param client - Connected ArchilClient instance
97
- * @param options - Optional configuration
98
- * @param options.user - Unix user context for permission checks
99
- * @param options.subdirectory - Subdirectory to treat as the root of the filesystem
100
- */
101
- static create(client: ArchilClient, options?: {
102
- user?: UnixUser;
103
- subdirectory?: string;
104
- }): Promise<ArchilFs>;
105
- /**
106
- * Normalize a path (remove . and .., ensure leading /)
107
- */
108
- private normalizePath;
109
- private static readonly MAX_SYMLINKS;
110
- /**
111
- * Resolve a path to its inode ID, walking the directory tree.
112
- * Follows symlinks on intermediate components but NOT on the final
113
- * component (matching lstat/readlink semantics).
114
- */
115
- private resolve;
116
- /**
117
- * Resolve a path, following symlinks on ALL components including the
118
- * final one (like stat(2)). Use resolve() when you need lstat semantics.
119
- */
120
- private resolveFollow;
121
- /**
122
- * Resolve parent directory and get child name
123
- */
124
- private resolveParent;
125
- /**
126
- * Convert InodeAttributes to FsStat
127
- */
128
- private toStat;
129
- private static readonly DIR_PAGE_SIZE;
130
- /**
131
- * Read all directory entries using the paginated API.
132
- */
133
- private readAllDirectoryEntries;
134
- resolvePath(base: string, ...paths: string[]): string;
135
- readFile(path: string, encoding?: BufferEncoding): Promise<string>;
136
- readFileBuffer(path: string): Promise<Uint8Array>;
137
- readdir(path: string): Promise<string[]>;
138
- readdirWithFileTypes(path: string): Promise<DirentEntry[]>;
139
- stat(path: string): Promise<FsStat>;
140
- lstat(path: string): Promise<FsStat>;
141
- exists(path: string): Promise<boolean>;
142
- readlink(path: string): Promise<string>;
143
- realpath(path: string, symlinkDepth?: number): Promise<string>;
144
- writeFile(path: string, content: FileContent): Promise<void>;
145
- appendFile(path: string, content: FileContent): Promise<void>;
146
- mkdir(path: string, options?: {
147
- recursive?: boolean;
148
- }): Promise<void>;
149
- private mkdirSingle;
150
- rm(path: string, options?: {
151
- recursive?: boolean;
152
- force?: boolean;
153
- }): Promise<void>;
154
- cp(src: string, dest: string, options?: {
155
- recursive?: boolean;
156
- }): Promise<void>;
157
- mv(src: string, dest: string): Promise<void>;
158
- symlink(target: string, path: string): Promise<void>;
159
- link(existingPath: string, newPath: string): Promise<void>;
160
- chmod(path: string, mode: number): Promise<void>;
161
- utimes(path: string, atime: Date, mtime: Date): Promise<void>;
162
- getAllPaths(): string[];
163
- /**
164
- * Resolve a path to its inode ID (public wrapper for delegation operations)
165
- */
166
- resolveInodeId(path: string): Promise<number>;
167
- }
168
-
169
- /**
170
- * Create the `archil` custom command for use with just-bash.
171
- *
172
- * Provides checkout/checkin delegation management, delegation listing, and
173
- * cache control (invalidate-cache, set-cache-expiry) as a shell command that
174
- * works in scripts, pipes, and interactive use.
175
- *
176
- * @example
177
- * ```typescript
178
- * import { Bash } from 'just-bash';
179
- * import { ArchilFs, createArchilCommand } from '@archildata/just-bash';
180
- *
181
- * const fs = await ArchilFs.create(client);
182
- * const bash = new Bash({
183
- * fs,
184
- * customCommands: [createArchilCommand(client, fs)],
185
- * });
186
- *
187
- * await bash.exec('archil checkout /mydir');
188
- * await bash.exec('echo "hello" > /mydir/file.txt');
189
- * await bash.exec('archil checkin /mydir');
190
- * ```
191
- */
192
- declare function createArchilCommand(client: ArchilClient, fs: ArchilFs): just_bash.Command;
193
-
194
- /**
195
- * Create an ArchilFs instance, optionally rooted at a subdirectory.
196
- *
197
- * @param client - Connected ArchilClient instance
198
- * @param options - Optional configuration
199
- * @returns Configured ArchilFs instance
200
- *
201
- * @example
202
- * ```typescript
203
- * import { ArchilClient } from '@archildata/native';
204
- * import { createArchilFs } from '@archildata/just-bash';
205
- *
206
- * const client = await ArchilClient.connectAuthenticated({...});
207
- * const fs = await createArchilFs(client, { user: { uid: 1000, gid: 1000 } });
208
- * ```
209
- */
210
- declare function createArchilFs(client: _archildata_native.ArchilClient, options?: {
211
- user?: _archildata_native.UnixUser;
212
- subdirectory?: string;
213
- }): Promise<ArchilFs>;
214
-
215
- export { ArchilFs, type BufferEncoding, type DirentEntry, type FileContent, type FsStat, type IFileSystem, createArchilCommand, createArchilFs };