# @ocas/cli CLI tool for ocas stores. ## Overview `@ocas/cli` provides the `ocas` command for managing a filesystem-backed store: node CRUD, integrity checks, reference listing, graph walks, variables, and output templates. It uses `@ocas/fs` for persistence and `@ocas/core` for core operations. The store is **auto-created and bootstrapped** on first use, so there is no `init`/`bootstrap` command. Schemas are ordinary `@ocas/schema`-typed nodes — register one with `ocas put @ocas/schema file.json` and list them with `ocas list --type @ocas/schema`; there is no dedicated `schema` subcommand. **Dependencies:** `@ocas/core`, `@ocas/fs` ## Installation Published as an npm package with a binary entry: ```bash pnpm add -g @ocas/cli # or from the monorepo workspace: pnpm link ``` **Binary name:** `ocas` (points to `dist/index.js`, run with Node). In development: ```bash node packages/cli/dist/index.js [args] ``` ## CLI Usage ``` Usage: ocas [--home ] [--json] [args] ``` ### Global flags | Flag | Description | |------|-------------| | `--home ` | Store directory (default: `$OCAS_HOME` or `~/.ocas`) | | `--var-db ` | Variable database path (default: `/variables.db`) | | `--store ` | Open a bundle file as a read-only store (write commands rejected) | | `--json` | Compact (single-line) JSON output | ### Envelope format Every JSON-emitting command prints a uniform `{ type, value }` envelope. `type` is the hash of the command's `@output/*` result schema and `value` is the command payload. The output is therefore self-describing and pipeable: feed any envelope into `render -p` to render its `value` (embedded `cas_ref` hashes are expanded). `render` is the only command that emits raw, non-envelope text. ```jsonc // ocas has { "type": "AYHQD2YA9G667", "value": true } // ocas template set --inline "Hi {{ payload.name }}" { "type": "9YJZ09DDAYAWR", "value": { "schemaHash": "7XX5H51CVD9H0", "contentHash": "FC8WACA792B6F" } } ``` ### Commands | Command | Envelope `value` | Result schema | |---------|------------------|---------------| | `put ` | stored node hash (string) | `@output/put` | | `get ` | `{ type, payload, timestamp }` | `@output/get` | | `has ` | boolean | `@output/has` | | `verify ` | `ok` / `corrupted` / `invalid` | `@output/verify` | | `refs ` | hashes (string[]) | `@output/refs` | | `walk [--format tree]` | hashes (string[]) or tree string | `@output/walk` | | `hash ` | computed hash (string) | `@output/hash` | | `render [options]` | raw text (no envelope) | — | | `render --pipe/-p [options]` | raw text from piped envelope | — | | `list --type ` | hashes (string[]) | `@output/list` | | `var set [--tag ...]` | variable object | `@output/var-set` | | `var get --schema ` | variable object | `@output/var-get` | | `var delete [--schema ]` | variable or variable[] | `@output/var-delete` | | `var tag --schema ` | variable object | `@output/var-tag` | | `var list [prefix] [--schema ] [--tag ...]` | variable[] | `@output/var-list` | | `template set \| --inline ` | `{ schemaHash, contentHash }` | `@output/template-set` | | `template get ` | template content (string) | `@output/template-get` | | `template list` | `{ schemaHash, contentHash }[]` | `@output/template-list` | | `template delete ` | `{ deleted: boolean }` | `@output/template-delete` | | `gc` | `{ total, reachable, collected, scanned }` | `@output/gc` | | `export -o ` | `{ nodes, vars, tags }` | `@output/export` | | `import [--scope @new]` | nested `{ nodes, vars, tags }` stats | `@output/import` | ### Examples ```bash # Register a schema (schemas are plain @ocas/schema nodes) and store a payload ocas put @ocas/schema ./schemas/item.json # → { "type": "...", "value": "0123456789ABC" } (the schema's type hash) ocas put 0123456789ABC ./payloads/item.json # → { "type": "...", "value": "" } ocas get --json ocas verify ocas walk --format tree # List every registered schema, then extract the hashes with jq ocas list --type @ocas/schema | jq -r '.value[]' ``` ### Pipe composition Because every command shares the `{ type, value }` envelope, output composes directly into `render -p`: ```bash # put emits a cas_ref hash envelope; render -p dereferences and renders the node ocas put @ocas/schema ./schemas/item.json | ocas render -p # render gc statistics ocas gc | ocas render -p # render every schema referenced by a list result ocas list --type @ocas/schema | ocas render -p ``` ### Variable names as hash arguments Every command that takes a hash also accepts a variable name. Builtin schema names like `@ocas/schema`, `@ocas/string`, `@ocas/output/*` are registered in the variable store during bootstrap; user variables created via `ocas var set ` resolve the same way: ```bash ocas put @ocas/object data.json # @ocas/object → builtin schema hash ocas list --type @ocas/schema # filter by builtin schema ocas var set myapp/config ocas get myapp/config # resolves to the user-bound hash ``` There is no separate alias system — names are just variables. ### Templates `template` commands manage the LiquidJS template bound to a schema (stored as a `@ocas/template/text/` variable). `render ` uses the template registered for the node's type, falling back to YAML when none exists. ```bash # Bind a template to a schema, then render a node of that type ocas template set 0123456789ABC --inline "Item: {{ payload.name }}" ocas render # → Item: Widget ``` ### Bundles (export / import) `ocas export` walks the transitive CAS closure (refs **and** schema chains) of one or more roots and writes a self-contained POSIX-tar archive containing every reachable CAS node (`cas/.bin`, CBOR-encoded), every variable whose value is in-closure (`vars.jsonl`), and every tag attached to an in-closure target (`tags.jsonl`). ```bash ocas export @myapp/config -o myapp.tar # single root by name ocas export @myapp/config @myapp/users -o m.tar # multiple roots ocas export 1ABC2DEF34567 -o snapshot.tar # raw hash root # Import into the current store (idempotent — content-addressed dedup) ocas import myapp.tar ocas import myapp.tar --scope @prod # remap @myapp/* → @prod/* # Inspect a bundle without unpacking it ocas get @myapp/config --store myapp.tar ocas walk @myapp/config --store myapp.tar ocas var list --store myapp.tar ``` `-o ` (required for `export`) names the output tar. `--scope @new` rewrites the leading `@scope` of every imported variable name except builtins (`@ocas/*`). `--store ` swaps the store backend for any read-only command (`get`, `has`, `refs`, `walk`, `list`, `var list`, `var get`, `verify`, `render`, …); write commands (`put`, `tag`, `gc`, `import`, `var set`, `template set`, …) refuse with `--store is read-only` when the flag is set. ## Internal Structure | File | Purpose | |------|---------| | `index.ts` | Argument parsing, command dispatch, and all CLI logic | There is no separate `src/` module tree; the CLI is a single entry file. Tests (if present) are co-located under the package. ## Configuration | Setting | Default | Override | |---------|---------|----------| | Store directory | `~/.ocas` | `--home ` or `OCAS_HOME` env var | No config file is read; all behavior is controlled via flags and command arguments.