wicked-garden 12.27.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.
- package/.claude-plugin/archetypes.json +166 -0
- package/.claude-plugin/components.json +75 -0
- package/.claude-plugin/marketplace.json +15 -0
- package/.claude-plugin/plugin.json +174 -0
- package/.claude-plugin/specialist.json +48 -0
- package/.claude-plugin/stack-registry.json +96 -0
- package/AGENTS.md +13 -0
- package/CHANGELOG.md +712 -0
- package/CONTRIBUTING.md +99 -0
- package/ETHOS.md +83 -0
- package/LICENSE +21 -0
- package/README.md +115 -0
- package/WICKED_GARDEN_BUS_EVENTS.md +149 -0
- package/agents/agentic/architect.md +449 -0
- package/agents/agentic/performance-analyst.md +702 -0
- package/agents/agentic/safety-reviewer.md +662 -0
- package/agents/crew/implementer.md +163 -0
- package/agents/crew/researcher.md +94 -0
- package/agents/crew/reviewer.md +184 -0
- package/agents/data/data-engineer.md +227 -0
- package/agents/engineering/api-documentarian.md +440 -0
- package/agents/engineering/migration-engineer.md +301 -0
- package/agents/engineering/solution-architect.md +208 -0
- package/agents/jam/brainstorm-facilitator.md +297 -0
- package/agents/jam/council.md +322 -0
- package/agents/jam/quick-facilitator.md +85 -0
- package/agents/persona/persona-agent.md +121 -0
- package/agents/platform/compliance-officer.md +266 -0
- package/agents/platform/privacy-expert.md +496 -0
- package/agents/platform/security-engineer.md +287 -0
- package/agents/product/a11y-expert.md +323 -0
- package/agents/product/requirements-analyst.md +238 -0
- package/agents/product/ui-reviewer.md +180 -0
- package/agents/product/ux-designer.md +199 -0
- package/agents/product/value-strategist.md +269 -0
- package/agents/qe/semantic-reviewer.md +78 -0
- package/commands/agentic/audit.md +24 -0
- package/commands/agentic/design.md +24 -0
- package/commands/agentic/frameworks.md +25 -0
- package/commands/agentic/review.md +27 -0
- package/commands/archetype/build.md +12 -0
- package/commands/archetype/decide.md +12 -0
- package/commands/archetype/explore.md +12 -0
- package/commands/archetype/incident.md +12 -0
- package/commands/archetype/migrate.md +12 -0
- package/commands/archetype/modernize.md +12 -0
- package/commands/archetype/review.md +14 -0
- package/commands/archetype/ship.md +12 -0
- package/commands/archetype/specify.md +12 -0
- package/commands/archetype/triage.md +12 -0
- package/commands/compile.md +37 -0
- package/commands/data/analyze.md +18 -0
- package/commands/data/data.md +21 -0
- package/commands/data/ml.md +18 -0
- package/commands/data/ontology.md +22 -0
- package/commands/data/pipeline.md +17 -0
- package/commands/deliberate.md +181 -0
- package/commands/engineering/add-field.md +77 -0
- package/commands/engineering/apply.md +58 -0
- package/commands/engineering/arch.md +26 -0
- package/commands/engineering/debug.md +27 -0
- package/commands/engineering/docs.md +27 -0
- package/commands/engineering/new-generator.md +257 -0
- package/commands/engineering/patch-plan.md +59 -0
- package/commands/engineering/plan.md +29 -0
- package/commands/engineering/remove.md +48 -0
- package/commands/engineering/rename.md +44 -0
- package/commands/engineering/review.md +32 -0
- package/commands/help.md +128 -0
- package/commands/install.md +118 -0
- package/commands/intent.md +54 -0
- package/commands/jam/brainstorm.md +37 -0
- package/commands/jam/council.md +49 -0
- package/commands/jam/quick.md +21 -0
- package/commands/jam/revisit.md +79 -0
- package/commands/persona/as.md +136 -0
- package/commands/persona/define.md +24 -0
- package/commands/persona/list.md +118 -0
- package/commands/platform/actions.md +20 -0
- package/commands/platform/assert.md +18 -0
- package/commands/platform/audit.md +23 -0
- package/commands/platform/compliance.md +20 -0
- package/commands/platform/gh.md +22 -0
- package/commands/platform/health.md +22 -0
- package/commands/platform/incident.md +23 -0
- package/commands/platform/infra.md +24 -0
- package/commands/platform/peer-health.md +103 -0
- package/commands/platform/plugin-health.md +58 -0
- package/commands/platform/security.md +38 -0
- package/commands/platform/toolchain.md +96 -0
- package/commands/platform/traces.md +20 -0
- package/commands/product/a11y.md +19 -0
- package/commands/product/acceptance.md +19 -0
- package/commands/product/align.md +20 -0
- package/commands/product/analyze.md +23 -0
- package/commands/product/elicit.md +19 -0
- package/commands/product/listen.md +24 -0
- package/commands/product/mockup.md +20 -0
- package/commands/product/screenshot.md +19 -0
- package/commands/product/strategy.md +40 -0
- package/commands/product/synthesize.md +23 -0
- package/commands/product/ux-review.md +42 -0
- package/commands/product/ux.md +20 -0
- package/commands/product/visual-direction.md +34 -0
- package/commands/prove.md +47 -0
- package/commands/report-issue.md +243 -0
- package/commands/reset.md +144 -0
- package/commands/search/blast-radius.md +58 -0
- package/commands/search/hotspots.md +55 -0
- package/commands/search/index.md +38 -0
- package/commands/search/lineage.md +47 -0
- package/commands/search/service-map.md +79 -0
- package/commands/setup.md +363 -0
- package/commands/smaht/briefing.md +200 -0
- package/commands/smaht/events-import.md +95 -0
- package/commands/smaht/state.md +19 -0
- package/commands/where-am-i.md +58 -0
- package/docs/README.md +32 -0
- package/docs/adr/0001-code-relationship-graph-engine.md +116 -0
- package/docs/adr/0002-major-cleanup-keep-cut.md +91 -0
- package/docs/adr/0003-peers-gate-required-layers-optin.md +41 -0
- package/docs/adr/0004-code-graph-moves-to-wicked-brain.md +47 -0
- package/docs/brain-chunk-format.md +135 -0
- package/docs/compiler.md +95 -0
- package/docs/daemon-api.md +70 -0
- package/docs/domains.md +197 -0
- package/docs/getting-started.md +208 -0
- package/docs/plans/2026-06-08-wicked-loom-conduct.md +1337 -0
- package/docs/plans/2026-06-08-wicked-loom-contract.md +638 -0
- package/docs/plans/2026-06-08-wicked-loom-cutover.md +1300 -0
- package/docs/plans/2026-06-08-wicked-loom-expand-compose.md +843 -0
- package/docs/plans/2026-06-08-wicked-loom-flow-cutover.md +403 -0
- package/docs/plans/2026-06-10-codegraph-to-brain-phase1a-graph-core.md +838 -0
- package/docs/plans/2026-06-10-codegraph-to-brain-phase1b-injected-edges.md +44 -0
- package/docs/required-peers.md +60 -0
- package/docs/specs/2026-06-08-wicked-loom-extraction.md +225 -0
- package/docs/specs/2026-06-10-codegraph-to-brain-migration.md +168 -0
- package/docs/v11/archetypes.md +231 -0
- package/hooks/hooks.json +275 -0
- package/hooks/scripts/bootstrap.py +1797 -0
- package/hooks/scripts/invoke.py +62 -0
- package/hooks/scripts/notification.py +166 -0
- package/hooks/scripts/permission_request.py +223 -0
- package/hooks/scripts/post_tool.py +1374 -0
- package/hooks/scripts/pre_compact.py +272 -0
- package/hooks/scripts/pre_tool.py +1278 -0
- package/hooks/scripts/prompt_submit.py +1109 -0
- package/hooks/scripts/session_end.py +95 -0
- package/hooks/scripts/stop.py +624 -0
- package/hooks/scripts/subagent_lifecycle.py +464 -0
- package/hooks/scripts/subscribers/on_gate_decided.py +84 -0
- package/hooks/scripts/task_completed.py +322 -0
- package/hooks/scripts/worktree_guard.py +148 -0
- package/hooks/subscriptions/on_gate_decided.json +9 -0
- package/install.mjs +128 -0
- package/package.json +41 -0
- package/pyproject.toml +59 -0
- package/schemas/README.md +32 -0
- package/schemas/assert_contracts.json +37 -0
- package/schemas/health_probe.json +46 -0
- package/schemas/plugin_status.json +37 -0
- package/scripts/_adapters/__init__.py +166 -0
- package/scripts/_adapters/jira_adapter.py +18 -0
- package/scripts/_adapters/linear_adapter.py +18 -0
- package/scripts/_adapters/miro_adapter.py +18 -0
- package/scripts/_adapters/notion_adapter.py +18 -0
- package/scripts/_agents.py +357 -0
- package/scripts/_brain_ingest/__init__.py +2 -0
- package/scripts/_brain_ingest/session_fact_extractor.py +341 -0
- package/scripts/_brain_port.py +163 -0
- package/scripts/_bus.py +1081 -0
- package/scripts/_bus_catalog_gen.py +93 -0
- package/scripts/_bus_consumers.json +46 -0
- package/scripts/_bus_emit.py +43 -0
- package/scripts/_capability_registry.py +334 -0
- package/scripts/_capability_resolver.py +322 -0
- package/scripts/_domain_store.py +559 -0
- package/scripts/_event_log_reader.py +154 -0
- package/scripts/_event_schema.py +305 -0
- package/scripts/_event_store.py +397 -0
- package/scripts/_heavy_cadence.py +324 -0
- package/scripts/_integration_resolver.py +321 -0
- package/scripts/_logger.py +151 -0
- package/scripts/_loom.py +482 -0
- package/scripts/_paths.py +133 -0
- package/scripts/_python.sh +22 -0
- package/scripts/_run.py +137 -0
- package/scripts/_session.py +502 -0
- package/scripts/_validate_registry.py +1042 -0
- package/scripts/_wicked_testing_probe.py +277 -0
- package/scripts/agentic/analyze_agents.py +391 -0
- package/scripts/agentic/detect_framework.py +420 -0
- package/scripts/agentic/issue_taxonomy.py +357 -0
- package/scripts/agentic/pattern_scorer.py +434 -0
- package/scripts/classify/persist.py +169 -0
- package/scripts/compiler/compile.py +552 -0
- package/scripts/compiler/phase0/VERDICT.md +60 -0
- package/scripts/compiler/phase0/detect.py +292 -0
- package/scripts/compiler/phase0/emit.py +228 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.bindings.json +30 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/honest-tests.txt +2 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/command_iq.bindings.json +45 -0
- package/scripts/compiler/phase0/evidence/command_iq.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/honest-tests.txt +3 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/memos.bindings.json +28 -0
- package/scripts/compiler/phase0/evidence/memos.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/honest-tests.txt +2 -0
- package/scripts/compiler/phase0/evidence/memos.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/memos.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/memos.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/memos.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/verdict.json +104 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.bindings.json +29 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/honest-tests.txt +3 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/wire-vault-transcript.txt +60 -0
- package/scripts/compiler/phase0/run_probe.py +234 -0
- package/scripts/compiler/phase0/wire_vault.py +310 -0
- package/scripts/crew/__init__.py +0 -0
- package/scripts/crew/_task_audit_writer.py +243 -0
- package/scripts/crew/_task_reader.py +389 -0
- package/scripts/crew/archetypes_v11.py +348 -0
- package/scripts/crew/detectors/__init__.py +12 -0
- package/scripts/crew/flow_compiler.py +121 -0
- package/scripts/crew/phase_manager.py +703 -0
- package/scripts/crew/scope_delta.py +264 -0
- package/scripts/crew/specialist_resolver.py +218 -0
- package/scripts/crew/stack_registry.py +189 -0
- package/scripts/data/data_profiler.py +271 -0
- package/scripts/data/ontology_recommender.py +231 -0
- package/scripts/data/schema_validator.py +267 -0
- package/scripts/delivery/drift.py +739 -0
- package/scripts/delivery/telemetry.py +614 -0
- package/scripts/engineering/patch/codegraph_db.py +125 -0
- package/scripts/engineering/patch/generators/__init__.py +56 -0
- package/scripts/engineering/patch/generators/base.py +373 -0
- package/scripts/engineering/patch/generators/csharp_generator.py +494 -0
- package/scripts/engineering/patch/generators/go_generator.py +430 -0
- package/scripts/engineering/patch/generators/java_generator.py +928 -0
- package/scripts/engineering/patch/generators/jsp_generator.py +454 -0
- package/scripts/engineering/patch/generators/kotlin_generator.py +561 -0
- package/scripts/engineering/patch/generators/perl_generator.py +510 -0
- package/scripts/engineering/patch/generators/php_generator.py +644 -0
- package/scripts/engineering/patch/generators/propagation_engine.py +929 -0
- package/scripts/engineering/patch/generators/python_generator.py +487 -0
- package/scripts/engineering/patch/generators/ruby_generator.py +463 -0
- package/scripts/engineering/patch/generators/rust_generator.py +400 -0
- package/scripts/engineering/patch/generators/sql_generator.py +594 -0
- package/scripts/engineering/patch/generators/typescript_generator.py +439 -0
- package/scripts/engineering/patch/patch.py +800 -0
- package/scripts/engineering/patch/safety.py +429 -0
- package/scripts/jam/__init__.py +0 -0
- package/scripts/jam/_bus_consumers.py +271 -0
- package/scripts/jam/agentic_cli_registry.py +703 -0
- package/scripts/jam/consensus.py +737 -0
- package/scripts/jam/detect_clis.py +409 -0
- package/scripts/jam/jam.py +283 -0
- package/scripts/jam/save_transcript.py +171 -0
- package/scripts/loom/__init__.py +22 -0
- package/scripts/loom/cli.py +170 -0
- package/scripts/loom/compose.py +180 -0
- package/scripts/loom/gate.py +120 -0
- package/scripts/loom/manifest.py +140 -0
- package/scripts/loom/resolve.py +59 -0
- package/scripts/persona/__init__.py +0 -0
- package/scripts/persona/registry.py +688 -0
- package/scripts/platform/guard_pipeline.py +1214 -0
- package/scripts/platform/guard_profiles.py +216 -0
- package/scripts/platform/observability/assert_contracts.py +434 -0
- package/scripts/platform/observability/health_probe.py +915 -0
- package/scripts/platform/observability/ops_log_viewer.py +209 -0
- package/scripts/platform/prereq_doctor.py +567 -0
- package/scripts/qe/conditions_manifest.py +260 -0
- package/scripts/qe/content_sanitizer.py +160 -0
- package/scripts/qe/coverage_tracker.py +535 -0
- package/scripts/qe/discover_scenarios.py +243 -0
- package/scripts/qe/evidence_tracker.py +232 -0
- package/scripts/qe/prove.py +196 -0
- package/scripts/qe/registry_lookup.py +80 -0
- package/scripts/qe/registry_store.py +176 -0
- package/scripts/qe/semantic_review.py +1005 -0
- package/scripts/qe/vault_gate.py +382 -0
- package/scripts/qe/verdict_audit.py +175 -0
- package/scripts/qe/verdict_schema.py +335 -0
- package/scripts/reset.py +220 -0
- package/scripts/resolve_path.py +22 -0
- package/scripts/sentinel/invariants.py +402 -0
- package/scripts/sentinel/pre_push.py +73 -0
- package/scripts/setup/__init__.py +1 -0
- package/scripts/setup/detect_state.py +114 -0
- package/scripts/setup/migrate_legacy.py +67 -0
- package/scripts/setup/migrate_v6_projects.py +232 -0
- package/scripts/setup/onboarding.py +114 -0
- package/scripts/smaht/_bus_consumers.py +98 -0
- package/scripts/smaht/adapters/__init__.py +83 -0
- package/scripts/smaht/adapters/brain_adapter.py +254 -0
- package/scripts/smaht/adapters/context7_adapter.py +438 -0
- package/scripts/smaht/adapters/delegation_adapter.py +104 -0
- package/scripts/smaht/adapters/domain_adapter.py +206 -0
- package/scripts/smaht/adapters/events_adapter.py +231 -0
- package/scripts/smaht/adapters/tools_adapter.py +49 -0
- package/scripts/smaht/cheatsheet_store.py +236 -0
- package/scripts/smaht/context_package.py +386 -0
- package/scripts/smaht/knowledge_graph.py +395 -0
- package/scripts/smaht/propose_skills.py +856 -0
- package/scripts/smaht/test_cheatsheet_store.py +428 -0
- package/scripts/statusline.py +151 -0
- package/scripts/where_am_i.py +236 -0
- package/skills/agentic/agentic-patterns/SKILL.md +91 -0
- package/skills/agentic/agentic-patterns/refs/anti-patterns-design.md +283 -0
- package/skills/agentic/agentic-patterns/refs/anti-patterns-operational.md +216 -0
- package/skills/agentic/agentic-patterns/refs/pattern-catalog.md +329 -0
- package/skills/agentic/context-engineering/SKILL.md +142 -0
- package/skills/agentic/context-engineering/refs/caching-and-optimization.md +251 -0
- package/skills/agentic/context-engineering/refs/compression-techniques.md +171 -0
- package/skills/agentic/context-engineering/refs/cost-calculation-budget.md +250 -0
- package/skills/agentic/context-engineering/refs/cost-optimization-reporting.md +300 -0
- package/skills/agentic/context-engineering/refs/selective-loading.md +179 -0
- package/skills/agentic/frameworks/SKILL.md +191 -0
- package/skills/agentic/frameworks/refs/framework-profiles-1.md +209 -0
- package/skills/agentic/frameworks/refs/framework-profiles-2.md +214 -0
- package/skills/agentic/frameworks/refs/migration-patterns-paths.md +267 -0
- package/skills/agentic/frameworks/refs/migration-patterns-testing.md +208 -0
- package/skills/agentic/refs/audit.md +134 -0
- package/skills/agentic/refs/design.md +137 -0
- package/skills/agentic/refs/frameworks.md +102 -0
- package/skills/agentic/refs/review.md +160 -0
- package/skills/agentic/review-methodology/SKILL.md +186 -0
- package/skills/agentic/review-methodology/refs/deliverable-templates.md +246 -0
- package/skills/agentic/review-methodology/refs/issue-taxonomy-quality-testing.md +277 -0
- package/skills/agentic/review-methodology/refs/issue-taxonomy-reliability-safety.md +253 -0
- package/skills/agentic/trust-and-safety/SKILL.md +177 -0
- package/skills/agentic/trust-and-safety/refs/guardrails-actions.md +246 -0
- package/skills/agentic/trust-and-safety/refs/guardrails-input-output.md +238 -0
- package/skills/agentic/trust-and-safety/refs/guardrails-resources.md +209 -0
- package/skills/agentic/trust-and-safety/refs/safety-checklist-advanced.md +209 -0
- package/skills/agentic/trust-and-safety/refs/safety-checklist-core.md +215 -0
- package/skills/archetype/SKILL.md +104 -0
- package/skills/archetype/refs/build.md +142 -0
- package/skills/archetype/refs/decide.md +117 -0
- package/skills/archetype/refs/explore.md +66 -0
- package/skills/archetype/refs/incident.md +149 -0
- package/skills/archetype/refs/migrate.md +170 -0
- package/skills/archetype/refs/modernize.md +187 -0
- package/skills/archetype/refs/review.md +145 -0
- package/skills/archetype/refs/ship.md +117 -0
- package/skills/archetype/refs/specify.md +108 -0
- package/skills/archetype/refs/triage.md +62 -0
- package/skills/classify/SKILL.md +157 -0
- package/skills/data/analysis/SKILL.md +125 -0
- package/skills/data/analysis/refs/templates.md +170 -0
- package/skills/data/data/SKILL.md +118 -0
- package/skills/data/data/refs/examples.md +235 -0
- package/skills/data/ml/SKILL.md +125 -0
- package/skills/data/ml/refs/templates.md +172 -0
- package/skills/data/pipeline/SKILL.md +136 -0
- package/skills/data/pipeline/refs/templates.md +175 -0
- package/skills/data/refs/analyze.md +123 -0
- package/skills/data/refs/data.md +95 -0
- package/skills/data/refs/ml.md +118 -0
- package/skills/data/refs/pipeline.md +92 -0
- package/skills/deliberate/SKILL.md +125 -0
- package/skills/deliberate/refs/architecture-lens.md +37 -0
- package/skills/deliberate/refs/assumptions-lens.md +43 -0
- package/skills/deliberate/refs/code-lens.md +38 -0
- package/skills/deliberate/refs/content-lens.md +37 -0
- package/skills/deliberate/refs/data-lens.md +43 -0
- package/skills/deliberate/refs/design-lens.md +37 -0
- package/skills/deliberate/refs/opportunity-patterns.md +107 -0
- package/skills/deliberate/refs/ops-lens.md +43 -0
- package/skills/deliberate/refs/product-lens.md +46 -0
- package/skills/deliberate/refs/rethink-framework.md +77 -0
- package/skills/deliberate/refs/security-lens.md +47 -0
- package/skills/deliberate/refs/testing-lens.md +45 -0
- package/skills/deliberate/refs/timing-lens.md +42 -0
- package/skills/engineering/architecture/SKILL.md +177 -0
- package/skills/engineering/architecture/refs/adr-template.md +268 -0
- package/skills/engineering/architecture/refs/architecture-template-deployment.md +176 -0
- package/skills/engineering/architecture/refs/architecture-template-design.md +300 -0
- package/skills/engineering/architecture/refs/examples-ecommerce-analytics.md +299 -0
- package/skills/engineering/architecture/refs/examples-saas-trading.md +291 -0
- package/skills/engineering/architecture/refs/patterns-advanced.md +238 -0
- package/skills/engineering/architecture/refs/patterns-structural.md +303 -0
- package/skills/engineering/backend/SKILL.md +102 -0
- package/skills/engineering/backend/refs/checklists.md +146 -0
- package/skills/engineering/backend/refs/patterns.md +181 -0
- package/skills/engineering/debugging/SKILL.md +99 -0
- package/skills/engineering/debugging/refs/patterns.md +248 -0
- package/skills/engineering/debugging/refs/process.md +203 -0
- package/skills/engineering/docs/SKILL.md +97 -0
- package/skills/engineering/engineering/SKILL.md +88 -0
- package/skills/engineering/engineering/refs/checklists.md +91 -0
- package/skills/engineering/engineering/refs/templates.md +71 -0
- package/skills/engineering/frontend/SKILL.md +92 -0
- package/skills/engineering/frontend/refs/checklists.md +96 -0
- package/skills/engineering/frontend/refs/patterns.md +167 -0
- package/skills/engineering/integration/SKILL.md +183 -0
- package/skills/engineering/integration/refs/error-handling-best-practices.md +139 -0
- package/skills/engineering/integration/refs/error-handling-error-classes-typescript.md +212 -0
- package/skills/engineering/integration/refs/error-handling-error-response-format.md +301 -0
- package/skills/engineering/integration/refs/error-handling-retry-strategies.md +190 -0
- package/skills/engineering/integration/refs/event-schemas-best-practices.md +225 -0
- package/skills/engineering/integration/refs/event-schemas-event-naming-conventions.md +303 -0
- package/skills/engineering/integration/refs/event-schemas-event-structure.md +288 -0
- package/skills/engineering/integration/refs/graphql-best-practices.md +138 -0
- package/skills/engineering/integration/refs/graphql-error-handling.md +198 -0
- package/skills/engineering/integration/refs/graphql-graphql-basics.md +197 -0
- package/skills/engineering/integration/refs/graphql-query-examples.md +226 -0
- package/skills/engineering/integration/refs/graphql-schema-design-patterns.md +280 -0
- package/skills/engineering/integration/refs/grpc-grpc-overview.md +246 -0
- package/skills/engineering/integration/refs/grpc-implementation-examples.md +269 -0
- package/skills/engineering/integration/refs/grpc-metadata-headers.md +304 -0
- package/skills/engineering/integration/refs/grpc-testing.md +49 -0
- package/skills/engineering/integration/refs/openapi-template.yaml +682 -0
- package/skills/engineering/integration/refs/resilience-best-practices.md +109 -0
- package/skills/engineering/integration/refs/resilience-circuit-breaker-pattern.md +302 -0
- package/skills/engineering/integration/refs/resilience-rate-limiting.md +245 -0
- package/skills/engineering/integration/refs/resilience-timeout-pattern.md +212 -0
- package/skills/engineering/integration/refs/rest-api-fundamentals.md +299 -0
- package/skills/engineering/integration/refs/rest-api-responses-security.md +302 -0
- package/skills/engineering/integration/refs/versioning-breaking-changes.md +237 -0
- package/skills/engineering/integration/refs/versioning-migration-strategies.md +257 -0
- package/skills/engineering/integration/refs/versioning-versioning-strategies.md +296 -0
- package/skills/engineering/large-scale-migration/SKILL.md +65 -0
- package/skills/engineering/patch/SKILL.md +184 -0
- package/skills/engineering/refs/arch.md +126 -0
- package/skills/engineering/refs/debug.md +142 -0
- package/skills/engineering/refs/docs.md +190 -0
- package/skills/engineering/refs/plan.md +109 -0
- package/skills/engineering/refs/review.md +138 -0
- package/skills/engineering/system-design/SKILL.md +154 -0
- package/skills/engineering/system-design/refs/anti-patterns-big-ball-of-mud.md +254 -0
- package/skills/engineering/system-design/refs/anti-patterns-circular-dependencies.md +241 -0
- package/skills/engineering/system-design/refs/anti-patterns-feature-envy.md +168 -0
- package/skills/engineering/system-design/refs/anti-patterns-god-object.md +247 -0
- package/skills/engineering/system-design/refs/component-template-lifecycle.md +210 -0
- package/skills/engineering/system-design/refs/component-template-maintenance.md +219 -0
- package/skills/engineering/system-design/refs/component-template-structure.md +276 -0
- package/skills/engineering/system-design/refs/dependencies-best-practices.md +260 -0
- package/skills/engineering/system-design/refs/dependencies-dependency-principles.md +295 -0
- package/skills/engineering/system-design/refs/dependencies-dependency-tracking.md +261 -0
- package/skills/engineering/system-design/refs/interface-template-lifecycle.md +211 -0
- package/skills/engineering/system-design/refs/interface-template-maintenance.md +212 -0
- package/skills/engineering/system-design/refs/interface-template-structure.md +269 -0
- package/skills/engineering/system-design/refs/patterns-dependency-injection.md +151 -0
- package/skills/engineering/system-design/refs/patterns-facade-pattern.md +257 -0
- package/skills/engineering/system-design/refs/patterns-layered-pattern.md +204 -0
- package/skills/engineering/system-design/refs/patterns-plugin-architecture.md +229 -0
- package/skills/engineering/unit-test-quality/SKILL.md +194 -0
- package/skills/ground/SKILL.md +130 -0
- package/skills/integration-discovery/SKILL.md +168 -0
- package/skills/integration-discovery/refs/capabilities.md +282 -0
- package/skills/integration-discovery/refs/cli-detection.md +295 -0
- package/skills/integration-discovery/refs/discovery-sources.md +233 -0
- package/skills/integration-discovery/refs/task-patterns.md +206 -0
- package/skills/jam/SKILL.md +45 -0
- package/skills/jam/refs/facilitation-patterns.md +125 -0
- package/skills/jam/refs/quick.md +64 -0
- package/skills/jam/refs/synthesis-patterns.md +114 -0
- package/skills/multi-model/SKILL.md +168 -0
- package/skills/multi-model/refs/aichat.md +119 -0
- package/skills/multi-model/refs/aider.md +100 -0
- package/skills/multi-model/refs/auditability.md +238 -0
- package/skills/multi-model/refs/codex.md +169 -0
- package/skills/multi-model/refs/context.md +306 -0
- package/skills/multi-model/refs/copilot.md +161 -0
- package/skills/multi-model/refs/examples.md +224 -0
- package/skills/multi-model/refs/gemini.md +185 -0
- package/skills/multi-model/refs/goose.md +112 -0
- package/skills/multi-model/refs/llm.md +124 -0
- package/skills/multi-model/refs/opencode.md +196 -0
- package/skills/multi-model/refs/orchestration.md +188 -0
- package/skills/multi-model/refs/pi.md +208 -0
- package/skills/persona/SKILL.md +144 -0
- package/skills/persona/refs/define.md +133 -0
- package/skills/platform/actions/refs/actions.md +114 -0
- package/skills/platform/audit/SKILL.md +174 -0
- package/skills/platform/audit/refs/audit.md +145 -0
- package/skills/platform/audit/refs/checklists-evidence-operations.md +144 -0
- package/skills/platform/audit/refs/checklists-gdpr-pci-evidence.md +213 -0
- package/skills/platform/audit/refs/checklists-soc2-hipaa.md +120 -0
- package/skills/platform/audit/refs/frameworks-gdpr-pci.md +225 -0
- package/skills/platform/audit/refs/frameworks-soc2-hipaa.md +228 -0
- package/skills/platform/compliance/SKILL.md +169 -0
- package/skills/platform/compliance/refs/checklists.md +303 -0
- package/skills/platform/compliance/refs/compliance.md +117 -0
- package/skills/platform/compliance/refs/frameworks.md +282 -0
- package/skills/platform/errors/SKILL.md +183 -0
- package/skills/platform/errors/refs/patterns.md +271 -0
- package/skills/platform/errors/refs/severity.md +264 -0
- package/skills/platform/gate-benchmark-rebaseline/SKILL.md +108 -0
- package/skills/platform/gh/refs/gh.md +105 -0
- package/skills/platform/gh-cli/SKILL.md +120 -0
- package/skills/platform/gh-cli/refs/automation.md +63 -0
- package/skills/platform/gh-cli/refs/gh-ops.md +103 -0
- package/skills/platform/gh-cli/refs/patterns.md +132 -0
- package/skills/platform/gh-cli/scripts/gh_ops.py +454 -0
- package/skills/platform/github-actions/SKILL.md +159 -0
- package/skills/platform/github-actions/refs/security.md +150 -0
- package/skills/platform/github-actions/refs/templates.md +230 -0
- package/skills/platform/github-actions/refs/troubleshooting.md +174 -0
- package/skills/platform/github-actions/scripts/workflow_gen.py +215 -0
- package/skills/platform/gitlab-ci/SKILL.md +140 -0
- package/skills/platform/gitlab-ci/refs/templates.md +223 -0
- package/skills/platform/gitlab-ci/refs/troubleshooting.md +213 -0
- package/skills/platform/glab-cli/SKILL.md +133 -0
- package/skills/platform/glab-cli/refs/ci-debugging.md +95 -0
- package/skills/platform/glab-cli/refs/glab-ops.md +78 -0
- package/skills/platform/glab-cli/refs/patterns.md +131 -0
- package/skills/platform/glab-cli/scripts/glab_ops.py +313 -0
- package/skills/platform/health/SKILL.md +177 -0
- package/skills/platform/health/refs/health.md +72 -0
- package/skills/platform/health/refs/sources.md +302 -0
- package/skills/platform/incident/refs/incident.md +136 -0
- package/skills/platform/infra/refs/infra.md +104 -0
- package/skills/platform/observability/SKILL.md +128 -0
- package/skills/platform/observability/refs/toolchain-discovery.md +243 -0
- package/skills/platform/prereq-doctor/SKILL.md +57 -0
- package/skills/platform/prereq-doctor/refs/tool-registry.md +58 -0
- package/skills/platform/traces/refs/traces.md +101 -0
- package/skills/product/acceptance-criteria/SKILL.md +193 -0
- package/skills/product/acceptance-criteria/refs/ac-anti-patterns.md +291 -0
- package/skills/product/acceptance-criteria/refs/ac-examples.md +277 -0
- package/skills/product/accessibility/SKILL.md +197 -0
- package/skills/product/accessibility/refs/aria-patterns-basics.md +250 -0
- package/skills/product/accessibility/refs/aria-patterns-dynamic.md +187 -0
- package/skills/product/accessibility/refs/aria-patterns-interactive.md +246 -0
- package/skills/product/accessibility/refs/audit-report-findings.md +248 -0
- package/skills/product/accessibility/refs/audit-report-results.md +276 -0
- package/skills/product/accessibility/refs/common-violations-html-css.md +270 -0
- package/skills/product/accessibility/refs/common-violations-interactive.md +303 -0
- package/skills/product/accessibility/refs/keyboard-testing-basics.md +222 -0
- package/skills/product/accessibility/refs/keyboard-testing-patterns.md +173 -0
- package/skills/product/accessibility/refs/screen-reader-testing-advanced.md +294 -0
- package/skills/product/accessibility/refs/screen-reader-testing-commands.md +255 -0
- package/skills/product/accessibility/refs/wcag-checklist.md +262 -0
- package/skills/product/analyze/SKILL.md +164 -0
- package/skills/product/analyze/refs/algorithms.md +238 -0
- package/skills/product/analyze/refs/sentiment-patterns.md +180 -0
- package/skills/product/imagery/SKILL.md +97 -0
- package/skills/product/imagery/alter/SKILL.md +105 -0
- package/skills/product/imagery/alter/refs/editing-reference.md +146 -0
- package/skills/product/imagery/create/SKILL.md +109 -0
- package/skills/product/imagery/create/refs/prompt-engineering.md +112 -0
- package/skills/product/imagery/create/refs/provider-reference.md +219 -0
- package/skills/product/imagery/review/SKILL.md +101 -0
- package/skills/product/imagery/review/refs/analysis-lenses.md +136 -0
- package/skills/product/imagery/review/refs/quality-gates.md +153 -0
- package/skills/product/imagery/scripts/analyze.sh +23 -0
- package/skills/product/imagery/scripts/edit.sh +14 -0
- package/skills/product/imagery/scripts/generate.sh +13 -0
- package/skills/product/imagery/scripts/provider.py +787 -0
- package/skills/product/listen/SKILL.md +175 -0
- package/skills/product/listen/refs/channels.md +220 -0
- package/skills/product/mockup/SKILL.md +106 -0
- package/skills/product/mockup/refs/templates.md +95 -0
- package/skills/product/refs/a11y.md +109 -0
- package/skills/product/refs/acceptance.md +79 -0
- package/skills/product/refs/align.md +67 -0
- package/skills/product/refs/analyze.md +77 -0
- package/skills/product/refs/elicit.md +67 -0
- package/skills/product/refs/listen.md +58 -0
- package/skills/product/refs/mockup.md +77 -0
- package/skills/product/refs/screenshot.md +59 -0
- package/skills/product/refs/strategy.md +77 -0
- package/skills/product/refs/synthesize.md +54 -0
- package/skills/product/refs/ux-review.md +68 -0
- package/skills/product/refs/ux.md +101 -0
- package/skills/product/requirements-analysis/SKILL.md +136 -0
- package/skills/product/requirements-analysis/refs/requirements-example-auth.md +264 -0
- package/skills/product/requirements-analysis/refs/requirements-example-export-integration.md +88 -0
- package/skills/product/requirements-analysis/refs/requirements-output-format-template.md +247 -0
- package/skills/product/requirements-analysis/refs/user-story-guide.md +296 -0
- package/skills/product/requirements-graph/SKILL.md +155 -0
- package/skills/product/requirements-graph/refs/examples.md +223 -0
- package/skills/product/requirements-graph/refs/schema.md +162 -0
- package/skills/product/requirements-migrate/SKILL.md +90 -0
- package/skills/product/requirements-navigate/SKILL.md +141 -0
- package/skills/product/requirements-navigate/refs/meta-templates.md +141 -0
- package/skills/product/screenshot/SKILL.md +147 -0
- package/skills/product/strategy/SKILL.md +198 -0
- package/skills/product/strategy/refs/frameworks.md +295 -0
- package/skills/product/strategy/refs/templates-competitive-market.md +299 -0
- package/skills/product/strategy/refs/templates-roi-value.md +207 -0
- package/skills/product/synthesize/SKILL.md +116 -0
- package/skills/product/synthesize/refs/journey-mapping.md +212 -0
- package/skills/product/synthesize/refs/prioritization.md +193 -0
- package/skills/product/ux-review/SKILL.md +164 -0
- package/skills/product/visual-direction/SKILL.md +137 -0
- package/skills/product/visual-review/SKILL.md +131 -0
- package/skills/runtime-exec/SKILL.md +138 -0
- package/skills/search/codebase-narrator/SKILL.md +131 -0
- package/skills/search/codebase-narrator/refs/output-template.md +100 -0
- package/skills/smaht/SKILL.md +72 -0
- package/skills/smaht/discovery/SKILL.md +65 -0
- package/skills/smaht/intent/SKILL.md +89 -0
- package/skills/smaht/propose-skills/SKILL.md +142 -0
- package/skills/smaht/refs/state.md +76 -0
- package/skills/swarm/SKILL.md +132 -0
- package/skills/swarm/refs/fan-out.md +104 -0
- package/skills/swarm/refs/independent-verification.md +86 -0
- package/skills/swarm/refs/receipts-and-evidence.md +69 -0
- package/skills/swarm/refs/recon-synthesis.md +87 -0
- package/skills/swarm/refs/ship-discipline.md +90 -0
- package/skills/wickedizer/SKILL.md +147 -0
- package/skills/wickedizer/refs/artifact-types.md +238 -0
- package/skills/wickedizer/refs/complexity.md +278 -0
- package/skills/wickedizer/refs/de-ai-pass.md +140 -0
- package/skills/wickedizer/refs/failure-modes.md +249 -0
- package/skills/wickedizer/refs/patterns.md +282 -0
- package/skills/wickedizer/refs/review.md +221 -0
- package/skills/wickedizer/refs/structure.md +282 -0
- package/skills/wickedizer/refs/voice-profile.md +125 -0
- package/skills/workflow/SKILL.md +132 -0
- package/skills/workflow/refs/archetype-adjustments.md +205 -0
- package/skills/workflow/refs/evidence.md +58 -0
- package/skills/workflow/refs/integration.md +130 -0
- package/skills/workflow/refs/risk-dimension-signals.md +260 -0
- package/skills/workflow/refs/scoring-rubric.md +49 -0
- package/skills/workflow/refs/signal-keywords.md +176 -0
- package/skills/workflow/refs/specialist-routing-rules.md +159 -0
- package/skills/worktrees/SKILL.md +87 -0
- package/skills/worktrees/refs/recipes.md +96 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Discover wicked-scenarios plugin and list available E2E scenarios.
|
|
3
|
+
|
|
4
|
+
Cross-plugin discovery utility that finds wicked-scenarios if installed,
|
|
5
|
+
parses scenario metadata, and returns structured JSON.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python3 discover_scenarios.py # All scenarios
|
|
9
|
+
python3 discover_scenarios.py --category api # Filter by category
|
|
10
|
+
python3 discover_scenarios.py --available-only # Only runnable scenarios
|
|
11
|
+
python3 discover_scenarios.py --check-tools # Include tool availability
|
|
12
|
+
"""
|
|
13
|
+
import json
|
|
14
|
+
import re
|
|
15
|
+
import subprocess
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _parse_version(v: str) -> tuple:
|
|
21
|
+
"""Parse semver string to comparable tuple."""
|
|
22
|
+
match = re.match(r"(\d+)\.(\d+)\.(\d+)", v)
|
|
23
|
+
if match:
|
|
24
|
+
return tuple(int(x) for x in match.groups())
|
|
25
|
+
return (0, 0, 0)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def discover_plugin(plugin_name: str) -> "Path | None":
|
|
29
|
+
"""Find a plugin's root directory via cache or local repo.
|
|
30
|
+
|
|
31
|
+
Discovery order:
|
|
32
|
+
1. Cache path (~/.claude/plugins/cache/wicked-garden/{plugin}/{version}/)
|
|
33
|
+
- Selects highest semver version
|
|
34
|
+
2. Local repo sibling path (../../../{plugin}/)
|
|
35
|
+
"""
|
|
36
|
+
# 1. Cache path (highest semver)
|
|
37
|
+
cache_base = Path.home() / ".claude" / "plugins" / "cache" / "wicked-garden" / plugin_name
|
|
38
|
+
if cache_base.exists():
|
|
39
|
+
versions = []
|
|
40
|
+
for d in cache_base.iterdir():
|
|
41
|
+
if d.is_dir():
|
|
42
|
+
versions.append((_parse_version(d.name), d))
|
|
43
|
+
if versions:
|
|
44
|
+
versions.sort(key=lambda x: x[0], reverse=True)
|
|
45
|
+
return versions[0][1]
|
|
46
|
+
|
|
47
|
+
# 2. Local repo sibling path
|
|
48
|
+
local = Path(__file__).parent.parent.parent / plugin_name
|
|
49
|
+
if local.exists() and (local / ".claude-plugin" / "plugin.json").exists():
|
|
50
|
+
return local
|
|
51
|
+
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def parse_frontmatter(filepath: Path) -> dict:
|
|
56
|
+
"""Parse YAML frontmatter from a scenario markdown file.
|
|
57
|
+
|
|
58
|
+
Returns dict with name, description, category, tools, difficulty, timeout, execution.
|
|
59
|
+
`execution` defaults to "auto" when absent; "manual" indicates the scenario
|
|
60
|
+
contains only slash commands and needs a Claude runtime to dispatch.
|
|
61
|
+
Uses simple regex parsing to avoid PyYAML dependency.
|
|
62
|
+
"""
|
|
63
|
+
try:
|
|
64
|
+
text = filepath.read_text()
|
|
65
|
+
except (OSError, UnicodeDecodeError):
|
|
66
|
+
return {}
|
|
67
|
+
match = re.match(r"^---\s*\n(.*?)\n---", text, re.DOTALL)
|
|
68
|
+
if not match:
|
|
69
|
+
return {}
|
|
70
|
+
|
|
71
|
+
fm = match.group(1)
|
|
72
|
+
result = {}
|
|
73
|
+
|
|
74
|
+
# Simple key: value parsing for flat keys
|
|
75
|
+
for line in fm.split("\n"):
|
|
76
|
+
line = line.strip()
|
|
77
|
+
if not line or line.startswith("#"):
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
kv = re.match(r"^(\w+):\s*(.+)$", line)
|
|
81
|
+
if kv:
|
|
82
|
+
key, val = kv.group(1), kv.group(2).strip().strip('"').strip("'")
|
|
83
|
+
if key in ("name", "description", "category", "difficulty", "execution"):
|
|
84
|
+
result[key] = val
|
|
85
|
+
elif key == "timeout":
|
|
86
|
+
try:
|
|
87
|
+
result["timeout"] = int(val)
|
|
88
|
+
except ValueError:
|
|
89
|
+
pass # intentional: invalid timeout ignored
|
|
90
|
+
|
|
91
|
+
# Default execution to "auto" if absent
|
|
92
|
+
result.setdefault("execution", "auto")
|
|
93
|
+
|
|
94
|
+
# Parse tools block (required/optional arrays)
|
|
95
|
+
# Supports both inline [curl, hurl] and list (- curl) syntax
|
|
96
|
+
tools_match = re.search(
|
|
97
|
+
r"^tools:\s*\n((?:[ \t]+.*\n?)*)", fm, re.MULTILINE
|
|
98
|
+
)
|
|
99
|
+
if tools_match:
|
|
100
|
+
tools_block = tools_match.group(1)
|
|
101
|
+
result["tools"] = {"required": [], "optional": []}
|
|
102
|
+
|
|
103
|
+
current_key = None
|
|
104
|
+
for line in tools_block.split("\n"):
|
|
105
|
+
stripped = line.strip()
|
|
106
|
+
for key in ("required", "optional"):
|
|
107
|
+
if stripped.startswith(f"{key}:"):
|
|
108
|
+
current_key = key
|
|
109
|
+
# Check for inline array: required: [curl, hurl]
|
|
110
|
+
inline = re.search(r"\[([^\]]*)\]", stripped)
|
|
111
|
+
if inline:
|
|
112
|
+
items = [i.strip() for i in inline.group(1).split(",") if i.strip()]
|
|
113
|
+
result["tools"][current_key] = items
|
|
114
|
+
break
|
|
115
|
+
else:
|
|
116
|
+
if stripped.startswith("- ") and current_key:
|
|
117
|
+
result["tools"][current_key].append(stripped[2:].strip())
|
|
118
|
+
|
|
119
|
+
return result
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def discover_scenarios(
|
|
123
|
+
plugin_root: Path,
|
|
124
|
+
category: "str | None" = None,
|
|
125
|
+
check_tools: bool = False,
|
|
126
|
+
) -> dict:
|
|
127
|
+
"""Discover scenarios from a wicked-scenarios plugin root.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
{
|
|
131
|
+
"available": true,
|
|
132
|
+
"plugin_root": "/path/to/wicked-scenarios",
|
|
133
|
+
"scenarios": [
|
|
134
|
+
{
|
|
135
|
+
"name": "api-health-check",
|
|
136
|
+
"file": "scenarios/api-health-check.md",
|
|
137
|
+
"category": "api",
|
|
138
|
+
"description": "...",
|
|
139
|
+
"tools": {"required": [...], "optional": [...]},
|
|
140
|
+
"difficulty": "basic",
|
|
141
|
+
"runnable": true # only if check_tools=True
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
"tool_status": {...} # only if check_tools=True
|
|
145
|
+
}
|
|
146
|
+
"""
|
|
147
|
+
scenarios_dir = plugin_root / "scenarios"
|
|
148
|
+
if not scenarios_dir.exists():
|
|
149
|
+
return {"available": True, "plugin_root": str(plugin_root), "scenarios": []}
|
|
150
|
+
|
|
151
|
+
scenarios = []
|
|
152
|
+
for md_file in sorted(scenarios_dir.glob("*.md")):
|
|
153
|
+
if md_file.name == "README.md":
|
|
154
|
+
continue
|
|
155
|
+
fm = parse_frontmatter(md_file)
|
|
156
|
+
if not fm.get("name"):
|
|
157
|
+
continue
|
|
158
|
+
if category and fm.get("category") != category:
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
scenario = {
|
|
162
|
+
"name": fm.get("name", md_file.stem),
|
|
163
|
+
"file": str(md_file),
|
|
164
|
+
"category": fm.get("category", "unknown"),
|
|
165
|
+
"description": fm.get("description", ""),
|
|
166
|
+
"tools": fm.get("tools", {"required": [], "optional": []}),
|
|
167
|
+
"difficulty": fm.get("difficulty", "basic"),
|
|
168
|
+
}
|
|
169
|
+
scenarios.append(scenario)
|
|
170
|
+
|
|
171
|
+
result = {
|
|
172
|
+
"available": True,
|
|
173
|
+
"plugin_root": str(plugin_root),
|
|
174
|
+
"scenarios": scenarios,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# Optionally check tool availability via cli_discovery.py
|
|
178
|
+
if check_tools:
|
|
179
|
+
cli_discovery = plugin_root / "scripts" / "cli_discovery.py"
|
|
180
|
+
if cli_discovery.exists():
|
|
181
|
+
try:
|
|
182
|
+
proc = subprocess.run(
|
|
183
|
+
[sys.executable, str(cli_discovery)],
|
|
184
|
+
capture_output=True,
|
|
185
|
+
text=True,
|
|
186
|
+
timeout=10,
|
|
187
|
+
)
|
|
188
|
+
if proc.returncode == 0:
|
|
189
|
+
tool_status = json.loads(proc.stdout)
|
|
190
|
+
result["tool_status"] = tool_status
|
|
191
|
+
|
|
192
|
+
# Mark each scenario as runnable or not
|
|
193
|
+
for s in scenarios:
|
|
194
|
+
required = s["tools"].get("required", [])
|
|
195
|
+
s["runnable"] = all(
|
|
196
|
+
tool_status.get(t, {}).get("available", False)
|
|
197
|
+
for t in required
|
|
198
|
+
)
|
|
199
|
+
except (subprocess.TimeoutExpired, json.JSONDecodeError):
|
|
200
|
+
pass # fail open: tool check failed, skip
|
|
201
|
+
|
|
202
|
+
return result
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def main():
|
|
206
|
+
flags = [a for a in sys.argv[1:] if a.startswith("-")]
|
|
207
|
+
args = [a for a in sys.argv[1:] if not a.startswith("-")]
|
|
208
|
+
|
|
209
|
+
category = None
|
|
210
|
+
available_only = "--available-only" in flags
|
|
211
|
+
do_check_tools = "--check-tools" in flags or available_only
|
|
212
|
+
|
|
213
|
+
# Parse --category value
|
|
214
|
+
for i, f in enumerate(flags):
|
|
215
|
+
if f == "--category" and i + 1 < len(sys.argv[1:]):
|
|
216
|
+
# Find the value after --category
|
|
217
|
+
idx = sys.argv.index("--category")
|
|
218
|
+
if idx + 1 < len(sys.argv):
|
|
219
|
+
category = sys.argv[idx + 1]
|
|
220
|
+
|
|
221
|
+
# Discover wicked-scenarios plugin
|
|
222
|
+
plugin_root = discover_plugin("wicked-scenarios")
|
|
223
|
+
if plugin_root is None:
|
|
224
|
+
print(json.dumps({"available": False, "scenarios": []}, indent=2))
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
result = discover_scenarios(
|
|
228
|
+
plugin_root, category=category, check_tools=do_check_tools
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
# Filter to runnable only
|
|
232
|
+
if available_only:
|
|
233
|
+
if "tool_status" in result:
|
|
234
|
+
result["scenarios"] = [s for s in result["scenarios"] if s.get("runnable", False)]
|
|
235
|
+
else:
|
|
236
|
+
# Can't verify runnability without tool status — return empty
|
|
237
|
+
result["scenarios"] = []
|
|
238
|
+
|
|
239
|
+
print(json.dumps(result, indent=2))
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
if __name__ == "__main__":
|
|
243
|
+
main()
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""evidence_tracker.py — Track produces-contracts per archetype phase.
|
|
3
|
+
|
|
4
|
+
Each archetype declares a ``produces`` contract in
|
|
5
|
+
``.claude-plugin/archetypes.json`` (e.g. build → ``shipped-code`` +
|
|
6
|
+
``test-report``; migrate → ``shape-change`` + ``rollback-proof``).
|
|
7
|
+
This module records when each produces item is met and provides
|
|
8
|
+
``produces_satisfied()`` for archetype playbooks to check before
|
|
9
|
+
advancing past their final phase.
|
|
10
|
+
|
|
11
|
+
The tracker is doctrine-light: it records what the archetype claims
|
|
12
|
+
to have produced, with a path to the artifact. It does not validate
|
|
13
|
+
the artifact's content. Validation is the archetype's job (build's
|
|
14
|
+
test phase runs tests; migrate's cutover phase runs rollback drill;
|
|
15
|
+
review's assess phase applies the rubric). The tracker just answers:
|
|
16
|
+
"have all produces items been claimed?"
|
|
17
|
+
|
|
18
|
+
Stdlib-only.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
from datetime import datetime, timezone
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Any, Dict, List, Optional
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _utc_now() -> str:
|
|
30
|
+
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _evidence_path(project_dir: Path) -> Path:
|
|
34
|
+
return Path(project_dir) / "audit" / "evidence.json"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _load_archetype_produces(archetype: str) -> List[str]:
|
|
38
|
+
"""Read produces[] from the catalog. Returns [] when unavailable."""
|
|
39
|
+
try:
|
|
40
|
+
from pathlib import Path as _Path
|
|
41
|
+
catalog_path = (
|
|
42
|
+
_Path(__file__).resolve().parents[2]
|
|
43
|
+
/ ".claude-plugin" / "archetypes.json"
|
|
44
|
+
)
|
|
45
|
+
catalog = json.loads(catalog_path.read_text(encoding="utf-8"))
|
|
46
|
+
return list(
|
|
47
|
+
catalog.get("archetypes", {}).get(archetype, {}).get("produces", [])
|
|
48
|
+
)
|
|
49
|
+
except Exception:
|
|
50
|
+
return []
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# Public API
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
def initialize_for_archetype(
|
|
58
|
+
project_dir: Path,
|
|
59
|
+
archetype: str,
|
|
60
|
+
) -> Path:
|
|
61
|
+
"""Initialise the evidence tracker for an archetype run. Pre-populates
|
|
62
|
+
each declared produces item with verified=False. Idempotent: re-init
|
|
63
|
+
over an existing tracker preserves prior verifications by name."""
|
|
64
|
+
project_dir = Path(project_dir)
|
|
65
|
+
path = _evidence_path(project_dir)
|
|
66
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
declared = _load_archetype_produces(archetype)
|
|
68
|
+
|
|
69
|
+
existing: Dict[str, Any] = {}
|
|
70
|
+
if path.exists():
|
|
71
|
+
try:
|
|
72
|
+
existing = json.loads(path.read_text(encoding="utf-8"))
|
|
73
|
+
except (OSError, json.JSONDecodeError):
|
|
74
|
+
existing = {}
|
|
75
|
+
|
|
76
|
+
by_name = {item.get("name"): item
|
|
77
|
+
for item in (existing.get("produces") or [])
|
|
78
|
+
if item.get("name")}
|
|
79
|
+
|
|
80
|
+
produces = []
|
|
81
|
+
for name in declared:
|
|
82
|
+
if name in by_name:
|
|
83
|
+
produces.append(by_name[name])
|
|
84
|
+
else:
|
|
85
|
+
produces.append({
|
|
86
|
+
"name": name,
|
|
87
|
+
"verified": False,
|
|
88
|
+
"claimed_at": None,
|
|
89
|
+
"artifact_path": None,
|
|
90
|
+
"claimed_by": None,
|
|
91
|
+
"note": None,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
tracker = {
|
|
95
|
+
"archetype": archetype,
|
|
96
|
+
"created_at": existing.get("created_at") or _utc_now(),
|
|
97
|
+
"updated_at": _utc_now(),
|
|
98
|
+
"produces": produces,
|
|
99
|
+
}
|
|
100
|
+
path.write_text(json.dumps(tracker, indent=2))
|
|
101
|
+
return path
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def claim_produces(
|
|
105
|
+
project_dir: Path,
|
|
106
|
+
name: str,
|
|
107
|
+
*,
|
|
108
|
+
artifact_path: str,
|
|
109
|
+
claimed_by: str,
|
|
110
|
+
note: Optional[str] = None,
|
|
111
|
+
) -> Dict[str, Any]:
|
|
112
|
+
"""Mark a produces item satisfied. ``artifact_path`` is a file path,
|
|
113
|
+
URL, or commit reference. ``claimed_by`` is the agent / task / user.
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
FileNotFoundError if no tracker exists.
|
|
117
|
+
ValueError if ``name`` is not in the tracker (typo guard).
|
|
118
|
+
"""
|
|
119
|
+
if not artifact_path or not artifact_path.strip():
|
|
120
|
+
raise ValueError("artifact_path is required")
|
|
121
|
+
if not claimed_by or not claimed_by.strip():
|
|
122
|
+
raise ValueError("claimed_by is required")
|
|
123
|
+
|
|
124
|
+
project_dir = Path(project_dir)
|
|
125
|
+
path = _evidence_path(project_dir)
|
|
126
|
+
if not path.exists():
|
|
127
|
+
raise FileNotFoundError(f"No evidence tracker at {path}")
|
|
128
|
+
|
|
129
|
+
tracker = json.loads(path.read_text(encoding="utf-8"))
|
|
130
|
+
produces = tracker.get("produces") or []
|
|
131
|
+
|
|
132
|
+
for item in produces:
|
|
133
|
+
if item.get("name") == name:
|
|
134
|
+
item["verified"] = True
|
|
135
|
+
item["claimed_at"] = _utc_now()
|
|
136
|
+
item["artifact_path"] = artifact_path
|
|
137
|
+
item["claimed_by"] = claimed_by
|
|
138
|
+
if note:
|
|
139
|
+
item["note"] = note
|
|
140
|
+
tracker["updated_at"] = _utc_now()
|
|
141
|
+
path.write_text(json.dumps(tracker, indent=2))
|
|
142
|
+
return item
|
|
143
|
+
|
|
144
|
+
known = [p.get("name") for p in produces]
|
|
145
|
+
raise ValueError(
|
|
146
|
+
f"Produces item '{name}' not declared for this archetype. "
|
|
147
|
+
f"Declared: {known}"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def status(project_dir: Path) -> Dict[str, Any]:
|
|
152
|
+
project_dir = Path(project_dir)
|
|
153
|
+
path = _evidence_path(project_dir)
|
|
154
|
+
empty = {"exists": False, "total": 0, "verified": 0, "pending": 0,
|
|
155
|
+
"produces": []}
|
|
156
|
+
if not path.exists():
|
|
157
|
+
return empty
|
|
158
|
+
try:
|
|
159
|
+
tracker = json.loads(path.read_text(encoding="utf-8"))
|
|
160
|
+
except (OSError, json.JSONDecodeError):
|
|
161
|
+
return empty
|
|
162
|
+
produces = tracker.get("produces") or []
|
|
163
|
+
verified = sum(1 for p in produces if p.get("verified"))
|
|
164
|
+
return {
|
|
165
|
+
"exists": True,
|
|
166
|
+
"archetype": tracker.get("archetype"),
|
|
167
|
+
"total": len(produces),
|
|
168
|
+
"verified": verified,
|
|
169
|
+
"pending": len(produces) - verified,
|
|
170
|
+
"produces": produces,
|
|
171
|
+
"created_at": tracker.get("created_at"),
|
|
172
|
+
"updated_at": tracker.get("updated_at"),
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def produces_satisfied(project_dir: Path) -> bool:
|
|
177
|
+
"""True iff every declared produces item is verified, OR no tracker
|
|
178
|
+
exists. The latter case is intentional — archetype playbooks may
|
|
179
|
+
skip evidence tracking for low-rigor work."""
|
|
180
|
+
s = status(project_dir)
|
|
181
|
+
if not s["exists"]:
|
|
182
|
+
return True
|
|
183
|
+
return s["pending"] == 0
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
__all__ = [
|
|
187
|
+
"initialize_for_archetype", "claim_produces", "status",
|
|
188
|
+
"produces_satisfied",
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
# ---------------------------------------------------------------------------
|
|
193
|
+
# CLI
|
|
194
|
+
# ---------------------------------------------------------------------------
|
|
195
|
+
|
|
196
|
+
if __name__ == "__main__":
|
|
197
|
+
import argparse, sys
|
|
198
|
+
parser = argparse.ArgumentParser(description="v11 evidence tracker tool.")
|
|
199
|
+
sub = parser.add_subparsers(dest="action", required=True)
|
|
200
|
+
|
|
201
|
+
init = sub.add_parser("init")
|
|
202
|
+
init.add_argument("project_dir")
|
|
203
|
+
init.add_argument("--archetype", required=True)
|
|
204
|
+
|
|
205
|
+
claim = sub.add_parser("claim")
|
|
206
|
+
claim.add_argument("project_dir")
|
|
207
|
+
claim.add_argument("--name", required=True)
|
|
208
|
+
claim.add_argument("--artifact", required=True)
|
|
209
|
+
claim.add_argument("--claimed-by", required=True)
|
|
210
|
+
claim.add_argument("--note", default=None)
|
|
211
|
+
|
|
212
|
+
stat = sub.add_parser("status")
|
|
213
|
+
stat.add_argument("project_dir")
|
|
214
|
+
|
|
215
|
+
args = parser.parse_args()
|
|
216
|
+
|
|
217
|
+
if args.action == "init":
|
|
218
|
+
path = initialize_for_archetype(Path(args.project_dir), args.archetype)
|
|
219
|
+
print(json.dumps({"ok": True, "path": str(path)}))
|
|
220
|
+
elif args.action == "claim":
|
|
221
|
+
try:
|
|
222
|
+
item = claim_produces(
|
|
223
|
+
Path(args.project_dir), args.name,
|
|
224
|
+
artifact_path=args.artifact, claimed_by=args.claimed_by,
|
|
225
|
+
note=args.note,
|
|
226
|
+
)
|
|
227
|
+
print(json.dumps({"ok": True, "produces_item": item}))
|
|
228
|
+
except (FileNotFoundError, ValueError) as exc:
|
|
229
|
+
print(json.dumps({"ok": False, "error": str(exc)}), file=sys.stderr)
|
|
230
|
+
sys.exit(1)
|
|
231
|
+
elif args.action == "status":
|
|
232
|
+
print(json.dumps(status(Path(args.project_dir)), indent=2))
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""prove.py — the one-line re-derivation verb.
|
|
3
|
+
|
|
4
|
+
The produces-gate is the plugin's most valuable feature for an agent: it stops
|
|
5
|
+
"done" from being self-asserted. But using it is a ~5-step ritual (vault init →
|
|
6
|
+
author a contract.json → declare-contract → record --run → gate). That friction
|
|
7
|
+
is exactly why an agent skips it and just *claims* the work is done — turning
|
|
8
|
+
the gate into ceremony that exists but isn't used.
|
|
9
|
+
|
|
10
|
+
This collapses the ritual into one verb an agent reaches for by reflex:
|
|
11
|
+
|
|
12
|
+
prove.py tests-pass --by "pytest -q"
|
|
13
|
+
prove.py build-clean --by "npm run build" --verifier exit_code_eq:0
|
|
14
|
+
|
|
15
|
+
It re-derives, never asserts: it RUNS <command>, freezes the real exit code as
|
|
16
|
+
vault evidence, then gates by re-running the verifier against that frozen
|
|
17
|
+
evidence. Exit 0 iff the gate PASSES (re-derived). When the loom/vault backend
|
|
18
|
+
is unresolvable it FAILS CLOSED (exit 3, gate: "unavailable") — never a vacuous
|
|
19
|
+
pass. Reuses scripts/qe/vault_gate.py (resolve + gate_satisfied) and the vault
|
|
20
|
+
CLI; it invents no new gating logic.
|
|
21
|
+
|
|
22
|
+
Stdlib-only. Cross-platform (argv lists, shell=False).
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import argparse
|
|
28
|
+
import json
|
|
29
|
+
import os
|
|
30
|
+
import subprocess # noqa: S404 — argv lists only, shell=False
|
|
31
|
+
import sys
|
|
32
|
+
import tempfile
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
|
|
35
|
+
# Importing the sibling gate module must work whether this runs as a CLI
|
|
36
|
+
# (`python3 scripts/qe/prove.py …` → only scripts/qe on sys.path) or imported.
|
|
37
|
+
# Add scripts/ for vault_gate's own sibling import (_loom). This is the same
|
|
38
|
+
# CLI-import discipline a subdir script that imports a top-level sibling needs.
|
|
39
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
40
|
+
try:
|
|
41
|
+
import vault_gate # scripts/qe sibling
|
|
42
|
+
except ImportError: # pragma: no cover
|
|
43
|
+
vault_gate = None # type: ignore
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Mirror wicked-vault's parseVerifier so prove can validate the OUTPUT, not
|
|
47
|
+
# just an exit code: regex_match / not_contains run against the command's
|
|
48
|
+
# stdout; jq_pred evaluates a predicate over JSON stdout; commit_exists checks
|
|
49
|
+
# a git SHA. This is what lets prove validate produced artifacts (an ADR has a
|
|
50
|
+
# Decision section, a config contains no TODO, a decision JSON has >=2 options),
|
|
51
|
+
# final or interim — not merely "a command exited 0".
|
|
52
|
+
_VERIFIERS = {
|
|
53
|
+
"exit_code_eq": lambda arg: {"kind": "exit_code_eq", "params": {"code": int(arg or "0")}},
|
|
54
|
+
"regex_match": lambda arg: {"kind": "regex_match", "params": {"pattern": arg}},
|
|
55
|
+
"not_contains": lambda arg: {"kind": "not_contains", "params": {"pattern": arg}},
|
|
56
|
+
"commit_exists": lambda arg: {"kind": "commit_exists", "params": {"sha": arg}},
|
|
57
|
+
"jq_pred": lambda arg: {"kind": "jq_pred", "params": {"expr": arg}},
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _parse_verifier(spec: str) -> dict:
|
|
62
|
+
"""`exit_code_eq:0` / `regex_match:## Decision` / `jq_pred:.options>=2` ->
|
|
63
|
+
{kind, params}. Defaults to exit_code_eq:0."""
|
|
64
|
+
name, sep, arg = spec.partition(":")
|
|
65
|
+
builder = _VERIFIERS.get(name)
|
|
66
|
+
if builder is None:
|
|
67
|
+
raise ValueError(f"unsupported verifier '{name}'; known: {sorted(_VERIFIERS)}")
|
|
68
|
+
if name != "exit_code_eq" and not (sep and arg):
|
|
69
|
+
raise ValueError(f"verifier '{name}' requires an argument, e.g. {name}:<value>")
|
|
70
|
+
return builder(arg)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _vault(prefix: list[str], project_dir: Path, *args: str) -> subprocess.CompletedProcess:
|
|
74
|
+
return subprocess.run(prefix + list(args), cwd=str(project_dir),
|
|
75
|
+
capture_output=True, text=True, timeout=300)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# The doer identity prove records evidence UNDER. wicked-vault hardens `attest`
|
|
79
|
+
# to fail closed when the recorded artifact's worker identity is "weak" (an
|
|
80
|
+
# ambient `$USER`, i.e. created_by_source='env-user') — so an independent
|
|
81
|
+
# attestation can't be trusted, and a `--with-attestations` hard gate can never
|
|
82
|
+
# reach PASS. We therefore record under an EXPLICIT actor (created_by_source=
|
|
83
|
+
# 'explicit'), which makes the independence check trustworthy with no
|
|
84
|
+
# `--allow-weak-worker-identity` flag. Source from WICKED_VAULT_ACTOR when the
|
|
85
|
+
# harness asserts one, else a deterministic fixed id. Crucially this id is the
|
|
86
|
+
# DOER — an independent reviewer must attest as a DIFFERENT actor (the vault
|
|
87
|
+
# still rejects a self-grade where evaluator == this actor), so the
|
|
88
|
+
# self-grading guarantee is preserved, not reopened.
|
|
89
|
+
def _prove_actor() -> str:
|
|
90
|
+
env = os.environ.get("WICKED_VAULT_ACTOR", "").strip()
|
|
91
|
+
return env or "garden-prove"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def prove(claim: str, command: str, *, verifier: str = "exit_code_eq:0",
|
|
95
|
+
scope: str = "prove", phase: str = "verify",
|
|
96
|
+
project_dir: str = ".", with_attestations: bool = False,
|
|
97
|
+
kind: str = "check") -> dict:
|
|
98
|
+
"""Re-derive a single claim end to end; return the gate verdict dict.
|
|
99
|
+
|
|
100
|
+
``with_attestations`` forwards to the gate's hard-gate requirement (the
|
|
101
|
+
evaluator must not be the agent that did the work) — use it for
|
|
102
|
+
incident/migrate/review gates."""
|
|
103
|
+
if vault_gate is None:
|
|
104
|
+
return {"satisfied": False, "gate": "unavailable", "re_derived": False,
|
|
105
|
+
"error": "vault_gate import failed"}
|
|
106
|
+
pd = Path(project_dir).resolve()
|
|
107
|
+
prefix = vault_gate.resolve_vault(project_dir=pd) # loom-resolved vault argv
|
|
108
|
+
if prefix is None:
|
|
109
|
+
return {"satisfied": False, "gate": "unavailable", "re_derived": False,
|
|
110
|
+
"error": ("evidence backend (wicked-loom/wicked-vault) not "
|
|
111
|
+
"resolvable — fails closed, never a vacuous pass")}
|
|
112
|
+
# jq_pred ergonomics: prove always records via --run, so the payload is the
|
|
113
|
+
# capture envelope {command, exit_code, stdout, ...}. An agent means "query
|
|
114
|
+
# my command's JSON OUTPUT", not the envelope — so target stdout-as-JSON.
|
|
115
|
+
# Rewrite `jq_pred:<expr>` -> evaluate <expr> over fromjson(.stdout), unless
|
|
116
|
+
# the expr already navigates the envelope (mentions .stdout). regex_match /
|
|
117
|
+
# not_contains already scan the captured text, so they need no rewrite.
|
|
118
|
+
if verifier.startswith("jq_pred:") and ".stdout" not in verifier:
|
|
119
|
+
expr = verifier[len("jq_pred:"):]
|
|
120
|
+
verifier = f"jq_pred:.stdout | fromjson | ({expr})"
|
|
121
|
+
try:
|
|
122
|
+
verifier_spec = _parse_verifier(verifier)
|
|
123
|
+
except ValueError as e:
|
|
124
|
+
return {"satisfied": False, "gate": "error", "re_derived": False,
|
|
125
|
+
"error": str(e)}
|
|
126
|
+
|
|
127
|
+
# init (idempotent — ignore "already initialized"), declare, record --run.
|
|
128
|
+
_vault(prefix, pd, "init")
|
|
129
|
+
claim_spec = {
|
|
130
|
+
"claim_id": claim, "kind": kind,
|
|
131
|
+
"verifier": verifier_spec, "required": True,
|
|
132
|
+
}
|
|
133
|
+
if with_attestations:
|
|
134
|
+
# Hard gate (incident/migrate/review): the doer's own evidence cannot
|
|
135
|
+
# satisfy it. Opt the contract into the vault's attestation enforcement
|
|
136
|
+
# (`require_attestation`) so the gate REJECTs as UNATTESTED until an
|
|
137
|
+
# INDEPENDENT evaluator records `wicked-vault attest` (evaluator !=
|
|
138
|
+
# creator). Without this flag the contract is integrity-only and the
|
|
139
|
+
# gate would pass on the doer's evidence alone — a vacuous hard gate.
|
|
140
|
+
claim_spec["require_attestation"] = True
|
|
141
|
+
contract = {"required_evidence": [claim_spec]}
|
|
142
|
+
with tempfile.NamedTemporaryFile("w", suffix=".json", delete=False) as fh:
|
|
143
|
+
fh.write(json.dumps(contract))
|
|
144
|
+
spec_path = fh.name
|
|
145
|
+
try:
|
|
146
|
+
_vault(prefix, pd, "declare-contract", "--scope", scope, "--phase", phase,
|
|
147
|
+
"--spec", spec_path)
|
|
148
|
+
_vault(prefix, pd, "record", "--scope", scope, "--phase", phase,
|
|
149
|
+
"--claim", claim, "--kind", kind, "--source", command,
|
|
150
|
+
"--criteria", f"{claim}: `{command}` satisfies {verifier}",
|
|
151
|
+
"--verifier", verifier, "--actor", _prove_actor(), "--run")
|
|
152
|
+
finally:
|
|
153
|
+
try:
|
|
154
|
+
Path(spec_path).unlink()
|
|
155
|
+
except OSError:
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
# The verdict is RE-DERIVED by the gate, not taken from the record above.
|
|
159
|
+
return vault_gate.gate_satisfied(pd, scope, phase,
|
|
160
|
+
with_attestations=with_attestations)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def main() -> int:
|
|
164
|
+
p = argparse.ArgumentParser(
|
|
165
|
+
description="Prove a claim by re-deriving it (run + gate), not asserting it.")
|
|
166
|
+
p.add_argument("claim", help="claim id, e.g. tests-pass")
|
|
167
|
+
p.add_argument("--by", required=True, metavar="COMMAND",
|
|
168
|
+
help="the command whose real exit code is the evidence; it "
|
|
169
|
+
"runs in --project-dir, so prefer absolute paths or a "
|
|
170
|
+
"command valid from there")
|
|
171
|
+
p.add_argument("--verifier", default="exit_code_eq:0",
|
|
172
|
+
help="verifier spec: exit_code_eq:0 | regex_match:<re> | not_contains:<re> | jq_pred:<expr> | commit_exists:<sha>. The regex/not_contains/jq_pred kinds validate the command's OUTPUT, not just its exit code.")
|
|
173
|
+
p.add_argument("--kind", default="check",
|
|
174
|
+
help="evidence kind label (e.g. test-run, doc, output)")
|
|
175
|
+
p.add_argument("--scope", default="prove")
|
|
176
|
+
p.add_argument("--phase", default="verify")
|
|
177
|
+
p.add_argument("--project-dir", default=".")
|
|
178
|
+
p.add_argument("--with-attestations", action="store_true",
|
|
179
|
+
help="hard gate (incident/migrate/review): require an "
|
|
180
|
+
"INDEPENDENT attestation. The gate stays REJECT "
|
|
181
|
+
"(UNATTESTED) until someone other than the doer runs "
|
|
182
|
+
"`wicked-vault attest <artifact> --opinion pass` — the "
|
|
183
|
+
"doer's own evidence cannot satisfy it")
|
|
184
|
+
a = p.parse_args()
|
|
185
|
+
verdict = prove(a.claim, a.by, verifier=a.verifier, scope=a.scope,
|
|
186
|
+
phase=a.phase, project_dir=a.project_dir,
|
|
187
|
+
with_attestations=a.with_attestations, kind=a.kind)
|
|
188
|
+
print(json.dumps(verdict, indent=2))
|
|
189
|
+
if verdict.get("satisfied"):
|
|
190
|
+
return 0
|
|
191
|
+
# distinguish fail-closed (backend gone) from a real REJECT
|
|
192
|
+
return 3 if verdict.get("gate") == "unavailable" else 1
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
if __name__ == "__main__":
|
|
196
|
+
sys.exit(main())
|