specsmith 0.3.13.dev211__tar.gz → 0.3.13.dev213__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 (180) hide show
  1. {specsmith-0.3.13.dev211/src/specsmith.egg-info → specsmith-0.3.13.dev213}/PKG-INFO +1 -1
  2. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/pyproject.toml +1 -1
  3. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/cli.py +38 -0
  4. specsmith-0.3.13.dev213/src/specsmith/serve.py +291 -0
  5. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213/src/specsmith.egg-info}/PKG-INFO +1 -1
  6. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith.egg-info/SOURCES.txt +1 -0
  7. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/LICENSE +0 -0
  8. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/README.md +0 -0
  9. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/setup.cfg +0 -0
  10. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/epistemic/__init__.py +0 -0
  11. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/epistemic/belief.py +0 -0
  12. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/epistemic/certainty.py +0 -0
  13. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/epistemic/failure_graph.py +0 -0
  14. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/epistemic/py.typed +0 -0
  15. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/epistemic/recovery.py +0 -0
  16. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/epistemic/session.py +0 -0
  17. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/epistemic/stress_tester.py +0 -0
  18. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/epistemic/trace.py +0 -0
  19. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/__init__.py +0 -0
  20. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/__main__.py +0 -0
  21. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/__init__.py +0 -0
  22. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/core.py +0 -0
  23. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/hooks.py +0 -0
  24. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/optimizer.py +0 -0
  25. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/profiles/epistemic-auditor.md +0 -0
  26. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/profiles/planner.md +0 -0
  27. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/profiles/verifier.md +0 -0
  28. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/providers/__init__.py +0 -0
  29. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/providers/anthropic.py +0 -0
  30. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/providers/gemini.py +0 -0
  31. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/providers/mistral.py +0 -0
  32. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/providers/ollama.py +0 -0
  33. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/providers/openai.py +0 -0
  34. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/runner.py +0 -0
  35. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/skills.py +0 -0
  36. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agent/tools.py +0 -0
  37. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/__init__.py +0 -0
  38. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/cli.py +0 -0
  39. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/config.py +0 -0
  40. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/reports.py +0 -0
  41. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/roles.py +0 -0
  42. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/tools/__init__.py +0 -0
  43. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/tools/filesystem.py +0 -0
  44. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/tools/git.py +0 -0
  45. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/tools/shell.py +0 -0
  46. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/tools/tests.py +0 -0
  47. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/workflows/__init__.py +0 -0
  48. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/agents/workflows/improve.py +0 -0
  49. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/architect.py +0 -0
  50. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/auditor.py +0 -0
  51. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/auth.py +0 -0
  52. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/commands/__init__.py +0 -0
  53. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/compressor.py +0 -0
  54. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/config.py +0 -0
  55. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/credit_analyzer.py +0 -0
  56. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/credits.py +0 -0
  57. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/differ.py +0 -0
  58. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/doctor.py +0 -0
  59. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/epistemic/__init__.py +0 -0
  60. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/epistemic/belief.py +0 -0
  61. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/epistemic/certainty.py +0 -0
  62. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/epistemic/failure_graph.py +0 -0
  63. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/epistemic/recovery.py +0 -0
  64. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/epistemic/stress_tester.py +0 -0
  65. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/executor.py +0 -0
  66. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/exporter.py +0 -0
  67. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/__init__.py +0 -0
  68. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/app.py +0 -0
  69. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/main_window.py +0 -0
  70. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/session_tab.py +0 -0
  71. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/theme.py +0 -0
  72. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/widgets/__init__.py +0 -0
  73. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/widgets/chat_view.py +0 -0
  74. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/widgets/input_bar.py +0 -0
  75. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  76. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/widgets/token_meter.py +0 -0
  77. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  78. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/widgets/update_checker.py +0 -0
  79. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/gui/worker.py +0 -0
  80. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/importer.py +0 -0
  81. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/integrations/__init__.py +0 -0
  82. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/integrations/aider.py +0 -0
  83. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/integrations/base.py +0 -0
  84. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/integrations/claude_code.py +0 -0
  85. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/integrations/copilot.py +0 -0
  86. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/integrations/cursor.py +0 -0
  87. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/integrations/gemini.py +0 -0
  88. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/integrations/warp.py +0 -0
  89. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/integrations/windsurf.py +0 -0
  90. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/languages.py +0 -0
  91. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/ledger.py +0 -0
  92. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/ollama_cmds.py +0 -0
  93. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/patent.py +0 -0
  94. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/phase.py +0 -0
  95. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/plugins.py +0 -0
  96. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/profiles.py +0 -0
  97. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/rate_limits.py +0 -0
  98. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/releaser.py +0 -0
  99. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/requirements.py +0 -0
  100. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/retrieval.py +0 -0
  101. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/scaffolder.py +0 -0
  102. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/session.py +0 -0
  103. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/agents.md.j2 +0 -0
  104. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  105. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  106. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  107. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  108. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  109. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  110. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  111. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/community/security.md.j2 +0 -0
  112. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  113. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  114. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  115. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  116. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  117. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/editorconfig.j2 +0 -0
  118. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/gitattributes.j2 +0 -0
  119. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/gitignore.j2 +0 -0
  120. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/go/go.mod.j2 +0 -0
  121. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/go/main.go.j2 +0 -0
  122. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  123. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  124. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  125. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  126. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  127. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
  128. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  129. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  130. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
  131. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  132. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  133. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/js/package.json.j2 +0 -0
  134. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/ledger.md.j2 +0 -0
  135. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/python/cli.py.j2 +0 -0
  136. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/python/init.py.j2 +0 -0
  137. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  138. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/readme.md.j2 +0 -0
  139. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  140. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  141. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  142. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  143. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  144. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  145. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  146. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  147. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  148. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/tool_installer.py +0 -0
  149. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/toolrules.py +0 -0
  150. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/tools.py +0 -0
  151. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/trace.py +0 -0
  152. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/updater.py +0 -0
  153. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/upgrader.py +0 -0
  154. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/validator.py +0 -0
  155. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/vcs/__init__.py +0 -0
  156. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/vcs/base.py +0 -0
  157. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/vcs/bitbucket.py +0 -0
  158. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/vcs/github.py +0 -0
  159. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/vcs/gitlab.py +0 -0
  160. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/vcs_commands.py +0 -0
  161. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/wireframes.py +0 -0
  162. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith/workspace.py +0 -0
  163. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith.egg-info/dependency_links.txt +0 -0
  164. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith.egg-info/entry_points.txt +0 -0
  165. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith.egg-info/requires.txt +0 -0
  166. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/src/specsmith.egg-info/top_level.txt +0 -0
  167. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_agent.py +0 -0
  168. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_auditor.py +0 -0
  169. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_cli.py +0 -0
  170. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_compressor.py +0 -0
  171. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_epistemic.py +0 -0
  172. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_importer.py +0 -0
  173. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_integrations.py +0 -0
  174. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_optimizer.py +0 -0
  175. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_rate_limits.py +0 -0
  176. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_scaffolder.py +0 -0
  177. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_smoke.py +0 -0
  178. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_tools.py +0 -0
  179. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_validator.py +0 -0
  180. {specsmith-0.3.13.dev211 → specsmith-0.3.13.dev213}/tests/test_vcs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.3.13.dev211
3
+ Version: 0.3.13.dev213
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.3.13.dev211"
7
+ version = "0.3.13.dev213"
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"
@@ -2064,6 +2064,44 @@ def run_cmd(
2064
2064
  raise SystemExit(1) from None
2065
2065
 
2066
2066
 
2067
+ @main.command(name="serve")
2068
+ @click.option(
2069
+ "--project-dir",
2070
+ type=click.Path(exists=True),
2071
+ default=".",
2072
+ help="Project root directory.",
2073
+ )
2074
+ @click.option("--provider", default="ollama", help="LLM provider.")
2075
+ @click.option("--model", default="", help="Model name (blank = provider default).")
2076
+ @click.option("--port", type=int, default=8421, help="HTTP port to listen on.")
2077
+ @click.option("--host", default="127.0.0.1", help="Bind address (use 0.0.0.0 for network access).")
2078
+ def serve_cmd(
2079
+ project_dir: str,
2080
+ provider: str,
2081
+ model: str,
2082
+ port: int,
2083
+ host: str,
2084
+ ) -> None:
2085
+ """Start a persistent HTTP server for agent sessions.
2086
+
2087
+ Faster than `specsmith run` — keeps the Python process and Ollama
2088
+ model warm between turns. Connect via SSE (GET /api/events) and
2089
+ POST /api/send.
2090
+
2091
+ Example:
2092
+ specsmith serve --port 8421 --provider ollama --model qwen2.5:14b
2093
+ """
2094
+ from specsmith.serve import run_server
2095
+
2096
+ run_server(
2097
+ project_dir=project_dir,
2098
+ provider=provider,
2099
+ model=model,
2100
+ port=port,
2101
+ host=host,
2102
+ )
2103
+
2104
+
2067
2105
  @main.group(name="agent")
2068
2106
  def agent_group() -> None:
2069
2107
  """Manage the specsmith agentic client configuration."""
@@ -0,0 +1,291 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
3
+ """specsmith serve — persistent HTTP server for agent sessions.
4
+
5
+ Replaces the stdio-based ``specsmith run --json-events`` with an HTTP
6
+ server that can be connected to by multiple clients (VS Code, browser,
7
+ scripts) without restarting the Python process or cold-loading the
8
+ Ollama model.
9
+
10
+ Endpoints:
11
+ POST /api/send — send a user message (body: {"text": "..."})
12
+ GET /api/events — SSE stream of JSONL events
13
+ GET /api/status — session state JSON
14
+ POST /api/stop — stop the current turn
15
+ GET /api/health — liveness probe
16
+
17
+ Launch:
18
+ specsmith serve --port 8421 --project-dir .
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import contextlib
24
+ import json
25
+ import queue
26
+ import sys
27
+ import threading
28
+ from http.server import BaseHTTPRequestHandler, HTTPServer
29
+ from pathlib import Path
30
+ from socketserver import ThreadingMixIn
31
+ from typing import Any
32
+
33
+
34
+ class _ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
35
+ """Non-blocking HTTP server (one thread per request)."""
36
+
37
+ daemon_threads = True
38
+ allow_reuse_address = True
39
+
40
+
41
+ class _EventBus:
42
+ """Thread-safe event bus — the agent thread pushes events, SSE
43
+ clients consume them. Supports multiple concurrent SSE listeners."""
44
+
45
+ def __init__(self) -> None:
46
+ self._listeners: list[queue.Queue[dict[str, Any] | None]] = []
47
+ self._lock = threading.Lock()
48
+
49
+ def subscribe(self) -> queue.Queue[dict[str, Any] | None]:
50
+ q: queue.Queue[dict[str, Any] | None] = queue.Queue(maxsize=512)
51
+ with self._lock:
52
+ self._listeners.append(q)
53
+ return q
54
+
55
+ def unsubscribe(self, q: queue.Queue[dict[str, Any] | None]) -> None:
56
+ with self._lock, contextlib.suppress(ValueError):
57
+ self._listeners.remove(q)
58
+
59
+ def emit(self, event: dict[str, Any]) -> None:
60
+ with self._lock:
61
+ for q in self._listeners:
62
+ with contextlib.suppress(queue.Full):
63
+ q.put_nowait(event)
64
+
65
+
66
+ class _AgentThread:
67
+ """Wraps AgentRunner in a background thread with message passing."""
68
+
69
+ def __init__(
70
+ self,
71
+ project_dir: str,
72
+ provider: str,
73
+ model: str,
74
+ bus: _EventBus,
75
+ ) -> None:
76
+ self._project_dir = project_dir
77
+ self._provider = provider
78
+ self._model = model
79
+ self._bus = bus
80
+ self._inbox: queue.Queue[str | None] = queue.Queue()
81
+ self._runner: Any = None
82
+ self._thread: threading.Thread | None = None
83
+ self._started = False
84
+
85
+ def start(self) -> None:
86
+ self._thread = threading.Thread(target=self._run, daemon=True, name="agent")
87
+ self._thread.start()
88
+
89
+ def send(self, text: str) -> None:
90
+ self._inbox.put(text)
91
+
92
+ def stop_turn(self) -> None:
93
+ """Interrupt the current agent turn (best-effort)."""
94
+ # The runner checks a flag between tool calls
95
+ if self._runner:
96
+ self._runner._hard_stop = True # noqa: SLF001
97
+
98
+ def status(self) -> dict[str, Any]:
99
+ if not self._runner:
100
+ return {"status": "starting"}
101
+ st = self._runner._state # noqa: SLF001
102
+ return {
103
+ "status": "running" if self._started else "starting",
104
+ "provider": st.provider_name,
105
+ "model": st.model_name,
106
+ "tokens": st.session_tokens,
107
+ "cost_usd": st.total_cost_usd,
108
+ "tool_calls": st.tool_calls_made,
109
+ "elapsed_min": round(st.elapsed_minutes, 1),
110
+ }
111
+
112
+ def _run(self) -> None:
113
+ """Agent loop — runs in a background thread."""
114
+ try:
115
+ from specsmith.agent.runner import AgentRunner
116
+
117
+ self._runner = AgentRunner(
118
+ project_dir=self._project_dir,
119
+ provider_name=self._provider,
120
+ model=self._model,
121
+ json_events=True,
122
+ )
123
+
124
+ # Monkey-patch _emit_event to route through the bus
125
+
126
+ def _bus_emit(**kwargs: Any) -> None:
127
+ self._bus.emit(kwargs)
128
+
129
+ self._runner._emit_event = _bus_emit # noqa: SLF001
130
+
131
+ # Print banner (emits 'ready' event)
132
+ self._runner._print_banner() # noqa: SLF001
133
+ self._started = True
134
+
135
+ # Main loop: read from inbox, dispatch to runner
136
+ while True:
137
+ text = self._inbox.get()
138
+ if text is None:
139
+ break # shutdown signal
140
+ try:
141
+ self._runner._handle_command(text) # noqa: SLF001
142
+ except Exception as e: # noqa: BLE001
143
+ self._bus.emit({"type": "error", "message": str(e)})
144
+ self._bus.emit({"type": "turn_done"})
145
+ except Exception as e: # noqa: BLE001
146
+ self._bus.emit({"type": "error", "message": f"Agent crashed: {e}"})
147
+ finally:
148
+ self._bus.emit({"type": "system", "message": "Agent thread ended."})
149
+
150
+
151
+ class _Handler(BaseHTTPRequestHandler):
152
+ """HTTP request handler for the serve endpoints."""
153
+
154
+ bus: _EventBus
155
+ agent: _AgentThread
156
+
157
+ def log_message(self, format: str, *args: Any) -> None: # noqa: A002
158
+ """Suppress default stderr logging."""
159
+
160
+ def do_GET(self) -> None: # noqa: N802
161
+ if self.path == "/api/events":
162
+ self._sse()
163
+ elif self.path == "/api/status":
164
+ self._json_response(self.agent.status())
165
+ elif self.path == "/api/health":
166
+ self._json_response({"ok": True})
167
+ else:
168
+ self.send_error(404)
169
+
170
+ def do_POST(self) -> None: # noqa: N802
171
+ if self.path == "/api/send":
172
+ body = self._read_json()
173
+ text = body.get("text", "").strip() if body else ""
174
+ if not text:
175
+ self._json_response({"error": "missing text"}, code=400)
176
+ return
177
+ self.agent.send(text)
178
+ self._json_response({"ok": True})
179
+ elif self.path == "/api/stop":
180
+ self.agent.stop_turn()
181
+ self._json_response({"ok": True})
182
+ else:
183
+ self.send_error(404)
184
+
185
+ def do_DELETE(self) -> None: # noqa: N802
186
+ if self.path == "/api/session":
187
+ self.agent.send(None) # type: ignore[arg-type]
188
+ self._json_response({"ok": True, "message": "session ending"})
189
+ else:
190
+ self.send_error(404)
191
+
192
+ # ── SSE ────────────────────────────────────────────────────────
193
+
194
+ def _sse(self) -> None:
195
+ self.send_response(200)
196
+ self.send_header("Content-Type", "text/event-stream")
197
+ self.send_header("Cache-Control", "no-cache")
198
+ self.send_header("Connection", "keep-alive")
199
+ self.send_header("Access-Control-Allow-Origin", "*")
200
+ self.end_headers()
201
+
202
+ q = self.bus.subscribe()
203
+ try:
204
+ while True:
205
+ try:
206
+ event = q.get(timeout=30)
207
+ except queue.Empty:
208
+ # Send SSE comment as keepalive
209
+ self.wfile.write(b": keepalive\n\n")
210
+ self.wfile.flush()
211
+ continue
212
+ if event is None:
213
+ break
214
+ data = json.dumps(event, ensure_ascii=False)
215
+ self.wfile.write(f"data: {data}\n\n".encode())
216
+ self.wfile.flush()
217
+ except (BrokenPipeError, ConnectionResetError, OSError):
218
+ pass # client disconnected
219
+ finally:
220
+ self.bus.unsubscribe(q)
221
+
222
+ # ── Helpers ────────────────────────────────────────────────────
223
+
224
+ def _read_json(self) -> dict[str, Any] | None:
225
+ length = int(self.headers.get("Content-Length", 0))
226
+ if length == 0:
227
+ return None
228
+ raw = self.rfile.read(length)
229
+ try:
230
+ result: dict[str, Any] = json.loads(raw)
231
+ return result
232
+ except json.JSONDecodeError:
233
+ return None
234
+
235
+ def _json_response(
236
+ self,
237
+ data: dict[str, Any],
238
+ code: int = 200,
239
+ ) -> None:
240
+ body = json.dumps(data, ensure_ascii=False).encode()
241
+ self.send_response(code)
242
+ self.send_header("Content-Type", "application/json")
243
+ self.send_header("Content-Length", str(len(body)))
244
+ self.send_header("Access-Control-Allow-Origin", "*")
245
+ self.end_headers()
246
+ self.wfile.write(body)
247
+
248
+
249
+ def run_server(
250
+ *,
251
+ project_dir: str = ".",
252
+ provider: str = "ollama",
253
+ model: str = "",
254
+ port: int = 8421,
255
+ host: str = "127.0.0.1",
256
+ ) -> None:
257
+ """Start the specsmith HTTP server."""
258
+ project_dir = str(Path(project_dir).resolve())
259
+ bus = _EventBus()
260
+ agent = _AgentThread(project_dir, provider, model, bus)
261
+
262
+ # Subclass to carry shared state into the handler
263
+ class Handler(_Handler):
264
+ pass
265
+
266
+ Handler.bus = bus
267
+ Handler.agent = agent
268
+
269
+ server = _ThreadedHTTPServer((host, port), Handler)
270
+ agent.start()
271
+
272
+ print( # noqa: T201
273
+ f"specsmith serve — http://{host}:{port}\n"
274
+ f" Project: {project_dir}\n"
275
+ f" Provider: {provider}/{model or '(default)'}\n"
276
+ f" Endpoints:\n"
277
+ f" GET /api/events — SSE event stream\n"
278
+ f" POST /api/send — send a message\n"
279
+ f" GET /api/status — session status\n"
280
+ f" POST /api/stop — stop current turn\n"
281
+ f" Press Ctrl+C to stop.\n",
282
+ file=sys.stderr,
283
+ )
284
+
285
+ try:
286
+ server.serve_forever()
287
+ except KeyboardInterrupt:
288
+ pass
289
+ finally:
290
+ agent.send(None) # type: ignore[arg-type]
291
+ server.shutdown()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.3.13.dev211
3
+ Version: 0.3.13.dev213
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
@@ -37,6 +37,7 @@ src/specsmith/releaser.py
37
37
  src/specsmith/requirements.py
38
38
  src/specsmith/retrieval.py
39
39
  src/specsmith/scaffolder.py
40
+ src/specsmith/serve.py
40
41
  src/specsmith/session.py
41
42
  src/specsmith/tool_installer.py
42
43
  src/specsmith/toolrules.py