wade-cli 1.2.6__tar.gz → 1.2.7__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 (442) hide show
  1. {wade_cli-1.2.6 → wade_cli-1.2.7}/CHANGELOG.md +6 -0
  2. {wade_cli-1.2.6 → wade_cli-1.2.7}/KNOWLEDGE.ratings.jsonl +2 -0
  3. {wade_cli-1.2.6 → wade_cli-1.2.7}/PKG-INFO +13 -1
  4. {wade_cli-1.2.6 → wade_cli-1.2.7}/README.md +12 -0
  5. {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/architecture.md +48 -0
  6. {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/extending.md +5 -0
  7. {wade_cli-1.2.6 → wade_cli-1.2.7}/pyproject.toml +1 -1
  8. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/__init__.py +1 -1
  9. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/main.py +28 -6
  10. wade_cli-1.2.7/src/wade/models/interactive_plan.py +90 -0
  11. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/base.py +16 -0
  12. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/clickup.py +36 -0
  13. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/github.py +32 -0
  14. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/markdown.py +19 -0
  15. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/draft_pr.py +29 -1
  16. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/interactive_plan_service.py +104 -26
  17. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/knowledge_service.py +73 -9
  18. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/native_plan_service.py +30 -5
  19. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/plan_service.py +1157 -289
  20. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/session_composition_service.py +16 -1
  21. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/plan_validation.py +4 -3
  22. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/safe_state.py +142 -5
  23. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_permission_mode.py +40 -0
  24. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/test_clickup.py +20 -0
  25. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/test_github.py +40 -0
  26. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/test_markdown.py +18 -0
  27. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_ai_resolution.py +10 -7
  28. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_draft_pr_retarget.py +130 -2
  29. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_interactive_plan_service.py +54 -0
  30. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_knowledge_service.py +58 -0
  31. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_native_plan_service.py +21 -0
  32. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_plan_service.py +1439 -59
  33. wade_cli-1.2.7/tests/unit/test_utils/test_safe_state.py +123 -0
  34. {wade_cli-1.2.6 → wade_cli-1.2.7}/uv.lock +1 -1
  35. wade_cli-1.2.6/src/wade/models/interactive_plan.py +0 -35
  36. {wade_cli-1.2.6 → wade_cli-1.2.7}/.gitattributes +0 -0
  37. {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/auto-version.yml +0 -0
  38. {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/ci.yml +0 -0
  39. {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/pr-title-lint.yml +0 -0
  40. {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/publish.yml +0 -0
  41. {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/release.yml +0 -0
  42. {wade_cli-1.2.6 → wade_cli-1.2.7}/.gitignore +0 -0
  43. {wade_cli-1.2.6 → wade_cli-1.2.7}/.pre-commit-config.yaml +0 -0
  44. {wade_cli-1.2.6 → wade_cli-1.2.7}/.wade.yml +0 -0
  45. {wade_cli-1.2.6 → wade_cli-1.2.7}/AGENTS.md +0 -0
  46. {wade_cli-1.2.6 → wade_cli-1.2.7}/CONTRIBUTING.md +0 -0
  47. {wade_cli-1.2.6 → wade_cli-1.2.7}/KNOWLEDGE.md +0 -0
  48. {wade_cli-1.2.6 → wade_cli-1.2.7}/assets/wade.png +0 -0
  49. {wade_cli-1.2.6 → wade_cli-1.2.7}/docker-compose.e2e.yml +0 -0
  50. {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/crossby-native-planning-checkpoint.md +0 -0
  51. {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/documentation-policies.md +0 -0
  52. {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/native-cli-plan-verification.md +0 -0
  53. {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/skills-system.md +0 -0
  54. {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/testing.md +0 -0
  55. {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/workflows-and-skills.md +0 -0
  56. {wade_cli-1.2.6 → wade_cli-1.2.7}/install.sh +0 -0
  57. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/auto_version.py +0 -0
  58. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/changelog.py +0 -0
  59. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/check-all.sh +0 -0
  60. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/check.sh +0 -0
  61. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/fmt.sh +0 -0
  62. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/hooks/pre-push +0 -0
  63. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/install-hooks.sh +0 -0
  64. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/probe_native_plan_handoff.py +0 -0
  65. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/release.sh +0 -0
  66. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/setup-worktree.sh +0 -0
  67. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-concurrency.sh +0 -0
  68. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-e2e-docker.sh +0 -0
  69. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-e2e.sh +0 -0
  70. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-live-ai-taskr.sh +0 -0
  71. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-live-ai.sh +0 -0
  72. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-live-gh.sh +0 -0
  73. {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test.sh +0 -0
  74. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/__main__.py +0 -0
  75. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/__init__.py +0 -0
  76. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/admin.py +0 -0
  77. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/autocomplete.py +0 -0
  78. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/deps_session.py +0 -0
  79. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/hook.py +0 -0
  80. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/implementation_session.py +0 -0
  81. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/knowledge.py +0 -0
  82. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/plan_session.py +0 -0
  83. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/review.py +0 -0
  84. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/review_pr_comments_session.py +0 -0
  85. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/session.py +0 -0
  86. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/session_shared.py +0 -0
  87. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/skills.py +0 -0
  88. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/task.py +0 -0
  89. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/worktree.py +0 -0
  90. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/config/__init__.py +0 -0
  91. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/config/loader.py +0 -0
  92. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/config/migrations.py +0 -0
  93. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/config/schema.py +0 -0
  94. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/__init__.py +0 -0
  95. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/branch.py +0 -0
  96. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/hooks.py +0 -0
  97. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/pr.py +0 -0
  98. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/repo.py +0 -0
  99. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/stash.py +0 -0
  100. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/sync.py +0 -0
  101. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/worktree.py +0 -0
  102. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/hooks/__init__.py +0 -0
  103. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/hooks/cli.py +0 -0
  104. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/hooks/policies.py +0 -0
  105. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/logging/__init__.py +0 -0
  106. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/logging/context.py +0 -0
  107. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/logging/setup.py +0 -0
  108. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/__init__.py +0 -0
  109. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/batch.py +0 -0
  110. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/config.py +0 -0
  111. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/delegation.py +0 -0
  112. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/deps.py +0 -0
  113. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/events.py +0 -0
  114. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/hooks.py +0 -0
  115. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/permission.py +0 -0
  116. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/plan_bundle.py +0 -0
  117. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/readiness.py +0 -0
  118. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/review.py +0 -0
  119. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/review_cycle.py +0 -0
  120. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/session.py +0 -0
  121. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/session_manifest.py +0 -0
  122. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/skill.py +0 -0
  123. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/task.py +0 -0
  124. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/workflow.py +0 -0
  125. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/worktree.py +0 -0
  126. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/__init__.py +0 -0
  127. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/_pr_delegate.py +0 -0
  128. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/registry.py +0 -0
  129. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/__init__.py +0 -0
  130. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/ai_resolution.py +0 -0
  131. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/batch_review_service.py +0 -0
  132. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/bot_trigger.py +0 -0
  133. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/check_service.py +0 -0
  134. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/delegation_service.py +0 -0
  135. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/deps_service.py +0 -0
  136. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/documentation_receipt_service.py +0 -0
  137. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/__init__.py +0 -0
  138. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/_shared.py +0 -0
  139. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/batch.py +0 -0
  140. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/bootstrap.py +0 -0
  141. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/cleanup.py +0 -0
  142. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/core.py +0 -0
  143. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/done.py +0 -0
  144. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/lifecycle.py +0 -0
  145. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/sync.py +0 -0
  146. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/usage_tracking.py +0 -0
  147. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/__init__.py +0 -0
  148. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/auth.py +0 -0
  149. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/commands.py +0 -0
  150. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/config_io.py +0 -0
  151. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/manifest.py +0 -0
  152. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/migrations.py +0 -0
  153. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/prompts_ai.py +0 -0
  154. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/prompts_setup.py +0 -0
  155. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/shell.py +0 -0
  156. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/knowledge_recovery.py +0 -0
  157. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/knowledge_search.py +0 -0
  158. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/prompt_delivery.py +0 -0
  159. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_cycle_service.py +0 -0
  160. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_delegation_service.py +0 -0
  161. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_record_service.py +0 -0
  162. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_service.py +0 -0
  163. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_settle.py +0 -0
  164. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/skill_diagnostics_service.py +0 -0
  165. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/skill_invocation_service.py +0 -0
  166. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/smart_start.py +0 -0
  167. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/task_service.py +0 -0
  168. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/__init__.py +0 -0
  169. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/catalog.py +0 -0
  170. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/discovery.py +0 -0
  171. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/doc_targets.py +0 -0
  172. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/installer.py +0 -0
  173. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/materializer.py +0 -0
  174. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/pointer.py +0 -0
  175. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/resolver.py +0 -0
  176. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/validation.py +0 -0
  177. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/ui/__init__.py +0 -0
  178. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/ui/console.py +0 -0
  179. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/ui/prompts.py +0 -0
  180. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/__init__.py +0 -0
  181. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/body_markers.py +0 -0
  182. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/clipboard.py +0 -0
  183. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/conventional.py +0 -0
  184. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/filelock.py +0 -0
  185. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/gitref.py +0 -0
  186. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/http.py +0 -0
  187. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/install.py +0 -0
  188. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/knowledge_file.py +0 -0
  189. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/markdown.py +0 -0
  190. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/markers.py +0 -0
  191. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/paths.py +0 -0
  192. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/process.py +0 -0
  193. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/runtime_env.py +0 -0
  194. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/slug.py +0 -0
  195. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/stale_base.py +0 -0
  196. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/templates.py +0 -0
  197. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/terminal.py +0 -0
  198. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/token_usage_markdown.py +0 -0
  199. {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/update_check.py +0 -0
  200. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/agents-pointer.md +0 -0
  201. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/hooks/commit-msg +0 -0
  202. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/hooks/pre-commit +0 -0
  203. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/hooks/pre-push +0 -0
  204. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/deps-analysis.md +0 -0
  205. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/implement-context.md +0 -0
  206. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/plan-session.md +0 -0
  207. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-batch.md +0 -0
  208. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-code.md +0 -0
  209. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-finding-admission.md +0 -0
  210. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-plan.md +0 -0
  211. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-pr-comments.md +0 -0
  212. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-batch.md +0 -0
  213. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-code.md +0 -0
  214. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-deps.md +0 -0
  215. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-full-branch.md +0 -0
  216. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-implementation.md +0 -0
  217. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-plan.md +0 -0
  218. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-pr-comments.md +0 -0
  219. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/session-start-implement.md +0 -0
  220. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/session-start-plan.md +0 -0
  221. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/session-start-review.md +0 -0
  222. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/setup-worktree.sh.example +0 -0
  223. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/batch-review/SKILL.md +0 -0
  224. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/code-review/SKILL.md +0 -0
  225. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/dependency-analysis/SKILL.md +0 -0
  226. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/feedback-fix-review/SKILL.md +0 -0
  227. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/implementation/SKILL.md +0 -0
  228. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/knowledge/SKILL.md +0 -0
  229. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/plan-review/SKILL.md +0 -0
  230. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/planning/SKILL.md +0 -0
  231. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/review-comments/SKILL.md +0 -0
  232. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/task/SKILL.md +0 -0
  233. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/task/examples.md +0 -0
  234. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/task/plan-format.md +0 -0
  235. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/task/reference/session-summary-format.md +0 -0
  236. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/statusline-command.sh +0 -0
  237. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/completion.md +0 -0
  238. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/documentation-step.md +0 -0
  239. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/interaction-policy.md +0 -0
  240. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/knowledge-step.md +0 -0
  241. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/review-budget.md +0 -0
  242. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/implementation.md +0 -0
  243. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/plan.md +0 -0
  244. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/documentation.md +0 -0
  245. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/new-plan.md +0 -0
  246. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/plan-output-contract.md +0 -0
  247. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/pr-summary-format.md +0 -0
  248. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/recovery.md +0 -0
  249. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/session-summary-format.md +0 -0
  250. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/tracking-issues.md +0 -0
  251. {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/review-pr-comments.md +0 -0
  252. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/__init__.py +0 -0
  253. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/__init__.py +0 -0
  254. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/test_batch_multi_pr.py +0 -0
  255. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/test_knowledge_merge.py +0 -0
  256. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/test_lock_retry.py +0 -0
  257. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/test_stash_race.py +0 -0
  258. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/conftest.py +0 -0
  259. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/__init__.py +0 -0
  260. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/_support.py +0 -0
  261. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/conftest.py +0 -0
  262. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/mock_gh_script.py +0 -0
  263. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_admin_contract.py +0 -0
  264. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_check_contract.py +0 -0
  265. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_implement_work_done_contract.py +0 -0
  266. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_knowledge_contract.py +0 -0
  267. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_mock_gh_contract.py +0 -0
  268. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_plan_contract.py +0 -0
  269. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_review_contract.py +0 -0
  270. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_smart_start_contract.py +0 -0
  271. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_task_contract.py +0 -0
  272. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_work_sync_list_contract.py +0 -0
  273. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/live/taskr_header_hi_body.md +0 -0
  274. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/live/taskr_header_howdy_body.md +0 -0
  275. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/transcripts/claude_session.txt +0 -0
  276. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/transcripts/codex_session.txt +0 -0
  277. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/transcripts/copilot_session.txt +0 -0
  278. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/transcripts/generic_session.txt +0 -0
  279. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/__init__.py +0 -0
  280. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_autostash.py +0 -0
  281. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_check.py +0 -0
  282. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_dynamic_skill_sessions.py +0 -0
  283. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_git.py +0 -0
  284. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_implementation_lifecycle.py +0 -0
  285. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_init.py +0 -0
  286. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_knowledge.py +0 -0
  287. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_markdown_provider.py +0 -0
  288. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_skill_context_budget.py +0 -0
  289. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_skill_install.py +0 -0
  290. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/live/__init__.py +0 -0
  291. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/live/test_wade_live_ai.py +0 -0
  292. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/live/test_wade_live_ai_taskr.py +0 -0
  293. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/live/test_wade_live_gh.py +0 -0
  294. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/test_cli_basics.py +0 -0
  295. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/__init__.py +0 -0
  296. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/conftest.py +0 -0
  297. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/__init__.py +0 -0
  298. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_autocomplete.py +0 -0
  299. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_done_doc_pass_advisory.py +0 -0
  300. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_done_review_hint.py +0 -0
  301. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_knowledge_cli.py +0 -0
  302. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_review_cli.py +0 -0
  303. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_session_subapps.py +0 -0
  304. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_shell_init.py +0 -0
  305. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_skills_session_cli.py +0 -0
  306. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_task_cli.py +0 -0
  307. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_work_ai_flags.py +0 -0
  308. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_work_cli.py +0 -0
  309. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/__init__.py +0 -0
  310. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_bot_review_config.py +0 -0
  311. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_dynamic_skill_config.py +0 -0
  312. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_loader.py +0 -0
  313. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_merge_strategy_migration.py +0 -0
  314. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_migrations.py +0 -0
  315. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_migrations_atomic.py +0 -0
  316. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_console.py +0 -0
  317. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_effort.py +0 -0
  318. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/__init__.py +0 -0
  319. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_all_patches_present.py +0 -0
  320. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_branch_list.py +0 -0
  321. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_branch_slugify.py +0 -0
  322. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_detached_worktree.py +0 -0
  323. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_is_merged_into.py +0 -0
  324. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_main_checkout_root.py +0 -0
  325. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_merge_count.py +0 -0
  326. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_pr_base.py +0 -0
  327. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_pr_lookup.py +0 -0
  328. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_pr_retry.py +0 -0
  329. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_pr_title.py +0 -0
  330. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_repo.py +0 -0
  331. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_reset_branch.py +0 -0
  332. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_scaffold_commit.py +0 -0
  333. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_stash_drop.py +0 -0
  334. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_sync_conflicted_files.py +0 -0
  335. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_tip_commit_is_empty.py +0 -0
  336. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_worktree_remove.py +0 -0
  337. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/__init__.py +0 -0
  338. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/test_hook_cli.py +0 -0
  339. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/test_policies.py +0 -0
  340. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/test_post_tool_use.py +0 -0
  341. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/test_session_start.py +0 -0
  342. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/__init__.py +0 -0
  343. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_batch.py +0 -0
  344. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_config_models.py +0 -0
  345. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_delegation.py +0 -0
  346. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_deps_models.py +0 -0
  347. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_deps_partition.py +0 -0
  348. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_review.py +0 -0
  349. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_review_expectation.py +0 -0
  350. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_task_models.py +0 -0
  351. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_workflow_models.py +0 -0
  352. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/__init__.py +0 -0
  353. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/test_github_pr.py +0 -0
  354. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_scripts/__init__.py +0 -0
  355. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_scripts/test_changelog.py +0 -0
  356. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/__init__.py +0 -0
  357. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_batch_build_cmd.py +0 -0
  358. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_batch_pr_index.py +0 -0
  359. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_batch_review_service.py +0 -0
  360. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_allowlist.py +0 -0
  361. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_guard_matcher.py +0 -0
  362. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_hook_timeout.py +0 -0
  363. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_post_tool_use.py +0 -0
  364. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_pre_push.py +0 -0
  365. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_session_start.py +0 -0
  366. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bot_trigger.py +0 -0
  367. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_catchup.py +0 -0
  368. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_catchup_reconcile.py +0 -0
  369. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_check.py +0 -0
  370. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_cleanup_loss_guard.py +0 -0
  371. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_codex_worktree_launch_context.py +0 -0
  372. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_delegation_service.py +0 -0
  373. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_deps_service.py +0 -0
  374. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_documentation_receipt.py +0 -0
  375. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_done_gates.py +0 -0
  376. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_done_idempotent.py +0 -0
  377. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_done_plan_flag.py +0 -0
  378. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_done_pr_title_sync.py +0 -0
  379. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_draft_pr_base_fetch.py +0 -0
  380. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_implementation_done_sync.py +0 -0
  381. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_implementation_launch_context.py +0 -0
  382. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_implementation_service.py +0 -0
  383. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_implementation_service_resume.py +0 -0
  384. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_init.py +0 -0
  385. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_init_shell_integration.py +0 -0
  386. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_knowledge_recovery.py +0 -0
  387. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_knowledge_search.py +0 -0
  388. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_managed_git_hooks.py +0 -0
  389. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_no_direct_git.py +0 -0
  390. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_plan_startup_events.py +0 -0
  391. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_poll_for_reviews.py +0 -0
  392. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_post_implementation_lifecycle.py +0 -0
  393. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_pr_lookup_guards.py +0 -0
  394. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_pr_summary_path.py +0 -0
  395. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_pre_push_backstop.py +0 -0
  396. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_preserve_session_data.py +0 -0
  397. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_prompt_delivery.py +0 -0
  398. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_push_recovery.py +0 -0
  399. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_resolve_task_branch.py +0 -0
  400. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_resume_autonomy.py +0 -0
  401. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_cycle_service.py +0 -0
  402. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_delegation_service.py +0 -0
  403. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_receipts.py +0 -0
  404. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_records.py +0 -0
  405. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_service.py +0 -0
  406. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_status_block.py +0 -0
  407. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_skill_diagnostics_service.py +0 -0
  408. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_skill_invocation_service.py +0 -0
  409. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_smart_start.py +0 -0
  410. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_smart_start_resume.py +0 -0
  411. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_stale_base_surface.py +0 -0
  412. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_sync_base_branch.py +0 -0
  413. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_task_service.py +0 -0
  414. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_tracked_managed_files.py +0 -0
  415. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_worktree_gitignore.py +0 -0
  416. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_crossby_contract.py +0 -0
  417. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_doc_targets.py +0 -0
  418. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_dynamic_skills.py +0 -0
  419. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_generic_builtin_boundaries.py +0 -0
  420. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_knowledge_attributes.py +0 -0
  421. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_managed_gitignore.py +0 -0
  422. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_pointer.py +0 -0
  423. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_review_budget_partial.py +0 -0
  424. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/__init__.py +0 -0
  425. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_body_markers.py +0 -0
  426. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_conventional.py +0 -0
  427. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_filelock.py +0 -0
  428. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_gitref.py +0 -0
  429. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_http.py +0 -0
  430. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_install.py +0 -0
  431. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_markdown.py +0 -0
  432. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_markers.py +0 -0
  433. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_plan_validation.py +0 -0
  434. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_process.py +0 -0
  435. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_prompts.py +0 -0
  436. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_runtime_env.py +0 -0
  437. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_slug.py +0 -0
  438. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_stale_base.py +0 -0
  439. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_terminal.py +0 -0
  440. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_terminal_launch.py +0 -0
  441. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_update_check.py +0 -0
  442. {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_yolo.py +0 -0
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Conventional Commits](https://conventionalcommits.org/).
6
6
 
7
+ ## [v1.2.7] — 2026-09-25
8
+
9
+ ### Bug Fixes
10
+
11
+ - preserve and recover completed handoffs after filesystem access denial (#516) (dc83f62)
12
+
7
13
  ## [v1.2.6] — 2026-09-23
8
14
 
9
15
  ### Chores
@@ -190,3 +190,5 @@
190
190
  {"dir": "up", "event_id": "66056751a7824f6bb780f4974e2e2d7d", "id": "b08abb58", "ts": "2026-09-15T15:24:18.781881+00:00"}
191
191
  {"dir": "up", "event_id": "86b45a2f2bf74f0c8736e3ce9c7a7642", "id": "40a26d7cfd61", "ts": "2026-09-15T15:24:18.938217+00:00"}
192
192
  {"dir": "stale", "event_id": "86da7ec333234953869f880b857ce682", "id": "6cd9b543", "ts": "2026-09-15T15:24:19.088735+00:00"}
193
+ {"dir": "up", "event_id": "5bf57cae39ae477f9295c18a3ac6d6c9", "id": "7c6526983755", "ts": "2026-09-16T22:22:59.183519+00:00"}
194
+ {"dir": "up", "event_id": "6cccca145ffa471abd9ee11f3c2d259b", "id": "2bc8b5ab31d3", "ts": "2026-09-24T18:50:40.963016+00:00"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: wade-cli
3
- Version: 1.2.6
3
+ Version: 1.2.7
4
4
  Summary: WADE — Workflow for AI-Driven Engineering
5
5
  Project-URL: Homepage, https://github.com/ivanviragine/wade
6
6
  Project-URL: Repository, https://github.com/ivanviragine/wade
@@ -344,6 +344,18 @@ Native terminal output is retained for recovery; usage is reported only when
344
344
  the adapter can extract it from that output. WADE's handoff ID is not a native
345
345
  CLI session ID.
346
346
 
347
+ If the OS denies the parent access after the terminal exits, WADE reports the
348
+ permission failure instead of calling the handoff absent, leaves the detached
349
+ planning worktree intact, and prints a recovery command. Restore filesystem
350
+ access, then run `wade plan --recover <planning-worktree>` from the source repo.
351
+ Recovery does not launch an AI or regenerate content: it accepts only a retained
352
+ registered detached worktree, then rechecks the frozen bindings, completed state,
353
+ exact plan content, review receipts, dependencies, and plan validation before any
354
+ task/provider write. It rejects a handoff whose original launch binding was never
355
+ durably recorded rather than applying settings changed after collection. If even the plans directory cannot be enumerated, WADE says
356
+ the retained plan count is unknown rather than reporting zero. WADE never changes
357
+ OS privacy or sandbox settings for you.
358
+
347
359
  `wade plan --issue <N>` re-plans an existing task. If the session produces a
348
360
  single plan file, it's attached to `#N` and the task stays open. If the
349
361
  session decides the work should be split into several independent pieces
@@ -308,6 +308,18 @@ Native terminal output is retained for recovery; usage is reported only when
308
308
  the adapter can extract it from that output. WADE's handoff ID is not a native
309
309
  CLI session ID.
310
310
 
311
+ If the OS denies the parent access after the terminal exits, WADE reports the
312
+ permission failure instead of calling the handoff absent, leaves the detached
313
+ planning worktree intact, and prints a recovery command. Restore filesystem
314
+ access, then run `wade plan --recover <planning-worktree>` from the source repo.
315
+ Recovery does not launch an AI or regenerate content: it accepts only a retained
316
+ registered detached worktree, then rechecks the frozen bindings, completed state,
317
+ exact plan content, review receipts, dependencies, and plan validation before any
318
+ task/provider write. It rejects a handoff whose original launch binding was never
319
+ durably recorded rather than applying settings changed after collection. If even the plans directory cannot be enumerated, WADE says
320
+ the retained plan count is unknown rather than reporting zero. WADE never changes
321
+ OS privacy or sandbox settings for you.
322
+
311
323
  `wade plan --issue <N>` re-plans an existing task. If the session produces a
312
324
  single plan file, it's attached to `#N` and the task stays open. If the
313
325
  session decides the work should be split into several independent pieces
@@ -256,6 +256,54 @@ The legacy file-presence Stop nudge is not installed; correctness depends on the
256
256
  completion and parent gates, not ambient hooks. Collected transports may exclude
257
257
  ambient settings; native terminals use their ordinary launch behavior.
258
258
 
259
+ Parent collection uses the additive strict `safe_state` read/list API. The
260
+ legacy API continues to collapse unsafe or unreadable state to `None` for review
261
+ receipts, review cycles, documentation receipts, and other established callers;
262
+ the strict path preserves `EACCES`/`EPERM` as `StateFileAccessError` while keeping
263
+ the same descriptor-relative `O_NOFOLLOW`, regular-file, and byte-limit checks.
264
+ An access denial after native exit causes no provider mutation and never enters
265
+ normal worktree cleanup. Enumeration denial reports an unknown plan count and
266
+ retains the original detached worktree. `wade plan --recover <worktree>` accepts
267
+ only a detached worktree still registered with the current repo, skips launch,
268
+ reloads its frozen plan manifest and explicit completed handoff, and reruns
269
+ binding, content, review, dependency, and strict plan-validation gates before
270
+ persistence. Successful recovery resumes the ordinary finalization and cleanup
271
+ path; WADE does not invoke platform privacy tools or weaken sandbox policy.
272
+
273
+ Recovery is idempotent because its launch binding and persistence are recorded as
274
+ they happen. Before a managed planner launches, its worktree gets
275
+ `.wade/plans/handoff-binding.json` (`PlanHandoffBinding`) with the resolved
276
+ model, complete provider configuration, project task-persistence settings, and
277
+ complete knowledge configuration. Recovery rejects a retained handoff without
278
+ that binding rather than synthesizing one from settings that may have changed
279
+ after collection. After collection and before any provider mutation, the worktree
280
+ gets `.wade/plans/handoff-progress.json` (`PlanHandoffProgress`), keyed to the
281
+ completed handoff's session id; it binds the vote set, a pending per-plan marker,
282
+ and a per-plan-file to task-id mapping written after each issue and draft PR
283
+ become durable. Each persisted mapping also records a digest of the exact plan
284
+ content in its draft PR, so a later review edit rejects reuse instead of letting
285
+ task metadata and the retained PR diverge. Recovery validates the provider
286
+ configuration before it instantiates or uses a provider, and reuses the original
287
+ project and knowledge settings rather than silently applying changed values. The
288
+ vote set is bound before staging, so a revised retained artifact cannot reuse a
289
+ previously delivered event ID with a different direction. The pending marker is
290
+ placed in the task's initial hidden body before creation, so a post-creation
291
+ progress-write failure can recover the exact task instead of guessing from its
292
+ title or creating a duplicate. Before recovery renames a task to its reviewed
293
+ plan title, it also records the original branch-forming title, so a rename whose
294
+ response or later progress write fails still refreshes the existing draft PR
295
+ instead of creating one from the new title. A later finalization or cleanup
296
+ failure therefore
297
+ leaves a retry reusing those tasks — and the original model for `planned-by`
298
+ provenance — instead of creating duplicates; a partial finalization with a
299
+ pending marker retains the original worktree for the same reconciliation path.
300
+ Attaching a plan to an existing issue is idempotent for the same reason:
301
+ `bootstrap_draft_pr` reuses the open PR, and the plan link is appended only when
302
+ the issue body lacks it. Recovery refreshes that PR's managed plan body before
303
+ accepting the attachment, so an approved recovery edit cannot be lost. A binding
304
+ or progress file that is unsafe, invalid, missing required data, or bound to
305
+ another session aborts recovery rather than being silently replaced.
306
+
259
307
  ## Hook Guard Layer
260
308
 
261
309
  wade installs AI-tool hooks that enforce session rules in *code* rather than
@@ -43,6 +43,11 @@ The provider system uses `AbstractTaskProvider` ABC (`src/wade/providers/base.py
43
43
  3. Add the provider ID to `ProviderID` enum in `models/config.py`
44
44
  4. Register the provider in `providers/__init__.py` via `register_provider(ProviderID.YOUR_ID, YourProvider)` (use a lazy loader for optional dependencies)
45
45
 
46
+ Providers that support planning handoff recovery must also implement
47
+ `find_tasks_by_body_marker`. It must exhaustively search the provider's open
48
+ tasks for the exact durable marker; a bounded task-list page can miss a task
49
+ created before a local recovery-progress write failed, causing a duplicate.
50
+
46
51
  Non-GitHub providers (ClickUp, Markdown) still need PRs and PR-review APIs, which are GitHub-only. They get these by composing `GitHubPRDelegateMixin` (`providers/_pr_delegate.py`), which routes PR/review calls through `gh` while task CRUD stays on the provider's own backend.
47
52
 
48
53
  ## Version Bumping
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "wade-cli"
7
- version = "1.2.6"
7
+ version = "1.2.7"
8
8
  description = "WADE — Workflow for AI-Driven Engineering"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,3 +1,3 @@
1
1
  """WADE (Workflow for AI-Driven Engineering) — AI-agent-driven git workflow management CLI."""
2
2
 
3
- __version__ = "1.2.6"
3
+ __version__ = "1.2.7"
@@ -9,6 +9,7 @@ import typer
9
9
 
10
10
  import wade
11
11
  from wade.config.loader import ConfigError
12
+ from wade.services.ai_resolution import LAUNCH_NETWORK_ACCESS
12
13
 
13
14
  app = typer.Typer(
14
15
  name="wade",
@@ -233,6 +234,11 @@ _SANDBOX_OPT = typer.Option(
233
234
  @app.command("plan", rich_help_panel="Workflow")
234
235
  def plan_cmd(
235
236
  issue: str | None = typer.Option(None, "--issue", "-i", help="Plan an existing issue by ID."),
237
+ recover: Path | None = typer.Option( # noqa: B008
238
+ None,
239
+ "--recover",
240
+ help="Revalidate and consume a retained completed planning worktree.",
241
+ ),
236
242
  ai: str | None = typer.Option(
237
243
  None, "--ai", help="AI tool to use for planning.", autocompletion=complete_ai_tools
238
244
  ),
@@ -308,6 +314,7 @@ def plan_cmd(
308
314
  approval_policy=approval_policy,
309
315
  trusted_dirs=trusted_dir,
310
316
  timeout=timeout,
317
+ recover=recover,
311
318
  )
312
319
  raise typer.Exit(0 if success else 1)
313
320
 
@@ -620,6 +627,7 @@ def smart_start_cmd(
620
627
  @app.command("p", hidden=True)
621
628
  def plan_alias(
622
629
  issue: str | None = typer.Option(None, "--issue", "-i", help="Plan an existing issue by ID."),
630
+ recover: Path | None = typer.Option(None, "--recover"), # noqa: B008
623
631
  ai: str | None = typer.Option(
624
632
  None, "--ai", help="AI tool to use for planning.", autocompletion=complete_ai_tools
625
633
  ),
@@ -640,18 +648,32 @@ def plan_alias(
640
648
  refresh_skills: bool = typer.Option(False, "--refresh-skills"),
641
649
  ) -> None:
642
650
  """Alias for plan."""
643
- plan_cmd(
644
- issue=issue,
645
- ai=ai,
651
+ from wade.services.plan_service import plan as do_plan
652
+
653
+ success = do_plan(
654
+ ai_tool=ai,
646
655
  model=model,
656
+ issue_id=issue,
657
+ ai_explicit=ai is not None,
658
+ model_explicit=model is not None,
647
659
  effort=effort,
648
- yolo=yolo,
660
+ effort_explicit=effort is not None,
661
+ yolo=yolo or None,
649
662
  permission_mode=permission_mode,
650
663
  sandbox=sandbox,
651
- skill=skill,
652
- review_skill=review_skill,
664
+ work_skills=skill,
665
+ review_skills=review_skill,
653
666
  refresh_skills=refresh_skills,
667
+ recover=recover,
668
+ # The short alias preserves the retired collector launch default, but
669
+ # must not turn it into an unsupported native-terminal requirement.
670
+ network_access=None,
671
+ collector_network_access=None if recover is not None else LAUNCH_NETWORK_ACCESS,
672
+ approval_policy="on-request",
673
+ trusted_dirs=None,
674
+ timeout=None,
654
675
  )
676
+ raise typer.Exit(0 if success else 1)
655
677
 
656
678
 
657
679
  @app.command("i", hidden=True)
@@ -0,0 +1,90 @@
1
+ """WADE-owned handoff from an ordinary native planning terminal."""
2
+
3
+ from typing import Literal
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+
7
+ from wade.models.config import KnowledgeConfig, ProjectSettings, ProviderConfig
8
+ from wade.models.plan_bundle import PlanBundle, PlanKnowledgeVote
9
+
10
+
11
+ class InteractivePlanState(BaseModel):
12
+ model_config = ConfigDict(extra="forbid")
13
+
14
+ version: Literal[1] = 1
15
+ session_id: str
16
+ tool: str
17
+ model: str | None = None
18
+ effort: str | None = None
19
+ sandbox: bool | None = None
20
+ review_required: bool
21
+ knowledge_required: bool = False
22
+ bundle_digest: str
23
+ bundle: PlanBundle | None = None
24
+ completed: bool = False
25
+
26
+
27
+ class PlanHandoffProgress(BaseModel):
28
+ """Durable parent-side progress for one completed planning handoff."""
29
+
30
+ model_config = ConfigDict(extra="forbid")
31
+
32
+ version: Literal[1] = 1
33
+ session_id: str
34
+ model: str | None = None
35
+ # The external task identities below are meaningful only for these exact
36
+ # settings. Optional fields let old retained files parse so recovery can
37
+ # reject their missing binding with a clear, safe error.
38
+ provider: ProviderConfig | None = None
39
+ project: ProjectSettings | None = None
40
+ knowledge: KnowledgeConfig | None = None
41
+ knowledge_required: bool | None = None
42
+ # The original vote set is persisted before staging any vote. This prevents
43
+ # a recovered artifact with the same session ID from changing a vote while
44
+ # retaining its already-delivered event identity.
45
+ knowledge_votes: tuple[PlanKnowledgeVote, ...] | None = None
46
+ persisted_issues: dict[str, str] = Field(default_factory=dict)
47
+ # Each persisted task's draft PR contains this exact plan content. Recovery
48
+ # must reject a reviewed edit rather than reusing the task with a stale PR.
49
+ persisted_plan_digests: dict[str, str] = Field(default_factory=dict)
50
+ # A task body carries each marker before its external creation. If the
51
+ # following local progress write fails, recovery can find that exact task
52
+ # instead of creating a duplicate.
53
+ pending_issue_markers: dict[str, str] = Field(default_factory=dict)
54
+ # A recovered task may be renamed to match a reviewed plan after its draft
55
+ # PR has been created. Retain the pre-rename title that identifies that PR's
56
+ # branch until the task/PR mapping is durably persisted, so a retry does not
57
+ # derive a second branch from the new task title.
58
+ pending_issue_branch_titles: dict[str, str] = Field(default_factory=dict)
59
+ # Once every split-plan task is durable, the original task's visible
60
+ # supersede actions are recorded before finalization. Recovery can then
61
+ # resume finalization without posting the comment or closing it again.
62
+ superseded_issue_ids: list[str] = Field(default_factory=list)
63
+
64
+
65
+ class PlanHandoffBinding(BaseModel):
66
+ """Immutable launch settings required to safely recover a completed handoff."""
67
+
68
+ model_config = ConfigDict(extra="forbid")
69
+
70
+ version: Literal[1] = 1
71
+ model: str | None = None
72
+ provider: ProviderConfig
73
+ project: ProjectSettings
74
+ knowledge: KnowledgeConfig
75
+ knowledge_required: bool
76
+
77
+
78
+ class InteractivePlanReview(BaseModel):
79
+ model_config = ConfigDict(extra="forbid")
80
+
81
+ session_id: str
82
+ bundle_digest: str
83
+ content_digest: str
84
+ self_review_pending: bool = False
85
+
86
+
87
+ class InteractivePlanReviews(BaseModel):
88
+ model_config = ConfigDict(extra="forbid")
89
+
90
+ plans: dict[str, InteractivePlanReview] = Field(default_factory=dict)
@@ -84,6 +84,22 @@ class AbstractTaskProvider(ABC):
84
84
  ) -> Task:
85
85
  """Update task title and/or body."""
86
86
 
87
+ def find_tasks_by_body_marker(
88
+ self,
89
+ marker: str,
90
+ label: str | None = None,
91
+ state: TaskState | None = TaskState.OPEN,
92
+ ) -> list[Task]:
93
+ """Exhaustively find tasks whose body contains an exact durable marker.
94
+
95
+ Implementations must not apply a caller-visible task-list limit. This is
96
+ used only for recovery markers, where silently missing a matching task
97
+ could create a duplicate external task.
98
+ """
99
+ raise NotImplementedError(
100
+ "This task provider cannot safely reconcile planning handoff markers"
101
+ )
102
+
87
103
  @abstractmethod
88
104
  def close_task(self, task_id: str, reason: CloseReason | None = None) -> Task:
89
105
  """Close a task, optionally with a typed reason (e.g. GitHub's "not planned").
@@ -171,6 +171,42 @@ class ClickUpProvider(GitHubPRDelegateMixin, AbstractTaskProvider):
171
171
 
172
172
  return tasks
173
173
 
174
+ def find_tasks_by_body_marker(
175
+ self,
176
+ marker: str,
177
+ label: str | None = None,
178
+ state: TaskState | None = TaskState.OPEN,
179
+ ) -> list[Task]:
180
+ """Exhaustively scan the configured list for one recovery marker."""
181
+ matches: list[Task] = []
182
+ page = 0
183
+ while True:
184
+ params: dict[str, Any] = {
185
+ "page": str(page),
186
+ "subtasks": "false",
187
+ "include_closed": "true" if state is None or state == TaskState.CLOSED else "false",
188
+ "list_ids[]": self._list_id,
189
+ }
190
+ if label:
191
+ params["tags[]"] = label
192
+ data = self._client.get(
193
+ f"/api/v2/team/{self._team_id}/task",
194
+ params=params,
195
+ )
196
+ raw_tasks: list[dict[str, Any]] = data.get("tasks", [])
197
+ if not raw_tasks:
198
+ break
199
+ for raw in raw_tasks:
200
+ task = _parse_clickup_task(raw)
201
+ if state is not None and task.state != state:
202
+ continue
203
+ if marker in task.body:
204
+ matches.append(task)
205
+ if len(raw_tasks) < self._PAGE_SIZE:
206
+ break
207
+ page += 1
208
+ return matches
209
+
174
210
  def create_task(
175
211
  self,
176
212
  title: str,
@@ -129,6 +129,38 @@ class GitHubProvider(AbstractTaskProvider):
129
129
  raw_list = json.loads(result.stdout)
130
130
  return [_parse_gh_task(item) for item in raw_list]
131
131
 
132
+ def find_tasks_by_body_marker(
133
+ self,
134
+ marker: str,
135
+ label: str | None = None,
136
+ state: TaskState | None = TaskState.OPEN,
137
+ ) -> list[Task]:
138
+ """Exhaustively scan matching GitHub issues for one recovery marker."""
139
+ nwo = self.get_repo_nwo()
140
+ state_value = "all" if state is None else state.value
141
+ query = f"repos/{nwo}/issues?state={state_value}&per_page=100"
142
+ if label:
143
+ query += f"&labels={quote(label, safe='')}"
144
+ result = run(
145
+ ["gh", "api", "--paginate", "--slurp", query],
146
+ check=True,
147
+ retries=3,
148
+ )
149
+ pages = json.loads(result.stdout)
150
+ tasks: list[Task] = []
151
+ for page in pages:
152
+ for raw in page:
153
+ # GitHub's REST issues endpoint includes pull requests. The
154
+ # issue-list command used elsewhere excludes them, so preserve
155
+ # that task-provider contract here too.
156
+ if "pull_request" in raw or marker not in (raw.get("body") or ""):
157
+ continue
158
+ raw["url"] = raw.get("html_url", raw.get("url", ""))
159
+ raw["createdAt"] = raw.get("created_at")
160
+ raw["updatedAt"] = raw.get("updated_at")
161
+ tasks.append(_parse_gh_task(raw))
162
+ return tasks
163
+
132
164
  def create_task(
133
165
  self,
134
166
  title: str,
@@ -466,6 +466,25 @@ class MarkdownIssueProvider(GitHubPRDelegateMixin, AbstractTaskProvider):
466
466
 
467
467
  return tasks
468
468
 
469
+ def find_tasks_by_body_marker(
470
+ self,
471
+ marker: str,
472
+ label: str | None = None,
473
+ state: TaskState | None = TaskState.OPEN,
474
+ ) -> list[Task]:
475
+ """Exhaustively scan the central Markdown file for one recovery marker."""
476
+ _, sections = self._load_sections()
477
+ matches: list[Task] = []
478
+ for section in sections:
479
+ task = _section_to_task(section)
480
+ if state is not None and task.state != state:
481
+ continue
482
+ if label and label not in {item.name for item in task.labels}:
483
+ continue
484
+ if marker in task.body:
485
+ matches.append(task)
486
+ return matches
487
+
469
488
  def create_task(
470
489
  self,
471
490
  title: str,
@@ -17,6 +17,7 @@ from wade.git.repo import GitError
17
17
  from wade.models.config import ProjectConfig
18
18
  from wade.models.task import Task
19
19
  from wade.ui.console import console
20
+ from wade.utils.body_markers import upsert_marked_block
20
21
 
21
22
  logger = structlog.get_logger()
22
23
 
@@ -318,6 +319,8 @@ def bootstrap_draft_pr(
318
319
  config: ProjectConfig,
319
320
  repo_root: Path,
320
321
  base_branch: str | None = None,
322
+ refresh_existing_plan: bool = False,
323
+ refresh_title: str | None = None,
321
324
  ) -> dict[str, str | int] | None:
322
325
  """Create branch + push + draft PR for an issue.
323
326
 
@@ -332,6 +335,11 @@ def bootstrap_draft_pr(
332
335
  repo_root: Repository root directory.
333
336
  base_branch: When set, branch from this instead of main and target
334
337
  the PR at it (stacked PR for chain execution).
338
+ refresh_existing_plan: Rewrite an existing PR's managed plan body before
339
+ accepting a recovered task as persisted.
340
+ refresh_title: When refreshing a recovered task, update the existing
341
+ draft PR title (or use it for a newly created PR) after locating
342
+ the branch from ``issue_title``.
335
343
 
336
344
  Returns:
337
345
  Dict with "number" (int) and "url" (str) keys, or None on failure.
@@ -387,6 +395,26 @@ def bootstrap_draft_pr(
387
395
  _restore_scaffold_head(repo_root, branch_name, pre_reroot_sha, existing.number)
388
396
  return None
389
397
  console.detail(f"Retargeted PR #{existing.number} base to {base_branch}")
398
+ if refresh_existing_plan:
399
+ current_body = git_pr.get_pr_body(repo_root, existing.number)
400
+ if current_body is None:
401
+ console.error(f"Failed to read the body of draft PR #{existing.number}.")
402
+ return None
403
+ refreshed_body = (
404
+ upsert_marked_block(current_body, PLAN_MARKER_START, PLAN_MARKER_END, plan_body)
405
+ if current_body
406
+ else _build_draft_pr_body(plan_body, issue_number)
407
+ )
408
+ if not git_pr.update_pr_body(repo_root, existing.number, refreshed_body):
409
+ console.error(f"Failed to refresh the plan in draft PR #{existing.number}.")
410
+ return None
411
+ if (
412
+ refresh_title is not None
413
+ and existing.title != refresh_title
414
+ and not git_pr.update_pr_title(repo_root, existing.number, refresh_title)
415
+ ):
416
+ console.error(f"Failed to refresh the title in draft PR #{existing.number}.")
417
+ return None
390
418
  logger.info(
391
419
  "bootstrap_draft_pr.existing",
392
420
  branch=branch_name,
@@ -431,7 +459,7 @@ def bootstrap_draft_pr(
431
459
  try:
432
460
  pr_info = git_pr.create_pr(
433
461
  repo_root=repo_root,
434
- title=issue_title,
462
+ title=refresh_title or issue_title,
435
463
  body=body,
436
464
  base=effective_base,
437
465
  head=branch_name,