claude-dev-env 4.3.0 → 7.1.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/.agents/agents/pr-description-writer.md +2 -2
- package/.agents/agents/test_agent_frontmatter.py +2 -2
- package/.agents/agents/test_pr_description_writer_style.py +1 -3
- package/.agents/skills/e-code-review/SKILL.md +12 -12
- package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
- package/.agents/skills/e-code-review/reference/fix.md +15 -17
- package/.agents/skills/e-code-review/reference/loop.md +35 -39
- package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
- package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
- package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
- package/.agents/skills/issue-tracker/SKILL.md +5 -4
- package/.agents/skills/pull-request/SKILL.md +11 -13
- package/.agents/skills/pull-request/reference/publication-tasks.md +3 -3
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +9 -1
- package/.agents/skills/pull-request/scripts/pull_request.py +35 -44
- package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +9 -0
- package/.agents/skills/pull-request/scripts/test_pull_request.py +35 -3
- package/.agents/skills/session-continuity/README.md +189 -0
- package/.agents/skills/session-continuity/SKILL.md +114 -0
- package/.agents/skills/session-continuity/continuity.mjs +375 -0
- package/.agents/skills/session-continuity/continuity.test.mjs +303 -0
- package/.agents/skills/skill-builder/SKILL.md +3 -196
- package/.agents/skills/syncing-submodules/scripts/test_sync_parent_pointer.py +0 -7
- package/.agents/skills/windows-scheduled-task/SKILL.md +153 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
- package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
- package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
- package/bin/cde.mjs +36 -8
- package/bin/cde.test.mjs +48 -0
- package/bin/ever-shipped-skills.mjs +2 -20
- package/bin/ever-shipped-skills.test.mjs +8 -0
- package/bin/expand_home_directory_tokens.mjs +4 -5
- package/bin/expand_home_directory_tokens.test.mjs +128 -0
- package/bin/git_hooks_installer.mjs +22 -3
- package/bin/git_hooks_installer.test.mjs +159 -5
- package/bin/install-session-continuity.mjs +78 -0
- package/bin/install-session-continuity.test.mjs +42 -0
- package/bin/install.agents-home.test.mjs +15 -13
- package/bin/install.codex-rules.test.mjs +5 -2
- package/bin/install.cursor-rules.test.mjs +5 -2
- package/bin/install.mjs +506 -63
- package/bin/install.policy-lint.test.mjs +130 -0
- package/bin/install.profiles.test.mjs +10 -0
- package/bin/install.prune.test.mjs +286 -37
- package/bin/install.pstack-plugin.test.mjs +114 -0
- package/bin/install.test.mjs +537 -120
- package/bin/install.transaction.test.mjs +3 -3
- package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
- package/docs/CODE_RULES.md +1 -1
- package/hooks/advisory/pr_done_reminder.py +342 -0
- package/hooks/advisory/test_pr_done_reminder.py +249 -0
- package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
- package/hooks/blocking/code_rules_banned_identifiers.py +3 -0
- package/hooks/blocking/code_rules_paired_test.py +22 -15
- package/hooks/blocking/precommit_code_rules_gate.py +5 -8
- package/hooks/blocking/test_bash_dispatcher_interpreter_starts.py +7 -52
- package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -69
- package/hooks/blocking/test_code_rules_banned_identifiers.py +64 -0
- package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
- package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
- package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +43 -342
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
- package/hooks/blocking/test_shared_stdin_adoption.py +1 -47
- package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
- package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +116 -0
- package/hooks/git-hooks/post_commit.py +33 -0
- package/hooks/git-hooks/pre_commit.py +18 -49
- package/hooks/git-hooks/pre_push.py +45 -541
- package/hooks/git-hooks/test_installed_policy_lint.py +208 -0
- package/hooks/git-hooks/test_native_hook_support.py +129 -0
- package/hooks/git-hooks/test_native_policy_commit.py +120 -0
- package/hooks/git-hooks/test_post_commit.py +43 -0
- package/hooks/git-hooks/test_pre_commit.py +38 -148
- package/hooks/git-hooks/test_pre_push.py +48 -1631
- package/hooks/git-hooks/test_verification_notice.py +60 -0
- package/hooks/git-hooks/test_verification_start.py +173 -0
- package/hooks/git-hooks/verification_notice.py +192 -0
- package/hooks/git-hooks/verification_notice_context.py +253 -0
- package/hooks/git-hooks/verification_notice_state.py +237 -0
- package/hooks/git-hooks/verification_start.py +100 -0
- package/hooks/hooks.json +1 -120
- package/hooks/hooks_constants/banned_identifiers_constants.py +4 -0
- package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +1 -15
- package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -4
- package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -93
- package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -4
- package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +3 -66
- package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +46 -201
- package/hooks/hooks_constants/test_stop_dispatcher_constants.py +3 -25
- package/hooks/validation/test_post_tool_use_dispatcher.py +35 -298
- package/hooks/validators/run_all_validators.py +5 -1
- package/hooks/validators/security_checks.py +57 -2
- package/hooks/validators/test_hook_timing_harness.py +2 -5
- package/hooks/validators/test_run_all_validators_mutation_tool_parity.py +3 -11
- package/hooks/validators/test_run_all_validators_policy_lint.py +36 -0
- package/hooks/validators/test_security_checks.py +57 -0
- package/package.json +2 -2
- package/rules/confirm-implementation-forks.md +2 -0
- package/rules/durable-post-artifacts.md +2 -1
- package/rules/git-workflow.md +18 -6
- package/rules/pstack-host-mapping.md +48 -0
- package/rules/vault-context.md +3 -5
- package/rules/verify-runtime-state.md +7 -0
- package/scripts/audit-hooks-cli.mjs +5 -0
- package/scripts/audit-hooks.mjs +72 -16
- package/scripts/automatic_advisory/__init__.py +1 -0
- package/scripts/automatic_advisory/checkout.py +51 -0
- package/scripts/automatic_advisory/cli.py +334 -0
- package/scripts/automatic_advisory/config/__init__.py +1 -0
- package/scripts/automatic_advisory/config/constants.py +93 -0
- package/scripts/automatic_advisory/config/timing.py +4 -0
- package/scripts/automatic_advisory/configuration.py +197 -0
- package/scripts/automatic_advisory/execution.py +350 -0
- package/scripts/automatic_advisory/git.py +69 -0
- package/scripts/automatic_advisory/model.py +107 -0
- package/scripts/automatic_advisory/process_host.py +32 -0
- package/scripts/automatic_advisory/publisher.py +84 -0
- package/scripts/automatic_advisory/runner.py +399 -0
- package/scripts/automatic_advisory/state.py +116 -0
- package/scripts/automatic_advisory/window_flags.py +41 -0
- package/scripts/automatic_advisory/windows_job.py +122 -0
- package/scripts/check.ps1 +0 -1
- package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
- package/scripts/ci/installer-lifecycle.test.mjs +26 -0
- package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
- package/scripts/codex_compat_materializer.py +99 -13
- package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
- package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +35 -43
- package/{.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py → scripts/durable_post_lint_config/config/constants.py} +10 -10
- package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +14 -1
- package/scripts/local_report_cli.py +184 -0
- package/scripts/local_report_core.py +247 -0
- package/scripts/local_report_publisher.py +12 -0
- package/scripts/local_report_validation.py +357 -0
- package/scripts/local_verification/__init__.py +23 -0
- package/scripts/local_verification/check_runner.py +364 -0
- package/scripts/local_verification/check_support.py +99 -0
- package/scripts/local_verification/cli.py +158 -0
- package/scripts/local_verification/command_runner.py +84 -0
- package/scripts/local_verification/config/__init__.py +1 -0
- package/scripts/local_verification/config/constants.py +89 -0
- package/scripts/local_verification/config/timing.py +1 -0
- package/scripts/local_verification/git_state.py +146 -0
- package/scripts/local_verification/manifest.py +224 -0
- package/scripts/local_verification/model.py +174 -0
- package/scripts/local_verification/runner.py +234 -0
- package/scripts/policy_lint/adapter_detectors.py +13 -6
- package/scripts/policy_lint/adapter_pairing.py +58 -3
- package/scripts/policy_lint/adapters.py +7 -4
- package/scripts/policy_lint/config/approved_test_pairs.py +323 -0
- package/scripts/policy_lint/config/constants.py +5 -0
- package/scripts/policy_lint/engine.py +48 -4
- package/scripts/policy_lint/model.py +1 -0
- package/scripts/policy_lint/registry.py +1 -1
- package/scripts/policy_lint/selection.py +2 -1
- package/scripts/policy_lint/selection_git.py +2 -0
- package/scripts/pr_verification/__init__.py +1 -0
- package/scripts/pr_verification/branch_refs.py +114 -0
- package/scripts/pr_verification/config/__init__.py +1 -0
- package/scripts/pr_verification/config/constants.py +84 -0
- package/scripts/pr_verification/config/timing.py +5 -0
- package/scripts/pr_verification/github.py +137 -0
- package/scripts/pr_verification/github_api.py +376 -0
- package/scripts/pr_verification/github_labels.py +88 -0
- package/scripts/pr_verification/github_parsing.py +182 -0
- package/scripts/pr_verification/github_transport.py +91 -0
- package/scripts/pr_verification/lock.py +122 -0
- package/scripts/pr_verification/model.py +43 -0
- package/scripts/pr_verification/requirements.txt +1 -0
- package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
- package/scripts/shared_tree_paths.py +32 -3
- package/{.agents/skills/_shared/pr-loop/scripts → scripts}/test_durable_post_lint.py +97 -0
- package/scripts/test_shared_tree_paths.py +33 -0
- package/scripts/tests/test-audit-hooks-cli.mjs +150 -0
- package/scripts/tests/test-audit-hooks.mjs +94 -2
- package/scripts/tests/test_automatic_advisory.py +376 -0
- package/scripts/tests/test_automatic_advisory_job_cleanup.py +71 -0
- package/scripts/tests/test_automatic_advisory_polling.py +216 -0
- package/scripts/tests/test_automatic_advisory_recovery.py +320 -0
- package/scripts/tests/test_automatic_advisory_repairs.py +400 -0
- package/scripts/tests/test_automatic_advisory_settings.py +48 -0
- package/scripts/tests/test_automatic_advisory_window_flags.py +163 -0
- package/scripts/tests/test_closed_pr_label.py +157 -0
- package/scripts/tests/test_codex_compat_materializer.py +189 -6
- package/scripts/tests/test_github_labels.py +101 -0
- package/scripts/tests/test_github_transport.py +125 -0
- package/scripts/tests/test_local_report_publisher.py +396 -0
- package/scripts/tests/test_local_report_publisher_cli.py +85 -0
- package/scripts/tests/test_local_verification.py +348 -0
- package/scripts/tests/test_local_verification_cli.py +98 -0
- package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
- package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
- package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
- package/scripts/tests/test_policy_lint_rules_pairing.py +163 -0
- package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
- package/scripts/tests/test_policy_lint_selection.py +25 -2
- package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
- package/scripts/tests/test_pr_verification_github.py +392 -0
- package/scripts/tests/test_pr_verification_lock.py +168 -0
- package/scripts/tests/test_rules.py +3 -7
- package/scripts/tests/test_verification_notice.py +347 -0
- package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
- package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
- package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
- package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
- package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
- package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
- package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
- package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
- package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
- package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
- package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
- package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
- package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
- package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
- package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
- package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
- package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
- package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
- package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
- package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
- package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
- package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
- package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
- package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
- package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
- package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
- package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
- package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
- package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
- package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
- package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
- package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
- package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
- package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
- package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
- package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
- package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
- package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
- package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
- package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
- package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/SKILL.md +0 -431
- package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
- package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
- package/.agents/skills/autoconverge/reference/convergence.md +0 -219
- package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
- package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
- package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
- package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
- package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
- package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
- package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
- package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
- package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
- package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
- package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
- package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
- package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
- package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
- package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
- package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
- package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
- package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
- package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
- package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
- package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
- package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
- package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
- package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
- package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
- package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
- package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
- package/.agents/skills/hitl/SKILL.md +0 -45
- package/.agents/skills/pr-cleanup/SKILL.md +0 -140
- package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
- package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
- package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
- package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
- package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
- package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
- package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
- package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
- package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
- package/.agents/skills/pr-refinement/SKILL.md +0 -31
- package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
- package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
- package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
- package/.agents/skills/pr-small-cl/SKILL.md +0 -52
- package/.agents/skills/pr-title-description/SKILL.md +0 -96
- package/.agents/skills/prototype/SKILL.md +0 -85
- package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
- package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
- package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
- package/.agents/skills/prototype/scripts/conftest.py +0 -15
- package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
- package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
- package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
- package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
- package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
- package/.agents/skills/prototype/workflows/promotion.md +0 -25
- package/.agents/skills/prototype/workflows/sandbox.md +0 -35
- package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
- package/.agents/skills/rebase/AGENTS.md +0 -1
- package/.agents/skills/rebase/SKILL.md +0 -178
- package/.agents/skills/review-router/SKILL.md +0 -51
- package/.agents/skills/review-router/reference/route-policy.json +0 -7
- package/.agents/skills/review-router/reference/task-seeds.md +0 -1
- package/.agents/skills/review-router/scripts/conftest.py +0 -4
- package/.agents/skills/review-router/scripts/review_router.py +0 -50
- package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
- package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
- package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
- package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
- package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
- package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
- package/.agents/skills/review-tier/SKILL.md +0 -56
- package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
- package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
- package/.agents/skills/review-tier/scripts/conftest.py +0 -4
- package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
- package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
- package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
- package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
- package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
- package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
- package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
- package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
- package/.agents/skills/session-log/AGENTS.md +0 -1
- package/.agents/skills/session-log/SKILL.md +0 -170
- package/.agents/skills/session-log/templates/frontmatter.md +0 -40
- package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
- package/.agents/skills/session-tidy/AGENTS.md +0 -1
- package/.agents/skills/session-tidy/SKILL.md +0 -191
- package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
- package/.agents/skills/skill-builder/references/description-field.md +0 -111
- package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
- package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
- package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
- package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
- package/.agents/skills/skill-builder/references/skill-types.md +0 -232
- package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
- package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
- package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
- package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
- package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
- package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
- package/.agents/skills/update/.claude/CLAUDE.md +0 -1
- package/.agents/skills/update/AGENTS.md +0 -1
- package/.agents/skills/update/SKILL.md +0 -190
- package/_shared/pr-loop/AGENTS.md +0 -1
- package/_shared/pr-loop/audit-contract.md +0 -183
- package/_shared/pr-loop/audit-reply-template.md +0 -151
- package/_shared/pr-loop/code-rules-gate.md +0 -65
- package/_shared/pr-loop/fix-protocol.md +0 -60
- package/_shared/pr-loop/gh-payloads.md +0 -75
- package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
- package/_shared/pr-loop/precatch-rubric.md +0 -66
- package/_shared/pr-loop/preflight-proposal.md +0 -56
- package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
- package/_shared/pr-loop/state-schema.md +0 -45
- package/_shared/pr-loop/worker-spawn.md +0 -189
- package/hooks/blocking/ask_user_question_shape_blocker.py +0 -83
- package/hooks/blocking/bot_mention_comment_blocker.py +0 -76
- package/hooks/blocking/claude_md_orphan_file_blocker.py +0 -129
- package/hooks/blocking/cursor_cli_python_misfire_blocker.py +0 -108
- package/hooks/blocking/destructive_command_blocker.py +0 -2073
- package/hooks/blocking/fable_spawn_gate.py +0 -187
- package/hooks/blocking/luna_fast_mode_gate.py +0 -160
- package/hooks/blocking/nas_ssh_binary_enforcer.py +0 -163
- package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +0 -260
- package/hooks/blocking/package_inventory_stale_blocker.py +0 -107
- package/hooks/blocking/pii_prevention_blocker.py +0 -365
- package/hooks/blocking/piped_pytest_blocker.py +0 -1223
- package/hooks/blocking/question_to_user_enforcer.py +0 -130
- package/hooks/blocking/send_user_file_open_locally_blocker.py +0 -71
- package/hooks/blocking/sensitive_file_protector.py +0 -167
- package/hooks/blocking/session_edit_stage_gate.py +0 -684
- package/hooks/blocking/session_handoff_blocker.py +0 -182
- package/hooks/blocking/shell_substitution_blocker.py +0 -350
- package/hooks/blocking/test_ask_user_question_shape.py +0 -69
- package/hooks/blocking/test_bot_mention_comment_blocker.py +0 -131
- package/hooks/blocking/test_claude_md_orphan_file_blocker.py +0 -1277
- package/hooks/blocking/test_cursor_cli_python_misfire_blocker.py +0 -208
- package/hooks/blocking/test_destructive_command_blocker.py +0 -2024
- package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +0 -105
- package/hooks/blocking/test_destructive_command_blocker_no_verify.py +0 -122
- package/hooks/blocking/test_destructive_command_blocker_patterns.py +0 -133
- package/hooks/blocking/test_fable_spawn_gate.py +0 -381
- package/hooks/blocking/test_inventory_deadlock_resolution.py +0 -154
- package/hooks/blocking/test_luna_fast_mode_gate.py +0 -211
- package/hooks/blocking/test_nas_ssh_binary_enforcer.py +0 -225
- package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +0 -231
- package/hooks/blocking/test_package_inventory_stale_blocker.py +0 -382
- package/hooks/blocking/test_pii_prevention_blocker.py +0 -1222
- package/hooks/blocking/test_pii_prevention_windows_git_path.py +0 -41
- package/hooks/blocking/test_pii_write_surface_ephemeral.py +0 -221
- package/hooks/blocking/test_piped_pytest_blocker.py +0 -587
- package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +0 -233
- package/hooks/blocking/test_question_to_user_enforcer.py +0 -169
- package/hooks/blocking/test_send_user_file_open_locally_blocker.py +0 -118
- package/hooks/blocking/test_sensitive_file_protector.py +0 -365
- package/hooks/blocking/test_session_edit_stage_gate.py +0 -537
- package/hooks/blocking/test_session_edit_stage_gate_staging.py +0 -64
- package/hooks/blocking/test_session_edit_stage_gate_support.py +0 -204
- package/hooks/blocking/test_session_edit_stage_gate_tracker.py +0 -116
- package/hooks/blocking/test_session_handoff_blocker.py +0 -318
- package/hooks/blocking/test_shell_substitution_blocker.py +0 -298
- package/hooks/blocking/test_unscoped_search_blocker.py +0 -102
- package/hooks/blocking/test_write_existing_file_blocker.py +0 -122
- package/hooks/blocking/tests/test_pii_prevention_blocker.py +0 -259
- package/hooks/blocking/unscoped_search_blocker.py +0 -391
- package/hooks/blocking/write_existing_file_blocker.py +0 -124
- package/hooks/hooks_constants/bot_mention_comment_blocker_constants.py +0 -19
- package/hooks/hooks_constants/cursor_cli_python_misfire_blocker_constants.py +0 -79
- package/hooks/hooks_constants/fable_spawn_gate_constants.py +0 -61
- package/hooks/hooks_constants/luna_fast_mode_gate_constants.py +0 -45
- package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +0 -20
- package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +0 -57
- package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +0 -17
- package/hooks/hooks_constants/sensitive_file_protector_constants.py +0 -40
- package/hooks/hooks_constants/session_handoff_blocker_constants.py +0 -10
- package/hooks/hooks_constants/shell_substitution_blocker_constants.py +0 -80
- /package/.agents/skills/{_shared/pr-loop → session-continuity}/AGENTS.md +0 -0
- /package/{_shared/pr-loop → .agents/skills/session-continuity}/CLAUDE.md +0 -0
|
@@ -1,29 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Smoke driver for the claude-dev-env installer.
|
|
4
|
-
*
|
|
5
|
-
* The installer (bin/install.mjs) writes into os.homedir()/.claude and
|
|
6
|
-
* os.homedir()/.agents and has
|
|
7
|
-
* three global side effects: it copies files under ~/.claude/ and ~/.agents/, sets
|
|
8
|
-
* `git config --global core.hooksPath`, and writes ~/.mypy.ini. There is no
|
|
9
|
-
* flag to redirect the target, so this driver isolates every side effect by
|
|
10
|
-
* spawning the installer with HOME, USERPROFILE, and GIT_CONFIG_GLOBAL all
|
|
11
|
-
* pointed at a throwaway sandbox directory. Node's os.homedir() follows
|
|
12
|
-
* USERPROFILE on Windows and HOME on POSIX, so setting both redirects the
|
|
13
|
-
* install target on either platform without touching the real ~/.claude/.
|
|
14
|
-
*
|
|
15
|
-
* The isolated GIT_CONFIG_GLOBAL is seeded with `safe.directory = *` so the
|
|
16
|
-
* installer's `git status` source-conflict guard runs even when the checkout
|
|
17
|
-
* lives somewhere git flags as dubious ownership (for example a UNC network
|
|
18
|
-
* share), while the installer's `git config --global core.hooksPath` write
|
|
19
|
-
* still lands only in the sandbox config.
|
|
20
|
-
*
|
|
21
|
-
* It runs the three lifecycle commands an agent cares about — `--help`, a full
|
|
22
|
-
* install, and `--uninstall` — and asserts the observable result of each
|
|
23
|
-
* against the sandbox tree. Exit code 0 means every assertion held.
|
|
24
|
-
*
|
|
25
|
-
* Usage: node .claude/skills/run-claude-dev-env/driver.mjs
|
|
26
|
-
*/
|
|
27
2
|
|
|
28
3
|
import { spawnSync } from 'node:child_process';
|
|
29
4
|
import {
|
|
@@ -41,7 +16,7 @@ import { tmpdir } from 'node:os';
|
|
|
41
16
|
import { fileURLToPath } from 'node:url';
|
|
42
17
|
|
|
43
18
|
const DRIVER_DIRECTORY = dirname(fileURLToPath(import.meta.url));
|
|
44
|
-
const PACKAGE_ROOT = resolve(DRIVER_DIRECTORY, '..', '..'
|
|
19
|
+
const PACKAGE_ROOT = resolve(DRIVER_DIRECTORY, '..', '..');
|
|
45
20
|
const INSTALL_ENTRY = join(PACKAGE_ROOT, 'bin', 'install.mjs');
|
|
46
21
|
|
|
47
22
|
const checks = [];
|
|
@@ -68,7 +43,7 @@ function collectFilesRecursive(directory) {
|
|
|
68
43
|
|
|
69
44
|
function runInstaller(sandboxHome, installerArguments) {
|
|
70
45
|
const gitConfigGlobal = join(sandboxHome, '.gitconfig-sandbox');
|
|
71
|
-
const
|
|
46
|
+
const installerProcess = spawnSync(process.execPath, [INSTALL_ENTRY, ...installerArguments], {
|
|
72
47
|
cwd: PACKAGE_ROOT,
|
|
73
48
|
encoding: 'utf8',
|
|
74
49
|
env: {
|
|
@@ -78,7 +53,7 @@ function runInstaller(sandboxHome, installerArguments) {
|
|
|
78
53
|
GIT_CONFIG_GLOBAL: gitConfigGlobal,
|
|
79
54
|
},
|
|
80
55
|
});
|
|
81
|
-
return
|
|
56
|
+
return installerProcess;
|
|
82
57
|
}
|
|
83
58
|
|
|
84
59
|
function main() {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const CI_DIRECTORY = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const DRIVER_PATH = join(CI_DIRECTORY, 'installer-lifecycle.mjs');
|
|
10
|
+
const DRIVER_TIMEOUT_MILLISECONDS = 60_000;
|
|
11
|
+
|
|
12
|
+
test('the installer lifecycle driver completes in an isolated home', () => {
|
|
13
|
+
const lifecycleProcess = spawnSync(process.execPath, [DRIVER_PATH], {
|
|
14
|
+
encoding: 'utf8',
|
|
15
|
+
timeout: DRIVER_TIMEOUT_MILLISECONDS,
|
|
16
|
+
});
|
|
17
|
+
assert.equal(lifecycleProcess.status, 0, `${lifecycleProcess.stdout}\n${lifecycleProcess.stderr}`);
|
|
18
|
+
assert.match(lifecycleProcess.stdout, /ALL CHECKS PASSED/);
|
|
19
|
+
assert.match(lifecycleProcess.stdout, /Sandbox removed:/);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('the Windows adapter invokes the CI-owned lifecycle driver', () => {
|
|
23
|
+
const adapterSource = readFileSync(join(CI_DIRECTORY, 'windows-installer-lifecycle.ps1'), 'utf8');
|
|
24
|
+
assert.match(adapterSource, /\$driverPath = Join-Path \$PSScriptRoot 'installer-lifecycle\.mjs'/);
|
|
25
|
+
assert.doesNotMatch(adapterSource, /skills\\run-claude-dev-env/);
|
|
26
|
+
});
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
# Windows CI adapter for the Node installer lifecycle driver.
|
|
2
|
-
#
|
|
3
|
-
# The driver already redirects HOME, USERPROFILE, and GIT_CONFIG_GLOBAL into a
|
|
4
|
-
# throwaway sandbox. This adapter records that isolation contract, runs the
|
|
5
|
-
# 16-check driver, and writes bounded evidence under -EvidenceRoot so a failed
|
|
6
|
-
# Windows runner leaves an actionable artifact.
|
|
7
|
-
#
|
|
8
|
-
# Usage (from packages/claude-dev-env):
|
|
9
|
-
# pwsh -NoProfile -File scripts/ci/windows-installer-lifecycle.ps1 -EvidenceRoot <dir>
|
|
10
|
-
|
|
11
1
|
[CmdletBinding()]
|
|
12
2
|
param(
|
|
13
3
|
[Parameter(Mandatory = $true)]
|
|
@@ -17,7 +7,7 @@ param(
|
|
|
17
7
|
$ErrorActionPreference = 'Stop'
|
|
18
8
|
|
|
19
9
|
$packageRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
|
|
20
|
-
$driverPath = Join-Path $
|
|
10
|
+
$driverPath = Join-Path $PSScriptRoot 'installer-lifecycle.mjs'
|
|
21
11
|
$allIsolationEnvNames = @(
|
|
22
12
|
'HOME',
|
|
23
13
|
'USERPROFILE',
|
|
@@ -615,7 +615,7 @@ def _resolved_codex_enforcer_command(config: MaterializerConfig) -> str:
|
|
|
615
615
|
|
|
616
616
|
def _source_codex_enforcer_hook(
|
|
617
617
|
all_source_manifest: dict[str, object], command: str
|
|
618
|
-
) -> dict[str, object]:
|
|
618
|
+
) -> dict[str, object] | None:
|
|
619
619
|
"""Read the source enforcer hook shape and resolve its target command."""
|
|
620
620
|
all_events = all_source_manifest.get("hooks")
|
|
621
621
|
if not isinstance(all_events, dict):
|
|
@@ -637,11 +637,7 @@ def _source_codex_enforcer_hook(
|
|
|
637
637
|
resolved_hook = dict(each_hook)
|
|
638
638
|
resolved_hook[codex_hook_command_field_name] = command
|
|
639
639
|
return resolved_hook
|
|
640
|
-
return
|
|
641
|
-
"type": "command",
|
|
642
|
-
codex_hook_command_field_name: command,
|
|
643
|
-
"timeout": codex_hook_timeout_seconds,
|
|
644
|
-
}
|
|
640
|
+
return None
|
|
645
641
|
|
|
646
642
|
|
|
647
643
|
def _hook_records(raw_hooks: object) -> list[dict[str, object]]:
|
|
@@ -668,6 +664,72 @@ def _is_code_rules_enforcer_hook(all_hook_record: dict[str, object]) -> bool:
|
|
|
668
664
|
)
|
|
669
665
|
|
|
670
666
|
|
|
667
|
+
def _is_managed_codex_enforcer_hook(
|
|
668
|
+
all_hook_record: dict[str, object], managed_command: str
|
|
669
|
+
) -> bool:
|
|
670
|
+
"""Report whether a hook record is the materializer's target command."""
|
|
671
|
+
command = all_hook_record.get(codex_hook_command_field_name)
|
|
672
|
+
if not isinstance(command, str):
|
|
673
|
+
return False
|
|
674
|
+
normalized_command = command.replace("\\", path_separator)
|
|
675
|
+
normalized_managed_command = managed_command.replace("\\", path_separator)
|
|
676
|
+
if os.name == "nt":
|
|
677
|
+
return normalized_command.casefold() == normalized_managed_command.casefold()
|
|
678
|
+
return normalized_command == normalized_managed_command
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
def _without_managed_codex_enforcer(
|
|
682
|
+
entry: object, managed_command: str
|
|
683
|
+
) -> object | None:
|
|
684
|
+
"""Remove the managed enforcer while preserving every other hook record."""
|
|
685
|
+
if not isinstance(entry, dict):
|
|
686
|
+
return entry
|
|
687
|
+
if entry.get("matcher") != codex_hook_matcher:
|
|
688
|
+
return entry
|
|
689
|
+
copied_entry = dict(entry)
|
|
690
|
+
all_hook_records = copied_entry.get(codex_hook_records_field_name)
|
|
691
|
+
if not isinstance(all_hook_records, list):
|
|
692
|
+
return copied_entry
|
|
693
|
+
all_retained_hooks = [
|
|
694
|
+
each_hook
|
|
695
|
+
for each_hook in all_hook_records
|
|
696
|
+
if not isinstance(each_hook, dict)
|
|
697
|
+
or not _is_managed_codex_enforcer_hook(each_hook, managed_command)
|
|
698
|
+
]
|
|
699
|
+
if all_retained_hooks == all_hook_records:
|
|
700
|
+
return copied_entry
|
|
701
|
+
if not all_retained_hooks:
|
|
702
|
+
return None
|
|
703
|
+
copied_entry[codex_hook_records_field_name] = all_retained_hooks
|
|
704
|
+
return copied_entry
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
def _remove_managed_codex_enforcer(
|
|
708
|
+
all_target_manifest: dict[str, object], managed_command: str
|
|
709
|
+
) -> dict[str, object]:
|
|
710
|
+
"""Remove the retired managed enforcer from the target manifest."""
|
|
711
|
+
all_events = all_target_manifest.get(codex_hook_records_field_name, {})
|
|
712
|
+
if not isinstance(all_events, dict):
|
|
713
|
+
raise MaterializerError("Codex hook manifest requires a hooks object")
|
|
714
|
+
all_pre_tool_use = all_events.get(codex_hook_event_name)
|
|
715
|
+
if all_pre_tool_use is None:
|
|
716
|
+
return _prune_retired_codex_hooks(all_target_manifest)
|
|
717
|
+
if not isinstance(all_pre_tool_use, list):
|
|
718
|
+
raise MaterializerError("Codex hook manifest requires a PreToolUse list")
|
|
719
|
+
all_retained_entries: list[object] = []
|
|
720
|
+
for each_entry in all_pre_tool_use:
|
|
721
|
+
maybe_retained_entry = _without_managed_codex_enforcer(
|
|
722
|
+
each_entry, managed_command
|
|
723
|
+
)
|
|
724
|
+
if maybe_retained_entry is not None:
|
|
725
|
+
all_retained_entries.append(maybe_retained_entry)
|
|
726
|
+
merged_events = dict(all_events)
|
|
727
|
+
merged_events[codex_hook_event_name] = all_retained_entries
|
|
728
|
+
merged_manifest = dict(all_target_manifest)
|
|
729
|
+
merged_manifest[codex_hook_records_field_name] = merged_events
|
|
730
|
+
return _prune_retired_codex_hooks(merged_manifest)
|
|
731
|
+
|
|
732
|
+
|
|
671
733
|
def _is_retired_codex_hook_command(command: object) -> bool:
|
|
672
734
|
"""Report whether a command names a known retired hook path."""
|
|
673
735
|
if not isinstance(command, str):
|
|
@@ -764,13 +826,20 @@ def _has_modified_codex_enforcer_hook(
|
|
|
764
826
|
current_hooks = _codex_enforcer_hooks(current_manifest)
|
|
765
827
|
if not current_hooks:
|
|
766
828
|
return False
|
|
767
|
-
|
|
829
|
+
planned_hooks = _codex_enforcer_hooks(planned_manifest)
|
|
830
|
+
if all(each_hook in current_hooks for each_hook in planned_hooks):
|
|
831
|
+
return False
|
|
832
|
+
return current_hooks != planned_hooks
|
|
768
833
|
|
|
769
834
|
|
|
770
835
|
def _merge_codex_hook_manifest(
|
|
771
|
-
all_target_manifest: dict[str, object],
|
|
836
|
+
all_target_manifest: dict[str, object],
|
|
837
|
+
all_focused_hook: dict[str, object] | None,
|
|
838
|
+
managed_command: str,
|
|
772
839
|
) -> dict[str, object]:
|
|
773
840
|
"""Preserve target hook order while merging one deterministic enforcer entry."""
|
|
841
|
+
if all_focused_hook is None:
|
|
842
|
+
return _remove_managed_codex_enforcer(all_target_manifest, managed_command)
|
|
774
843
|
all_events = all_target_manifest.get(codex_hook_records_field_name, {})
|
|
775
844
|
if not isinstance(all_events, dict):
|
|
776
845
|
raise MaterializerError("Codex hook manifest requires a hooks object")
|
|
@@ -797,13 +866,17 @@ def _merge_codex_hook_manifest(
|
|
|
797
866
|
if merged_apply_patch_entry is None:
|
|
798
867
|
merged_apply_patch_entry = copied_entry
|
|
799
868
|
merged_hooks = [
|
|
800
|
-
each_hook
|
|
869
|
+
each_hook
|
|
870
|
+
for each_hook in all_hook_records
|
|
871
|
+
if not _is_managed_codex_enforcer_hook(each_hook, managed_command)
|
|
801
872
|
]
|
|
802
873
|
merged_apply_patch_entry[codex_hook_records_field_name] = merged_hooks
|
|
803
874
|
merged_pre_tool_use.append(merged_apply_patch_entry)
|
|
804
875
|
else:
|
|
805
876
|
merged_hooks.extend(
|
|
806
|
-
each_hook
|
|
877
|
+
each_hook
|
|
878
|
+
for each_hook in all_hook_records
|
|
879
|
+
if not _is_managed_codex_enforcer_hook(each_hook, managed_command)
|
|
807
880
|
)
|
|
808
881
|
if merged_apply_patch_entry is None:
|
|
809
882
|
merged_apply_patch_entry = {
|
|
@@ -831,10 +904,11 @@ def _build_codex_hook_projection(config: MaterializerConfig) -> PlannedFile | No
|
|
|
831
904
|
if target_path.is_file()
|
|
832
905
|
else {"hooks": {}}
|
|
833
906
|
)
|
|
834
|
-
|
|
835
|
-
|
|
907
|
+
managed_command = _resolved_codex_enforcer_command(config)
|
|
908
|
+
focused_hook = _source_codex_enforcer_hook(source_manifest, managed_command)
|
|
909
|
+
projected_manifest = _merge_codex_hook_manifest(
|
|
910
|
+
target_manifest, focused_hook, managed_command
|
|
836
911
|
)
|
|
837
|
-
projected_manifest = _merge_codex_hook_manifest(target_manifest, focused_hook)
|
|
838
912
|
projected_content = json.dumps(projected_manifest, ensure_ascii=False, indent=manifest_indentation_width) + line_separator
|
|
839
913
|
return PlannedFile(
|
|
840
914
|
codex_hook_manifest_source_path,
|
|
@@ -849,6 +923,8 @@ def _build_codex_hook_dependency_projection(
|
|
|
849
923
|
config: MaterializerConfig,
|
|
850
924
|
) -> list[PlannedFile]:
|
|
851
925
|
"""Build the reviewed source files required by the target enforcer."""
|
|
926
|
+
if not _has_source_codex_enforcer(config):
|
|
927
|
+
return []
|
|
852
928
|
all_dependencies: list[PlannedFile] = []
|
|
853
929
|
for each_relative_path in codex_hook_dependency_manifest:
|
|
854
930
|
source_path = _validated_source_file(
|
|
@@ -871,6 +947,16 @@ def _build_codex_hook_dependency_projection(
|
|
|
871
947
|
return all_dependencies
|
|
872
948
|
|
|
873
949
|
|
|
950
|
+
def _has_source_codex_enforcer(config: MaterializerConfig) -> bool:
|
|
951
|
+
"""Report whether hooks.json registers the enforcer."""
|
|
952
|
+
source_path = _find_codex_hook_source(config)
|
|
953
|
+
if source_path is None:
|
|
954
|
+
return False
|
|
955
|
+
source_manifest = _read_json_object(source_path, "source Codex hook manifest")
|
|
956
|
+
managed_command = _resolved_codex_enforcer_command(config)
|
|
957
|
+
return _source_codex_enforcer_hook(source_manifest, managed_command) is not None
|
|
958
|
+
|
|
959
|
+
|
|
874
960
|
def discover_agents(config: MaterializerConfig) -> list[ClaudeAgent]:
|
|
875
961
|
"""Discover and parse Markdown agents below the source root.
|
|
876
962
|
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
These name the shape of the installed tree itself, not any one worker or
|
|
4
|
-
skill that reads it, so every caller of shared_tree_paths shares them.
|
|
5
|
-
"""
|
|
1
|
+
"""Directory names for the installed shared tree."""
|
|
6
2
|
|
|
7
3
|
from __future__ import annotations
|
|
8
4
|
|
|
@@ -15,3 +11,6 @@ SCRIPTS_DIRECTORY_NAME: str = "scripts"
|
|
|
15
11
|
PROCESS_TREE_DIRECTORY_NAME: str = "process-tree"
|
|
16
12
|
|
|
17
13
|
PROCESS_TREE_KILL_MODULE_FILENAME: str = "process_tree_kill.py"
|
|
14
|
+
|
|
15
|
+
AGENTS_DIRECTORY_SUFFIX: str = ".agents"
|
|
16
|
+
DEFAULT_MANAGED_ROOT_NAME: str = ".claude"
|
|
@@ -8,7 +8,7 @@ from collections.abc import Sequence
|
|
|
8
8
|
from dataclasses import dataclass
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
|
-
from
|
|
11
|
+
from durable_post_lint_config.config.constants import (
|
|
12
12
|
ACTION_PR_CREATE,
|
|
13
13
|
ACTION_PR_EDIT,
|
|
14
14
|
ALL_BARE_VOLATILE_PATH_MARKERS,
|
|
@@ -16,6 +16,7 @@ from skills_pr_loop_constants.durable_post_lint_constants import (
|
|
|
16
16
|
ALL_PATH_ANCHORED_VOLATILE_PATH_MARKERS,
|
|
17
17
|
ALL_POST_ACTIONS,
|
|
18
18
|
ALL_PR_DESCRIPTION_ACTIONS,
|
|
19
|
+
ALL_RELEASE_BODY_MARKERS,
|
|
19
20
|
ALL_REQUIRED_PR_DESCRIPTION_HEADINGS,
|
|
20
21
|
ALL_TITLE_ACTIONS,
|
|
21
22
|
BODY_FILE_ENCODING,
|
|
@@ -35,6 +36,9 @@ from skills_pr_loop_constants.durable_post_lint_constants import (
|
|
|
35
36
|
MISSING_HEADING_MESSAGE_TEMPLATE,
|
|
36
37
|
PATH_ANCHOR_CHARACTER,
|
|
37
38
|
PATH_SEGMENT_START_CHARACTERS,
|
|
39
|
+
RELEASE_BRANCH_PREFIX,
|
|
40
|
+
REWRITTEN_RELEASE_BODY_CODE,
|
|
41
|
+
REWRITTEN_RELEASE_BODY_MESSAGE,
|
|
38
42
|
TITLE_NOT_ALLOWED_MESSAGE,
|
|
39
43
|
TITLE_REQUIRED_MESSAGE,
|
|
40
44
|
VOLATILE_PATH_CODE,
|
|
@@ -82,14 +86,7 @@ def _text_has_anchored_marker(normalized_text: str, marker: str) -> bool:
|
|
|
82
86
|
|
|
83
87
|
|
|
84
88
|
def find_volatile_path_marker(body_text: str) -> str | None:
|
|
85
|
-
"""Return the first volatile path marker in a GitHub post body.
|
|
86
|
-
|
|
87
|
-
Args:
|
|
88
|
-
body_text: Post body text to scan.
|
|
89
|
-
|
|
90
|
-
Returns:
|
|
91
|
-
The matched marker, or None when the body names no volatile path.
|
|
92
|
-
"""
|
|
89
|
+
"""Return the first volatile path marker in a GitHub post body."""
|
|
93
90
|
normalized_text = body_text.replace("\\", PATH_ANCHOR_CHARACTER).lower()
|
|
94
91
|
for each_marker in ALL_PATH_ANCHORED_VOLATILE_PATH_MARKERS:
|
|
95
92
|
if _text_has_anchored_marker(normalized_text, each_marker):
|
|
@@ -101,17 +98,7 @@ def find_volatile_path_marker(body_text: str) -> str | None:
|
|
|
101
98
|
|
|
102
99
|
|
|
103
100
|
def read_body_file(body_file: Path) -> str:
|
|
104
|
-
"""Read one UTF-8 body file without exposing its contents on failure.
|
|
105
|
-
|
|
106
|
-
Args:
|
|
107
|
-
body_file: Local post body file.
|
|
108
|
-
|
|
109
|
-
Returns:
|
|
110
|
-
Decoded body text.
|
|
111
|
-
|
|
112
|
-
Raises:
|
|
113
|
-
DurablePostInputError: The file is missing, unreadable, or invalid UTF-8.
|
|
114
|
-
"""
|
|
101
|
+
"""Read one UTF-8 body file without exposing its contents on failure."""
|
|
115
102
|
try:
|
|
116
103
|
return body_file.read_text(encoding=BODY_FILE_ENCODING)
|
|
117
104
|
except (OSError, UnicodeError) as error:
|
|
@@ -153,9 +140,25 @@ def _title_findings(title: str | None) -> list[DurablePostFinding]:
|
|
|
153
140
|
return [DurablePostFinding(code=INVALID_TITLE_CODE, message=INVALID_TITLE_MESSAGE)]
|
|
154
141
|
|
|
155
142
|
|
|
143
|
+
def _is_release_automation_branch(head_branch: str | None) -> bool:
|
|
144
|
+
return head_branch is not None and head_branch.startswith(RELEASE_BRANCH_PREFIX)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _release_body_findings(body_text: str) -> list[DurablePostFinding]:
|
|
148
|
+
if all(each_marker in body_text for each_marker in ALL_RELEASE_BODY_MARKERS):
|
|
149
|
+
return []
|
|
150
|
+
return [
|
|
151
|
+
DurablePostFinding(
|
|
152
|
+
code=REWRITTEN_RELEASE_BODY_CODE,
|
|
153
|
+
message=REWRITTEN_RELEASE_BODY_MESSAGE,
|
|
154
|
+
)
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
|
|
156
158
|
def _body_findings(
|
|
157
159
|
action: str,
|
|
158
160
|
body_text: str | None,
|
|
161
|
+
head_branch: str | None = None,
|
|
159
162
|
) -> list[DurablePostFinding]:
|
|
160
163
|
if body_text is None:
|
|
161
164
|
return []
|
|
@@ -167,7 +170,9 @@ def _body_findings(
|
|
|
167
170
|
message=BODY_MUST_NOT_BE_EMPTY_MESSAGE,
|
|
168
171
|
)
|
|
169
172
|
)
|
|
170
|
-
if
|
|
173
|
+
if _is_release_automation_branch(head_branch):
|
|
174
|
+
all_findings.extend(_release_body_findings(body_text))
|
|
175
|
+
elif action in ALL_PR_DESCRIPTION_ACTIONS:
|
|
171
176
|
all_findings.extend(_description_heading_findings(body_text))
|
|
172
177
|
if find_volatile_path_marker(body_text) is not None:
|
|
173
178
|
all_findings.append(
|
|
@@ -183,22 +188,14 @@ def lint_durable_post(
|
|
|
183
188
|
action: str,
|
|
184
189
|
title: str | None,
|
|
185
190
|
body_text: str | None,
|
|
191
|
+
head_branch: str | None = None,
|
|
186
192
|
) -> tuple[DurablePostFinding, ...]:
|
|
187
|
-
"""Return content findings for one locally valid GitHub post request.
|
|
188
|
-
|
|
189
|
-
Args:
|
|
190
|
-
action: GitHub post action name.
|
|
191
|
-
title: Pull request title when the action accepts one.
|
|
192
|
-
body_text: Decoded body text when the action accepts a body.
|
|
193
|
-
|
|
194
|
-
Returns:
|
|
195
|
-
Content findings in stable rule order.
|
|
196
|
-
|
|
197
|
-
Raises:
|
|
198
|
-
DurablePostUsageError: The action and supplied fields are not a valid request.
|
|
199
|
-
"""
|
|
193
|
+
"""Return content findings for one locally valid GitHub post request."""
|
|
200
194
|
_validate_request_shape(action, title, body_text)
|
|
201
|
-
return (
|
|
195
|
+
return (
|
|
196
|
+
*_title_findings(title),
|
|
197
|
+
*_body_findings(action, body_text, head_branch),
|
|
198
|
+
)
|
|
202
199
|
|
|
203
200
|
|
|
204
201
|
def _parse_arguments(all_arguments: Sequence[str]) -> argparse.Namespace:
|
|
@@ -206,18 +203,12 @@ def _parse_arguments(all_arguments: Sequence[str]) -> argparse.Namespace:
|
|
|
206
203
|
parser.add_argument("--action", required=True)
|
|
207
204
|
parser.add_argument("--title")
|
|
208
205
|
parser.add_argument("--body-file", type=Path)
|
|
206
|
+
parser.add_argument("--head-branch")
|
|
209
207
|
return parser.parse_args(list(all_arguments))
|
|
210
208
|
|
|
211
209
|
|
|
212
210
|
def main(all_arguments: Sequence[str]) -> int:
|
|
213
|
-
"""Validate one GitHub post and return its result status.
|
|
214
|
-
|
|
215
|
-
Args:
|
|
216
|
-
all_arguments: Command arguments after the script name.
|
|
217
|
-
|
|
218
|
-
Returns:
|
|
219
|
-
Zero when clean, one for content findings, or two for invalid input.
|
|
220
|
-
"""
|
|
211
|
+
"""Validate one GitHub post and return its result status."""
|
|
221
212
|
arguments = _parse_arguments(all_arguments)
|
|
222
213
|
try:
|
|
223
214
|
body_text = (
|
|
@@ -229,6 +220,7 @@ def main(all_arguments: Sequence[str]) -> int:
|
|
|
229
220
|
action=arguments.action,
|
|
230
221
|
title=arguments.title,
|
|
231
222
|
body_text=body_text,
|
|
223
|
+
head_branch=arguments.head_branch,
|
|
232
224
|
)
|
|
233
225
|
except (DurablePostInputError, DurablePostUsageError) as error:
|
|
234
226
|
sys.stderr.write(f"{error}\n")
|
|
@@ -23,7 +23,6 @@ ALL_POST_ACTIONS: frozenset[str] = frozenset(
|
|
|
23
23
|
ACTION_PR_REVIEW,
|
|
24
24
|
}
|
|
25
25
|
)
|
|
26
|
-
|
|
27
26
|
ALL_BODY_REQUIRED_ACTIONS: frozenset[str] = frozenset(
|
|
28
27
|
{
|
|
29
28
|
ACTION_GITHUB_MCP_POST,
|
|
@@ -35,13 +34,10 @@ ALL_BODY_REQUIRED_ACTIONS: frozenset[str] = frozenset(
|
|
|
35
34
|
ACTION_PR_REVIEW,
|
|
36
35
|
}
|
|
37
36
|
)
|
|
38
|
-
|
|
39
37
|
ALL_PR_DESCRIPTION_ACTIONS: frozenset[str] = frozenset(
|
|
40
38
|
{ACTION_PR_CREATE, ACTION_PR_EDIT}
|
|
41
39
|
)
|
|
42
|
-
|
|
43
40
|
ALL_TITLE_ACTIONS: frozenset[str] = frozenset({ACTION_PR_CREATE, ACTION_PR_EDIT})
|
|
44
|
-
|
|
45
41
|
ALL_CONVENTIONAL_TITLE_TYPES: tuple[str, ...] = (
|
|
46
42
|
"build",
|
|
47
43
|
"chore",
|
|
@@ -55,11 +51,9 @@ ALL_CONVENTIONAL_TITLE_TYPES: tuple[str, ...] = (
|
|
|
55
51
|
"style",
|
|
56
52
|
"test",
|
|
57
53
|
)
|
|
58
|
-
|
|
59
54
|
CONVENTIONAL_TITLE_PATTERN: re.Pattern[str] = re.compile(
|
|
60
55
|
rf"^(?:{'|'.join(ALL_CONVENTIONAL_TITLE_TYPES)})(?:\([^)\r\n]+\))?!?: [^\s].*$"
|
|
61
56
|
)
|
|
62
|
-
|
|
63
57
|
ALL_REQUIRED_PR_DESCRIPTION_HEADINGS: tuple[str, ...] = (
|
|
64
58
|
"Summary",
|
|
65
59
|
"Description",
|
|
@@ -67,12 +61,10 @@ ALL_REQUIRED_PR_DESCRIPTION_HEADINGS: tuple[str, ...] = (
|
|
|
67
61
|
"How",
|
|
68
62
|
"Verification",
|
|
69
63
|
)
|
|
70
|
-
|
|
71
64
|
ALL_PATH_ANCHORED_VOLATILE_PATH_MARKERS: tuple[str, ...] = (
|
|
72
65
|
".claude-profile-a/jobs/",
|
|
73
66
|
".claude/worktrees/",
|
|
74
67
|
)
|
|
75
|
-
|
|
76
68
|
ALL_BARE_VOLATILE_PATH_MARKERS: tuple[str, ...] = (
|
|
77
69
|
"appdata/local/temp",
|
|
78
70
|
"/tmp/",
|
|
@@ -80,7 +72,6 @@ ALL_BARE_VOLATILE_PATH_MARKERS: tuple[str, ...] = (
|
|
|
80
72
|
"$env:temp",
|
|
81
73
|
"$claude_job_dir",
|
|
82
74
|
)
|
|
83
|
-
|
|
84
75
|
BODY_FILE_ENCODING = "utf-8"
|
|
85
76
|
CLEAN_EXIT_CODE = 0
|
|
86
77
|
CONTENT_FINDING_EXIT_CODE = 1
|
|
@@ -88,7 +79,6 @@ EMPTY_BODY_CODE = "empty-body"
|
|
|
88
79
|
INPUT_ERROR_EXIT_CODE = 2
|
|
89
80
|
PATH_ANCHOR_CHARACTER = "/"
|
|
90
81
|
PATH_SEGMENT_START_CHARACTERS = "_-"
|
|
91
|
-
|
|
92
82
|
BODY_FILE_UNREADABLE_MESSAGE = "body file is not readable UTF-8 text"
|
|
93
83
|
BODY_REQUIRED_MESSAGE = "this action requires a body file"
|
|
94
84
|
BODY_MUST_NOT_BE_EMPTY_MESSAGE = "body file must contain text"
|
|
@@ -104,3 +94,13 @@ TITLE_NOT_ALLOWED_MESSAGE = "this action does not accept a title"
|
|
|
104
94
|
TITLE_REQUIRED_MESSAGE = "pr-create requires a title"
|
|
105
95
|
VOLATILE_PATH_CODE = "volatile-local-path"
|
|
106
96
|
VOLATILE_PATH_MESSAGE = "body contains a volatile local artifact path"
|
|
97
|
+
RELEASE_BRANCH_PREFIX = "release-please--branches--"
|
|
98
|
+
ALL_RELEASE_BODY_MARKERS: tuple[str, ...] = (
|
|
99
|
+
":robot: I have created a release",
|
|
100
|
+
"This PR was generated with [Release Please]",
|
|
101
|
+
)
|
|
102
|
+
REWRITTEN_RELEASE_BODY_CODE = "rewritten-release-body"
|
|
103
|
+
REWRITTEN_RELEASE_BODY_MESSAGE = (
|
|
104
|
+
"release automation reads this body back to recognize its own merge; "
|
|
105
|
+
"keep the generated text whole"
|
|
106
|
+
)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"""Tests for durable GitHub post linter constants."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from durable_post_lint_config.config.constants import (
|
|
4
4
|
ALL_CONVENTIONAL_TITLE_TYPES,
|
|
5
5
|
ALL_POST_ACTIONS,
|
|
6
|
+
ALL_RELEASE_BODY_MARKERS,
|
|
6
7
|
CONVENTIONAL_TITLE_PATTERN,
|
|
8
|
+
RELEASE_BRANCH_PREFIX,
|
|
7
9
|
)
|
|
8
10
|
|
|
9
11
|
|
|
@@ -23,3 +25,14 @@ def test_action_inventory_covers_pull_request_issue_and_tool_posts() -> None:
|
|
|
23
25
|
def test_title_pattern_uses_every_configured_type() -> None:
|
|
24
26
|
for each_title_type in ALL_CONVENTIONAL_TITLE_TYPES:
|
|
25
27
|
assert CONVENTIONAL_TITLE_PATTERN.fullmatch(f"{each_title_type}: one change")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def should_carry_both_markers_release_automation_writes() -> None:
|
|
31
|
+
assert ALL_RELEASE_BODY_MARKERS == (
|
|
32
|
+
":robot: I have created a release",
|
|
33
|
+
"This PR was generated with [Release Please]",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def should_name_the_branch_prefix_release_automation_pushes() -> None:
|
|
38
|
+
assert RELEASE_BRANCH_PREFIX == "release-please--branches--"
|