specsmith 0.10.1.dev293__tar.gz → 0.10.1.dev295__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 (234) hide show
  1. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/PKG-INFO +1 -1
  2. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/pyproject.toml +1 -1
  3. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/governance_logic.py +40 -0
  4. specsmith-0.10.1.dev295/src/specsmith/mcp_generator.py +210 -0
  5. specsmith-0.10.1.dev295/src/specsmith/skills_builder.py +193 -0
  6. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/PKG-INFO +1 -1
  7. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/SOURCES.txt +3 -0
  8. specsmith-0.10.1.dev295/tests/test_skills_mcp.py +109 -0
  9. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/LICENSE +0 -0
  10. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/README.md +0 -0
  11. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/setup.cfg +0 -0
  12. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/__init__.py +0 -0
  13. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/belief.py +0 -0
  14. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/certainty.py +0 -0
  15. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/failure_graph.py +0 -0
  16. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/py.typed +0 -0
  17. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/recovery.py +0 -0
  18. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/session.py +0 -0
  19. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/stress_tester.py +0 -0
  20. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/trace.py +0 -0
  21. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/__init__.py +0 -0
  22. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/__main__.py +0 -0
  23. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/__init__.py +0 -0
  24. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/broker.py +0 -0
  25. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/chat_runner.py +0 -0
  26. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/cleanup.py +0 -0
  27. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/core.py +0 -0
  28. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/endpoints.py +0 -0
  29. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/events.py +0 -0
  30. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/execution_profiles.py +0 -0
  31. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/fallback.py +0 -0
  32. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/hf_sync.py +0 -0
  33. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/indexer.py +0 -0
  34. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/mcp.py +0 -0
  35. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/memory.py +0 -0
  36. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/model_intelligence.py +0 -0
  37. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/orchestrator.py +0 -0
  38. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/permissions.py +0 -0
  39. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/profiles.py +0 -0
  40. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/provider_registry.py +0 -0
  41. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/repl.py +0 -0
  42. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/router.py +0 -0
  43. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/rules.py +0 -0
  44. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/runner.py +0 -0
  45. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/safety.py +0 -0
  46. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/spawner.py +0 -0
  47. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/suggester.py +0 -0
  48. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/teams.py +0 -0
  49. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/tools.py +0 -0
  50. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/verifier.py +0 -0
  51. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/voice.py +0 -0
  52. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/architect.py +0 -0
  53. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/auditor.py +0 -0
  54. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/auth.py +0 -0
  55. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/block_export.py +0 -0
  56. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/cli.py +0 -0
  57. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/commands/__init__.py +0 -0
  58. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/commands/intelligence.py +0 -0
  59. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/compliance.py +0 -0
  60. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/compressor.py +0 -0
  61. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/config.py +0 -0
  62. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/console_utils.py +0 -0
  63. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/context_window.py +0 -0
  64. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/credit_analyzer.py +0 -0
  65. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/credits.py +0 -0
  66. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/__init__.py +0 -0
  67. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/base.py +0 -0
  68. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/citations.py +0 -0
  69. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/fpd.py +0 -0
  70. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/odp.py +0 -0
  71. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/patentsview.py +0 -0
  72. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/pfw.py +0 -0
  73. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/ppubs.py +0 -0
  74. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/ptab.py +0 -0
  75. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/differ.py +0 -0
  76. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/doctor.py +0 -0
  77. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/drive.py +0 -0
  78. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/editor.py +0 -0
  79. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/__init__.py +0 -0
  80. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/belief.py +0 -0
  81. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/certainty.py +0 -0
  82. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/failure_graph.py +0 -0
  83. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/recovery.py +0 -0
  84. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/stress_tester.py +0 -0
  85. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/esdb/__init__.py +0 -0
  86. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/esdb/bridge.py +0 -0
  87. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/eval/__init__.py +0 -0
  88. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/eval/builtins.py +0 -0
  89. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/eval/runner.py +0 -0
  90. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/executor.py +0 -0
  91. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/exporter.py +0 -0
  92. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/__init__.py +0 -0
  93. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/app.py +0 -0
  94. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/main_window.py +0 -0
  95. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/session_tab.py +0 -0
  96. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/theme.py +0 -0
  97. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/__init__.py +0 -0
  98. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/chat_view.py +0 -0
  99. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/input_bar.py +0 -0
  100. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  101. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/token_meter.py +0 -0
  102. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  103. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/update_checker.py +0 -0
  104. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/worker.py +0 -0
  105. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/history_search.py +0 -0
  106. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/importer.py +0 -0
  107. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/instinct.py +0 -0
  108. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/__init__.py +0 -0
  109. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/agent_skill.py +0 -0
  110. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/aider.py +0 -0
  111. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/base.py +0 -0
  112. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/claude_code.py +0 -0
  113. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/copilot.py +0 -0
  114. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/cursor.py +0 -0
  115. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/gemini.py +0 -0
  116. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/windsurf.py +0 -0
  117. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/languages.py +0 -0
  118. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/ledger.py +0 -0
  119. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/patent.py +0 -0
  120. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/paths.py +0 -0
  121. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/phase.py +0 -0
  122. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/plugins.py +0 -0
  123. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/profiles.py +0 -0
  124. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/rate_limits.py +0 -0
  125. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/releaser.py +0 -0
  126. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/requirements.py +0 -0
  127. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/requirements_parser.py +0 -0
  128. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/retrieval.py +0 -0
  129. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/safe_write.py +0 -0
  130. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/scaffolder.py +0 -0
  131. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/serve.py +0 -0
  132. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/session.py +0 -0
  133. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/session_init.py +0 -0
  134. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/skills.py +0 -0
  135. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/sync.py +0 -0
  136. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/agents.md.j2 +0 -0
  137. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  138. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  139. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  140. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  141. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  142. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  143. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  144. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/security.md.j2 +0 -0
  145. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  146. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  147. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  148. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  149. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  150. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/editorconfig.j2 +0 -0
  151. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/gitattributes.j2 +0 -0
  152. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/gitignore.j2 +0 -0
  153. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/go/go.mod.j2 +0 -0
  154. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/go/main.go.j2 +0 -0
  155. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  156. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  157. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  158. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  159. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  160. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
  161. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  162. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  163. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
  164. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  165. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  166. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/js/package.json.j2 +0 -0
  167. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/ledger.md.j2 +0 -0
  168. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/python/cli.py.j2 +0 -0
  169. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/python/init.py.j2 +0 -0
  170. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  171. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/readme.md.j2 +0 -0
  172. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  173. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  174. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  175. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  176. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  177. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  178. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  179. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  180. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  181. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/tool_installer.py +0 -0
  182. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/toolrules.py +0 -0
  183. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/tools.py +0 -0
  184. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/trace.py +0 -0
  185. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/updater.py +0 -0
  186. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/upgrader.py +0 -0
  187. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/validator.py +0 -0
  188. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/__init__.py +0 -0
  189. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/base.py +0 -0
  190. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/bitbucket.py +0 -0
  191. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/github.py +0 -0
  192. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/gitlab.py +0 -0
  193. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs_commands.py +0 -0
  194. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/wireframes.py +0 -0
  195. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/workspace.py +0 -0
  196. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/dependency_links.txt +0 -0
  197. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/entry_points.txt +0 -0
  198. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/requires.txt +0 -0
  199. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/top_level.txt +0 -0
  200. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_CMD_001.py +0 -0
  201. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_agent_profiles.py +0 -0
  202. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_agent_runner_ready.py +0 -0
  203. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_auditor.py +0 -0
  204. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_chat_diff_decision.py +0 -0
  205. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_chat_runner_openai_compat.py +0 -0
  206. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_chat_stdin_protocol.py +0 -0
  207. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_cli.py +0 -0
  208. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_cli_workflows_history_drive.py +0 -0
  209. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_compliance.py +0 -0
  210. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_compressor.py +0 -0
  211. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_e2e_nexus.py +0 -0
  212. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_endpoints_cli.py +0 -0
  213. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_endpoints_store.py +0 -0
  214. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_epistemic.py +0 -0
  215. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_fallback_chain.py +0 -0
  216. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_importer.py +0 -0
  217. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_integrations.py +0 -0
  218. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_intelligence.py +0 -0
  219. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_mcp_client.py +0 -0
  220. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_new_modules.py +0 -0
  221. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_nexus.py +0 -0
  222. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_permissions.py +0 -0
  223. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_phase1_4_new.py +0 -0
  224. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_phase34_completion.py +0 -0
  225. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_rate_limits.py +0 -0
  226. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_scaffolder.py +0 -0
  227. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_skill_marketplace.py +0 -0
  228. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_smoke.py +0 -0
  229. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_suggester.py +0 -0
  230. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_tools.py +0 -0
  231. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_validator.py +0 -0
  232. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_vcs.py +0 -0
  233. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_warp_parity.py +0 -0
  234. {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/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.dev293
3
+ Version: 0.10.1.dev295
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.dev293"
7
+ version = "0.10.1.dev295"
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"
@@ -614,6 +614,46 @@ class GovernanceHTTPServer:
614
614
  except Exception as exc: # noqa: BLE001
615
615
  self._json_err(str(exc), code=500)
616
616
 
617
+ # ── Skills ───────────────────────────────────────────
618
+ elif self.path == "/api/skills":
619
+ try:
620
+ from specsmith.skills_builder import list_skills
621
+
622
+ skills = list_skills(project_dir)
623
+ self._json_ok({"skills": [s.to_dict() for s in skills]})
624
+ except Exception as exc: # noqa: BLE001
625
+ self._json_err(str(exc), code=500)
626
+
627
+ # ── Eval ────────────────────────────────────────────
628
+ elif self.path == "/api/eval/suites":
629
+ try:
630
+ from specsmith.eval.builtins import list_suites
631
+
632
+ suites = list_suites()
633
+ self._json_ok({"suites": [s.to_dict() for s in suites]})
634
+ except Exception as exc: # noqa: BLE001
635
+ self._json_err(str(exc), code=500)
636
+
637
+ # ── Teams ───────────────────────────────────────────
638
+ elif self.path == "/api/teams":
639
+ try:
640
+ from specsmith.agent.teams import list_teams
641
+
642
+ teams = list_teams()
643
+ self._json_ok({"teams": [t.to_dict() for t in teams]})
644
+ except Exception as exc: # noqa: BLE001
645
+ self._json_err(str(exc), code=500)
646
+
647
+ # ── MCP Servers ─────────────────────────────────────
648
+ elif self.path == "/api/mcp/servers":
649
+ try:
650
+ from specsmith.mcp_generator import list_mcp_servers
651
+
652
+ servers = list_mcp_servers(project_dir)
653
+ self._json_ok({"servers": [s.to_dict() for s in servers]})
654
+ except Exception as exc: # noqa: BLE001
655
+ self._json_err(str(exc), code=500)
656
+
617
657
  # ── ESDB ──────────────────────────────────────────────
618
658
  elif self.path == "/api/esdb/status":
619
659
  try:
@@ -0,0 +1,210 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
3
+ """MCP Server Generator — auto-scaffold Model Context Protocol servers.
4
+
5
+ Generates Python MCP servers from natural-language tool descriptions using
6
+ the FastMCP pattern. Each generated server includes a `server.py`,
7
+ `tool_schema.json`, and `README.md`.
8
+
9
+ Usage:
10
+ from specsmith.mcp_generator import generate_mcp_server, list_mcp_servers
11
+ server = generate_mcp_server("Search USPTO patents by keyword")
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import re
18
+ import uuid
19
+ from dataclasses import dataclass, field
20
+ from pathlib import Path
21
+ from typing import Any
22
+
23
+
24
+ @dataclass
25
+ class MCPServerSpec:
26
+ """Specification for a generated MCP server."""
27
+
28
+ id: str
29
+ name: str
30
+ description: str
31
+ tools: list[MCPToolSpec] = field(default_factory=list)
32
+ transport: str = "stdio" # "stdio" or "http"
33
+ port: int = 8100
34
+
35
+ def to_dict(self) -> dict[str, Any]:
36
+ return {
37
+ "id": self.id,
38
+ "name": self.name,
39
+ "description": self.description,
40
+ "tools": [t.to_dict() for t in self.tools],
41
+ "transport": self.transport,
42
+ "port": self.port,
43
+ }
44
+
45
+
46
+ @dataclass
47
+ class MCPToolSpec:
48
+ """Specification for a single MCP tool."""
49
+
50
+ name: str
51
+ description: str
52
+ input_params: dict[str, str] = field(default_factory=dict)
53
+ output_type: str = "text"
54
+
55
+ def to_dict(self) -> dict[str, Any]:
56
+ return {
57
+ "name": self.name,
58
+ "description": self.description,
59
+ "input_params": self.input_params,
60
+ "output_type": self.output_type,
61
+ }
62
+
63
+
64
+ def _generate_server_id(name: str) -> str:
65
+ slug = re.sub(r"[^a-z0-9]+", "-", name.lower().strip())[:30]
66
+ return f"mcp-{slug}-{uuid.uuid4().hex[:6]}"
67
+
68
+
69
+ def _generate_server_py(spec: MCPServerSpec) -> str:
70
+ """Generate a Python MCP server file."""
71
+ tool_funcs = []
72
+ for tool in spec.tools:
73
+ params = ", ".join(f"{k}: str" for k in tool.input_params)
74
+ func = f'''
75
+ @mcp.tool()
76
+ def {tool.name}({params}) -> dict:
77
+ """{tool.description}"""
78
+ # TODO: implement actual logic
79
+ return {{"result": "stub response", "tool": "{tool.name}"}}
80
+ '''
81
+ tool_funcs.append(func)
82
+
83
+ transport_line = (
84
+ f' mcp.run(transport="streamable-http", host="127.0.0.1", port={spec.port})'
85
+ if spec.transport == "http"
86
+ else ' mcp.run(transport="stdio")'
87
+ )
88
+
89
+ return f'''#!/usr/bin/env python3
90
+ # Auto-generated MCP server: {spec.name}
91
+ # Generated by specsmith mcp generate
92
+
93
+ from mcp.server.fastmcp import FastMCP
94
+
95
+ mcp = FastMCP("{spec.name}")
96
+ {"".join(tool_funcs)}
97
+
98
+ if __name__ == "__main__":
99
+ {transport_line}
100
+ '''
101
+
102
+
103
+ def _generate_readme(spec: MCPServerSpec) -> str:
104
+ """Generate README.md for the MCP server."""
105
+ tool_list = "\n".join(f"- **{t.name}**: {t.description}" for t in spec.tools)
106
+ return f"""# {spec.name}
107
+
108
+ {spec.description}
109
+
110
+ ## Tools
111
+
112
+ {tool_list}
113
+
114
+ ## Usage
115
+
116
+ ```bash
117
+ # stdio mode
118
+ python server.py
119
+
120
+ # HTTP mode (if configured)
121
+ python server.py
122
+ ```
123
+
124
+ ## Configuration
125
+
126
+ Add to your MCP client config:
127
+
128
+ ```json
129
+ {{
130
+ "mcpServers": {{
131
+ "{spec.id}": {{
132
+ "command": "python",
133
+ "args": ["server.py"]
134
+ }}
135
+ }}
136
+ }}
137
+ ```
138
+ """
139
+
140
+
141
+ def generate_mcp_server(
142
+ tool_description: str,
143
+ project_dir: str = ".",
144
+ transport: str = "stdio",
145
+ port: int = 8100,
146
+ ) -> MCPServerSpec:
147
+ """Generate an MCP server from a natural-language tool description.
148
+
149
+ Creates a server directory with `server.py`, `tool_schema.json`, and `README.md`.
150
+ """
151
+ # Parse description into server + tool spec
152
+ name = tool_description.strip()[:50]
153
+ server_id = _generate_server_id(name)
154
+ tool_name = re.sub(r"[^a-z0-9_]+", "_", name.lower().strip())[:40]
155
+
156
+ tool = MCPToolSpec(
157
+ name=tool_name,
158
+ description=tool_description.strip(),
159
+ input_params={"query": "Search query or input"},
160
+ )
161
+
162
+ spec = MCPServerSpec(
163
+ id=server_id,
164
+ name=name,
165
+ description=tool_description.strip(),
166
+ tools=[tool],
167
+ transport=transport,
168
+ port=port,
169
+ )
170
+
171
+ # Create server directory
172
+ server_dir = Path(project_dir).resolve() / ".specsmith" / "mcp-servers" / server_id
173
+ server_dir.mkdir(parents=True, exist_ok=True)
174
+
175
+ # Write files
176
+ (server_dir / "server.py").write_text(_generate_server_py(spec), encoding="utf-8")
177
+ (server_dir / "tool_schema.json").write_text(
178
+ json.dumps(spec.to_dict(), indent=2, ensure_ascii=False), encoding="utf-8"
179
+ )
180
+ (server_dir / "README.md").write_text(_generate_readme(spec), encoding="utf-8")
181
+
182
+ return spec
183
+
184
+
185
+ def list_mcp_servers(project_dir: str = ".") -> list[MCPServerSpec]:
186
+ """List all generated MCP servers."""
187
+ servers_dir = Path(project_dir).resolve() / ".specsmith" / "mcp-servers"
188
+ if not servers_dir.is_dir():
189
+ return []
190
+ servers: list[MCPServerSpec] = []
191
+ for server_dir in sorted(servers_dir.iterdir()):
192
+ schema_path = server_dir / "tool_schema.json"
193
+ if schema_path.is_file():
194
+ try:
195
+ raw = json.loads(schema_path.read_text(encoding="utf-8"))
196
+ servers.append(
197
+ MCPServerSpec(
198
+ id=raw.get("id", ""),
199
+ name=raw.get("name", ""),
200
+ description=raw.get("description", ""),
201
+ transport=raw.get("transport", "stdio"),
202
+ port=raw.get("port", 8100),
203
+ )
204
+ )
205
+ except (OSError, ValueError):
206
+ continue
207
+ return servers
208
+
209
+
210
+ __all__ = ["MCPServerSpec", "MCPToolSpec", "generate_mcp_server", "list_mcp_servers"]
@@ -0,0 +1,193 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
3
+ """AI-powered Skills Builder — generate agent skills from natural-language descriptions.
4
+
5
+ Skills follow the SkillNet-style ontology: each skill is a folder containing
6
+ a SKILL.md file with structured metadata (name, purpose, activation rules,
7
+ input/output schema, epistemic contract, tools used, tests required).
8
+
9
+ Usage:
10
+ from specsmith.skills_builder import build_skill, list_skills
11
+ skill = build_skill("Summarize a Python file into bullet points")
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import re
18
+ import uuid
19
+ from dataclasses import dataclass, field
20
+ from pathlib import Path
21
+ from typing import Any
22
+
23
+
24
+ @dataclass
25
+ class SkillSpec:
26
+ """Structured specification for an agent skill."""
27
+
28
+ id: str
29
+ name: str
30
+ purpose: str
31
+ activation_rules: list[str] = field(default_factory=list)
32
+ input_schema: dict[str, str] = field(default_factory=dict)
33
+ output_schema: dict[str, str] = field(default_factory=dict)
34
+ epistemic_contract: str = ""
35
+ tools_used: list[str] = field(default_factory=list)
36
+ tests_required: list[str] = field(default_factory=list)
37
+ stop_conditions: list[str] = field(default_factory=list)
38
+ tags: list[str] = field(default_factory=list)
39
+ active: bool = False
40
+
41
+ def to_dict(self) -> dict[str, Any]:
42
+ return {
43
+ "id": self.id,
44
+ "name": self.name,
45
+ "purpose": self.purpose,
46
+ "activation_rules": self.activation_rules,
47
+ "input_schema": self.input_schema,
48
+ "output_schema": self.output_schema,
49
+ "epistemic_contract": self.epistemic_contract,
50
+ "tools_used": self.tools_used,
51
+ "tests_required": self.tests_required,
52
+ "stop_conditions": self.stop_conditions,
53
+ "tags": self.tags,
54
+ "active": self.active,
55
+ }
56
+
57
+ def to_markdown(self) -> str:
58
+ """Generate SKILL.md content."""
59
+ lines = [
60
+ f"# {self.name}",
61
+ "",
62
+ f"**ID:** {self.id}",
63
+ f"**Purpose:** {self.purpose}",
64
+ "",
65
+ "## Activation Rules",
66
+ "",
67
+ ]
68
+ for rule in self.activation_rules:
69
+ lines.append(f"- {rule}")
70
+ lines.extend(
71
+ [
72
+ "",
73
+ "## Input Schema",
74
+ "",
75
+ "```json",
76
+ json.dumps(self.input_schema, indent=2),
77
+ "```",
78
+ "",
79
+ "## Output Schema",
80
+ "",
81
+ "```json",
82
+ json.dumps(self.output_schema, indent=2),
83
+ "```",
84
+ "",
85
+ "## Epistemic Contract",
86
+ "",
87
+ self.epistemic_contract or "No epistemic contract defined.",
88
+ "",
89
+ "## Tools Used",
90
+ "",
91
+ ]
92
+ )
93
+ for tool in self.tools_used:
94
+ lines.append(f"- {tool}")
95
+ lines.extend(["", "## Tests Required", ""])
96
+ for test in self.tests_required:
97
+ lines.append(f"- {test}")
98
+ lines.extend(["", "## Stop Conditions", ""])
99
+ for cond in self.stop_conditions:
100
+ lines.append(f"- {cond}")
101
+ return "\n".join(lines)
102
+
103
+
104
+ def _generate_skill_id(name: str) -> str:
105
+ slug = re.sub(r"[^a-z0-9]+", "-", name.lower().strip())[:30]
106
+ return f"skill-{slug}-{uuid.uuid4().hex[:6]}"
107
+
108
+
109
+ def build_skill(
110
+ description: str,
111
+ project_dir: str = ".",
112
+ tags: list[str] | None = None,
113
+ ) -> SkillSpec:
114
+ """Build a skill from a natural-language description.
115
+
116
+ Currently generates a deterministic skill spec from the description.
117
+ When an AI provider is configured, this will use the LLM to generate
118
+ richer skill content.
119
+ """
120
+ # Deterministic generation (no LLM required)
121
+ name = description.strip()[:60]
122
+ skill_id = _generate_skill_id(name)
123
+
124
+ spec = SkillSpec(
125
+ id=skill_id,
126
+ name=name,
127
+ purpose=description.strip(),
128
+ activation_rules=[f"User requests: {description[:80]}"],
129
+ input_schema={"task": "string", "context": "string (optional)"},
130
+ output_schema={"result": "string", "confidence": "number"},
131
+ epistemic_contract="Output must be verifiable against the input task.",
132
+ tools_used=["read_file", "run_shell"],
133
+ tests_required=[f"Verify {name} produces correct output"],
134
+ stop_conditions=["Confidence below 0.3", "Timeout exceeded"],
135
+ tags=tags or [],
136
+ )
137
+
138
+ # Save to disk
139
+ skill_dir = Path(project_dir).resolve() / ".specsmith" / "skills" / skill_id
140
+ skill_dir.mkdir(parents=True, exist_ok=True)
141
+ (skill_dir / "SKILL.md").write_text(spec.to_markdown(), encoding="utf-8")
142
+
143
+ # Save JSON metadata
144
+ (skill_dir / "skill.json").write_text(
145
+ json.dumps(spec.to_dict(), indent=2, ensure_ascii=False),
146
+ encoding="utf-8",
147
+ )
148
+
149
+ return spec
150
+
151
+
152
+ def list_skills(project_dir: str = ".") -> list[SkillSpec]:
153
+ """List all available skills in the project."""
154
+ skills_dir = Path(project_dir).resolve() / ".specsmith" / "skills"
155
+ if not skills_dir.is_dir():
156
+ return []
157
+ skills: list[SkillSpec] = []
158
+ for skill_dir in sorted(skills_dir.iterdir()):
159
+ meta_path = skill_dir / "skill.json"
160
+ if meta_path.is_file():
161
+ try:
162
+ raw = json.loads(meta_path.read_text(encoding="utf-8"))
163
+ skills.append(
164
+ SkillSpec(
165
+ id=raw.get("id", ""),
166
+ name=raw.get("name", ""),
167
+ purpose=raw.get("purpose", ""),
168
+ activation_rules=raw.get("activation_rules", []),
169
+ tools_used=raw.get("tools_used", []),
170
+ tags=raw.get("tags", []),
171
+ active=raw.get("active", False),
172
+ )
173
+ )
174
+ except (OSError, ValueError):
175
+ continue
176
+ return skills
177
+
178
+
179
+ def activate_skill(skill_id: str, project_dir: str = ".") -> bool:
180
+ """Activate a skill by ID."""
181
+ meta_path = Path(project_dir).resolve() / ".specsmith" / "skills" / skill_id / "skill.json"
182
+ if not meta_path.is_file():
183
+ return False
184
+ try:
185
+ raw = json.loads(meta_path.read_text(encoding="utf-8"))
186
+ raw["active"] = True
187
+ meta_path.write_text(json.dumps(raw, indent=2, ensure_ascii=False), encoding="utf-8")
188
+ return True
189
+ except (OSError, ValueError):
190
+ return False
191
+
192
+
193
+ __all__ = ["SkillSpec", "activate_skill", "build_skill", "list_skills"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.10.1.dev293
3
+ Version: 0.10.1.dev295
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
@@ -36,6 +36,7 @@ src/specsmith/importer.py
36
36
  src/specsmith/instinct.py
37
37
  src/specsmith/languages.py
38
38
  src/specsmith/ledger.py
39
+ src/specsmith/mcp_generator.py
39
40
  src/specsmith/patent.py
40
41
  src/specsmith/paths.py
41
42
  src/specsmith/phase.py
@@ -52,6 +53,7 @@ src/specsmith/serve.py
52
53
  src/specsmith/session.py
53
54
  src/specsmith/session_init.py
54
55
  src/specsmith/skills.py
56
+ src/specsmith/skills_builder.py
55
57
  src/specsmith/sync.py
56
58
  src/specsmith/tool_installer.py
57
59
  src/specsmith/toolrules.py
@@ -220,6 +222,7 @@ tests/test_phase34_completion.py
220
222
  tests/test_rate_limits.py
221
223
  tests/test_scaffolder.py
222
224
  tests/test_skill_marketplace.py
225
+ tests/test_skills_mcp.py
223
226
  tests/test_smoke.py
224
227
  tests/test_suggester.py
225
228
  tests/test_tools.py
@@ -0,0 +1,109 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
3
+ """Tests for Skills Builder and MCP Server Generator."""
4
+
5
+ from __future__ import annotations
6
+
7
+ from pathlib import Path
8
+
9
+
10
+ class TestSkillsBuilder:
11
+ def test_build_skill(self, tmp_path: Path) -> None:
12
+ from specsmith.skills_builder import build_skill
13
+
14
+ skill = build_skill("Summarize Python files into bullet points", str(tmp_path))
15
+ assert skill.id.startswith("skill-")
16
+ assert skill.name == "Summarize Python files into bullet points"
17
+ assert skill.purpose
18
+ assert len(skill.activation_rules) > 0
19
+
20
+ def test_skill_saved_to_disk(self, tmp_path: Path) -> None:
21
+ from specsmith.skills_builder import build_skill
22
+
23
+ skill = build_skill("Analyze code complexity", str(tmp_path))
24
+ skill_dir = tmp_path / ".specsmith" / "skills" / skill.id
25
+ assert (skill_dir / "SKILL.md").is_file()
26
+ assert (skill_dir / "skill.json").is_file()
27
+ content = (skill_dir / "SKILL.md").read_text(encoding="utf-8")
28
+ assert "Analyze code complexity" in content
29
+
30
+ def test_list_skills_empty(self, tmp_path: Path) -> None:
31
+ from specsmith.skills_builder import list_skills
32
+
33
+ assert list_skills(str(tmp_path)) == []
34
+
35
+ def test_list_skills_after_build(self, tmp_path: Path) -> None:
36
+ from specsmith.skills_builder import build_skill, list_skills
37
+
38
+ build_skill("Skill A", str(tmp_path))
39
+ build_skill("Skill B", str(tmp_path))
40
+ skills = list_skills(str(tmp_path))
41
+ assert len(skills) == 2
42
+
43
+ def test_activate_skill(self, tmp_path: Path) -> None:
44
+ from specsmith.skills_builder import activate_skill, build_skill, list_skills
45
+
46
+ skill = build_skill("Activatable skill", str(tmp_path))
47
+ assert not skill.active
48
+ assert activate_skill(skill.id, str(tmp_path))
49
+ skills = list_skills(str(tmp_path))
50
+ assert any(s.active for s in skills)
51
+
52
+ def test_skill_to_dict(self) -> None:
53
+ from specsmith.skills_builder import SkillSpec
54
+
55
+ spec = SkillSpec(id="test", name="Test", purpose="Testing")
56
+ d = spec.to_dict()
57
+ assert d["id"] == "test"
58
+ assert d["name"] == "Test"
59
+
60
+
61
+ class TestMCPGenerator:
62
+ def test_generate_server(self, tmp_path: Path) -> None:
63
+ from specsmith.mcp_generator import generate_mcp_server
64
+
65
+ spec = generate_mcp_server("Search USPTO patents by keyword", str(tmp_path))
66
+ assert spec.id.startswith("mcp-")
67
+ assert len(spec.tools) == 1
68
+ assert spec.transport == "stdio"
69
+
70
+ def test_server_files_created(self, tmp_path: Path) -> None:
71
+ from specsmith.mcp_generator import generate_mcp_server
72
+
73
+ spec = generate_mcp_server("Lookup weather data", str(tmp_path))
74
+ server_dir = tmp_path / ".specsmith" / "mcp-servers" / spec.id
75
+ assert (server_dir / "server.py").is_file()
76
+ assert (server_dir / "tool_schema.json").is_file()
77
+ assert (server_dir / "README.md").is_file()
78
+
79
+ def test_server_py_contains_tool(self, tmp_path: Path) -> None:
80
+ from specsmith.mcp_generator import generate_mcp_server
81
+
82
+ spec = generate_mcp_server("Calculate BMI", str(tmp_path))
83
+ server_dir = tmp_path / ".specsmith" / "mcp-servers" / spec.id
84
+ content = (server_dir / "server.py").read_text(encoding="utf-8")
85
+ assert "FastMCP" in content
86
+ assert "@mcp.tool()" in content
87
+
88
+ def test_list_servers_empty(self, tmp_path: Path) -> None:
89
+ from specsmith.mcp_generator import list_mcp_servers
90
+
91
+ assert list_mcp_servers(str(tmp_path)) == []
92
+
93
+ def test_list_servers_after_generate(self, tmp_path: Path) -> None:
94
+ from specsmith.mcp_generator import generate_mcp_server, list_mcp_servers
95
+
96
+ generate_mcp_server("Tool A", str(tmp_path))
97
+ generate_mcp_server("Tool B", str(tmp_path))
98
+ servers = list_mcp_servers(str(tmp_path))
99
+ assert len(servers) == 2
100
+
101
+ def test_http_transport(self, tmp_path: Path) -> None:
102
+ from specsmith.mcp_generator import generate_mcp_server
103
+
104
+ spec = generate_mcp_server("HTTP tool", str(tmp_path), transport="http", port=9000)
105
+ assert spec.transport == "http"
106
+ assert spec.port == 9000
107
+ server_dir = tmp_path / ".specsmith" / "mcp-servers" / spec.id
108
+ content = (server_dir / "server.py").read_text(encoding="utf-8")
109
+ assert "streamable-http" in content