wicked-garden 12.53.0 → 12.53.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.
@@ -1 +1 @@
1
- {"name": "wicked-garden", "owner": {"name": "Mike Parcewski"}, "plugins": [{"name": "wicked-garden", "source": "./", "description": "Your coding agent already plans and swarms \u2014 Wicked Garden is the curated toolkit for what it can't: proof-not-claims gates, code links grep can't see, deterministic refactor, cross-session memory, multi-model second opinions (fallback seats labelled). Don't fight the harness; fill its gaps. The gate needs wicked-vault (a self-contained infra peer, installed directly) and re-derives through garden's built-in engine; estate/bus are opt-in layers (wicked-testing and wicked-brain are retired \u2014 QE ships in-catalog as the qe domain, memory lives in wicked-estate).", "version": "12.53.0"}], "version": "12.53.0"}
1
+ {"name": "wicked-garden", "owner": {"name": "Mike Parcewski"}, "plugins": [{"name": "wicked-garden", "source": "./", "description": "Your coding agent already plans and swarms \u2014 Wicked Garden is the curated toolkit for what it can't: proof-not-claims gates, code links grep can't see, deterministic refactor, cross-session memory, multi-model second opinions (fallback seats labelled). Don't fight the harness; fill its gaps. The gate needs wicked-vault (a self-contained infra peer, installed directly) and re-derives through garden's built-in engine; estate/bus are opt-in layers (wicked-testing and wicked-brain are retired \u2014 QE ships in-catalog as the qe domain, memory lives in wicked-estate).", "version": "12.53.1"}], "version": "12.53.1"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-garden",
3
- "version": "12.53.0",
3
+ "version": "12.53.1",
4
4
  "description": "Your coding agent's harness already plans and swarms; Wicked Garden is the curated toolkit for what it can't do alone. Proof, not claims \u2014 gates re-derive 'done' through the internal loom engine (fail-closed, independently attested via wicked-vault), so a self-asserted pass can't lie its way green. Relationships grep can't see \u2014 the wicked-estate code graph + injected bus/dispatch/capability/archetype edges power blast-radius & lineage. Plus deterministic multi-file refactor (wicked-patch), cross-session memory + knowledge (the mem domain over wicked-estate), multi-model second opinions (fallback seats labelled) (jam:council), portable expertise as on-demand skill-refs, and evidence-gated testing (the in-catalog qe domain). It reads the shape of your work to apply the right rigor \u2014 steering, not a pipeline \u2014 then gets out of the way. The compiler stamps a self-contained evidence gate into any repo that runs with no wicked-garden installed. Don't fight the harness; fill its gaps. The evidence gate requires wicked-vault, a self-contained infra peer wicked-garden installs directly; wicked-bus is an opt-in layer \u2014 install what you'll use, the toolkit works without the rest.",
5
5
  "wicked_vault_version": "^0.5.0",
6
6
  "wicked_ledger_version": "^0.6.0",
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [12.53.1] — 2026-10-11
6
+
7
+ ### Fixed
8
+ - **One wicked-ledger resolver, `$WICKED_LEDGER_PKG_DIR` first (PR #1284, crew#951).** `wicked-garden-qe` accept, the gate and the campaign scoreboard resolve wicked-ledger through one resolver that honours `$WICKED_LEDGER_PKG_DIR` first (wicked-crew 0.9.7 sets it for a governed run), so a governed QE unit records its verdict without the repository installing wicked-ledger.
9
+ - **Learn: the author computes claim ids (PR #1288, E2E F-LEARN-1);** synthesize leaves them.
10
+
5
11
  ## [12.53.0] — 2026-10-11
6
12
 
7
13
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-garden",
3
- "version": "12.53.0",
3
+ "version": "12.53.1",
4
4
  "type": "module",
5
5
  "description": "Curated toolkit for what AI coding agents can't do alone: evidence-gated work, codegraph relationships, deterministic multi-file refactor, multi-model second opinions, and cross-session memory. Installs as a Claude Code plugin.",
6
6
  "keywords": [
@@ -93,6 +93,7 @@
93
93
  import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
94
94
  import { join, dirname, resolve, isAbsolute } from "node:path";
95
95
  import { pathToFileURL } from "node:url";
96
+ import { resolveLedgerModule } from "./ledger-pkg.mjs";
96
97
  import { parseArgs } from "node:util";
97
98
 
98
99
  import {
@@ -168,54 +169,9 @@ export function resolveLedgerRootLocal(repoRoot, env = process.env) {
168
169
  return current;
169
170
  }
170
171
 
171
- // --- wicked-ledger resolution (target-repo-anchored, like gate.mjs) ----------
172
-
173
- function esmEntryForPackageDir(pkgDir) {
174
- const pj = join(pkgDir, "package.json");
175
- if (!existsSync(pj)) return null;
176
- const pkg = readJsonSafe(pj);
177
- if (!pkg) return null;
178
- const dot = pkg.exports && pkg.exports["."] !== undefined ? pkg.exports["."] : pkg.exports;
179
- const rel =
180
- (dot && typeof dot === "object" && (dot.import || dot.default)) ||
181
- (typeof dot === "string" ? dot : null) ||
182
- pkg.module ||
183
- pkg.main ||
184
- "index.js";
185
- return join(pkgDir, rel);
186
- }
172
+ // --- wicked-ledger resolution: the shared resolver (./ledger-pkg.mjs) -----------
187
173
 
188
- export async function resolveLedgerModule(repoRoot, env = process.env) {
189
- // 1. explicit override (tests, TH-6 wiring, unpublished-floor installs)
190
- if (env.WICKED_LEDGER_PKG_DIR) {
191
- const entry = esmEntryForPackageDir(env.WICKED_LEDGER_PKG_DIR);
192
- if (entry && existsSync(entry)) return await import(pathToFileURL(entry).href);
193
- return null;
194
- }
195
- // 2. bare import (global / hoisted install)
196
- try {
197
- return await import("wicked-ledger");
198
- } catch {
199
- /* fall through */
200
- }
201
- // 3. walk up from the target repo root
202
- let dir = resolve(repoRoot);
203
- for (let i = 0; i < 10; i++) {
204
- const cand = join(dir, "node_modules", "wicked-ledger");
205
- const entry = esmEntryForPackageDir(cand);
206
- if (entry && existsSync(entry)) {
207
- try {
208
- return await import(pathToFileURL(entry).href);
209
- } catch {
210
- return null;
211
- }
212
- }
213
- const parent = dirname(dir);
214
- if (parent === dir) break;
215
- dir = parent;
216
- }
217
- return null;
218
- }
174
+ export { resolveLedgerModule } from "./ledger-pkg.mjs";
219
175
 
220
176
  // --- evidence extraction ------------------------------------------------------
221
177
 
@@ -83,50 +83,15 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
83
83
  import { join, dirname, isAbsolute } from "node:path";
84
84
  import { spawnSync } from "node:child_process";
85
85
  import { createHash } from "node:crypto";
86
- import { createRequire } from "node:module";
87
86
  import { pathToFileURL } from "node:url";
88
87
  import { parseArgs } from "node:util";
89
88
 
90
89
  import { buildExclusionsClause } from "./flake-policy.mjs";
91
90
  import { resolveVaultModule, applyVaultIntegrity, VaultEvidenceError } from "./vault-evidence.mjs";
92
91
  import { crewRunStamp } from "./crew-run.mjs";
92
+ import { resolveLedgerModule } from "./ledger-pkg.mjs";
93
93
 
94
- // --- wicked-ledger resolution (cwd-anchored; mirrors wicked-vault's bus.mjs) ---
95
-
96
- function esmEntryForPackage(resolvedFile) {
97
- let dir = dirname(resolvedFile);
98
- for (let i = 0; i < 10; i++) {
99
- const pj = join(dir, "package.json");
100
- if (existsSync(pj)) {
101
- let pkg;
102
- try { pkg = JSON.parse(readFileSync(pj, "utf8")); } catch { return null; }
103
- const dot = pkg.exports && pkg.exports["."] !== undefined ? pkg.exports["."] : pkg.exports;
104
- const rel =
105
- (dot && typeof dot === "object" && (dot.import || dot.default)) ||
106
- (typeof dot === "string" ? dot : null) ||
107
- pkg.module || pkg.main || "index.js";
108
- return join(dir, rel);
109
- }
110
- const parent = dirname(dir);
111
- if (parent === dir) break;
112
- dir = parent;
113
- }
114
- return null;
115
- }
116
-
117
- async function resolveLedgerModule(cwd) {
118
- try {
119
- return await import("wicked-ledger");
120
- } catch { /* fall through */ }
121
- try {
122
- const require = createRequire(join(cwd, "__qe_gate_anchor__.js"));
123
- const located = require.resolve("wicked-ledger");
124
- const esm = esmEntryForPackage(located) || located;
125
- return await import(pathToFileURL(esm).href);
126
- } catch {
127
- return null;
128
- }
129
- }
94
+ // --- wicked-ledger resolution: the shared resolver (./ledger-pkg.mjs, $WICKED_LEDGER_PKG_DIR first) ---
130
95
 
131
96
  /**
132
97
  * Resolve the ledger root the gate writes to (TH-6). MUST mirror the TH-2
@@ -357,7 +322,7 @@ export async function runGate({ projectId, runId, verdict, verdictSummary, ratio
357
322
  process.stderr.write(
358
323
  JSON.stringify({
359
324
  error: "LEDGER_UNRESOLVABLE",
360
- detail: "wicked-ledger is not resolvable from this repo — npm i --no-save wicked-ledger",
325
+ detail: "wicked-ledger is not resolvable — set WICKED_LEDGER_PKG_DIR (a governed crew run sets it) or npm i --no-save wicked-ledger",
361
326
  }) + "\n"
362
327
  );
363
328
  process.exit(3);
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The ONE wicked-ledger resolver of garden's QE pipeline (accept, the gate, the campaign
3
+ * scoreboard). wicked-ledger is resolved for the TARGET repo — the plugin ships no node_modules —
4
+ * in this order:
5
+ *
6
+ * 1. `$WICKED_LEDGER_PKG_DIR` — an explicit package dir. wicked-crew exports its OWN bundled
7
+ * wicked-ledger here (wicked-crew#951), so a governed run's QE unit records its verdict with
8
+ * the very package crew's acceptance check reads it with, and needs no install in the
9
+ * worktree (a fenced governed seat cannot `npm i`, and an install would change the tree).
10
+ * Set but unusable ⇒ `null` (an explicit pin never falls back to a different package).
11
+ * 2. a bare `import("wicked-ledger")` (a global / hoisted install);
12
+ * 3. a walk up from the target repo for `node_modules/wicked-ledger`.
13
+ *
14
+ * `null` when none resolves; callers say so (never a silent no-op).
15
+ */
16
+ import { existsSync, readFileSync } from "node:fs";
17
+ import { dirname, join, resolve } from "node:path";
18
+ import { pathToFileURL } from "node:url";
19
+
20
+ export const LEDGER_PKG_ENV = "WICKED_LEDGER_PKG_DIR";
21
+
22
+ /** The ESM entry file of a package dir (its `exports["."]` import/default, else module/main). */
23
+ export function esmEntryForPackageDir(pkgDir) {
24
+ const pj = join(pkgDir, "package.json");
25
+ if (!existsSync(pj)) return null;
26
+ let pkg;
27
+ try {
28
+ pkg = JSON.parse(readFileSync(pj, "utf8"));
29
+ } catch {
30
+ return null;
31
+ }
32
+ const dot = pkg.exports && pkg.exports["."] !== undefined ? pkg.exports["."] : pkg.exports;
33
+ const rel =
34
+ (dot && typeof dot === "object" && (dot.import || dot.default)) ||
35
+ (typeof dot === "string" ? dot : null) ||
36
+ pkg.module ||
37
+ pkg.main ||
38
+ "index.js";
39
+ return join(pkgDir, rel);
40
+ }
41
+
42
+ /** The resolved wicked-ledger module for `repoRoot`, or `null`. */
43
+ export async function resolveLedgerModule(repoRoot = process.cwd(), env = process.env) {
44
+ const pinned = env[LEDGER_PKG_ENV]?.trim();
45
+ if (pinned) {
46
+ const entry = esmEntryForPackageDir(pinned);
47
+ if (!entry || !existsSync(entry)) return null;
48
+ try {
49
+ return await import(pathToFileURL(entry).href);
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+ try {
55
+ return await import("wicked-ledger");
56
+ } catch {
57
+ /* fall through */
58
+ }
59
+ let dir = resolve(repoRoot);
60
+ for (let i = 0; i < 10; i++) {
61
+ const entry = esmEntryForPackageDir(join(dir, "node_modules", "wicked-ledger"));
62
+ if (entry && existsSync(entry)) {
63
+ try {
64
+ return await import(pathToFileURL(entry).href);
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+ const parent = dirname(dir);
70
+ if (parent === dir) break;
71
+ dir = parent;
72
+ }
73
+ return null;
74
+ }
@@ -43,9 +43,9 @@ Relative paths in this skill are relative to the directory that contains this SK
43
43
  |---|---|---|---|
44
44
  | `scope` | neutral | nothing | Name the slug (kebab-case, at most 64 characters), the kind (`topic` or `event`), 3 to 7 questions to answer, what is out of scope, and the source policy: primary sources first (specs, official docs, release notes, the project's own site), dated reporting for events. Read `.wicked/knowledge/<slug>/` if it exists: then this run is a **refresh** (see refs/refresh.md). |
45
45
  | `research` | neutral | nothing | Fetch sources with your web tools (or `curl -sL`). For each source, record the URL, title, published date when the page states one, and `observed_at` = now in UTC. Draft candidate claims, each tied to the sources that support it. No network: write `research: no web access` and stop; never answer from memory as if it were sourced. |
46
- | `synthesize` | neutral | nothing | Turn the candidates into the claims ledger (refs/claims.md): one atomic, checkable statement per claim, deduplicated, ids from `claim_id`. Keep only claims that would help a fresh session in 3 months. On a refresh, output the diff against the existing ledger. |
46
+ | `synthesize` | neutral | nothing | Turn the candidates into the claims ledger (refs/claims.md): one atomic, checkable statement per claim, deduplicated. Leave new claim ids to the author (a neutral seat may not run scripts); on a refresh keep each existing id. Keep only claims that would help a fresh session in 3 months. On a refresh, output the diff against the existing ledger. |
47
47
  | `walkthrough` | neutral | nothing | Teach it in the run thread: a 5-line summary, a worked example, what changed (on a refresh), the open questions, and 3 to 5 check questions. The operator answers, asks or corrects by sending the step back; answer each point, re-teach what was unclear, and mark which corrections you verified against a source. |
48
- | `author` | creator | `.wicked/knowledge/<slug>/`, skills | Write the files (refs/claims.md), then run the check below and paste its JSON and exit code. |
48
+ | `author` | creator | `.wicked/knowledge/<slug>/`, skills | Compute each new claim's id (`wicked-garden run scripts/learn/check.py --claim-id "<text>"`), write the files (refs/claims.md), then run the check below and paste its JSON and exit code. |
49
49
  | `review` | evaluator | nothing | Re-run the check yourself; re-fetch and spot-check at least 3 claims (every retirement, too); judge the durability test; last line `VERDICT: PASS` or `VERDICT: FAIL`. |
50
50
  | `check` | any | nothing | `wicked-garden run scripts/learn/check.py --repo . [--slug <slug>]` |
51
51
  | `index` | human or daemon only | estate knowledge | `wicked-garden run scripts/learn/index.py --repo <default-branch checkout>` after the PR merged. It refuses inside a governed run. |
@@ -123,7 +123,15 @@ the run's canonical UUID. This serves three goals at once:
123
123
  // Resolve the ledger root (wicked-ledger >= 0.6.0): WICKED_QE_LEDGER_DIR when set — inside a
124
124
  // governed wicked-crew run, the run's own ledger OUTSIDE the worktree (crew#951) — else dual-read
125
125
  // (Phase 6c): '.wicked-qe', or a legacy '.wicked-testing' root written before the rename. <!-- historical -->
126
- import { createDomainStore, resolveLedgerRoot } from 'wicked-ledger';
126
+ // wicked-ledger through the ONE resolver ($WICKED_LEDGER_PKG_DIR — set by a governed crew run —,
127
+ // else an install the target repo resolves); see § wicked-ledger resolution.
128
+ import { pathToFileURL } from 'node:url';
129
+ import { join as joinPath } from 'node:path';
130
+ // {WT_LIB} is a native path (Windows too): import it as a file URL, never a bare string.
131
+ const { resolveLedgerModule } = await import(pathToFileURL(joinPath(String.raw`{WT_LIB}`, 'ledger-pkg.mjs')).href);
132
+ const ledger = await resolveLedgerModule(process.cwd());
133
+ if (!ledger) throw new Error("wicked-ledger is not resolvable: set WICKED_LEDGER_PKG_DIR or npm i --no-save wicked-ledger");
134
+ const { createDomainStore, resolveLedgerRoot } = ledger;
127
135
  import { join } from 'node:path';
128
136
  const LEDGER_ROOT = resolveLedgerRoot(process.cwd());
129
137
  const store = createDomainStore({ root: LEDGER_ROOT });
@@ -394,7 +402,7 @@ const verdictRecord = store.create('verdicts', {
394
402
  });
395
403
 
396
404
  // 3. Materialize the public manifest at the contract path
397
- import { buildManifest, emitBusEvent } from 'wicked-ledger';
405
+ const { buildManifest, emitBusEvent } = ledger; // the same resolved wicked-ledger as step 0
398
406
  import { readFileSync } from 'node:fs';
399
407
  const pkgVersion = JSON.parse(readFileSync('package.json','utf8')).version;
400
408
  const runAfter = store.get('runs', run.id);
@@ -475,7 +483,13 @@ WT_LIB="$(wicked-garden path scripts/qe/lib)"
475
483
  ## wicked-ledger resolution
476
484
 
477
485
  `wicked-ledger` (npm) is the QE data layer — DomainStore, oracle queries, and
478
- manifest building. Import-style snippets above must run where the package
479
- resolves: the target project's `node_modules` (`npm i --no-save wicked-ledger`)
480
- or any directory with it installed. The pinned range lives in
481
- `.claude-plugin/plugin.json` → `wicked_ledger_version`.
486
+ manifest building. The snippets above load it through `{WT_LIB}/ledger-pkg.mjs`,
487
+ the one resolver the gate shares:
488
+
489
+ 1. `$WICKED_LEDGER_PKG_DIR`. Inside a governed wicked-crew run it is set to crew's
490
+ own wicked-ledger, the package crew's acceptance check reads the verdict with.
491
+ Do not `npm i` in a governed run: a fenced seat is refused the install, and it
492
+ would change the tree under review.
493
+ 2. otherwise, an install the target repo resolves (`npm i --no-save wicked-ledger`).
494
+
495
+ The pinned range lives in `.claude-plugin/plugin.json` → `wicked_ledger_version`.