claude-dev-env 1.38.1 → 1.40.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.
- package/CLAUDE.md +10 -36
- package/_shared/pr-loop/audit-reply-template.md +147 -0
- package/_shared/pr-loop/fix-protocol.md +25 -4
- package/_shared/pr-loop/gh-payloads.md +37 -50
- package/_shared/pr-loop/scripts/code_rules_gate.py +0 -60
- package/_shared/pr-loop/scripts/config/post_audit_thread_constants.py +199 -0
- package/_shared/pr-loop/scripts/config/reviews_disabled_constants.py +8 -0
- package/_shared/pr-loop/scripts/post_audit_thread.py +1242 -0
- package/_shared/pr-loop/scripts/preflight.py +129 -2
- package/_shared/pr-loop/scripts/reviews_disabled.py +59 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +0 -19
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +1116 -0
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +127 -0
- package/_shared/pr-loop/scripts/tests/test_preflight.py +41 -0
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +36 -0
- package/_shared/pr-loop/state-schema.md +1 -1
- package/agents/clean-coder.md +2 -2
- package/agents/pr-description-writer.md +150 -52
- package/bin/install.mjs +6 -7
- package/bin/install.test.mjs +8 -0
- package/commands/doc-gist.md +16 -0
- package/commands/plan.md +0 -2
- package/commands/review-plan.md +1 -1
- package/docs/CODE_RULES.md +122 -2
- package/docs/PR_DESCRIPTION_GUIDE.md +127 -64
- package/hooks/blocking/bot_mention_comment_blocker.py +75 -0
- package/hooks/blocking/code_rules_enforcer.py +1143 -129
- package/hooks/blocking/convergence_gate_blocker.py +130 -0
- package/hooks/blocking/destructive_command_blocker.py +74 -0
- package/hooks/blocking/gh_body_arg_blocker.py +30 -0
- package/hooks/blocking/md_to_html_blocker.py +119 -0
- package/hooks/blocking/pr_description_enforcer.py +57 -22
- package/hooks/blocking/test_bot_mention_comment_blocker.py +131 -0
- package/hooks/blocking/test_code_rules_enforcer.py +21 -0
- package/hooks/blocking/test_code_rules_enforcer_any_exempt_files.py +70 -0
- package/hooks/blocking/test_code_rules_enforcer_any_imports_and_cast.py +92 -0
- package/hooks/blocking/test_code_rules_enforcer_banned_import_alias.py +143 -0
- package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +152 -0
- package/hooks/blocking/test_code_rules_enforcer_bare_except.py +120 -0
- package/hooks/blocking/test_code_rules_enforcer_boundary_types.py +175 -0
- package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +0 -1
- package/hooks/blocking/test_code_rules_enforcer_collection_prefix.py +50 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_format.py +255 -0
- package/hooks/blocking/test_code_rules_enforcer_inline_tuple_string_magic.py +130 -0
- package/hooks/blocking/test_code_rules_enforcer_stub_implementations.py +141 -0
- package/hooks/blocking/test_code_rules_enforcer_test_branching.py +143 -0
- package/hooks/blocking/test_code_rules_enforcer_thin_wrapper_files.py +169 -0
- package/hooks/blocking/test_code_rules_enforcer_todo_markers.py +99 -0
- package/hooks/blocking/test_code_rules_enforcer_typed_dict_pairs.py +141 -0
- package/hooks/blocking/test_convergence_gate_blocker.py +63 -0
- package/hooks/blocking/test_destructive_command_blocker.py +146 -0
- package/hooks/blocking/test_destructive_command_blocker_no_verify.py +102 -0
- package/hooks/blocking/test_gh_body_arg_blocker.py +45 -0
- package/hooks/blocking/test_md_to_html_blocker.py +317 -0
- package/hooks/blocking/test_pr_description_enforcer.py +69 -8
- package/hooks/config/any_type_config.py +7 -0
- package/hooks/config/banned_identifiers_constants.py +11 -0
- package/hooks/config/blocking_check_limits.py +38 -0
- package/hooks/config/bot_mention_comment_blocker_constants.py +20 -0
- package/hooks/config/code_rules_enforcer_constants.py +53 -0
- package/hooks/config/convergence_branch_constants.py +9 -0
- package/hooks/config/doc_gist_auto_publish_constants.py +18 -0
- package/hooks/config/html_companion_constants.py +20 -0
- package/hooks/config/inline_tuple_string_magic_constants.py +22 -0
- package/hooks/config/pr_description_enforcer_constants.py +14 -0
- package/hooks/config/test_banned_identifiers_constants.py +17 -0
- package/hooks/hooks.json +28 -20
- package/hooks/pyproject.toml +69 -0
- package/hooks/validators/mypy_integration.py +47 -1
- package/hooks/validators/run_all_validators.py +3 -3
- package/hooks/validators/test_mypy_integration.py +50 -1
- package/hooks/workflow/doc_gist_auto_publish.py +144 -0
- package/hooks/workflow/md_to_html_companion.py +365 -0
- package/hooks/workflow/test_doc_gist_auto_publish.py +117 -0
- package/hooks/workflow/test_md_to_html_companion.py +452 -0
- package/package.json +1 -1
- package/rules/gh-body-file.md +2 -0
- package/scripts/Install-SweepEmptyDirs.ps1 +111 -0
- package/scripts/check.ps1 +106 -0
- package/scripts/config/timing.py +11 -0
- package/scripts/sweep_empty_dirs.py +138 -0
- package/scripts/sync_to_cursor/rules.py +1 -1
- package/scripts/test_sweep_empty_dirs.py +183 -0
- package/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +323 -0
- package/skills/_shared/pr-loop/scripts/_cli_utils.py +22 -0
- package/skills/_shared/pr-loop/scripts/_path_resolver.py +165 -0
- package/skills/_shared/pr-loop/scripts/_xml_utils.py +20 -0
- package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +182 -0
- package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +185 -0
- package/skills/_shared/pr-loop/scripts/config/__init__.py +0 -0
- package/skills/_shared/pr-loop/scripts/config/path_resolver_constants.py +78 -0
- package/skills/_shared/pr-loop/scripts/init_loop_state.py +135 -0
- package/skills/_shared/pr-loop/scripts/teardown_worktrees.py +175 -0
- package/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +182 -0
- package/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +206 -0
- package/skills/bugteam/CONSTRAINTS.md +21 -22
- package/skills/bugteam/EXAMPLES.md +3 -3
- package/skills/bugteam/PROMPTS.md +227 -67
- package/skills/bugteam/SKILL.md +132 -455
- package/skills/bugteam/reference/README.md +1 -1
- package/skills/bugteam/reference/audit-and-teammates.md +112 -39
- package/skills/bugteam/reference/audit-contract.md +4 -22
- package/skills/bugteam/reference/copilot-gap-analysis.md +8 -5
- package/skills/bugteam/reference/design-rationale.md +2 -2
- package/skills/bugteam/reference/github-pr-reviews.md +50 -57
- package/skills/bugteam/reference/obstacles/audit-assign-ids.md +13 -0
- package/skills/bugteam/reference/obstacles/audit-capture-excerpts.md +13 -0
- package/skills/bugteam/reference/obstacles/audit-walk-categories.md +13 -0
- package/skills/bugteam/reference/obstacles/audit-write-xml.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-append-summary.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-apply-fixes.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-git-add-commit.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-git-push.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-post-reply.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-publish-summary.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-py-compile.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-read-files.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-resolve-thread.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-test-suite.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-violation-count.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-write-xml.md +13 -0
- package/skills/bugteam/reference/team-setup.md +111 -9
- package/skills/bugteam/reference/teardown-publish-permissions.md +39 -8
- package/skills/bugteam/scripts/README.md +60 -0
- package/skills/bugteam/scripts/_claude_permissions_common.py +358 -0
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +976 -0
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +375 -0
- package/skills/bugteam/scripts/bugteam_preflight.py +328 -0
- package/skills/bugteam/scripts/config/bugteam_code_rules_gate_constants.py +25 -0
- package/skills/bugteam/scripts/config/bugteam_fix_hookspath_constants.py +26 -0
- package/skills/bugteam/scripts/config/bugteam_preflight_constants.py +35 -0
- package/skills/bugteam/scripts/config/claude_permissions_common_constants.py +20 -0
- package/skills/bugteam/scripts/config/probe_code_rules_enforcer_check_constants.py +12 -0
- package/skills/bugteam/scripts/config/windows_safe_rmtree_constants.py +7 -0
- package/skills/bugteam/scripts/grant_project_claude_permissions.py +175 -0
- package/skills/bugteam/scripts/probe_code_rules_enforcer_check.py +107 -0
- package/skills/bugteam/scripts/revoke_project_claude_permissions.py +220 -0
- package/skills/bugteam/scripts/test__claude_permissions_common.py +112 -0
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +400 -0
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +384 -0
- package/skills/bugteam/scripts/test_bugteam_preflight.py +309 -0
- package/skills/bugteam/scripts/test_claude_permissions_common.py +195 -0
- package/skills/bugteam/scripts/test_grant_project_claude_permissions.py +55 -0
- package/skills/bugteam/scripts/test_probe_code_rules_enforcer_check.py +76 -0
- package/skills/bugteam/scripts/test_revoke_project_claude_permissions.py +55 -0
- package/skills/bugteam/scripts/test_windows_safe_rmtree.py +108 -0
- package/skills/bugteam/scripts/windows_safe_rmtree.py +100 -0
- package/skills/bugteam/test_skill_additions.py +1 -11
- package/skills/code/SKILL.md +176 -0
- package/skills/copilot-review/SKILL.md +16 -0
- package/skills/doc-gist/SKILL.md +99 -0
- package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +453 -0
- package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +515 -0
- package/skills/doc-gist/references/examples/03-code-review-pr.html +638 -0
- package/skills/doc-gist/references/examples/04-code-understanding.html +491 -0
- package/skills/doc-gist/references/examples/05-design-system.html +629 -0
- package/skills/doc-gist/references/examples/06-component-variants.html +605 -0
- package/skills/doc-gist/references/examples/07-prototype-animation.html +455 -0
- package/skills/doc-gist/references/examples/08-prototype-interaction.html +396 -0
- package/skills/doc-gist/references/examples/09-slide-deck.html +592 -0
- package/skills/doc-gist/references/examples/10-svg-illustrations.html +492 -0
- package/skills/doc-gist/references/examples/11-status-report.html +528 -0
- package/skills/doc-gist/references/examples/12-incident-report.html +596 -0
- package/skills/doc-gist/references/examples/13-flowchart-diagram.html +395 -0
- package/skills/doc-gist/references/examples/14-research-feature-explainer.html +381 -0
- package/skills/doc-gist/references/examples/15-research-concept-explainer.html +368 -0
- package/skills/doc-gist/references/examples/16-implementation-plan.html +702 -0
- package/skills/doc-gist/references/examples/17-pr-writeup.html +595 -0
- package/skills/doc-gist/references/examples/18-editor-triage-board.html +573 -0
- package/skills/doc-gist/references/examples/19-editor-feature-flags.html +663 -0
- package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +722 -0
- package/skills/doc-gist/references/examples/README.md +5 -0
- package/skills/doc-gist/scripts/config/__init__.py +0 -0
- package/skills/doc-gist/scripts/config/gist_upload_constants.py +16 -0
- package/skills/doc-gist/scripts/gist_upload.py +177 -0
- package/skills/doc-gist/scripts/test_gist_upload.py +51 -0
- package/skills/findbugs/SKILL.md +96 -2
- package/skills/monitor-open-prs/SKILL.md +14 -32
- package/skills/monitor-open-prs/test_skill_contract.py +0 -11
- package/skills/pr-consistency-audit/SKILL.md +112 -0
- package/skills/pr-consistency-audit/reference/detection-rules.md +96 -0
- package/skills/pr-consistency-audit/reference/illustrations.md +78 -0
- package/skills/pr-converge/SKILL.md +229 -23
- package/skills/pr-converge/config/__init__.py +0 -0
- package/skills/pr-converge/config/constants.py +63 -0
- package/skills/pr-converge/reference/convergence-gates.md +138 -44
- package/skills/pr-converge/reference/examples.md +43 -11
- package/skills/pr-converge/reference/fix-protocol.md +6 -5
- package/skills/pr-converge/reference/ground-rules.md +5 -3
- package/skills/pr-converge/reference/multi-pr-orchestration.md +44 -19
- package/skills/pr-converge/reference/obstacles/fix-post-replies.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-push.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-read-filelines.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-reset-state.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-resolve-threads.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-spawn-clean-coder.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-stage-commit.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-trigger-bugbot.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-write-test.md +13 -0
- package/skills/pr-converge/reference/per-tick.md +107 -31
- package/skills/pr-converge/reference/state-schema.md +22 -1
- package/skills/pr-converge/reference/stop-conditions.md +9 -7
- package/skills/pr-converge/scripts/README.md +34 -46
- package/skills/pr-converge/scripts/check_bugbot_ci.py +279 -0
- package/skills/pr-converge/scripts/check_convergence.py +497 -0
- package/skills/pr-converge/scripts/check_pending_reviews.py +154 -0
- package/skills/pr-converge/scripts/config/pr_converge_constants.py +118 -0
- package/skills/pr-converge/scripts/fetch_copilot_reviews.py +134 -0
- package/skills/pr-converge/scripts/post_fix_reply.py +168 -0
- package/skills/pr-converge/scripts/test_check_bugbot_ci.py +312 -0
- package/skills/pr-converge/workflows/schedule-wakeup-loop.md +5 -12
- package/skills/qbug/SKILL.md +157 -27
- package/skills/session-log/SKILL.md +216 -114
- package/skills/session-tidy/SKILL.md +1 -1
- package/skills/skill-builder/SKILL.md +138 -56
- package/skills/skill-builder/references/delegation-map.md +72 -113
- package/skills/skill-builder/references/progressive-disclosure.md +122 -0
- package/skills/skill-builder/references/self-audit-checklist.md +92 -0
- package/skills/skill-builder/references/skill-types.md +228 -0
- package/skills/skill-builder/references/thariq-x-post-skills.json +33 -0
- package/skills/skill-builder/templates/gap-analysis.md +15 -8
- package/skills/skill-builder/workflows/improve-skill.md +86 -57
- package/skills/skill-builder/workflows/new-skill.md +80 -168
- package/skills/skill-builder/workflows/polish-skill.md +78 -54
- package/skills/structure-prompt/SKILL.md +50 -0
- package/skills/structure-prompt/reference/adversarial-tuning.md +62 -0
- package/skills/structure-prompt/reference/block-classification.md +27 -0
- package/skills/structure-prompt/reference/canonical-case.md +48 -0
- package/skills/structure-prompt/reference/citation-depth.md +70 -0
- package/skills/structure-prompt/reference/cleanup.md +33 -0
- package/skills/structure-prompt/reference/constraints.md +33 -0
- package/skills/structure-prompt/reference/directives.md +37 -0
- package/skills/structure-prompt/reference/examples.md +72 -0
- package/skills/structure-prompt/reference/instantiation.md +51 -0
- package/skills/structure-prompt/reference/output-contract.md +72 -0
- package/skills/structure-prompt/reference/per-category.md +23 -0
- package/skills/structure-prompt/reference/persona.md +38 -0
- package/skills/structure-prompt/reference/research.md +33 -0
- package/skills/structure-prompt/reference/structure.md +28 -0
- package/agents/code-standards-agent.md +0 -93
- package/agents/groq-coder.md +0 -113
- package/agents/plan-executor.md +0 -226
- package/agents/project-docs-analyzer.md +0 -53
- package/agents/project-structure-organizer-agent.md +0 -72
- package/agents/skill-to-agent-converter.md +0 -370
- package/agents/skill-writer-agent.md +0 -470
- package/agents/user-docs-writer.md +0 -67
- package/agents/workflow-visual-documenter.md +0 -82
- package/commands/readability-review.md +0 -20
- package/hooks/mypy.ini +0 -2
- package/hooks/notification/attention_needed_notify.py +0 -71
- package/hooks/notification/claude_notification_handler.py +0 -67
- package/hooks/notification/notification_utils.py +0 -267
- package/hooks/notification/subagent_complete_notify.py +0 -381
- package/hooks/notification/test_attention_needed_notify.py +0 -47
- package/hooks/notification/test_claude_notification_handler.py +0 -54
- package/hooks/notification/test_notification_utils.py +0 -91
- package/hooks/notification/test_subagent_complete_notify.py +0 -79
- package/scripts/config/groq_bugteam_config.py +0 -230
- package/scripts/config/test_groq_bugteam_config.py +0 -83
- package/scripts/config/test_spec_implementer_prompt.py +0 -32
- package/scripts/groq_bugteam.README.md +0 -131
- package/scripts/groq_bugteam.py +0 -647
- package/scripts/groq_bugteam_dotenv.py +0 -40
- package/scripts/groq_bugteam_spec.py +0 -226
- package/scripts/test_groq_bugteam.py +0 -529
- package/scripts/test_groq_bugteam_apply_fix_from_spec.py +0 -426
- package/scripts/test_groq_bugteam_dotenv.py +0 -66
- package/scripts/test_groq_bugteam_spec.py +0 -338
- package/skills/bugteam/SKILL_EVALS.md +0 -309
- package/skills/dream/SKILL.md +0 -118
- package/skills/ingest/SKILL.md +0 -40
- package/skills/npm-creator/SKILL.md +0 -187
- package/skills/readability-review/SKILL.md +0 -127
- package/skills/resume-review/SKILL.md +0 -261
- package/skills/rule-audit/SKILL.md +0 -307
- package/skills/rule-creator/SKILL.md +0 -150
- package/skills/searching-obsidian-vault/SKILL.md +0 -131
- package/skills/skill-writer/REFERENCE.md +0 -284
- package/skills/skill-writer/SKILL.md +0 -222
- package/skills/tdd-team/SKILL.md +0 -128
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Shared CLI utilities for pr-loop scripts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def require_file(file_path: Path, label: str) -> int | None:
|
|
10
|
+
"""Verify a required file exists, returning an exit code when absent.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
file_path: Path to the required file.
|
|
14
|
+
label: Human-readable label for the error message.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
None when the file exists (caller continues), or 1 when absent.
|
|
18
|
+
"""
|
|
19
|
+
if not file_path.is_file():
|
|
20
|
+
print(f"{label} not found: {file_path}", file=sys.stderr)
|
|
21
|
+
return 1
|
|
22
|
+
return None
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Canonical path resolution for pr-loop skills (bugteam, qbug, findbugs, fixbugs).
|
|
2
|
+
|
|
3
|
+
Single source of truth for all path patterns — when a path changes, only this
|
|
4
|
+
file is edited. Pure functions with no side effects.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import tempfile
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from config.path_resolver_constants import (
|
|
13
|
+
DIFF_PATCH_TEMPLATE,
|
|
14
|
+
FIX_OUTCOME_XML_TEMPLATE,
|
|
15
|
+
MULTI_PR_SLUG_TEMPLATE,
|
|
16
|
+
OUTCOME_XML_TEMPLATE,
|
|
17
|
+
PER_PR_WORKSPACE_TEMPLATE,
|
|
18
|
+
RUN_NAME_TEMPLATE_MULTI,
|
|
19
|
+
RUN_NAME_TEMPLATE_SINGLE,
|
|
20
|
+
SLUGIFY_REPLACEMENT,
|
|
21
|
+
SLUGIFY_SAFE_CHARS,
|
|
22
|
+
WORKTREE_DIRNAME,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def sanitize_branch_name(head_branch: str) -> str:
|
|
27
|
+
"""Replace filesystem-unsafe characters in a git branch name.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
head_branch: Raw git branch name (e.g. 'feat/my-branch').
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Sanitized string safe for use in directory names.
|
|
34
|
+
"""
|
|
35
|
+
return SLUGIFY_SAFE_CHARS.sub(SLUGIFY_REPLACEMENT, head_branch)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def build_run_name(pr_number: int, head_branch: str, *, is_multi_pr: bool) -> str:
|
|
39
|
+
"""Build the run_name directory token for a single or multi-PR run.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
pr_number: Pull request number.
|
|
43
|
+
head_branch: Head branch ref (used for multi-PR naming).
|
|
44
|
+
is_multi_pr: True when the run spans multiple PRs.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Run name string (e.g. 'bugteam-pr-422' or 'bugteam-feat-my-branch').
|
|
48
|
+
"""
|
|
49
|
+
if is_multi_pr:
|
|
50
|
+
return RUN_NAME_TEMPLATE_MULTI.format(
|
|
51
|
+
sanitized_branch=sanitize_branch_name(head_branch),
|
|
52
|
+
)
|
|
53
|
+
return RUN_NAME_TEMPLATE_SINGLE.format(number=pr_number)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def resolve_run_temp_dir(run_name: str) -> Path:
|
|
57
|
+
"""Resolve the temporary directory for a given run name.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
run_name: Run name token (from build_run_name).
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Absolute path to the run's temp directory.
|
|
64
|
+
"""
|
|
65
|
+
return Path(tempfile.gettempdir()) / run_name
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def slugify_pr_identity(owner: str, repo: str, pr_number: int) -> str:
|
|
69
|
+
"""Generate a slugified identity token for a PR.
|
|
70
|
+
|
|
71
|
+
Used as a subdirectory name under the run temp dir in multi-PR scenarios.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
owner: GitHub repository owner.
|
|
75
|
+
repo: GitHub repository name.
|
|
76
|
+
pr_number: Pull request number.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Slugified token (e.g. 'jl-cmd-claude-code-config-pr-422').
|
|
80
|
+
"""
|
|
81
|
+
return MULTI_PR_SLUG_TEMPLATE.format(owner=owner, repo=repo, number=pr_number)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def per_pr_workspace(
|
|
85
|
+
run_temp_dir: Path, owner: str, repo: str, pr_number: int
|
|
86
|
+
) -> dict[str, object]:
|
|
87
|
+
"""Build the per-PR workspace paths dict.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
run_temp_dir: Run temp directory (from resolve_run_temp_dir).
|
|
91
|
+
owner: GitHub repository owner.
|
|
92
|
+
repo: GitHub repository name.
|
|
93
|
+
pr_number: Pull request number.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Dict with keys:
|
|
97
|
+
- worktree: Path to the git worktree checkout
|
|
98
|
+
- diff_patch_template: str template with {loop} placeholder
|
|
99
|
+
- outcome_xml_template: str template with {number} and {loop} placeholders
|
|
100
|
+
- fix_outcome_xml_template: str template with {number} and {loop} placeholders
|
|
101
|
+
"""
|
|
102
|
+
pr_workspace_dir = run_temp_dir / PER_PR_WORKSPACE_TEMPLATE.format(number=pr_number)
|
|
103
|
+
slug = slugify_pr_identity(owner, repo, pr_number)
|
|
104
|
+
return {
|
|
105
|
+
"worktree": pr_workspace_dir / WORKTREE_DIRNAME,
|
|
106
|
+
"diff_patch_template": str(pr_workspace_dir / slug / DIFF_PATCH_TEMPLATE),
|
|
107
|
+
"outcome_xml_template": OUTCOME_XML_TEMPLATE,
|
|
108
|
+
"fix_outcome_xml_template": FIX_OUTCOME_XML_TEMPLATE,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def outcome_xml_path(worktree_path: Path, pr_number: int, loop_number: int) -> Path:
|
|
113
|
+
"""Construct the canonical path for an AUDIT outcome XML file.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
worktree_path: Path to the git worktree (from per_pr_workspace).
|
|
117
|
+
pr_number: Pull request number.
|
|
118
|
+
loop_number: Current loop iteration.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Absolute path (e.g. '<worktree>/.bugteam-pr422-loop3.outcomes.xml').
|
|
122
|
+
"""
|
|
123
|
+
return worktree_path / OUTCOME_XML_TEMPLATE.format(
|
|
124
|
+
number=pr_number, loop=loop_number
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def fix_outcome_xml_path(worktree_path: Path, pr_number: int, loop_number: int) -> Path:
|
|
129
|
+
"""Construct the canonical path for a FIX outcome XML file.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
worktree_path: Path to the git worktree (from per_pr_workspace).
|
|
133
|
+
pr_number: Pull request number.
|
|
134
|
+
loop_number: Current loop iteration.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Absolute path (e.g. '<worktree>/.bugteam-pr422-loop3.fix-outcomes.xml').
|
|
138
|
+
"""
|
|
139
|
+
return worktree_path / FIX_OUTCOME_XML_TEMPLATE.format(
|
|
140
|
+
number=pr_number, loop=loop_number
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def diff_patch_path(
|
|
145
|
+
run_temp_dir: Path,
|
|
146
|
+
owner: str,
|
|
147
|
+
repo: str,
|
|
148
|
+
pr_number: int,
|
|
149
|
+
loop_number: int,
|
|
150
|
+
) -> Path:
|
|
151
|
+
"""Construct the path for a diff/patch file.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
run_temp_dir: Run temp directory (from resolve_run_temp_dir).
|
|
155
|
+
owner: GitHub repository owner.
|
|
156
|
+
repo: GitHub repository name.
|
|
157
|
+
pr_number: Pull request number.
|
|
158
|
+
loop_number: Current loop iteration.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Absolute path (e.g. '<run_temp>/jl-cmd-claude-code-config-pr-422/loop-3.patch').
|
|
162
|
+
"""
|
|
163
|
+
slug = slugify_pr_identity(owner, repo, pr_number)
|
|
164
|
+
filename = DIFF_PATCH_TEMPLATE.format(loop=loop_number)
|
|
165
|
+
return run_temp_dir / slug / filename
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Shared XML utilities for pr-loop scripts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from xml.dom import minidom
|
|
6
|
+
from xml.etree.ElementTree import Element, tostring
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def emit_pretty_xml(root: Element) -> str:
|
|
10
|
+
"""Serialize an ElementTree to a pretty-printed XML string.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
root: Root XML element.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
Pretty-printed XML string.
|
|
17
|
+
"""
|
|
18
|
+
raw_text = tostring(root, encoding="unicode")
|
|
19
|
+
reparsed_dom = minidom.parseString(raw_text)
|
|
20
|
+
return reparsed_dom.toprettyxml(indent=" ")
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Emit the complete AUDIT spawn prompt XML to stdout.
|
|
2
|
+
|
|
3
|
+
Substitutes <context>, <scope>, <bug_categories>, <constraints>,
|
|
4
|
+
<comment_posting>, and <output_format> blocks from CLI args.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
python scripts/build_audit_prompt.py --owner jl-cmd --repo claude-code-config --pr-number 422 --loop 1 --head-ref feat/branch --base-ref main --worktree-path <PATH> --run-temp-dir <PATH>
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import sys
|
|
14
|
+
from xml.etree.ElementTree import Element, SubElement
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
_self_dir = Path(__file__).resolve().parent
|
|
18
|
+
if str(_self_dir) not in sys.path:
|
|
19
|
+
sys.path.insert(0, str(_self_dir))
|
|
20
|
+
|
|
21
|
+
from _xml_utils import emit_pretty_xml
|
|
22
|
+
from config.path_resolver_constants import (
|
|
23
|
+
ALL_AUDIT_CATEGORY_ENTRIES,
|
|
24
|
+
ALL_AUDIT_CONSTRAINT_TEXTS,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def build_audit_prompt_xml(
|
|
29
|
+
*,
|
|
30
|
+
owner: str,
|
|
31
|
+
repo: str,
|
|
32
|
+
pr_number: int,
|
|
33
|
+
loop: int,
|
|
34
|
+
head_ref: str,
|
|
35
|
+
base_ref: str,
|
|
36
|
+
worktree_path: Path,
|
|
37
|
+
run_temp_dir: Path,
|
|
38
|
+
) -> Element:
|
|
39
|
+
"""Build the complete AUDIT spawn prompt XML.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
owner: GitHub repository owner.
|
|
43
|
+
repo: GitHub repository name.
|
|
44
|
+
pr_number: Pull request number.
|
|
45
|
+
loop: Loop iteration number.
|
|
46
|
+
head_ref: Head branch ref.
|
|
47
|
+
base_ref: Base branch ref.
|
|
48
|
+
worktree_path: Path to the git worktree.
|
|
49
|
+
run_temp_dir: Path to the run temp directory.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Root <spawn_prompt> element.
|
|
53
|
+
"""
|
|
54
|
+
root = Element("spawn_prompt", {"role": "audit", "loop": str(loop)})
|
|
55
|
+
|
|
56
|
+
context = SubElement(root, "context")
|
|
57
|
+
SubElement(context, "owner").text = owner
|
|
58
|
+
SubElement(context, "repo").text = repo
|
|
59
|
+
SubElement(context, "pr_number").text = str(pr_number)
|
|
60
|
+
SubElement(context, "head_ref").text = head_ref
|
|
61
|
+
SubElement(context, "base_ref").text = base_ref
|
|
62
|
+
SubElement(context, "worktree_path").text = str(worktree_path)
|
|
63
|
+
SubElement(context, "run_temp_dir").text = str(run_temp_dir)
|
|
64
|
+
|
|
65
|
+
scope = SubElement(root, "scope")
|
|
66
|
+
scope.text = (
|
|
67
|
+
f"Audit the full diff of {owner}/{repo}#{pr_number} "
|
|
68
|
+
f"({head_ref} against {base_ref}) for CODE_RULES violations, "
|
|
69
|
+
f"bugs, and anti-patterns. Work in {worktree_path}."
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
bug_categories = SubElement(root, "bug_categories")
|
|
73
|
+
for each_category_id, each_category_label in ALL_AUDIT_CATEGORY_ENTRIES:
|
|
74
|
+
cat_elem = SubElement(bug_categories, "category", {"id": each_category_id})
|
|
75
|
+
cat_elem.text = each_category_label
|
|
76
|
+
|
|
77
|
+
constraints = SubElement(root, "constraints")
|
|
78
|
+
for each_constraint in ALL_AUDIT_CONSTRAINT_TEXTS:
|
|
79
|
+
SubElement(constraints, "constraint").text = each_constraint
|
|
80
|
+
|
|
81
|
+
comment_posting = SubElement(root, "comment_posting")
|
|
82
|
+
comment_posting.text = (
|
|
83
|
+
"Post findings as inline review comments on the PR via "
|
|
84
|
+
"the GitHub MCP add_comment_to_pending_review tool. "
|
|
85
|
+
"Group related findings into a single pending review."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
output_format = SubElement(root, "output_format")
|
|
89
|
+
output_format.text = (
|
|
90
|
+
"Emit findings as JSON array of objects with keys: "
|
|
91
|
+
"severity (P0/P1/P2), file, line, category, message, suggestion."
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
return root
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def emit_audit_prompt(
|
|
98
|
+
*,
|
|
99
|
+
owner: str,
|
|
100
|
+
repo: str,
|
|
101
|
+
pr_number: int,
|
|
102
|
+
loop: int,
|
|
103
|
+
head_ref: str,
|
|
104
|
+
base_ref: str,
|
|
105
|
+
worktree_path: Path,
|
|
106
|
+
run_temp_dir: Path,
|
|
107
|
+
) -> str:
|
|
108
|
+
"""Build and serialize the AUDIT spawn prompt to a pretty-printed XML string.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
owner: GitHub repository owner.
|
|
112
|
+
repo: GitHub repository name.
|
|
113
|
+
pr_number: Pull request number.
|
|
114
|
+
loop: Loop iteration number.
|
|
115
|
+
head_ref: Head branch ref.
|
|
116
|
+
base_ref: Base branch ref.
|
|
117
|
+
worktree_path: Path to the git worktree.
|
|
118
|
+
run_temp_dir: Path to the run temp directory.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Pretty-printed XML string.
|
|
122
|
+
"""
|
|
123
|
+
root = build_audit_prompt_xml(
|
|
124
|
+
owner=owner,
|
|
125
|
+
repo=repo,
|
|
126
|
+
pr_number=pr_number,
|
|
127
|
+
loop=loop,
|
|
128
|
+
head_ref=head_ref,
|
|
129
|
+
base_ref=base_ref,
|
|
130
|
+
worktree_path=worktree_path,
|
|
131
|
+
run_temp_dir=run_temp_dir,
|
|
132
|
+
)
|
|
133
|
+
return emit_pretty_xml(root)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def parse_arguments(all_argv: list[str]) -> argparse.Namespace:
|
|
137
|
+
"""Parse command-line arguments.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
all_argv: Command-line argument list.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Parsed namespace with all required audit prompt parameters.
|
|
144
|
+
"""
|
|
145
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
146
|
+
parser.add_argument("--owner", required=True)
|
|
147
|
+
parser.add_argument("--repo", required=True)
|
|
148
|
+
parser.add_argument("--pr-number", type=int, required=True)
|
|
149
|
+
parser.add_argument("--loop", type=int, required=True)
|
|
150
|
+
parser.add_argument("--head-ref", required=True)
|
|
151
|
+
parser.add_argument("--base-ref", required=True)
|
|
152
|
+
parser.add_argument("--worktree-path", type=Path, required=True)
|
|
153
|
+
parser.add_argument("--run-temp-dir", type=Path, required=True)
|
|
154
|
+
return parser.parse_args(all_argv)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def main(all_arguments: list[str]) -> int:
|
|
158
|
+
"""Entry point: emit AUDIT spawn prompt XML to stdout.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
all_arguments: Command-line arguments.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
0 on success.
|
|
165
|
+
"""
|
|
166
|
+
arguments = parse_arguments(all_arguments)
|
|
167
|
+
xml_output = emit_audit_prompt(
|
|
168
|
+
owner=arguments.owner,
|
|
169
|
+
repo=arguments.repo,
|
|
170
|
+
pr_number=getattr(arguments, "pr_number"),
|
|
171
|
+
loop=arguments.loop,
|
|
172
|
+
head_ref=getattr(arguments, "head_ref"),
|
|
173
|
+
base_ref=getattr(arguments, "base_ref"),
|
|
174
|
+
worktree_path=getattr(arguments, "worktree_path"),
|
|
175
|
+
run_temp_dir=getattr(arguments, "run_temp_dir"),
|
|
176
|
+
)
|
|
177
|
+
sys.stdout.write(xml_output)
|
|
178
|
+
return 0
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
if __name__ == "__main__":
|
|
182
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Emit the complete FIX spawn prompt XML to stdout.
|
|
2
|
+
|
|
3
|
+
Populates <bug> entries from findings JSON, plus <execution> checklist
|
|
4
|
+
and <constraints>.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
python scripts/build_fix_prompt.py --owner jl-cmd --repo claude-code-config --pr-number 422 --loop 1 --head-ref feat/branch --base-ref main --worktree-path <PATH> --findings-json <PATH>
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import sys
|
|
15
|
+
from xml.etree.ElementTree import Element, SubElement
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
_self_dir = Path(__file__).resolve().parent
|
|
19
|
+
if str(_self_dir) not in sys.path:
|
|
20
|
+
sys.path.insert(0, str(_self_dir))
|
|
21
|
+
|
|
22
|
+
from _cli_utils import require_file
|
|
23
|
+
from _xml_utils import emit_pretty_xml
|
|
24
|
+
from config.path_resolver_constants import (
|
|
25
|
+
ALL_FIX_CONSTRAINT_TEXTS,
|
|
26
|
+
ALL_FIX_EXECUTION_STEPS,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def build_fix_prompt_xml(
|
|
31
|
+
*,
|
|
32
|
+
owner: str,
|
|
33
|
+
repo: str,
|
|
34
|
+
pr_number: int,
|
|
35
|
+
loop: int,
|
|
36
|
+
head_ref: str,
|
|
37
|
+
base_ref: str,
|
|
38
|
+
worktree_path: Path,
|
|
39
|
+
findings_json_path: Path,
|
|
40
|
+
) -> Element:
|
|
41
|
+
"""Build the complete FIX spawn prompt XML.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
owner: GitHub repository owner.
|
|
45
|
+
repo: GitHub repository name.
|
|
46
|
+
pr_number: Pull request number.
|
|
47
|
+
loop: Loop iteration number.
|
|
48
|
+
head_ref: Head branch ref.
|
|
49
|
+
base_ref: Base branch ref.
|
|
50
|
+
worktree_path: Path to the git worktree.
|
|
51
|
+
findings_json_path: Path to the findings JSON file.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Root <spawn_prompt> element.
|
|
55
|
+
"""
|
|
56
|
+
findings_data = json.loads(findings_json_path.read_text(encoding="utf-8"))
|
|
57
|
+
|
|
58
|
+
root = Element("spawn_prompt", {"role": "fix", "loop": str(loop)})
|
|
59
|
+
|
|
60
|
+
context = SubElement(root, "context")
|
|
61
|
+
SubElement(context, "owner").text = owner
|
|
62
|
+
SubElement(context, "repo").text = repo
|
|
63
|
+
SubElement(context, "pr_number").text = str(pr_number)
|
|
64
|
+
SubElement(context, "head_ref").text = head_ref
|
|
65
|
+
SubElement(context, "base_ref").text = base_ref
|
|
66
|
+
SubElement(context, "worktree_path").text = str(worktree_path)
|
|
67
|
+
|
|
68
|
+
bugs_elem = SubElement(root, "bugs")
|
|
69
|
+
if isinstance(findings_data, list):
|
|
70
|
+
for each_finding in findings_data:
|
|
71
|
+
if isinstance(each_finding, dict):
|
|
72
|
+
bug = SubElement(bugs_elem, "bug")
|
|
73
|
+
for each_key, each_field_detail in each_finding.items():
|
|
74
|
+
child = SubElement(bug, each_key)
|
|
75
|
+
child.text = (
|
|
76
|
+
str(each_field_detail) if each_field_detail is not None else ""
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
execution = SubElement(root, "execution")
|
|
80
|
+
for each_step in ALL_FIX_EXECUTION_STEPS:
|
|
81
|
+
SubElement(execution, "step").text = each_step
|
|
82
|
+
|
|
83
|
+
constraints = SubElement(root, "constraints")
|
|
84
|
+
for each_constraint in ALL_FIX_CONSTRAINT_TEXTS:
|
|
85
|
+
SubElement(constraints, "constraint").text = each_constraint
|
|
86
|
+
|
|
87
|
+
return root
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def emit_fix_prompt(
|
|
91
|
+
*,
|
|
92
|
+
owner: str,
|
|
93
|
+
repo: str,
|
|
94
|
+
pr_number: int,
|
|
95
|
+
loop: int,
|
|
96
|
+
head_ref: str,
|
|
97
|
+
base_ref: str,
|
|
98
|
+
worktree_path: Path,
|
|
99
|
+
findings_json_path: Path,
|
|
100
|
+
) -> str:
|
|
101
|
+
"""Build and serialize the FIX spawn prompt to a pretty-printed XML string.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
owner: GitHub repository owner.
|
|
105
|
+
repo: GitHub repository name.
|
|
106
|
+
pr_number: Pull request number.
|
|
107
|
+
loop: Loop iteration number.
|
|
108
|
+
head_ref: Head branch ref.
|
|
109
|
+
base_ref: Base branch ref.
|
|
110
|
+
worktree_path: Path to the git worktree.
|
|
111
|
+
findings_json_path: Path to the findings JSON file.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Pretty-printed XML string.
|
|
115
|
+
"""
|
|
116
|
+
root = build_fix_prompt_xml(
|
|
117
|
+
owner=owner,
|
|
118
|
+
repo=repo,
|
|
119
|
+
pr_number=pr_number,
|
|
120
|
+
loop=loop,
|
|
121
|
+
head_ref=head_ref,
|
|
122
|
+
base_ref=base_ref,
|
|
123
|
+
worktree_path=worktree_path,
|
|
124
|
+
findings_json_path=findings_json_path,
|
|
125
|
+
)
|
|
126
|
+
return emit_pretty_xml(root)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def parse_arguments(all_argv: list[str]) -> argparse.Namespace:
|
|
130
|
+
"""Parse command-line arguments.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
all_argv: Command-line argument list.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Parsed namespace with all required fix prompt parameters.
|
|
137
|
+
"""
|
|
138
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
139
|
+
parser.add_argument("--owner", required=True)
|
|
140
|
+
parser.add_argument("--repo", required=True)
|
|
141
|
+
parser.add_argument("--pr-number", type=int, required=True)
|
|
142
|
+
parser.add_argument("--loop", type=int, required=True)
|
|
143
|
+
parser.add_argument("--head-ref", required=True)
|
|
144
|
+
parser.add_argument("--base-ref", required=True)
|
|
145
|
+
parser.add_argument("--worktree-path", type=Path, required=True)
|
|
146
|
+
parser.add_argument("--findings-json", type=Path, required=True)
|
|
147
|
+
return parser.parse_args(all_argv)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def main(all_arguments: list[str]) -> int:
|
|
151
|
+
"""Entry point: emit FIX spawn prompt XML to stdout.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
all_arguments: Command-line arguments.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
0 on success, 1 on failure.
|
|
158
|
+
"""
|
|
159
|
+
arguments = parse_arguments(all_arguments)
|
|
160
|
+
findings_path = getattr(arguments, "findings_json")
|
|
161
|
+
|
|
162
|
+
early_exit = require_file(findings_path, "findings-json")
|
|
163
|
+
if early_exit is not None:
|
|
164
|
+
return early_exit
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
xml_output = emit_fix_prompt(
|
|
168
|
+
owner=arguments.owner,
|
|
169
|
+
repo=arguments.repo,
|
|
170
|
+
pr_number=getattr(arguments, "pr_number"),
|
|
171
|
+
loop=arguments.loop,
|
|
172
|
+
head_ref=getattr(arguments, "head_ref"),
|
|
173
|
+
base_ref=getattr(arguments, "base_ref"),
|
|
174
|
+
worktree_path=getattr(arguments, "worktree_path"),
|
|
175
|
+
findings_json_path=findings_path,
|
|
176
|
+
)
|
|
177
|
+
except (json.JSONDecodeError, OSError) as exc:
|
|
178
|
+
print(f"emit_fix_prompt failed: {exc}", file=sys.stderr)
|
|
179
|
+
return 1
|
|
180
|
+
sys.stdout.write(xml_output)
|
|
181
|
+
return 0
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if __name__ == "__main__":
|
|
185
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
File without changes
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Path template constants for the bugteam / pr-loop shared scripts."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
RUN_NAME_TEMPLATE_SINGLE = "bugteam-pr-{number}"
|
|
6
|
+
RUN_NAME_TEMPLATE_MULTI = "bugteam-{sanitized_branch}"
|
|
7
|
+
PER_PR_WORKSPACE_TEMPLATE = "pr-{number}"
|
|
8
|
+
WORKTREE_DIRNAME = "worktree"
|
|
9
|
+
DIFF_PATCH_TEMPLATE = "loop-{loop}.patch"
|
|
10
|
+
OUTCOME_XML_TEMPLATE = ".bugteam-pr{number}-loop{loop}.outcomes.xml"
|
|
11
|
+
FIX_OUTCOME_XML_TEMPLATE = ".bugteam-pr{number}-loop{loop}.fix-outcomes.xml"
|
|
12
|
+
LOOP_STATE_FILENAME = "loop-state.json"
|
|
13
|
+
SLUGIFY_SAFE_CHARS = re.compile(r"[^A-Za-z0-9._-]")
|
|
14
|
+
SLUGIFY_REPLACEMENT = "-"
|
|
15
|
+
MULTI_PR_SLUG_TEMPLATE = "{owner}-{repo}-pr-{number}"
|
|
16
|
+
LOOP_STATE_JSON_INDENT = 2
|
|
17
|
+
ALL_VALID_FIX_STATUSES = frozenset({
|
|
18
|
+
"fixed",
|
|
19
|
+
"could_not_address",
|
|
20
|
+
"hook_blocked",
|
|
21
|
+
"unverified_fixed",
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
ALL_AUDIT_CONSTRAINT_TEXTS = [
|
|
25
|
+
"Work exclusively within the worktree directory.",
|
|
26
|
+
"Every finding must cite file:line.",
|
|
27
|
+
"Document each finding with severity, file, line, and suggested fix.",
|
|
28
|
+
"Read each file in the diff before reporting on it.",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
ALL_AUDIT_CATEGORY_ENTRIES = [
|
|
32
|
+
("A", "Documentation / API call accuracy"),
|
|
33
|
+
("B", "Type safety / boundary types"),
|
|
34
|
+
("C", "Magic values / hardcoded constants"),
|
|
35
|
+
("D", "Naming / banned identifiers"),
|
|
36
|
+
("E", "Orphans / dead code"),
|
|
37
|
+
("F", "Error handling / bare except"),
|
|
38
|
+
("G", "Bounds / silent cap exits"),
|
|
39
|
+
("H", "Testing / test quality"),
|
|
40
|
+
("I", "Control flow / logic errors"),
|
|
41
|
+
("J", "Architecture / SOLID violations"),
|
|
42
|
+
("K", "Codebase conflicts / DRY"),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
ALL_FIX_EXECUTION_STEPS = [
|
|
46
|
+
"Read the finding and verify it against the current file at file:line.",
|
|
47
|
+
"Write a failing test that reproduces the bug.",
|
|
48
|
+
"Implement the smallest change that resolves the finding.",
|
|
49
|
+
"Run the full test suite — confirm the new test and all existing tests pass.",
|
|
50
|
+
"Stage and commit the fix with a descriptive message.",
|
|
51
|
+
"Push the commit to the head branch.",
|
|
52
|
+
"Post an inline reply on the finding thread confirming the fix.",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
ALL_FIX_CONSTRAINT_TEXTS = [
|
|
56
|
+
"Work exclusively within the worktree directory.",
|
|
57
|
+
"Change only the lines directly related to each finding.",
|
|
58
|
+
"Create one commit per fix loop, each focused on a single category of findings.",
|
|
59
|
+
"Every fix must have a corresponding test.",
|
|
60
|
+
"Remove deprecated code directly and update all call sites.",
|
|
61
|
+
"Handle each error case with a named exception type.",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
XML_PRETTY_INDENT = " "
|
|
65
|
+
XML_SERIALIZE_ENCODING = "unicode"
|
|
66
|
+
XML_OUTPUT_ENCODING = "utf-8"
|
|
67
|
+
ALL_PYTHON_ONEXC_VERSION = (3, 12)
|
|
68
|
+
|
|
69
|
+
ALL_FINDING_BODY_ELEMENT_KEYS: tuple[str, ...] = (
|
|
70
|
+
"title",
|
|
71
|
+
"excerpt",
|
|
72
|
+
"description",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
ALL_FIX_OUTCOME_BODY_ELEMENT_KEYS: tuple[str, ...] = (
|
|
76
|
+
"reason",
|
|
77
|
+
"hook_output",
|
|
78
|
+
)
|