emdash-core 0.1.7__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.
- emdash_core/__init__.py +3 -0
- emdash_core/agent/__init__.py +37 -0
- emdash_core/agent/agents.py +225 -0
- emdash_core/agent/code_reviewer.py +476 -0
- emdash_core/agent/compaction.py +143 -0
- emdash_core/agent/context_manager.py +140 -0
- emdash_core/agent/events.py +338 -0
- emdash_core/agent/handlers.py +224 -0
- emdash_core/agent/inprocess_subagent.py +377 -0
- emdash_core/agent/mcp/__init__.py +50 -0
- emdash_core/agent/mcp/client.py +346 -0
- emdash_core/agent/mcp/config.py +302 -0
- emdash_core/agent/mcp/manager.py +496 -0
- emdash_core/agent/mcp/tool_factory.py +213 -0
- emdash_core/agent/prompts/__init__.py +38 -0
- emdash_core/agent/prompts/main_agent.py +104 -0
- emdash_core/agent/prompts/subagents.py +131 -0
- emdash_core/agent/prompts/workflow.py +136 -0
- emdash_core/agent/providers/__init__.py +34 -0
- emdash_core/agent/providers/base.py +143 -0
- emdash_core/agent/providers/factory.py +80 -0
- emdash_core/agent/providers/models.py +220 -0
- emdash_core/agent/providers/openai_provider.py +463 -0
- emdash_core/agent/providers/transformers_provider.py +217 -0
- emdash_core/agent/research/__init__.py +81 -0
- emdash_core/agent/research/agent.py +143 -0
- emdash_core/agent/research/controller.py +254 -0
- emdash_core/agent/research/critic.py +428 -0
- emdash_core/agent/research/macros.py +469 -0
- emdash_core/agent/research/planner.py +449 -0
- emdash_core/agent/research/researcher.py +436 -0
- emdash_core/agent/research/state.py +523 -0
- emdash_core/agent/research/synthesizer.py +594 -0
- emdash_core/agent/reviewer_profile.py +475 -0
- emdash_core/agent/rules.py +123 -0
- emdash_core/agent/runner.py +601 -0
- emdash_core/agent/session.py +262 -0
- emdash_core/agent/spec_schema.py +66 -0
- emdash_core/agent/specification.py +479 -0
- emdash_core/agent/subagent.py +397 -0
- emdash_core/agent/subagent_prompts.py +13 -0
- emdash_core/agent/toolkit.py +482 -0
- emdash_core/agent/toolkits/__init__.py +64 -0
- emdash_core/agent/toolkits/base.py +96 -0
- emdash_core/agent/toolkits/explore.py +47 -0
- emdash_core/agent/toolkits/plan.py +55 -0
- emdash_core/agent/tools/__init__.py +141 -0
- emdash_core/agent/tools/analytics.py +436 -0
- emdash_core/agent/tools/base.py +131 -0
- emdash_core/agent/tools/coding.py +484 -0
- emdash_core/agent/tools/github_mcp.py +592 -0
- emdash_core/agent/tools/history.py +13 -0
- emdash_core/agent/tools/modes.py +153 -0
- emdash_core/agent/tools/plan.py +206 -0
- emdash_core/agent/tools/plan_write.py +135 -0
- emdash_core/agent/tools/search.py +412 -0
- emdash_core/agent/tools/spec.py +341 -0
- emdash_core/agent/tools/task.py +262 -0
- emdash_core/agent/tools/task_output.py +204 -0
- emdash_core/agent/tools/tasks.py +454 -0
- emdash_core/agent/tools/traversal.py +588 -0
- emdash_core/agent/tools/web.py +179 -0
- emdash_core/analytics/__init__.py +5 -0
- emdash_core/analytics/engine.py +1286 -0
- emdash_core/api/__init__.py +5 -0
- emdash_core/api/agent.py +308 -0
- emdash_core/api/agents.py +154 -0
- emdash_core/api/analyze.py +264 -0
- emdash_core/api/auth.py +173 -0
- emdash_core/api/context.py +77 -0
- emdash_core/api/db.py +121 -0
- emdash_core/api/embed.py +131 -0
- emdash_core/api/feature.py +143 -0
- emdash_core/api/health.py +93 -0
- emdash_core/api/index.py +162 -0
- emdash_core/api/plan.py +110 -0
- emdash_core/api/projectmd.py +210 -0
- emdash_core/api/query.py +320 -0
- emdash_core/api/research.py +122 -0
- emdash_core/api/review.py +161 -0
- emdash_core/api/router.py +76 -0
- emdash_core/api/rules.py +116 -0
- emdash_core/api/search.py +119 -0
- emdash_core/api/spec.py +99 -0
- emdash_core/api/swarm.py +223 -0
- emdash_core/api/tasks.py +109 -0
- emdash_core/api/team.py +120 -0
- emdash_core/auth/__init__.py +17 -0
- emdash_core/auth/github.py +389 -0
- emdash_core/config.py +74 -0
- emdash_core/context/__init__.py +52 -0
- emdash_core/context/models.py +50 -0
- emdash_core/context/providers/__init__.py +11 -0
- emdash_core/context/providers/base.py +74 -0
- emdash_core/context/providers/explored_areas.py +183 -0
- emdash_core/context/providers/touched_areas.py +360 -0
- emdash_core/context/registry.py +73 -0
- emdash_core/context/reranker.py +199 -0
- emdash_core/context/service.py +260 -0
- emdash_core/context/session.py +352 -0
- emdash_core/core/__init__.py +104 -0
- emdash_core/core/config.py +454 -0
- emdash_core/core/exceptions.py +55 -0
- emdash_core/core/models.py +265 -0
- emdash_core/core/review_config.py +57 -0
- emdash_core/db/__init__.py +67 -0
- emdash_core/db/auth.py +134 -0
- emdash_core/db/models.py +91 -0
- emdash_core/db/provider.py +222 -0
- emdash_core/db/providers/__init__.py +5 -0
- emdash_core/db/providers/supabase.py +452 -0
- emdash_core/embeddings/__init__.py +24 -0
- emdash_core/embeddings/indexer.py +534 -0
- emdash_core/embeddings/models.py +192 -0
- emdash_core/embeddings/providers/__init__.py +7 -0
- emdash_core/embeddings/providers/base.py +112 -0
- emdash_core/embeddings/providers/fireworks.py +141 -0
- emdash_core/embeddings/providers/openai.py +104 -0
- emdash_core/embeddings/registry.py +146 -0
- emdash_core/embeddings/service.py +215 -0
- emdash_core/graph/__init__.py +26 -0
- emdash_core/graph/builder.py +134 -0
- emdash_core/graph/connection.py +692 -0
- emdash_core/graph/schema.py +416 -0
- emdash_core/graph/writer.py +667 -0
- emdash_core/ingestion/__init__.py +7 -0
- emdash_core/ingestion/change_detector.py +150 -0
- emdash_core/ingestion/git/__init__.py +5 -0
- emdash_core/ingestion/git/commit_analyzer.py +196 -0
- emdash_core/ingestion/github/__init__.py +6 -0
- emdash_core/ingestion/github/pr_fetcher.py +296 -0
- emdash_core/ingestion/github/task_extractor.py +100 -0
- emdash_core/ingestion/orchestrator.py +540 -0
- emdash_core/ingestion/parsers/__init__.py +10 -0
- emdash_core/ingestion/parsers/base_parser.py +66 -0
- emdash_core/ingestion/parsers/call_graph_builder.py +121 -0
- emdash_core/ingestion/parsers/class_extractor.py +154 -0
- emdash_core/ingestion/parsers/function_extractor.py +202 -0
- emdash_core/ingestion/parsers/import_analyzer.py +119 -0
- emdash_core/ingestion/parsers/python_parser.py +123 -0
- emdash_core/ingestion/parsers/registry.py +72 -0
- emdash_core/ingestion/parsers/ts_ast_parser.js +313 -0
- emdash_core/ingestion/parsers/typescript_parser.py +278 -0
- emdash_core/ingestion/repository.py +346 -0
- emdash_core/models/__init__.py +38 -0
- emdash_core/models/agent.py +68 -0
- emdash_core/models/index.py +77 -0
- emdash_core/models/query.py +113 -0
- emdash_core/planning/__init__.py +7 -0
- emdash_core/planning/agent_api.py +413 -0
- emdash_core/planning/context_builder.py +265 -0
- emdash_core/planning/feature_context.py +232 -0
- emdash_core/planning/feature_expander.py +646 -0
- emdash_core/planning/llm_explainer.py +198 -0
- emdash_core/planning/similarity.py +509 -0
- emdash_core/planning/team_focus.py +821 -0
- emdash_core/server.py +153 -0
- emdash_core/sse/__init__.py +5 -0
- emdash_core/sse/stream.py +196 -0
- emdash_core/swarm/__init__.py +17 -0
- emdash_core/swarm/merge_agent.py +383 -0
- emdash_core/swarm/session_manager.py +274 -0
- emdash_core/swarm/swarm_runner.py +226 -0
- emdash_core/swarm/task_definition.py +137 -0
- emdash_core/swarm/worker_spawner.py +319 -0
- emdash_core/swarm/worktree_manager.py +278 -0
- emdash_core/templates/__init__.py +10 -0
- emdash_core/templates/defaults/agent-builder.md.template +82 -0
- emdash_core/templates/defaults/focus.md.template +115 -0
- emdash_core/templates/defaults/pr-review-enhanced.md.template +309 -0
- emdash_core/templates/defaults/pr-review.md.template +80 -0
- emdash_core/templates/defaults/project.md.template +85 -0
- emdash_core/templates/defaults/research_critic.md.template +112 -0
- emdash_core/templates/defaults/research_planner.md.template +85 -0
- emdash_core/templates/defaults/research_synthesizer.md.template +128 -0
- emdash_core/templates/defaults/reviewer.md.template +81 -0
- emdash_core/templates/defaults/spec.md.template +41 -0
- emdash_core/templates/defaults/tasks.md.template +78 -0
- emdash_core/templates/loader.py +296 -0
- emdash_core/utils/__init__.py +45 -0
- emdash_core/utils/git.py +84 -0
- emdash_core/utils/image.py +502 -0
- emdash_core/utils/logger.py +51 -0
- emdash_core-0.1.7.dist-info/METADATA +35 -0
- emdash_core-0.1.7.dist-info/RECORD +187 -0
- emdash_core-0.1.7.dist-info/WHEEL +4 -0
- emdash_core-0.1.7.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Research Synthesizer Prompt
|
|
2
|
+
|
|
3
|
+
You are a research synthesizer that produces team-usable reports.
|
|
4
|
+
|
|
5
|
+
## Your Role
|
|
6
|
+
|
|
7
|
+
Combine research findings into a structured report that helps the team take action. Your output should be immediately useful for developers and reviewers.
|
|
8
|
+
|
|
9
|
+
## Required Sections (in order)
|
|
10
|
+
|
|
11
|
+
### 1. Findings
|
|
12
|
+
- List claims with evidence IDs: "**C7** [E12, E13]: Statement here"
|
|
13
|
+
- Group by topic or question
|
|
14
|
+
- Only include claims that have evidence
|
|
15
|
+
- Separate high-confidence (2-3) from lower confidence (0-1)
|
|
16
|
+
|
|
17
|
+
### 2. Evidence Coverage Matrix
|
|
18
|
+
- Show which questions are covered by which evidence
|
|
19
|
+
- Format as markdown table
|
|
20
|
+
- Highlight gaps with ❌
|
|
21
|
+
- Mark answered questions with ✅
|
|
22
|
+
|
|
23
|
+
### 3. Design/Spec Implications
|
|
24
|
+
- What must be true for implementation
|
|
25
|
+
- Design constraints discovered
|
|
26
|
+
- Patterns to follow
|
|
27
|
+
- Reference evidence for each implication
|
|
28
|
+
|
|
29
|
+
### 4. Risks & Unknowns
|
|
30
|
+
- List all gaps explicitly
|
|
31
|
+
- Impact of unknowns on the project
|
|
32
|
+
- How to close each gap
|
|
33
|
+
- Unresolved contradictions
|
|
34
|
+
|
|
35
|
+
### 5. Recommended Tasks
|
|
36
|
+
- Actionable items with clear scope
|
|
37
|
+
- Map each task to supporting evidence
|
|
38
|
+
- Include owner placeholders: "**Owner TBD**"
|
|
39
|
+
- Prioritize based on evidence confidence
|
|
40
|
+
|
|
41
|
+
### 6. Reviewer Checklist
|
|
42
|
+
- What to verify in PRs
|
|
43
|
+
- Critical paths to check
|
|
44
|
+
- Tests to ensure pass
|
|
45
|
+
- Files that need review
|
|
46
|
+
|
|
47
|
+
### 7. Tooling Summary
|
|
48
|
+
- Macro runs and results
|
|
49
|
+
- Tool calls made
|
|
50
|
+
- Budget used vs allocated
|
|
51
|
+
- Iteration history
|
|
52
|
+
|
|
53
|
+
## Critical Rules
|
|
54
|
+
|
|
55
|
+
- **Every claim must show evidence IDs** - No ungrounded statements
|
|
56
|
+
- **No claim without evidence** - Prefer "unknown" to speculation
|
|
57
|
+
- **Gaps must be explicit** - Don't hide unknowns
|
|
58
|
+
- **Use team vocabulary** - Tasks, PRs, reviewers, owners
|
|
59
|
+
- **Be actionable** - End with concrete next steps
|
|
60
|
+
|
|
61
|
+
## Evidence ID Format
|
|
62
|
+
|
|
63
|
+
When referencing evidence, use this format:
|
|
64
|
+
- Single: `[E12]`
|
|
65
|
+
- Multiple: `[E12, E13, E15]`
|
|
66
|
+
- In claims: `**C7** [E12, E13]: The statement here`
|
|
67
|
+
|
|
68
|
+
## Example Output Structure
|
|
69
|
+
|
|
70
|
+
```markdown
|
|
71
|
+
# Research Report: [Topic]
|
|
72
|
+
|
|
73
|
+
## Executive Summary
|
|
74
|
+
Brief overview with key metrics.
|
|
75
|
+
|
|
76
|
+
## Findings
|
|
77
|
+
|
|
78
|
+
### High Confidence
|
|
79
|
+
- **C1** [E1, E3]: Statement with strong evidence
|
|
80
|
+
- **C2** [E2, E4]: Another well-supported claim
|
|
81
|
+
|
|
82
|
+
### Lower Confidence
|
|
83
|
+
- **C3** [E5]: Statement with less support _(Assumption: X)_
|
|
84
|
+
|
|
85
|
+
## Evidence Coverage Matrix
|
|
86
|
+
| Question | Priority | Evidence | Claims | Status |
|
|
87
|
+
|----------|----------|----------|--------|--------|
|
|
88
|
+
| Q1: ... | P0 | E1, E3 | C1 | ✅ |
|
|
89
|
+
| Q2: ... | P1 | - | - | ❌ Gap |
|
|
90
|
+
|
|
91
|
+
## Design/Spec Implications
|
|
92
|
+
1. Based on C1 [E1, E3]: Implication here
|
|
93
|
+
2. Based on C2 [E2, E4]: Another implication
|
|
94
|
+
|
|
95
|
+
## Risks & Unknowns
|
|
96
|
+
### Unanswered Questions
|
|
97
|
+
- **Q2: What about X?**
|
|
98
|
+
- Reason: No relevant code found
|
|
99
|
+
- Impact: May affect Y
|
|
100
|
+
- Suggested: Run `semantic_search` with different terms
|
|
101
|
+
|
|
102
|
+
## Recommended Tasks
|
|
103
|
+
1. Implement based on C1
|
|
104
|
+
- **Owner**: TBD
|
|
105
|
+
- **Evidence**: E1, E3
|
|
106
|
+
|
|
107
|
+
## Reviewer Checklist
|
|
108
|
+
- [ ] Verify: Statement from C1
|
|
109
|
+
- [ ] Check file: `path/to/file.py`
|
|
110
|
+
- [ ] Tests pass for affected areas
|
|
111
|
+
|
|
112
|
+
## Tooling Summary
|
|
113
|
+
| Tool | Calls |
|
|
114
|
+
|------|-------|
|
|
115
|
+
| semantic_search | 5 |
|
|
116
|
+
| expand_node | 3 |
|
|
117
|
+
|
|
118
|
+
Budget: 15/50 tool calls (30%)
|
|
119
|
+
Iterations: 2/3
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Guidelines
|
|
123
|
+
|
|
124
|
+
- Keep it readable - use clear headers and formatting
|
|
125
|
+
- Be honest about gaps - unknowns are valuable information
|
|
126
|
+
- Focus on actionability - what can the team do with this?
|
|
127
|
+
- Reference evidence consistently - build trust through traceability
|
|
128
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Reviewer Profile
|
|
2
|
+
|
|
3
|
+
This template defines the code review patterns and expectations for this repository.
|
|
4
|
+
It is generated by `emdash create-reviewer` based on analysis of top reviewers and contributors.
|
|
5
|
+
|
|
6
|
+
## Identity
|
|
7
|
+
|
|
8
|
+
- **Primary reviewers analyzed**: (none - run `emdash create-reviewer` to populate)
|
|
9
|
+
- **Cross-team contributors analyzed**: (none)
|
|
10
|
+
- **PRs analyzed**: 0
|
|
11
|
+
|
|
12
|
+
## Review Focus Areas
|
|
13
|
+
|
|
14
|
+
When reviewing code, prioritize these aspects:
|
|
15
|
+
|
|
16
|
+
1. **Correctness**: Does the code do what it claims to do?
|
|
17
|
+
2. **Security**: Are there potential vulnerabilities (injection, auth bypass, data exposure)?
|
|
18
|
+
3. **Performance**: Are there obvious inefficiencies or scaling concerns?
|
|
19
|
+
4. **Maintainability**: Is the code readable and well-structured?
|
|
20
|
+
5. **Testing**: Are there adequate tests for the changes?
|
|
21
|
+
|
|
22
|
+
## Feedback Patterns
|
|
23
|
+
|
|
24
|
+
### What to commonly comment on:
|
|
25
|
+
- Missing error handling
|
|
26
|
+
- Unclear variable/function names
|
|
27
|
+
- Missing or outdated documentation
|
|
28
|
+
- Potential edge cases not covered
|
|
29
|
+
- Code duplication that could be refactored
|
|
30
|
+
|
|
31
|
+
### Code quality expectations:
|
|
32
|
+
- Functions should be focused and do one thing well
|
|
33
|
+
- Error messages should be actionable
|
|
34
|
+
- Public APIs should be documented
|
|
35
|
+
- Complex logic should have explanatory comments
|
|
36
|
+
|
|
37
|
+
### Style preferences:
|
|
38
|
+
- Follow the existing patterns in the codebase
|
|
39
|
+
- Prefer explicit over implicit
|
|
40
|
+
- Keep functions reasonably sized
|
|
41
|
+
- Use meaningful names over abbreviations
|
|
42
|
+
|
|
43
|
+
## Tone & Communication
|
|
44
|
+
|
|
45
|
+
- Be constructive and specific
|
|
46
|
+
- Explain the "why" behind suggestions
|
|
47
|
+
- Acknowledge good patterns when you see them
|
|
48
|
+
- Ask questions when intent is unclear rather than assuming
|
|
49
|
+
- Use phrases like "Consider...", "What about...", "Have you thought about..."
|
|
50
|
+
|
|
51
|
+
## Example Comments
|
|
52
|
+
|
|
53
|
+
### Good inline comment:
|
|
54
|
+
```
|
|
55
|
+
Consider using a context manager here to ensure the file handle is always closed,
|
|
56
|
+
even if an exception occurs: `with open(path) as f:`
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Good question:
|
|
60
|
+
```
|
|
61
|
+
I see this catches all exceptions - is that intentional? It might be hiding
|
|
62
|
+
specific errors that we'd want to handle differently.
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Good suggestion:
|
|
66
|
+
```
|
|
67
|
+
This logic appears in three places now. Consider extracting it into a helper
|
|
68
|
+
function like `validate_user_input()` to reduce duplication.
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Review Checklist
|
|
72
|
+
|
|
73
|
+
Before approving, verify:
|
|
74
|
+
|
|
75
|
+
- [ ] Code compiles/passes linting
|
|
76
|
+
- [ ] Tests pass and cover new functionality
|
|
77
|
+
- [ ] No obvious security issues
|
|
78
|
+
- [ ] Error handling is appropriate
|
|
79
|
+
- [ ] Documentation is updated if needed
|
|
80
|
+
- [ ] No sensitive data in logs or responses
|
|
81
|
+
- [ ] Backwards compatibility considered (if applicable)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Specification Rules (JSON)
|
|
2
|
+
|
|
3
|
+
Return a single JSON object that matches this shape. All fields are required.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"title": "Feature name",
|
|
8
|
+
"summary": "One sentence: what is this and why it matters.",
|
|
9
|
+
"problem": "What's broken or missing today? 2-3 sentences.",
|
|
10
|
+
"solution": "Plain English description of the feature.",
|
|
11
|
+
"how_it_works": [
|
|
12
|
+
"Main scenario or flow, step by step",
|
|
13
|
+
"Secondary scenario or edge flow"
|
|
14
|
+
],
|
|
15
|
+
"edge_cases": [
|
|
16
|
+
{ "case": "Edge case", "expected_behavior": "What should happen" }
|
|
17
|
+
],
|
|
18
|
+
"related_code": [
|
|
19
|
+
{ "path": "path/to/file.py", "reason": "Why it's relevant" }
|
|
20
|
+
],
|
|
21
|
+
"assumptions": [
|
|
22
|
+
"Assumption 1"
|
|
23
|
+
],
|
|
24
|
+
"non_goals": [
|
|
25
|
+
"Out of scope item"
|
|
26
|
+
],
|
|
27
|
+
"success_metrics": [
|
|
28
|
+
"How we will measure success"
|
|
29
|
+
],
|
|
30
|
+
"open_questions": [
|
|
31
|
+
"Unknowns or decisions needed"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Rules:
|
|
37
|
+
- Output JSON only, no markdown fences, no commentary.
|
|
38
|
+
- Use actual file paths from the project in related_code.
|
|
39
|
+
- Be specific about behavior; no hand-waving.
|
|
40
|
+
- Avoid implementation details; focus on WHAT, not HOW.
|
|
41
|
+
- If you need clarification, call ask_clarification first, then submit JSON.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Implementation Plan Rules
|
|
2
|
+
|
|
3
|
+
> How we break down features into actionable tasks.
|
|
4
|
+
|
|
5
|
+
## Document Structure
|
|
6
|
+
|
|
7
|
+
An implementation plan should have:
|
|
8
|
+
|
|
9
|
+
1. **Overview** - 1-2 sentences of what we're building and approach
|
|
10
|
+
2. **Reviewer** - Code owner (person with most commits to affected files)
|
|
11
|
+
3. **Blockers** - Only if there are actual blockers (open PRs, unclear requirements)
|
|
12
|
+
4. **Tasks** - Numbered list of specific, single-file tasks
|
|
13
|
+
5. **Tests** - What to test and where test patterns live
|
|
14
|
+
|
|
15
|
+
## Task Design Principles
|
|
16
|
+
|
|
17
|
+
Each task should be:
|
|
18
|
+
|
|
19
|
+
- **Single-prompt executable** - An LLM can complete it in one go
|
|
20
|
+
- **One file focus** - Primarily touches ONE file
|
|
21
|
+
- **Pattern-based** - References similar existing code ("do it like X")
|
|
22
|
+
- **Specific** - Exact file paths and line numbers, not vague directions
|
|
23
|
+
|
|
24
|
+
## What to Explore First
|
|
25
|
+
|
|
26
|
+
Before writing tasks:
|
|
27
|
+
- Find similar PRs to learn team patterns
|
|
28
|
+
- Use get_file_history to find the CODE OWNER (most commits, not PR similarity)
|
|
29
|
+
- Check for open PRs that might conflict
|
|
30
|
+
- Map which files need changes
|
|
31
|
+
|
|
32
|
+
## Example Format
|
|
33
|
+
|
|
34
|
+
```markdown
|
|
35
|
+
# Implementation Plan: Feature Name
|
|
36
|
+
|
|
37
|
+
## Overview
|
|
38
|
+
Brief description of what and how.
|
|
39
|
+
|
|
40
|
+
## Reviewer
|
|
41
|
+
Name - top contributor to `affected/files/` (X commits)
|
|
42
|
+
|
|
43
|
+
## Blockers
|
|
44
|
+
- PR #123 touches same files (wait or coordinate)
|
|
45
|
+
|
|
46
|
+
## Tasks
|
|
47
|
+
|
|
48
|
+
### 1. Add the new component
|
|
49
|
+
**File**: `src/components/NewThing.tsx`
|
|
50
|
+
|
|
51
|
+
Create a new component following the pattern in `src/components/ExistingThing.tsx:15-45`.
|
|
52
|
+
It should accept X props and render Y.
|
|
53
|
+
|
|
54
|
+
**Done when**:
|
|
55
|
+
- [ ] Component renders correctly
|
|
56
|
+
- [ ] Props are typed
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### 2. Wire up to the parent
|
|
61
|
+
**File**: `src/pages/Parent.tsx`
|
|
62
|
+
|
|
63
|
+
Import and use NewThing. Follow how OtherThing is used on line 78.
|
|
64
|
+
|
|
65
|
+
**Done when**:
|
|
66
|
+
- [ ] NewThing appears on the page
|
|
67
|
+
|
|
68
|
+
## Tests
|
|
69
|
+
Add tests in `src/__tests__/` following the pattern in `ExistingThing.test.tsx`.
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Things to Avoid
|
|
73
|
+
|
|
74
|
+
- Time estimates (no "2-3 hours")
|
|
75
|
+
- Vague tasks ("improve error handling")
|
|
76
|
+
- Tasks that touch many files
|
|
77
|
+
- Sections listing "what I found" - synthesize into tasks
|
|
78
|
+
- Guessing where code should go - explore more if unsure
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"""Template loader with 3-tier priority: project -> user -> defaults."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional, Tuple
|
|
6
|
+
|
|
7
|
+
# Template names and their corresponding files
|
|
8
|
+
TEMPLATE_NAMES = {
|
|
9
|
+
"spec": "spec.md.template",
|
|
10
|
+
"tasks": "tasks.md.template",
|
|
11
|
+
"project": "project.md.template",
|
|
12
|
+
"focus": "focus.md.template",
|
|
13
|
+
"pr-review": "pr-review.md.template",
|
|
14
|
+
"reviewer": "reviewer.md.template",
|
|
15
|
+
"agent-builder": "agent-builder.md.template",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# Directory name for templates
|
|
19
|
+
EMDASH_RULES_DIR = ".emdash-rules"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_defaults_dir() -> Path:
|
|
23
|
+
"""Get the path to the bundled defaults directory."""
|
|
24
|
+
return Path(__file__).parent / "defaults"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_project_rules_dir() -> Optional[Path]:
|
|
28
|
+
"""Get the project-local .emdash-rules directory if it exists."""
|
|
29
|
+
cwd = Path.cwd()
|
|
30
|
+
rules_dir = cwd / EMDASH_RULES_DIR
|
|
31
|
+
return rules_dir if rules_dir.is_dir() else None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_user_rules_dir() -> Optional[Path]:
|
|
35
|
+
"""Get the user-wide ~/.emdash-rules directory if it exists."""
|
|
36
|
+
home = Path.home()
|
|
37
|
+
rules_dir = home / EMDASH_RULES_DIR
|
|
38
|
+
return rules_dir if rules_dir.is_dir() else None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_template_path(name: str) -> Tuple[Path, str]:
|
|
42
|
+
"""Get the path to a template and its source tier.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
name: Template name ("spec", "tasks", or "project")
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Tuple of (path, tier) where tier is "project", "user", or "default"
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
ValueError: If template name is invalid
|
|
52
|
+
"""
|
|
53
|
+
if name not in TEMPLATE_NAMES:
|
|
54
|
+
raise ValueError(f"Invalid template name: {name}. Must be one of: {list(TEMPLATE_NAMES.keys())}")
|
|
55
|
+
|
|
56
|
+
filename = TEMPLATE_NAMES[name]
|
|
57
|
+
|
|
58
|
+
# Priority 1: Project-local .emdash-rules/
|
|
59
|
+
project_dir = get_project_rules_dir()
|
|
60
|
+
if project_dir:
|
|
61
|
+
project_path = project_dir / filename
|
|
62
|
+
if project_path.is_file():
|
|
63
|
+
return project_path, "project"
|
|
64
|
+
|
|
65
|
+
# Priority 2: User-wide ~/.emdash-rules/
|
|
66
|
+
user_dir = get_user_rules_dir()
|
|
67
|
+
if user_dir:
|
|
68
|
+
user_path = user_dir / filename
|
|
69
|
+
if user_path.is_file():
|
|
70
|
+
return user_path, "user"
|
|
71
|
+
|
|
72
|
+
# Priority 3: Bundled defaults
|
|
73
|
+
defaults_path = get_defaults_dir() / filename
|
|
74
|
+
return defaults_path, "default"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def load_template(name: str) -> str:
|
|
78
|
+
"""Load a template by name.
|
|
79
|
+
|
|
80
|
+
Searches in order:
|
|
81
|
+
1. .emdash-rules/ in current directory (project-specific)
|
|
82
|
+
2. ~/.emdash-rules/ in home directory (user-wide)
|
|
83
|
+
3. Built-in defaults
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
name: Template name ("spec", "tasks", or "project")
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
The template content as a string
|
|
90
|
+
|
|
91
|
+
Raises:
|
|
92
|
+
ValueError: If template name is invalid
|
|
93
|
+
FileNotFoundError: If template file doesn't exist
|
|
94
|
+
"""
|
|
95
|
+
path, tier = get_template_path(name)
|
|
96
|
+
|
|
97
|
+
if not path.is_file():
|
|
98
|
+
raise FileNotFoundError(f"Template file not found: {path}")
|
|
99
|
+
|
|
100
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
101
|
+
return f.read()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def list_templates() -> list[dict]:
|
|
105
|
+
"""List all templates and their active sources.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
List of dicts with name, path, and tier for each template
|
|
109
|
+
"""
|
|
110
|
+
templates = []
|
|
111
|
+
for name in TEMPLATE_NAMES:
|
|
112
|
+
try:
|
|
113
|
+
path, tier = get_template_path(name)
|
|
114
|
+
templates.append({
|
|
115
|
+
"name": name,
|
|
116
|
+
"filename": TEMPLATE_NAMES[name],
|
|
117
|
+
"path": str(path),
|
|
118
|
+
"tier": tier,
|
|
119
|
+
"exists": path.is_file(),
|
|
120
|
+
})
|
|
121
|
+
except Exception as e:
|
|
122
|
+
templates.append({
|
|
123
|
+
"name": name,
|
|
124
|
+
"filename": TEMPLATE_NAMES[name],
|
|
125
|
+
"path": None,
|
|
126
|
+
"tier": "error",
|
|
127
|
+
"exists": False,
|
|
128
|
+
"error": str(e),
|
|
129
|
+
})
|
|
130
|
+
return templates
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def copy_templates_to_dir(target_dir: Path, overwrite: bool = False) -> list[str]:
|
|
134
|
+
"""Copy default templates to a target directory.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
target_dir: Directory to copy templates to
|
|
138
|
+
overwrite: Whether to overwrite existing files
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
List of copied template filenames
|
|
142
|
+
"""
|
|
143
|
+
defaults_dir = get_defaults_dir()
|
|
144
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
145
|
+
|
|
146
|
+
copied = []
|
|
147
|
+
for name, filename in TEMPLATE_NAMES.items():
|
|
148
|
+
source = defaults_dir / filename
|
|
149
|
+
target = target_dir / filename
|
|
150
|
+
|
|
151
|
+
if not source.is_file():
|
|
152
|
+
continue
|
|
153
|
+
|
|
154
|
+
if target.exists() and not overwrite:
|
|
155
|
+
continue
|
|
156
|
+
|
|
157
|
+
with open(source, "r", encoding="utf-8") as f:
|
|
158
|
+
content = f.read()
|
|
159
|
+
|
|
160
|
+
with open(target, "w", encoding="utf-8") as f:
|
|
161
|
+
f.write(content)
|
|
162
|
+
|
|
163
|
+
copied.append(filename)
|
|
164
|
+
|
|
165
|
+
return copied
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def load_template_for_agent(name: str) -> str:
|
|
169
|
+
"""Load a template and wrap it for LLM agent use.
|
|
170
|
+
|
|
171
|
+
This takes the human-readable rules markdown and wraps it with
|
|
172
|
+
instructions for the LLM to follow those rules.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
name: Template name ("spec", "tasks", or "project")
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
LLM-ready system prompt incorporating the rules
|
|
179
|
+
"""
|
|
180
|
+
rules = load_template(name)
|
|
181
|
+
|
|
182
|
+
# Common tool guidance for all agents
|
|
183
|
+
area_tool_guidance = """
|
|
184
|
+
## Key Tool: get_area_importance
|
|
185
|
+
|
|
186
|
+
Use this tool to understand where activity is concentrated in the codebase:
|
|
187
|
+
|
|
188
|
+
**Directory-level (default):**
|
|
189
|
+
- `get_area_importance(sort='focus')` - Find HOT SPOTS: areas with recent concentrated activity
|
|
190
|
+
- `get_area_importance(sort='importance')` - Find historically important areas (commits × authors)
|
|
191
|
+
- `get_area_importance(sort='commits')` - Areas with most total commits
|
|
192
|
+
- `get_area_importance(sort='authors')` - Areas with most contributors
|
|
193
|
+
|
|
194
|
+
**File-level (use files=true):**
|
|
195
|
+
- `get_area_importance(files=true, sort='focus')` - Hot FILES with most recent commits
|
|
196
|
+
- `get_area_importance(files=true, sort='importance')` - Most important individual files
|
|
197
|
+
|
|
198
|
+
The tool returns for each area/file:
|
|
199
|
+
- path/file_path: Directory or file path
|
|
200
|
+
- total_commits/commits: Commit count
|
|
201
|
+
- file_count: Number of files (areas only)
|
|
202
|
+
- unique_authors/authors: Number of contributors
|
|
203
|
+
- focus_pct/recent_commits: Recent activity metric
|
|
204
|
+
|
|
205
|
+
**Recommended workflow:**
|
|
206
|
+
1. First use sort='focus' to find hot areas
|
|
207
|
+
2. Then use files=true to drill into specific files in those areas
|
|
208
|
+
3. Use semantic_search or expand_node to explore the hot files"""
|
|
209
|
+
|
|
210
|
+
if name == "spec":
|
|
211
|
+
return f"""You are writing a feature specification. Follow these rules:
|
|
212
|
+
|
|
213
|
+
{rules}
|
|
214
|
+
|
|
215
|
+
{area_tool_guidance}
|
|
216
|
+
|
|
217
|
+
IMPORTANT:
|
|
218
|
+
- Your output must be a single JSON object matching the schema in the rules
|
|
219
|
+
- START by using get_area_importance(sort='focus') to find active areas related to the feature
|
|
220
|
+
- Explore the codebase using tools to find similar patterns
|
|
221
|
+
- Use ask_clarification if you need to ask the user questions
|
|
222
|
+
- Be specific and reference actual file paths from the project
|
|
223
|
+
- The hot spots tell you where similar work is happening - look there for patterns"""
|
|
224
|
+
|
|
225
|
+
elif name == "tasks":
|
|
226
|
+
return f"""You are creating an implementation plan. Follow these rules:
|
|
227
|
+
|
|
228
|
+
{rules}
|
|
229
|
+
|
|
230
|
+
{area_tool_guidance}
|
|
231
|
+
|
|
232
|
+
IMPORTANT:
|
|
233
|
+
- Your output must be markdown following the format in the rules
|
|
234
|
+
- START by using get_area_importance(sort='focus') to understand where changes should go
|
|
235
|
+
- Use get_file_history on hot spot files to find the CODE OWNER (most commits)
|
|
236
|
+
- Each task should be executable by an LLM in a single prompt
|
|
237
|
+
- Include exact file paths and line references
|
|
238
|
+
- Reference patterns from the active areas when describing tasks"""
|
|
239
|
+
|
|
240
|
+
elif name == "project":
|
|
241
|
+
return f"""You are writing a PROJECT.md to help new team members understand the codebase. Follow these rules:
|
|
242
|
+
|
|
243
|
+
{rules}
|
|
244
|
+
|
|
245
|
+
{area_tool_guidance}
|
|
246
|
+
|
|
247
|
+
IMPORTANT:
|
|
248
|
+
- Your output must be markdown following the format in the rules
|
|
249
|
+
- START by using get_area_importance(sort='focus') to find where the team spends time
|
|
250
|
+
- The "Where The Action Is" section should highlight these hot spots
|
|
251
|
+
- Use get_area_importance(sort='importance') to find historically critical areas
|
|
252
|
+
- Write like explaining to a teammate, not writing documentation
|
|
253
|
+
- Focus on insight and understanding, not comprehensive lists
|
|
254
|
+
- Hot spots reveal what's actively being built - explain WHY those areas matter"""
|
|
255
|
+
|
|
256
|
+
elif name == "focus":
|
|
257
|
+
return f"""You are a senior engineering manager analyzing team activity and focus. Follow these rules:
|
|
258
|
+
|
|
259
|
+
{rules}
|
|
260
|
+
|
|
261
|
+
CRITICAL REQUIREMENTS:
|
|
262
|
+
- ALL PRs must be clickable links: [PR #123](https://github.com/owner/repo/pull/123)
|
|
263
|
+
- ALL contributors must be clickable links: [@username](https://github.com/username)
|
|
264
|
+
- The GitHub repository URL will be provided in the data - use it for constructing links
|
|
265
|
+
- Explain WHAT is being built, not just which files are touched
|
|
266
|
+
- Use function/class names and docstrings to understand purpose
|
|
267
|
+
- Group work into thematic streams with activity percentages
|
|
268
|
+
- Include a table for PR analysis and key contributors
|
|
269
|
+
- Provide actionable insights and recommendations"""
|
|
270
|
+
|
|
271
|
+
elif name == "pr-review":
|
|
272
|
+
return f"""You are producing a PR review report. Follow these rules:
|
|
273
|
+
|
|
274
|
+
{rules}
|
|
275
|
+
|
|
276
|
+
IMPORTANT:
|
|
277
|
+
- Your output must be markdown
|
|
278
|
+
- Tell a coherent story of the change, not a file list
|
|
279
|
+
- Cite file paths and functions inline when relevant
|
|
280
|
+
- If data is truncated, note it explicitly"""
|
|
281
|
+
|
|
282
|
+
elif name == "reviewer":
|
|
283
|
+
return f"""You are a code reviewer following the team's established review patterns. Use this reviewer profile:
|
|
284
|
+
|
|
285
|
+
{rules}
|
|
286
|
+
|
|
287
|
+
CRITICAL REQUIREMENTS:
|
|
288
|
+
- Review code with the same focus areas and quality expectations as the top reviewers
|
|
289
|
+
- Match the tone and communication style described in the profile
|
|
290
|
+
- Generate inline comments for specific lines of code
|
|
291
|
+
- Provide actionable, constructive feedback
|
|
292
|
+
- Use the checklist to ensure comprehensive review coverage
|
|
293
|
+
- Your output must be structured JSON with summary, verdict, and inline comments"""
|
|
294
|
+
|
|
295
|
+
else:
|
|
296
|
+
return rules
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Utility modules for EmDash."""
|
|
2
|
+
|
|
3
|
+
from .logger import log, setup_logger
|
|
4
|
+
|
|
5
|
+
from .image import (
|
|
6
|
+
is_clipboard_image_available,
|
|
7
|
+
read_clipboard_image,
|
|
8
|
+
encode_image_to_base64,
|
|
9
|
+
encode_image_for_llm,
|
|
10
|
+
resize_image_if_needed,
|
|
11
|
+
get_image_info,
|
|
12
|
+
estimate_image_tokens,
|
|
13
|
+
read_and_prepare_image,
|
|
14
|
+
ClipboardImageError,
|
|
15
|
+
ImageProcessingError,
|
|
16
|
+
ImageFormat,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from .git import (
|
|
20
|
+
get_git_remote_url,
|
|
21
|
+
normalize_repo_url,
|
|
22
|
+
get_normalized_remote_url,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
# Logger
|
|
27
|
+
"log",
|
|
28
|
+
"setup_logger",
|
|
29
|
+
# Image
|
|
30
|
+
"is_clipboard_image_available",
|
|
31
|
+
"read_clipboard_image",
|
|
32
|
+
"encode_image_to_base64",
|
|
33
|
+
"encode_image_for_llm",
|
|
34
|
+
"resize_image_if_needed",
|
|
35
|
+
"get_image_info",
|
|
36
|
+
"estimate_image_tokens",
|
|
37
|
+
"read_and_prepare_image",
|
|
38
|
+
"ClipboardImageError",
|
|
39
|
+
"ImageProcessingError",
|
|
40
|
+
"ImageFormat",
|
|
41
|
+
# Git
|
|
42
|
+
"get_git_remote_url",
|
|
43
|
+
"normalize_repo_url",
|
|
44
|
+
"get_normalized_remote_url",
|
|
45
|
+
]
|