Get the FREE Ultimate OpenClaw Setup Guide →

core-development

npx machina-cli add skill aiskillstore/marketplace/core-development --openclaw
Files (1)
SKILL.md
3.8 KB

Core Package Development

The core package (packages/core/) is dependency-free and handles all DSL processing.

Data Flow

DSL (YAML input) → validate() → normalize() → IR → diff() → Patch

Key Files

FilePurposeExports
types.tsType definitionsDSL*, IR*, Patch, WebSocket protocol
validate.tsYAML validationvalidate(dsl): ValidationResult
normalize.tsDSL → IR conversionnormalize(dsl): IRDocument
diff.tsIR diff calculationdiff(prev, next): Patch

Type Hierarchy

DSL Types (user input)      IR Types (normalized)
─────────────────────       ────────────────────
DSLDocument                 IRDocument
  ├─ version: number          ├─ version: number
  ├─ docId: string            ├─ docId: string
  ├─ title?: string           ├─ title: string
  ├─ nodes: DSLNode[]         ├─ nodes: Record<string, IRNode>
  └─ edges?: DSLEdge[]        └─ edges: Record<string, IREdge>

DSLNode                     IRNode
  ├─ id: string               ├─ id: string
  ├─ provider: string         ├─ provider: string
  ├─ kind: string             ├─ kind: string
  ├─ label?: string           ├─ label: string (default: id)
  ├─ parent?: string          ├─ parent: string | null
  └─ layout: DSLLayout        └─ layout: { x, y, w, h }

DSLEdge                     IREdge
  ├─ id: string               ├─ id: string
  ├─ from: string             ├─ from: string
  ├─ to: string               ├─ to: string
  └─ label?: string           └─ label: string (default: "")

Patch Operations

type PatchOp =
  | { op: "upsertNode"; node: IRNode }
  | { op: "removeNode"; id: string }
  | { op: "upsertEdge"; edge: IREdge }
  | { op: "removeEdge"; id: string };

interface Patch {
  baseRev: number;
  nextRev: number;
  ops: PatchOp[];
}

WebSocket Protocol Types

// Plugin → CLI
interface HelloMessage {
  type: "hello";
  docId: string;
  secret?: string;
}

interface RequestFullMessage {
  type: "requestFull";
  docId: string;
}

// CLI → Plugin
interface FullMessage {
  type: "full";
  rev: number;
  ir: IRDocument;
}

interface PatchMessage {
  type: "patch";
  baseRev: number;
  nextRev: number;
  ops: PatchOp[];
}

interface ErrorMessage {
  type: "error";
  message: string;
}

Development Workflow

  1. Modify types → Update types.ts
  2. Update validation → Ensure validate.ts catches invalid input
  3. Update normalization → Handle new fields/defaults in normalize.ts
  4. Update diff → Handle new patch scenarios in diff.ts
  5. Add tests → Co-located *.test.ts files
  6. Run testsbun test packages/core/

Testing

# All core tests
bun test packages/core/

# Specific test file
bun test packages/core/src/diff.test.ts
bun test packages/core/src/validate.test.ts
bun test packages/core/src/normalize.test.ts

# Watch mode
bun test --watch packages/core/

Common Patterns

Adding a new node property

  1. Add to DSLNode and IRNode in types.ts
  2. Add validation in validate.ts
  3. Add default value handling in normalize.ts
  4. Update diff logic if property affects equality
  5. Add test cases for validation, normalization, and diff

Adding a new edge property

  1. Add to DSLEdge and IREdge in types.ts
  2. Add validation in validate.ts
  3. Add default value handling in normalize.ts
  4. Update diff logic for edge equality check
  5. Add test cases

Source

git clone https://github.com/aiskillstore/marketplace/blob/main/skills/7nohe/core-development/SKILL.mdView on GitHub

Overview

Core package development covers the essential DSL processing pipeline: validating YAML input, normalizing it into an IR, and diffing IR states to produce patches. It’s the backbone for any changes to DSL processing logic or data flow. This skill ensures the core types, validation rules, and patch logic stay in sync as the system evolves.

How This Skill Works

The core package processes DSL input through a fixed pipeline: DSL YAML input is validated, then normalized into an IRDocument, which is diffed against the previous IR to produce a Patch. The core files—types.ts, validate.ts, normalize.ts, and diff.ts—expose typed interfaces and operations; WebSocket protocol types define messaging for live synchronization. Development workflow emphasizes updating these files in tandem and adding tests to verify the full flow.

When to Use It

  • You’re adding or modifying core DSL types in types.ts (e.g., DSLNode, DSLEdge, IRNode, IREdge).
  • You need to adjust validation rules in validate.ts for new or changed DSL input constraints.
  • You’re changing DSL→IR conversion logic in normalize.ts (defaults, mappings, or field handling).
  • You’re extending patch logic in diff.ts to account for new PatchOp scenarios or edge cases.
  • You’re improving or expanding the core flow and tests in the core package (adding/co-locating tests and running the core test suite).

Quick Start

  1. Step 1: Identify the affected core files (types.ts, validate.ts, normalize.ts, diff.ts) based on the change.
  2. Step 2: Implement changes across the core files and update or add tests to cover validation, normalization, and diff.
  3. Step 3: Run the core test suite: bun test packages/core/ and iterate until all tests pass.

Best Practices

  • Keep types.ts, validate.ts, normalize.ts, and diff.ts in sync whenever you add or change fields.
  • Add or update tests co-located with core files to cover validation, normalization, and diff scenarios.
  • Run the core test suite regularly: bun test packages/core/.
  • Document new fields and default behavior in normalize.ts to avoid silent regressions.
  • Plan for backward compatibility when changing patch semantics or patch operations.

Example Use Cases

  • Add a new optional 'description' field to DSLNode and IRNode, ensure validation allows it, and populate a default label during normalization.
  • Introduce a new DSLEdge property (e.g., 'type') and implement validation, normalization defaults, and adjusted diff logic.
  • Require IRNode label to be non-optional by default and implement normalization to fallback to 'id' when missing.
  • Change IR storage from an array to a map (Record<string, IREdge>) and update diff to handle edge-equality accordingly.
  • Plan for a future patch operation (e.g., 'moveNode') by outlining changes in PatchOp types and adding placeholder tests to verify extensibility.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers