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
|
@@ -14,4 +14,4 @@ In Node, call `mkdirSync(targetPath, { recursive: true })` on possibly-existing
|
|
|
14
14
|
|
|
15
15
|
The `windows_rmtree_blocker.py` PreToolUse hook (Write/Edit/Bash) blocks the unsafe rmtree pattern and returns the full `force_rmtree` safe-pattern code.
|
|
16
16
|
|
|
17
|
-
Define the safe handler trio (`_strip_read_only_and_retry`, `_force_remove_tree` / `force_rmtree`, and the `inspect.signature` onexc/onerror guard) once in a shared Windows-filesystem utility module, and import it from every call site. A second local copy drifts from the first — a fix lands in one and the other keeps the bug (CODE_RULES.md
|
|
17
|
+
Define the safe handler trio (`_strip_read_only_and_retry`, `_force_remove_tree` / `force_rmtree`, and the `inspect.signature` onexc/onerror guard) once in a shared Windows-filesystem utility module, and import it from every call site. A second local copy drifts from the first — a fix lands in one and the other keeps the bug (CODE_RULES.md, CORE PRINCIPLES — "Reuse before create"). The `duplicate_rmtree_helper_blocker.py` PreToolUse hook (Write/Edit) blocks a local re-definition of any trio member outside the shared home and points the writer at the import. This complements the same-directory `check_duplicate_function_body_across_files` gate, which a copy between two distant packages slips past.
|
|
@@ -2,4 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Before marking a task `completed` that spawned workers — subagents, workflow agents, or background shells — confirm both: every worker has finished, and each worker's result is merged into run state (`state.json`, `pr-converge-state.json`, the task list, or whatever record the task keeps). A worker still running, or one whose output never landed in run state, keeps the task `in_progress`: list the live workers, report any dead or hung one as a finding rather than dropping it in silence, and schedule a wakeup so the run picks the workers back up before the task closes.
|
|
4
4
|
|
|
5
|
+
This rule gates a task's status, not your own work. It never says wait before acting: keep working while a worker runs, and hold only the `completed` mark until the worker's result has landed.
|
|
6
|
+
|
|
7
|
+
Verify every sub-agent file list, count, description, and finding against the repository and the diff before you merge it into run state or repeat it to the user.
|
|
8
|
+
|
|
5
9
|
Checklist, examples, and run-state detail: `@~/.claude/docs/worker-completion-gate.md`.
|
package/scripts/CLAUDE.md
CHANGED
|
@@ -27,6 +27,7 @@ Utility scripts installed into `~/.claude/scripts/` by `bin/install.mjs`. Each s
|
|
|
27
27
|
| `check.ps1` | Runs the full code-quality check suite |
|
|
28
28
|
| `Show-Asset.ps1` | Opens files on screen, sizing each image window to the image's pixel dimensions (scaled to fit the screen); non-image files open in their default application |
|
|
29
29
|
| `Get-SessionAccount.ps1` | Reports which Claude account the current session is actually logged into by comparing `~/.claude.json`'s CLI login against a `CLAUDE_USER_DATA_DIR` desktop profile's `lastKnownAccountUuid`, recovering the desktop account's email from profile storage when the two accounts differ |
|
|
30
|
+
| `Capture-PoolHealth.ps1` | Captures Windows memory pool counters, high-handle processes, and kernel pool tags (via `NtQuerySystemInformation` class 22), prints a threshold verdict with a remediation map, and exits non-zero when any alert threshold fires |
|
|
30
31
|
|
|
31
32
|
## Subdirectories
|
|
32
33
|
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Captures Windows pool counters, handle pressure, and kernel pool tags for host health checks.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Reads memory pool counters, total handle/thread counts, processes over the handle alert
|
|
7
|
+
threshold, and top kernel pool tags via NtQuerySystemInformation (class 22). Prints a
|
|
8
|
+
threshold verdict so an operator can re-run the same recipe from a clean shell.
|
|
9
|
+
|
|
10
|
+
Alert thresholds (defaults):
|
|
11
|
+
- Pool Nonpaged Bytes > 2 GB
|
|
12
|
+
- Any process Handles > 2000
|
|
13
|
+
- Process(_Total) handles > 500000
|
|
14
|
+
|
|
15
|
+
Attribution context (evidence pack results/04-pool-tags.md): dominant tags File (nonpaged)
|
|
16
|
+
and Toke (paged) mean process-object / object-manager pressure. Remediate via RC2 (MCP
|
|
17
|
+
lifecycle), RC3 (Show-Asset orphans), RC4 (Git find handle storms) — not a single driver.
|
|
18
|
+
|
|
19
|
+
.PARAMETER TopTagCount
|
|
20
|
+
How many pool tags to print per nonpaged and paged ranking. Default 20.
|
|
21
|
+
|
|
22
|
+
.PARAMETER TopProcessCount
|
|
23
|
+
How many high-handle processes to list. Default 15.
|
|
24
|
+
|
|
25
|
+
.PARAMETER OutPath
|
|
26
|
+
Optional file path. When set, the full report is also written there as UTF-8 text.
|
|
27
|
+
|
|
28
|
+
.PARAMETER NonpagedAlertBytes
|
|
29
|
+
Nonpaged pool alert threshold in bytes. Default 2147483648 (2 GB).
|
|
30
|
+
|
|
31
|
+
.PARAMETER ProcessHandleAlert
|
|
32
|
+
Per-process handle alert threshold. Default 2000.
|
|
33
|
+
|
|
34
|
+
.PARAMETER TotalHandleAlert
|
|
35
|
+
System-wide handle alert threshold. Default 500000.
|
|
36
|
+
|
|
37
|
+
.EXAMPLE
|
|
38
|
+
pwsh -NoProfile -File "$HOME\.claude\scripts\Capture-PoolHealth.ps1"
|
|
39
|
+
|
|
40
|
+
.EXAMPLE
|
|
41
|
+
pwsh -NoProfile -File .\Capture-PoolHealth.ps1 -OutPath "$env:TEMP\pool-health.txt"
|
|
42
|
+
#>
|
|
43
|
+
[CmdletBinding()]
|
|
44
|
+
param(
|
|
45
|
+
[int]$TopTagCount = 20,
|
|
46
|
+
[int]$TopProcessCount = 15,
|
|
47
|
+
[string]$OutPath = '',
|
|
48
|
+
[long]$NonpagedAlertBytes = 2147483648,
|
|
49
|
+
[int]$ProcessHandleAlert = 2000,
|
|
50
|
+
[int]$TotalHandleAlert = 500000
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
Set-StrictMode -Version Latest
|
|
54
|
+
$ErrorActionPreference = 'Stop'
|
|
55
|
+
|
|
56
|
+
$script:ReportLines = [System.Collections.Generic.List[string]]::new()
|
|
57
|
+
|
|
58
|
+
function Write-ReportLine {
|
|
59
|
+
param([string]$Text = '')
|
|
60
|
+
$script:ReportLines.Add($Text)
|
|
61
|
+
Write-Output $Text
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function Format-BytesAsGigabytes {
|
|
65
|
+
param([long]$ByteCount)
|
|
66
|
+
return ('{0:N3} GB' -f ($ByteCount / 1GB))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function Get-MemoryAndHandleCounters {
|
|
70
|
+
# One source of truth for the counters: request order and lookup key both
|
|
71
|
+
# derive from this map, so a name never has to be restated at the call site.
|
|
72
|
+
$counterPathByName = [ordered]@{
|
|
73
|
+
NonpagedBytes = '\Memory\Pool Nonpaged Bytes'
|
|
74
|
+
PagedBytes = '\Memory\Pool Paged Bytes'
|
|
75
|
+
CommittedBytes = '\Memory\Committed Bytes'
|
|
76
|
+
CommitLimit = '\Memory\Commit Limit'
|
|
77
|
+
AvailableMBytes = '\Memory\Available MBytes'
|
|
78
|
+
TotalHandles = '\Process(_Total)\Handle Count'
|
|
79
|
+
TotalThreads = '\Process(_Total)\Thread Count'
|
|
80
|
+
}
|
|
81
|
+
$sample = Get-Counter -Counter @($counterPathByName.Values) -ErrorAction Stop
|
|
82
|
+
$valueByName = @{}
|
|
83
|
+
$index = 0
|
|
84
|
+
foreach ($eachName in $counterPathByName.Keys) {
|
|
85
|
+
$valueByName[$eachName] = [int64]$sample.CounterSamples[$index++].CookedValue
|
|
86
|
+
}
|
|
87
|
+
return $valueByName
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function Get-HighHandleProcessReport {
|
|
91
|
+
param(
|
|
92
|
+
[int]$HandleThreshold,
|
|
93
|
+
[int]$MaximumRows
|
|
94
|
+
)
|
|
95
|
+
$allHotProcesses = @(
|
|
96
|
+
Get-Process -ErrorAction SilentlyContinue |
|
|
97
|
+
Where-Object { $_.HandleCount -gt $HandleThreshold } |
|
|
98
|
+
Sort-Object -Property HandleCount -Descending
|
|
99
|
+
)
|
|
100
|
+
$topProcesses = @($allHotProcesses | Select-Object -First $MaximumRows)
|
|
101
|
+
$cimByProcessId = @{}
|
|
102
|
+
if ($topProcesses.Count -gt 0) {
|
|
103
|
+
$processIdFilter = @($topProcesses | ForEach-Object { "ProcessId=$($_.Id)" }) -join ' OR '
|
|
104
|
+
try {
|
|
105
|
+
foreach ($eachCimProcess in @(
|
|
106
|
+
Get-CimInstance -ClassName Win32_Process -Filter $processIdFilter `
|
|
107
|
+
-ErrorAction SilentlyContinue)) {
|
|
108
|
+
$cimByProcessId[[int]$eachCimProcess.ProcessId] = $eachCimProcess
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
$null = $_
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
$topRows = foreach ($eachProcess in $topProcesses) {
|
|
116
|
+
$commandLine = ''
|
|
117
|
+
$parentProcessId = 0
|
|
118
|
+
$cimProcess = $cimByProcessId[[int]$eachProcess.Id]
|
|
119
|
+
if ($cimProcess) {
|
|
120
|
+
$commandLine = [string]$cimProcess.CommandLine
|
|
121
|
+
$parentProcessId = [int]$cimProcess.ParentProcessId
|
|
122
|
+
}
|
|
123
|
+
[pscustomobject]@{
|
|
124
|
+
ProcessId = $eachProcess.Id
|
|
125
|
+
Name = $eachProcess.ProcessName
|
|
126
|
+
HandleCount = $eachProcess.HandleCount
|
|
127
|
+
ParentProcessId = $parentProcessId
|
|
128
|
+
CommandLine = $commandLine
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return [pscustomobject]@{
|
|
132
|
+
TotalCount = $allHotProcesses.Count
|
|
133
|
+
TopRows = @($topRows)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function Ensure-PoolTagCaptureType {
|
|
138
|
+
if ('PoolTagCapture' -as [type]) {
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
$source = @'
|
|
142
|
+
using System;
|
|
143
|
+
using System.Collections.Generic;
|
|
144
|
+
using System.Linq;
|
|
145
|
+
using System.Runtime.InteropServices;
|
|
146
|
+
using System.Text;
|
|
147
|
+
|
|
148
|
+
public static class PoolTagCapture {
|
|
149
|
+
const int SystemPoolTagInformation = 22;
|
|
150
|
+
|
|
151
|
+
[DllImport("ntdll.dll")]
|
|
152
|
+
static extern int NtQuerySystemInformation(
|
|
153
|
+
int systemInformationClass,
|
|
154
|
+
IntPtr systemInformation,
|
|
155
|
+
int systemInformationLength,
|
|
156
|
+
out int returnLength);
|
|
157
|
+
|
|
158
|
+
[StructLayout(LayoutKind.Explicit, Size = 40)]
|
|
159
|
+
struct SYSTEM_POOLTAG {
|
|
160
|
+
[FieldOffset(0)] public byte Tag0;
|
|
161
|
+
[FieldOffset(1)] public byte Tag1;
|
|
162
|
+
[FieldOffset(2)] public byte Tag2;
|
|
163
|
+
[FieldOffset(3)] public byte Tag3;
|
|
164
|
+
[FieldOffset(4)] public uint PagedAllocs;
|
|
165
|
+
[FieldOffset(8)] public uint PagedFrees;
|
|
166
|
+
[FieldOffset(16)] public ulong PagedUsed;
|
|
167
|
+
[FieldOffset(24)] public uint NonPagedAllocs;
|
|
168
|
+
[FieldOffset(28)] public uint NonPagedFrees;
|
|
169
|
+
[FieldOffset(32)] public ulong NonPagedUsed;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public static string Capture(int topN) {
|
|
173
|
+
int size = 2 * 1024 * 1024;
|
|
174
|
+
int retLen = 0;
|
|
175
|
+
int status = -1;
|
|
176
|
+
IntPtr buffer = IntPtr.Zero;
|
|
177
|
+
try {
|
|
178
|
+
for (int attempt = 0; attempt < 10; attempt++) {
|
|
179
|
+
buffer = Marshal.AllocHGlobal(size);
|
|
180
|
+
status = NtQuerySystemInformation(
|
|
181
|
+
SystemPoolTagInformation, buffer, size, out retLen);
|
|
182
|
+
if (unchecked((uint)status) == 0xC0000004u) {
|
|
183
|
+
Marshal.FreeHGlobal(buffer);
|
|
184
|
+
buffer = IntPtr.Zero;
|
|
185
|
+
size = Math.Max(retLen + 8192, size * 2);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
if (status != 0) {
|
|
191
|
+
return "NTSTATUS=0x" + unchecked((uint)status).ToString("X8")
|
|
192
|
+
+ " retLen=" + retLen;
|
|
193
|
+
}
|
|
194
|
+
int count = Marshal.ReadInt32(buffer);
|
|
195
|
+
int baseOff = 8;
|
|
196
|
+
var tags = new List<SYSTEM_POOLTAG>();
|
|
197
|
+
for (int i = 0; i < count; i++) {
|
|
198
|
+
int offset = baseOff + i * 40;
|
|
199
|
+
if (offset + 40 > retLen) break;
|
|
200
|
+
tags.Add(Marshal.PtrToStructure<SYSTEM_POOLTAG>(
|
|
201
|
+
IntPtr.Add(buffer, offset)));
|
|
202
|
+
}
|
|
203
|
+
long sumNonPaged = 0;
|
|
204
|
+
long sumPaged = 0;
|
|
205
|
+
foreach (var eachTag in tags) {
|
|
206
|
+
sumNonPaged += (long)eachTag.NonPagedUsed;
|
|
207
|
+
sumPaged += (long)eachTag.PagedUsed;
|
|
208
|
+
}
|
|
209
|
+
var report = new StringBuilder();
|
|
210
|
+
report.AppendLine("retLen=" + retLen + " count=" + count
|
|
211
|
+
+ " sizeof_tag=40 status=0 baseOff=" + baseOff);
|
|
212
|
+
report.AppendLine(string.Format(
|
|
213
|
+
"SUM NonPaged={0} ({1:N3} GB) Paged={2} ({3:N3} GB)",
|
|
214
|
+
sumNonPaged, sumNonPaged / 1073741824.0,
|
|
215
|
+
sumPaged, sumPaged / 1073741824.0));
|
|
216
|
+
report.AppendLine(string.Format(
|
|
217
|
+
"{0,-6} {1,14} {2,14}", "Tag", "NonPaged", "Paged"));
|
|
218
|
+
report.AppendLine("--- TOP BY NONPAGED ---");
|
|
219
|
+
foreach (var eachTag in tags.OrderByDescending(t => t.NonPagedUsed).Take(topN)) {
|
|
220
|
+
report.AppendLine(FormatTag(eachTag));
|
|
221
|
+
}
|
|
222
|
+
report.AppendLine("--- TOP BY PAGED ---");
|
|
223
|
+
foreach (var eachTag in tags.OrderByDescending(t => t.PagedUsed).Take(topN)) {
|
|
224
|
+
report.AppendLine(FormatTag(eachTag));
|
|
225
|
+
}
|
|
226
|
+
var watchTagNames = new[] { "File", "IoFE", "Toke", "Key", "FMfn" };
|
|
227
|
+
var watchNames = new HashSet<string>(watchTagNames, StringComparer.Ordinal);
|
|
228
|
+
report.AppendLine("--- WATCHLIST " + string.Join(" ", watchTagNames) + " ---");
|
|
229
|
+
foreach (var eachTag in tags) {
|
|
230
|
+
string cleanedName = TagName(eachTag).TrimEnd(' ', '.', '\0');
|
|
231
|
+
if (watchNames.Contains(cleanedName)) {
|
|
232
|
+
report.AppendLine(FormatTag(eachTag));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return report.ToString().TrimEnd();
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
if (buffer != IntPtr.Zero) {
|
|
239
|
+
Marshal.FreeHGlobal(buffer);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
static string TagName(SYSTEM_POOLTAG tag) {
|
|
245
|
+
return string.Concat(CharOf(tag.Tag0), CharOf(tag.Tag1),
|
|
246
|
+
CharOf(tag.Tag2), CharOf(tag.Tag3));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
static char CharOf(byte value) {
|
|
250
|
+
return (value >= 32 && value < 127) ? (char)value : '.';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
static string FormatTag(SYSTEM_POOLTAG tag) {
|
|
254
|
+
return string.Format("{0,-6} {1,14} {2,14}",
|
|
255
|
+
TagName(tag), tag.NonPagedUsed, tag.PagedUsed);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
'@
|
|
259
|
+
Add-Type -TypeDefinition $source -Language CSharp
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function Get-PoolTagReport {
|
|
263
|
+
param([int]$TopCount)
|
|
264
|
+
Ensure-PoolTagCaptureType
|
|
265
|
+
return [PoolTagCapture]::Capture($TopCount)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function Get-ThresholdAlerts {
|
|
269
|
+
param(
|
|
270
|
+
[int64]$NonpagedBytes,
|
|
271
|
+
[int64]$TotalHandles,
|
|
272
|
+
[int]$HighHandleProcessCount,
|
|
273
|
+
[long]$NonpagedAlert,
|
|
274
|
+
[int]$ProcessHandleAlert,
|
|
275
|
+
[int]$TotalHandleAlert
|
|
276
|
+
)
|
|
277
|
+
$allAlerts = [System.Collections.Generic.List[string]]::new()
|
|
278
|
+
if ($NonpagedBytes -gt $NonpagedAlert) {
|
|
279
|
+
$allAlerts.Add((
|
|
280
|
+
"ALERT nonpaged={0} threshold={1}" -f
|
|
281
|
+
(Format-BytesAsGigabytes $NonpagedBytes),
|
|
282
|
+
(Format-BytesAsGigabytes $NonpagedAlert)
|
|
283
|
+
))
|
|
284
|
+
}
|
|
285
|
+
if ($TotalHandles -gt $TotalHandleAlert) {
|
|
286
|
+
$allAlerts.Add((
|
|
287
|
+
"ALERT total_handles={0} threshold={1}" -f $TotalHandles, $TotalHandleAlert
|
|
288
|
+
))
|
|
289
|
+
}
|
|
290
|
+
if ($HighHandleProcessCount -gt 0) {
|
|
291
|
+
$allAlerts.Add((
|
|
292
|
+
"ALERT processes_over_{0}_handles={1}" -f
|
|
293
|
+
$ProcessHandleAlert, $HighHandleProcessCount
|
|
294
|
+
))
|
|
295
|
+
}
|
|
296
|
+
return , $allAlerts
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
# --- main ---
|
|
300
|
+
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz'
|
|
301
|
+
Write-ReportLine "TIMESTAMP: $timestamp"
|
|
302
|
+
Write-ReportLine "HOST: $env:COMPUTERNAME"
|
|
303
|
+
Write-ReportLine (
|
|
304
|
+
"THRESHOLDS: nonpaged>{0}; process_handles>{1}; total_handles>{2}" -f
|
|
305
|
+
(Format-BytesAsGigabytes $NonpagedAlertBytes),
|
|
306
|
+
$ProcessHandleAlert,
|
|
307
|
+
$TotalHandleAlert
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
Write-ReportLine ''
|
|
311
|
+
Write-ReportLine '=== COUNTERS ==='
|
|
312
|
+
$counterByName = Get-MemoryAndHandleCounters
|
|
313
|
+
$nonpagedBytes = $counterByName['NonpagedBytes']
|
|
314
|
+
$pagedBytes = $counterByName['PagedBytes']
|
|
315
|
+
$committedBytes = $counterByName['CommittedBytes']
|
|
316
|
+
$commitLimitBytes = $counterByName['CommitLimit']
|
|
317
|
+
$availableMBytes = $counterByName['AvailableMBytes']
|
|
318
|
+
$totalHandles = $counterByName['TotalHandles']
|
|
319
|
+
$totalThreads = $counterByName['TotalThreads']
|
|
320
|
+
|
|
321
|
+
Write-ReportLine ("Pool Nonpaged Bytes = {0} ({1})" -f $nonpagedBytes, (Format-BytesAsGigabytes $nonpagedBytes))
|
|
322
|
+
Write-ReportLine ("Pool Paged Bytes = {0} ({1})" -f $pagedBytes, (Format-BytesAsGigabytes $pagedBytes))
|
|
323
|
+
Write-ReportLine ("Committed Bytes = {0} ({1})" -f $committedBytes, (Format-BytesAsGigabytes $committedBytes))
|
|
324
|
+
Write-ReportLine ("Commit Limit = {0} ({1})" -f $commitLimitBytes, (Format-BytesAsGigabytes $commitLimitBytes))
|
|
325
|
+
Write-ReportLine ("Available MBytes = {0}" -f $availableMBytes)
|
|
326
|
+
Write-ReportLine ("Handle Count Total = {0}" -f $totalHandles)
|
|
327
|
+
Write-ReportLine ("Thread Count Total = {0}" -f $totalThreads)
|
|
328
|
+
|
|
329
|
+
Write-ReportLine ''
|
|
330
|
+
Write-ReportLine ("=== PROCESSES WITH HANDLES > {0} ===" -f $ProcessHandleAlert)
|
|
331
|
+
$highHandleReport = Get-HighHandleProcessReport `
|
|
332
|
+
-HandleThreshold $ProcessHandleAlert `
|
|
333
|
+
-MaximumRows $TopProcessCount
|
|
334
|
+
if ($highHandleReport.TopRows.Count -eq 0) {
|
|
335
|
+
Write-ReportLine '(none)'
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
foreach ($eachProcess in $highHandleReport.TopRows) {
|
|
339
|
+
$commandPreview = ''
|
|
340
|
+
if ($eachProcess.CommandLine) {
|
|
341
|
+
$commandPreview = $eachProcess.CommandLine
|
|
342
|
+
if ($commandPreview.Length -gt 120) {
|
|
343
|
+
$commandPreview = $commandPreview.Substring(0, 117) + '...'
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
Write-ReportLine (
|
|
347
|
+
"PID={0} Name={1} Handles={2} Parent={3} Cmd={4}" -f
|
|
348
|
+
$eachProcess.ProcessId,
|
|
349
|
+
$eachProcess.Name,
|
|
350
|
+
$eachProcess.HandleCount,
|
|
351
|
+
$eachProcess.ParentProcessId,
|
|
352
|
+
$commandPreview
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
$highHandleProcessCount = $highHandleReport.TotalCount
|
|
358
|
+
Write-ReportLine ("High-handle process count (all): {0}" -f $highHandleProcessCount)
|
|
359
|
+
|
|
360
|
+
Write-ReportLine ''
|
|
361
|
+
Write-ReportLine '=== POOL TAGS (NtQuerySystemInformation class 22) ==='
|
|
362
|
+
try {
|
|
363
|
+
Write-ReportLine (Get-PoolTagReport -TopCount $TopTagCount)
|
|
364
|
+
}
|
|
365
|
+
catch {
|
|
366
|
+
Write-ReportLine ("POOL TAG CAPTURE FAILED: {0}" -f $_.Exception.Message)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
Write-ReportLine ''
|
|
370
|
+
Write-ReportLine '=== REMEDIATION MAP (process-object pressure) ==='
|
|
371
|
+
Write-ReportLine 'Dominant tags File (nonpaged) + Toke (paged) -> object-manager sprawl, not a lone driver leak.'
|
|
372
|
+
Write-ReportLine 'RC2 #255 Cap MCP servers (mcpvault/playwright/serena spawn-without-reap) -> cuts File/Toke/Thre'
|
|
373
|
+
Write-ReportLine 'RC3 #254 Show-Asset.ps1 exit on parent death + timeout -> cuts orphan UI process handles'
|
|
374
|
+
Write-ReportLine 'RC4 #253 Block Git find walks; es.exe primary; kill find with handles >2k -> cuts Key/handle storms'
|
|
375
|
+
Write-ReportLine 'RC5 #256 Attribute WSL/Docker starters only after measurement (VdMm secondary)'
|
|
376
|
+
Write-ReportLine 'Optional: install WDK poolmon.exe for stock binary snapshots (this script needs no WDK).'
|
|
377
|
+
|
|
378
|
+
$allThresholdAlerts = Get-ThresholdAlerts `
|
|
379
|
+
-NonpagedBytes $nonpagedBytes `
|
|
380
|
+
-TotalHandles $totalHandles `
|
|
381
|
+
-HighHandleProcessCount $highHandleProcessCount `
|
|
382
|
+
-NonpagedAlert $NonpagedAlertBytes `
|
|
383
|
+
-ProcessHandleAlert $ProcessHandleAlert `
|
|
384
|
+
-TotalHandleAlert $TotalHandleAlert
|
|
385
|
+
Write-ReportLine ''
|
|
386
|
+
Write-ReportLine '=== THRESHOLD VERDICT ==='
|
|
387
|
+
if ($allThresholdAlerts.Count -eq 0) {
|
|
388
|
+
Write-ReportLine 'OK - all thresholds clear'
|
|
389
|
+
$thresholdExitCode = 0
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
foreach ($eachAlert in $allThresholdAlerts) {
|
|
393
|
+
Write-ReportLine $eachAlert
|
|
394
|
+
}
|
|
395
|
+
Write-ReportLine 'REMEDIATE: process-object pressure (File/Toke tags) -> RC2 #255, RC3 #254, RC4 #253'
|
|
396
|
+
$thresholdExitCode = 1
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if ($OutPath) {
|
|
400
|
+
$destinationDirectory = Split-Path -Parent $OutPath
|
|
401
|
+
if ($destinationDirectory -and -not (Test-Path -LiteralPath $destinationDirectory)) {
|
|
402
|
+
New-Item -ItemType Directory -Path $destinationDirectory -Force | Out-Null
|
|
403
|
+
}
|
|
404
|
+
$script:ReportLines -join [Environment]::NewLine |
|
|
405
|
+
Set-Content -LiteralPath $OutPath -Encoding utf8
|
|
406
|
+
Write-Output ""
|
|
407
|
+
Write-Output "Wrote report: $OutPath"
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
exit $thresholdExitCode
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
settings.local.json, and settings.local.json.template, and rewrites permission
|
|
10
10
|
rule strings that invoke powershell / powershell.exe / bash -c / cmd /c
|
|
11
11
|
into their pwsh equivalents per the migration mapping in
|
|
12
|
-
rules/shell-invocation
|
|
12
|
+
rules/shell-invocation.md. Defaults to dry-run; pass -Apply to write
|
|
13
13
|
changes. Prints exactly one summary line.
|
|
14
14
|
|
|
15
15
|
.PARAMETER Roots
|