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,703 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""phase_manager.py — v11 slim project-state manager.
|
|
3
|
+
|
|
4
|
+
The v6-v10 universal-pipeline implementation (gate-result.json schema
|
|
5
|
+
validators, addendum freshness, conditions-manifest enforcement, BLEND-
|
|
6
|
+
RULE dispatch, banned-reviewer enforcement, dispatch-log HMAC,
|
|
7
|
+
convergence-verify, semantic-alignment, propose-process facilitator
|
|
8
|
+
rubric, rigor tiers, gate-policy.json) lived in this module across many
|
|
9
|
+
thousands of lines. v11 collapsed all of that into per-archetype playbooks
|
|
10
|
+
under skills/archetype/refs/{archetype}.md, with the catalog at
|
|
11
|
+
.claude-plugin/archetypes.json driving phase shape, produces, HITL
|
|
12
|
+
discipline, and cost band per archetype.
|
|
13
|
+
|
|
14
|
+
What's left here:
|
|
15
|
+
- ProjectState dataclass: name, current_phase, phase_plan, phases dict,
|
|
16
|
+
extras, created_at.
|
|
17
|
+
- create_project / load_project_state / save_project_state.
|
|
18
|
+
- start_phase / complete_phase / approve_phase / skip_phase — slim state
|
|
19
|
+
transitions, no gate machinery.
|
|
20
|
+
- CLI: status, create, start, complete, approve, skip, advance.
|
|
21
|
+
|
|
22
|
+
Archetype mode is the v11 default for new projects; legacy projects
|
|
23
|
+
(no phase_plan_mode) still load and read but don't get the legacy gate
|
|
24
|
+
checks back — they were the bug, not the value.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import argparse
|
|
30
|
+
import json
|
|
31
|
+
import re
|
|
32
|
+
import sys
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from datetime import datetime, timezone
|
|
35
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
36
|
+
from dataclasses import dataclass, field, asdict
|
|
37
|
+
|
|
38
|
+
# Make scripts/ importable for _domain_store
|
|
39
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
40
|
+
from _domain_store import DomainStore, get_local_path # noqa: E402
|
|
41
|
+
|
|
42
|
+
_sm = DomainStore("projects")
|
|
43
|
+
logger = __import__("logging").getLogger("wicked-garden.phase-manager")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _bus_emit_safe(event_type: str, payload: dict, *,
|
|
47
|
+
chain_id: Optional[str] = None) -> None:
|
|
48
|
+
"""Fire-and-forget bus emit. Fail-open on every error.
|
|
49
|
+
|
|
50
|
+
The phase_manager is the v11 source-of-truth surface for project
|
|
51
|
+
state transitions. Each transition emits an event for downstream
|
|
52
|
+
consumers (audit, dashboards, future replay). Bus unavailable
|
|
53
|
+
must never block the disk write — bus failure is recorded only
|
|
54
|
+
in emit_stats.
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
from _bus import emit_event # type: ignore
|
|
58
|
+
emit_event(event_type, payload, chain_id=chain_id)
|
|
59
|
+
except Exception:
|
|
60
|
+
pass # Bus is optional infrastructure.
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# Strangler shim toward wicked-loom (cutover phase). Read-only parity mirror:
|
|
64
|
+
# the in-process hard-gate enforcement below STAYS authoritative; loom is
|
|
65
|
+
# consulted only to cross-check the park-at-hard-gate decision during cutover.
|
|
66
|
+
try:
|
|
67
|
+
import _loom # scripts/ is on sys.path
|
|
68
|
+
except ImportError: # pragma: no cover
|
|
69
|
+
_loom = None # type: ignore
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _loom_confirms_hard_gate(archetype: str, phase: str) -> "Optional[bool]":
|
|
73
|
+
"""Ask loom (via the compiled flow def) whether (archetype, phase) is a
|
|
74
|
+
hard gate. Returns True/False, or None when loom is unavailable/uncertain
|
|
75
|
+
(in which case the in-process _HARD_GATE_PHASES map remains authoritative).
|
|
76
|
+
Best-effort, fail-soft — never raises, never blocks the state write."""
|
|
77
|
+
if _loom is None or not _loom.use_loom():
|
|
78
|
+
return None
|
|
79
|
+
try:
|
|
80
|
+
from flow_compiler import compile_flow
|
|
81
|
+
flow_def = compile_flow(archetype, flow_id=f"{archetype}-parity")
|
|
82
|
+
for p in flow_def.get("phases", []):
|
|
83
|
+
if p.get("name") == phase:
|
|
84
|
+
hitl = p.get("hitl")
|
|
85
|
+
return isinstance(hitl, str) and hitl.startswith("hard:")
|
|
86
|
+
return False
|
|
87
|
+
except Exception:
|
|
88
|
+
return None # fail-soft: in-process map stays authoritative
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# Naming & resolution
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
_PROJECT_NAME_RE = re.compile(r"^[A-Za-z0-9_-]{1,64}$")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def is_safe_project_name(name: str) -> bool:
|
|
99
|
+
"""Names are kebab/snake/alphanumeric, max 64 chars."""
|
|
100
|
+
return bool(_PROJECT_NAME_RE.match(name or ""))
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# Phase aliases used historically — keep the resolver so old project files
|
|
104
|
+
# still load correctly.
|
|
105
|
+
_PHASE_ALIASES: Dict[str, str] = {
|
|
106
|
+
"implement": "implement",
|
|
107
|
+
"implementation": "implement",
|
|
108
|
+
"plan": "plan",
|
|
109
|
+
"test": "test",
|
|
110
|
+
"review": "review",
|
|
111
|
+
"build": "build",
|
|
112
|
+
"clarify": "clarify",
|
|
113
|
+
"design": "design",
|
|
114
|
+
"operate": "operate",
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def resolve_phase(phase: str) -> str:
|
|
119
|
+
"""Normalize a phase name. Returns the input unchanged when no alias matches."""
|
|
120
|
+
if not phase:
|
|
121
|
+
return phase
|
|
122
|
+
return _PHASE_ALIASES.get(phase.lower(), phase)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def get_utc_timestamp() -> str:
|
|
126
|
+
return datetime.now(timezone.utc).isoformat()
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# ---------------------------------------------------------------------------
|
|
130
|
+
# Project state
|
|
131
|
+
# ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
@dataclass
|
|
134
|
+
class PhaseState:
|
|
135
|
+
"""Per-phase status. Status is one of: pending | in_progress | completed | approved | skipped."""
|
|
136
|
+
status: str = "pending"
|
|
137
|
+
started_at: Optional[str] = None
|
|
138
|
+
completed_at: Optional[str] = None
|
|
139
|
+
approved_at: Optional[str] = None
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@dataclass
|
|
143
|
+
class ProjectState:
|
|
144
|
+
name: str
|
|
145
|
+
current_phase: str
|
|
146
|
+
created_at: str
|
|
147
|
+
version: str = "v11"
|
|
148
|
+
phase_plan: List[str] = field(default_factory=list)
|
|
149
|
+
phases: Dict[str, PhaseState] = field(default_factory=dict)
|
|
150
|
+
extras: Dict[str, Any] = field(default_factory=dict)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def get_project_dir(project_name: str) -> Path:
|
|
154
|
+
"""Resolve and create the on-disk project directory."""
|
|
155
|
+
if not is_safe_project_name(project_name):
|
|
156
|
+
raise ValueError(f"Invalid project name: {project_name!r}")
|
|
157
|
+
base = get_local_path("wicked-crew", "projects")
|
|
158
|
+
project_dir = (base / project_name).resolve()
|
|
159
|
+
try:
|
|
160
|
+
project_dir.relative_to(base.resolve())
|
|
161
|
+
except ValueError:
|
|
162
|
+
raise ValueError("Path traversal detected")
|
|
163
|
+
project_dir.mkdir(parents=True, exist_ok=True)
|
|
164
|
+
return project_dir
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def save_project_state(state: ProjectState) -> None:
|
|
168
|
+
"""Persist state to the DomainStore.
|
|
169
|
+
|
|
170
|
+
Uses ``id = state.name`` as the canonical key. Update is idempotent
|
|
171
|
+
via ``DomainStore.update`` when the record exists; otherwise we
|
|
172
|
+
create.
|
|
173
|
+
"""
|
|
174
|
+
payload = {
|
|
175
|
+
"id": state.name,
|
|
176
|
+
"name": state.name,
|
|
177
|
+
"current_phase": state.current_phase,
|
|
178
|
+
"created_at": state.created_at,
|
|
179
|
+
"version": state.version,
|
|
180
|
+
"phase_plan": list(state.phase_plan),
|
|
181
|
+
"phases": {k: asdict(v) for k, v in state.phases.items()},
|
|
182
|
+
"extras": dict(state.extras),
|
|
183
|
+
}
|
|
184
|
+
existing = _sm.get("projects", state.name)
|
|
185
|
+
if existing:
|
|
186
|
+
_sm.update("projects", state.name, payload)
|
|
187
|
+
else:
|
|
188
|
+
_sm.create("projects", payload)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def load_project_state(project_name: str) -> Optional[ProjectState]:
|
|
192
|
+
"""Load state from DomainStore, hydrating phases dict from raw."""
|
|
193
|
+
if not is_safe_project_name(project_name):
|
|
194
|
+
return None
|
|
195
|
+
data = _sm.get("projects", project_name)
|
|
196
|
+
if not data:
|
|
197
|
+
return None
|
|
198
|
+
phases: Dict[str, PhaseState] = {}
|
|
199
|
+
for k, v in (data.get("phases") or {}).items():
|
|
200
|
+
if isinstance(v, dict):
|
|
201
|
+
phases[resolve_phase(k)] = PhaseState(
|
|
202
|
+
status=v.get("status", "pending"),
|
|
203
|
+
started_at=v.get("started_at"),
|
|
204
|
+
completed_at=v.get("completed_at"),
|
|
205
|
+
approved_at=v.get("approved_at"),
|
|
206
|
+
)
|
|
207
|
+
return ProjectState(
|
|
208
|
+
name=data.get("name", project_name),
|
|
209
|
+
current_phase=resolve_phase(data.get("current_phase", "")),
|
|
210
|
+
created_at=data.get("created_at", get_utc_timestamp()),
|
|
211
|
+
version=data.get("version", "v11"),
|
|
212
|
+
phase_plan=[resolve_phase(p) for p in (data.get("phase_plan") or [])],
|
|
213
|
+
phases=phases,
|
|
214
|
+
extras=dict(data.get("extras") or {}),
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# ---------------------------------------------------------------------------
|
|
219
|
+
# Project creation
|
|
220
|
+
# ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
def create_project(
|
|
223
|
+
name: str,
|
|
224
|
+
description: str = "",
|
|
225
|
+
archetype_mode: Optional[str] = None,
|
|
226
|
+
) -> Tuple[ProjectState, Path]:
|
|
227
|
+
"""Create a new project. When ``archetype_mode`` is set, hydrate the
|
|
228
|
+
phase_plan from .claude-plugin/archetypes.json and stamp the project
|
|
229
|
+
as v11 archetype-driven."""
|
|
230
|
+
if not is_safe_project_name(name):
|
|
231
|
+
raise ValueError(f"Invalid project name: {name!r}")
|
|
232
|
+
|
|
233
|
+
state = ProjectState(
|
|
234
|
+
name=name,
|
|
235
|
+
current_phase="",
|
|
236
|
+
created_at=get_utc_timestamp(),
|
|
237
|
+
version="v11",
|
|
238
|
+
)
|
|
239
|
+
if description:
|
|
240
|
+
state.extras["description"] = description
|
|
241
|
+
|
|
242
|
+
if archetype_mode:
|
|
243
|
+
try:
|
|
244
|
+
from archetypes_v11 import load_catalog
|
|
245
|
+
catalog = load_catalog()
|
|
246
|
+
arch_def = catalog.get("archetypes", {}).get(archetype_mode)
|
|
247
|
+
if not arch_def:
|
|
248
|
+
raise ValueError(
|
|
249
|
+
f"Unknown archetype '{archetype_mode}'. "
|
|
250
|
+
f"Known: {list(catalog.get('archetypes', {}).keys())}"
|
|
251
|
+
)
|
|
252
|
+
state.phase_plan = list(arch_def.get("phases", []))
|
|
253
|
+
state.current_phase = state.phase_plan[0] if state.phase_plan else ""
|
|
254
|
+
state.extras["phase_plan_mode"] = "archetype"
|
|
255
|
+
state.extras["v11_archetype"] = archetype_mode
|
|
256
|
+
state.extras["archetype_produces"] = list(arch_def.get("produces", []))
|
|
257
|
+
state.extras["archetype_hitl"] = arch_def.get("hitl")
|
|
258
|
+
except ImportError:
|
|
259
|
+
raise RuntimeError("archetypes_v11 unavailable — cannot init archetype-mode project")
|
|
260
|
+
|
|
261
|
+
project_dir = get_project_dir(name)
|
|
262
|
+
save_project_state(state)
|
|
263
|
+
|
|
264
|
+
# v11.1.1: bus emit for archetype-mode creation. Legacy (no archetype)
|
|
265
|
+
# projects also emit project.created via the v6 path; archetype-mode
|
|
266
|
+
# gets its own event so dashboards can distinguish.
|
|
267
|
+
if archetype_mode:
|
|
268
|
+
_bus_emit_safe(
|
|
269
|
+
"wicked.archetype.created",
|
|
270
|
+
{
|
|
271
|
+
"project_id": name,
|
|
272
|
+
"archetype": archetype_mode,
|
|
273
|
+
"phase_plan": state.phase_plan,
|
|
274
|
+
"produces": list(state.extras.get("archetype_produces") or []),
|
|
275
|
+
"hitl": state.extras.get("archetype_hitl"),
|
|
276
|
+
},
|
|
277
|
+
chain_id=f"{name}.{archetype_mode}.root",
|
|
278
|
+
)
|
|
279
|
+
else:
|
|
280
|
+
_bus_emit_safe(
|
|
281
|
+
"wicked.project.created",
|
|
282
|
+
{"project_id": name},
|
|
283
|
+
chain_id=f"{name}.root",
|
|
284
|
+
)
|
|
285
|
+
return state, project_dir
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# ---------------------------------------------------------------------------
|
|
289
|
+
# State transitions
|
|
290
|
+
# ---------------------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
def start_phase(state: ProjectState, phase: str) -> ProjectState:
|
|
293
|
+
"""Mark a phase as in_progress."""
|
|
294
|
+
phase = resolve_phase(phase)
|
|
295
|
+
ps = state.phases.get(phase) or PhaseState()
|
|
296
|
+
ps.status = "in_progress"
|
|
297
|
+
ps.started_at = ps.started_at or get_utc_timestamp()
|
|
298
|
+
state.phases[phase] = ps
|
|
299
|
+
state.current_phase = phase
|
|
300
|
+
save_project_state(state)
|
|
301
|
+
return state
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def complete_phase(state: ProjectState, phase: str) -> ProjectState:
|
|
305
|
+
"""Mark a phase as completed (work done; awaiting approval)."""
|
|
306
|
+
phase = resolve_phase(phase)
|
|
307
|
+
ps = state.phases.get(phase) or PhaseState(started_at=get_utc_timestamp())
|
|
308
|
+
ps.status = "completed"
|
|
309
|
+
ps.completed_at = get_utc_timestamp()
|
|
310
|
+
state.phases[phase] = ps
|
|
311
|
+
save_project_state(state)
|
|
312
|
+
return state
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
_HARD_GATE_PHASES: Dict[str, Tuple[str, ...]] = {
|
|
316
|
+
# The (archetype, phase) pairs that genuinely need the user in the loop
|
|
317
|
+
# AT RUNTIME — not just in playbook prose. These MUST mirror the archetypes
|
|
318
|
+
# declared ``hard:<gate>`` in .claude-plugin/archetypes.json (the source of
|
|
319
|
+
# truth). migrate/modernize/incident/review are hard; specify
|
|
320
|
+
# (discrete:validate) and decide (discrete:select) are discrete gates that
|
|
321
|
+
# auto-pass when the produces contract re-derives — promoting them here
|
|
322
|
+
# over-reached the catalog and contradicted the "steering, not blocking"
|
|
323
|
+
# doctrine, so they were removed. modernize's cutover is the legacy→new-stack
|
|
324
|
+
# parity-proved switch — the same hard-gate discipline as migrate.cutover.
|
|
325
|
+
# test_hard_gate_map_matches_catalog locks this alignment.
|
|
326
|
+
"migrate": ("cutover",),
|
|
327
|
+
"modernize": ("cutover",),
|
|
328
|
+
"incident": ("mitigate",),
|
|
329
|
+
"review": ("remediate-or-accept",),
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _is_hard_gate(state: ProjectState, phase: str) -> bool:
|
|
334
|
+
"""True iff (archetype, phase) is a hard gate per _HARD_GATE_PHASES."""
|
|
335
|
+
archetype = (state.extras or {}).get("v11_archetype")
|
|
336
|
+
if not archetype:
|
|
337
|
+
return False
|
|
338
|
+
return resolve_phase(phase) in _HARD_GATE_PHASES.get(archetype, ())
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def resolve_hard_gate(state: ProjectState, phase: str) -> bool:
|
|
342
|
+
"""Authoritative hard-gate decision for ``(archetype, phase)`` (flow cutover).
|
|
343
|
+
|
|
344
|
+
The flow surface is now loom-AUTHORITATIVE for *where the human stops*:
|
|
345
|
+
loom's verdict (derived from the compiled flow-def, which reproduces loom's
|
|
346
|
+
own ``hitl.startswith("hard:")`` park rule) decides whether this phase is a
|
|
347
|
+
hard gate — WHEN loom is available. The in-process ``_HARD_GATE_PHASES`` map
|
|
348
|
+
is two things at once:
|
|
349
|
+
|
|
350
|
+
- the FALLBACK: when loom is unavailable/uncertain
|
|
351
|
+
(``_loom_confirms_hard_gate`` returns None — off, auto-unresolvable, or
|
|
352
|
+
a compile error), the map answers (fail-soft, rollback-safe).
|
|
353
|
+
- the FLOOR: even when loom answers, the resolved decision is
|
|
354
|
+
``loom or in_process`` — loom may ADD a park the map omits, but can
|
|
355
|
+
NEVER remove a park the map asserts. This is the fail-closed posture of
|
|
356
|
+
the flow surface: we never silently skip a human-in-the-loop stop that
|
|
357
|
+
the in-process doctrine demands. A loom that (wrongly) says "not hard"
|
|
358
|
+
for migrate.cutover cannot disarm the cutover gate.
|
|
359
|
+
|
|
360
|
+
A divergence (loom != in_process, with loom present) is surfaced as a
|
|
361
|
+
``wicked.loom.parity_mismatch`` signal — retained from the parity mirror —
|
|
362
|
+
so operators see drift even though the resolved decision is the safe OR.
|
|
363
|
+
"""
|
|
364
|
+
in_process = _is_hard_gate(state, phase)
|
|
365
|
+
archetype = (state.extras or {}).get("v11_archetype")
|
|
366
|
+
if not archetype:
|
|
367
|
+
return in_process
|
|
368
|
+
|
|
369
|
+
loom_says = _loom_confirms_hard_gate(archetype, phase)
|
|
370
|
+
if loom_says is None:
|
|
371
|
+
return in_process # fail-soft: in-process map is authoritative
|
|
372
|
+
|
|
373
|
+
if loom_says != in_process:
|
|
374
|
+
print(f"[wicked-garden] loom/in-process hard-gate parity mismatch: "
|
|
375
|
+
f"archetype={archetype} phase={phase} "
|
|
376
|
+
f"loom={loom_says} in_process={in_process}", file=sys.stderr)
|
|
377
|
+
_bus_emit_safe(
|
|
378
|
+
"wicked.loom.parity_mismatch",
|
|
379
|
+
{"project_id": state.name, "archetype": archetype,
|
|
380
|
+
"phase": phase, "loom": loom_says, "in_process": in_process,
|
|
381
|
+
"resolved": loom_says or in_process},
|
|
382
|
+
chain_id=f"{state.name}.{archetype}.{phase}.parity",
|
|
383
|
+
)
|
|
384
|
+
# loom authoritative, but fail-closed floor: a park is required if EITHER
|
|
385
|
+
# source says hard. loom can add a park; it can never remove the map's.
|
|
386
|
+
return loom_says or in_process
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def approve_phase(
|
|
390
|
+
state: ProjectState,
|
|
391
|
+
phase: str,
|
|
392
|
+
approver: str = "user",
|
|
393
|
+
*,
|
|
394
|
+
confirmed_by: Optional[str] = None,
|
|
395
|
+
confirmation_evidence: Optional[str] = None,
|
|
396
|
+
) -> Tuple[ProjectState, Optional[str]]:
|
|
397
|
+
"""Approve a phase. Returns (state, next_phase_name_or_None).
|
|
398
|
+
|
|
399
|
+
Hard-gate enforcement (v11): when (archetype, phase) is in
|
|
400
|
+
``_HARD_GATE_PHASES`` (e.g. migrate.cutover, incident.mitigate),
|
|
401
|
+
advancing past the phase REQUIRES non-empty ``confirmed_by`` AND
|
|
402
|
+
``confirmation_evidence``. The audit log records both. ``approver``
|
|
403
|
+
alone is not enough — the doctrine of "user in the loop" becomes
|
|
404
|
+
runtime: the caller must explicitly attest that confirmation
|
|
405
|
+
happened, and name the artifact (commit / dashboard URL / ticket /
|
|
406
|
+
Slack thread) that proves it.
|
|
407
|
+
|
|
408
|
+
Non-hard phases retain the v11 default: lightweight state transition,
|
|
409
|
+
no gate machinery, archetype's playbook owns discipline.
|
|
410
|
+
"""
|
|
411
|
+
phase = resolve_phase(phase)
|
|
412
|
+
|
|
413
|
+
# --- loom cutover (flow surface): loom-AUTHORITATIVE park decision -------
|
|
414
|
+
# The hard-gate verdict now routes through resolve_hard_gate: loom wins when
|
|
415
|
+
# present, the in-process _HARD_GATE_PHASES map is the fallback (loom
|
|
416
|
+
# unavailable) AND the floor (loom can ADD a park, never remove one the map
|
|
417
|
+
# asserts). The parity-mismatch signal lives inside resolve_hard_gate.
|
|
418
|
+
# -------------------------------------------------------------------------
|
|
419
|
+
|
|
420
|
+
# Hard-gate guard: enforce explicit confirmation at runtime.
|
|
421
|
+
if resolve_hard_gate(state, phase):
|
|
422
|
+
if not confirmed_by or not confirmed_by.strip():
|
|
423
|
+
archetype = (state.extras or {}).get("v11_archetype")
|
|
424
|
+
raise ValueError(
|
|
425
|
+
f"Hard gate at archetype={archetype!r} phase={phase!r} "
|
|
426
|
+
f"requires --confirmed-by (user / oncall / approver name). "
|
|
427
|
+
f"This is a v11 enforced HITL gate, not a doctrinal "
|
|
428
|
+
f"hint — the playbook documents this as hard:* and the "
|
|
429
|
+
f"runtime mirrors that. Pass --confirmed-by AND "
|
|
430
|
+
f"--confirmation-evidence (path / URL / ticket id)."
|
|
431
|
+
)
|
|
432
|
+
if not confirmation_evidence or not confirmation_evidence.strip():
|
|
433
|
+
archetype = (state.extras or {}).get("v11_archetype")
|
|
434
|
+
raise ValueError(
|
|
435
|
+
f"Hard gate at archetype={archetype!r} phase={phase!r} "
|
|
436
|
+
f"requires --confirmation-evidence (path to artifact "
|
|
437
|
+
f"proving the gate-specific check passed: rollback "
|
|
438
|
+
f"drill log, dashboard screenshot, mitigation commit, "
|
|
439
|
+
f"approval ticket, etc.)."
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
ps = state.phases.get(phase) or PhaseState()
|
|
443
|
+
ps.status = "approved"
|
|
444
|
+
ps.approved_at = get_utc_timestamp()
|
|
445
|
+
state.phases[phase] = ps
|
|
446
|
+
|
|
447
|
+
approval_record = {
|
|
448
|
+
"phase": phase, "approver": approver, "at": ps.approved_at,
|
|
449
|
+
}
|
|
450
|
+
if confirmed_by:
|
|
451
|
+
approval_record["confirmed_by"] = confirmed_by
|
|
452
|
+
approval_record["confirmation_evidence"] = confirmation_evidence
|
|
453
|
+
approval_record["hard_gate"] = True
|
|
454
|
+
|
|
455
|
+
state.extras.setdefault("approvals", []).append(approval_record)
|
|
456
|
+
|
|
457
|
+
# Resolve next phase from phase_plan
|
|
458
|
+
next_phase: Optional[str] = None
|
|
459
|
+
if state.phase_plan:
|
|
460
|
+
try:
|
|
461
|
+
idx = state.phase_plan.index(phase)
|
|
462
|
+
if idx + 1 < len(state.phase_plan):
|
|
463
|
+
next_phase = state.phase_plan[idx + 1]
|
|
464
|
+
except ValueError:
|
|
465
|
+
pass
|
|
466
|
+
|
|
467
|
+
if next_phase:
|
|
468
|
+
state.current_phase = next_phase
|
|
469
|
+
save_project_state(state)
|
|
470
|
+
|
|
471
|
+
# v11.1.1: emit hard_gate_passed when a hard gate advanced
|
|
472
|
+
archetype = (state.extras or {}).get("v11_archetype")
|
|
473
|
+
if archetype and confirmed_by:
|
|
474
|
+
_bus_emit_safe(
|
|
475
|
+
"wicked.archetype.hard_gate_passed",
|
|
476
|
+
{
|
|
477
|
+
"project_id": state.name,
|
|
478
|
+
"archetype": archetype,
|
|
479
|
+
"phase": phase,
|
|
480
|
+
"confirmed_by": confirmed_by,
|
|
481
|
+
"confirmation_evidence": confirmation_evidence,
|
|
482
|
+
},
|
|
483
|
+
chain_id=f"{state.name}.{archetype}.{phase}.hard-gate",
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
# v11.1.1: emit advance event for any archetype-mode approval
|
|
487
|
+
if archetype:
|
|
488
|
+
_bus_emit_safe(
|
|
489
|
+
"wicked.archetype.advanced",
|
|
490
|
+
{
|
|
491
|
+
"project_id": state.name,
|
|
492
|
+
"archetype": archetype,
|
|
493
|
+
"phase": phase,
|
|
494
|
+
"next_phase": next_phase,
|
|
495
|
+
},
|
|
496
|
+
chain_id=f"{state.name}.{archetype}.{phase}",
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
# v11.1.1: emit completed event when project is_complete after this approval
|
|
500
|
+
if archetype and is_complete(state):
|
|
501
|
+
_bus_emit_safe(
|
|
502
|
+
"wicked.archetype.completed",
|
|
503
|
+
{
|
|
504
|
+
"project_id": state.name,
|
|
505
|
+
"archetype": archetype,
|
|
506
|
+
"final_phase": phase,
|
|
507
|
+
},
|
|
508
|
+
chain_id=f"{state.name}.{archetype}.completed",
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
return state, next_phase
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def skip_phase(state: ProjectState, phase: str, reason: str = "") -> ProjectState:
|
|
515
|
+
phase = resolve_phase(phase)
|
|
516
|
+
ps = state.phases.get(phase) or PhaseState()
|
|
517
|
+
ps.status = "skipped"
|
|
518
|
+
ps.completed_at = get_utc_timestamp()
|
|
519
|
+
state.phases[phase] = ps
|
|
520
|
+
state.extras.setdefault("skips", []).append({
|
|
521
|
+
"phase": phase, "reason": reason, "at": ps.completed_at,
|
|
522
|
+
})
|
|
523
|
+
save_project_state(state)
|
|
524
|
+
return state
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
def is_complete(state: ProjectState) -> bool:
|
|
528
|
+
"""All phases in the plan are approved or skipped."""
|
|
529
|
+
if not state.phase_plan:
|
|
530
|
+
return False
|
|
531
|
+
for p in state.phase_plan:
|
|
532
|
+
ps = state.phases.get(p)
|
|
533
|
+
if not ps or ps.status not in ("approved", "skipped"):
|
|
534
|
+
return False
|
|
535
|
+
return True
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
# ---------------------------------------------------------------------------
|
|
539
|
+
# CLI
|
|
540
|
+
# ---------------------------------------------------------------------------
|
|
541
|
+
|
|
542
|
+
def _emit(payload: Dict[str, Any], as_json: bool, fallback: str = "") -> None:
|
|
543
|
+
if as_json:
|
|
544
|
+
print(json.dumps(payload, indent=2, default=str))
|
|
545
|
+
elif fallback:
|
|
546
|
+
print(fallback)
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def main() -> None:
|
|
550
|
+
parser = argparse.ArgumentParser(description="v11 slim project state manager")
|
|
551
|
+
parser.add_argument("project")
|
|
552
|
+
parser.add_argument(
|
|
553
|
+
"action",
|
|
554
|
+
choices=["status", "create", "start", "complete", "approve", "skip",
|
|
555
|
+
"advance", "delete"],
|
|
556
|
+
)
|
|
557
|
+
parser.add_argument("--phase", default=None)
|
|
558
|
+
parser.add_argument("--description", default="")
|
|
559
|
+
parser.add_argument("--reason", default="")
|
|
560
|
+
parser.add_argument("--approver", default="user")
|
|
561
|
+
parser.add_argument(
|
|
562
|
+
"--confirmed-by", default=None,
|
|
563
|
+
help="v11 hard-gate confirmation: name of the user/oncall/approver "
|
|
564
|
+
"who confirmed the gate-specific check (required for "
|
|
565
|
+
"migrate:cutover, modernize:cutover, incident:mitigate, "
|
|
566
|
+
"review:remediate-or-accept).",
|
|
567
|
+
)
|
|
568
|
+
parser.add_argument(
|
|
569
|
+
"--confirmation-evidence", default=None,
|
|
570
|
+
help="v11 hard-gate confirmation evidence: path / URL / ticket id "
|
|
571
|
+
"proving the check passed (e.g. rollback drill log, "
|
|
572
|
+
"dashboard screenshot, mitigation commit).",
|
|
573
|
+
)
|
|
574
|
+
parser.add_argument(
|
|
575
|
+
"--archetype-mode",
|
|
576
|
+
default=None,
|
|
577
|
+
choices=["triage", "explore", "specify", "decide", "ship",
|
|
578
|
+
"review", "incident", "build", "migrate", "modernize"],
|
|
579
|
+
help="Hydrate phase_plan from .claude-plugin/archetypes.json on create.",
|
|
580
|
+
)
|
|
581
|
+
parser.add_argument("--json", action="store_true")
|
|
582
|
+
args = parser.parse_args()
|
|
583
|
+
|
|
584
|
+
if args.action == "create":
|
|
585
|
+
try:
|
|
586
|
+
state, _project_dir = create_project(
|
|
587
|
+
args.project,
|
|
588
|
+
description=args.description,
|
|
589
|
+
archetype_mode=args.archetype_mode,
|
|
590
|
+
)
|
|
591
|
+
except (ValueError, RuntimeError) as exc:
|
|
592
|
+
_emit({"ok": False, "error": str(exc)}, args.json,
|
|
593
|
+
f"Error: {exc}")
|
|
594
|
+
sys.exit(1)
|
|
595
|
+
_emit(
|
|
596
|
+
{"ok": True, "name": state.name, "phase_plan": state.phase_plan,
|
|
597
|
+
"current_phase": state.current_phase,
|
|
598
|
+
"v11_archetype": state.extras.get("v11_archetype")},
|
|
599
|
+
args.json,
|
|
600
|
+
f"Created project '{state.name}' "
|
|
601
|
+
f"(phases: {' -> '.join(state.phase_plan) or 'none'})",
|
|
602
|
+
)
|
|
603
|
+
return
|
|
604
|
+
|
|
605
|
+
state = load_project_state(args.project)
|
|
606
|
+
if state is None:
|
|
607
|
+
_emit({"ok": False, "error": f"Project not found: {args.project}"},
|
|
608
|
+
args.json, f"Error: project not found: {args.project}")
|
|
609
|
+
sys.exit(1)
|
|
610
|
+
|
|
611
|
+
phase = args.phase or state.current_phase
|
|
612
|
+
|
|
613
|
+
if args.action == "status":
|
|
614
|
+
complete = is_complete(state)
|
|
615
|
+
_emit(
|
|
616
|
+
{
|
|
617
|
+
"name": state.name,
|
|
618
|
+
"current_phase": state.current_phase,
|
|
619
|
+
"phase_plan": state.phase_plan,
|
|
620
|
+
"phases": {k: asdict(v) for k, v in state.phases.items()},
|
|
621
|
+
"extras": state.extras,
|
|
622
|
+
"is_complete": complete,
|
|
623
|
+
"v11_archetype": state.extras.get("v11_archetype"),
|
|
624
|
+
},
|
|
625
|
+
args.json,
|
|
626
|
+
f"Project: {state.name}\n"
|
|
627
|
+
f"Phase: {state.current_phase}\n"
|
|
628
|
+
f"Plan: {' -> '.join(state.phase_plan) or 'none'}\n"
|
|
629
|
+
f"Complete: {complete}",
|
|
630
|
+
)
|
|
631
|
+
return
|
|
632
|
+
|
|
633
|
+
if args.action == "start":
|
|
634
|
+
state = start_phase(state, phase)
|
|
635
|
+
_emit({"ok": True, "phase": phase, "status": "in_progress"},
|
|
636
|
+
args.json, f"Started phase '{phase}'.")
|
|
637
|
+
return
|
|
638
|
+
|
|
639
|
+
if args.action == "complete":
|
|
640
|
+
state = complete_phase(state, phase)
|
|
641
|
+
_emit({"ok": True, "phase": phase, "status": "completed"},
|
|
642
|
+
args.json, f"Completed phase '{phase}'.")
|
|
643
|
+
return
|
|
644
|
+
|
|
645
|
+
if args.action == "approve":
|
|
646
|
+
try:
|
|
647
|
+
state, next_phase = approve_phase(
|
|
648
|
+
state, phase, approver=args.approver,
|
|
649
|
+
confirmed_by=args.confirmed_by,
|
|
650
|
+
confirmation_evidence=args.confirmation_evidence,
|
|
651
|
+
)
|
|
652
|
+
except ValueError as exc:
|
|
653
|
+
_emit({"ok": False, "error": str(exc)}, args.json,
|
|
654
|
+
f"Error: {exc}")
|
|
655
|
+
sys.exit(1)
|
|
656
|
+
_emit(
|
|
657
|
+
{"ok": True, "phase": phase, "status": "approved",
|
|
658
|
+
"next_phase": next_phase, "is_complete": is_complete(state),
|
|
659
|
+
"hard_gate_confirmed": bool(args.confirmed_by)},
|
|
660
|
+
args.json,
|
|
661
|
+
f"Approved phase '{phase}'. "
|
|
662
|
+
f"{'Next: ' + next_phase if next_phase else 'Project complete.'}",
|
|
663
|
+
)
|
|
664
|
+
return
|
|
665
|
+
|
|
666
|
+
if args.action == "skip":
|
|
667
|
+
state = skip_phase(state, phase, reason=args.reason)
|
|
668
|
+
_emit({"ok": True, "phase": phase, "status": "skipped",
|
|
669
|
+
"reason": args.reason},
|
|
670
|
+
args.json, f"Skipped phase '{phase}'.")
|
|
671
|
+
return
|
|
672
|
+
|
|
673
|
+
if args.action == "advance":
|
|
674
|
+
try:
|
|
675
|
+
state, next_phase = approve_phase(
|
|
676
|
+
state, phase, approver=args.approver,
|
|
677
|
+
confirmed_by=args.confirmed_by,
|
|
678
|
+
confirmation_evidence=args.confirmation_evidence,
|
|
679
|
+
)
|
|
680
|
+
except ValueError as exc:
|
|
681
|
+
_emit({"ok": False, "error": str(exc)}, args.json,
|
|
682
|
+
f"Error: {exc}")
|
|
683
|
+
sys.exit(1)
|
|
684
|
+
if next_phase:
|
|
685
|
+
state = start_phase(state, next_phase)
|
|
686
|
+
_emit(
|
|
687
|
+
{"ok": True, "approved": phase, "started": next_phase,
|
|
688
|
+
"is_complete": is_complete(state)},
|
|
689
|
+
args.json,
|
|
690
|
+
f"Approved '{phase}', started '{next_phase}'." if next_phase
|
|
691
|
+
else f"Approved '{phase}'. Project complete.",
|
|
692
|
+
)
|
|
693
|
+
return
|
|
694
|
+
|
|
695
|
+
if args.action == "delete":
|
|
696
|
+
_sm.delete("projects", args.project)
|
|
697
|
+
_emit({"ok": True, "deleted": args.project},
|
|
698
|
+
args.json, f"Deleted project '{args.project}'.")
|
|
699
|
+
return
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
if __name__ == "__main__":
|
|
703
|
+
main()
|