henchman-ai 0.1.11__tar.gz → 0.1.12__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 (312) hide show
  1. henchman_ai-0.1.12/ALPHA_TEST_LOG.md +45 -0
  2. henchman_ai-0.1.12/BETA_TESTING_ISSUES.md +55 -0
  3. henchman_ai-0.1.12/BETA_TESTING_ISSUES2.md +215 -0
  4. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/PKG-INFO +1 -1
  5. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/pyproject.toml +1 -1
  6. henchman_ai-0.1.12/src/henchman/cli/app.py +322 -0
  7. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/commands/builtins.py +6 -0
  8. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/commands/chat.py +50 -36
  9. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/commands/rag.py +9 -4
  10. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/console.py +5 -1
  11. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/input.py +65 -0
  12. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/repl.py +190 -33
  13. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/core/turn.py +15 -9
  14. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/rag/system.py +33 -1
  15. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/utils/compaction.py +4 -3
  16. henchman_ai-0.1.12/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  17. henchman_ai-0.1.12/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  18. henchman_ai-0.1.12/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  19. henchman_ai-0.1.12/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  20. henchman_ai-0.1.12/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  21. henchman_ai-0.1.12/tests/__init__.py +0 -0
  22. henchman_ai-0.1.12/tests/cli/__init__.py +0 -0
  23. henchman_ai-0.1.12/tests/config/__init__.py +0 -0
  24. henchman_ai-0.1.12/tests/core/__init__.py +0 -0
  25. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/core/test_turn_state.py +12 -9
  26. henchman_ai-0.1.12/tests/mcp/__init__.py +0 -0
  27. henchman_ai-0.1.12/tests/providers/__init__.py +0 -0
  28. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/test_version.py +1 -1
  29. henchman_ai-0.1.12/tests/tools/__init__.py +0 -0
  30. henchman_ai-0.1.11/src/henchman/cli/app.py +0 -213
  31. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/.github/copilot-instructions.md +0 -0
  32. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/.github/workflows/ci.yml +0 -0
  33. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/.github/workflows/publish.yml +0 -0
  34. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/.gitignore +0 -0
  35. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/CHANGELOG.md +0 -0
  36. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/LICENSE +0 -0
  37. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/MagicMock/mock.rag.cache_dir/131782863223120/b0c5ce5844ad8acc/.rag.lock +0 -0
  38. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/MagicMock/mock.rag.cache_dir/131782952758032/b0c5ce5844ad8acc/.rag.lock +0 -0
  39. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/MagicMock/mock.rag.cache_dir/131782953186608/b0c5ce5844ad8acc/.rag.lock +0 -0
  40. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/MagicMock/mock.rag.cache_dir/131783467925184/b0c5ce5844ad8acc/.rag.lock +0 -0
  41. /henchman_ai-0.1.11/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/131953655609296/b0c5ce5844ad8acc/.rag.lock +0 -0
  42. /henchman_ai-0.1.11/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/131953656855104/b0c5ce5844ad8acc/.rag.lock +0 -0
  43. /henchman_ai-0.1.11/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/131954146008512/b0c5ce5844ad8acc/.rag.lock +0 -0
  44. /henchman_ai-0.1.11/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/131954155550192/b0c5ce5844ad8acc/.rag.lock +0 -0
  45. /henchman_ai-0.1.11/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/134508512171968/b0c5ce5844ad8acc/.rag.lock +0 -0
  46. /henchman_ai-0.1.11/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/134508512231200/b0c5ce5844ad8acc/.rag.lock +0 -0
  47. /henchman_ai-0.1.11/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/134508512485616/b0c5ce5844ad8acc/.rag.lock +0 -0
  48. /henchman_ai-0.1.11/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/134508855764000/b0c5ce5844ad8acc/.rag.lock +0 -0
  49. /henchman_ai-0.1.11/tests/__init__.py → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/139391159286624/b0c5ce5844ad8acc/.rag.lock +0 -0
  50. /henchman_ai-0.1.11/tests/cli/__init__.py → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/139391160298352/b0c5ce5844ad8acc/.rag.lock +0 -0
  51. /henchman_ai-0.1.11/tests/config/__init__.py → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/139391160361968/b0c5ce5844ad8acc/.rag.lock +0 -0
  52. /henchman_ai-0.1.11/tests/core/__init__.py → /henchman_ai-0.1.12/MagicMock/mock.rag.cache_dir/139391778658240/b0c5ce5844ad8acc/.rag.lock +0 -0
  53. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/PROJECT_PLAN.md +0 -0
  54. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/README.md +0 -0
  55. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/TASK_COMPLETION_SUMMARY.md +0 -0
  56. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/debug_compaction.py +0 -0
  57. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/docs/api.md +0 -0
  58. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/docs/configuration.md +0 -0
  59. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/docs/extensions.md +0 -0
  60. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/docs/getting-started.md +0 -0
  61. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/docs/index.md +0 -0
  62. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/docs/mcp.md +0 -0
  63. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/docs/providers.md +0 -0
  64. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/docs/tools.md +0 -0
  65. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/evals/README.md +0 -0
  66. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/evals/__init__.py +0 -0
  67. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/evals/conftest.py +0 -0
  68. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/evals/helpers.py +0 -0
  69. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/evals/test_answer_vs_action.py +0 -0
  70. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/evals/test_coding_tasks.py +0 -0
  71. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/evals/test_edit_precision.py +0 -0
  72. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/evals/test_skills_memory.py +0 -0
  73. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/evals/test_tool_selection.py +0 -0
  74. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/fix_repl.py +0 -0
  75. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/fix_repl_simple.py +0 -0
  76. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/mkdocs.yml +0 -0
  77. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/replace_method.py +0 -0
  78. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/reproduce_400_error.py +0 -0
  79. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/run_interactive_tests.py +0 -0
  80. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/scripts/ci.sh +0 -0
  81. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/scripts/run_evals.sh +0 -0
  82. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/__init__.py +0 -0
  83. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/__main__.py +0 -0
  84. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/__init__.py +0 -0
  85. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/commands/__init__.py +0 -0
  86. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/commands/extensions.py +0 -0
  87. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/commands/mcp.py +0 -0
  88. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/commands/plan.py +0 -0
  89. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/commands/skill.py +0 -0
  90. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/commands/unlimited.py +0 -0
  91. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/json_output.py +0 -0
  92. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/prompts.py +0 -0
  93. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/repl.py.backup +0 -0
  94. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/cli/repl.py.backup2 +0 -0
  95. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/config/__init__.py +0 -0
  96. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/config/context.py +0 -0
  97. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/config/schema.py +0 -0
  98. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/config/settings.py +0 -0
  99. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/core/__init__.py +0 -0
  100. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/core/agent.py +0 -0
  101. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/core/agent.py.backup +0 -0
  102. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/core/events.py +0 -0
  103. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/core/session.py +0 -0
  104. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/extensions/__init__.py +0 -0
  105. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/extensions/base.py +0 -0
  106. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/extensions/manager.py +0 -0
  107. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/mcp/__init__.py +0 -0
  108. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/mcp/client.py +0 -0
  109. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/mcp/config.py +0 -0
  110. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/mcp/manager.py +0 -0
  111. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/mcp/tool.py +0 -0
  112. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/providers/__init__.py +0 -0
  113. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/providers/anthropic.py +0 -0
  114. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/providers/base.py +0 -0
  115. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/providers/deepseek.py +0 -0
  116. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/providers/ollama.py +0 -0
  117. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/providers/openai_compat.py +0 -0
  118. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/providers/openai_compat.py.backup +0 -0
  119. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/providers/registry.py +0 -0
  120. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/rag/__init__.py +0 -0
  121. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/rag/chunker.py +0 -0
  122. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/rag/concurrency.py +0 -0
  123. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/rag/embedder.py +0 -0
  124. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/rag/indexer.py +0 -0
  125. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/rag/repo_id.py +0 -0
  126. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/rag/store.py +0 -0
  127. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/skills/__init__.py +0 -0
  128. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/skills/executor.py +0 -0
  129. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/skills/learner.py +0 -0
  130. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/skills/models.py +0 -0
  131. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/skills/store.py +0 -0
  132. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/__init__.py +0 -0
  133. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/base.py +0 -0
  134. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/__init__.py +0 -0
  135. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/ask_user.py +0 -0
  136. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/file_edit.py +0 -0
  137. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/file_read.py +0 -0
  138. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/file_write.py +0 -0
  139. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/glob_tool.py +0 -0
  140. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/grep.py +0 -0
  141. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/ls.py +0 -0
  142. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/rag_search.py +0 -0
  143. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/shell.py +0 -0
  144. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/builtins/web_fetch.py +0 -0
  145. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/tools/registry.py +0 -0
  146. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/utils/__init__.py +0 -0
  147. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/utils/retry.py +0 -0
  148. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/utils/tokens.py +0 -0
  149. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/utils/validation.py +0 -0
  150. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/src/henchman/version.py +0 -0
  151. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/test_compaction.py +0 -0
  152. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/test_compaction_fix.py +0 -0
  153. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/test_fixes.py +0 -0
  154. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/test_output.txt +0 -0
  155. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/test_run.py +0 -0
  156. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  157. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  158. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  159. /henchman_ai-0.1.11/tests/mcp/__init__.py → /henchman_ai-0.1.12/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  160. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  161. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572362825280/b0c5ce5844ad8acc/manifest.json +0 -0
  162. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  163. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  164. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  165. /henchman_ai-0.1.11/tests/providers/__init__.py → /henchman_ai-0.1.12/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  166. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  167. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572765096208/b0c5ce5844ad8acc/manifest.json +0 -0
  168. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  169. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  170. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  171. /henchman_ai-0.1.11/tests/tools/__init__.py → /henchman_ai-0.1.12/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/link_lists.bin +0 -0
  172. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  173. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572822401392/b0c5ce5844ad8acc/manifest.json +0 -0
  174. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  175. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  176. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  177. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  178. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/125572896176320/b0c5ce5844ad8acc/manifest.json +0 -0
  179. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  180. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  181. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  182. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  183. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520285986352/b0c5ce5844ad8acc/manifest.json +0 -0
  184. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  185. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  186. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  187. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  188. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520286228656/b0c5ce5844ad8acc/manifest.json +0 -0
  189. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  190. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  191. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  192. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  193. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520287933552/b0c5ce5844ad8acc/manifest.json +0 -0
  194. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/data_level0.bin +0 -0
  195. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/header.bin +0 -0
  196. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/88b10860-7f3a-42c9-a3aa-20e09850b445/length.bin +0 -0
  197. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/chroma/chroma.sqlite3 +0 -0
  198. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/MagicMock/mock.rag.cache_dir/135520588106160/b0c5ce5844ad8acc/manifest.json +0 -0
  199. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/commands/test_plan.py +0 -0
  200. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/commands/test_skill.py +0 -0
  201. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/commands/test_skill_extended.py +0 -0
  202. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/commands/test_unlimited.py +0 -0
  203. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_app.py +0 -0
  204. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_app_extended.py +0 -0
  205. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_builtins.py +0 -0
  206. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_chat_command.py +0 -0
  207. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_cli_smoke.py +0 -0
  208. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_commands.py +0 -0
  209. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_commands_repro.py +0 -0
  210. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_console.py +0 -0
  211. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_enhanced_tool_display.py +0 -0
  212. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_input.py +0 -0
  213. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_input_bindings.py +0 -0
  214. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_json_output.py +0 -0
  215. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_keyboard_fixes.py +0 -0
  216. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_keyboard_integration.py +0 -0
  217. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_keyboard_interrupt.py +0 -0
  218. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_keyboard_verification.py +0 -0
  219. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_loop_protection.py +0 -0
  220. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_mcp_command.py +0 -0
  221. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_repl.py +0 -0
  222. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_repl_attribute_fix.py +0 -0
  223. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_repl_startup_message.py +0 -0
  224. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/cli/test_repl_toolbar.py +0 -0
  225. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/config/test_context.py +0 -0
  226. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/config/test_schema.py +0 -0
  227. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/config/test_settings.py +0 -0
  228. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/conftest.py +0 -0
  229. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/core/test_automatic_compaction.py +0 -0
  230. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/core/test_events.py +0 -0
  231. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/core/test_session.py +0 -0
  232. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/core/test_session_manager.py +0 -0
  233. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/core/test_streaming_tool_calls.py +0 -0
  234. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/e2e/test_context_safety.py +0 -0
  235. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/e2e/test_tool_fix.py +0 -0
  236. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/empty_message_validation/test_empty_messages.py +0 -0
  237. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/extensions/__init__.py +0 -0
  238. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/extensions/test_base.py +0 -0
  239. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/extensions/test_command.py +0 -0
  240. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/extensions/test_manager.py +0 -0
  241. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/integration/test_context_limits.py +0 -0
  242. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/integration/test_tool_integration.py +0 -0
  243. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/mcp/test_client.py +0 -0
  244. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/mcp/test_config.py +0 -0
  245. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/mcp/test_manager.py +0 -0
  246. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/mcp/test_tool.py +0 -0
  247. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/providers/test_413_error_handling.py +0 -0
  248. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/providers/test_anthropic.py +0 -0
  249. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/providers/test_base.py +0 -0
  250. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/providers/test_deepseek.py +0 -0
  251. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/providers/test_ollama.py +0 -0
  252. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/providers/test_openai_compat.py +0 -0
  253. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/providers/test_registry.py +0 -0
  254. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/__init__.py +0 -0
  255. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_chunker.py +0 -0
  256. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_concurrency.py +0 -0
  257. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_concurrency_smoke.py +0 -0
  258. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_embedder.py +0 -0
  259. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_indexer.py +0 -0
  260. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_rag_command.py +0 -0
  261. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_rag_concurrency_integration.py +0 -0
  262. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_rag_search_tool.py +0 -0
  263. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_repo_id.py +0 -0
  264. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_store.py +0 -0
  265. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/rag/test_system.py +0 -0
  266. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/skills/test_executor.py +0 -0
  267. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/skills/test_learner.py +0 -0
  268. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/skills/test_markdown_skills.py +0 -0
  269. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/skills/test_models.py +0 -0
  270. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/skills/test_store.py +0 -0
  271. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/skills/test_store_extended.py +0 -0
  272. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/smoke/test_escape_key_behavior.py +0 -0
  273. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/smoke/test_large_file_handling.py +0 -0
  274. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/test_coverage_suite.py +0 -0
  275. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/test_main.py +0 -0
  276. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/tools/test_ask_user_tool.py +0 -0
  277. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/tools/test_base.py +0 -0
  278. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/tools/test_directory_tools.py +0 -0
  279. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/tools/test_file_tools.py +0 -0
  280. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/tools/test_grep_tool.py +0 -0
  281. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/tools/test_plan_mode_enforcement.py +0 -0
  282. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/tools/test_registry.py +0 -0
  283. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/tools/test_shell_tool.py +0 -0
  284. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/tools/test_web_fetch_tool.py +0 -0
  285. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/INTERACTIVE_SESSION_TESTS.md +0 -0
  286. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/__init__.py +0 -0
  287. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/conftest.py +0 -0
  288. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_agent.py +0 -0
  289. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_compaction_llm.py +0 -0
  290. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_events.py +0 -0
  291. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_llm.py +0 -0
  292. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_mcp.py +0 -0
  293. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_plan_mode.py +0 -0
  294. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_repl_e2e.py +0 -0
  295. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_repl_integration.py +0 -0
  296. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_session.py +0 -0
  297. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_skills.py +0 -0
  298. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_slash_commands.py +0 -0
  299. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_tokens_llm.py +0 -0
  300. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_tool_calls.py +0 -0
  301. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/ui_integration/test_tool_integration.py +0 -0
  302. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_compaction.py +0 -0
  303. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_compaction_edge_cases.py +0 -0
  304. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_compaction_validation.py +0 -0
  305. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_multi_turn_tool_calls.py +0 -0
  306. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_protected_zone.py +0 -0
  307. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_retry.py +0 -0
  308. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_summarization.py +0 -0
  309. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_tiktoken_integration.py +0 -0
  310. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_token_counter_extended.py +0 -0
  311. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_tool_sequence_compaction.py +0 -0
  312. {henchman_ai-0.1.11 → henchman_ai-0.1.12}/tests/utils/test_validation.py +0 -0
@@ -0,0 +1,45 @@
1
+ # Henchman Alpha Test Log
2
+ **Date:** 2026-02-02
3
+ **Tester:** Senior Principal QA Lead
4
+
5
+ ## Objectives
6
+ - Verify architectural constraints.
7
+ - specific tool usage patterns.
8
+ - Test self-correction capabilities.
9
+ - Verify context maintenance.
10
+
11
+ ## Issues Found
12
+
13
+ ### 1. Session Management Completely Missing in CLI
14
+ **Severity:** Critical
15
+ **Description:** `app.py` does not initialize `SessionManager` or `Session` for `Repl`. As a result, conversation history is not recorded or saved to disk by default.
16
+ **Impact:** Users lose all conversation history when the CLI exits.
17
+
18
+ ### 2. Session Loading Amnesia
19
+ **Severity:** High
20
+ **Description:** When a session is loaded (manually or via `/chat resume`), the `Agent.messages` history is not automatically synced with the loaded session's history. While `/chat resume` attempts to do this, it doesn't update `Repl.session`, leading to inconsistent state.
21
+ **Impact:** Context loss and failed auto-saves for resumed sessions.
22
+
23
+ ### 4. Interrupted Turn Inconsistency
24
+ **Severity:** High
25
+ **Description:** If a turn is interrupted (e.g., Ctrl+C) during tool execution, the assistant message is recorded in the session with tool calls, but no tool results are added.
26
+ **Impact:** Resuming such a session creates an invalid message sequence for most LLM providers (OpenAI requires responses for all tool calls), causing the next turn to fail with an API error.
27
+
28
+ ### 5. Brittle Tool Execution Loop
29
+ **Severity:** Medium
30
+ **Description:** `Repl` executes tool calls sequentially instead of using `ToolRegistry.execute_batch`.
31
+ **Impact:** Significant performance penalty when multiple independent tools are called in a single turn.
32
+
33
+ ### 6. Duplication Risk in Context Compaction
34
+ **Severity:** Low/Medium
35
+ **Description:** The `ContextCompactor` extracts system messages to prepend them to the result, but also includes them in the first atomic sequence. If the first sequence is kept, the system message is duplicated.
36
+ **Impact:** Minor token waste, but could potentially confuse some sensitive models.
37
+
38
+ ### 7. Missing Tool Confirmation Handler
39
+ **Severity:** Critical (Security)
40
+ **Description:** The CLI does not set a confirmation handler on the `ToolRegistry`. Consequently, tools marked as `WRITE`, `EXECUTE`, or `NETWORK` (like `shell` or `write_file`) are executed immediately without any user oversight.
41
+ **Impact:** Highly dangerous. The agent can run arbitrary shell commands or modify any file without the user being able to stop it.
42
+
43
+ ## Summary for Development Team
44
+ The core agent logic and loop protection are robust, but the **CLI integration layer** is currently an "Alpha" state with broken session persistence and context handling. Priority should be given to wiring up `SessionManager` in `app.py` and ensuring `Agent.messages` is always synced with `Repl.session.messages`.
45
+
@@ -0,0 +1,55 @@
1
+ # Beta Testing Issues Report
2
+
3
+ **Date:** 2026-02-02
4
+ **Tester:** Gemini CLI
5
+
6
+ ## Summary
7
+ The Henchman CLI (v0.1.11) shows significant improvements over the Alpha state. Session persistence is functional (files are saved), and tool confirmation workflows are implemented. However, critical CLI commands for managing sessions and MCP servers are missing from the registry, making it impossible to manage sessions or MCP connections interactively.
8
+
9
+ ## Issues Found
10
+
11
+ ### 1. Missing `/chat` Command
12
+ **Severity:** High
13
+ **Description:** The `/chat` command (implemented in `src/henchman/cli/commands/chat.py`) is not registered in `src/henchman/cli/commands/builtins.py`.
14
+ **Impact:** Users cannot save, list, or resume sessions interactively. The `ChatCommand` class exists but is unreachable.
15
+ **Reproduction:**
16
+ ```bash
17
+ henchman
18
+ > /chat list
19
+ ✗ Unknown command: /chat
20
+ ```
21
+
22
+ ### 2. Missing `/mcp` Command
23
+ **Severity:** Medium
24
+ **Description:** The `/mcp` command (implemented in `src/henchman/cli/commands/mcp.py`) is not registered in `src/henchman/cli/commands/builtins.py`.
25
+ **Impact:** Users cannot manage or inspect Model Context Protocol (MCP) servers interactively.
26
+ **Reproduction:**
27
+ ```bash
28
+ henchman
29
+ > /mcp list
30
+ ✗ Unknown command: /mcp
31
+ ```
32
+
33
+ ### 3. Session Resume Requires Tags
34
+ **Severity:** Medium
35
+ **Description:** The `/chat resume` command implementation only supports loading by `tag` (`manager.load_by_tag`). It does not appear to support loading by Session ID. Since sessions are created without tags by default, users cannot easily resume a specific previous session without manually editing the session file to add a tag or implementing a tagging workflow.
36
+ **Impact:** Resuming the "last session" or a specific untitled session is difficult/impossible via the CLI.
37
+ **Location:** `src/henchman/cli/commands/chat.py`, `_resume` method.
38
+
39
+ ### 4. Cosmetic: CLI Self-Identification
40
+ **Severity:** Low
41
+ **Description:** `henchman --version` output identifies as `mlg`.
42
+ **Output:** `mlg, version 0.1.11`
43
+ **Expected:** `henchman, version 0.1.11`
44
+
45
+ ## Verification of Alpha Issues
46
+
47
+ - **Session Management Missing:** [FIXED] `SessionManager` is correctly initialized in `app.py`, and session files are created in `~/.henchman/sessions`.
48
+ - **Missing Tool Confirmation Handler:** [FIXED] `ToolRegistry.set_confirmation_handler` is called in `Repl.__init__`, and prompts are displayed for dangerous tools (verified with `write_file`).
49
+ - **Session Loading Amnesia:** [PARTIALLY VERIFIED] Could not fully verify due to missing `/chat` command, but code inspection of `ChatCommand._resume` suggests it now correctly syncs `Repl.session` and `Agent.messages`.
50
+
51
+ ## Recommendations
52
+
53
+ 1. **Register Missing Commands:** Add `ChatCommand()` and `McpCommand()` to the list returned by `get_builtin_commands()` in `src/henchman/cli/commands/builtins.py`.
54
+ 2. **Enhance Resume:** Modify `ChatCommand._resume` to try loading by ID if loading by tag fails, or add a separate `load` subcommand that accepts IDs.
55
+ 3. **Auto-Resume:** Consider an option or flag (e.g., `henchman --resume`) to automatically load the most recent session.
@@ -0,0 +1,215 @@
1
+ # Henchman Beta Testing Notes
2
+
3
+ **Tester**: GitHub Copilot (Claude Opus 4.5)
4
+ **Date**: February 2, 2026
5
+ **Version Tested**: v0.1.11 (package name: `mlg`)
6
+ **CLI Location**: `/home/matthew/mlg-cli`
7
+
8
+ ---
9
+
10
+ ## Overview
11
+
12
+ Henchman is a model-agnostic AI agent CLI. It supports interactive sessions and headless mode with `--prompt`. This document captures observations, issues, and feedback from beta testing.
13
+
14
+ ---
15
+
16
+ ## CLI Options Discovered
17
+
18
+ ```
19
+ Usage: henchman [OPTIONS]
20
+
21
+ Options:
22
+ --version Show the version and exit.
23
+ -p, --prompt TEXT Run with a single prompt and exit
24
+ --output-format [text|json|stream-json] Output format for responses
25
+ --plan Start in plan mode (read-only)
26
+ --help Show this message and exit.
27
+ ```
28
+
29
+ ---
30
+
31
+ ## Testing Sessions
32
+
33
+ ### Session 1 - Initial Launch (Prior)
34
+ - **Command**: `henchman`
35
+ - **Working Directory**: `/home/matthew/mlg-cli`
36
+ - **Exit Code**: 130 (Ctrl+C interrupt)
37
+ - **Status**: ⚠️ Inconclusive - manual interrupt
38
+
39
+ ### Session 2 - Help & Version Check
40
+ - **Command**: `henchman --help` and `henchman --version`
41
+ - **Result**: ✅ Success - Clean output, proper CLI structure
42
+ - **Version**: 0.1.11
43
+
44
+ ### Session 3 - Simple Workspace Query
45
+ - **Command**: `henchman -p "What files are in this workspace?"`
46
+ - **Result**: ✅ Success - Correctly listed directories and files
47
+ - **Tools Used**: `ls()`
48
+ - **Iterations**: 1/25
49
+
50
+ ### Session 4 - File Reading & Summarization
51
+ - **Command**: `henchman -p "Read .github/copilot-instructions.md and summarize"`
52
+ - **Result**: ✅ Success - Read file, provided accurate 2-sentence summary
53
+ - **Tools Used**: `read_file()`
54
+ - **Quality**: Excellent - understood project context accurately
55
+
56
+ ### Session 5 - Plan Mode (Complex Analysis)
57
+ - **Command**: `henchman --plan -p "What tests would you run to validate Elo?"`
58
+ - **Result**: ✅ Success - Comprehensive analysis with 10 test categories
59
+ - **Tools Used**: `ls()`, `read_file()`, `rag_search()`
60
+ - **Iterations**: 14/25
61
+ - **Note**: Loop detection triggered at iteration 11 ("⚠ Possible loop detected") but recovered gracefully
62
+
63
+ ### Session 6 - Code Generation (File Creation)
64
+ - **Command**: `henchman -p "Create a test file for NBAEloRating"`
65
+ - **Result**: ✅ Success - Created valid, working test file
66
+ - **Tools Used**: `rag_search()`, `read_file()`, `ls()`, `write_file()`
67
+ - **File Created**: `tests/test_henchman_demo.py` (3944 bytes)
68
+ - **Test Verification**: Both tests passed when run with pytest!
69
+ - **User Interaction**: Required "y/n" confirmation for file write (good safety feature)
70
+
71
+ ### Session 7 - JSON Output Format
72
+ - **Command**: `henchman -p "What is 2+2?" --output-format json`
73
+ - **Result**: ✅ Success - Streamed JSON tokens properly
74
+ - **Note**: Output is token-by-token, final line has full response
75
+
76
+ ### Session 8 - Shell Command Execution
77
+ - **Command**: `henchman -p "Run 'echo Hello from Henchman'"`
78
+ - **Result**: ✅ Success - Executed command, showed output
79
+ - **Tools Used**: `shell()`
80
+ - **User Interaction**: Required "y/n" confirmation (good safety feature)
81
+
82
+ ### Session 9 - Multi-Step File Operations
83
+ - **Command**: `henchman -p "Find Python files in plugins/elo and count them"`
84
+ - **Result**: ✅ Success - Found all 15 Python files correctly
85
+ - **Tools Used**: `ls()`, `glob()`, `shell()`
86
+ - **Iterations**: 6/35
87
+
88
+ ---
89
+
90
+ ## Issues Found
91
+
92
+ ### Issue #1: Loop Detection Warning (Minor)
93
+ - **Severity**: Low
94
+ - **Description**: During complex analysis tasks, Henchman triggers "⚠ Possible loop detected" warnings when reading multiple files sequentially.
95
+ - **Observed In**: Session 5 (Plan mode analysis)
96
+ - **Impact**: None - it recovered and continued successfully
97
+ - **Suggestion**: Consider adjusting the loop detection heuristics to differentiate between legitimate sequential file reads and actual loops.
98
+
99
+ ### Issue #2: Version Mismatch Display
100
+ - **Severity**: Very Low (cosmetic)
101
+ - **Description**: `--version` shows `mlg, version 0.1.11` but product is "Henchman"
102
+ - **Expected**: `henchman, version 0.1.11`
103
+ - **Impact**: Confusion about package vs. product naming
104
+
105
+ ### Issue #3: JSON Output Token Streaming
106
+ - **Severity**: Low
107
+ - **Description**: JSON output streams token-by-token which may not be ideal for programmatic consumption
108
+ - **Observed**: `{"type": "content", "data": "2"}` per token
109
+ - **Suggestion**: Consider a `--output-format json-complete` option for full response in single JSON object
110
+
111
+ ---
112
+
113
+ ## Feature Requests
114
+
115
+ 1. **Non-interactive mode flag**: A `--yes` or `-y` flag to auto-approve tool executions for CI/CD pipelines
116
+ 2. **Verbosity control**: `--quiet` or `--verbose` flags to control output detail
117
+ 3. **Session logging**: Option to log full session to file for debugging
118
+ 4. **Context file**: Ability to specify a context file (like copilot-instructions.md) for automatic project conventions
119
+
120
+ ---
121
+
122
+ ## Positive Observations
123
+
124
+ ### ✅ Excellent Code Quality
125
+ The test file Henchman generated was:
126
+ - Properly structured with docstrings
127
+ - Followed existing project conventions
128
+ - Included multiple test cases beyond requirements
129
+ - **Actually passed when run with pytest!**
130
+
131
+ ### ✅ Smart Tool Selection
132
+ - Uses RAG search for semantic queries
133
+ - Falls back to file system operations for concrete tasks
134
+ - Chains tools effectively (ls → read_file → write_file)
135
+
136
+ ### ✅ Good Safety Features
137
+ - Prompts for confirmation before file writes
138
+ - Prompts for confirmation before shell commands
139
+ - Clear display of what tool is being called
140
+
141
+ ### ✅ Context Awareness
142
+ - Understood project structure quickly
143
+ - Read relevant files before generating code
144
+ - Matched existing code style and imports
145
+
146
+ ### ✅ Plan Mode
147
+ - Excellent for read-only analysis
148
+ - Thorough exploration of codebase
149
+ - Generates actionable recommendations
150
+
151
+ ### ✅ Progress Indicators
152
+ - Shows iteration count (e.g., "[Iter 3/25 | 3 calls | 2K tokens]")
153
+ - Indicates token usage and protection status
154
+ - Shows "✓ progress" vs "⚠ spinning" status
155
+
156
+ ---
157
+
158
+ ## Comparison Notes
159
+
160
+ As an agentic coding AI myself, here's my evaluation:
161
+
162
+ - [x] **Tool Usage**: Excellent - smart tool selection, effective chaining
163
+ - [x] **Context Awareness**: Excellent - understands project structure
164
+ - [x] **Autonomy**: Good - handles multi-step tasks independently
165
+ - [x] **Error Recovery**: Good - recovered from loop detection warnings
166
+ - [x] **Code Quality**: Excellent - generated working, idiomatic code
167
+ - [x] **Communication**: Good - clear about what it's doing
168
+ - [x] **Persistence**: Good - follows through on complex tasks
169
+
170
+ ---
171
+
172
+ ## Testing Checklist
173
+
174
+ - [x] Basic CLI functionality
175
+ - [x] File reading/editing capabilities
176
+ - [x] Terminal command execution
177
+ - [ ] Multi-file refactoring (not tested yet)
178
+ - [ ] Error handling and recovery (partially tested)
179
+ - [x] Project-specific conventions
180
+ - [ ] Database operations (not tested yet)
181
+ - [x] Test execution (generated tests that work!)
182
+ - [ ] Long-running task management (not tested yet)
183
+
184
+ ---
185
+
186
+ ## Recommendations for Henchman Team
187
+
188
+ 1. **Fix version string**: Change from `mlg` to `henchman` in `--version` output
189
+ 2. **Tune loop detection**: Current threshold may be too aggressive for legitimate file exploration
190
+ 3. **Add batch mode**: For CI/CD integration, add `--yes` flag to skip confirmations
191
+ 4. **Document tool set**: List available tools (ls, read_file, write_file, shell, rag_search, glob) in docs
192
+ 5. **Consider token limits**: Show remaining context budget more prominently
193
+
194
+ ---
195
+
196
+ ## Overall Assessment
197
+
198
+ **Rating: 8.5/10** ⭐⭐⭐⭐
199
+
200
+ Henchman is a solid, well-designed agentic AI CLI. The headless mode (`-p`) is particularly useful for scripting. Code generation quality is impressive - the test file it created actually worked! The safety features (confirmations for writes/commands) are appropriate for a beta. Minor polish issues exist but don't impact functionality.
201
+
202
+ **Would recommend for**: Developers who want CLI-based AI assistance for file exploration, code generation, and analysis tasks.
203
+
204
+ ---
205
+
206
+ ## Changelog
207
+
208
+ | Date | Notes |
209
+ |------|-------|
210
+ | 2026-02-02 | Created initial beta testing document |
211
+ | 2026-02-02 | Completed comprehensive testing - 9 sessions, 3 issues found, overall positive |
212
+
213
+ ---
214
+
215
+ *Testing complete. Document may be updated with additional findings.*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: henchman-ai
3
- Version: 0.1.11
3
+ Version: 0.1.12
4
4
  Summary: A model-agnostic AI agent CLI - your AI henchman for the terminal
5
5
  Project-URL: Homepage, https://github.com/MGPowerlytics/henchman-ai
6
6
  Project-URL: Repository, https://github.com/MGPowerlytics/henchman-ai
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "henchman-ai"
7
- version = "0.1.11"
7
+ version = "0.1.12"
8
8
  description = "A model-agnostic AI agent CLI - your AI henchman for the terminal"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -0,0 +1,322 @@
1
+ """MLG CLI application entry point."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import os
7
+ from typing import TYPE_CHECKING
8
+
9
+ import anyio
10
+ import click
11
+ from rich.console import Console
12
+
13
+ from henchman.version import VERSION
14
+
15
+ if TYPE_CHECKING:
16
+ from henchman.providers.base import ModelProvider
17
+
18
+ console = Console()
19
+
20
+
21
+ def _get_provider() -> ModelProvider:
22
+ """Get the configured model provider.
23
+
24
+ Returns:
25
+ A ModelProvider instance.
26
+
27
+ Raises:
28
+ click.ClickException: If no provider is configured.
29
+ """
30
+ from henchman.providers import DeepSeekProvider, get_default_registry
31
+
32
+ # Check environment for API key
33
+ api_key = os.environ.get("DEEPSEEK_API_KEY") or os.environ.get("HENCHMAN_API_KEY")
34
+
35
+ if api_key:
36
+ return DeepSeekProvider(api_key=api_key)
37
+
38
+ # Try to load from settings
39
+ try:
40
+ from henchman.config import load_settings
41
+
42
+ settings = load_settings()
43
+ registry = get_default_registry()
44
+
45
+ provider_name = settings.providers.default or "deepseek"
46
+ provider_settings = getattr(settings.providers, provider_name, None)
47
+
48
+ if provider_settings:
49
+ return registry.create(
50
+ provider_name,
51
+ api_key=getattr(provider_settings, "api_key", None) or "",
52
+ model=getattr(provider_settings, "model", None),
53
+ )
54
+ except Exception: # pragma: no cover
55
+ pass
56
+
57
+ raise click.ClickException( # pragma: no cover
58
+ "No API key configured. Set DEEPSEEK_API_KEY or configure in ~/.henchman/settings.yaml"
59
+ )
60
+
61
+
62
+ def _run_interactive(output_format: str, plan_mode: bool = False, yes: bool = False) -> None:
63
+ """Run interactive REPL mode.
64
+
65
+ Args:
66
+ output_format: Output format (text, json, stream-json, json-complete).
67
+ plan_mode: Whether to start in plan mode.
68
+ yes: Auto-approve all tool executions.
69
+ """
70
+ from pathlib import Path
71
+ from henchman.cli.repl import Repl, ReplConfig
72
+ from henchman.config import ContextLoader, load_settings
73
+ from henchman.core.session import SessionManager
74
+ from henchman.rag import initialize_rag
75
+
76
+ provider = _get_provider()
77
+ settings = load_settings()
78
+
79
+ # Load context from MLG.md files
80
+ context_loader = ContextLoader()
81
+ system_prompt = context_loader.load()
82
+
83
+ config = ReplConfig(system_prompt=system_prompt, auto_approve_tools=yes)
84
+ repl = Repl(
85
+ provider=provider,
86
+ console=console,
87
+ config=config,
88
+ settings=settings
89
+ )
90
+
91
+ # Initialize session management
92
+ session_manager = SessionManager()
93
+ project_hash = session_manager.compute_project_hash(Path.cwd())
94
+ session = session_manager.create_session(project_hash)
95
+
96
+ repl.session_manager = session_manager
97
+ repl.session = session
98
+
99
+ # Initialize RAG system
100
+ rag_system = initialize_rag(settings.rag, console=console, index=False)
101
+ if rag_system:
102
+ repl.tool_registry.register(rag_system.search_tool)
103
+ repl.rag_system = rag_system
104
+
105
+ # Set plan mode if requested
106
+ if plan_mode and repl.session:
107
+ repl.session.plan_mode = True
108
+ repl.tool_registry.set_plan_mode(True)
109
+ # Add plan mode prompt to system prompt
110
+ from henchman.cli.commands.plan import PLAN_MODE_PROMPT
111
+ repl.agent.system_prompt += PLAN_MODE_PROMPT
112
+
113
+ if output_format == "text":
114
+ anyio.run(repl.run)
115
+ else: # pragma: no cover
116
+ console.print(
117
+ "[yellow]Warning: JSON output formats not supported in interactive mode. "
118
+ "Using text format.[/yellow]"
119
+ )
120
+ anyio.run(repl.run)
121
+
122
+
123
+ def _run_headless(prompt: str, output_format: str, plan_mode: bool = False, yes: bool = False) -> None:
124
+ """Run headless mode with a single prompt.
125
+
126
+ Args:
127
+ prompt: The prompt to process.
128
+ output_format: Output format (text, json, stream-json, json-complete).
129
+ plan_mode: Whether to run in plan mode.
130
+ yes: Auto-approve all tool executions.
131
+ """
132
+ from pathlib import Path
133
+ from henchman.cli.json_output import JsonOutputRenderer
134
+ from henchman.cli.repl import Repl, ReplConfig
135
+ from henchman.config import ContextLoader, load_settings
136
+ from henchman.core.events import EventType
137
+ from henchman.core.session import SessionManager
138
+ from henchman.rag import initialize_rag
139
+
140
+ provider = _get_provider()
141
+ settings = load_settings()
142
+
143
+ # Load context from MLG.md files
144
+ context_loader = ContextLoader()
145
+ system_prompt = context_loader.load()
146
+
147
+ # Add plan mode prompt if requested
148
+ if plan_mode: # pragma: no cover
149
+ from henchman.cli.commands.plan import PLAN_MODE_PROMPT
150
+ system_prompt += PLAN_MODE_PROMPT
151
+
152
+ config = ReplConfig(system_prompt=system_prompt, auto_approve_tools=yes)
153
+ repl = Repl(provider=provider, console=console, config=config, settings=settings)
154
+
155
+ # Initialize session management
156
+ session_manager = SessionManager()
157
+ project_hash = session_manager.compute_project_hash(Path.cwd())
158
+ session = session_manager.create_session(project_hash)
159
+
160
+ repl.session_manager = session_manager
161
+ repl.session = session
162
+
163
+ # Initialize RAG system
164
+ rag_system = initialize_rag(settings.rag, index=False) # No console output in headless
165
+ if rag_system:
166
+ repl.tool_registry.register(rag_system.search_tool)
167
+ repl.rag_system = rag_system
168
+
169
+ # Set plan mode if requested
170
+ if plan_mode and repl.session: # pragma: no cover
171
+ repl.session.plan_mode = True
172
+ repl.tool_registry.set_plan_mode(True)
173
+
174
+ async def run_single_prompt_text() -> None: # pragma: no cover
175
+ """Process a single prompt and exit with text output."""
176
+ if repl.rag_system:
177
+ asyncio.create_task(repl.rag_system.index_async())
178
+ await repl.process_input(prompt)
179
+
180
+ async def run_single_prompt_json() -> None:
181
+ """Process a single prompt and exit with JSON output."""
182
+ from henchman.core.events import AgentEvent, EventType
183
+ from henchman.providers.base import ToolCall
184
+ from collections.abc import AsyncIterator
185
+
186
+ if repl.rag_system:
187
+ asyncio.create_task(repl.rag_system.index_async())
188
+
189
+ json_renderer = JsonOutputRenderer(console)
190
+
191
+ # We need to manually run the tool loop for JSON output
192
+ # to ensure all events are rendered as JSON
193
+ async def run_and_render(stream: AsyncIterator[AgentEvent]) -> None:
194
+ pending_tool_calls = []
195
+ async for event in stream:
196
+ json_renderer.render(event)
197
+ if event.type == EventType.TOOL_CALL_REQUEST:
198
+ pending_tool_calls.append(event.data)
199
+
200
+ if pending_tool_calls:
201
+ # Execute tool calls
202
+ for tool_call in pending_tool_calls:
203
+ result = await repl.tool_registry.execute(tool_call.name, tool_call.arguments)
204
+ repl.agent.submit_tool_result(tool_call.id, result.content)
205
+ # Emit tool result event
206
+ json_renderer.render(AgentEvent(type=EventType.TOOL_RESULT, data=result))
207
+
208
+ # Continue
209
+ await run_and_render(repl.agent.continue_with_tool_results())
210
+
211
+ await run_and_render(repl.agent.run(prompt))
212
+
213
+ async def run_single_prompt_stream_json() -> None:
214
+ """Process a single prompt and exit with streaming JSON output."""
215
+ from henchman.core.events import AgentEvent, EventType
216
+ from henchman.providers.base import ToolCall
217
+ from collections.abc import AsyncIterator
218
+
219
+ if repl.rag_system:
220
+ asyncio.create_task(repl.rag_system.index_async())
221
+
222
+ json_renderer = JsonOutputRenderer(console)
223
+
224
+ async def run_and_render_stream(stream: AsyncIterator[AgentEvent]) -> None:
225
+ pending_tool_calls = []
226
+ async for event in stream:
227
+ json_renderer.render_stream_json(event)
228
+ if event.type == EventType.TOOL_CALL_REQUEST:
229
+ pending_tool_calls.append(event.data)
230
+
231
+ if pending_tool_calls:
232
+ for tool_call in pending_tool_calls:
233
+ result = await repl.tool_registry.execute(tool_call.name, tool_call.arguments)
234
+ repl.agent.submit_tool_result(tool_call.id, result.content)
235
+ json_renderer.render_stream_json(AgentEvent(type=EventType.TOOL_RESULT, data=result))
236
+
237
+ await run_and_render_stream(repl.agent.continue_with_tool_results())
238
+
239
+ await run_and_render_stream(repl.agent.run(prompt))
240
+
241
+ async def run_single_prompt_json_complete() -> None:
242
+ """Process a single prompt and exit with complete JSON output."""
243
+ from henchman.core.events import AgentEvent, EventType
244
+ from henchman.providers.base import ToolCall
245
+ from collections.abc import AsyncIterator
246
+
247
+ if repl.rag_system:
248
+ asyncio.create_task(repl.rag_system.index_async())
249
+
250
+ json_renderer = JsonOutputRenderer(console)
251
+ all_events: list[AgentEvent] = []
252
+
253
+ async def run_and_collect(stream: AsyncIterator[AgentEvent]) -> None:
254
+ pending_tool_calls = []
255
+ async for event in stream:
256
+ all_events.append(event)
257
+ if event.type == EventType.TOOL_CALL_REQUEST:
258
+ pending_tool_calls.append(event.data)
259
+
260
+ if pending_tool_calls:
261
+ for tool_call in pending_tool_calls:
262
+ result = await repl.tool_registry.execute(tool_call.name, tool_call.arguments)
263
+ repl.agent.submit_tool_result(tool_call.id, result.content)
264
+ all_events.append(AgentEvent(type=EventType.TOOL_RESULT, data=result))
265
+
266
+ await run_and_collect(repl.agent.continue_with_tool_results())
267
+
268
+ await run_and_collect(repl.agent.run(prompt))
269
+ json_renderer.render_final_json(all_events)
270
+
271
+ if output_format == "text":
272
+ anyio.run(run_single_prompt_text)
273
+ elif output_format == "json":
274
+ anyio.run(run_single_prompt_json)
275
+ elif output_format == "stream-json":
276
+ anyio.run(run_single_prompt_stream_json)
277
+ elif output_format == "json-complete":
278
+ anyio.run(run_single_prompt_json_complete)
279
+ else: # pragma: no cover
280
+ pass
281
+
282
+
283
+ @click.command()
284
+ @click.version_option(version=VERSION, prog_name="henchman")
285
+ @click.option("-p", "--prompt", help="Run with a single prompt and exit")
286
+ @click.option(
287
+ "--output-format",
288
+ type=click.Choice(["text", "json", "stream-json", "json-complete"]),
289
+ default="text",
290
+ help="Output format for responses",
291
+ )
292
+ @click.option(
293
+ "--plan",
294
+ is_flag=True,
295
+ default=False,
296
+ help="Start in plan mode (read-only)",
297
+ )
298
+ @click.option(
299
+ "-y",
300
+ "--yes",
301
+ is_flag=True,
302
+ default=False,
303
+ help="Auto-approve all tool executions (non-interactive mode)",
304
+ )
305
+ def cli(prompt: str | None, output_format: str, plan: bool, yes: bool) -> None:
306
+ """Henchman-AI: A model-agnostic AI agent CLI.
307
+
308
+ Start an interactive session or run with --prompt for headless mode.
309
+ """
310
+ if prompt:
311
+ _run_headless(prompt, output_format, plan, yes)
312
+ else:
313
+ _run_interactive(output_format, plan, yes)
314
+
315
+
316
+ def main() -> None: # pragma: no cover
317
+ """Main entry point for the CLI."""
318
+ cli()
319
+
320
+
321
+ if __name__ == "__main__": # pragma: no cover
322
+ main()
@@ -6,6 +6,8 @@ This module provides the default slash commands like /help, /quit, /clear, /tool
6
6
  from __future__ import annotations
7
7
 
8
8
  from henchman.cli.commands import Command, CommandContext
9
+ from henchman.cli.commands.chat import ChatCommand
10
+ from henchman.cli.commands.mcp import McpCommand
9
11
  from henchman.cli.commands.plan import PlanCommand
10
12
  from henchman.cli.commands.rag import RagCommand
11
13
  from henchman.cli.commands.skill import SkillCommand
@@ -53,6 +55,8 @@ class HelpCommand(Command):
53
55
  ctx.console.print(" /plan - Toggle Plan Mode (Read-Only)")
54
56
  ctx.console.print(" /rag - Manage semantic search index")
55
57
  ctx.console.print(" /skill - Manage and execute learned skills")
58
+ ctx.console.print(" /chat - Manage chat sessions (save, list, resume)")
59
+ ctx.console.print(" /mcp - Manage MCP server connections")
56
60
  ctx.console.print(" /quit - Exit the CLI")
57
61
  ctx.console.print(" /clear - Clear the screen")
58
62
  ctx.console.print(" /tools - List available tools")
@@ -206,6 +210,8 @@ def get_builtin_commands() -> list[Command]:
206
210
  QuitCommand(),
207
211
  ClearCommand(),
208
212
  ToolsCommand(),
213
+ ChatCommand(),
214
+ McpCommand(),
209
215
  PlanCommand(),
210
216
  RagCommand(),
211
217
  SkillCommand(),