specsmith 0.10.1.dev272__tar.gz → 0.10.1.dev277__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 (217) hide show
  1. {specsmith-0.10.1.dev272/src/specsmith.egg-info → specsmith-0.10.1.dev277}/PKG-INFO +22 -48
  2. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/README.md +21 -47
  3. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/pyproject.toml +1 -1
  4. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/cli.py +107 -0
  5. specsmith-0.10.1.dev277/src/specsmith/editor.py +277 -0
  6. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277/src/specsmith.egg-info}/PKG-INFO +22 -48
  7. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith.egg-info/SOURCES.txt +1 -0
  8. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_nexus.py +8 -3
  9. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/LICENSE +0 -0
  10. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/setup.cfg +0 -0
  11. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/epistemic/__init__.py +0 -0
  12. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/epistemic/belief.py +0 -0
  13. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/epistemic/certainty.py +0 -0
  14. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/epistemic/failure_graph.py +0 -0
  15. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/epistemic/py.typed +0 -0
  16. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/epistemic/recovery.py +0 -0
  17. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/epistemic/session.py +0 -0
  18. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/epistemic/stress_tester.py +0 -0
  19. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/epistemic/trace.py +0 -0
  20. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/__init__.py +0 -0
  21. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/__main__.py +0 -0
  22. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/__init__.py +0 -0
  23. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/broker.py +0 -0
  24. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/chat_runner.py +0 -0
  25. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/cleanup.py +0 -0
  26. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/core.py +0 -0
  27. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/endpoints.py +0 -0
  28. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/events.py +0 -0
  29. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/execution_profiles.py +0 -0
  30. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/fallback.py +0 -0
  31. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/indexer.py +0 -0
  32. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/mcp.py +0 -0
  33. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/memory.py +0 -0
  34. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/model_intelligence.py +0 -0
  35. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/orchestrator.py +0 -0
  36. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/permissions.py +0 -0
  37. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/profiles.py +0 -0
  38. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/provider_registry.py +0 -0
  39. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/repl.py +0 -0
  40. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/router.py +0 -0
  41. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/rules.py +0 -0
  42. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/runner.py +0 -0
  43. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/safety.py +0 -0
  44. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/suggester.py +0 -0
  45. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/tools.py +0 -0
  46. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/verifier.py +0 -0
  47. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/agent/voice.py +0 -0
  48. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/architect.py +0 -0
  49. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/auditor.py +0 -0
  50. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/auth.py +0 -0
  51. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/block_export.py +0 -0
  52. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/commands/__init__.py +0 -0
  53. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/commands/intelligence.py +0 -0
  54. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/compressor.py +0 -0
  55. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/config.py +0 -0
  56. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/console_utils.py +0 -0
  57. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/credit_analyzer.py +0 -0
  58. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/credits.py +0 -0
  59. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/datasources/__init__.py +0 -0
  60. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/datasources/base.py +0 -0
  61. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/datasources/citations.py +0 -0
  62. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/datasources/fpd.py +0 -0
  63. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/datasources/odp.py +0 -0
  64. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/datasources/patentsview.py +0 -0
  65. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/datasources/pfw.py +0 -0
  66. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/datasources/ppubs.py +0 -0
  67. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/datasources/ptab.py +0 -0
  68. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/differ.py +0 -0
  69. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/doctor.py +0 -0
  70. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/drive.py +0 -0
  71. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/epistemic/__init__.py +0 -0
  72. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/epistemic/belief.py +0 -0
  73. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/epistemic/certainty.py +0 -0
  74. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/epistemic/failure_graph.py +0 -0
  75. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/epistemic/recovery.py +0 -0
  76. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/epistemic/stress_tester.py +0 -0
  77. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/executor.py +0 -0
  78. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/exporter.py +0 -0
  79. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/governance_logic.py +0 -0
  80. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/__init__.py +0 -0
  81. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/app.py +0 -0
  82. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/main_window.py +0 -0
  83. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/session_tab.py +0 -0
  84. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/theme.py +0 -0
  85. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/widgets/__init__.py +0 -0
  86. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/widgets/chat_view.py +0 -0
  87. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/widgets/input_bar.py +0 -0
  88. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  89. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/widgets/token_meter.py +0 -0
  90. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  91. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/widgets/update_checker.py +0 -0
  92. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/gui/worker.py +0 -0
  93. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/history_search.py +0 -0
  94. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/importer.py +0 -0
  95. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/instinct.py +0 -0
  96. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/integrations/__init__.py +0 -0
  97. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/integrations/agent_skill.py +0 -0
  98. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/integrations/aider.py +0 -0
  99. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/integrations/base.py +0 -0
  100. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/integrations/claude_code.py +0 -0
  101. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/integrations/copilot.py +0 -0
  102. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/integrations/cursor.py +0 -0
  103. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/integrations/gemini.py +0 -0
  104. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/integrations/windsurf.py +0 -0
  105. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/languages.py +0 -0
  106. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/ledger.py +0 -0
  107. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/patent.py +0 -0
  108. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/paths.py +0 -0
  109. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/phase.py +0 -0
  110. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/plugins.py +0 -0
  111. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/profiles.py +0 -0
  112. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/rate_limits.py +0 -0
  113. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/releaser.py +0 -0
  114. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/requirements.py +0 -0
  115. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/requirements_parser.py +0 -0
  116. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/retrieval.py +0 -0
  117. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/safe_write.py +0 -0
  118. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/scaffolder.py +0 -0
  119. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/serve.py +0 -0
  120. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/session.py +0 -0
  121. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/skills.py +0 -0
  122. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/sync.py +0 -0
  123. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/agents.md.j2 +0 -0
  124. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  125. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  126. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  127. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  128. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  129. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  130. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  131. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/community/security.md.j2 +0 -0
  132. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  133. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  134. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  135. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  136. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  137. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/editorconfig.j2 +0 -0
  138. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/gitattributes.j2 +0 -0
  139. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/gitignore.j2 +0 -0
  140. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/go/go.mod.j2 +0 -0
  141. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/go/main.go.j2 +0 -0
  142. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  143. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  144. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  145. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  146. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  147. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
  148. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  149. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  150. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
  151. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  152. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  153. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/js/package.json.j2 +0 -0
  154. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/ledger.md.j2 +0 -0
  155. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/python/cli.py.j2 +0 -0
  156. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/python/init.py.j2 +0 -0
  157. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  158. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/readme.md.j2 +0 -0
  159. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  160. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  161. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  162. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  163. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  164. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  165. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  166. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  167. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  168. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/tool_installer.py +0 -0
  169. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/toolrules.py +0 -0
  170. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/tools.py +0 -0
  171. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/trace.py +0 -0
  172. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/updater.py +0 -0
  173. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/upgrader.py +0 -0
  174. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/validator.py +0 -0
  175. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/vcs/__init__.py +0 -0
  176. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/vcs/base.py +0 -0
  177. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/vcs/bitbucket.py +0 -0
  178. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/vcs/github.py +0 -0
  179. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/vcs/gitlab.py +0 -0
  180. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/vcs_commands.py +0 -0
  181. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/wireframes.py +0 -0
  182. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith/workspace.py +0 -0
  183. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith.egg-info/dependency_links.txt +0 -0
  184. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith.egg-info/entry_points.txt +0 -0
  185. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith.egg-info/requires.txt +0 -0
  186. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/src/specsmith.egg-info/top_level.txt +0 -0
  187. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_CMD_001.py +0 -0
  188. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_agent_profiles.py +0 -0
  189. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_agent_runner_ready.py +0 -0
  190. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_auditor.py +0 -0
  191. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_chat_diff_decision.py +0 -0
  192. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_chat_runner_openai_compat.py +0 -0
  193. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_chat_stdin_protocol.py +0 -0
  194. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_cli.py +0 -0
  195. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_cli_workflows_history_drive.py +0 -0
  196. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_compressor.py +0 -0
  197. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_e2e_nexus.py +0 -0
  198. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_endpoints_cli.py +0 -0
  199. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_endpoints_store.py +0 -0
  200. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_epistemic.py +0 -0
  201. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_fallback_chain.py +0 -0
  202. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_importer.py +0 -0
  203. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_integrations.py +0 -0
  204. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_mcp_client.py +0 -0
  205. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_permissions.py +0 -0
  206. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_phase1_4_new.py +0 -0
  207. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_phase34_completion.py +0 -0
  208. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_rate_limits.py +0 -0
  209. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_scaffolder.py +0 -0
  210. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_skill_marketplace.py +0 -0
  211. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_smoke.py +0 -0
  212. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_suggester.py +0 -0
  213. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_tools.py +0 -0
  214. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_validator.py +0 -0
  215. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_vcs.py +0 -0
  216. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_warp_parity.py +0 -0
  217. {specsmith-0.10.1.dev272 → specsmith-0.10.1.dev277}/tests/test_warp_parity_followup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.10.1.dev272
3
+ Version: 0.10.1.dev277
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
@@ -78,8 +78,6 @@ Dynamic: license-file
78
78
  [![PyPI](https://img.shields.io/pypi/v/specsmith?label=stable&style=flat&color=blue&cacheSeconds=60)](https://pypi.org/project/specsmith/)
79
79
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
80
80
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
81
- [![VS Code Extension](https://img.shields.io/badge/VS%20Code-AEE%20Workbench-4ec9b0?logo=visualstudiocode)](https://github.com/BitConcepts/specsmith-vscode)
82
-
83
81
  **Applied Epistemic Engineering toolkit for AI-assisted development.**
84
82
 
85
83
  > Intelligence proposes. Constraints decide. The ledger remembers.
@@ -142,23 +140,15 @@ specsmith phase set requirements # jump to a specific phase
142
140
  specsmith phase list # list all phases
143
141
  ```
144
142
 
145
- The current phase is persisted in `scaffold.yml` as `aee_phase` and displayed in the VS Code
146
- Settings Panel. Each phase has a checklist of file/command criteria, recommended commands,
147
- and a readiness percentage.
143
+ The current phase is persisted in `scaffold.yml` as `aee_phase` and displayed in the
144
+ Kairos Governance page. Each phase has a checklist of file/command criteria, recommended
145
+ commands, and a readiness percentage.
148
146
 
149
147
  ---
150
148
 
151
149
  ## Install
152
150
 
153
- **Recommended — via the VS Code extension (creates a project-isolated environment):**
154
-
155
- 1. Install the [specsmith AEE Workbench](https://github.com/BitConcepts/specsmith-vscode) VS Code extension
156
- 2. Open `Ctrl+Shift+,` (⚙ specsmith Settings)
157
- 3. Click **🔒 Create Environment** — creates `~/.specsmith/venv/` with specsmith + your provider packages
158
-
159
- The extension uses this environment for all agent sessions and terminal commands.
160
-
161
- **Or via pipx (system-wide):**
151
+ **Recommended — via pipx (works with Kairos, any terminal, and CI):**
162
152
 
163
153
  ```bash
164
154
  pipx install specsmith # core CLI + epistemic library
@@ -316,36 +306,20 @@ requirement, test, and work-item identifiers Specsmith assigned.
316
306
 
317
307
  ---
318
308
 
319
- ## VS Code Extension
309
+ ## Kairos Flagship Terminal Client
320
310
 
321
- The **specsmith AEE Workbench** VS Code extension is the flagship client:
311
+ **[Kairos](https://github.com/BitConcepts/kairos)** is the recommended terminal client for specsmith.
312
+ Kairos spawns specsmith as a managed governance child process at startup and routes all
313
+ preflight, verify, and BYOE proxy calls through it. The Governance settings page shows live
314
+ specsmith status, version, and one-click update.
322
315
 
323
- ```
324
- # VS Code: Ctrl+Shift+P specsmith: New Agent Session
325
- # Settings: Ctrl+Shift+, (⚙ specsmith Settings global)
326
- # Project Settings: Ctrl+Shift+G (⚙ Project Settings — per-project)
316
+ ```bash
317
+ # Kairos starts specsmith automatically; or run manually:
318
+ specsmith governance-serve --port 7700 --project-dir .
327
319
  ```
328
320
 
329
- **Key features:**
330
- - **Dual-panel architecture** **⚙ specsmith Settings** (global: venv, version, Ollama, system)
331
- and **⚙ Project Settings** (per-project: scaffold, tools, files, actions, execution)
332
- - **Global environment management** — `~/.specsmith/venv/` with Create / Update / Rebuild / Delete;
333
- persistent restart banner; Remove System Installs cleanup button
334
- - **VCS context at session start** — git status + recent commits shown in chat and in system prompt
335
- - **Execution profiles** — safe / standard / open / admin; custom allow/block command lists
336
- - **AEE phase indicator** — shows current phase with readiness %, Next Phase button, phase selector
337
- - **AI agent sessions** — independent process per project, JSONL bridge, chat with file injection
338
- - **AG2 agent shell** — Planner/Builder/Verifier agents over Ollama in Actions tab
339
- - **Agent tab** — per-project provider/model/context/iteration config (overrides global defaults)
340
- - **Live model listing** — Anthropic, OpenAI, Gemini, Mistral, local Ollama (GPU-aware)
341
- - **Ollama model catalog** — 16 models, 4 tiers, GPU-aware recommendations, filter by installed/available
342
- - **Ollama integration** — model manager (update/remove/update-all), version check, upgrade
343
- - **FPGA/HDL tool support** — vivado, gtkwave, vsg, ghdl, verilator, yosys, nextpnr, and 15 more
344
- - **Tool installer** — scan installed tools; one-click install via winget/brew/apt for missing tools
345
- - **API key management** — stored in OS credential store (Windows Credential Manager / macOS Keychain)
346
- - **Update checker** — PyPI version check, auto-checks on panel open, release channel selector
347
-
348
- **[→ specsmith-vscode on GitHub](https://github.com/BitConcepts/specsmith-vscode)**
321
+ The VS Code extension (`specsmith-vscode`) has been **deprecated** in favour of Kairos.
322
+ Use `pipx install specsmith` for standalone CLI usage from any terminal.
349
323
 
350
324
  ---
351
325
 
@@ -353,7 +327,7 @@ The **specsmith AEE Workbench** VS Code extension is the flagship client:
353
327
 
354
328
  specsmith is open source and built by a small team. Every bit of support helps:
355
329
 
356
- - ⭐ **Star** [specsmith](https://github.com/BitConcepts/specsmith) and [specsmith-vscode](https://github.com/BitConcepts/specsmith-vscode) on GitHub
330
+ - ⭐ **Star** [specsmith](https://github.com/BitConcepts/specsmith) and [kairos](https://github.com/BitConcepts/kairos) on GitHub
357
331
  - 📣 **Tell your friends and colleagues** — word of mouth is our best marketing
358
332
  - 🐛 **Report bugs** via [GitHub Issues](https://github.com/BitConcepts/specsmith/issues) — even small ones help
359
333
  - 💡 **Suggest features** via [GitHub Discussions](https://github.com/BitConcepts/specsmith/discussions) — we read every suggestion
@@ -376,8 +350,8 @@ specsmith ollama suggest requirements # task-based recommendations
376
350
  specsmith ollama list # show installed models
377
351
  ```
378
352
 
379
- GPU-aware context sizing in the VS Code extension: 4K/8K/16K/32K tokens based on detected VRAM.
380
- Override with `specsmith.ollamaContextLength` in VS Code settings.
353
+ GPU-aware context sizing: 4K/8K/16K/32K tokens based on detected VRAM.
354
+ Override via `SPECSMITH_OLLAMA_CONTEXT_LENGTH` env var or `ollama.context_length` in `.specsmith/config.yml`.
381
355
 
382
356
  ---
383
357
 
@@ -478,20 +452,20 @@ Use cases: linguistics research, compliance pipelines, AI alignment, patent pros
478
452
 
479
453
  specsmith governs itself — the specsmith repo is a specsmith-managed project. Run `specsmith audit`
480
454
  in this repo to check its governance health. This means every feature we add to specsmith is
481
- immediately dogfooded on specsmith itself. The [VS Code extension](https://github.com/BitConcepts/specsmith-vscode)
482
- is developed alongside it as the flagship client.
455
+ immediately dogfooded on specsmith itself. [Kairos](https://github.com/BitConcepts/kairos)
456
+ is the companion terminal and flagship client.
483
457
 
484
458
  ## Documentation
485
459
 
486
460
  **[specsmith.readthedocs.io](https://specsmith.readthedocs.io)** — Full manual: AEE primer,
487
- command reference, project types, tool registry, governance model, Ollama guide, VS Code extension.
461
+ command reference, project types, tool registry, governance model, Ollama guide, Kairos integration.
488
462
 
489
463
  ## Links
490
464
 
491
465
  - [PyPI](https://pypi.org/project/specsmith/)
492
466
  - [Documentation](https://specsmith.readthedocs.io)
493
467
  - [Changelog](CHANGELOG.md)
494
- - [VS Code Extension](https://github.com/BitConcepts/specsmith-vscode)
468
+ - [Kairos terminal client](https://github.com/BitConcepts/kairos)
495
469
  - [Contributing](CONTRIBUTING.md)
496
470
  - [Security](SECURITY.md)
497
471
 
@@ -6,8 +6,6 @@
6
6
  [![PyPI](https://img.shields.io/pypi/v/specsmith?label=stable&style=flat&color=blue&cacheSeconds=60)](https://pypi.org/project/specsmith/)
7
7
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
8
8
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
9
- [![VS Code Extension](https://img.shields.io/badge/VS%20Code-AEE%20Workbench-4ec9b0?logo=visualstudiocode)](https://github.com/BitConcepts/specsmith-vscode)
10
-
11
9
  **Applied Epistemic Engineering toolkit for AI-assisted development.**
12
10
 
13
11
  > Intelligence proposes. Constraints decide. The ledger remembers.
@@ -70,23 +68,15 @@ specsmith phase set requirements # jump to a specific phase
70
68
  specsmith phase list # list all phases
71
69
  ```
72
70
 
73
- The current phase is persisted in `scaffold.yml` as `aee_phase` and displayed in the VS Code
74
- Settings Panel. Each phase has a checklist of file/command criteria, recommended commands,
75
- and a readiness percentage.
71
+ The current phase is persisted in `scaffold.yml` as `aee_phase` and displayed in the
72
+ Kairos Governance page. Each phase has a checklist of file/command criteria, recommended
73
+ commands, and a readiness percentage.
76
74
 
77
75
  ---
78
76
 
79
77
  ## Install
80
78
 
81
- **Recommended — via the VS Code extension (creates a project-isolated environment):**
82
-
83
- 1. Install the [specsmith AEE Workbench](https://github.com/BitConcepts/specsmith-vscode) VS Code extension
84
- 2. Open `Ctrl+Shift+,` (⚙ specsmith Settings)
85
- 3. Click **🔒 Create Environment** — creates `~/.specsmith/venv/` with specsmith + your provider packages
86
-
87
- The extension uses this environment for all agent sessions and terminal commands.
88
-
89
- **Or via pipx (system-wide):**
79
+ **Recommended — via pipx (works with Kairos, any terminal, and CI):**
90
80
 
91
81
  ```bash
92
82
  pipx install specsmith # core CLI + epistemic library
@@ -244,36 +234,20 @@ requirement, test, and work-item identifiers Specsmith assigned.
244
234
 
245
235
  ---
246
236
 
247
- ## VS Code Extension
237
+ ## Kairos Flagship Terminal Client
248
238
 
249
- The **specsmith AEE Workbench** VS Code extension is the flagship client:
239
+ **[Kairos](https://github.com/BitConcepts/kairos)** is the recommended terminal client for specsmith.
240
+ Kairos spawns specsmith as a managed governance child process at startup and routes all
241
+ preflight, verify, and BYOE proxy calls through it. The Governance settings page shows live
242
+ specsmith status, version, and one-click update.
250
243
 
251
- ```
252
- # VS Code: Ctrl+Shift+P specsmith: New Agent Session
253
- # Settings: Ctrl+Shift+, (⚙ specsmith Settings global)
254
- # Project Settings: Ctrl+Shift+G (⚙ Project Settings — per-project)
244
+ ```bash
245
+ # Kairos starts specsmith automatically; or run manually:
246
+ specsmith governance-serve --port 7700 --project-dir .
255
247
  ```
256
248
 
257
- **Key features:**
258
- - **Dual-panel architecture** **⚙ specsmith Settings** (global: venv, version, Ollama, system)
259
- and **⚙ Project Settings** (per-project: scaffold, tools, files, actions, execution)
260
- - **Global environment management** — `~/.specsmith/venv/` with Create / Update / Rebuild / Delete;
261
- persistent restart banner; Remove System Installs cleanup button
262
- - **VCS context at session start** — git status + recent commits shown in chat and in system prompt
263
- - **Execution profiles** — safe / standard / open / admin; custom allow/block command lists
264
- - **AEE phase indicator** — shows current phase with readiness %, Next Phase button, phase selector
265
- - **AI agent sessions** — independent process per project, JSONL bridge, chat with file injection
266
- - **AG2 agent shell** — Planner/Builder/Verifier agents over Ollama in Actions tab
267
- - **Agent tab** — per-project provider/model/context/iteration config (overrides global defaults)
268
- - **Live model listing** — Anthropic, OpenAI, Gemini, Mistral, local Ollama (GPU-aware)
269
- - **Ollama model catalog** — 16 models, 4 tiers, GPU-aware recommendations, filter by installed/available
270
- - **Ollama integration** — model manager (update/remove/update-all), version check, upgrade
271
- - **FPGA/HDL tool support** — vivado, gtkwave, vsg, ghdl, verilator, yosys, nextpnr, and 15 more
272
- - **Tool installer** — scan installed tools; one-click install via winget/brew/apt for missing tools
273
- - **API key management** — stored in OS credential store (Windows Credential Manager / macOS Keychain)
274
- - **Update checker** — PyPI version check, auto-checks on panel open, release channel selector
275
-
276
- **[→ specsmith-vscode on GitHub](https://github.com/BitConcepts/specsmith-vscode)**
249
+ The VS Code extension (`specsmith-vscode`) has been **deprecated** in favour of Kairos.
250
+ Use `pipx install specsmith` for standalone CLI usage from any terminal.
277
251
 
278
252
  ---
279
253
 
@@ -281,7 +255,7 @@ The **specsmith AEE Workbench** VS Code extension is the flagship client:
281
255
 
282
256
  specsmith is open source and built by a small team. Every bit of support helps:
283
257
 
284
- - ⭐ **Star** [specsmith](https://github.com/BitConcepts/specsmith) and [specsmith-vscode](https://github.com/BitConcepts/specsmith-vscode) on GitHub
258
+ - ⭐ **Star** [specsmith](https://github.com/BitConcepts/specsmith) and [kairos](https://github.com/BitConcepts/kairos) on GitHub
285
259
  - 📣 **Tell your friends and colleagues** — word of mouth is our best marketing
286
260
  - 🐛 **Report bugs** via [GitHub Issues](https://github.com/BitConcepts/specsmith/issues) — even small ones help
287
261
  - 💡 **Suggest features** via [GitHub Discussions](https://github.com/BitConcepts/specsmith/discussions) — we read every suggestion
@@ -304,8 +278,8 @@ specsmith ollama suggest requirements # task-based recommendations
304
278
  specsmith ollama list # show installed models
305
279
  ```
306
280
 
307
- GPU-aware context sizing in the VS Code extension: 4K/8K/16K/32K tokens based on detected VRAM.
308
- Override with `specsmith.ollamaContextLength` in VS Code settings.
281
+ GPU-aware context sizing: 4K/8K/16K/32K tokens based on detected VRAM.
282
+ Override via `SPECSMITH_OLLAMA_CONTEXT_LENGTH` env var or `ollama.context_length` in `.specsmith/config.yml`.
309
283
 
310
284
  ---
311
285
 
@@ -406,20 +380,20 @@ Use cases: linguistics research, compliance pipelines, AI alignment, patent pros
406
380
 
407
381
  specsmith governs itself — the specsmith repo is a specsmith-managed project. Run `specsmith audit`
408
382
  in this repo to check its governance health. This means every feature we add to specsmith is
409
- immediately dogfooded on specsmith itself. The [VS Code extension](https://github.com/BitConcepts/specsmith-vscode)
410
- is developed alongside it as the flagship client.
383
+ immediately dogfooded on specsmith itself. [Kairos](https://github.com/BitConcepts/kairos)
384
+ is the companion terminal and flagship client.
411
385
 
412
386
  ## Documentation
413
387
 
414
388
  **[specsmith.readthedocs.io](https://specsmith.readthedocs.io)** — Full manual: AEE primer,
415
- command reference, project types, tool registry, governance model, Ollama guide, VS Code extension.
389
+ command reference, project types, tool registry, governance model, Ollama guide, Kairos integration.
416
390
 
417
391
  ## Links
418
392
 
419
393
  - [PyPI](https://pypi.org/project/specsmith/)
420
394
  - [Documentation](https://specsmith.readthedocs.io)
421
395
  - [Changelog](CHANGELOG.md)
422
- - [VS Code Extension](https://github.com/BitConcepts/specsmith-vscode)
396
+ - [Kairos terminal client](https://github.com/BitConcepts/kairos)
423
397
  - [Contributing](CONTRIBUTING.md)
424
398
  - [Security](SECURITY.md)
425
399
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specsmith"
7
- version = "0.10.1.dev272"
7
+ version = "0.10.1.dev277"
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"
@@ -5066,6 +5066,113 @@ def instinct_import(file_path: str, project_dir: str) -> None:
5066
5066
  main.add_command(instinct_group)
5067
5067
 
5068
5068
 
5069
+ # ---------------------------------------------------------------------------
5070
+ # specsmith config — global configuration (editor, etc.)
5071
+ # ---------------------------------------------------------------------------
5072
+
5073
+
5074
+ @main.group(name="config")
5075
+ def config_group() -> None:
5076
+ """Manage global specsmith configuration.
5077
+
5078
+ Settings are stored in ``~/.specsmith/config.toml``.
5079
+ """
5080
+
5081
+
5082
+ @config_group.command(name="editor")
5083
+ @click.argument("command", required=False, default=None)
5084
+ @click.option(
5085
+ "--list",
5086
+ "list_editors",
5087
+ is_flag=True,
5088
+ default=False,
5089
+ help="List all editors detected on this machine.",
5090
+ )
5091
+ @click.option(
5092
+ "--set",
5093
+ "set_cmd",
5094
+ default="",
5095
+ help="Set the preferred editor (saved to ~/.specsmith/config.toml).",
5096
+ )
5097
+ def config_editor_cmd(
5098
+ command: str | None,
5099
+ list_editors: bool,
5100
+ set_cmd: str,
5101
+ ) -> None:
5102
+ """Manage the editor used by specsmith to open files.
5103
+
5104
+ \b
5105
+ Resolution order:
5106
+ 1. $EDITOR environment variable (highest priority)
5107
+ 2. 'editor' key in ~/.specsmith/config.toml
5108
+ 3. Auto-detected editor for this platform
5109
+
5110
+ \b
5111
+ Examples:
5112
+ specsmith config editor # show currently resolved editor
5113
+ specsmith config editor --list # show all detected editors
5114
+ specsmith config editor --set code # set VS Code as preferred editor
5115
+ """
5116
+ from specsmith.editor import (
5117
+ list_detected_editors,
5118
+ resolve_editor,
5119
+ set_editor_preference,
5120
+ )
5121
+
5122
+ # --set flag takes precedence
5123
+ if set_cmd or (command and not list_editors):
5124
+ target = set_cmd or command or ""
5125
+ if not target:
5126
+ console.print("[red]Error:[/red] specify a command, e.g. --set code")
5127
+ raise SystemExit(1)
5128
+ saved_path = set_editor_preference(target)
5129
+ console.print(
5130
+ f"[green]\u2713[/green] Saved editor preference: [bold]{target}[/bold]\n"
5131
+ f" Config: {saved_path}"
5132
+ )
5133
+ return
5134
+
5135
+ if list_editors:
5136
+ candidates = list_detected_editors()
5137
+ if not candidates:
5138
+ console.print("[yellow]No editors detected on this machine.[/yellow]")
5139
+ console.print(
5140
+ " Install VS Code, Neovim, or another editor and re-run, or set $EDITOR manually."
5141
+ )
5142
+ return
5143
+ console.print("[bold]Detected editors:[/bold]\n")
5144
+ for c in candidates:
5145
+ path_hint = f" [dim]({c.path})[/dim]" if c.path else ""
5146
+ console.print(f" [cyan]{c.command:<20}[/cyan] {c.name}{path_hint}")
5147
+ return
5148
+
5149
+ # Default: show the currently resolved editor
5150
+ import os
5151
+
5152
+ env_val = os.environ.get("EDITOR", "").strip()
5153
+ resolved = resolve_editor()
5154
+
5155
+ console.print("[bold]Editor configuration[/bold]\n")
5156
+ if env_val:
5157
+ console.print(" Source: [green]$EDITOR[/green] environment variable")
5158
+ console.print(f" Command: [bold]{env_val}[/bold]")
5159
+ elif resolved:
5160
+ console.print(" Source: auto-detected")
5161
+ console.print(f" Command: [bold]{resolved}[/bold]")
5162
+ else:
5163
+ console.print(" [yellow]No editor resolved.[/yellow]")
5164
+ console.print(" Set $EDITOR or run [bold]specsmith config editor --set <command>[/bold].")
5165
+ console.print()
5166
+ console.print(
5167
+ " [dim]Override: set $EDITOR, or run "
5168
+ "'specsmith config editor --set <cmd>' to persist.[/dim]"
5169
+ )
5170
+ console.print(" [dim]List available editors: 'specsmith config editor --list'[/dim]")
5171
+
5172
+
5173
+ main.add_command(config_group)
5174
+
5175
+
5069
5176
  # ---------------------------------------------------------------------------
5070
5177
  # Kill-switch / emergency stop (REG-005)
5071
5178
  # ---------------------------------------------------------------------------
@@ -0,0 +1,277 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 BitConcepts, LLC. All rights reserved.
3
+ """Cross-platform $EDITOR auto-detection for specsmith.
4
+
5
+ Resolution order (highest to lowest priority):
6
+ 1. ``$EDITOR`` environment variable
7
+ 2. ``editor`` key in ``~/.specsmith/config.toml`` or project ``.specsmith/config.yml``
8
+ 3. Auto-detection: probe PATH + well-known install locations per platform
9
+
10
+ Usage::
11
+
12
+ from specsmith.editor import resolve_editor, list_detected_editors, set_editor_preference
13
+
14
+ # What will specsmith use to open files?
15
+ editor = resolve_editor() # e.g. "code", "notepad++", "nvim"
16
+
17
+ # Show all detected editors on this machine:
18
+ editors = list_detected_editors() # list of (name, path) tuples
19
+
20
+ # Persist a preference:
21
+ set_editor_preference("code") # writes to ~/.specsmith/config.toml
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import os
27
+ import platform
28
+ import shutil
29
+ from pathlib import Path
30
+ from typing import NamedTuple
31
+
32
+ __all__ = [
33
+ "EditorCandidate",
34
+ "list_detected_editors",
35
+ "resolve_editor",
36
+ "set_editor_preference",
37
+ ]
38
+
39
+ # ---------------------------------------------------------------------------
40
+ # Data model
41
+ # ---------------------------------------------------------------------------
42
+
43
+
44
+ class EditorCandidate(NamedTuple):
45
+ """A discovered editor."""
46
+
47
+ name: str
48
+ """Short display name (e.g. 'VS Code', 'Notepad++')."""
49
+ command: str
50
+ """The executable / command to invoke (e.g. 'code', 'notepad++')."""
51
+ path: str | None
52
+ """Resolved absolute path, or None if only found via PATH probe."""
53
+
54
+
55
+ # ---------------------------------------------------------------------------
56
+ # Platform-specific candidate lists
57
+ # ---------------------------------------------------------------------------
58
+
59
+ #: Ordered list of (display_name, command) pairs for each platform.
60
+ #: The first entry that resolves wins for auto-detection.
61
+ _WINDOWS_CANDIDATES: list[tuple[str, str | list[str]]] = [
62
+ # VS Code (most popular cross-platform)
63
+ ("VS Code", "code"),
64
+ # Cursor (AI-first VS Code fork)
65
+ ("Cursor", "cursor"),
66
+ # Notepad++ — check common install paths since it's not always on PATH
67
+ ("Notepad++", r"%LOCALAPPDATA%\Programs\Notepad++\notepad++.exe"),
68
+ ("Notepad++", r"%PROGRAMFILES%\Notepad++\notepad++.exe"),
69
+ ("Notepad++", r"%PROGRAMFILES(X86)%\Notepad++\notepad++.exe"),
70
+ ("Notepad++", "notepad++"),
71
+ # Neovim (scoop / choco)
72
+ ("Neovim", "nvim"),
73
+ # Vim (git-bash / scoop / choco)
74
+ ("Vim", "vim"),
75
+ # Sublime Text
76
+ ("Sublime Text", r"%PROGRAMFILES%\Sublime Text\subl.exe"),
77
+ ("Sublime Text", r"%PROGRAMFILES%\Sublime Text 4\subl.exe"),
78
+ ("Sublime Text", "subl"),
79
+ # Built-in last resort
80
+ ("Notepad", "notepad"),
81
+ ]
82
+
83
+ _MACOS_CANDIDATES: list[tuple[str, str | list[str]]] = [
84
+ ("VS Code", "code"),
85
+ ("Cursor", "cursor"),
86
+ ("Neovim", "nvim"),
87
+ ("Vim", "vim"),
88
+ ("BBEdit", "/Applications/BBEdit.app/Contents/OS X Resources/bbedit"),
89
+ ("BBEdit", "bbedit"),
90
+ ("Nano", "nano"),
91
+ # TextEdit — open -e opens the file in TextEdit
92
+ ("TextEdit", ["/usr/bin/open", "-e"]),
93
+ ]
94
+
95
+ _LINUX_CANDIDATES: list[tuple[str, str | list[str]]] = [
96
+ ("VS Code", "code"),
97
+ ("Cursor", "cursor"),
98
+ ("Neovim", "nvim"),
99
+ ("Vim", "vim"),
100
+ ("Nano", "nano"),
101
+ ("Kate", "kate"),
102
+ ("gedit", "gedit"),
103
+ ("xed", "xed"),
104
+ ("Mousepad", "mousepad"),
105
+ ("Geany", "geany"),
106
+ ("Micro", "micro"),
107
+ ("Helix", "hx"),
108
+ ]
109
+
110
+
111
+ # ---------------------------------------------------------------------------
112
+ # Internal helpers
113
+ # ---------------------------------------------------------------------------
114
+
115
+
116
+ def _expand(path_str: str) -> str:
117
+ """Expand environment variables in a path string (Windows-style %VAR%)."""
118
+ return os.path.expandvars(path_str)
119
+
120
+
121
+ def _probe_command(cmd: str | list[str]) -> str | None:
122
+ """Return the resolved path for *cmd* if it is runnable, else None."""
123
+ # Multi-token command (e.g. ["open", "-e"]) — probe the first token.
124
+ executable = cmd[0] if isinstance(cmd, list) else cmd
125
+
126
+ # Expand env vars in Windows-style paths (%PROGRAMFILES%\...)
127
+ expanded = _expand(executable)
128
+ if os.sep in expanded or "/" in expanded:
129
+ # Looks like an absolute/relative path — check if the file exists
130
+ p = Path(expanded)
131
+ if p.is_file() and os.access(p, os.X_OK):
132
+ return str(p)
133
+ return None
134
+
135
+ # Plain command name — search PATH
136
+ found = shutil.which(executable)
137
+ return found if found else None
138
+
139
+
140
+ def _platform_candidates() -> list[tuple[str, str | list[str]]]:
141
+ system = platform.system()
142
+ if system == "Windows":
143
+ return _WINDOWS_CANDIDATES
144
+ if system == "Darwin":
145
+ return _MACOS_CANDIDATES
146
+ return _LINUX_CANDIDATES # Linux / BSD / WSL
147
+
148
+
149
+ # ---------------------------------------------------------------------------
150
+ # Public API
151
+ # ---------------------------------------------------------------------------
152
+
153
+
154
+ def list_detected_editors() -> list[EditorCandidate]:
155
+ """Return all editor candidates that are runnable on this machine.
156
+
157
+ Each ``EditorCandidate`` is unique by *command* (the first token for
158
+ multi-token commands). Duplicates (e.g. multiple Notepad++ paths) are
159
+ deduplicated to the first match.
160
+
161
+ Returns:
162
+ Ordered list of :class:`EditorCandidate`, best-first.
163
+ """
164
+ seen_commands: set[str] = set()
165
+ result: list[EditorCandidate] = []
166
+
167
+ for display_name, cmd in _platform_candidates():
168
+ cmd_key = cmd[0] if isinstance(cmd, list) else cmd
169
+ if cmd_key in seen_commands:
170
+ continue
171
+
172
+ resolved = _probe_command(cmd)
173
+ if resolved is None and isinstance(cmd, str):
174
+ # For plain command names that aren't found, skip
175
+ continue
176
+ if resolved is not None:
177
+ seen_commands.add(cmd_key)
178
+ result.append(
179
+ EditorCandidate(
180
+ name=display_name,
181
+ command=cmd_key,
182
+ path=resolved if resolved != cmd_key else None,
183
+ )
184
+ )
185
+
186
+ return result
187
+
188
+
189
+ def resolve_editor() -> str | None:
190
+ """Return the editor command specsmith should use, or ``None`` if unresolvable.
191
+
192
+ Resolution order:
193
+ 1. ``$EDITOR`` environment variable (user's explicit choice)
194
+ 2. ``editor`` key in ``~/.specsmith/config.toml``
195
+ 3. First auto-detected editor on this machine
196
+
197
+ Returns:
198
+ The command string (e.g. ``"code"``, ``"notepad++"``, ``"nvim"``),
199
+ or ``None`` if nothing was found.
200
+ """
201
+ # Priority 1: $EDITOR env var
202
+ env_editor = os.environ.get("EDITOR", "").strip()
203
+ if env_editor:
204
+ return env_editor
205
+
206
+ # Priority 2: ~/.specsmith/config.toml
207
+ config_editor = _read_config_editor()
208
+ if config_editor:
209
+ return config_editor
210
+
211
+ # Priority 3: auto-detect
212
+ candidates = list_detected_editors()
213
+ return candidates[0].command if candidates else None
214
+
215
+
216
+ def set_editor_preference(command: str) -> Path:
217
+ """Persist *command* as the preferred editor in ``~/.specsmith/config.toml``.
218
+
219
+ Creates the file and directory if they do not exist.
220
+
221
+ Args:
222
+ command: The editor command to save (e.g. ``"code"``, ``"nvim"``).
223
+
224
+ Returns:
225
+ The path of the written config file.
226
+ """
227
+ config_path = _global_config_path()
228
+ config_path.parent.mkdir(parents=True, exist_ok=True)
229
+
230
+ # Read existing content (if any) and update/insert the editor key
231
+ existing = config_path.read_text(encoding="utf-8") if config_path.exists() else ""
232
+ lines = existing.splitlines()
233
+
234
+ # Find and replace an existing `editor = ...` line, or append
235
+ new_lines: list[str] = []
236
+ found = False
237
+ for line in lines:
238
+ stripped = line.strip()
239
+ if stripped.startswith("editor") and "=" in stripped:
240
+ new_lines.append(f'editor = "{command}"')
241
+ found = True
242
+ else:
243
+ new_lines.append(line)
244
+ if not found:
245
+ new_lines.append(f'editor = "{command}"')
246
+
247
+ config_path.write_text("\n".join(new_lines) + "\n", encoding="utf-8")
248
+ return config_path
249
+
250
+
251
+ # ---------------------------------------------------------------------------
252
+ # Private helpers
253
+ # ---------------------------------------------------------------------------
254
+
255
+
256
+ def _global_config_path() -> Path:
257
+ """Return ``~/.specsmith/config.toml``."""
258
+ return Path.home() / ".specsmith" / "config.toml"
259
+
260
+
261
+ def _read_config_editor() -> str | None:
262
+ """Read the ``editor`` key from ``~/.specsmith/config.toml``."""
263
+ config_path = _global_config_path()
264
+ if not config_path.is_file():
265
+ return None
266
+ try:
267
+ # Minimal TOML parser for the editor key — avoids a tomllib dependency on 3.10
268
+ for line in config_path.read_text(encoding="utf-8").splitlines():
269
+ stripped = line.strip()
270
+ if stripped.startswith("editor") and "=" in stripped:
271
+ _, _, value = stripped.partition("=")
272
+ value = value.strip().strip('"').strip("'")
273
+ if value:
274
+ return value
275
+ except OSError:
276
+ pass
277
+ return None