specsmith 0.12.0.dev493__tar.gz → 0.12.0.dev496__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 (289) hide show
  1. {specsmith-0.12.0.dev493/src/specsmith.egg-info → specsmith-0.12.0.dev496}/PKG-INFO +1 -1
  2. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/pyproject.toml +1 -1
  3. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/auditor.py +46 -4
  4. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/cli.py +243 -40
  5. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/mcp_server.py +159 -11
  6. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496/src/specsmith.egg-info}/PKG-INFO +1 -1
  7. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_auditor.py +89 -0
  8. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_mcp_server.py +177 -3
  9. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/LICENSE +0 -0
  10. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/README.md +0 -0
  11. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/setup.cfg +0 -0
  12. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/epistemic/__init__.py +0 -0
  13. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/epistemic/belief.py +0 -0
  14. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/epistemic/certainty.py +0 -0
  15. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/epistemic/failure_graph.py +0 -0
  16. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/epistemic/py.typed +0 -0
  17. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/epistemic/recovery.py +0 -0
  18. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/epistemic/session.py +0 -0
  19. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/epistemic/stress_tester.py +0 -0
  20. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/epistemic/trace.py +0 -0
  21. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/__init__.py +0 -0
  22. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/__main__.py +0 -0
  23. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/__init__.py +0 -0
  24. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/broker.py +0 -0
  25. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/chat_runner.py +0 -0
  26. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/cleanup.py +0 -0
  27. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/context_seed.py +0 -0
  28. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/core.py +0 -0
  29. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/dispatch/__init__.py +0 -0
  30. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/dispatch/_status.py +0 -0
  31. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/dispatch/dag.py +0 -0
  32. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
  33. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/dispatch/events.py +0 -0
  34. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/dispatch/result.py +0 -0
  35. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/endpoints.py +0 -0
  36. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/events.py +0 -0
  37. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/execution_profiles.py +0 -0
  38. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/fallback.py +0 -0
  39. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/hf_leaderboard.py +0 -0
  40. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/hf_sync.py +0 -0
  41. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/indexer.py +0 -0
  42. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/llm_client.py +0 -0
  43. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/mcp.py +0 -0
  44. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/memory.py +0 -0
  45. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/model_intelligence.py +0 -0
  46. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/model_profiles.py +0 -0
  47. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/orchestrator.py +0 -0
  48. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/permissions.py +0 -0
  49. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/profiles.py +0 -0
  50. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/provider_registry.py +0 -0
  51. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/repl.py +0 -0
  52. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/router.py +0 -0
  53. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/rules.py +0 -0
  54. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/runner.py +0 -0
  55. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/safety.py +0 -0
  56. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/spawner.py +0 -0
  57. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/suggester.py +0 -0
  58. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/teams.py +0 -0
  59. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/tools.py +0 -0
  60. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/verifier.py +0 -0
  61. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/agent/voice.py +0 -0
  62. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/architect.py +0 -0
  63. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/auth.py +0 -0
  64. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/block_export.py +0 -0
  65. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/channel.py +0 -0
  66. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/ci_manager.py +0 -0
  67. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/commands/__init__.py +0 -0
  68. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/commands/intelligence.py +0 -0
  69. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/compliance/__init__.py +0 -0
  70. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/compliance/_compat.py +0 -0
  71. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/compliance/checker.py +0 -0
  72. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/compliance/evidence.py +0 -0
  73. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/compliance/regulations.py +0 -0
  74. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/compliance/reporter.py +0 -0
  75. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/compressor.py +0 -0
  76. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/config.py +0 -0
  77. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/console_utils.py +0 -0
  78. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/context_orchestrator.py +0 -0
  79. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/context_window.py +0 -0
  80. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/credit_analyzer.py +0 -0
  81. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/credits.py +0 -0
  82. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/datasources/__init__.py +0 -0
  83. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/datasources/base.py +0 -0
  84. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/datasources/citations.py +0 -0
  85. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/datasources/fpd.py +0 -0
  86. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/datasources/odp.py +0 -0
  87. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/datasources/patentsview.py +0 -0
  88. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/datasources/pfw.py +0 -0
  89. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/datasources/ppubs.py +0 -0
  90. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/datasources/ptab.py +0 -0
  91. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/differ.py +0 -0
  92. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/doctor.py +0 -0
  93. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/drive.py +0 -0
  94. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/editor.py +0 -0
  95. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/epistemic/__init__.py +0 -0
  96. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/epistemic/belief.py +0 -0
  97. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/epistemic/certainty.py +0 -0
  98. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/epistemic/failure_graph.py +0 -0
  99. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/epistemic/recovery.py +0 -0
  100. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/epistemic/stress_tester.py +0 -0
  101. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/esdb/__init__.py +0 -0
  102. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/esdb/bridge.py +0 -0
  103. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/eval/__init__.py +0 -0
  104. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/eval/builtins.py +0 -0
  105. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/eval/runner.py +0 -0
  106. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/executor.py +0 -0
  107. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/exporter.py +0 -0
  108. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/governance_logic.py +0 -0
  109. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/governance_store.py +0 -0
  110. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/governance_yaml.py +0 -0
  111. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/__init__.py +0 -0
  112. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/app.py +0 -0
  113. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/main_window.py +0 -0
  114. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/session_tab.py +0 -0
  115. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/theme.py +0 -0
  116. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/widgets/__init__.py +0 -0
  117. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/widgets/chat_view.py +0 -0
  118. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/widgets/input_bar.py +0 -0
  119. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  120. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/widgets/token_meter.py +0 -0
  121. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  122. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/widgets/update_checker.py +0 -0
  123. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/gui/worker.py +0 -0
  124. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/history_search.py +0 -0
  125. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/importer.py +0 -0
  126. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/instinct.py +0 -0
  127. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/__init__.py +0 -0
  128. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/agent_skill.py +0 -0
  129. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/aider.py +0 -0
  130. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/base.py +0 -0
  131. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/claude_code.py +0 -0
  132. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/codity.py +0 -0
  133. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/copilot.py +0 -0
  134. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/cursor.py +0 -0
  135. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/gemini.py +0 -0
  136. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/integrations/windsurf.py +0 -0
  137. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/issue_reporter.py +0 -0
  138. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/languages.py +0 -0
  139. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/ledger.py +0 -0
  140. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/mcp_generator.py +0 -0
  141. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/migrations/__init__.py +0 -0
  142. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
  143. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/migrations/m002_agents_slim.py +0 -0
  144. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/migrations/m003_compliance_init.py +0 -0
  145. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
  146. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
  147. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/migrations/m006_session_governance.py +0 -0
  148. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/migrations/runner.py +0 -0
  149. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/ollama_cmds.py +0 -0
  150. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/patent.py +0 -0
  151. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/paths.py +0 -0
  152. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/phase.py +0 -0
  153. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/plugins.py +0 -0
  154. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/profiles.py +0 -0
  155. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/rate_limits.py +0 -0
  156. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/releaser.py +0 -0
  157. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/requirements.py +0 -0
  158. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/requirements_parser.py +0 -0
  159. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/retrieval.py +0 -0
  160. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/safe_write.py +0 -0
  161. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/scaffolder.py +0 -0
  162. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/serve.py +0 -0
  163. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/session.py +0 -0
  164. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/session_init.py +0 -0
  165. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/session_store.py +0 -0
  166. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/__init__.py +0 -0
  167. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/cloud.py +0 -0
  168. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/corporate.py +0 -0
  169. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/cross_platform.py +0 -0
  170. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/devops.py +0 -0
  171. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/docs.py +0 -0
  172. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/embedded.py +0 -0
  173. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/governance.py +0 -0
  174. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/hardware.py +0 -0
  175. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/mobile.py +0 -0
  176. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/productivity.py +0 -0
  177. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/specsmith_skills.py +0 -0
  178. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills/ssh.py +0 -0
  179. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/skills_builder.py +0 -0
  180. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/sync.py +0 -0
  181. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/agents.md.j2 +0 -0
  182. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  183. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  184. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  185. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  186. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  187. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  188. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  189. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/community/security.md.j2 +0 -0
  190. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  191. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  192. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  193. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  194. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  195. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/editorconfig.j2 +0 -0
  196. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/gitattributes.j2 +0 -0
  197. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/gitignore.j2 +0 -0
  198. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/go/go.mod.j2 +0 -0
  199. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/go/main.go.j2 +0 -0
  200. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  201. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  202. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  203. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  204. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  205. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
  206. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  207. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  208. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
  209. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  210. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  211. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/js/package.json.j2 +0 -0
  212. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/ledger.md.j2 +0 -0
  213. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/python/cli.py.j2 +0 -0
  214. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/python/init.py.j2 +0 -0
  215. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  216. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/readme.md.j2 +0 -0
  217. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  218. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  219. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  220. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  221. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  222. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  223. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  224. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  225. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  226. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/tool_installer.py +0 -0
  227. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/toolrules.py +0 -0
  228. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/tools.py +0 -0
  229. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/trace.py +0 -0
  230. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/updater.py +0 -0
  231. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/upgrader.py +0 -0
  232. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/validator.py +0 -0
  233. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/vcs/__init__.py +0 -0
  234. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/vcs/base.py +0 -0
  235. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/vcs/bitbucket.py +0 -0
  236. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/vcs/github.py +0 -0
  237. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/vcs/gitlab.py +0 -0
  238. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/vcs_commands.py +0 -0
  239. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/wireframes.py +0 -0
  240. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith/workspace.py +0 -0
  241. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith.egg-info/SOURCES.txt +0 -0
  242. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith.egg-info/dependency_links.txt +0 -0
  243. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith.egg-info/entry_points.txt +0 -0
  244. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith.egg-info/requires.txt +0 -0
  245. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/src/specsmith.egg-info/top_level.txt +0 -0
  246. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_CMD_001.py +0 -0
  247. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_agent_profiles.py +0 -0
  248. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_agent_run_feedback.py +0 -0
  249. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_agent_runner_ready.py +0 -0
  250. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_ai_client.py +0 -0
  251. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_ai_intelligence.py +0 -0
  252. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_channel.py +0 -0
  253. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_chat_diff_decision.py +0 -0
  254. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_chat_runner_openai_compat.py +0 -0
  255. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_chat_stdin_protocol.py +0 -0
  256. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_cli.py +0 -0
  257. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_cli_workflows_history_drive.py +0 -0
  258. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_compliance.py +0 -0
  259. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_compressor.py +0 -0
  260. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_dispatch.py +0 -0
  261. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_e2e_nexus.py +0 -0
  262. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_endpoints_cli.py +0 -0
  263. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_endpoints_store.py +0 -0
  264. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_epistemic.py +0 -0
  265. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_fallback_chain.py +0 -0
  266. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_importer.py +0 -0
  267. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_integrations.py +0 -0
  268. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_integrations_codity.py +0 -0
  269. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_intelligence.py +0 -0
  270. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_issue_reporter.py +0 -0
  271. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_mcp_client.py +0 -0
  272. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_new_modules.py +0 -0
  273. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_nexus.py +0 -0
  274. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_permissions.py +0 -0
  275. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_phase1_4_new.py +0 -0
  276. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_phase34_completion.py +0 -0
  277. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_rate_limits.py +0 -0
  278. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_req_248_262.py +0 -0
  279. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_req_358_359.py +0 -0
  280. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_scaffolder.py +0 -0
  281. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_skill_marketplace.py +0 -0
  282. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_skills_mcp.py +0 -0
  283. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_smoke.py +0 -0
  284. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_suggester.py +0 -0
  285. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_tools.py +0 -0
  286. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_validator.py +0 -0
  287. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_vcs.py +0 -0
  288. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/tests/test_warp_parity.py +0 -0
  289. {specsmith-0.12.0.dev493 → specsmith-0.12.0.dev496}/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.12.0.dev493
3
+ Version: 0.12.0.dev496
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.12.0.dev493"
7
+ version = "0.12.0.dev496"
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"
@@ -441,9 +441,11 @@ def check_ledger_health(root: Path) -> list[AuditResult]:
441
441
  )
442
442
  )
443
443
 
444
- # Open TODOs
445
- open_todos = sum(1 for line in lines if "- [ ]" in line)
446
- closed_todos = sum(1 for line in lines if "- [x]" in line)
444
+ # Open TODOs — only count lines where the checklist marker is at the
445
+ # start of the trimmed line, not prose references such as:
446
+ # "- TODO closure: all 109 - [ ] items changed to - [x]"
447
+ open_todos = sum(1 for line in lines if line.lstrip().startswith("- [ ]"))
448
+ closed_todos = sum(1 for line in lines if line.lstrip().startswith("- [x]"))
447
449
  if open_todos > 20:
448
450
  results.append(
449
451
  AuditResult(
@@ -715,8 +717,34 @@ def check_tool_configuration(root: Path) -> list[AuditResult]:
715
717
  return results
716
718
 
717
719
 
720
+ # Types that require explicit configuration and cannot be reliably inferred
721
+ # from file-extension counts alone. When a project declares one of these,
722
+ # auto-detection is skipped so that auxiliary tooling languages (e.g. Python
723
+ # verification scripts in an FPGA project) do not produce a false-positive
724
+ # mismatch. See GitHub issue #194.
725
+ _EXPLICIT_ONLY_TYPES: frozenset[str] = frozenset(
726
+ [
727
+ "fpga-rtl",
728
+ "fpga-rtl-amd",
729
+ "fpga-rtl-intel",
730
+ "fpga-rtl-lattice",
731
+ "mixed-fpga-embedded",
732
+ "mixed-fpga-firmware",
733
+ "embedded-hardware",
734
+ "pcb-hardware",
735
+ "yocto-bsp",
736
+ ]
737
+ )
738
+
739
+
718
740
  def check_type_mismatch(root: Path) -> list[AuditResult]:
719
- """Check if scaffold.yml type matches actual detected project type."""
741
+ """Check if scaffold.yml type matches actual detected project type.
742
+
743
+ For hardware / vendor-specific types that cannot be auto-detected from
744
+ file-extension counts (see ``_EXPLICIT_ONLY_TYPES``), the detection step
745
+ is skipped entirely so that auxiliary languages (e.g. Python scripts in an
746
+ FPGA project) never produce a false-positive mismatch.
747
+ """
720
748
  results: list[AuditResult] = []
721
749
  scaffold_path = root / "scaffold.yml"
722
750
  if not scaffold_path.exists():
@@ -731,6 +759,20 @@ def check_type_mismatch(root: Path) -> list[AuditResult]:
731
759
  with open(scaffold_path) as f:
732
760
  raw = yaml.safe_load(f)
733
761
  config = ProjectConfig(**raw)
762
+
763
+ # Skip auto-detection for types that must be specified explicitly.
764
+ if config.type in _EXPLICIT_ONLY_TYPES:
765
+ results.append(
766
+ AuditResult(
767
+ name="type-mismatch",
768
+ passed=True,
769
+ message=(
770
+ f"Project type {config.type} is explicitly set; auto-detection skipped"
771
+ ),
772
+ )
773
+ )
774
+ return results
775
+
734
776
  detected = detect_project(root)
735
777
  if detected.inferred_type and detected.inferred_type != config.type:
736
778
  results.append(
@@ -350,6 +350,16 @@ def init(config_path: str | None, output_dir: str, no_git: bool, guided: bool) -
350
350
 
351
351
  write_phase(target, "inception")
352
352
 
353
+ # Auto-register with the MCP governance server (best-effort, never blocks)
354
+ with contextlib.suppress(Exception):
355
+ from specsmith.mcp_server import register_project
356
+
357
+ if register_project(str(target)):
358
+ console.print(
359
+ " [dim]\u2713 Registered with MCP server "
360
+ "([bold]specsmith mcp projects[/bold] to view)[/dim]"
361
+ )
362
+
353
363
 
354
364
  def _load_config_with_inheritance(config_path: str) -> dict[str, object]:
355
365
  """Load scaffold.yml, merging parent config if `extends` is set."""
@@ -1746,6 +1756,16 @@ def import_project(
1746
1756
  console.print(f"\n[bold green]Done.[/bold green] {len(created)} governance files generated.")
1747
1757
  console.print("Governance files generated. Review project configuration.")
1748
1758
 
1759
+ # Auto-register with the MCP governance server (best-effort, never blocks)
1760
+ with contextlib.suppress(Exception):
1761
+ from specsmith.mcp_server import register_project
1762
+
1763
+ if register_project(str(root)):
1764
+ console.print(
1765
+ " [dim]\u2713 Registered with MCP server "
1766
+ "([bold]specsmith mcp projects[/bold] to view)[/dim]"
1767
+ )
1768
+
1749
1769
 
1750
1770
  def _run_guided_architecture(cfg: ProjectConfig, target: Path) -> list[Path]:
1751
1771
  """Run interactive architecture definition and generate REQ/TEST stubs."""
@@ -3207,32 +3227,61 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
3207
3227
 
3208
3228
  # ── Human-readable anchor block ───────────────────────────────────────────
3209
3229
  # Designed to be compact and survive context summarization.
3210
- hbar = "\u2550" * 57 # ═══…
3230
+ _w = 57 # interior width — must match len(hbar)
3231
+ hbar = "\u2550" * _w # ═══…
3211
3232
  vbar = "\u2551" # ║
3212
3233
  health_icon = "\u2713" if health_ok else "\u2717"
3213
3234
  esdb_icon = "\u2713" if esdb_ok else "\u2717"
3214
3235
  wi_str = ", ".join(recent_wis) if recent_wis else "none seen"
3215
3236
 
3237
+ def _arow(rich: str, plain: str, wide: int = 0) -> str:
3238
+ """Format one anchor box row: ║ <content padded to _w terminal cols> ║.
3239
+
3240
+ ``plain`` is the markup-free string used for width calculation.
3241
+ ``wide`` is the count of 2-wide (full-width/emoji) characters in ``plain``
3242
+ that add an extra terminal column beyond their Python ``len()``.
3243
+ """
3244
+ pad = " " * max(0, _w - len(plain) - wide)
3245
+ return f"[bold cyan]{vbar}[/bold cyan]{rich}{pad}[bold cyan]{vbar}[/bold cyan]"
3246
+
3216
3247
  console.print(f"[bold cyan]\u2554{hbar}\u2557[/bold cyan]")
3217
- console.print(f"[bold cyan]{vbar}[/bold cyan] GOVERNANCE ANCHOR {ts}")
3218
- console.print(f"[bold cyan]{vbar}[/bold cyan] Project : [bold]{project_name}[/bold]")
3219
- console.print(
3220
- f"[bold cyan]{vbar}[/bold cyan] Phase : {phase_emoji} {phase_label} ({phase_pct}%)"
3248
+
3249
+ r1 = f" GOVERNANCE ANCHOR {ts}"
3250
+ console.print(_arow(r1, r1))
3251
+
3252
+ r2_plain = f" Project : {project_name}"
3253
+ console.print(_arow(f" Project : [bold]{project_name}[/bold]", r2_plain))
3254
+
3255
+ r3_plain = f" Phase : {phase_emoji} {phase_label} ({phase_pct}%)"
3256
+ console.print(_arow(r3_plain, r3_plain, wide=1 if phase_emoji else 0))
3257
+
3258
+ r4_plain = (
3259
+ f" Health : {health_icon} clean"
3260
+ if health_ok
3261
+ else f" Health : {health_icon} {audit_failed} issues"
3221
3262
  )
3222
- health_str = (
3223
- f"[green]{health_icon} clean[/green]"
3263
+ r4_rich = (
3264
+ f" Health : [green]{health_icon} clean[/green]"
3224
3265
  if health_ok
3225
- else f"[red]{health_icon} {audit_failed} issues[/red]"
3266
+ else f" Health : [red]{health_icon} {audit_failed} issues[/red]"
3226
3267
  )
3227
- console.print(f"[bold cyan]{vbar}[/bold cyan] Health : {health_str}")
3228
- console.print(
3229
- f"[bold cyan]{vbar}[/bold cyan] REQs : {req_count} TESTs: {test_count}"
3268
+ console.print(_arow(r4_rich, r4_plain))
3269
+
3270
+ r5 = (
3271
+ f" REQs : {req_count} TESTs: {test_count}"
3230
3272
  f" ESDB: {esdb_records} records ({esdb_icon} chain)"
3231
3273
  )
3232
- console.print(f"[bold cyan]{vbar}[/bold cyan] WIs : {wi_str}")
3274
+ console.print(_arow(r5, r5))
3275
+
3276
+ r6 = f" WIs : {wi_str}"
3277
+ console.print(_arow(r6, r6))
3278
+
3233
3279
  if last_preflight:
3234
- pf_short = last_preflight[:55]
3235
- console.print(f"[bold cyan]{vbar}[/bold cyan] Preflight: {pf_short}")
3280
+ _pf_max = _w - len(" Preflight: ") # 45 — was incorrectly 55
3281
+ pf_short = last_preflight[:_pf_max]
3282
+ r7 = f" Preflight: {pf_short}"
3283
+ console.print(_arow(r7, r7))
3284
+
3236
3285
  console.print(f"[bold cyan]\u255a{hbar}\u255d[/bold cyan]")
3237
3286
  console.print(
3238
3287
  "[dim]Include this block verbatim in any context summary "
@@ -9020,42 +9069,63 @@ def mcp_list_cmd(project_dir: str, as_json: bool) -> None:
9020
9069
 
9021
9070
 
9022
9071
  @mcp_group.command(name="serve")
9023
- @click.option("--project-dir", type=click.Path(), default=".", show_default=True)
9024
- def mcp_serve_cmd(project_dir: str) -> None:
9072
+ @click.option(
9073
+ "--project-dir",
9074
+ type=click.Path(),
9075
+ default=None,
9076
+ help=(
9077
+ "Set this path as the *primary* project (first slot / default for tool calls "
9078
+ "that omit project_dir). Omit to use the registry automatically."
9079
+ ),
9080
+ )
9081
+ @click.option(
9082
+ "--project-dirs",
9083
+ default="",
9084
+ help=(
9085
+ "Extra project directories to add on top of the registry (comma-separated absolute paths)."
9086
+ ),
9087
+ )
9088
+ def mcp_serve_cmd(project_dir: str | None, project_dirs: str) -> None:
9025
9089
  """Start the native governance MCP stdio server (REQ-363).
9026
9090
 
9027
9091
  Implements MCP 2024-11-05 over stdin/stdout (JSON-RPC 2.0).
9028
- Exposes six governance tools to any MCP client:
9092
+ Exposes seven governance tools to any MCP client.
9029
9093
 
9030
9094
  \b
9031
- governance_audit Run governance audit
9032
- governance_checkpoint Emit GOVERNANCE ANCHOR JSON
9033
- governance_preflight Preflight a change intent
9034
- governance_phase Current AEE phase + readiness %
9035
- governance_req_list List all requirements
9036
- governance_trace_seal Seal a milestone/decision
9095
+ Recommended Warp config (set once, never touch again)::
9096
+
9097
+ {"specsmith-governance": {"command": "specsmith", "args": ["mcp", "serve"]}}
9037
9098
 
9038
9099
  \b
9039
- Warp config (Settings Agents MCP servers)::
9100
+ Then register each project once from inside that project::
9040
9101
 
9041
- {"specsmith-governance": {"command": "specsmith", "args": ["mcp", "serve"]}}
9102
+ specsmith mcp register
9103
+
9104
+ \b
9105
+ The server reads the registry at startup and serves all registered
9106
+ projects automatically — no config changes needed for new projects.
9042
9107
 
9043
9108
  \b
9044
- Or pass inline to oz (use ``specsmith mcp install-warp`` for the full snippet)::
9109
+ Or pass inline to oz (use ``specsmith mcp install-warp`` for the snippet)::
9045
9110
 
9046
9111
  oz agent run --mcp "$(specsmith mcp install-warp --json)" --prompt "..."
9047
9112
  """
9048
9113
  from specsmith.mcp_server import run_server
9049
9114
 
9050
- run_server(project_dir=project_dir)
9115
+ extra = [p.strip() for p in project_dirs.split(",") if p.strip()] if project_dirs else []
9116
+ run_server(project_dir=project_dir, extra_project_dirs=extra)
9051
9117
 
9052
9118
 
9053
9119
  @mcp_group.command(name="install-warp")
9054
- @click.option("--project-dir", type=click.Path(), default=".", show_default=True)
9055
9120
  @click.option("--json", "as_json", is_flag=True, default=False, help="Emit JSON config only.")
9056
- def mcp_install_warp_cmd(project_dir: str, as_json: bool) -> None:
9121
+ def mcp_install_warp_cmd(as_json: bool) -> None:
9057
9122
  """Print the Warp MCP config snippet for the governance server (REQ-363).
9058
9123
 
9124
+ Generates a minimal, registry-aware config — paste it into Warp once
9125
+ and never change it again. Register new projects with::
9126
+
9127
+ specsmith mcp register # in the project directory
9128
+
9059
9129
  Copy the output into Warp Settings → Agents → MCP servers, or pass it
9060
9130
  to ``oz agent run --mcp '<json>'`` for a one-off cloud agent run.
9061
9131
  """
@@ -9063,15 +9133,36 @@ def mcp_install_warp_cmd(project_dir: str, as_json: bool) -> None:
9063
9133
  import shutil
9064
9134
  import sys
9065
9135
 
9066
- # Resolve the specsmith CLI executable: prefer the one on PATH, then
9067
- # fall back to deriving it from the current interpreter (dev installs).
9068
- specsmith_exe = shutil.which("specsmith") or str(
9069
- Path(sys.executable).parent / ("specsmith.exe" if sys.platform == "win32" else "specsmith")
9070
- )
9136
+ # Env vars the server needs regardless of how it is invoked.
9137
+ # SPECSMITH_ALLOW_NON_PIPX=1 — prevents the pipx-enforcement gate from
9138
+ # exiting before the MCP handshake when Warp starts the server directly.
9139
+ # SPECSMITH_NO_AUTO_UPDATE / SPECSMITH_PYPI_CHECKED — suppress network
9140
+ # calls on startup so the server responds immediately.
9141
+ server_env = {
9142
+ "SPECSMITH_ALLOW_NON_PIPX": "1",
9143
+ "SPECSMITH_NO_AUTO_UPDATE": "1",
9144
+ "SPECSMITH_PYPI_CHECKED": "1",
9145
+ }
9146
+
9147
+ # Executable detection strategy (in priority order):
9148
+ # 1. specsmith (or specsmith.exe) on PATH — covers pipx shims and system installs.
9149
+ # 2. python -m specsmith via the current interpreter — reliable fallback
9150
+ # for editable dev installs and venvs where the console script wrapper
9151
+ # is absent or resolves incorrectly (e.g. some Windows pipx setups).
9152
+ specsmith_exe = shutil.which("specsmith") or shutil.which("specsmith.exe")
9153
+ if specsmith_exe:
9154
+ cmd = specsmith_exe
9155
+ args: list[str] = ["mcp", "serve"]
9156
+ else:
9157
+ # Fall back to `python -m specsmith` using the current interpreter.
9158
+ cmd = sys.executable
9159
+ args = ["-m", "specsmith", "mcp", "serve"]
9160
+
9071
9161
  config = {
9072
9162
  "specsmith-governance": {
9073
- "command": specsmith_exe,
9074
- "args": ["mcp", "serve", "--project-dir", str(Path(project_dir).resolve())],
9163
+ "command": cmd,
9164
+ "args": args,
9165
+ "env": server_env,
9075
9166
  }
9076
9167
  }
9077
9168
 
@@ -9086,10 +9177,122 @@ def mcp_install_warp_cmd(project_dir: str, as_json: bool) -> None:
9086
9177
  )
9087
9178
  console.print(_json.dumps(config, indent=2))
9088
9179
  console.print(
9089
- "\n[dim]After adding, Warp/Oz can call governance_audit, governance_preflight,\n"
9090
- "governance_checkpoint, governance_phase, governance_req_list, and\n"
9091
- "governance_trace_seal as structured MCP tool calls.\n"
9092
- "\nVerify with: specsmith mcp serve (then send an initialize message).[/dim]"
9180
+ "\n[dim][bold]One-time setup[/bold] paste this config into Warp once," # noqa: E501
9181
+ " then never touch it again.\n"
9182
+ "\nTo add each project, run this inside the project directory:\n"
9183
+ " [bold]specsmith mcp register[/bold]\n"
9184
+ "\nThe server reads [bold]~/.specsmith/mcp-projects.json[/bold] at startup\n"
9185
+ "and serves all registered projects automatically.\n"
9186
+ "\nView registered projects: [bold]specsmith mcp projects[/bold]\n"
9187
+ "\nVerify server: specsmith mcp serve (then send an initialize message).[/dim]"
9188
+ )
9189
+
9190
+
9191
+ @mcp_group.command(name="register")
9192
+ @click.argument("path", default=".", required=False)
9193
+ def mcp_register_cmd(path: str) -> None:
9194
+ """Register a project directory with the MCP server registry.
9195
+
9196
+ Run once inside a project directory to add it to
9197
+ ``~/.specsmith/mcp-projects.json``. The next ``specsmith mcp serve``
9198
+ invocation will automatically include it — no Warp config changes needed.
9199
+
9200
+ \b
9201
+ Examples::
9202
+
9203
+ specsmith mcp register # register current directory
9204
+ specsmith mcp register /path/to/myproject
9205
+ """
9206
+ from specsmith.mcp_server import register_project
9207
+
9208
+ root = Path(path).resolve()
9209
+ if not root.exists():
9210
+ console.print(f"[red]\u2717[/red] Path does not exist: {root}")
9211
+ raise SystemExit(1)
9212
+
9213
+ added = register_project(str(root))
9214
+ if added:
9215
+ console.print(f"[green]\u2713[/green] Registered: [bold]{root}[/bold]")
9216
+ if not (root / ".specsmith").exists():
9217
+ console.print(
9218
+ " [yellow]\u26a0[/yellow] No .specsmith/ found. "
9219
+ "Run [bold]specsmith init[/bold] or [bold]specsmith import[/bold] first."
9220
+ )
9221
+ else:
9222
+ console.print(f"[dim]Already registered: {root}[/dim]")
9223
+ console.print(
9224
+ " [dim]specsmith mcp projects ← view all registered[/dim]\n"
9225
+ " [dim]specsmith mcp serve ← start the server[/dim]"
9226
+ )
9227
+
9228
+
9229
+ @mcp_group.command(name="unregister")
9230
+ @click.argument("path", default=".", required=False)
9231
+ def mcp_unregister_cmd(path: str) -> None:
9232
+ """Remove a project directory from the MCP server registry.
9233
+
9234
+ \b
9235
+ Examples::
9236
+
9237
+ specsmith mcp unregister # unregister current directory
9238
+ specsmith mcp unregister /path/to/myproject
9239
+ """
9240
+ from specsmith.mcp_server import unregister_project
9241
+
9242
+ root = Path(path).resolve()
9243
+ removed = unregister_project(str(root))
9244
+ if removed:
9245
+ console.print(f"[green]\u2713[/green] Unregistered: [bold]{root}[/bold]")
9246
+ else:
9247
+ console.print(f"[yellow]Not registered: {root}[/yellow]")
9248
+
9249
+
9250
+ @mcp_group.command(name="projects")
9251
+ @click.option("--json", "as_json", is_flag=True, default=False, help="Emit as JSON.")
9252
+ def mcp_projects_cmd(as_json: bool) -> None:
9253
+ """List all projects registered with the MCP server.
9254
+
9255
+ Shows each registered project path and whether it still exists on disk.
9256
+ The first entry is the default (used when a tool call omits project_dir).
9257
+ """
9258
+ import json as _json
9259
+ import os
9260
+
9261
+ from specsmith.mcp_server import _registry_file, read_registry
9262
+
9263
+ projects = read_registry()
9264
+ reg_path = _registry_file()
9265
+
9266
+ if as_json:
9267
+ entries = [
9268
+ {"path": p, "exists": Path(p).exists(), "is_default": i == 0}
9269
+ for i, p in enumerate(projects)
9270
+ ]
9271
+ click.echo(_json.dumps({"registry": str(reg_path), "projects": entries}, indent=2))
9272
+ return
9273
+
9274
+ if not projects:
9275
+ console.print("[yellow]No projects registered.[/yellow]")
9276
+ console.print(
9277
+ "[dim]Run [bold]specsmith mcp register[/bold] inside a project to add it.[/dim]"
9278
+ )
9279
+ return
9280
+
9281
+ console.print(
9282
+ f"[bold]Registered MCP projects[/bold] ({len(projects)}) [dim]{reg_path}[/dim]\n"
9283
+ )
9284
+ for i, p in enumerate(projects):
9285
+ exists = Path(p).exists()
9286
+ default_tag = " [bold cyan][default][/bold cyan]" if i == 0 else ""
9287
+ health = "[green]\u2713 exists[/green]" if exists else "[red]\u2717 not found[/red]"
9288
+ # Abbreviate long paths using ~ for home
9289
+ display = p.replace(os.path.expanduser("~"), "~")
9290
+ console.print(f" {health} {display}{default_tag}")
9291
+
9292
+ console.print(
9293
+ "\n[dim] specsmith mcp register [path] ← add a project"
9294
+ "\n specsmith mcp unregister [path] ← remove a project"
9295
+ "\n specsmith mcp serve ← start the server[/dim]"
9093
9296
  )
9094
9297
 
9095
9298
 
@@ -35,8 +35,8 @@ No external dependencies — stdlib only + existing specsmith modules.
35
35
 
36
36
  from __future__ import annotations
37
37
 
38
- import contextlib
39
38
  import json
39
+ import os
40
40
  import sys
41
41
  import time
42
42
  from pathlib import Path
@@ -50,7 +50,92 @@ MCP_PROTOCOL_VERSION = "2024-11-05"
50
50
  SERVER_NAME = "specsmith-governance"
51
51
  SERVER_VERSION = "0.12.0"
52
52
 
53
+ # ---------------------------------------------------------------------------
54
+ # Multi-project state — populated by run_server() at startup
55
+ # ---------------------------------------------------------------------------
56
+
57
+ # Default project dir used when a tool call omits ``project_dir``.
58
+ _DEFAULT_PROJECT_DIR: str = "."
59
+
60
+ # All registered project directories (absolute paths), default first.
61
+ _REGISTERED_PROJECTS: list[str] = []
62
+
63
+
64
+ # ---------------------------------------------------------------------------
65
+ # Persistent project registry (~/.specsmith/mcp-projects.json)
66
+ # ---------------------------------------------------------------------------
67
+
68
+
69
+ def _registry_file() -> Path:
70
+ """Return the path to the user-level MCP project registry file.
71
+
72
+ Respects ``SPECSMITH_HOME`` if set; otherwise uses
73
+ ``~/.specsmith/mcp-projects.json``.
74
+ """
75
+ base = os.environ.get("SPECSMITH_HOME", "").strip()
76
+ home = Path(base) if base else Path.home() / ".specsmith"
77
+ return home / "mcp-projects.json"
78
+
79
+
80
+ def read_registry() -> list[str]:
81
+ """Return all absolute project paths from the registry.
82
+
83
+ Returns an empty list when the registry file is missing or malformed.
84
+ Invalid entries (empty strings, non-strings) are silently skipped.
85
+ """
86
+ try:
87
+ data = json.loads(_registry_file().read_text(encoding="utf-8"))
88
+ projects = data.get("projects", []) if isinstance(data, dict) else []
89
+ return [p for p in projects if isinstance(p, str) and p]
90
+ except Exception: # noqa: BLE001
91
+ return []
92
+
93
+
94
+ def write_registry(paths: list[str]) -> None:
95
+ """Persist *paths* to the registry file (creates parent dirs as needed)."""
96
+ reg = _registry_file()
97
+ reg.parent.mkdir(parents=True, exist_ok=True)
98
+ reg.write_text(
99
+ json.dumps({"projects": paths}, indent=2, ensure_ascii=False),
100
+ encoding="utf-8",
101
+ )
102
+
103
+
104
+ def register_project(path: str = ".") -> bool:
105
+ """Add *path* to the registry. Returns True if it was newly added."""
106
+ abs_path = str(Path(path).resolve())
107
+ projects = read_registry()
108
+ if abs_path in projects:
109
+ return False
110
+ projects.append(abs_path)
111
+ write_registry(projects)
112
+ return True
113
+
114
+
115
+ def unregister_project(path: str = ".") -> bool:
116
+ """Remove *path* from the registry. Returns True if it was present."""
117
+ abs_path = str(Path(path).resolve())
118
+ projects = read_registry()
119
+ if abs_path not in projects:
120
+ return False
121
+ write_registry([p for p in projects if p != abs_path])
122
+ return True
123
+
124
+
53
125
  _TOOLS: list[dict[str, Any]] = [
126
+ {
127
+ "name": "governance_project_list",
128
+ "description": (
129
+ "List all project directories registered in this MCP server instance. "
130
+ "Use the returned paths as the `project_dir` argument for other tools "
131
+ "when working with multiple simultaneous projects."
132
+ ),
133
+ "inputSchema": {
134
+ "type": "object",
135
+ "properties": {},
136
+ "required": [],
137
+ },
138
+ },
54
139
  {
55
140
  "name": "governance_audit",
56
141
  "description": (
@@ -195,10 +280,25 @@ _TOOLS: list[dict[str, Any]] = [
195
280
 
196
281
 
197
282
  def _resolve_root(args: dict[str, Any]) -> Path:
198
- raw = args.get("project_dir", ".")
283
+ """Resolve project_dir from args, falling back to the server default.
284
+
285
+ If ``project_dir`` is not in *args* (or is empty), we use
286
+ ``_DEFAULT_PROJECT_DIR`` so callers don't have to repeat the path on
287
+ every tool call when only one project is active.
288
+ """
289
+ raw = args.get("project_dir") or _DEFAULT_PROJECT_DIR
199
290
  return Path(str(raw)).resolve()
200
291
 
201
292
 
293
+ def _handle_governance_project_list(args: dict[str, Any]) -> dict[str, Any]: # noqa: ARG001
294
+ """Return the list of projects registered in this server instance."""
295
+ return {
296
+ "default_project": _DEFAULT_PROJECT_DIR,
297
+ "projects": _REGISTERED_PROJECTS,
298
+ "count": len(_REGISTERED_PROJECTS),
299
+ }
300
+
301
+
202
302
  def _handle_governance_audit(args: dict[str, Any]) -> dict[str, Any]:
203
303
  """Run the governance audit and return structured results."""
204
304
  root = _resolve_root(args)
@@ -487,6 +587,7 @@ def _handle_governance_trace_seal(args: dict[str, Any]) -> dict[str, Any]:
487
587
  # ---------------------------------------------------------------------------
488
588
 
489
589
  _HANDLERS = {
590
+ "governance_project_list": _handle_governance_project_list,
490
591
  "governance_audit": _handle_governance_audit,
491
592
  "governance_checkpoint": _handle_governance_checkpoint,
492
593
  "governance_preflight": _handle_governance_preflight,
@@ -576,20 +677,57 @@ def _handle_request(msg: dict[str, Any]) -> dict[str, Any] | None:
576
677
  return None
577
678
 
578
679
 
579
- def run_server(project_dir: str = ".") -> None:
680
+ def run_server(
681
+ project_dir: str | None = None,
682
+ extra_project_dirs: list[str] | None = None,
683
+ ) -> None:
580
684
  """Start the MCP stdio server. Blocks until stdin closes.
581
685
 
582
686
  Reads newline-delimited JSON-RPC 2.0 messages from stdin and
583
687
  writes responses to stdout. Stderr is used for diagnostic messages.
584
- The ``project_dir`` is injected into every tool call that doesn't
585
- supply its own ``project_dir`` argument.
688
+
689
+ Project discovery order (highest priority first):
690
+
691
+ 1. ``project_dir`` — if provided, becomes the *default* project (first
692
+ slot). Any tool call that omits ``project_dir`` will target this.
693
+ 2. **Registry** — all paths in ``~/.specsmith/mcp-projects.json`` are
694
+ merged in. Run ``specsmith mcp register`` in a project once to add it.
695
+ 3. ``extra_project_dirs`` — additional paths appended after the registry.
696
+ 4. **Fallback** — if nothing resolves, the current working directory is
697
+ used (useful for development/testing).
698
+
699
+ All paths are resolved to absolute form; duplicates are silently dropped.
700
+ The server never calls ``os.chdir()``.
586
701
  """
587
- import os
702
+ global _DEFAULT_PROJECT_DIR, _REGISTERED_PROJECTS
703
+
704
+ all_dirs: list[str] = []
705
+ seen: set[str] = set()
588
706
 
589
- # Set working directory so relative paths in tool calls resolve correctly
590
- if project_dir and project_dir != ".":
591
- with contextlib.suppress(OSError):
592
- os.chdir(project_dir)
707
+ def _add(p: str) -> None:
708
+ abs_p = str(Path(p).resolve())
709
+ if abs_p not in seen:
710
+ seen.add(abs_p)
711
+ all_dirs.append(abs_p)
712
+
713
+ # 1. Explicit primary project (becomes the default)
714
+ if project_dir is not None:
715
+ _add(project_dir)
716
+
717
+ # 2. Persistent registry
718
+ for p in read_registry():
719
+ _add(p)
720
+
721
+ # 3. Additional explicit dirs
722
+ for p in extra_project_dirs or []:
723
+ _add(p)
724
+
725
+ # 4. CWD fallback when nothing is registered
726
+ if not all_dirs:
727
+ _add(".")
728
+
729
+ _DEFAULT_PROJECT_DIR = all_dirs[0]
730
+ _REGISTERED_PROJECTS = all_dirs
593
731
 
594
732
  for raw_line in sys.stdin:
595
733
  raw_line = raw_line.strip()
@@ -615,4 +753,14 @@ def run_server(project_dir: str = ".") -> None:
615
753
  _send(response)
616
754
 
617
755
 
618
- __all__ = ["run_server", "SERVER_NAME", "SERVER_VERSION", "_TOOLS", "_HANDLERS"]
756
+ __all__ = [
757
+ "run_server",
758
+ "read_registry",
759
+ "write_registry",
760
+ "register_project",
761
+ "unregister_project",
762
+ "SERVER_NAME",
763
+ "SERVER_VERSION",
764
+ "_TOOLS",
765
+ "_HANDLERS",
766
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.12.0.dev493
3
+ Version: 0.12.0.dev496
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