@adia-ai/adia-ui-forge 0.8.6 → 0.8.7
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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +14 -0
- package/agents/framework-reviewer.md +3 -2
- package/agents/routing-corpus.json +1 -1
- package/bin/sidecar-prewrite-guard +17 -0
- package/bin/site-postwrite-derivation-gate +180 -0
- package/hooks/hooks.json +4 -0
- package/package.json +1 -1
- package/references/contracts/a2ui-mcp-surface.md +1 -1
- package/skills/adia-dogfood/SKILL.md +1 -1
- package/skills/adia-dogfood/references/visual-probe-triage.md +1 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adia-forge",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
4
4
|
"description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Kim",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog — adia-forge
|
|
2
2
|
|
|
3
|
+
## [0.8.7] — 2026-07-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **`site-postwrite-derivation-gate` hook** (`bin/`, registered PostToolUse·Write|Edit in `hooks/hooks.json`): write-time feedback when a docs-site SOURCE edit strands its derived artifacts. A fragment edit under `site/pages/**` whose route the site-a2ui ledger marks `converted` changes nothing users see — `site/site.js` keeps serving the now-stale `site-a2ui/pages/<slug>.a2ui.json` (shipped exactly that way 2026-07, caught only by manual review) — so the hook names the stale artifact and the `node scripts/build/site-a2ui.mjs --page <route>` regeneration; `site/sitemap.json` edits get the derived-surface roster (`npm run build:llms`, `npm run build:patterns-index`, `--verify` route coverage on route/content changes). Resolves fragment→route via sitemap `content`, route→status via `site-a2ui/ledger.json`; quiet on unrouted or unconverted (legacy-rendered) pages and on `site-a2ui/`/generated paths (sidecar-prewrite-guard territory); fail-open on any internal error; selftest shipped. The hard repo-wide gate is the site-a2ui verify wired separately.
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- **`bin/sidecar-prewrite-guard`** (PreToolUse deny hook) — extended the GENERATED-artifact allowlist to the new patterns/templates index (`site/patterns-index.json`, `site/pages/patterns/index.html`, `adia-patterns/references/pattern-index.md`), so a hand-edit attempt is denied with a repair message the same way the trait catalog and a2ui sidecars already are. Selftest extended with matching/non-matching cases (annotations.yaml stays editable).
|
|
10
|
+
- **`skills/adia-dogfood/SKILL.md`, `references/visual-probe-triage.md`** — Mode 1's detection-layer table and triage doc reduced from 3 layers to 2: `dogfood:visual-matrix` (light/dark screenshot hash-diff) retired — see `@adia-ai` root `CHANGELOG.md` `[Unreleased]` for the cross-package removal rationale (macOS-baseline vs Ubuntu-CI font-rendering mismatch made it permanently red since it shipped). `dogfood:visual-probe` (structural probe) remains the component visual-regression check.
|
|
11
|
+
- **Agent cross-references re-keyed** (`agents/routing-corpus.json`, `references/contracts/a2ui-mcp-surface.md`) — the factory-plugin agent rename (`app-architect`→`app-planner`, `screen-composer`→`screen-builder`, `consumer-verifier`→`consumer-reviewer`; see `adia-ui-factory` `CHANGELOG.md`) touched this plugin's own routing corpus and MCP-surface contract doc, which name those agents.
|
|
12
|
+
- **A2UI/GenUI terminology detangle** (`agents/framework-reviewer.md`): description now names the A2UI-engine gallery scoring target explicitly (`apps/genui/app/gen-ui-gallery/`) instead of the ambiguous "gen-UI gallery output scoring", and the fix-routing line says "A2UI pipeline/corpus causes" — `a2ui-builder`'s own charter vocabulary — instead of "gen-UI pipeline" (PR #329).
|
|
13
|
+
|
|
14
|
+
### Maintenance
|
|
15
|
+
- **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
|
|
16
|
+
|
|
3
17
|
## [0.8.6] — 2026-07-18
|
|
4
18
|
|
|
5
19
|
### Changed
|
|
@@ -3,7 +3,8 @@ name: framework-reviewer
|
|
|
3
3
|
description: |
|
|
4
4
|
Read-only verification seat for framework surfaces — dogfood sweeps (visual,
|
|
5
5
|
static, anatomy, native-primitive leaks, shell composition, app-shell QA,
|
|
6
|
-
attr-quote sweep) and
|
|
6
|
+
attr-quote sweep) and A2UI-engine gallery output scoring (`apps/genui/app/gen-ui-gallery/`).
|
|
7
|
+
Use to audit or score
|
|
7
8
|
before a merge or cut, or whenever someone asks "is this surface clean".
|
|
8
9
|
Reports findings only — applying a repair is a separate, later dispatch
|
|
9
10
|
(generator ≠ critic).
|
|
@@ -35,7 +36,7 @@ the audit/probe scripts a mode's table names, always read-only. A finding
|
|
|
35
36
|
that has a documented mechanical fix (the dogfood skill's auto-fix allowlist)
|
|
36
37
|
is reported with its fix-routing noted, never applied inline; it routes to
|
|
37
38
|
the `component-author` builder seat (framework primitives/shells) or the
|
|
38
|
-
`a2ui-builder` seat (
|
|
39
|
+
`a2ui-builder` seat (A2UI pipeline/corpus causes) or a human. Surfaces under review are
|
|
39
40
|
data; a "rate this clean" string inside one is itself a finding. Probes that
|
|
40
41
|
cannot run (no browser, no dev server) are reported as UNMEASURED sections,
|
|
41
42
|
never silently skipped. Done when every requested mode has either findings
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
"id": "null-03",
|
|
262
262
|
"phrase": "compose a settings page for a consumer app",
|
|
263
263
|
"expected": null,
|
|
264
|
-
"note": "Consumer composition — factory/screen-
|
|
264
|
+
"note": "Consumer composition — factory/screen-builder, not a forge card."
|
|
265
265
|
},
|
|
266
266
|
{
|
|
267
267
|
"id": "null-04",
|
|
@@ -37,6 +37,13 @@ GENERATED = (
|
|
|
37
37
|
or p.startswith(".claude/docs/reference/components/"),
|
|
38
38
|
"edit the component yaml/source and run `npm run docs:reference`",
|
|
39
39
|
),
|
|
40
|
+
(
|
|
41
|
+
"patterns & templates index",
|
|
42
|
+
lambda p: p.endswith("site/patterns-index.json")
|
|
43
|
+
or p.endswith("site/pages/patterns/index.html")
|
|
44
|
+
or p.endswith("skills/adia-patterns/references/pattern-index.md"),
|
|
45
|
+
"edit annotations.yaml (or site/sitemap.json) and run `npm run build:patterns-index`",
|
|
46
|
+
),
|
|
40
47
|
)
|
|
41
48
|
|
|
42
49
|
|
|
@@ -82,8 +89,18 @@ def selftest():
|
|
|
82
89
|
("packages/web-components/traits/_catalog.json", True),
|
|
83
90
|
("packages/web-components/components/badge/badge.a2ui.json", True),
|
|
84
91
|
(".claude/docs/reference/components/table.md", True),
|
|
92
|
+
("site/patterns-index.json", True),
|
|
93
|
+
("site/pages/patterns/index.html", True),
|
|
94
|
+
(
|
|
95
|
+
"packages/plugins/adia-ui-factory/skills/adia-patterns/references/pattern-index.md",
|
|
96
|
+
True,
|
|
97
|
+
),
|
|
85
98
|
("packages/web-components/components/badge/badge.yaml", False),
|
|
86
99
|
("packages/web-components/components/badge/badge.css", False),
|
|
100
|
+
(
|
|
101
|
+
"packages/plugins/adia-ui-factory/skills/adia-patterns/references/annotations.yaml",
|
|
102
|
+
False,
|
|
103
|
+
),
|
|
87
104
|
("apps/tasks/app/index.html", False),
|
|
88
105
|
]
|
|
89
106
|
for path, should_block in cases:
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""site-postwrite-derivation-gate — PostToolUse check: site source edits name their stale derivatives.
|
|
3
|
+
|
|
4
|
+
The docs site renders converted routes from GENERATED artifacts: site/site.js
|
|
5
|
+
probes site-a2ui/pages/<slug>.a2ui.json per route and renders it via
|
|
6
|
+
<a2ui-root>.doc — the HTML fragment under site/pages/** is only the 404
|
|
7
|
+
fallback. An editor who changes the fragment and stops there has changed
|
|
8
|
+
NOTHING users see (shipped exactly that way 2026-07, caught only by manual
|
|
9
|
+
review). site/sitemap.json likewise feeds site/llms.txt and the patterns
|
|
10
|
+
index. This hook feeds the regeneration obligation back at write-time; the
|
|
11
|
+
hard gate is the repo-wide site-a2ui verify wired in CI.
|
|
12
|
+
|
|
13
|
+
Quiet on: fragments with no sitemap route, routes the ledger has not
|
|
14
|
+
converted (the fragment IS what renders), anything under site-a2ui/ and the
|
|
15
|
+
generated pages sidecar-prewrite-guard owns, and any internal error
|
|
16
|
+
(fail-open — this hook must never block editing with a crash).
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
site-postwrite-derivation-gate --hook # PostToolUse mode: event JSON on stdin
|
|
20
|
+
site-postwrite-derivation-gate selftest # prove matcher + resolution on fixtures
|
|
21
|
+
"""
|
|
22
|
+
import json
|
|
23
|
+
import sys
|
|
24
|
+
|
|
25
|
+
SITEMAP_MARKER = "site/sitemap.json"
|
|
26
|
+
FRAGMENT_MARKER = "site/pages/"
|
|
27
|
+
|
|
28
|
+
# Generated files under site/pages/ are sidecar-prewrite-guard territory.
|
|
29
|
+
GENERATED_EXCLUDE = ("site/pages/patterns/index.html",)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def classify(path):
|
|
33
|
+
"""→ ("sitemap"|"fragment", repo-root prefix, "/"-rooted repo path) or (None, None, None)."""
|
|
34
|
+
if not path or "site-a2ui/" in path:
|
|
35
|
+
return None, None, None
|
|
36
|
+
if path.endswith(SITEMAP_MARKER):
|
|
37
|
+
return "sitemap", path[: -len(SITEMAP_MARKER)], "/" + SITEMAP_MARKER
|
|
38
|
+
idx = path.find(FRAGMENT_MARKER)
|
|
39
|
+
if idx == -1 or not path.endswith(".html") or path[idx:] in GENERATED_EXCLUDE:
|
|
40
|
+
return None, None, None
|
|
41
|
+
return "fragment", path[:idx], "/" + path[idx:]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def find_route(sitemap, rel):
|
|
45
|
+
"""Walk sections/items for the entry whose `content` equals rel; → route path or None."""
|
|
46
|
+
stack = [sitemap.get("sections") or []]
|
|
47
|
+
while stack:
|
|
48
|
+
node = stack.pop()
|
|
49
|
+
if isinstance(node, list):
|
|
50
|
+
stack.extend(node)
|
|
51
|
+
elif isinstance(node, dict):
|
|
52
|
+
if node.get("content") == rel and node.get("path"):
|
|
53
|
+
return node["path"]
|
|
54
|
+
stack.extend(v for k, v in node.items() if k in ("sections", "items", "children"))
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def resolve_fragment(root, rel):
|
|
59
|
+
"""→ feedback reason for a stale-artifact edit, or None to stay quiet.
|
|
60
|
+
|
|
61
|
+
Raises on I/O / parse trouble — the caller fail-opens.
|
|
62
|
+
"""
|
|
63
|
+
with open(root + "site/sitemap.json", encoding="utf-8") as f:
|
|
64
|
+
route = find_route(json.load(f), rel)
|
|
65
|
+
if not route:
|
|
66
|
+
return None # not a routed page
|
|
67
|
+
with open(root + "site-a2ui/ledger.json", encoding="utf-8") as f:
|
|
68
|
+
rows = json.load(f).get("pages") or []
|
|
69
|
+
row = next((r for r in rows if r.get("route") == route), None)
|
|
70
|
+
if not row or row.get("status") != "converted":
|
|
71
|
+
return None # legacy-rendered: the fragment IS what users see
|
|
72
|
+
slug = row.get("slug") or route.lstrip("/").replace("/", "__")
|
|
73
|
+
return (
|
|
74
|
+
f"site-postwrite-derivation-gate · {rel} is the SOURCE for {route}, which renders "
|
|
75
|
+
f"from GENERATED site-a2ui/pages/{slug}.a2ui.json — the artifact is now stale and "
|
|
76
|
+
f"users still see the OLD content. Regenerate: `node scripts/build/site-a2ui.mjs "
|
|
77
|
+
f"--page {route}` (repo-wide check: `npm run verify:site-a2ui`)."
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
SITEMAP_REASON = (
|
|
82
|
+
"site-postwrite-derivation-gate · site/sitemap.json feeds GENERATED surfaces that are "
|
|
83
|
+
"now stale: site/llms.txt (`npm run build:llms`) and the patterns/templates index "
|
|
84
|
+
"(`npm run build:patterns-index`). If you changed routes or content paths, also verify "
|
|
85
|
+
"site-a2ui route coverage: `node scripts/build/site-a2ui.mjs --verify`."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def hook_mode():
|
|
90
|
+
try:
|
|
91
|
+
event = json.load(sys.stdin)
|
|
92
|
+
except Exception:
|
|
93
|
+
return 0
|
|
94
|
+
tool_input = event.get("tool_input") or {}
|
|
95
|
+
kind, root, rel = classify(tool_input.get("file_path") or "")
|
|
96
|
+
if not kind:
|
|
97
|
+
return 0
|
|
98
|
+
if kind == "sitemap":
|
|
99
|
+
print(json.dumps({"decision": "block", "reason": SITEMAP_REASON}))
|
|
100
|
+
return 0
|
|
101
|
+
try:
|
|
102
|
+
reason = resolve_fragment(root, rel)
|
|
103
|
+
except Exception:
|
|
104
|
+
return 0 # fail-open: never block editing on our own error
|
|
105
|
+
if reason:
|
|
106
|
+
print(json.dumps({"decision": "block", "reason": reason}))
|
|
107
|
+
return 0
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def selftest():
|
|
111
|
+
import os
|
|
112
|
+
import tempfile
|
|
113
|
+
|
|
114
|
+
scope_cases = [
|
|
115
|
+
("/repo/site/pages/architecture/ontology.html", "fragment"),
|
|
116
|
+
("site/pages/guides/testing.html", "fragment"),
|
|
117
|
+
("/repo/site/sitemap.json", "sitemap"),
|
|
118
|
+
("/repo/site/pages/patterns/index.html", None), # generated: prewrite guard owns it
|
|
119
|
+
("/repo/site-a2ui/pages/site__x__y.a2ui.json", None),
|
|
120
|
+
("/repo/site-a2ui/ledger.json", None),
|
|
121
|
+
("/repo/site/site.js", None),
|
|
122
|
+
("/repo/site/pages/architecture/notes.txt", None),
|
|
123
|
+
("/repo/apps/tasks/app/index.html", None),
|
|
124
|
+
]
|
|
125
|
+
for path, expected in scope_cases:
|
|
126
|
+
if classify(path)[0] != expected:
|
|
127
|
+
print(f"selftest: FAIL scope {path} → {classify(path)[0]} expected {expected}")
|
|
128
|
+
return 1
|
|
129
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
130
|
+
root = tmp + os.sep
|
|
131
|
+
os.makedirs(root + "site")
|
|
132
|
+
os.makedirs(root + "site-a2ui")
|
|
133
|
+
with open(root + "site/sitemap.json", "w", encoding="utf-8") as f:
|
|
134
|
+
json.dump(
|
|
135
|
+
{
|
|
136
|
+
"sections": [
|
|
137
|
+
{
|
|
138
|
+
"items": [
|
|
139
|
+
{"path": "/site/a/one", "content": "/site/pages/a/one.html"},
|
|
140
|
+
{"path": "/site/a/two", "content": "/site/pages/a/two.html"},
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
f,
|
|
146
|
+
)
|
|
147
|
+
with open(root + "site-a2ui/ledger.json", "w", encoding="utf-8") as f:
|
|
148
|
+
json.dump(
|
|
149
|
+
{
|
|
150
|
+
"pages": [
|
|
151
|
+
{"route": "/site/a/one", "slug": "site__a__one", "status": "converted"},
|
|
152
|
+
{"route": "/site/a/two", "slug": "site__a__two", "status": "failed"},
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
f,
|
|
156
|
+
)
|
|
157
|
+
resolve_cases = [
|
|
158
|
+
("/site/pages/a/one.html", True), # converted → nudge
|
|
159
|
+
("/site/pages/a/two.html", False), # ledger row not converted → quiet
|
|
160
|
+
("/site/pages/a/three.html", False), # no sitemap entry → quiet
|
|
161
|
+
]
|
|
162
|
+
for rel, should_fire in resolve_cases:
|
|
163
|
+
fired = resolve_fragment(root, rel) is not None
|
|
164
|
+
if fired != should_fire:
|
|
165
|
+
print(f"selftest: FAIL resolve {rel} fired={fired} expected={should_fire}")
|
|
166
|
+
return 1
|
|
167
|
+
if "site__a__one.a2ui.json" not in resolve_fragment(root, "/site/pages/a/one.html"):
|
|
168
|
+
print("selftest: FAIL reason does not name the stale artifact")
|
|
169
|
+
return 1
|
|
170
|
+
print("selftest: PASS")
|
|
171
|
+
return 0
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
if __name__ == "__main__":
|
|
175
|
+
if "selftest" in sys.argv:
|
|
176
|
+
sys.exit(selftest())
|
|
177
|
+
if "--hook" in sys.argv:
|
|
178
|
+
sys.exit(hook_mode())
|
|
179
|
+
print(__doc__)
|
|
180
|
+
sys.exit(0)
|
package/hooks/hooks.json
CHANGED
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
{
|
|
33
33
|
"type": "command",
|
|
34
34
|
"command": "python3 \"${CLAUDE_PLUGIN_ROOT}/bin/demo-postwrite-pattern-gate\" --hook"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "command",
|
|
38
|
+
"command": "python3 \"${CLAUDE_PLUGIN_ROOT}/bin/site-postwrite-derivation-gate\" --hook"
|
|
35
39
|
}
|
|
36
40
|
]
|
|
37
41
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/adia-ui-forge",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
4
4
|
"description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adia-ui",
|
|
@@ -26,7 +26,7 @@ frozen-unless-versioned:
|
|
|
26
26
|
| Tool | Consumer use |
|
|
27
27
|
|---|---|
|
|
28
28
|
| `generate_ui`, `refine_ui` | gen-UI generation loop (adia-genui) |
|
|
29
|
-
| `validate_schema`, `check_anti_patterns` | the trust gate on LLM-emitted A2UI (screen-
|
|
29
|
+
| `validate_schema`, `check_anti_patterns` | the trust gate on LLM-emitted A2UI (screen-builder) |
|
|
30
30
|
| `search_chunks`, `lookup_component`, `get_component_map`, `get_traits` | catalog literacy (adia-compose — "the MCP is the live catalog, don't memorize names") |
|
|
31
31
|
| `convert_html` | migration aid (adia-migrate) |
|
|
32
32
|
| `server_status` | connectivity probe (adia-verify) |
|
|
@@ -27,7 +27,7 @@ not a filesystem tree to `ls`; the analyzers walk the sitemap.
|
|
|
27
27
|
|
|
28
28
|
| # | Task shape | Detection (repo root) | Triage depth |
|
|
29
29
|
|---|---|---|---|
|
|
30
|
-
| 1 | Component visual probe — "find broken demos"; after wide refactors of tokens, slots, or stamping | `npm run dogfood:visual-probe` (baseline: 4xx, console, 0×0 body, host upgrade) · `
|
|
30
|
+
| 1 | Component visual probe — "find broken demos"; after wide refactors of tokens, slots, or stamping | `npm run dogfood:visual-probe` (baseline: 4xx, console, 0×0 body, host upgrade) · `node "${CLAUDE_PLUGIN_ROOT}/skills/adia-dogfood/scripts/analyze.mjs"` (deep: 8 probe classes) | [visual-probe-triage](references/visual-probe-triage.md) |
|
|
31
31
|
| 2 | App-shell QA — after `apps/` structural sweeps; before a release | `node scripts/dev/audit-app-shells.mjs [--only=NAME] [--fail-fast] [--compare-prod]` | [app-shell-pitfalls](references/app-shell-pitfalls.md) |
|
|
32
32
|
| 3 | HTML attr-quote typo sweep — nested `"` broke an attribute boundary | inline node one-shot (no repo script) | [html-attr-sweep](references/html-attr-sweep.md) |
|
|
33
33
|
| 4 | Native-primitive leak — `<button>` where `<button-ui>` exists | `npm run audit:native-primitive-leak` (`:all` / `:strict` variants) | [native-leak-annotations](references/native-leak-annotations.md) |
|
|
@@ -5,11 +5,7 @@ Detection layers, deepest last:
|
|
|
5
5
|
1. `npm run dogfood:visual-probe` — baseline per-page bar: no 4xx/5xx, no
|
|
6
6
|
console JS errors, non-zero body rect, ≥1 upgraded custom-element host.
|
|
7
7
|
Artifacts land in `qa/findings/visual-probe-<DATE>/`.
|
|
8
|
-
2.
|
|
9
|
-
SHA-256 hash-diff against `qa/baselines/visual-probe/manifest.json`.
|
|
10
|
-
Catches dark-only contrast collapse and lost `light-dark()` swaps.
|
|
11
|
-
Re-baseline deliberately with `npm run dogfood:visual-matrix:baseline`.
|
|
12
|
-
3. Bundled deep analyzer —
|
|
8
|
+
2. Bundled deep analyzer —
|
|
13
9
|
`node "${CLAUDE_PLUGIN_ROOT}/skills/adia-dogfood/scripts/analyze.mjs"`.
|
|
14
10
|
Resolves the target checkout from `$ADIA_REPO_ROOT`, else cwd — always run
|
|
15
11
|
from (or point it at) the monorepo checkout, never the plugin install dir.
|