specsmith 0.11.3.dev428__tar.gz → 0.11.3.dev431__tar.gz
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.
- {specsmith-0.11.3.dev428/src/specsmith.egg-info → specsmith-0.11.3.dev431}/PKG-INFO +1 -1
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/pyproject.toml +3 -1
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/cli.py +29 -6
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/devops.py +170 -0
- specsmith-0.11.3.dev431/src/specsmith/skills/governance.py +418 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/vcs_commands.py +35 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431/src/specsmith.egg-info}/PKG-INFO +1 -1
- specsmith-0.11.3.dev428/src/specsmith/skills/governance.py +0 -168
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/LICENSE +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/README.md +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/setup.cfg +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/epistemic/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/epistemic/belief.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/epistemic/certainty.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/epistemic/py.typed +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/epistemic/recovery.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/epistemic/session.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/epistemic/trace.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/__main__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/context_seed.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/dispatch/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/dispatch/_status.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/dispatch/dag.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/dispatch/events.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/dispatch/result.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/hf_leaderboard.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/llm_client.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/model_profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/architect.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/auditor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/auth.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/block_export.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/channel.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/ci_manager.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/compliance/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/compliance/_compat.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/compliance/checker.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/compliance/evidence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/compliance/regulations.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/compliance/reporter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/compressor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/config.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/context_orchestrator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/context_window.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/credits.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/differ.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/doctor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/drive.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/editor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/esdb/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/esdb/bridge.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/executor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/exporter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/governance_logic.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/governance_store.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/governance_yaml.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/history_search.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/importer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/instinct.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/issue_reporter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/languages.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/ledger.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/mcp_generator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/migrations/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/migrations/m002_agents_slim.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/migrations/m003_compliance_init.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/migrations/runner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/ollama_cmds.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/patent.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/paths.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/phase.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/plugins.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/releaser.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/requirements.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/serve.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/session.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/session_init.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/session_store.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/cloud.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/corporate.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/cross_platform.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/docs.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/embedded.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/hardware.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/mobile.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/productivity.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills/ssh.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/skills_builder.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/sync.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/tools.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/trace.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/updater.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/validator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith/workspace.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith.egg-info/SOURCES.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_CMD_001.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_ai_client.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_ai_intelligence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_auditor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_channel.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_cli.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_compliance.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_compressor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_dispatch.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_epistemic.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_importer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_integrations.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_intelligence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_issue_reporter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_mcp_client.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_new_modules.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_nexus.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_permissions.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_rate_limits.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_req_248_262.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_scaffolder.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_skills_mcp.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_smoke.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_suggester.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_tools.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_validator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_vcs.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_warp_parity.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev431}/tests/test_warp_parity_followup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.11.3.
|
|
3
|
+
Version: 0.11.3.dev431
|
|
4
4
|
Summary: Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands.
|
|
5
5
|
Author: BitConcepts
|
|
6
6
|
License-Expression: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specsmith"
|
|
7
|
-
version = "0.11.3.
|
|
7
|
+
version = "0.11.3.dev431"
|
|
8
8
|
description = "Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -127,6 +127,8 @@ select = ["E", "F", "W", "I", "UP", "B", "SIM"]
|
|
|
127
127
|
"src/specsmith/ci_manager.py" = ["E501"]
|
|
128
128
|
# Context orchestrator: tier descriptions are intentionally descriptive
|
|
129
129
|
"src/specsmith/context_orchestrator.py" = ["E501"]
|
|
130
|
+
# Skills module: skill body strings contain markdown content with long lines
|
|
131
|
+
"src/specsmith/skills/*.py" = ["E501"]
|
|
130
132
|
# Migration files: rule description strings and template content
|
|
131
133
|
"src/specsmith/migrations/m001_governance_yaml.py" = ["E501"]
|
|
132
134
|
"src/specsmith/migrations/m004_ledger_esdb.py" = ["E501"]
|
|
@@ -2471,8 +2471,14 @@ def push_cmd(project_dir: str, force: bool) -> None:
|
|
|
2471
2471
|
default=False,
|
|
2472
2472
|
help="Commit only; skip push.",
|
|
2473
2473
|
)
|
|
2474
|
+
@click.option(
|
|
2475
|
+
"--force",
|
|
2476
|
+
is_flag=True,
|
|
2477
|
+
default=False,
|
|
2478
|
+
help="Override push safety checks (e.g. direct-to-main guard).",
|
|
2479
|
+
)
|
|
2474
2480
|
@click.option("--json", "as_json", is_flag=True, default=False)
|
|
2475
|
-
def save_cmd(project_dir: str, message: str, no_push: bool, as_json: bool) -> None:
|
|
2481
|
+
def save_cmd(project_dir: str, message: str, no_push: bool, force: bool, as_json: bool) -> None:
|
|
2476
2482
|
"""Save governance state: ESDB backup, commit, and push.
|
|
2477
2483
|
|
|
2478
2484
|
Combines ``specsmith esdb backup`` + ``specsmith commit`` + ``specsmith push``
|
|
@@ -2511,7 +2517,7 @@ def save_cmd(project_dir: str, message: str, no_push: bool, as_json: bool) -> No
|
|
|
2511
2517
|
|
|
2512
2518
|
# 3. Push
|
|
2513
2519
|
if not no_push:
|
|
2514
|
-
push_result = run_push(root)
|
|
2520
|
+
push_result = run_push(root, force=force)
|
|
2515
2521
|
steps.append({"step": "push", "ok": push_result.success, "message": push_result.message})
|
|
2516
2522
|
|
|
2517
2523
|
ok = all(s["ok"] for s in steps)
|
|
@@ -2688,11 +2694,28 @@ def pr_cmd(project_dir: str, title: str, draft: bool) -> None:
|
|
|
2688
2694
|
|
|
2689
2695
|
@main.command(name="pull")
|
|
2690
2696
|
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
2691
|
-
|
|
2692
|
-
""
|
|
2693
|
-
|
|
2697
|
+
@click.option(
|
|
2698
|
+
"--discard",
|
|
2699
|
+
is_flag=True,
|
|
2700
|
+
default=False,
|
|
2701
|
+
help="Hard-reset to remote and pull, discarding all local changes.",
|
|
2702
|
+
)
|
|
2703
|
+
@click.option(
|
|
2704
|
+
"--clean",
|
|
2705
|
+
is_flag=True,
|
|
2706
|
+
default=False,
|
|
2707
|
+
help="Like --discard but also removes untracked files (git clean -fd).",
|
|
2708
|
+
)
|
|
2709
|
+
def pull_cmd(project_dir: str, discard: bool, clean: bool) -> None:
|
|
2710
|
+
"""Pull latest changes and check for governance conflicts.
|
|
2711
|
+
|
|
2712
|
+
Use --discard to hard-reset to the remote branch, discarding local
|
|
2713
|
+
changes. Add --clean to also remove untracked files.
|
|
2714
|
+
"""
|
|
2715
|
+
from specsmith.vcs_commands import run_discard, run_sync
|
|
2694
2716
|
|
|
2695
|
-
|
|
2717
|
+
root = Path(project_dir).resolve()
|
|
2718
|
+
result = run_discard(root, clean=clean) if discard or clean else run_sync(root)
|
|
2696
2719
|
if result.success:
|
|
2697
2720
|
console.print(f"[green]\u2713[/green] {result.message}")
|
|
2698
2721
|
else:
|
|
@@ -4,6 +4,176 @@
|
|
|
4
4
|
from specsmith.skills import SkillDomain, SkillEntry
|
|
5
5
|
|
|
6
6
|
SKILLS: list[SkillEntry] = [
|
|
7
|
+
SkillEntry(
|
|
8
|
+
slug="github-actions-ci",
|
|
9
|
+
name="GitHub Actions CI — Layer1Labs pattern (zero-trust, parallel, coverage-gated)",
|
|
10
|
+
description=(
|
|
11
|
+
"Standard Layer1Labs GitHub Actions CI pattern: permissions: {} at workflow level, "
|
|
12
|
+
"per-job contents: read grants, parallel jobs (no needs chain), full Python matrix "
|
|
13
|
+
"3.10–3.13, and --cov-fail-under=85 coverage gate."
|
|
14
|
+
),
|
|
15
|
+
domain=SkillDomain.DEVOPS,
|
|
16
|
+
tags=[
|
|
17
|
+
"ci",
|
|
18
|
+
"github-actions",
|
|
19
|
+
"permissions",
|
|
20
|
+
"pytest",
|
|
21
|
+
"coverage",
|
|
22
|
+
"ruff",
|
|
23
|
+
"mypy",
|
|
24
|
+
"security",
|
|
25
|
+
"python",
|
|
26
|
+
"matrix",
|
|
27
|
+
"zero-trust",
|
|
28
|
+
],
|
|
29
|
+
platforms=["linux", "windows", "macos"],
|
|
30
|
+
prerequisites=["gh"],
|
|
31
|
+
body=(
|
|
32
|
+
"""\
|
|
33
|
+
# GitHub Actions CI Skill (Layer1Labs pattern)
|
|
34
|
+
|
|
35
|
+
Standard CI pattern used across all Layer1Labs / BitConcepts Python projects.
|
|
36
|
+
Reference implementation: `chronomemory/.github/workflows/ci.yml`
|
|
37
|
+
|
|
38
|
+
## Core principles
|
|
39
|
+
- `permissions: {}` at workflow level — deny all by default.
|
|
40
|
+
- `permissions: contents: read` on each individual job — grant minimum needed.
|
|
41
|
+
- All jobs run **in parallel** — no `needs:` dependency chain unless truly required.
|
|
42
|
+
- Full Python matrix: **3.10, 3.11, 3.12, 3.13** × ubuntu-latest, windows-latest.
|
|
43
|
+
- Coverage gate: `--cov-fail-under=85`.
|
|
44
|
+
- Named jobs (`name:` field) for readable GitHub UI.
|
|
45
|
+
- `fail-fast: false` on the test matrix so all combinations are reported.
|
|
46
|
+
|
|
47
|
+
## Canonical template
|
|
48
|
+
```yaml
|
|
49
|
+
name: CI
|
|
50
|
+
|
|
51
|
+
on:
|
|
52
|
+
push:
|
|
53
|
+
branches: [main, develop]
|
|
54
|
+
pull_request:
|
|
55
|
+
branches: [main, develop]
|
|
56
|
+
workflow_dispatch:
|
|
57
|
+
|
|
58
|
+
# Default: deny all. Each job grants only what it needs.
|
|
59
|
+
permissions: {}
|
|
60
|
+
|
|
61
|
+
jobs:
|
|
62
|
+
lint:
|
|
63
|
+
name: Lint (ruff)
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
permissions:
|
|
66
|
+
contents: read
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v6
|
|
69
|
+
- uses: actions/setup-python@v6
|
|
70
|
+
with:
|
|
71
|
+
python-version: "3.12"
|
|
72
|
+
cache: pip
|
|
73
|
+
- run: pip install ruff
|
|
74
|
+
- name: ruff format --check
|
|
75
|
+
run: ruff format --check src/ tests/
|
|
76
|
+
- name: ruff check
|
|
77
|
+
run: ruff check src/ tests/
|
|
78
|
+
|
|
79
|
+
typecheck:
|
|
80
|
+
name: Type check (mypy)
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
permissions:
|
|
83
|
+
contents: read
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/checkout@v6
|
|
86
|
+
- uses: actions/setup-python@v6
|
|
87
|
+
with:
|
|
88
|
+
python-version: "3.12"
|
|
89
|
+
cache: pip
|
|
90
|
+
- run: pip install -e ".[dev]"
|
|
91
|
+
- run: mypy src/<package>/
|
|
92
|
+
|
|
93
|
+
test:
|
|
94
|
+
name: Test (Python ${{ matrix.python-version }} / ${{ matrix.os }})
|
|
95
|
+
runs-on: ${{ matrix.os }}
|
|
96
|
+
permissions:
|
|
97
|
+
contents: read
|
|
98
|
+
strategy:
|
|
99
|
+
fail-fast: false
|
|
100
|
+
matrix:
|
|
101
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
102
|
+
os: [ubuntu-latest, windows-latest]
|
|
103
|
+
steps:
|
|
104
|
+
- uses: actions/checkout@v6
|
|
105
|
+
- uses: actions/setup-python@v6
|
|
106
|
+
with:
|
|
107
|
+
python-version: ${{ matrix.python-version }}
|
|
108
|
+
cache: pip
|
|
109
|
+
- run: pip install -e ".[dev]"
|
|
110
|
+
- run: pytest --cov=<package> --cov-report=term-missing --cov-fail-under=85
|
|
111
|
+
|
|
112
|
+
security:
|
|
113
|
+
name: Security audit (pip-audit)
|
|
114
|
+
runs-on: ubuntu-latest
|
|
115
|
+
permissions:
|
|
116
|
+
contents: read
|
|
117
|
+
steps:
|
|
118
|
+
- uses: actions/checkout@v6
|
|
119
|
+
- uses: actions/setup-python@v6
|
|
120
|
+
with:
|
|
121
|
+
python-version: "3.12"
|
|
122
|
+
cache: pip
|
|
123
|
+
- run: pip install pip-audit
|
|
124
|
+
- run: pip install -e .
|
|
125
|
+
- run: pip-audit
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## What NOT to do
|
|
129
|
+
- Do NOT set `permissions: contents: read` at workflow level — use `permissions: {}` + per-job grants.
|
|
130
|
+
- Do NOT use `needs: [lint, typecheck]` to gate the test job — run all in parallel.
|
|
131
|
+
- Do NOT omit Python 3.11 from the matrix.
|
|
132
|
+
- Do NOT skip `--cov-fail-under` — the 85% gate is non-negotiable.
|
|
133
|
+
- Do NOT use `cancel-in-progress: true` (concurrency block) unless there is a
|
|
134
|
+
specific reason — chronomemory pattern omits it.
|
|
135
|
+
- Do NOT use `macos-latest` in the matrix unless macOS-specific behavior must be
|
|
136
|
+
tested — it is ~10× slower and uses more CI minutes.
|
|
137
|
+
|
|
138
|
+
## Rust projects (additional jobs)
|
|
139
|
+
```yaml
|
|
140
|
+
rust-lint:
|
|
141
|
+
name: Rust lint (clippy + fmt)
|
|
142
|
+
runs-on: ubuntu-latest
|
|
143
|
+
permissions:
|
|
144
|
+
contents: read
|
|
145
|
+
steps:
|
|
146
|
+
- uses: actions/checkout@v6
|
|
147
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
148
|
+
with:
|
|
149
|
+
components: clippy, rustfmt
|
|
150
|
+
- run: cargo fmt --check --all
|
|
151
|
+
- run: cargo clippy --workspace -- -D warnings
|
|
152
|
+
|
|
153
|
+
rust-test:
|
|
154
|
+
name: Rust tests
|
|
155
|
+
runs-on: ubuntu-latest
|
|
156
|
+
permissions:
|
|
157
|
+
contents: read
|
|
158
|
+
steps:
|
|
159
|
+
- uses: actions/checkout@v6
|
|
160
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
161
|
+
- run: cargo test --workspace
|
|
162
|
+
|
|
163
|
+
security:
|
|
164
|
+
name: Security audit (cargo-audit)
|
|
165
|
+
runs-on: ubuntu-latest
|
|
166
|
+
permissions:
|
|
167
|
+
contents: read
|
|
168
|
+
steps:
|
|
169
|
+
- uses: actions/checkout@v6
|
|
170
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
171
|
+
- run: cargo install cargo-audit --locked
|
|
172
|
+
- run: cargo audit
|
|
173
|
+
```
|
|
174
|
+
"""
|
|
175
|
+
),
|
|
176
|
+
),
|
|
7
177
|
SkillEntry(
|
|
8
178
|
slug="docker-workflow",
|
|
9
179
|
name="Docker — multi-stage builds, Compose, registries, security",
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Governance skills — project lifecycle, verification, review, and release."""
|
|
3
|
+
|
|
4
|
+
from specsmith.skills import SkillDomain, SkillEntry
|
|
5
|
+
|
|
6
|
+
SKILLS: list[SkillEntry] = [
|
|
7
|
+
SkillEntry(
|
|
8
|
+
slug="verifier",
|
|
9
|
+
name="Verifier — five-gate verification",
|
|
10
|
+
description=(
|
|
11
|
+
"Runs the standard five-gate loop: ruff, mypy, pytest, pip-audit, "
|
|
12
|
+
"and specsmith audit/validate. Halts at the first failing gate."
|
|
13
|
+
),
|
|
14
|
+
domain=SkillDomain.GOVERNANCE,
|
|
15
|
+
tags=["verification", "ci", "python", "lint", "test", "security"],
|
|
16
|
+
project_types=["cli-python", "library-python", "backend-frontend"],
|
|
17
|
+
platforms=[],
|
|
18
|
+
prerequisites=["ruff", "mypy", "pytest", "pip-audit"],
|
|
19
|
+
body=(
|
|
20
|
+
"# Verifier Skill\n\n"
|
|
21
|
+
"## Purpose\n"
|
|
22
|
+
"Enforce a deterministic, ordered quality gate before any commit.\n\n"
|
|
23
|
+
"## Gates (run in strict order — halt at first failure)\n"
|
|
24
|
+
"1. `ruff check .` — zero lint errors.\n"
|
|
25
|
+
"2. `ruff format --check src tests` — zero format drift.\n"
|
|
26
|
+
"3. `mypy src/` — zero type errors.\n"
|
|
27
|
+
"4. `pytest -q --tb=short` — all tests green.\n"
|
|
28
|
+
"5. `pip-audit` — no known vulnerabilities.\n"
|
|
29
|
+
"6. `specsmith audit && specsmith validate --strict` — governance clean.\n\n"
|
|
30
|
+
"## Rules\n"
|
|
31
|
+
"- Never skip a gate. Never amend a commit to bypass failures.\n"
|
|
32
|
+
"- Surface the first failing gate's output verbatim in your response.\n"
|
|
33
|
+
"- If gate 6 fails with a sync-drift warning, run `specsmith sync` first.\n\n"
|
|
34
|
+
"## After all gates pass\n"
|
|
35
|
+
'```\nspecsmith ledger add "All gates passed — ready to commit"\n'
|
|
36
|
+
'git add -A && git commit -m "<msg>"\n```\n'
|
|
37
|
+
),
|
|
38
|
+
),
|
|
39
|
+
SkillEntry(
|
|
40
|
+
slug="planner",
|
|
41
|
+
name="Planner — propose-then-execute",
|
|
42
|
+
description=(
|
|
43
|
+
"Forces the agent to emit a Plan block with explicit success criteria "
|
|
44
|
+
"before any tool call. Each step is gated on prior-step success."
|
|
45
|
+
),
|
|
46
|
+
domain=SkillDomain.GOVERNANCE,
|
|
47
|
+
tags=["planning", "governance", "aee"],
|
|
48
|
+
prerequisites=[],
|
|
49
|
+
body=(
|
|
50
|
+
"# Planner Skill\n\n"
|
|
51
|
+
"## Purpose\n"
|
|
52
|
+
"Prevent surprise changes. All work must be planned before execution.\n\n"
|
|
53
|
+
"## Protocol\n"
|
|
54
|
+
"1. Emit a `Plan:` block listing each step with a measurable success criterion.\n"
|
|
55
|
+
"2. Wait for user confirmation (`safe` profile) or proceed (`yolo` profile).\n"
|
|
56
|
+
"3. Execute steps one at a time; update `status: done | failed` after each.\n"
|
|
57
|
+
"4. Never call tools outside the plan. If new work is discovered, amend the plan.\n"
|
|
58
|
+
"5. Log plan completion to LEDGER.md.\n\n"
|
|
59
|
+
"## Plan block format\n"
|
|
60
|
+
"```\nPlan:\n 1. [step] — success: [criterion]\n"
|
|
61
|
+
" 2. [step] — success: [criterion]\n```\n"
|
|
62
|
+
),
|
|
63
|
+
),
|
|
64
|
+
SkillEntry(
|
|
65
|
+
slug="diff-reviewer",
|
|
66
|
+
name="Diff Reviewer — surface changes for approval",
|
|
67
|
+
description=(
|
|
68
|
+
"Emits a diff block per changed file and waits for Accept/Reject "
|
|
69
|
+
"before committing. Rejected diffs feed the next retry."
|
|
70
|
+
),
|
|
71
|
+
domain=SkillDomain.GOVERNANCE,
|
|
72
|
+
tags=["review", "diff", "governance", "approval"],
|
|
73
|
+
prerequisites=[],
|
|
74
|
+
body=(
|
|
75
|
+
"# Diff Reviewer Skill\n\n"
|
|
76
|
+
"## When to use\n"
|
|
77
|
+
"Any task that modifies source files, config, or governance docs.\n\n"
|
|
78
|
+
"## Protocol\n"
|
|
79
|
+
"1. Perform all changes in working tree (do not commit yet).\n"
|
|
80
|
+
"2. Run `git diff HEAD` and emit one fenced diff block per file.\n"
|
|
81
|
+
"3. Pause and wait for `accept` / `reject` / `comment` per diff.\n"
|
|
82
|
+
"4. For rejected diffs: revert that file, apply the comment as context, retry.\n"
|
|
83
|
+
"5. Only commit once every diff has been accepted.\n\n"
|
|
84
|
+
"## Rules\n"
|
|
85
|
+
"- Never auto-accept your own changes.\n"
|
|
86
|
+
"- Surface the full diff, not a summary. Summaries hide bugs.\n"
|
|
87
|
+
),
|
|
88
|
+
),
|
|
89
|
+
SkillEntry(
|
|
90
|
+
slug="onboarding-coach",
|
|
91
|
+
name="Onboarding Coach — guided first session",
|
|
92
|
+
description=(
|
|
93
|
+
"Walks a new user through the project: scaffold check, REQUIREMENTS "
|
|
94
|
+
"tour, AGENTS.md rules summary, and a suggested first action."
|
|
95
|
+
),
|
|
96
|
+
domain=SkillDomain.GOVERNANCE,
|
|
97
|
+
tags=["onboarding", "documentation", "new-user"],
|
|
98
|
+
prerequisites=["specsmith"],
|
|
99
|
+
body=(
|
|
100
|
+
"# Onboarding Coach Skill\n\n"
|
|
101
|
+
"## Sequence\n"
|
|
102
|
+
"1. `specsmith doctor --onboarding` — surface any missing setup step.\n"
|
|
103
|
+
"2. Read `AGENTS.md`; summarise hard rules in ≤ 5 bullets.\n"
|
|
104
|
+
"3. Read `docs/REQUIREMENTS.md`; list top 5 P1 requirements.\n"
|
|
105
|
+
"4. `specsmith phase show` — report current AEE phase and readiness %.\n"
|
|
106
|
+
"5. Suggest one concrete preflight utterance the user can run next.\n\n"
|
|
107
|
+
"## Output format\n"
|
|
108
|
+
"```\n🌱 Phase: <phase> (<pct>% ready)\n"
|
|
109
|
+
"📋 Top requirements: ...\n📌 Rules: ...\n"
|
|
110
|
+
'→ Suggested next: specsmith preflight "..."\n```\n'
|
|
111
|
+
),
|
|
112
|
+
),
|
|
113
|
+
SkillEntry(
|
|
114
|
+
slug="release-pilot",
|
|
115
|
+
name="Release Pilot — gitflow release cut",
|
|
116
|
+
description=(
|
|
117
|
+
"Drives a full gitflow release: CI green check, version bump, "
|
|
118
|
+
"CHANGELOG entry, tag, and publish."
|
|
119
|
+
),
|
|
120
|
+
domain=SkillDomain.GOVERNANCE,
|
|
121
|
+
tags=["release", "vcs", "gitflow", "automation", "pypi", "github"],
|
|
122
|
+
prerequisites=["gh", "git"],
|
|
123
|
+
body=(
|
|
124
|
+
"# Release Pilot Skill\n\n"
|
|
125
|
+
"## Preconditions (abort if any fail)\n"
|
|
126
|
+
"- `gh run list --branch develop --limit 1 --json conclusion` = `SUCCESS`.\n"
|
|
127
|
+
"- `gh pr list --state open --base main` returns 0 open PRs.\n"
|
|
128
|
+
"- `CHANGELOG.md` has the new version section already drafted.\n"
|
|
129
|
+
"- `specsmith audit && specsmith validate --strict` clean on develop.\n\n"
|
|
130
|
+
"## Sequence\n"
|
|
131
|
+
"1. Bump version: `specsmith release <version>`.\n"
|
|
132
|
+
"2. `git add -A && git commit -m 'release: v<version>'`.\n"
|
|
133
|
+
"3. Push develop: `git push origin develop`.\n"
|
|
134
|
+
"4. Wait for CI: `gh run watch`.\n"
|
|
135
|
+
"5. Merge to main: `git checkout main && git merge --ff-only develop`.\n"
|
|
136
|
+
"6. Tag: `git tag -a v<version> -m 'v<version>'`.\n"
|
|
137
|
+
"7. Push: `git push origin main --tags`.\n"
|
|
138
|
+
"8. Release workflow handles PyPI upload + GitHub Release automatically.\n\n"
|
|
139
|
+
"## Rollback\n"
|
|
140
|
+
"If step 7 fails: `git tag -d v<version> && git reset --hard HEAD~1`.\n"
|
|
141
|
+
),
|
|
142
|
+
),
|
|
143
|
+
SkillEntry(
|
|
144
|
+
slug="chronomemory-esdb",
|
|
145
|
+
name="ChronoMemory ESDB — epistemic state database (v0.1.1)",
|
|
146
|
+
description=(
|
|
147
|
+
"Full API reference and critical rules for chronomemory v0.1.1: "
|
|
148
|
+
"ChronoStore WAL, query module, ContextPackCompiler, DepGraph, "
|
|
149
|
+
"token metrics, skills system, and Rust acceleration."
|
|
150
|
+
),
|
|
151
|
+
domain=SkillDomain.GOVERNANCE,
|
|
152
|
+
tags=[
|
|
153
|
+
"esdb",
|
|
154
|
+
"chronomemory",
|
|
155
|
+
"epistemics",
|
|
156
|
+
"wal",
|
|
157
|
+
"persistence",
|
|
158
|
+
"context-pack",
|
|
159
|
+
"query",
|
|
160
|
+
"dep-graph",
|
|
161
|
+
"rollback",
|
|
162
|
+
"token-metrics",
|
|
163
|
+
"aee",
|
|
164
|
+
"anti-hallucination",
|
|
165
|
+
],
|
|
166
|
+
prerequisites=["chronomemory"],
|
|
167
|
+
body=(
|
|
168
|
+
"""\
|
|
169
|
+
# ChronoMemory ESDB Skill (v0.1.1)
|
|
170
|
+
|
|
171
|
+
EpiStemic State Database for Layer1Labs agentic projects.
|
|
172
|
+
WAL at `<root>/.chronomemory/events.wal` — NDJSON, append-only, SHA-256 chained.
|
|
173
|
+
|
|
174
|
+
## Imports
|
|
175
|
+
```python
|
|
176
|
+
from chronomemory import (
|
|
177
|
+
ChronoStore, ChronoRecord, WalEvent, open_store, # Core
|
|
178
|
+
EsdbBridge, # Backward-compat bridge
|
|
179
|
+
DepGraph, DependencyEdge, # Phase 2: dep graph
|
|
180
|
+
RollbackReport, invalidate, # Phase 2: rollback
|
|
181
|
+
ContextPack, ContextPackCompiler, ContextPackEntry, # Phase 2: context packs
|
|
182
|
+
RustChronoStore, RustRecord, RUST_BACKEND, # Phase 3: Rust (optional)
|
|
183
|
+
)
|
|
184
|
+
from chronomemory import query # 18 ESDB §23 query functions
|
|
185
|
+
from chronomemory import metrics # token metrics + skill system
|
|
186
|
+
|
|
187
|
+
# Or via specsmith.esdb namespace (preferred within specsmith code):
|
|
188
|
+
from specsmith.esdb import ChronoStore, query, metrics, ContextPackCompiler
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Critical rules — never break these
|
|
192
|
+
1. `dependencies = []` in pyproject.toml must stay empty — chronomemory is stdlib-only.
|
|
193
|
+
2. Never physically delete WAL records — always `store.delete(id)` (tombstone only).
|
|
194
|
+
3. Use `query.what_is_known(store)` not `store.query(rag_filter=True)` for LLM context
|
|
195
|
+
— the former excludes infra record kinds (edge, rollback_event, token_metric, skill_run).
|
|
196
|
+
4. Governance status (`defined`/`implemented`) ≠ ESDB status (`active`/`tombstone`)
|
|
197
|
+
— never conflate when migrating from `.specsmith/*.json`.
|
|
198
|
+
5. WAL is append-only NDJSON — one JSON object per line, SHA-256 chained.
|
|
199
|
+
|
|
200
|
+
## Core write/read
|
|
201
|
+
```python
|
|
202
|
+
with ChronoStore(project_root) as store:
|
|
203
|
+
store.upsert(ChronoRecord(
|
|
204
|
+
id="FACT-001", kind="fact",
|
|
205
|
+
label="CPSC projection is the sole validity authority",
|
|
206
|
+
source_type="observed", confidence=0.99,
|
|
207
|
+
evidence=["CPSC-Specification.md §9"],
|
|
208
|
+
))
|
|
209
|
+
store.delete("OLD-001") # tombstone only — never physically removes
|
|
210
|
+
store.chain_valid() # verify SHA-256 WAL integrity
|
|
211
|
+
|
|
212
|
+
# For LLM context — always use query.what_is_known (rule #3)
|
|
213
|
+
with ChronoStore(project_root) as store:
|
|
214
|
+
beliefs = query.what_is_known(store) # active, conf>=0.6, no infra records
|
|
215
|
+
hypotheses = query.what_requires_reverification(store)
|
|
216
|
+
done = query.has_this_work_been_done(store, "migrate flat JSON")
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Backward-compat bridge
|
|
220
|
+
```python
|
|
221
|
+
bridge = EsdbBridge(project_root)
|
|
222
|
+
bridge.status().backend # "ChronoStore WAL" or "json"
|
|
223
|
+
store.migrate_from_json(Path(project_root) / ".specsmith")
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Dependency graph
|
|
227
|
+
```python
|
|
228
|
+
g = DepGraph(store=store)
|
|
229
|
+
g.add_edge("HYP-001", "FACT-001", "depends_on")
|
|
230
|
+
# Valid edge types: assumes contradicts depends_on derived_from
|
|
231
|
+
# generated_from invalidates supports supersedes validated_by
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Epistemic rollback
|
|
235
|
+
```python
|
|
236
|
+
report = store.invalidate("FACT-001", "reason", dep_graph=g)
|
|
237
|
+
# Cascades depends_on/derived_from → status=hypothesis, confidence halved
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Context pack for LLM injection
|
|
241
|
+
```python
|
|
242
|
+
pack = ContextPackCompiler(store).compile(
|
|
243
|
+
task_id="TASK-42", goal="fix ruff errors", token_budget=4096
|
|
244
|
+
)
|
|
245
|
+
context_json = pack.to_dict() # inject into LLM context
|
|
246
|
+
# Excludes: tombstone/invalidated/hypothesis, conf<0.6, infra kinds, over-budget
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Query API (18 functions — all degrade gracefully without dep_graph)
|
|
250
|
+
```python
|
|
251
|
+
query.what_is_known(store) # active beliefs, no infra kinds
|
|
252
|
+
query.what_requires_reverification(store) # hypotheses needing confirmation
|
|
253
|
+
query.has_this_work_been_done(store, label) # bool — check prior decisions
|
|
254
|
+
query.why_do_we_believe(store, "FACT-001") # evidence chain for a record
|
|
255
|
+
query.what_skills_apply(store, "run lint") # skills matching task label
|
|
256
|
+
query.what_changed_since(store, seq) # records written after WAL seq N
|
|
257
|
+
query.what_confidence_collapsed(store, 0.6) # hypotheses below threshold
|
|
258
|
+
query.what_can_agent_do_next(store, goal) # unblocked action records
|
|
259
|
+
query.what_should_agent_not_do(store) # stop_condition records
|
|
260
|
+
query.is_this_action_duplicate(store, label) # alias for has_this_work_been_done
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Token metrics
|
|
264
|
+
```python
|
|
265
|
+
metrics.record_token_metric(
|
|
266
|
+
store, task_id="TASK-1",
|
|
267
|
+
context_tokens=512, input_tokens=256, output_tokens=128,
|
|
268
|
+
tool_calls=4, elapsed_ms=1800, success=True,
|
|
269
|
+
)
|
|
270
|
+
metrics.token_efficiency_report(store) # {tokens_per_success, avg_tool_calls, ...}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Skills system
|
|
274
|
+
```python
|
|
275
|
+
# Register a skill
|
|
276
|
+
store.upsert(ChronoRecord(
|
|
277
|
+
id="SKILL-ruff", kind="skill", label="ruff linter", confidence=0.9,
|
|
278
|
+
data={"activation": ["lint", "ruff", "python"]},
|
|
279
|
+
))
|
|
280
|
+
metrics.find_skills(store, "run ruff lint") # returns matching skill records
|
|
281
|
+
metrics.record_skill_run(store, "SKILL-ruff", # writes a skill_run WAL record
|
|
282
|
+
success=True, tokens_used=150, output={"errors": 0})
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Rust acceleration (Phase 3)
|
|
286
|
+
```python
|
|
287
|
+
from chronomemory import RUST_BACKEND
|
|
288
|
+
# False by default — requires: pip install maturin
|
|
289
|
+
# maturin develop --manifest-path crates/chronomemory-py/Cargo.toml
|
|
290
|
+
# When True, RustChronoStore and RustRecord are available.
|
|
291
|
+
print("Rust backend:", RUST_BACKEND)
|
|
292
|
+
```
|
|
293
|
+
"""
|
|
294
|
+
),
|
|
295
|
+
),
|
|
296
|
+
SkillEntry(
|
|
297
|
+
slug="gh-ci-polling",
|
|
298
|
+
name="GitHub Actions CI polling — smart wait with gh CLI",
|
|
299
|
+
description=(
|
|
300
|
+
"Poll GitHub Actions CI using gh run watch or gh run list with JSON output. "
|
|
301
|
+
"Never use sleep-based waiting. Covers: wait for run, check latest run status, "
|
|
302
|
+
"tail failure logs, and poll a specific job."
|
|
303
|
+
),
|
|
304
|
+
domain=SkillDomain.GOVERNANCE,
|
|
305
|
+
tags=[
|
|
306
|
+
"ci",
|
|
307
|
+
"github-actions",
|
|
308
|
+
"gh",
|
|
309
|
+
"polling",
|
|
310
|
+
"wait",
|
|
311
|
+
"workflow",
|
|
312
|
+
"devops",
|
|
313
|
+
],
|
|
314
|
+
prerequisites=["gh"],
|
|
315
|
+
body=(
|
|
316
|
+
"""\
|
|
317
|
+
# GitHub Actions CI Polling Skill
|
|
318
|
+
|
|
319
|
+
## Rule: NEVER sleep-wait for CI
|
|
320
|
+
Do NOT use `Start-Sleep`, `sleep`, `time.sleep`, or any fixed delay to wait
|
|
321
|
+
for CI. Always use `gh run watch` or poll with `gh run list --json`.
|
|
322
|
+
|
|
323
|
+
## 1. Wait for the most recent run on a branch to complete
|
|
324
|
+
```bash
|
|
325
|
+
# Blocks until the latest run finishes, then exits 0 (pass) or non-zero (fail)
|
|
326
|
+
gh run watch --repo <owner>/<repo> $(gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json databaseId --jq '.[0].databaseId')
|
|
327
|
+
```
|
|
328
|
+
```pwsh
|
|
329
|
+
# PowerShell equivalent
|
|
330
|
+
$runId = gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json databaseId | ConvertFrom-Json | Select-Object -ExpandProperty databaseId
|
|
331
|
+
gh run watch --repo <owner>/<repo> $runId
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## 2. Check status of the latest N runs (non-blocking)
|
|
335
|
+
```bash
|
|
336
|
+
gh run list --repo <owner>/<repo> --limit 3 --branch <branch>
|
|
337
|
+
# STATUS column: ✓ = success X = failure * = in_progress - = queued
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## 3. Check if latest run is complete and passed (scripted)
|
|
341
|
+
```bash
|
|
342
|
+
status=$(gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json conclusion --jq '.[0].conclusion')
|
|
343
|
+
echo "Conclusion: $status" # success | failure | cancelled | ""
|
|
344
|
+
# Empty string = still running
|
|
345
|
+
```
|
|
346
|
+
```pwsh
|
|
347
|
+
$status = gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json conclusion | ConvertFrom-Json | Select-Object -ExpandProperty conclusion
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## 4. Poll until complete (manual loop — use only when gh run watch unavailable)
|
|
351
|
+
```bash
|
|
352
|
+
while true; do
|
|
353
|
+
status=$(gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json status,conclusion --jq '.[0]')
|
|
354
|
+
running=$(echo $status | jq -r '.status')
|
|
355
|
+
conclusion=$(echo $status | jq -r '.conclusion')
|
|
356
|
+
if [ "$running" != "in_progress" ] && [ "$running" != "queued" ]; then
|
|
357
|
+
echo "Done: $conclusion"; break
|
|
358
|
+
fi
|
|
359
|
+
echo "Still running ($running)..."
|
|
360
|
+
sleep 15 # Only acceptable here — inside an explicit polling loop with state check
|
|
361
|
+
done
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## 5. View failure logs immediately
|
|
365
|
+
```bash
|
|
366
|
+
# Show only the failed step logs for the latest run
|
|
367
|
+
gh run view --repo <owner>/<repo> --log-failed $(gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json databaseId --jq '.[0].databaseId')
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## 6. Watch a specific run ID
|
|
371
|
+
```bash
|
|
372
|
+
gh run watch --repo <owner>/<repo> <run-id> # blocks, streams progress
|
|
373
|
+
gh run view --repo <owner>/<repo> <run-id> # snapshot of current state
|
|
374
|
+
gh run view --repo <owner>/<repo> <run-id> --log-failed # failure logs only
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Extracting run IDs after a push
|
|
378
|
+
```bash
|
|
379
|
+
# Get the run triggered by the most recent push
|
|
380
|
+
gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json databaseId,status,name
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Key rules
|
|
384
|
+
- `gh run watch` is the correct primitive — it polls internally and exits when done.
|
|
385
|
+
- Never substitute `sleep N; gh run list` for `gh run watch`.
|
|
386
|
+
- If `gh run watch` is unavailable (older gh version), use the polling loop in §4
|
|
387
|
+
with a minimum 15-second interval and an explicit status check, NOT a fixed sleep.
|
|
388
|
+
- Always check `conclusion` (not just `status`) to determine pass/fail.
|
|
389
|
+
`status=completed` with `conclusion=failure` is a failure.
|
|
390
|
+
"""
|
|
391
|
+
),
|
|
392
|
+
),
|
|
393
|
+
SkillEntry(
|
|
394
|
+
slug="issue-triage",
|
|
395
|
+
name="Issue Triage — classify and prioritise GitHub issues",
|
|
396
|
+
description=(
|
|
397
|
+
"Reads open GitHub issues, deduplicates, labels by type/severity, "
|
|
398
|
+
"and produces a prioritised action list."
|
|
399
|
+
),
|
|
400
|
+
domain=SkillDomain.GOVERNANCE,
|
|
401
|
+
tags=["github", "issues", "triage", "project-management"],
|
|
402
|
+
prerequisites=["gh", "specsmith"],
|
|
403
|
+
body=(
|
|
404
|
+
"# Issue Triage Skill\n\n"
|
|
405
|
+
"## Sequence\n"
|
|
406
|
+
"1. `gh issue list --state open --limit 100 --json number,title,labels,createdAt`\n"
|
|
407
|
+
"2. Group by type: bug / enhancement / question / docs.\n"
|
|
408
|
+
"3. Detect duplicates: flag issues with >60% title-word overlap.\n"
|
|
409
|
+
"4. Score severity: crash/data-loss = P0; broken feature = P1;"
|
|
410
|
+
" UX = P2; nice-to-have = P3.\n"
|
|
411
|
+
"5. Emit a prioritised table: `| # | Title | Type | Severity | Duplicate of |`\n"
|
|
412
|
+
"6. Ask: 'Which should I implement first this session?'\n\n"
|
|
413
|
+
"## Rules\n"
|
|
414
|
+
"- Never close an issue without fixing it or explicitly marking as won't-fix.\n"
|
|
415
|
+
"- Link PRs: `gh issue develop <number> --checkout` creates a fix branch.\n"
|
|
416
|
+
),
|
|
417
|
+
),
|
|
418
|
+
]
|