lemming-cli 0.5.2__tar.gz → 0.6.1__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 (196) hide show
  1. lemming_cli-0.5.2/README.md → lemming_cli-0.6.1/PKG-INFO +48 -7
  2. lemming_cli-0.5.2/PKG-INFO → lemming_cli-0.6.1/README.md +28 -30
  3. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/SKILL.md +7 -1
  4. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/docs/HOOKS.md +32 -0
  5. lemming_cli-0.6.1/docs/WORKSPACE.md +120 -0
  6. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/pyproject.toml +4 -7
  7. lemming_cli-0.6.1/src/lemming/api/__init__.py +1 -0
  8. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/auth_test.py +14 -14
  9. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/config.py +7 -6
  10. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/config_test.py +3 -3
  11. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/conftest.py +43 -42
  12. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/directories_test.py +5 -5
  13. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/hooks_test.py +2 -2
  14. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/logging_test.py +2 -2
  15. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/loop.py +2 -2
  16. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/loop_test.py +9 -3
  17. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/main.py +0 -4
  18. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/tasks.py +22 -21
  19. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/tasks_test.py +76 -60
  20. lemming_cli-0.6.1/src/lemming/artifact_test.py +141 -0
  21. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/brief_test.py +6 -4
  22. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/__init__.py +1 -3
  23. lemming_cli-0.6.1/src/lemming/cli/artifact.py +141 -0
  24. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/brief.py +5 -4
  25. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/config.py +4 -4
  26. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/config_test.py +9 -8
  27. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/exec_cli.py +16 -13
  28. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/exec_cli_test.py +71 -58
  29. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/goal.py +5 -4
  30. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/goal_test.py +5 -4
  31. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/hooks_test.py +4 -3
  32. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/machine_output_test.py +8 -7
  33. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/main_test.py +26 -20
  34. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/operations.py +43 -27
  35. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/operations_test.py +24 -11
  36. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/progress.py +2 -2
  37. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/progress_test.py +10 -9
  38. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/skill_test.py +3 -3
  39. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/stop_test.py +18 -17
  40. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/tasks.py +99 -55
  41. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/tasks_test.py +73 -56
  42. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/fixtures.py +3 -3
  43. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/harness_test.py +3 -2
  44. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/readability_test.py +8 -7
  45. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/roadmap_test.py +20 -17
  46. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/trial.py +7 -4
  47. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/integration_test.py +40 -51
  48. lemming_cli-0.6.1/src/lemming/main.py +18 -0
  49. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/main_test.py +18 -5
  50. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/models.py +5 -0
  51. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/orchestrator.py +105 -50
  52. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/orchestrator_test.py +261 -136
  53. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/paths.py +52 -0
  54. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/prompts/hooks/50-readability.md +11 -2
  55. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/prompts/hooks/60-testing.md +13 -4
  56. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/prompts/hooks/90-roadmap.md +18 -11
  57. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/prompts/taskrunner.md +39 -14
  58. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/prompts.py +78 -27
  59. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/prompts_test.py +43 -43
  60. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/runner.py +9 -8
  61. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/runner_test.py +54 -47
  62. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/shutdown_integration_test.py +7 -7
  63. lemming_cli-0.6.1/src/lemming/tasks/__init__.py +1 -0
  64. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/tasks/lifecycle.py +57 -4
  65. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/tasks/lifecycle_test.py +29 -1
  66. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/tasks/limits.py +5 -10
  67. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/tasks/operations.py +31 -2
  68. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/tasks/progress.py +3 -5
  69. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/tasks/progress_test.py +2 -2
  70. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/uv.lock +9 -226
  71. lemming_cli-0.5.2/src/lemming/api/__init__.py +0 -5
  72. lemming_cli-0.5.2/src/lemming/api_test.py +0 -7
  73. lemming_cli-0.5.2/src/lemming/cli_test.py +0 -22
  74. lemming_cli-0.5.2/src/lemming/main.py +0 -6
  75. lemming_cli-0.5.2/src/lemming/tasks/__init__.py +0 -108
  76. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/.dockerignore +0 -0
  77. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/.github/workflows/ci.yml +0 -0
  78. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/.github/workflows/publish.yml +0 -0
  79. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/.github/workflows/screenshots.yml +0 -0
  80. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/.gitignore +0 -0
  81. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/.prettierignore +0 -0
  82. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/.prettierrc +0 -0
  83. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/Dockerfile +0 -0
  84. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/LICENSE +0 -0
  85. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/biome.json +0 -0
  86. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/docker-compose.yml +0 -0
  87. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/docs/EVALS.md +0 -0
  88. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/docs/screenshots/dashboard-desktop.png +0 -0
  89. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/docs/screenshots/dashboard-mobile.png +0 -0
  90. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/docs/screenshots/task-log-desktop.png +0 -0
  91. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/docs/screenshots/task-log-mobile.png +0 -0
  92. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/package-lock.json +0 -0
  93. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/package.json +0 -0
  94. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/playwright.config.js +0 -0
  95. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/__init__.py +0 -0
  96. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/auth.py +0 -0
  97. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/context.py +0 -0
  98. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/context_test.py +0 -0
  99. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/directories.py +0 -0
  100. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/files.py +0 -0
  101. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/files_test.py +0 -0
  102. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/hooks.py +0 -0
  103. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/logging.py +0 -0
  104. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/api/main_test.py +0 -0
  105. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/hooks.py +0 -0
  106. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/main.py +0 -0
  107. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/readability_cli.py +0 -0
  108. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/readability_cli_test.py +0 -0
  109. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/cli/skill.py +0 -0
  110. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/conftest.py +0 -0
  111. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/__init__.py +0 -0
  112. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/__main__.py +0 -0
  113. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/cli.py +0 -0
  114. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/cli_test.py +0 -0
  115. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/container.py +0 -0
  116. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/container_test.py +0 -0
  117. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/fixtures_test.py +0 -0
  118. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/harness.py +0 -0
  119. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/metrics.py +0 -0
  120. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/metrics_test.py +0 -0
  121. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/base/README.md +0 -0
  122. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/base/calc/__init__.py +0 -0
  123. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/base/calc/legacy.py +0 -0
  124. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/base/calc/ops.py +0 -0
  125. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/base/calc/ops_test.py +0 -0
  126. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/clean/calc/ops.py +0 -0
  127. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/clean/calc/ops_test.py +0 -0
  128. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/dead-code/calc/ops.py +0 -0
  129. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/dead-code/calc/ops_test.py +0 -0
  130. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/duplicated-behavior/calc/ops.py +0 -0
  131. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/duplicated-behavior/calc/ops_test.py +0 -0
  132. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/false-reuse/calc/limits.py +0 -0
  133. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/false-reuse/calc/limits_test.py +0 -0
  134. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/lint-debt/calc/ops.py +0 -0
  135. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/readability/lint-debt/calc/ops_test.py +0 -0
  136. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/add-only/README.md +0 -0
  137. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/add-only/calc/__init__.py +0 -0
  138. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/add-only/calc/ops.py +0 -0
  139. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/add-only/calc/ops_test.py +0 -0
  140. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/buggy-subtract/README.md +0 -0
  141. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/buggy-subtract/calc/__init__.py +0 -0
  142. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/buggy-subtract/calc/ops.py +0 -0
  143. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/buggy-subtract/calc/ops_test.py +0 -0
  144. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/full-ops/README.md +0 -0
  145. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/full-ops/calc/__init__.py +0 -0
  146. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/full-ops/calc/ops.py +0 -0
  147. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/full-ops/calc/ops_test.py +0 -0
  148. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/unwired-cli/README.md +0 -0
  149. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/unwired-cli/calc/__init__.py +0 -0
  150. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/unwired-cli/calc/cli.py +0 -0
  151. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/unwired-cli/calc/cli_test.py +0 -0
  152. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/unwired-cli/calc/ops.py +0 -0
  153. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/roadmap/unwired-cli/calc/ops_test.py +0 -0
  154. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/task/hidden/stats/summary_hidden_test.py +0 -0
  155. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/task/summary/README.md +0 -0
  156. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/task/summary/stats/__init__.py +0 -0
  157. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/task/summary/stats/summary.py +0 -0
  158. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/projects/task/summary/stats/summary_test.py +0 -0
  159. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/readability.py +0 -0
  160. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/report.py +0 -0
  161. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/report_test.py +0 -0
  162. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/roadmap.py +0 -0
  163. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/scenarios.py +0 -0
  164. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/scenarios_test.py +0 -0
  165. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/suites.py +0 -0
  166. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/task.py +0 -0
  167. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/task_test.py +0 -0
  168. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/evals/trial_test.py +0 -0
  169. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/hooks.py +0 -0
  170. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/hooks_test.py +0 -0
  171. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/models_test.py +0 -0
  172. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/paths_test.py +0 -0
  173. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/persistence.py +0 -0
  174. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/persistence_test.py +0 -0
  175. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/prompts/hooks/70-ux.md +0 -0
  176. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/providers.py +0 -0
  177. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/providers_test.py +0 -0
  178. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/scope.py +0 -0
  179. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/scope_test.py +0 -0
  180. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/shutdown.py +0 -0
  181. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/shutdown_test.py +0 -0
  182. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/tasks/operations_test.py +0 -0
  183. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/tasks/queries.py +0 -0
  184. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/tasks/queries_test.py +0 -0
  185. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/dashboard.spec.js +0 -0
  186. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/dashboard.test.js +0 -0
  187. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/favicon.js +0 -0
  188. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/favicon.spec.js +0 -0
  189. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/files.html +0 -0
  190. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/files.spec.js +0 -0
  191. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/index.html +0 -0
  192. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/index.js +0 -0
  193. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/logs.html +0 -0
  194. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/logs.test.js +0 -0
  195. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/mancha.js +0 -0
  196. {lemming_cli-0.5.2 → lemming_cli-0.6.1}/src/lemming/web/screenshots.spec.js +0 -0
@@ -1,3 +1,23 @@
1
+ Metadata-Version: 2.5
2
+ Name: lemming-cli
3
+ Version: 0.6.1
4
+ Summary: An autonomous, iterative task runner for AI coding agents.
5
+ Project-URL: Homepage, https://github.com/owahltinez/lemming
6
+ Project-URL: Repository, https://github.com/owahltinez/lemming
7
+ Author: Lemming Contributors
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: agents,ai,antigravity,automation,claude,opencode
11
+ Requires-Python: >=3.12
12
+ Requires-Dist: click-agentcli>=0.5.0
13
+ Requires-Dist: click>=8.0.0
14
+ Requires-Dist: fastapi>=0.124.4
15
+ Requires-Dist: pydantic>=2.12.5
16
+ Requires-Dist: pyyaml>=6.0.3
17
+ Requires-Dist: readability-cli>=0.10.4
18
+ Requires-Dist: uvicorn>=0.33.0
19
+ Description-Content-Type: text/markdown
20
+
1
21
  # Lemming 🐹
2
22
 
3
23
  **The transparent, tool-agnostic orchestrator for autonomous AI coding agents.**
@@ -78,6 +98,11 @@ lemming run
78
98
  lemming run -- --model claude-3-5-sonnet
79
99
  ```
80
100
 
101
+ The loop runs every task in one shared workspace, and the orchestrator never
102
+ branches or commits on your behalf. Give the whole run its own branch or
103
+ worktree first if you want to be able to throw it away — see
104
+ [docs/WORKSPACE.md](docs/WORKSPACE.md).
105
+
81
106
  ---
82
107
 
83
108
  ## One-Off Tasks Without a Roadmap
@@ -158,6 +183,8 @@ For Git, stop when the source checkout has modified or untracked files instead
158
183
  of silently excluding them. Retain every isolated working copy until its changes
159
184
  have been recovered. The packaged skill includes a minimal Git example.
160
185
 
186
+ For a roadmap loop, see [docs/WORKSPACE.md](docs/WORKSPACE.md).
187
+
161
188
  ### Teaching Your Agent to Use It
162
189
 
163
190
  Lemming ships an Agent Skill so that an agent already running — Codex, Claude
@@ -246,6 +273,9 @@ conventions control their behavior:
246
273
  runs before `90-roadmap.md`); files without a prefix default to priority 50.
247
274
  - **Failure hooks**: Hooks at priority 90 and above also run when a task fails;
248
275
  all others only run on success.
276
+ - **Oneshot tasks**: A task added with `--oneshot` skips all hooks once it
277
+ completes, so mechanical work (a typo fix, a version bump) does not pay for
278
+ the full review lifecycle. Failure hooks still run if it fails.
249
279
  - **Disabling**: An empty file masks (disables) the hook of the same name from a
250
280
  lower-precedence layer.
251
281
 
@@ -349,17 +379,24 @@ These come before the subcommand and apply to all of them.
349
379
  - `--brief`: Omit task descriptions, which otherwise dominate the output.
350
380
  - **`goal [<text>]`**: Set or view the long-term goal shared by all tasks.
351
381
  Supports `-f/--file`.
352
- - **`add <desc>`**: Append a new task. Supports `--index`, `--runner`, and
353
- `--model`.
354
- - **`edit <id>`**: Modify a task's description, runner, model, or position.
382
+ - **`add <desc>`**: Append a new task. Supports `--index`, `--runner`,
383
+ `--model`, and `--oneshot`.
384
+ - **`edit <id>`**: Modify a task's description, runner, model, position, or
385
+ oneshot flag (`--oneshot/--no-oneshot`).
355
386
  - **`brief <id> [text]`**: View or set a task's long-form brief. Unlike the
356
387
  description it has no length cap, and it is appended to the runner prompt
357
388
  automatically — the right home for measured timings, exact failing selectors,
358
389
  or why a previous attempt was wrong. Supports `-f/--file`.
359
- - **`delete <id>`**: Remove an unstarted task while retaining its runner log.
360
- Tasks with execution history require `--force`; autonomous restructuring
361
- should use `supersede`. Supports `--all` and `--completed` for bulk cleanup,
362
- including logs.
390
+ - **`artifact <id> [name] [text]`**: Store or read a task's verbose
391
+ diagnostics — stack traces, test dumps, long logs — outside `tasks.yml`, so
392
+ they never bloat the prompts of later attempts. With no name it lists what the
393
+ task has stored; with `--note` it also records the one-line progress pointer
394
+ for you. Later attempts see the artifact names in their prompt automatically.
395
+ Supports `-f/--file`.
396
+ - **`delete <id>`**: Remove an unstarted task while retaining its runner log;
397
+ its artifacts go with it. Tasks with execution history require `--force`;
398
+ autonomous restructuring should use `supersede`. Supports `--all` and
399
+ `--completed` for bulk cleanup, including logs.
363
400
  - **`supersede <id> --reason <text>`**: Retire a replaced or split task without
364
401
  losing its progress, timings, log, or links to replacement tasks.
365
402
  - **`progress`**: Manage progress entries and findings for specific tasks.
@@ -468,6 +505,10 @@ lemming -C ~/src/other-project add "check --fix drops the trailing newline"
468
505
  # Attach the evidence; the brief has no length cap
469
506
  lemming -C ~/src/other-project brief <id> --file repro.md
470
507
 
508
+ # Park a failed attempt's output out of band, with a one-line pointer
509
+ lemming -C ~/src/other-project artifact <id> pytest.log --file pytest.log \
510
+ --note 'suite fails in teardown'
511
+
471
512
  # Read the other project's roadmap without leaving yours
472
513
  lemming -C ~/src/other-project status
473
514
  ```
@@ -1,26 +1,3 @@
1
- Metadata-Version: 2.5
2
- Name: lemming-cli
3
- Version: 0.5.2
4
- Summary: An autonomous, iterative task runner for AI coding agents.
5
- Project-URL: Homepage, https://github.com/owahltinez/lemming
6
- Project-URL: Repository, https://github.com/owahltinez/lemming
7
- Author: Lemming Contributors
8
- License: MIT
9
- License-File: LICENSE
10
- Keywords: agents,ai,antigravity,automation,claude,opencode
11
- Requires-Python: >=3.12
12
- Requires-Dist: beautifulsoup4>=4.13.3
13
- Requires-Dist: click-agentcli>=0.4.1
14
- Requires-Dist: click>=8.0.0
15
- Requires-Dist: fastapi>=0.124.4
16
- Requires-Dist: markdownify>=0.14.1
17
- Requires-Dist: pydantic>=2.12.5
18
- Requires-Dist: pyyaml>=6.0.3
19
- Requires-Dist: readability-cli>=0.10.0
20
- Requires-Dist: requests>=2.32.3
21
- Requires-Dist: uvicorn>=0.33.0
22
- Description-Content-Type: text/markdown
23
-
24
1
  # Lemming 🐹
25
2
 
26
3
  **The transparent, tool-agnostic orchestrator for autonomous AI coding agents.**
@@ -101,6 +78,11 @@ lemming run
101
78
  lemming run -- --model claude-3-5-sonnet
102
79
  ```
103
80
 
81
+ The loop runs every task in one shared workspace, and the orchestrator never
82
+ branches or commits on your behalf. Give the whole run its own branch or
83
+ worktree first if you want to be able to throw it away — see
84
+ [docs/WORKSPACE.md](docs/WORKSPACE.md).
85
+
104
86
  ---
105
87
 
106
88
  ## One-Off Tasks Without a Roadmap
@@ -181,6 +163,8 @@ For Git, stop when the source checkout has modified or untracked files instead
181
163
  of silently excluding them. Retain every isolated working copy until its changes
182
164
  have been recovered. The packaged skill includes a minimal Git example.
183
165
 
166
+ For a roadmap loop, see [docs/WORKSPACE.md](docs/WORKSPACE.md).
167
+
184
168
  ### Teaching Your Agent to Use It
185
169
 
186
170
  Lemming ships an Agent Skill so that an agent already running — Codex, Claude
@@ -269,6 +253,9 @@ conventions control their behavior:
269
253
  runs before `90-roadmap.md`); files without a prefix default to priority 50.
270
254
  - **Failure hooks**: Hooks at priority 90 and above also run when a task fails;
271
255
  all others only run on success.
256
+ - **Oneshot tasks**: A task added with `--oneshot` skips all hooks once it
257
+ completes, so mechanical work (a typo fix, a version bump) does not pay for
258
+ the full review lifecycle. Failure hooks still run if it fails.
272
259
  - **Disabling**: An empty file masks (disables) the hook of the same name from a
273
260
  lower-precedence layer.
274
261
 
@@ -372,17 +359,24 @@ These come before the subcommand and apply to all of them.
372
359
  - `--brief`: Omit task descriptions, which otherwise dominate the output.
373
360
  - **`goal [<text>]`**: Set or view the long-term goal shared by all tasks.
374
361
  Supports `-f/--file`.
375
- - **`add <desc>`**: Append a new task. Supports `--index`, `--runner`, and
376
- `--model`.
377
- - **`edit <id>`**: Modify a task's description, runner, model, or position.
362
+ - **`add <desc>`**: Append a new task. Supports `--index`, `--runner`,
363
+ `--model`, and `--oneshot`.
364
+ - **`edit <id>`**: Modify a task's description, runner, model, position, or
365
+ oneshot flag (`--oneshot/--no-oneshot`).
378
366
  - **`brief <id> [text]`**: View or set a task's long-form brief. Unlike the
379
367
  description it has no length cap, and it is appended to the runner prompt
380
368
  automatically — the right home for measured timings, exact failing selectors,
381
369
  or why a previous attempt was wrong. Supports `-f/--file`.
382
- - **`delete <id>`**: Remove an unstarted task while retaining its runner log.
383
- Tasks with execution history require `--force`; autonomous restructuring
384
- should use `supersede`. Supports `--all` and `--completed` for bulk cleanup,
385
- including logs.
370
+ - **`artifact <id> [name] [text]`**: Store or read a task's verbose
371
+ diagnostics — stack traces, test dumps, long logs — outside `tasks.yml`, so
372
+ they never bloat the prompts of later attempts. With no name it lists what the
373
+ task has stored; with `--note` it also records the one-line progress pointer
374
+ for you. Later attempts see the artifact names in their prompt automatically.
375
+ Supports `-f/--file`.
376
+ - **`delete <id>`**: Remove an unstarted task while retaining its runner log;
377
+ its artifacts go with it. Tasks with execution history require `--force`;
378
+ autonomous restructuring should use `supersede`. Supports `--all` and
379
+ `--completed` for bulk cleanup, including logs.
386
380
  - **`supersede <id> --reason <text>`**: Retire a replaced or split task without
387
381
  losing its progress, timings, log, or links to replacement tasks.
388
382
  - **`progress`**: Manage progress entries and findings for specific tasks.
@@ -491,6 +485,10 @@ lemming -C ~/src/other-project add "check --fix drops the trailing newline"
491
485
  # Attach the evidence; the brief has no length cap
492
486
  lemming -C ~/src/other-project brief <id> --file repro.md
493
487
 
488
+ # Park a failed attempt's output out of band, with a one-line pointer
489
+ lemming -C ~/src/other-project artifact <id> pytest.log --file pytest.log \
490
+ --note 'suite fails in teardown'
491
+
494
492
  # Read the other project's roadmap without leaving yours
495
493
  lemming -C ~/src/other-project status
496
494
  ```
@@ -156,6 +156,10 @@ lemming add "Queue writes in IndexedDB while offline"
156
156
  lemming run # runs until the queue drains
157
157
  ```
158
158
 
159
+ The loop shares one workspace across all its tasks, so isolate the **whole run**
160
+ — one branch or worktree created before `lemming run`, driven with
161
+ `lemming -C <worktree> run` — never one per task.
162
+
159
163
  Check on it, and read what an agent actually did:
160
164
 
161
165
  ```sh
@@ -173,7 +177,9 @@ lemming stop --after-current-task # drain, then stop
173
177
 
174
178
  After each task, review hooks run automatically and a roadmap hook may revise
175
179
  the queue. `lemming hooks list` shows them; `lemming hooks disable <name>` turns
176
- one off for the project.
180
+ one off for the project. Queue a mechanical task — a typo fix, a version bump, a
181
+ rename — with `lemming add "..." --oneshot` to skip those hooks when it
182
+ completes.
177
183
 
178
184
  ## What to know before running any of it
179
185
 
@@ -31,6 +31,11 @@ conventions control their behavior:
31
31
  - **Failure hooks**: Hooks at priority 90 and above also run when a task fails.
32
32
  All other hooks only run after successful tasks. The built-in `roadmap` hook
33
33
  ships as `90-roadmap.md` so it can react to failures.
34
+ - **Oneshot tasks**: No hook runs after a task marked `--oneshot` completes,
35
+ keeping mechanical changes cheap. A oneshot task that fails still gets its
36
+ failure hooks, so recovery is never skipped. Note that `roadmap` is skipped
37
+ too: if a oneshot task is the last one in the queue, the run ends without a
38
+ goal audit, so nothing is queued to carry the goal further.
34
39
  - **Masking**: An empty file disables the hook of the same name from a
35
40
  lower-precedence layer (see below). For example, an empty
36
41
  `.lemming/hooks/readability.md` disables the built-in `readability` hook for
@@ -72,6 +77,33 @@ gaps, and exits immediately when the task did not change user-facing behavior.
72
77
  Its prompt instructs the agent to stay advisory, but this is not
73
78
  sandbox-enforced. It runs after `testing` and before `roadmap`.
74
79
 
80
+ ### Rejecting Completion
81
+
82
+ A hook that finds a real defect it cannot fix should not exit 0 and let the
83
+ task be marked completed. It rejects the completion instead:
84
+
85
+ ```bash
86
+ lemming --tasks-file <path> reject <taskid> '<reason>'
87
+ ```
88
+
89
+ A rejection only applies to a task that is finalizing as completed, and it
90
+ does not change the task's status on the spot. The remaining hooks still run
91
+ and see the task as `REJECTED` with the reason, so the roadmap hook can tell
92
+ a rejected task from a finished one. Once every hook has run, the task is
93
+ reverted to pending with its attempt count intact, exactly as it is when a
94
+ hook process fails, and the reason is left in its progress so the next
95
+ attempt starts with the diagnosis.
96
+
97
+ Under `lemming exec` there is no second attempt: the run ends on the first
98
+ rejection, and under `lemming run` a rejection on the task's final attempt
99
+ sends it straight to the exhausted-retries path, where the failure hooks get
100
+ their chance to repair it.
101
+
102
+ Reject only for an objective, reproducible failure the hook could not repair
103
+ itself, such as a failing test suite or a `lemming readability check` that
104
+ still fails. Advisory findings, and anything the hook already fixed, belong
105
+ in `lemming progress`.
106
+
75
107
  ### Reviews Are Not Read-Only
76
108
 
77
109
  When selected with `lemming exec --review`, the hooks above may edit the working
@@ -0,0 +1,120 @@
1
+ # Workspace Isolation 🧰
2
+
3
+ ## Lemming is VCS-Agnostic
4
+
5
+ An agent run writes to a real directory on your disk. The orchestrator never
6
+ creates a branch, a commit, or a worktree, and never reverts anything: it runs
7
+ the agent in a directory and gets out of the way, so whatever a run leaves
8
+ behind — finished work, half-applied edits, scratch files — is what you get. The
9
+ task-runner prompt does allow the agent itself to commit when that is the
10
+ project's convention, but the orchestrator neither asks for that nor relies on
11
+ it.
12
+
13
+ This is deliberate: branching would tie the orchestrator to Git, and Lemming is
14
+ expected to work in a Mercurial repository, a Perforce client, or a plain
15
+ directory under no version control at all. No portable "undo the last run"
16
+ primitive exists across those, so **isolation and recovery are the caller's
17
+ job**. If you need to be able to throw a run away, set that up before it starts.
18
+
19
+ ## Isolating a One-Off `exec` Run
20
+
21
+ Concurrent writing runs must not share a checkout: two agents editing one
22
+ directory interleave their edits, and neither result is reviewable. Give each
23
+ writing run its own working copy and pass it with the global `-C` option
24
+ (`lemming -C <working-copy> -v exec ...`). The full Git worktree recipe is under
25
+ "Isolate concurrent writing runs" in [SKILL.md](../SKILL.md), summarized in the
26
+ [README](../README.md#one-off-tasks-without-a-roadmap).
27
+
28
+ ## Isolating a Roadmap Loop
29
+
30
+ `lemming run` executes its tasks **sequentially in one shared workspace**. Task
31
+ 2 starts in whatever state task 1 left behind — that is the point, since tasks
32
+ build on each other. So the unit of isolation is the whole run: **one branch or
33
+ worktree for the entire loop**, created once before `lemming run`.
34
+
35
+ **Never one branch per task.** Whichever branch the last runner left checked out
36
+ would silently become the next task's baseline, and the loop's history would
37
+ fragment across branches nobody asked for. This is why the task-runner prompt
38
+ says nothing about branching: a runner has no business changing what is checked
39
+ out under it.
40
+
41
+ The minimal Git shape, from a clean tree:
42
+
43
+ ```bash
44
+ repo=$(git rev-parse --show-toplevel) || exit 1
45
+ test -z "$(git -C "$repo" status --porcelain)" || exit 1
46
+
47
+ # One worktree for the whole run, from committed HEAD.
48
+ worktree=$(mktemp -d "${TMPDIR:-/tmp}/lemming-run.XXXXXX") || exit 1
49
+ branch="lemming/$(basename "$worktree")"
50
+ git -C "$repo" worktree add -b "$branch" "$worktree" HEAD || exit 1
51
+
52
+ # Drive the loop against it; -C is a global option, before the subcommand.
53
+ lemming -C "$worktree" goal "<the long-term goal>"
54
+ lemming -C "$worktree" add "<first task>"
55
+ lemming -C "$worktree" -v run
56
+ ```
57
+
58
+ A plain branch (`git switch -c lemming/<run>`) does just as well when nothing
59
+ else needs the checkout; the worktree only buys you the original directory to
60
+ keep working in meanwhile. Either way the roadmap travels with the workspace: a
61
+ tracked `tasks.yml` is copied into the worktree and the loop's edits stay there,
62
+ and without one Lemming keeps isolated state keyed on the worktree path.
63
+
64
+ ## Recovering After an Aborted Run
65
+
66
+ With a pre-run baseline, recovery is ordinary version control, and `-C` reaches
67
+ the run's own records without your having to know where they are stored:
68
+
69
+ ```bash
70
+ git -C "$worktree" status # what the run touched
71
+ git -C "$worktree" log HEAD # commits, if the runners made any
72
+ git -C "$worktree" diff # whatever is still uncommitted
73
+
74
+ lemming -C "$worktree" status # queue, attempts, recorded progress
75
+ lemming -C "$worktree" logs <id> # the full runner log for one task
76
+ ```
77
+
78
+ Keep the branch, or discard it wholesale. There is no partial rollback of one
79
+ task inside a loop — the tasks share a workspace, so their edits are not
80
+ separable unless the runners committed them separately.
81
+
82
+ Runners are also told to write verbose evidence into Lemming's per-project
83
+ scratch directory rather than into the workspace, so a failed task's notes
84
+ survive even after you throw the branch away. It sits under `~/.local/lemming/`
85
+ (or `$LEMMING_HOME`), named for the first 12 hex digits of the SHA-256 of the
86
+ resolved tasks-file path — or of the workspace path, when Lemming is keeping the
87
+ roadmap itself. Once the worktree is gone `-C` can no longer resolve it, and
88
+ `lemming --tasks-file <that dir>/tasks.yml logs <id>` is the way back in.
89
+
90
+ So retain the worktree until its changes have been recovered, then clean up
91
+ non-forcibly, which refuses rather than destroying uncommitted work — including
92
+ a tracked `tasks.yml` the loop has edited, which must be committed or discarded
93
+ first:
94
+
95
+ ```bash
96
+ git -C "$repo" worktree remove "$worktree"
97
+ git -C "$repo" branch -d "$branch"
98
+ ```
99
+
100
+ ## What the Runner Prompt Guarantees
101
+
102
+ Runners are instructed to leave a coherent workspace, to back out their own
103
+ half-applied edits before failing, and never to restore files from version
104
+ control history; the rules live in the "Workspace Hygiene" directive of
105
+ `src/lemming/prompts/taskrunner.md`, not in a copy here. Treat them as a strong
106
+ prior, not a guarantee: runners are LLMs, a prompt is guidance rather than
107
+ enforcement, and a run killed by a timeout never gets to clean up at all. The
108
+ branch or worktree is what actually makes a bad run recoverable; the prompt only
109
+ reduces how often you need it.
110
+
111
+ ## Workspaces Not Under Version Control
112
+
113
+ If the workspace is a plain directory, there is nothing to diff against and
114
+ nothing to reset. **Copy the directory before the run**; that copy is the only
115
+ rollback available.
116
+
117
+ ```bash
118
+ cp -a project project.bak
119
+ lemming -C project run
120
+ ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "lemming-cli"
7
- version = "0.5.2"
7
+ version = "0.6.1"
8
8
  description = "An autonomous, iterative task runner for AI coding agents."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -14,15 +14,12 @@ license = { text = "MIT" }
14
14
  requires-python = ">=3.12"
15
15
  keywords = ["ai", "agents", "automation", "antigravity", "claude", "opencode"]
16
16
  dependencies = [
17
- "beautifulsoup4>=4.13.3",
18
17
  "click>=8.0.0",
19
- "click-agentcli>=0.4.1",
18
+ "click-agentcli>=0.5.0",
20
19
  "fastapi>=0.124.4",
21
- "markdownify>=0.14.1",
22
20
  "pydantic>=2.12.5",
23
21
  "pyyaml>=6.0.3",
24
- "readability-cli>=0.10.0",
25
- "requests>=2.32.3",
22
+ "readability-cli>=0.10.4",
26
23
  "uvicorn>=0.33.0",
27
24
  ]
28
25
 
@@ -49,7 +46,7 @@ Homepage = "https://github.com/owahltinez/lemming"
49
46
  Repository = "https://github.com/owahltinez/lemming"
50
47
 
51
48
  [project.scripts]
52
- lemming = "lemming.main:cli"
49
+ lemming = "lemming.main:main"
53
50
 
54
51
  [tool.hatch.metadata]
55
52
  allow-direct-references = true
@@ -0,0 +1 @@
1
+ """HTTP API for the lemming web UI, built on FastAPI."""
@@ -1,17 +1,17 @@
1
1
  import fastapi.testclient
2
2
 
3
- from lemming import api
3
+ from lemming.api import main
4
4
 
5
5
 
6
6
  def test_share_token_middleware():
7
7
  # Setup test client
8
- original_token = getattr(api.app.state, "share_token", None)
8
+ original_token = getattr(main.app.state, "share_token", None)
9
9
  try:
10
- api.app.state.share_token = "secret123"
10
+ main.app.state.share_token = "secret123"
11
11
  # We need a fresh client for each test that modifies app state
12
12
  # middleware if it uses the app state, but here TestClient is
13
- # created with api.app
14
- client = fastapi.testclient.TestClient(api.app)
13
+ # created with main.app
14
+ client = fastapi.testclient.TestClient(main.app)
15
15
 
16
16
  # Missing token -> 401
17
17
  response = client.get("/api/data")
@@ -36,15 +36,15 @@ def test_share_token_middleware():
36
36
  assert response.status_code == 401, host
37
37
  finally:
38
38
  # Restore
39
- api.app.state.share_token = original_token
39
+ main.app.state.share_token = original_token
40
40
 
41
41
 
42
42
  def test_share_token_middleware_rejects_exotic_tokens():
43
43
  """Odd tokens must be rejected, not crash the comparison."""
44
- original_token = getattr(api.app.state, "share_token", None)
44
+ original_token = getattr(main.app.state, "share_token", None)
45
45
  try:
46
- api.app.state.share_token = "secret123"
47
- client = fastapi.testclient.TestClient(api.app)
46
+ main.app.state.share_token = "secret123"
47
+ client = fastapi.testclient.TestClient(main.app)
48
48
 
49
49
  # Non-ASCII and differing lengths must stay a clean 401. A digest
50
50
  # comparison rejects both only if the values are encoded first.
@@ -53,15 +53,15 @@ def test_share_token_middleware_rejects_exotic_tokens():
53
53
  assert response.status_code == 401, token
54
54
  finally:
55
55
  # Restore
56
- api.app.state.share_token = original_token
56
+ main.app.state.share_token = original_token
57
57
 
58
58
 
59
59
  def test_share_token_middleware_inert_without_token():
60
60
  """Local (non-tunnel) mode sets no share token, so nothing is required."""
61
- original_token = getattr(api.app.state, "share_token", None)
61
+ original_token = getattr(main.app.state, "share_token", None)
62
62
  try:
63
- api.app.state.share_token = None
64
- client = fastapi.testclient.TestClient(api.app)
63
+ main.app.state.share_token = None
64
+ client = fastapi.testclient.TestClient(main.app)
65
65
 
66
66
  response = client.get("/api/data")
67
67
  assert response.status_code == 200
@@ -70,4 +70,4 @@ def test_share_token_middleware_inert_without_token():
70
70
  )
71
71
  finally:
72
72
  # Restore
73
- api.app.state.share_token = original_token
73
+ main.app.state.share_token = original_token
@@ -7,7 +7,8 @@ import sys
7
7
  import fastapi
8
8
  import pydantic
9
9
 
10
- from .. import models, tasks
10
+ from .. import models, persistence
11
+ from ..tasks import operations
11
12
  from . import context
12
13
 
13
14
  router = fastapi.APIRouter()
@@ -25,22 +26,22 @@ def update_goal(
25
26
  ):
26
27
  """Update the long-term goal shared with all task runners."""
27
28
  tasks_file = context.resolve_tasks_file(request.app.state, project)
28
- tasks.update_goal(tasks_file, update.get("goal", ""))
29
+ operations.update_goal(tasks_file, update.get("goal", ""))
29
30
  return {"status": "ok"}
30
31
 
31
32
 
32
33
  @router.post("/api/config")
33
34
  def update_config(
34
35
  request: fastapi.Request,
35
- config: tasks.RoadmapConfig,
36
+ config: models.RoadmapConfig,
36
37
  project: str | None = None,
37
38
  ):
38
39
  """Replace the roadmap configuration and return the saved value."""
39
40
  tasks_file = context.resolve_tasks_file(request.app.state, project)
40
- with tasks.lock_tasks(tasks_file):
41
- data = tasks.load_tasks(tasks_file)
41
+ with persistence.lock_tasks(tasks_file):
42
+ data = persistence.load_tasks(tasks_file)
42
43
  data.config = config
43
- tasks.save_tasks(tasks_file, data)
44
+ persistence.save_tasks(tasks_file, data)
44
45
  return data.config
45
46
 
46
47
 
@@ -1,6 +1,6 @@
1
1
  from unittest.mock import patch
2
2
 
3
- from lemming import api
3
+ from lemming.api import main
4
4
 
5
5
 
6
6
  def test_run_loop(client, test_tasks):
@@ -25,7 +25,7 @@ def test_get_runners(client):
25
25
 
26
26
  def test_project_goal_isolation(client, test_tasks):
27
27
  """The goal is isolated per project."""
28
- root = api.app.state.root
28
+ root = main.app.state.root
29
29
  subdir = root / "goal_test"
30
30
  subdir.mkdir(exist_ok=True)
31
31
 
@@ -50,7 +50,7 @@ def test_project_goal_isolation(client, test_tasks):
50
50
 
51
51
  def test_run_loop_with_project(client, test_tasks):
52
52
  """POST /api/run with project param uses the correct tasks file."""
53
- root = api.app.state.root
53
+ root = main.app.state.root
54
54
  subdir = root / "run_project"
55
55
  subdir.mkdir(exist_ok=True)
56
56
  (subdir / "tasks.yml").touch()