@vibecook/mille · v0.2.1

API reference · v0.2.1

Public surface

The types and factories you integrate against. Authoritative declarations live in packages/mille/api.d.ts. This page is the curated, navigable guide.

Engine @vibecook/mille UI @vibecook/mille-ui Node ≥ 20 React 19 for UI

Design principles

These constraints shape every public type. Read them once; they explain the rest of the API.

PrincipleWhat it means for you
Tree in Rust Canonical structure, watch, walk, and search live natively. JS owns expansion, selection, scroll.
Snapshot reads All sync reads go through an immutable MirrorSnapshot. Safe during React render; identity-stable until the next change.
Flat over nested Rows and entries cross NAPI as flat records. Virtualizers never walk a nested object tree.
Stable EntryId Session-scoped ids stay stable across renames/moves. Capped at 2^53-1 for JS safety.
Typed errors Expected FS failures throw FileSystemError with POSIX-like codes — use try/catch, not Result unions.
Version channels treeVersion and decorationVersion bump independently so SCM churn does not thrash row caches.

Module entries

Import only what you need. Host code never belongs in the renderer bundle.

@vibecook/mille FileExplorer, errors, decorations, connect helpers
@vibecook/mille/host createFileExplorerHost — UtilityProcess only
@vibecook/mille/client connectFileExplorer, PortFileExplorer
@vibecook/mille/react useFileExplorerSnapshot
@vibecook/mille-ui Styled FileTree + hooks
@vibecook/mille-ui/headless Structure only · ~12.5 KB gzip
@vibecook/mille-ui/git Git decoration provider (browser-safe)
@vibecook/mille-ui/git/node createShellGitClient — Node/utility only

Core types

Shared identifiers and records used across engine and UI.

EntryId type
type EntryId = number

Monotonic id assigned in Rust. Stable across renames and moves within a session. Reassigned on process boot. Safe as a React key, Map key, or JSON value.

Uri interface

Scheme-based resource locator. Mirrors VS Code’s Uri shape. Local mode typically accepts absolute path strings as a convenience; hosts may pass full Uris.

FieldTypeNotes
schemestringfile | memfs | ssh | …
authority?stringRemote host, etc.
pathstringAlways POSIX-style
query?string
fragment?string
EntryKind enum
MemberValue
File0
Directory1
Symlink2
Unknown3
Entry interface
One row in the flat-array model
FieldTypeNotes
idEntryId
parentIdEntryId | nullnull only for roots
namestringBasename
kindEntryKindNumeric enum
sizenumberBytes; 0 for directories
mtimeMsnumberUnix ms
ctimeMsnumberUnix ms
symlinkTargetIsDir?booleanFor UI caret rendering
pathSegments?string[]Set when compact-folders collapses a chain
isIgnoredbooleanMatched by ignore rules
isReadonlyboolean
isHiddenbooleanDotfile or platform-hidden
Capability const enum

Bitmask providers advertise. Local mode currently reports ReadWrite | CaseSensitive | Watch.

FlagValue
ReadWrite1 << 0
CaseSensitive1 << 1
Readonly1 << 2
Trash1 << 3
AtomicWrite1 << 4
Watch1 << 5
Stream1 << 6
Clone1 << 7
Realpath1 << 8
FileLock1 << 9
FileSystemError class
class FileSystemError extends Error

Expected filesystem failures. Check with isFileSystemError(e).

MemberTypeNotes
codeErrorCodeEACCES, ENOENT, EEXIST, EISDIR, ENOTDIR, ELOOP, ENOSPC, EROFS, EBUSY, EINVAL, ECANCELED, EUNSUPPORTED, EUNKNOWN
path?stringPath involved in the failure
try {
  await fx.rename(id, 'new-name');
} catch (e) {
  if (isFileSystemError(e) && e.code === 'EEXIST') {
    // handle collision
  } else throw e;
}

Explorer

Construct, populate, snapshot, mutate. Construction never walks the filesystem.

ExplorerOptions interface
FieldTypeDefault / notes
rootsreadonly (Uri | string)[]Required. Absolute paths or Uris.
respectIgnore?booleantrue — parse .gitignore / .ignore / .rgignore
followSymlinks?boolean | 'smart''smart' — canonicalize, dedupe, block cycles
walkerConcurrency?numbernum_cpus
watchDebounceMs?number75
compactFolders?booleantrue
excludeGlobs?string[]Extra excludes layered on ignore
snapshotPath?stringCrash-resume snapshot file
maxCachedEntries?number500_000
initialWalk?'full' | 'roots-only' | 'none'Host walk policy. 'roots-only' for huge repos. Default 'full' (host does not auto-walk; caller populates).
FileExplorer class
new FileExplorer(options: ExplorerOptions)
Read path: getSnapshot() → sync queries on the snapshot.
Write path: methods on the explorer (create, rename, …).
Subscribe: on('change', …) with useSyncExternalStore.
getSnapshot(): MirrorSnapshot

Current immutable snapshot. Identity-stable until the next change event.

populateFromRoots(): Promise<number>

Parallel walk of configured roots. Returns total entry count. Call once after construction for full load.

setExpanded(diff: { add?: EntryId[]; remove?: EntryId[] }): void

Update session expansion. Host may trigger shallow walks for newly expanded folders (lazy list-on-expand).

setViewport(opts: { offset; limit; overscan? }): void

Declare the visible window so the host can prioritize mirror rows.

list(parentId, options?): Promise<ListPage>

Async paginated children. Prefer snapshot for already-loaded data.

prefetch(id, options?): Promise<void>

Warm children without adding to the expansion set.

create / rename / move / delete / copy

Structural mutations. Reject with FileSystemError on expected failures.

readFile / readText / writeFile / readFileStream

I/O by EntryId. Stream is AsyncIterable<Uint8Array>.

search(query, options?): Promise<SearchHit[]>

Fuzzy filename search over the in-memory tree (nucleo).

on(event, listener): Disposable

Events: change, change:tree, change:decorations, event, batch, warning, error, ready.

registerDecorationProvider(provider): Disposable

SCM / lint / problems overlay. Reads via snapshot.getDecorations(id).

writeSnapshot(path): Promise<void>

Persist crash-resume snapshot.

dispose(): Promise<void>

Stop watcher threads, release native resources. Idempotent.

MirrorSnapshot interface

Immutable view at a specific tree-version + decoration-version. Never mutate. Diff with ===.

readonly treeVersion: number

Structural version.

readonly decorationVersion: number

Decoration channel version.

roots(): readonly Entry[]

Workspace roots in display order.

visibleRows(options): readonly VisibleRow[]

Flat slice for virtualizers: expanded set + offset/limit. Cache-miss rows may set pending: true.

visibleRowCount(expanded, includeIgnored?): VisibleRowCount

known count plus pendingExpansions for incomplete folders.

getById / directChildCount / hasChildren / getDecorations

Point queries for rows and overlays.

const rows = snap.visibleRows({
  expanded,
  offset: 0,
  limit: 100,
  includeIgnored: false,
});
VisibleRow interface
extends Entry
FieldTypeNotes
depthnumber0 = root level
hasChildrenbooleanCaret affordance
isExpandedbooleanFrom the query’s expansion set
pending?truePlaceholder while children load
ChangeNotice interface

Payload for on('change' | 'change:tree' | 'change:decorations'). Pull model: bump version, re-read only the rows you need.

FieldTypeNotes
treeVersionnumber
decorationVersionnumber
changed{ tree; decorations }Which dimensions moved
changedIdsEntryId[]Entries that may have changed
childSetChangedEntryId[]Parents whose children changed
decorationChangedIdsEntryId[]Decoration-only updates
coarseSubtreesEntryId[]Watcher overflow regions

Host / client split

Recommended Electron deployment. Both sides satisfy the FileExplorer shape so renderers stay agnostic.

createFileExplorerHost function
function createFileExplorerHost(options: ExplorerOptions): Promise<FileExplorerHost>

UtilityProcess-side factory. Loads the native module, owns the EntryStore, walker, and watcher. Import from @vibecook/mille/host.

FileExplorerHost interface
attachPort(port: MessagePortLike): Disposable

Each port is an independent session (expansion + viewport + knownIds).

readonly sessionCount: number

Attached client sessions.

readonly local: FileExplorer

In-process access for host-side SCM/indexers. Prefer host.registerDecorationProvider when badges must fan out to port clients.

registerDecorationProvider(provider): Disposable

Host-level decorations store shared by every session.

dispose(): Promise<void>

Tear down host and native resources.

connectFileExplorer function
function connectFileExplorer(port: MessagePortLike, options?: ClientOptions): Promise<FileExplorer>

Renderer-side factory. Reads from a local ViewportMirror; writes round-trip to the host over the wire protocol (v1 frames).

ClientOptions interface
FieldTypeDefault
prefetchRows?number200 — tune to virtualizer overscan
mirrorCap?number20_000 — LRU eviction of cold expansions

UI — @vibecook/mille-ui

The engine owns structure; this package renders it. Peer: React 19, @tanstack/react-virtual. Radix peers optional for the styled entry.

FileTree component
<FileTree fx={…} ariaLabel="Files" />

Virtualized ARIA tree. Pass fx for standalone use (self-wraps provider), or nest inside FileTreeProvider for shared command registry / multi-tree setups.

PropTypeNotes
fx?FileTreeEngineExplorer or port client
ariaLabelstringRequired for accessibility
rowHeight?numberDefault 22
overscan?numberDefault 20
iconTheme?IconThemeVS Code File Icon Theme compatible. Prefer duotoneIconTheme, defaultIconTheme, or loadMaterialIconTheme()
emptyState?ReactNode
loadingState?ReactNode
ref?FileTreeRefImperative handle (v0.2)
import { FileTree } from '@vibecook/mille-ui';
import { duotoneIconTheme } from '@vibecook/mille-ui/icons/duotone';
import '@vibecook/mille-ui/tokens.css';

<FileTree fx={fx} ariaLabel="Files" rowHeight={22} iconTheme={duotoneIconTheme} />;
FileTreeRef interface

Imperative handle via forwardRef / useFileTreeRef.

revealPath / revealId

Expand ancestors and scroll the target into view.

scrollToRow

Scroll to a visible row index.

clearSelection / clearFilter / clearClipboard

Reset interaction state.

focusFilter

Move focus to the filter input.

UI entry points modules
ImportContents
@vibecook/mille-uiStyled FileTree, hooks, decorations UI
…/headlessStructural components + class catalog
…/commandsCommand registry + defaults (expand, rename, delete…)
…/gitregisterGitDecorations (host-wired client)
…/git/nodecreateShellGitClient — spawns git status
…/agent-rules.cursor/rules, CLAUDE.md, .kiro badges
…/iconsRe-exports default + duotone themes
…/icons/defaultMonoline folder + file icons
…/icons/duotoneSoft-duotone set (product default)
…/icons/materialMaterial Icon Theme bundle
…/testingcreateFakeEngine for unit tests
…/tokens.cssCSS variables for the styled tree
Need the full wire protocol or packaging notes? See EMBEDDING.md for UtilityProcess diagrams, electron-builder packaging, and performance tuning. Source of truth for types: api.d.ts.