@hacksmith/doraval 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +236 -0
- package/bin/doraval-wrapper.js +28 -0
- package/bin/doraval.js +3578 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# doraval
|
|
2
|
+
|
|
3
|
+
The context engineering toolkit for coding agents.
|
|
4
|
+
|
|
5
|
+
Validate skills, plugins, hooks, MCP configs, and memory files across providers — locally or from a Git URL. Works with Claude Code today; Cursor, Codex, and Windsurf coming next.
|
|
6
|
+
|
|
7
|
+
> **Quick start:** [Install Bun](https://bun.sh), then run `bunx jsr @hacksmith/doraval validate .`
|
|
8
|
+
> Node/npm users: `npx jsr @hacksmith/doraval validate .` (Bun still required).
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Pluggable validators** — Auto-detect and validate skills, plugins, marketplaces, hooks, MCP config, subagents, commands, and memory files
|
|
13
|
+
- **Multi-provider** — Claude Code validators built in; Cursor, Codex, Windsurf planned
|
|
14
|
+
- **Remote validation** — Point at a GitHub URL instead of cloning first
|
|
15
|
+
- **Rubric drift detection** — Measure deviation across trigger phrases, voice, examples, guardrails, and clarity
|
|
16
|
+
- **AI-driven judging** — Qualitative skill assessment via LLM *(coming soon)*
|
|
17
|
+
- **CI-friendly** — JSON output and non-zero exit codes for pipeline integration
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
doraval is published on [JSR](https://jsr.io/@hacksmith/doraval) as **`@hacksmith/doraval`**.
|
|
22
|
+
|
|
23
|
+
It is **not** on the npm registry — `npx doraval` and `bunx doraval` will 404.
|
|
24
|
+
|
|
25
|
+
### 1. Install Bun (required)
|
|
26
|
+
|
|
27
|
+
doraval is a **Bun CLI**. Having Node.js installed is not enough.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
curl -fsSL https://bun.sh/install | bash # macOS/Linux
|
|
31
|
+
# Windows: https://bun.sh/docs/installation
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Requires Bun **v1.2+**.
|
|
35
|
+
|
|
36
|
+
### 2. Run doraval
|
|
37
|
+
|
|
38
|
+
**One-off (recommended)** — no global install:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Bun users
|
|
42
|
+
bunx jsr @hacksmith/doraval validate .
|
|
43
|
+
|
|
44
|
+
# Node/npm users (still requires Bun — doraval runs on Bun, not Node)
|
|
45
|
+
npx jsr @hacksmith/doraval validate .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Both commands download from JSR and invoke the CLI. The `npx` form is fine if you already use npm; you do **not** need to publish to npm.
|
|
49
|
+
|
|
50
|
+
**Aliases:** subcommands are `validate`, `skill`, `journal`, etc. (there is no separate `dora` binary on your PATH unless you add one — see below).
|
|
51
|
+
|
|
52
|
+
### `jsr add` is not a global CLI install
|
|
53
|
+
|
|
54
|
+
`npx jsr add @hacksmith/doraval` adds doraval as a **project dependency** in `package.json`. It does **not** put `dora` or `doraval` on your shell PATH. JSR’s npm compatibility layer also omits the `bin` field today, so `node_modules/.bin/doraval` is not created.
|
|
55
|
+
|
|
56
|
+
To **run** the CLI, use `npx jsr @hacksmith/doraval` (no `add`):
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx jsr @hacksmith/doraval validate .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Optional — shorthand on your PATH** (from the project where you ran `jsr add`, or anywhere):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# shell alias (add to ~/.zshrc)
|
|
66
|
+
alias dora='npx jsr @hacksmith/doraval'
|
|
67
|
+
alias doraval='npx jsr @hacksmith/doraval'
|
|
68
|
+
|
|
69
|
+
# or an npm script in package.json
|
|
70
|
+
# "doraval": "jsr @hacksmith/doraval"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### What does *not* work
|
|
74
|
+
|
|
75
|
+
| Command | Why |
|
|
76
|
+
|---------|-----|
|
|
77
|
+
| `npx doraval …` | Package is not on npmjs.org |
|
|
78
|
+
| `bunx doraval …` | Same — looks up npm, not JSR |
|
|
79
|
+
| `npx jsr add @hacksmith/doraval` then `dora` | `add` installs a library dep, not a global binary |
|
|
80
|
+
| `node …` / Deno only | CLI uses Bun APIs (`Bun.file`, etc.) |
|
|
81
|
+
|
|
82
|
+
> [!NOTE]
|
|
83
|
+
> **Node users:** use `npx jsr @hacksmith/doraval` to *fetch* the tool, but install **Bun** first to *run* it. There is no Node-native build today.
|
|
84
|
+
|
|
85
|
+
## Usage
|
|
86
|
+
|
|
87
|
+
### `validate` — Auto-detect and validate
|
|
88
|
+
|
|
89
|
+
The main command. Point it at a local directory or a Git URL, and it auto-detects what validators apply.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
dora validate . # local directory
|
|
93
|
+
dora validate https://github.com/obra/superpowers # remote repo
|
|
94
|
+
dora validate https://github.com/obra/superpowers/tree/main/skills/brainstorming # subdirectory
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Filter by provider or specific validator with `--for`:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
dora validate . --for claude # all Claude validators that match
|
|
101
|
+
dora validate . --for claude:plugin # just the plugin validator
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### Available validators (Claude)
|
|
105
|
+
|
|
106
|
+
| Validator | Detects | What it checks |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| `claude:skill` | `SKILL.md` | Frontmatter (relaxed name/desc; recommended + directory-derived command), body, supporting files, dynamic injection, substitutions, advanced fields (allowed-tools, context, etc.) |
|
|
109
|
+
| `claude:plugin` | `.claude-plugin/plugin.json` | Manifest fields, component paths, skill/command/agent dirs |
|
|
110
|
+
| `claude:marketplace` | `plugins/` with plugin subdirs | Plugin directory structure, README, LICENSE |
|
|
111
|
+
| `claude:hooks` | `hooks/hooks.json` or `hooks.json` | Valid JSON, known event names |
|
|
112
|
+
| `claude:mcp` | `.mcp.json` | Valid JSON, server definitions |
|
|
113
|
+
| `claude:subagent` | `agents/*.md` | Frontmatter with description, non-empty body (stricter than skills) |
|
|
114
|
+
| `claude:command` | `commands/*.md` | Frontmatter with description, body; supports advanced fields (allowed-tools, context, when_to_use, etc.) |
|
|
115
|
+
| `claude:memory` | `CLAUDE.md` | Non-empty, length limit, @path import resolution |
|
|
116
|
+
|
|
117
|
+
#### Remote URLs
|
|
118
|
+
|
|
119
|
+
`dora validate` accepts GitHub URLs (and any Git URL). It clones the repo to a temp directory, validates, and cleans up. For GitHub repos, it tries `gh` first (handles private repos via your existing auth), then falls back to `git clone`.
|
|
120
|
+
|
|
121
|
+
Supported URL forms:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
dora validate https://github.com/owner/repo
|
|
125
|
+
dora validate https://github.com/owner/repo/tree/branch
|
|
126
|
+
dora validate https://github.com/owner/repo/tree/main/sub/dir
|
|
127
|
+
dora validate github.com/owner/repo # shorthand
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### `skill validate` — Structural checks (single skill)
|
|
131
|
+
|
|
132
|
+
Validate a single skill directory. This is the original command and continues to work unchanged.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
dora skill validate ./skills/my-skill/
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
doraval skill validate — Structural validation
|
|
140
|
+
|
|
141
|
+
Path: ./skills/my-skill/
|
|
142
|
+
|
|
143
|
+
✓ YAML frontmatter present and parseable
|
|
144
|
+
✓ name: "my-skill"
|
|
145
|
+
✓ description field present
|
|
146
|
+
✓ Markdown body is non-empty
|
|
147
|
+
✓ references/ directory exists
|
|
148
|
+
✓ advanced frontmatter: allowed-tools, context
|
|
149
|
+
✓ uses dynamic context injection (!`...` or ```! blocks)
|
|
150
|
+
|
|
151
|
+
Result: 0 error(s), 0 warning(s)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
> Note: `name` and `description` are recommended (not hard requirements). Missing them produces warnings rather than errors. The directory name usually provides the invocable `/command`.
|
|
155
|
+
|
|
156
|
+
### `skill drift` — Rubric deviation
|
|
157
|
+
|
|
158
|
+
Measure how far a skill has drifted from known-good rubric standards. Each check maps to a drift category:
|
|
159
|
+
|
|
160
|
+
| Category | What it checks |
|
|
161
|
+
|---|---|
|
|
162
|
+
| **Trigger** | Description or `when_to_use` includes activation phrases (`Use when...`) |
|
|
163
|
+
| **Structure** | Body has numbered steps or checklists |
|
|
164
|
+
| **Voice** | Uses imperative language (`Create`, `Run`, `Ensure`) |
|
|
165
|
+
| **Example** | Contains code blocks |
|
|
166
|
+
| **Guardrail** | Has explicit `MUST` / `MUST NOT` constraints |
|
|
167
|
+
| **Clarity** | Free of ambiguous words (`maybe`, `perhaps`, `consider`) |
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
dora skill drift ./skills/my-skill/
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
doraval skill drift — Measuring rubric drift
|
|
175
|
+
|
|
176
|
+
Path: ./skills/my-skill/
|
|
177
|
+
|
|
178
|
+
· Trigger Description includes activation phrases
|
|
179
|
+
· Structure Has step-by-step instructions
|
|
180
|
+
· Voice Uses imperative voice ("Do X" not "You might X")
|
|
181
|
+
↗ Example No code blocks found — add examples if the skill involves code
|
|
182
|
+
↗ Guardrail No explicit constraints — add MUST / MUST NOT guardrails
|
|
183
|
+
· Clarity No ambiguous language found
|
|
184
|
+
|
|
185
|
+
2/6 rubric areas have drifted.
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `skill judge` — AI-driven assessment
|
|
189
|
+
|
|
190
|
+
> [!WARNING]
|
|
191
|
+
> Not yet implemented. This command will send the skill to an LLM for qualitative review of clarity, completeness, and effectiveness.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
dora skill judge ./skills/my-skill/
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Options
|
|
198
|
+
|
|
199
|
+
| Flag | Short | Description |
|
|
200
|
+
|---|---|---|
|
|
201
|
+
| `--format <type>` | `-f` | Output format: `table` (default) or `json` |
|
|
202
|
+
| `--for <spec>` | | Target a provider (`claude`) or specific validator (`claude:plugin`) |
|
|
203
|
+
| `--verbose` | `-v` | Show detailed diagnostics |
|
|
204
|
+
| `--ci` | | Machine-friendly output, non-zero exit on issues |
|
|
205
|
+
|
|
206
|
+
### CI/CD integration
|
|
207
|
+
|
|
208
|
+
Use `--format json` and `--ci` for pipeline-friendly output:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
dora validate . --for claude --format json --ci
|
|
212
|
+
dora skill validate ./my-skill/ --format json --ci
|
|
213
|
+
dora skill drift ./my-skill/ --format json --ci
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`validate` exits with code `1` when errors are found. Commands write structured JSON to stdout when `--format json` is set — pipe it to `jq` or consume it programmatically.
|
|
217
|
+
|
|
218
|
+
## `journal` — Decision memory with pushback
|
|
219
|
+
|
|
220
|
+
Record, view, and sync project principles and decisions so that future you (and agents) don't accidentally contradict past choices.
|
|
221
|
+
|
|
222
|
+
The journal lives in a private GitHub repo you control (by convention `yourname/yourname.md`). All config and cache lives under `~/.doraval/`.
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
dora init # Recommended: set up journal + the coding agent dora will use on the fly for rich `add`
|
|
226
|
+
dora journal list # View active principles
|
|
227
|
+
dora journal update # Pull latest from the remote into local cache
|
|
228
|
+
dora journal add "..." # Propose a decision/note (or long rich markdown via --raw-markdown); staged locally; uses configured agent when input is minimal
|
|
229
|
+
dora journal sync # Publish pending entries + refresh cache
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
`update` is the recommended way to keep your local mirror fresh (e.g. at the start of a session or before `skill drift`).
|
|
233
|
+
|
|
234
|
+
Requires the GitHub CLI (`gh`) for talking to the remote journal repo.
|
|
235
|
+
|
|
236
|
+
See the docs site for full details and rationale.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync, spawnSync } from 'node:child_process'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { join, dirname } from 'node:path'
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
execSync('bun --version', { stdio: 'ignore' })
|
|
10
|
+
} catch {
|
|
11
|
+
console.error(
|
|
12
|
+
'doraval requires the Bun runtime.\n\n' +
|
|
13
|
+
'Install Bun (~10s):\n' +
|
|
14
|
+
' curl -fsSL https://bun.sh/install | bash\n\n' +
|
|
15
|
+
'Then run:\n' +
|
|
16
|
+
' bunx doraval'
|
|
17
|
+
)
|
|
18
|
+
process.exit(1)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const cli = join(__dirname, 'doraval.js')
|
|
22
|
+
|
|
23
|
+
const result = spawnSync('bun', [cli, ...process.argv.slice(2)], { stdio: 'inherit' })
|
|
24
|
+
if (result.error) {
|
|
25
|
+
console.error('Failed to execute Bun:', result.error.message)
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
process.exit(result.status ?? (result.signal ? 128 : 1))
|