wicked-vault 0.2.0 → 0.3.0
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 +20 -5
- package/bin/wicked-vault.mjs +46 -0
- package/install.mjs +33 -2
- package/package.json +1 -1
- package/skills/wicked-vault/update/SKILL.md +140 -0
- package/src/bus.mjs +45 -7
package/README.md
CHANGED
|
@@ -51,14 +51,20 @@ config root (Claude Code, Gemini, Copilot, Codex, Cursor, Kiro, Antigravity):
|
|
|
51
51
|
npx wicked-vault-install # detect and install everywhere
|
|
52
52
|
npx wicked-vault-install --cli=claude # one CLI only (comma-separated for several)
|
|
53
53
|
npx wicked-vault-install --path ~/.claude # a specific config root
|
|
54
|
+
npx wicked-vault-install --help # options
|
|
54
55
|
```
|
|
55
56
|
|
|
56
57
|
This mirrors the shared wicked-bus / wicked-brain installer: `$CLAUDE_CONFIG_DIR`
|
|
57
58
|
is honored, alt-config layouts are probed, and skills land as
|
|
58
|
-
`wicked-vault-{init,record-evidence,verify-evidence,analyze-evidence,cross-check-evidence}/`
|
|
59
|
+
`wicked-vault-{init,record-evidence,verify-evidence,analyze-evidence,cross-check-evidence,update}/`
|
|
59
60
|
under each CLI's `skills/`. If wicked-bus is installed, the installer also
|
|
60
61
|
registers the vault as a bus provider (see below).
|
|
61
62
|
|
|
63
|
+
**Updating:** say `wicked-vault:update` to your agent, or run
|
|
64
|
+
`npm install -g wicked-vault@latest && npx wicked-vault-install` — it compares
|
|
65
|
+
your version against npm and refreshes the skills across every CLI. Both
|
|
66
|
+
binaries support `--help`.
|
|
67
|
+
|
|
62
68
|
## CLI
|
|
63
69
|
|
|
64
70
|
```bash
|
|
@@ -121,6 +127,10 @@ isn't — or when `WICKED_VAULT_NO_BUS=1` is set — emission is a silent no-op
|
|
|
121
127
|
the CLI behaves identically. A bus error never changes a verdict, the JSON on
|
|
122
128
|
stdout, or an exit code.
|
|
123
129
|
|
|
130
|
+
Proven end-to-end: `test/bus-integration.sh` drives the vault into a **real**
|
|
131
|
+
wicked-bus (db isolated to a temp dir) and reads every event back off the bus —
|
|
132
|
+
and runs in CI on every push.
|
|
133
|
+
|
|
124
134
|
| Command | event_type | subdomain | key payload |
|
|
125
135
|
|---|---|---|---|
|
|
126
136
|
| `record` | `wicked.evidence.recorded` | `vault.record` | scope, phase, claim_id, kind, id, envelope_hash |
|
|
@@ -167,10 +177,15 @@ evaluator may cite — not the whole story. Nondeterministic observation verifie
|
|
|
167
177
|
npm run prove # record -> tamper -> verify-rejects on a real repo
|
|
168
178
|
bash test/verifiers.sh # the 5 verifiers, pass + fail cases
|
|
169
179
|
bash test/attestation.sh # criteria-binding, attest fail-closed/independence, require_attestation
|
|
170
|
-
bash test/bus-integration.sh # graceful no-op +
|
|
180
|
+
bash test/bus-integration.sh # graceful no-op + schema validity + real-bus emission (init/record/attest/cross-check)
|
|
171
181
|
```
|
|
172
182
|
|
|
173
|
-
|
|
183
|
+
`attestation.sh` and `bus-integration.sh` are the gating proofs and run in CI
|
|
184
|
+
(`.github/workflows/ci.yml`) on ubuntu + macos, with a Windows CLI smoke.
|
|
185
|
+
|
|
186
|
+
Status: v0.3.0 — deterministic core proven on real repos; criteria-binding +
|
|
174
187
|
independent judgment tier (ADR-0002, council 5–0) implemented and proven;
|
|
175
|
-
wicked-bus
|
|
176
|
-
|
|
188
|
+
wicked-bus integration **proven end-to-end against a real bus** (emit → store →
|
|
189
|
+
poll), optional and fire-and-forget; `--help` on both binaries + a
|
|
190
|
+
`wicked-vault:update` skill. Not yet implemented:
|
|
191
|
+
`pr_check_status`/`http_status_eq` and the sqlite query cache.
|
package/bin/wicked-vault.mjs
CHANGED
|
@@ -33,7 +33,53 @@ function emit(obj, ok) {
|
|
|
33
33
|
process.exit(ok ? 0 : 1);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
const HELP = `wicked-vault — local-first evidence primitive
|
|
37
|
+
Record evidence with the acceptance criteria it must clear, re-derive integrity
|
|
38
|
+
deterministically, and record independent third-party judgments. Never trusts a
|
|
39
|
+
stored verdict; never lets work self-grade its own "done".
|
|
40
|
+
|
|
41
|
+
USAGE
|
|
42
|
+
wicked-vault <command> [options]
|
|
43
|
+
|
|
44
|
+
COMMANDS
|
|
45
|
+
init Create .wicked-vault/ in the current repo
|
|
46
|
+
record Capture evidence + the criteria it must clear
|
|
47
|
+
--scope S --phase P --claim C --kind K --source "<cmd|file>"
|
|
48
|
+
--criteria "<text|@file>" (--run | --artifact <file>) [--verifier "kind:arg"]
|
|
49
|
+
verify <artifact-id> Integrity tier: re-derive hashes + verifier (deterministic,
|
|
50
|
+
model-free). Exit 0 iff intact AND pass. Surfaces latest opinion.
|
|
51
|
+
inspect <artifact-id> Frozen criteria + evidence + integrity (what a judge evaluates)
|
|
52
|
+
attest <artifact-id> Record an INDEPENDENT judgment (fail-closed; evaluator != creator)
|
|
53
|
+
--opinion <pass|reject|unclear> --rationale "..." --evaluator ID
|
|
54
|
+
[--model prov/ver] [--prompt-hash H] [--sampling '<json>']
|
|
55
|
+
attestations <artifact-id> Show the append-only opinion log
|
|
56
|
+
cross-check Mechanical contract verdict; exit 0 iff PASS
|
|
57
|
+
--scope S --phase P [--integrity-only (default) | --with-attestations]
|
|
58
|
+
declare-contract Pin a contract --scope S --phase P --spec <file>
|
|
59
|
+
supersede <old-id> Append-only replacement (same flags as record)
|
|
60
|
+
list --scope S [--phase P]
|
|
61
|
+
|
|
62
|
+
GLOBAL
|
|
63
|
+
--cwd <dir> Operate on a vault rooted at <dir> (default: walk up from cwd)
|
|
64
|
+
--help, -h Show this help
|
|
65
|
+
|
|
66
|
+
OUTPUT JSON on stdout; exit code is the gate signal (0 = PASS / success).
|
|
67
|
+
ENV WICKED_VAULT_NO_BUS=1 Disable optional wicked-bus event emission
|
|
68
|
+
|
|
69
|
+
Skills (AI CLIs): wicked-vault:{init,record-evidence,verify-evidence,analyze-evidence,cross-check-evidence,update}
|
|
70
|
+
Install skills: npx wicked-vault-install (run with --help for options)
|
|
71
|
+
Docs: https://github.com/mikeparcewski/wicked-vault
|
|
72
|
+
`;
|
|
73
|
+
|
|
36
74
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
75
|
+
|
|
76
|
+
// Help / no-command: print usage to stdout and exit 0 — before any vault or bus
|
|
77
|
+
// work, so `--help` works outside a repo and never errors.
|
|
78
|
+
if (cmd === undefined || cmd === '--help' || cmd === '-h' || cmd === 'help') {
|
|
79
|
+
process.stdout.write(HELP);
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
|
|
37
83
|
const args = parseArgs(rest);
|
|
38
84
|
const cwd = (typeof args.cwd === 'string' && args.cwd) || process.cwd();
|
|
39
85
|
|
package/install.mjs
CHANGED
|
@@ -64,10 +64,41 @@ const CLI_TARGETS = [
|
|
|
64
64
|
{ name: "antigravity", dir: join(home, ".antigravity", "skills"), platform: "antigravity" },
|
|
65
65
|
];
|
|
66
66
|
|
|
67
|
-
console.log("wicked-vault installer\n");
|
|
68
|
-
|
|
69
67
|
const args = argv.slice(2);
|
|
70
68
|
|
|
69
|
+
// Help: print usage and exit 0 before doing any detection or filesystem work.
|
|
70
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
71
|
+
process.stdout.write(`wicked-vault-install — install wicked-vault skills into your AI CLIs/IDEs
|
|
72
|
+
|
|
73
|
+
Copies the wicked-vault skills into every detected CLI config root so your
|
|
74
|
+
agent knows how to use the vault. Also registers wicked-vault as a wicked-bus
|
|
75
|
+
provider when the bus is available.
|
|
76
|
+
|
|
77
|
+
USAGE
|
|
78
|
+
npx wicked-vault-install [options]
|
|
79
|
+
|
|
80
|
+
OPTIONS
|
|
81
|
+
(no options) Detect and install into every supported CLI found
|
|
82
|
+
--cli=<name> Install into one CLI only (comma-separated for several),
|
|
83
|
+
e.g. --cli=claude or --cli=claude,cursor
|
|
84
|
+
--path=<dir> Install into a specific config root, e.g. --path=~/.claude
|
|
85
|
+
--help, -h Show this help
|
|
86
|
+
|
|
87
|
+
SUPPORTED CLIs claude, gemini, copilot, codex, cursor, kiro, antigravity
|
|
88
|
+
(\$CLAUDE_CONFIG_DIR is honored; alt-config layouts are probed)
|
|
89
|
+
|
|
90
|
+
INSTALLS (per CLI, under skills/)
|
|
91
|
+
wicked-vault-init · -record-evidence · -verify-evidence · -analyze-evidence
|
|
92
|
+
· -cross-check-evidence · -update
|
|
93
|
+
|
|
94
|
+
To update later: npm install -g wicked-vault@latest && npx wicked-vault-install
|
|
95
|
+
(or just say "wicked-vault:update" to your agent)
|
|
96
|
+
`);
|
|
97
|
+
process.exit(0);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log("wicked-vault installer\n");
|
|
101
|
+
|
|
71
102
|
// Flag parser supporting both --flag=value and --flag value forms, plus
|
|
72
103
|
// narrow string-boolean coercion ("true" / "false" → booleans). The ad-hoc
|
|
73
104
|
// parser this replaces silently dropped space-separated values — same bug
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wicked-vault",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Local-first evidence primitive — record evidence with its acceptance criteria, re-derive integrity deterministically, and record independent third-party judgments. Never trusts a stored verdict, never lets work self-grade its own \"done\".",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wicked-vault:update
|
|
3
|
+
description: |
|
|
4
|
+
Check for and install wicked-vault updates. Compares the installed version
|
|
5
|
+
against the npm registry, updates the published CLI, and refreshes the skills
|
|
6
|
+
across all detected AI CLIs (Claude Code, Gemini, Copilot, Codex, Cursor,
|
|
7
|
+
Kiro, Antigravity).
|
|
8
|
+
|
|
9
|
+
Use when: "update wicked-vault", "check for vault updates", "wicked-vault update",
|
|
10
|
+
or periodically to stay current.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# wicked-vault:update
|
|
14
|
+
|
|
15
|
+
Check for and install updates to wicked-vault and its skills.
|
|
16
|
+
|
|
17
|
+
## Cross-Platform Notes
|
|
18
|
+
|
|
19
|
+
Commands work on macOS, Linux, and Windows. Prefer agent-native tools
|
|
20
|
+
(Read, Write, Grep, Glob) over shell where possible. JSON parsing uses
|
|
21
|
+
`python3 … || python …` so it runs on macOS, Linux, WSL, and Git Bash.
|
|
22
|
+
|
|
23
|
+
## When to use
|
|
24
|
+
|
|
25
|
+
- User asks to update or check for updates.
|
|
26
|
+
- After unexpected behavior that might be fixed in a newer version.
|
|
27
|
+
- Periodically (suggest checking monthly).
|
|
28
|
+
|
|
29
|
+
## Process
|
|
30
|
+
|
|
31
|
+
### Step 1 — Check the installed version
|
|
32
|
+
|
|
33
|
+
Global install:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm list -g wicked-vault --json 2>/dev/null | python3 -c "
|
|
37
|
+
import json, sys
|
|
38
|
+
try:
|
|
39
|
+
d = json.load(sys.stdin)
|
|
40
|
+
print(d.get('dependencies', {}).get('wicked-vault', {}).get('version', 'not installed'))
|
|
41
|
+
except Exception:
|
|
42
|
+
print('not installed')
|
|
43
|
+
" 2>/dev/null || npm list -g wicked-vault --json 2>/dev/null | python -c "
|
|
44
|
+
import json, sys
|
|
45
|
+
try:
|
|
46
|
+
d = json.load(sys.stdin)
|
|
47
|
+
print(d.get('dependencies', {}).get('wicked-vault', {}).get('version', 'not installed'))
|
|
48
|
+
except Exception:
|
|
49
|
+
print('not installed')
|
|
50
|
+
"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Also check a local (project-level) install:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm list wicked-vault --json 2>/dev/null
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If neither is installed, the user may be running via `npx wicked-vault@latest`
|
|
60
|
+
(always current) — note that and skip to Step 5 to (re)install skills.
|
|
61
|
+
|
|
62
|
+
### Step 2 — Check the latest version on npm
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm view wicked-vault version 2>/dev/null
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Step 3 — Compare
|
|
69
|
+
|
|
70
|
+
- Up to date: "wicked-vault is up to date (v{version})."
|
|
71
|
+
- Update available: "wicked-vault v{new} is available (you have v{current}). Update now?"
|
|
72
|
+
|
|
73
|
+
If the user only wanted to check, stop here and report current vs. available.
|
|
74
|
+
|
|
75
|
+
### Step 4 — Update the package (if approved)
|
|
76
|
+
|
|
77
|
+
Global:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm install -g wicked-vault@latest 2>&1
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Local (project):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm install wicked-vault@latest 2>&1
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If `EACCES` / permission denied:
|
|
90
|
+
- macOS/Linux: `sudo npm install -g wicked-vault@latest`
|
|
91
|
+
- Windows: re-run the shell as Administrator
|
|
92
|
+
- Report the failure — do NOT silently skip.
|
|
93
|
+
|
|
94
|
+
### Step 5 — Refresh the skills in all CLIs
|
|
95
|
+
|
|
96
|
+
After updating the package, re-run the installer to copy the updated skills
|
|
97
|
+
into every detected CLI:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npx wicked-vault-install
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Or target one CLI:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npx wicked-vault-install --cli=claude
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
(The installer is idempotent — re-running overwrites the installed skills with
|
|
110
|
+
the current version and re-registers the wicked-bus provider if the bus is
|
|
111
|
+
present.)
|
|
112
|
+
|
|
113
|
+
### Step 6 — Verify
|
|
114
|
+
|
|
115
|
+
Re-run the Step 1 version check and confirm it matches latest. Also confirm the
|
|
116
|
+
CLI runs:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npx wicked-vault --help | head -1
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
If it still shows the old version:
|
|
123
|
+
1. `which wicked-vault` (macOS/Linux) or `where wicked-vault` (Windows).
|
|
124
|
+
2. `npm cache clean --force`.
|
|
125
|
+
3. Check whether nvm / fnm / volta is pinning a stale copy.
|
|
126
|
+
|
|
127
|
+
### Step 7 — Report
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
wicked-vault updated: v{old} → v{new}
|
|
131
|
+
Skills refreshed in {N} CLIs: {list}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Notes
|
|
135
|
+
|
|
136
|
+
- wicked-vault has **no background server** to update (unlike wicked-brain) —
|
|
137
|
+
updating is just the package + the skills.
|
|
138
|
+
- The published package is provenance-signed; `npm view wicked-vault --json`
|
|
139
|
+
shows the attestation under `dist.attestations` if you want to confirm
|
|
140
|
+
supply-chain integrity after updating.
|
package/src/bus.mjs
CHANGED
|
@@ -9,18 +9,49 @@
|
|
|
9
9
|
//
|
|
10
10
|
// Opt out entirely with WICKED_VAULT_NO_BUS=1.
|
|
11
11
|
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
12
13
|
import { createRequire } from 'node:module';
|
|
13
14
|
import { pathToFileURL } from 'node:url';
|
|
14
|
-
import { join } from 'node:path';
|
|
15
|
+
import { join, dirname } from 'node:path';
|
|
15
16
|
|
|
16
17
|
const DOMAIN = 'wicked-vault';
|
|
17
18
|
|
|
19
|
+
// Given a resolved file inside a package, return its ESM ("import") entry.
|
|
20
|
+
// `require.resolve()` applies the "require" condition, so for a dual-published
|
|
21
|
+
// package it returns the CJS entry — and wicked-bus ships a CJS *shim* with no
|
|
22
|
+
// real exports (importing it yields `emit: undefined`). We must read the
|
|
23
|
+
// package.json and import the ESM entry instead. (`require.resolve` can't fetch
|
|
24
|
+
// package.json directly when "exports" doesn't expose it, so walk up to the
|
|
25
|
+
// package root and read it from disk.)
|
|
26
|
+
function esmEntryForPackage(resolvedFile) {
|
|
27
|
+
let dir = dirname(resolvedFile);
|
|
28
|
+
for (let i = 0; i < 10; i++) {
|
|
29
|
+
const pj = join(dir, 'package.json');
|
|
30
|
+
if (existsSync(pj)) {
|
|
31
|
+
let pkg;
|
|
32
|
+
try { pkg = JSON.parse(readFileSync(pj, 'utf8')); } catch { return null; }
|
|
33
|
+
const dot = pkg.exports && pkg.exports['.'] !== undefined ? pkg.exports['.'] : pkg.exports;
|
|
34
|
+
const rel =
|
|
35
|
+
(dot && typeof dot === 'object' && (dot.import || dot.default)) ||
|
|
36
|
+
(typeof dot === 'string' ? dot : null) ||
|
|
37
|
+
pkg.module || pkg.main || 'index.js';
|
|
38
|
+
return join(dir, rel);
|
|
39
|
+
}
|
|
40
|
+
const parent = dirname(dir);
|
|
41
|
+
if (parent === dir) break;
|
|
42
|
+
dir = parent;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
18
47
|
// Resolve the wicked-bus module namespace, or null. Two layers, in order:
|
|
19
48
|
// 1. bare specifier — works when wicked-bus is installed globally or hoisted
|
|
20
|
-
// alongside the vault.
|
|
49
|
+
// alongside the vault. import() uses the ESM condition, so it returns the
|
|
50
|
+
// real module.
|
|
21
51
|
// 2. the consumer project's node_modules (anchored at cwd) — the common case,
|
|
22
52
|
// since sibling tools live in the same repo the vault is invoked from, and
|
|
23
|
-
// the vault itself ships no node_modules.
|
|
53
|
+
// the vault itself ships no node_modules. require.resolve locates the
|
|
54
|
+
// package; we import its ESM entry so we get real exports, not a CJS shim.
|
|
24
55
|
async function resolveBus(cwd) {
|
|
25
56
|
try {
|
|
26
57
|
return await import('wicked-bus');
|
|
@@ -29,8 +60,9 @@ async function resolveBus(cwd) {
|
|
|
29
60
|
}
|
|
30
61
|
try {
|
|
31
62
|
const require = createRequire(join(cwd, '__vault_bus_anchor__.js'));
|
|
32
|
-
const
|
|
33
|
-
|
|
63
|
+
const located = require.resolve('wicked-bus');
|
|
64
|
+
const esm = esmEntryForPackage(located) || located;
|
|
65
|
+
return await import(pathToFileURL(esm).href);
|
|
34
66
|
} catch {
|
|
35
67
|
return null;
|
|
36
68
|
}
|
|
@@ -49,9 +81,15 @@ export async function initBus(cwd = process.cwd()) {
|
|
|
49
81
|
if (process.env.WICKED_VAULT_NO_BUS === '1') return NOOP;
|
|
50
82
|
|
|
51
83
|
const bus = await resolveBus(cwd);
|
|
52
|
-
|
|
53
|
-
|
|
84
|
+
// Defensive capability check — a pathological module (e.g. a CJS shim whose
|
|
85
|
+
// property access throws) must degrade to a no-op, never crash the vault.
|
|
86
|
+
let usable = false;
|
|
87
|
+
try {
|
|
88
|
+
usable = !!bus && typeof bus.emit === 'function' && typeof bus.openDb === 'function';
|
|
89
|
+
} catch {
|
|
90
|
+
usable = false;
|
|
54
91
|
}
|
|
92
|
+
if (!usable) return NOOP;
|
|
55
93
|
|
|
56
94
|
let db;
|
|
57
95
|
let config;
|