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,409 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
detect_clis.py — detect & probe agentic LLM CLIs for the council.
|
|
4
|
+
|
|
5
|
+
Reads ``agentic_cli_registry.py`` and answers two questions the council needs:
|
|
6
|
+
|
|
7
|
+
1. Which registered CLIs are INSTALLED on this machine (``shutil.which``)?
|
|
8
|
+
2. With ``--probe``: which installed CLIs are actually USABLE right now —
|
|
9
|
+
i.e. running their headless form (+ trust flags) on a trivial prompt
|
|
10
|
+
returns a sane reply — vs INSTALLED-BUT-UNUSABLE (auth revoked, no
|
|
11
|
+
provider configured, daemon down, …)?
|
|
12
|
+
|
|
13
|
+
The probe is the difference between "the binary is on PATH" and "the council
|
|
14
|
+
can get a real answer out of it". A CLI can be installed yet 401, or print
|
|
15
|
+
"no provider configured", or fail to reach a local daemon. Those seats must
|
|
16
|
+
NOT be counted toward quorum.
|
|
17
|
+
|
|
18
|
+
Safety / cross-platform contract (mirrors _capability_registry.py + CLAUDE.md):
|
|
19
|
+
* stdlib only — no third-party imports.
|
|
20
|
+
* detection via ``shutil.which``.
|
|
21
|
+
* each probe runs with ``subprocess.run(..., timeout=N, stdin=DEVNULL,
|
|
22
|
+
cwd=<fresh tempdir under tempfile.gettempdir()>)`` so a hanging CLI is
|
|
23
|
+
bounded, nothing reads our stdin, and no CLI mutates the real project.
|
|
24
|
+
* never perl/bash-isms, never a bare ``/tmp``.
|
|
25
|
+
|
|
26
|
+
Modes:
|
|
27
|
+
detect_clis.py # PATH scan, human output
|
|
28
|
+
detect_clis.py --json # PATH scan, JSON
|
|
29
|
+
detect_clis.py --probe # PATH scan + usability probe (JSON-capable)
|
|
30
|
+
detect_clis.py --list # dump the registry (no detection)
|
|
31
|
+
detect_clis.py --list --json # registry dump as JSON
|
|
32
|
+
|
|
33
|
+
Output JSON shape (--probe):
|
|
34
|
+
{
|
|
35
|
+
"detected": [ {key, display_name, binary, resolved_path, category,
|
|
36
|
+
confidence, enabled_for_council, version}, ... ],
|
|
37
|
+
"usable": [ "<key>", ... ],
|
|
38
|
+
"unusable": [ {"cli": "<key>", "reason": "<class>: <detail>"}, ... ],
|
|
39
|
+
"collisions": [ {"binary": "...", "keys": [...]}, ... ]
|
|
40
|
+
}
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from __future__ import annotations
|
|
44
|
+
|
|
45
|
+
import argparse
|
|
46
|
+
import json
|
|
47
|
+
import re
|
|
48
|
+
import subprocess
|
|
49
|
+
import sys
|
|
50
|
+
import tempfile
|
|
51
|
+
from dataclasses import asdict
|
|
52
|
+
from pathlib import Path
|
|
53
|
+
|
|
54
|
+
# Import the registry. Works both when run as a file from anywhere
|
|
55
|
+
# (sys.path bootstrap) and when imported as a module.
|
|
56
|
+
try:
|
|
57
|
+
from agentic_cli_registry import ( # type: ignore
|
|
58
|
+
AGENTIC_CLI_REGISTRY,
|
|
59
|
+
AgenticCLI,
|
|
60
|
+
detect as registry_detect,
|
|
61
|
+
)
|
|
62
|
+
except ModuleNotFoundError: # pragma: no cover — path bootstrap for direct runs
|
|
63
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
64
|
+
from agentic_cli_registry import ( # type: ignore
|
|
65
|
+
AGENTIC_CLI_REGISTRY,
|
|
66
|
+
AgenticCLI,
|
|
67
|
+
detect as registry_detect,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# Trivial prompt: cheap, deterministic, and the reply is easy to sanity-check.
|
|
72
|
+
PROBE_PROMPT = "Reply with the single word: pong"
|
|
73
|
+
|
|
74
|
+
# Per-CLI probe timeout (seconds). Agentic coders spin up tools/MCP and can be
|
|
75
|
+
# slow on a cold start; this bounds a hang (e.g. cursor-agent `-p`) without
|
|
76
|
+
# starving a legitimately-slow-but-working CLI. Local runners get longer
|
|
77
|
+
# because first-token latency on a cold model load is high.
|
|
78
|
+
DEFAULT_TIMEOUT = 45
|
|
79
|
+
LOCAL_RUNNER_TIMEOUT = 60
|
|
80
|
+
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
# Error-signature classification.
|
|
83
|
+
# A CLI that is installed-but-unusable fails in a recognisable way. We match
|
|
84
|
+
# stdout+stderr (lower-cased) against these signatures to label WHY a seat is
|
|
85
|
+
# unusable, so the council can tell the user "codex: auth revoked" rather than
|
|
86
|
+
# a generic failure. Order matters: first match wins.
|
|
87
|
+
# ---------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
_UNUSABLE_SIGNATURES: list[tuple[str, re.Pattern[str]]] = [
|
|
90
|
+
(
|
|
91
|
+
"auth",
|
|
92
|
+
re.compile(
|
|
93
|
+
r"\b(401|403|unauthor|authentication (failed|required)|not (logged|signed) in"
|
|
94
|
+
r"|please (log ?in|sign ?in|run .*login)|invalid api key|api key (not|is missing)"
|
|
95
|
+
r"|expired (token|credential)|forbidden|access denied"
|
|
96
|
+
r"|credentials? (not found|missing|expired)|re-?authenticate)\b",
|
|
97
|
+
re.IGNORECASE,
|
|
98
|
+
),
|
|
99
|
+
),
|
|
100
|
+
(
|
|
101
|
+
"no-provider",
|
|
102
|
+
re.compile(
|
|
103
|
+
r"\b(no (provider|model) (configured|set|selected|available)"
|
|
104
|
+
r"|no api key|set (the )?\w*_?api_key|missing .*api[_ ]?key"
|
|
105
|
+
r"|configure (a )?(provider|model|api key)|run .*configure"
|
|
106
|
+
r"|no default model|model not (found|configured))\b",
|
|
107
|
+
re.IGNORECASE,
|
|
108
|
+
),
|
|
109
|
+
),
|
|
110
|
+
(
|
|
111
|
+
"daemon-down",
|
|
112
|
+
re.compile(
|
|
113
|
+
r"\b(could not connect|connection refused|connection error"
|
|
114
|
+
r"|failed to connect|daemon (not|isn'?t) running|is the server running"
|
|
115
|
+
r"|ollama (server|app) (not|isn'?t) running|dial tcp|econnrefused"
|
|
116
|
+
r"|no such model|model .* not found, try pulling)\b",
|
|
117
|
+
re.IGNORECASE,
|
|
118
|
+
),
|
|
119
|
+
),
|
|
120
|
+
(
|
|
121
|
+
"quota",
|
|
122
|
+
re.compile(
|
|
123
|
+
r"\b(quota|rate ?limit|429|insufficient (credit|funds|balance)"
|
|
124
|
+
r"|billing|payment required|402)\b",
|
|
125
|
+
re.IGNORECASE,
|
|
126
|
+
),
|
|
127
|
+
),
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
# If a CLI exits non-zero with no recognised signature, we still mark it
|
|
131
|
+
# unusable but with this generic label so the seat is not silently trusted.
|
|
132
|
+
_GENERIC_UNUSABLE = "error"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _classify_failure(
|
|
136
|
+
returncode: int | None, combined: str, timed_out: bool
|
|
137
|
+
) -> tuple[str, str] | None:
|
|
138
|
+
"""Classify a probe run. Returns ``(reason_class, matched_line)`` for an
|
|
139
|
+
unusable run, or ``None`` if the run looks usable.
|
|
140
|
+
|
|
141
|
+
``matched_line`` is the specific line that tripped the signature (e.g. the
|
|
142
|
+
401 line), so the human-facing reason is honest rather than echoing a
|
|
143
|
+
cosmetic banner line. A run is USABLE only when it did not time out, exited
|
|
144
|
+
0, and produced non-trivial stdout free of a failure signature (some CLIs
|
|
145
|
+
print the error to stdout yet still exit 0).
|
|
146
|
+
"""
|
|
147
|
+
if timed_out:
|
|
148
|
+
return ("timeout", "")
|
|
149
|
+
lines = combined.splitlines()
|
|
150
|
+
for label, pat in _UNUSABLE_SIGNATURES:
|
|
151
|
+
for line in lines:
|
|
152
|
+
if pat.search(line):
|
|
153
|
+
return (label, line.strip())
|
|
154
|
+
# Fall back to a whole-text match (signature spanning the buffer).
|
|
155
|
+
if pat.search(combined):
|
|
156
|
+
return (label, "")
|
|
157
|
+
if returncode not in (0, None):
|
|
158
|
+
return (_GENERIC_UNUSABLE, "")
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _looks_like_real_reply(stdout: str) -> bool:
|
|
163
|
+
"""A sane reply has some printable content beyond whitespace/banners.
|
|
164
|
+
|
|
165
|
+
We do NOT require the literal word 'pong' — models phrase things their own
|
|
166
|
+
way and some CLIs wrap output. We only require that *something* substantive
|
|
167
|
+
came back, since auth/provider/daemon failures produce either empty stdout
|
|
168
|
+
or an error string (already caught by signature matching)."""
|
|
169
|
+
stripped = stdout.strip()
|
|
170
|
+
return len(stripped) >= 2
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _probe_version(cli: AgenticCLI, timeout: int) -> str:
|
|
174
|
+
"""Capture the version string (disambiguates binary collisions like grok)."""
|
|
175
|
+
try:
|
|
176
|
+
proc = subprocess.run(
|
|
177
|
+
cli.version_probe,
|
|
178
|
+
stdin=subprocess.DEVNULL,
|
|
179
|
+
capture_output=True,
|
|
180
|
+
text=True,
|
|
181
|
+
timeout=min(timeout, 15),
|
|
182
|
+
)
|
|
183
|
+
out = (proc.stdout or proc.stderr or "").strip()
|
|
184
|
+
# Keep it to the first line — version banners can be multi-line.
|
|
185
|
+
return out.splitlines()[0].strip() if out else ""
|
|
186
|
+
except (subprocess.TimeoutExpired, OSError, ValueError):
|
|
187
|
+
return ""
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _build_probe_argv(cli: AgenticCLI) -> list[str] | None:
|
|
191
|
+
"""Build the headless argv for a probe run: rendered template + trust flags.
|
|
192
|
+
|
|
193
|
+
Returns None for CLIs that cannot be safely auto-probed with a trivial
|
|
194
|
+
prompt (e.g. ollama needs a model name we don't know). Those are reported
|
|
195
|
+
as detected but skipped by the probe with an explicit reason.
|
|
196
|
+
"""
|
|
197
|
+
if cli.key == "ollama" or "{MODEL}" in cli.headless_invocation:
|
|
198
|
+
# Local runners need a concrete pulled model; we won't guess one.
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
rendered = cli.render(PROBE_PROMPT)
|
|
202
|
+
try:
|
|
203
|
+
import shlex
|
|
204
|
+
|
|
205
|
+
argv = shlex.split(rendered, posix=(sys.platform != "win32"))
|
|
206
|
+
except ValueError:
|
|
207
|
+
return None
|
|
208
|
+
if not argv:
|
|
209
|
+
return None
|
|
210
|
+
# Append trust flags AFTER the template so headless runs don't block on a
|
|
211
|
+
# permission / trust / git-repo prompt.
|
|
212
|
+
argv.extend(cli.trust_flags)
|
|
213
|
+
return argv
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _probe_one(cli: AgenticCLI) -> dict:
|
|
217
|
+
"""Probe a single detected CLI. Returns {usable: bool, reason, version}."""
|
|
218
|
+
timeout = LOCAL_RUNNER_TIMEOUT if cli.category == "local-runner" else DEFAULT_TIMEOUT
|
|
219
|
+
version = _probe_version(cli, timeout)
|
|
220
|
+
|
|
221
|
+
argv = _build_probe_argv(cli)
|
|
222
|
+
if argv is None:
|
|
223
|
+
return {
|
|
224
|
+
"usable": False,
|
|
225
|
+
"reason": "skipped: requires a model/daemon not auto-probeable (e.g. ollama needs a pulled model + running daemon)",
|
|
226
|
+
"version": version,
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
tmpdir = tempfile.mkdtemp(prefix="wg-council-probe-")
|
|
230
|
+
timed_out = False
|
|
231
|
+
returncode: int | None = None
|
|
232
|
+
stdout = ""
|
|
233
|
+
stderr = ""
|
|
234
|
+
try:
|
|
235
|
+
proc = subprocess.run(
|
|
236
|
+
argv,
|
|
237
|
+
stdin=subprocess.DEVNULL,
|
|
238
|
+
capture_output=True,
|
|
239
|
+
text=True,
|
|
240
|
+
timeout=timeout,
|
|
241
|
+
cwd=tmpdir,
|
|
242
|
+
)
|
|
243
|
+
returncode = proc.returncode
|
|
244
|
+
stdout = proc.stdout or ""
|
|
245
|
+
stderr = proc.stderr or ""
|
|
246
|
+
except subprocess.TimeoutExpired as exc:
|
|
247
|
+
timed_out = True
|
|
248
|
+
stdout = (exc.stdout or b"").decode("utf-8", "replace") if isinstance(exc.stdout, bytes) else (exc.stdout or "")
|
|
249
|
+
stderr = (exc.stderr or b"").decode("utf-8", "replace") if isinstance(exc.stderr, bytes) else (exc.stderr or "")
|
|
250
|
+
except (OSError, ValueError) as exc:
|
|
251
|
+
return {"usable": False, "reason": f"error: could not launch ({exc})", "version": version}
|
|
252
|
+
finally:
|
|
253
|
+
# Best-effort cleanup of the scratch cwd (aider et al. drop cache files).
|
|
254
|
+
try:
|
|
255
|
+
import shutil as _sh
|
|
256
|
+
|
|
257
|
+
_sh.rmtree(tmpdir, ignore_errors=True)
|
|
258
|
+
except Exception:
|
|
259
|
+
pass
|
|
260
|
+
|
|
261
|
+
combined = f"{stdout}\n{stderr}"
|
|
262
|
+
classified = _classify_failure(returncode, combined, timed_out)
|
|
263
|
+
if classified is None and _looks_like_real_reply(stdout):
|
|
264
|
+
return {"usable": True, "reason": None, "version": version}
|
|
265
|
+
|
|
266
|
+
if classified is None:
|
|
267
|
+
# Exited 0 but produced nothing substantive — treat as unusable so the
|
|
268
|
+
# council does not seat an empty responder.
|
|
269
|
+
reason, matched = "empty-response", ""
|
|
270
|
+
else:
|
|
271
|
+
reason, matched = classified
|
|
272
|
+
|
|
273
|
+
# Prefer the line that actually matched the failure signature (e.g. the
|
|
274
|
+
# 401 line); fall back to the first non-empty line if nothing matched
|
|
275
|
+
# (timeout / generic non-zero exit).
|
|
276
|
+
detail = matched
|
|
277
|
+
if not detail:
|
|
278
|
+
for line in combined.splitlines():
|
|
279
|
+
s = line.strip()
|
|
280
|
+
if s:
|
|
281
|
+
detail = s
|
|
282
|
+
break
|
|
283
|
+
detail = detail[:160]
|
|
284
|
+
full = f"{reason}: {detail}" if detail else reason
|
|
285
|
+
return {"usable": False, "reason": full, "version": version}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def run_detect(probe: bool) -> dict:
|
|
289
|
+
"""Detect installed CLIs and, if ``probe``, classify usable vs unusable."""
|
|
290
|
+
base = registry_detect(probe=False)
|
|
291
|
+
detected = base["detected"]
|
|
292
|
+
collisions = base["collisions"]
|
|
293
|
+
|
|
294
|
+
if not probe:
|
|
295
|
+
return {"detected": detected, "collisions": collisions}
|
|
296
|
+
|
|
297
|
+
usable: list[str] = []
|
|
298
|
+
unusable: list[dict] = []
|
|
299
|
+
for entry in detected:
|
|
300
|
+
key = entry["key"]
|
|
301
|
+
if key == "claude":
|
|
302
|
+
# Claude is the in-process host, not an external seat. Record its
|
|
303
|
+
# version for collision/audit purposes but don't probe it as a CLI.
|
|
304
|
+
cli = AGENTIC_CLI_REGISTRY[key]
|
|
305
|
+
entry["version"] = _probe_version(cli, DEFAULT_TIMEOUT)
|
|
306
|
+
continue
|
|
307
|
+
cli = AGENTIC_CLI_REGISTRY[key]
|
|
308
|
+
result = _probe_one(cli)
|
|
309
|
+
entry["version"] = result["version"]
|
|
310
|
+
if result["usable"]:
|
|
311
|
+
usable.append(key)
|
|
312
|
+
else:
|
|
313
|
+
unusable.append({"cli": key, "reason": result["reason"]})
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
"detected": detected,
|
|
317
|
+
"usable": usable,
|
|
318
|
+
"unusable": unusable,
|
|
319
|
+
"collisions": collisions,
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def list_registry() -> dict:
|
|
324
|
+
"""Dump the full registry as plain dicts (for --list)."""
|
|
325
|
+
return {
|
|
326
|
+
"clis": [asdict(cli) for cli in AGENTIC_CLI_REGISTRY.values()],
|
|
327
|
+
"count": len(AGENTIC_CLI_REGISTRY),
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# ---------------------------------------------------------------------------
|
|
332
|
+
# Human-readable rendering
|
|
333
|
+
# ---------------------------------------------------------------------------
|
|
334
|
+
|
|
335
|
+
def _emit_human_list(reg: dict) -> None:
|
|
336
|
+
sys.stdout.write(f"agentic CLI registry — {reg['count']} entries\n")
|
|
337
|
+
for cli in reg["clis"]:
|
|
338
|
+
flag = "" if cli["enabled_for_council"] else " [council-disabled]"
|
|
339
|
+
conf = "" if cli["confidence"] == "verified" else f" ({cli['confidence']})"
|
|
340
|
+
sys.stdout.write(
|
|
341
|
+
f" {cli['key']:<14} {cli['category']:<14} {cli['vendor']}{conf}{flag}\n"
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def _emit_human_detect(result: dict, probed: bool) -> None:
|
|
346
|
+
detected = result["detected"]
|
|
347
|
+
sys.stdout.write(f"detected {len(detected)} installed CLI(s):\n")
|
|
348
|
+
usable = set(result.get("usable", []))
|
|
349
|
+
unusable_map = {u["cli"]: u["reason"] for u in result.get("unusable", [])}
|
|
350
|
+
for entry in detected:
|
|
351
|
+
key = entry["key"]
|
|
352
|
+
ver = entry.get("version", "")
|
|
353
|
+
ver_s = f" v={ver}" if ver else ""
|
|
354
|
+
if not probed:
|
|
355
|
+
status = ""
|
|
356
|
+
elif key == "claude":
|
|
357
|
+
status = " [in-process host]"
|
|
358
|
+
elif key in usable:
|
|
359
|
+
status = " USABLE"
|
|
360
|
+
elif key in unusable_map:
|
|
361
|
+
status = f" UNUSABLE — {unusable_map[key]}"
|
|
362
|
+
else:
|
|
363
|
+
status = ""
|
|
364
|
+
sys.stdout.write(f" {key:<14} {entry['resolved_path']}{ver_s}{status}\n")
|
|
365
|
+
|
|
366
|
+
if probed:
|
|
367
|
+
sys.stdout.write(
|
|
368
|
+
f"\nquorum: {len(usable)} usable external CLI(s)"
|
|
369
|
+
+ (
|
|
370
|
+
" — full council"
|
|
371
|
+
if len(usable) >= 2
|
|
372
|
+
else " — below quorum (fallback to Task() subagent seats)"
|
|
373
|
+
)
|
|
374
|
+
+ "\n"
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
if result.get("collisions"):
|
|
378
|
+
sys.stdout.write("\nbinary collisions (disambiguate by version):\n")
|
|
379
|
+
for c in result["collisions"]:
|
|
380
|
+
sys.stdout.write(f" {c['binary']}: {', '.join(c['keys'])}\n")
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def main(argv: list[str] | None = None) -> int:
|
|
384
|
+
parser = argparse.ArgumentParser(
|
|
385
|
+
description="Detect & probe agentic LLM CLIs for the wicked-garden council."
|
|
386
|
+
)
|
|
387
|
+
parser.add_argument("--probe", action="store_true", help="run headless usability probe")
|
|
388
|
+
parser.add_argument("--list", action="store_true", help="dump the registry and exit")
|
|
389
|
+
parser.add_argument("--json", action="store_true", help="emit JSON instead of human text")
|
|
390
|
+
args = parser.parse_args(argv)
|
|
391
|
+
|
|
392
|
+
if args.list:
|
|
393
|
+
reg = list_registry()
|
|
394
|
+
if args.json:
|
|
395
|
+
sys.stdout.write(json.dumps(reg, indent=2) + "\n")
|
|
396
|
+
else:
|
|
397
|
+
_emit_human_list(reg)
|
|
398
|
+
return 0
|
|
399
|
+
|
|
400
|
+
result = run_detect(probe=args.probe)
|
|
401
|
+
if args.json:
|
|
402
|
+
sys.stdout.write(json.dumps(result, indent=2) + "\n")
|
|
403
|
+
else:
|
|
404
|
+
_emit_human_detect(result, probed=args.probe)
|
|
405
|
+
return 0
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
if __name__ == "__main__":
|
|
409
|
+
sys.exit(main())
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
wicked-jam query CLI -- exposes session data for cross-plugin access.
|
|
4
|
+
|
|
5
|
+
All data flows through DomainStore("wicked-jam") which routes to MCP
|
|
6
|
+
integrations when available and falls back to local JSON files.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
jam.py list-sessions [--query Q] [--limit N] [--json] [--project P]
|
|
10
|
+
jam.py transcript [--session-id ID] [--json]
|
|
11
|
+
jam.py persona <name> [--session-id ID] [--json]
|
|
12
|
+
jam.py thinking [--session-id ID] [--json]
|
|
13
|
+
|
|
14
|
+
Transcript entry schema:
|
|
15
|
+
{
|
|
16
|
+
"session_id": "...",
|
|
17
|
+
"round": 1,
|
|
18
|
+
"persona_name": "Technical Architect",
|
|
19
|
+
"persona_type": "technical", # technical | user | business | process | council
|
|
20
|
+
"raw_text": "...",
|
|
21
|
+
"thinking": "...", # optional: pre-synthesis deliberation (alternatives, trade-offs)
|
|
22
|
+
"timestamp": "...",
|
|
23
|
+
"entry_type": "perspective" # perspective | synthesis | council_response
|
|
24
|
+
}
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import argparse
|
|
28
|
+
import json
|
|
29
|
+
import sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
# Resolve _domain_store from the parent scripts/ directory
|
|
33
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
34
|
+
from _domain_store import DomainStore
|
|
35
|
+
|
|
36
|
+
_sm = DomainStore("wicked-jam")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def list_sessions(query: str = None, limit: int = 10, project: str = None) -> dict:
|
|
40
|
+
"""List recent brainstorming sessions, optionally filtered by query."""
|
|
41
|
+
params = {}
|
|
42
|
+
if query:
|
|
43
|
+
params["q"] = query
|
|
44
|
+
if project:
|
|
45
|
+
params["project"] = project
|
|
46
|
+
|
|
47
|
+
records = _sm.list("sessions", **params)
|
|
48
|
+
|
|
49
|
+
results = []
|
|
50
|
+
query_lower = query.lower() if query else None
|
|
51
|
+
|
|
52
|
+
for session in records:
|
|
53
|
+
topic = session.get("topic", "")
|
|
54
|
+
summary = session.get("synthesis", {}).get("summary", "")
|
|
55
|
+
perspectives = session.get("perspectives", [])
|
|
56
|
+
created = session.get("created", "")
|
|
57
|
+
session_project = session.get("project", "")
|
|
58
|
+
|
|
59
|
+
# Filter by project if specified (in case local fallback doesn't filter)
|
|
60
|
+
if project and session_project and session_project != project:
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
# Filter by query if specified (in case local fallback doesn't filter)
|
|
64
|
+
if query_lower:
|
|
65
|
+
text = f"{topic} {summary}".lower()
|
|
66
|
+
if not any(word in text for word in query_lower.split() if len(word) > 2):
|
|
67
|
+
continue
|
|
68
|
+
|
|
69
|
+
results.append({
|
|
70
|
+
"id": session.get("id", ""),
|
|
71
|
+
"topic": topic,
|
|
72
|
+
"summary": summary[:300] if summary else "",
|
|
73
|
+
"perspectives_count": len(perspectives) if isinstance(perspectives, list) else 0,
|
|
74
|
+
"created": created,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
if len(results) >= limit:
|
|
78
|
+
break
|
|
79
|
+
|
|
80
|
+
return {"sessions": results}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _resolve_session_id(session_id: str = None) -> str:
|
|
84
|
+
"""Return the given session_id or derive the most recent one from stored sessions."""
|
|
85
|
+
if session_id:
|
|
86
|
+
return session_id
|
|
87
|
+
records = _sm.list("sessions")
|
|
88
|
+
if not records:
|
|
89
|
+
return None
|
|
90
|
+
# Sessions are expected to be in insertion order; take the last one.
|
|
91
|
+
latest = records[-1]
|
|
92
|
+
return latest.get("id", "")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_transcript(session_id: str = None) -> dict:
|
|
96
|
+
"""Return the full transcript (all entries) for a session, in chronological order."""
|
|
97
|
+
sid = _resolve_session_id(session_id)
|
|
98
|
+
if not sid:
|
|
99
|
+
return {"session_id": None, "entries": [], "error": "No sessions found."}
|
|
100
|
+
|
|
101
|
+
data = _sm.get("transcripts", sid)
|
|
102
|
+
if not data:
|
|
103
|
+
return {
|
|
104
|
+
"session_id": sid,
|
|
105
|
+
"entries": [],
|
|
106
|
+
"error": f"No transcript found for session: {sid}",
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
entries = data.get("entries", [])
|
|
110
|
+
return {"session_id": sid, "entries": entries}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def get_persona(name: str, session_id: str = None) -> dict:
|
|
114
|
+
"""Return all transcript entries from a specific persona (case-insensitive match)."""
|
|
115
|
+
sid = _resolve_session_id(session_id)
|
|
116
|
+
if not sid:
|
|
117
|
+
return {"session_id": None, "persona": name, "entries": [], "error": "No sessions found."}
|
|
118
|
+
|
|
119
|
+
data = _sm.get("transcripts", sid)
|
|
120
|
+
if not data:
|
|
121
|
+
return {
|
|
122
|
+
"session_id": sid,
|
|
123
|
+
"persona": name,
|
|
124
|
+
"entries": [],
|
|
125
|
+
"error": f"No transcript found for session: {sid}",
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
name_lower = name.lower()
|
|
129
|
+
entries = [
|
|
130
|
+
e for e in data.get("entries", [])
|
|
131
|
+
if e.get("persona_name", "").lower() == name_lower
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
if not entries:
|
|
135
|
+
return {
|
|
136
|
+
"session_id": sid,
|
|
137
|
+
"persona": name,
|
|
138
|
+
"entries": [],
|
|
139
|
+
"error": f"No contributions found for persona: {name}",
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return {"session_id": sid, "persona": name, "entries": entries}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_thinking(session_id: str = None) -> dict:
|
|
146
|
+
"""Return all pre-synthesis perspective entries for a session."""
|
|
147
|
+
sid = _resolve_session_id(session_id)
|
|
148
|
+
if not sid:
|
|
149
|
+
return {"session_id": None, "entries": [], "error": "No sessions found."}
|
|
150
|
+
|
|
151
|
+
data = _sm.get("transcripts", sid)
|
|
152
|
+
if not data:
|
|
153
|
+
return {
|
|
154
|
+
"session_id": sid,
|
|
155
|
+
"entries": [],
|
|
156
|
+
"error": f"No transcript found for session: {sid}",
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
entries = [
|
|
160
|
+
e for e in data.get("entries", [])
|
|
161
|
+
if e.get("entry_type") == "perspective"
|
|
162
|
+
]
|
|
163
|
+
return {"session_id": sid, "entries": entries}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _print_entry(entry: dict, index: int = None) -> None:
|
|
167
|
+
"""Pretty-print a single transcript entry."""
|
|
168
|
+
prefix = f"[{index}] " if index is not None else ""
|
|
169
|
+
round_num = entry.get("round", "?")
|
|
170
|
+
persona = entry.get("persona_name", "Unknown")
|
|
171
|
+
ptype = entry.get("persona_type", "")
|
|
172
|
+
etype = entry.get("entry_type", "")
|
|
173
|
+
timestamp = entry.get("timestamp", "")
|
|
174
|
+
|
|
175
|
+
type_label = f" ({etype})" if etype else ""
|
|
176
|
+
ptype_label = f" [{ptype}]" if ptype else ""
|
|
177
|
+
ts_label = f" {timestamp}" if timestamp else ""
|
|
178
|
+
|
|
179
|
+
print(f"\n{prefix}Round {round_num} — {persona}{ptype_label}{type_label}{ts_label}")
|
|
180
|
+
print("-" * 60)
|
|
181
|
+
thinking = entry.get("thinking", "").strip()
|
|
182
|
+
if thinking:
|
|
183
|
+
print(f"[thinking]\n{thinking}\n")
|
|
184
|
+
print(entry.get("raw_text", "").strip())
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def main():
|
|
188
|
+
parser = argparse.ArgumentParser(description="wicked-jam query CLI")
|
|
189
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
190
|
+
|
|
191
|
+
ls_parser = subparsers.add_parser("list-sessions", help="List brainstorming sessions")
|
|
192
|
+
ls_parser.add_argument("--query", "-q", help="Filter by topic/summary text")
|
|
193
|
+
ls_parser.add_argument("--limit", "-n", type=int, default=10, help="Max results")
|
|
194
|
+
ls_parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
195
|
+
ls_parser.add_argument("--project", "-p", help="Filter by project")
|
|
196
|
+
|
|
197
|
+
tr_parser = subparsers.add_parser("transcript", help="Full conversation transcript")
|
|
198
|
+
tr_parser.add_argument("--session-id", help="Session ID (defaults to most recent)")
|
|
199
|
+
tr_parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
200
|
+
|
|
201
|
+
pe_parser = subparsers.add_parser("persona", help="Specific persona's contributions")
|
|
202
|
+
pe_parser.add_argument("name", help="Persona name (case-insensitive)")
|
|
203
|
+
pe_parser.add_argument("--session-id", help="Session ID (defaults to most recent)")
|
|
204
|
+
pe_parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
205
|
+
|
|
206
|
+
th_parser = subparsers.add_parser("thinking", help="All pre-synthesis perspectives")
|
|
207
|
+
th_parser.add_argument("--session-id", help="Session ID (defaults to most recent)")
|
|
208
|
+
th_parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
209
|
+
|
|
210
|
+
args = parser.parse_args()
|
|
211
|
+
|
|
212
|
+
if not args.command:
|
|
213
|
+
parser.print_help()
|
|
214
|
+
sys.exit(1)
|
|
215
|
+
|
|
216
|
+
if args.command == "list-sessions":
|
|
217
|
+
result = list_sessions(
|
|
218
|
+
query=args.query,
|
|
219
|
+
limit=args.limit,
|
|
220
|
+
project=args.project,
|
|
221
|
+
)
|
|
222
|
+
if getattr(args, "json", False):
|
|
223
|
+
print(json.dumps(result, indent=2))
|
|
224
|
+
else:
|
|
225
|
+
sessions = result["sessions"]
|
|
226
|
+
if not sessions:
|
|
227
|
+
print("No sessions found.")
|
|
228
|
+
return
|
|
229
|
+
for s in sessions:
|
|
230
|
+
print(f" {s['id']}: {s['topic']} ({s['perspectives_count']} perspectives)")
|
|
231
|
+
|
|
232
|
+
elif args.command == "transcript":
|
|
233
|
+
result = get_transcript(session_id=getattr(args, "session_id", None))
|
|
234
|
+
if getattr(args, "json", False):
|
|
235
|
+
print(json.dumps(result, indent=2))
|
|
236
|
+
else:
|
|
237
|
+
error = result.get("error")
|
|
238
|
+
if error and not result["entries"]:
|
|
239
|
+
print(error)
|
|
240
|
+
return
|
|
241
|
+
sid = result.get("session_id", "")
|
|
242
|
+
entries = result["entries"]
|
|
243
|
+
print(f"Transcript — session: {sid} ({len(entries)} entries)")
|
|
244
|
+
for i, entry in enumerate(entries, start=1):
|
|
245
|
+
_print_entry(entry, index=i)
|
|
246
|
+
|
|
247
|
+
elif args.command == "persona":
|
|
248
|
+
result = get_persona(name=args.name, session_id=getattr(args, "session_id", None))
|
|
249
|
+
if getattr(args, "json", False):
|
|
250
|
+
print(json.dumps(result, indent=2))
|
|
251
|
+
else:
|
|
252
|
+
error = result.get("error")
|
|
253
|
+
if error and not result["entries"]:
|
|
254
|
+
print(error)
|
|
255
|
+
return
|
|
256
|
+
sid = result.get("session_id", "")
|
|
257
|
+
entries = result["entries"]
|
|
258
|
+
persona = result.get("persona", args.name)
|
|
259
|
+
print(f"Contributions from: {persona} | session: {sid} ({len(entries)} entries)")
|
|
260
|
+
for i, entry in enumerate(entries, start=1):
|
|
261
|
+
_print_entry(entry, index=i)
|
|
262
|
+
|
|
263
|
+
elif args.command == "thinking":
|
|
264
|
+
result = get_thinking(session_id=getattr(args, "session_id", None))
|
|
265
|
+
if getattr(args, "json", False):
|
|
266
|
+
print(json.dumps(result, indent=2))
|
|
267
|
+
else:
|
|
268
|
+
error = result.get("error")
|
|
269
|
+
if error and not result["entries"]:
|
|
270
|
+
print(error)
|
|
271
|
+
return
|
|
272
|
+
sid = result.get("session_id", "")
|
|
273
|
+
entries = result["entries"]
|
|
274
|
+
print(f"Pre-synthesis perspectives — session: {sid} ({len(entries)} entries)")
|
|
275
|
+
entries_with_thinking = [e for e in entries if e.get("thinking", "").strip()]
|
|
276
|
+
if entries and not entries_with_thinking:
|
|
277
|
+
print("No thinking data available for this session.")
|
|
278
|
+
for i, entry in enumerate(entries, start=1):
|
|
279
|
+
_print_entry(entry, index=i)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
if __name__ == "__main__":
|
|
283
|
+
main()
|