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,402 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""invariants.py — the claim sentinel: state-transition gates without command lists.
|
|
3
|
+
|
|
4
|
+
The design problem (session-tested): steering that fires at *prompt time* ("this
|
|
5
|
+
is a build!") or as ambient tips gets ignored — the agent overrides even MUST
|
|
6
|
+
wording when local context says "irrelevant", and nothing records the skip. What
|
|
7
|
+
changes behavior is a check that fires **at the claim moment**, carries **observed
|
|
8
|
+
evidence**, names **one action**, and makes skipping a **recorded decision**.
|
|
9
|
+
|
|
10
|
+
And you can't catch claim moments by pattern-matching commands (`gh pr merge`,
|
|
11
|
+
raw `git push`, `glab`, an API curl, next year's tool…). You catch the state all
|
|
12
|
+
of them converge on:
|
|
13
|
+
|
|
14
|
+
- a **git ref moving** is the universal "ship it" (ref-watch, below);
|
|
15
|
+
- a **task completing** is the universal in-session "done" (TaskCompleted hook);
|
|
16
|
+
- the **session ending** is the last exit (info tier).
|
|
17
|
+
|
|
18
|
+
Each toolkit component already has one observable state-store, so every gate here
|
|
19
|
+
is an *invariant between two observable states* — never a command match:
|
|
20
|
+
|
|
21
|
+
invariant observable A observable B
|
|
22
|
+
------------------------ ---------------------- -------------------------
|
|
23
|
+
done-claim has a verdict sentinel verdict ledger ref advance / task done
|
|
24
|
+
evidence is fresh .wicked-testing ledger mtime of modified files
|
|
25
|
+
learnings captured brain memory dir session activity
|
|
26
|
+
playbooks current repo-* skill dirs commits since their mtime
|
|
27
|
+
|
|
28
|
+
Tiers: info (one line, ignorable) → **answer** (the agent must act or the skip
|
|
29
|
+
is logged to the bus as `wicked.sentinel.*` — the skip becomes evidence) →
|
|
30
|
+
block (git pre-push / CI, outside this module). Everything here fails OPEN on
|
|
31
|
+
error (a broken sentinel must never break a session) but never invents an OK.
|
|
32
|
+
|
|
33
|
+
Stdlib-only. All git access via argv subprocess, short timeouts, throttled.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
import hashlib
|
|
39
|
+
import json
|
|
40
|
+
import os
|
|
41
|
+
import re
|
|
42
|
+
import subprocess # noqa: S404 — argv lists only, shell=False
|
|
43
|
+
import time
|
|
44
|
+
from pathlib import Path
|
|
45
|
+
from typing import Any, Dict, List, Optional
|
|
46
|
+
|
|
47
|
+
_GIT_TIMEOUT = 5
|
|
48
|
+
_LEDGER_MAX_STAMPS = 200 # ledger read window (recent stamps only)
|
|
49
|
+
_RECENT_HISTORY = 80 # a verdict covers a sha within this many ancestors
|
|
50
|
+
_PLAYBOOK_STALE_COMMITS = 30 # repo-playbooks "drifted" threshold
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# git plumbing (fail-open: None / {} on any error)
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
def _git(repo: Path, *args: str) -> Optional[str]:
|
|
58
|
+
try:
|
|
59
|
+
proc = subprocess.run( # noqa: S603 — argv list, shell=False
|
|
60
|
+
["git", "-C", str(repo), *args],
|
|
61
|
+
capture_output=True, text=True, timeout=_GIT_TIMEOUT,
|
|
62
|
+
)
|
|
63
|
+
if proc.returncode != 0:
|
|
64
|
+
return None
|
|
65
|
+
return proc.stdout.strip()
|
|
66
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def repo_toplevel(cwd: Optional[Path] = None) -> Optional[Path]:
|
|
71
|
+
top = _git(Path(cwd) if cwd else Path.cwd(), "rev-parse", "--show-toplevel")
|
|
72
|
+
return Path(top) if top else None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
# The verdict ledger — stamped by the gate, read by every claim check.
|
|
77
|
+
# Keyed by repo toplevel (NOT cwd) so gate runs and hook checks agree even when
|
|
78
|
+
# they run from different directories of the same repo.
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
def _ledger_path(repo: Path) -> Path:
|
|
82
|
+
slug = hashlib.sha256(str(repo.resolve()).encode("utf-8")).hexdigest()[:12]
|
|
83
|
+
base = Path.home() / ".something-wicked" / "wicked-garden" / "sentinel"
|
|
84
|
+
base.mkdir(parents=True, exist_ok=True)
|
|
85
|
+
return base / f"{slug}.jsonl"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def stamp_verdict(repo: Path, *, overall: str, satisfied: bool,
|
|
89
|
+
re_derived: bool, scope: str = "", phase: str = "") -> None:
|
|
90
|
+
"""Record a gate verdict for the repo's current HEAD. Called by the
|
|
91
|
+
produces-gate (vault_gate.gate_satisfied) — the single front door — so any
|
|
92
|
+
prove/gate run anywhere stamps the ledger. Fail-open."""
|
|
93
|
+
try:
|
|
94
|
+
sha = _git(repo, "rev-parse", "HEAD")
|
|
95
|
+
if not sha:
|
|
96
|
+
return
|
|
97
|
+
rec = {"sha": sha, "overall": overall, "satisfied": bool(satisfied),
|
|
98
|
+
"re_derived": bool(re_derived), "scope": scope, "phase": phase,
|
|
99
|
+
"ts": time.time()}
|
|
100
|
+
with _ledger_path(repo).open("a", encoding="utf-8") as fh:
|
|
101
|
+
fh.write(json.dumps(rec) + "\n")
|
|
102
|
+
except Exception: # noqa: BLE001 — sentinel must never break the gate
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _recent_stamps(repo: Path) -> List[Dict[str, Any]]:
|
|
107
|
+
try:
|
|
108
|
+
p = _ledger_path(repo)
|
|
109
|
+
if not p.exists():
|
|
110
|
+
return []
|
|
111
|
+
lines = p.read_text(encoding="utf-8").splitlines()[-_LEDGER_MAX_STAMPS:]
|
|
112
|
+
return [json.loads(ln) for ln in lines if ln.strip()]
|
|
113
|
+
except Exception: # noqa: BLE001
|
|
114
|
+
return []
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def verdict_for(repo: Path, sha: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
118
|
+
"""The most recent satisfied+re-derived stamp covering `sha` (default HEAD):
|
|
119
|
+
the stamped commit must be the sha itself or one of its recent ancestors."""
|
|
120
|
+
target = sha or _git(repo, "rev-parse", "HEAD")
|
|
121
|
+
if not target:
|
|
122
|
+
return None
|
|
123
|
+
history = _git(repo, "rev-list", f"-{_RECENT_HISTORY}", target)
|
|
124
|
+
if history is None:
|
|
125
|
+
return None
|
|
126
|
+
recent = set(history.splitlines())
|
|
127
|
+
for rec in reversed(_recent_stamps(repo)):
|
|
128
|
+
if rec.get("sha") in recent and rec.get("satisfied") and rec.get("re_derived"):
|
|
129
|
+
return rec
|
|
130
|
+
return None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# ---------------------------------------------------------------------------
|
|
134
|
+
# Override / detection events → the bus (fire-and-forget; the skip is evidence)
|
|
135
|
+
# ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
def log_sentinel_event(repo: Path, event: str, detail: Dict[str, Any]) -> None:
|
|
138
|
+
"""Emit wicked.sentinel.<event> to the bus if available; always append to a
|
|
139
|
+
local trail so the record exists even without the bus layer."""
|
|
140
|
+
payload = {"repo": str(repo), "ts": time.time(), **detail}
|
|
141
|
+
try:
|
|
142
|
+
trail = _ledger_path(repo).with_suffix(".events.jsonl")
|
|
143
|
+
with trail.open("a", encoding="utf-8") as fh:
|
|
144
|
+
fh.write(json.dumps({"event": event, **payload}) + "\n")
|
|
145
|
+
except Exception: # noqa: BLE001
|
|
146
|
+
pass
|
|
147
|
+
try:
|
|
148
|
+
import sys
|
|
149
|
+
plugin_scripts = Path(__file__).resolve().parents[1]
|
|
150
|
+
if str(plugin_scripts) not in sys.path:
|
|
151
|
+
sys.path.insert(0, str(plugin_scripts))
|
|
152
|
+
from _bus import emit_event # type: ignore
|
|
153
|
+
emit_event(f"wicked.sentinel.{event}", payload)
|
|
154
|
+
except Exception: # noqa: BLE001 — bus is an opt-in layer; fail open
|
|
155
|
+
pass
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
# ---------------------------------------------------------------------------
|
|
159
|
+
# Invariant 1 — claim-gate (answer tier): a done/passing CLAIM must have a
|
|
160
|
+
# verdict. Fires at the Stop boundary, and only when the turn's final message
|
|
161
|
+
# actually asserts done/passing/shipped — never as a side effect of a tool
|
|
162
|
+
# call. Ship/publish protection (an actual push to main or a tag) is the BLOCK
|
|
163
|
+
# tier (pre_push.py + CI); this is the harness backstop nudge.
|
|
164
|
+
#
|
|
165
|
+
# History: this replaced a PostToolUse ref-watch that keyed off git-ref state
|
|
166
|
+
# (origin default branch + newest tag advancing) with no claim check, wired to
|
|
167
|
+
# a blanket Bash matcher — so any Bash call (git log, cat, find) during pure
|
|
168
|
+
# planning tripped "the claim sentinel that never checked for a claim".
|
|
169
|
+
# ---------------------------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
# Verification-completion phrases. Deliberately conservative — the failure mode
|
|
172
|
+
# being fixed is OVER-firing, so we match explicit verification/publish
|
|
173
|
+
# assertions, not bare "done" (too common in progress chatter).
|
|
174
|
+
_CLAIM_PATTERNS = (
|
|
175
|
+
r"\btests?\s+(?:all\s+)?(?:pass|passing|passes|passed)\b",
|
|
176
|
+
r"\ball\s+tests?\s+(?:are\s+)?(?:pass|passing|green)",
|
|
177
|
+
r"\ball\s+green\b",
|
|
178
|
+
r"\ball\s+checks?\s+(?:pass|passing|green)",
|
|
179
|
+
r"\bbuild\s+(?:is\s+)?clean\b",
|
|
180
|
+
r"\bready\s+to\s+(?:merge|ship)\b",
|
|
181
|
+
r"\bshipped\b",
|
|
182
|
+
r"\bship(?:ping)?\s+it\b",
|
|
183
|
+
r"\bit\s+works\b",
|
|
184
|
+
r"\bverified\b",
|
|
185
|
+
)
|
|
186
|
+
_CLAIM_RE = re.compile("|".join(_CLAIM_PATTERNS), re.IGNORECASE)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def is_done_claim(text: Optional[str]) -> bool:
|
|
190
|
+
"""True iff `text` asserts verified completion / shipping — a 'done' claim.
|
|
191
|
+
Conservative by design (matches explicit verification/publish phrases, not
|
|
192
|
+
bare 'done') so planning and progress chatter never trip the sentinel."""
|
|
193
|
+
if not text:
|
|
194
|
+
return False
|
|
195
|
+
return bool(_CLAIM_RE.search(text))
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def claim_tick(state_get, state_set, *, final_message: Optional[str],
|
|
199
|
+
cwd: Optional[Path] = None) -> Optional[Dict[str, Any]]:
|
|
200
|
+
"""Stop-hook entry point. Fires ONLY when the turn's final assistant message
|
|
201
|
+
asserts done/passing/shipped (is_done_claim) AND the repo HEAD has no
|
|
202
|
+
re-derived verdict. Debounced once per unproven sha per session. Fail-open.
|
|
203
|
+
|
|
204
|
+
`state_get(key)`/`state_set(key, value)` wrap SessionState so this module
|
|
205
|
+
stays import-light."""
|
|
206
|
+
try:
|
|
207
|
+
if not is_done_claim(final_message):
|
|
208
|
+
return None
|
|
209
|
+
repo = repo_toplevel(cwd)
|
|
210
|
+
if repo is None:
|
|
211
|
+
return None
|
|
212
|
+
head = _git(repo, "rev-parse", "HEAD")
|
|
213
|
+
if not head:
|
|
214
|
+
return None
|
|
215
|
+
if verdict_for(repo, head): # a re-derived verdict covers HEAD — suppress
|
|
216
|
+
return None
|
|
217
|
+
if state_get("sentinel_claim_sha") == head: # debounce: once per sha/session
|
|
218
|
+
return None
|
|
219
|
+
state_set("sentinel_claim_sha", head)
|
|
220
|
+
violation = {
|
|
221
|
+
"tier": "answer",
|
|
222
|
+
"invariant": "done-claim-verdict",
|
|
223
|
+
"evidence": (f"a done/passing claim was made but HEAD {head[:9]} has no "
|
|
224
|
+
"re-derived verdict on record"),
|
|
225
|
+
"action": ("Run `/wicked-garden:prove` to re-derive the claim now, or state "
|
|
226
|
+
"the override reason — the claim is logged either way."),
|
|
227
|
+
}
|
|
228
|
+
log_sentinel_event(repo, "unverified_claim",
|
|
229
|
+
{"sha": head, "invariant": "done-claim-verdict"})
|
|
230
|
+
return violation
|
|
231
|
+
except Exception: # noqa: BLE001 — sentinel never breaks a hook
|
|
232
|
+
return None
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# ---------------------------------------------------------------------------
|
|
236
|
+
# Invariant 2 — evidence freshness: a claim is stale when source moved after
|
|
237
|
+
# the newest recorded evidence. Applies only when the testing layer is present.
|
|
238
|
+
# ---------------------------------------------------------------------------
|
|
239
|
+
|
|
240
|
+
def _newest_evidence_ts(repo: Path) -> Optional[float]:
|
|
241
|
+
root = repo / ".wicked-testing"
|
|
242
|
+
if not root.is_dir():
|
|
243
|
+
return None
|
|
244
|
+
newest = 0.0
|
|
245
|
+
try:
|
|
246
|
+
for p in root.rglob("*"):
|
|
247
|
+
if p.is_file():
|
|
248
|
+
ts = p.stat().st_mtime
|
|
249
|
+
if ts > newest:
|
|
250
|
+
newest = ts
|
|
251
|
+
except OSError:
|
|
252
|
+
return None
|
|
253
|
+
return newest or None
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def check_evidence_freshness(repo: Path) -> Optional[Dict[str, Any]]:
|
|
257
|
+
"""Answer-tier (only when .wicked-testing exists). Modified-but-uncommitted /
|
|
258
|
+
just-committed files newer than the newest evidence record = stale claim."""
|
|
259
|
+
newest_evidence = _newest_evidence_ts(repo)
|
|
260
|
+
if newest_evidence is None:
|
|
261
|
+
return None # testing layer absent or no runs — not applicable
|
|
262
|
+
changed = _git(repo, "diff", "--name-only", "HEAD")
|
|
263
|
+
if changed is None:
|
|
264
|
+
return None
|
|
265
|
+
paths = [repo / ln for ln in changed.splitlines() if ln.strip()]
|
|
266
|
+
newest_src = 0.0
|
|
267
|
+
for p in paths:
|
|
268
|
+
try:
|
|
269
|
+
ts = p.stat().st_mtime
|
|
270
|
+
if ts > newest_src:
|
|
271
|
+
newest_src = ts
|
|
272
|
+
except OSError:
|
|
273
|
+
continue
|
|
274
|
+
if newest_src <= newest_evidence:
|
|
275
|
+
return None
|
|
276
|
+
age_min = (newest_src - newest_evidence) / 60
|
|
277
|
+
return {
|
|
278
|
+
"tier": "answer",
|
|
279
|
+
"invariant": "evidence-freshness",
|
|
280
|
+
"evidence": (f"source files changed {age_min:.0f}m after the newest "
|
|
281
|
+
f".wicked-testing evidence — the recorded runs predate this work"),
|
|
282
|
+
"action": "Re-run the relevant scenario (/wicked-testing:execution) or state why the evidence still holds.",
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
# ---------------------------------------------------------------------------
|
|
287
|
+
# Invariant 3+4+5 — session-end info tier (one line each, never blocking)
|
|
288
|
+
# ---------------------------------------------------------------------------
|
|
289
|
+
|
|
290
|
+
def _brain_memory_dir(repo: Path) -> Optional[Path]:
|
|
291
|
+
projects = Path.home() / ".wicked-brain" / "projects"
|
|
292
|
+
if not projects.is_dir():
|
|
293
|
+
return None
|
|
294
|
+
try:
|
|
295
|
+
for proj in projects.iterdir():
|
|
296
|
+
cfg = proj / "_meta" / "config.json"
|
|
297
|
+
if cfg.is_file():
|
|
298
|
+
try:
|
|
299
|
+
src = json.loads(cfg.read_text(encoding="utf-8")).get("source_path", "")
|
|
300
|
+
if src and Path(src).resolve() == repo.resolve():
|
|
301
|
+
mem = proj / "memory"
|
|
302
|
+
return mem if mem.is_dir() else None
|
|
303
|
+
except (json.JSONDecodeError, OSError):
|
|
304
|
+
continue
|
|
305
|
+
except OSError:
|
|
306
|
+
return None
|
|
307
|
+
return None
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def check_session_capture(repo: Path, session_start_ts: float,
|
|
311
|
+
activity_count: int) -> Optional[Dict[str, Any]]:
|
|
312
|
+
"""Info-tier: a significant session (>= 10 tracked activities) that captured
|
|
313
|
+
zero brain memories. Only applies when the brain layer is present."""
|
|
314
|
+
if activity_count < 10:
|
|
315
|
+
return None
|
|
316
|
+
mem = _brain_memory_dir(repo)
|
|
317
|
+
if mem is None:
|
|
318
|
+
return None # brain layer absent for this repo — not applicable
|
|
319
|
+
try:
|
|
320
|
+
wrote = any(p.stat().st_mtime >= session_start_ts
|
|
321
|
+
for p in mem.glob("*.md"))
|
|
322
|
+
except OSError:
|
|
323
|
+
return None
|
|
324
|
+
if wrote:
|
|
325
|
+
return None
|
|
326
|
+
return {
|
|
327
|
+
"tier": "info",
|
|
328
|
+
"invariant": "session-capture",
|
|
329
|
+
"evidence": f"{activity_count} tracked activities this session, 0 memories captured",
|
|
330
|
+
"action": "Worth one `wicked-brain:memory` store (decision/gotcha) before you go?",
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def check_playbook_freshness(repo: Path) -> Optional[Dict[str, Any]]:
|
|
335
|
+
"""Info-tier: wicked-understanding playbooks exist but the repo has moved
|
|
336
|
+
well past them (commits since their newest mtime > threshold)."""
|
|
337
|
+
roots = [Path.home() / ".claude" / "skills"]
|
|
338
|
+
cfg = os.environ.get("CLAUDE_CONFIG_DIR")
|
|
339
|
+
if cfg:
|
|
340
|
+
roots.append(Path(cfg) / "skills")
|
|
341
|
+
newest = 0.0
|
|
342
|
+
for root in roots:
|
|
343
|
+
try:
|
|
344
|
+
if root.is_dir():
|
|
345
|
+
for entry in root.iterdir():
|
|
346
|
+
if entry.is_dir() and entry.name.startswith(("repo-", "fix-bug", "add-feature")):
|
|
347
|
+
ts = entry.stat().st_mtime
|
|
348
|
+
if ts > newest:
|
|
349
|
+
newest = ts
|
|
350
|
+
except OSError:
|
|
351
|
+
continue
|
|
352
|
+
if not newest:
|
|
353
|
+
return None # understanding layer absent — not applicable
|
|
354
|
+
iso = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(newest))
|
|
355
|
+
count = _git(repo, "rev-list", "--count", f"--since={iso}", "HEAD")
|
|
356
|
+
try:
|
|
357
|
+
behind = int(count) if count else 0
|
|
358
|
+
except ValueError:
|
|
359
|
+
return None
|
|
360
|
+
if behind < _PLAYBOOK_STALE_COMMITS:
|
|
361
|
+
return None
|
|
362
|
+
return {
|
|
363
|
+
"tier": "info",
|
|
364
|
+
"invariant": "playbook-freshness",
|
|
365
|
+
"evidence": f"repo playbooks were generated ~{behind} commits ago",
|
|
366
|
+
"action": "Re-run `repo-analyst` so the how-to playbooks track HEAD.",
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def session_end_lines(cwd: Optional[Path], session_start_ts: float,
|
|
371
|
+
activity_count: int) -> List[str]:
|
|
372
|
+
"""The Stop/SessionEnd bundle — info-tier lines only, each fail-open."""
|
|
373
|
+
repo = repo_toplevel(cwd)
|
|
374
|
+
if repo is None:
|
|
375
|
+
return []
|
|
376
|
+
lines: List[str] = []
|
|
377
|
+
for check in (lambda: check_session_capture(repo, session_start_ts, activity_count),
|
|
378
|
+
lambda: check_playbook_freshness(repo)):
|
|
379
|
+
try:
|
|
380
|
+
v = check()
|
|
381
|
+
except Exception: # noqa: BLE001
|
|
382
|
+
v = None
|
|
383
|
+
if v:
|
|
384
|
+
lines.append(f"[Sentinel:{v['invariant']}] {v['evidence']} → {v['action']}")
|
|
385
|
+
return lines
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
# ---------------------------------------------------------------------------
|
|
389
|
+
# Rendering — one consistent voice for the answer tier
|
|
390
|
+
# ---------------------------------------------------------------------------
|
|
391
|
+
|
|
392
|
+
def render(violation: Dict[str, Any]) -> str:
|
|
393
|
+
return (f"[Sentinel:{violation['invariant']}] {violation['evidence']}.\n"
|
|
394
|
+
f"→ {violation['action']}")
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
__all__ = [
|
|
398
|
+
"repo_toplevel", "stamp_verdict", "verdict_for", "log_sentinel_event",
|
|
399
|
+
"is_done_claim", "claim_tick",
|
|
400
|
+
"check_evidence_freshness", "check_session_capture",
|
|
401
|
+
"check_playbook_freshness", "session_end_lines", "render",
|
|
402
|
+
]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""pre_push.py — the claim sentinel's local pre-push gate (layer 1 of 3).
|
|
3
|
+
|
|
4
|
+
Reads git's pre-push stdin ("<local_ref> <local_sha> <remote_ref> <remote_sha>"
|
|
5
|
+
per line) and BLOCKS (exit 1) when a *publish-shaped* ref — the remote default
|
|
6
|
+
branch or any tag — is being pushed with no re-derived verdict covering the
|
|
7
|
+
pushed sha on the sentinel ledger. Feature-branch pushes always pass: the claim
|
|
8
|
+
moment is publishing "done", not sharing work-in-progress.
|
|
9
|
+
|
|
10
|
+
Layers (see scripts/sentinel/invariants.py):
|
|
11
|
+
1. this hook — local, fires for ANY tool that pushes through git
|
|
12
|
+
2. required CI check — server-side, catches gh-pr-merge/web/API paths
|
|
13
|
+
3. harness ref-watch — detects + records what slipped past both
|
|
14
|
+
|
|
15
|
+
Override: `git push --no-verify` (git's own explicit skip — visible, and the
|
|
16
|
+
server layer still gates). Fail-open on machinery errors: a broken sentinel
|
|
17
|
+
must never brick pushes; only a *present ledger with no verdict* blocks.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import sys
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
26
|
+
from invariants import log_sentinel_event, repo_toplevel, verdict_for # noqa: E402
|
|
27
|
+
|
|
28
|
+
_ZERO_SHA = "0" * 40
|
|
29
|
+
_DEFAULT_BRANCH_REFS = ("refs/heads/main", "refs/heads/master")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _publish_shaped(remote_ref: str) -> bool:
|
|
33
|
+
return remote_ref in _DEFAULT_BRANCH_REFS or remote_ref.startswith("refs/tags/")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def main() -> int:
|
|
37
|
+
try:
|
|
38
|
+
repo = repo_toplevel()
|
|
39
|
+
if repo is None:
|
|
40
|
+
return 0 # not a repo — nothing to gate
|
|
41
|
+
blocked = []
|
|
42
|
+
for line in sys.stdin.read().splitlines():
|
|
43
|
+
parts = line.split()
|
|
44
|
+
if len(parts) != 4:
|
|
45
|
+
continue
|
|
46
|
+
_local_ref, local_sha, remote_ref, _remote_sha = parts
|
|
47
|
+
if local_sha == _ZERO_SHA: # deletion — not a done-claim
|
|
48
|
+
continue
|
|
49
|
+
if not _publish_shaped(remote_ref):
|
|
50
|
+
continue
|
|
51
|
+
if verdict_for(repo, local_sha) is None:
|
|
52
|
+
blocked.append((remote_ref, local_sha))
|
|
53
|
+
if not blocked:
|
|
54
|
+
return 0
|
|
55
|
+
for remote_ref, sha in blocked:
|
|
56
|
+
print(
|
|
57
|
+
f"[Sentinel:done-claim-verdict] pushing {remote_ref} @ {sha[:9]} "
|
|
58
|
+
"with no re-derived verdict on record.\n"
|
|
59
|
+
"→ Run `/wicked-garden:prove` (stamps the ledger via the gate), "
|
|
60
|
+
"or override deliberately with `git push --no-verify` — the server "
|
|
61
|
+
"gate still applies.",
|
|
62
|
+
file=sys.stderr,
|
|
63
|
+
)
|
|
64
|
+
log_sentinel_event(repo, "prepush_blocked",
|
|
65
|
+
{"ref": remote_ref, "sha": sha,
|
|
66
|
+
"invariant": "done-claim-verdict"})
|
|
67
|
+
return 1
|
|
68
|
+
except Exception: # noqa: BLE001 — machinery failure must not brick pushes
|
|
69
|
+
return 0
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if __name__ == "__main__":
|
|
73
|
+
sys.exit(main())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Setup helpers for /wicked-garden:setup. Stdlib-only."""
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""detect_state.py — environment + config detection for /wicked-garden:setup.
|
|
3
|
+
|
|
4
|
+
Pure-function probes that the slash command would otherwise inline as
|
|
5
|
+
ad-hoc Python. Each subcommand prints a single JSON object so the
|
|
6
|
+
markdown body can `jq` or read raw.
|
|
7
|
+
|
|
8
|
+
Stdlib-only.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
_SCRIPTS_ROOT = Path(__file__).resolve().parents[1]
|
|
20
|
+
sys.path.insert(0, str(_SCRIPTS_ROOT))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def detect_question_mode() -> str:
|
|
24
|
+
"""Return ``'PLAIN_TEXT'`` if dangerous mode is active, else ``'INTERACTIVE'``.
|
|
25
|
+
|
|
26
|
+
The slash command branches between AskUserQuestion and numbered-list
|
|
27
|
+
prompts on this value.
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
from _session import SessionState # type: ignore
|
|
31
|
+
except Exception:
|
|
32
|
+
return "INTERACTIVE"
|
|
33
|
+
try:
|
|
34
|
+
state = SessionState.load()
|
|
35
|
+
except Exception:
|
|
36
|
+
return "INTERACTIVE"
|
|
37
|
+
return "PLAIN_TEXT" if getattr(state, "dangerous_mode", False) else "INTERACTIVE"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def read_config() -> dict:
|
|
41
|
+
"""Read ``~/.something-wicked/wicked-garden/config.json`` if present."""
|
|
42
|
+
path = Path.home() / ".something-wicked" / "wicked-garden" / "config.json"
|
|
43
|
+
if not path.exists():
|
|
44
|
+
return {"present": False, "path": str(path)}
|
|
45
|
+
try:
|
|
46
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
47
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
48
|
+
return {"present": True, "path": str(path), "error": str(exc)}
|
|
49
|
+
return {"present": True, "path": str(path), "config": data}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# Marker files used to fingerprint the working directory.
|
|
53
|
+
_LANGUAGE_MARKERS: dict[str, list[str]] = {
|
|
54
|
+
"Python": ["pyproject.toml", "setup.py", "requirements.txt", "Pipfile"],
|
|
55
|
+
"Node/TypeScript": ["package.json", "tsconfig.json"],
|
|
56
|
+
"Go": ["go.mod"],
|
|
57
|
+
"Rust": ["Cargo.toml"],
|
|
58
|
+
"Java/Kotlin": ["pom.xml", "build.gradle", "build.gradle.kts"],
|
|
59
|
+
"Ruby": ["Gemfile"],
|
|
60
|
+
"PHP": ["composer.json"],
|
|
61
|
+
"Swift": ["Package.swift"],
|
|
62
|
+
"C/C++": ["CMakeLists.txt", "Makefile"],
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
_FRAMEWORK_MARKERS: dict[str, list[str]] = {
|
|
66
|
+
"FastAPI": ["app/main.py", "main.py"],
|
|
67
|
+
"Django": ["manage.py"],
|
|
68
|
+
"Flask": ["app.py"],
|
|
69
|
+
"Next.js": ["next.config.js", "next.config.ts"],
|
|
70
|
+
"React": ["src/App.tsx", "src/App.jsx"],
|
|
71
|
+
"Vue": ["vue.config.js"],
|
|
72
|
+
"Rails": ["config/routes.rb"],
|
|
73
|
+
"Claude Plugin": [".claude-plugin/plugin.json"],
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def detect_project_env(cwd: Path | None = None) -> dict:
|
|
78
|
+
"""Detect languages and frameworks in ``cwd`` (defaults to CWD)."""
|
|
79
|
+
root = (cwd or Path.cwd()).resolve()
|
|
80
|
+
languages = [
|
|
81
|
+
name
|
|
82
|
+
for name, files in _LANGUAGE_MARKERS.items()
|
|
83
|
+
if any((root / f).exists() for f in files)
|
|
84
|
+
]
|
|
85
|
+
frameworks = [
|
|
86
|
+
name
|
|
87
|
+
for name, files in _FRAMEWORK_MARKERS.items()
|
|
88
|
+
if any((root / f).exists() for f in files)
|
|
89
|
+
]
|
|
90
|
+
return {"cwd": str(root), "languages": languages, "frameworks": frameworks}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _cli() -> int:
|
|
94
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
95
|
+
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
96
|
+
sub.add_parser("question-mode", help="INTERACTIVE | PLAIN_TEXT")
|
|
97
|
+
sub.add_parser("config", help="Show wicked-garden config.json contents")
|
|
98
|
+
env = sub.add_parser("project-env", help="Detect languages + frameworks in CWD")
|
|
99
|
+
env.add_argument("--cwd", default=None)
|
|
100
|
+
args = parser.parse_args()
|
|
101
|
+
if args.cmd == "question-mode":
|
|
102
|
+
sys.stdout.write(detect_question_mode() + "\n")
|
|
103
|
+
elif args.cmd == "config":
|
|
104
|
+
json.dump(read_config(), sys.stdout, indent=2)
|
|
105
|
+
sys.stdout.write("\n")
|
|
106
|
+
elif args.cmd == "project-env":
|
|
107
|
+
cwd = Path(args.cwd) if args.cwd else None
|
|
108
|
+
json.dump(detect_project_env(cwd), sys.stdout, indent=2)
|
|
109
|
+
sys.stdout.write("\n")
|
|
110
|
+
return 0
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == "__main__":
|
|
114
|
+
sys.exit(_cli())
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""migrate_legacy.py — legacy reference scans for /wicked-garden:setup.
|
|
3
|
+
|
|
4
|
+
Section 2.6 of the setup command needs to scan crew project directories
|
|
5
|
+
for legacy ``qe-evaluator`` strings in reeval and amendment logs. The
|
|
6
|
+
scan was inlined in markdown; this module exposes it as a callable +
|
|
7
|
+
CLI so the command body can stay slim.
|
|
8
|
+
|
|
9
|
+
Stdlib-only.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import json
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
_LEGACY_PATTERNS = (
|
|
20
|
+
'"reviewer": "qe-evaluator"',
|
|
21
|
+
'"trigger": "qe-evaluator:',
|
|
22
|
+
)
|
|
23
|
+
_TARGET_GLOBS = (
|
|
24
|
+
"phases/*/reeval-log.jsonl",
|
|
25
|
+
"phases/*/amendments.jsonl",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def scan_qe_evaluator_refs(projects_root: Path | None = None) -> list[str]:
|
|
30
|
+
"""Return the list of files that still contain legacy qe-evaluator refs."""
|
|
31
|
+
root = projects_root or (
|
|
32
|
+
Path.home() / ".something-wicked" / "wicked-garden" / "projects"
|
|
33
|
+
)
|
|
34
|
+
found: list[str] = []
|
|
35
|
+
if not root.exists():
|
|
36
|
+
return found
|
|
37
|
+
for pattern in _TARGET_GLOBS:
|
|
38
|
+
for f in root.glob("*/" + pattern):
|
|
39
|
+
try:
|
|
40
|
+
text = f.read_text(encoding="utf-8")
|
|
41
|
+
except OSError:
|
|
42
|
+
continue
|
|
43
|
+
if any(p in text for p in _LEGACY_PATTERNS):
|
|
44
|
+
found.append(str(f))
|
|
45
|
+
return found
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _cli() -> int:
|
|
49
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
50
|
+
parser.add_argument("--projects-root", default=None)
|
|
51
|
+
parser.add_argument("--json", action="store_true", help="Emit JSON instead of human text")
|
|
52
|
+
args = parser.parse_args()
|
|
53
|
+
root = Path(args.projects_root) if args.projects_root else None
|
|
54
|
+
found = scan_qe_evaluator_refs(root)
|
|
55
|
+
if args.json:
|
|
56
|
+
json.dump({"status": "LEGACY_FOUND" if found else "CLEAN", "files": found},
|
|
57
|
+
sys.stdout, indent=2)
|
|
58
|
+
sys.stdout.write("\n")
|
|
59
|
+
else:
|
|
60
|
+
sys.stdout.write("LEGACY_FOUND\n" if found else "CLEAN\n")
|
|
61
|
+
for path in found:
|
|
62
|
+
sys.stdout.write(path + "\n")
|
|
63
|
+
return 0
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
sys.exit(_cli())
|