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,171 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
wicked-jam transcript persistence helper.
|
|
4
|
+
|
|
5
|
+
Called by facilitator and council agents after each session to store
|
|
6
|
+
individual persona contributions for later retrieval via jam.py.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
save_transcript.py --session-id ID --entries '[{...}, ...]'
|
|
10
|
+
|
|
11
|
+
The --entries argument must be a JSON array of transcript entry objects.
|
|
12
|
+
Each entry schema:
|
|
13
|
+
{
|
|
14
|
+
"session_id": "...",
|
|
15
|
+
"round": 1,
|
|
16
|
+
"persona_name": "Technical Architect",
|
|
17
|
+
"persona_type": "technical", # technical | user | business | process | council
|
|
18
|
+
"raw_text": "...",
|
|
19
|
+
"timestamp": "...", # ISO 8601 (auto-set if omitted)
|
|
20
|
+
"entry_type": "perspective" # perspective | synthesis | council_response
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
Existing entries for the session are loaded, new entries are appended,
|
|
24
|
+
then the whole transcript is saved back via DomainStore.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import argparse
|
|
28
|
+
import json
|
|
29
|
+
import sys
|
|
30
|
+
from datetime import datetime, timezone
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
34
|
+
|
|
35
|
+
_sm = None
|
|
36
|
+
|
|
37
|
+
VALID_ENTRY_TYPES = {"perspective", "synthesis", "council_response"}
|
|
38
|
+
VALID_PERSONA_TYPES = {"technical", "user", "business", "process", "council"}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _iso_now() -> str:
|
|
42
|
+
return datetime.now(timezone.utc).isoformat()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _validate_entry(entry: dict, session_id: str) -> dict:
|
|
46
|
+
"""Fill defaults and validate a single transcript entry. Returns the normalised entry."""
|
|
47
|
+
entry = dict(entry)
|
|
48
|
+
|
|
49
|
+
# Enforce session_id
|
|
50
|
+
entry["session_id"] = session_id
|
|
51
|
+
|
|
52
|
+
# Default timestamp
|
|
53
|
+
if not entry.get("timestamp"):
|
|
54
|
+
entry["timestamp"] = _iso_now()
|
|
55
|
+
|
|
56
|
+
# Default round
|
|
57
|
+
if "round" not in entry:
|
|
58
|
+
entry["round"] = 1
|
|
59
|
+
|
|
60
|
+
# Validate entry_type
|
|
61
|
+
etype = entry.get("entry_type", "")
|
|
62
|
+
if etype not in VALID_ENTRY_TYPES:
|
|
63
|
+
raise ValueError(
|
|
64
|
+
f"Invalid entry_type {etype!r}. Must be one of: {sorted(VALID_ENTRY_TYPES)}"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Validate persona_type (soft — unknown types are kept but warned)
|
|
68
|
+
ptype = entry.get("persona_type", "")
|
|
69
|
+
if ptype and ptype not in VALID_PERSONA_TYPES:
|
|
70
|
+
print(
|
|
71
|
+
f"Warning: unknown persona_type {ptype!r}. "
|
|
72
|
+
f"Expected one of: {sorted(VALID_PERSONA_TYPES)}",
|
|
73
|
+
file=sys.stderr,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Require raw_text
|
|
77
|
+
if not entry.get("raw_text", "").strip():
|
|
78
|
+
raise ValueError("Entry is missing required field: raw_text")
|
|
79
|
+
|
|
80
|
+
# Require persona_name
|
|
81
|
+
if not entry.get("persona_name", "").strip():
|
|
82
|
+
raise ValueError("Entry is missing required field: persona_name")
|
|
83
|
+
|
|
84
|
+
return entry
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _get_sm():
|
|
88
|
+
"""Lazy DomainStore init — deferred to call time, not import time."""
|
|
89
|
+
global _sm
|
|
90
|
+
if _sm is None:
|
|
91
|
+
from _domain_store import DomainStore
|
|
92
|
+
_sm = DomainStore("wicked-jam")
|
|
93
|
+
return _sm
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def save_transcript_entries(session_id: str, new_entries: list) -> dict:
|
|
97
|
+
"""
|
|
98
|
+
Append new_entries to the stored transcript for session_id.
|
|
99
|
+
|
|
100
|
+
Returns a result dict with counts and any error.
|
|
101
|
+
"""
|
|
102
|
+
if not session_id:
|
|
103
|
+
return {"ok": False, "error": "session_id is required"}
|
|
104
|
+
|
|
105
|
+
if not isinstance(new_entries, list) or not new_entries:
|
|
106
|
+
return {"ok": False, "error": "entries must be a non-empty JSON array"}
|
|
107
|
+
|
|
108
|
+
sm = _get_sm()
|
|
109
|
+
|
|
110
|
+
# Load existing transcript (or start fresh)
|
|
111
|
+
existing = sm.get("transcripts", session_id)
|
|
112
|
+
existing_entries = existing.get("entries", []) if existing else []
|
|
113
|
+
|
|
114
|
+
validated = []
|
|
115
|
+
for i, entry in enumerate(new_entries):
|
|
116
|
+
try:
|
|
117
|
+
validated.append(_validate_entry(entry, session_id))
|
|
118
|
+
except (ValueError, TypeError) as exc:
|
|
119
|
+
return {"ok": False, "error": f"Entry #{i}: {exc}"}
|
|
120
|
+
|
|
121
|
+
merged = existing_entries + validated
|
|
122
|
+
transcript_doc = {"id": session_id, "session_id": session_id, "entries": merged}
|
|
123
|
+
|
|
124
|
+
if existing:
|
|
125
|
+
sm.update("transcripts", session_id, {"entries": merged})
|
|
126
|
+
else:
|
|
127
|
+
sm.create("transcripts", transcript_doc)
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
"ok": True,
|
|
131
|
+
"session_id": session_id,
|
|
132
|
+
"entries_added": len(validated),
|
|
133
|
+
"entries_total": len(merged),
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def main():
|
|
138
|
+
parser = argparse.ArgumentParser(description="Persist jam transcript entries")
|
|
139
|
+
parser.add_argument("--session-id", required=True, help="Brainstorm session ID")
|
|
140
|
+
parser.add_argument(
|
|
141
|
+
"--entries",
|
|
142
|
+
required=True,
|
|
143
|
+
help="JSON array of transcript entry objects",
|
|
144
|
+
)
|
|
145
|
+
parser.add_argument("--json", action="store_true", help="Output result as JSON")
|
|
146
|
+
args = parser.parse_args()
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
entries = json.loads(args.entries)
|
|
150
|
+
except json.JSONDecodeError as exc:
|
|
151
|
+
result = {"ok": False, "error": f"Invalid JSON in --entries: {exc}"}
|
|
152
|
+
print(json.dumps(result, indent=2) if getattr(args, "json", False) else result["error"])
|
|
153
|
+
sys.exit(1)
|
|
154
|
+
|
|
155
|
+
result = save_transcript_entries(session_id=args.session_id, new_entries=entries)
|
|
156
|
+
|
|
157
|
+
if getattr(args, "json", False):
|
|
158
|
+
print(json.dumps(result, indent=2))
|
|
159
|
+
else:
|
|
160
|
+
if result.get("ok"):
|
|
161
|
+
added = result["entries_added"]
|
|
162
|
+
total = result["entries_total"]
|
|
163
|
+
print(f"Saved {added} transcript {'entry' if added == 1 else 'entries'} "
|
|
164
|
+
f"(total: {total}) for session: {args.session_id}")
|
|
165
|
+
else:
|
|
166
|
+
print(f"Error: {result.get('error', 'unknown error')}", file=sys.stderr)
|
|
167
|
+
sys.exit(1)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
if __name__ == "__main__":
|
|
171
|
+
main()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""loom — absorbed peer-resolution runtime (wicked-loom Phase B absorption).
|
|
2
|
+
|
|
3
|
+
This package is the absorbed peer-resolution surface from wicked-loom,
|
|
4
|
+
moved into wicked-garden as part of the wicked-* ecosystem rationalization
|
|
5
|
+
(ECOSYSTEM-RATIONALIZATION.md §5a Phase B).
|
|
6
|
+
|
|
7
|
+
KEPT (peer-resolution surface — this package):
|
|
8
|
+
manifest.py — peer registry: peer names, version pins, install/probe commands
|
|
9
|
+
resolve.py — runtime resolution ladder: env → PATH → npx
|
|
10
|
+
compose.py — version-check + install orchestration (doctor / compose install)
|
|
11
|
+
gate.py — synchronous fail-closed produces gate (vault cross-check wrapper)
|
|
12
|
+
cli.py — slim CLI: resolve / doctor / compose / gate ONLY
|
|
13
|
+
|
|
14
|
+
RETIRED (flow conductor surface — NOT included):
|
|
15
|
+
flow.py — loom flow run/status/resume → RETIRED, replaced by wicked-crew
|
|
16
|
+
flowstate.py — flow state persistence → RETIRED
|
|
17
|
+
busemit.py — bus event emission for flow → RETIRED
|
|
18
|
+
|
|
19
|
+
wicked-loom as a standalone npm package is absorbed — users do not need to
|
|
20
|
+
install it separately. The external CLI (wicked-loom / loom) is no longer
|
|
21
|
+
required; garden's scripts/_loom.py dispatches to this package in-process.
|
|
22
|
+
"""
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""cli.py — argument dispatch + JSON output for the peer-resolution surface.
|
|
2
|
+
|
|
3
|
+
Absorbed from wicked-loom (Phase B — ECOSYSTEM-RATIONALIZATION.md §5a).
|
|
4
|
+
|
|
5
|
+
ACTIVE commands (absorbed into wicked-garden):
|
|
6
|
+
loom resolve <peer> -> {"peer","command"} exit 0/1
|
|
7
|
+
loom doctor [--strict] -> {"peers":[check rows], ...} exit 0/1
|
|
8
|
+
loom compose install [--peer X] -> {"results":[install rows]} exit 0/1
|
|
9
|
+
loom gate <produces> [--scope S] -> {"gate":{...}} exit 0/1
|
|
10
|
+
|
|
11
|
+
RETIRED commands (NOT included — replaced by wicked-crew + wicked-orchestration):
|
|
12
|
+
loom flow run — RETIRED (was: run a flow from a JSON definition)
|
|
13
|
+
loom flow status — RETIRED (was: read persisted flow state)
|
|
14
|
+
loom flow resume — RETIRED (was: resume a parked/running flow)
|
|
15
|
+
|
|
16
|
+
No business logic lives here — only parsing + formatting.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
import sys
|
|
23
|
+
from typing import Optional
|
|
24
|
+
|
|
25
|
+
from loom import manifest
|
|
26
|
+
from loom.compose import check_all, install_peer
|
|
27
|
+
from loom.resolve import resolve
|
|
28
|
+
from loom.gate import run_gate
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _emit(obj: dict) -> None:
|
|
32
|
+
sys.stdout.write(json.dumps(obj) + "\n")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _cmd_resolve(args: list) -> int:
|
|
36
|
+
if not args:
|
|
37
|
+
_emit({"error": "usage: loom resolve <peer>"})
|
|
38
|
+
return 2
|
|
39
|
+
cmd = resolve(args[0])
|
|
40
|
+
_emit({"peer": args[0], "command": cmd})
|
|
41
|
+
return 0 if cmd is not None else 1
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _cmd_doctor(args: list) -> int:
|
|
45
|
+
"""Report every peer's reachability AND declared capability.
|
|
46
|
+
|
|
47
|
+
Two orthogonal signals live on each row:
|
|
48
|
+
* ``status`` — runtime REACHABILITY (ok/drift/present/missing/error)
|
|
49
|
+
* ``capability_ok`` — declared CAPABILITY readiness (True only for ``wired``)
|
|
50
|
+
|
|
51
|
+
Default exit keys on reachability only (``status == "ok"``). ``--strict``
|
|
52
|
+
makes the EXIT additionally assert ``capability_ok`` for every peer.
|
|
53
|
+
"""
|
|
54
|
+
strict = "--strict" in args
|
|
55
|
+
rows = check_all()
|
|
56
|
+
all_reachable = all(r.get("status") == "ok" for r in rows)
|
|
57
|
+
not_capable = [r.get("peer") for r in rows if not r.get("capability_ok")]
|
|
58
|
+
all_capable = not not_capable
|
|
59
|
+
_emit({
|
|
60
|
+
"peers": rows,
|
|
61
|
+
"all_reachable": all_reachable,
|
|
62
|
+
"all_capable": all_capable,
|
|
63
|
+
"not_capable": not_capable,
|
|
64
|
+
"strict": strict,
|
|
65
|
+
})
|
|
66
|
+
ok = all_reachable and (all_capable if strict else True)
|
|
67
|
+
return 0 if ok else 1
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _cmd_compose(args: list) -> int:
|
|
71
|
+
if not args or args[0] != "install":
|
|
72
|
+
_emit({"error": "usage: loom compose install [--peer <name>]"})
|
|
73
|
+
return 2
|
|
74
|
+
target = None
|
|
75
|
+
if "--peer" in args:
|
|
76
|
+
i = args.index("--peer")
|
|
77
|
+
if i + 1 < len(args):
|
|
78
|
+
target = args[i + 1]
|
|
79
|
+
names = [target] if target else list(manifest.PEERS)
|
|
80
|
+
results = [install_peer(n) for n in names]
|
|
81
|
+
_emit({"results": results})
|
|
82
|
+
return 0 if all(r.get("status") == "installed" for r in results) else 1
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
_VALUE_OPTS = ("--scope", "--verifier-spec")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _positionals(args: list) -> list:
|
|
89
|
+
"""Return the positional tokens, skipping flags and value-taking option tokens."""
|
|
90
|
+
out: list = []
|
|
91
|
+
i = 0
|
|
92
|
+
n = len(args)
|
|
93
|
+
while i < n:
|
|
94
|
+
tok = args[i]
|
|
95
|
+
if tok in _VALUE_OPTS:
|
|
96
|
+
i += 2
|
|
97
|
+
continue
|
|
98
|
+
if tok.startswith("--"):
|
|
99
|
+
i += 1
|
|
100
|
+
continue
|
|
101
|
+
out.append(tok)
|
|
102
|
+
i += 1
|
|
103
|
+
return out
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _opt(args: list, name: str) -> Optional[str]:
|
|
107
|
+
"""Return the value following ``--name`` in args, or None."""
|
|
108
|
+
if name in args:
|
|
109
|
+
i = args.index(name)
|
|
110
|
+
if i + 1 < len(args):
|
|
111
|
+
return args[i + 1]
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _cmd_gate(args: list) -> int:
|
|
116
|
+
scope = _opt(args, "--scope") or "default"
|
|
117
|
+
verifier_spec = _opt(args, "--verifier-spec")
|
|
118
|
+
positional = _positionals(args)
|
|
119
|
+
produces = positional[0] if positional else None
|
|
120
|
+
if produces is None:
|
|
121
|
+
_emit({"error": "usage: loom gate <produces> [--scope S] "
|
|
122
|
+
"[--verifier-spec PATH] [--with-attestations]"})
|
|
123
|
+
return 2
|
|
124
|
+
verdict = run_gate(produces, scope=scope, verifier_spec=verifier_spec,
|
|
125
|
+
with_attestations="--with-attestations" in args)
|
|
126
|
+
_emit({"gate": verdict})
|
|
127
|
+
return 0 if verdict.get("satisfied") else 1
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
_DISPATCH = {
|
|
131
|
+
"resolve": _cmd_resolve,
|
|
132
|
+
"doctor": _cmd_doctor,
|
|
133
|
+
"compose": _cmd_compose,
|
|
134
|
+
"gate": _cmd_gate,
|
|
135
|
+
# flow subcommands are RETIRED — not included. Use wicked-crew for
|
|
136
|
+
# multi-phase orchestration (see ECOSYSTEM-RATIONALIZATION.md §5a).
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def main(argv: "list[str] | None" = None) -> int:
|
|
141
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
142
|
+
if not argv or argv[0] in ("-h", "--help"):
|
|
143
|
+
_emit({"commands": list(_DISPATCH)})
|
|
144
|
+
return 0
|
|
145
|
+
handler = _DISPATCH.get(argv[0])
|
|
146
|
+
if handler is None:
|
|
147
|
+
if argv[0] == "flow":
|
|
148
|
+
_emit({
|
|
149
|
+
"error": "loom flow is retired",
|
|
150
|
+
"detail": (
|
|
151
|
+
"loom flow run/status/resume was part of the loom conduct "
|
|
152
|
+
"surface, replaced by wicked-crew + wicked-orchestration "
|
|
153
|
+
"(ECOSYSTEM-RATIONALIZATION.md §5a Phase B). "
|
|
154
|
+
"See /wicked-garden:archetype:migrate for the migration path."
|
|
155
|
+
),
|
|
156
|
+
})
|
|
157
|
+
return 2
|
|
158
|
+
_emit({"error": f"unknown command: {argv[0]}", "commands": list(_DISPATCH)})
|
|
159
|
+
return 2
|
|
160
|
+
try:
|
|
161
|
+
return handler(argv[1:])
|
|
162
|
+
except Exception as e: # noqa: BLE001 — surface as data, never traceback.
|
|
163
|
+
_emit({"error": f"{type(e).__name__}: {e}",
|
|
164
|
+
"command": argv[0],
|
|
165
|
+
"detail": "loom never raises at the CLI boundary (R4)."})
|
|
166
|
+
return 2
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
if __name__ == "__main__":
|
|
170
|
+
sys.exit(main())
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""compose.py — version-check + install orchestration over the peer set.
|
|
2
|
+
|
|
3
|
+
Absorbed from wicked-loom (Phase B — ECOSYSTEM-RATIONALIZATION.md §5a).
|
|
4
|
+
|
|
5
|
+
check_peer: resolve -> probe -> parse version -> compare MAJOR.MINOR to the pin.
|
|
6
|
+
install_peer: run the peer's headless install command.
|
|
7
|
+
check_all: one check_peer row per known peer.
|
|
8
|
+
|
|
9
|
+
Subprocess execution is injected (the ``run`` parameter) so callers (and tests)
|
|
10
|
+
control side effects. Nothing here raises — failures are returned as status
|
|
11
|
+
rows ("ok" | "drift" | "present" | "missing" | "error" | "installed"
|
|
12
|
+
| "install-failed").
|
|
13
|
+
|
|
14
|
+
Status semantics (no cry-wolf — see R4 "never raise, surface as data"):
|
|
15
|
+
ok — resolved, probe ran, version parsed, version >= pin.
|
|
16
|
+
drift — resolved, probe ran, version parsed, version < pin.
|
|
17
|
+
present — resolved AND the probe binary RAN (we got a RunResult, not an
|
|
18
|
+
exception), but its version could not be determined: a non-zero
|
|
19
|
+
exit (older CLIs print help/usage when given ``--version``) or
|
|
20
|
+
unparseable output. The peer is healthy/responding; we just can't
|
|
21
|
+
read its version. This is WARN-level, NOT an error — reporting a
|
|
22
|
+
responding peer as "error" was a false alarm (cry-wolf). The
|
|
23
|
+
``ok`` flag on the row is True so health probes don't fail hard.
|
|
24
|
+
missing — unresolvable: no binary on PATH / npx / env override (kill-switch).
|
|
25
|
+
error — reserved for genuine faults: unknown peer, or the probe attempt
|
|
26
|
+
RAISED (binary vanished, OS error). A responding-but-unparseable
|
|
27
|
+
peer is NEVER "error".
|
|
28
|
+
|
|
29
|
+
``status`` above is runtime REACHABILITY (can we run it / does its version meet
|
|
30
|
+
the pin). Every row ALSO carries the peer's declared CAPABILITY readiness under
|
|
31
|
+
a separate ``capability`` key (``wired``/``planned``/``experimental`` from
|
|
32
|
+
manifest.Peer.status) plus ``capability_ok``. The two are deliberately distinct:
|
|
33
|
+
a peer can be perfectly reachable (status ``ok``) yet not wired as a capability
|
|
34
|
+
(``capability`` ``planned``) — doctor must answer "reachable but not wired yet"
|
|
35
|
+
distinctly from "missing/drift". Overloading the reachability ``status`` key
|
|
36
|
+
would break doctor's exit logic, so the capability lives on its own key.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
import re
|
|
42
|
+
import subprocess
|
|
43
|
+
from dataclasses import dataclass
|
|
44
|
+
from typing import Callable
|
|
45
|
+
|
|
46
|
+
from loom import manifest
|
|
47
|
+
from loom.manifest import Peer
|
|
48
|
+
from loom.resolve import resolve_version_bin
|
|
49
|
+
|
|
50
|
+
_VERSION_RE = re.compile(r"(\d+)\.(\d+)(?:\.(\d+))?")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class RunResult:
|
|
55
|
+
returncode: int
|
|
56
|
+
stdout: str
|
|
57
|
+
stderr: str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
Runner = Callable[..., RunResult]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _default_run(cmd: list, timeout: int = 30) -> RunResult:
|
|
64
|
+
p = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
|
|
65
|
+
return RunResult(returncode=p.returncode, stdout=p.stdout, stderr=p.stderr)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _parse_version(text: str) -> "str | None":
|
|
69
|
+
m = _VERSION_RE.search(text or "")
|
|
70
|
+
if not m:
|
|
71
|
+
return None
|
|
72
|
+
major, minor, patch = m.group(1), m.group(2), m.group(3) or "0"
|
|
73
|
+
return f"{major}.{minor}.{patch}"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _meets_pin(installed: str, pin: str) -> bool:
|
|
77
|
+
iv = _parse_version(installed)
|
|
78
|
+
pv = _parse_version(pin)
|
|
79
|
+
if iv is None or pv is None:
|
|
80
|
+
return False
|
|
81
|
+
ip = [int(x) for x in iv.split(".")]
|
|
82
|
+
pp = [int(x) for x in pv.split(".")]
|
|
83
|
+
return (ip[0], ip[1]) >= (pp[0], pp[1]) # MAJOR.MINOR floor
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _probe_command(version_cmd: list, peer: Peer) -> list:
|
|
87
|
+
"""The version-probe argv: the resolved version binary + the probe's
|
|
88
|
+
trailing args.
|
|
89
|
+
|
|
90
|
+
The version binary can differ from the runnable package — brain runs as
|
|
91
|
+
``wicked-brain`` but reports its version via ``wicked-brain-server`` — so
|
|
92
|
+
we resolve ``peer.version_package`` (not npm_package) here.
|
|
93
|
+
"""
|
|
94
|
+
return version_cmd + peer.probe_cmd[1:]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _stamp_capability(row: dict, peer: "Peer | None") -> dict:
|
|
98
|
+
"""Add the peer's declared capability readiness to a reachability row.
|
|
99
|
+
|
|
100
|
+
``capability`` is the manifest's honest status (wired/planned/experimental)
|
|
101
|
+
— orthogonal to the row's ``status`` (reachability). ``capability_ok`` mirrors
|
|
102
|
+
the never-fake predicate (``True`` only for ``wired``). For an unknown peer
|
|
103
|
+
(no manifest entry) there is no declared capability, so both are None/False.
|
|
104
|
+
Doctor surfaces these so "reachable but not wired" reads distinctly from
|
|
105
|
+
"missing/drift". This NEVER changes the reachability ``status`` or ``ok`` keys
|
|
106
|
+
— the capability is purely additive (no cry-wolf, no exit-logic change).
|
|
107
|
+
"""
|
|
108
|
+
if peer is None:
|
|
109
|
+
row["capability"] = None
|
|
110
|
+
row["capability_ok"] = False
|
|
111
|
+
else:
|
|
112
|
+
row["capability"] = peer.status
|
|
113
|
+
row["capability_ok"] = peer.is_wired
|
|
114
|
+
return row
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def check_peer(name: str, run: Runner = _default_run) -> dict:
|
|
118
|
+
peer = manifest.get(name)
|
|
119
|
+
return _stamp_capability(_check_peer_reachability(name, peer, run=run), peer)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _check_peer_reachability(name: str, peer: "Peer | None",
|
|
123
|
+
run: Runner = _default_run) -> dict:
|
|
124
|
+
if peer is None:
|
|
125
|
+
return {"peer": name, "status": "error", "ok": False, "detail": "unknown peer"}
|
|
126
|
+
|
|
127
|
+
version_cmd = resolve_version_bin(name)
|
|
128
|
+
if version_cmd is None:
|
|
129
|
+
# Genuinely unresolvable — no binary anywhere. Legitimately not-ok.
|
|
130
|
+
return {"peer": name, "status": "missing", "ok": False, "pin": peer.version_pin}
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
result = run(_probe_command(version_cmd, peer))
|
|
134
|
+
except Exception as e: # noqa: BLE001 — surface as data, never crash (R4)
|
|
135
|
+
# The probe itself RAISED (binary vanished mid-call, OS error). This is
|
|
136
|
+
# the only path that means "absent/unrunnable" once resolution succeeded
|
|
137
|
+
# — a genuine error, not cry-wolf.
|
|
138
|
+
return {"peer": name, "status": "error", "ok": False,
|
|
139
|
+
"detail": str(e), "pin": peer.version_pin}
|
|
140
|
+
|
|
141
|
+
# From here the binary resolved AND produced a RunResult: the peer is
|
|
142
|
+
# PRESENT and RESPONDING. Prefer stdout for the version, but tolerate older
|
|
143
|
+
# CLIs that print it to stderr.
|
|
144
|
+
installed = _parse_version(result.stdout) or _parse_version(result.stderr)
|
|
145
|
+
|
|
146
|
+
if installed is not None:
|
|
147
|
+
status = "ok" if _meets_pin(installed, peer.version_pin) else "drift"
|
|
148
|
+
return {"peer": name, "status": status, "ok": status == "ok",
|
|
149
|
+
"installed": installed, "pin": peer.version_pin}
|
|
150
|
+
|
|
151
|
+
# Present + responding, but version unknown: a non-zero exit (older buses
|
|
152
|
+
# print help/usage JSON for an unrecognized ``--version``) OR parseable-free
|
|
153
|
+
# output. The peer is healthy — do NOT raise a hard "error" (the cry-wolf
|
|
154
|
+
# finding). Surface it as WARN-level "present" with ok=True so doctor/health
|
|
155
|
+
# probes don't treat a responding peer as a failure.
|
|
156
|
+
detail = (
|
|
157
|
+
"probe exited %d; version not reported (older CLI may print help "
|
|
158
|
+
"for --version)" % result.returncode
|
|
159
|
+
if result.returncode != 0
|
|
160
|
+
else "version not reported by probe output"
|
|
161
|
+
)
|
|
162
|
+
return {"peer": name, "status": "present", "ok": True,
|
|
163
|
+
"detail": detail, "pin": peer.version_pin}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def install_peer(name: str, run: Runner = _default_run) -> dict:
|
|
167
|
+
peer = manifest.get(name)
|
|
168
|
+
if peer is None:
|
|
169
|
+
return {"peer": name, "status": "error", "detail": "unknown peer"}
|
|
170
|
+
try:
|
|
171
|
+
result = run(peer.install_cmd, timeout=300)
|
|
172
|
+
except Exception as e: # noqa: BLE001
|
|
173
|
+
return {"peer": name, "status": "install-failed", "detail": str(e)}
|
|
174
|
+
if result.returncode != 0:
|
|
175
|
+
return {"peer": name, "status": "install-failed", "detail": result.stderr.strip()}
|
|
176
|
+
return {"peer": name, "status": "installed"}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def check_all(run: Runner = _default_run) -> list:
|
|
180
|
+
return [check_peer(name, run=run) for name in manifest.PEERS]
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""gate.py — the synchronous, fail-closed produces gate (vault re-derivation).
|
|
2
|
+
|
|
3
|
+
Absorbed from wicked-loom (Phase B — ECOSYSTEM-RATIONALIZATION.md §5a).
|
|
4
|
+
|
|
5
|
+
Ported from wicked-garden scripts/qe/vault_gate.py, with the subprocess
|
|
6
|
+
execution injected (the ``run`` parameter, same RunResult shape as compose.py)
|
|
7
|
+
so callers and tests control side effects and no real vault is ever spawned in
|
|
8
|
+
a unit test.
|
|
9
|
+
|
|
10
|
+
Invariants (spec §5):
|
|
11
|
+
I1 — synchronous + in-line: exactly one blocking vault call per invocation;
|
|
12
|
+
no events are consulted. An event NEVER satisfies a gate.
|
|
13
|
+
I2 — fail-closed: vault unresolvable OR unrunnable OR non-JSON ->
|
|
14
|
+
gate "unavailable" / overall "ERROR", satisfied False. Never a pass.
|
|
15
|
+
I3 — fail-soft on the verifier spec only: a present ``verifier_spec`` is
|
|
16
|
+
forwarded to the vault; its ABSENCE never blocks and never vacates the
|
|
17
|
+
gate — the vault falls back to generic detection.
|
|
18
|
+
|
|
19
|
+
Hard gates additionally require an independent attestation: pass
|
|
20
|
+
``with_attestations=True`` -> ``--with-attestations`` forwarded to the vault.
|
|
21
|
+
|
|
22
|
+
The return is a status dict (R4 — surface as data, never raise):
|
|
23
|
+
{satisfied, re_derived, gate, overall, exit_code, argv, detail, error}
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import json
|
|
29
|
+
from typing import Callable, Optional
|
|
30
|
+
|
|
31
|
+
from loom.compose import RunResult, _default_run
|
|
32
|
+
from loom.resolve import resolve
|
|
33
|
+
|
|
34
|
+
Runner = Callable[..., RunResult]
|
|
35
|
+
|
|
36
|
+
_DEFAULT_TIMEOUT = 120 # seconds; bounds the blocking re-derivation (R5).
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _build_argv(vault_prefix: list, produces: str, scope: str, *,
|
|
40
|
+
with_attestations: bool,
|
|
41
|
+
verifier_spec: Optional[str]) -> list:
|
|
42
|
+
"""The full vault argv: <prefix> cross-check --scope S --phase <produces> ...
|
|
43
|
+
|
|
44
|
+
``produces`` maps to the vault's ``--phase`` (the produces-contract id, e.g.
|
|
45
|
+
"test-report"); ``scope`` maps to ``--scope`` (the project/flow scope).
|
|
46
|
+
"""
|
|
47
|
+
argv = list(vault_prefix) + ["cross-check", "--scope", scope, "--phase", produces]
|
|
48
|
+
if with_attestations:
|
|
49
|
+
argv.append("--with-attestations")
|
|
50
|
+
if verifier_spec:
|
|
51
|
+
argv += ["--verifier-spec", verifier_spec]
|
|
52
|
+
return argv
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def run_gate(produces: str, *, scope: str,
|
|
56
|
+
with_attestations: bool = False,
|
|
57
|
+
verifier_spec: Optional[str] = None,
|
|
58
|
+
run: Runner = _default_run,
|
|
59
|
+
timeout: int = _DEFAULT_TIMEOUT) -> dict:
|
|
60
|
+
"""Re-derive ``produces`` via ``vault cross-check`` and return the verdict.
|
|
61
|
+
|
|
62
|
+
Fail-closed (I2): no resolvable vault, an unrunnable vault, or non-JSON
|
|
63
|
+
output all yield ``satisfied: False`` with ``gate: "unavailable"`` (or
|
|
64
|
+
overall "ERROR") — never an invented pass.
|
|
65
|
+
"""
|
|
66
|
+
vault_prefix = resolve("vault")
|
|
67
|
+
if vault_prefix is None:
|
|
68
|
+
return {
|
|
69
|
+
"satisfied": False,
|
|
70
|
+
"re_derived": False,
|
|
71
|
+
"gate": "unavailable",
|
|
72
|
+
"overall": "ERROR",
|
|
73
|
+
"argv": [],
|
|
74
|
+
"error": "wicked-vault not resolvable",
|
|
75
|
+
"detail": "Gate fails closed — 'done' cannot be self-asserted (I2).",
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
argv = _build_argv(vault_prefix, produces, scope,
|
|
79
|
+
with_attestations=with_attestations,
|
|
80
|
+
verifier_spec=verifier_spec)
|
|
81
|
+
try:
|
|
82
|
+
result = run(argv, timeout=timeout)
|
|
83
|
+
except Exception as e: # noqa: BLE001 — surface as data, fail closed (R4/I2)
|
|
84
|
+
return {
|
|
85
|
+
"satisfied": False,
|
|
86
|
+
"re_derived": False,
|
|
87
|
+
"gate": "unavailable",
|
|
88
|
+
"overall": "ERROR",
|
|
89
|
+
"argv": argv,
|
|
90
|
+
"error": str(e),
|
|
91
|
+
"detail": "vault resolvable but not runnable; gate fails closed (I2).",
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
parsed = json.loads(result.stdout) if (result.stdout or "").strip() else {}
|
|
96
|
+
except json.JSONDecodeError:
|
|
97
|
+
return {
|
|
98
|
+
"satisfied": False,
|
|
99
|
+
"re_derived": True,
|
|
100
|
+
"gate": "vault-cross-check",
|
|
101
|
+
"overall": "ERROR",
|
|
102
|
+
"exit_code": result.returncode,
|
|
103
|
+
"argv": argv,
|
|
104
|
+
"error": "vault returned non-JSON output",
|
|
105
|
+
"detail": result.stderr.strip()[:500],
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
overall = parsed.get("overall", "ERROR")
|
|
109
|
+
return {
|
|
110
|
+
"satisfied": overall == "PASS",
|
|
111
|
+
"re_derived": True,
|
|
112
|
+
"gate": "vault-cross-check",
|
|
113
|
+
"overall": overall,
|
|
114
|
+
"exit_code": result.returncode,
|
|
115
|
+
"argv": argv,
|
|
116
|
+
"claims": parsed.get("claims", []),
|
|
117
|
+
"contract_version": parsed.get("contract_version"),
|
|
118
|
+
"detail": parsed.get("detail"),
|
|
119
|
+
"error": None,
|
|
120
|
+
}
|