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
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
HOOKS_DIRECTORY = Path(__file__).resolve().parents[2] / "hooks" / "git-hooks"
|
|
11
|
+
NOTICE_SCRIPT = HOOKS_DIRECTORY / "verification_notice.py"
|
|
12
|
+
ALL_REMOTE_URLS = (
|
|
13
|
+
"https://github.com/JonEcho/python-automation.git",
|
|
14
|
+
"git@github.com:JonEcho/python-automation.git",
|
|
15
|
+
"ssh://git@github.com/JonEcho/python-automation.git",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def run_notice(
|
|
20
|
+
repository_path: Path,
|
|
21
|
+
event_name: str = "commit",
|
|
22
|
+
) -> subprocess.CompletedProcess[str]:
|
|
23
|
+
return subprocess.run(
|
|
24
|
+
[
|
|
25
|
+
sys.executable,
|
|
26
|
+
str(NOTICE_SCRIPT),
|
|
27
|
+
"--event",
|
|
28
|
+
event_name,
|
|
29
|
+
"--repo",
|
|
30
|
+
str(repository_path),
|
|
31
|
+
],
|
|
32
|
+
check=False,
|
|
33
|
+
capture_output=True,
|
|
34
|
+
text=True,
|
|
35
|
+
encoding="utf-8",
|
|
36
|
+
env={**os.environ, "PYTHONIOENCODING": "utf-8"},
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def create_target_repository(
|
|
41
|
+
temporary_directory: Path,
|
|
42
|
+
remote_url: str,
|
|
43
|
+
) -> tuple[Path, str]:
|
|
44
|
+
repository_path = temporary_directory / "Jon Echo project with spaces Ω"
|
|
45
|
+
repository_path.mkdir(parents=True)
|
|
46
|
+
run_git(repository_path, "init", "--quiet")
|
|
47
|
+
run_git(repository_path, "config", "user.email", "test@example.invalid")
|
|
48
|
+
run_git(repository_path, "config", "user.name", "Verification Test")
|
|
49
|
+
(repository_path / "README.md").write_text("check\n", encoding="utf-8")
|
|
50
|
+
run_git(repository_path, "add", "README.md")
|
|
51
|
+
run_git(repository_path, "commit", "--quiet", "-m", "initial")
|
|
52
|
+
run_git(repository_path, "remote", "add", "origin", remote_url)
|
|
53
|
+
current_head = run_git(repository_path, "rev-parse", "HEAD").stdout.strip()
|
|
54
|
+
return repository_path, current_head
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def run_git(
|
|
58
|
+
repository_path: Path,
|
|
59
|
+
*arguments: str,
|
|
60
|
+
) -> subprocess.CompletedProcess[str]:
|
|
61
|
+
return subprocess.run(
|
|
62
|
+
["git", *arguments],
|
|
63
|
+
cwd=repository_path,
|
|
64
|
+
check=True,
|
|
65
|
+
capture_output=True,
|
|
66
|
+
text=True,
|
|
67
|
+
encoding="utf-8",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def write_report(
|
|
72
|
+
repository_path: Path,
|
|
73
|
+
report_fields: dict[str, object],
|
|
74
|
+
) -> None:
|
|
75
|
+
manifest_path = repository_path / "config" / "local-verification.json"
|
|
76
|
+
manifest_path.parent.mkdir(exist_ok=True)
|
|
77
|
+
manifest_mapping = {
|
|
78
|
+
"version": 1,
|
|
79
|
+
"checks": [
|
|
80
|
+
{
|
|
81
|
+
"id": "smoke",
|
|
82
|
+
"argv": ["python", "-c", "pass"],
|
|
83
|
+
"cwd": ".",
|
|
84
|
+
"timeout_seconds": 1.0,
|
|
85
|
+
"minimum_tests": None,
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"exclusions": [],
|
|
89
|
+
}
|
|
90
|
+
manifest_path.write_text(json.dumps(manifest_mapping), encoding="utf-8")
|
|
91
|
+
report_path = repository_path / ".git" / "local-verification" / "report.json"
|
|
92
|
+
report_path.parent.mkdir(exist_ok=True)
|
|
93
|
+
all_report_fields = {
|
|
94
|
+
"selection": {"selected_manifest_path": "config/local-verification.json"},
|
|
95
|
+
"manifest_digest": hashlib.sha256(
|
|
96
|
+
json.dumps(manifest_mapping, sort_keys=True, separators=(",", ":")).encode()
|
|
97
|
+
).hexdigest(),
|
|
98
|
+
**report_fields,
|
|
99
|
+
}
|
|
100
|
+
report_path.write_text(json.dumps(all_report_fields), encoding="utf-8")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def write_passing_report(repository_path: Path) -> str:
|
|
104
|
+
write_report(repository_path, {})
|
|
105
|
+
run_git(repository_path, "add", "config/local-verification.json")
|
|
106
|
+
run_git(repository_path, "commit", "--quiet", "-m", "manifest")
|
|
107
|
+
current_head = run_git(repository_path, "rev-parse", "HEAD").stdout.strip()
|
|
108
|
+
run_git(repository_path, "update-ref", "refs/remotes/origin/main", current_head)
|
|
109
|
+
write_report(
|
|
110
|
+
repository_path,
|
|
111
|
+
{
|
|
112
|
+
"head": current_head,
|
|
113
|
+
"base": current_head,
|
|
114
|
+
"worktree_clean": True,
|
|
115
|
+
"inputs_unchanged": True,
|
|
116
|
+
"publishable": True,
|
|
117
|
+
"status": "passed",
|
|
118
|
+
"aggregate": {
|
|
119
|
+
"status": "passed",
|
|
120
|
+
"total": 1,
|
|
121
|
+
"passed": 1,
|
|
122
|
+
"failed": 0,
|
|
123
|
+
"incomplete": 0,
|
|
124
|
+
"exit_code": 0,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
)
|
|
128
|
+
return current_head
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def write_worktree_passing_report(
|
|
132
|
+
repository_path: Path,
|
|
133
|
+
linked_git_directory: Path,
|
|
134
|
+
) -> str:
|
|
135
|
+
current_head = run_git(repository_path, "rev-parse", "HEAD").stdout.strip()
|
|
136
|
+
source_manifest_path = repository_path / "config" / "local-verification.json"
|
|
137
|
+
source_report_path = repository_path / ".git" / "local-verification" / "report.json"
|
|
138
|
+
metadata_directory = linked_git_directory / "local-verification"
|
|
139
|
+
metadata_directory.mkdir(parents=True, exist_ok=True)
|
|
140
|
+
metadata_manifest_path = metadata_directory / "local-verification.json"
|
|
141
|
+
metadata_manifest_path.write_bytes(source_manifest_path.read_bytes())
|
|
142
|
+
all_report_fields = json.loads(source_report_path.read_text(encoding="utf-8"))
|
|
143
|
+
all_report_fields["selection"]["selected_manifest_path"] = str(
|
|
144
|
+
metadata_manifest_path
|
|
145
|
+
)
|
|
146
|
+
metadata_report_path = metadata_directory / "report.json"
|
|
147
|
+
metadata_report_path.write_text(json.dumps(all_report_fields), encoding="utf-8")
|
|
148
|
+
return current_head
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_notice_matches_remote_formats_and_quotes_paths(tmp_path: Path) -> None:
|
|
152
|
+
for each_index, each_remote_url in enumerate(ALL_REMOTE_URLS):
|
|
153
|
+
repository_path, current_head = create_target_repository(
|
|
154
|
+
tmp_path / str(each_index), each_remote_url
|
|
155
|
+
)
|
|
156
|
+
completed_notice = run_notice(repository_path, "push")
|
|
157
|
+
assert completed_notice.returncode == 0
|
|
158
|
+
assert "LOCAL VERIFICATION ADVISORY" in completed_notice.stdout
|
|
159
|
+
assert f"Current SHA: {current_head}" in completed_notice.stdout
|
|
160
|
+
assert "State: pending" in completed_notice.stdout
|
|
161
|
+
assert "python '" in completed_notice.stdout
|
|
162
|
+
wrapper_suffix = str(Path(".github") / "ci" / "local_verify.py")
|
|
163
|
+
assert f"{wrapper_suffix}' --base origin/main" in completed_notice.stdout
|
|
164
|
+
assert "--executor '" in completed_notice.stdout
|
|
165
|
+
assert "--output '" in completed_notice.stdout
|
|
166
|
+
assert repository_path.name in completed_notice.stdout
|
|
167
|
+
assert "--base origin/main" in completed_notice.stdout
|
|
168
|
+
assert "does not block commit or push" in completed_notice.stdout
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_notice_reports_pending_when_manifest_exists_without_report(
|
|
172
|
+
tmp_path: Path,
|
|
173
|
+
) -> None:
|
|
174
|
+
repository_path, _ = create_target_repository(
|
|
175
|
+
tmp_path,
|
|
176
|
+
"https://github.com/JonEcho/python-automation.git",
|
|
177
|
+
)
|
|
178
|
+
write_report(repository_path, {})
|
|
179
|
+
(repository_path / ".git" / "local-verification" / "report.json").unlink()
|
|
180
|
+
|
|
181
|
+
completed_notice = run_notice(repository_path)
|
|
182
|
+
|
|
183
|
+
assert completed_notice.returncode == 0
|
|
184
|
+
assert "State: pending" in completed_notice.stdout
|
|
185
|
+
assert "manifest is missing or unreadable" not in completed_notice.stdout
|
|
186
|
+
assert "No complete current pass is recorded" in completed_notice.stdout
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_notice_ignores_unrelated_remote(tmp_path: Path) -> None:
|
|
190
|
+
repository_path, _ = create_target_repository(
|
|
191
|
+
tmp_path,
|
|
192
|
+
"https://github.com/other-owner/other-repository.git",
|
|
193
|
+
)
|
|
194
|
+
completed_notice = run_notice(repository_path)
|
|
195
|
+
assert completed_notice.returncode == 0
|
|
196
|
+
assert completed_notice.stdout == ""
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_notice_reports_failed_checks_without_pass_label(tmp_path: Path) -> None:
|
|
200
|
+
repository_path, current_head = create_target_repository(
|
|
201
|
+
tmp_path,
|
|
202
|
+
"https://github.com/JonEcho/python-automation.git",
|
|
203
|
+
)
|
|
204
|
+
write_report(repository_path, {"head": current_head, "status": "failed"})
|
|
205
|
+
completed_notice = run_notice(repository_path)
|
|
206
|
+
assert completed_notice.returncode == 0
|
|
207
|
+
assert f"Current SHA: {current_head}" in completed_notice.stdout
|
|
208
|
+
assert "State: failed" in completed_notice.stdout
|
|
209
|
+
assert "recorded local checks failed" in completed_notice.stdout
|
|
210
|
+
assert "local-checks:passed" not in completed_notice.stdout
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def test_notice_reports_pass_only_for_complete_current_revision(tmp_path: Path) -> None:
|
|
214
|
+
repository_path, _ = create_target_repository(
|
|
215
|
+
tmp_path,
|
|
216
|
+
"https://github.com/JonEcho/python-automation.git",
|
|
217
|
+
)
|
|
218
|
+
current_head = write_passing_report(repository_path)
|
|
219
|
+
completed_notice = run_notice(repository_path)
|
|
220
|
+
assert completed_notice.returncode == 0
|
|
221
|
+
assert f"Verified SHA: {current_head}" in completed_notice.stdout
|
|
222
|
+
assert "State: passed" in completed_notice.stdout
|
|
223
|
+
assert (
|
|
224
|
+
"local-checks:passed is valid only for this exact current SHA"
|
|
225
|
+
in completed_notice.stdout
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def test_notice_handles_malformed_report_and_missing_repository(tmp_path: Path) -> None:
|
|
230
|
+
repository_path, _ = create_target_repository(
|
|
231
|
+
tmp_path,
|
|
232
|
+
"https://github.com/JonEcho/python-automation.git",
|
|
233
|
+
)
|
|
234
|
+
manifest_path = repository_path / "config" / "local-verification.json"
|
|
235
|
+
manifest_path.parent.mkdir(exist_ok=True)
|
|
236
|
+
manifest_mapping = {
|
|
237
|
+
"version": 1,
|
|
238
|
+
"checks": [
|
|
239
|
+
{
|
|
240
|
+
"id": "smoke",
|
|
241
|
+
"argv": ["python", "-c", "pass"],
|
|
242
|
+
"cwd": ".",
|
|
243
|
+
"timeout_seconds": 1.0,
|
|
244
|
+
"minimum_tests": None,
|
|
245
|
+
}
|
|
246
|
+
],
|
|
247
|
+
"exclusions": [],
|
|
248
|
+
}
|
|
249
|
+
manifest_path.write_text(json.dumps(manifest_mapping), encoding="utf-8")
|
|
250
|
+
report_path = repository_path / ".git" / "local-verification" / "report.json"
|
|
251
|
+
report_path.parent.mkdir(exist_ok=True)
|
|
252
|
+
report_path.write_bytes(b"not-json\xff")
|
|
253
|
+
malformed_notice = run_notice(repository_path)
|
|
254
|
+
missing_notice = run_notice(tmp_path / "missing repository")
|
|
255
|
+
assert malformed_notice.returncode == 0
|
|
256
|
+
assert "State: unverified" in malformed_notice.stdout
|
|
257
|
+
assert missing_notice.returncode == 0
|
|
258
|
+
assert missing_notice.stdout == ""
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def test_notice_uses_worktree_specific_report_path(tmp_path: Path) -> None:
|
|
262
|
+
repository_path, _ = create_target_repository(
|
|
263
|
+
tmp_path / "main",
|
|
264
|
+
"https://github.com/JonEcho/python-automation.git",
|
|
265
|
+
)
|
|
266
|
+
linked_worktree_path = tmp_path / "linked worktree Ω"
|
|
267
|
+
run_git(repository_path, "worktree", "add", "--detach", str(linked_worktree_path))
|
|
268
|
+
linked_git_directory = Path(
|
|
269
|
+
run_git(linked_worktree_path, "rev-parse", "--absolute-git-dir").stdout.strip()
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
completed_notice = run_notice(linked_worktree_path)
|
|
273
|
+
|
|
274
|
+
expected_report_path = linked_git_directory / "local-verification" / "report.json"
|
|
275
|
+
shared_report_path = repository_path / ".git" / "local-verification" / "report.json"
|
|
276
|
+
assert completed_notice.returncode == 0
|
|
277
|
+
assert str(expected_report_path) in completed_notice.stdout
|
|
278
|
+
assert str(shared_report_path) not in completed_notice.stdout
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def test_notice_accepts_complete_report_in_worktree_metadata(tmp_path: Path) -> None:
|
|
282
|
+
repository_path, _ = create_target_repository(
|
|
283
|
+
tmp_path / "main",
|
|
284
|
+
"https://github.com/JonEcho/python-automation.git",
|
|
285
|
+
)
|
|
286
|
+
current_head = write_passing_report(repository_path)
|
|
287
|
+
linked_worktree_path = tmp_path / "linked worktree Ω"
|
|
288
|
+
run_git(repository_path, "worktree", "add", "--detach", str(linked_worktree_path))
|
|
289
|
+
linked_git_directory = Path(
|
|
290
|
+
run_git(linked_worktree_path, "rev-parse", "--absolute-git-dir").stdout.strip()
|
|
291
|
+
)
|
|
292
|
+
write_worktree_passing_report(repository_path, linked_git_directory)
|
|
293
|
+
|
|
294
|
+
completed_notice = run_notice(linked_worktree_path)
|
|
295
|
+
|
|
296
|
+
future_path = linked_worktree_path / "future.txt"
|
|
297
|
+
future_path.write_text("future\n", encoding="utf-8")
|
|
298
|
+
run_git(linked_worktree_path, "add", "future.txt")
|
|
299
|
+
run_git(linked_worktree_path, "commit", "--quiet", "-m", "future")
|
|
300
|
+
future_head = run_git(linked_worktree_path, "rev-parse", "HEAD").stdout.strip()
|
|
301
|
+
stale_notice = run_notice(linked_worktree_path)
|
|
302
|
+
run_git(linked_worktree_path, "reset", "--quiet", "--hard", current_head)
|
|
303
|
+
run_git(linked_worktree_path, "update-ref", "refs/remotes/origin/main", future_head)
|
|
304
|
+
moved_base_notice = run_notice(linked_worktree_path)
|
|
305
|
+
|
|
306
|
+
assert "State: passed" in completed_notice.stdout
|
|
307
|
+
assert f"Verified SHA: {current_head}" in completed_notice.stdout
|
|
308
|
+
assert "State: stale" in stale_notice.stdout
|
|
309
|
+
assert "State: unverified" in moved_base_notice.stdout
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def test_notice_invalidates_pass_after_worktree_edit(tmp_path: Path) -> None:
|
|
313
|
+
repository_path, _ = create_target_repository(
|
|
314
|
+
tmp_path,
|
|
315
|
+
"https://github.com/JonEcho/python-automation.git",
|
|
316
|
+
)
|
|
317
|
+
current_head = write_passing_report(repository_path)
|
|
318
|
+
passed_notice = run_notice(repository_path)
|
|
319
|
+
(repository_path / "untracked.txt").write_text("changed\n", encoding="utf-8")
|
|
320
|
+
|
|
321
|
+
changed_notice = run_notice(repository_path)
|
|
322
|
+
|
|
323
|
+
assert f"Verified SHA: {current_head}" in passed_notice.stdout
|
|
324
|
+
assert "State: passed" in passed_notice.stdout
|
|
325
|
+
assert "Verified SHA: none" in changed_notice.stdout
|
|
326
|
+
assert "State: unverified" in changed_notice.stdout
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def test_notice_invalidates_pass_after_origin_base_moves(tmp_path: Path) -> None:
|
|
330
|
+
repository_path, _ = create_target_repository(
|
|
331
|
+
tmp_path,
|
|
332
|
+
"https://github.com/JonEcho/python-automation.git",
|
|
333
|
+
)
|
|
334
|
+
current_head = write_passing_report(repository_path)
|
|
335
|
+
passed_notice = run_notice(repository_path)
|
|
336
|
+
(repository_path / "future.txt").write_text("future\n", encoding="utf-8")
|
|
337
|
+
run_git(repository_path, "add", "future.txt")
|
|
338
|
+
run_git(repository_path, "commit", "--quiet", "-m", "future")
|
|
339
|
+
future_head = run_git(repository_path, "rev-parse", "HEAD").stdout.strip()
|
|
340
|
+
run_git(repository_path, "reset", "--quiet", "--hard", current_head)
|
|
341
|
+
run_git(repository_path, "update-ref", "refs/remotes/origin/main", future_head)
|
|
342
|
+
|
|
343
|
+
moved_base_notice = run_notice(repository_path)
|
|
344
|
+
|
|
345
|
+
assert "State: passed" in passed_notice.stdout
|
|
346
|
+
assert "Verified SHA: none" in moved_base_notice.stdout
|
|
347
|
+
assert "State: unverified" in moved_base_notice.stdout
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@../AGENTS.md
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# Portable converge driver
|
|
2
|
-
|
|
3
|
-
**Rule: deterministic control is script-only.** Phase transitions, wait delays,
|
|
4
|
-
clean stamps, ready decisions, task lists, and “what next” never live as prose
|
|
5
|
-
for the agent to invent. The agent runs scripts, reads JSON, and only performs
|
|
6
|
-
judgment steps the JSON names.
|
|
7
|
-
|
|
8
|
-
## Step 1 — task list (every autoconverge portable run)
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
python "$HOME/.claude/skills/_shared/pr-loop/scripts/build_converge_task_list.py" \
|
|
12
|
-
[--bugbot-down 0|1] [--copilot-down 0|1] \
|
|
13
|
-
[--codex-down 0|1] [--codex-required 0|1]
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Register every `tasks[]` entry on the session task list. **Final task id is
|
|
17
|
-
always** `all_runnable_reviews_clean_same_head`. The run is complete only when
|
|
18
|
-
that final task is completed: every runnable code review is CLEAN on one
|
|
19
|
-
shared HEAD. Do not invent tasks in prose.
|
|
20
|
-
|
|
21
|
-
`open-run` embeds the same list (`tasks`, `runnable_review_ids`,
|
|
22
|
-
`final_task_id`, `done_when`).
|
|
23
|
-
|
|
24
|
-
## Pacer selection
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
python "$HOME/.claude/skills/_shared/pr-loop/scripts/select_converge_pacer.py" \
|
|
28
|
-
--skill autoconverge \
|
|
29
|
-
--has-workflow <0|1> \
|
|
30
|
-
--has-schedule-wakeup <0|1>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
When `pacer` is not `portable`, use the skill’s native Workflow or
|
|
34
|
-
ScheduleWakeup path. When `pacer=portable`, use the control script below.
|
|
35
|
-
|
|
36
|
-
## Isolation and worktree
|
|
37
|
-
|
|
38
|
-
1. When the tool list includes `EnterWorktree`, call it (same contract as the
|
|
39
|
-
Claude-host skills).
|
|
40
|
-
2. When `EnterWorktree` is absent, isolate with git worktree machinery:
|
|
41
|
-
- Prefer an existing worktree already on the PR head ref under
|
|
42
|
-
`.claude/worktrees/` (or another dedicated worktree path).
|
|
43
|
-
- Otherwise `git fetch origin <headRefName>` and
|
|
44
|
-
`git worktree add <path> <headRefName>` (or `gh pr checkout <N>` into a
|
|
45
|
-
dedicated directory), then `cd` into that checkout.
|
|
46
|
-
3. Confirm the working directory is the PR’s own repo on the PR head SHA:
|
|
47
|
-
`python "$HOME/.claude/skills/_shared/pr-loop/scripts/preflight_worktree.py" --owner <O> --repo <R> --mode strict`.
|
|
48
|
-
Non-zero exit → report the `ABORT` line and stop.
|
|
49
|
-
4. Cross-repo routing: every local review and edit runs with cwd set to the **PR worktree** (see autoconverge pre-flight and `preflight_worktree.py --mode strict`).
|
|
50
|
-
|
|
51
|
-
`open-run` runs the same strict preflight before seeding state.
|
|
52
|
-
|
|
53
|
-
## Control script
|
|
54
|
-
|
|
55
|
-
```
|
|
56
|
-
python "$HOME/.claude/skills/_shared/pr-loop/scripts/portable_converge_driver.py" <command> ...
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Stdout JSON: `status`, `next`, `phase`, `state_file`, optional `commands`,
|
|
60
|
-
`wait_seconds`, `blocker`, and on `open-run` the task-list fields. Exit `0` =
|
|
61
|
-
ok; `1` = contract failure; `2` = usage error.
|
|
62
|
-
|
|
63
|
-
| Command | Deterministic effect |
|
|
64
|
-
|---|---|
|
|
65
|
-
| `open-run` | Require `portable`; preflight; seed state + task list; when `--codex-down` is off, set `codex_required` from CLI force-on or the weekly usage probe (same rule as `check_convergence`); next=`run_code_review` |
|
|
66
|
-
| `after-code-review` | From returncode / dirty_tree / served_command |
|
|
67
|
-
| `after-bugteam` | From pushed / converged (bug-audit phase on portable pacer) |
|
|
68
|
-
| `after-bugbot` | From classification / inline lag |
|
|
69
|
-
| `after-codex` | From classification clean / dirty / down |
|
|
70
|
-
| `after-copilot-wait` | From review surfaced / wait cap |
|
|
71
|
-
| `after-ready-check` | From check_convergence exit |
|
|
72
|
-
| `show-state` | Echo state; rehydrate `commands` / `wait_seconds` for pending next |
|
|
73
|
-
|
|
74
|
-
## Continuous tick loop
|
|
75
|
-
|
|
76
|
-
After transport check, PR scope, isolation, permission grant, and the once-per-run
|
|
77
|
-
Copilot quota pre-check:
|
|
78
|
-
|
|
79
|
-
1. Seed or restore state via `open-run` or `show-state` (and handoff
|
|
80
|
-
`state-copy.json` when resuming).
|
|
81
|
-
2. Run the driver command for the current step; read JSON `next` / `commands` /
|
|
82
|
-
`wait_seconds`.
|
|
83
|
-
3. On non-terminal `next`:
|
|
84
|
-
- Write state and handoff when the after-* payload says so.
|
|
85
|
-
- If `next` is `poll_wait`, sleep `wait_seconds` only, then re-poll and call
|
|
86
|
-
the matching after-*.
|
|
87
|
-
- If `next` is immediate work, continue in the same turn without sleeping.
|
|
88
|
-
4. On `mark_ready` / `stop_blocked` / named stop: run lifecycle Close, print the
|
|
89
|
-
entry skill’s exit block, omit further pacing.
|
|
90
|
-
5. External reviewers remain skippable the same way as Claude-host runs when
|
|
91
|
-
opted out or down. Push and head-change reset push-invalidated markers
|
|
92
|
-
(`*_clean_at`, `merge_state_status`, `bugbot_down`, `codex_down`).
|
|
93
|
-
|
|
94
|
-
## Agent loop (judgment only)
|
|
95
|
-
|
|
96
|
-
1. Run the driver command for the current step.
|
|
97
|
-
2. If JSON `commands` is non-empty, run that argv (scripted helper).
|
|
98
|
-
3. Map JSON `next` to the single judgment action; report back via the matching
|
|
99
|
-
`after-*` command.
|
|
100
|
-
4. Mark session tasks complete only when the scripted stamps say so; complete
|
|
101
|
-
the final task only when every runnable review is clean on the same HEAD.
|
|
102
|
-
|
|
103
|
-
| `next` | Agent does | Report with |
|
|
104
|
-
|---|---|---|
|
|
105
|
-
| `run_code_review` | Run `commands` | `after-code-review` |
|
|
106
|
-
| `apply_fixes_and_push` | Fix protocol; commit; push | re-review then `after-code-review` |
|
|
107
|
-
| `run_bugteam` | Bug-audit lens / worker spawn body | `after-bugteam` |
|
|
108
|
-
| `run_bugbot_gate` | Bugbot helper scripts | `after-bugbot` |
|
|
109
|
-
| `run_codex_review` | Run Codex review step | `after-codex` |
|
|
110
|
-
| `request_copilot_review` | Request Copilot | `after-copilot-wait` |
|
|
111
|
-
| `poll_wait` | Sleep `wait_seconds` only | re-poll then after-* |
|
|
112
|
-
| `check_ready` | Run `commands` (check_convergence) | `after-ready-check` |
|
|
113
|
-
| `mark_ready` | Run `commands` (`gh pr ready`) | teardown |
|
|
114
|
-
| `stop_blocked` | Teardown; print blocker | stop |
|
|
115
|
-
|
|
116
|
-
## Autoconverge entry on portable pacer
|
|
117
|
-
|
|
118
|
-
When `/autoconverge` selects `pacer=portable`:
|
|
119
|
-
|
|
120
|
-
- Complete autoconverge pre-flight (scope, draft ownership, strict worktree,
|
|
121
|
-
grant, Copilot quota).
|
|
122
|
-
- Drive the continuous tick loop above (scripted phase machine) until ready
|
|
123
|
-
or a documented blocker.
|
|
124
|
-
- Skip `Workflow({ scriptPath: converge.mjs })` — that path requires the
|
|
125
|
-
Workflow tool.
|
|
126
|
-
- Teardown uses the lifecycle Close path; the Workflow-only closing HTML
|
|
127
|
-
journal report is optional and skipped when no workflow run id exists.
|
|
128
|
-
- Resume command on handoff: `/autoconverge <PR URL>`.
|
|
129
|
-
|
|
130
|
-
When `/autoconverge` selects `pacer=workflow`, follow the skill’s Workflow
|
|
131
|
-
sections unchanged.
|
|
132
|
-
|
|
133
|
-
## Helpers (scripted)
|
|
134
|
-
|
|
135
|
-
| Concern | Script |
|
|
136
|
-
|---|---|
|
|
137
|
-
| Task list | `build_converge_task_list.py` |
|
|
138
|
-
| Pacer | `select_converge_pacer.py` |
|
|
139
|
-
| Worktree | `preflight_worktree.py` |
|
|
140
|
-
| Code review | `$HOME/.claude/scripts/invoke_code_review.py` |
|
|
141
|
-
| Workers | `$HOME/.claude/scripts/resolve_worker_spawn.py` |
|
|
142
|
-
| Ready | `$HOME/.claude/_shared/pr-loop/scripts/check_convergence.py` |
|
|
143
|
-
| Handoff | `write_handoff.py` |
|
|
144
|
-
|
|
145
|
-
## Fail closed
|
|
146
|
-
|
|
147
|
-
Never abort solely because Workflow or ScheduleWakeup is missing once
|
|
148
|
-
pacer=`portable`. Fail closed on contract failures only: auth, worktree,
|
|
149
|
-
unresolvable gates, and wait caps.
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict'
|
|
2
|
-
import { readFileSync } from 'node:fs'
|
|
3
|
-
import { dirname, resolve } from 'node:path'
|
|
4
|
-
import test from 'node:test'
|
|
5
|
-
import { fileURLToPath } from 'node:url'
|
|
6
|
-
|
|
7
|
-
const THIS_DIRECTORY = dirname(fileURLToPath(import.meta.url))
|
|
8
|
-
const canonicalContractSource = readFileSync(
|
|
9
|
-
resolve(THIS_DIRECTORY, '../../../../_shared/pr-loop/preflight-proposal.md'),
|
|
10
|
-
'utf8',
|
|
11
|
-
)
|
|
12
|
-
const sharedSkillSource = readFileSync(
|
|
13
|
-
resolve(THIS_DIRECTORY, '../../pr-shared-extraction/SKILL.md'),
|
|
14
|
-
'utf8',
|
|
15
|
-
)
|
|
16
|
-
const capabilitySkillSource = readFileSync(
|
|
17
|
-
resolve(THIS_DIRECTORY, '../../pr-name-by-capability/SKILL.md'),
|
|
18
|
-
'utf8',
|
|
19
|
-
)
|
|
20
|
-
const capabilityTaskSeedsSource = readFileSync(
|
|
21
|
-
resolve(THIS_DIRECTORY, '../../pr-name-by-capability/reference/task-seeds.md'),
|
|
22
|
-
'utf8',
|
|
23
|
-
)
|
|
24
|
-
const reviewSkillSource = readFileSync(
|
|
25
|
-
resolve(THIS_DIRECTORY, '../../e-code-review/SKILL.md'),
|
|
26
|
-
'utf8',
|
|
27
|
-
)
|
|
28
|
-
const reviewProposalSource = readFileSync(
|
|
29
|
-
resolve(THIS_DIRECTORY, '../../e-code-review/reference/preflight-proposal.md'),
|
|
30
|
-
'utf8',
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
const allSkillContracts = [
|
|
34
|
-
{
|
|
35
|
-
name: 'shared extraction audit',
|
|
36
|
-
skillSource: sharedSkillSource,
|
|
37
|
-
invocationPattern: /pr-shared-extraction preflight-proposal/,
|
|
38
|
-
classificationPattern: /priority and target/,
|
|
39
|
-
expectedDefaultBehavior: 'applies the prioritized fix band by default',
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: 'name by capability audit',
|
|
43
|
-
skillSource: capabilitySkillSource,
|
|
44
|
-
invocationPattern: /pr-name-by-capability preflight-proposal/,
|
|
45
|
-
classificationPattern: /violation or OK-driver classification/,
|
|
46
|
-
expectedDefaultBehavior: 'applies the suggested rename direction by default',
|
|
47
|
-
},
|
|
48
|
-
]
|
|
49
|
-
|
|
50
|
-
function assertProposalAdapter(skillContract) {
|
|
51
|
-
const preflightRoutingOffset = skillContract.skillSource.indexOf('`preflight-proposal`')
|
|
52
|
-
const reportOnlyRoutingOffset = skillContract.skillSource.indexOf('`audit-only`')
|
|
53
|
-
|
|
54
|
-
assert.ok(preflightRoutingOffset >= 0, `${skillContract.name} selects proposal mode`)
|
|
55
|
-
assert.ok(preflightRoutingOffset < reportOnlyRoutingOffset, `${skillContract.name} routes proposal mode first`)
|
|
56
|
-
assert.match(skillContract.skillSource, skillContract.invocationPattern)
|
|
57
|
-
assert.match(skillContract.skillSource, skillContract.classificationPattern)
|
|
58
|
-
assert.match(skillContract.skillSource, new RegExp(skillContract.expectedDefaultBehavior))
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function assertTaskRoutingAndNormalMode() {
|
|
62
|
-
assert.match(sharedSkillSource, /Register this checklist with `update_plan`/)
|
|
63
|
-
assert.match(capabilitySkillSource, /Register every bullet from `reference\/task-seeds\.md` with `update_plan`/)
|
|
64
|
-
assert.match(capabilityTaskSeedsSource, /Register each item with `update_plan`/)
|
|
65
|
-
assert.doesNotMatch(sharedSkillSource, /TodoWrite|TaskCreate/)
|
|
66
|
-
assert.doesNotMatch(capabilitySkillSource, /TodoWrite|TaskCreate/)
|
|
67
|
-
assert.doesNotMatch(capabilityTaskSeedsSource, /TodoWrite|TaskCreate/)
|
|
68
|
-
assert.match(sharedSkillSource, /audit-only` is report-only/)
|
|
69
|
-
assert.match(capabilitySkillSource, /audit-only` is report-only/)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function assertSharedProposalContract(contractSource) {
|
|
73
|
-
assert.match(contractSource, /caller-supplied isolated worktree/)
|
|
74
|
-
assert.match(contractSource, /resolved PR number/)
|
|
75
|
-
assert.match(contractSource, /immutable base SHA/)
|
|
76
|
-
assert.match(contractSource, /immutable head SHA/)
|
|
77
|
-
assert.match(contractSource, /exact `base_sha\.\.\.head_sha` range/)
|
|
78
|
-
assert.match(contractSource, /require exact equality with the head SHA/)
|
|
79
|
-
assert.match(contractSource, /immutable proposal identity/)
|
|
80
|
-
assert.match(contractSource, /deterministic diff hash/)
|
|
81
|
-
assert.match(contractSource, /changed paths/)
|
|
82
|
-
assert.match(contractSource, /exact tests and outcomes/)
|
|
83
|
-
assert.match(contractSource, /selected-candidate-ready proposal evidence/)
|
|
84
|
-
assert.match(contractSource, /selected or dispositioned proposal collection/)
|
|
85
|
-
assert.match(contractSource, /Reapplication uses exactly the selected records/)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function assertReviewProposalAdapter() {
|
|
89
|
-
const preflightRoutingOffset = reviewSkillSource.indexOf('`preflight-proposal`')
|
|
90
|
-
const refusalRoutingOffset = reviewSkillSource.indexOf('**Refusal — first match wins:**')
|
|
91
|
-
const allProposalEntryMatches = reviewSkillSource.match(
|
|
92
|
-
/Route the selected mode through \[reference\/preflight-proposal.md\]\(reference\/preflight-proposal.md\) to establish proposal context/g,
|
|
93
|
-
) ?? []
|
|
94
|
-
|
|
95
|
-
assert.ok(preflightRoutingOffset >= 0)
|
|
96
|
-
assert.ok(preflightRoutingOffset < refusalRoutingOffset)
|
|
97
|
-
assert.equal(allProposalEntryMatches.length, 1)
|
|
98
|
-
assert.match(reviewSkillSource, /e-code-review preflight-proposal/)
|
|
99
|
-
assert.match(reviewSkillSource, /`--level <low\|medium\|xhigh>`/)
|
|
100
|
-
assert.match(reviewSkillSource, /@~\/.claude\/_shared\/pr-loop\/preflight-proposal.md/)
|
|
101
|
-
assert.match(reviewSkillSource, /Normal mode follows the current level/)
|
|
102
|
-
assert.match(reviewProposalSource, /Keep Gate 1, Gate 2, the bare code-rules gate, and exact required tests/)
|
|
103
|
-
assert.match(reviewProposalSource, /review_level: low \| medium \| xhigh/)
|
|
104
|
-
assert.match(reviewProposalSource, /severity: blocker \| high \| medium \| low \| nit/)
|
|
105
|
-
assert.match(reviewProposalSource, /verdict: CONFIRMED \| PLAUSIBLE/)
|
|
106
|
-
assert.match(reviewProposalSource, /outcome: fixed \| no_change_needed \| skipped/)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
test('audit modes retain their normal routing behavior', () => {
|
|
110
|
-
assertTaskRoutingAndNormalMode()
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
test('one shared contract defines proposal evidence for audit and review skills', () => {
|
|
114
|
-
for (const eachSkillContract of allSkillContracts) {
|
|
115
|
-
assertProposalAdapter(eachSkillContract)
|
|
116
|
-
}
|
|
117
|
-
assertReviewProposalAdapter()
|
|
118
|
-
assertSharedProposalContract(canonicalContractSource)
|
|
119
|
-
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@../AGENTS.md
|