specsmith 0.10.1.dev283__tar.gz → 0.10.1.dev287__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/PKG-INFO +1 -1
  2. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/pyproject.toml +1 -1
  3. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/cli.py +4 -0
  4. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/commands/intelligence.py +124 -0
  5. specsmith-0.10.1.dev287/src/specsmith/compliance.py +232 -0
  6. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/governance_logic.py +145 -0
  7. specsmith-0.10.1.dev287/src/specsmith/session_init.py +280 -0
  8. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/PKG-INFO +1 -1
  9. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/SOURCES.txt +3 -0
  10. specsmith-0.10.1.dev287/tests/test_intelligence.py +298 -0
  11. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/LICENSE +0 -0
  12. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/README.md +0 -0
  13. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/setup.cfg +0 -0
  14. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/__init__.py +0 -0
  15. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/belief.py +0 -0
  16. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/certainty.py +0 -0
  17. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/failure_graph.py +0 -0
  18. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/py.typed +0 -0
  19. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/recovery.py +0 -0
  20. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/session.py +0 -0
  21. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/stress_tester.py +0 -0
  22. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/epistemic/trace.py +0 -0
  23. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/__init__.py +0 -0
  24. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/__main__.py +0 -0
  25. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/__init__.py +0 -0
  26. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/broker.py +0 -0
  27. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/chat_runner.py +0 -0
  28. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/cleanup.py +0 -0
  29. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/core.py +0 -0
  30. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/endpoints.py +0 -0
  31. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/events.py +0 -0
  32. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/execution_profiles.py +0 -0
  33. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/fallback.py +0 -0
  34. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/indexer.py +0 -0
  35. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/mcp.py +0 -0
  36. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/memory.py +0 -0
  37. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/model_intelligence.py +0 -0
  38. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/orchestrator.py +0 -0
  39. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/permissions.py +0 -0
  40. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/profiles.py +0 -0
  41. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/provider_registry.py +0 -0
  42. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/repl.py +0 -0
  43. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/router.py +0 -0
  44. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/rules.py +0 -0
  45. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/runner.py +0 -0
  46. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/safety.py +0 -0
  47. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/suggester.py +0 -0
  48. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/tools.py +0 -0
  49. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/verifier.py +0 -0
  50. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/agent/voice.py +0 -0
  51. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/architect.py +0 -0
  52. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/auditor.py +0 -0
  53. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/auth.py +0 -0
  54. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/block_export.py +0 -0
  55. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/commands/__init__.py +0 -0
  56. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/compressor.py +0 -0
  57. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/config.py +0 -0
  58. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/console_utils.py +0 -0
  59. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/context_window.py +0 -0
  60. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/credit_analyzer.py +0 -0
  61. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/credits.py +0 -0
  62. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/__init__.py +0 -0
  63. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/base.py +0 -0
  64. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/citations.py +0 -0
  65. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/fpd.py +0 -0
  66. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/odp.py +0 -0
  67. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/patentsview.py +0 -0
  68. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/pfw.py +0 -0
  69. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/ppubs.py +0 -0
  70. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/datasources/ptab.py +0 -0
  71. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/differ.py +0 -0
  72. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/doctor.py +0 -0
  73. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/drive.py +0 -0
  74. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/editor.py +0 -0
  75. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/__init__.py +0 -0
  76. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/belief.py +0 -0
  77. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/certainty.py +0 -0
  78. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/failure_graph.py +0 -0
  79. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/recovery.py +0 -0
  80. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/epistemic/stress_tester.py +0 -0
  81. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/executor.py +0 -0
  82. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/exporter.py +0 -0
  83. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/__init__.py +0 -0
  84. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/app.py +0 -0
  85. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/main_window.py +0 -0
  86. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/session_tab.py +0 -0
  87. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/theme.py +0 -0
  88. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/__init__.py +0 -0
  89. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/chat_view.py +0 -0
  90. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/input_bar.py +0 -0
  91. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  92. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/token_meter.py +0 -0
  93. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  94. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/widgets/update_checker.py +0 -0
  95. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/gui/worker.py +0 -0
  96. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/history_search.py +0 -0
  97. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/importer.py +0 -0
  98. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/instinct.py +0 -0
  99. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/__init__.py +0 -0
  100. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/agent_skill.py +0 -0
  101. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/aider.py +0 -0
  102. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/base.py +0 -0
  103. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/claude_code.py +0 -0
  104. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/copilot.py +0 -0
  105. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/cursor.py +0 -0
  106. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/gemini.py +0 -0
  107. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/integrations/windsurf.py +0 -0
  108. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/languages.py +0 -0
  109. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/ledger.py +0 -0
  110. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/patent.py +0 -0
  111. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/paths.py +0 -0
  112. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/phase.py +0 -0
  113. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/plugins.py +0 -0
  114. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/profiles.py +0 -0
  115. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/rate_limits.py +0 -0
  116. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/releaser.py +0 -0
  117. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/requirements.py +0 -0
  118. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/requirements_parser.py +0 -0
  119. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/retrieval.py +0 -0
  120. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/safe_write.py +0 -0
  121. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/scaffolder.py +0 -0
  122. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/serve.py +0 -0
  123. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/session.py +0 -0
  124. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/skills.py +0 -0
  125. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/sync.py +0 -0
  126. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/agents.md.j2 +0 -0
  127. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  128. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  129. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  130. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  131. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  132. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  133. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  134. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/community/security.md.j2 +0 -0
  135. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  136. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  137. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  138. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  139. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  140. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/editorconfig.j2 +0 -0
  141. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/gitattributes.j2 +0 -0
  142. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/gitignore.j2 +0 -0
  143. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/go/go.mod.j2 +0 -0
  144. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/go/main.go.j2 +0 -0
  145. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  146. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  147. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  148. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  149. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  150. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
  151. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  152. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  153. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
  154. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  155. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  156. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/js/package.json.j2 +0 -0
  157. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/ledger.md.j2 +0 -0
  158. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/python/cli.py.j2 +0 -0
  159. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/python/init.py.j2 +0 -0
  160. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  161. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/readme.md.j2 +0 -0
  162. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  163. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  164. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  165. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  166. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  167. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  168. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  169. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  170. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  171. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/tool_installer.py +0 -0
  172. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/toolrules.py +0 -0
  173. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/tools.py +0 -0
  174. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/trace.py +0 -0
  175. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/updater.py +0 -0
  176. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/upgrader.py +0 -0
  177. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/validator.py +0 -0
  178. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/__init__.py +0 -0
  179. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/base.py +0 -0
  180. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/bitbucket.py +0 -0
  181. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/github.py +0 -0
  182. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs/gitlab.py +0 -0
  183. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/vcs_commands.py +0 -0
  184. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/wireframes.py +0 -0
  185. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith/workspace.py +0 -0
  186. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/dependency_links.txt +0 -0
  187. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/entry_points.txt +0 -0
  188. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/requires.txt +0 -0
  189. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/src/specsmith.egg-info/top_level.txt +0 -0
  190. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_CMD_001.py +0 -0
  191. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_agent_profiles.py +0 -0
  192. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_agent_runner_ready.py +0 -0
  193. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_auditor.py +0 -0
  194. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_chat_diff_decision.py +0 -0
  195. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_chat_runner_openai_compat.py +0 -0
  196. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_chat_stdin_protocol.py +0 -0
  197. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_cli.py +0 -0
  198. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_cli_workflows_history_drive.py +0 -0
  199. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_compliance.py +0 -0
  200. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_compressor.py +0 -0
  201. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_e2e_nexus.py +0 -0
  202. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_endpoints_cli.py +0 -0
  203. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_endpoints_store.py +0 -0
  204. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_epistemic.py +0 -0
  205. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_fallback_chain.py +0 -0
  206. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_importer.py +0 -0
  207. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_integrations.py +0 -0
  208. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_mcp_client.py +0 -0
  209. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_nexus.py +0 -0
  210. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_permissions.py +0 -0
  211. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_phase1_4_new.py +0 -0
  212. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_phase34_completion.py +0 -0
  213. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_rate_limits.py +0 -0
  214. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_scaffolder.py +0 -0
  215. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_skill_marketplace.py +0 -0
  216. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_smoke.py +0 -0
  217. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_suggester.py +0 -0
  218. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_tools.py +0 -0
  219. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_validator.py +0 -0
  220. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_vcs.py +0 -0
  221. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_warp_parity.py +0 -0
  222. {specsmith-0.10.1.dev283 → specsmith-0.10.1.dev287}/tests/test_warp_parity_followup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.10.1.dev283
3
+ Version: 0.10.1.dev287
4
4
  Summary: Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands.
5
5
  Author: BitConcepts
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specsmith"
7
- version = "0.10.1.dev283"
7
+ version = "0.10.1.dev287"
8
8
  description = "Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -7965,16 +7965,20 @@ main.add_command(rules_group)
7965
7965
  # ---------------------------------------------------------------------------
7966
7966
  try:
7967
7967
  from specsmith.commands.intelligence import (
7968
+ compliance_group,
7968
7969
  datasources_group,
7969
7970
  models_group,
7970
7971
  profiles_group,
7971
7972
  providers_group,
7973
+ session_group,
7972
7974
  )
7973
7975
 
7974
7976
  main.add_command(providers_group)
7975
7977
  main.add_command(profiles_group)
7976
7978
  main.add_command(datasources_group)
7977
7979
  main.add_command(models_group)
7980
+ main.add_command(compliance_group)
7981
+ main.add_command(session_group)
7978
7982
  except Exception: # noqa: BLE001
7979
7983
  pass # graceful degradation if commands module has issues
7980
7984
 
@@ -290,3 +290,127 @@ def models_rank(role: str, provider_type: str) -> None:
290
290
  click.echo(f"Top models for '{role}':")
291
291
  for model, score in ranked[:10]:
292
292
  click.echo(f" {score:5.1f} {model}")
293
+
294
+
295
+ # ---------------------------------------------------------------------------
296
+ # specsmith compliance
297
+ # ---------------------------------------------------------------------------
298
+
299
+
300
+ @click.group("compliance")
301
+ def compliance_group() -> None:
302
+ """Compliance scoring, gaps, and traceability."""
303
+
304
+
305
+ @compliance_group.command("summary")
306
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
307
+ @click.option("--json-output", "as_json", is_flag=True)
308
+ def compliance_summary(project_dir: str, as_json: bool) -> None:
309
+ """Show overall compliance score and coverage."""
310
+ from specsmith.compliance import get_compliance_summary
311
+
312
+ s = get_compliance_summary(project_dir)
313
+ if as_json:
314
+ click.echo(json.dumps(s.to_dict(), indent=2))
315
+ else:
316
+ click.echo(f" Requirements: {s.covered_requirements}/{s.total_requirements} covered")
317
+ click.echo(f" Tests: {s.total_tests}")
318
+ click.echo(f" Coverage: {s.requirement_coverage_pct}%")
319
+ click.echo(f" Score: {s.compliance_score}%")
320
+ if s.uncovered_requirements:
321
+ click.echo(f" Uncovered: {', '.join(s.uncovered_requirements[:10])}")
322
+
323
+
324
+ @compliance_group.command("gaps")
325
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
326
+ def compliance_gaps(project_dir: str) -> None:
327
+ """Show uncovered requirements and orphaned tests."""
328
+ from specsmith.compliance import get_compliance_summary
329
+
330
+ s = get_compliance_summary(project_dir)
331
+ if s.uncovered_requirements:
332
+ click.echo(f"Uncovered requirements ({len(s.uncovered_requirements)}):")
333
+ for r in s.uncovered_requirements:
334
+ click.echo(f" \u2717 {r}")
335
+ else:
336
+ click.echo("\u2713 All requirements have test coverage.")
337
+ if s.orphaned_tests:
338
+ click.echo(f"\nOrphaned tests ({len(s.orphaned_tests)}):")
339
+ for t in s.orphaned_tests:
340
+ click.echo(f" \u26a0 {t}")
341
+
342
+
343
+ @compliance_group.command("trace")
344
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
345
+ @click.option("--json-output", "as_json", is_flag=True)
346
+ def compliance_trace(project_dir: str, as_json: bool) -> None:
347
+ """Show REQ \u2192 TEST traceability matrix."""
348
+ from specsmith.compliance import get_compliance_summary
349
+
350
+ s = get_compliance_summary(project_dir)
351
+ if as_json:
352
+ click.echo(json.dumps(s.trace_matrix, indent=2))
353
+ else:
354
+ for entry in s.trace_matrix:
355
+ icon = "\u2713" if entry["covered"] else "\u2717"
356
+ tests = ", ".join(entry["tests"]) if entry["tests"] else "(none)"
357
+ click.echo(f" {icon} {entry['requirement_id']:<12} \u2192 {tests}")
358
+
359
+
360
+ @compliance_group.command("rules")
361
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
362
+ def compliance_rules(project_dir: str) -> None:
363
+ """Show governance hard rules status (H1-H14)."""
364
+ from specsmith.compliance import get_governance_rules_status
365
+
366
+ rules = get_governance_rules_status(project_dir)
367
+ for r in rules:
368
+ icon = {"ok": "\u2713", "warning": "\u26a0", "violation": "\u2717"}.get(r["status"], "?")
369
+ click.echo(f" {icon} {r['id']}: {r['name']}")
370
+
371
+
372
+ # ---------------------------------------------------------------------------
373
+ # specsmith session
374
+ # ---------------------------------------------------------------------------
375
+
376
+
377
+ @click.group("session")
378
+ def session_group() -> None:
379
+ """Session lifecycle management."""
380
+
381
+
382
+ @session_group.command("info")
383
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
384
+ @click.option("--json-output", "as_json", is_flag=True)
385
+ def session_info(project_dir: str, as_json: bool) -> None:
386
+ """Show current session context."""
387
+ from specsmith.session_init import init_session
388
+
389
+ ctx = init_session(project_dir)
390
+ if as_json:
391
+ click.echo(json.dumps(ctx.to_dict(), indent=2))
392
+ else:
393
+ gov = "\u2713" if ctx.is_governed else "\u2717"
394
+ click.echo(f" Project: {ctx.project_name}")
395
+ click.echo(f" Governed: {gov}")
396
+ phase = ctx.phase_emoji
397
+ label = ctx.phase_label
398
+ pct = ctx.phase_readiness_pct
399
+ click.echo(f" Phase: {phase} {label} ({pct}%)")
400
+ click.echo(f" Health: {ctx.health_score}%")
401
+ click.echo(f" Compliance: {ctx.compliance_score}%")
402
+ click.echo(f" Profile: {ctx.active_profile}")
403
+ rp = ctx.reachable_providers
404
+ pc = ctx.provider_count
405
+ click.echo(f" Providers: {rp}/{pc} reachable")
406
+ click.echo(f" Session: {ctx.session_id}")
407
+ if ctx.needs_import:
408
+ click.echo(
409
+ "\n \u26a0 Not a specsmith project. Run 'specsmith import' to add governance."
410
+ )
411
+ if ctx.needs_migration:
412
+ sv = ctx.spec_version
413
+ iv = ctx.installed_version
414
+ click.echo(
415
+ f"\n \u26a0 Spec version mismatch ({sv} vs {iv}). Run 'specsmith migrate-project'."
416
+ )
@@ -0,0 +1,232 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
3
+ """Compliance scoring and reporting (REQ-224).
4
+
5
+ Provides compliance summary, requirement gaps, test coverage, and
6
+ traceability matrix. Used by both CLI commands and REST endpoints.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import re
12
+ from dataclasses import dataclass, field
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+
17
+ @dataclass
18
+ class ComplianceSummary:
19
+ """Overall compliance status for a project."""
20
+
21
+ total_requirements: int = 0
22
+ covered_requirements: int = 0
23
+ uncovered_requirements: list[str] = field(default_factory=list)
24
+ total_tests: int = 0
25
+ orphaned_tests: list[str] = field(default_factory=list)
26
+ compliance_score: int = 0 # 0-100
27
+ requirement_coverage_pct: int = 0
28
+ trace_matrix: list[dict[str, Any]] = field(default_factory=list)
29
+
30
+ def to_dict(self) -> dict[str, Any]:
31
+ return {
32
+ "total_requirements": self.total_requirements,
33
+ "covered_requirements": self.covered_requirements,
34
+ "uncovered_requirements": self.uncovered_requirements,
35
+ "total_tests": self.total_tests,
36
+ "orphaned_tests": self.orphaned_tests,
37
+ "compliance_score": self.compliance_score,
38
+ "requirement_coverage_pct": self.requirement_coverage_pct,
39
+ "trace_count": len(self.trace_matrix),
40
+ }
41
+
42
+
43
+ def _parse_requirements(root: Path) -> dict[str, dict[str, str]]:
44
+ """Parse REQUIREMENTS.md into {req_id: {title, status, ...}}."""
45
+ req_path = root / "docs" / "REQUIREMENTS.md"
46
+ if not req_path.is_file():
47
+ req_path = root / "REQUIREMENTS.md"
48
+ if not req_path.is_file():
49
+ return {}
50
+
51
+ text = req_path.read_text(encoding="utf-8", errors="replace")
52
+ reqs: dict[str, dict[str, str]] = {}
53
+
54
+ # Parse markdown sections: ## N. Title\n- **ID:** REQ-NNN
55
+ blocks = re.split(r"\n## ", text)
56
+ for block in blocks:
57
+ id_match = re.search(r"\*\*ID:\*\*\s*(REQ-\d+)", block)
58
+ if not id_match:
59
+ # Try alternate format: ## REQ-NNN
60
+ id_match = re.search(r"^(REQ-\d+)", block.strip())
61
+ if id_match:
62
+ req_id = id_match.group(1)
63
+ title_match = re.search(r"\*\*Title:\*\*\s*(.+)", block)
64
+ status_match = re.search(r"\*\*Status:\*\*\s*(.+)", block)
65
+ reqs[req_id] = {
66
+ "id": req_id,
67
+ "title": title_match.group(1).strip() if title_match else "",
68
+ "status": status_match.group(1).strip() if status_match else "draft",
69
+ }
70
+
71
+ return reqs
72
+
73
+
74
+ def _parse_tests(root: Path) -> dict[str, dict[str, str]]:
75
+ """Parse TESTS.md into {test_id: {title, requirement_id, ...}}."""
76
+ test_path = root / "docs" / "TESTS.md"
77
+ if not test_path.is_file():
78
+ test_path = root / "TESTS.md"
79
+ if not test_path.is_file():
80
+ return {}
81
+
82
+ text = test_path.read_text(encoding="utf-8", errors="replace")
83
+ tests: dict[str, dict[str, str]] = {}
84
+
85
+ blocks = re.split(r"\n## ", text)
86
+ for block in blocks:
87
+ id_match = re.search(r"\*\*ID:\*\*\s*(TEST-\d+)", block)
88
+ if not id_match:
89
+ id_match = re.search(r"^(TEST-\d+)", block.strip())
90
+ if id_match:
91
+ test_id = id_match.group(1)
92
+ req_match = re.search(r"\*\*Requirement(?:\s+ID)?:\*\*\s*(REQ-\d+)", block)
93
+ title_match = re.search(r"\*\*Title:\*\*\s*(.+)", block)
94
+ tests[test_id] = {
95
+ "id": test_id,
96
+ "title": title_match.group(1).strip() if title_match else "",
97
+ "requirement_id": req_match.group(1) if req_match else "",
98
+ }
99
+
100
+ return tests
101
+
102
+
103
+ def get_compliance_summary(project_dir: str | Path = ".") -> ComplianceSummary:
104
+ """Compute full compliance summary for a project."""
105
+ root = Path(project_dir).resolve()
106
+ reqs = _parse_requirements(root)
107
+ tests = _parse_tests(root)
108
+
109
+ # Build coverage map
110
+ covered_req_ids: set[str] = set()
111
+ for test in tests.values():
112
+ req_id = test.get("requirement_id", "")
113
+ if req_id and req_id in reqs:
114
+ covered_req_ids.add(req_id)
115
+
116
+ uncovered = [r for r in reqs if r not in covered_req_ids]
117
+
118
+ # Find orphaned tests (reference non-existent requirements)
119
+ orphaned = []
120
+ for test in tests.values():
121
+ req_id = test.get("requirement_id", "")
122
+ if req_id and req_id not in reqs:
123
+ orphaned.append(f"{test['id']} -> {req_id}")
124
+
125
+ total = len(reqs)
126
+ covered = len(covered_req_ids)
127
+ coverage_pct = int(covered / total * 100) if total > 0 else 0
128
+
129
+ # Build trace matrix
130
+ trace: list[dict[str, Any]] = []
131
+ for req_id, req in sorted(reqs.items()):
132
+ linked_tests = [t["id"] for t in tests.values() if t.get("requirement_id") == req_id]
133
+ trace.append(
134
+ {
135
+ "requirement_id": req_id,
136
+ "title": req.get("title", ""),
137
+ "status": req.get("status", ""),
138
+ "tests": linked_tests,
139
+ "covered": len(linked_tests) > 0,
140
+ }
141
+ )
142
+
143
+ return ComplianceSummary(
144
+ total_requirements=total,
145
+ covered_requirements=covered,
146
+ uncovered_requirements=uncovered,
147
+ total_tests=len(tests),
148
+ orphaned_tests=orphaned,
149
+ compliance_score=coverage_pct,
150
+ requirement_coverage_pct=coverage_pct,
151
+ trace_matrix=trace,
152
+ )
153
+
154
+
155
+ def get_governance_rules_status(project_dir: str | Path = ".") -> list[dict[str, Any]]:
156
+ """Return status of hard governance rules (H1-H14)."""
157
+ root = Path(project_dir).resolve()
158
+
159
+ rules = [
160
+ {"id": "H1", "name": "Ledger required", "description": "No ledger entry = work not done"},
161
+ {"id": "H2", "name": "Proposal required", "description": "No proposal = no execution"},
162
+ {
163
+ "id": "H3",
164
+ "name": "Cross-platform awareness",
165
+ "description": "All work must consider every target platform",
166
+ },
167
+ {
168
+ "id": "H4",
169
+ "name": "Environment isolation",
170
+ "description": "No system-dependent assumptions",
171
+ },
172
+ {"id": "H5", "name": "Explicit startup", "description": "No hidden service logic"},
173
+ {
174
+ "id": "H6",
175
+ "name": "No silent scope expansion",
176
+ "description": "If task grows, stop and re-propose",
177
+ },
178
+ {
179
+ "id": "H7",
180
+ "name": "No undocumented state changes",
181
+ "description": "Every change must be traceable",
182
+ },
183
+ {
184
+ "id": "H8",
185
+ "name": "Documentation is implementation",
186
+ "description": "Architecture changes MUST update docs",
187
+ },
188
+ {
189
+ "id": "H9",
190
+ "name": "Execution timeout required",
191
+ "description": "All agent commands must have timeouts",
192
+ },
193
+ {
194
+ "id": "H10",
195
+ "name": "No hardcoded versions",
196
+ "description": "Use importlib.metadata at runtime",
197
+ },
198
+ {
199
+ "id": "H11",
200
+ "name": "No unbounded loops",
201
+ "description": "Every loop must have a deadline",
202
+ },
203
+ {
204
+ "id": "H12",
205
+ "name": "Windows automation via .cmd",
206
+ "description": "Multi-step automation uses .cmd files",
207
+ },
208
+ {
209
+ "id": "H13",
210
+ "name": "Epistemic boundaries required",
211
+ "description": "Proposals must state assumptions",
212
+ },
213
+ {
214
+ "id": "H14",
215
+ "name": "Documentation freshness",
216
+ "description": "Docs updated in same commit as code",
217
+ },
218
+ ]
219
+
220
+ # Quick checks for common violations
221
+ ledger_exists = (root / "docs" / "LEDGER.md").is_file() or (root / "LEDGER.md").is_file()
222
+ agents_exists = (root / "AGENTS.md").is_file()
223
+
224
+ for rule in rules:
225
+ rule["status"] = "ok" # default
226
+
227
+ if not ledger_exists:
228
+ rules[0]["status"] = "violation"
229
+ if not agents_exists:
230
+ rules[1]["status"] = "warning"
231
+
232
+ return rules
@@ -485,6 +485,151 @@ class GovernanceHTTPServer:
485
485
 
486
486
  if self.path in ("/health", "/api/health"):
487
487
  self._json_ok({"status": "ok", "version": __version__})
488
+
489
+ # ── Session ────────────────────────────────────────────
490
+ elif self.path == "/api/session":
491
+ try:
492
+ from specsmith.session_init import init_session
493
+
494
+ ctx = init_session(project_dir)
495
+ self._json_ok(ctx.to_dict())
496
+ except Exception as exc: # noqa: BLE001
497
+ self._json_err(str(exc), code=500)
498
+
499
+ # ── Compliance ─────────────────────────────────────────
500
+ elif self.path == "/api/compliance/summary":
501
+ try:
502
+ from specsmith.compliance import get_compliance_summary
503
+
504
+ s = get_compliance_summary(project_dir)
505
+ self._json_ok(s.to_dict())
506
+ except Exception as exc: # noqa: BLE001
507
+ self._json_err(str(exc), code=500)
508
+ elif self.path == "/api/compliance/gaps":
509
+ try:
510
+ from specsmith.compliance import get_compliance_summary
511
+
512
+ s = get_compliance_summary(project_dir)
513
+ self._json_ok(
514
+ {"uncovered": s.uncovered_requirements, "orphaned": s.orphaned_tests}
515
+ )
516
+ except Exception as exc: # noqa: BLE001
517
+ self._json_err(str(exc), code=500)
518
+ elif self.path == "/api/compliance/trace":
519
+ try:
520
+ from specsmith.compliance import get_compliance_summary
521
+
522
+ s = get_compliance_summary(project_dir)
523
+ self._json_ok({"trace_matrix": s.trace_matrix})
524
+ except Exception as exc: # noqa: BLE001
525
+ self._json_err(str(exc), code=500)
526
+
527
+ # ── Governance ─────────────────────────────────────────
528
+ elif self.path == "/api/governance/rules":
529
+ try:
530
+ from specsmith.compliance import get_governance_rules_status
531
+
532
+ self._json_ok({"rules": get_governance_rules_status(project_dir)})
533
+ except Exception as exc: # noqa: BLE001
534
+ self._json_err(str(exc), code=500)
535
+ elif self.path == "/api/governance/phase":
536
+ try:
537
+ from specsmith.phase import PHASE_MAP, phase_progress_pct, read_phase
538
+
539
+ root = Path(project_dir).resolve()
540
+ key = read_phase(root)
541
+ phase = PHASE_MAP[key]
542
+ self._json_ok(
543
+ {
544
+ "phase": key,
545
+ "label": phase.label,
546
+ "emoji": phase.emoji,
547
+ "readiness_pct": phase_progress_pct(phase, root),
548
+ }
549
+ )
550
+ except Exception as exc: # noqa: BLE001
551
+ self._json_err(str(exc), code=500)
552
+ elif self.path == "/api/governance/audit":
553
+ try:
554
+ from specsmith.auditor import run_audit
555
+
556
+ report = run_audit(Path(project_dir).resolve())
557
+ self._json_ok(
558
+ {
559
+ "healthy": report.healthy,
560
+ "passed": report.passed,
561
+ "failed": report.failed,
562
+ "results": [
563
+ {"passed": r.passed, "message": r.message}
564
+ for r in report.results
565
+ ],
566
+ }
567
+ )
568
+ except Exception as exc: # noqa: BLE001
569
+ self._json_err(str(exc), code=500)
570
+
571
+ # ── Providers ──────────────────────────────────────────
572
+ elif self.path == "/api/providers":
573
+ try:
574
+ from specsmith.agent.provider_registry import ProviderRegistry
575
+
576
+ reg = ProviderRegistry.load()
577
+ self._json_ok({"providers": [p.to_public_dict() for p in reg.providers]})
578
+ except Exception as exc: # noqa: BLE001
579
+ self._json_err(str(exc), code=500)
580
+
581
+ # ── Profiles ───────────────────────────────────────────
582
+ elif self.path == "/api/profiles":
583
+ try:
584
+ from specsmith.agent.execution_profiles import ExecutionProfileStore
585
+
586
+ store = ExecutionProfileStore.load()
587
+ self._json_ok(
588
+ {
589
+ "profiles": [p.to_dict() for p in store.profiles],
590
+ "default": store.default().id,
591
+ }
592
+ )
593
+ except Exception as exc: # noqa: BLE001
594
+ self._json_err(str(exc), code=500)
595
+
596
+ # ── Model Scores ───────────────────────────────────────
597
+ elif self.path.startswith("/api/models/scores"):
598
+ try:
599
+ import urllib.parse as _up
600
+
601
+ from specsmith.agent.model_intelligence import (
602
+ BASELINE_SCORES,
603
+ rank_models_for_role,
604
+ )
605
+
606
+ qs = _up.urlparse(self.path).query
607
+ params = _up.parse_qs(qs)
608
+ role = params.get("role", ["coder"])[0]
609
+ models = list(BASELINE_SCORES.keys())
610
+ ranked = rank_models_for_role(role, models)
611
+ self._json_ok(
612
+ {"role": role, "scores": [{"model": m, "score": s} for m, s in ranked]}
613
+ )
614
+ except Exception as exc: # noqa: BLE001
615
+ self._json_err(str(exc), code=500)
616
+
617
+ # ── Datasources ────────────────────────────────────────
618
+ elif self.path == "/api/datasources":
619
+ try:
620
+ sources = [
621
+ {"id": "patentsview", "name": "PatentsView"},
622
+ {"id": "ppubs", "name": "Patent Public Search (PPUBS)"},
623
+ {"id": "odp", "name": "USPTO Open Data Portal"},
624
+ {"id": "pfw", "name": "Patent File Wrapper"},
625
+ {"id": "citations", "name": "USPTO Enriched Citations"},
626
+ {"id": "fpd", "name": "Final Petition Decisions"},
627
+ {"id": "ptab", "name": "USPTO PTAB"},
628
+ ]
629
+ self._json_ok({"datasources": sources})
630
+ except Exception as exc: # noqa: BLE001
631
+ self._json_err(str(exc), code=500)
632
+
488
633
  else:
489
634
  self.send_error(404)
490
635