- var set <name> <hash> (upsert, replaces create+update)
- var get <name> --schema <hash> (schema required)
- var delete <name> [--schema <hash>] (optional schema)
- var list [prefix] (replaces --scope)
- var tag <name> --schema <hash> ...
- 41 CLI tests, all passing
Fixes#34
Ref #31
Migrate CLI var subcommands from ULID ID model to (name, schema) composite key model.
- Replace var create/update with unified var set (upsert semantics)
- Update var get to require --schema parameter for precise query
- Enhance var delete with batch (no --schema) and precise (with --schema) modes
- Refactor var list to use positional prefix parameter
- Update var tag to target composite keys
- Add comprehensive test suite (41 tests, 100% coverage)
- Update Variable schema: remove id/scope, add name field
Fixes#34
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses Review Round 2 feedback for variable model refactor:
1. Remove create() method - set() is now the unified entry point
2. Remove VariableDuplicateError class (only used by create())
3. Clean up dead code: Array.isArray(existing) checks in update()/remove()/tag()
4. Add tag/label conflict validation to set() update path
5. Migrate gc.test.ts from create() to set()
Changes:
- Delete create() method (lines 381-467) and VariableDuplicateError class
- Remove Array.isArray checks from 3 methods (always null, never array)
- Remove orphaned delete() JSDoc comment
- Add 3 new tests for set() update path tag/label conflict validation
- Replace 10 create() calls with set() in gc.test.ts
Test results: 193 pass (190 existing + 3 new)
Build: clean, Lint: clean
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Closes#33
## Changes
### 1. Enhanced Name Validation
- Added `validateName()` private method with comprehensive validation rules
- Updated `InvalidVariableNameError` to include specific `reason` field
- Validation rules:
- Each segment must match [a-zA-Z0-9._-]+
- Segments separated by /
- No empty segments (e.g., a//b)
- No leading/trailing slashes (e.g., /a or a/)
- Applied to all mutating operations: set(), create(), update(), tag()
### 2. New set() Upsert Method
- Implements upsert semantics: insert if not exists, update if exists
- Checks (name, schema) pair existence using extractSchema(value)
- On update: preserves created timestamp, updates value and updated timestamp
- Preserves existing tags/labels when called without options
- Replaces tags/labels when called with options
- Allows same name with different schemas
### 3. Optional Schema in get()
- Overloaded signature: get(name) and get(name, schema)
- get(name) without schema:
- Returns null when no variables exist
- Returns single Variable when one schema variant exists
- Returns Variable[] when multiple schema variants exist
- get(name, schema) with schema:
- Returns Variable | null for exact match
- Includes complete tags and labels
### 4. Renamed delete() to remove() with Optional Schema
- Overloaded signature: remove(name) and remove(name, schema)
- remove(name) without schema:
- Deletes all schema variants for the name
- Returns Variable[] (all deleted variants)
- Returns empty array [] when nothing found
- remove(name, schema) with schema:
- Deletes specific (name, schema) variant
- Returns single Variable
- Throws VariableNotFoundError when not found
- Cascades deletion to tags and labels via foreign key constraints
### 5. Code Quality Improvements
- Fixed `any` type usage, replaced with `unknown` and proper type guards
- Fixed string concatenation to use template literals
- Updated all internal get() calls to handle new return types
- Applied strict null checks and array checks
### 6. Comprehensive Test Coverage
- 36 tests covering all new behaviors
- Test suites for:
- set() upsert method (7 tests)
- get() with optional schema (6 tests)
- remove() with optional schema (6 tests)
- Name validation (6 tests)
- Integration workflows (2 tests)
- Legacy methods (2 tests)
- Database schema verification
- List and tag operations
- All tests pass: bun test (151 pass, 0 fail)
## Verification
- ✅ bun test - All 151 tests pass
- ✅ bun run build - Clean TypeScript build
- ✅ bunx biome check - No lint errors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements RFC-31 Phase 1 - refactors the Variable model to use a composite
primary key of (name, schema) instead of the previous ULID id + scope approach.
Key changes:
1. **Type Model**:
- Removed `id: VariableId` and `scope: string` fields
- Added `name: string` as part of composite key with `schema: Hash`
- Variables with same name but different schemas are now distinct entities
2. **Database Schema**:
- Changed primary key from `id` to `(name, schema)`
- Updated foreign keys in `variable_tags` and `variable_labels` tables
- Replaced scope-based indexes with name-based indexes
- Enabled foreign key constraints for proper cascade deletes
3. **CRUD Operations** - all methods updated to use `(name, schema)`:
- `create(name, value, options)` - validates unique (name, schema)
- `get(name, schema)` - retrieves by composite key
- `update(name, schema, value)` - updates with schema validation
- `delete(name, schema)` - deletes with cascade to tags/labels
- `list({ namePrefix?, schema?, tags?, labels? })` - filters by name prefix and schema
- `tag(name, schema, operations)` - manages tags/labels by composite key
4. **Error Types**:
- New: `VariableDuplicateError` for duplicate `(name, schema)` pairs
- New: `InvalidVariableNameError` for empty names
- Removed: `InvalidScopeError` (no longer needed)
- Updated: `VariableNotFoundError` to reference `(name, schema)`
5. **GC Adaptation**:
- Garbage collection works correctly with refactored model
- Preserves nodes referenced by variables across all schemas
- Global collection across all variable names and schemas
6. **Tests**:
- Added comprehensive test suite covering all new functionality
- Database schema validation tests
- CRUD operation tests with composite keys
- Multi-schema scenarios (same name, different schemas)
- Tag/label management tests
- GC integration tests
- End-to-end workflow tests
7. **Breaking Changes**:
- This is a backward-incompatible change
- CLI commands will need updates in a future phase (out of scope for Phase 1)
- Data migration is out of scope for Phase 1
Fixes#32
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements garbage collection (GC) with mark-and-sweep algorithm:
- Mark phase: recursively walks references from all variable values (global, not scoped)
- Sweep phase: deletes unmarked CAS nodes
- Schema preservation: schemas referenced by reachable nodes are preserved
- Bootstrap preservation: self-referencing meta-schema always preserved
New features:
- Core gc() function in packages/json-cas/src/gc.ts with GcStats interface
- Extended Store interface with listAll() and delete() methods
- CLI command: json-cas gc (outputs JSON stats)
- Comprehensive test suite with 16 test scenarios
Implements: #23
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements comprehensive tag/label functionality for variables:
## Core Features
- Tags: key-value pairs with same-key override semantics
- Labels: bare identifiers
- Deletion syntax: `:name` removes tag or label
- Mutual exclusion: tag keys and label names cannot coexist
- Unified `var tag` command for all tag/label operations
## Data Model
- Extended Variable type with tags/labels fields
- New variable_tags and variable_labels SQLite tables
- Foreign key constraints with CASCADE delete
- Proper indexes for efficient querying
## Query Capabilities
- Filter by scope (hierarchical prefix matching)
- Filter by tags (key:value pairs, AND logic)
- Filter by labels (bare names, AND logic)
- Combined filtering (scope + tags/labels)
## CLI Commands
- `json-cas var create --tag <tag>...` - initial tags/labels
- `json-cas var tag <id> <tag>...` - add/update/delete
- `json-cas var list --tag <tag>...` - query with filters
## Implementation Details
- TagLabelConflictError and InvalidTagFormatError types
- Atomic batch operations with rollback
- 46 comprehensive tests for tags/labels
- Backward compatible with Phase 1
- All 214 tests pass
Closes#22
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes#27
Changes:
1. Variable uses type instead of interface
2. Add JSON envelope output {type, value} to all CLI var commands
3. Add list method with scope prefix matching to VariableStore and CLI
4. Fix var-db path to default to <storePath>/variables.db instead of <defaultStorePath>/variables.db
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Applied monorepo normalization:
- Updated TypeScript to use composite project references with NodeNext
- Configured Biome for linting and formatting
- Standardized package.json metadata across all packages
- Set up changesets for version management and npm publishing
- Added vitest test infrastructure to all packages
- Created Gitea Actions CI pipeline
- Added solve-issue workflow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add oneOf to BOOTSTRAP_PAYLOAD (meta-schema)
- Add oneOf to ALLOWED_SCHEMA_KEYS
- Add oneOf validation in isValidSchema
- Add test 2.7b for oneOf acceptance
- Remove oneOf from unsupported keywords test
Required by workflow's solve-issue.yaml which uses oneOf for
discriminated union frontmatter schemas.
- Add tsc --build pipeline for json-cas, json-cas-fs, json-cas-workflow
- Update package.json exports to point to dist/ (types + import)
- Fix Store type error: use BootstrapCapableStore for stores with bootstrap
- Export BootstrapCapableStore type from json-cas
- Fix meta-schema: nodeSchema now uses real JSON Schema (draft 2020-12)
- Exclude test files from tsc compilation
Breaking: bootstrap hash changes due to meta-schema payload update.
小橘 🍊(NEKO Team)
Removes the list() method from the Store type and all implementations.
Callers now use listByType() or has() instead.
The CLI 'list' subcommand is removed. 'schema list' now uses
listByType(metaHash) to enumerate schemas.
Closes#11