@danmoisan/drm-copilot-mcp 0.0.5 → 1.0.0

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.
Files changed (96) hide show
  1. package/out/mcp-server.js +10268 -380
  2. package/package.json +2 -2
  3. package/resources/claude-customizations/.claude/agents/orchestrator.md +6 -2
  4. package/resources/claude-customizations/.claude/agents/pr-author.md +78 -0
  5. package/resources/claude-customizations/.claude/agents/task-researcher.md +10 -6
  6. package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +68 -10
  7. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +148 -11
  8. package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +163 -0
  9. package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +40 -14
  10. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +198 -0
  11. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +153 -10
  12. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +68 -1
  13. package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +136 -0
  14. package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +22 -6
  15. package/resources/claude-customizations/.claude/settings.json +22 -0
  16. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +0 -1
  17. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +76 -2
  18. package/resources/claude-customizations/.claude/skills/research-issue/SKILL.md +5 -3
  19. package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +69 -0
  20. package/resources/claude-customizations/.claude-variants/csharp-legacy/rules/csharp.md +96 -0
  21. package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +77 -0
  22. package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/invoke-csharp-engineer/SKILL.md +64 -0
  23. package/resources/claude-customizations/pack-manifests/core.json +65 -0
  24. package/resources/claude-customizations/pack-manifests/csharp-legacy.json +11 -0
  25. package/resources/claude-customizations/pack-manifests/csharp-modern.json +12 -0
  26. package/resources/claude-customizations/pack-manifests/powershell.json +14 -0
  27. package/resources/claude-customizations/pack-manifests/python.json +14 -0
  28. package/resources/claude-customizations/pack-manifests/typescript.json +9 -0
  29. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +30 -13
  30. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +113 -10
  31. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +33 -8
  32. package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +12 -7
  33. package/resources/codex-and-agents-customizations/.codex/config.toml +65 -6
  34. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +303 -0
  35. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +300 -0
  36. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +148 -0
  37. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-pr-author-skill.ps1 +336 -0
  38. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +83 -17
  39. package/resources/config/orchestration-routing.json +5 -13
  40. package/resources/customizations/.github/agents/pr-author.agent.md +25 -0
  41. package/resources/customizations/.github/agents/task-researcher.agent.md +4 -4
  42. package/resources/customizations/.github/prompts/fillout-prd-feature.prompt.md +1 -1
  43. package/resources/customizations/.github/prompts/research-issue.prompt.md +4 -3
  44. package/resources/codex-and-agents-customizations/.codex/scripts/post-codex-worktree-session.ps1 +0 -5
  45. package/resources/scripts/dev_tools/__init__.py +0 -0
  46. package/resources/scripts/dev_tools/_orchestrator_state_human_interaction.py +0 -127
  47. package/resources/scripts/dev_tools/_orchestrator_state_routing.py +0 -216
  48. package/resources/scripts/dev_tools/agentic_sync.py +0 -819
  49. package/resources/scripts/dev_tools/codex_native_converter/__init__.py +0 -11
  50. package/resources/scripts/dev_tools/codex_native_converter/__main__.py +0 -6
  51. package/resources/scripts/dev_tools/codex_native_converter/cli.py +0 -11
  52. package/resources/scripts/dev_tools/new_active_feature_folder.py +0 -79
  53. package/resources/scripts/dev_tools/new_active_feature_folder_docs.py +0 -268
  54. package/resources/scripts/dev_tools/new_active_feature_folder_flow.py +0 -366
  55. package/resources/scripts/dev_tools/new_active_feature_folder_io.py +0 -306
  56. package/resources/scripts/dev_tools/new_active_feature_folder_markdown.py +0 -252
  57. package/resources/scripts/dev_tools/new_active_feature_folder_models.py +0 -136
  58. package/resources/scripts/dev_tools/new_potential_bug_entry.py +0 -465
  59. package/resources/scripts/dev_tools/potential_to_issue.py +0 -421
  60. package/resources/scripts/dev_tools/potential_to_issue_content.py +0 -212
  61. package/resources/scripts/dev_tools/pr_context/__init__.py +0 -0
  62. package/resources/scripts/dev_tools/pr_context/collector.py +0 -619
  63. package/resources/scripts/dev_tools/pr_context/feature_docs.py +0 -349
  64. package/resources/scripts/dev_tools/pr_context/git.py +0 -153
  65. package/resources/scripts/dev_tools/pr_context/github.py +0 -549
  66. package/resources/scripts/dev_tools/pr_context/models.py +0 -198
  67. package/resources/scripts/dev_tools/pr_context/render.py +0 -342
  68. package/resources/scripts/dev_tools/pr_context/render_feature_excerpts.py +0 -256
  69. package/resources/scripts/dev_tools/pr_context/render_pr_helpers.py +0 -291
  70. package/resources/scripts/dev_tools/pr_context/summary_helpers.py +0 -386
  71. package/resources/scripts/dev_tools/pr_context/verification_evidence.py +0 -171
  72. package/resources/scripts/dev_tools/prompt_mode_contract.py +0 -152
  73. package/resources/scripts/dev_tools/push_down_claude_customizations.py +0 -374
  74. package/resources/scripts/dev_tools/push_down_codex_and_agents_customizations.py +0 -139
  75. package/resources/scripts/dev_tools/push_down_copilot_customizations.py +0 -504
  76. package/resources/scripts/dev_tools/push_down_copilot_customizations_filesystem.py +0 -217
  77. package/resources/scripts/dev_tools/push_down_copilot_customizations_rewrites.py +0 -293
  78. package/resources/scripts/dev_tools/resolve_file_prompt.py +0 -457
  79. package/resources/scripts/dev_tools/resolve_hard_lock_prompt.py +0 -444
  80. package/resources/scripts/dev_tools/validate_orchestration_artifacts.py +0 -246
  81. package/resources/scripts/dev_tools/validate_orchestration_review_artifacts.py +0 -107
  82. package/resources/scripts/dev_tools/validate_orchestrator_state.py +0 -428
  83. package/resources/scripts/dev_tools/validate_policy_audit_artifact.py +0 -448
  84. package/resources/templates/codex_native_converter.py +0 -35
  85. package/resources/templates/collect_commit_context.py +0 -212
  86. package/resources/templates/collect_pr_context.py +0 -74
  87. package/resources/templates/hello_python.py +0 -11
  88. package/resources/templates/new_active_feature_folder.py +0 -67
  89. package/resources/templates/new_potential_bug_entry.py +0 -54
  90. package/resources/templates/potential_to_issue.py +0 -55
  91. package/resources/templates/push_down_claude_customizations.py +0 -409
  92. package/resources/templates/push_down_codex_and_agents_customizations.py +0 -95
  93. package/resources/templates/push_down_copilot_customizations.py +0 -124
  94. package/resources/templates/resolve_atomic_plan_prompt.py +0 -75
  95. package/resources/templates/resolve_hard_lock_prompt.py +0 -65
  96. package/resources/templates/validate_orchestration_artifacts.py +0 -55
@@ -1,198 +0,0 @@
1
- """Shared models and helpers for PR context collection."""
2
-
3
- from __future__ import annotations
4
-
5
- import re
6
- from dataclasses import dataclass
7
- from typing import TYPE_CHECKING
8
-
9
- if TYPE_CHECKING:
10
- from collections.abc import Iterable
11
-
12
- SECTION_LINE = "===== {title} ====="
13
- CONVENTIONAL_TYPES = (
14
- "feat",
15
- "fix",
16
- "refactor",
17
- "perf",
18
- "docs",
19
- "test",
20
- "chore",
21
- "build",
22
- "ci",
23
- "style",
24
- )
25
-
26
-
27
- @dataclass
28
- class CommandResult:
29
- """Represents the outcome of a shell command."""
30
-
31
- stdout: str
32
- stderr: str
33
- code: int
34
-
35
-
36
- @dataclass
37
- class IssueDetails:
38
- """Issue metadata, body, comments, and optional user story content."""
39
-
40
- number: str
41
- title: str
42
- state: str
43
- labels: list[str]
44
- assignees: list[str]
45
- author: str
46
- created_at: str
47
- updated_at: str
48
- body: str
49
- comments: list[str]
50
- user_story_path: str | None = None
51
- user_story_content: str | None = None
52
-
53
-
54
- @dataclass
55
- class PullRequestDetails:
56
- """Pull request metadata and body content."""
57
-
58
- number: str
59
- title: str
60
- state: str
61
- author: str
62
- base_ref: str
63
- head_ref: str
64
- created_at: str
65
- updated_at: str
66
- merged_at: str | None
67
- labels: list[str]
68
- assignees: list[str]
69
- body: str
70
- closing_issues: list[str]
71
- files_changed: list[str]
72
-
73
-
74
- @dataclass
75
- class FeatureDocExcerpt:
76
- """Feature documentation excerpts and referenced issues."""
77
-
78
- feature: str
79
- excerpt: str
80
- issue_refs: list[str]
81
- context_files: list[str]
82
- primary_issue_ref: str | None = None
83
- readiness_signal: str | None = None
84
-
85
-
86
- @dataclass
87
- class PRContextResult:
88
- """Structured result from building the PR comparison section."""
89
-
90
- text: str
91
- referenced_issues: list[str]
92
- referenced_prs: list[str]
93
- verified_closing: list[str]
94
- invalid_references: list[str]
95
- base_ref: str | None
96
- resolved_base: str | None
97
- base_sha: str | None
98
- head_ref: str | None
99
- head_sha: str | None
100
- merge_base: str | None
101
- rev_range: str | None
102
- gh_available: bool = True
103
-
104
-
105
- @dataclass
106
- class GitHubCLIStatus:
107
- """Status snapshot for GitHub CLI availability."""
108
-
109
- healthy: bool
110
- message: str
111
-
112
-
113
- @dataclass
114
- class CIStatusSnapshot:
115
- """Minimal CI status for a given commit."""
116
-
117
- status: str | None
118
- failing_jobs: list[str]
119
-
120
-
121
- @dataclass
122
- class BaseHeadInfo:
123
- """Resolved base/head refs and merge-base provenance."""
124
-
125
- requested_base: str | None
126
- resolved_base: str
127
- base_sha: str
128
- head_ref: str
129
- head_sha: str
130
- merge_base: str
131
- warning: str | None = None
132
-
133
-
134
- @dataclass
135
- class ScopingDocChange:
136
- """Represents a scoping doc change and its materiality."""
137
-
138
- path: str
139
- additions: int
140
- deletions: int
141
- change_type: str
142
- material: bool
143
- reasons: list[str]
144
- excerpt: str | None = None
145
-
146
-
147
- def section(title: str) -> str:
148
- return "\n" + SECTION_LINE.format(title=title) + "\n"
149
-
150
-
151
- def truncate(text: str, limit: int = 800) -> str:
152
- if len(text) <= limit:
153
- return text
154
- return text[: limit - 3].rstrip() + "..."
155
-
156
-
157
- def truncate_lines(text: str, limit: int) -> str:
158
- lines = text.splitlines()
159
- if len(lines) <= limit:
160
- return text
161
- head = "\n".join(lines[:limit])
162
- return f"{head}\n\nTRUNCATED: first {limit} lines shown"
163
-
164
-
165
- def normalize_reference(ref: str) -> str:
166
- return ref.lstrip("#").strip()
167
-
168
-
169
- def find_user_story_link(body: str) -> str | None:
170
- if not body:
171
- return None
172
-
173
- match = re.search(r"\(([^)]+user-story\.md)\)", body, flags=re.IGNORECASE)
174
- candidate = match.group(1) if match else None
175
-
176
- if not candidate:
177
- fallback = re.search(r"\b\S*user-story\.md\b", body, flags=re.IGNORECASE)
178
- candidate = fallback.group(0) if fallback else None
179
-
180
- if not candidate:
181
- return None
182
-
183
- github_blob = re.search(
184
- r"github\.com/[^/]+/[^/]+/blob/[^/]+/(.+user-story\.md)",
185
- candidate,
186
- flags=re.IGNORECASE,
187
- )
188
- if github_blob:
189
- return github_blob.group(1)
190
-
191
- return candidate.lstrip("/")
192
-
193
-
194
- def format_list(values: Iterable[str], empty_text: str) -> str:
195
- values_list = [value for value in values if value]
196
- if not values_list:
197
- return empty_text
198
- return "\n".join(f"- {item}" for item in values_list)
@@ -1,342 +0,0 @@
1
- """Rendering and extraction helpers for PR context collection."""
2
-
3
- from __future__ import annotations
4
-
5
- import re
6
- import subprocess
7
- from typing import TYPE_CHECKING, Protocol
8
-
9
- from .models import PRContextResult, normalize_reference, section
10
- from .render_feature_excerpts import (
11
- build_excerpt_text,
12
- completed_plan_tasks,
13
- directory_exists,
14
- extract_features_from_paths,
15
- extract_plan_sections,
16
- extract_spec_parts,
17
- extract_story_parts,
18
- gather_feature_excerpts,
19
- parse_section,
20
- read_text_file,
21
- )
22
- from .render_pr_helpers import (
23
- build_close_candidates_section,
24
- convert_numstat,
25
- extension_summary,
26
- extract_changed_paths,
27
- extract_issue_references,
28
- extract_merge_pr_numbers,
29
- format_diff_path,
30
- format_issue_details,
31
- format_pr_details,
32
- select_default_base,
33
- summarize_conventional_commits,
34
- )
35
-
36
- if TYPE_CHECKING:
37
- from collections.abc import Iterable
38
- from pathlib import Path
39
-
40
- from .git import GitClient
41
- from .models import PullRequestDetails
42
-
43
- __all__ = [
44
- "build_close_candidates_section",
45
- "build_excerpt_text",
46
- "build_pr_context",
47
- "completed_plan_tasks",
48
- "convert_numstat",
49
- "directory_exists",
50
- "extension_summary",
51
- "extract_changed_paths",
52
- "extract_features_from_paths",
53
- "extract_issue_references",
54
- "extract_merge_pr_numbers",
55
- "extract_plan_sections",
56
- "extract_spec_parts",
57
- "extract_story_parts",
58
- "format_diff_path",
59
- "format_issue_details",
60
- "format_pr_details",
61
- "gather_feature_excerpts",
62
- "parse_section",
63
- "read_text_file",
64
- "resolve_feature_dir",
65
- "select_default_base",
66
- "summarize_conventional_commits",
67
- ]
68
-
69
-
70
- class GhLike(Protocol):
71
- def ensure_available(self) -> None: ...
72
-
73
- def classify_entity(self, number: str) -> str | None: ...
74
-
75
- @property
76
- def available(self) -> bool: ...
77
-
78
-
79
- def resolve_feature_dir(base_dir: Path, feature: str) -> Path | None:
80
- """Resolve feature directory by exact, strong-pattern, then weak match."""
81
- direct = base_dir / feature
82
- if directory_exists(direct):
83
- return direct
84
-
85
- if not directory_exists(base_dir):
86
- return None
87
-
88
- pattern = re.compile(rf"(?:^|[-_]){re.escape(feature)}(?:[-_]|$)")
89
- strong_matches: list[Path] = []
90
- weak_matches: list[Path] = []
91
-
92
- for candidate in sorted(base_dir.iterdir()):
93
- if not candidate.is_dir():
94
- continue
95
- name = candidate.name
96
- if pattern.search(name):
97
- strong_matches.append(candidate)
98
- elif feature in name:
99
- weak_matches.append(candidate)
100
-
101
- if strong_matches:
102
- return strong_matches[0]
103
- if weak_matches:
104
- return weak_matches[0]
105
- return None
106
-
107
-
108
- def build_pr_context(
109
- *,
110
- git: GitClient,
111
- gh: GhLike,
112
- base_ref: str | None,
113
- head_ref: str | None,
114
- include_untracked: bool,
115
- feature_issue_refs: Iterable[str] | None = None,
116
- current_pr: PullRequestDetails | None = None,
117
- gh_available: bool | None = None,
118
- ) -> PRContextResult:
119
- """Build the full PR context payload from git/gh state and references."""
120
- gh_available = (
121
- gh.available
122
- if gh_available is None and hasattr(gh, "available")
123
- else gh_available
124
- )
125
- gh_available = True if gh_available is None else gh_available
126
- if gh_available:
127
- gh.ensure_available()
128
- branch_name = git.branch_name()
129
- upstream = git.upstream() or "(none)"
130
-
131
- remotes = git.remote_verbose()
132
- status_short = git.status_short()
133
- untracked = git.untracked() if include_untracked else ""
134
- untracked_display = untracked if untracked.strip() else "(none)"
135
-
136
- feature_issue_list = list(feature_issue_refs or [])
137
- referenced_issues: list[str] = []
138
- referenced_prs: list[str] = []
139
- verified_closing = (
140
- current_pr.closing_issues if (current_pr and gh_available) else []
141
- )
142
- invalid_references: list[str] = []
143
-
144
- resolved_base: str | None = None
145
- base_sha: str | None = None
146
- head_sha: str | None = None
147
- head_ref_resolved: str | None = head_ref or branch_name
148
- merge_base: str | None = None
149
- rev_range: str | None = None
150
-
151
- pr_block = ""
152
- base_warning: str | None = None
153
- try:
154
- requested_base = base_ref
155
- resolved_base = base_ref or select_default_base(git)
156
- if not resolved_base:
157
- raise RuntimeError("Failed to resolve base ref (tried common defaults)")
158
-
159
- if not resolved_base.startswith("origin/"):
160
- remote_candidate = f"origin/{resolved_base}"
161
- remote_probe = git.run(
162
- ["rev-parse", "--verify", "--quiet", remote_candidate],
163
- allow_error=True,
164
- )
165
- if remote_probe.code == 0 and remote_probe.stdout.strip():
166
- resolved_base = remote_candidate
167
- elif requested_base:
168
- base_warning = (
169
- "WARNING: Requested base is local and may be stale; prefer "
170
- f"origin/{requested_base}"
171
- )
172
-
173
- base_sha = git.rev_parse(resolved_base)
174
- head_ref_resolved = head_ref or branch_name
175
- head_sha = git.rev_parse(head_ref_resolved or "HEAD")
176
- merge_base = git.merge_base(base_sha, head_sha)
177
- rev_range = f"{merge_base}..{head_sha}"
178
-
179
- oneline = git.log("--pretty=format:%h %ad %an %s", rev_range)
180
- subjects = git.log("--pretty=%s", rev_range)
181
- authors = git.log("--format=%an <%ae>", rev_range)
182
- authors_list = sorted(
183
- {line.strip() for line in authors.splitlines() if line.strip()}
184
- )
185
-
186
- name_status = git.diff_range(["--name-status", merge_base, head_sha])
187
- numstat = git.diff_range(["--numstat", merge_base, head_sha])
188
- shortstat = git.diff_range(["--shortstat", merge_base, head_sha])
189
- stat = git.diff_range(["--stat", merge_base, head_sha])
190
-
191
- additions, deletions, files = convert_numstat(numstat)
192
- ext_summary = extension_summary(files)
193
- merge_prs = extract_merge_pr_numbers(oneline.splitlines())
194
-
195
- issue_candidates = [
196
- ref
197
- for ref in extract_issue_references(oneline + "\n" + subjects)
198
- if ref not in merge_prs
199
- ]
200
- issues: list[str] = []
201
- prs: list[str] = []
202
- for ref in issue_candidates:
203
- number = normalize_reference(ref)
204
- if gh_available:
205
- entity = gh.classify_entity(number)
206
- else:
207
- entity = None
208
- formatted_ref = ref if ref.startswith("#") else f"#{ref}"
209
- if entity == "issue":
210
- issues.append(formatted_ref)
211
- elif entity == "pull":
212
- prs.append(formatted_ref)
213
- else:
214
- if gh_available:
215
- invalid_references.append(formatted_ref)
216
- else:
217
- issues.append(formatted_ref)
218
- referenced_issues = sorted(set(issues))
219
- referenced_prs = sorted(set(prs + merge_prs))
220
-
221
- issues_display = ", ".join(sorted(set(referenced_issues + feature_issue_list)))
222
- if not issues_display:
223
- issues_display = "(none)"
224
- prs_display = ", ".join(referenced_prs) if referenced_prs else "(none)"
225
-
226
- oneline_display = oneline if oneline.strip() else "(none)"
227
- authors_display = "\n".join(authors_list) if authors_list else "(none)"
228
- name_status_display = name_status if name_status.strip() else "(none)"
229
- short_display = shortstat if shortstat.strip() else "(none)"
230
- ext_display = ext_summary if ext_summary else "(none)"
231
- stat_display = stat if stat.strip() else "(none)"
232
-
233
- block_lines = [
234
- section("PR Comparison"),
235
- f"Base ref (requested): {requested_base or '(default)'}",
236
- f"Base ref (resolved): {resolved_base} @ {base_sha}",
237
- f"Head ref (resolved): {head_ref_resolved} @ {head_sha}",
238
- f"Merge-base: {merge_base}",
239
- ]
240
- if base_warning:
241
- block_lines.append(f"Base warning: {base_warning}")
242
- block_lines.extend(
243
- [
244
- f"Range: {rev_range}\n",
245
- section("Commits in range"),
246
- oneline_display,
247
- "",
248
- section("Conventional commit type summary"),
249
- summarize_conventional_commits(subjects),
250
- "",
251
- section("Authors"),
252
- authors_display,
253
- "",
254
- section("Changed files (name-status)"),
255
- name_status_display,
256
- "",
257
- section("Diff shortstat"),
258
- short_display,
259
- "",
260
- section("Additions/Deletions totals (from numstat)"),
261
- f"Additions: {additions}\nDeletions: {deletions}\n",
262
- section("Files by extension"),
263
- ext_display,
264
- "",
265
- section("Referenced issues (detected)"),
266
- issues_display,
267
- "",
268
- section("PRs in range"),
269
- prs_display,
270
- "",
271
- section("Diff stat"),
272
- stat_display,
273
- ]
274
- )
275
- pr_block = "\n".join(block_lines)
276
- except (subprocess.CalledProcessError, RuntimeError, ValueError, OSError) as exc:
277
- pr_block = section("PR Comparison") + f"(FAILED to compute PR context: {exc})\n"
278
- referenced_issues = []
279
- referenced_prs = []
280
- verified_closing = []
281
- invalid_references = []
282
- resolved_base = None
283
- base_sha = None
284
- head_sha = None
285
- head_ref_resolved = head_ref or branch_name
286
- merge_base = None
287
- rev_range = None
288
-
289
- intent = "\n".join(
290
- [
291
- section("PR Intent (edit before generating PR body)"),
292
- "Primary outcome:",
293
- "Impact (user/developer):",
294
- "Risks:",
295
- "Author-asserted autoclose issues:",
296
- ]
297
- )
298
-
299
- combined_text = "\n".join(
300
- [
301
- intent,
302
- section("Repository remotes"),
303
- remotes,
304
- "",
305
- section("Current branch"),
306
- branch_name,
307
- "",
308
- section("Upstream"),
309
- upstream,
310
- "",
311
- section("Status (short)"),
312
- status_short,
313
- "",
314
- section("Untracked files"),
315
- untracked_display,
316
- "",
317
- section("Working tree diff (staged)"),
318
- git.diff_name_status(staged=True),
319
- git.diff_patch(staged=True),
320
- "",
321
- section("Working tree diff (unstaged)"),
322
- git.diff_name_status(staged=False),
323
- git.diff_patch(staged=False),
324
- pr_block,
325
- ]
326
- )
327
-
328
- return PRContextResult(
329
- text=combined_text,
330
- referenced_issues=referenced_issues,
331
- referenced_prs=referenced_prs,
332
- verified_closing=sorted(set(verified_closing)),
333
- invalid_references=sorted(set(invalid_references)),
334
- base_ref=base_ref,
335
- resolved_base=resolved_base,
336
- base_sha=base_sha,
337
- head_ref=head_ref_resolved,
338
- head_sha=head_sha,
339
- merge_base=merge_base,
340
- rev_range=rev_range,
341
- gh_available=gh_available,
342
- )