Files
ocas/packages/cli/README.md
T
xiaomo c4d9205eb2 docs: update all documentation for node:sqlite, pnpm, proman workflow
- README: bun → pnpm, update API examples, add Node >=22.5.0 requirement
- CLAUDE.md: replace 3-phase release process with proman bump/publish
- Package READMEs: fix package names, update storage/API descriptions
- Cards: update store.md (sqlite), cli.md (db filename, remove --var-db)
- docs/sync-readme.md: update to proman workflow
2026-06-03 23:21:30 +00:00

6.0 KiB

@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:

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:

node packages/cli/dist/index.js <command> [args]

CLI Usage

Usage: ocas [--home <path>] [--json] <command> [args]

Global flags

Flag Description
--home <path> Store directory (default: $OCAS_HOME or ~/.ocas)
--var-db <path> Variable database path (default: <home>/variables.db)
--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.

// ocas has <hash>
{ "type": "AYHQD2YA9G667", "value": true }

// ocas template set <schema-hash> --inline "Hi {{ payload.name }}"
{ "type": "9YJZ09DDAYAWR", "value": { "schemaHash": "7XX5H51CVD9H0", "contentHash": "FC8WACA792B6F" } }

Commands

Command Envelope value Result schema
put <type-hash> <file.json> stored node hash (string) @output/put
get <hash> { type, payload, timestamp } @output/get
has <hash> boolean @output/has
verify <hash> ok / corrupted / invalid @output/verify
refs <hash> hashes (string[]) @output/refs
walk <hash> [--format tree] hashes (string[]) or tree string @output/walk
hash <type-hash> <file.json> computed hash (string) @output/hash
render <hash> [options] raw text (no envelope)
render --pipe/-p [options] raw text from piped envelope
list --type <hash-or-name> hashes (string[]) @output/list
var set <name> <hash> [--tag ...] variable object @output/var-set
var get <name> --schema <hash> variable object @output/var-get
var delete <name> [--schema <hash>] variable or variable[] @output/var-delete
var tag <name> --schema <hash> <ops...> variable object @output/var-tag
var list [prefix] [--schema <hash>] [--tag ...] variable[] @output/var-list
template set <schema-hash> <file> | --inline <text> { schemaHash, contentHash } @output/template-set
template get <schema-hash> template content (string) @output/template-get
template list { schemaHash, contentHash }[] @output/template-list
template delete <schema-hash> { deleted: boolean } @output/template-delete
gc { total, reachable, collected, scanned } @output/gc

Examples

# 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": "<content-hash>" }

ocas get <content-hash> --json
ocas verify <content-hash>
ocas walk <content-hash> --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:

# 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 <name> <hash> resolve the same way:

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 <hash>
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/<schema-hash> variable). render <hash> uses the template registered for the node's type, falling back to YAML when none exists.

# Bind a template to a schema, then render a node of that type
ocas template set 0123456789ABC --inline "Item: {{ payload.name }}"
ocas render <content-hash>
# → Item: Widget

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 <path> or OCAS_HOME env var

No config file is read; all behavior is controlled via flags and command arguments.