specsmith 0.22.0__tar.gz → 0.22.2__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 (395) hide show
  1. {specsmith-0.22.0/src/specsmith.egg-info → specsmith-0.22.2}/PKG-INFO +7 -4
  2. {specsmith-0.22.0 → specsmith-0.22.2}/README.md +5 -0
  3. {specsmith-0.22.0 → specsmith-0.22.2}/pyproject.toml +5 -5
  4. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/__init__.py +1 -1
  5. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/broker.py +11 -2
  6. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/cli.py +81 -60
  7. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/config.py +1 -1
  8. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/governance_logic.py +36 -0
  9. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs_commands.py +15 -3
  10. {specsmith-0.22.0 → specsmith-0.22.2/src/specsmith.egg-info}/PKG-INFO +7 -4
  11. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/SOURCES.txt +4 -0
  12. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/requires.txt +1 -3
  13. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_cli.py +62 -0
  14. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_license.py +12 -0
  15. specsmith-0.22.2/tests/test_esdb_migrate_wal_repair.py +79 -0
  16. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_nexus.py +42 -0
  17. specsmith-0.22.2/tests/test_release_version_contract.py +36 -0
  18. specsmith-0.22.2/tests/test_rtd_deploy_workflow.py +22 -0
  19. specsmith-0.22.2/tests/test_vcs_commands.py +57 -0
  20. {specsmith-0.22.0 → specsmith-0.22.2}/LICENSE +0 -0
  21. {specsmith-0.22.0 → specsmith-0.22.2}/setup.cfg +0 -0
  22. {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/__init__.py +0 -0
  23. {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/belief.py +0 -0
  24. {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/certainty.py +0 -0
  25. {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/failure_graph.py +0 -0
  26. {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/py.typed +0 -0
  27. {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/recovery.py +0 -0
  28. {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/session.py +0 -0
  29. {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/stress_tester.py +0 -0
  30. {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/trace.py +0 -0
  31. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/__main__.py +0 -0
  32. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/advanced_code_analysis.py +0 -0
  33. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/__init__.py +0 -0
  34. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/chat_runner.py +0 -0
  35. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/cleanup.py +0 -0
  36. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/context_seed.py +0 -0
  37. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/core.py +0 -0
  38. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/__init__.py +0 -0
  39. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/_status.py +0 -0
  40. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/dag.py +0 -0
  41. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
  42. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/events.py +0 -0
  43. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/result.py +0 -0
  44. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/endpoints.py +0 -0
  45. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/events.py +0 -0
  46. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/execution_profiles.py +0 -0
  47. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/fallback.py +0 -0
  48. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/hf_leaderboard.py +0 -0
  49. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/hf_sync.py +0 -0
  50. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/indexer.py +0 -0
  51. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/llm_client.py +0 -0
  52. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/mcp.py +0 -0
  53. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/memory.py +0 -0
  54. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/model_intelligence.py +0 -0
  55. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/model_profiles.py +0 -0
  56. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/model_router.py +0 -0
  57. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/orchestrator.py +0 -0
  58. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/permissions.py +0 -0
  59. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/profiles.py +0 -0
  60. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/provider_registry.py +0 -0
  61. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/repl.py +0 -0
  62. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/router.py +0 -0
  63. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/rules.py +0 -0
  64. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/runner.py +0 -0
  65. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/safety.py +0 -0
  66. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/spawner.py +0 -0
  67. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/suggester.py +0 -0
  68. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/teams.py +0 -0
  69. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/terminal_env.py +0 -0
  70. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/token_pricing.py +0 -0
  71. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/tools.py +0 -0
  72. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/verifier.py +0 -0
  73. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/voice.py +0 -0
  74. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/approvals.py +0 -0
  75. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/architect.py +0 -0
  76. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/auditor.py +0 -0
  77. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/auth.py +0 -0
  78. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/block_export.py +0 -0
  79. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/channel.py +0 -0
  80. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/chat_handoff.py +0 -0
  81. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/ci_manager.py +0 -0
  82. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/code_analysis.py +0 -0
  83. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/__init__.py +0 -0
  84. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/intelligence.py +0 -0
  85. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/issues_policy.py +0 -0
  86. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/reporting.py +0 -0
  87. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/zoo_code.py +0 -0
  88. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/__init__.py +0 -0
  89. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/_compat.py +0 -0
  90. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/checker.py +0 -0
  91. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/evidence.py +0 -0
  92. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/regulations.py +0 -0
  93. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/reporter.py +0 -0
  94. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compressor.py +0 -0
  95. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/console_utils.py +0 -0
  96. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/context_orchestrator.py +0 -0
  97. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/context_window.py +0 -0
  98. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/credit_analyzer.py +0 -0
  99. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/credits.py +0 -0
  100. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/dashboard.py +0 -0
  101. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/__init__.py +0 -0
  102. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/base.py +0 -0
  103. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/citations.py +0 -0
  104. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/fpd.py +0 -0
  105. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/odp.py +0 -0
  106. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/patentsview.py +0 -0
  107. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/pfw.py +0 -0
  108. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/ppubs.py +0 -0
  109. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/ptab.py +0 -0
  110. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/differ.py +0 -0
  111. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/doctor.py +0 -0
  112. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/drive.py +0 -0
  113. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/editor.py +0 -0
  114. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/efficiency.py +0 -0
  115. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/__init__.py +0 -0
  116. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/belief.py +0 -0
  117. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/certainty.py +0 -0
  118. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/failure_graph.py +0 -0
  119. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/recovery.py +0 -0
  120. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/stress_tester.py +0 -0
  121. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb/__init__.py +0 -0
  122. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb/_license.py +0 -0
  123. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb/bridge.py +0 -0
  124. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb/sqlite_store.py +0 -0
  125. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb_sweep.py +0 -0
  126. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb_writer.py +0 -0
  127. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/eval/__init__.py +0 -0
  128. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/eval/builtins.py +0 -0
  129. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/eval/runner.py +0 -0
  130. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/executor.py +0 -0
  131. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/exporter.py +0 -0
  132. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/governance_store.py +0 -0
  133. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/governance_yaml.py +0 -0
  134. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/governed_pr.py +0 -0
  135. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/__init__.py +0 -0
  136. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/app.py +0 -0
  137. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/main_window.py +0 -0
  138. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/session_tab.py +0 -0
  139. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/theme.py +0 -0
  140. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/__init__.py +0 -0
  141. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/chat_view.py +0 -0
  142. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/input_bar.py +0 -0
  143. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  144. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/token_meter.py +0 -0
  145. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  146. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/update_checker.py +0 -0
  147. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/worker.py +0 -0
  148. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/history_search.py +0 -0
  149. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/importer.py +0 -0
  150. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/improvement_tracker.py +0 -0
  151. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/instinct.py +0 -0
  152. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/__init__.py +0 -0
  153. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/agent_skill.py +0 -0
  154. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/aider.py +0 -0
  155. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/base.py +0 -0
  156. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/claude_code.py +0 -0
  157. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/codity.py +0 -0
  158. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/copilot.py +0 -0
  159. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/cursor.py +0 -0
  160. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/gemini.py +0 -0
  161. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/warp.py +0 -0
  162. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/windsurf.py +0 -0
  163. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/issue_reporter.py +0 -0
  164. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/languages.py +0 -0
  165. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/ledger.py +0 -0
  166. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/local_model.py +0 -0
  167. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/mcp_generator.py +0 -0
  168. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/mcp_server.py +0 -0
  169. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/__init__.py +0 -0
  170. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
  171. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m002_agents_slim.py +0 -0
  172. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m003_compliance_init.py +0 -0
  173. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
  174. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
  175. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m006_session_governance.py +0 -0
  176. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m007_yaml_first.py +0 -0
  177. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m008_esdb_full_coverage.py +0 -0
  178. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m009_esdb_first.py +0 -0
  179. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m010_post_esdb_cleanup.py +0 -0
  180. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m011_windows_skill_shell.py +0 -0
  181. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m012_normalize_skill_shell.py +0 -0
  182. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/runner.py +0 -0
  183. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/model_optimizer.py +0 -0
  184. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/model_registry.py +0 -0
  185. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/ollama_cmds.py +0 -0
  186. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/patent.py +0 -0
  187. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/paths.py +0 -0
  188. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/phase.py +0 -0
  189. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/plugins.py +0 -0
  190. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/policy.py +0 -0
  191. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/profiles.py +0 -0
  192. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/project_metrics.py +0 -0
  193. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/quality_report.py +0 -0
  194. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/rate_limits.py +0 -0
  195. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/recover.py +0 -0
  196. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/release_guard.py +0 -0
  197. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/releaser.py +0 -0
  198. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/requirements.py +0 -0
  199. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/requirements_parser.py +0 -0
  200. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/retrieval.py +0 -0
  201. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/risk.py +0 -0
  202. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/safe_write.py +0 -0
  203. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/scaffolder.py +0 -0
  204. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/serve.py +0 -0
  205. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/session.py +0 -0
  206. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/session_init.py +0 -0
  207. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/session_store.py +0 -0
  208. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/__init__.py +0 -0
  209. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/ai_agents.py +0 -0
  210. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/cloud.py +0 -0
  211. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/corporate.py +0 -0
  212. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/cross_platform.py +0 -0
  213. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/data_engineering.py +0 -0
  214. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/devops.py +0 -0
  215. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/docs.py +0 -0
  216. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/embedded.py +0 -0
  217. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/governance.py +0 -0
  218. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/hardware.py +0 -0
  219. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/mobile.py +0 -0
  220. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/platform_engineering.py +0 -0
  221. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/productivity.py +0 -0
  222. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/software_engineering.py +0 -0
  223. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/specsmith_core_commands.py +0 -0
  224. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/specsmith_operations.py +0 -0
  225. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/specsmith_skills.py +0 -0
  226. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/ssh.py +0 -0
  227. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/web_backend.py +0 -0
  228. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills_builder.py +0 -0
  229. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/sync.py +0 -0
  230. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/agents.md.j2 +0 -0
  231. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  232. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  233. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  234. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  235. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  236. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  237. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  238. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/security.md.j2 +0 -0
  239. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  240. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  241. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  242. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  243. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  244. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/editorconfig.j2 +0 -0
  245. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/gitattributes.j2 +0 -0
  246. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/gitignore.j2 +0 -0
  247. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/go/go.mod.j2 +0 -0
  248. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/go/main.go.j2 +0 -0
  249. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  250. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  251. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  252. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  253. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  254. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
  255. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  256. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  257. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
  258. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  259. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  260. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/js/package.json.j2 +0 -0
  261. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/ledger.md.j2 +0 -0
  262. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/python/cli.py.j2 +0 -0
  263. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/python/init.py.j2 +0 -0
  264. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  265. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/readme.md.j2 +0 -0
  266. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  267. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  268. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  269. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  270. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  271. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  272. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  273. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  274. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  275. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/tool_installer.py +0 -0
  276. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/toolrules.py +0 -0
  277. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/tools.py +0 -0
  278. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/trace.py +0 -0
  279. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/transcripts.py +0 -0
  280. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/updater.py +0 -0
  281. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/upgrader.py +0 -0
  282. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/validator.py +0 -0
  283. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/__init__.py +0 -0
  284. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/base.py +0 -0
  285. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/bitbucket.py +0 -0
  286. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/github.py +0 -0
  287. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/gitlab.py +0 -0
  288. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/wi_store.py +0 -0
  289. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/wireframes.py +0 -0
  290. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/workspace.py +0 -0
  291. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/dependency_links.txt +0 -0
  292. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/entry_points.txt +0 -0
  293. {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/top_level.txt +0 -0
  294. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_CMD_001.py +0 -0
  295. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_agent_profiles.py +0 -0
  296. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_agent_run_feedback.py +0 -0
  297. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_agent_runner_ready.py +0 -0
  298. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_ai_client.py +0 -0
  299. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_ai_intelligence.py +0 -0
  300. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_architect_interview.py +0 -0
  301. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_architect_v2.py +0 -0
  302. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_architecture.py +0 -0
  303. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_audit_governance.py +0 -0
  304. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_auditor.py +0 -0
  305. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_benchmark_harness.py +0 -0
  306. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_branch_workflow.py +0 -0
  307. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_broker_scope.py +0 -0
  308. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_channel.py +0 -0
  309. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_chat_diff_decision.py +0 -0
  310. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_chat_handoff.py +0 -0
  311. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_chat_runner_openai_compat.py +0 -0
  312. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_chat_stdin_protocol.py +0 -0
  313. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_cleanup_cmd.py +0 -0
  314. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_cli_regressions.py +0 -0
  315. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_cli_workflows_history_drive.py +0 -0
  316. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_compliance.py +0 -0
  317. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_compliance_governance.py +0 -0
  318. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_compressor.py +0 -0
  319. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_deprecation_registry.py +0 -0
  320. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_dispatch.py +0 -0
  321. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_docs_artifacts.py +0 -0
  322. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_dual_write.py +0 -0
  323. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_e2e_nexus.py +0 -0
  324. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_efficiency.py +0 -0
  325. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_endpoints_cli.py +0 -0
  326. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_endpoints_store.py +0 -0
  327. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_epistemic.py +0 -0
  328. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_backend_switch.py +0 -0
  329. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_enforcement.py +0 -0
  330. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_integration.py +0 -0
  331. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_sqlite.py +0 -0
  332. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_status_integrity.py +0 -0
  333. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_status_output.py +0 -0
  334. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_sweep.py +0 -0
  335. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_verify_chain_cli.py +0 -0
  336. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_writer.py +0 -0
  337. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_fallback_chain.py +0 -0
  338. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_golden_path.py +0 -0
  339. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_importer.py +0 -0
  340. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_improvement_tracker.py +0 -0
  341. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_init_modes.py +0 -0
  342. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_integrations.py +0 -0
  343. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_integrations_codity.py +0 -0
  344. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_integrations_warp.py +0 -0
  345. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_intelligence.py +0 -0
  346. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_issue_policy_features.py +0 -0
  347. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_issue_reporter.py +0 -0
  348. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_issues_263_264.py +0 -0
  349. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_local_model.py +0 -0
  350. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_markdown_deprecation.py +0 -0
  351. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_mcp_client.py +0 -0
  352. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_mcp_server.py +0 -0
  353. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_metrics_flush.py +0 -0
  354. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_migration_direction.py +0 -0
  355. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_migrations_skill_shell.py +0 -0
  356. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_model_registry.py +0 -0
  357. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_model_router.py +0 -0
  358. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_new_modules.py +0 -0
  359. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_parallel_agents.py +0 -0
  360. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_permissions.py +0 -0
  361. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_phase1_4_new.py +0 -0
  362. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_phase34_completion.py +0 -0
  363. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_project_metrics.py +0 -0
  364. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_quality_report.py +0 -0
  365. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_rate_limits.py +0 -0
  366. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_release_guard.py +0 -0
  367. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_releaser.py +0 -0
  368. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_repl.py +0 -0
  369. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_repl_extended.py +0 -0
  370. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_reporting_commands.py +0 -0
  371. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_req_248_262.py +0 -0
  372. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_req_358_359.py +0 -0
  373. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_resume_command.py +0 -0
  374. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_scaffolder.py +0 -0
  375. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_schema_migrations.py +0 -0
  376. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_session_events.py +0 -0
  377. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_skill_marketplace.py +0 -0
  378. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_skills_mcp.py +0 -0
  379. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_smoke.py +0 -0
  380. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_sqlite_parity.py +0 -0
  381. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_suggester.py +0 -0
  382. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_sync_reconcile.py +0 -0
  383. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_terminal_env.py +0 -0
  384. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_token_cost.py +0 -0
  385. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_tools.py +0 -0
  386. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_trace_vault_esdb.py +0 -0
  387. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_typing_guardrails.py +0 -0
  388. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_updater.py +0 -0
  389. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_validator.py +0 -0
  390. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_vcs.py +0 -0
  391. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_warp_parity.py +0 -0
  392. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_warp_parity_followup.py +0 -0
  393. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_wi_lifecycle.py +0 -0
  394. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_wi_lifecycle_extended.py +0 -0
  395. {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_windows_launcher.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.22.0
3
+ Version: 0.22.2
4
4
  Summary: AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider.
5
5
  Author: Layer1Labs Silicon, Inc.
6
6
  License-Expression: MIT
@@ -27,6 +27,7 @@ Requires-Python: >=3.10
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
29
  Requires-Dist: click>=8.1
30
+ Requires-Dist: cryptography>=42.0
30
31
  Requires-Dist: jinja2>=3.1
31
32
  Requires-Dist: pyyaml>=6.0
32
33
  Requires-Dist: pydantic>=2.0
@@ -38,10 +39,8 @@ Requires-Dist: ruff>=0.4; extra == "dev"
38
39
  Requires-Dist: mypy>=1.10; extra == "dev"
39
40
  Requires-Dist: pre-commit>=3.0; extra == "dev"
40
41
  Requires-Dist: types-pyyaml>=6.0; extra == "dev"
41
- Requires-Dist: cryptography>=42.0; extra == "dev"
42
42
  Provides-Extra: esdb
43
43
  Requires-Dist: chronomemory>=0.2.7; extra == "esdb"
44
- Requires-Dist: cryptography>=42.0; extra == "esdb"
45
44
  Provides-Extra: docs
46
45
  Requires-Dist: mkdocs>=1.6; extra == "docs"
47
46
  Requires-Dist: mkdocs-material>=9.5; extra == "docs"
@@ -73,7 +72,6 @@ Requires-Dist: pytest-cov>=4.0; extra == "all"
73
72
  Requires-Dist: ruff>=0.4; extra == "all"
74
73
  Requires-Dist: mypy>=1.10; extra == "all"
75
74
  Provides-Extra: license-verify
76
- Requires-Dist: cryptography>=42.0; extra == "license-verify"
77
75
  Dynamic: license-file
78
76
 
79
77
  # specsmith
@@ -317,6 +315,7 @@ If you hold a chronomemory ESDB license, activate the commercial backend:
317
315
  pip install "specsmith[esdb]" # installs chronomemory from PyPI
318
316
  # or if using pipx:
319
317
  pipx inject specsmith "chronomemory>=0.2.0" # inject into the specsmith pipx venv
318
+ # The license verifier is included in base specsmith; no cryptography injection is needed.
320
319
 
321
320
  # Step 2 — activate your license key
322
321
  specsmith esdb enable --key-file /path/to/your.esdb.key
@@ -340,6 +339,10 @@ pipx upgrade specsmith # preferred — upgrades the pipx-isolated CLI
340
339
  specsmith self-update # alternative: self-update from within specsmith
341
340
  ```
342
341
 
342
+ An intent limited to maintaining the local pipx CLI is returned as the non-blocking
343
+ `environment_only` preflight decision. It exits successfully and creates no project
344
+ work item, ledger entry, or ESDB record. All `--help` invocations are read-only.
345
+
343
346
  ---
344
347
 
345
348
  ## Quick Start
@@ -239,6 +239,7 @@ If you hold a chronomemory ESDB license, activate the commercial backend:
239
239
  pip install "specsmith[esdb]" # installs chronomemory from PyPI
240
240
  # or if using pipx:
241
241
  pipx inject specsmith "chronomemory>=0.2.0" # inject into the specsmith pipx venv
242
+ # The license verifier is included in base specsmith; no cryptography injection is needed.
242
243
 
243
244
  # Step 2 — activate your license key
244
245
  specsmith esdb enable --key-file /path/to/your.esdb.key
@@ -262,6 +263,10 @@ pipx upgrade specsmith # preferred — upgrades the pipx-isolated CLI
262
263
  specsmith self-update # alternative: self-update from within specsmith
263
264
  ```
264
265
 
266
+ An intent limited to maintaining the local pipx CLI is returned as the non-blocking
267
+ `environment_only` preflight decision. It exits successfully and creates no project
268
+ work item, ledger entry, or ESDB record. All `--help` invocations are read-only.
269
+
265
270
  ---
266
271
 
267
272
  ## Quick Start
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specsmith"
7
- version = "0.22.0"
7
+ version = "0.22.2"
8
8
  description = "AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -37,6 +37,8 @@ classifiers = [
37
37
 
38
38
  dependencies = [
39
39
  "click>=8.1",
40
+ # `specsmith esdb enable` verifies Ed25519 license signatures in every install.
41
+ "cryptography>=42.0",
40
42
  "jinja2>=3.1",
41
43
  "pyyaml>=6.0",
42
44
  "pydantic>=2.0",
@@ -54,7 +56,6 @@ dev = [
54
56
  "mypy>=1.10",
55
57
  "pre-commit>=3.0",
56
58
  "types-pyyaml>=6.0",
57
- "cryptography>=42.0", # needed for test_esdb_license.py signing helpers
58
59
  ]
59
60
  # ESDB commercial backend — requires a valid license from licensing@layer1labs.ai
60
61
  # Install: pip install specsmith[esdb]
@@ -62,7 +63,6 @@ dev = [
62
63
  # Terms: https://github.com/layer1labs/specsmith/blob/develop/COMMERCIAL-LICENSE.md
63
64
  esdb = [
64
65
  "chronomemory>=0.2.7", # proprietary commercial — ChronoMemory terms only (not SQLite free tier)
65
- "cryptography>=42.0",
66
66
  ]
67
67
  docs = [
68
68
  "mkdocs>=1.6",
@@ -95,8 +95,8 @@ all = [
95
95
  "ruff>=0.4",
96
96
  "mypy>=1.10",
97
97
  ]
98
- # cryptography for license verification (usable without full esdb extra)
99
- license-verify = ["cryptography>=42.0"]
98
+ # Compatibility extra: cryptography is now part of every supported installation.
99
+ license-verify = []
100
100
 
101
101
  [project.scripts]
102
102
  specsmith = "specsmith.cli:main"
@@ -8,4 +8,4 @@ from importlib.metadata import version as _pkg_version
8
8
  try:
9
9
  __version__: str = _pkg_version("specsmith")
10
10
  except PackageNotFoundError: # running from source without install
11
- __version__ = "0.22.0" # fallback: keep in sync with pyproject.toml
11
+ __version__ = "0.22.2" # fallback: keep in sync with pyproject.toml
@@ -416,7 +416,12 @@ class PreflightDecision:
416
416
 
417
417
  @property
418
418
  def accepted(self) -> bool:
419
- return self.decision.lower() == "accepted"
419
+ return self.decision.lower() in {"accepted", "environment_only"}
420
+
421
+ @property
422
+ def environment_only(self) -> bool:
423
+ """Whether this decision permits local tool maintenance only."""
424
+ return self.decision.lower() == "environment_only"
420
425
 
421
426
 
422
427
  def _resolve_specsmith_executable() -> str:
@@ -523,7 +528,11 @@ def narrate_plan(
523
528
  else:
524
529
  lines.append("No matching governance scope found; will ask before drafting anything new.")
525
530
 
526
- if decision.accepted:
531
+ if decision.environment_only:
532
+ lines.append(
533
+ "Environment-only SpecSmith CLI maintenance may proceed; no project work is governed."
534
+ )
535
+ elif decision.accepted:
527
536
  lines.append("Specsmith approved this work.")
528
537
  elif decision.decision == "needs_clarification":
529
538
  # Surface only one clarifying question (REQ-063 stop-and-align).
@@ -130,9 +130,11 @@ class _AutoUpdateGroup(click.Group):
130
130
  warnings.simplefilter("ignore", DeprecationWarning)
131
131
  protected = list(ctx.protected_args) # [subcommand] in 8.x, [] in 9.0
132
132
  subcommand = protected[0] if protected else (ctx.args[0] if ctx.args else "")
133
+ help_requested = any(arg in {"--help", "-h"} for arg in (*protected, *ctx.args))
133
134
  skip = (
134
135
  os.environ.get("SPECSMITH_NO_AUTO_UPDATE", "").strip() in ("1", "true", "yes")
135
136
  or subcommand in self._SKIP_COMMANDS
137
+ or help_requested
136
138
  )
137
139
 
138
140
  if not skip:
@@ -939,7 +941,7 @@ def preflight_cmd(
939
941
 
940
942
  # REQ-092: decision-specific exit codes so CI / shell wrappers can branch
941
943
  # on intent without parsing the JSON payload.
942
- if decision_str == "accepted":
944
+ if decision_str in {"accepted", "environment_only"}:
943
945
  return # exit 0
944
946
  if decision_str == "needs_clarification":
945
947
  raise SystemExit(2)
@@ -3853,7 +3855,7 @@ def channel_set_cmd(channel: str) -> None:
3853
3855
  if channel == "stable" and is_prerelease_version(__version__):
3854
3856
  raise click.UsageError(
3855
3857
  "Cannot select stable while a prerelease is installed. "
3856
- f"Install a stable build first: {version_mismatch_remediation('0.22.0')}"
3858
+ f"Install a stable build first: {version_mismatch_remediation('0.22.2')}"
3857
3859
  )
3858
3860
 
3859
3861
  set_persisted_channel(channel)
@@ -4100,7 +4102,7 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
4100
4102
  pass
4101
4103
 
4102
4104
  # ── Phase ─────────────────────────────────────────────────────────────────
4103
- phase_key, phase_label, phase_emoji, phase_pct = "unknown", "Unknown", "", 0
4105
+ phase_key, phase_label, phase_pct = "unknown", "Unknown", 0
4104
4106
  try:
4105
4107
  from specsmith.phase import PHASE_MAP, phase_progress_pct, read_phase
4106
4108
 
@@ -4108,7 +4110,6 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
4108
4110
  phase = PHASE_MAP.get(phase_key)
4109
4111
  if phase:
4110
4112
  phase_label = phase.label
4111
- phase_emoji = phase.emoji
4112
4113
  phase_pct = phase_progress_pct(phase, root)
4113
4114
  except Exception: # noqa: BLE001
4114
4115
  pass
@@ -4203,7 +4204,7 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
4203
4204
  "ts": ts,
4204
4205
  "project": project_name,
4205
4206
  "phase": phase_key,
4206
- "phase_label": f"{phase_emoji} {phase_label}",
4207
+ "phase_label": phase_label,
4207
4208
  "phase_pct": phase_pct,
4208
4209
  "health": "clean" if health_ok else f"{audit_failed} issues",
4209
4210
  "audit_failed": audit_failed,
@@ -4223,69 +4224,37 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
4223
4224
 
4224
4225
  # ── Human-readable anchor block ───────────────────────────────────────────
4225
4226
  # Designed to be compact and survive context summarization.
4226
- _w = 57 # interior width — must match len(hbar)
4227
- hbar = "\u2550" * _w # ═══…
4228
- vbar = "\u2551" #
4229
- health_icon = "\u2713" if health_ok else "\u2717"
4230
- esdb_icon = "\u2713" if esdb_ok else "\u2717"
4227
+ _w = 72
4228
+ health_status = "OK" if health_ok else "FAIL"
4229
+ esdb_status = "OK" if esdb_ok else "FAIL"
4231
4230
  if esdb_backend == "chronomemory":
4232
- esdb_field = f"ESDB: {esdb_records} records ({esdb_icon} chain)"
4231
+ esdb_field = f"ESDB: chronomemory {esdb_records} records chain={esdb_status}"
4233
4232
  elif esdb_backend == "sqlite":
4234
- # Compact format keeps the row within the 57-char box interior.
4235
- # " REQs : NNN TESTs: NNN " = 30 chars, leaving 27 for esdb_field.
4236
- esdb_field = f"ESDB: SQLite {esdb_records} recs {esdb_icon}"
4233
+ esdb_field = f"ESDB: sqlite {esdb_records} records chain={esdb_status}"
4237
4234
  else:
4238
4235
  esdb_field = "ESDB: N/A"
4239
4236
  wi_str = ", ".join(recent_wis) if recent_wis else "none seen"
4240
4237
 
4241
- def _arow(rich: str, plain: str, wide: int = 0) -> str:
4242
- """Format one anchor box row: <content padded to _w terminal cols> ║.
4238
+ def _arow(content: str) -> str:
4239
+ """Return an ASCII-only row with a stable terminal-column width."""
4240
+ ascii_content = content.encode("ascii", "backslashreplace").decode("ascii")
4241
+ return f"|{ascii_content[:_w].ljust(_w)}|"
4243
4242
 
4244
- ``plain`` is the markup-free string used for width calculation.
4245
- ``wide`` is the count of 2-wide (full-width/emoji) characters in ``plain``
4246
- that add an extra terminal column beyond their Python ``len()``.
4247
- """
4248
- pad = " " * max(0, _w - len(plain) - wide)
4249
- return f"[bold cyan]{vbar}[/bold cyan]{rich}{pad}[bold cyan]{vbar}[/bold cyan]"
4250
-
4251
- console.print(f"[bold cyan]\u2554{hbar}\u2557[/bold cyan]")
4252
-
4253
- r1 = f" GOVERNANCE ANCHOR {ts}"
4254
- console.print(_arow(r1, r1))
4255
-
4256
- r2_plain = f" Project : {project_name}"
4257
- console.print(_arow(f" Project : [bold]{project_name}[/bold]", r2_plain))
4258
-
4259
- # Emoji omitted from the anchor box: full-width glyphs vary by terminal
4260
- # and break the fixed-width box alignment unpredictably (GH #align).
4261
- r3_plain = f" Phase : {phase_label} ({phase_pct}%)"
4262
- console.print(_arow(r3_plain, r3_plain))
4263
-
4264
- r4_plain = (
4265
- f" Health : {health_icon} clean"
4266
- if health_ok
4267
- else f" Health : {health_icon} {audit_failed} issues"
4268
- )
4269
- r4_rich = (
4270
- f" Health : [green]{health_icon} clean[/green]"
4271
- if health_ok
4272
- else f" Health : [red]{health_icon} {audit_failed} issues[/red]"
4273
- )
4274
- console.print(_arow(r4_rich, r4_plain))
4275
-
4276
- r5 = f" REQs : {req_count} TESTs: {test_count} {esdb_field}"
4277
- console.print(_arow(r5, r5))
4278
-
4279
- r6 = f" WIs : {wi_str}"
4280
- console.print(_arow(r6, r6))
4243
+ click.echo("+" + "-" * _w + "+")
4244
+ click.echo(_arow(f" GOVERNANCE ANCHOR {ts}"))
4245
+ click.echo(_arow(f" Project : {project_name}"))
4246
+ click.echo(_arow(f" Phase : {phase_label} ({phase_pct}%)"))
4247
+ health_field = "clean" if health_ok else f"{audit_failed} issues"
4248
+ click.echo(_arow(f" Health : {health_status} {health_field}"))
4249
+ click.echo(_arow(f" REQs : {req_count} TESTs: {test_count} {esdb_field}"))
4250
+ click.echo(_arow(f" WIs : {wi_str}"))
4281
4251
 
4282
4252
  if last_preflight:
4283
- _pf_max = _w - len(" Preflight: ") # 45 — was incorrectly 55
4253
+ _pf_max = _w - len(" Preflight: ")
4284
4254
  pf_short = last_preflight[:_pf_max]
4285
- r7 = f" Preflight: {pf_short}"
4286
- console.print(_arow(r7, r7))
4255
+ click.echo(_arow(f" Preflight: {pf_short}"))
4287
4256
 
4288
- console.print(f"[bold cyan]\u255a{hbar}\u255d[/bold cyan]")
4257
+ click.echo("+" + "-" * _w + "+")
4289
4258
  console.print(
4290
4259
  "[dim]Include this block verbatim in any context summary "
4291
4260
  r"(\`specsmith checkpoint\` re-generates it).[/dim]",
@@ -11975,18 +11944,50 @@ def esdb_migrate_cmd(project_dir: str, as_json: bool) -> None:
11975
11944
  }
11976
11945
 
11977
11946
  manifest_path = root / ".specsmith" / "esdb_migration_manifest.json"
11978
- manifest_path.parent.mkdir(parents=True, exist_ok=True)
11979
- manifest_path.write_text(_json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8")
11980
11947
 
11981
11948
  # --- Phase 2: migrate into active ESDB backend (if validation passed) ---
11982
11949
  migrate_counts: dict[str, int] = {}
11950
+ wal_repair: dict[str, Any] = {"attempted": False}
11983
11951
  if ok:
11984
11952
  try:
11985
11953
  from specsmith.esdb import open_default_store
11986
11954
 
11987
11955
  with open_default_store(root, warn=False) as store: # type: ignore[attr-defined]
11956
+ from specsmith.esdb import ESDB_BACKEND
11957
+
11958
+ chain_valid = getattr(store, "chain_valid", None)
11959
+ is_invalid_chrono_wal = (
11960
+ ESDB_BACKEND == "chronomemory"
11961
+ and callable(chain_valid)
11962
+ and chain_valid() is False
11963
+ )
11964
+ if is_invalid_chrono_wal:
11965
+ # ChronoMemory < 0.1.3 can retain readable records in a
11966
+ # WAL whose historical hash chain no longer validates.
11967
+ # Back up first, then compact to rebuild the chain safely.
11968
+ wal_repair = {
11969
+ "attempted": True,
11970
+ "detected_invalid": True,
11971
+ "method": "backup_then_compact",
11972
+ }
11973
+ backup = getattr(store, "backup", None)
11974
+ compact = getattr(store, "compact", None)
11975
+ if not callable(backup) or not callable(compact):
11976
+ raise RuntimeError(
11977
+ "ChronoStore cannot repair a legacy WAL because backup() or "
11978
+ "compact() is unavailable",
11979
+ )
11980
+ backup_path = backup()
11981
+ wal_repair["backup_path"] = str(backup_path)
11982
+ compact()
11983
+ wal_repair["chain_valid_after"] = chain_valid() is not False
11984
+ if not wal_repair["chain_valid_after"]:
11985
+ raise RuntimeError(
11986
+ "ChronoStore compact() did not restore WAL chain validity"
11987
+ )
11988
+ wal_repair["ok"] = True
11989
+
11988
11990
  migrate_counts = store.migrate_from_json(root / ".specsmith")
11989
- from specsmith.esdb import ESDB_BACKEND
11990
11991
 
11991
11992
  manifest["migrated"] = migrate_counts
11992
11993
  if ESDB_BACKEND == "chronomemory":
@@ -11994,7 +11995,27 @@ def esdb_migrate_cmd(project_dir: str, as_json: bool) -> None:
11994
11995
  else:
11995
11996
  manifest["backend"] = "SQLite (.specsmith/esdb.sqlite3)"
11996
11997
  except Exception as _me: # noqa: BLE001
11998
+ issue_kind = "legacy-wal-chain-repair" if wal_repair["attempted"] else "esdb-migration"
11999
+ migration_issue = {"kind": issue_kind, "detail": str(_me)}
12000
+ issues.append(migration_issue)
12001
+ errors.append(migration_issue)
12002
+ ok = False
11997
12003
  manifest["chrono_error"] = str(_me)
12004
+ if wal_repair["attempted"]:
12005
+ wal_repair["ok"] = False
12006
+
12007
+ manifest["ok"] = ok
12008
+ manifest["issues"] = issues
12009
+ manifest["error_count"] = len(errors)
12010
+ manifest["warning_count"] = len(issues) - len(errors)
12011
+ manifest["wal_repair"] = wal_repair
12012
+ manifest["next_step"] = (
12013
+ "Ready for ChronoMemory native ingestion."
12014
+ if ok
12015
+ else "Fix errors above, then re-run to update the manifest."
12016
+ )
12017
+ manifest_path.parent.mkdir(parents=True, exist_ok=True)
12018
+ manifest_path.write_text(_json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8")
11998
12019
 
11999
12020
  if as_json:
12000
12021
  click.echo(_json.dumps(manifest, indent=2))
@@ -140,7 +140,7 @@ class ProjectConfig(BaseModel):
140
140
  ),
141
141
  )
142
142
  language: str = Field(default="python", description="Primary language/runtime")
143
- spec_version: str = Field(default="0.22.0", description="Spec version to scaffold from")
143
+ spec_version: str = Field(default="0.22.2", description="Spec version to scaffold from")
144
144
  description: str = Field(default="", description="Short project description")
145
145
 
146
146
  # Options
@@ -19,6 +19,16 @@ from pathlib import Path
19
19
  from typing import Any, cast
20
20
 
21
21
 
22
+ def _is_environment_only_specsmith_upgrade(utterance: str) -> bool:
23
+ """Return whether an utterance only maintains the local pipx CLI."""
24
+ text = utterance.casefold()
25
+ return (
26
+ "specsmith" in text
27
+ and "pipx" in text
28
+ and any(action in text for action in ("install", "update", "upgrade"))
29
+ )
30
+
31
+
22
32
  def _safe_resolve(path: str | Path) -> Path:
23
33
  """Resolve a project directory path and reject traversal sequences.
24
34
 
@@ -88,6 +98,32 @@ def run_preflight(
88
98
  _safe_root = os.path.realpath(_raw)
89
99
  _root_str = _safe_root # alias used by helpers later in this function
90
100
  intent = classify_intent(utterance)
101
+
102
+ # Local pipx maintenance is not a repository change. Return before scope
103
+ # inference and persistence so the command cannot dirty a governed project.
104
+ if _is_environment_only_specsmith_upgrade(utterance):
105
+ return {
106
+ "decision": "environment_only",
107
+ "scope": "environment_only",
108
+ "work_item_id": "",
109
+ "requirement_ids": [],
110
+ "test_case_ids": [],
111
+ "confidence_target": 1.0,
112
+ "instruction": (
113
+ "Pipx-managed local SpecSmith CLI maintenance is outside project governance. "
114
+ "Proceed with `pipx upgrade specsmith`; no project work item or "
115
+ "records were created."
116
+ ),
117
+ "intent": intent.value,
118
+ "ai_disclosure": {
119
+ "governed_by": "specsmith",
120
+ "governance_gated": True,
121
+ "provider": os.environ.get("SPECSMITH_PROVIDER", "local/heuristic"),
122
+ "model": os.environ.get("SPECSMITH_MODEL", "deterministic-broker"),
123
+ "spec_version": __version__,
124
+ },
125
+ }
126
+
91
127
  # Requirements scope source for keyword matching in infer_scope().
92
128
  # Requirements are sourced from .specsmith/requirements.json (YAML-first mode);
93
129
  # the REQUIREMENTS.md markdown is only a token-overlap fallback. The canonical
@@ -39,9 +39,16 @@ def _run_git(root: Path, args: list[str], *, timeout: int = 30) -> GitResult:
39
39
 
40
40
 
41
41
  def get_current_branch(root: Path) -> str:
42
- """Get the current git branch name."""
42
+ """Get the current git branch name for the supplied worktree."""
43
43
  result = _run_git(root, ["branch", "--show-current"])
44
- return result.output if result.success else ""
44
+ branch = result.output.strip() if result.success else ""
45
+ if branch:
46
+ return branch
47
+
48
+ # ``branch --show-current`` is empty in some shell/worktree combinations
49
+ # despite HEAD being attached. ``symbolic-ref`` is the authoritative fallback.
50
+ result = _run_git(root, ["symbolic-ref", "--quiet", "--short", "HEAD"])
51
+ return result.output.strip() if result.success else ""
45
52
 
46
53
 
47
54
  def has_uncommitted_changes(root: Path) -> bool:
@@ -166,7 +173,12 @@ def run_push(root: Path, *, force: bool = False) -> GitResult:
166
173
 
167
174
  branch = get_current_branch(root)
168
175
  if not branch:
169
- return GitResult(success=False, message="Not on any branch")
176
+ worktree = _run_git(root, ["rev-parse", "--show-toplevel"])
177
+ inspected = worktree.output.strip() if worktree.success else str(root.resolve())
178
+ return GitResult(
179
+ success=False,
180
+ message=f"Not on any branch in git worktree: {inspected}",
181
+ )
170
182
 
171
183
  # Safety: check branching strategy
172
184
  from specsmith.paths import find_scaffold
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.22.0
3
+ Version: 0.22.2
4
4
  Summary: AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider.
5
5
  Author: Layer1Labs Silicon, Inc.
6
6
  License-Expression: MIT
@@ -27,6 +27,7 @@ Requires-Python: >=3.10
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
29
  Requires-Dist: click>=8.1
30
+ Requires-Dist: cryptography>=42.0
30
31
  Requires-Dist: jinja2>=3.1
31
32
  Requires-Dist: pyyaml>=6.0
32
33
  Requires-Dist: pydantic>=2.0
@@ -38,10 +39,8 @@ Requires-Dist: ruff>=0.4; extra == "dev"
38
39
  Requires-Dist: mypy>=1.10; extra == "dev"
39
40
  Requires-Dist: pre-commit>=3.0; extra == "dev"
40
41
  Requires-Dist: types-pyyaml>=6.0; extra == "dev"
41
- Requires-Dist: cryptography>=42.0; extra == "dev"
42
42
  Provides-Extra: esdb
43
43
  Requires-Dist: chronomemory>=0.2.7; extra == "esdb"
44
- Requires-Dist: cryptography>=42.0; extra == "esdb"
45
44
  Provides-Extra: docs
46
45
  Requires-Dist: mkdocs>=1.6; extra == "docs"
47
46
  Requires-Dist: mkdocs-material>=9.5; extra == "docs"
@@ -73,7 +72,6 @@ Requires-Dist: pytest-cov>=4.0; extra == "all"
73
72
  Requires-Dist: ruff>=0.4; extra == "all"
74
73
  Requires-Dist: mypy>=1.10; extra == "all"
75
74
  Provides-Extra: license-verify
76
- Requires-Dist: cryptography>=42.0; extra == "license-verify"
77
75
  Dynamic: license-file
78
76
 
79
77
  # specsmith
@@ -317,6 +315,7 @@ If you hold a chronomemory ESDB license, activate the commercial backend:
317
315
  pip install "specsmith[esdb]" # installs chronomemory from PyPI
318
316
  # or if using pipx:
319
317
  pipx inject specsmith "chronomemory>=0.2.0" # inject into the specsmith pipx venv
318
+ # The license verifier is included in base specsmith; no cryptography injection is needed.
320
319
 
321
320
  # Step 2 — activate your license key
322
321
  specsmith esdb enable --key-file /path/to/your.esdb.key
@@ -340,6 +339,10 @@ pipx upgrade specsmith # preferred — upgrades the pipx-isolated CLI
340
339
  specsmith self-update # alternative: self-update from within specsmith
341
340
  ```
342
341
 
342
+ An intent limited to maintaining the local pipx CLI is returned as the non-blocking
343
+ `environment_only` preflight decision. It exits successfully and creates no project
344
+ work item, ledger entry, or ESDB record. All `--help` invocations are read-only.
345
+
343
346
  ---
344
347
 
345
348
  ## Quick Start
@@ -321,6 +321,7 @@ tests/test_esdb_backend_switch.py
321
321
  tests/test_esdb_enforcement.py
322
322
  tests/test_esdb_integration.py
323
323
  tests/test_esdb_license.py
324
+ tests/test_esdb_migrate_wal_repair.py
324
325
  tests/test_esdb_sqlite.py
325
326
  tests/test_esdb_status_integrity.py
326
327
  tests/test_esdb_status_output.py
@@ -358,6 +359,7 @@ tests/test_project_metrics.py
358
359
  tests/test_quality_report.py
359
360
  tests/test_rate_limits.py
360
361
  tests/test_release_guard.py
362
+ tests/test_release_version_contract.py
361
363
  tests/test_releaser.py
362
364
  tests/test_repl.py
363
365
  tests/test_repl_extended.py
@@ -365,6 +367,7 @@ tests/test_reporting_commands.py
365
367
  tests/test_req_248_262.py
366
368
  tests/test_req_358_359.py
367
369
  tests/test_resume_command.py
370
+ tests/test_rtd_deploy_workflow.py
368
371
  tests/test_scaffolder.py
369
372
  tests/test_schema_migrations.py
370
373
  tests/test_session_events.py
@@ -382,6 +385,7 @@ tests/test_typing_guardrails.py
382
385
  tests/test_updater.py
383
386
  tests/test_validator.py
384
387
  tests/test_vcs.py
388
+ tests/test_vcs_commands.py
385
389
  tests/test_warp_parity.py
386
390
  tests/test_warp_parity_followup.py
387
391
  tests/test_wi_lifecycle.py
@@ -1,4 +1,5 @@
1
1
  click>=8.1
2
+ cryptography>=42.0
2
3
  jinja2>=3.1
3
4
  pyyaml>=6.0
4
5
  pydantic>=2.0
@@ -29,7 +30,6 @@ ruff>=0.4
29
30
  mypy>=1.10
30
31
  pre-commit>=3.0
31
32
  types-pyyaml>=6.0
32
- cryptography>=42.0
33
33
 
34
34
  [docs]
35
35
  mkdocs>=1.6
@@ -37,7 +37,6 @@ mkdocs-material>=9.5
37
37
 
38
38
  [esdb]
39
39
  chronomemory>=0.2.7
40
- cryptography>=42.0
41
40
 
42
41
  [gemini]
43
42
  google-genai>=1.0
@@ -50,7 +49,6 @@ sentence-transformers>=2.2
50
49
  numpy>=1.24
51
50
 
52
51
  [license-verify]
53
- cryptography>=42.0
54
52
 
55
53
  [mistral]
56
54
  openai>=1.0
@@ -70,6 +70,68 @@ class TestCLIVersion:
70
70
  assert __version__ in result.output
71
71
 
72
72
 
73
+ class TestCLIHelp:
74
+ def test_preflight_help_does_not_migrate_or_write_project_files(
75
+ self, tmp_path, monkeypatch
76
+ ) -> None:
77
+ """TEST-475: help must not mutate a project that needs migration."""
78
+ docs = tmp_path / "docs"
79
+ docs.mkdir()
80
+ (docs / "SPECSMITH.yml").write_text(
81
+ "name: temp-specsmith-repro\ntype: cli-python\nspec_version: 0.22.0\n",
82
+ encoding="utf-8",
83
+ )
84
+ (tmp_path / "LEDGER.md").write_text("# Ledger\n", encoding="utf-8")
85
+ before = {
86
+ path.relative_to(tmp_path): path.read_bytes()
87
+ for path in tmp_path.rglob("*")
88
+ if path.is_file()
89
+ }
90
+
91
+ monkeypatch.chdir(tmp_path)
92
+ result = CliRunner().invoke(
93
+ main,
94
+ ["preflight", "--help"],
95
+ env={"SPECSMITH_NO_UPDATE_CHECK": "1"},
96
+ catch_exceptions=False,
97
+ )
98
+
99
+ assert result.exit_code == 0, result.output
100
+ assert "Usage: " in result.output
101
+ assert "Auto-migrating" not in result.output
102
+ after = {
103
+ path.relative_to(tmp_path): path.read_bytes()
104
+ for path in tmp_path.rglob("*")
105
+ if path.is_file()
106
+ }
107
+ assert after == before
108
+
109
+
110
+ class TestCheckpointAnchor:
111
+ def test_checkpoint_anchor_is_ascii_and_fixed_width(self, tmp_path: Path) -> None:
112
+ """TEST-479: anchor rows must render safely in proportional-font clients."""
113
+ result = CliRunner().invoke(
114
+ main,
115
+ ["checkpoint", "--project-dir", str(tmp_path)],
116
+ env={"SPECSMITH_NO_AUTO_UPDATE": "1"},
117
+ catch_exceptions=False,
118
+ )
119
+
120
+ assert result.exit_code == 0, result.output
121
+ lines = result.output.splitlines()
122
+ top = next(index for index, line in enumerate(lines) if line.startswith("+---"))
123
+ bottom = next(
124
+ index for index, line in enumerate(lines[top + 1 :], top + 1) if line.startswith("+---")
125
+ )
126
+ anchor = lines[top : bottom + 1]
127
+
128
+ assert all(line.isascii() for line in anchor)
129
+ assert all(len(line) == len(anchor[0]) for line in anchor)
130
+ assert anchor[0] == anchor[-1]
131
+ assert all(line.startswith("|") and line.endswith("|") for line in anchor[1:-1])
132
+ assert "Health : " in "\n".join(anchor)
133
+
134
+
73
135
  class TestCLIInit:
74
136
  def test_init_from_config(self, tmp_path: Path) -> None:
75
137
  config = {