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.
- {wade_cli-1.2.6 → wade_cli-1.2.7}/CHANGELOG.md +6 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/KNOWLEDGE.ratings.jsonl +2 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/PKG-INFO +13 -1
- {wade_cli-1.2.6 → wade_cli-1.2.7}/README.md +12 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/architecture.md +48 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/extending.md +5 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/pyproject.toml +1 -1
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/__init__.py +1 -1
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/main.py +28 -6
- wade_cli-1.2.7/src/wade/models/interactive_plan.py +90 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/base.py +16 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/clickup.py +36 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/github.py +32 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/markdown.py +19 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/draft_pr.py +29 -1
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/interactive_plan_service.py +104 -26
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/knowledge_service.py +73 -9
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/native_plan_service.py +30 -5
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/plan_service.py +1157 -289
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/session_composition_service.py +16 -1
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/plan_validation.py +4 -3
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/safe_state.py +142 -5
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_permission_mode.py +40 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/test_clickup.py +20 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/test_github.py +40 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/test_markdown.py +18 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_ai_resolution.py +10 -7
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_draft_pr_retarget.py +130 -2
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_interactive_plan_service.py +54 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_knowledge_service.py +58 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_native_plan_service.py +21 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_plan_service.py +1439 -59
- wade_cli-1.2.7/tests/unit/test_utils/test_safe_state.py +123 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/uv.lock +1 -1
- wade_cli-1.2.6/src/wade/models/interactive_plan.py +0 -35
- {wade_cli-1.2.6 → wade_cli-1.2.7}/.gitattributes +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/auto-version.yml +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/ci.yml +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/pr-title-lint.yml +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/publish.yml +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/.github/workflows/release.yml +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/.gitignore +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/.pre-commit-config.yaml +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/.wade.yml +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/AGENTS.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/CONTRIBUTING.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/KNOWLEDGE.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/assets/wade.png +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/docker-compose.e2e.yml +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/crossby-native-planning-checkpoint.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/documentation-policies.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/native-cli-plan-verification.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/skills-system.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/testing.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/docs/dev/workflows-and-skills.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/install.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/auto_version.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/changelog.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/check-all.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/check.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/fmt.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/hooks/pre-push +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/install-hooks.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/probe_native_plan_handoff.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/release.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/setup-worktree.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-concurrency.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-e2e-docker.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-e2e.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-live-ai-taskr.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-live-ai.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test-live-gh.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/scripts/test.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/__main__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/admin.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/autocomplete.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/deps_session.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/hook.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/implementation_session.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/knowledge.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/plan_session.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/review.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/review_pr_comments_session.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/session.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/session_shared.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/skills.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/task.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/cli/worktree.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/config/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/config/loader.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/config/migrations.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/config/schema.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/branch.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/hooks.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/pr.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/repo.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/stash.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/sync.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/git/worktree.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/hooks/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/hooks/cli.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/hooks/policies.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/logging/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/logging/context.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/logging/setup.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/batch.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/config.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/delegation.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/deps.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/events.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/hooks.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/permission.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/plan_bundle.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/readiness.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/review.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/review_cycle.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/session.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/session_manifest.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/skill.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/task.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/workflow.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/models/worktree.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/_pr_delegate.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/providers/registry.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/ai_resolution.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/batch_review_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/bot_trigger.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/check_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/delegation_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/deps_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/documentation_receipt_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/_shared.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/batch.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/bootstrap.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/cleanup.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/core.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/done.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/lifecycle.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/sync.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/implementation_service/usage_tracking.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/auth.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/commands.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/config_io.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/manifest.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/migrations.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/prompts_ai.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/prompts_setup.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/init_service/shell.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/knowledge_recovery.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/knowledge_search.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/prompt_delivery.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_cycle_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_delegation_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_record_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/review_settle.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/skill_diagnostics_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/skill_invocation_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/smart_start.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/services/task_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/catalog.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/discovery.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/doc_targets.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/installer.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/materializer.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/pointer.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/resolver.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/skills/validation.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/ui/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/ui/console.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/ui/prompts.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/body_markers.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/clipboard.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/conventional.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/filelock.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/gitref.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/http.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/install.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/knowledge_file.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/markdown.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/markers.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/paths.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/process.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/runtime_env.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/slug.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/stale_base.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/templates.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/terminal.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/token_usage_markdown.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/src/wade/utils/update_check.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/agents-pointer.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/hooks/commit-msg +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/hooks/pre-commit +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/hooks/pre-push +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/deps-analysis.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/implement-context.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/plan-session.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-batch.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-code.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-finding-admission.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-plan.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-pr-comments.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-batch.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-code.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-deps.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-full-branch.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-implementation.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-plan.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/review-result-pr-comments.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/session-start-implement.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/session-start-plan.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/prompts/session-start-review.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/setup-worktree.sh.example +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/batch-review/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/code-review/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/dependency-analysis/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/feedback-fix-review/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/implementation/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/knowledge/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/plan-review/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/planning/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/review-comments/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/task/SKILL.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/task/examples.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/task/plan-format.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/skills/task/reference/session-summary-format.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/statusline-command.sh +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/completion.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/documentation-step.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/interaction-policy.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/knowledge-step.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/_partials/review-budget.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/implementation.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/plan.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/documentation.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/new-plan.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/plan-output-contract.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/pr-summary-format.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/recovery.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/session-summary-format.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/reference/tracking-issues.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/templates/workflows/review-pr-comments.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/test_batch_multi_pr.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/test_knowledge_merge.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/test_lock_retry.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/concurrency/test_stash_race.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/conftest.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/_support.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/conftest.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/mock_gh_script.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_admin_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_check_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_implement_work_done_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_knowledge_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_mock_gh_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_plan_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_review_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_smart_start_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_task_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/e2e/test_work_sync_list_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/live/taskr_header_hi_body.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/live/taskr_header_howdy_body.md +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/transcripts/claude_session.txt +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/transcripts/codex_session.txt +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/transcripts/copilot_session.txt +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/fixtures/transcripts/generic_session.txt +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_autostash.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_check.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_dynamic_skill_sessions.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_git.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_implementation_lifecycle.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_init.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_knowledge.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_markdown_provider.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_skill_context_budget.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/integration/test_skill_install.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/live/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/live/test_wade_live_ai.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/live/test_wade_live_ai_taskr.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/live/test_wade_live_gh.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/test_cli_basics.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/conftest.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_autocomplete.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_done_doc_pass_advisory.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_done_review_hint.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_knowledge_cli.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_review_cli.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_session_subapps.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_shell_init.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_skills_session_cli.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_task_cli.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_work_ai_flags.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_cli/test_work_cli.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_bot_review_config.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_dynamic_skill_config.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_loader.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_merge_strategy_migration.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_migrations.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_config/test_migrations_atomic.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_console.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_effort.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_all_patches_present.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_branch_list.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_branch_slugify.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_detached_worktree.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_is_merged_into.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_main_checkout_root.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_merge_count.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_pr_base.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_pr_lookup.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_pr_retry.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_pr_title.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_repo.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_reset_branch.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_scaffold_commit.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_stash_drop.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_sync_conflicted_files.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_tip_commit_is_empty.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_git/test_worktree_remove.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/test_hook_cli.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/test_policies.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/test_post_tool_use.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_hooks/test_session_start.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_batch.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_config_models.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_delegation.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_deps_models.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_deps_partition.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_review.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_review_expectation.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_task_models.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_models/test_workflow_models.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_providers/test_github_pr.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_scripts/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_scripts/test_changelog.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_batch_build_cmd.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_batch_pr_index.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_batch_review_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_allowlist.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_guard_matcher.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_hook_timeout.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_post_tool_use.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_pre_push.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bootstrap_session_start.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_bot_trigger.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_catchup.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_catchup_reconcile.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_check.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_cleanup_loss_guard.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_codex_worktree_launch_context.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_delegation_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_deps_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_documentation_receipt.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_done_gates.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_done_idempotent.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_done_plan_flag.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_done_pr_title_sync.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_draft_pr_base_fetch.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_implementation_done_sync.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_implementation_launch_context.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_implementation_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_implementation_service_resume.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_init.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_init_shell_integration.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_knowledge_recovery.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_knowledge_search.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_managed_git_hooks.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_no_direct_git.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_plan_startup_events.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_poll_for_reviews.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_post_implementation_lifecycle.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_pr_lookup_guards.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_pr_summary_path.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_pre_push_backstop.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_preserve_session_data.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_prompt_delivery.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_push_recovery.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_resolve_task_branch.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_resume_autonomy.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_cycle_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_delegation_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_receipts.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_records.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_review_status_block.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_skill_diagnostics_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_skill_invocation_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_smart_start.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_smart_start_resume.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_stale_base_surface.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_sync_base_branch.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_task_service.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_tracked_managed_files.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_services/test_worktree_gitignore.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_crossby_contract.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_doc_targets.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_dynamic_skills.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_generic_builtin_boundaries.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_knowledge_attributes.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_managed_gitignore.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_pointer.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_skills/test_review_budget_partial.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/__init__.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_body_markers.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_conventional.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_filelock.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_gitref.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_http.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_install.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_markdown.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_markers.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_plan_validation.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_process.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_prompts.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_runtime_env.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_slug.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_stale_base.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_terminal.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_terminal_launch.py +0 -0
- {wade_cli-1.2.6 → wade_cli-1.2.7}/tests/unit/test_utils/test_update_check.py +0 -0
- {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.
|
|
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
|
|
@@ -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
|
-
|
|
644
|
-
|
|
645
|
-
|
|
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
|
-
|
|
660
|
+
effort_explicit=effort is not None,
|
|
661
|
+
yolo=yolo or None,
|
|
649
662
|
permission_mode=permission_mode,
|
|
650
663
|
sandbox=sandbox,
|
|
651
|
-
|
|
652
|
-
|
|
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,
|