wade-cli 1.0.0__tar.gz → 1.1.0__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 (417) hide show
  1. {wade_cli-1.0.0 → wade_cli-1.1.0}/CHANGELOG.md +6 -0
  2. {wade_cli-1.0.0 → wade_cli-1.1.0}/KNOWLEDGE.md +42 -0
  3. {wade_cli-1.0.0 → wade_cli-1.1.0}/KNOWLEDGE.ratings.jsonl +12 -0
  4. {wade_cli-1.0.0 → wade_cli-1.1.0}/PKG-INFO +100 -14
  5. {wade_cli-1.0.0 → wade_cli-1.1.0}/README.md +99 -13
  6. {wade_cli-1.0.0 → wade_cli-1.1.0}/docs/dev/architecture.md +168 -14
  7. {wade_cli-1.0.0 → wade_cli-1.1.0}/pyproject.toml +1 -1
  8. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/__init__.py +1 -1
  9. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/main.py +14 -0
  10. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/review.py +29 -0
  11. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/task.py +7 -0
  12. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/delegation.py +34 -0
  13. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/session_manifest.py +6 -0
  14. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/ai_resolution.py +93 -0
  15. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/batch_review_service.py +9 -0
  16. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/delegation_service.py +207 -45
  17. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/deps_service.py +24 -4
  18. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/batch.py +28 -0
  19. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/core.py +95 -93
  20. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/plan_service.py +42 -13
  21. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/review_delegation_service.py +224 -15
  22. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/review_record_service.py +33 -16
  23. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/review_service.py +70 -18
  24. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/smart_start.py +4 -0
  25. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/filelock.py +16 -3
  26. wade_cli-1.1.0/src/wade/utils/runtime_env.py +316 -0
  27. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/conftest.py +19 -0
  28. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_plan_contract.py +5 -0
  29. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_review_contract.py +233 -0
  30. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_review_cli.py +39 -1
  31. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_session_subapps.py +10 -1
  32. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_task_cli.py +20 -0
  33. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_ai_resolution.py +84 -0
  34. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_batch_build_cmd.py +29 -0
  35. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_batch_review_service.py +7 -2
  36. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_delegation_service.py +385 -1
  37. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_deps_service.py +62 -2
  38. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_done_gates.py +48 -0
  39. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_implementation_launch_context.py +157 -109
  40. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_implementation_service.py +53 -0
  41. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_plan_service.py +28 -27
  42. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_review_delegation_service.py +215 -1
  43. wade_cli-1.1.0/tests/unit/test_services/test_review_receipts.py +497 -0
  44. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_review_records.py +44 -0
  45. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_review_service.py +250 -1
  46. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_smart_start.py +8 -4
  47. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_filelock.py +10 -0
  48. wade_cli-1.1.0/tests/unit/test_utils/test_runtime_env.py +252 -0
  49. wade_cli-1.0.0/tests/unit/test_services/test_review_receipts.py +0 -223
  50. {wade_cli-1.0.0 → wade_cli-1.1.0}/.gitattributes +0 -0
  51. {wade_cli-1.0.0 → wade_cli-1.1.0}/.github/workflows/auto-version.yml +0 -0
  52. {wade_cli-1.0.0 → wade_cli-1.1.0}/.github/workflows/ci.yml +0 -0
  53. {wade_cli-1.0.0 → wade_cli-1.1.0}/.github/workflows/pr-title-lint.yml +0 -0
  54. {wade_cli-1.0.0 → wade_cli-1.1.0}/.github/workflows/publish.yml +0 -0
  55. {wade_cli-1.0.0 → wade_cli-1.1.0}/.github/workflows/release.yml +0 -0
  56. {wade_cli-1.0.0 → wade_cli-1.1.0}/.gitignore +0 -0
  57. {wade_cli-1.0.0 → wade_cli-1.1.0}/.pre-commit-config.yaml +0 -0
  58. {wade_cli-1.0.0 → wade_cli-1.1.0}/.wade.yml +0 -0
  59. {wade_cli-1.0.0 → wade_cli-1.1.0}/AGENTS.md +0 -0
  60. {wade_cli-1.0.0 → wade_cli-1.1.0}/CONTRIBUTING.md +0 -0
  61. {wade_cli-1.0.0 → wade_cli-1.1.0}/assets/wade.png +0 -0
  62. {wade_cli-1.0.0 → wade_cli-1.1.0}/docker-compose.e2e.yml +0 -0
  63. {wade_cli-1.0.0 → wade_cli-1.1.0}/docs/dev/documentation-policies.md +0 -0
  64. {wade_cli-1.0.0 → wade_cli-1.1.0}/docs/dev/extending.md +0 -0
  65. {wade_cli-1.0.0 → wade_cli-1.1.0}/docs/dev/skills-system.md +0 -0
  66. {wade_cli-1.0.0 → wade_cli-1.1.0}/docs/dev/testing.md +0 -0
  67. {wade_cli-1.0.0 → wade_cli-1.1.0}/docs/dev/workflows-and-skills.md +0 -0
  68. {wade_cli-1.0.0 → wade_cli-1.1.0}/install.sh +0 -0
  69. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/auto_version.py +0 -0
  70. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/changelog.py +0 -0
  71. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/check-all.sh +0 -0
  72. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/check.sh +0 -0
  73. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/fmt.sh +0 -0
  74. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/hooks/pre-push +0 -0
  75. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/install-hooks.sh +0 -0
  76. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/release.sh +0 -0
  77. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/setup-worktree.sh +0 -0
  78. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/test-concurrency.sh +0 -0
  79. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/test-e2e-docker.sh +0 -0
  80. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/test-e2e.sh +0 -0
  81. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/test-live-ai-taskr.sh +0 -0
  82. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/test-live-ai.sh +0 -0
  83. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/test-live-gh.sh +0 -0
  84. {wade_cli-1.0.0 → wade_cli-1.1.0}/scripts/test.sh +0 -0
  85. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/__main__.py +0 -0
  86. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/__init__.py +0 -0
  87. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/admin.py +0 -0
  88. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/autocomplete.py +0 -0
  89. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/deps_session.py +0 -0
  90. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/hook.py +0 -0
  91. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/implementation_session.py +0 -0
  92. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/knowledge.py +0 -0
  93. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/plan_session.py +0 -0
  94. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/review_pr_comments_session.py +0 -0
  95. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/session.py +0 -0
  96. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/session_shared.py +0 -0
  97. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/skills.py +0 -0
  98. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/cli/worktree.py +0 -0
  99. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/config/__init__.py +0 -0
  100. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/config/loader.py +0 -0
  101. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/config/migrations.py +0 -0
  102. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/config/schema.py +0 -0
  103. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/git/__init__.py +0 -0
  104. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/git/branch.py +0 -0
  105. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/git/hooks.py +0 -0
  106. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/git/pr.py +0 -0
  107. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/git/repo.py +0 -0
  108. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/git/stash.py +0 -0
  109. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/git/sync.py +0 -0
  110. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/git/worktree.py +0 -0
  111. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/hooks/__init__.py +0 -0
  112. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/hooks/cli.py +0 -0
  113. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/hooks/policies.py +0 -0
  114. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/logging/__init__.py +0 -0
  115. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/logging/context.py +0 -0
  116. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/logging/setup.py +0 -0
  117. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/__init__.py +0 -0
  118. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/batch.py +0 -0
  119. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/config.py +0 -0
  120. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/deps.py +0 -0
  121. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/events.py +0 -0
  122. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/hooks.py +0 -0
  123. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/permission.py +0 -0
  124. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/readiness.py +0 -0
  125. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/review.py +0 -0
  126. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/session.py +0 -0
  127. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/skill.py +0 -0
  128. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/task.py +0 -0
  129. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/workflow.py +0 -0
  130. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/models/worktree.py +0 -0
  131. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/providers/__init__.py +0 -0
  132. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/providers/_pr_delegate.py +0 -0
  133. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/providers/base.py +0 -0
  134. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/providers/clickup.py +0 -0
  135. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/providers/github.py +0 -0
  136. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/providers/markdown.py +0 -0
  137. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/providers/registry.py +0 -0
  138. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/__init__.py +0 -0
  139. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/bot_trigger.py +0 -0
  140. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/check_service.py +0 -0
  141. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/documentation_receipt_service.py +0 -0
  142. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/__init__.py +0 -0
  143. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/_shared.py +0 -0
  144. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/bootstrap.py +0 -0
  145. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/cleanup.py +0 -0
  146. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/done.py +0 -0
  147. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/draft_pr.py +0 -0
  148. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/lifecycle.py +0 -0
  149. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/sync.py +0 -0
  150. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/implementation_service/usage_tracking.py +0 -0
  151. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/init_service/__init__.py +0 -0
  152. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/init_service/auth.py +0 -0
  153. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/init_service/commands.py +0 -0
  154. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/init_service/config_io.py +0 -0
  155. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/init_service/manifest.py +0 -0
  156. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/init_service/migrations.py +0 -0
  157. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/init_service/prompts_ai.py +0 -0
  158. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/init_service/prompts_setup.py +0 -0
  159. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/init_service/shell.py +0 -0
  160. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/knowledge_recovery.py +0 -0
  161. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/knowledge_search.py +0 -0
  162. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/knowledge_service.py +0 -0
  163. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/prompt_delivery.py +0 -0
  164. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/review_settle.py +0 -0
  165. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/session_composition_service.py +0 -0
  166. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/skill_diagnostics_service.py +0 -0
  167. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/skill_invocation_service.py +0 -0
  168. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/services/task_service.py +0 -0
  169. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/skills/__init__.py +0 -0
  170. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/skills/catalog.py +0 -0
  171. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/skills/discovery.py +0 -0
  172. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/skills/doc_targets.py +0 -0
  173. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/skills/installer.py +0 -0
  174. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/skills/materializer.py +0 -0
  175. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/skills/pointer.py +0 -0
  176. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/skills/resolver.py +0 -0
  177. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/skills/validation.py +0 -0
  178. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/ui/__init__.py +0 -0
  179. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/ui/console.py +0 -0
  180. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/ui/prompts.py +0 -0
  181. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/__init__.py +0 -0
  182. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/body_markers.py +0 -0
  183. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/clipboard.py +0 -0
  184. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/conventional.py +0 -0
  185. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/gitref.py +0 -0
  186. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/http.py +0 -0
  187. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/install.py +0 -0
  188. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/knowledge_file.py +0 -0
  189. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/markdown.py +0 -0
  190. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/markers.py +0 -0
  191. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/paths.py +0 -0
  192. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/plan_validation.py +0 -0
  193. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/process.py +0 -0
  194. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/safe_state.py +0 -0
  195. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/slug.py +0 -0
  196. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/stale_base.py +0 -0
  197. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/templates.py +0 -0
  198. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/terminal.py +0 -0
  199. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/token_usage_markdown.py +0 -0
  200. {wade_cli-1.0.0 → wade_cli-1.1.0}/src/wade/utils/update_check.py +0 -0
  201. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/agents-pointer.md +0 -0
  202. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/hooks/commit-msg +0 -0
  203. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/hooks/pre-commit +0 -0
  204. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/hooks/pre-push +0 -0
  205. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/deps-analysis.md +0 -0
  206. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/implement-context.md +0 -0
  207. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/plan-session.md +0 -0
  208. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/review-batch.md +0 -0
  209. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/review-code.md +0 -0
  210. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/review-plan.md +0 -0
  211. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/review-pr-comments.md +0 -0
  212. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/session-start-implement.md +0 -0
  213. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/session-start-plan.md +0 -0
  214. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/prompts/session-start-review.md +0 -0
  215. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/setup-worktree.sh.example +0 -0
  216. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/batch-review/SKILL.md +0 -0
  217. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/code-review/SKILL.md +0 -0
  218. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/dependency-analysis/SKILL.md +0 -0
  219. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/implementation/SKILL.md +0 -0
  220. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/knowledge/SKILL.md +0 -0
  221. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/plan-review/SKILL.md +0 -0
  222. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/planning/SKILL.md +0 -0
  223. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/review-comments/SKILL.md +0 -0
  224. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/task/SKILL.md +0 -0
  225. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/task/examples.md +0 -0
  226. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/task/plan-format.md +0 -0
  227. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/skills/task/reference/session-summary-format.md +0 -0
  228. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/statusline-command.sh +0 -0
  229. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/_partials/completion.md +0 -0
  230. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/_partials/documentation-step.md +0 -0
  231. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/_partials/interaction-policy.md +0 -0
  232. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/_partials/knowledge-step.md +0 -0
  233. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/_partials/review-budget.md +0 -0
  234. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/implementation.md +0 -0
  235. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/plan.md +0 -0
  236. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/reference/documentation.md +0 -0
  237. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/reference/new-plan.md +0 -0
  238. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/reference/plan-output-contract.md +0 -0
  239. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/reference/pr-summary-format.md +0 -0
  240. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/reference/recovery.md +0 -0
  241. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/reference/session-summary-format.md +0 -0
  242. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/reference/tracking-issues.md +0 -0
  243. {wade_cli-1.0.0 → wade_cli-1.1.0}/templates/workflows/review-pr-comments.md +0 -0
  244. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/__init__.py +0 -0
  245. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/concurrency/__init__.py +0 -0
  246. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/concurrency/test_batch_multi_pr.py +0 -0
  247. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/concurrency/test_knowledge_merge.py +0 -0
  248. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/concurrency/test_lock_retry.py +0 -0
  249. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/concurrency/test_stash_race.py +0 -0
  250. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/__init__.py +0 -0
  251. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/_support.py +0 -0
  252. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/conftest.py +0 -0
  253. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/mock_gh_script.py +0 -0
  254. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_admin_contract.py +0 -0
  255. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_check_contract.py +0 -0
  256. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_implement_work_done_contract.py +0 -0
  257. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_knowledge_contract.py +0 -0
  258. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_mock_gh_contract.py +0 -0
  259. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_smart_start_contract.py +0 -0
  260. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_task_contract.py +0 -0
  261. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/e2e/test_work_sync_list_contract.py +0 -0
  262. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/fixtures/live/taskr_header_hi_body.md +0 -0
  263. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/fixtures/live/taskr_header_howdy_body.md +0 -0
  264. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/fixtures/transcripts/claude_session.txt +0 -0
  265. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/fixtures/transcripts/codex_session.txt +0 -0
  266. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/fixtures/transcripts/copilot_session.txt +0 -0
  267. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/fixtures/transcripts/generic_session.txt +0 -0
  268. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/__init__.py +0 -0
  269. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_autostash.py +0 -0
  270. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_check.py +0 -0
  271. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_dynamic_skill_sessions.py +0 -0
  272. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_git.py +0 -0
  273. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_implementation_lifecycle.py +0 -0
  274. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_init.py +0 -0
  275. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_knowledge.py +0 -0
  276. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_markdown_provider.py +0 -0
  277. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_skill_context_budget.py +0 -0
  278. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/integration/test_skill_install.py +0 -0
  279. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/live/__init__.py +0 -0
  280. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/live/test_wade_live_ai.py +0 -0
  281. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/live/test_wade_live_ai_taskr.py +0 -0
  282. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/live/test_wade_live_gh.py +0 -0
  283. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/test_cli_basics.py +0 -0
  284. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/__init__.py +0 -0
  285. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/conftest.py +0 -0
  286. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/__init__.py +0 -0
  287. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_autocomplete.py +0 -0
  288. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_done_doc_pass_advisory.py +0 -0
  289. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_done_review_hint.py +0 -0
  290. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_knowledge_cli.py +0 -0
  291. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_shell_init.py +0 -0
  292. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_skills_session_cli.py +0 -0
  293. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_work_ai_flags.py +0 -0
  294. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_cli/test_work_cli.py +0 -0
  295. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_config/__init__.py +0 -0
  296. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_config/test_bot_review_config.py +0 -0
  297. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_config/test_dynamic_skill_config.py +0 -0
  298. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_config/test_loader.py +0 -0
  299. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_config/test_merge_strategy_migration.py +0 -0
  300. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_config/test_migrations.py +0 -0
  301. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_config/test_migrations_atomic.py +0 -0
  302. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_console.py +0 -0
  303. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_effort.py +0 -0
  304. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/__init__.py +0 -0
  305. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_all_patches_present.py +0 -0
  306. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_branch_list.py +0 -0
  307. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_branch_slugify.py +0 -0
  308. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_detached_worktree.py +0 -0
  309. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_is_merged_into.py +0 -0
  310. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_main_checkout_root.py +0 -0
  311. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_merge_count.py +0 -0
  312. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_pr_base.py +0 -0
  313. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_pr_lookup.py +0 -0
  314. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_pr_retry.py +0 -0
  315. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_pr_title.py +0 -0
  316. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_repo.py +0 -0
  317. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_reset_branch.py +0 -0
  318. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_scaffold_commit.py +0 -0
  319. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_stash_drop.py +0 -0
  320. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_sync_conflicted_files.py +0 -0
  321. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_tip_commit_is_empty.py +0 -0
  322. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_git/test_worktree_remove.py +0 -0
  323. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_hooks/__init__.py +0 -0
  324. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_hooks/test_hook_cli.py +0 -0
  325. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_hooks/test_policies.py +0 -0
  326. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_hooks/test_post_tool_use.py +0 -0
  327. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_hooks/test_session_start.py +0 -0
  328. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/__init__.py +0 -0
  329. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/test_batch.py +0 -0
  330. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/test_config_models.py +0 -0
  331. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/test_delegation.py +0 -0
  332. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/test_deps_models.py +0 -0
  333. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/test_deps_partition.py +0 -0
  334. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/test_review.py +0 -0
  335. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/test_review_expectation.py +0 -0
  336. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/test_task_models.py +0 -0
  337. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_models/test_workflow_models.py +0 -0
  338. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_permission_mode.py +0 -0
  339. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_providers/__init__.py +0 -0
  340. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_providers/test_clickup.py +0 -0
  341. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_providers/test_github.py +0 -0
  342. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_providers/test_github_pr.py +0 -0
  343. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_providers/test_markdown.py +0 -0
  344. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_scripts/__init__.py +0 -0
  345. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_scripts/test_changelog.py +0 -0
  346. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/__init__.py +0 -0
  347. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_batch_pr_index.py +0 -0
  348. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_bootstrap_allowlist.py +0 -0
  349. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_bootstrap_guard_matcher.py +0 -0
  350. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_bootstrap_hook_timeout.py +0 -0
  351. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_bootstrap_post_tool_use.py +0 -0
  352. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_bootstrap_pre_push.py +0 -0
  353. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_bootstrap_session_start.py +0 -0
  354. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_bot_trigger.py +0 -0
  355. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_catchup.py +0 -0
  356. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_catchup_reconcile.py +0 -0
  357. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_check.py +0 -0
  358. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_cleanup_loss_guard.py +0 -0
  359. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_codex_worktree_launch_context.py +0 -0
  360. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_documentation_receipt.py +0 -0
  361. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_done_idempotent.py +0 -0
  362. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_done_plan_flag.py +0 -0
  363. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_done_pr_title_sync.py +0 -0
  364. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_draft_pr_base_fetch.py +0 -0
  365. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_draft_pr_retarget.py +0 -0
  366. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_implementation_done_sync.py +0 -0
  367. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_implementation_service_resume.py +0 -0
  368. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_init.py +0 -0
  369. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_init_shell_integration.py +0 -0
  370. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_knowledge_recovery.py +0 -0
  371. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_knowledge_search.py +0 -0
  372. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_knowledge_service.py +0 -0
  373. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_managed_git_hooks.py +0 -0
  374. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_no_direct_git.py +0 -0
  375. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_poll_for_reviews.py +0 -0
  376. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_post_implementation_lifecycle.py +0 -0
  377. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_pr_lookup_guards.py +0 -0
  378. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_pr_summary_path.py +0 -0
  379. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_pre_push_backstop.py +0 -0
  380. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_preserve_session_data.py +0 -0
  381. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_prompt_delivery.py +0 -0
  382. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_push_recovery.py +0 -0
  383. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_resolve_task_branch.py +0 -0
  384. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_resume_autonomy.py +0 -0
  385. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_review_status_block.py +0 -0
  386. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_skill_diagnostics_service.py +0 -0
  387. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_smart_start_resume.py +0 -0
  388. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_stale_base_surface.py +0 -0
  389. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_sync_base_branch.py +0 -0
  390. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_task_service.py +0 -0
  391. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_tracked_managed_files.py +0 -0
  392. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_services/test_worktree_gitignore.py +0 -0
  393. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_skills/test_crossby_contract.py +0 -0
  394. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_skills/test_doc_targets.py +0 -0
  395. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_skills/test_dynamic_skills.py +0 -0
  396. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_skills/test_generic_builtin_boundaries.py +0 -0
  397. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_skills/test_knowledge_attributes.py +0 -0
  398. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_skills/test_managed_gitignore.py +0 -0
  399. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_skills/test_pointer.py +0 -0
  400. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_skills/test_review_budget_partial.py +0 -0
  401. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/__init__.py +0 -0
  402. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_body_markers.py +0 -0
  403. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_conventional.py +0 -0
  404. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_gitref.py +0 -0
  405. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_http.py +0 -0
  406. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_install.py +0 -0
  407. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_markdown.py +0 -0
  408. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_markers.py +0 -0
  409. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_plan_validation.py +0 -0
  410. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_process.py +0 -0
  411. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_prompts.py +0 -0
  412. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_slug.py +0 -0
  413. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_stale_base.py +0 -0
  414. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_terminal.py +0 -0
  415. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_terminal_launch.py +0 -0
  416. {wade_cli-1.0.0 → wade_cli-1.1.0}/tests/unit/test_utils/test_update_check.py +0 -0
  417. {wade_cli-1.0.0 → wade_cli-1.1.0}/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.1.0] — 2026-09-04
8
+
9
+ ### Features
10
+
11
+ - diagnose sandboxed parent runtimes and keep review gates closed (#481) (4440220)
12
+
7
13
  ## [v1.0.0] — 2026-09-03
8
14
 
9
15
  ### Breaking Changes
@@ -749,3 +749,45 @@ scripts/changelog.py's format_range is re-run by generate() for EVERY tag range
749
749
  The release version bump is derived from the PR title ALONE — .github/workflows/auto-version.yml greps only github.event.pull_request.title, never commit history — and done.py's PR-title sync overwrites that title from the ISSUE title on every done. So a `feat!:` commit with a real BREAKING CHANGE footer still ships as a MINOR release unless issue #N's own title carries the `!`; retitle the issue (gh issue edit --title, since wade task update only edits the body), not just the PR, or done reverts it.
750
750
 
751
751
  ---
752
+
753
+ ## 1f23c00660aa | 2026-09-04 | implementation | tags: delegation, architecture, sandbox | Issue #480
754
+
755
+ `delegation_service.delegate()` is the single dispatcher for deps, standalone plan/code review, and batch review — `deps_service` and `review_delegation_service` call it directly and `batch_review_service` reaches it through the latter — so a cross-cutting launch concern belongs there ONCE, not per service. Centralising costs per-operation context, so remediation text must ride on `DelegationRequest` fields rather than being generated inside the dispatcher. `implementation_service/batch.py` is NOT a launch path: it builds ["wade", "implement", <id>] and spawns child `wade` processes that reach the `core.py` check themselves, so a check there is a dead no-op implying coverage it does not add.
756
+
757
+ ---
758
+
759
+ ## 280ed6e410b6 | 2026-09-04 | implementation | tags: delegation, sandbox, gotcha, error-handling | Issue #480
760
+
761
+ `DelegationResult.never_launched` means no process ever started (absent/unknown tool, `supports_headless` rejection, `CommandError` spawn failure, `OSError` on exec) — a non-zero exit AND a real timeout must both keep it False, because "relaunch the outer session" is wrong advice for a reviewer that actually ran. `utils.process.run` maps only `FileNotFoundError` to `CommandError`, so a `PermissionError` on a binary that resolves on PATH but cannot be executed escapes `_delegate_headless` entirely unless caught explicitly — one of the exact shapes an inherited sandbox produces. The interactive path needs an explicit `launched` flag because `adapter.launch` and the post-session output-file read share one exception handler.
762
+
763
+ ---
764
+
765
+ ## 65ee7eb64d81 | 2026-09-04 | implementation | tags: testing, sandbox, gotcha | Issue #480
766
+
767
+ `tests/conftest.py` carries an autouse fixture clearing `runtime_env.SANDBOX_SIGNAL_ENV_VARS`, because `utils/runtime_env.py` reads the REAL environment — without it a suite run from inside a sandboxed Codex session sees a genuine SANDBOXED verdict and takes relaunch/diagnosis branches no test asked for. It clears only the sandbox-signal vars, never the identity markers (`CODEX_CLI`, `CLAUDE_CODE`, …) that existing tests patch directly. Any test asserting on the parent-sandbox diagnosis must also clear competing identity markers, since the probe returns the FIRST one it recognises.
768
+
769
+ ---
770
+
771
+ ## 397994e37408 | 2026-09-04 | implementation | tags: delegation, error-handling, gotcha | Issue #480
772
+
773
+ `DelegationResult.never_launched` means no process ever started, and an explicit `launched` flag set after `adapter.launch()` returns is NOT enough to decide it: `launch` blocks until the child exits for most runtimes, so an adapter that checks the exit status raises `CalledProcessError` from a session that ran and failed. Classify the interactive launch boundary by exception SHAPE — an `OSError` at the spawn started nothing, every `subprocess.SubprocessError` variant carries a child that was created — and keep the post-launch section in its own handler. `utils.process.run` maps only `FileNotFoundError` to `CommandError`, so a `PermissionError` on a binary that resolves on PATH but cannot be executed escapes `_delegate_headless` unless caught explicitly.
774
+
775
+ ---
776
+
777
+ ## 12dd26da8910 | 2026-09-04 | implementation | tags: testing, gotcha, e2e | Issue #480
778
+
779
+ A non-executable file earlier on PATH does NOT make a later real binary unreachable: CPython builds an exec candidate from every PATH entry and keeps going past EACCES, so an E2E test that drops a chmod 644 stand-in into the mocked bin dir still runs the users real tool. To force a denial-shaped spawn failure, narrow PATH in the child env to the mocked bin plus only the dirs actually needed (`wade`, `git`, `/usr/bin`, `/bin`). `shutil.which` skips non-executables, so it is the right assertion that no real binary remains reachable.
780
+
781
+ ---
782
+
783
+ ## 4668ee29b835 | 2026-09-04 | implementation | tags: delegation, sandbox, batch | Issue #480
784
+
785
+ For issue #480, delegation_service.delegate() remains the one dispatcher for deps and standalone/batch reviews, but implement-batch crosses a different terminal-broker boundary. Diagnose a known parent sandbox once in implementation_service.batch before broker shells can lose its markers; child implementation checks remain a backstop, not the sole diagnosis.
786
+
787
+ ---
788
+
789
+ ## 54236b4243bc | 2026-09-04 | implementation | tags: testing, sandbox, gotcha | Issue #480
790
+
791
+ For issue #480 sandbox tests, the autouse conftest fixture clears both SANDBOX_SIGNAL_ENV_VARS and real Codex identity markers in CODEX_IDENTITY_ENV_VARS. Tests that need another enclosing runtime still set or clear competing identity markers deliberately; do not claim the fixture never clears identity markers.
792
+
793
+ ---
@@ -158,3 +158,15 @@
158
158
  {"dir": "up", "event_id": "5cde95ece3844529a88448383c60e822", "id": "d7e3010043a2", "ts": "2026-09-03T02:07:17.166938+00:00"}
159
159
  {"dir": "up", "event_id": "18179aae748f444487502929584aa632", "id": "6eb12fb5eb3a", "ts": "2026-09-03T12:24:58.444706+00:00"}
160
160
  {"dir": "up", "event_id": "0c1be71273e34c50b609348a7c09622e", "id": "1c79175312c9", "ts": "2026-09-03T12:24:58.649116+00:00"}
161
+ {"dir": "up", "event_id": "67eb4181748e4cd2974a60ed014efe12", "id": "851bb6ec", "ts": "2026-09-04T11:02:22.496706+00:00"}
162
+ {"dir": "up", "event_id": "b15b9eba905749c78eded32f991397a1", "id": "d7e3010043a2", "ts": "2026-09-04T11:02:22.654506+00:00"}
163
+ {"dir": "stale", "event_id": "69e1b360de924aa5b0a27874d8be935e", "id": "8a9bfc96", "ts": "2026-09-04T11:02:22.809044+00:00"}
164
+ {"dir": "up", "event_id": "79dac0524f60401fb457dcb44c62ac5a", "id": "1f23c00660aa", "ts": "2026-09-04T14:17:48.792141+00:00"}
165
+ {"dir": "up", "event_id": "962d19cb9fa3460eb7f351bbdf0abe76", "id": "65ee7eb64d81", "ts": "2026-09-04T14:17:48.947672+00:00"}
166
+ {"id": "280ed6e410b6", "superseded_by": "397994e37408", "ts": "2026-09-04T14:18:00.060874+00:00"}
167
+ {"dir": "up", "event_id": "5aaf8dca23da43409dae899f50e04111", "id": "1f23c00660aa", "ts": "2026-09-04T16:19:49.643133+00:00"}
168
+ {"dir": "up", "event_id": "96bedf22dcd74c3cabdace8dd850f125", "id": "280ed6e410b6", "ts": "2026-09-04T16:19:49.795516+00:00"}
169
+ {"dir": "stale", "event_id": "de4b4ee2ffa24276a4b35d93ccb16b11", "id": "1f23c00660aa", "ts": "2026-09-04T22:14:03.557181+00:00"}
170
+ {"dir": "stale", "event_id": "71f6ebba04cc4c86bc4e2d02ed19ea9d", "id": "65ee7eb64d81", "ts": "2026-09-04T22:14:03.707575+00:00"}
171
+ {"id": "1f23c00660aa", "superseded_by": "4668ee29b835", "ts": "2026-09-04T22:14:10.938819+00:00"}
172
+ {"id": "65ee7eb64d81", "superseded_by": "54236b4243bc", "ts": "2026-09-04T22:14:17.907524+00:00"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: wade-cli
3
- Version: 1.0.0
3
+ Version: 1.1.0
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
@@ -276,7 +276,7 @@ These are invoked by the AI during a session — you normally don't run them by
276
276
  | `wade plan-session done <plan_dir>` | Finalize a planning session |
277
277
  | `wade deps-session check` | Verify the detached dependency-analysis runtime before writing output or staging a knowledge vote |
278
278
 
279
- Most workflow commands accept `--ai <tool>`, `--model <model>`, `--effort <level>`, `--permission-mode <tier>`, and `--yolo` to override configured defaults. `plan`, `implement`, and `review pr-comments` accept repeatable `--skill` and `--review-skill` methodology bindings plus `--refresh-skills` for an existing frozen session; `implement-batch` forwards the same binding request to every child session. Standalone plan/code/batch review and `task deps` accept repeatable `--skill`. `plan`, `implement`, `implement-batch`, `review pr-comments`, and the `wade <N>` shorthand also accept `--sandbox` / `--no-sandbox` (see [AI runtime sandbox profile](#ai-runtime-sandbox-profile)); batch and shorthand forward an explicit flag to the child session they launch. `implement` additionally supports `--detach` (new terminal tab), `--cd` (print worktree path only), and `--base <branch>` (see [Planning & base branches](#planning--base-branches)).
279
+ Most workflow commands accept `--ai <tool>`, `--model <model>`, `--effort <level>`, `--permission-mode <tier>`, and `--yolo` to override configured defaults. `review pr-comments` additionally accepts `--effort none` to pin the tool default instead of a configured effort across a later wait/relaunch. `plan`, `implement`, and `review pr-comments` accept repeatable `--skill` and `--review-skill` methodology bindings plus `--refresh-skills` for an existing frozen session; `implement-batch` forwards the same binding request to every child session. Standalone plan/code/batch review and `task deps` accept repeatable `--skill`. `plan`, `implement`, `implement-batch`, standalone reviews (`review plan`, `review implementation`, `review batch`), `review pr-comments`, `task deps`, and the `wade <N>` shorthand also accept `--sandbox` / `--no-sandbox` (see [AI runtime sandbox profile](#ai-runtime-sandbox-profile)); batch and shorthand forward an explicit flag to the child session they launch. `implement` additionally supports `--detach` (new terminal tab), `--cd` (print worktree path only), and `--base <branch>` (see [Planning & base branches](#planning--base-branches)).
280
280
 
281
281
  ## Planning & base branches
282
282
 
@@ -707,7 +707,7 @@ fetch`/`push`, `gh`, package installs — cannot work without it, and the profil
707
707
  is fixed at launch.
708
708
 
709
709
  Set it globally or per command, and override it on any launch command
710
- (`implement`, `implement-batch`, `plan`, `review pr-comments`, `smart-start`,
710
+ (`implement`, `implement-batch`, `plan`, `review pr-comments`, `task deps`, `smart-start`,
711
711
  and the `i`/`r`/`p` aliases) with `--sandbox` / `--no-sandbox`:
712
712
 
713
713
  ```yaml
@@ -773,17 +773,87 @@ the Stop hook, and the pre-push backstop are identical in both profiles.
773
773
  #### Plan → implement handoff
774
774
 
775
775
  The sandbox is a launch-time OS property: a process started confined cannot drop
776
- its sandbox later. So when an accepted plan handoff runs inside a **sandboxed**
777
- Codex planner and the implementation profile resolves to **unrestricted**, WADE
778
- starts a fresh detached Codex context rather than reusing the planner process. If
779
- it cannot open that context, the handoff fails rather than reporting an
780
- implementation session ready — open a new host terminal and run the displayed
781
- `wade implement <issue> --no-sandbox` command. When both sessions resolve to the
782
- same profile there is no mismatch and the ordinary nested-launch guard applies.
783
-
784
- The comparison uses the profile the planner **actually launched under**, so a
785
- `wade plan --sandbox` / `--no-sandbox` override is honored here rather than
786
- losing out to `ai.plan.sandbox`.
776
+ its sandbox later. An accepted plan handoff runs after the planner child exits,
777
+ so WADE assesses the **actual parent runtime enclosing the handoff**, not the
778
+ former planner's requested profile. When that runtime is detected as sandboxed
779
+ and implementation resolves to **unrestricted**, WADE fails the handoff rather
780
+ than claiming a terminal child escaped the parent boundary. It names the runtime
781
+ it could not escape, and you open a new host terminal and run the displayed
782
+ `wade implement <issue> --no-sandbox` command. Without a published sandbox
783
+ signal, the ordinary nested-launch guard applies rather than guessing.
784
+
785
+ #### An inner `wade` process cannot escape a parent sandbox
786
+
787
+ Every `wade` command you run from inside an AI CLI session is a **child** of that
788
+ session. If the session was launched under an OS sandbox, every descendant
789
+ inherits the boundary — no profile WADE resolves, and no flag it passes to a
790
+ delegated runtime, can widen it. WADE will never claim otherwise, and there is no
791
+ setting that changes it. **The fix is always to relaunch the outer session with
792
+ the profile you want**, from a host terminal.
793
+
794
+ What WADE does instead is say so. When the resolved profile is unrestricted and
795
+ the enclosing runtime is *known* to be sandboxed, it names that runtime when it
796
+ can (or says **the enclosing AI runtime** when an identity marker is absent) and
797
+ prints the exact command to re-run — on implementation, plan,
798
+ PR-comment review, and every delegated operation (dependency analysis, plan/code
799
+ review, batch review), plus batch implementation before it dispatches terminal
800
+ brokers. That command preserves the resolved tool, model, effort,
801
+ and permission mode; only the sandbox profile changes to `--no-sandbox`.
802
+ Implementation and PR-comment retries reuse their frozen method bindings rather
803
+ than repeating `--skill` / `--review-skill` flags, while fresh delegated
804
+ operations carry their requested bindings. It warns and proceeds rather than
805
+ blocking: a delegated tool whose credentials happen to be reachable from inside
806
+ the sandbox may still
807
+ succeed, so refusing to try would break sessions that work today.
808
+
809
+ Detection is deliberately **best-effort and conservative**. WADE reads only
810
+ sandbox signals a runtime actually publishes and never infers confinement from
811
+ tool identity — a tool that *can* be sandboxed is not a tool that *is* sandboxed.
812
+ Today Codex publishes `CODEX_SANDBOX` for macOS Seatbelt, but its Linux Landlock
813
+ sandbox with network enabled publishes neither that marker nor a usable
814
+ `CODEX_SANDBOX_NETWORK_DISABLED` marker. WADE must report that Linux environment
815
+ as *unknown*, not unrestricted; if the distinction matters, relaunch from a host
816
+ terminal rather than expecting a diagnostic. When there is no signal WADE stays
817
+ silent rather than asserting a cause it cannot support. A confident wrong
818
+ diagnosis is worse than the opaque error it would replace. Managed Codex sessions
819
+ are still recognised when they expose session/thread markers instead of the
820
+ legacy `CODEX_CLI` marker; their displayed identity remains **Codex CLI**.
821
+
822
+ An explicit unrestricted signal (for example, Codex's
823
+ `CODEX_SANDBOX=danger-full-access`) is different from an absent signal: WADE
824
+ does **not** recommend relaunching the outer session for a permission- or
825
+ network-shaped launch failure in that case. The parent has already confirmed it
826
+ is unrestricted, so check executable permissions and network configuration
827
+ instead.
828
+
829
+ **Troubleshooting order** when a delegated tool fails to launch:
830
+
831
+ 1. **Read what WADE printed.** An explicit sandbox-policy denial plus a named
832
+ runtime and command means relaunch the outer session with that command. A
833
+ generic permission or network denial also needs local checks below.
834
+ 2. **Check whether the reviewer actually started.** A reviewer that ran and
835
+ exited non-zero is a different problem; "relaunch the outer session" is wrong
836
+ advice for it. WADE distinguishes the two. A generic launch denial can also
837
+ be bad executable permissions or network configuration; a refusal WADE made
838
+ itself (an unknown tool, a tool with no headless mode) never reached the
839
+ sandbox and gets generic remediation instead.
840
+ 3. **Check executable permissions, network, and the tool's own login/PATH** in the runtime where it must run
841
+ (`gh auth status`, the delegate's own auth command). A separately
842
+ authenticated delegate needs its *own* credentials, not WADE's.
843
+ 4. **Re-run the phase readiness check** (`wade implementation-session check`,
844
+ `wade review-pr-comments-session check`, …) for a narrow `reason=…` and its
845
+ least-privilege remediation.
846
+ 5. **Only then** widen the profile — and widen the *outer* session, not the
847
+ child.
848
+
849
+ > **Narrow, optional exception: Codex project prefix rules.** Codex can be
850
+ > configured to run specific command prefixes outside its sandbox, which elevates
851
+ > a single command without relaunching the session. It is a Codex-side setting
852
+ > WADE neither writes nor reads, it applies per command rather than to the
853
+ > session, and it does not change anything above: the session is still sandboxed
854
+ > and every other child still inherits that. Treat it as an escape hatch for one
855
+ > stubborn command, **not** as WADE's path for running unrestricted — that path
856
+ > is relaunching the outer session.
787
857
 
788
858
  #### Migrating from `ai.network_access`
789
859
 
@@ -857,11 +927,27 @@ credentials, PATH, or sandbox execution access, it does not consume a
857
927
  timeout still counts as a bounded review attempt, so the review/fix loop cannot
858
928
  run forever.
859
929
 
930
+ A reviewer that **never started** — including a sandbox-capability refusal before
931
+ the launch — is recorded as an *unattempted* review so the state is auditable,
932
+ and that record is deliberately inert: it satisfies no review
933
+ requirement, spends no review pass, cannot overwrite a real receipt already
934
+ written for the same commit, and leaves `wade implementation-session done` and
935
+ `wade review-pr-comments-session done` closed. An infrastructure failure must
936
+ never be able to certify a commit. A reviewer that started and exited non-zero
937
+ stays distinguishable from one that never ran, because the two need opposite
938
+ remediation.
939
+
860
940
  For Codex, WADE launches unsandboxed by default so delegated tools keep their
861
941
  own host credentials; set `ai.sandbox: true` (or pass `--sandbox`) to keep
862
942
  `--sandbox workspace-write`, where WADE/crossby add only the linked worktree's
863
943
  private/common Git metadata directories. Every session has network access in
864
944
  both profiles for its GitHub lifecycle.
945
+ Standalone `wade review plan`, `wade review implementation`, and `wade review
946
+ batch` runs also accept `--sandbox` / `--no-sandbox`; an inherited-sandbox
947
+ diagnosis gives the host-terminal relaunch command with `--no-sandbox` so it
948
+ overrides an `ai.sandbox: true` configuration. The command also preserves the
949
+ selected review mode, tool, model, effort, permission mode, staged scope, and
950
+ review-skill overrides so the retry reviews the same operation.
865
951
  For Claude Code and Cursor, allowlist the worktree/Git metadata paths and only
866
952
  the GitHub domains needed by the session rather than choosing unrestricted shell
867
953
  access. Copilot and VS Code need network plus usable `gh` credentials in their
@@ -240,7 +240,7 @@ These are invoked by the AI during a session — you normally don't run them by
240
240
  | `wade plan-session done <plan_dir>` | Finalize a planning session |
241
241
  | `wade deps-session check` | Verify the detached dependency-analysis runtime before writing output or staging a knowledge vote |
242
242
 
243
- Most workflow commands accept `--ai <tool>`, `--model <model>`, `--effort <level>`, `--permission-mode <tier>`, and `--yolo` to override configured defaults. `plan`, `implement`, and `review pr-comments` accept repeatable `--skill` and `--review-skill` methodology bindings plus `--refresh-skills` for an existing frozen session; `implement-batch` forwards the same binding request to every child session. Standalone plan/code/batch review and `task deps` accept repeatable `--skill`. `plan`, `implement`, `implement-batch`, `review pr-comments`, and the `wade <N>` shorthand also accept `--sandbox` / `--no-sandbox` (see [AI runtime sandbox profile](#ai-runtime-sandbox-profile)); batch and shorthand forward an explicit flag to the child session they launch. `implement` additionally supports `--detach` (new terminal tab), `--cd` (print worktree path only), and `--base <branch>` (see [Planning & base branches](#planning--base-branches)).
243
+ Most workflow commands accept `--ai <tool>`, `--model <model>`, `--effort <level>`, `--permission-mode <tier>`, and `--yolo` to override configured defaults. `review pr-comments` additionally accepts `--effort none` to pin the tool default instead of a configured effort across a later wait/relaunch. `plan`, `implement`, and `review pr-comments` accept repeatable `--skill` and `--review-skill` methodology bindings plus `--refresh-skills` for an existing frozen session; `implement-batch` forwards the same binding request to every child session. Standalone plan/code/batch review and `task deps` accept repeatable `--skill`. `plan`, `implement`, `implement-batch`, standalone reviews (`review plan`, `review implementation`, `review batch`), `review pr-comments`, `task deps`, and the `wade <N>` shorthand also accept `--sandbox` / `--no-sandbox` (see [AI runtime sandbox profile](#ai-runtime-sandbox-profile)); batch and shorthand forward an explicit flag to the child session they launch. `implement` additionally supports `--detach` (new terminal tab), `--cd` (print worktree path only), and `--base <branch>` (see [Planning & base branches](#planning--base-branches)).
244
244
 
245
245
  ## Planning & base branches
246
246
 
@@ -671,7 +671,7 @@ fetch`/`push`, `gh`, package installs — cannot work without it, and the profil
671
671
  is fixed at launch.
672
672
 
673
673
  Set it globally or per command, and override it on any launch command
674
- (`implement`, `implement-batch`, `plan`, `review pr-comments`, `smart-start`,
674
+ (`implement`, `implement-batch`, `plan`, `review pr-comments`, `task deps`, `smart-start`,
675
675
  and the `i`/`r`/`p` aliases) with `--sandbox` / `--no-sandbox`:
676
676
 
677
677
  ```yaml
@@ -737,17 +737,87 @@ the Stop hook, and the pre-push backstop are identical in both profiles.
737
737
  #### Plan → implement handoff
738
738
 
739
739
  The sandbox is a launch-time OS property: a process started confined cannot drop
740
- its sandbox later. So when an accepted plan handoff runs inside a **sandboxed**
741
- Codex planner and the implementation profile resolves to **unrestricted**, WADE
742
- starts a fresh detached Codex context rather than reusing the planner process. If
743
- it cannot open that context, the handoff fails rather than reporting an
744
- implementation session ready — open a new host terminal and run the displayed
745
- `wade implement <issue> --no-sandbox` command. When both sessions resolve to the
746
- same profile there is no mismatch and the ordinary nested-launch guard applies.
747
-
748
- The comparison uses the profile the planner **actually launched under**, so a
749
- `wade plan --sandbox` / `--no-sandbox` override is honored here rather than
750
- losing out to `ai.plan.sandbox`.
740
+ its sandbox later. An accepted plan handoff runs after the planner child exits,
741
+ so WADE assesses the **actual parent runtime enclosing the handoff**, not the
742
+ former planner's requested profile. When that runtime is detected as sandboxed
743
+ and implementation resolves to **unrestricted**, WADE fails the handoff rather
744
+ than claiming a terminal child escaped the parent boundary. It names the runtime
745
+ it could not escape, and you open a new host terminal and run the displayed
746
+ `wade implement <issue> --no-sandbox` command. Without a published sandbox
747
+ signal, the ordinary nested-launch guard applies rather than guessing.
748
+
749
+ #### An inner `wade` process cannot escape a parent sandbox
750
+
751
+ Every `wade` command you run from inside an AI CLI session is a **child** of that
752
+ session. If the session was launched under an OS sandbox, every descendant
753
+ inherits the boundary — no profile WADE resolves, and no flag it passes to a
754
+ delegated runtime, can widen it. WADE will never claim otherwise, and there is no
755
+ setting that changes it. **The fix is always to relaunch the outer session with
756
+ the profile you want**, from a host terminal.
757
+
758
+ What WADE does instead is say so. When the resolved profile is unrestricted and
759
+ the enclosing runtime is *known* to be sandboxed, it names that runtime when it
760
+ can (or says **the enclosing AI runtime** when an identity marker is absent) and
761
+ prints the exact command to re-run — on implementation, plan,
762
+ PR-comment review, and every delegated operation (dependency analysis, plan/code
763
+ review, batch review), plus batch implementation before it dispatches terminal
764
+ brokers. That command preserves the resolved tool, model, effort,
765
+ and permission mode; only the sandbox profile changes to `--no-sandbox`.
766
+ Implementation and PR-comment retries reuse their frozen method bindings rather
767
+ than repeating `--skill` / `--review-skill` flags, while fresh delegated
768
+ operations carry their requested bindings. It warns and proceeds rather than
769
+ blocking: a delegated tool whose credentials happen to be reachable from inside
770
+ the sandbox may still
771
+ succeed, so refusing to try would break sessions that work today.
772
+
773
+ Detection is deliberately **best-effort and conservative**. WADE reads only
774
+ sandbox signals a runtime actually publishes and never infers confinement from
775
+ tool identity — a tool that *can* be sandboxed is not a tool that *is* sandboxed.
776
+ Today Codex publishes `CODEX_SANDBOX` for macOS Seatbelt, but its Linux Landlock
777
+ sandbox with network enabled publishes neither that marker nor a usable
778
+ `CODEX_SANDBOX_NETWORK_DISABLED` marker. WADE must report that Linux environment
779
+ as *unknown*, not unrestricted; if the distinction matters, relaunch from a host
780
+ terminal rather than expecting a diagnostic. When there is no signal WADE stays
781
+ silent rather than asserting a cause it cannot support. A confident wrong
782
+ diagnosis is worse than the opaque error it would replace. Managed Codex sessions
783
+ are still recognised when they expose session/thread markers instead of the
784
+ legacy `CODEX_CLI` marker; their displayed identity remains **Codex CLI**.
785
+
786
+ An explicit unrestricted signal (for example, Codex's
787
+ `CODEX_SANDBOX=danger-full-access`) is different from an absent signal: WADE
788
+ does **not** recommend relaunching the outer session for a permission- or
789
+ network-shaped launch failure in that case. The parent has already confirmed it
790
+ is unrestricted, so check executable permissions and network configuration
791
+ instead.
792
+
793
+ **Troubleshooting order** when a delegated tool fails to launch:
794
+
795
+ 1. **Read what WADE printed.** An explicit sandbox-policy denial plus a named
796
+ runtime and command means relaunch the outer session with that command. A
797
+ generic permission or network denial also needs local checks below.
798
+ 2. **Check whether the reviewer actually started.** A reviewer that ran and
799
+ exited non-zero is a different problem; "relaunch the outer session" is wrong
800
+ advice for it. WADE distinguishes the two. A generic launch denial can also
801
+ be bad executable permissions or network configuration; a refusal WADE made
802
+ itself (an unknown tool, a tool with no headless mode) never reached the
803
+ sandbox and gets generic remediation instead.
804
+ 3. **Check executable permissions, network, and the tool's own login/PATH** in the runtime where it must run
805
+ (`gh auth status`, the delegate's own auth command). A separately
806
+ authenticated delegate needs its *own* credentials, not WADE's.
807
+ 4. **Re-run the phase readiness check** (`wade implementation-session check`,
808
+ `wade review-pr-comments-session check`, …) for a narrow `reason=…` and its
809
+ least-privilege remediation.
810
+ 5. **Only then** widen the profile — and widen the *outer* session, not the
811
+ child.
812
+
813
+ > **Narrow, optional exception: Codex project prefix rules.** Codex can be
814
+ > configured to run specific command prefixes outside its sandbox, which elevates
815
+ > a single command without relaunching the session. It is a Codex-side setting
816
+ > WADE neither writes nor reads, it applies per command rather than to the
817
+ > session, and it does not change anything above: the session is still sandboxed
818
+ > and every other child still inherits that. Treat it as an escape hatch for one
819
+ > stubborn command, **not** as WADE's path for running unrestricted — that path
820
+ > is relaunching the outer session.
751
821
 
752
822
  #### Migrating from `ai.network_access`
753
823
 
@@ -821,11 +891,27 @@ credentials, PATH, or sandbox execution access, it does not consume a
821
891
  timeout still counts as a bounded review attempt, so the review/fix loop cannot
822
892
  run forever.
823
893
 
894
+ A reviewer that **never started** — including a sandbox-capability refusal before
895
+ the launch — is recorded as an *unattempted* review so the state is auditable,
896
+ and that record is deliberately inert: it satisfies no review
897
+ requirement, spends no review pass, cannot overwrite a real receipt already
898
+ written for the same commit, and leaves `wade implementation-session done` and
899
+ `wade review-pr-comments-session done` closed. An infrastructure failure must
900
+ never be able to certify a commit. A reviewer that started and exited non-zero
901
+ stays distinguishable from one that never ran, because the two need opposite
902
+ remediation.
903
+
824
904
  For Codex, WADE launches unsandboxed by default so delegated tools keep their
825
905
  own host credentials; set `ai.sandbox: true` (or pass `--sandbox`) to keep
826
906
  `--sandbox workspace-write`, where WADE/crossby add only the linked worktree's
827
907
  private/common Git metadata directories. Every session has network access in
828
908
  both profiles for its GitHub lifecycle.
909
+ Standalone `wade review plan`, `wade review implementation`, and `wade review
910
+ batch` runs also accept `--sandbox` / `--no-sandbox`; an inherited-sandbox
911
+ diagnosis gives the host-terminal relaunch command with `--no-sandbox` so it
912
+ overrides an `ai.sandbox: true` configuration. The command also preserves the
913
+ selected review mode, tool, model, effort, permission mode, staged scope, and
914
+ review-skill overrides so the retry reviews the same operation.
829
915
  For Claude Code and Cursor, allowlist the worktree/Git metadata paths and only
830
916
  the GitHub domains needed by the session rather than choosing unrestricted shell
831
917
  access. Copilot and VS Code need network plus usable `gh` credentials in their
@@ -551,20 +551,174 @@ explicit-only rule — an unset value emits no flag, so a child re-resolves from
551
551
  its own config rather than freezing the parent's resolved value. `None` (unset)
552
552
  matches how a non-explicit `permission_mode` is threaded.
553
553
 
554
- `requires_fresh_codex_handoff` (`implementation_service/core.py`) is the restated
555
- form of the retired network-pin predicate. Its old premise — "the planner always
556
- ran network-off" — died with the per-command asymmetry, but the mismatch it
557
- guarded is real and now expressible directly: the sandbox is a launch-time OS
558
- property, so a **sandboxed** Codex planner handing off to an **unrestricted**
559
- Codex implementation needs a fresh detached process rather than the planner's.
560
- Note the **polarity flip** — the old flag fired on the permissive value being
561
- `True` (network on), this one fires on the permissive value being `False`
562
- (sandbox off), and the detached branch states the forced value (`False`)
563
- explicitly. A token-level rename would have silently inverted the intent. If the
564
- detached launch cannot be created the handoff fails closed and prints
565
- `wade implement <issue> --no-sandbox`; it must not fall back to an inline or
566
- nested agent. Matching profiles produce no handoff, and all other nested-agent
567
- starts retain the ordinary launch guard.
554
+ `requires_fresh_runtime` (`implementation_service/core.py`) is the restated form
555
+ of the retired network-pin predicate. It fires only when an accepted plan handoff
556
+ runs inside a **detected, known-sandboxed parent runtime** while implementation
557
+ resolves **unrestricted**. The planner child has already exited when the accepted
558
+ handoff runs, so its requested `--sandbox`/`--no-sandbox` profile is not evidence
559
+ about the process now enclosing implementation. Note the **polarity flip** — the
560
+ old flag fired on the permissive value being `True` (network on), this one fires
561
+ on the permissive value being `False` (sandbox off). A token-level rename would
562
+ have silently inverted the intent. A new terminal launched by the confined
563
+ process is still only its child — neither terminal-broker acceptance nor a live
564
+ readiness probe proves it escaped the OS sandbox — so the handoff fails closed,
565
+ names the actual parent runtime, and prints `wade implement <issue>
566
+ --no-sandbox`; it must not launch an inline, nested, or detached child. An
567
+ unknown parent keeps the ordinary nested-agent guard rather than guessing.
568
+
569
+ The two tool-identity conjuncts it used to carry — parent is Codex, target is
570
+ Codex — were **proxies** for "this process is confined", and they under-fired on
571
+ exactly the cases that matter (#480): a sandboxed Codex parent handing off to
572
+ Claude confines it just as surely, and being separately authenticated is where
573
+ the lost host login shows first. The predicate is now the shared
574
+ `requires_unsandboxed_relaunch()` described next.
575
+
576
+ ### Parent-runtime detection & conservative classification (#480)
577
+
578
+ Every `wade` command started from inside an AI CLI session is a **child** of that
579
+ session. If the parent launched under an OS sandbox, every descendant inherits
580
+ the boundary: no profile wade resolves, and no flag it passes to a child runtime,
581
+ widens it. **An inner wade process can never escape an existing parent sandbox** —
582
+ the only fix is relaunching the *outer* session. Code must never imply otherwise.
583
+
584
+ `utils/runtime_env.py` is the leaf module holding that knowledge, so services,
585
+ review, and delegation paths share one probe. It answers two deliberately
586
+ independent questions:
587
+
588
+ | Question | API | Note |
589
+ |---|---|---|
590
+ | Which session are we inside? | `detect_ai_cli_env()` | The historical identity probe moved out of `core.py` (re-exported there as `_detect_ai_cli_env`, which `__all__` and much of the suite still patch). Drives the nested-launch guard. |
591
+ | Is that session confined? | `assess_parent_sandbox()` → `SandboxAssessment` | Tri-state: `SANDBOXED` / `UNRESTRICTED` / `UNKNOWN`. |
592
+
593
+ Keeping them independent matters in both directions: identity alone says nothing
594
+ about confinement (Codex runs either way under the canonical `CODEX_CLI`
595
+ identity, including managed `CODEX_SESSION_ID` / `CODEX_THREAD_ID` aliases), and
596
+ a sandbox signal is actionable even when the tool cannot be named.
597
+
598
+ **`UNKNOWN` is a first-class answer, never a fallback to a guess.** The
599
+ assessment is read only from published signals: a present `CODEX_SANDBOX` policy
600
+ name is high-confidence (`danger-full-access` reads `UNRESTRICTED`; another
601
+ non-empty value reads `SANDBOXED`) and `CODEX_SANDBOX_NETWORK_DISABLED` is
602
+ secondary. Codex currently publishes `CODEX_SANDBOX` for macOS Seatbelt, but its
603
+ Linux Landlock sandbox with network enabled publishes neither usable marker; that
604
+ environment deliberately reads `UNKNOWN`, not `UNRESTRICTED`. Every other
605
+ runtime publishes nothing, so `UNKNOWN` is correct and final for them — crossby's
606
+ static `sandboxes_writes` capability describes the *tool*, not this process's
607
+ boundary, and inferring from tool identity is exactly the confident wrong cause
608
+ the module exists to avoid. A requested profile of a finished child process is
609
+ not a substitute for an OS signal on the runtime that currently encloses wade.
610
+ The tri-state also controls launch-failure wording: an absent signal keeps a
611
+ denial-shaped failure conditional, while an explicit unrestricted signal (such
612
+ as `CODEX_SANDBOX=danger-full-access`) rules out inherited confinement and sends
613
+ the user to executable-permission or network configuration instead of suggesting
614
+ an outer-session relaunch.
615
+
616
+ **One predicate, four call sites.** `requires_unsandboxed_relaunch()` is true
617
+ only for *resolved profile unrestricted* **and** *parent known sandboxed* — a
618
+ published signal remains enough to warn even if the separate identity probe has
619
+ no match. Identity is required only for the nested-launch guard; an identityless
620
+ published sandbox signal also makes the plan-handoff path fail closed.
621
+ `ai_resolution.announce_inherited_sandbox()` is the single user-facing emitter, so
622
+ the paths cannot drift into four explanations of one boundary. It is **advisory,
623
+ never a block** (wade cannot prove the delegated tool will fail) and says nothing
624
+ at all on `UNKNOWN`. Host-terminal recovery commands are built as quoted argv,
625
+ then displayed literally, preserving each operation's supported resolved tool,
626
+ model, effort, and permission mode (plus review mode and staged scope where
627
+ applicable); only the sandbox profile changes to `--no-sandbox`.
628
+ Session-based implementation and PR-comment retries omit method overrides and
629
+ reuse the existing frozen bundle; fresh delegated operations preserve their
630
+ bindings. In a PR-comment session, the confirmation UI's "none — use tool
631
+ default" effort choice is distinct from an unset value: retry and host-terminal
632
+ recovery argv carry `--effort none` so a configured effort cannot return on the
633
+ next launch.
634
+
635
+ | Launch path | Site | Relaunch command it supplies |
636
+ |---|---|---|
637
+ | implementation | `implementation_service/core.py` | `wade implement <id> --no-sandbox` |
638
+ | batch implementation | `implementation_service/batch.py` | `wade implement-batch <ids> --no-sandbox` — assessed once before terminal-broker dispatch, because broker shells may not retain the parent's markers |
639
+ | PR-comment review | `review_service.py` | `wade review pr-comments <id> --no-sandbox` |
640
+ | plan | `plan_service.py` | `wade plan --issue <id> --no-sandbox` (or `wade plan --no-sandbox`) — built here because it calls `build_launch_command` + `run_with_transcript` directly, bypassing `delegate()`, and has no nested-AI guard |
641
+ | deps, standalone plan/code review, batch review | `delegation_service.delegate()` | per-operation, from `DelegationRequest.operation` / `.relaunch_command` |
642
+
643
+ Deps (`deps_service.py`), standalone review (`review_delegation_service.py`) and
644
+ batch review (via `review_delegation_service`) all funnel through the one
645
+ `delegate()` dispatcher, so this cross-cutting concern lives there **once**.
646
+ Centralising costs per-operation context, which is why the remediation fields
647
+ ride on `DelegationRequest` — generic advice would defeat the purpose. The
648
+ dispatcher emits that advisory only after tool/mode validation and immediately
649
+ before a runtime launch; a missing tool or headless-capability refusal cannot be
650
+ fixed by relaunching the enclosing session. The command is built by
651
+ `review_delegation_service._relaunch_command()`, which
652
+ forces `--no-sandbox` (so the host-terminal retry overrides any sandboxed config)
653
+ and appends the operation's own **required positional operand** (the plan path
654
+ for `wade review plan`, the tracking issue for `wade review batch`). It withholds
655
+ the hint entirely when it has no required operand: those base commands are
656
+ rejected by Typer, and a line the user cannot paste is worse than no line — the
657
+ same rule already applied to an unmapped command.
658
+ Batch implementation diagnoses once in `implementation_service/batch.py` before
659
+ it dispatches terminal brokers. Those brokers can start child shells without the
660
+ enclosing process's diagnostic markers, so deferring solely to child `wade
661
+ implement` processes can lose a known boundary and produce no remediation.
662
+
663
+ **`DelegationResult.never_launched`** closes the gap that used to force hedged
664
+ remediation: it is `True` only when no process ever started — an absent/unknown
665
+ tool, a `supports_headless` rejection, a `CommandError` spawn failure, or an
666
+ `OSError` on exec (`utils.process.run` maps only `FileNotFoundError` to
667
+ `CommandError`, so a `PermissionError` on a resolvable-but-unexecutable binary
668
+ used to escape `_delegate_headless` and abort the command with a traceback). A
669
+ **non-zero exit** keeps it `False`: that process ran, and a timeout still sets
670
+ `timed_out` and still consumes a pass. The interactive path splits the launch
671
+ boundary into its own handler and classifies by **exception shape**, because
672
+ `adapter.launch` blocks until the child exits for most runtimes: an `OSError` at
673
+ the spawn started nothing, while every `subprocess.SubprocessError` variant
674
+ (`CalledProcessError`, `TimeoutExpired`) carries a child that was created and so
675
+ counts as launched even though the call never returned. Everything after the
676
+ adapter returns — the confirm prompt, the output-file read — is post-launch by
677
+ position, whatever it raises. The headless path matters most — this repo configures
678
+ `mode: headless` for `deps`, `review_plan` and `review_implementation`, and the
679
+ receipt gate excludes `PROMPT` outright.
680
+
681
+ `launch_attempted` is a separate structured boundary: it becomes true only after
682
+ dispatch has passed validation and is about to call the process launcher. A
683
+ preflight error can be `never_launched` without being a spawn attempt (for
684
+ example, `Unknown AI tool: seatbelt`). Specific inherited-sandbox remediation
685
+ therefore requires both that boundary and an actual denial-shaped spawn failure;
686
+ user-controlled error text alone cannot choose the diagnosis.
687
+
688
+ Failure text is matched against sandbox-denial *shapes*
689
+ (`looks_like_sandbox_denial`) — permission/exec denials, read-only filesystems,
690
+ network denials. Those generic OS errors stay **hedged** even when the parent is
691
+ known sandboxed: non-executable binaries and local network configuration can
692
+ produce the same text. Only explicit policy markers (`sandbox policy`, `seatbelt`,
693
+ or `landlock`) support a confident sandbox cause. "Command not found" is
694
+ deliberately **excluded**: from inside a sandbox the host filesystem is exactly
695
+ what is not observable, so "a binary that exists on the host but is missing here"
696
+ is unverifiable at the point of failure and equally the signature of a genuinely
697
+ uninstalled tool.
698
+
699
+ **Review-gate outcome semantics.** `ReviewOutcome.UNATTEMPTED`
700
+ (`models/session_manifest.py`) has `satisfies_review` **and** `consumes_pass`
701
+ both `False`, and sits at the **bottom** of `_OUTCOME_PRECEDENCE`
702
+ (`review_record_service.py`) — a reviewer that never started carries strictly
703
+ less information than any outcome from one that did, so recording it can never
704
+ downgrade or overwrite a real receipt for the same commit+binding. Budget
705
+ protection (#462) and receipt *classification* remain separate problems: the gate
706
+ at `review_delegation_service.py` already withheld budget, and `never_launched`
707
+ is what now lets the remediation be trusted instead of hedged.
708
+ `_report_failed_review()` grades it by what wade actually knows — (1) known
709
+ sandboxed parent **and** an explicit policy denial → state the cause and exact
710
+ relaunch command; (2) a generic denial-shaped failure → explain it might also be
711
+ executable permissions or network configuration alongside `_HEDGED_REVIEW_FAILURE`;
712
+ (3) anything else → that hedged wording alone, kept verbatim. `done` gates stay
713
+ closed in every case.
714
+
715
+ The denial shape is required in (1), not implied by the sandbox: a known boundary
716
+ says the reviewer *could* have been denied, never that it *was*. Without it every
717
+ `never_launched` result took that branch — including a configuration refusal that
718
+ never touched the OS (`Unknown AI tool`, `No AI tool specified`) and a genuinely
719
+ uninstalled binary — blaming inaccessible host credentials and returning before
720
+ the more useful generic remediation. `UNATTEMPTED` is still recorded from
721
+ `never_launched` alone; only the *explanation* is graded.
568
722
 
569
723
  **Retirement path for `ai.network_access`.** The loader deliberately never reads
570
724
  the key (an un-migrated `.wade.yml` keeps loading), `strip_retired_network_access`
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "wade-cli"
7
- version = "1.0.0"
7
+ version = "1.1.0"
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.0.0"
3
+ __version__ = "1.1.0"