erk 0.4.5__py3-none-any.whl
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.
- erk/__init__.py +12 -0
- erk/__main__.py +6 -0
- erk/agent_docs/__init__.py +5 -0
- erk/agent_docs/models.py +123 -0
- erk/agent_docs/operations.py +666 -0
- erk/artifacts/__init__.py +5 -0
- erk/artifacts/artifact_health.py +623 -0
- erk/artifacts/detection.py +16 -0
- erk/artifacts/discovery.py +343 -0
- erk/artifacts/models.py +63 -0
- erk/artifacts/staleness.py +56 -0
- erk/artifacts/state.py +100 -0
- erk/artifacts/sync.py +624 -0
- erk/cli/__init__.py +0 -0
- erk/cli/activation.py +132 -0
- erk/cli/alias.py +53 -0
- erk/cli/cli.py +221 -0
- erk/cli/commands/__init__.py +0 -0
- erk/cli/commands/admin.py +153 -0
- erk/cli/commands/artifact/__init__.py +1 -0
- erk/cli/commands/artifact/check.py +260 -0
- erk/cli/commands/artifact/group.py +31 -0
- erk/cli/commands/artifact/list_cmd.py +89 -0
- erk/cli/commands/artifact/show.py +62 -0
- erk/cli/commands/artifact/sync_cmd.py +39 -0
- erk/cli/commands/branch/__init__.py +26 -0
- erk/cli/commands/branch/assign_cmd.py +152 -0
- erk/cli/commands/branch/checkout_cmd.py +357 -0
- erk/cli/commands/branch/create_cmd.py +161 -0
- erk/cli/commands/branch/list_cmd.py +82 -0
- erk/cli/commands/branch/unassign_cmd.py +197 -0
- erk/cli/commands/cc/__init__.py +15 -0
- erk/cli/commands/cc/jsonl_cmd.py +20 -0
- erk/cli/commands/cc/session/AGENTS.md +30 -0
- erk/cli/commands/cc/session/CLAUDE.md +1 -0
- erk/cli/commands/cc/session/__init__.py +15 -0
- erk/cli/commands/cc/session/list_cmd.py +167 -0
- erk/cli/commands/cc/session/show_cmd.py +175 -0
- erk/cli/commands/completion.py +89 -0
- erk/cli/commands/completions.py +165 -0
- erk/cli/commands/config.py +327 -0
- erk/cli/commands/docs/__init__.py +1 -0
- erk/cli/commands/docs/group.py +16 -0
- erk/cli/commands/docs/sync.py +121 -0
- erk/cli/commands/docs/validate.py +102 -0
- erk/cli/commands/doctor.py +243 -0
- erk/cli/commands/down.py +171 -0
- erk/cli/commands/exec/__init__.py +1 -0
- erk/cli/commands/exec/group.py +164 -0
- erk/cli/commands/exec/scripts/AGENTS.md +79 -0
- erk/cli/commands/exec/scripts/CLAUDE.md +1 -0
- erk/cli/commands/exec/scripts/__init__.py +5 -0
- erk/cli/commands/exec/scripts/add_reaction_to_comment.py +69 -0
- erk/cli/commands/exec/scripts/add_remote_execution_note.py +68 -0
- erk/cli/commands/exec/scripts/check_impl.py +152 -0
- erk/cli/commands/exec/scripts/ci_update_pr_body.py +294 -0
- erk/cli/commands/exec/scripts/create_extraction_branch.py +138 -0
- erk/cli/commands/exec/scripts/create_extraction_plan.py +242 -0
- erk/cli/commands/exec/scripts/create_issue_from_session.py +103 -0
- erk/cli/commands/exec/scripts/create_plan_from_context.py +103 -0
- erk/cli/commands/exec/scripts/create_worker_impl_from_issue.py +93 -0
- erk/cli/commands/exec/scripts/detect_trunk_branch.py +121 -0
- erk/cli/commands/exec/scripts/exit_plan_mode_hook.py +777 -0
- erk/cli/commands/exec/scripts/extract_latest_plan.py +49 -0
- erk/cli/commands/exec/scripts/extract_session_from_issue.py +150 -0
- erk/cli/commands/exec/scripts/find_project_dir.py +214 -0
- erk/cli/commands/exec/scripts/generate_pr_summary.py +112 -0
- erk/cli/commands/exec/scripts/get_closing_text.py +98 -0
- erk/cli/commands/exec/scripts/get_embedded_prompt.py +62 -0
- erk/cli/commands/exec/scripts/get_plan_metadata.py +95 -0
- erk/cli/commands/exec/scripts/get_pr_body_footer.py +70 -0
- erk/cli/commands/exec/scripts/get_pr_discussion_comments.py +149 -0
- erk/cli/commands/exec/scripts/get_pr_review_comments.py +155 -0
- erk/cli/commands/exec/scripts/impl_init.py +158 -0
- erk/cli/commands/exec/scripts/impl_signal.py +375 -0
- erk/cli/commands/exec/scripts/impl_verify.py +49 -0
- erk/cli/commands/exec/scripts/issue_title_to_filename.py +34 -0
- erk/cli/commands/exec/scripts/list_sessions.py +296 -0
- erk/cli/commands/exec/scripts/mark_impl_ended.py +188 -0
- erk/cli/commands/exec/scripts/mark_impl_started.py +188 -0
- erk/cli/commands/exec/scripts/marker.py +163 -0
- erk/cli/commands/exec/scripts/objective_save_to_issue.py +109 -0
- erk/cli/commands/exec/scripts/plan_save_to_issue.py +269 -0
- erk/cli/commands/exec/scripts/plan_update_issue.py +147 -0
- erk/cli/commands/exec/scripts/post_extraction_comment.py +237 -0
- erk/cli/commands/exec/scripts/post_or_update_pr_summary.py +133 -0
- erk/cli/commands/exec/scripts/post_pr_inline_comment.py +143 -0
- erk/cli/commands/exec/scripts/post_workflow_started_comment.py +168 -0
- erk/cli/commands/exec/scripts/preprocess_session.py +777 -0
- erk/cli/commands/exec/scripts/quick_submit.py +32 -0
- erk/cli/commands/exec/scripts/rebase_with_conflict_resolution.py +260 -0
- erk/cli/commands/exec/scripts/reply_to_discussion_comment.py +173 -0
- erk/cli/commands/exec/scripts/resolve_review_thread.py +170 -0
- erk/cli/commands/exec/scripts/session_id_injector_hook.py +52 -0
- erk/cli/commands/exec/scripts/setup_impl_from_issue.py +159 -0
- erk/cli/commands/exec/scripts/slot_objective.py +102 -0
- erk/cli/commands/exec/scripts/tripwires_reminder_hook.py +20 -0
- erk/cli/commands/exec/scripts/update_dispatch_info.py +116 -0
- erk/cli/commands/exec/scripts/user_prompt_hook.py +113 -0
- erk/cli/commands/exec/scripts/validate_plan_content.py +98 -0
- erk/cli/commands/exec/scripts/wrap_plan_in_metadata_block.py +34 -0
- erk/cli/commands/implement.py +695 -0
- erk/cli/commands/implement_shared.py +649 -0
- erk/cli/commands/info/__init__.py +14 -0
- erk/cli/commands/info/release_notes_cmd.py +128 -0
- erk/cli/commands/init.py +801 -0
- erk/cli/commands/land_cmd.py +690 -0
- erk/cli/commands/log_cmd.py +137 -0
- erk/cli/commands/md/__init__.py +5 -0
- erk/cli/commands/md/check.py +118 -0
- erk/cli/commands/md/group.py +14 -0
- erk/cli/commands/navigation_helpers.py +430 -0
- erk/cli/commands/objective/__init__.py +16 -0
- erk/cli/commands/objective/list_cmd.py +47 -0
- erk/cli/commands/objective_helpers.py +132 -0
- erk/cli/commands/plan/__init__.py +32 -0
- erk/cli/commands/plan/check_cmd.py +174 -0
- erk/cli/commands/plan/close_cmd.py +69 -0
- erk/cli/commands/plan/create_cmd.py +120 -0
- erk/cli/commands/plan/docs/__init__.py +18 -0
- erk/cli/commands/plan/docs/extract_cmd.py +53 -0
- erk/cli/commands/plan/docs/unextract_cmd.py +38 -0
- erk/cli/commands/plan/docs/unextracted_cmd.py +72 -0
- erk/cli/commands/plan/extraction/__init__.py +16 -0
- erk/cli/commands/plan/extraction/complete_cmd.py +101 -0
- erk/cli/commands/plan/extraction/create_raw_cmd.py +63 -0
- erk/cli/commands/plan/get.py +71 -0
- erk/cli/commands/plan/list_cmd.py +754 -0
- erk/cli/commands/plan/log_cmd.py +440 -0
- erk/cli/commands/plan/start_cmd.py +459 -0
- erk/cli/commands/planner/__init__.py +40 -0
- erk/cli/commands/planner/configure_cmd.py +73 -0
- erk/cli/commands/planner/connect_cmd.py +96 -0
- erk/cli/commands/planner/create_cmd.py +148 -0
- erk/cli/commands/planner/list_cmd.py +51 -0
- erk/cli/commands/planner/register_cmd.py +105 -0
- erk/cli/commands/planner/set_default_cmd.py +23 -0
- erk/cli/commands/planner/unregister_cmd.py +43 -0
- erk/cli/commands/pr/__init__.py +23 -0
- erk/cli/commands/pr/check_cmd.py +112 -0
- erk/cli/commands/pr/checkout_cmd.py +165 -0
- erk/cli/commands/pr/fix_conflicts_cmd.py +82 -0
- erk/cli/commands/pr/parse_pr_reference.py +10 -0
- erk/cli/commands/pr/submit_cmd.py +360 -0
- erk/cli/commands/pr/sync_cmd.py +181 -0
- erk/cli/commands/prepare_cwd_recovery.py +60 -0
- erk/cli/commands/project/__init__.py +16 -0
- erk/cli/commands/project/init_cmd.py +91 -0
- erk/cli/commands/run/__init__.py +17 -0
- erk/cli/commands/run/list_cmd.py +189 -0
- erk/cli/commands/run/logs_cmd.py +54 -0
- erk/cli/commands/run/shared.py +19 -0
- erk/cli/commands/shell_integration.py +29 -0
- erk/cli/commands/slot/__init__.py +23 -0
- erk/cli/commands/slot/check_cmd.py +277 -0
- erk/cli/commands/slot/common.py +314 -0
- erk/cli/commands/slot/init_pool_cmd.py +157 -0
- erk/cli/commands/slot/list_cmd.py +228 -0
- erk/cli/commands/slot/repair_cmd.py +190 -0
- erk/cli/commands/stack/__init__.py +23 -0
- erk/cli/commands/stack/consolidate_cmd.py +470 -0
- erk/cli/commands/stack/list_cmd.py +79 -0
- erk/cli/commands/stack/move_cmd.py +309 -0
- erk/cli/commands/stack/split_old/README.md +64 -0
- erk/cli/commands/stack/split_old/__init__.py +5 -0
- erk/cli/commands/stack/split_old/command.py +233 -0
- erk/cli/commands/stack/split_old/display.py +116 -0
- erk/cli/commands/stack/split_old/plan.py +216 -0
- erk/cli/commands/status.py +58 -0
- erk/cli/commands/submit.py +768 -0
- erk/cli/commands/up.py +154 -0
- erk/cli/commands/upgrade.py +82 -0
- erk/cli/commands/wt/__init__.py +29 -0
- erk/cli/commands/wt/checkout_cmd.py +110 -0
- erk/cli/commands/wt/create_cmd.py +998 -0
- erk/cli/commands/wt/current_cmd.py +35 -0
- erk/cli/commands/wt/delete_cmd.py +573 -0
- erk/cli/commands/wt/list_cmd.py +332 -0
- erk/cli/commands/wt/rename_cmd.py +66 -0
- erk/cli/config.py +242 -0
- erk/cli/constants.py +29 -0
- erk/cli/core.py +65 -0
- erk/cli/debug.py +9 -0
- erk/cli/ensure-conversion-tasks.md +288 -0
- erk/cli/ensure.py +628 -0
- erk/cli/github_parsing.py +96 -0
- erk/cli/graphite.py +81 -0
- erk/cli/graphite_command.py +80 -0
- erk/cli/help_formatter.py +345 -0
- erk/cli/output.py +361 -0
- erk/cli/presets/dagster.toml +12 -0
- erk/cli/presets/generic.toml +12 -0
- erk/cli/prompt_hooks_templates/README.md +68 -0
- erk/cli/script_output.py +32 -0
- erk/cli/shell_integration/bash_wrapper.sh +32 -0
- erk/cli/shell_integration/fish_wrapper.fish +39 -0
- erk/cli/shell_integration/handler.py +338 -0
- erk/cli/shell_integration/zsh_wrapper.sh +32 -0
- erk/cli/shell_utils.py +171 -0
- erk/cli/subprocess_utils.py +92 -0
- erk/cli/uvx_detection.py +59 -0
- erk/core/__init__.py +0 -0
- erk/core/claude_executor.py +511 -0
- erk/core/claude_settings.py +317 -0
- erk/core/command_log.py +406 -0
- erk/core/commit_message_generator.py +234 -0
- erk/core/completion.py +10 -0
- erk/core/consolidation_utils.py +177 -0
- erk/core/context.py +570 -0
- erk/core/display/__init__.py +4 -0
- erk/core/display/abc.py +24 -0
- erk/core/display/real.py +30 -0
- erk/core/display_utils.py +526 -0
- erk/core/file_utils.py +87 -0
- erk/core/health_checks.py +1315 -0
- erk/core/health_checks_dogfooder/__init__.py +85 -0
- erk/core/health_checks_dogfooder/deprecated_dot_agent_config.py +64 -0
- erk/core/health_checks_dogfooder/legacy_claude_docs.py +69 -0
- erk/core/health_checks_dogfooder/legacy_config_locations.py +122 -0
- erk/core/health_checks_dogfooder/legacy_erk_docs_agent.py +61 -0
- erk/core/health_checks_dogfooder/legacy_erk_kits_folder.py +60 -0
- erk/core/health_checks_dogfooder/legacy_hook_settings.py +104 -0
- erk/core/health_checks_dogfooder/legacy_kit_yaml.py +78 -0
- erk/core/health_checks_dogfooder/legacy_kits_toml.py +43 -0
- erk/core/health_checks_dogfooder/outdated_erk_skill.py +43 -0
- erk/core/implementation_queue/__init__.py +1 -0
- erk/core/implementation_queue/github/__init__.py +8 -0
- erk/core/implementation_queue/github/abc.py +7 -0
- erk/core/implementation_queue/github/noop.py +38 -0
- erk/core/implementation_queue/github/printing.py +43 -0
- erk/core/implementation_queue/github/real.py +119 -0
- erk/core/init_utils.py +227 -0
- erk/core/output_filter.py +338 -0
- erk/core/plan_store/__init__.py +6 -0
- erk/core/planner/__init__.py +1 -0
- erk/core/planner/registry_abc.py +8 -0
- erk/core/planner/registry_fake.py +129 -0
- erk/core/planner/registry_real.py +195 -0
- erk/core/planner/types.py +7 -0
- erk/core/pr_utils.py +30 -0
- erk/core/release_notes.py +263 -0
- erk/core/repo_discovery.py +126 -0
- erk/core/script_writer.py +41 -0
- erk/core/services/__init__.py +1 -0
- erk/core/services/plan_list_service.py +94 -0
- erk/core/shell.py +51 -0
- erk/core/user_feedback.py +11 -0
- erk/core/version_check.py +55 -0
- erk/core/workflow_display.py +75 -0
- erk/core/worktree_pool.py +190 -0
- erk/core/worktree_utils.py +300 -0
- erk/data/CHANGELOG.md +438 -0
- erk/data/__init__.py +1 -0
- erk/data/claude/agents/devrun.md +180 -0
- erk/data/claude/commands/erk/__init__.py +0 -0
- erk/data/claude/commands/erk/create-extraction-plan.md +360 -0
- erk/data/claude/commands/erk/fix-conflicts.md +25 -0
- erk/data/claude/commands/erk/git-pr-push.md +345 -0
- erk/data/claude/commands/erk/implement-stacked-plan.md +96 -0
- erk/data/claude/commands/erk/land.md +193 -0
- erk/data/claude/commands/erk/objective-create.md +370 -0
- erk/data/claude/commands/erk/objective-list.md +34 -0
- erk/data/claude/commands/erk/objective-next-plan.md +220 -0
- erk/data/claude/commands/erk/objective-update-with-landed-pr.md +216 -0
- erk/data/claude/commands/erk/plan-implement.md +202 -0
- erk/data/claude/commands/erk/plan-save.md +45 -0
- erk/data/claude/commands/erk/plan-submit.md +39 -0
- erk/data/claude/commands/erk/pr-address.md +367 -0
- erk/data/claude/commands/erk/pr-submit.md +58 -0
- erk/data/claude/skills/dignified-python/SKILL.md +48 -0
- erk/data/claude/skills/dignified-python/cli-patterns.md +155 -0
- erk/data/claude/skills/dignified-python/dignified-python-core.md +1190 -0
- erk/data/claude/skills/dignified-python/subprocess.md +99 -0
- erk/data/claude/skills/dignified-python/versions/python-3.10.md +517 -0
- erk/data/claude/skills/dignified-python/versions/python-3.11.md +536 -0
- erk/data/claude/skills/dignified-python/versions/python-3.12.md +662 -0
- erk/data/claude/skills/dignified-python/versions/python-3.13.md +653 -0
- erk/data/claude/skills/erk-diff-analysis/SKILL.md +27 -0
- erk/data/claude/skills/erk-diff-analysis/references/commit-message-prompt.md +78 -0
- erk/data/claude/skills/learned-docs/SKILL.md +362 -0
- erk/data/github/actions/setup-claude-erk/action.yml +11 -0
- erk/data/github/prompts/dignified-python-review.md +125 -0
- erk/data/github/workflows/dignified-python-review.yml +61 -0
- erk/data/github/workflows/erk-impl.yml +251 -0
- erk/hooks/__init__.py +1 -0
- erk/hooks/decorators.py +319 -0
- erk/status/__init__.py +8 -0
- erk/status/collectors/__init__.py +9 -0
- erk/status/collectors/base.py +52 -0
- erk/status/collectors/git.py +76 -0
- erk/status/collectors/github.py +81 -0
- erk/status/collectors/graphite.py +80 -0
- erk/status/collectors/impl.py +145 -0
- erk/status/models/__init__.py +4 -0
- erk/status/models/status_data.py +404 -0
- erk/status/orchestrator.py +169 -0
- erk/status/renderers/__init__.py +5 -0
- erk/status/renderers/simple.py +322 -0
- erk/tui/AGENTS.md +193 -0
- erk/tui/CLAUDE.md +1 -0
- erk/tui/__init__.py +1 -0
- erk/tui/app.py +1404 -0
- erk/tui/commands/__init__.py +1 -0
- erk/tui/commands/executor.py +66 -0
- erk/tui/commands/provider.py +165 -0
- erk/tui/commands/real_executor.py +63 -0
- erk/tui/commands/registry.py +121 -0
- erk/tui/commands/types.py +36 -0
- erk/tui/data/__init__.py +1 -0
- erk/tui/data/provider.py +492 -0
- erk/tui/data/types.py +104 -0
- erk/tui/filtering/__init__.py +1 -0
- erk/tui/filtering/logic.py +43 -0
- erk/tui/filtering/types.py +55 -0
- erk/tui/jsonl_viewer/__init__.py +1 -0
- erk/tui/jsonl_viewer/app.py +61 -0
- erk/tui/jsonl_viewer/models.py +208 -0
- erk/tui/jsonl_viewer/widgets.py +204 -0
- erk/tui/sorting/__init__.py +6 -0
- erk/tui/sorting/logic.py +55 -0
- erk/tui/sorting/types.py +68 -0
- erk/tui/styles/dash.tcss +95 -0
- erk/tui/widgets/__init__.py +1 -0
- erk/tui/widgets/command_output.py +112 -0
- erk/tui/widgets/plan_table.py +276 -0
- erk/tui/widgets/status_bar.py +116 -0
- erk-0.4.5.dist-info/METADATA +376 -0
- erk-0.4.5.dist-info/RECORD +331 -0
- erk-0.4.5.dist-info/WHEEL +4 -0
- erk-0.4.5.dist-info/entry_points.txt +2 -0
- erk-0.4.5.dist-info/licenses/LICENSE.md +3 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Static exec group for erk scripts.
|
|
2
|
+
|
|
3
|
+
This module provides the `erk exec` command group with all scripts
|
|
4
|
+
statically registered.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
# Import and register all scripts
|
|
10
|
+
from erk.cli.commands.exec.scripts.add_reaction_to_comment import (
|
|
11
|
+
add_reaction_to_comment,
|
|
12
|
+
)
|
|
13
|
+
from erk.cli.commands.exec.scripts.add_remote_execution_note import (
|
|
14
|
+
add_remote_execution_note,
|
|
15
|
+
)
|
|
16
|
+
from erk.cli.commands.exec.scripts.check_impl import check_impl
|
|
17
|
+
from erk.cli.commands.exec.scripts.ci_update_pr_body import ci_update_pr_body
|
|
18
|
+
from erk.cli.commands.exec.scripts.create_extraction_branch import (
|
|
19
|
+
create_extraction_branch,
|
|
20
|
+
)
|
|
21
|
+
from erk.cli.commands.exec.scripts.create_extraction_plan import (
|
|
22
|
+
create_extraction_plan,
|
|
23
|
+
)
|
|
24
|
+
from erk.cli.commands.exec.scripts.create_issue_from_session import (
|
|
25
|
+
create_issue_from_session,
|
|
26
|
+
)
|
|
27
|
+
from erk.cli.commands.exec.scripts.create_plan_from_context import (
|
|
28
|
+
create_plan_from_context,
|
|
29
|
+
)
|
|
30
|
+
from erk.cli.commands.exec.scripts.create_worker_impl_from_issue import (
|
|
31
|
+
create_worker_impl_from_issue,
|
|
32
|
+
)
|
|
33
|
+
from erk.cli.commands.exec.scripts.detect_trunk_branch import detect_trunk_branch
|
|
34
|
+
from erk.cli.commands.exec.scripts.exit_plan_mode_hook import exit_plan_mode_hook
|
|
35
|
+
from erk.cli.commands.exec.scripts.extract_latest_plan import extract_latest_plan
|
|
36
|
+
from erk.cli.commands.exec.scripts.extract_session_from_issue import (
|
|
37
|
+
extract_session_from_issue,
|
|
38
|
+
)
|
|
39
|
+
from erk.cli.commands.exec.scripts.find_project_dir import find_project_dir
|
|
40
|
+
from erk.cli.commands.exec.scripts.generate_pr_summary import generate_pr_summary
|
|
41
|
+
from erk.cli.commands.exec.scripts.get_closing_text import get_closing_text
|
|
42
|
+
from erk.cli.commands.exec.scripts.get_embedded_prompt import get_embedded_prompt
|
|
43
|
+
from erk.cli.commands.exec.scripts.get_plan_metadata import get_plan_metadata
|
|
44
|
+
from erk.cli.commands.exec.scripts.get_pr_body_footer import get_pr_body_footer
|
|
45
|
+
from erk.cli.commands.exec.scripts.get_pr_discussion_comments import (
|
|
46
|
+
get_pr_discussion_comments,
|
|
47
|
+
)
|
|
48
|
+
from erk.cli.commands.exec.scripts.get_pr_review_comments import (
|
|
49
|
+
get_pr_review_comments,
|
|
50
|
+
)
|
|
51
|
+
from erk.cli.commands.exec.scripts.impl_init import impl_init
|
|
52
|
+
from erk.cli.commands.exec.scripts.impl_signal import impl_signal
|
|
53
|
+
from erk.cli.commands.exec.scripts.impl_verify import impl_verify
|
|
54
|
+
from erk.cli.commands.exec.scripts.issue_title_to_filename import (
|
|
55
|
+
issue_title_to_filename,
|
|
56
|
+
)
|
|
57
|
+
from erk.cli.commands.exec.scripts.list_sessions import list_sessions
|
|
58
|
+
from erk.cli.commands.exec.scripts.mark_impl_ended import mark_impl_ended
|
|
59
|
+
from erk.cli.commands.exec.scripts.mark_impl_started import mark_impl_started
|
|
60
|
+
from erk.cli.commands.exec.scripts.marker import marker
|
|
61
|
+
from erk.cli.commands.exec.scripts.objective_save_to_issue import (
|
|
62
|
+
objective_save_to_issue,
|
|
63
|
+
)
|
|
64
|
+
from erk.cli.commands.exec.scripts.plan_save_to_issue import plan_save_to_issue
|
|
65
|
+
from erk.cli.commands.exec.scripts.plan_update_issue import plan_update_issue
|
|
66
|
+
from erk.cli.commands.exec.scripts.post_extraction_comment import (
|
|
67
|
+
post_extraction_comment,
|
|
68
|
+
)
|
|
69
|
+
from erk.cli.commands.exec.scripts.post_or_update_pr_summary import (
|
|
70
|
+
post_or_update_pr_summary,
|
|
71
|
+
)
|
|
72
|
+
from erk.cli.commands.exec.scripts.post_pr_inline_comment import (
|
|
73
|
+
post_pr_inline_comment,
|
|
74
|
+
)
|
|
75
|
+
from erk.cli.commands.exec.scripts.post_workflow_started_comment import (
|
|
76
|
+
post_workflow_started_comment,
|
|
77
|
+
)
|
|
78
|
+
from erk.cli.commands.exec.scripts.preprocess_session import preprocess_session
|
|
79
|
+
from erk.cli.commands.exec.scripts.quick_submit import quick_submit
|
|
80
|
+
from erk.cli.commands.exec.scripts.rebase_with_conflict_resolution import (
|
|
81
|
+
rebase_with_conflict_resolution,
|
|
82
|
+
)
|
|
83
|
+
from erk.cli.commands.exec.scripts.reply_to_discussion_comment import (
|
|
84
|
+
reply_to_discussion_comment,
|
|
85
|
+
)
|
|
86
|
+
from erk.cli.commands.exec.scripts.resolve_review_thread import (
|
|
87
|
+
resolve_review_thread,
|
|
88
|
+
)
|
|
89
|
+
from erk.cli.commands.exec.scripts.session_id_injector_hook import (
|
|
90
|
+
session_id_injector_hook,
|
|
91
|
+
)
|
|
92
|
+
from erk.cli.commands.exec.scripts.setup_impl_from_issue import (
|
|
93
|
+
setup_impl_from_issue,
|
|
94
|
+
)
|
|
95
|
+
from erk.cli.commands.exec.scripts.slot_objective import slot_objective
|
|
96
|
+
from erk.cli.commands.exec.scripts.tripwires_reminder_hook import (
|
|
97
|
+
tripwires_reminder_hook,
|
|
98
|
+
)
|
|
99
|
+
from erk.cli.commands.exec.scripts.update_dispatch_info import update_dispatch_info
|
|
100
|
+
from erk.cli.commands.exec.scripts.user_prompt_hook import user_prompt_hook
|
|
101
|
+
from erk.cli.commands.exec.scripts.validate_plan_content import (
|
|
102
|
+
validate_plan_content,
|
|
103
|
+
)
|
|
104
|
+
from erk.cli.commands.exec.scripts.wrap_plan_in_metadata_block import (
|
|
105
|
+
wrap_plan_in_metadata_block,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# Create the exec group (hidden from top-level help)
|
|
110
|
+
@click.group(name="exec", hidden=True)
|
|
111
|
+
def exec_group() -> None:
|
|
112
|
+
"""Execute erk workflow scripts."""
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# Register all commands
|
|
116
|
+
exec_group.add_command(add_reaction_to_comment, name="add-reaction-to-comment")
|
|
117
|
+
exec_group.add_command(add_remote_execution_note, name="add-remote-execution-note")
|
|
118
|
+
exec_group.add_command(check_impl, name="check-impl")
|
|
119
|
+
exec_group.add_command(create_extraction_branch, name="create-extraction-branch")
|
|
120
|
+
exec_group.add_command(create_extraction_plan, name="create-extraction-plan")
|
|
121
|
+
exec_group.add_command(create_issue_from_session, name="create-issue-from-session")
|
|
122
|
+
exec_group.add_command(create_plan_from_context, name="create-plan-from-context")
|
|
123
|
+
exec_group.add_command(create_worker_impl_from_issue, name="create-worker-impl-from-issue")
|
|
124
|
+
exec_group.add_command(detect_trunk_branch, name="detect-trunk-branch")
|
|
125
|
+
exec_group.add_command(exit_plan_mode_hook, name="exit-plan-mode-hook")
|
|
126
|
+
exec_group.add_command(extract_latest_plan, name="extract-latest-plan")
|
|
127
|
+
exec_group.add_command(extract_session_from_issue, name="extract-session-from-issue")
|
|
128
|
+
exec_group.add_command(find_project_dir, name="find-project-dir")
|
|
129
|
+
exec_group.add_command(generate_pr_summary, name="generate-pr-summary")
|
|
130
|
+
exec_group.add_command(get_closing_text, name="get-closing-text")
|
|
131
|
+
exec_group.add_command(get_plan_metadata, name="get-plan-metadata")
|
|
132
|
+
exec_group.add_command(get_embedded_prompt, name="get-embedded-prompt")
|
|
133
|
+
exec_group.add_command(get_pr_body_footer, name="get-pr-body-footer")
|
|
134
|
+
exec_group.add_command(get_pr_discussion_comments, name="get-pr-discussion-comments")
|
|
135
|
+
exec_group.add_command(get_pr_review_comments, name="get-pr-review-comments")
|
|
136
|
+
exec_group.add_command(impl_init, name="impl-init")
|
|
137
|
+
exec_group.add_command(impl_signal, name="impl-signal")
|
|
138
|
+
exec_group.add_command(impl_verify, name="impl-verify")
|
|
139
|
+
exec_group.add_command(issue_title_to_filename, name="issue-title-to-filename")
|
|
140
|
+
exec_group.add_command(list_sessions, name="list-sessions")
|
|
141
|
+
exec_group.add_command(mark_impl_ended, name="mark-impl-ended")
|
|
142
|
+
exec_group.add_command(mark_impl_started, name="mark-impl-started")
|
|
143
|
+
exec_group.add_command(marker, name="marker")
|
|
144
|
+
exec_group.add_command(objective_save_to_issue, name="objective-save-to-issue")
|
|
145
|
+
exec_group.add_command(plan_save_to_issue, name="plan-save-to-issue")
|
|
146
|
+
exec_group.add_command(plan_update_issue, name="plan-update-issue")
|
|
147
|
+
exec_group.add_command(post_extraction_comment, name="post-extraction-comment")
|
|
148
|
+
exec_group.add_command(post_or_update_pr_summary, name="post-or-update-pr-summary")
|
|
149
|
+
exec_group.add_command(post_pr_inline_comment, name="post-pr-inline-comment")
|
|
150
|
+
exec_group.add_command(post_workflow_started_comment, name="post-workflow-started-comment")
|
|
151
|
+
exec_group.add_command(preprocess_session, name="preprocess-session")
|
|
152
|
+
exec_group.add_command(quick_submit, name="quick-submit")
|
|
153
|
+
exec_group.add_command(rebase_with_conflict_resolution, name="rebase-with-conflict-resolution")
|
|
154
|
+
exec_group.add_command(resolve_review_thread, name="resolve-review-thread")
|
|
155
|
+
exec_group.add_command(reply_to_discussion_comment, name="reply-to-discussion-comment")
|
|
156
|
+
exec_group.add_command(session_id_injector_hook, name="session-id-injector-hook")
|
|
157
|
+
exec_group.add_command(setup_impl_from_issue, name="setup-impl-from-issue")
|
|
158
|
+
exec_group.add_command(slot_objective, name="slot-objective")
|
|
159
|
+
exec_group.add_command(tripwires_reminder_hook, name="tripwires-reminder-hook")
|
|
160
|
+
exec_group.add_command(update_dispatch_info, name="update-dispatch-info")
|
|
161
|
+
exec_group.add_command(ci_update_pr_body)
|
|
162
|
+
exec_group.add_command(user_prompt_hook, name="user-prompt-hook")
|
|
163
|
+
exec_group.add_command(validate_plan_content, name="validate-plan-content")
|
|
164
|
+
exec_group.add_command(wrap_plan_in_metadata_block, name="wrap-plan-in-metadata-block")
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Exec Script Standards
|
|
2
|
+
|
|
3
|
+
## Required Pattern: Click Context Dependency Injection
|
|
4
|
+
|
|
5
|
+
All exec CLI commands in this folder MUST use Click's context system for dependency injection.
|
|
6
|
+
|
|
7
|
+
### Required Pattern
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import click
|
|
11
|
+
from erk_shared.context.helpers import require_cwd
|
|
12
|
+
|
|
13
|
+
@click.command(name="my-command")
|
|
14
|
+
@click.pass_context
|
|
15
|
+
def my_command(ctx: click.Context) -> None:
|
|
16
|
+
"""Command description."""
|
|
17
|
+
cwd = require_cwd(ctx)
|
|
18
|
+
# Use cwd instead of Path.cwd()
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Why This Pattern?
|
|
22
|
+
|
|
23
|
+
1. **Testability**: Tests inject dependencies via `obj=ErkContext.for_test(cwd=tmp_path)`
|
|
24
|
+
2. **No monkeypatching**: Tests don't need `monkeypatch.chdir()` or filesystem manipulation
|
|
25
|
+
3. **Explicit dependencies**: All dependencies visible in function signature via context
|
|
26
|
+
4. **Consistency**: All commands follow the same pattern
|
|
27
|
+
|
|
28
|
+
### Available Helper Functions
|
|
29
|
+
|
|
30
|
+
From `erk_shared.context.helpers`:
|
|
31
|
+
|
|
32
|
+
| Helper | Returns | Usage |
|
|
33
|
+
| ------------------------ | -------- | ------------------------- |
|
|
34
|
+
| `require_cwd(ctx)` | `Path` | Current working directory |
|
|
35
|
+
| `require_repo_root(ctx)` | `Path` | Repository root path |
|
|
36
|
+
| `require_git(ctx)` | `Git` | Git operations |
|
|
37
|
+
| `require_github(ctx)` | `GitHub` | GitHub operations |
|
|
38
|
+
|
|
39
|
+
### Anti-Patterns
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
# WRONG: bypasses dependency injection
|
|
43
|
+
def my_command() -> None:
|
|
44
|
+
progress_file = Path.cwd() / ".impl" / "progress.md"
|
|
45
|
+
|
|
46
|
+
# CORRECT: uses injected path
|
|
47
|
+
@click.pass_context
|
|
48
|
+
def my_command(ctx: click.Context) -> None:
|
|
49
|
+
cwd = require_cwd(ctx)
|
|
50
|
+
progress_file = cwd / ".impl" / "progress.md"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Testing Requirements
|
|
54
|
+
|
|
55
|
+
Every exec CLI command MUST have tests that use context injection:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from click.testing import CliRunner
|
|
59
|
+
from erk_shared.context import ErkContext
|
|
60
|
+
|
|
61
|
+
def test_my_command(tmp_path: Path) -> None:
|
|
62
|
+
"""Test using context injection."""
|
|
63
|
+
runner = CliRunner()
|
|
64
|
+
result = runner.invoke(
|
|
65
|
+
my_command,
|
|
66
|
+
["--json"],
|
|
67
|
+
obj=ErkContext.for_test(cwd=tmp_path),
|
|
68
|
+
)
|
|
69
|
+
assert result.exit_code == 0
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Test Location
|
|
73
|
+
|
|
74
|
+
- Unit tests: `tests/unit/cli/commands/exec/scripts/`
|
|
75
|
+
|
|
76
|
+
## See Also
|
|
77
|
+
|
|
78
|
+
- [Kit CLI Dependency Injection Patterns](/docs/learned/kits/dependency-injection.md)
|
|
79
|
+
- [fake-driven-testing skill](/.claude/skills/fake-driven-testing/)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Add a reaction to a PR/issue comment to mark it as addressed.
|
|
2
|
+
|
|
3
|
+
This exec command adds a reaction (typically +1) to a PR discussion comment
|
|
4
|
+
to indicate the comment has been addressed.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
erk exec add-reaction-to-comment --comment-id 12345
|
|
8
|
+
erk exec add-reaction-to-comment --comment-id 12345 --reaction "+1"
|
|
9
|
+
erk exec add-reaction-to-comment --comment-id 12345 --reaction "eyes"
|
|
10
|
+
|
|
11
|
+
Output:
|
|
12
|
+
JSON with success status
|
|
13
|
+
|
|
14
|
+
Exit Codes:
|
|
15
|
+
0: Always (even on error, to support || true pattern)
|
|
16
|
+
1: Context not initialized
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
$ erk exec add-reaction-to-comment --comment-id 12345
|
|
20
|
+
{"success": true, "comment_id": 12345, "reaction": "+1"}
|
|
21
|
+
|
|
22
|
+
$ erk exec add-reaction-to-comment --comment-id 12345 --reaction "rocket"
|
|
23
|
+
{"success": true, "comment_id": 12345, "reaction": "rocket"}
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import json
|
|
27
|
+
|
|
28
|
+
import click
|
|
29
|
+
|
|
30
|
+
from erk.cli.script_output import exit_with_error
|
|
31
|
+
from erk_shared.context.helpers import require_issues as require_github_issues
|
|
32
|
+
from erk_shared.context.helpers import require_repo_root
|
|
33
|
+
from erk_shared.github.checks import GitHubChecks
|
|
34
|
+
from erk_shared.non_ideal_state import GitHubAPIFailed
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@click.command(name="add-reaction-to-comment")
|
|
38
|
+
@click.option("--comment-id", required=True, type=int, help="Numeric comment ID")
|
|
39
|
+
@click.option(
|
|
40
|
+
"--reaction",
|
|
41
|
+
default="+1",
|
|
42
|
+
help="Reaction type: +1, -1, laugh, confused, heart, hooray, rocket, eyes",
|
|
43
|
+
)
|
|
44
|
+
@click.pass_context
|
|
45
|
+
def add_reaction_to_comment(ctx: click.Context, comment_id: int, reaction: str) -> None:
|
|
46
|
+
"""Add a reaction to a PR/issue comment.
|
|
47
|
+
|
|
48
|
+
Takes a numeric comment ID (from get-pr-discussion-comments output) and
|
|
49
|
+
adds a reaction to mark the comment as addressed. Default reaction is +1.
|
|
50
|
+
|
|
51
|
+
The GitHub API is idempotent - adding the same reaction twice returns
|
|
52
|
+
the existing reaction.
|
|
53
|
+
"""
|
|
54
|
+
# Get dependencies from context
|
|
55
|
+
repo_root = require_repo_root(ctx)
|
|
56
|
+
github_issues = require_github_issues(ctx)
|
|
57
|
+
|
|
58
|
+
# Add the reaction (exits on failure)
|
|
59
|
+
reaction_result = GitHubChecks.add_reaction(github_issues, repo_root, comment_id, reaction)
|
|
60
|
+
if isinstance(reaction_result, GitHubAPIFailed):
|
|
61
|
+
exit_with_error(reaction_result.error_type, reaction_result.message)
|
|
62
|
+
|
|
63
|
+
result = {
|
|
64
|
+
"success": True,
|
|
65
|
+
"comment_id": comment_id,
|
|
66
|
+
"reaction": reaction,
|
|
67
|
+
}
|
|
68
|
+
click.echo(json.dumps(result, indent=2))
|
|
69
|
+
raise SystemExit(0)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Add remote execution note to PR body.
|
|
2
|
+
|
|
3
|
+
This exec command appends a remote execution tracking note to a PR body.
|
|
4
|
+
Used by GitHub Actions workflows to track workflow runs that executed against a PR.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
erk exec add-remote-execution-note --pr-number 123 --run-id 456 --run-url https://...
|
|
8
|
+
|
|
9
|
+
Output:
|
|
10
|
+
Success message on stdout
|
|
11
|
+
|
|
12
|
+
Exit Codes:
|
|
13
|
+
0: Success
|
|
14
|
+
1: Error (missing arguments, gh command failed)
|
|
15
|
+
|
|
16
|
+
Examples:
|
|
17
|
+
$ erk exec add-remote-execution-note \\
|
|
18
|
+
--pr-number 1895 \\
|
|
19
|
+
--run-id 12345678 \\
|
|
20
|
+
--run-url https://github.com/owner/repo/actions/runs/12345678
|
|
21
|
+
|
|
22
|
+
Added remote execution note to PR #1895
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import click
|
|
26
|
+
|
|
27
|
+
from erk_shared.context.helpers import require_github, require_repo_root
|
|
28
|
+
from erk_shared.github.pr_footer import build_remote_execution_note
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@click.command(name="add-remote-execution-note")
|
|
32
|
+
@click.option("--pr-number", type=int, required=True, help="PR number to update")
|
|
33
|
+
@click.option("--run-id", type=str, required=True, help="Workflow run ID")
|
|
34
|
+
@click.option("--run-url", type=str, required=True, help="Full URL to workflow run")
|
|
35
|
+
@click.pass_context
|
|
36
|
+
def add_remote_execution_note(
|
|
37
|
+
ctx: click.Context, pr_number: int, run_id: str, run_url: str
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Add remote execution tracking note to PR body.
|
|
40
|
+
|
|
41
|
+
Fetches the current PR body, appends a remote execution note with the
|
|
42
|
+
workflow run link, and updates the PR. This creates a history of all
|
|
43
|
+
workflow runs that executed against the PR.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
ctx: Click context with GitHub interface
|
|
47
|
+
pr_number: The PR number to update
|
|
48
|
+
run_id: The GitHub Actions workflow run ID
|
|
49
|
+
run_url: Full URL to the workflow run
|
|
50
|
+
"""
|
|
51
|
+
github = require_github(ctx)
|
|
52
|
+
repo_root = require_repo_root(ctx)
|
|
53
|
+
|
|
54
|
+
# Get current PR body
|
|
55
|
+
current_body = github.get_pr_body(repo_root, pr_number)
|
|
56
|
+
if current_body is None:
|
|
57
|
+
current_body = ""
|
|
58
|
+
|
|
59
|
+
# Build the remote execution note
|
|
60
|
+
remote_note = build_remote_execution_note(run_id, run_url)
|
|
61
|
+
|
|
62
|
+
# Append note to body
|
|
63
|
+
new_body = f"{current_body}{remote_note}"
|
|
64
|
+
|
|
65
|
+
# Update PR body
|
|
66
|
+
github.update_pr_body(repo_root, pr_number, new_body)
|
|
67
|
+
|
|
68
|
+
click.echo(f"Added remote execution note to PR #{pr_number}")
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Check .impl/ folder structure and validate prerequisites.
|
|
2
|
+
|
|
3
|
+
This exec command validates that .impl/ folder has required files
|
|
4
|
+
(plan.md, progress.md) and checks for optional GitHub issue tracking.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
erk exec check-impl
|
|
8
|
+
erk exec check-impl --dry-run
|
|
9
|
+
|
|
10
|
+
Output:
|
|
11
|
+
JSON with validation status and tracking info (dry-run mode)
|
|
12
|
+
Instructions for implementation (normal mode)
|
|
13
|
+
|
|
14
|
+
Exit Codes:
|
|
15
|
+
0: Success
|
|
16
|
+
1: Validation error
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
$ erk exec check-impl --dry-run
|
|
20
|
+
{"valid": true, "has_issue_tracking": true, "plan_length": 1234}
|
|
21
|
+
|
|
22
|
+
$ erk exec check-impl
|
|
23
|
+
Plan loaded from .impl/plan.md
|
|
24
|
+
GitHub tracking: ENABLED (issue #123)
|
|
25
|
+
...
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
import json
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
from typing import NoReturn
|
|
31
|
+
|
|
32
|
+
import click
|
|
33
|
+
|
|
34
|
+
from erk_shared.impl_folder import read_issue_reference
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _error(msg: str) -> NoReturn:
|
|
38
|
+
"""Output error message and exit with code 1."""
|
|
39
|
+
click.echo(f"❌ Error: {msg}", err=True)
|
|
40
|
+
raise SystemExit(1)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _validate_impl_folder() -> Path:
|
|
44
|
+
"""Validate .impl/ folder exists and has required files.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Path to .impl/ directory
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
SystemExit: If validation fails
|
|
51
|
+
"""
|
|
52
|
+
impl_dir = Path.cwd() / ".impl"
|
|
53
|
+
|
|
54
|
+
if not impl_dir.exists():
|
|
55
|
+
_error("No .impl/ folder found in current directory")
|
|
56
|
+
|
|
57
|
+
plan_file = impl_dir / "plan.md"
|
|
58
|
+
if not plan_file.exists():
|
|
59
|
+
_error("No plan.md found in .impl/ folder")
|
|
60
|
+
|
|
61
|
+
progress_file = impl_dir / "progress.md"
|
|
62
|
+
if not progress_file.exists():
|
|
63
|
+
_error("No progress.md found in .impl/ folder")
|
|
64
|
+
|
|
65
|
+
return impl_dir
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _get_issue_reference(impl_dir: Path, *, silent: bool = False) -> dict[str, int | str] | None:
|
|
69
|
+
"""Get issue reference if available, None if not (non-fatal).
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
impl_dir: Path to .impl/ directory
|
|
73
|
+
silent: If True, don't print info message when tracking disabled
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Dict with issue_number and issue_url, or None if not available
|
|
77
|
+
"""
|
|
78
|
+
issue_ref = read_issue_reference(impl_dir)
|
|
79
|
+
|
|
80
|
+
if issue_ref is None:
|
|
81
|
+
# Not an error - just means no GitHub tracking
|
|
82
|
+
if not silent:
|
|
83
|
+
click.echo(
|
|
84
|
+
"ℹ️ No issue reference found - GitHub progress tracking disabled",
|
|
85
|
+
err=True,
|
|
86
|
+
)
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
"issue_number": issue_ref.issue_number,
|
|
91
|
+
"issue_url": issue_ref.issue_url,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _execute_plan(plan_content: str, issue_info: dict[str, int | str] | None) -> None:
|
|
96
|
+
"""Display plan execution instructions.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
plan_content: Content of plan.md
|
|
100
|
+
issue_info: Issue info dict or None
|
|
101
|
+
"""
|
|
102
|
+
if issue_info:
|
|
103
|
+
tracking_msg = f"GitHub tracking: ENABLED (issue #{issue_info['issue_number']})"
|
|
104
|
+
else:
|
|
105
|
+
tracking_msg = "GitHub tracking: DISABLED (no issue.json)"
|
|
106
|
+
|
|
107
|
+
msg = f"""
|
|
108
|
+
Plan loaded from .impl/plan.md
|
|
109
|
+
|
|
110
|
+
{tracking_msg}
|
|
111
|
+
|
|
112
|
+
To implement:
|
|
113
|
+
claude --permission-mode acceptEdits "/erk:plan-implement"
|
|
114
|
+
|
|
115
|
+
The /erk:plan-implement slash command will:
|
|
116
|
+
1. Execute implementation steps
|
|
117
|
+
2. Update progress.md as steps complete"""
|
|
118
|
+
|
|
119
|
+
if issue_info:
|
|
120
|
+
msg += f"\n 3. Post progress to GitHub issue #{issue_info['issue_number']}"
|
|
121
|
+
|
|
122
|
+
click.echo(msg)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@click.command(name="check-impl")
|
|
126
|
+
@click.option("--dry-run", is_flag=True, help="Validate and output JSON")
|
|
127
|
+
def check_impl(dry_run: bool) -> None:
|
|
128
|
+
"""Check .impl/ folder structure and validate prerequisites.
|
|
129
|
+
|
|
130
|
+
Validates that .impl/ folder exists with required files (plan.md, progress.md).
|
|
131
|
+
Checks for optional issue.json to enable GitHub progress tracking.
|
|
132
|
+
|
|
133
|
+
In dry-run mode, outputs JSON with validation status.
|
|
134
|
+
In normal mode, outputs instructions for running the implementation.
|
|
135
|
+
"""
|
|
136
|
+
impl_dir = _validate_impl_folder()
|
|
137
|
+
# In dry-run mode, suppress info messages to keep JSON output clean
|
|
138
|
+
issue_info = _get_issue_reference(impl_dir, silent=dry_run)
|
|
139
|
+
|
|
140
|
+
plan_file = impl_dir / "plan.md"
|
|
141
|
+
plan_content = plan_file.read_text(encoding="utf-8")
|
|
142
|
+
|
|
143
|
+
if dry_run:
|
|
144
|
+
result = {
|
|
145
|
+
"valid": True,
|
|
146
|
+
"has_issue_tracking": issue_info is not None,
|
|
147
|
+
"plan_length": len(plan_content),
|
|
148
|
+
}
|
|
149
|
+
click.echo(json.dumps(result))
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
_execute_plan(plan_content, issue_info)
|