@danmoisan/drm-copilot-mcp 1.1.17 → 1.1.19
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/out/mcp-server.js +1405 -684
- package/package.json +6 -4
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +11 -0
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +10 -0
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +12 -4
- package/resources/claude-customizations/.claude/agents/epic-planner.md +5 -4
- package/resources/claude-customizations/.claude/agents/feature-review.md +16 -5
- package/resources/claude-customizations/.claude/agents/orchestrator.md +21 -7
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +37 -13
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +9 -6
- package/resources/claude-customizations/.claude/agents/pr-author.md +15 -2
- package/resources/claude-customizations/.claude/agents/prd-feature.md +1 -1
- package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +111 -46
- package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +8 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +116 -59
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +55 -23
- package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +74 -75
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +127 -35
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +61 -57
- package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +129 -39
- package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +39 -51
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +17 -12
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +65 -50
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +49 -42
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +54 -72
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +279 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +129 -75
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.artifact-root.ps1 +233 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +224 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +69 -24
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +29 -18
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +10 -4
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +14 -5
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/claude-customizations/.claude/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/claude-customizations/.claude/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-payload.ps1 +484 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/claude-customizations/.claude/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/claude-customizations/.claude/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/claude-customizations/.claude/hooks/subagentstop-envelope.ps1 +192 -0
- package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +40 -42
- package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +66 -38
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-metrics.ps1 +180 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +195 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +141 -395
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-resolution.ps1 +311 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-routing.ps1 +170 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +115 -190
- package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +64 -32
- package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +39 -44
- package/resources/claude-customizations/.claude/hooks/validate-prd-feature-output.ps1 +43 -14
- package/resources/claude-customizations/.claude/hooks/validate-required-artifact-output.ps1 +66 -36
- package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +31 -34
- package/resources/claude-customizations/.claude/lib/bash/mutate-parallel-run.sh +191 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +13 -3
- package/resources/claude-customizations/.claude/lib/bash/parallel-lane-assertion.sh +4 -2
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-cli.sh +152 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-ops.sh +193 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation.sh +322 -0
- package/resources/claude-customizations/.claude/lib/bash/remove-parallel-item.sh +146 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +23 -33
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +86 -6
- package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +91 -19
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -13
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +396 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +22 -15
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +337 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +9 -1
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +79 -2
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +3 -3
- package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +5 -5
- package/resources/claude-customizations/.claude/rules/csharp.md +2 -2
- package/resources/claude-customizations/.claude/rules/general-code-change.md +1 -1
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +3 -2
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +153 -4
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +47 -8
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +11 -7
- package/resources/claude-customizations/.claude/rules/shell.md +10 -8
- package/resources/claude-customizations/.claude/rules/typescript.md +1 -1
- package/resources/claude-customizations/.claude/settings.json +3 -4
- package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +7 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +11 -3
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +11 -2
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +171 -5
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +6 -43
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +6 -15
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +45 -11
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +10 -0
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +7 -4
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +42 -16
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +52 -14
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +22 -9
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +97 -19
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +63 -7
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +35 -12
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
- package/resources/claude-customizations/pack-manifests/core.json +25 -0
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +5 -5
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +11 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +10 -0
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +13 -3
- package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +17 -1
- package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +2 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +30 -6
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +16 -6
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +3 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +43 -11
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +19 -4
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +11 -7
- package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +2 -0
- package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +2 -1
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +318 -273
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +97 -44
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +37 -5
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +6 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +54 -41
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +35 -14
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +24 -11
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +13 -4
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload.ps1 +484 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +24 -8
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +9 -0
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +2 -2
- package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +4 -4
- package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +2 -2
- package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
- package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +25 -28
- package/resources/powershell/PoshQC/PoshQC.psm1 +1 -0
- package/resources/powershell/PoshQC/README.md +8 -2
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +2 -315
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# parallel-mutation.sh: sourceable bash port of the three removal functions of
|
|
3
|
+
# the parallel mutation engine, so a workspace that received the Claude
|
|
4
|
+
# customization payload can decide a removal, recolor the unstarted subgraph,
|
|
5
|
+
# and build the removal's mutations[] record without an interpreter.
|
|
6
|
+
#
|
|
7
|
+
# Parity reference (the repository authority; this file reproduces its
|
|
8
|
+
# observable outputs and rejection messages byte for byte):
|
|
9
|
+
# decide_removal scripts/dev_tools/parallel_mutation_protocol.py
|
|
10
|
+
# recolor_unstarted scripts/dev_tools/parallel_mutation_protocol.py
|
|
11
|
+
# build_remove_entry scripts/dev_tools/_parallel_mutation_entries.py
|
|
12
|
+
# MutationEntry scripts/dev_tools/_parallel_mutation_models.py
|
|
13
|
+
# rejection messages scripts/dev_tools/_parallel_mutation_errors.py
|
|
14
|
+
#
|
|
15
|
+
# Declared divergences (also listed in both parity lanes):
|
|
16
|
+
# 1. A `--removal-disposition` value outside `detach abandon` is a usage error
|
|
17
|
+
# (exit 2) raised by the command line before the library runs. A direct
|
|
18
|
+
# library call and the Python `UnknownEnumMemberError` both reject it with
|
|
19
|
+
# the same message, which lists `detach, abandon`
|
|
20
|
+
# (spec D5; aligned under #890).
|
|
21
|
+
# 2. `at` is a caller-supplied string instead of a `datetime`.
|
|
22
|
+
# 3. Option abbreviations are rejected.
|
|
23
|
+
#
|
|
24
|
+
# Contract. Every public function is pure: no file I/O, no network access, no
|
|
25
|
+
# clock read, and no external utility beyond the ones parallel-cohorts.sh
|
|
26
|
+
# already uses. Each sets PM_RESULT to one compact JSON object and returns 0 on
|
|
27
|
+
# success, or sets PM_ERROR to the exact reference message and returns 1 on a
|
|
28
|
+
# rule rejection. Integer arguments are expected in canonical decimal form; the
|
|
29
|
+
# entry point remove-parallel-item.sh validates them before calling here.
|
|
30
|
+
#
|
|
31
|
+
# shellcheck disable=SC2034
|
|
32
|
+
# SC2034 is disabled file-wide because PM_RESULT and PM_ERROR are written here
|
|
33
|
+
# and read by the entry point remove-parallel-item.sh and by the bats suites,
|
|
34
|
+
# which shellcheck analyses separately.
|
|
35
|
+
|
|
36
|
+
# Resolve this file's own directory so its dependencies source regardless of
|
|
37
|
+
# the caller's working directory.
|
|
38
|
+
PM_LIB_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
|
39
|
+
# shellcheck source=.claude/lib/bash/parallel-cohorts.sh
|
|
40
|
+
# shellcheck disable=SC1091
|
|
41
|
+
source "$PM_LIB_DIR/parallel-cohorts.sh"
|
|
42
|
+
|
|
43
|
+
# The compact JSON object produced by the most recent success.
|
|
44
|
+
PM_RESULT=""
|
|
45
|
+
|
|
46
|
+
# The rejection message set by the most recent non-zero return.
|
|
47
|
+
PM_ERROR=""
|
|
48
|
+
|
|
49
|
+
# Literal prefix shared by every engine rejection message.
|
|
50
|
+
PM_REJECTION_PREFIX="Parallel mutation rejected:"
|
|
51
|
+
|
|
52
|
+
# Item states whose items have not started (vertices of the recolored subgraph).
|
|
53
|
+
PM_UNSTARTED_STATES="proposed admitted prepared scheduled"
|
|
54
|
+
|
|
55
|
+
# The single item state that pins an item against recoloring.
|
|
56
|
+
PM_PINNED_STATE="in_flight"
|
|
57
|
+
|
|
58
|
+
# The two accepted dispositions of an in-flight removal, in canonical order.
|
|
59
|
+
PM_VALID_DISPOSITIONS="detach abandon"
|
|
60
|
+
|
|
61
|
+
pm_fail() {
|
|
62
|
+
# Record a rejection message and return 1.
|
|
63
|
+
#
|
|
64
|
+
# Args: $1 = the complete, literal rejection message.
|
|
65
|
+
PM_ERROR="$1"
|
|
66
|
+
return 1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
pm_json_string() {
|
|
70
|
+
# Echo a JSON string literal for a raw value.
|
|
71
|
+
#
|
|
72
|
+
# Args: $1 = the raw value. Escapes the backslash first so a later escape's
|
|
73
|
+
# own backslash is not doubled, then the quote and the three control
|
|
74
|
+
# characters a caller-supplied token could carry.
|
|
75
|
+
local body="$1"
|
|
76
|
+
body=${body//\\/\\\\}
|
|
77
|
+
body=${body//\"/\\\"}
|
|
78
|
+
body=${body//$'\n'/\\n}
|
|
79
|
+
body=${body//$'\r'/\\r}
|
|
80
|
+
body=${body//$'\t'/\\t}
|
|
81
|
+
printf '"%s"' "$body"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pm_json_nullable_string() {
|
|
85
|
+
# Echo a JSON string literal, or null for an empty value.
|
|
86
|
+
#
|
|
87
|
+
# Args: $1 = the raw value; empty means absent (Python None).
|
|
88
|
+
if [[ -z ${1-} ]]; then
|
|
89
|
+
printf 'null'
|
|
90
|
+
else
|
|
91
|
+
pm_json_string "$1"
|
|
92
|
+
fi
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
pm_unknown_item_message() {
|
|
96
|
+
# Echo the UnknownItemError message for one item key.
|
|
97
|
+
#
|
|
98
|
+
# Args: $1 = the offending integer key, rendered as Python repr renders it.
|
|
99
|
+
printf '%s item key %s does not resolve to a tracked items[].issue_num.' \
|
|
100
|
+
"$PM_REJECTION_PREFIX" "$1"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
pm_entry_contract_message() {
|
|
104
|
+
# Echo the MutationEntryContractError message for one op.
|
|
105
|
+
#
|
|
106
|
+
# Args: $1 = field name, $2 = the already-rendered repr of the value, $3 =
|
|
107
|
+
# the op name, optional and defaulting to `remove` so every removal call
|
|
108
|
+
# site passes two arguments unchanged.
|
|
109
|
+
printf "Parallel mutation entry rejected: %s %s violates the F3 mutations[] contract for op '%s'." \
|
|
110
|
+
"$1" "$2" "${3:-remove}"
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
pm_decide_removal() {
|
|
114
|
+
# Decide the outcome of removing one item, per the FR2 behavior table.
|
|
115
|
+
#
|
|
116
|
+
# Args: $1 = item key, $2 = the item's state, or empty when the key resolves
|
|
117
|
+
# to no tracked item, $3 = disposition, or empty when none was supplied.
|
|
118
|
+
# Returns 0 with PM_RESULT holding the decision, 1 with PM_ERROR holding the
|
|
119
|
+
# reference rejection message.
|
|
120
|
+
local item_key="$1" state="${2-}" disposition="${3-}" prior
|
|
121
|
+
PM_RESULT=""
|
|
122
|
+
PM_ERROR=""
|
|
123
|
+
# An absent record and a non-positive key both name nothing the run tracks;
|
|
124
|
+
# the reference rejects the latter while constructing the item record.
|
|
125
|
+
if [[ -z $state ]] || ((item_key <= 0)); then
|
|
126
|
+
pm_fail "$(pm_unknown_item_message "$item_key")"
|
|
127
|
+
return 1
|
|
128
|
+
fi
|
|
129
|
+
if ! pc_enum_members_contains "$PC_VALID_ITEM_STATES" "$state"; then
|
|
130
|
+
pm_fail "$PM_REJECTION_PREFIX item $item_key state $(pc_repr str "$state") is not one of $PC_VALID_ITEM_STATES."
|
|
131
|
+
return 1
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# Routing table, one branch per FR2 row. An unstarted item is a vertex of
|
|
135
|
+
# the recolored subgraph, so its removal recomputes and records no
|
|
136
|
+
# disposition even when one was supplied.
|
|
137
|
+
if pc_contains_word "$PM_UNSTARTED_STATES" "$state"; then
|
|
138
|
+
PM_RESULT="{\"item_key\":$item_key,\"prior_state\":$(pm_json_string "$state"),\"new_state\":\"withdrawn\",\"disposition\":null,\"triggers_recompute\":true}"
|
|
139
|
+
return 0
|
|
140
|
+
fi
|
|
141
|
+
if [[ $state == "$PM_PINNED_STATE" ]]; then
|
|
142
|
+
if [[ -z $disposition ]]; then
|
|
143
|
+
pm_fail "$PM_REJECTION_PREFIX removal of in-flight item $item_key requires an explicit disposition, one of detach, abandon; no default is inferred."
|
|
144
|
+
return 1
|
|
145
|
+
fi
|
|
146
|
+
if ! pc_contains_word "$PM_VALID_DISPOSITIONS" "$disposition"; then
|
|
147
|
+
pm_fail "$PM_REJECTION_PREFIX item $item_key disposition $(pc_repr str "$disposition") is not one of ${PM_VALID_DISPOSITIONS// /, }."
|
|
148
|
+
return 1
|
|
149
|
+
fi
|
|
150
|
+
prior="$PM_PINNED_STATE"
|
|
151
|
+
PM_RESULT="{\"item_key\":$item_key,\"prior_state\":\"$prior\",\"new_state\":\"withdrawn\",\"disposition\":\"$disposition\",\"triggers_recompute\":false}"
|
|
152
|
+
return 0
|
|
153
|
+
fi
|
|
154
|
+
if [[ $state == merged ]]; then
|
|
155
|
+
pm_fail "$PM_REJECTION_PREFIX item $item_key is already merged into main and cannot be removed."
|
|
156
|
+
return 1
|
|
157
|
+
fi
|
|
158
|
+
# Only withdrawn and blocked remain; neither is a live removal target.
|
|
159
|
+
pm_fail "$(pm_unknown_item_message "$item_key")"
|
|
160
|
+
return 1
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
pm_smallest_overlap() {
|
|
164
|
+
# Echo the smallest key present in both key lists, or nothing.
|
|
165
|
+
#
|
|
166
|
+
# Args: $1 = space-separated unstarted keys, $2 = space-separated pinned keys.
|
|
167
|
+
local key smallest=""
|
|
168
|
+
pcoh_split_words "$1"
|
|
169
|
+
local -a unstarted_keys=("${PCOH_WORDS[@]}")
|
|
170
|
+
pcoh_split_words "$2"
|
|
171
|
+
local pinned=" ${PCOH_WORDS[*]} "
|
|
172
|
+
for key in "${unstarted_keys[@]}"; do
|
|
173
|
+
[[ $pinned == *" $key "* ]] || continue
|
|
174
|
+
if [[ -z $smallest ]] || ((key < smallest)); then
|
|
175
|
+
smallest="$key"
|
|
176
|
+
fi
|
|
177
|
+
done
|
|
178
|
+
printf '%s' "$smallest"
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
pm_render_assignments() {
|
|
182
|
+
# Echo the cohort_assignments object for a cohort list and an offset.
|
|
183
|
+
#
|
|
184
|
+
# Args: $1 = compact JSON array of arrays from pcoh_compute_cohorts, $2 = the
|
|
185
|
+
# uniform offset. List position is the local color index; keys are emitted
|
|
186
|
+
# in ascending numeric order, matching the reference rendering.
|
|
187
|
+
local cohorts="$1" offset="$2" group key index=0 lines="" ordered rendered=""
|
|
188
|
+
# Strip the outer brackets and the first and last inner bracket, then turn
|
|
189
|
+
# each `],[` boundary into a space so every group is one comma-joined word.
|
|
190
|
+
cohorts=${cohorts#[}
|
|
191
|
+
cohorts=${cohorts%]}
|
|
192
|
+
cohorts=${cohorts#[}
|
|
193
|
+
cohorts=${cohorts%]}
|
|
194
|
+
pcoh_split_words "${cohorts//'],['/ }"
|
|
195
|
+
local -a groups=("${PCOH_WORDS[@]}")
|
|
196
|
+
for group in "${groups[@]}"; do
|
|
197
|
+
pcoh_split_words "${group//,/ }"
|
|
198
|
+
for key in "${PCOH_WORDS[@]}"; do
|
|
199
|
+
lines="$lines$key $((offset + index))"$'\n'
|
|
200
|
+
done
|
|
201
|
+
index=$((index + 1))
|
|
202
|
+
done
|
|
203
|
+
if [[ -n $lines ]]; then
|
|
204
|
+
ordered=$(printf '%s' "$lines" | LC_ALL=C sort -k1,1n)
|
|
205
|
+
while IFS=' ' read -r key index; do
|
|
206
|
+
[[ -n $key ]] || continue
|
|
207
|
+
[[ -z $rendered ]] || rendered="$rendered,"
|
|
208
|
+
rendered="$rendered\"$key\":$index"
|
|
209
|
+
done <<<"$ordered"
|
|
210
|
+
fi
|
|
211
|
+
printf '{%s}' "$rendered"
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
pm_recolor_unstarted() {
|
|
215
|
+
# Recolor the unstarted subgraph, leaving every pinned item untouched.
|
|
216
|
+
#
|
|
217
|
+
# Args: $1 = space-separated unstarted keys, $2 = space-separated `a:b`
|
|
218
|
+
# conflict edges over all items, $3 = space-separated pinned keys, $4 = the
|
|
219
|
+
# generation before this recolor, $5 = current_cohort, $6 =
|
|
220
|
+
# highest_pinned_cohort. Returns 0 with PM_RESULT holding the assignments
|
|
221
|
+
# and the next generation, 1 with PM_ERROR holding the reference message.
|
|
222
|
+
local unstarted="$1" edges="$2" pinned="$3" generation="$4"
|
|
223
|
+
local current_cohort="$5" highest_pinned="$6"
|
|
224
|
+
local overlap edge first second crosses=0 induced="" offset
|
|
225
|
+
PM_RESULT=""
|
|
226
|
+
PM_ERROR=""
|
|
227
|
+
|
|
228
|
+
# Check order is part of the contract: overlap, then the negative base,
|
|
229
|
+
# then the pinned barrier, then the induced coloring.
|
|
230
|
+
overlap=$(pm_smallest_overlap "$unstarted" "$pinned")
|
|
231
|
+
if [[ -n $overlap ]]; then
|
|
232
|
+
pm_fail "$(pm_unknown_item_message "$overlap")"
|
|
233
|
+
return 1
|
|
234
|
+
fi
|
|
235
|
+
if ((current_cohort < 0)); then
|
|
236
|
+
pm_fail "current_cohort must be >= 0 per F3 invariant 12; received $current_cohort."
|
|
237
|
+
return 1
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
pcoh_split_words "$unstarted"
|
|
241
|
+
local unstarted_set=" ${PCOH_WORDS[*]} "
|
|
242
|
+
pcoh_split_words "$pinned"
|
|
243
|
+
local pinned_set=" ${PCOH_WORDS[*]} "
|
|
244
|
+
pcoh_split_words "$edges"
|
|
245
|
+
local -a edge_list=("${PCOH_WORDS[@]}")
|
|
246
|
+
# Decide the pinned barrier before the induced restriction discards the
|
|
247
|
+
# unstarted-to-pinned edges, then keep only edges with both ends unstarted.
|
|
248
|
+
for edge in "${edge_list[@]}"; do
|
|
249
|
+
first="${edge%%:*}"
|
|
250
|
+
second="${edge#*:}"
|
|
251
|
+
if [[ $unstarted_set == *" $first "* && $pinned_set == *" $second "* ]] ||
|
|
252
|
+
[[ $unstarted_set == *" $second "* && $pinned_set == *" $first "* ]]; then
|
|
253
|
+
crosses=1
|
|
254
|
+
fi
|
|
255
|
+
if [[ $unstarted_set == *" $first "* && $unstarted_set == *" $second "* ]]; then
|
|
256
|
+
induced="$induced $edge"
|
|
257
|
+
fi
|
|
258
|
+
done
|
|
259
|
+
|
|
260
|
+
if ! pcoh_compute_cohorts "$unstarted" "$induced"; then
|
|
261
|
+
pm_fail "$PCOH_ERROR"
|
|
262
|
+
return 1
|
|
263
|
+
fi
|
|
264
|
+
|
|
265
|
+
# A uniform shift keeps the local-to-absolute map injective.
|
|
266
|
+
if ((crosses == 1)); then
|
|
267
|
+
offset=$((highest_pinned + 1))
|
|
268
|
+
else
|
|
269
|
+
offset="$current_cohort"
|
|
270
|
+
fi
|
|
271
|
+
PM_RESULT="{\"cohort_assignments\":$(pm_render_assignments "$PCOH_RESULT" "$offset"),\"generation\":$((generation + 1))}"
|
|
272
|
+
return 0
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
pm_build_remove_entry() {
|
|
276
|
+
# Build the single mutations[] record for an accepted removal.
|
|
277
|
+
#
|
|
278
|
+
# Args: $1 = item key, $2 = prior state, $3 = disposition, or empty for
|
|
279
|
+
# none, $4 = `true` when the removal recomputes, otherwise `false`, $5 = the
|
|
280
|
+
# generation before the removal, $6 = the `at` timestamp string. Returns 0
|
|
281
|
+
# with PM_RESULT holding the record in F3 field order, 1 with PM_ERROR
|
|
282
|
+
# holding the reference contract message.
|
|
283
|
+
local item_key="$1" prior_state="$2" disposition="${3-}" recompute="$4"
|
|
284
|
+
local generation="$5" at="$6" stamped
|
|
285
|
+
PM_RESULT=""
|
|
286
|
+
PM_ERROR=""
|
|
287
|
+
# The stamped generation is computed first; the record validation then
|
|
288
|
+
# runs in field order, so the first violation names the earliest field.
|
|
289
|
+
stamped="$generation"
|
|
290
|
+
if [[ $recompute == true ]]; then
|
|
291
|
+
stamped=$((generation + 1))
|
|
292
|
+
fi
|
|
293
|
+
if ((stamped < 0)); then
|
|
294
|
+
pm_fail "$(pm_entry_contract_message recolor_generation "$stamped")"
|
|
295
|
+
return 1
|
|
296
|
+
fi
|
|
297
|
+
if ((item_key <= 0)); then
|
|
298
|
+
pm_fail "$(pm_entry_contract_message item_key "$item_key")"
|
|
299
|
+
return 1
|
|
300
|
+
fi
|
|
301
|
+
if ! pc_enum_members_contains "$PC_VALID_ITEM_STATES" "$prior_state"; then
|
|
302
|
+
pm_fail "$PM_REJECTION_PREFIX item $item_key state $(pc_repr str "$prior_state") is not one of $PC_VALID_ITEM_STATES."
|
|
303
|
+
return 1
|
|
304
|
+
fi
|
|
305
|
+
# An in-flight removal must record a valid disposition; every other
|
|
306
|
+
# removal must record none.
|
|
307
|
+
if [[ $prior_state == "$PM_PINNED_STATE" ]]; then
|
|
308
|
+
if [[ -z $disposition ]]; then
|
|
309
|
+
pm_fail "$(pm_entry_contract_message disposition None)"
|
|
310
|
+
return 1
|
|
311
|
+
fi
|
|
312
|
+
if ! pc_contains_word "$PM_VALID_DISPOSITIONS" "$disposition"; then
|
|
313
|
+
pm_fail "$(pm_entry_contract_message disposition "$(pc_repr str "$disposition")")"
|
|
314
|
+
return 1
|
|
315
|
+
fi
|
|
316
|
+
elif [[ -n $disposition ]]; then
|
|
317
|
+
pm_fail "$(pm_entry_contract_message disposition "$(pc_repr str "$disposition")")"
|
|
318
|
+
return 1
|
|
319
|
+
fi
|
|
320
|
+
PM_RESULT="{\"op\":\"remove\",\"item_key\":$item_key,\"at\":$(pm_json_string "$at"),\"prior_state\":$(pm_json_string "$prior_state"),\"new_state\":\"withdrawn\",\"disposition\":$(pm_json_nullable_string "$disposition"),\"recolor_generation\":$stamped}"
|
|
321
|
+
return 0
|
|
322
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# remove-parallel-item.sh: destination-portable command-line entry point for
|
|
3
|
+
# the parallel-remove skill's decision, recolor, and audit-record steps. It
|
|
4
|
+
# exists so a workspace that received the Claude customization payload can run
|
|
5
|
+
# those steps with nothing but bash -- no interpreter, no repository checkout.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# bash .claude/lib/bash/remove-parallel-item.sh decide --item <key> \
|
|
9
|
+
# [--state <state>] [--removal-disposition detach|abandon]
|
|
10
|
+
# bash .claude/lib/bash/remove-parallel-item.sh recolor --unstarted "<k> ..." \
|
|
11
|
+
# [--edges "<a>:<b> ..."] --pinned "<k> ..." --generation <g> \
|
|
12
|
+
# --current-cohort <c> --highest-pinned-cohort <h>
|
|
13
|
+
# bash .claude/lib/bash/remove-parallel-item.sh entry --item <key> \
|
|
14
|
+
# --prior-state <state> [--removal-disposition detach|abandon] \
|
|
15
|
+
# --recompute true|false --generation <g> [--at <timestamp>]
|
|
16
|
+
#
|
|
17
|
+
# `decide` without `--state` means the key resolves to no tracked item.
|
|
18
|
+
# `--unstarted`, `--edges`, and `--pinned` accept an empty string. Integer
|
|
19
|
+
# tokens match `-?(0|[1-9][0-9]*)`. `--at` defaults to the current UTC time as
|
|
20
|
+
# yyyy-MM-ddTHH-mm; the clock is read only when `--at` is omitted.
|
|
21
|
+
#
|
|
22
|
+
# Exit-code contract:
|
|
23
|
+
# exit 0 success; one compact JSON object on stdout
|
|
24
|
+
# exit 1 rule rejection; the reference implementation's exact message as
|
|
25
|
+
# one stderr line
|
|
26
|
+
# exit 2 usage error; one stderr line beginning
|
|
27
|
+
# "PARALLEL_MUTATION_ERROR: usage error:"
|
|
28
|
+
# Argument validation runs first, then rule rejection, then output.
|
|
29
|
+
#
|
|
30
|
+
# Parity reference: scripts/dev_tools/parallel_mutation_protocol.py
|
|
31
|
+
# (decide_removal, recolor_unstarted) and
|
|
32
|
+
# scripts/dev_tools/_parallel_mutation_entries.py (build_remove_entry).
|
|
33
|
+
#
|
|
34
|
+
# Declared divergences (also listed in both parity lanes):
|
|
35
|
+
# 1. A `--removal-disposition` value outside `detach abandon` is a usage error
|
|
36
|
+
# (exit 2) raised by the command line before the library runs. A direct
|
|
37
|
+
# library call and the Python `UnknownEnumMemberError` both reject it with
|
|
38
|
+
# the same message, which lists `detach, abandon`
|
|
39
|
+
# (spec D5; aligned under #890).
|
|
40
|
+
# 2. `at` is a caller-supplied string instead of a `datetime`.
|
|
41
|
+
# 3. Option abbreviations are rejected.
|
|
42
|
+
set -euo pipefail
|
|
43
|
+
|
|
44
|
+
# Resolve this script's own directory so the libraries source regardless of
|
|
45
|
+
# cwd. The option-parsing helpers (pmcli_*) are shared with
|
|
46
|
+
# mutate-parallel-run.sh through parallel-mutation-cli.sh (issue #890).
|
|
47
|
+
RPI_SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
|
48
|
+
# shellcheck source=.claude/lib/bash/parallel-mutation.sh
|
|
49
|
+
# shellcheck disable=SC1091
|
|
50
|
+
source "$RPI_SCRIPT_DIR/parallel-mutation.sh"
|
|
51
|
+
# shellcheck source=.claude/lib/bash/parallel-mutation-cli.sh
|
|
52
|
+
# shellcheck disable=SC1091
|
|
53
|
+
source "$RPI_SCRIPT_DIR/parallel-mutation-cli.sh"
|
|
54
|
+
|
|
55
|
+
pc_enforce_c_locale
|
|
56
|
+
|
|
57
|
+
rpi_disposition() {
|
|
58
|
+
# Validate the optional disposition; store it, or empty when absent.
|
|
59
|
+
PMCLI_VALUE="${PMCLI_OPTS["removal-disposition"]-}"
|
|
60
|
+
if [[ -n ${PMCLI_OPTS["removal-disposition"]+set} ]] && ! pc_contains_word "detach abandon" "$PMCLI_VALUE"; then
|
|
61
|
+
pmcli_usage_error "--removal-disposition must be one of detach, abandon; found: $PMCLI_VALUE"
|
|
62
|
+
fi
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
rpi_decide() {
|
|
66
|
+
# Run the decide subcommand.
|
|
67
|
+
local item state="" disposition rc=0
|
|
68
|
+
pmcli_parse_options "item state removal-disposition" "$@"
|
|
69
|
+
pmcli_require item
|
|
70
|
+
pmcli_integer "${PMCLI_OPTS[item]}" "--item"
|
|
71
|
+
item="$PMCLI_VALUE"
|
|
72
|
+
if [[ -n ${PMCLI_OPTS[state]+set} ]]; then
|
|
73
|
+
state="${PMCLI_OPTS[state]}"
|
|
74
|
+
pc_enum_members_contains "$PC_VALID_ITEM_STATES" "$state" ||
|
|
75
|
+
pmcli_usage_error "--state must be one of $PC_VALID_ITEM_STATES; found: $state"
|
|
76
|
+
fi
|
|
77
|
+
rpi_disposition
|
|
78
|
+
disposition="$PMCLI_VALUE"
|
|
79
|
+
pm_decide_removal "$item" "$state" "$disposition" || rc=$?
|
|
80
|
+
pmcli_emit "$rc"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
rpi_recolor() {
|
|
84
|
+
# Run the recolor subcommand.
|
|
85
|
+
local unstarted edges pinned generation current highest rc=0
|
|
86
|
+
pmcli_parse_options "unstarted edges pinned generation current-cohort highest-pinned-cohort" "$@"
|
|
87
|
+
pmcli_require unstarted pinned generation current-cohort highest-pinned-cohort
|
|
88
|
+
pmcli_integer_list "${PMCLI_OPTS[unstarted]}" "--unstarted"
|
|
89
|
+
unstarted="$PMCLI_VALUE"
|
|
90
|
+
pmcli_edge_list "${PMCLI_OPTS[edges]-}"
|
|
91
|
+
edges="$PMCLI_VALUE"
|
|
92
|
+
pmcli_integer_list "${PMCLI_OPTS[pinned]}" "--pinned"
|
|
93
|
+
pinned="$PMCLI_VALUE"
|
|
94
|
+
pmcli_integer "${PMCLI_OPTS[generation]}" "--generation"
|
|
95
|
+
generation="$PMCLI_VALUE"
|
|
96
|
+
pmcli_integer "${PMCLI_OPTS["current-cohort"]}" "--current-cohort"
|
|
97
|
+
current="$PMCLI_VALUE"
|
|
98
|
+
pmcli_integer "${PMCLI_OPTS["highest-pinned-cohort"]}" "--highest-pinned-cohort"
|
|
99
|
+
highest="$PMCLI_VALUE"
|
|
100
|
+
pm_recolor_unstarted "$unstarted" "$edges" "$pinned" "$generation" "$current" "$highest" || rc=$?
|
|
101
|
+
pmcli_emit "$rc"
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
rpi_entry() {
|
|
105
|
+
# Run the entry subcommand.
|
|
106
|
+
local item prior disposition recompute generation at rc=0
|
|
107
|
+
pmcli_parse_options "item prior-state removal-disposition recompute generation at" "$@"
|
|
108
|
+
pmcli_require item prior-state recompute generation
|
|
109
|
+
pmcli_integer "${PMCLI_OPTS[item]}" "--item"
|
|
110
|
+
item="$PMCLI_VALUE"
|
|
111
|
+
prior="${PMCLI_OPTS["prior-state"]}"
|
|
112
|
+
[[ $prior =~ ^[A-Za-z_]+$ ]] || pmcli_usage_error "--prior-state must match [A-Za-z_]+; found: $prior"
|
|
113
|
+
rpi_disposition
|
|
114
|
+
disposition="$PMCLI_VALUE"
|
|
115
|
+
recompute="${PMCLI_OPTS[recompute]}"
|
|
116
|
+
[[ $recompute == true || $recompute == false ]] ||
|
|
117
|
+
pmcli_usage_error "--recompute must be true or false; found: $recompute"
|
|
118
|
+
pmcli_integer "${PMCLI_OPTS[generation]}" "--generation"
|
|
119
|
+
generation="$PMCLI_VALUE"
|
|
120
|
+
# The clock is read only when --at is omitted.
|
|
121
|
+
pmcli_timestamp
|
|
122
|
+
at="$PMCLI_VALUE"
|
|
123
|
+
pm_build_remove_entry "$item" "$prior" "$disposition" "$recompute" "$generation" "$at" || rc=$?
|
|
124
|
+
pmcli_emit "$rc"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
rpi_main() {
|
|
128
|
+
# Dispatch on the subcommand.
|
|
129
|
+
(($# > 0)) || pmcli_usage_error "missing subcommand; expected one of decide, recolor, entry"
|
|
130
|
+
local subcommand="$1"
|
|
131
|
+
shift
|
|
132
|
+
case "$subcommand" in
|
|
133
|
+
decide) rpi_decide "$@" ;;
|
|
134
|
+
recolor) rpi_recolor "$@" ;;
|
|
135
|
+
entry) rpi_entry "$@" ;;
|
|
136
|
+
*) pmcli_usage_error "unknown subcommand: $subcommand" ;;
|
|
137
|
+
esac
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
# Guard so the file can be sourced without executing main. main's return code
|
|
141
|
+
# is captured and re-exited explicitly as the final statement.
|
|
142
|
+
if [[ ${BASH_SOURCE[0]} == "${0}" ]]; then
|
|
143
|
+
rpi_rc=0
|
|
144
|
+
rpi_main "$@" || rpi_rc=$?
|
|
145
|
+
exit "$rpi_rc"
|
|
146
|
+
fi
|
|
@@ -68,31 +68,23 @@ $script:PlanTaskPattern = [regex]::new(
|
|
|
68
68
|
# on its own line, from producing spurious spans.
|
|
69
69
|
$script:InlineCodeSpanPattern = [regex]::new('`([^`]+)`')
|
|
70
70
|
|
|
71
|
-
# Top-level directories of this repository. A token starting with one of
|
|
72
|
-
# accepted without
|
|
73
|
-
# subtree. artifacts/ is deliberately absent (issue
|
|
74
|
-
# tree is read by mandate rather than written by a
|
|
75
|
-
# artifacts/** as a subtree claim made unrelated items
|
|
71
|
+
# Top-level directories of this repository. A wildcard token starting with one of
|
|
72
|
+
# these is accepted without its final component naming a file (issue #797), which
|
|
73
|
+
# admits ** globs naming a subtree. artifacts/ is deliberately absent (issue
|
|
74
|
+
# #489): the process-artifact tree is read by mandate rather than written by a
|
|
75
|
+
# work item, so admitting artifacts/** as a subtree claim made unrelated items
|
|
76
|
+
# contend.
|
|
76
77
|
$script:KnownTopLevelSegment = @(
|
|
77
78
|
'scripts/', 'tests/', 'docs/', 'config/', 'schemas/', 'packages/',
|
|
78
79
|
'extensions/', '.claude/', '.codex/', '.github/', '.agents/'
|
|
79
80
|
)
|
|
80
81
|
|
|
81
82
|
# A file citation may carry a trailing line reference such as :90. The suffix is
|
|
82
|
-
# stripped before the
|
|
83
|
-
# acceptance its unanchored form has; the token itself is recorded
|
|
83
|
+
# stripped before the file-shape test (issue #797) so a line-anchored citation
|
|
84
|
+
# keeps the acceptance its unanchored form has; the token itself is recorded
|
|
85
|
+
# verbatim.
|
|
84
86
|
$script:LineSuffixPattern = [regex]::new(':\d+$')
|
|
85
87
|
|
|
86
|
-
# Fallback acceptance rule: a token shaped <segment>/.../<name>.<ext> counts as a
|
|
87
|
-
# repository path when its final component carries one of these extensions.
|
|
88
|
-
$script:RecognizedPathExtension = [System.Collections.Generic.HashSet[string]]::new(
|
|
89
|
-
[string[]] @(
|
|
90
|
-
'cfg', 'cs', 'csproj', 'ini', 'js', 'json', 'jsx', 'lock', 'md', 'ps1',
|
|
91
|
-
'psd1', 'psm1', 'py', 'sh', 'sln', 'toml', 'ts', 'tsx', 'txt', 'xml',
|
|
92
|
-
'yaml', 'yml'
|
|
93
|
-
),
|
|
94
|
-
[StringComparer]::Ordinal)
|
|
95
|
-
|
|
96
88
|
# Classification vocabulary for accepted path tokens. Concrete entries take part
|
|
97
89
|
# in exact-match checks; glob entries cannot and are matched by pattern.
|
|
98
90
|
$script:PathKindConcrete = 'concrete'
|
|
@@ -249,8 +241,11 @@ function Get-PathTokenKind {
|
|
|
249
241
|
bare word such as a function name is a contract identifier, not a path.
|
|
250
242
|
It must also be repository-relative: a leading separator marks an absolute
|
|
251
243
|
path and a colon in the leading segment marks a URL scheme or a Windows
|
|
252
|
-
drive.
|
|
253
|
-
|
|
244
|
+
drive. A wildcard-free token is then accepted only when its final
|
|
245
|
+
component, after any :<line> suffix is stripped, names a file according
|
|
246
|
+
to Test-FileShapedComponent (a letter-led extension or a known file
|
|
247
|
+
name, issue #797); a wildcard token needs a known top-level segment or
|
|
248
|
+
such a final component.
|
|
254
249
|
|
|
255
250
|
A token carrying any configured placeholder or interpolation marker is
|
|
256
251
|
rejected wherever the marker sits, because it documents a shape rather
|
|
@@ -305,7 +300,7 @@ function Get-PathTokenKind {
|
|
|
305
300
|
# disagree, and putting the cheaper marker scan first would only add work to
|
|
306
301
|
# the common accepted case. It runs BEFORE the separator guard because a
|
|
307
302
|
# marker-bearing token frequently does carry a separator and would otherwise
|
|
308
|
-
# sail past that guard and reach the
|
|
303
|
+
# sail past that guard and reach the file-shape rule, which accepts it: the
|
|
309
304
|
# dominant corpus shape is an angle-bracketed leading segment followed by a
|
|
310
305
|
# real .md tail, and that is exactly the token this guard exists to reject.
|
|
311
306
|
if (Test-PlaceholderMarker -Token $Token) {
|
|
@@ -320,26 +315,20 @@ function Get-PathTokenKind {
|
|
|
320
315
|
return $null
|
|
321
316
|
}
|
|
322
317
|
|
|
323
|
-
#
|
|
324
|
-
#
|
|
325
|
-
#
|
|
326
|
-
#
|
|
318
|
+
# Decide whether the final component names a file (issue #797): a letter-led
|
|
319
|
+
# extension or a known file name does; a directory name, a dot-directory, **,
|
|
320
|
+
# a digit-led tail, and a trailing dot do not. A trailing line reference is
|
|
321
|
+
# stripped first so file.md:90 reads as file.md rather than as md:90.
|
|
327
322
|
$finalComponent = $script:LineSuffixPattern.Replace(
|
|
328
323
|
$Token.Substring($Token.LastIndexOf('/') + 1), '')
|
|
329
|
-
$
|
|
330
|
-
$dotIndex = $finalComponent.LastIndexOf('.')
|
|
331
|
-
if ($dotIndex -ge 0) {
|
|
332
|
-
$extension = $finalComponent.Substring($dotIndex + 1).ToLowerInvariant()
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
$hasExtension = $script:RecognizedPathExtension.Contains($extension)
|
|
324
|
+
$namesFile = Test-FileShapedComponent -Component $finalComponent
|
|
336
325
|
|
|
337
326
|
# A wildcard-free token must name a file, not a directory (issue #489). A
|
|
338
327
|
# directory-shaped token such as scripts/dev_tools is a location reference,
|
|
339
328
|
# not a write claim, and admitting it made every item touching anything under
|
|
340
329
|
# that directory contend at the path level.
|
|
341
330
|
if ($Token.IndexOf('*') -lt 0) {
|
|
342
|
-
if ($
|
|
331
|
+
if ($namesFile) {
|
|
343
332
|
return $script:PathKindConcrete
|
|
344
333
|
}
|
|
345
334
|
return $null
|
|
@@ -356,7 +345,7 @@ function Get-PathTokenKind {
|
|
|
356
345
|
# A wildcard-bearing token must still satisfy one of the two documented shape
|
|
357
346
|
# rules; failing both means the token is prose or a non-path expression that
|
|
358
347
|
# merely contains a separator, so it is dropped.
|
|
359
|
-
if (-not $hasKnownSegment -and -not $
|
|
348
|
+
if (-not $hasKnownSegment -and -not $namesFile) {
|
|
360
349
|
return $null
|
|
361
350
|
}
|
|
362
351
|
|
|
@@ -469,6 +458,7 @@ Export-ModuleMember -Function `
|
|
|
469
458
|
Get-InlineCodeToken, `
|
|
470
459
|
Test-PlaceholderMarker, `
|
|
471
460
|
Test-MultipleFeatureFolderSpan, `
|
|
461
|
+
Test-FileShapedComponent, `
|
|
472
462
|
Get-PathTokenKind, `
|
|
473
463
|
Get-PathFromLine, `
|
|
474
464
|
Get-PlanPaths
|