claude-dev-env 2.4.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +26 -59
- package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
- package/_shared/pr-loop/scripts/code_rules_gate.py +6 -3
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +12 -2
- package/_shared/pr-loop/scripts/code_rules_gate_parts/baseline_import_isolation.py +309 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +540 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +206 -70
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/__init__.py +1 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/_repo_test_helpers.py +76 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_baseline_import_isolation.py +248 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_regression.py +309 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +91 -58
- package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +202 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
- package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
- package/_shared/pr-loop/worker-spawn.md +1 -1
- package/agents/CLAUDE.md +3 -2
- package/agents/caveman.md +0 -1
- package/agents/clasp-deployment-orchestrator.md +0 -1
- package/agents/clean-coder.md +0 -1
- package/agents/code-advisor.md +0 -1
- package/agents/code-quality-agent.md +1 -2
- package/agents/code-verifier.md +36 -8
- package/agents/deep-research.md +0 -1
- package/agents/docs-agent.md +0 -1
- package/agents/git-commit-crafter.md +0 -1
- package/agents/issue-tracker.md +42 -0
- package/agents/plan-packet-validator.md +0 -1
- package/agents/pr-description-writer.md +0 -1
- package/agents/test_agent_frontmatter.py +67 -18
- package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +143 -141
- package/bin/CLAUDE.md +68 -5
- package/bin/codex-compat.mjs +104 -0
- package/bin/codex-compat.test.mjs +51 -0
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +88 -0
- package/bin/install.mjs +1138 -114
- package/bin/install.prune.test.mjs +869 -19
- package/bin/install.test.mjs +906 -2
- package/codex-capability-map.json +13 -0
- package/commands/implement.md +1 -1
- package/commands/right-size.md +1 -1
- package/docs/CLAUDE.md +1 -0
- package/docs/CODE_RULES.md +2 -0
- package/docs/codex-compatibility.md +25 -0
- package/docs/host-pool-health-monitor.md +102 -0
- package/docs/nas-ssh-invocation.md +96 -12
- package/docs/references/CLAUDE.md +4 -2
- package/docs/references/advisor-tool.md +13 -0
- package/docs/references/code-review-enforcement.md +35 -0
- package/docs/references/team-advisor-skill.md +14 -0
- package/hooks/blocking/CLAUDE.md +4 -0
- package/hooks/blocking/code_review_pr_create_gate.py +7 -3
- package/hooks/blocking/code_review_push_gate.py +9 -4
- package/hooks/blocking/code_review_stamp_directory_write_blocker.py +8 -0
- package/hooks/blocking/config/__init__.py +5 -5
- package/hooks/blocking/config/code_review_enforcement_constants.py +40 -7
- package/hooks/blocking/config/test_code_review_enforcement_constants.py +58 -0
- package/hooks/blocking/config/verified_commit_constants.py +160 -159
- package/hooks/blocking/eli11_reply_enforcer.py +479 -0
- package/hooks/blocking/gh_body_arg_blocker.py +1 -1
- package/hooks/blocking/nas_ssh_binary_enforcer.py +8 -46
- package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
- package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
- package/hooks/blocking/shell_substitution_blocker.py +129 -0
- package/hooks/blocking/state_description_blocker.py +1 -1
- package/hooks/blocking/stop_dispatcher.py +1 -1
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +2 -3
- package/hooks/blocking/test_code_review_pr_create_gate.py +14 -0
- package/hooks/blocking/test_code_review_push_gate.py +16 -0
- package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +19 -0
- package/hooks/blocking/test_eli11_reply_enforcer.py +457 -0
- package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +10 -1
- package/hooks/blocking/test_shell_substitution_blocker.py +124 -0
- package/hooks/blocking/test_stop_dispatcher.py +23 -0
- package/hooks/blocking/test_unscoped_search_blocker.py +102 -0
- package/hooks/blocking/test_verdict_directory_write_blocker.py +804 -808
- package/hooks/blocking/test_verification_verdict_store.py +54 -0
- package/hooks/blocking/test_verified_commit_gate.py +581 -581
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
- package/hooks/blocking/unscoped_search_blocker.py +391 -0
- package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
- package/hooks/blocking/verification_verdict_store.py +1039 -1036
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
- package/hooks/blocking/verifier_verdict_minter.py +280 -280
- package/hooks/git-hooks/CLAUDE.md +3 -0
- package/hooks/git-hooks/conftest.py +30 -0
- package/hooks/git-hooks/gate_utils.py +2 -2
- package/hooks/git-hooks/git_hooks_constants/__init__.py +41 -2
- package/hooks/git-hooks/pre_push.py +75 -4
- package/hooks/git-hooks/pre_push_base_reference.py +166 -0
- package/hooks/git-hooks/test_config.py +0 -15
- package/hooks/git-hooks/test_gate_utils.py +3 -15
- package/hooks/git-hooks/test_pre_commit.py +1 -15
- package/hooks/git-hooks/test_pre_push.py +257 -23
- package/hooks/git-hooks/test_pre_push_base_reference.py +339 -0
- package/hooks/hooks.json +10 -12
- package/hooks/hooks_constants/CLAUDE.md +7 -2
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +4 -4
- package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +101 -0
- package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
- package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +2 -8
- package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
- package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
- package/hooks/hooks_constants/shell_command_segments.py +82 -0
- package/hooks/hooks_constants/shell_substitution_blocker_constants.py +67 -0
- package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -0
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +5 -6
- package/hooks/hooks_constants/test_stop_dispatcher_constants.py +1 -0
- package/hooks/hooks_constants/unscoped_search_blocker_constants.py +153 -0
- package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
- package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
- package/hooks/pyproject.toml +1 -0
- package/hooks/validators/CLAUDE.md +1 -0
- package/hooks/validators/config/__init__.py +0 -0
- package/hooks/validators/config/directory_exemption_constants.py +183 -0
- package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
- package/hooks/validators/conftest.py +4 -0
- package/hooks/validators/ruff_integration.py +49 -5
- package/hooks/validators/run_all_validators.py +206 -9
- package/hooks/validators/test_directory_exemption_constants.py +185 -0
- package/hooks/validators/test_python_antipattern_checks.py +110 -5
- package/hooks/validators/test_ruff_integration.py +92 -1
- package/hooks/validators/test_run_all_validators.py +115 -68
- package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
- package/package.json +13 -3
- package/rules/CLAUDE.md +17 -22
- package/rules/agent-spawn-protocol.md +6 -6
- package/rules/anti-corollary-tests.md +1 -1
- package/rules/bdd.md +1 -1
- package/rules/cleanup-temp-files.md +10 -4
- package/rules/code-standards.md +7 -0
- package/rules/conservative-action.md +1 -5
- package/rules/context7.md +0 -4
- package/rules/destructive-commands.md +47 -0
- package/rules/doc-inventory-integrity.md +48 -0
- package/rules/doc-prose-cuts.md +58 -0
- package/rules/docstring-prose-matches-implementation.md +53 -44
- package/rules/durable-post-artifacts.md +0 -4
- package/rules/eli11-replies.md +31 -0
- package/rules/explore-thoroughly.md +4 -4
- package/rules/falsify-before-green.md +68 -0
- package/rules/file-global-constants.md +1 -1
- package/rules/filesystem-search.md +51 -0
- package/rules/gh-cli-conventions.md +27 -0
- package/rules/git-workflow.md +26 -0
- package/rules/hedging-claims.md +9 -0
- package/rules/long-horizon-autonomy.md +0 -4
- package/rules/measurement-denominators.md +48 -0
- package/rules/nas-ssh-invocation.md +23 -5
- package/rules/parallel-tools.md +2 -2
- package/rules/plain-illustrative-docstrings.md +3 -7
- package/rules/plain-language.md +2 -0
- package/rules/proof-of-work-pr-comments.md +0 -4
- package/rules/re-stage-before-commit.md +2 -0
- package/rules/research-mode.md +10 -0
- package/rules/shell-invocation.md +21 -0
- package/rules/testing.md +4 -0
- package/rules/verified-commit-gate-skip.md +3 -27
- package/rules/verify-before-asking.md +5 -0
- package/rules/windows-filesystem-safe.md +1 -1
- package/rules/workers-done-before-complete.md +4 -0
- package/scripts/CLAUDE.md +1 -0
- package/scripts/Capture-PoolHealth.ps1 +410 -0
- package/scripts/Migrate-ShellPolicy.ps1 +1 -1
- package/scripts/_code_review_test_support.py +404 -0
- package/scripts/claude_chain_runner.py +141 -1
- package/scripts/codex_capability_bridge.py +171 -0
- package/scripts/codex_compat_materializer.py +1087 -0
- package/scripts/codex_compat_watcher.py +502 -0
- package/scripts/conftest.py +16 -1
- package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -1
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +9 -0
- package/scripts/dev_env_scripts_constants/code_review_constants.py +37 -0
- package/scripts/invoke_code_review.py +11 -4
- package/scripts/resolve_worker_spawn.py +626 -626
- package/scripts/spawn_grok_batch.py +672 -672
- package/scripts/sync_to_cursor/rules.py +0 -10
- package/scripts/test_claude_chain_runner.py +131 -0
- package/scripts/test_invoke_code_review.py +85 -908
- package/scripts/test_invoke_code_review_chain.py +70 -0
- package/scripts/test_invoke_code_review_cli.py +192 -0
- package/scripts/test_invoke_code_review_contract.py +256 -0
- package/scripts/test_invoke_code_review_git.py +123 -0
- package/scripts/test_invoke_code_review_mode.py +99 -0
- package/scripts/test_resolve_worker_spawn.py +1014 -1014
- package/scripts/tests/test_code_review_constants.py +80 -0
- package/scripts/tests/test_codex_capability_bridge.py +91 -0
- package/scripts/tests/test_codex_compat_materializer.py +632 -0
- package/scripts/tests/test_codex_compat_watcher.py +599 -0
- package/scripts/tests/test_sync_to_cursor.py +0 -1
- package/skills/CLAUDE.md +2 -0
- package/skills/auditing-claude-config/SKILL.md +114 -114
- package/skills/autoconverge/SKILL.md +427 -427
- package/skills/autoconverge/reference/convergence.md +24 -3
- package/skills/autoconverge/workflow/CLAUDE.md +1 -0
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +3 -3
- package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1263
- package/skills/autoconverge/workflow/converge.mjs +168 -1
- package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
- package/skills/bugteam/reference/copilot-gap-analysis.md +1 -1
- package/skills/closeout/SKILL.md +33 -50
- package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
- package/skills/codex-review/scripts/run_codex_review.py +233 -1
- package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
- package/skills/condensing-instructions/SKILL.md +72 -0
- package/skills/copilot-review/SKILL.md +119 -119
- package/skills/e-code-review/SKILL.md +52 -0
- package/skills/e-code-review/reference/fix.md +54 -0
- package/skills/e-code-review/reference/loop.md +43 -0
- package/skills/e-code-review/reference/low.md +57 -0
- package/skills/e-code-review/reference/medium.md +153 -0
- package/skills/e-code-review/reference/xhigh.md +182 -0
- package/skills/e-simplify/SKILL.md +97 -0
- package/skills/fresh-branch/CLAUDE.md +1 -1
- package/skills/fresh-branch/SKILL.md +5 -6
- package/skills/fresh-branch/scripts/create_fresh_branch.py +42 -24
- package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -3
- package/skills/fresh-branch/scripts/test_create_fresh_branch.py +30 -126
- package/skills/issue-tracker/SKILL.md +92 -0
- package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
- package/skills/issue-tracker/reference/handoff-schema.md +64 -0
- package/skills/issue-tracker/reference/operation-matrix.md +41 -0
- package/skills/orchestrator/SKILL.md +177 -22
- package/skills/orchestrator/scripts/status_gate.py +625 -0
- package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
- package/skills/orchestrator/scripts/test_status_gate.py +439 -0
- package/skills/orchestrator-refresh/SKILL.md +129 -35
- package/skills/plan-to-pr/SKILL.md +155 -0
- package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
- package/skills/plan-to-pr/reference/model-routing.md +36 -0
- package/skills/plan-to-pr/reference/packet-contract.md +43 -0
- package/skills/plan-to-pr/reference/packet-schema.json +57 -0
- package/skills/plan-to-pr/reference/process-inventory.md +22 -0
- package/skills/plan-to-pr/reference/review-loop.md +33 -0
- package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
- package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
- package/skills/plan-to-pr/reference/task-seeds.md +14 -0
- package/skills/plan-to-pr/reference/task-ticket.md +38 -0
- package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
- package/skills/plan-to-pr/scripts/config/constants.py +193 -0
- package/skills/plan-to-pr/scripts/create_packet.py +173 -0
- package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
- package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
- package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
- package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
- package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
- package/skills/plan-to-pr/scripts/validate_run.py +173 -0
- package/skills/plan-to-pr/test_skill_contract.py +207 -0
- package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
- package/skills/pr-converge/SKILL.md +472 -469
- package/skills/pr-converge/reference/examples.md +3 -3
- package/skills/pr-converge/reference/fix-protocol.md +1 -1
- package/skills/pr-converge/reference/ground-rules.md +7 -4
- package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
- package/skills/pr-converge/reference/per-tick.md +5 -5
- package/skills/pr-converge/reference/progress-checklist.md +1 -1
- package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
- package/skills/pr-converge/test_step5_host_branch.py +1 -1
- package/skills/pr-fix-protocol/SKILL.md +1 -1
- package/skills/privacy-hygiene/SKILL.md +68 -68
- package/skills/privacy-hygiene/reference/sweep-procedure.md +1 -1
- package/skills/prototype/workflows/promotion.md +1 -1
- package/skills/release-notes-html/SKILL.md +164 -0
- package/skills/session-log/SKILL.md +1 -1
- package/skills/task-build/CLAUDE.md +8 -7
- package/skills/task-build/SKILL.md +16 -8
- package/skills/task-build/reference/tool-routing.md +19 -0
- package/rules/claude-md-orphan-file.md +0 -28
- package/rules/cleanup-command-forms.md +0 -23
- package/rules/code-reviews.md +0 -11
- package/rules/env-var-table-code-drift.md +0 -10
- package/rules/gh-body-file.md +0 -5
- package/rules/gh-paginate.md +0 -3
- package/rules/hook-prose-matches-detector.md +0 -15
- package/rules/no-historical-clutter.md +0 -26
- package/rules/no-inline-destructive-literals.md +0 -9
- package/rules/no-justification-noise.md +0 -61
- package/rules/package-inventory-stale-entry.md +0 -25
- package/rules/right-sized-engineering.md +0 -28
- package/rules/self-contained-docs.md +0 -17
- package/rules/shell-invocation-policy.md +0 -5
- package/rules/tdd.md +0 -7
- package/skills/closeout/reference/issue-body-templates.md +0 -108
|
@@ -59,7 +59,6 @@ def _strip_code_standards_blockquote(markdown: str) -> str:
|
|
|
59
59
|
_merged_mapping_key_order = (
|
|
60
60
|
"code-standards",
|
|
61
61
|
"tasklings-preferences",
|
|
62
|
-
"right-sized-engineering",
|
|
63
62
|
"bdd",
|
|
64
63
|
"test-quality",
|
|
65
64
|
"research-mode",
|
|
@@ -350,15 +349,6 @@ def _always_apply_mappings(rules_directory: Path, docs_directory: Path) -> tuple
|
|
|
350
349
|
"Core code standards: naming, types, config, hook-enforced rules",
|
|
351
350
|
"merge_code_standards",
|
|
352
351
|
),
|
|
353
|
-
RuleMapping(
|
|
354
|
-
"right-sized-engineering",
|
|
355
|
-
(rules_directory / "right-sized-engineering.md",),
|
|
356
|
-
"right-sized-engineering.mdc",
|
|
357
|
-
True,
|
|
358
|
-
None,
|
|
359
|
-
"Right-sized engineering and complexity budget",
|
|
360
|
-
"verbatim",
|
|
361
|
-
),
|
|
362
352
|
RuleMapping(
|
|
363
353
|
"bdd",
|
|
364
354
|
(rules_directory / "bdd.md",),
|
|
@@ -30,6 +30,7 @@ from dev_env_scripts_constants.claude_chain_constants import ( # noqa: E402
|
|
|
30
30
|
CLAUDE_HOME_SUBDIRECTORY,
|
|
31
31
|
CLI_ARGUMENTS_SEPARATOR,
|
|
32
32
|
CLI_TIMEOUT_FLAG,
|
|
33
|
+
CODEC_ERROR_STRATEGY,
|
|
33
34
|
CONFIG_CHAIN_EMPTY_REASON,
|
|
34
35
|
CONFIG_CHAIN_KEY,
|
|
35
36
|
CONFIG_CHAIN_NOT_LIST_REASON,
|
|
@@ -50,6 +51,14 @@ from dev_env_scripts_constants.claude_chain_constants import ( # noqa: E402
|
|
|
50
51
|
UTF8_ENCODING,
|
|
51
52
|
)
|
|
52
53
|
|
|
54
|
+
_LARGE_CAPTURE_BYTE_COUNT = 400_000
|
|
55
|
+
_LARGE_CAPTURE_MARKER = "X"
|
|
56
|
+
_STDIN_ECHO_PAYLOAD = "charter body for spool path"
|
|
57
|
+
_UNDECODABLE_STDOUT_BYTES = b"ok \x90 end"
|
|
58
|
+
_DECODED_UNDECODABLE_STDOUT = "ok \ufffd end"
|
|
59
|
+
_CRLF_CHILD_STDOUT_BYTES = b"a\r\nb\rc\n"
|
|
60
|
+
_CRLF_CHILD_STDOUT_NORMALIZED = "a\nb\nc\n"
|
|
61
|
+
|
|
53
62
|
_A_SIGNATURE = ALL_USAGE_LIMIT_SIGNATURES[0]
|
|
54
63
|
_PROMPT_ARGUMENTS = ["-p", "hello"]
|
|
55
64
|
_EQUAL_WEEKLY_REMAINING_PERCENT = 50.0
|
|
@@ -955,6 +964,128 @@ def test_real_subprocess_capture_preserves_utf8_text(
|
|
|
955
964
|
assert chain_result.stdout == "report ✅ done"
|
|
956
965
|
|
|
957
966
|
|
|
967
|
+
def test_run_captured_subprocess_spools_large_stdout_and_stderr() -> None:
|
|
968
|
+
child_code = (
|
|
969
|
+
"import sys;"
|
|
970
|
+
f"sys.stdout.write({_LARGE_CAPTURE_MARKER!r} * {_LARGE_CAPTURE_BYTE_COUNT});"
|
|
971
|
+
"sys.stderr.write('err-marker');"
|
|
972
|
+
"sys.exit(3)"
|
|
973
|
+
)
|
|
974
|
+
completion = runner._run_captured_subprocess(
|
|
975
|
+
[sys.executable, "-c", child_code],
|
|
976
|
+
encoding=UTF8_ENCODING,
|
|
977
|
+
errors=CODEC_ERROR_STRATEGY,
|
|
978
|
+
timeout=60,
|
|
979
|
+
check=False,
|
|
980
|
+
input=None,
|
|
981
|
+
)
|
|
982
|
+
assert completion.returncode == 3
|
|
983
|
+
assert len(completion.stdout) == _LARGE_CAPTURE_BYTE_COUNT
|
|
984
|
+
assert completion.stdout == _LARGE_CAPTURE_MARKER * _LARGE_CAPTURE_BYTE_COUNT
|
|
985
|
+
assert completion.stderr == "err-marker"
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
def test_run_captured_subprocess_forwards_stdin_input() -> None:
|
|
989
|
+
child_code = "import sys; sys.stdout.write(sys.stdin.read())"
|
|
990
|
+
completion = runner._run_captured_subprocess(
|
|
991
|
+
[sys.executable, "-c", child_code],
|
|
992
|
+
encoding=UTF8_ENCODING,
|
|
993
|
+
errors=CODEC_ERROR_STRATEGY,
|
|
994
|
+
timeout=60,
|
|
995
|
+
check=False,
|
|
996
|
+
input=_STDIN_ECHO_PAYLOAD,
|
|
997
|
+
)
|
|
998
|
+
assert completion.returncode == 0
|
|
999
|
+
assert completion.stdout == _STDIN_ECHO_PAYLOAD
|
|
1000
|
+
assert completion.stderr == ""
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
def test_run_captured_subprocess_replaces_undecodable_stdout_bytes() -> None:
|
|
1004
|
+
child_code = (
|
|
1005
|
+
"import sys;"
|
|
1006
|
+
f"sys.stdout.buffer.write({_UNDECODABLE_STDOUT_BYTES!r})"
|
|
1007
|
+
)
|
|
1008
|
+
completion = runner._run_captured_subprocess(
|
|
1009
|
+
[sys.executable, "-c", child_code],
|
|
1010
|
+
encoding=UTF8_ENCODING,
|
|
1011
|
+
errors=CODEC_ERROR_STRATEGY,
|
|
1012
|
+
timeout=60,
|
|
1013
|
+
check=False,
|
|
1014
|
+
input=None,
|
|
1015
|
+
)
|
|
1016
|
+
assert completion.returncode == 0
|
|
1017
|
+
assert completion.stdout == _DECODED_UNDECODABLE_STDOUT
|
|
1018
|
+
|
|
1019
|
+
|
|
1020
|
+
def test_run_captured_subprocess_normalizes_crlf_to_lf() -> None:
|
|
1021
|
+
"""Spool decode matches subprocess text=True universal-newline translation."""
|
|
1022
|
+
child_code = (
|
|
1023
|
+
"import sys;"
|
|
1024
|
+
f"sys.stdout.buffer.write({_CRLF_CHILD_STDOUT_BYTES!r})"
|
|
1025
|
+
)
|
|
1026
|
+
completion = runner._run_captured_subprocess(
|
|
1027
|
+
[sys.executable, "-c", child_code],
|
|
1028
|
+
encoding=UTF8_ENCODING,
|
|
1029
|
+
errors=CODEC_ERROR_STRATEGY,
|
|
1030
|
+
timeout=60,
|
|
1031
|
+
check=False,
|
|
1032
|
+
input=None,
|
|
1033
|
+
)
|
|
1034
|
+
assert completion.returncode == 0
|
|
1035
|
+
assert completion.stdout == _CRLF_CHILD_STDOUT_NORMALIZED
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
def test_run_captured_subprocess_honors_cwd(tmp_path: Path) -> None:
|
|
1039
|
+
child_code = "import os, sys; sys.stdout.write(os.getcwd())"
|
|
1040
|
+
completion = runner._run_captured_subprocess(
|
|
1041
|
+
[sys.executable, "-c", child_code],
|
|
1042
|
+
encoding=UTF8_ENCODING,
|
|
1043
|
+
errors=CODEC_ERROR_STRATEGY,
|
|
1044
|
+
timeout=60,
|
|
1045
|
+
check=False,
|
|
1046
|
+
cwd=str(tmp_path),
|
|
1047
|
+
)
|
|
1048
|
+
assert completion.returncode == 0
|
|
1049
|
+
assert Path(completion.stdout).resolve() == tmp_path.resolve()
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
def test_run_captured_subprocess_timeout_keeps_partial_stdout() -> None:
|
|
1053
|
+
child_code = (
|
|
1054
|
+
"import sys, time;"
|
|
1055
|
+
"sys.stdout.write('partial-before-timeout');"
|
|
1056
|
+
"sys.stdout.flush();"
|
|
1057
|
+
"time.sleep(30)"
|
|
1058
|
+
)
|
|
1059
|
+
with pytest.raises(subprocess.TimeoutExpired) as raised:
|
|
1060
|
+
runner._run_captured_subprocess(
|
|
1061
|
+
[sys.executable, "-c", child_code],
|
|
1062
|
+
encoding=UTF8_ENCODING,
|
|
1063
|
+
errors=CODEC_ERROR_STRATEGY,
|
|
1064
|
+
timeout=1,
|
|
1065
|
+
check=False,
|
|
1066
|
+
input=None,
|
|
1067
|
+
)
|
|
1068
|
+
assert raised.value.stdout == "partial-before-timeout"
|
|
1069
|
+
assert isinstance(raised.value.stdout, str)
|
|
1070
|
+
|
|
1071
|
+
|
|
1072
|
+
def test_run_captured_subprocess_reads_stdin_stream(tmp_path: Path) -> None:
|
|
1073
|
+
prompt_path = tmp_path / "prompt_body.txt"
|
|
1074
|
+
prompt_path.write_text(_STDIN_ECHO_PAYLOAD, encoding=UTF8_ENCODING)
|
|
1075
|
+
child_code = "import sys; sys.stdout.write(sys.stdin.read())"
|
|
1076
|
+
with prompt_path.open(encoding=UTF8_ENCODING) as prompt_stream:
|
|
1077
|
+
completion = runner._run_captured_subprocess(
|
|
1078
|
+
[sys.executable, "-c", child_code],
|
|
1079
|
+
encoding=UTF8_ENCODING,
|
|
1080
|
+
errors=CODEC_ERROR_STRATEGY,
|
|
1081
|
+
timeout=60,
|
|
1082
|
+
check=False,
|
|
1083
|
+
stdin=prompt_stream,
|
|
1084
|
+
)
|
|
1085
|
+
assert completion.returncode == 0
|
|
1086
|
+
assert completion.stdout == _STDIN_ECHO_PAYLOAD
|
|
1087
|
+
|
|
1088
|
+
|
|
958
1089
|
def test_cli_emits_utf8_when_console_encoding_is_legacy(tmp_path: Path) -> None:
|
|
959
1090
|
tmp_home = tmp_path / "home"
|
|
960
1091
|
claude_directory = tmp_home / CLAUDE_HOME_SUBDIRECTORY
|