specsmith 0.10.1.dev283__tar.gz → 0.10.1.dev287__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.dev287}/PKG-INFO +1 -1
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/pyproject.toml +1 -1
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/cli.py +4 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/commands/intelligence.py +124 -0
- specsmith-0.10.1.dev287/src/specsmith/compliance.py +232 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/governance_logic.py +145 -0
- specsmith-0.10.1.dev287/src/specsmith/session_init.py +280 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/PKG-INFO +1 -1
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/SOURCES.txt +3 -0
- specsmith-0.10.1.dev287/tests/test_intelligence.py +298 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/LICENSE +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/README.md +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/setup.cfg +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/belief.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/certainty.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/py.typed +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/recovery.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/session.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/trace.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/__main__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/architect.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/auditor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/auth.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/block_export.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/compressor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/config.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/context_window.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/credits.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/differ.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/doctor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/drive.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/editor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/executor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/exporter.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/history_search.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/importer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/instinct.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/languages.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/ledger.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/patent.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/paths.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/phase.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/plugins.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/profiles.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/releaser.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/requirements.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/serve.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/session.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/skills.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/sync.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/tools.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/trace.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/updater.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/validator.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/workspace.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_CMD_001.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_auditor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_cli.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_compliance.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_compressor.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_epistemic.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_importer.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_integrations.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_mcp_client.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_nexus.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_permissions.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_rate_limits.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_scaffolder.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_smoke.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_suggester.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_tools.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_validator.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_vcs.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_warp_parity.py +0 -0
- {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/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.dev287
|
|
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.dev287"
|
|
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"
|
|
@@ -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
|
+
)
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
|
|
3
|
+
"""Compliance scoring and reporting (REQ-224).
|
|
4
|
+
|
|
5
|
+
Provides compliance summary, requirement gaps, test coverage, and
|
|
6
|
+
traceability matrix. Used by both CLI commands and REST endpoints.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import re
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ComplianceSummary:
|
|
19
|
+
"""Overall compliance status for a project."""
|
|
20
|
+
|
|
21
|
+
total_requirements: int = 0
|
|
22
|
+
covered_requirements: int = 0
|
|
23
|
+
uncovered_requirements: list[str] = field(default_factory=list)
|
|
24
|
+
total_tests: int = 0
|
|
25
|
+
orphaned_tests: list[str] = field(default_factory=list)
|
|
26
|
+
compliance_score: int = 0 # 0-100
|
|
27
|
+
requirement_coverage_pct: int = 0
|
|
28
|
+
trace_matrix: list[dict[str, Any]] = field(default_factory=list)
|
|
29
|
+
|
|
30
|
+
def to_dict(self) -> dict[str, Any]:
|
|
31
|
+
return {
|
|
32
|
+
"total_requirements": self.total_requirements,
|
|
33
|
+
"covered_requirements": self.covered_requirements,
|
|
34
|
+
"uncovered_requirements": self.uncovered_requirements,
|
|
35
|
+
"total_tests": self.total_tests,
|
|
36
|
+
"orphaned_tests": self.orphaned_tests,
|
|
37
|
+
"compliance_score": self.compliance_score,
|
|
38
|
+
"requirement_coverage_pct": self.requirement_coverage_pct,
|
|
39
|
+
"trace_count": len(self.trace_matrix),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _parse_requirements(root: Path) -> dict[str, dict[str, str]]:
|
|
44
|
+
"""Parse REQUIREMENTS.md into {req_id: {title, status, ...}}."""
|
|
45
|
+
req_path = root / "docs" / "REQUIREMENTS.md"
|
|
46
|
+
if not req_path.is_file():
|
|
47
|
+
req_path = root / "REQUIREMENTS.md"
|
|
48
|
+
if not req_path.is_file():
|
|
49
|
+
return {}
|
|
50
|
+
|
|
51
|
+
text = req_path.read_text(encoding="utf-8", errors="replace")
|
|
52
|
+
reqs: dict[str, dict[str, str]] = {}
|
|
53
|
+
|
|
54
|
+
# Parse markdown sections: ## N. Title\n- **ID:** REQ-NNN
|
|
55
|
+
blocks = re.split(r"\n## ", text)
|
|
56
|
+
for block in blocks:
|
|
57
|
+
id_match = re.search(r"\*\*ID:\*\*\s*(REQ-\d+)", block)
|
|
58
|
+
if not id_match:
|
|
59
|
+
# Try alternate format: ## REQ-NNN
|
|
60
|
+
id_match = re.search(r"^(REQ-\d+)", block.strip())
|
|
61
|
+
if id_match:
|
|
62
|
+
req_id = id_match.group(1)
|
|
63
|
+
title_match = re.search(r"\*\*Title:\*\*\s*(.+)", block)
|
|
64
|
+
status_match = re.search(r"\*\*Status:\*\*\s*(.+)", block)
|
|
65
|
+
reqs[req_id] = {
|
|
66
|
+
"id": req_id,
|
|
67
|
+
"title": title_match.group(1).strip() if title_match else "",
|
|
68
|
+
"status": status_match.group(1).strip() if status_match else "draft",
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return reqs
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _parse_tests(root: Path) -> dict[str, dict[str, str]]:
|
|
75
|
+
"""Parse TESTS.md into {test_id: {title, requirement_id, ...}}."""
|
|
76
|
+
test_path = root / "docs" / "TESTS.md"
|
|
77
|
+
if not test_path.is_file():
|
|
78
|
+
test_path = root / "TESTS.md"
|
|
79
|
+
if not test_path.is_file():
|
|
80
|
+
return {}
|
|
81
|
+
|
|
82
|
+
text = test_path.read_text(encoding="utf-8", errors="replace")
|
|
83
|
+
tests: dict[str, dict[str, str]] = {}
|
|
84
|
+
|
|
85
|
+
blocks = re.split(r"\n## ", text)
|
|
86
|
+
for block in blocks:
|
|
87
|
+
id_match = re.search(r"\*\*ID:\*\*\s*(TEST-\d+)", block)
|
|
88
|
+
if not id_match:
|
|
89
|
+
id_match = re.search(r"^(TEST-\d+)", block.strip())
|
|
90
|
+
if id_match:
|
|
91
|
+
test_id = id_match.group(1)
|
|
92
|
+
req_match = re.search(r"\*\*Requirement(?:\s+ID)?:\*\*\s*(REQ-\d+)", block)
|
|
93
|
+
title_match = re.search(r"\*\*Title:\*\*\s*(.+)", block)
|
|
94
|
+
tests[test_id] = {
|
|
95
|
+
"id": test_id,
|
|
96
|
+
"title": title_match.group(1).strip() if title_match else "",
|
|
97
|
+
"requirement_id": req_match.group(1) if req_match else "",
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return tests
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_compliance_summary(project_dir: str | Path = ".") -> ComplianceSummary:
|
|
104
|
+
"""Compute full compliance summary for a project."""
|
|
105
|
+
root = Path(project_dir).resolve()
|
|
106
|
+
reqs = _parse_requirements(root)
|
|
107
|
+
tests = _parse_tests(root)
|
|
108
|
+
|
|
109
|
+
# Build coverage map
|
|
110
|
+
covered_req_ids: set[str] = set()
|
|
111
|
+
for test in tests.values():
|
|
112
|
+
req_id = test.get("requirement_id", "")
|
|
113
|
+
if req_id and req_id in reqs:
|
|
114
|
+
covered_req_ids.add(req_id)
|
|
115
|
+
|
|
116
|
+
uncovered = [r for r in reqs if r not in covered_req_ids]
|
|
117
|
+
|
|
118
|
+
# Find orphaned tests (reference non-existent requirements)
|
|
119
|
+
orphaned = []
|
|
120
|
+
for test in tests.values():
|
|
121
|
+
req_id = test.get("requirement_id", "")
|
|
122
|
+
if req_id and req_id not in reqs:
|
|
123
|
+
orphaned.append(f"{test['id']} -> {req_id}")
|
|
124
|
+
|
|
125
|
+
total = len(reqs)
|
|
126
|
+
covered = len(covered_req_ids)
|
|
127
|
+
coverage_pct = int(covered / total * 100) if total > 0 else 0
|
|
128
|
+
|
|
129
|
+
# Build trace matrix
|
|
130
|
+
trace: list[dict[str, Any]] = []
|
|
131
|
+
for req_id, req in sorted(reqs.items()):
|
|
132
|
+
linked_tests = [t["id"] for t in tests.values() if t.get("requirement_id") == req_id]
|
|
133
|
+
trace.append(
|
|
134
|
+
{
|
|
135
|
+
"requirement_id": req_id,
|
|
136
|
+
"title": req.get("title", ""),
|
|
137
|
+
"status": req.get("status", ""),
|
|
138
|
+
"tests": linked_tests,
|
|
139
|
+
"covered": len(linked_tests) > 0,
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
return ComplianceSummary(
|
|
144
|
+
total_requirements=total,
|
|
145
|
+
covered_requirements=covered,
|
|
146
|
+
uncovered_requirements=uncovered,
|
|
147
|
+
total_tests=len(tests),
|
|
148
|
+
orphaned_tests=orphaned,
|
|
149
|
+
compliance_score=coverage_pct,
|
|
150
|
+
requirement_coverage_pct=coverage_pct,
|
|
151
|
+
trace_matrix=trace,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def get_governance_rules_status(project_dir: str | Path = ".") -> list[dict[str, Any]]:
|
|
156
|
+
"""Return status of hard governance rules (H1-H14)."""
|
|
157
|
+
root = Path(project_dir).resolve()
|
|
158
|
+
|
|
159
|
+
rules = [
|
|
160
|
+
{"id": "H1", "name": "Ledger required", "description": "No ledger entry = work not done"},
|
|
161
|
+
{"id": "H2", "name": "Proposal required", "description": "No proposal = no execution"},
|
|
162
|
+
{
|
|
163
|
+
"id": "H3",
|
|
164
|
+
"name": "Cross-platform awareness",
|
|
165
|
+
"description": "All work must consider every target platform",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"id": "H4",
|
|
169
|
+
"name": "Environment isolation",
|
|
170
|
+
"description": "No system-dependent assumptions",
|
|
171
|
+
},
|
|
172
|
+
{"id": "H5", "name": "Explicit startup", "description": "No hidden service logic"},
|
|
173
|
+
{
|
|
174
|
+
"id": "H6",
|
|
175
|
+
"name": "No silent scope expansion",
|
|
176
|
+
"description": "If task grows, stop and re-propose",
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"id": "H7",
|
|
180
|
+
"name": "No undocumented state changes",
|
|
181
|
+
"description": "Every change must be traceable",
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"id": "H8",
|
|
185
|
+
"name": "Documentation is implementation",
|
|
186
|
+
"description": "Architecture changes MUST update docs",
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"id": "H9",
|
|
190
|
+
"name": "Execution timeout required",
|
|
191
|
+
"description": "All agent commands must have timeouts",
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"id": "H10",
|
|
195
|
+
"name": "No hardcoded versions",
|
|
196
|
+
"description": "Use importlib.metadata at runtime",
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"id": "H11",
|
|
200
|
+
"name": "No unbounded loops",
|
|
201
|
+
"description": "Every loop must have a deadline",
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"id": "H12",
|
|
205
|
+
"name": "Windows automation via .cmd",
|
|
206
|
+
"description": "Multi-step automation uses .cmd files",
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"id": "H13",
|
|
210
|
+
"name": "Epistemic boundaries required",
|
|
211
|
+
"description": "Proposals must state assumptions",
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"id": "H14",
|
|
215
|
+
"name": "Documentation freshness",
|
|
216
|
+
"description": "Docs updated in same commit as code",
|
|
217
|
+
},
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
# Quick checks for common violations
|
|
221
|
+
ledger_exists = (root / "docs" / "LEDGER.md").is_file() or (root / "LEDGER.md").is_file()
|
|
222
|
+
agents_exists = (root / "AGENTS.md").is_file()
|
|
223
|
+
|
|
224
|
+
for rule in rules:
|
|
225
|
+
rule["status"] = "ok" # default
|
|
226
|
+
|
|
227
|
+
if not ledger_exists:
|
|
228
|
+
rules[0]["status"] = "violation"
|
|
229
|
+
if not agents_exists:
|
|
230
|
+
rules[1]["status"] = "warning"
|
|
231
|
+
|
|
232
|
+
return rules
|
|
@@ -485,6 +485,151 @@ class GovernanceHTTPServer:
|
|
|
485
485
|
|
|
486
486
|
if self.path in ("/health", "/api/health"):
|
|
487
487
|
self._json_ok({"status": "ok", "version": __version__})
|
|
488
|
+
|
|
489
|
+
# ── Session ────────────────────────────────────────────
|
|
490
|
+
elif self.path == "/api/session":
|
|
491
|
+
try:
|
|
492
|
+
from specsmith.session_init import init_session
|
|
493
|
+
|
|
494
|
+
ctx = init_session(project_dir)
|
|
495
|
+
self._json_ok(ctx.to_dict())
|
|
496
|
+
except Exception as exc: # noqa: BLE001
|
|
497
|
+
self._json_err(str(exc), code=500)
|
|
498
|
+
|
|
499
|
+
# ── Compliance ─────────────────────────────────────────
|
|
500
|
+
elif self.path == "/api/compliance/summary":
|
|
501
|
+
try:
|
|
502
|
+
from specsmith.compliance import get_compliance_summary
|
|
503
|
+
|
|
504
|
+
s = get_compliance_summary(project_dir)
|
|
505
|
+
self._json_ok(s.to_dict())
|
|
506
|
+
except Exception as exc: # noqa: BLE001
|
|
507
|
+
self._json_err(str(exc), code=500)
|
|
508
|
+
elif self.path == "/api/compliance/gaps":
|
|
509
|
+
try:
|
|
510
|
+
from specsmith.compliance import get_compliance_summary
|
|
511
|
+
|
|
512
|
+
s = get_compliance_summary(project_dir)
|
|
513
|
+
self._json_ok(
|
|
514
|
+
{"uncovered": s.uncovered_requirements, "orphaned": s.orphaned_tests}
|
|
515
|
+
)
|
|
516
|
+
except Exception as exc: # noqa: BLE001
|
|
517
|
+
self._json_err(str(exc), code=500)
|
|
518
|
+
elif self.path == "/api/compliance/trace":
|
|
519
|
+
try:
|
|
520
|
+
from specsmith.compliance import get_compliance_summary
|
|
521
|
+
|
|
522
|
+
s = get_compliance_summary(project_dir)
|
|
523
|
+
self._json_ok({"trace_matrix": s.trace_matrix})
|
|
524
|
+
except Exception as exc: # noqa: BLE001
|
|
525
|
+
self._json_err(str(exc), code=500)
|
|
526
|
+
|
|
527
|
+
# ── Governance ─────────────────────────────────────────
|
|
528
|
+
elif self.path == "/api/governance/rules":
|
|
529
|
+
try:
|
|
530
|
+
from specsmith.compliance import get_governance_rules_status
|
|
531
|
+
|
|
532
|
+
self._json_ok({"rules": get_governance_rules_status(project_dir)})
|
|
533
|
+
except Exception as exc: # noqa: BLE001
|
|
534
|
+
self._json_err(str(exc), code=500)
|
|
535
|
+
elif self.path == "/api/governance/phase":
|
|
536
|
+
try:
|
|
537
|
+
from specsmith.phase import PHASE_MAP, phase_progress_pct, read_phase
|
|
538
|
+
|
|
539
|
+
root = Path(project_dir).resolve()
|
|
540
|
+
key = read_phase(root)
|
|
541
|
+
phase = PHASE_MAP[key]
|
|
542
|
+
self._json_ok(
|
|
543
|
+
{
|
|
544
|
+
"phase": key,
|
|
545
|
+
"label": phase.label,
|
|
546
|
+
"emoji": phase.emoji,
|
|
547
|
+
"readiness_pct": phase_progress_pct(phase, root),
|
|
548
|
+
}
|
|
549
|
+
)
|
|
550
|
+
except Exception as exc: # noqa: BLE001
|
|
551
|
+
self._json_err(str(exc), code=500)
|
|
552
|
+
elif self.path == "/api/governance/audit":
|
|
553
|
+
try:
|
|
554
|
+
from specsmith.auditor import run_audit
|
|
555
|
+
|
|
556
|
+
report = run_audit(Path(project_dir).resolve())
|
|
557
|
+
self._json_ok(
|
|
558
|
+
{
|
|
559
|
+
"healthy": report.healthy,
|
|
560
|
+
"passed": report.passed,
|
|
561
|
+
"failed": report.failed,
|
|
562
|
+
"results": [
|
|
563
|
+
{"passed": r.passed, "message": r.message}
|
|
564
|
+
for r in report.results
|
|
565
|
+
],
|
|
566
|
+
}
|
|
567
|
+
)
|
|
568
|
+
except Exception as exc: # noqa: BLE001
|
|
569
|
+
self._json_err(str(exc), code=500)
|
|
570
|
+
|
|
571
|
+
# ── Providers ──────────────────────────────────────────
|
|
572
|
+
elif self.path == "/api/providers":
|
|
573
|
+
try:
|
|
574
|
+
from specsmith.agent.provider_registry import ProviderRegistry
|
|
575
|
+
|
|
576
|
+
reg = ProviderRegistry.load()
|
|
577
|
+
self._json_ok({"providers": [p.to_public_dict() for p in reg.providers]})
|
|
578
|
+
except Exception as exc: # noqa: BLE001
|
|
579
|
+
self._json_err(str(exc), code=500)
|
|
580
|
+
|
|
581
|
+
# ── Profiles ───────────────────────────────────────────
|
|
582
|
+
elif self.path == "/api/profiles":
|
|
583
|
+
try:
|
|
584
|
+
from specsmith.agent.execution_profiles import ExecutionProfileStore
|
|
585
|
+
|
|
586
|
+
store = ExecutionProfileStore.load()
|
|
587
|
+
self._json_ok(
|
|
588
|
+
{
|
|
589
|
+
"profiles": [p.to_dict() for p in store.profiles],
|
|
590
|
+
"default": store.default().id,
|
|
591
|
+
}
|
|
592
|
+
)
|
|
593
|
+
except Exception as exc: # noqa: BLE001
|
|
594
|
+
self._json_err(str(exc), code=500)
|
|
595
|
+
|
|
596
|
+
# ── Model Scores ───────────────────────────────────────
|
|
597
|
+
elif self.path.startswith("/api/models/scores"):
|
|
598
|
+
try:
|
|
599
|
+
import urllib.parse as _up
|
|
600
|
+
|
|
601
|
+
from specsmith.agent.model_intelligence import (
|
|
602
|
+
BASELINE_SCORES,
|
|
603
|
+
rank_models_for_role,
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
qs = _up.urlparse(self.path).query
|
|
607
|
+
params = _up.parse_qs(qs)
|
|
608
|
+
role = params.get("role", ["coder"])[0]
|
|
609
|
+
models = list(BASELINE_SCORES.keys())
|
|
610
|
+
ranked = rank_models_for_role(role, models)
|
|
611
|
+
self._json_ok(
|
|
612
|
+
{"role": role, "scores": [{"model": m, "score": s} for m, s in ranked]}
|
|
613
|
+
)
|
|
614
|
+
except Exception as exc: # noqa: BLE001
|
|
615
|
+
self._json_err(str(exc), code=500)
|
|
616
|
+
|
|
617
|
+
# ── Datasources ────────────────────────────────────────
|
|
618
|
+
elif self.path == "/api/datasources":
|
|
619
|
+
try:
|
|
620
|
+
sources = [
|
|
621
|
+
{"id": "patentsview", "name": "PatentsView"},
|
|
622
|
+
{"id": "ppubs", "name": "Patent Public Search (PPUBS)"},
|
|
623
|
+
{"id": "odp", "name": "USPTO Open Data Portal"},
|
|
624
|
+
{"id": "pfw", "name": "Patent File Wrapper"},
|
|
625
|
+
{"id": "citations", "name": "USPTO Enriched Citations"},
|
|
626
|
+
{"id": "fpd", "name": "Final Petition Decisions"},
|
|
627
|
+
{"id": "ptab", "name": "USPTO PTAB"},
|
|
628
|
+
]
|
|
629
|
+
self._json_ok({"datasources": sources})
|
|
630
|
+
except Exception as exc: # noqa: BLE001
|
|
631
|
+
self._json_err(str(exc), code=500)
|
|
632
|
+
|
|
488
633
|
else:
|
|
489
634
|
self.send_error(404)
|
|
490
635
|
|