wicked-garden 12.48.0 → 12.49.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.
@@ -2,7 +2,7 @@
2
2
  "_comment": "Issue #328: Component declarations for wicked-garden plugin. Claude Code plugin.json does not yet support inline component declarations beyond path overrides. This manifest documents all components for tooling, validation, and future schema support. When plugin.json gains a 'components' field, merge this data into plugin.json. The plugin is skills-only: former commands/ became actions of consolidated per-domain skills, and former agents/ became standalone context:fork worker skills (enumerated under fork_skills). Regenerate derived blocks with scripts/ci/sync_components.py.",
3
3
  "domains": ["agentic", "crew", "data", "demo", "engineering", "jam", "mem", "persona", "platform", "product", "qe", "search"],
4
4
  "summary": {
5
- "skills": 136,
5
+ "skills": 137,
6
6
  "fork_skills": 69,
7
7
  "hooks": 13,
8
8
  "specialists": 7
@@ -24,6 +24,7 @@
24
24
  "domain-extractor": ["domain-extractor"],
25
25
  "domain-modeler": ["domain-modeler"],
26
26
  "draft": ["draft"],
27
+ "editor-scaffold": ["editor-scaffold"],
27
28
  "engineering": ["architecture", "backend", "debugging", "docs", "engineering", "frontend", "integration", "large-scale-migration", "patch", "system-design", "unit-test-quality"],
28
29
  "engineering-api-documentarian": ["engineering-api-documentarian"],
29
30
  "engineering-migration-engineer": ["engineering-migration-engineer"],
@@ -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, real multi-model second opinions. 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.48.0"}], "version": "12.48.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.49.0"}], "version": "12.49.0"}
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "wicked-garden",
3
- "version": "12.48.0",
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), real multi-model second opinions (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.",
3
+ "version": "12.49.0",
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
- "wicked_ledger_version": "^0.4.0",
6
+ "wicked_ledger_version": "^0.6.0",
7
7
  "wicked_bus_version": "^2.0.0",
8
8
  "author": {
9
9
  "name": "Mike Parcewski",
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [12.49.0] — 2026-10-11
6
+
7
+ ### Added
8
+ - **`wicked-garden-editor-scaffold`: build, check and install an artifact editor plugin (X3, PR #1269).** A new skill plus `scripts/editor/`.
9
+ - **Inventory-report codebook (crew#721, PR #1266).** An enumerating step says whether its list is complete.
10
+
11
+ ### Fixed
12
+ - **QE acceptance inside a governed crew run records into the run's ledger, not the worktree (wicked-crew#951, PR #1270).** When `WICKED_QE_LEDGER_DIR` is set, it is the ledger root. A governed run hands its QE unit the run's own ledger, outside the worktree, this way.
13
+ - The preflight config check, setup's scaffold and `config.json`, accept's evidence dir, the executor and reviewer briefs, and the vault-record argument all use that root.
14
+ - accept resolves it through wicked-ledger's `resolveLedgerRoot`.
15
+ - Before, a governed `qe accept` wrote `<worktree>/.wicked-qe`; the run's guard discarded it, the PASS with it, and delivery was refused.
16
+
17
+ ### Changed
18
+ - **`wicked_ledger_version` is `^0.6.0`** (PR #1270): `resolveLedgerRoot` honours `WICKED_QE_LEDGER_DIR`. The QE runner requires wicked-ledger `^0.5.0` (PR #1267).
19
+ - Docs: guidance and the site say what ships, and what blocks vs what advises (PR #1265). Python 3.15 (PR #1268).
20
+
5
21
  ## [12.48.0] — 2026-10-09
6
22
 
7
23
  ### Added
package/README.md CHANGED
@@ -32,11 +32,11 @@ Most plugins try to boss them around — re-implement planning, impose a workflo
32
32
  | refactors on a hope and a prayer | renames across files as a **graph operation**, not find-replace roulette → wicked-patch |
33
33
  | forgets everything at `exit` | remembers what session 1 decided when you're in session 47 → the mem domain over wicked-estate |
34
34
  | re-derives *how to work in this repo* every task — which file owns the bug, the wiring step, the test command | loads the repo's own playbooks (`fix-bug`/`add-feature`/`verify`…), generated from HEAD → wicked-understanding |
35
- | asks *itself* for a second opinion | convenes a **real multi-model panel** (Antigravity / Codex / …) → the jam skill's `council` action |
35
+ | asks *itself* for a second opinion | convenes a **review panel** → the jam skill's `council` action: usable external CLIs (Antigravity / Codex / …) take the seats; with fewer than two it fills them with isolated same-family workers and **labels them as weaker diversity**, and below two isolated seats it reports *no quorum* instead of synthesizing |
36
36
  | re-derives WCAG/CWE/SOC2 from memory every time | loads the rubric on demand, ships it to any repo |
37
- | grades its own homework | author ≠ executor ≠ reviewer → evidence-gated testing |
37
+ | grades its own homework | author ≠ executor ≠ reviewer as separate workers → evidence-gated testing (the `qe` domain) |
38
38
 
39
- The throughline: **done is re-derived, not asserted.** Verdicts you can trust on the first read — not green checkmarks you can't.
39
+ The throughline: **done is re-derived, not asserted** — wherever the gate actually runs. Which entry paths block and which only advise is spelled out in [What blocks, what advises](#what-blocks-what-advises).
40
40
 
41
41
  ## What it's *not*
42
42
 
@@ -106,14 +106,14 @@ Optional, lights up the code graph: **wicked-estate** (single binary; `wicked-es
106
106
  ## Try it
107
107
 
108
108
  ```bash
109
- # Just work — the hook applies the right rigor underneath, quietly
109
+ # Just work — in Claude Code the plugin's hook reads the work's shape and suggests the rigor (advisory)
110
110
  "implement caching for the dashboard"
111
111
 
112
112
  # Or reach for a gap-filler on purpose — everything is a skill now
113
113
  /wicked-garden-prove # re-derive "done" from evidence (fail-closed)
114
114
  /wicked-garden-search blast-radius emit_event # impact, incl. edges grep can't see
115
115
  /wicked-garden-engineering-patch rename oldField newField # deterministic, graph-driven
116
- /wicked-garden-jam council "redis or memcached?" # a panel that isn't just you
116
+ /wicked-garden-jam council "redis or memcached?" # a panel; it says which seats were external models
117
117
 
118
118
  # Stamp the evidence gate into ANY repo (runs with no wicked-garden installed)
119
119
  /wicked-garden-prove compile ~/path/to/repo --trigger ci
@@ -121,6 +121,24 @@ Optional, lights up the code graph: **wicked-estate** (single binary; `wicked-es
121
121
 
122
122
  ---
123
123
 
124
+ ## What blocks, what advises
125
+
126
+ "Done is re-derived" is a property of the **gate**, not of every surface the toolkit touches. What a
127
+ false "done" runs into depends on the host and the entry path:
128
+
129
+ | Host · entry path | Blocks | Only advises |
130
+ |---|---|---|
131
+ | **Any host — the gate, invoked** (`wicked-garden-prove`, an archetype's produces-gate → `scripts/qe/vault_gate.py`) | Re-hashes the recorded evidence and re-runs its verifier through `wicked-vault`: a false claim is **rejected**, an unresolvable backend **fails closed** (`gate: "unavailable"`). Hard gates also need an attestation under an explicit `--actor` that differs from the author's — a local label, not an authenticated identity. The verdict stops whatever acts on it. | With `--no-require`, a backend that cannot run falls back to the claim-only tracker and says so (`claim-only`, not re-derived); a working backend still re-derives. |
132
+ | **Claude Code — plugin hooks** (plain conversation, "just work") | `PreToolUse` denies a few specific tool calls: native `EnterPlanMode` (always — planning goes through the archetype playbooks), writes to `MEMORY.md` / the auto-memory dir, build-phase writes on a high-complexity crew project with no challenge artifacts, a `phase_manager.py approve` whose gate preflight fails, a worktree cwd leak, and — only in `strict` mode (default `warn`) — invalid task metadata (`WG_TASK_METADATA`) and orphan state writes (`WG_BUS_EMIT_LINT`). Prompts are held until `/wicked-garden-core setup` completes. | Everything else. The archetype detector **steers** (it does not gate), the Stop-time claim sentinel is a fail-open **nudge** when a "done/passing" claim has no verdict for HEAD, `TaskCompleted` never blocks, and output governance is advisory. A completion claim is **not** blocked unless a gate is run. |
133
+ | **Codex · OpenCode · Pi · Antigravity — skills only** (`npx wicked-installer install-<cli> wicked-garden`) | Nothing by itself: no plugin hooks are installed on those hosts. | The skill text tells the agent to run the gate; it blocks only when the agent does run it (and the launcher + `wicked-vault` are present). |
134
+ | **Compiled repo gate** (`/wicked-garden-prove compile <repo> --trigger hook,ci`) | `.wicked/gate.py` fails the **git pre-push hook / CI job** it is wired into, with no wicked-garden installed. | Without a trigger it is a script you run by hand. |
135
+ | **wicked-crew governed run** | crew's engine decides each gated phase deny-dominates, on the layers that actually ran — deterministic floors, repo checks, policies, a judge. Review moves to a distinct seat when the roster has an eligible one; team runs refuse without one. | An ordinary run on a too-small roster keeps review on the creator seat and labels it "evaluator ≠ creator not held"; a pinned floor with no distinct judge is labelled "floor only"; a phase nothing gated is "approved by default, not verified". |
136
+
137
+ Garden's own daemon `/council` endpoint is a single-model synthesis (v0.1); the multi-model panel is
138
+ the jam skill's `council` action above.
139
+
140
+ ---
141
+
124
142
  ## Build on it
125
143
 
126
144
  The catalog is open: ship your own domain pack — a `wicked-pack.json`
@@ -141,7 +159,7 @@ Full author guide: [`docs/extending.md`](docs/extending.md).
141
159
  ## Principles
142
160
 
143
161
  - **Don't fight the harness.** Fill the gaps; never re-implement what it already does well.
144
- - **Done is re-derived, not asserted.** Every gate recomputes the evidence; the gates that matter are signed by someone who isn't the author.
162
+ - **Done is re-derived, not asserted.** Every gate recomputes the evidence; the gates that matter need an attestation recorded under an actor other than the author (a declared label, not an authenticated identity).
145
163
  - **Steering, not blocking.** Rigor follows the shape of the work, applied only where it earns its keep.
146
164
  - **Enforcement that travels.** The gate compiles into any repo and runs without wicked-garden present.
147
165
  - **Borrow the harness's primitives.** Extend `TaskCreate`/`Task()`/skills/hooks — don't rebuild them.
package/docs/extending.md CHANGED
@@ -97,6 +97,16 @@ Manifest `spec: 2` keeps every spec-1 field and adds two arrays. A spec-1 pack s
97
97
  wicked-studio and first-party blocks are core presets. Example (garden's own spec-2 fixture):
98
98
  [`tests/fixtures/packs/acme-terms/`](../tests/fixtures/packs/acme-terms/).
99
99
 
100
+ **Building an editor-only pack.** The `wicked-garden-editor-scaffold` skill writes one
101
+ (`scripts/editor/scaffold.py`), from a template that already speaks `wicked.editor/1`; `scripts/editor/pin.py`
102
+ re-pins the entry hash after each edit; `scripts/editor/conformance.py` runs the plugin's conformance
103
+ cases in headless Chromium inside studio's own conformance host page; and `scripts/editor/install.py`
104
+ stages the pack under `~/.wicked/editors/<name>/current/` and installs it into a wicked-crew daemon,
105
+ which re-runs `pack check` and the conformance cases itself before it records the editor (fail closed:
106
+ no headless browser is a refusal). A pack that also ships skills or blocks is not installable yet: their
107
+ own approval step is still to come. The governed route is the `editor-plugin` workflow (studio
108
+ Settings → Developer → Create an editor plugin).
109
+
100
110
  ## Validate: the shipped conformance gate
101
111
 
102
112
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-garden",
3
- "version": "12.48.0",
3
+ "version": "12.49.0",
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": [
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env python3
2
+ """Shared helpers for the editor-plugin scripts (scaffold, pin, conformance, install).
3
+
4
+ An editor plugin is a ``wicked-pack.json`` spec-2 pack (DES-artifact-editor-plugins §5.2): the
5
+ manifest lists ``editors[]``, each with ONE self-contained HTML ``entry`` inside the pack and that
6
+ file's full sha256. These helpers read such a pack; none of them writes outside the pack directory.
7
+ Standard library only.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import hashlib
13
+ import json
14
+ import re
15
+ from pathlib import Path
16
+
17
+ MANIFEST_NAME = "wicked-pack.json"
18
+ # The editor id and pack name shape (garden's kebab names, <= 64); `wicked`/`wicked-*` is reserved
19
+ # for the editors that ship inside studio and is refused in every pack (schema, PK061).
20
+ ID_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
21
+ RESERVED_RE = re.compile(r"^wicked(?:$|-)")
22
+ KIND_RE = re.compile(r"^[a-z][a-z0-9-]{1,40}$")
23
+ SEMVER_RE = re.compile(r"^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$")
24
+ SIZES = ("inline", "pane", "full")
25
+ # §6.1's permission table, with the plain words the install sheet shows.
26
+ PERMISSIONS = {
27
+ "artifact.read": "to read the artifact it opens",
28
+ "artifact.write": "to change it, as new versions you can undo",
29
+ "selection.chip": "to point at parts of it in your message box",
30
+ "composer.draft": "to suggest what to ask the helpers (you send it)",
31
+ "checks.read": "to see the checks and their evidence",
32
+ "checks.contribute": "to point things out, marked as its own notes",
33
+ "sources.read": "to see the sources attached to it",
34
+ "media.read": "to play the recording",
35
+ "artifact.export": "to download it",
36
+ "ui.fullscreen": "to go full screen",
37
+ "network.media": "to load images and fonts from the internet",
38
+ }
39
+ HOST_BUNDLE_CAP = 5 * 1024 * 1024
40
+
41
+
42
+ class PackError(Exception):
43
+ """A pack that cannot be read as an editor pack, with the reason."""
44
+
45
+
46
+ def sha256_file(path: Path) -> str:
47
+ return hashlib.sha256(path.read_bytes()).hexdigest()
48
+
49
+
50
+ def read_manifest(pack: Path) -> dict:
51
+ path = pack / MANIFEST_NAME
52
+ if not path.is_file():
53
+ raise PackError(f"{pack} holds no {MANIFEST_NAME}")
54
+ try:
55
+ manifest = json.loads(path.read_text(encoding="utf-8"))
56
+ except (OSError, ValueError) as exc:
57
+ raise PackError(f"{path} is not JSON: {exc}") from exc
58
+ if not isinstance(manifest, dict):
59
+ raise PackError(f"{path} is not a JSON object")
60
+ return manifest
61
+
62
+
63
+ def editors_of(manifest: dict) -> list[dict]:
64
+ editors = manifest.get("editors")
65
+ if manifest.get("spec") != 2 or not isinstance(editors, list) or not editors:
66
+ raise PackError("the pack declares no editors (wicked-pack.json spec 2 `editors[]`)")
67
+ return [e for e in editors if isinstance(e, dict)]
68
+
69
+
70
+ def entry_path(pack: Path, editor: dict) -> Path:
71
+ """The editor's entry file, resolved inside the pack (a path that escapes it is refused)."""
72
+ entry = editor.get("entry")
73
+ if not isinstance(entry, str) or not entry.endswith(".html"):
74
+ raise PackError(f"editor {editor.get('id')!r}: entry must name one .html file")
75
+ # A plain relative POSIX path: no absolute or drive-qualified form, no backslash, no `..` or `.`
76
+ # part — the same string is joined under a staging directory, so it must not climb out of one.
77
+ parts = entry.split("/")
78
+ if entry.startswith("/") or "\\" in entry or ":" in entry or any(p in ("", ".", "..") for p in parts):
79
+ raise PackError(f"editor {editor.get('id')!r}: entry {entry!r} must be a plain relative path inside the pack")
80
+ root = pack.resolve()
81
+ target = (pack / entry).resolve()
82
+ if root != target and root not in target.parents:
83
+ raise PackError(f"editor {editor.get('id')!r}: entry {entry} is outside the pack")
84
+ if not target.is_file():
85
+ raise PackError(f"editor {editor.get('id')!r}: entry {entry} is missing")
86
+ if target.stat().st_size > HOST_BUNDLE_CAP:
87
+ raise PackError(f"editor {editor.get('id')!r}: entry {entry} is over the host's {HOST_BUNDLE_CAP}-byte cap")
88
+ return target
89
+
90
+
91
+ def write_manifest(pack: Path, manifest: dict) -> None:
92
+ path = pack / MANIFEST_NAME
93
+ tmp = path.with_suffix(".json.tmp")
94
+ tmp.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8", newline="\n")
95
+ tmp.replace(path)