Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 72 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"description": "A zero-terminal, real-time sync engine powered by your own Cloudflare Worker.",
"main": "main.js",
"type": "module",
"workspaces": [
"packages/*"
],
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
Expand Down
93 changes: 93 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# YAOS CLI

Headless YAOS client for mirroring a Markdown vault directory to the YAOS CRDT room.

## Commands

```bash
yaos-cli daemon --host <url> --token <token> --vault-id <id> --dir <path>
yaos-cli sync --host <url> --token <token> --vault-id <id> --dir <path>
yaos-cli status --host <url> --token <token> --vault-id <id>
```

- `daemon` performs startup reconciliation, starts the filesystem watcher, and stays running.
- `sync` performs one reconciliation pass and exits.
- `status` connects to YAOS and prints current connection/cache state as JSON.

## State persistence

`sync` and `daemon` persist local Yjs state in the mirrored vault directory:

- `.yaos-state.bin` — operational Yjs update cache used on the next startup for delta sync.
- `.yaos-state.json` — human-readable metadata about the last persisted state.

If `.yaos-state.bin` is missing, `yaos-cli sync` warns because it must fetch room state before it can delta-sync.
If provider sync times out, the CLI continues in conservative mode rather than pretending it has current room state.
Future runs reuse the cache after a synced state is persisted.
If the file is corrupt, the CLI fails loudly instead of silently pretending the cache loaded; delete the file only when you intentionally want a full resync.

## Runtime support constraints

Supported:

- Linux on a local filesystem.
- One YAOS headless process per vault directory.

Unsupported:

- NFS, SMB, FUSE, cloud-drive mounts, or other non-local filesystems.
- Running two `yaos-cli daemon` processes against the same vault directory.
- Running `yaos-cli daemon` against a directory that an Obsidian YAOS plugin instance is also writing through a shared drive.
- Attachment/blob sync. The CLI is markdown-only for now.
- `.obsidian` settings/plugin sync.

These constraints are correctness boundaries, not performance suggestions. Multiple writers against the same filesystem path can generate colliding file IDs and orphan CRDT state.

## systemd restart behavior

If the server reports `update_required`, the CLI exits with status `2`. For systemd services, prevent restart loops with:

```ini
Restart=always
RestartPreventExitStatus=2
```

## Configuration precedence

1. CLI flags
2. Environment variables
3. `~/.config/yaos/cli.json` (or `$XDG_CONFIG_HOME/yaos/cli.json`)

## Environment variables

- `YAOS_HOST`
- `YAOS_TOKEN`
- `YAOS_VAULT_ID`
- `YAOS_DIR`
- `YAOS_DEVICE_NAME`
- `YAOS_DEBUG`
- `YAOS_EXCLUDE_PATTERNS`
- `YAOS_MAX_FILE_SIZE_KB`
- `YAOS_EXTERNAL_EDIT_POLICY`
- `YAOS_FRONTMATTER_GUARD`
- `YAOS_CONFIG_DIR`

## Config file example

```json
{
"host": "https://sync.example.com",
"token": "...",
"vaultId": "vault-123",
"dir": "/srv/vault",
"deviceName": "n100-headless",
"debug": false,
"excludePatterns": "templates/,scratch/",
"maxFileSizeKB": 2048,
"externalEditPolicy": "always",
"frontmatterGuardEnabled": true,
"configDir": ".obsidian"
}
```

Use file mode `0600` if you store the token in this file.
27 changes: 27 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@yaos/cli",
"version": "0.0.0",
"private": true,
"type": "module",
"bin": {
"yaos-cli": "dist/index.cjs"
},
"scripts": {
"dev": "esbuild src/index.ts --bundle --platform=node --format=cjs --outfile=dist/index.cjs --watch",
"prepare": "esbuild src/index.ts --bundle --platform=node --format=cjs --outfile=dist/index.cjs",
"build": "esbuild src/index.ts --bundle --platform=node --format=cjs --outfile=dist/index.cjs",
"typecheck": "tsc --noEmit -p tsconfig.json",
"test": "node --import jiti/register --test tests/*.ts"
},
"dependencies": {
"chokidar": "^5.0.0",
"commander": "^14.0.0",
"ws": "^8.18.2"
},
"devDependencies": {
"@types/node": "^16.11.6",
"@types/ws": "^8.18.0",
"esbuild": "0.25.5",
"typescript": "^5.8.3"
}
}
Loading
Loading