specsmith 0.17.1.dev669__tar.gz → 0.17.1.dev684__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.
Files changed (354) hide show
  1. {specsmith-0.17.1.dev669/src/specsmith.egg-info → specsmith-0.17.1.dev684}/PKG-INFO +1 -1
  2. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/pyproject.toml +1 -1
  3. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/runner.py +25 -1
  4. specsmith-0.17.1.dev684/src/specsmith/agent/token_pricing.py +191 -0
  5. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/auditor.py +2 -1
  6. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/compliance/_compat.py +89 -44
  7. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/__init__.py +2 -0
  8. specsmith-0.17.1.dev684/src/specsmith/migrations/m010_post_esdb_cleanup.py +241 -0
  9. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/agents.md.j2 +27 -0
  10. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684/src/specsmith.egg-info}/PKG-INFO +1 -1
  11. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith.egg-info/SOURCES.txt +6 -0
  12. specsmith-0.17.1.dev684/tests/test_benchmark_harness.py +688 -0
  13. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_nexus.py +8 -3
  14. specsmith-0.17.1.dev684/tests/test_parallel_agents.py +511 -0
  15. specsmith-0.17.1.dev684/tests/test_repl_extended.py +391 -0
  16. specsmith-0.17.1.dev684/tests/test_token_cost.py +319 -0
  17. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/LICENSE +0 -0
  18. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/README.md +0 -0
  19. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/setup.cfg +0 -0
  20. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/epistemic/__init__.py +0 -0
  21. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/epistemic/belief.py +0 -0
  22. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/epistemic/certainty.py +0 -0
  23. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/epistemic/failure_graph.py +0 -0
  24. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/epistemic/py.typed +0 -0
  25. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/epistemic/recovery.py +0 -0
  26. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/epistemic/session.py +0 -0
  27. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/epistemic/stress_tester.py +0 -0
  28. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/epistemic/trace.py +0 -0
  29. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/__init__.py +0 -0
  30. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/__main__.py +0 -0
  31. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/__init__.py +0 -0
  32. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/broker.py +0 -0
  33. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/chat_runner.py +0 -0
  34. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/cleanup.py +0 -0
  35. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/context_seed.py +0 -0
  36. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/core.py +0 -0
  37. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/dispatch/__init__.py +0 -0
  38. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/dispatch/_status.py +0 -0
  39. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/dispatch/dag.py +0 -0
  40. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
  41. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/dispatch/events.py +0 -0
  42. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/dispatch/result.py +0 -0
  43. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/endpoints.py +0 -0
  44. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/events.py +0 -0
  45. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/execution_profiles.py +0 -0
  46. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/fallback.py +0 -0
  47. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/hf_leaderboard.py +0 -0
  48. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/hf_sync.py +0 -0
  49. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/indexer.py +0 -0
  50. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/llm_client.py +0 -0
  51. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/mcp.py +0 -0
  52. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/memory.py +0 -0
  53. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/model_intelligence.py +0 -0
  54. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/model_profiles.py +0 -0
  55. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/model_router.py +0 -0
  56. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/orchestrator.py +0 -0
  57. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/permissions.py +0 -0
  58. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/profiles.py +0 -0
  59. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/provider_registry.py +0 -0
  60. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/repl.py +0 -0
  61. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/router.py +0 -0
  62. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/rules.py +0 -0
  63. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/safety.py +0 -0
  64. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/spawner.py +0 -0
  65. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/suggester.py +0 -0
  66. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/teams.py +0 -0
  67. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/tools.py +0 -0
  68. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/verifier.py +0 -0
  69. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/agent/voice.py +0 -0
  70. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/approvals.py +0 -0
  71. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/architect.py +0 -0
  72. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/auth.py +0 -0
  73. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/block_export.py +0 -0
  74. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/channel.py +0 -0
  75. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/ci_manager.py +0 -0
  76. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/cli.py +0 -0
  77. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/commands/__init__.py +0 -0
  78. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/commands/intelligence.py +0 -0
  79. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/commands/issues_policy.py +0 -0
  80. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/commands/reporting.py +0 -0
  81. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/compliance/__init__.py +0 -0
  82. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/compliance/checker.py +0 -0
  83. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/compliance/evidence.py +0 -0
  84. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/compliance/regulations.py +0 -0
  85. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/compliance/reporter.py +0 -0
  86. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/compressor.py +0 -0
  87. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/config.py +0 -0
  88. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/console_utils.py +0 -0
  89. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/context_orchestrator.py +0 -0
  90. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/context_window.py +0 -0
  91. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/credit_analyzer.py +0 -0
  92. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/credits.py +0 -0
  93. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/dashboard.py +0 -0
  94. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/datasources/__init__.py +0 -0
  95. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/datasources/base.py +0 -0
  96. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/datasources/citations.py +0 -0
  97. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/datasources/fpd.py +0 -0
  98. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/datasources/odp.py +0 -0
  99. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/datasources/patentsview.py +0 -0
  100. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/datasources/pfw.py +0 -0
  101. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/datasources/ppubs.py +0 -0
  102. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/datasources/ptab.py +0 -0
  103. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/differ.py +0 -0
  104. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/doctor.py +0 -0
  105. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/drive.py +0 -0
  106. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/editor.py +0 -0
  107. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/efficiency.py +0 -0
  108. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/epistemic/__init__.py +0 -0
  109. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/epistemic/belief.py +0 -0
  110. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/epistemic/certainty.py +0 -0
  111. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/epistemic/failure_graph.py +0 -0
  112. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/epistemic/recovery.py +0 -0
  113. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/epistemic/stress_tester.py +0 -0
  114. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/esdb/__init__.py +0 -0
  115. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/esdb/_license.py +0 -0
  116. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/esdb/bridge.py +0 -0
  117. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/esdb/sqlite_store.py +0 -0
  118. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/esdb_sweep.py +0 -0
  119. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/esdb_writer.py +0 -0
  120. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/eval/__init__.py +0 -0
  121. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/eval/builtins.py +0 -0
  122. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/eval/runner.py +0 -0
  123. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/executor.py +0 -0
  124. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/exporter.py +0 -0
  125. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/governance_logic.py +0 -0
  126. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/governance_store.py +0 -0
  127. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/governance_yaml.py +0 -0
  128. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/governed_pr.py +0 -0
  129. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/__init__.py +0 -0
  130. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/app.py +0 -0
  131. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/main_window.py +0 -0
  132. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/session_tab.py +0 -0
  133. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/theme.py +0 -0
  134. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/widgets/__init__.py +0 -0
  135. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/widgets/chat_view.py +0 -0
  136. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/widgets/input_bar.py +0 -0
  137. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  138. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/widgets/token_meter.py +0 -0
  139. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  140. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/widgets/update_checker.py +0 -0
  141. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/gui/worker.py +0 -0
  142. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/history_search.py +0 -0
  143. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/importer.py +0 -0
  144. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/instinct.py +0 -0
  145. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/__init__.py +0 -0
  146. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/agent_skill.py +0 -0
  147. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/aider.py +0 -0
  148. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/base.py +0 -0
  149. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/claude_code.py +0 -0
  150. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/codity.py +0 -0
  151. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/copilot.py +0 -0
  152. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/cursor.py +0 -0
  153. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/gemini.py +0 -0
  154. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/integrations/windsurf.py +0 -0
  155. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/issue_reporter.py +0 -0
  156. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/languages.py +0 -0
  157. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/ledger.py +0 -0
  158. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/local_model.py +0 -0
  159. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/mcp_generator.py +0 -0
  160. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/mcp_server.py +0 -0
  161. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
  162. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/m002_agents_slim.py +0 -0
  163. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/m003_compliance_init.py +0 -0
  164. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
  165. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
  166. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/m006_session_governance.py +0 -0
  167. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/m007_yaml_first.py +0 -0
  168. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/m008_esdb_full_coverage.py +0 -0
  169. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/m009_esdb_first.py +0 -0
  170. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/migrations/runner.py +0 -0
  171. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/ollama_cmds.py +0 -0
  172. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/patent.py +0 -0
  173. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/paths.py +0 -0
  174. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/phase.py +0 -0
  175. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/plugins.py +0 -0
  176. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/policy.py +0 -0
  177. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/profiles.py +0 -0
  178. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/project_metrics.py +0 -0
  179. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/quality_report.py +0 -0
  180. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/rate_limits.py +0 -0
  181. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/recover.py +0 -0
  182. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/releaser.py +0 -0
  183. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/requirements.py +0 -0
  184. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/requirements_parser.py +0 -0
  185. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/retrieval.py +0 -0
  186. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/risk.py +0 -0
  187. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/safe_write.py +0 -0
  188. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/scaffolder.py +0 -0
  189. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/serve.py +0 -0
  190. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/session.py +0 -0
  191. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/session_init.py +0 -0
  192. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/session_store.py +0 -0
  193. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/__init__.py +0 -0
  194. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/ai_agents.py +0 -0
  195. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/cloud.py +0 -0
  196. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/corporate.py +0 -0
  197. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/cross_platform.py +0 -0
  198. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/data_engineering.py +0 -0
  199. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/devops.py +0 -0
  200. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/docs.py +0 -0
  201. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/embedded.py +0 -0
  202. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/governance.py +0 -0
  203. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/hardware.py +0 -0
  204. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/mobile.py +0 -0
  205. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/platform_engineering.py +0 -0
  206. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/productivity.py +0 -0
  207. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/software_engineering.py +0 -0
  208. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/specsmith_skills.py +0 -0
  209. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/ssh.py +0 -0
  210. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills/web_backend.py +0 -0
  211. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/skills_builder.py +0 -0
  212. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/sync.py +0 -0
  213. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  214. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  215. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  216. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  217. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  218. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  219. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  220. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/community/security.md.j2 +0 -0
  221. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  222. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  223. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  224. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  225. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  226. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/editorconfig.j2 +0 -0
  227. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/gitattributes.j2 +0 -0
  228. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/gitignore.j2 +0 -0
  229. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/go/go.mod.j2 +0 -0
  230. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/go/main.go.j2 +0 -0
  231. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  232. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  233. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  234. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  235. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  236. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
  237. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  238. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  239. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
  240. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  241. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  242. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/js/package.json.j2 +0 -0
  243. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/ledger.md.j2 +0 -0
  244. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/python/cli.py.j2 +0 -0
  245. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/python/init.py.j2 +0 -0
  246. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  247. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/readme.md.j2 +0 -0
  248. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  249. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  250. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  251. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  252. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  253. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  254. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  255. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  256. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  257. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/tool_installer.py +0 -0
  258. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/toolrules.py +0 -0
  259. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/tools.py +0 -0
  260. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/trace.py +0 -0
  261. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/transcripts.py +0 -0
  262. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/updater.py +0 -0
  263. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/upgrader.py +0 -0
  264. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/validator.py +0 -0
  265. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/vcs/__init__.py +0 -0
  266. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/vcs/base.py +0 -0
  267. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/vcs/bitbucket.py +0 -0
  268. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/vcs/github.py +0 -0
  269. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/vcs/gitlab.py +0 -0
  270. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/vcs_commands.py +0 -0
  271. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/wi_store.py +0 -0
  272. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/wireframes.py +0 -0
  273. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith/workspace.py +0 -0
  274. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith.egg-info/dependency_links.txt +0 -0
  275. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith.egg-info/entry_points.txt +0 -0
  276. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith.egg-info/requires.txt +0 -0
  277. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/src/specsmith.egg-info/top_level.txt +0 -0
  278. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_CMD_001.py +0 -0
  279. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_agent_profiles.py +0 -0
  280. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_agent_run_feedback.py +0 -0
  281. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_agent_runner_ready.py +0 -0
  282. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_ai_client.py +0 -0
  283. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_ai_intelligence.py +0 -0
  284. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_architect_interview.py +0 -0
  285. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_architect_v2.py +0 -0
  286. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_architecture.py +0 -0
  287. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_auditor.py +0 -0
  288. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_channel.py +0 -0
  289. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_chat_diff_decision.py +0 -0
  290. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_chat_runner_openai_compat.py +0 -0
  291. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_chat_stdin_protocol.py +0 -0
  292. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_cleanup_cmd.py +0 -0
  293. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_cli.py +0 -0
  294. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_cli_regressions.py +0 -0
  295. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_cli_workflows_history_drive.py +0 -0
  296. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_compliance.py +0 -0
  297. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_compliance_governance.py +0 -0
  298. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_compressor.py +0 -0
  299. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_dispatch.py +0 -0
  300. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_dual_write.py +0 -0
  301. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_e2e_nexus.py +0 -0
  302. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_efficiency.py +0 -0
  303. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_endpoints_cli.py +0 -0
  304. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_endpoints_store.py +0 -0
  305. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_epistemic.py +0 -0
  306. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_esdb_backend_switch.py +0 -0
  307. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_esdb_enforcement.py +0 -0
  308. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_esdb_integration.py +0 -0
  309. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_esdb_license.py +0 -0
  310. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_esdb_sqlite.py +0 -0
  311. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_esdb_sweep.py +0 -0
  312. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_esdb_verify_chain_cli.py +0 -0
  313. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_esdb_writer.py +0 -0
  314. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_fallback_chain.py +0 -0
  315. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_golden_path.py +0 -0
  316. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_importer.py +0 -0
  317. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_init_modes.py +0 -0
  318. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_integrations.py +0 -0
  319. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_integrations_codity.py +0 -0
  320. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_intelligence.py +0 -0
  321. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_issue_policy_features.py +0 -0
  322. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_issue_reporter.py +0 -0
  323. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_issues_263_264.py +0 -0
  324. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_local_model.py +0 -0
  325. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_markdown_deprecation.py +0 -0
  326. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_mcp_client.py +0 -0
  327. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_mcp_server.py +0 -0
  328. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_migration_direction.py +0 -0
  329. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_model_router.py +0 -0
  330. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_new_modules.py +0 -0
  331. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_permissions.py +0 -0
  332. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_phase1_4_new.py +0 -0
  333. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_phase34_completion.py +0 -0
  334. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_project_metrics.py +0 -0
  335. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_quality_report.py +0 -0
  336. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_rate_limits.py +0 -0
  337. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_repl.py +0 -0
  338. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_reporting_commands.py +0 -0
  339. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_req_248_262.py +0 -0
  340. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_req_358_359.py +0 -0
  341. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_resume_command.py +0 -0
  342. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_scaffolder.py +0 -0
  343. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_schema_migrations.py +0 -0
  344. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_skill_marketplace.py +0 -0
  345. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_skills_mcp.py +0 -0
  346. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_smoke.py +0 -0
  347. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_suggester.py +0 -0
  348. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_tools.py +0 -0
  349. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_typing_guardrails.py +0 -0
  350. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_validator.py +0 -0
  351. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_vcs.py +0 -0
  352. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_warp_parity.py +0 -0
  353. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/tests/test_warp_parity_followup.py +0 -0
  354. {specsmith-0.17.1.dev669 → specsmith-0.17.1.dev684}/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.dev669
3
+ Version: 0.17.1.dev684
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.dev669"
7
+ version = "0.17.1.dev684"
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(" \u26a0 No provider available — commands will return no response.")
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": 200,
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 REQUIREMENTS.md into {req_id: {title, status, ...}}."""
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
- 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",
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 reqs
94
+ return {}
72
95
 
73
96
 
74
97
  def _parse_tests(root: Path) -> dict[str, dict[str, str]]:
75
- """Parse TESTS.md into {test_id: {title, requirement_id, ...}}."""
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
- 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 "",
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 tests
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