erk-shared 0.2.6__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.
- erk_shared-0.2.6/.gitignore +22 -0
- erk_shared-0.2.6/PKG-INFO +43 -0
- erk_shared-0.2.6/README.md +33 -0
- erk_shared-0.2.6/pyproject.toml +24 -0
- erk_shared-0.2.6/src/erk_shared/__init__.py +20 -0
- erk_shared-0.2.6/src/erk_shared/context/__init__.py +10 -0
- erk_shared-0.2.6/src/erk_shared/context/context.py +177 -0
- erk_shared-0.2.6/src/erk_shared/context/factories.py +141 -0
- erk_shared-0.2.6/src/erk_shared/context/helpers.py +314 -0
- erk_shared-0.2.6/src/erk_shared/context/testing.py +129 -0
- erk_shared-0.2.6/src/erk_shared/context/types.py +99 -0
- erk_shared-0.2.6/src/erk_shared/core/__init__.py +38 -0
- erk_shared-0.2.6/src/erk_shared/core/claude_executor.py +395 -0
- erk_shared-0.2.6/src/erk_shared/core/config_store.py +54 -0
- erk_shared-0.2.6/src/erk_shared/core/fakes.py +234 -0
- erk_shared-0.2.6/src/erk_shared/core/plan_list_service.py +62 -0
- erk_shared-0.2.6/src/erk_shared/core/planner_registry.py +141 -0
- erk_shared-0.2.6/src/erk_shared/core/script_writer.py +143 -0
- erk_shared-0.2.6/src/erk_shared/debug.py +33 -0
- erk_shared-0.2.6/src/erk_shared/debug_timing.py +24 -0
- erk_shared-0.2.6/src/erk_shared/env.py +23 -0
- erk_shared-0.2.6/src/erk_shared/extraction/__init__.py +1 -0
- erk_shared-0.2.6/src/erk_shared/extraction/claude_code_session_store/__init__.py +29 -0
- erk_shared-0.2.6/src/erk_shared/extraction/claude_code_session_store/abc.py +122 -0
- erk_shared-0.2.6/src/erk_shared/extraction/claude_code_session_store/fake.py +179 -0
- erk_shared-0.2.6/src/erk_shared/extraction/claude_code_session_store/real.py +178 -0
- erk_shared-0.2.6/src/erk_shared/extraction/llm_distillation.py +106 -0
- erk_shared-0.2.6/src/erk_shared/extraction/local_plans.py +49 -0
- erk_shared-0.2.6/src/erk_shared/extraction/raw_extraction.py +264 -0
- erk_shared-0.2.6/src/erk_shared/extraction/session_context.py +144 -0
- erk_shared-0.2.6/src/erk_shared/extraction/session_discovery.py +154 -0
- erk_shared-0.2.6/src/erk_shared/extraction/session_preprocessing.py +427 -0
- erk_shared-0.2.6/src/erk_shared/extraction/session_selection.py +63 -0
- erk_shared-0.2.6/src/erk_shared/extraction/types.py +36 -0
- erk_shared-0.2.6/src/erk_shared/git/__init__.py +6 -0
- erk_shared-0.2.6/src/erk_shared/git/abc.py +717 -0
- erk_shared-0.2.6/src/erk_shared/git/dry_run.py +300 -0
- erk_shared-0.2.6/src/erk_shared/git/fake.py +957 -0
- erk_shared-0.2.6/src/erk_shared/git/printing.py +294 -0
- erk_shared-0.2.6/src/erk_shared/git/real.py +881 -0
- erk_shared-0.2.6/src/erk_shared/github/__init__.py +10 -0
- erk_shared-0.2.6/src/erk_shared/github/abc.py +550 -0
- erk_shared-0.2.6/src/erk_shared/github/dry_run.py +245 -0
- erk_shared-0.2.6/src/erk_shared/github/emoji.py +115 -0
- erk_shared-0.2.6/src/erk_shared/github/fake.py +703 -0
- erk_shared-0.2.6/src/erk_shared/github/graphql_queries.py +153 -0
- erk_shared-0.2.6/src/erk_shared/github/issues/__init__.py +19 -0
- erk_shared-0.2.6/src/erk_shared/github/issues/abc.py +258 -0
- erk_shared-0.2.6/src/erk_shared/github/issues/dry_run.py +105 -0
- erk_shared-0.2.6/src/erk_shared/github/issues/fake.py +368 -0
- erk_shared-0.2.6/src/erk_shared/github/issues/label_cache.py +215 -0
- erk_shared-0.2.6/src/erk_shared/github/issues/real.py +361 -0
- erk_shared-0.2.6/src/erk_shared/github/issues/types.py +68 -0
- erk_shared-0.2.6/src/erk_shared/github/metadata.py +2206 -0
- erk_shared-0.2.6/src/erk_shared/github/metadata_blocks.py +628 -0
- erk_shared-0.2.6/src/erk_shared/github/parsing.py +321 -0
- erk_shared-0.2.6/src/erk_shared/github/plan_issues.py +227 -0
- erk_shared-0.2.6/src/erk_shared/github/pr_footer.py +44 -0
- erk_shared-0.2.6/src/erk_shared/github/printing.py +258 -0
- erk_shared-0.2.6/src/erk_shared/github/real.py +1633 -0
- erk_shared-0.2.6/src/erk_shared/github/status_history.py +121 -0
- erk_shared-0.2.6/src/erk_shared/github/types.py +293 -0
- erk_shared-0.2.6/src/erk_shared/hooks/__init__.py +1 -0
- erk_shared-0.2.6/src/erk_shared/hooks/logging.py +184 -0
- erk_shared-0.2.6/src/erk_shared/hooks/types.py +65 -0
- erk_shared-0.2.6/src/erk_shared/impl_folder.py +574 -0
- erk_shared-0.2.6/src/erk_shared/integrations/__init__.py +1 -0
- erk_shared-0.2.6/src/erk_shared/integrations/browser/__init__.py +7 -0
- erk_shared-0.2.6/src/erk_shared/integrations/browser/abc.py +23 -0
- erk_shared-0.2.6/src/erk_shared/integrations/browser/fake.py +57 -0
- erk_shared-0.2.6/src/erk_shared/integrations/browser/real.py +25 -0
- erk_shared-0.2.6/src/erk_shared/integrations/clipboard/__init__.py +7 -0
- erk_shared-0.2.6/src/erk_shared/integrations/clipboard/abc.py +24 -0
- erk_shared-0.2.6/src/erk_shared/integrations/clipboard/fake.py +57 -0
- erk_shared-0.2.6/src/erk_shared/integrations/clipboard/real.py +33 -0
- erk_shared-0.2.6/src/erk_shared/integrations/completion/__init__.py +5 -0
- erk_shared-0.2.6/src/erk_shared/integrations/completion/abc.py +72 -0
- erk_shared-0.2.6/src/erk_shared/integrations/completion/fake.py +106 -0
- erk_shared-0.2.6/src/erk_shared/integrations/completion/real.py +71 -0
- erk_shared-0.2.6/src/erk_shared/integrations/erk_wt/__init__.py +23 -0
- erk_shared-0.2.6/src/erk_shared/integrations/erk_wt/abc.py +141 -0
- erk_shared-0.2.6/src/erk_shared/integrations/erk_wt/fake.py +155 -0
- erk_shared-0.2.6/src/erk_shared/integrations/erk_wt/real.py +211 -0
- erk_shared-0.2.6/src/erk_shared/integrations/feedback/__init__.py +6 -0
- erk_shared-0.2.6/src/erk_shared/integrations/feedback/abc.py +50 -0
- erk_shared-0.2.6/src/erk_shared/integrations/feedback/fake.py +70 -0
- erk_shared-0.2.6/src/erk_shared/integrations/feedback/real.py +42 -0
- erk_shared-0.2.6/src/erk_shared/integrations/graphite/__init__.py +11 -0
- erk_shared-0.2.6/src/erk_shared/integrations/graphite/abc.py +346 -0
- erk_shared-0.2.6/src/erk_shared/integrations/graphite/dry_run.py +95 -0
- erk_shared-0.2.6/src/erk_shared/integrations/graphite/fake.py +313 -0
- erk_shared-0.2.6/src/erk_shared/integrations/graphite/parsing.py +138 -0
- erk_shared-0.2.6/src/erk_shared/integrations/graphite/printing.py +75 -0
- erk_shared-0.2.6/src/erk_shared/integrations/graphite/real.py +394 -0
- erk_shared-0.2.6/src/erk_shared/integrations/graphite/types.py +70 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/__init__.py +15 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/abc.py +64 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/cli.py +63 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/commit_message_prompt.md +59 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/events.py +42 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/fake.py +7 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/operations/__init__.py +29 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/operations/finalize.py +167 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/operations/land_pr.py +164 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/operations/pre_analysis.py +314 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/operations/preflight.py +379 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/operations/restack_continue.py +99 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/operations/restack_finalize.py +145 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/operations/restack_preflight.py +113 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/operations/squash.py +56 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/prompts.py +27 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/real.py +45 -0
- erk_shared-0.2.6/src/erk_shared/integrations/gt/types.py +317 -0
- erk_shared-0.2.6/src/erk_shared/integrations/parallel/__init__.py +6 -0
- erk_shared-0.2.6/src/erk_shared/integrations/parallel/abc.py +34 -0
- erk_shared-0.2.6/src/erk_shared/integrations/parallel/real.py +65 -0
- erk_shared-0.2.6/src/erk_shared/integrations/pr/__init__.py +18 -0
- erk_shared-0.2.6/src/erk_shared/integrations/pr/diff_extraction.py +61 -0
- erk_shared-0.2.6/src/erk_shared/integrations/pr/graphite_enhance.py +256 -0
- erk_shared-0.2.6/src/erk_shared/integrations/pr/submit.py +247 -0
- erk_shared-0.2.6/src/erk_shared/integrations/pr/types.py +62 -0
- erk_shared-0.2.6/src/erk_shared/integrations/shell/__init__.py +6 -0
- erk_shared-0.2.6/src/erk_shared/integrations/shell/abc.py +97 -0
- erk_shared-0.2.6/src/erk_shared/integrations/shell/fake.py +122 -0
- erk_shared-0.2.6/src/erk_shared/integrations/shell/real.py +113 -0
- erk_shared-0.2.6/src/erk_shared/integrations/time/__init__.py +6 -0
- erk_shared-0.2.6/src/erk_shared/integrations/time/abc.py +30 -0
- erk_shared-0.2.6/src/erk_shared/integrations/time/fake.py +57 -0
- erk_shared-0.2.6/src/erk_shared/integrations/time/real.py +26 -0
- erk_shared-0.2.6/src/erk_shared/naming.py +536 -0
- erk_shared-0.2.6/src/erk_shared/non_ideal_state.py +94 -0
- erk_shared-0.2.6/src/erk_shared/objectives/__init__.py +11 -0
- erk_shared-0.2.6/src/erk_shared/objectives/parser.py +226 -0
- erk_shared-0.2.6/src/erk_shared/objectives/storage.py +304 -0
- erk_shared-0.2.6/src/erk_shared/objectives/turn.py +186 -0
- erk_shared-0.2.6/src/erk_shared/objectives/types.py +90 -0
- erk_shared-0.2.6/src/erk_shared/output/__init__.py +5 -0
- erk_shared-0.2.6/src/erk_shared/output/next_steps.py +77 -0
- erk_shared-0.2.6/src/erk_shared/output/output.py +66 -0
- erk_shared-0.2.6/src/erk_shared/plan_store/__init__.py +11 -0
- erk_shared-0.2.6/src/erk_shared/plan_store/fake.py +113 -0
- erk_shared-0.2.6/src/erk_shared/plan_store/github.py +209 -0
- erk_shared-0.2.6/src/erk_shared/plan_store/store.py +69 -0
- erk_shared-0.2.6/src/erk_shared/plan_store/types.py +57 -0
- erk_shared-0.2.6/src/erk_shared/plan_utils.py +230 -0
- erk_shared-0.2.6/src/erk_shared/printing/__init__.py +5 -0
- erk_shared-0.2.6/src/erk_shared/printing/base.py +54 -0
- erk_shared-0.2.6/src/erk_shared/project_discovery.py +86 -0
- erk_shared-0.2.6/src/erk_shared/prompt_executor/__init__.py +14 -0
- erk_shared-0.2.6/src/erk_shared/prompt_executor/abc.py +65 -0
- erk_shared-0.2.6/src/erk_shared/prompt_executor/fake.py +91 -0
- erk_shared-0.2.6/src/erk_shared/prompt_executor/real.py +59 -0
- erk_shared-0.2.6/src/erk_shared/scratch/__init__.py +8 -0
- erk_shared-0.2.6/src/erk_shared/scratch/markers.py +75 -0
- erk_shared-0.2.6/src/erk_shared/scratch/scratch.py +131 -0
- erk_shared-0.2.6/src/erk_shared/shell_utils/__init__.py +5 -0
- erk_shared-0.2.6/src/erk_shared/shell_utils/temp_files.py +64 -0
- erk_shared-0.2.6/src/erk_shared/subprocess_utils.py +148 -0
- erk_shared-0.2.6/src/erk_shared/worker_impl_folder.py +140 -0
- erk_shared-0.2.6/tests/__init__.py +1 -0
- erk_shared-0.2.6/tests/unit/__init__.py +1 -0
- erk_shared-0.2.6/tests/unit/extraction/__init__.py +1 -0
- erk_shared-0.2.6/tests/unit/extraction/claude_code_session_store/__init__.py +1 -0
- erk_shared-0.2.6/tests/unit/extraction/claude_code_session_store/test_fake.py +445 -0
- erk_shared-0.2.6/tests/unit/extraction/test_llm_distillation.py +186 -0
- erk_shared-0.2.6/tests/unit/extraction/test_raw_extraction.py +344 -0
- erk_shared-0.2.6/tests/unit/extraction/test_session_context.py +269 -0
- erk_shared-0.2.6/tests/unit/extraction/test_session_discovery.py +220 -0
- erk_shared-0.2.6/tests/unit/extraction/test_session_preprocessing.py +336 -0
- erk_shared-0.2.6/tests/unit/extraction/test_session_selection.py +197 -0
- erk_shared-0.2.6/tests/unit/github/__init__.py +0 -0
- erk_shared-0.2.6/tests/unit/github/test_issues_fake.py +113 -0
- erk_shared-0.2.6/tests/unit/github/test_parsing.py +140 -0
- erk_shared-0.2.6/tests/unit/github/test_plan_issues.py +394 -0
- erk_shared-0.2.6/tests/unit/github/test_pr_footer.py +81 -0
- erk_shared-0.2.6/tests/unit/github/test_pr_review_threads.py +248 -0
- erk_shared-0.2.6/tests/unit/github/test_session_content.py +433 -0
- erk_shared-0.2.6/tests/unit/hooks/__init__.py +1 -0
- erk_shared-0.2.6/tests/unit/hooks/test_logging.py +169 -0
- erk_shared-0.2.6/tests/unit/hooks/test_types.py +22 -0
- erk_shared-0.2.6/tests/unit/integrations/__init__.py +0 -0
- erk_shared-0.2.6/tests/unit/integrations/gt/__init__.py +0 -0
- erk_shared-0.2.6/tests/unit/integrations/gt/cli/__init__.py +0 -0
- erk_shared-0.2.6/tests/unit/integrations/gt/cli/test_render_events.py +60 -0
- erk_shared-0.2.6/tests/unit/integrations/gt/operations/__init__.py +0 -0
- erk_shared-0.2.6/tests/unit/integrations/gt/operations/test_finalize.py +150 -0
- erk_shared-0.2.6/tests/unit/integrations/gt/operations/test_pre_analysis.py +595 -0
- erk_shared-0.2.6/tests/unit/integrations/pr/__init__.py +1 -0
- erk_shared-0.2.6/tests/unit/integrations/pr/test_diff_extraction.py +121 -0
- erk_shared-0.2.6/tests/unit/integrations/pr/test_graphite_enhance.py +267 -0
- erk_shared-0.2.6/tests/unit/integrations/pr/test_submit.py +261 -0
- erk_shared-0.2.6/tests/unit/plan_store/__init__.py +1 -0
- erk_shared-0.2.6/tests/unit/plan_store/test_fake_plan_store.py +333 -0
- erk_shared-0.2.6/tests/unit/scratch/__init__.py +1 -0
- erk_shared-0.2.6/tests/unit/scratch/test_scratch.py +186 -0
- erk_shared-0.2.6/tests/unit/test_plan_utils.py +327 -0
- erk_shared-0.2.6/tests/unit/test_project_discovery.py +114 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Testing
|
|
10
|
+
.pytest_cache
|
|
11
|
+
.coverage
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv
|
|
15
|
+
activate.sh
|
|
16
|
+
|
|
17
|
+
# Local implementation and configuration (not tracked in git)
|
|
18
|
+
.impl/
|
|
19
|
+
.erk/scratch/
|
|
20
|
+
.env
|
|
21
|
+
|
|
22
|
+
CLAUDE.local.md
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: erk-shared
|
|
3
|
+
Version: 0.2.6
|
|
4
|
+
Summary: Shared utilities and interfaces for erk and erk-kits
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: click>=8.1.7
|
|
7
|
+
Requires-Dist: python-frontmatter>=1.0.0
|
|
8
|
+
Requires-Dist: pyyaml>=6.0
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# erk-shared
|
|
12
|
+
|
|
13
|
+
Shared utilities and interfaces for erk and erk-kits packages.
|
|
14
|
+
|
|
15
|
+
This package provides:
|
|
16
|
+
|
|
17
|
+
- **GitHub Issues Interface**: ABC with Real/Fake implementations
|
|
18
|
+
- **Naming Utilities**: Filename and worktree name transformations
|
|
19
|
+
- **Metadata Blocks**: GitHub comment formatting utilities
|
|
20
|
+
- **Impl Folder Utilities**: Issue reference management and progress parsing
|
|
21
|
+
|
|
22
|
+
## Purpose
|
|
23
|
+
|
|
24
|
+
This package exists to break the circular dependency between `erk` and `erk-kits`:
|
|
25
|
+
|
|
26
|
+
- `erk` imports kit utilities from `erk-kits`
|
|
27
|
+
- `erk-kits` imports interfaces and utilities from `erk`
|
|
28
|
+
|
|
29
|
+
By extracting shared code to `erk-shared`, we create an acyclic dependency graph:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
erk-shared (no dependencies)
|
|
33
|
+
↑
|
|
34
|
+
|
|
|
35
|
+
erk-kits (depends on: erk-shared)
|
|
36
|
+
↑
|
|
37
|
+
|
|
|
38
|
+
erk (depends on: erk-kits, erk-shared)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Note
|
|
42
|
+
|
|
43
|
+
This is an internal workspace package, not published to PyPI.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# erk-shared
|
|
2
|
+
|
|
3
|
+
Shared utilities and interfaces for erk and erk-kits packages.
|
|
4
|
+
|
|
5
|
+
This package provides:
|
|
6
|
+
|
|
7
|
+
- **GitHub Issues Interface**: ABC with Real/Fake implementations
|
|
8
|
+
- **Naming Utilities**: Filename and worktree name transformations
|
|
9
|
+
- **Metadata Blocks**: GitHub comment formatting utilities
|
|
10
|
+
- **Impl Folder Utilities**: Issue reference management and progress parsing
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
This package exists to break the circular dependency between `erk` and `erk-kits`:
|
|
15
|
+
|
|
16
|
+
- `erk` imports kit utilities from `erk-kits`
|
|
17
|
+
- `erk-kits` imports interfaces and utilities from `erk`
|
|
18
|
+
|
|
19
|
+
By extracting shared code to `erk-shared`, we create an acyclic dependency graph:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
erk-shared (no dependencies)
|
|
23
|
+
↑
|
|
24
|
+
|
|
|
25
|
+
erk-kits (depends on: erk-shared)
|
|
26
|
+
↑
|
|
27
|
+
|
|
|
28
|
+
erk (depends on: erk-kits, erk-shared)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Note
|
|
32
|
+
|
|
33
|
+
This is an internal workspace package, not published to PyPI.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "erk-shared"
|
|
3
|
+
version = "0.2.6"
|
|
4
|
+
description = "Shared utilities and interfaces for erk and erk-kits"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"pyyaml>=6.0",
|
|
9
|
+
"python-frontmatter>=1.0.0",
|
|
10
|
+
"click>=8.1.7",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
[build-system]
|
|
14
|
+
requires = ["hatchling"]
|
|
15
|
+
build-backend = "hatchling.build"
|
|
16
|
+
|
|
17
|
+
[tool.hatch.build.targets.wheel]
|
|
18
|
+
packages = ["src/erk_shared"]
|
|
19
|
+
|
|
20
|
+
[tool.pyright]
|
|
21
|
+
include = ["src", "tests"]
|
|
22
|
+
pythonVersion = "3.11"
|
|
23
|
+
typeCheckingMode = "strict"
|
|
24
|
+
reportPrivateUsage = false
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Shared utilities and interfaces for erk and erk-kits.
|
|
2
|
+
|
|
3
|
+
Import from submodules:
|
|
4
|
+
- env: in_github_actions
|
|
5
|
+
- git.abc: Git, WorktreeInfo, find_worktree_for_branch
|
|
6
|
+
- git.real: RealGit
|
|
7
|
+
- github.abc: GitHub
|
|
8
|
+
- github.types: PRInfo, PRMergeability, PRState, PullRequestInfo, WorkflowRun
|
|
9
|
+
- github.issues: GitHubIssues, RealGitHubIssues, FakeGitHubIssues, etc.
|
|
10
|
+
- github.metadata: MetadataBlock, create_metadata_block, etc.
|
|
11
|
+
- impl_folder: IssueReference, read_issue_reference, etc.
|
|
12
|
+
- naming: sanitize_worktree_name, generate_filename_from_title
|
|
13
|
+
- output.output: user_output, machine_output, format_duration
|
|
14
|
+
- subprocess_utils: run_subprocess_with_context
|
|
15
|
+
- integrations.graphite.*: Graphite, RealGraphite, FakeGraphite, etc.
|
|
16
|
+
- integrations.time.*: Time, RealTime
|
|
17
|
+
- integrations.parallel.*: ParallelTaskRunner, RealParallelTaskRunner
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Unified context for erk and erk-kits.
|
|
2
|
+
|
|
3
|
+
This module provides the canonical ErkContext that holds all dependencies
|
|
4
|
+
for erk and erk-kits operations.
|
|
5
|
+
|
|
6
|
+
Note: Import helpers from erk_shared.context.helpers and types from
|
|
7
|
+
erk_shared.context.types directly.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from erk_shared.context.context import ErkContext as ErkContext
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""Unified context for erk and erk-kits operations.
|
|
2
|
+
|
|
3
|
+
This module provides ErkContext - the unified context that holds all dependencies
|
|
4
|
+
for erk and erk-kits operations.
|
|
5
|
+
|
|
6
|
+
The ABCs for erk-specific services (ClaudeExecutor, ConfigStore, ScriptWriter,
|
|
7
|
+
PlannerRegistry, PlanListService) are defined in erk_shared.core, enabling
|
|
8
|
+
proper type hints without circular imports. Real implementations remain in erk.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from erk_shared.context.types import (
|
|
15
|
+
GlobalConfig,
|
|
16
|
+
LoadedConfig,
|
|
17
|
+
NoRepoSentinel,
|
|
18
|
+
RepoContext,
|
|
19
|
+
)
|
|
20
|
+
from erk_shared.core.claude_executor import ClaudeExecutor
|
|
21
|
+
from erk_shared.core.config_store import ConfigStore
|
|
22
|
+
from erk_shared.core.plan_list_service import PlanListService
|
|
23
|
+
from erk_shared.core.planner_registry import PlannerRegistry
|
|
24
|
+
from erk_shared.core.script_writer import ScriptWriter
|
|
25
|
+
from erk_shared.extraction.claude_code_session_store import ClaudeCodeSessionStore
|
|
26
|
+
from erk_shared.git.abc import Git
|
|
27
|
+
from erk_shared.github.abc import GitHub
|
|
28
|
+
from erk_shared.github.issues import GitHubIssues
|
|
29
|
+
from erk_shared.github.types import RepoInfo
|
|
30
|
+
from erk_shared.integrations.completion import Completion
|
|
31
|
+
from erk_shared.integrations.feedback import UserFeedback
|
|
32
|
+
from erk_shared.integrations.graphite.abc import Graphite
|
|
33
|
+
from erk_shared.integrations.shell import Shell
|
|
34
|
+
from erk_shared.integrations.time.abc import Time
|
|
35
|
+
from erk_shared.objectives.storage import ObjectiveStore
|
|
36
|
+
from erk_shared.plan_store.store import PlanStore
|
|
37
|
+
from erk_shared.project_discovery import ProjectContext
|
|
38
|
+
from erk_shared.prompt_executor import PromptExecutor
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(frozen=True)
|
|
42
|
+
class ErkContext:
|
|
43
|
+
"""Immutable context holding all dependencies for erk and erk-kits operations.
|
|
44
|
+
|
|
45
|
+
Created at CLI entry point and threaded through the application via Click's
|
|
46
|
+
context system. Frozen to prevent accidental modification at runtime.
|
|
47
|
+
|
|
48
|
+
This unified context replaces both the old ErkContext (from erk.core.context)
|
|
49
|
+
and DotAgentContext (from erk_kits.context).
|
|
50
|
+
|
|
51
|
+
Note:
|
|
52
|
+
- global_config may be None only during init command before config is created.
|
|
53
|
+
All other commands should have a valid GlobalConfig.
|
|
54
|
+
|
|
55
|
+
DotAgentContext Compatibility:
|
|
56
|
+
- github_issues -> issues (renamed for consistency)
|
|
57
|
+
- repo_root property -> repo.root (access via repo property or require_repo_root helper)
|
|
58
|
+
- debug field -> debug (preserved)
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
# Gateway integrations (from erk_shared)
|
|
62
|
+
git: Git
|
|
63
|
+
github: GitHub
|
|
64
|
+
issues: GitHubIssues # Note: ErkContext naming (was github_issues in DotAgentContext)
|
|
65
|
+
graphite: Graphite
|
|
66
|
+
time: Time
|
|
67
|
+
session_store: ClaudeCodeSessionStore
|
|
68
|
+
plan_store: PlanStore
|
|
69
|
+
objectives: ObjectiveStore
|
|
70
|
+
prompt_executor: PromptExecutor # From DotAgentContext
|
|
71
|
+
|
|
72
|
+
# Shell/CLI integrations (moved to erk_shared)
|
|
73
|
+
shell: Shell
|
|
74
|
+
completion: Completion
|
|
75
|
+
feedback: UserFeedback
|
|
76
|
+
|
|
77
|
+
# Erk-specific services (ABCs now in erk_shared.core for proper type hints)
|
|
78
|
+
claude_executor: ClaudeExecutor
|
|
79
|
+
config_store: ConfigStore
|
|
80
|
+
script_writer: ScriptWriter
|
|
81
|
+
planner_registry: PlannerRegistry
|
|
82
|
+
plan_list_service: PlanListService
|
|
83
|
+
|
|
84
|
+
# Paths
|
|
85
|
+
cwd: Path # Current working directory at CLI invocation
|
|
86
|
+
|
|
87
|
+
# Repository context
|
|
88
|
+
repo: RepoContext | NoRepoSentinel
|
|
89
|
+
project: ProjectContext | None # None if not in a project subdirectory
|
|
90
|
+
repo_info: RepoInfo | None # None when not in a GitHub repo
|
|
91
|
+
|
|
92
|
+
# Configuration
|
|
93
|
+
global_config: GlobalConfig | None
|
|
94
|
+
local_config: LoadedConfig
|
|
95
|
+
|
|
96
|
+
# Mode flags
|
|
97
|
+
dry_run: bool
|
|
98
|
+
debug: bool # From DotAgentContext
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def repo_root(self) -> Path:
|
|
102
|
+
"""DotAgentContext compatibility - get repo root from repo.
|
|
103
|
+
|
|
104
|
+
Raises:
|
|
105
|
+
RuntimeError: If not in a git repository
|
|
106
|
+
"""
|
|
107
|
+
if isinstance(self.repo, NoRepoSentinel):
|
|
108
|
+
raise RuntimeError("Not in a git repository")
|
|
109
|
+
return self.repo.root
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def trunk_branch(self) -> str | None:
|
|
113
|
+
"""Get the trunk branch name from git detection.
|
|
114
|
+
|
|
115
|
+
Returns None if not in a repository, otherwise uses git to detect trunk.
|
|
116
|
+
"""
|
|
117
|
+
if isinstance(self.repo, NoRepoSentinel):
|
|
118
|
+
return None
|
|
119
|
+
return self.git.detect_trunk_branch(self.repo.root)
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def github_issues(self) -> GitHubIssues:
|
|
123
|
+
"""DotAgentContext compatibility - alias for issues field.
|
|
124
|
+
|
|
125
|
+
Deprecated: Use ctx.issues instead. This property is provided for
|
|
126
|
+
backward compatibility with code written for the old DotAgentContext.
|
|
127
|
+
"""
|
|
128
|
+
return self.issues
|
|
129
|
+
|
|
130
|
+
@staticmethod
|
|
131
|
+
def for_test(
|
|
132
|
+
github_issues: GitHubIssues | None = None,
|
|
133
|
+
git: Git | None = None,
|
|
134
|
+
github: GitHub | None = None,
|
|
135
|
+
session_store: ClaudeCodeSessionStore | None = None,
|
|
136
|
+
prompt_executor: PromptExecutor | None = None,
|
|
137
|
+
debug: bool = False,
|
|
138
|
+
repo_root: Path | None = None,
|
|
139
|
+
cwd: Path | None = None,
|
|
140
|
+
) -> "ErkContext":
|
|
141
|
+
"""Create test context with optional pre-configured implementations.
|
|
142
|
+
|
|
143
|
+
Provides full control over all context parameters with sensible test defaults
|
|
144
|
+
for any unspecified values. Uses fakes by default to avoid subprocess calls.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
github_issues: Optional GitHubIssues implementation. If None, creates FakeGitHubIssues.
|
|
148
|
+
git: Optional Git implementation. If None, creates FakeGit.
|
|
149
|
+
github: Optional GitHub implementation. If None, creates FakeGitHub.
|
|
150
|
+
session_store: Optional SessionStore. If None, creates FakeClaudeCodeSessionStore.
|
|
151
|
+
prompt_executor: Optional PromptExecutor. If None, creates FakePromptExecutor.
|
|
152
|
+
debug: Whether to enable debug mode (default False).
|
|
153
|
+
repo_root: Repository root path (defaults to Path("/fake/repo"))
|
|
154
|
+
cwd: Current working directory (defaults to Path("/fake/worktree"))
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
ErkContext configured with provided values and test defaults
|
|
158
|
+
|
|
159
|
+
Example:
|
|
160
|
+
>>> from erk_shared.github.issues import FakeGitHubIssues
|
|
161
|
+
>>> from erk_shared.git.fake import FakeGit
|
|
162
|
+
>>> github = FakeGitHubIssues()
|
|
163
|
+
>>> git_ops = FakeGit()
|
|
164
|
+
>>> ctx = ErkContext.for_test(github_issues=github, git=git_ops, debug=True)
|
|
165
|
+
"""
|
|
166
|
+
from erk_shared.context.testing import context_for_test
|
|
167
|
+
|
|
168
|
+
return context_for_test(
|
|
169
|
+
github_issues=github_issues,
|
|
170
|
+
git=git,
|
|
171
|
+
github=github,
|
|
172
|
+
session_store=session_store,
|
|
173
|
+
prompt_executor=prompt_executor,
|
|
174
|
+
debug=debug,
|
|
175
|
+
repo_root=repo_root,
|
|
176
|
+
cwd=cwd,
|
|
177
|
+
)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Factory functions for creating ErkContext instances.
|
|
2
|
+
|
|
3
|
+
This module provides factory functions for creating production contexts
|
|
4
|
+
with real implementations. Used by CLI entry points.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import subprocess
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
from erk_shared.core.fakes import (
|
|
12
|
+
FakeClaudeExecutor,
|
|
13
|
+
FakeConfigStore,
|
|
14
|
+
FakePlanListService,
|
|
15
|
+
FakePlannerRegistry,
|
|
16
|
+
FakeScriptWriter,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from erk_shared.context.context import ErkContext
|
|
21
|
+
from erk_shared.git.abc import Git
|
|
22
|
+
from erk_shared.github.types import RepoInfo
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_repo_info(git: "Git", repo_root: Path) -> "RepoInfo | None":
|
|
26
|
+
"""Detect repository info from git remote URL.
|
|
27
|
+
|
|
28
|
+
Parses the origin remote URL to extract owner/name for GitHub API calls.
|
|
29
|
+
Returns None if no origin remote is configured or URL cannot be parsed.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
git: Git interface for operations
|
|
33
|
+
repo_root: Repository root path
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
RepoInfo with owner/name, or None if not determinable
|
|
37
|
+
"""
|
|
38
|
+
from erk_shared.github.parsing import parse_git_remote_url
|
|
39
|
+
from erk_shared.github.types import RepoInfo
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
remote_url = git.get_remote_url(repo_root)
|
|
43
|
+
owner, name = parse_git_remote_url(remote_url)
|
|
44
|
+
return RepoInfo(owner=owner, name=name)
|
|
45
|
+
except ValueError:
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def create_minimal_context(*, debug: bool, cwd: Path | None = None) -> "ErkContext":
|
|
50
|
+
"""Create production context with real implementations for erk-kits.
|
|
51
|
+
|
|
52
|
+
This factory creates a minimal context suitable for erk-kits commands.
|
|
53
|
+
It uses real implementations for GitHub, git, and session store, but uses
|
|
54
|
+
fake implementations for erk-specific services (ClaudeExecutor, etc.) that
|
|
55
|
+
erk-kits doesn't need.
|
|
56
|
+
|
|
57
|
+
Detects repository root using git rev-parse. Returns context with
|
|
58
|
+
NoRepoSentinel if not in a git repository.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
debug: If True, enable debug mode (full stack traces in error handling)
|
|
62
|
+
cwd: Current working directory (defaults to Path.cwd())
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
ErkContext with real GitHub integrations and detected repo context
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
>>> ctx = create_minimal_context(debug=False)
|
|
69
|
+
>>> issue_number = ctx.issues.create_issue(ctx.repo_root, title, body, labels)
|
|
70
|
+
"""
|
|
71
|
+
from erk_shared.context.context import ErkContext
|
|
72
|
+
from erk_shared.context.types import LoadedConfig, NoRepoSentinel, RepoContext
|
|
73
|
+
from erk_shared.extraction.claude_code_session_store import RealClaudeCodeSessionStore
|
|
74
|
+
from erk_shared.git.real import RealGit
|
|
75
|
+
from erk_shared.github.issues import RealGitHubIssues
|
|
76
|
+
from erk_shared.github.real import RealGitHub
|
|
77
|
+
from erk_shared.integrations.completion import FakeCompletion
|
|
78
|
+
from erk_shared.integrations.feedback import SuppressedFeedback
|
|
79
|
+
from erk_shared.integrations.graphite.fake import FakeGraphite
|
|
80
|
+
from erk_shared.integrations.shell import FakeShell
|
|
81
|
+
from erk_shared.integrations.time.fake import FakeTime
|
|
82
|
+
from erk_shared.integrations.time.real import RealTime
|
|
83
|
+
from erk_shared.objectives.storage import FakeObjectiveStore
|
|
84
|
+
from erk_shared.plan_store.fake import FakePlanStore
|
|
85
|
+
from erk_shared.prompt_executor.real import RealPromptExecutor
|
|
86
|
+
|
|
87
|
+
resolved_cwd = cwd if cwd is not None else Path.cwd()
|
|
88
|
+
|
|
89
|
+
# Detect repo root using git rev-parse
|
|
90
|
+
result = subprocess.run(
|
|
91
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
92
|
+
capture_output=True,
|
|
93
|
+
text=True,
|
|
94
|
+
check=False,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Create git instance
|
|
98
|
+
git = RealGit()
|
|
99
|
+
|
|
100
|
+
if result.returncode != 0:
|
|
101
|
+
# Not in a git repository
|
|
102
|
+
repo: RepoContext | NoRepoSentinel = NoRepoSentinel()
|
|
103
|
+
repo_info = None
|
|
104
|
+
else:
|
|
105
|
+
repo_root = Path(result.stdout.strip())
|
|
106
|
+
repo_info = get_repo_info(git, repo_root)
|
|
107
|
+
repo = RepoContext(
|
|
108
|
+
root=repo_root,
|
|
109
|
+
repo_name=repo_root.name,
|
|
110
|
+
repo_dir=Path.home() / ".erk" / "repos" / repo_root.name,
|
|
111
|
+
worktrees_dir=Path.home() / ".erk" / "repos" / repo_root.name / "worktrees",
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Use fake implementations for erk-specific services that erk-kits doesn't need
|
|
115
|
+
return ErkContext(
|
|
116
|
+
git=git,
|
|
117
|
+
github=RealGitHub(time=RealTime(), repo_info=repo_info),
|
|
118
|
+
issues=RealGitHubIssues(),
|
|
119
|
+
session_store=RealClaudeCodeSessionStore(),
|
|
120
|
+
prompt_executor=RealPromptExecutor(),
|
|
121
|
+
graphite=FakeGraphite(),
|
|
122
|
+
time=FakeTime(),
|
|
123
|
+
plan_store=FakePlanStore(),
|
|
124
|
+
objectives=FakeObjectiveStore(),
|
|
125
|
+
shell=FakeShell(),
|
|
126
|
+
completion=FakeCompletion(),
|
|
127
|
+
feedback=SuppressedFeedback(),
|
|
128
|
+
claude_executor=FakeClaudeExecutor(),
|
|
129
|
+
config_store=FakeConfigStore(),
|
|
130
|
+
script_writer=FakeScriptWriter(),
|
|
131
|
+
planner_registry=FakePlannerRegistry(),
|
|
132
|
+
plan_list_service=FakePlanListService(),
|
|
133
|
+
cwd=resolved_cwd,
|
|
134
|
+
repo=repo,
|
|
135
|
+
project=None,
|
|
136
|
+
repo_info=repo_info,
|
|
137
|
+
global_config=None,
|
|
138
|
+
local_config=LoadedConfig(env={}, post_create_commands=[], post_create_shell=None),
|
|
139
|
+
dry_run=False,
|
|
140
|
+
debug=debug,
|
|
141
|
+
)
|