specsmith 0.17.1.dev669__tar.gz → 0.17.1.dev685__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.17.1.dev669/src/specsmith.egg-info → specsmith-0.17.1.dev685}/PKG-INFO +1 -1
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/pyproject.toml +1 -1
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/runner.py +25 -1
- specsmith-0.17.1.dev685/src/specsmith/agent/token_pricing.py +191 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/auditor.py +2 -1
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/compliance/_compat.py +89 -44
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/__init__.py +2 -0
- specsmith-0.17.1.dev685/src/specsmith/migrations/m010_post_esdb_cleanup.py +241 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/agents.md.j2 +27 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685/src/specsmith.egg-info}/PKG-INFO +1 -1
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith.egg-info/SOURCES.txt +6 -0
- specsmith-0.17.1.dev685/tests/test_benchmark_harness.py +688 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_nexus.py +8 -3
- specsmith-0.17.1.dev685/tests/test_parallel_agents.py +511 -0
- specsmith-0.17.1.dev685/tests/test_repl_extended.py +391 -0
- specsmith-0.17.1.dev685/tests/test_token_cost.py +319 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/LICENSE +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/README.md +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/setup.cfg +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/epistemic/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/epistemic/belief.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/epistemic/certainty.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/epistemic/py.typed +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/epistemic/recovery.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/epistemic/session.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/epistemic/trace.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/__main__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/context_seed.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/dispatch/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/dispatch/_status.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/dispatch/dag.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/dispatch/events.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/dispatch/result.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/hf_leaderboard.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/llm_client.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/model_profiles.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/model_router.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/approvals.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/architect.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/auth.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/block_export.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/channel.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/ci_manager.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/cli.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/commands/issues_policy.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/commands/reporting.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/compliance/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/compliance/checker.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/compliance/evidence.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/compliance/regulations.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/compliance/reporter.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/compressor.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/config.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/context_orchestrator.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/context_window.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/credits.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/dashboard.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/differ.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/doctor.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/drive.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/editor.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/efficiency.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/esdb/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/esdb/_license.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/esdb/bridge.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/esdb/sqlite_store.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/esdb_sweep.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/esdb_writer.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/executor.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/exporter.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/governance_logic.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/governance_store.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/governance_yaml.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/governed_pr.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/history_search.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/importer.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/instinct.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/codity.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/issue_reporter.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/languages.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/ledger.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/local_model.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/mcp_generator.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/mcp_server.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/m002_agents_slim.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/m003_compliance_init.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/m006_session_governance.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/m007_yaml_first.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/m008_esdb_full_coverage.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/m009_esdb_first.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/migrations/runner.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/ollama_cmds.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/patent.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/paths.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/phase.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/plugins.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/policy.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/profiles.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/project_metrics.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/quality_report.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/recover.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/releaser.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/requirements.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/risk.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/serve.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/session.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/session_init.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/session_store.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/ai_agents.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/cloud.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/corporate.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/cross_platform.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/data_engineering.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/devops.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/docs.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/embedded.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/governance.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/hardware.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/mobile.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/platform_engineering.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/productivity.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/software_engineering.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/specsmith_skills.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/ssh.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills/web_backend.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/skills_builder.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/sync.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/tools.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/trace.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/transcripts.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/updater.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/validator.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/wi_store.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith/workspace.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_CMD_001.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_agent_run_feedback.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_ai_client.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_ai_intelligence.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_architect_interview.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_architect_v2.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_architecture.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_auditor.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_channel.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_cleanup_cmd.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_cli.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_cli_regressions.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_compliance.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_compliance_governance.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_compressor.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_dispatch.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_dual_write.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_efficiency.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_epistemic.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_esdb_backend_switch.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_esdb_enforcement.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_esdb_integration.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_esdb_license.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_esdb_sqlite.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_esdb_sweep.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_esdb_verify_chain_cli.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_esdb_writer.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_golden_path.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_importer.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_init_modes.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_integrations.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_integrations_codity.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_intelligence.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_issue_policy_features.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_issue_reporter.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_issues_263_264.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_local_model.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_markdown_deprecation.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_mcp_client.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_mcp_server.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_migration_direction.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_model_router.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_new_modules.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_permissions.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_project_metrics.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_quality_report.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_rate_limits.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_repl.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_reporting_commands.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_req_248_262.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_req_358_359.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_resume_command.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_scaffolder.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_schema_migrations.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_skills_mcp.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_smoke.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_suggester.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_tools.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_typing_guardrails.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_validator.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_vcs.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_warp_parity.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_warp_parity_followup.py +0 -0
- {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev685}/tests/test_wi_lifecycle.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.17.1.
|
|
3
|
+
Version: 0.17.1.dev685
|
|
4
4
|
Summary: AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider.
|
|
5
5
|
Author: Layer1Labs Silicon, Inc.
|
|
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.17.1.
|
|
7
|
+
version = "0.17.1.dev685"
|
|
8
8
|
description = "AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -394,7 +394,9 @@ class AgentRunner:
|
|
|
394
394
|
lines.append(f" {s.icon} {s.name:<10} \u2717 {s.note}")
|
|
395
395
|
lines.append("")
|
|
396
396
|
if active_count == 0:
|
|
397
|
-
lines.append(
|
|
397
|
+
lines.append(
|
|
398
|
+
" \u26a0 No provider available \u2014 commands will return no response."
|
|
399
|
+
)
|
|
398
400
|
else:
|
|
399
401
|
# Show multi-model routing if the router is configured (REQ-389).
|
|
400
402
|
if self._model_router is not None:
|
|
@@ -585,6 +587,28 @@ class AgentRunner:
|
|
|
585
587
|
self._emit_event(type="system", message=hint)
|
|
586
588
|
return None
|
|
587
589
|
|
|
590
|
+
if result is None:
|
|
591
|
+
# All providers failed — give the user an actionable explanation
|
|
592
|
+
# rather than silent emptiness.
|
|
593
|
+
import os as _os
|
|
594
|
+
|
|
595
|
+
host = _os.environ.get("OLLAMA_HOST", DEFAULT_OLLAMA_HOST).rstrip("/")
|
|
596
|
+
if _ollama_alive(host):
|
|
597
|
+
model = _pick_ollama_model(host)
|
|
598
|
+
hint = (
|
|
599
|
+
f"Ollama is running but returned no response "
|
|
600
|
+
f"(model: {model}). "
|
|
601
|
+
"Try: ollama run " + model
|
|
602
|
+
)
|
|
603
|
+
else:
|
|
604
|
+
hint = (
|
|
605
|
+
"No LLM provider available. Options:\n"
|
|
606
|
+
" • Start Ollama: ollama serve\n"
|
|
607
|
+
" • Set ANTHROPIC_API_KEY / OPENAI_API_KEY / GOOGLE_API_KEY"
|
|
608
|
+
)
|
|
609
|
+
self._emit_event(type="system", message=hint)
|
|
610
|
+
return None
|
|
611
|
+
|
|
588
612
|
# Aggregate metrics into the session state (C1).
|
|
589
613
|
# ``run_chat`` now reports tokens_in / tokens_out / cost_usd off the
|
|
590
614
|
# provider response (Ollama prompt_eval_count + eval_count, OpenAI
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved.
|
|
3
|
+
"""specsmith.agent.token_pricing — static per-token cost lookup.
|
|
4
|
+
|
|
5
|
+
Provides a single function :func:`cost_for_tokens` that returns the estimated
|
|
6
|
+
USD cost for a given (provider, model, input_tokens, output_tokens) tuple.
|
|
7
|
+
|
|
8
|
+
Design contract
|
|
9
|
+
---------------
|
|
10
|
+
- ``ollama`` provider (and its aliases ``llamacpp``, ``vllm``, ``lmstudio``)
|
|
11
|
+
always returns **0.0** — local inference is free; this is intentional and
|
|
12
|
+
correct, not a bug or missing data.
|
|
13
|
+
- Known cloud models (OpenAI, Anthropic, Google) use a static pricing table
|
|
14
|
+
updated to Q2 2026 list prices.
|
|
15
|
+
- Unknown providers/models fall back to a conservative default rate so
|
|
16
|
+
``cost_of_pass`` analysis degrades gracefully rather than crashing.
|
|
17
|
+
|
|
18
|
+
Pricing source
|
|
19
|
+
--------------
|
|
20
|
+
Q2 2026 provider pricing pages. All figures are in USD per 1 M tokens.
|
|
21
|
+
Update this table when provider pricing changes (bump the table version comment).
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from typing import Any
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# Pricing table — (input_usd_per_1M, output_usd_per_1M)
|
|
30
|
+
# Table version: 2026-Q2
|
|
31
|
+
# ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
#: Providers that are always zero-cost (local inference).
|
|
34
|
+
_FREE_PROVIDERS: frozenset[str] = frozenset({"ollama", "llamacpp", "vllm", "lmstudio", "local"})
|
|
35
|
+
|
|
36
|
+
#: Static pricing table. Keys are normalised model name substrings matched
|
|
37
|
+
#: from longest to shortest so that more-specific keys win over generic ones.
|
|
38
|
+
_PRICING_PER_1M: dict[str, tuple[float, float]] = {
|
|
39
|
+
# ── OpenAI GPT-4 family ────────────────────────────────────────────────
|
|
40
|
+
"gpt-4o-mini": (0.15, 0.60),
|
|
41
|
+
"gpt-4o": (2.50, 10.00),
|
|
42
|
+
"gpt-4.1-nano": (0.10, 0.40),
|
|
43
|
+
"gpt-4.1-mini": (0.40, 1.60),
|
|
44
|
+
"gpt-4.1": (2.00, 8.00),
|
|
45
|
+
"gpt-4-turbo": (10.00, 30.00),
|
|
46
|
+
# ── OpenAI GPT-5 family ────────────────────────────────────────────────
|
|
47
|
+
"gpt-5-nano": (0.50, 2.00),
|
|
48
|
+
"gpt-5-mini": (2.00, 8.00),
|
|
49
|
+
"gpt-5-pro": (50.00, 200.00),
|
|
50
|
+
"gpt-5.4-nano": (0.30, 1.20),
|
|
51
|
+
"gpt-5.4-mini": (1.00, 4.00),
|
|
52
|
+
"gpt-5.4-pro": (20.00, 80.00),
|
|
53
|
+
"gpt-5.4": (5.00, 20.00),
|
|
54
|
+
"gpt-5.5-pro": (15.00, 60.00),
|
|
55
|
+
"gpt-5.5": (3.00, 12.00),
|
|
56
|
+
"gpt-5.2-codex": (10.00, 40.00),
|
|
57
|
+
"gpt-5.2-pro": (40.00, 160.00),
|
|
58
|
+
"gpt-5.2": (10.00, 40.00),
|
|
59
|
+
"gpt-5.3-codex": (8.00, 32.00),
|
|
60
|
+
"gpt-5.1": (12.00, 48.00),
|
|
61
|
+
"gpt-5-codex": (15.00, 60.00),
|
|
62
|
+
"gpt-5": (15.00, 60.00),
|
|
63
|
+
# ── OpenAI reasoning ──────────────────────────────────────────────────
|
|
64
|
+
"o4-mini": (1.10, 4.40),
|
|
65
|
+
"o3-mini": (1.10, 4.40),
|
|
66
|
+
"o3": (10.00, 40.00),
|
|
67
|
+
"o1": (15.00, 60.00),
|
|
68
|
+
# ── Anthropic ─────────────────────────────────────────────────────────
|
|
69
|
+
"claude-haiku-4-5": (0.25, 1.25),
|
|
70
|
+
"claude-haiku": (0.25, 1.25),
|
|
71
|
+
"claude-sonnet-4-5": (3.00, 15.00),
|
|
72
|
+
"claude-sonnet-4-6": (3.00, 15.00),
|
|
73
|
+
"claude-sonnet": (3.00, 15.00),
|
|
74
|
+
"claude-opus-4-5": (15.00, 75.00),
|
|
75
|
+
"claude-opus-4-6": (15.00, 75.00),
|
|
76
|
+
"claude-opus": (15.00, 75.00),
|
|
77
|
+
# ── Google ────────────────────────────────────────────────────────────
|
|
78
|
+
"gemini-3.5-flash": (0.15, 0.60),
|
|
79
|
+
"gemini-3-flash": (0.35, 1.05),
|
|
80
|
+
"gemini-flash": (0.075, 0.30),
|
|
81
|
+
"gemini-3.1-pro": (1.25, 5.00),
|
|
82
|
+
"gemini-pro": (1.25, 5.00),
|
|
83
|
+
# ── Conservative fallback ─────────────────────────────────────────────
|
|
84
|
+
"unknown": (3.00, 15.00),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _lookup_rates(model: str) -> tuple[float, float]:
|
|
89
|
+
"""Return (input_usd_per_1M, output_usd_per_1M) for *model*.
|
|
90
|
+
|
|
91
|
+
Tries an exact key match first, then a longest-substring match, and
|
|
92
|
+
finally falls back to the ``"unknown"`` conservative default.
|
|
93
|
+
"""
|
|
94
|
+
key = model.strip().lower()
|
|
95
|
+
if key in _PRICING_PER_1M:
|
|
96
|
+
return _PRICING_PER_1M[key]
|
|
97
|
+
# Longest-prefix / substring match so that "gpt-4o-mini-2026-04-09"
|
|
98
|
+
# still resolves to "gpt-4o-mini".
|
|
99
|
+
best_match = ""
|
|
100
|
+
for table_key in _PRICING_PER_1M:
|
|
101
|
+
if table_key in key and len(table_key) > len(best_match):
|
|
102
|
+
best_match = table_key
|
|
103
|
+
if best_match:
|
|
104
|
+
return _PRICING_PER_1M[best_match]
|
|
105
|
+
return _PRICING_PER_1M["unknown"]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def cost_for_tokens(
|
|
109
|
+
provider: str,
|
|
110
|
+
model: str,
|
|
111
|
+
input_tokens: int,
|
|
112
|
+
output_tokens: int,
|
|
113
|
+
) -> float:
|
|
114
|
+
"""Return estimated USD cost for a single LLM call.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
provider: Provider name (e.g. ``"ollama"``, ``"openai"``, ``"anthropic"``).
|
|
118
|
+
model: Model name or slug (e.g. ``"gpt-4o"``, ``"qwen2.5-coder:14b"``).
|
|
119
|
+
input_tokens: Number of prompt/context tokens consumed.
|
|
120
|
+
output_tokens: Number of generated/completion tokens.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Estimated cost in USD. Always ``0.0`` for local/free providers
|
|
124
|
+
(Ollama, llamacpp, vllm, lmstudio, local). Returns ``0.0`` when
|
|
125
|
+
both token counts are zero regardless of provider.
|
|
126
|
+
|
|
127
|
+
Examples::
|
|
128
|
+
|
|
129
|
+
>>> cost_for_tokens("ollama", "qwen2.5-coder:14b", 1000, 500)
|
|
130
|
+
0.0
|
|
131
|
+
>>> cost_for_tokens("openai", "gpt-4o-mini", 1_000_000, 0)
|
|
132
|
+
0.15
|
|
133
|
+
>>> cost_for_tokens("anthropic", "claude-haiku-4-5", 0, 1_000_000)
|
|
134
|
+
1.25
|
|
135
|
+
"""
|
|
136
|
+
if not provider and not model:
|
|
137
|
+
return 0.0
|
|
138
|
+
if (provider or "").strip().lower() in _FREE_PROVIDERS:
|
|
139
|
+
return 0.0
|
|
140
|
+
if input_tokens == 0 and output_tokens == 0:
|
|
141
|
+
return 0.0
|
|
142
|
+
inp_per_m, out_per_m = _lookup_rates(model)
|
|
143
|
+
return (input_tokens * inp_per_m + output_tokens * out_per_m) / 1_000_000
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def cost_for_tokens_breakdown(
|
|
147
|
+
provider: str,
|
|
148
|
+
model: str,
|
|
149
|
+
input_tokens: int,
|
|
150
|
+
output_tokens: int,
|
|
151
|
+
) -> tuple[float, float, float]:
|
|
152
|
+
"""Return ``(input_cost_usd, output_cost_usd, total_cost_usd)``."""
|
|
153
|
+
if (provider or "").strip().lower() in _FREE_PROVIDERS:
|
|
154
|
+
return 0.0, 0.0, 0.0
|
|
155
|
+
inp_per_m, out_per_m = _lookup_rates(model)
|
|
156
|
+
inp_cost = input_tokens * inp_per_m / 1_000_000
|
|
157
|
+
out_cost = output_tokens * out_per_m / 1_000_000
|
|
158
|
+
return inp_cost, out_cost, inp_cost + out_cost
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def tokens_per_correct_answer(
|
|
162
|
+
records: list[Any],
|
|
163
|
+
*,
|
|
164
|
+
token_attr: str = "tokens_total",
|
|
165
|
+
passed_attr: str = "passed",
|
|
166
|
+
) -> float | None:
|
|
167
|
+
"""Compute mean tokens consumed per correct (passing) answer.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
records: Sequence of record objects (e.g. :class:`MetricsRecord` or
|
|
171
|
+
:class:`RunResult`) with numeric ``token_attr`` and bool
|
|
172
|
+
``passed_attr`` attributes.
|
|
173
|
+
token_attr: Attribute name for total token count.
|
|
174
|
+
passed_attr: Attribute name for pass/fail boolean.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Mean total tokens among passing records, or ``None`` if no passing
|
|
178
|
+
records exist.
|
|
179
|
+
"""
|
|
180
|
+
passing = [r for r in records if getattr(r, passed_attr, False)]
|
|
181
|
+
if not passing:
|
|
182
|
+
return None
|
|
183
|
+
totals = [getattr(r, token_attr, 0) for r in passing]
|
|
184
|
+
return sum(totals) / len(totals)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
__all__ = [
|
|
188
|
+
"cost_for_tokens",
|
|
189
|
+
"cost_for_tokens_breakdown",
|
|
190
|
+
"tokens_per_correct_answer",
|
|
191
|
+
]
|
|
@@ -554,8 +554,9 @@ def check_ledger_health(root: Path) -> list[AuditResult]:
|
|
|
554
554
|
|
|
555
555
|
|
|
556
556
|
# Default thresholds (used when no project type is detected)
|
|
557
|
+
# AGENTS.md: raised to 250 (template now generates ~202 lines with Parallel Agents section)
|
|
557
558
|
_DEFAULT_THRESHOLDS: dict[str, int] = {
|
|
558
|
-
"AGENTS.md":
|
|
559
|
+
"AGENTS.md": 250,
|
|
559
560
|
"docs/governance/RULES.md": 800,
|
|
560
561
|
"docs/governance/SESSION-PROTOCOL.md": 400,
|
|
561
562
|
"docs/governance/LIFECYCLE.md": 200,
|
|
@@ -8,6 +8,7 @@ traceability matrix. Used by both CLI commands and REST endpoints.
|
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
+
import json
|
|
11
12
|
import re
|
|
12
13
|
from dataclasses import dataclass, field
|
|
13
14
|
from pathlib import Path
|
|
@@ -41,63 +42,107 @@ class ComplianceSummary:
|
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
def _parse_requirements(root: Path) -> dict[str, dict[str, str]]:
|
|
44
|
-
"""Parse
|
|
45
|
+
"""Parse requirements into {req_id: {title, status, ...}}.
|
|
46
|
+
|
|
47
|
+
Sources tried in order:
|
|
48
|
+
1. ``docs/REQUIREMENTS.md`` (legacy markdown mode)
|
|
49
|
+
2. ``REQUIREMENTS.md`` (legacy markdown mode, repo-root variant)
|
|
50
|
+
3. ``.specsmith/requirements.json`` (YAML-first sync cache)
|
|
51
|
+
"""
|
|
45
52
|
req_path = root / "docs" / "REQUIREMENTS.md"
|
|
46
53
|
if not req_path.is_file():
|
|
47
54
|
req_path = root / "REQUIREMENTS.md"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
55
|
+
|
|
56
|
+
if req_path.is_file():
|
|
57
|
+
text = req_path.read_text(encoding="utf-8", errors="replace")
|
|
58
|
+
reqs: dict[str, dict[str, str]] = {}
|
|
59
|
+
# Parse markdown sections: ## N. Title\n- **ID:** REQ-NNN
|
|
60
|
+
blocks = re.split(r"\n## ", text)
|
|
61
|
+
for block in blocks:
|
|
62
|
+
id_match = re.search(r"\*\*ID:\*\*\s*(REQ-\d+)", block)
|
|
63
|
+
if not id_match:
|
|
64
|
+
# Try alternate format: ## REQ-NNN
|
|
65
|
+
id_match = re.search(r"^(REQ-\d+)", block.strip())
|
|
66
|
+
if id_match:
|
|
67
|
+
req_id = id_match.group(1)
|
|
68
|
+
title_match = re.search(r"\*\*Title:\*\*\s*(.+)", block)
|
|
69
|
+
status_match = re.search(r"\*\*Status:\*\*\s*(.+)", block)
|
|
70
|
+
reqs[req_id] = {
|
|
71
|
+
"id": req_id,
|
|
72
|
+
"title": title_match.group(1).strip() if title_match else "",
|
|
73
|
+
"status": status_match.group(1).strip() if status_match else "draft",
|
|
74
|
+
}
|
|
75
|
+
return reqs
|
|
76
|
+
|
|
77
|
+
# YAML-first fallback: read from the .specsmith sync cache
|
|
78
|
+
json_path = root / ".specsmith" / "requirements.json"
|
|
79
|
+
if json_path.is_file():
|
|
80
|
+
try:
|
|
81
|
+
entries = json.loads(json_path.read_text(encoding="utf-8"))
|
|
82
|
+
except (json.JSONDecodeError, OSError):
|
|
83
|
+
return {}
|
|
84
|
+
return {
|
|
85
|
+
entry["id"]: {
|
|
86
|
+
"id": entry["id"],
|
|
87
|
+
"title": entry.get("title", ""),
|
|
88
|
+
"status": entry.get("status", "draft"),
|
|
69
89
|
}
|
|
90
|
+
for entry in entries
|
|
91
|
+
if isinstance(entry, dict) and "id" in entry
|
|
92
|
+
}
|
|
70
93
|
|
|
71
|
-
return
|
|
94
|
+
return {}
|
|
72
95
|
|
|
73
96
|
|
|
74
97
|
def _parse_tests(root: Path) -> dict[str, dict[str, str]]:
|
|
75
|
-
"""Parse
|
|
98
|
+
"""Parse test cases into {test_id: {title, requirement_id, ...}}.
|
|
99
|
+
|
|
100
|
+
Sources tried in order:
|
|
101
|
+
1. ``docs/TESTS.md`` (legacy markdown mode)
|
|
102
|
+
2. ``TESTS.md`` (legacy markdown mode, repo-root variant)
|
|
103
|
+
3. ``.specsmith/testcases.json`` (YAML-first sync cache)
|
|
104
|
+
"""
|
|
76
105
|
test_path = root / "docs" / "TESTS.md"
|
|
77
106
|
if not test_path.is_file():
|
|
78
107
|
test_path = root / "TESTS.md"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
108
|
+
|
|
109
|
+
if test_path.is_file():
|
|
110
|
+
text = test_path.read_text(encoding="utf-8", errors="replace")
|
|
111
|
+
tests: dict[str, dict[str, str]] = {}
|
|
112
|
+
blocks = re.split(r"\n## ", text)
|
|
113
|
+
for block in blocks:
|
|
114
|
+
id_match = re.search(r"\*\*ID:\*\*\s*(TEST-\d+)", block)
|
|
115
|
+
if not id_match:
|
|
116
|
+
id_match = re.search(r"^(TEST-\d+)", block.strip())
|
|
117
|
+
if id_match:
|
|
118
|
+
test_id = id_match.group(1)
|
|
119
|
+
req_match = re.search(r"\*\*Requirement(?:\s+ID)?:\*\*\s*(REQ-\d+)", block)
|
|
120
|
+
title_match = re.search(r"\*\*Title:\*\*\s*(.+)", block)
|
|
121
|
+
tests[test_id] = {
|
|
122
|
+
"id": test_id,
|
|
123
|
+
"title": title_match.group(1).strip() if title_match else "",
|
|
124
|
+
"requirement_id": req_match.group(1) if req_match else "",
|
|
125
|
+
}
|
|
126
|
+
return tests
|
|
127
|
+
|
|
128
|
+
# YAML-first fallback: read from the .specsmith sync cache
|
|
129
|
+
json_path = root / ".specsmith" / "testcases.json"
|
|
130
|
+
if json_path.is_file():
|
|
131
|
+
try:
|
|
132
|
+
entries = json.loads(json_path.read_text(encoding="utf-8"))
|
|
133
|
+
except (json.JSONDecodeError, OSError):
|
|
134
|
+
return {}
|
|
135
|
+
return {
|
|
136
|
+
entry["id"]: {
|
|
137
|
+
"id": entry["id"],
|
|
138
|
+
"title": entry.get("title", ""),
|
|
139
|
+
"requirement_id": entry.get("requirement_id", ""),
|
|
98
140
|
}
|
|
141
|
+
for entry in entries
|
|
142
|
+
if isinstance(entry, dict) and "id" in entry
|
|
143
|
+
}
|
|
99
144
|
|
|
100
|
-
return
|
|
145
|
+
return {}
|
|
101
146
|
|
|
102
147
|
|
|
103
148
|
def get_compliance_summary(project_dir: str | Path = ".") -> ComplianceSummary:
|
|
@@ -117,6 +117,7 @@ class _MigrationRegistry:
|
|
|
117
117
|
m007_yaml_first,
|
|
118
118
|
m008_esdb_full_coverage,
|
|
119
119
|
m009_esdb_first,
|
|
120
|
+
m010_post_esdb_cleanup,
|
|
120
121
|
)
|
|
121
122
|
|
|
122
123
|
instances: list[Migration] = [
|
|
@@ -129,6 +130,7 @@ class _MigrationRegistry:
|
|
|
129
130
|
m007_yaml_first.YamlFirstMigration(),
|
|
130
131
|
m008_esdb_full_coverage.EsdbFullCoverageMigration(),
|
|
131
132
|
m009_esdb_first.EsdbFirstMigration(),
|
|
133
|
+
m010_post_esdb_cleanup.PostEsdbCleanupMigration(),
|
|
132
134
|
]
|
|
133
135
|
instances.sort(key=lambda m: m.version)
|
|
134
136
|
self._migrations = instances
|