{"_id":"@automatalabs/libfusefs-ffi","_rev":"2-87a362603fefd151b32561e0b2dd3a3e","name":"@automatalabs/libfusefs-ffi","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@automatalabs/libfusefs-ffi","version":"0.1.0","license":"MIT","_id":"@automatalabs/libfusefs-ffi@0.1.0","maintainers":[{"name":"automatalabsteam","email":"packages@automatalabs.io"}],"homepage":"https://github.com/VikashLoomba/libfusefs-ffi#readme","bugs":{"url":"https://github.com/VikashLoomba/libfusefs-ffi/issues"},"dist":{"shasum":"2db6239d84f99134db4600667021ffa972a7bc99","tarball":"https://registry.npmjs.org/@automatalabs/libfusefs-ffi/-/libfusefs-ffi-0.1.0.tgz","fileCount":24,"integrity":"sha512-NFVsBUpbQ4OoaDzCiX7c0JwhIpunQPR6E/raqjTrBnXQax1Fno4pL86VamNID4A9dozYX1HvaWGMmTK3VwcEow==","signatures":[{"sig":"MEYCIQDVcViU0PDe3Idpzp2NiBqav9DlIg6hj5XO0jEbI9fSOgIhAN3k8Zr+eiixlWpwRvYFdBcrDmLbIqQbTzkDXCqUCgVX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":52908},"main":"./dist/index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","aarch64-unknown-linux-gnu"],"binaryName":"libfusefs_ffi"},"type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js","default":"./dist/testing.js"}},"gitHead":"cadf3318f6961f6587c56952945cd4740266b3ed","scripts":{"test":"node --import tsx --test tests/**/*.test.ts","build":"npm run build:native && npm run build:ts","build:ts":"tsc -p tsconfig.json","artifacts":"napi artifacts","test:unit":"node --import tsx --test tests/workspace.test.ts","typecheck":"tsc -p tsconfig.json --noEmit","build:native":"napi build --platform --release","prepublishOnly":"npm run build:native && npm run build:ts && napi prepublish -t npm --no-gh-release","create-npm-dirs":"napi create-npm-dirs","test:integration":"npm run build:native && RUN_FUSE_TESTS=1 node --import tsx --test tests/integration.native.test.ts"},"_npmUser":{"name":"automatalabsteam","email":"packages@automatalabs.io"},"repository":{"url":"git+https://github.com/VikashLoomba/libfusefs-ffi.git","type":"git"},"_npmVersion":"11.11.1","description":"Thin Node.js wrapper around libfuse-fs overlay workspaces via napi-rs","directories":{},"_nodeVersion":"25.6.1","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.3","typescript":"^5.8.3","@types/node":"^22.15.3","@napi-rs/cli":"^3.0.0"},"optionalDependencies":{"@automatalabs/libfusefs-ffi-darwin-x64":"0.1.0","@automatalabs/libfusefs-ffi-darwin-arm64":"0.1.0","@automatalabs/libfusefs-ffi-linux-x64-gnu":"0.1.0","@automatalabs/libfusefs-ffi-linux-arm64-gnu":"0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/libfusefs-ffi_0.1.0_1775690221427_0.6933125245216119","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@automatalabs/libfusefs-ffi","version":"0.1.2","description":"Thin Node.js wrapper around libfuse-fs overlay workspaces via napi-rs","license":"MIT","repository":{"type":"git","url":"git+https://github.com/VikashLoomba/libfusefs-ffi.git"},"homepage":"https://github.com/VikashLoomba/libfusefs-ffi#readme","bugs":{"url":"https://github.com/VikashLoomba/libfusefs-ffi/issues"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","publishConfig":{"registry":"https://registry.npmjs.org/","access":"public"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","import":"./dist/testing.js","default":"./dist/testing.js"}},"napi":{"binaryName":"libfusefs_ffi","targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","aarch64-unknown-linux-gnu"]},"scripts":{"artifacts":"napi artifacts","create-npm-dirs":"napi create-npm-dirs","build:native":"napi build --platform --release","build:ts":"tsc -p tsconfig.json","build":"npm run build:native && npm run build:ts","prepublishOnly":"npm run build:native && npm run build:ts && napi prepublish -t npm --no-gh-release","typecheck":"tsc -p tsconfig.json --noEmit","test":"node --import tsx --test tests/**/*.test.ts","test:unit":"node --import tsx --test tests/workspace.test.ts","test:integration":"npm run build:native && RUN_FUSE_TESTS=1 node --import tsx --test tests/integration.native.test.ts"},"devDependencies":{"@napi-rs/cli":"^3.0.0","@types/node":"^22.15.3","tsx":"^4.19.3","typescript":"^5.8.3"},"optionalDependencies":{"@automatalabs/libfusefs-ffi-darwin-x64":"0.1.2","@automatalabs/libfusefs-ffi-darwin-arm64":"0.1.2","@automatalabs/libfusefs-ffi-linux-x64-gnu":"0.1.2","@automatalabs/libfusefs-ffi-linux-arm64-gnu":"0.1.2"},"gitHead":"2239fc7d934127a000f97ee702ebe1769b241ffb","_id":"@automatalabs/libfusefs-ffi@0.1.2","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-hATUVuYx8/tHfW3jpBGttMEbcSdLJJN2JiiBofJvMpPHXmVekDkNVpRc/P6q/DmgiWENku/IJkhxfa4/sWyNSg==","shasum":"54c767f4f312aee19d7bd980fceaec2c43e87db4","tarball":"https://registry.npmjs.org/@automatalabs/libfusefs-ffi/-/libfusefs-ffi-0.1.2.tgz","fileCount":24,"unpackedSize":52908,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@automatalabs%2flibfusefs-ffi@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFkhJLXFsnxj4DkglfGbPseKbqW/gdU4JANtSYeXWgJHAiEA5geEXNtZDUYoytrx6opwVFtC6xDOefh9o5batiywR8I="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:2c98b618-ff18-4936-b842-82a30bf6fd90"}},"directories":{},"maintainers":[{"name":"automatalabsteam","email":"packages@automatalabs.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/libfusefs-ffi_0.1.2_1775692605351_0.7297176749736913"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-08T23:17:01.341Z","modified":"2026-04-08T23:56:45.892Z","0.1.0":"2026-04-08T23:17:01.560Z","0.1.2":"2026-04-08T23:56:45.518Z"},"bugs":{"url":"https://github.com/VikashLoomba/libfusefs-ffi/issues"},"license":"MIT","homepage":"https://github.com/VikashLoomba/libfusefs-ffi#readme","repository":{"type":"git","url":"git+https://github.com/VikashLoomba/libfusefs-ffi.git"},"description":"Thin Node.js wrapper around libfuse-fs overlay workspaces via napi-rs","maintainers":[{"name":"automatalabsteam","email":"packages@automatalabs.io"}],"readme":"# @automatalabs/libfusefs-ffi\n\nNode.js bindings for sandboxed agent workspaces backed by [`libfuse-fs`](https://crates.io/crates/libfuse-fs) via `napi-rs`.\n\n## Scope\n\nThis package is intentionally a **thin wrapper** around the Rust FUSE layer.\n\nIt mounts and unmounts overlay workspaces using `libfuse-fs` / `rfuse3`.\nIt does **not** implement its own workspace directory manager, metadata store, or temp-root lifecycle.\n\nThat means callers are responsible for creating the directories they want to use:\n\n- the existing repo path\n- the mount path\n- the upper layer path\n\n## What it does\n\nThis package creates copy-on-write agent workspaces over an existing local repository:\n\n- the repo is mounted as the read-only lower layer\n- agent writes go into a separate upper layer\n- the user can keep working in the original repo\n- the mounted workspace looks like a normal writable filesystem view to the agent\n\nExample:\n\n```ts\nimport { createWorkspace } from '@automatalabs/libfusefs-ffi'\n\nconst workspace = await createWorkspace({\n  repoPath: '/path/to/repo',\n  mountPath: '/path/to/mount',\n  upperPath: '/path/to/upper',\n})\n\nconsole.log(workspace.mountPath)\nawait workspace.close()\n```\n\n## Platform support\n\nSupported targets:\n\n- Linux with FUSE available\n- macOS with macFUSE available\n\nRuntime checks are performed before workspace creation. On machines without usable FUSE support, `getPlatformSupport()` explains why the native layer is unavailable.\n\n## API\n\n### `createWorkspace(options)`\n\nCreates an agent workspace and returns a `WorkspaceMount`.\n\nRequired:\n\n- `repoPath: string`\n  - must already exist\n  - must point to a directory\n- `mountPath: string`\n  - must already exist\n  - must point to a directory\n  - must be empty before mount\n- `upperPath: string`\n  - must already exist\n  - must point to a directory\n\nOptional:\n\n- `privileged?: boolean`\n- `allowOther?: boolean`\n- `uidMap?: IdMapEntry[]`\n- `gidMap?: IdMapEntry[]`\n\nNotes:\n\n- the lower repo path must live outside the mount and upper directories\n- `uidMap`/`gidMap` are Linux-only right now\n- `uidMap` and `gidMap` must either both be provided or both be omitted\n\n### `WorkspaceMount`\n\nReturned from `createWorkspace()`.\n\nProperties:\n\n- `id`\n- `repoPath`\n- `mountPath`\n- `upperPath`\n- `platform`\n- `kind`\n\nMethods:\n\n- `isMounted(): boolean`\n- `close(): Promise<void>`\n- `toJSON()`\n\n`close()` uses the underlying `rfuse3::MountHandle::unmount()` path. The wrapper does not perform its own directory cleanup.\n\n## Why the API is explicit\n\nThe wrapper is meant to stay close to the underlying Rust crate.\n\nSo, unlike a higher-level sandbox manager, it does **not**:\n\n- invent temp workspace roots\n- create metadata files\n- delete user directories on close\n\nThat behavior belongs in a separate higher-level package if you want it.\n\n## Development\n\n### Install\n\n```bash\nnpm ci\n```\n\n### Build\n\n```bash\nnpm run build\n```\n\n### Typecheck\n\n```bash\nnpm run typecheck\n```\n\n### Unit tests\n\nUnit tests are behavior-driven and test the public TypeScript API using injected native bindings.\n\n```bash\nnpm test\n```\n\n### Real FUSE integration tests\n\nThese tests create and tear down **real FUSE mounts** and verify behavior as a black box:\n\n- mounted overlay view exposes lower-layer repo content\n- writes to the mounted workspace land in the upper layer\n- the original repo stays unchanged\n- create-then-immediate-close succeeds without leaving a mounted filesystem behind\n\nRun them only on machines with FUSE correctly provisioned:\n\n```bash\nnpm run test:integration\n```\n\nTo make missing FUSE support fail the run instead of skipping tests:\n\n```bash\nREQUIRE_FUSE=1 npm run test:integration\n```\n\n## CI\n\nGitHub Actions is configured with:\n\n- a GitHub-hosted unit/check job\n- self-hosted Linux FUSE integration job\n- self-hosted macOS macFUSE integration job\n- a release workflow that builds prebuilt native binaries and publishes the scoped npm package `@automatalabs/libfusefs-ffi`\n\nSee `RELEASING.md` for the end-to-end commit/push/publish flow, including npm trusted publisher setup.\n\nExpected self-hosted runner labels:\n\n- Linux integration runner:\n  - `self-hosted`\n  - `linux`\n  - `fuse`\n- macOS integration runner:\n  - `self-hosted`\n  - `macOS`\n  - `macfuse`\n\n### Linux self-hosted runner requirements\n\n- `/dev/fuse` exists\n- `fusermount3` is installed and on `PATH`\n- the runner user is allowed to perform FUSE mounts\n- the working directory is on a filesystem that supports the required xattrs\n\n### macOS self-hosted runner requirements\n\n- macFUSE is installed and loaded\n- `/dev/macfuse0` or `/dev/osxfuse0` exists\n- the runner user can mount and unmount FUSE filesystems\n\n## Publishing prebuilt binaries\n\nPublishing is handled by `.github/workflows/release.yml`.\n\nRelease flow:\n\n1. Push a semver tag like `v0.1.0`\n2. GitHub-hosted runners build prebuilt binaries for:\n   - `x86_64-apple-darwin`\n   - `aarch64-apple-darwin`\n   - `x86_64-unknown-linux-gnu`\n   - `aarch64-unknown-linux-gnu`\n3. The publish job regenerates the N-API JS shim, builds the TypeScript wrapper, creates the per-platform npm package directories, and collects downloaded artifacts with `napi artifacts`\n4. `npm publish` triggers `napi prepublish -t npm --no-gh-release`, which:\n   - publishes the platform packages\n   - updates optional dependencies for the root package\n   - publishes the root scoped package `@automatalabs/libfusefs-ffi`\n\nThe workflow is configured for npm **trusted publishing** with GitHub Actions OIDC (`id-token: write`).\n\nImportant bootstrap note:\n\n- npm trusted publishers are configured per package and require the package to already exist\n- because this project publishes a root package plus per-platform packages, the **first** release is intended to be done manually with the npm CLI so those package names exist\n- after the first release exists, configure trusted publishers for all package names and use the GitHub Actions release workflow for later releases\n\nSee `RELEASING.md` for the exact manual bootstrap and trusted-publisher setup steps.\n\n## Testing philosophy\n\nPer `AGENTS.md`, tests are written against intended behavior, not incidental implementation details. The integration tests therefore validate:\n\n- what the public API promises\n- what a real mounted workspace does\n- what teardown guarantees the caller can depend on\n\nThey are allowed to fail if the implementation regresses, even if such failures reduce short-term coverage comfort.\n","readmeFilename":"README.md"}