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,137 @@
|
|
|
1
|
+
"""Log command for querying erk command history.
|
|
2
|
+
|
|
3
|
+
Provides access to the command audit trail stored in ~/.erk/command_history.jsonl.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from datetime import UTC, datetime
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from erk.core.command_log import (
|
|
11
|
+
CommandLogEntry,
|
|
12
|
+
format_relative_time,
|
|
13
|
+
is_iso_datetime_format,
|
|
14
|
+
parse_relative_time,
|
|
15
|
+
read_log_entries,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _parse_since(value: str | None) -> datetime | None:
|
|
20
|
+
"""Parse --since value into datetime.
|
|
21
|
+
|
|
22
|
+
Supports:
|
|
23
|
+
- Relative: "1 hour ago", "2 days ago", "30 minutes ago"
|
|
24
|
+
- ISO format: "2024-01-01T00:00:00"
|
|
25
|
+
"""
|
|
26
|
+
if value is None:
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
value_lower = value.strip().lower()
|
|
30
|
+
|
|
31
|
+
# Try relative time parsing
|
|
32
|
+
delta = parse_relative_time(value_lower)
|
|
33
|
+
if delta is not None:
|
|
34
|
+
return datetime.now(UTC) - delta
|
|
35
|
+
|
|
36
|
+
# Try ISO format
|
|
37
|
+
if not is_iso_datetime_format(value_lower):
|
|
38
|
+
raise click.BadParameter(
|
|
39
|
+
f"Invalid time format: {value}. Use 'N unit ago' (e.g., '1 hour ago') "
|
|
40
|
+
"or ISO format (e.g., '2024-01-01T00:00:00')"
|
|
41
|
+
)
|
|
42
|
+
return datetime.fromisoformat(value_lower)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _format_entry_line(entry: CommandLogEntry, show_cwd: bool, show_full: bool) -> str:
|
|
46
|
+
"""Format a single log entry for display."""
|
|
47
|
+
# Get time display
|
|
48
|
+
if show_full:
|
|
49
|
+
# For full mode, parse and format as full timestamp
|
|
50
|
+
if is_iso_datetime_format(entry.timestamp):
|
|
51
|
+
dt = datetime.fromisoformat(entry.timestamp)
|
|
52
|
+
time_str = dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
53
|
+
else:
|
|
54
|
+
time_str = entry.timestamp[:19]
|
|
55
|
+
else:
|
|
56
|
+
time_str = format_relative_time(entry.timestamp)
|
|
57
|
+
|
|
58
|
+
# Build command display
|
|
59
|
+
cmd_display = entry.command
|
|
60
|
+
if entry.args:
|
|
61
|
+
cmd_display += " " + " ".join(entry.args)
|
|
62
|
+
|
|
63
|
+
# Exit code indicator
|
|
64
|
+
if entry.exit_code is None:
|
|
65
|
+
status = click.style("?", fg="yellow")
|
|
66
|
+
elif entry.exit_code == 0:
|
|
67
|
+
status = click.style("✓", fg="green")
|
|
68
|
+
else:
|
|
69
|
+
status = click.style("✗", fg="red")
|
|
70
|
+
|
|
71
|
+
# Format line
|
|
72
|
+
parts = [
|
|
73
|
+
click.style(f"[{time_str}]", dim=True),
|
|
74
|
+
status,
|
|
75
|
+
cmd_display,
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
if show_cwd:
|
|
79
|
+
parts.append(click.style(f"({entry.cwd})", dim=True))
|
|
80
|
+
|
|
81
|
+
return " ".join(parts)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@click.command("log")
|
|
85
|
+
@click.option("--since", "-s", help="Show entries since time (e.g., '1 hour ago', '2024-01-01')")
|
|
86
|
+
@click.option("--filter", "-f", "command_filter", help="Filter by command substring")
|
|
87
|
+
@click.option("--cwd", "-c", "cwd_filter", help="Filter by working directory")
|
|
88
|
+
@click.option("--limit", "-n", type=int, help="Maximum entries to show (default: 50)")
|
|
89
|
+
@click.option("--full", is_flag=True, help="Show full timestamps and details")
|
|
90
|
+
@click.option("--show-cwd", is_flag=True, help="Show working directory for each entry")
|
|
91
|
+
def log_cmd(
|
|
92
|
+
since: str | None,
|
|
93
|
+
command_filter: str | None,
|
|
94
|
+
cwd_filter: str | None,
|
|
95
|
+
limit: int | None,
|
|
96
|
+
full: bool,
|
|
97
|
+
show_cwd: bool,
|
|
98
|
+
) -> None:
|
|
99
|
+
"""Show erk command history.
|
|
100
|
+
|
|
101
|
+
Displays recent erk command invocations with their status.
|
|
102
|
+
|
|
103
|
+
\b
|
|
104
|
+
Examples:
|
|
105
|
+
erk log # Show recent commands
|
|
106
|
+
erk log --since "1 hour ago" # Commands from last hour
|
|
107
|
+
erk log --filter "wt delete" # Only worktree deletions
|
|
108
|
+
erk log --cwd /path/to/repo # Commands from specific directory
|
|
109
|
+
erk log -n 10 # Show last 10 commands
|
|
110
|
+
"""
|
|
111
|
+
# Parse since option
|
|
112
|
+
since_dt = _parse_since(since)
|
|
113
|
+
|
|
114
|
+
# Default limit
|
|
115
|
+
if limit is None:
|
|
116
|
+
limit = 50
|
|
117
|
+
|
|
118
|
+
# Read entries
|
|
119
|
+
entries = read_log_entries(
|
|
120
|
+
since=since_dt,
|
|
121
|
+
until=None,
|
|
122
|
+
command_filter=command_filter,
|
|
123
|
+
cwd_filter=cwd_filter,
|
|
124
|
+
limit=limit,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if not entries:
|
|
128
|
+
click.echo(click.style("No matching entries found.", dim=True))
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
# Display entries
|
|
132
|
+
for entry in entries:
|
|
133
|
+
click.echo(_format_entry_line(entry, show_cwd, full))
|
|
134
|
+
|
|
135
|
+
# Show count if there might be more
|
|
136
|
+
if len(entries) == limit:
|
|
137
|
+
click.echo(click.style(f"\n(Showing {limit} most recent. Use --limit for more.)", dim=True))
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Check AGENTS.md standard compliance command.
|
|
2
|
+
|
|
3
|
+
This command validates that repositories follow the AGENTS.md standard where:
|
|
4
|
+
- AGENTS.md is the primary context file
|
|
5
|
+
- CLAUDE.md contains '@AGENTS.md' reference for backwards compatibility
|
|
6
|
+
|
|
7
|
+
See: https://code.claude.com/docs/en/claude-code-on-the-web
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import subprocess
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
|
|
15
|
+
from erk_shared.output.output import user_output
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.command(name="check")
|
|
19
|
+
def check_command() -> None:
|
|
20
|
+
"""Validate AGENTS.md standard compliance in the repository.
|
|
21
|
+
|
|
22
|
+
Checks that:
|
|
23
|
+
- Every CLAUDE.md file has a peer AGENTS.md file
|
|
24
|
+
- Every CLAUDE.md file contains '@AGENTS.md' reference
|
|
25
|
+
|
|
26
|
+
Exit codes:
|
|
27
|
+
- 0: All checks passed
|
|
28
|
+
- 1: Violations found
|
|
29
|
+
"""
|
|
30
|
+
# Find repository root
|
|
31
|
+
result = subprocess.run(
|
|
32
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
33
|
+
check=True,
|
|
34
|
+
capture_output=True,
|
|
35
|
+
text=True,
|
|
36
|
+
)
|
|
37
|
+
repo_root_str = result.stdout.strip()
|
|
38
|
+
repo_root_path = Path(repo_root_str)
|
|
39
|
+
|
|
40
|
+
if not repo_root_path.exists():
|
|
41
|
+
user_output(click.style("✗ Error: Repository root not found", fg="red"))
|
|
42
|
+
raise SystemExit(1)
|
|
43
|
+
|
|
44
|
+
# Find all CLAUDE.md and AGENTS.md files
|
|
45
|
+
claude_files = list(repo_root_path.rglob("CLAUDE.md"))
|
|
46
|
+
agents_files = list(repo_root_path.rglob("AGENTS.md"))
|
|
47
|
+
|
|
48
|
+
if len(claude_files) == 0 and len(agents_files) == 0:
|
|
49
|
+
message = "ℹ️ No CLAUDE.md or AGENTS.md files found in repository"
|
|
50
|
+
user_output(click.style(message, fg="cyan"))
|
|
51
|
+
raise SystemExit(0)
|
|
52
|
+
|
|
53
|
+
# Track violations
|
|
54
|
+
missing_agents: list[Path] = [] # CLAUDE.md without peer AGENTS.md
|
|
55
|
+
missing_claude: list[Path] = [] # AGENTS.md without peer CLAUDE.md
|
|
56
|
+
invalid_content: list[Path] = []
|
|
57
|
+
|
|
58
|
+
for claude_path in claude_files:
|
|
59
|
+
# Check for peer AGENTS.md
|
|
60
|
+
agents_path = claude_path.parent / "AGENTS.md"
|
|
61
|
+
if not agents_path.exists():
|
|
62
|
+
missing_agents.append(claude_path.parent)
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
# Check CLAUDE.md content
|
|
66
|
+
content = claude_path.read_text(encoding="utf-8")
|
|
67
|
+
if content.strip() != "@AGENTS.md":
|
|
68
|
+
invalid_content.append(claude_path)
|
|
69
|
+
|
|
70
|
+
# Check that all AGENTS.md files have peer CLAUDE.md
|
|
71
|
+
for agents_path in agents_files:
|
|
72
|
+
claude_path = agents_path.parent / "CLAUDE.md"
|
|
73
|
+
if not claude_path.exists():
|
|
74
|
+
missing_claude.append(agents_path.parent)
|
|
75
|
+
|
|
76
|
+
# Report results
|
|
77
|
+
violation_count = len(missing_agents) + len(missing_claude) + len(invalid_content)
|
|
78
|
+
if violation_count == 0:
|
|
79
|
+
user_output(click.style("✓ AGENTS.md standard: PASSED", fg="green", bold=True))
|
|
80
|
+
user_output()
|
|
81
|
+
user_output("All CLAUDE.md and AGENTS.md files properly paired.")
|
|
82
|
+
user_output()
|
|
83
|
+
user_output(f"CLAUDE.md files checked: {len(claude_files)}")
|
|
84
|
+
user_output("Violations: 0")
|
|
85
|
+
raise SystemExit(0)
|
|
86
|
+
|
|
87
|
+
# Found violations
|
|
88
|
+
user_output(click.style("✗ AGENTS.md standard: FAILED", fg="red", bold=True))
|
|
89
|
+
user_output()
|
|
90
|
+
plural = "s" if violation_count != 1 else ""
|
|
91
|
+
user_output(f"Found {violation_count} violation{plural}:")
|
|
92
|
+
user_output()
|
|
93
|
+
|
|
94
|
+
if len(missing_agents) > 0:
|
|
95
|
+
user_output(click.style("Missing AGENTS.md:", fg="yellow"))
|
|
96
|
+
for path in missing_agents:
|
|
97
|
+
rel_path = path.relative_to(repo_root_path)
|
|
98
|
+
user_output(f" • {click.style(str(rel_path) + '/', fg='cyan')}")
|
|
99
|
+
user_output()
|
|
100
|
+
|
|
101
|
+
if len(missing_claude) > 0:
|
|
102
|
+
user_output(click.style("Missing CLAUDE.md:", fg="yellow"))
|
|
103
|
+
for path in missing_claude:
|
|
104
|
+
rel_path = path.relative_to(repo_root_path)
|
|
105
|
+
user_output(f" • {click.style(str(rel_path) + '/', fg='cyan')}")
|
|
106
|
+
user_output()
|
|
107
|
+
|
|
108
|
+
if len(invalid_content) > 0:
|
|
109
|
+
user_output(click.style("Invalid CLAUDE.md content:", fg="yellow"))
|
|
110
|
+
for path in invalid_content:
|
|
111
|
+
rel_path = path.relative_to(repo_root_path)
|
|
112
|
+
content = path.read_text(encoding="utf-8")
|
|
113
|
+
styled_path = click.style(str(rel_path), fg="cyan")
|
|
114
|
+
user_output(f" • {styled_path}: Content is '{content.strip()}', expected '@AGENTS.md'")
|
|
115
|
+
user_output()
|
|
116
|
+
|
|
117
|
+
user_output("Fix these issues and run again.")
|
|
118
|
+
raise SystemExit(1)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Markdown file command group."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from erk.cli.commands.md.check import check_command
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group(name="md")
|
|
9
|
+
def md_group() -> None:
|
|
10
|
+
"""Manage and validate markdown context files."""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Register commands
|
|
14
|
+
md_group.add_command(check_command)
|