@topy-ai/maggie 0.7.44 → 0.7.46

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 (39) hide show
  1. package/README-zh-TW.md +29 -6
  2. package/README.md +86 -12
  3. package/bin/maggie.js +207 -58
  4. package/bundled-contracts/google-integrations/capability-report-v2.schema.json +76 -0
  5. package/bundled-contracts/google-integrations/external-write-readback-v1.schema.json +36 -0
  6. package/bundled-contracts/maggie-deployment/deployer-delegation-v1.schema.json +20 -0
  7. package/bundled-contracts/maggie-deployment/release-profile-v1.schema.json +34 -0
  8. package/bundled-contracts/maggie-design/browser-capability-v1.schema.json +33 -0
  9. package/bundled-contracts/maggie-feedback/evidence-bundle-v1.schema.json +38 -0
  10. package/bundled-references/browser-inspection.md +17 -0
  11. package/bundled-references/google-integrations-runbook.md +8 -1
  12. package/bundled-skills/maggie-blog-bootstrap/SKILL.md +7 -7
  13. package/bundled-skills/maggie-clone/SKILL.md +21 -14
  14. package/bundled-skills/maggie-clone-to-template/SKILL.md +11 -11
  15. package/bundled-skills/maggie-clone-to-template/references/workflow.md +2 -2
  16. package/bundled-skills/maggie-content-localization/SKILL.md +10 -10
  17. package/bundled-skills/maggie-deployment/SKILL.md +57 -23
  18. package/bundled-skills/maggie-deployment/references/vps.md +4 -4
  19. package/bundled-skills/maggie-design/SKILL.md +12 -12
  20. package/bundled-skills/maggie-feedback/SKILL.md +23 -0
  21. package/bundled-skills/maggie-marketplace/SKILL.md +12 -12
  22. package/bundled-skills/maggie-ops/SKILL.md +28 -6
  23. package/bundled-skills/maggie-project-context/SKILL.md +1 -1
  24. package/bundled-skills/maggie-seo-geo/SKILL.md +6 -3
  25. package/bundled-skills/maggie-service-booking/SKILL.md +24 -24
  26. package/bundled-skills/maggie-social-share/SKILL.md +2 -2
  27. package/bundled-skills/maggie-template/SKILL.md +5 -5
  28. package/bundled-tools/clis/maggie_analytics.py +8 -0
  29. package/bundled-tools/clis/maggie_browser_audit.py +13 -2
  30. package/bundled-tools/clis/maggie_deployment.py +167 -6
  31. package/bundled-tools/clis/maggie_feedback.py +115 -1
  32. package/bundled-tools/clis/maggie_ops.py +33 -0
  33. package/bundled-tools/clis/maggie_release.py +124 -19
  34. package/bundled-tools/runtime/browser_capability.py +143 -0
  35. package/bundled-tools/runtime/external_write.py +122 -0
  36. package/bundled-tools/runtime/google_capabilities.py +37 -5
  37. package/package.json +1 -1
  38. package/references/browser-inspection.md +17 -0
  39. package/references/google-integrations-runbook.md +8 -1
@@ -34,6 +34,23 @@ The draft is written to `.maggie/feedback/`. It contains the Maggie version,
34
34
  skill, run ID, phase, error fingerprint, expected/actual result, reproduction
35
35
  steps, resolution, validation, and metadata-only screenshot references.
36
36
 
37
+ Attach bounded, privacy-safe evidence and relationships when a maintainer will
38
+ need to connect a report to a test, deployment, issue, or related run. Only
39
+ identifiers are stored; file contents, logs, credentials, and local paths are
40
+ never copied:
41
+
42
+ ```bash
43
+ maggie feedback collect --project . --summary "Adapter unavailable" \
44
+ --evidence-ref test:browser-capability:passed \
45
+ --evidence-ref report:browser-capability:v1 \
46
+ --relationship same-run=clone-001
47
+ ```
48
+
49
+ Evidence references are bounded and normalized into the
50
+ `maggie-feedback-evidence-bundle.v1` contract. The accepted kinds are
51
+ `test`, `report`, `screenshot`, `command`, `deployment`, `issue`, `commit`,
52
+ and `artifact`; relationships connect safe IDs such as feedback or run IDs.
53
+
37
54
  If a draft is marked fixed with `--fixed` (or the supplied run report says
38
55
  `fixed`), both `--resolution` and `--validation` are required. Feedback text
39
56
  also scrubs common POSIX/home/temp and Windows absolute paths by default while
@@ -78,6 +95,12 @@ This writes `.maggie/feedback/batches/<batch-id>-review.json` under the
78
95
  duplicate fingerprints/summaries, while retaining only redacted observations;
79
96
  review the aggregate and each draft before submitting.
80
97
 
98
+ Batch review also emits a bounded `evidenceGraph` and
99
+ `remediationSuggestions`. The graph links feedback IDs to evidence IDs and
100
+ safe related references, while suggestions flag duplicate fingerprints,
101
+ missing batch indexes, shared evidence, or a batch with no validation
102
+ references. These are review aids, not automatic issue or memory writes.
103
+
81
104
  Example:
82
105
 
83
106
  {
@@ -37,18 +37,18 @@ API Pull integration, analytics, booking provider, or Maggie Ops backend.
37
37
  ## Commands
38
38
 
39
39
  ```bash
40
- python3 tools/clis/maggie_marketplace.py list
41
- python3 tools/clis/maggie_marketplace.py add \
40
+ maggie tool maggie_marketplace.py list
41
+ maggie tool maggie_marketplace.py add \
42
42
  https://www.aura.build/templates/medical-spa-landing-30 clone \
43
43
  https://medical-spa-landing-30.aura.build/ \
44
44
  --rename medical-spa-landing-001 --replace-id medical-spa-landing-30
45
- python3 tools/clis/maggie_marketplace.py import \
45
+ maggie tool maggie_marketplace.py import \
46
46
  --id medical-spa-landing-30 \
47
47
  --template-url https://www.aura.build/templates/medical-spa-landing-30 \
48
48
  --preview-url https://medical-spa-landing-30.aura.build/ \
49
49
  --category spa --category medical-spa --tags premium --tags clinical
50
- python3 tools/clis/maggie_marketplace.py validate marketplace/templates/medical-spa-landing-30
51
- python3 tools/clis/maggie_marketplace.py apply \
50
+ maggie tool maggie_marketplace.py validate marketplace/templates/medical-spa-landing-30
51
+ maggie tool maggie_marketplace.py apply \
52
52
  --id medical-spa-landing-30 --project /path/to/astro-project
53
53
  ```
54
54
 
@@ -84,8 +84,8 @@ The workflow is persisted as `.maggie/marketplace-jobs/<template-id>.json` and
84
84
  uses fail-closed checkpoints. Inspect or resume a job with:
85
85
 
86
86
  ```bash
87
- python3 tools/clis/maggie_marketplace.py status <template-id>
88
- python3 tools/clis/maggie_marketplace.py resume <template-id>
87
+ maggie tool maggie_marketplace.py status <template-id>
88
+ maggie tool maggie_marketplace.py resume <template-id>
89
89
  ```
90
90
 
91
91
  If generated assets are missing, the job stops at `WAITING_FOR_ASSETS`; cloned
@@ -114,16 +114,16 @@ or while an output image is reused across content occurrences.
114
114
  sample only when the marketplace intentionally introduces a new contract:
115
115
 
116
116
  ```bash
117
- python3 tools/clis/maggie_marketplace.py validate \
117
+ maggie tool maggie_marketplace.py validate \
118
118
  marketplace/templates/<template-id>
119
- python3 tools/clis/maggie_marketplace.py validate \
119
+ maggie tool maggie_marketplace.py validate \
120
120
  marketplace/templates/<template-id> --sample marketplace/templates/<sample-id>
121
121
  ```
122
122
 
123
123
  For a local export, pass the quoted HTML path as the preview argument:
124
124
 
125
125
  ```bash
126
- python3 tools/clis/maggie_marketplace.py add \
126
+ maggie tool maggie_marketplace.py add \
127
127
  https://www.aura.build/templates/medical-spa-landing-30 clone \
128
128
  "/path/to/Medical Aesthetics & Wellness Landing Page Template.html" \
129
129
  --rename medical-spa-landing-001 --category spa --category medical-spa \
@@ -197,7 +197,7 @@ manifest. A spinner, blank iframe, empty React root, loading skeleton, or page
197
197
  without meaningful content is a failed clone and must not be packaged.
198
198
 
199
199
  ```bash
200
- python3 tools/clis/maggie_clone.py extract \
200
+ maggie tool maggie_clone.py extract \
201
201
  "https://medical-spa-landing-30.aura.build/" \
202
202
  --run-id marketplace-medical-spa-landing-001
203
203
  ```
@@ -301,7 +301,7 @@ redesign is explicitly requested.
301
301
  ### 10. Validate and apply
302
302
 
303
303
  ```bash
304
- python3 tools/clis/maggie_marketplace.py validate \
304
+ maggie tool maggie_marketplace.py validate \
305
305
  marketplace/templates/medical-spa-landing-001
306
306
  python3 scripts/validate_skills.py
307
307
  git diff --check
@@ -38,13 +38,13 @@ Invoke it as:
38
38
  Use the deterministic control-plane CLI for lifecycle gates:
39
39
 
40
40
  ```bash
41
- python3 tools/clis/maggie_ops.py --project . audit
42
- python3 tools/clis/maggie_ops.py --project . preflight --write
43
- python3 tools/clis/maggie_ops.py --project . status
44
- python3 tools/clis/maggie_ops.py --project . verify
45
- python3 tools/clis/maggie_ops.py --project . favicon-check \
41
+ maggie tool maggie_ops.py --project . audit
42
+ maggie tool maggie_ops.py --project . preflight --write
43
+ maggie tool maggie_ops.py --project . status
44
+ maggie tool maggie_ops.py --project . verify
45
+ maggie tool maggie_ops.py --project . favicon-check \
46
46
  --origin https://example.com
47
- python3 tools/clis/maggie_ops.py --project . record sitemap-match \
47
+ maggie tool maggie_ops.py --project . record sitemap-match \
48
48
  --dry-run --quota-impact quota --idempotency-key match-2026-08-29-001
49
49
  ```
50
50
 
@@ -88,6 +88,14 @@ maggie ops google-capabilities --project . \
88
88
  --report .maggie/google-capability-input.json
89
89
  ```
90
90
 
91
+ The input must use `maggie-google-capability-report.v2`: each row records the
92
+ redacted active account, the selected target (`property`, `container`,
93
+ `customer`, `project`, or `site`), and the exact scopes. Both account and target
94
+ must be explicitly verified, and `target.id` must equal `resource`. The command
95
+ prints these safe identifiers and scopes before any separate provider adapter
96
+ is allowed to perform a write. A v1 report is rejected because it cannot prove
97
+ that the browser/session is on the intended Google account and property.
98
+
91
99
  The result separates `read`, `report`, `edit`, and `publish` for each
92
100
  provider/resource. Write and publish remain `not_tested` until the operator
93
101
  explicitly confirms the exact mutation and a successful read-back is captured.
@@ -164,6 +172,20 @@ Every mutation must validate the session, role, resource ownership/project
164
172
  scope, input schema, legal state transition, and idempotency/correlation key.
165
173
  Record actor, timestamp, previous state, next state, reason, and result.
166
174
 
175
+ For a GA4/GTM or other Google provider write, validate a hash-only
176
+ write/readback bundle before treating the operation as complete:
177
+
178
+ ```bash
179
+ maggie ops external-write-gate --project . \
180
+ --evidence .maggie/external-write-readback-input.json \
181
+ --output .maggie/external-write-readback.json
182
+ ```
183
+
184
+ The bundle requires one stable idempotency key across bounded retries, explicit
185
+ confirmation, successful readback fingerprints, an empty duplicate list, and
186
+ an empty orphaned-workspace list. It never stores provider payloads; an
187
+ incomplete or mismatched readback blocks the release gate.
188
+
167
189
  ### Operate
168
190
 
169
191
  Use the dashboard or API to perform an explicitly requested operation. Show an
@@ -61,7 +61,7 @@ context. Product roles, OAuth scopes, and Cloud IAM are distinct evidence.
61
61
  For the combined API Pull lifecycle, use the repository CLI in dry-run first:
62
62
 
63
63
  ```bash
64
- python3 tools/clis/maggie.py api lifecycle --project .
64
+ maggie tool maggie.py api lifecycle --project .
65
65
  ```
66
66
 
67
67
  The executing form can pull posts/updates, inspect rewrite queue/history and
@@ -125,7 +125,10 @@ maggie analytics release-gate --project . --environment staging \
125
125
 
126
126
  Use `contracts/maggie-seo/gsc-readiness-v1.schema.json` as the evidence
127
127
  boundary. Credentials and mutation scopes remain host-owned; a passing local
128
- contract is not proof of property ownership or live readback.
128
+ contract is not proof of property ownership or live readback. If a GA4/GTM
129
+ write is part of the workflow, also pass hash-only
130
+ `.maggie/external-write-readback.json` evidence to the analytics release gate;
131
+ duplicate or orphaned provider objects fail closed.
129
132
 
130
133
  ## Freeze and compare a reviewed site
131
134
 
@@ -302,7 +305,7 @@ correct.
302
305
  For a deterministic technical smoke check, run:
303
306
 
304
307
  ```bash
305
- python3 tools/clis/site_audit.py https://example.com --crawl --json
308
+ maggie tool site_audit.py https://example.com --crawl --json
306
309
  ```
307
310
 
308
311
  This validates observable public output only. Strategy, AI visibility
@@ -350,7 +353,7 @@ enter the rewrite queue.
350
353
  The deterministic local orchestration entry point is:
351
354
 
352
355
  ```bash
353
- python3 tools/clis/maggie.py api lifecycle --project .
356
+ maggie tool maggie.py api lifecycle --project .
354
357
  ```
355
358
 
356
359
  Use `--execute` only after reviewing the dry-run, and add `--allow-quota` for
@@ -80,66 +80,66 @@ provider research.
80
80
  Run from the project root:
81
81
 
82
82
  ```bash
83
- python3 tools/clis/maggie_service_booking.py import \
83
+ maggie tool maggie_service_booking.py import \
84
84
  "https://www.fresha.com/a/spa-chevy-chase-chevy-chase-4500-north-park-avenue-sbic60h4?pId=512061" \
85
85
  --project .
86
86
 
87
- python3 tools/clis/maggie_service_booking.py sync \
87
+ maggie tool maggie_service_booking.py sync \
88
88
  "https://www.fresha.com/a/spa-chevy-chase-chevy-chase-4500-north-park-avenue-sbic60h4?pId=512061" \
89
89
  --project .
90
90
 
91
- python3 tools/clis/maggie_service_booking.py sync-report --project .
91
+ maggie tool maggie_service_booking.py sync-report --project .
92
92
 
93
- python3 tools/clis/maggie_service_booking.py generate --project . --copy-data docs/service-page-copy.json
94
- python3 tools/clis/maggie_service_booking.py validate --project .
93
+ maggie tool maggie_service_booking.py generate --project . --copy-data docs/service-page-copy.json
94
+ maggie tool maggie_service_booking.py validate --project .
95
95
 
96
- python3 tools/clis/maggie_service_booking.py validate-copy \
96
+ maggie tool maggie_service_booking.py validate-copy \
97
97
  --project . \
98
98
  --service-id fresha:15510886 \
99
99
  --copy-data docs/service-page-copy.json
100
100
 
101
- python3 tools/clis/maggie_service_booking.py run \
101
+ maggie tool maggie_service_booking.py run \
102
102
  "https://www.fresha.com/a/your-location" --project .
103
103
 
104
- python3 tools/clis/maggie_service_booking.py inspect --project .
105
- python3 tools/clis/maggie_service_booking.py status --project .
104
+ maggie tool maggie_service_booking.py inspect --project .
105
+ maggie tool maggie_service_booking.py status --project .
106
106
 
107
- python3 tools/clis/maggie_service_booking.py convert-page \
107
+ maggie tool maggie_service_booking.py convert-page \
108
108
  src/pages/services/scalp-ritual.astro --project .
109
109
 
110
- python3 tools/clis/maggie_service_booking.py match-pages \
110
+ maggie tool maggie_service_booking.py match-pages \
111
111
  --project . --pages-dir src/pages
112
112
 
113
113
  # Apply only reviewed matches; do not accept the first candidate automatically.
114
- python3 tools/clis/maggie_service_booking.py match-pages \
114
+ maggie tool maggie_service_booking.py match-pages \
115
115
  --project . --select 'fresha:15510886=/src/pages/lymphatic-drainage-massage-chevy-chase-md.astro'
116
116
 
117
117
  # One service may intentionally have multiple reviewed pages; repeat --select.
118
- python3 tools/clis/maggie_service_booking.py match-pages \
118
+ maggie tool maggie_service_booking.py match-pages \
119
119
  --project . \
120
120
  --select 'fresha:15510886=/src/pages/lymphatic-drainage-massage-chevy-chase-md.astro' \
121
121
  --select 'fresha:15510886=/src/pages/friendship-heights/lymphatic-drainage-massage.astro'
122
122
 
123
- python3 tools/clis/maggie_service_booking.py polish \
123
+ maggie tool maggie_service_booking.py polish \
124
124
  --project . \
125
125
  --service-id fresha:15510886 \
126
126
  --page src/pages/lymphatic-drainage-massage-chevy-chase-md.astro \
127
127
  --copy-data docs/service-page-copy.json
128
128
 
129
- python3 tools/clis/maggie_service_booking.py validate-polish \
129
+ maggie tool maggie_service_booking.py validate-polish \
130
130
  --project . --service-id fresha:15510886 \
131
131
  --page src/pages/lymphatic-drainage-massage-chevy-chase-md.astro \
132
132
  --copy-data docs/service-page-copy.json \
133
133
  --rendered http://127.0.0.1:4323/lymphatic-drainage-massage-chevy-chase-md/
134
134
 
135
- python3 tools/clis/maggie_service_booking.py category-audit \
135
+ maggie tool maggie_service_booking.py category-audit \
136
136
  --project . --rendered-dir /tmp/category-rendered
137
137
 
138
- python3 tools/clis/maggie_service_booking.py category-context --project .
138
+ maggie tool maggie_service_booking.py category-context --project .
139
139
 
140
140
  # Declare provider behavior, then validate it against the imported catalogue
141
141
  # and a sanitized fixture before publishing service pages.
142
- python3 tools/clis/maggie_service_booking.py capability-audit \
142
+ maggie tool maggie_service_booking.py capability-audit \
143
143
  --project . \
144
144
  --catalogue .maggie/booking/services.json \
145
145
  --capabilities-file .maggie/booking/provider-capabilities.json \
@@ -147,11 +147,11 @@ python3 tools/clis/maggie_service_booking.py capability-audit \
147
147
 
148
148
  # Answer whether provider-owned treatments are present using the same parser
149
149
  # as import/sync; do not search the whole provider page for a name.
150
- python3 tools/clis/maggie_service_booking.py catalogue-check \
150
+ maggie tool maggie_service_booking.py catalogue-check \
151
151
  "https://www.fresha.com/a/your-location" \
152
152
  --provider fresha --treatment "Lymphatic drainage massage"
153
153
 
154
- python3 tools/clis/maggie_service_booking.py retirement-audit \
154
+ maggie tool maggie_service_booking.py retirement-audit \
155
155
  --project . \
156
156
  --catalogue .maggie/booking/services.json \
157
157
  --evidence .maggie/booking/retirement-evidence.json
@@ -258,7 +258,7 @@ After the AI artifact is finalised, backfill only deterministic provenance
258
258
  metadata with:
259
259
 
260
260
  ```bash
261
- python3 tools/clis/maggie_service_booking.py category-hash \
261
+ maggie tool maggie_service_booking.py category-hash \
262
262
  --project . --copy-data docs/category-page-copy.json --apply
263
263
  ```
264
264
 
@@ -282,7 +282,7 @@ is `passed`.
282
282
  Run the imported-fact gate before generating service or category copy:
283
283
 
284
284
  ```bash
285
- python3 tools/clis/maggie_service_booking.py fact-audit \
285
+ maggie tool maggie_service_booking.py fact-audit \
286
286
  --project . --backfill-source
287
287
  ```
288
288
 
@@ -466,7 +466,7 @@ never let a catch-all route render an unlisted fallback page.
466
466
 
467
467
  Validate rendered sitemap output with:
468
468
 
469
- python3 tools/clis/maggie_service_booking.py sitemap-audit \
469
+ maggie tool maggie_service_booking.py sitemap-audit \
470
470
  --project . --index .maggie/rendered-sitemaps/sitemap.xml \
471
471
  --sitemap-dir .maggie/rendered-sitemaps
472
472
 
@@ -482,7 +482,7 @@ the route.
482
482
 
483
483
  Then audit the live route graph:
484
484
 
485
- python3 tools/clis/maggie_service_booking.py route-audit \
485
+ maggie tool maggie_service_booking.py route-audit \
486
486
  --project . --base-url https://example.co.uk
487
487
 
488
488
  This fetches every sitemap URL, requires HTTP 200, records internal inbound
@@ -22,9 +22,9 @@ and GEO. It is not a second content source of truth.
22
22
  Create the reviewable channel contract before generating copy:
23
23
 
24
24
  ```bash
25
- python3 tools/clis/maggie_social_share.py plan content.json \
25
+ maggie tool maggie_social_share.py plan content.json \
26
26
  --channels linkedin,facebook --output .maggie/social-share-plan.json
27
- python3 tools/clis/maggie_social_share.py validate .maggie/social-share-plan.json
27
+ maggie tool maggie_social_share.py validate .maggie/social-share-plan.json
28
28
  ```
29
29
 
30
30
  The CLI does not generate copy or publish. It validates identity, canonical
@@ -20,11 +20,11 @@ publish marketplace entries.
20
20
  Run from the AI CMO Skills repository, or use the equivalent installed tool:
21
21
 
22
22
  ```bash
23
- python3 tools/clis/maggie_marketplace.py list
24
- python3 tools/clis/maggie_marketplace.py list --category spa --tag luxury
25
- python3 tools/clis/maggie_marketplace.py suggest "premium London medical spa with editorial typography"
26
- python3 tools/clis/maggie_marketplace.py inspect medical-spa-landing-001
27
- python3 tools/clis/maggie_marketplace.py apply \
23
+ maggie tool maggie_marketplace.py list
24
+ maggie tool maggie_marketplace.py list --category spa --tag luxury
25
+ maggie tool maggie_marketplace.py suggest "premium London medical spa with editorial typography"
26
+ maggie tool maggie_marketplace.py inspect medical-spa-landing-001
27
+ maggie tool maggie_marketplace.py apply \
28
28
  --id medical-spa-landing-001 --project /path/to/astro-project
29
29
  ```
30
30
 
@@ -13,6 +13,7 @@ from urllib.parse import urlsplit
13
13
  import sys
14
14
  sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "runtime"))
15
15
  from analytics_traffic import audit_events # noqa: E402
16
+ from external_write import validate as validate_external_write # noqa: E402
16
17
 
17
18
 
18
19
  GA4_ID = re.compile(r"^G-[A-Z0-9]+$", re.I)
@@ -122,6 +123,12 @@ def release_gate(args: argparse.Namespace) -> int:
122
123
  errors.append("gsc-evidence-schema")
123
124
  elif args.require_gsc:
124
125
  errors.append("gsc-evidence-required")
126
+ if args.write_readback:
127
+ write_readback, write_errors = load_json(Path(args.write_readback).resolve(), "external write readback")
128
+ errors.extend(write_errors)
129
+ write_result = validate_external_write(write_readback or {})
130
+ check("external-write-readback", write_result["passed"], "idempotency, readback, duplicate, and cleanup evidence", checks)
131
+ errors.extend(write_result["errors"])
125
132
  if browser:
126
133
  check("browser-schema", browser.get("schemaVersion") == "maggie-analytics-browser.v1", "versioned browser evidence", checks)
127
134
  check("browser-render", browser.get("passed") is True and isinstance(browser.get("routes"), list) and bool(browser["routes"]), "routes rendered without a browser failure", checks)
@@ -191,6 +198,7 @@ def main() -> int:
191
198
  parser.add_argument("--smoke-report", help="production smoke evidence for release-gate")
192
199
  parser.add_argument("--gsc-evidence", help="versioned GSC readiness evidence for release-gate")
193
200
  parser.add_argument("--require-gsc", action="store_true", help="require GSC readiness evidence in release-gate")
201
+ parser.add_argument("--write-readback", help="hash-only external write/readback evidence for release-gate")
194
202
  parser.add_argument("--events", help="redacted JSON array of analytics events for traffic-audit")
195
203
  args = parser.parse_args()
196
204
  if args.command == "gsc-readiness":
@@ -10,6 +10,7 @@ from urllib.parse import urlparse
10
10
  RUNTIME = Path(__file__).resolve().parents[1] / "runtime"
11
11
  sys.path.insert(0, str(RUNTIME))
12
12
  from browser_behavior import validate_samples
13
+ from browser_capability import discover_browser_adapter, require_browser_adapter
13
14
  from localization_runner import checkpoint
14
15
 
15
16
 
@@ -108,10 +109,17 @@ def run_interactions(call, steps: list[dict]) -> list[dict]:
108
109
  def audit(args):
109
110
  if urlparse(args.url).scheme not in {"http", "https", "file"}:
110
111
  raise ValueError("URL must use http, https or file")
111
- if not args.required:
112
+ if not args.required and not args.check_browser:
112
113
  raise ValueError("at least one --required selector is necessary")
113
114
  output = args.output.resolve()
114
115
  output.mkdir(parents=True, exist_ok=True)
116
+ capability = discover_browser_adapter(args.browse)
117
+ capability_path = args.capability_report.resolve() if args.capability_report else output / "browser-capability.json"
118
+ checkpoint(capability_path, capability)
119
+ if args.check_browser:
120
+ print(json.dumps(capability, indent=2))
121
+ return 0 if capability["status"] == "ready" else 1
122
+ require_browser_adapter(args.browse)
115
123
  interactions = load_interactions(args.interactions)
116
124
  def call(*command):
117
125
  result = subprocess.run([str(args.browse), *command], capture_output=True, text=True, timeout=45)
@@ -120,7 +128,8 @@ def audit(args):
120
128
  return result.stdout
121
129
  report = {"schemaVersion": "maggie-browser-audit.v1", "url": args.url,
122
130
  "passed": False, "viewports": [], "evidence": "browser-captured",
123
- "interactionManifest": str(args.interactions.resolve()) if args.interactions else None}
131
+ "interactionManifest": str(args.interactions.resolve()) if args.interactions else None,
132
+ "browserCapability": str(capability_path)}
124
133
  try:
125
134
  for index, viewport in enumerate(args.viewport or ["390x844", "768x1024", "1440x900"]):
126
135
  width, height = [int(value) for value in viewport.split("x")]
@@ -158,6 +167,8 @@ def main():
158
167
  parser.add_argument("url")
159
168
  parser.add_argument("--browse", type=Path, required=True)
160
169
  parser.add_argument("--output", type=Path, required=True, help="new directory for evidence")
170
+ parser.add_argument("--capability-report", type=Path, help="write the redacted browser adapter capability report here")
171
+ parser.add_argument("--check-browser", action="store_true", help="only check adapter capability; do not navigate or write page evidence")
161
172
  parser.add_argument("--viewport", action="append")
162
173
  parser.add_argument("--required", action="append", default=[])
163
174
  parser.add_argument("--sticky", action="append", default=[])