wicked-vault 0.2.0 → 0.2.1

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.
Files changed (3) hide show
  1. package/README.md +12 -4
  2. package/package.json +1 -1
  3. package/src/bus.mjs +45 -7
package/README.md CHANGED
@@ -121,6 +121,10 @@ isn't — or when `WICKED_VAULT_NO_BUS=1` is set — emission is a silent no-op
121
121
  the CLI behaves identically. A bus error never changes a verdict, the JSON on
122
122
  stdout, or an exit code.
123
123
 
124
+ Proven end-to-end: `test/bus-integration.sh` drives the vault into a **real**
125
+ wicked-bus (db isolated to a temp dir) and reads every event back off the bus —
126
+ and runs in CI on every push.
127
+
124
128
  | Command | event_type | subdomain | key payload |
125
129
  |---|---|---|---|
126
130
  | `record` | `wicked.evidence.recorded` | `vault.record` | scope, phase, claim_id, kind, id, envelope_hash |
@@ -167,10 +171,14 @@ evaluator may cite — not the whole story. Nondeterministic observation verifie
167
171
  npm run prove # record -> tamper -> verify-rejects on a real repo
168
172
  bash test/verifiers.sh # the 5 verifiers, pass + fail cases
169
173
  bash test/attestation.sh # criteria-binding, attest fail-closed/independence, require_attestation
170
- bash test/bus-integration.sh # graceful no-op + event validity + emission (incl. attested)
174
+ bash test/bus-integration.sh # graceful no-op + schema validity + real-bus emission (init/record/attest/cross-check)
171
175
  ```
172
176
 
173
- Status: v0.2.0 deterministic core proven on real repos; criteria-binding +
177
+ `attestation.sh` and `bus-integration.sh` are the gating proofs and run in CI
178
+ (`.github/workflows/ci.yml`) on ubuntu + macos, with a Windows CLI smoke.
179
+
180
+ Status: v0.2.1 — deterministic core proven on real repos; criteria-binding +
174
181
  independent judgment tier (ADR-0002, council 5–0) implemented and proven;
175
- wicked-bus emission + provider registration (optional, fire-and-forget). Not yet
176
- implemented: `pr_check_status`/`http_status_eq` and the sqlite query cache.
182
+ wicked-bus integration **proven end-to-end against a real bus** (emit store
183
+ poll), optional and fire-and-forget. Not yet implemented:
184
+ `pr_check_status`/`http_status_eq` and the sqlite query cache.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-vault",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
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": {
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 entry = require.resolve('wicked-bus');
33
- return await import(pathToFileURL(entry).href);
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
- if (!bus || typeof bus.emit !== 'function' || typeof bus.openDb !== 'function') {
53
- return NOOP;
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;