Files
ocas/CLAUDE.md
T
xiaoju 9ac08e5893 chore: 去掉 Bun,切换到 pnpm + 纯 Node runtime
- bun.lock → pnpm-lock.yaml + pnpm-workspace.yaml
- 删除 sqlite-adapter.ts(Bun/Node 双 runtime 兼容层,未被使用)
- package.json 删除 workspaces 字段,加 pnpm.onlyBuiltDependencies
- 加 vite 8 显式依赖(vitest 4.x peer dep)
- CLAUDE.md 全面更新:Runtime/Commands/Release 流程
- .gitignore 加 bun.lock

36/36 files pass, 617/617 tests pass

Fixes #66
2026-06-03 07:43:09 +00:00

6.6 KiB

CLAUDE.md — OCAS

Object Content Addressable Store — self-describing CAS with JSON Schema typed nodes.

Project Structure

Monorepo with 3 packages under packages/:

Package Directory Description
@ocas/core packages/core Core CAS engine — hashing, schema, store, verify, bootstrap
@ocas/fs packages/fs Filesystem-backed CAS store
@ocas/cli packages/cli CLI tool (ocas binary)

Tech Stack

  • Runtime: Node.js
  • Language: TypeScript (strict mode, exactOptionalPropertyTypes, noUncheckedIndexedAccess)
  • Build: tsc (composite project references, sequential: core → fs → cli)
  • Test: Vitest (npx vitest run)
  • Package Manager: pnpm (workspace)
  • Lint/Format: Biome (biome check . / biome format --write .)
  • Publish: Changesets + pnpm publish → npmjs (@ocas/*)

Commands

pnpm run test     # Run all tests (vitest)
pnpm run build    # Build all packages (tsc via proman)
pnpm run check    # Biome lint
pnpm run format   # Biome format (auto-fix)

Code Conventions

TypeScript

  • Strict mode — no any, no unchecked index access, no implicit overrides
  • verbatimModuleSyntax — use import type for type-only imports
  • Import paths — use .js extension in imports (ESM convention with bundler resolution)
  • Export style — named exports only, re-export from index.ts

Biome Rules

  • noConsole: "error" globally (except packages/cli)
  • Recommended ruleset enabled
  • Auto-organize imports via assist.actions.source.organizeImports
  • Indent: 2 spaces

Naming

  • Types: PascalCase (CasNode, Hash, Store)
  • Functions: camelCase (computeHash, createMemoryStore)
  • Constants: UPPER_SNAKE_CASE (BOOTSTRAP_STORE)
  • Files: kebab-case.ts
  • Test files: co-located as *.test.ts

Key Types

  • Hash — 13-character uppercase Crockford Base32 string (XXH64)
  • CasNode — content-addressed node with schema
  • Store — unified storage interface { cas: CasStore, var: VarStore, tag: TagStore }
  • ListOptions — sorting/pagination options (sort, desc, limit, offset)
  • ListEntry — list result entry (hash, created, updated)

List Utilities

packages/core/src/list-utils.ts provides applyListOptions() — in-memory sort/paginate for ListEntry[] arrays. Used by MemoryStore; FsStore pushes sort/limit to SQLite. Core layer treats limit: undefined as "no limit"; the CLI defaults to 100 in parseListOptions().

Architecture Notes

  • No "alias" concept — every name resolution flows through store.var. Builtin schemas (@ocas/schema, @ocas/string, @ocas/output/*, …) are registered as variables during bootstrap(store), alongside user-defined variables created via ocas var set.
  • bootstrap(store) synchronously writes builtin name → hash bindings into the unified store; called automatically by openStore().
  • resolveHash(input, store) is the unified hash/name resolver in the CLI. If input matches the 13-char hash format it is returned as-is; otherwise store.var is queried by exact name. This means every CLI command that accepts a hash argument also accepts a variable name (schema names, user vars, etc.).
  • Variable naming: all names must follow @scope/name format (@[a-zA-Z][a-zA-Z0-9]*/segments). @ocas/* is reserved for builtins. The @ prefix ensures names are visually distinct from hashes.
  • openStore() returns a unified Store with cas, var, and tag sub-stores, and bootstraps automatically. @ocas/core has zero SQLite dependency.

Internal Dependencies

Workspace packages reference each other with workspace:* in package.json. This is resolved to real version numbers only during publishing (see below).

Git

  • Commit format: type: description (conventional commits)
  • Reference issues: Fixes #N / Closes #N
  • Author: 小橘 <xiaoju@shazhou.work>

Project Rules

Before Submitting

  1. pnpm run test — all tests pass
  2. pnpm run check — no lint errors
  3. pnpm run build — builds cleanly

Release Process

Releases use a release branch workflow with three phases: prepare → candidate → finalize.

main always keeps workspace:* for internal deps; release branches fix them to real versions. Changeset files are only consumed once during finalize — prerelease (rc) never touches them.

Adding a Changeset

Add changesets alongside feature PRs on main:

<!-- .changeset/my-change.md -->
---
"@ocas/cli": patch
---

Description of the change

Changesets live in .changeset/ as markdown files. Bump types: patch / minor / major. One changeset can cover multiple packages.

Phase 1: Prepare (cut release branch)

  • Precondition: on main, clean tree, .changeset/ has pending changesets
  • Steps:
    1. Determine target version (from changeset bump types or manually)
    2. git checkout -b release/<version>
    3. Fix workspace:* → real version numbers in all package.json
    4. Commit
  • Does NOT run changeset version, does NOT write CHANGELOG

Phase 2: Candidate (publish rc for validation)

  • Precondition: on release/* branch
  • Steps:
    1. Set version to <version>-rc.N (first time rc.1, increment on subsequent runs)
    2. pnpm install && pnpm run build && pnpm run test && pnpm run check
    3. Publish: pnpm publish --tag rc (order: core → fs → cli)
    4. Commit + push
  • Repeatable: fix bugs → add new changesets on the release branch → rc.N+1
  • Does NOT consume changesets, does NOT write CHANGELOG
  • Install for testing: pnpm add -g @ocas/cli@rc

Phase 3: Finalize (official release)

  • Precondition: on release/* branch, rc validated
  • Steps:
    1. Consume all .changeset/*.md → write CHANGELOG entries (use changeset version or manual)
    2. Set final version <version> (remove -rc.N)
    3. pnpm install && pnpm run build && pnpm run test && pnpm run check
    4. Publish: pnpm publish --tag latest (order: core → fs → cli)
    5. Git tag v<version>
    6. Merge back to main (CHANGELOG comes along)
    7. Restore workspace:* on main
    8. Delete release branch

Key Rules

  • Publish order is always @ocas/core@ocas/fs@ocas/cli
  • workspace:* must be fixed before any publish — pnpm publish does NOT auto-replace them
  • CHANGELOG only contains official releases, never rc entries
  • Changesets added on release branch (bug fixes during rc) are consumed together at finalize