specsmith 0.10.1.dev283__tar.gz → 0.10.1.dev291__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.10.1.dev283 → specsmith-0.10.1.dev291}/PKG-INFO +1 -1
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/pyproject.toml +1 -1
- specsmith-0.10.1.dev291/src/specsmith/agent/hf_sync.py +181 -0
- specsmith-0.10.1.dev291/src/specsmith/agent/spawner.py +92 -0
- specsmith-0.10.1.dev291/src/specsmith/agent/teams.py +103 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/cli.py +4 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/commands/intelligence.py +124 -0
- specsmith-0.10.1.dev291/src/specsmith/compliance.py +232 -0
- specsmith-0.10.1.dev291/src/specsmith/eval/__init__.py +111 -0
- specsmith-0.10.1.dev291/src/specsmith/eval/builtins.py +95 -0
- specsmith-0.10.1.dev291/src/specsmith/eval/runner.py +102 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/governance_logic.py +203 -0
- specsmith-0.10.1.dev291/src/specsmith/session_init.py +280 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith.egg-info/PKG-INFO +1 -1
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith.egg-info/SOURCES.txt +10 -0
- specsmith-0.10.1.dev291/tests/test_intelligence.py +298 -0
- specsmith-0.10.1.dev291/tests/test_new_modules.py +260 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/LICENSE +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/README.md +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/setup.cfg +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/epistemic/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/epistemic/belief.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/epistemic/certainty.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/epistemic/py.typed +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/epistemic/recovery.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/epistemic/session.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/epistemic/trace.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/__main__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/architect.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/auditor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/auth.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/block_export.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/compressor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/config.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/context_window.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/credits.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/differ.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/doctor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/drive.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/editor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/executor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/exporter.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/history_search.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/importer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/instinct.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/languages.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/ledger.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/patent.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/paths.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/phase.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/plugins.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/profiles.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/releaser.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/requirements.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/serve.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/session.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/skills.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/sync.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/tools.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/trace.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/updater.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/validator.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith/workspace.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_CMD_001.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_auditor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_cli.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_compliance.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_compressor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_epistemic.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_importer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_integrations.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_mcp_client.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_nexus.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_permissions.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_rate_limits.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_scaffolder.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_smoke.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_suggester.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_tools.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_validator.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_vcs.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/tests/test_warp_parity.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev291}/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.10.1.
|
|
3
|
+
Version: 0.10.1.dev291
|
|
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.10.1.
|
|
7
|
+
version = "0.10.1.dev291"
|
|
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"
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
|
|
3
|
+
"""HuggingFace Open LLM Leaderboard sync for model intelligence (REQ-223).
|
|
4
|
+
|
|
5
|
+
Fetches benchmark scores from the HuggingFace API and populates
|
|
6
|
+
`.specsmith/model_scores.json` so that `rank_models_for_role()` uses
|
|
7
|
+
real data instead of hardcoded baselines.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from specsmith.agent.hf_sync import sync_scores
|
|
11
|
+
results = sync_scores() # returns dict of model_id -> {benchmark: score}
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import time
|
|
18
|
+
import urllib.request
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
# HF Inference API endpoint for model info
|
|
23
|
+
HF_API_BASE = "https://huggingface.co/api"
|
|
24
|
+
|
|
25
|
+
# Models we track (subset of popular models with known benchmark data)
|
|
26
|
+
TRACKED_MODELS: list[str] = [
|
|
27
|
+
"gpt-4.1",
|
|
28
|
+
"gpt-4.1-mini",
|
|
29
|
+
"gpt-4o",
|
|
30
|
+
"gpt-4o-mini",
|
|
31
|
+
"claude-sonnet-4-20250514",
|
|
32
|
+
"claude-3.5-sonnet",
|
|
33
|
+
"gemini-2.5-pro",
|
|
34
|
+
"gemini-2.5-flash",
|
|
35
|
+
"Qwen/Qwen2.5-Coder-32B-Instruct",
|
|
36
|
+
"Qwen/Qwen2.5-Coder-7B-Instruct",
|
|
37
|
+
"mistralai/Mistral-Large-Latest",
|
|
38
|
+
"meta-llama/Llama-3.3-70B-Instruct",
|
|
39
|
+
"deepseek-ai/DeepSeek-V3",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
# Default scores file path (relative to project root)
|
|
43
|
+
SCORES_FILENAME = "model_scores.json"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _scores_path(project_dir: str | Path = ".") -> Path:
|
|
47
|
+
return Path(project_dir).resolve() / ".specsmith" / SCORES_FILENAME
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def load_cached_scores(project_dir: str | Path = ".") -> dict[str, Any]:
|
|
51
|
+
"""Load cached model scores from disk."""
|
|
52
|
+
path = _scores_path(project_dir)
|
|
53
|
+
if not path.is_file():
|
|
54
|
+
return {}
|
|
55
|
+
try:
|
|
56
|
+
result: dict[str, Any] = json.loads(path.read_text(encoding="utf-8"))
|
|
57
|
+
return result
|
|
58
|
+
except (OSError, ValueError):
|
|
59
|
+
return {}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def save_scores(scores: dict[str, Any], project_dir: str | Path = ".") -> None:
|
|
63
|
+
"""Persist model scores to disk."""
|
|
64
|
+
path = _scores_path(project_dir)
|
|
65
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
66
|
+
data = {
|
|
67
|
+
"synced_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
|
68
|
+
"models": scores,
|
|
69
|
+
}
|
|
70
|
+
path.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def fetch_hf_model_info(model_id: str, timeout: int = 10) -> dict[str, Any]:
|
|
74
|
+
"""Fetch model metadata from HuggingFace API.
|
|
75
|
+
|
|
76
|
+
Returns a dict with model card data. On failure returns empty dict.
|
|
77
|
+
"""
|
|
78
|
+
url = f"{HF_API_BASE}/models/{model_id}"
|
|
79
|
+
try:
|
|
80
|
+
req = urllib.request.Request(url, headers={"Accept": "application/json"})
|
|
81
|
+
with urllib.request.urlopen(req, timeout=timeout) as resp: # noqa: S310
|
|
82
|
+
result: dict[str, Any] = json.loads(resp.read())
|
|
83
|
+
return result
|
|
84
|
+
except Exception: # noqa: BLE001
|
|
85
|
+
return {}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _extract_benchmark_scores(model_info: dict[str, Any]) -> dict[str, float]:
|
|
89
|
+
"""Extract benchmark scores from HF model card metadata.
|
|
90
|
+
|
|
91
|
+
Looks for eval_results in the model card data. Returns a dict of
|
|
92
|
+
benchmark_name -> score.
|
|
93
|
+
"""
|
|
94
|
+
scores: dict[str, float] = {}
|
|
95
|
+
# HF model cards store eval results in cardData.eval_results
|
|
96
|
+
card_data = model_info.get("cardData", {}) or {}
|
|
97
|
+
eval_results = card_data.get("eval_results", []) or []
|
|
98
|
+
for result in eval_results:
|
|
99
|
+
if not isinstance(result, dict):
|
|
100
|
+
continue
|
|
101
|
+
dataset = result.get("dataset", {})
|
|
102
|
+
name = dataset.get("name", "") if isinstance(dataset, dict) else str(dataset)
|
|
103
|
+
metrics = result.get("metrics", []) or []
|
|
104
|
+
for metric in metrics:
|
|
105
|
+
if isinstance(metric, dict):
|
|
106
|
+
metric_name = metric.get("name", "")
|
|
107
|
+
value = metric.get("value")
|
|
108
|
+
if metric_name and value is not None:
|
|
109
|
+
try:
|
|
110
|
+
key = f"{name}/{metric_name}" if name else metric_name
|
|
111
|
+
scores[key] = float(value)
|
|
112
|
+
except (TypeError, ValueError):
|
|
113
|
+
continue
|
|
114
|
+
return scores
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def sync_scores(
|
|
118
|
+
project_dir: str | Path = ".",
|
|
119
|
+
models: list[str] | None = None,
|
|
120
|
+
timeout: int = 10,
|
|
121
|
+
) -> dict[str, Any]:
|
|
122
|
+
"""Sync model scores from HuggingFace.
|
|
123
|
+
|
|
124
|
+
For HF-hosted models, fetches real benchmark data from model cards.
|
|
125
|
+
For proprietary models (GPT, Claude, Gemini), uses curated baselines.
|
|
126
|
+
|
|
127
|
+
Returns dict of model_id -> {benchmark: score}.
|
|
128
|
+
"""
|
|
129
|
+
from specsmith.agent.model_intelligence import BASELINE_SCORES
|
|
130
|
+
|
|
131
|
+
target_models = models or TRACKED_MODELS
|
|
132
|
+
all_scores: dict[str, Any] = {}
|
|
133
|
+
|
|
134
|
+
for model_id in target_models:
|
|
135
|
+
# For non-HF models, use baseline scores
|
|
136
|
+
if "/" not in model_id:
|
|
137
|
+
baseline = BASELINE_SCORES.get(model_id)
|
|
138
|
+
if baseline:
|
|
139
|
+
all_scores[model_id] = {"baseline_composite": baseline}
|
|
140
|
+
continue
|
|
141
|
+
|
|
142
|
+
# For HF models, try to fetch real data
|
|
143
|
+
info = fetch_hf_model_info(model_id, timeout=timeout)
|
|
144
|
+
if info:
|
|
145
|
+
benchmarks = _extract_benchmark_scores(info)
|
|
146
|
+
if benchmarks:
|
|
147
|
+
all_scores[model_id] = benchmarks
|
|
148
|
+
continue
|
|
149
|
+
|
|
150
|
+
# Fallback to baseline
|
|
151
|
+
baseline = BASELINE_SCORES.get(model_id)
|
|
152
|
+
if baseline:
|
|
153
|
+
all_scores[model_id] = {"baseline_composite": baseline}
|
|
154
|
+
|
|
155
|
+
save_scores(all_scores, project_dir)
|
|
156
|
+
return all_scores
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def is_stale(project_dir: str | Path = ".", max_age_hours: int = 24) -> bool:
|
|
160
|
+
"""Check if cached scores are older than max_age_hours."""
|
|
161
|
+
cached = load_cached_scores(project_dir)
|
|
162
|
+
synced_at = cached.get("synced_at", "")
|
|
163
|
+
if not synced_at:
|
|
164
|
+
return True
|
|
165
|
+
try:
|
|
166
|
+
from datetime import datetime, timezone
|
|
167
|
+
|
|
168
|
+
synced = datetime.fromisoformat(synced_at.replace("Z", "+00:00"))
|
|
169
|
+
age = datetime.now(timezone.utc) - synced
|
|
170
|
+
return age.total_seconds() > max_age_hours * 3600
|
|
171
|
+
except (ValueError, TypeError):
|
|
172
|
+
return True
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
__all__ = [
|
|
176
|
+
"fetch_hf_model_info",
|
|
177
|
+
"is_stale",
|
|
178
|
+
"load_cached_scores",
|
|
179
|
+
"save_scores",
|
|
180
|
+
"sync_scores",
|
|
181
|
+
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
|
|
3
|
+
"""Sub-agent spawner — spawn isolated agent workers with tool subsets.
|
|
4
|
+
|
|
5
|
+
ARCHITECTURE.md §13 Phase 2: Multi-Agent Layer.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class SpawnedAgent:
|
|
16
|
+
"""Metadata for a spawned sub-agent."""
|
|
17
|
+
|
|
18
|
+
id: str
|
|
19
|
+
role: str
|
|
20
|
+
tools: list[str]
|
|
21
|
+
status: str = "idle" # idle, running, completed, failed
|
|
22
|
+
result: dict[str, Any] = field(default_factory=dict)
|
|
23
|
+
|
|
24
|
+
def to_dict(self) -> dict[str, Any]:
|
|
25
|
+
return {
|
|
26
|
+
"id": self.id,
|
|
27
|
+
"role": self.role,
|
|
28
|
+
"tools": self.tools,
|
|
29
|
+
"status": self.status,
|
|
30
|
+
"result": self.result,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Tool subsets for different agent roles
|
|
35
|
+
ROLE_TOOLS: dict[str, list[str]] = {
|
|
36
|
+
"coder": ["read_file", "write_file", "run_shell", "apply_diff"],
|
|
37
|
+
"reviewer": ["read_file", "run_shell", "git_diff"],
|
|
38
|
+
"tester": ["read_file", "run_shell", "run_tests"],
|
|
39
|
+
"architect": ["read_file", "write_file"],
|
|
40
|
+
"researcher": ["read_file", "search_web", "search_repo"],
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SubAgentSpawner:
|
|
45
|
+
"""Spawn and manage isolated agent workers.
|
|
46
|
+
|
|
47
|
+
Each spawned agent gets a restricted tool subset based on its role,
|
|
48
|
+
preventing accidental cross-domain actions (e.g., a reviewer can't
|
|
49
|
+
write files).
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self) -> None:
|
|
53
|
+
self._agents: dict[str, SpawnedAgent] = {}
|
|
54
|
+
self._counter = 0
|
|
55
|
+
|
|
56
|
+
def spawn(self, role: str, tools: list[str] | None = None) -> SpawnedAgent:
|
|
57
|
+
"""Spawn a new sub-agent with the given role and tool set."""
|
|
58
|
+
self._counter += 1
|
|
59
|
+
agent_id = f"agent-{role}-{self._counter:03d}"
|
|
60
|
+
effective_tools = tools or ROLE_TOOLS.get(role, [])
|
|
61
|
+
agent = SpawnedAgent(id=agent_id, role=role, tools=effective_tools)
|
|
62
|
+
self._agents[agent_id] = agent
|
|
63
|
+
return agent
|
|
64
|
+
|
|
65
|
+
def get(self, agent_id: str) -> SpawnedAgent | None:
|
|
66
|
+
"""Get a spawned agent by ID."""
|
|
67
|
+
return self._agents.get(agent_id)
|
|
68
|
+
|
|
69
|
+
def list_active(self) -> list[SpawnedAgent]:
|
|
70
|
+
"""List all agents that are not completed/failed."""
|
|
71
|
+
return [a for a in self._agents.values() if a.status in ("idle", "running")]
|
|
72
|
+
|
|
73
|
+
def list_all(self) -> list[SpawnedAgent]:
|
|
74
|
+
"""List all spawned agents."""
|
|
75
|
+
return list(self._agents.values())
|
|
76
|
+
|
|
77
|
+
def complete(self, agent_id: str, result: dict[str, Any]) -> None:
|
|
78
|
+
"""Mark an agent as completed with its result."""
|
|
79
|
+
agent = self._agents.get(agent_id)
|
|
80
|
+
if agent:
|
|
81
|
+
agent.status = "completed"
|
|
82
|
+
agent.result = result
|
|
83
|
+
|
|
84
|
+
def fail(self, agent_id: str, error: str) -> None:
|
|
85
|
+
"""Mark an agent as failed."""
|
|
86
|
+
agent = self._agents.get(agent_id)
|
|
87
|
+
if agent:
|
|
88
|
+
agent.status = "failed"
|
|
89
|
+
agent.result = {"error": error}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
__all__ = ["ROLE_TOOLS", "SpawnedAgent", "SubAgentSpawner"]
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
|
|
3
|
+
"""Team definitions for multi-agent coordination.
|
|
4
|
+
|
|
5
|
+
ARCHITECTURE.md §13 Phase 2: predefined agent team compositions.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class TeamMember:
|
|
16
|
+
"""A role slot within a team."""
|
|
17
|
+
|
|
18
|
+
role: str
|
|
19
|
+
required: bool = True
|
|
20
|
+
tools_override: list[str] | None = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class TeamDefinition:
|
|
25
|
+
"""A named team of agent roles that work together."""
|
|
26
|
+
|
|
27
|
+
id: str
|
|
28
|
+
name: str
|
|
29
|
+
description: str
|
|
30
|
+
members: list[TeamMember] = field(default_factory=list)
|
|
31
|
+
|
|
32
|
+
def to_dict(self) -> dict[str, Any]:
|
|
33
|
+
return {
|
|
34
|
+
"id": self.id,
|
|
35
|
+
"name": self.name,
|
|
36
|
+
"description": self.description,
|
|
37
|
+
"members": [{"role": m.role, "required": m.required} for m in self.members],
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Pre-defined teams
|
|
42
|
+
PAIR_REVIEW = TeamDefinition(
|
|
43
|
+
id="pair-review",
|
|
44
|
+
name="Pair Review",
|
|
45
|
+
description="Coder + Reviewer pair for code changes with built-in review",
|
|
46
|
+
members=[
|
|
47
|
+
TeamMember(role="coder"),
|
|
48
|
+
TeamMember(role="reviewer"),
|
|
49
|
+
],
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
FULL_STACK = TeamDefinition(
|
|
53
|
+
id="full-stack",
|
|
54
|
+
name="Full Stack",
|
|
55
|
+
description="Architect + Coder + Tester trio for complete feature development",
|
|
56
|
+
members=[
|
|
57
|
+
TeamMember(role="architect"),
|
|
58
|
+
TeamMember(role="coder"),
|
|
59
|
+
TeamMember(role="tester"),
|
|
60
|
+
],
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
IP_ANALYSIS = TeamDefinition(
|
|
64
|
+
id="ip-analysis",
|
|
65
|
+
name="IP Analysis",
|
|
66
|
+
description="IP Analyst + Researcher + Strategist for patent work",
|
|
67
|
+
members=[
|
|
68
|
+
TeamMember(role="ip-analyst"),
|
|
69
|
+
TeamMember(role="researcher"),
|
|
70
|
+
TeamMember(role="strategist"),
|
|
71
|
+
],
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
SPEC_DRAFT = TeamDefinition(
|
|
75
|
+
id="spec-draft",
|
|
76
|
+
name="Specification Drafting",
|
|
77
|
+
description="Architect + Drafter + Reviewer for specification writing",
|
|
78
|
+
members=[
|
|
79
|
+
TeamMember(role="architect"),
|
|
80
|
+
TeamMember(role="drafter"),
|
|
81
|
+
TeamMember(role="reviewer"),
|
|
82
|
+
],
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
BUILTIN_TEAMS: dict[str, TeamDefinition] = {
|
|
86
|
+
"pair-review": PAIR_REVIEW,
|
|
87
|
+
"full-stack": FULL_STACK,
|
|
88
|
+
"ip-analysis": IP_ANALYSIS,
|
|
89
|
+
"spec-draft": SPEC_DRAFT,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_team(team_id: str) -> TeamDefinition | None:
|
|
94
|
+
"""Get a built-in team by ID."""
|
|
95
|
+
return BUILTIN_TEAMS.get(team_id)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def list_teams() -> list[TeamDefinition]:
|
|
99
|
+
"""List all available teams."""
|
|
100
|
+
return list(BUILTIN_TEAMS.values())
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
__all__ = ["BUILTIN_TEAMS", "TeamDefinition", "TeamMember", "get_team", "list_teams"]
|
|
@@ -7965,16 +7965,20 @@ main.add_command(rules_group)
|
|
|
7965
7965
|
# ---------------------------------------------------------------------------
|
|
7966
7966
|
try:
|
|
7967
7967
|
from specsmith.commands.intelligence import (
|
|
7968
|
+
compliance_group,
|
|
7968
7969
|
datasources_group,
|
|
7969
7970
|
models_group,
|
|
7970
7971
|
profiles_group,
|
|
7971
7972
|
providers_group,
|
|
7973
|
+
session_group,
|
|
7972
7974
|
)
|
|
7973
7975
|
|
|
7974
7976
|
main.add_command(providers_group)
|
|
7975
7977
|
main.add_command(profiles_group)
|
|
7976
7978
|
main.add_command(datasources_group)
|
|
7977
7979
|
main.add_command(models_group)
|
|
7980
|
+
main.add_command(compliance_group)
|
|
7981
|
+
main.add_command(session_group)
|
|
7978
7982
|
except Exception: # noqa: BLE001
|
|
7979
7983
|
pass # graceful degradation if commands module has issues
|
|
7980
7984
|
|
|
@@ -290,3 +290,127 @@ def models_rank(role: str, provider_type: str) -> None:
|
|
|
290
290
|
click.echo(f"Top models for '{role}':")
|
|
291
291
|
for model, score in ranked[:10]:
|
|
292
292
|
click.echo(f" {score:5.1f} {model}")
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
# ---------------------------------------------------------------------------
|
|
296
|
+
# specsmith compliance
|
|
297
|
+
# ---------------------------------------------------------------------------
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
@click.group("compliance")
|
|
301
|
+
def compliance_group() -> None:
|
|
302
|
+
"""Compliance scoring, gaps, and traceability."""
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@compliance_group.command("summary")
|
|
306
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
307
|
+
@click.option("--json-output", "as_json", is_flag=True)
|
|
308
|
+
def compliance_summary(project_dir: str, as_json: bool) -> None:
|
|
309
|
+
"""Show overall compliance score and coverage."""
|
|
310
|
+
from specsmith.compliance import get_compliance_summary
|
|
311
|
+
|
|
312
|
+
s = get_compliance_summary(project_dir)
|
|
313
|
+
if as_json:
|
|
314
|
+
click.echo(json.dumps(s.to_dict(), indent=2))
|
|
315
|
+
else:
|
|
316
|
+
click.echo(f" Requirements: {s.covered_requirements}/{s.total_requirements} covered")
|
|
317
|
+
click.echo(f" Tests: {s.total_tests}")
|
|
318
|
+
click.echo(f" Coverage: {s.requirement_coverage_pct}%")
|
|
319
|
+
click.echo(f" Score: {s.compliance_score}%")
|
|
320
|
+
if s.uncovered_requirements:
|
|
321
|
+
click.echo(f" Uncovered: {', '.join(s.uncovered_requirements[:10])}")
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
@compliance_group.command("gaps")
|
|
325
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
326
|
+
def compliance_gaps(project_dir: str) -> None:
|
|
327
|
+
"""Show uncovered requirements and orphaned tests."""
|
|
328
|
+
from specsmith.compliance import get_compliance_summary
|
|
329
|
+
|
|
330
|
+
s = get_compliance_summary(project_dir)
|
|
331
|
+
if s.uncovered_requirements:
|
|
332
|
+
click.echo(f"Uncovered requirements ({len(s.uncovered_requirements)}):")
|
|
333
|
+
for r in s.uncovered_requirements:
|
|
334
|
+
click.echo(f" \u2717 {r}")
|
|
335
|
+
else:
|
|
336
|
+
click.echo("\u2713 All requirements have test coverage.")
|
|
337
|
+
if s.orphaned_tests:
|
|
338
|
+
click.echo(f"\nOrphaned tests ({len(s.orphaned_tests)}):")
|
|
339
|
+
for t in s.orphaned_tests:
|
|
340
|
+
click.echo(f" \u26a0 {t}")
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@compliance_group.command("trace")
|
|
344
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
345
|
+
@click.option("--json-output", "as_json", is_flag=True)
|
|
346
|
+
def compliance_trace(project_dir: str, as_json: bool) -> None:
|
|
347
|
+
"""Show REQ \u2192 TEST traceability matrix."""
|
|
348
|
+
from specsmith.compliance import get_compliance_summary
|
|
349
|
+
|
|
350
|
+
s = get_compliance_summary(project_dir)
|
|
351
|
+
if as_json:
|
|
352
|
+
click.echo(json.dumps(s.trace_matrix, indent=2))
|
|
353
|
+
else:
|
|
354
|
+
for entry in s.trace_matrix:
|
|
355
|
+
icon = "\u2713" if entry["covered"] else "\u2717"
|
|
356
|
+
tests = ", ".join(entry["tests"]) if entry["tests"] else "(none)"
|
|
357
|
+
click.echo(f" {icon} {entry['requirement_id']:<12} \u2192 {tests}")
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@compliance_group.command("rules")
|
|
361
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
362
|
+
def compliance_rules(project_dir: str) -> None:
|
|
363
|
+
"""Show governance hard rules status (H1-H14)."""
|
|
364
|
+
from specsmith.compliance import get_governance_rules_status
|
|
365
|
+
|
|
366
|
+
rules = get_governance_rules_status(project_dir)
|
|
367
|
+
for r in rules:
|
|
368
|
+
icon = {"ok": "\u2713", "warning": "\u26a0", "violation": "\u2717"}.get(r["status"], "?")
|
|
369
|
+
click.echo(f" {icon} {r['id']}: {r['name']}")
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
# ---------------------------------------------------------------------------
|
|
373
|
+
# specsmith session
|
|
374
|
+
# ---------------------------------------------------------------------------
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
@click.group("session")
|
|
378
|
+
def session_group() -> None:
|
|
379
|
+
"""Session lifecycle management."""
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
@session_group.command("info")
|
|
383
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
384
|
+
@click.option("--json-output", "as_json", is_flag=True)
|
|
385
|
+
def session_info(project_dir: str, as_json: bool) -> None:
|
|
386
|
+
"""Show current session context."""
|
|
387
|
+
from specsmith.session_init import init_session
|
|
388
|
+
|
|
389
|
+
ctx = init_session(project_dir)
|
|
390
|
+
if as_json:
|
|
391
|
+
click.echo(json.dumps(ctx.to_dict(), indent=2))
|
|
392
|
+
else:
|
|
393
|
+
gov = "\u2713" if ctx.is_governed else "\u2717"
|
|
394
|
+
click.echo(f" Project: {ctx.project_name}")
|
|
395
|
+
click.echo(f" Governed: {gov}")
|
|
396
|
+
phase = ctx.phase_emoji
|
|
397
|
+
label = ctx.phase_label
|
|
398
|
+
pct = ctx.phase_readiness_pct
|
|
399
|
+
click.echo(f" Phase: {phase} {label} ({pct}%)")
|
|
400
|
+
click.echo(f" Health: {ctx.health_score}%")
|
|
401
|
+
click.echo(f" Compliance: {ctx.compliance_score}%")
|
|
402
|
+
click.echo(f" Profile: {ctx.active_profile}")
|
|
403
|
+
rp = ctx.reachable_providers
|
|
404
|
+
pc = ctx.provider_count
|
|
405
|
+
click.echo(f" Providers: {rp}/{pc} reachable")
|
|
406
|
+
click.echo(f" Session: {ctx.session_id}")
|
|
407
|
+
if ctx.needs_import:
|
|
408
|
+
click.echo(
|
|
409
|
+
"\n \u26a0 Not a specsmith project. Run 'specsmith import' to add governance."
|
|
410
|
+
)
|
|
411
|
+
if ctx.needs_migration:
|
|
412
|
+
sv = ctx.spec_version
|
|
413
|
+
iv = ctx.installed_version
|
|
414
|
+
click.echo(
|
|
415
|
+
f"\n \u26a0 Spec version mismatch ({sv} vs {iv}). Run 'specsmith migrate-project'."
|
|
416
|
+
)
|