@ccoalm/ccl-skills 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +49 -0
- package/dist/assets/marketplace/.agents/plugins/marketplace.json +12 -0
- package/dist/assets/marketplace/.claude-plugin/marketplace.json +13 -0
- package/dist/assets/marketplace/marketplace-manifest.json +12 -0
- package/dist/assets/marketplace/plugins/ccl-skills/.claude-plugin/marketplace.json +16 -0
- package/dist/assets/marketplace/plugins/ccl-skills/.claude-plugin/plugin.json +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/.codex-plugin/plugin.json +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/.worktree-only +3 -0
- package/dist/assets/marketplace/plugins/ccl-skills/agent-context/session-start.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/agent-context/subagent-start.md +12 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/AGENTS.md +19 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-delegation-owner.sh +125 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-edit-isolation.sh +102 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-merge-authorization.sh +1156 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/hooks.json +131 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/merge-authorization-prompt.sh +142 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/owner-dispatch-guard.sh +12 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/owner-dispatch-stop.sh +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/remind-post-merge-cleanup.sh +144 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/session-context.sh +87 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/session-start.sh +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/skill-extraction-gate-stop.sh +69 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/subagent-start.sh +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_delegation_owner.sh +329 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_edit_isolation.sh +322 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_merge_authorization.sh +902 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_merge_authorization_prompt.sh +178 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_remind_post_merge_cleanup.sh +121 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_session_start.sh +170 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/AGENTS.md +17 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/ccl-skills.ts +564 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-install-skills.md +14 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-update-skills.md +44 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-verify-skills.md +109 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-worktree-check.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/AGENTS.md +28 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/README.md +276 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.example.json +10 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.sh +1307 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/test.sh +941 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/agents-file-coverage-gate/SKILL.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/agents-file-coverage-gate/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/SKILL.md +188 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/android-dev.md +92 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/flutter-dev.md +80 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/ios-dev.md +72 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/kotlin-multiplatform.md +93 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/mobile-platform-boundaries.md +77 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/mobile-quality-release.md +77 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/source-evidence-map.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/SKILL.md +353 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/client-routing.md +419 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/manual-invocation-and-prompts.md +126 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/staged-review-contract.md +197 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/timeout-auth-and-capabilities.md +179 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/AGENTS.md +98 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/classify_envelope.py +93 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/classify_timeout_exit.sh +15 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/claude_review.sh +1438 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/codex_review.sh +324 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/concern_excerpt.py +295 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/egress_schema.py +214 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/init_policy_matrix.py +642 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_packet_mcp.py +181 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_review.sh +1165 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/opencode_review.sh +1190 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_cli_review.py +946 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_opencode_review.py +474 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_probe_result.py +1899 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_review_json.py +200 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +2845 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.sh +6 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/run_claude_capture.py +71 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/runtime-surface-verification-design.md +53 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_classify_envelope.sh +68 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_claude_review_probe.sh +2311 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_cli_review_wrappers.sh +1832 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_code_review_identity.sh +73 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_concern_excerpt.sh +245 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_egress_schema.sh +177 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_init_policy_matrix.sh +272 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_kimi_packet_mcp.py +195 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_opencode_review_concurrency.sh +120 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_opencode_review_retry.sh +1005 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_opencode_review.sh +258 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_probe_result.sh +574 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_review_json.sh +349 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_compat.py +434 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_order.sh +264 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate.sh +2412 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/verify_native_skill_binding.py +123 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/SKILL.md +153 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/references/diagnosis-playbook.md +54 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/references/prevention-routing.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/SKILL.md +69 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/references/security-review-gate.md +41 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/SKILL.md +165 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/api-security-boundaries.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/architecture-playbook.md +160 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/artifact-generation-architecture.md +37 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/audit-history-architecture.md +29 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/bulk-workflow-architecture.md +33 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/config-rule-routing-architecture.md +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/cross-cutting-concerns.md +72 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/data-modeling-and-migrations.md +79 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/data-platform-architecture.md +210 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/dependency-platform.md +105 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/developer-tooling-architecture.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/error-contract-architecture.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/event-driven-architecture.md +260 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/http-gateway-architecture.md +74 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/mq-consumer-architecture.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/multi-tenant-isolation.md +275 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/notification-architecture.md +25 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/ops-checklist.md +57 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/performance-capacity-architecture.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/protobuf-contract-architecture.md +119 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/redis-cache-coordination.md +93 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/release-runtime-readiness.md +65 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/replay-comparison-architecture.md +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/runtime-observability.md +94 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/service-scaffold.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/source-evidence-map.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/workflow-state-architecture.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/SKILL.md +159 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/artifact-generation-patterns.md +37 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/audit-history-patterns.md +28 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/bulk-import-export-patterns.md +56 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/config-rule-routing-patterns.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/data-access-patterns.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/db-schema-and-dal-patterns.md +109 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/dependency-client-patterns.md +130 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/developer-tooling-patterns.md +70 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/domain-feature-patterns.md +78 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/engineering-patterns.md +119 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/error-contract-patterns.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/feature-playbook.md +61 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/http-gateway-client-patterns.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/mq-consumer-patterns.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/notification-patterns.md +42 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/observability-implementation-patterns.md +101 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/performance-capacity-patterns.md +44 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/protobuf-contract-patterns.md +72 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/public-api-integration-patterns.md +56 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/quality-and-testing-patterns.md +91 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/redis-cache-lock-patterns.md +123 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/release-ops-patterns.md +112 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/reliability-patterns.md +83 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/replay-comparison-patterns.md +32 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/scaffold-and-codegen.md +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/source-evidence-map.md +54 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/state-machine-task-patterns.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/grill-me/SKILL.md +80 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/grill-me/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/SKILL.md +117 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-approval-auto-reviewer.md +106 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-command-sandbox.md +441 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-context-freshness.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-credentials-auth.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-extensions-skills.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-file-edit-protocol.md +129 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-ide-integration.md +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-input-ingestion.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-instruction-composition.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-lifecycle-hooks.md +92 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-messaging.md +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-runtime-bootstrap.md +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-session-persistence.md +448 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-task-orchestration.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-tool-dispatch.md +123 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-turn-lifecycle.md +131 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/inference-capacity-operations.md +162 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/llm-client-gateway.md +156 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/model-prompt-evaluation.md +146 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/retrieval-agent-safety.md +273 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/SKILL.md +202 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/contracts-and-state.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/cross-stack-alignment.md +94 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/framework-choice.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/online-practice-uptake.md +56 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/platform-capabilities.md +91 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/product-page-checklist.md +40 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/qa-release.md +72 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/source-evidence-map.md +82 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/SKILL.md +103 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/agents/openai.yaml +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/references/multi-agent-delegation-playbook.md +100 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/SKILL.md +70 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/public-data-acquisition.md +549 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/public-disclosure-channels.md +97 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/research-prompts.md +66 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/scripts/AGENTS.md +32 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/scripts/test-public-data-acquisition-recipes.sh +379 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/SKILL.md +244 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/alerting-and-on-call.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/framework-middleware-checklist.md +142 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/infra-component-deployment.md +268 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/log-correlation-recipe.md +124 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/log-schema-canonical.md +208 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/metrics-conventions.md +105 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/obs-stack-architecture.md +107 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/sli-slo-design.md +95 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/source-register.md +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/SKILL.md +303 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/canary-and-rollout-strategy.md +163 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/config-center-via-etcd.md +245 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/custom-control-plane-boundary.md +298 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/deploy-cli-concrete-recipe.md +312 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/deploy-pipeline.md +165 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/env-and-lane-matrix.md +126 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/lane-orchestration-control-plane.md +383 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/multi-region-and-cluster.md +135 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/promotion-gate-and-review.md +149 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/python-package-registry-release.md +462 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/rollback-playbook.md +123 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/secret-and-config-management.md +231 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/version-authority-and-deprecation.md +21 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/SKILL.md +276 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/dual-sidecar-and-traffic-config-center.md +127 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/framework-middleware.md +143 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/grpc-authority-workaround.md +90 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/http-response-envelope-contract.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/mesh-architecture.md +127 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/multi-env-routing.md +192 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/protobuf-http-contract-signals.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/retry-timeout-circuit-breaker.md +124 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/rpc-framework-recipe.md +494 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-choice.md +113 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-migration-playbook.md +231 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-recipe.md +131 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/SKILL.md +235 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/adr-convention.md +146 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-checklist.md +30 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-evaluation-report-template.md +25 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-execution-spec.md +108 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-sop.md +457 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-templates.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/artifact-egress-confidentiality.md +58 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/code-review-checklist.md +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/cross-repo-coordination.md +46 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/delivery-lifecycle.md +192 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-review-gate-mechanics.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-routing-and-readiness.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/diagnostic-spec-match-gate.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/dispatch-owner-skills.md +35 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/dormant-code-activation.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/existing-project-assessment-report.md +223 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/external-skill-augmentation.md +46 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/feature-deprecation-cascade.md +15 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/high-risk-resilience-gates.md +73 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/implementation-completeness-and-minimality.md +120 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/implementation-entry-reentry-gate.md +122 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/modular-monolith-heuristic.md +105 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/pre-final-continuation-gate.md +115 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/problem-resolution-and-learning.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/quality-attributes.md +112 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/quality-remediation-program.md +88 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/rd-standards-doc-family-checklist.md +27 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/refactoring-discipline.md +52 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/review-reception.md +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/shared-gate-artifact-classification.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/source-evidence-map.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/status-tracker-sync.md +77 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/sync-spec-repo-contract.md +25 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/verify-developer-experience.md +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/worktree-mechanics.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/scripts/AGENTS.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/scripts/check-agent-contract-coverage.sh +213 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/SKILL.md +136 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/agents/openai.yaml +9 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/analytics-visualization-interactions.md +206 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/behavioral-aesthetic-logic.md +108 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/complex-creation-interactions.md +194 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-execution-checklist.md +214 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-impl-naming-and-versioning.md +53 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-intake-and-acceptance.md +129 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-system-source-of-truth.md +97 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/external-ui-ux-quality-benchmarks.md +79 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/frontend-code-evidence-map.md +63 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/interaction-design-patterns.md +146 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/layout-recipes-and-screenshot-acceptance.md +250 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-project-token-consistency.md +237 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-stack-strategy.md +65 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/operational-processing-workflows.md +237 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/platform-mobile-patterns.md +324 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/platform-web-desktop-patterns.md +456 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-lifecycle-acceptance-and-iteration.md +114 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-surface-patterns.md +79 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/resource-management-interactions.md +113 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/scenario-community-patterns.md +133 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/source-map.md +130 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/tokens-and-components.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/trust-sensitive-ai-and-data-patterns.md +96 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-audit.md +106 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-design-development.md +176 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/visual-craft.md +111 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/SKILL.md +157 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/ai-service-integration-boundaries.md +57 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/api-contract-and-schema.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/api-security-boundaries.md +39 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/architecture-playbook.md +46 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/async-execution-model.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/background-jobs-and-scheduling.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/batch-and-pipeline-architecture.md +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/config-secrets-runtime.md +22 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/data-modeling-and-migrations.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/data-platform-architecture.md +211 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/event-driven-architecture.md +263 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/multi-tenant-isolation.md +281 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/observability-and-ops.md +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/packaging-runtime-readiness.md +20 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/redis-cache-coordination.md +41 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/reliability-and-error-contract.md +17 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/source-evidence-map.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/web-framework-boundaries.md +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/SKILL.md +143 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/ai-service-wiring-patterns.md +16 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/async-and-worker-patterns.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/background-job-patterns.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/batch-and-artifact-patterns.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/dependency-client-patterns.md +39 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/error-handling-patterns.md +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/feature-playbook.md +43 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/observability-implementation-patterns.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/project-structure-and-tooling.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/public-api-security-patterns.md +52 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/redis-cache-lock-patterns.md +78 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/schema-and-validation-patterns.md +23 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/source-evidence-map.md +56 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/sqlalchemy-and-migrations-patterns.md +99 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/testing-and-quality-patterns.md +61 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/web-framework-patterns.md +35 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/SKILL.md +91 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/config-runtime-readback.md +20 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/mr-merge-authorization.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/post-release-env-reset.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/release-closeout-evidence.md +20 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/release-scope-confirmation.md +21 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/tag-and-prod-pipeline-gate.md +20 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/test-scope-prompt.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/watcher-discipline.md +14 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/SKILL.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/references/comment-safe-release-doc.md +19 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/references/release-evidence-workflow.md +23 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/references/release-testing-scope-section.md +15 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-baseline/SKILL.md +87 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-baseline/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/SKILL.md +130 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/references/prd-composition-contract.md +35 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/references/requirement-closure-contract.md +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/references/security-four-questions.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-intent/SKILL.md +91 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-intent/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-scope/SKILL.md +88 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-scope/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/SKILL.md +337 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/analysis-parse-fix-test-challenge-replay.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/attribution-verification.md +69 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/bootstrap-slim-c3-obligation-table.md +112 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/coverage-exhaustion-traps.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/description-authoring.md +162 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/dual-track-review-gate.md +507 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/eval-routing.md +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/evidence-card-template.md +51 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/example-domain-preselect.md +79 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/external-practice-controls.md +57 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-lifecycle-handoff.md +65 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-quickstart.md +194 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/firing-point-placement.md +75 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/harness-patterns-and-eval.md +286 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/incident-postmortem-extraction.md +190 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/l0-l1-l2-routing.md +114 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/online-skill-review.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/parallel-stack-references-pattern.md +164 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/r0-leakage-audit.md +90 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/recurring-anti-patterns-checklist.md +320 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/resume-paused-delivery.md +16 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/review-feedback-mining.md +33 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/review-finding-standards.md +57 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/review-rubric.md +40 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/rule-consolidation.md +118 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/skill-listing-budget.md +19 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +254 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-to-skill-extraction.md +658 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/two-source-extraction-pattern.md +167 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/uiux-judgment-extraction.md +179 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/uiux-routing-map.md +51 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/validation-and-landing.md +180 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/AGENTS.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-ccl-skills.sh +1452 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-evidence-card-leak.sh +491 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-mr-target-freshness.sh +173 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-size-budget.sh +488 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-sync-pointers.sh +419 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-golden-trace.rb +197 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-health.rb +327 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-routing-bank.rb +401 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-routing.rb +248 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/generic-r0-leak-scan.sh +282 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/governing-chain-diff.py +321 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb +964 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/register-firing-path-resolution.rb +708 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/skill-behavior-eval.py +540 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/source-register-lifecycle.rb +51 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/source-register-pending-status.rb +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_ai_coding_implementation_gates.sh +829 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_impact_chain_refscripts.sh +1203 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_r0_status.sh +75 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_register_pending_exclusion.sh +137 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_regressions.sh +173 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_route_drift.sh +377 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_size_budget.sh +833 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_skill_catalog.sh +491 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_source_register_lifecycle.sh +114 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_mr_target_freshness.sh +261 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_sync_pointers.sh +538 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_controlled_escalation_pins.sh +154 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_grader_diagnostics.sh +190 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_surface_binding.sh +178 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_prose_target.sh +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_generic_r0_leak_scan.sh +131 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_git_identity_predicate_gate.sh +243 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_governing_chain_diff.sh +419 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_gate_dateless_host.sh +120 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_resolution.sh +724 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_wiring.sh +414 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_regression_runner_registration.sh +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_routing_bank_integrity.sh +205 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_routing_pointer_integrity.sh +194 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_credential_cwd.sh +61 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_cross_refs.sh +111 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_root_depth.sh +53 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/validate-skill.sh +257 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/SKILL.md +98 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/references/input-state-machines.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/references/streaming-rich-output.md +130 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/references/terminal-side-channels.md +96 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/SKILL.md +408 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/AGENTS.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/bitable-setup.md +573 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/README.md +120 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/github-actions.yml +119 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/gitlab-ci.yml +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/jenkins.Jenkinsfile +106 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/classical-test-design-techniques.md +279 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/gen_report.py +2807 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/makefile-template.md +200 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/report-config-schema.md +272 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/run_pytestless.py +475 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/source-to-case-workflows.md +258 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc-marker-conventions.md +316 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc-review-and-prioritization.md +145 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/AGENTS.md +16 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.dart +129 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.go +197 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.py +135 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.ts +285 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/test_gen_report.py +2144 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/update-lifecycle.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/SKILL.md +212 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/ci-fixtures-and-flake-control.md +75 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/client-runtime-test-matrices.md +50 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/data-and-workflow-testing.md +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/design-closed-contract-oracles.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/e2e-real-flow-testing.md +71 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/fitness-functions.md +240 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/integration-contract-testing.md +235 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/non-functional-specialized-scenarios.md +296 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/rd-testing-standard-template.md +126 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/run-killing-mutation-walk.md +43 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/scenario-testing.md +136 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/source-evidence-map.md +59 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/structured-tc-input-translation.md +67 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-code-authoring-patterns.md +392 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-data-and-determinism.md +39 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-topology-and-commands.md +92 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/unit-testing.md +46 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/vendored-contract-drift-checklist.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/verify-enforcement-mechanisms.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/AGENTS.md +17 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/client-terminal-ansi-check.py +140 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/client-terminal-ansi-check.test.sh +75 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-ast-check.py +170 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-ast-check.test.sh +87 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-go-check.go +198 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-go-check.test.sh +109 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/test_mutation_backup_recipe.sh +237 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/SKILL.md +184 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/comment-safe-feishu.md +93 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/cross-model-co-review.md +3 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/delivery-face-closeout.md +60 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/doc-charter-first.md +17 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/session-vantage-leakage.md +58 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/SKILL.md +126 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/complex-workspace-patterns.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/embedded-h5-in-host.md +87 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/react-architecture.md +194 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/source-evidence-map.md +60 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/web-quality-release.md +190 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/web-ui-quality.md +83 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/SKILL.md +179 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/references/shared-branch-rebase.md +25 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/AGENTS.md +23 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/test_worktree_status.sh +207 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/test_worktree_sweep.sh +481 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/worktree-status.sh +325 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/worktree-sweep.sh +245 -0
- package/dist/assets/release.json +2797 -0
- package/dist/claude-adapter.d.ts +9 -0
- package/dist/claude-adapter.js +240 -0
- package/dist/cli-worker.d.ts +1 -0
- package/dist/cli-worker.js +32 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.js +214 -0
- package/dist/codex-host.d.ts +30 -0
- package/dist/codex-host.js +162 -0
- package/dist/fs-safe.d.ts +21 -0
- package/dist/fs-safe.js +241 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/manifest.d.ts +8 -0
- package/dist/manifest.js +135 -0
- package/dist/opencode-adapter.d.ts +10 -0
- package/dist/opencode-adapter.js +416 -0
- package/dist/operations.d.ts +3 -0
- package/dist/operations.js +956 -0
- package/dist/paths.d.ts +20 -0
- package/dist/paths.js +4 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.js +1 -0
- package/dist/unified.d.ts +4 -0
- package/dist/unified.js +64 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +5 -0
- package/package.json +35 -0
|
@@ -0,0 +1,1156 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PreToolUse guard — merge-authorization hard gate (Bash tool only).
|
|
3
|
+
#
|
|
4
|
+
# WHY: merge authorization used to be prose-only (bootstrap 硬纪律 1 /
|
|
5
|
+
# worktree-isolation 合并执行协议). In a continuous commit→push→MR flow an
|
|
6
|
+
# agent can slide past the prose and auto-merge to main. This guard is the
|
|
7
|
+
# mechanical control at the firing moment: it DENIES merge-executing commands
|
|
8
|
+
# so the agent must stop at the pending-review MR. It complements
|
|
9
|
+
# guard-edit-isolation.sh (which guards edits; this guards landings).
|
|
10
|
+
#
|
|
11
|
+
# DENY set (best-effort string heuristic over the Bash tool's command):
|
|
12
|
+
# - `glab mr merge ...`
|
|
13
|
+
# - `gh pr merge ...`
|
|
14
|
+
# - `glab api ... merge_requests/<id>/merge` (platform merge API)
|
|
15
|
+
# - `git push` whose refspec targets the default branch (main/master,
|
|
16
|
+
# incl. `HEAD:main`, `feat:main`, `:main`), or a bare `git push`/`push
|
|
17
|
+
# origin`/`push origin HEAD` while the current branch IS the default
|
|
18
|
+
# - `git merge ...` executed while the current branch IS the default
|
|
19
|
+
# branch (merging INTO main locally). Carve-out: `git merge --ff-only
|
|
20
|
+
# origin/<default>` on the default branch stays allowed (post-merge local
|
|
21
|
+
# sync is sanctioned by product-rd-workflow).
|
|
22
|
+
# ALLOW (must not false-positive): push to non-default branches; local
|
|
23
|
+
# merge/rebase between dev branches; merging main INTO a feature branch;
|
|
24
|
+
# glab/gh view/create/list; quoted mentions (commit messages) are masked.
|
|
25
|
+
#
|
|
26
|
+
# RELEASE VALVE (user-directive — specs:
|
|
27
|
+
# specs/007-merge-gate-user-directive-valve/spec.md +
|
|
28
|
+
# specs/008-batch-merge-grant/spec.md): the prose contract says the USER's
|
|
29
|
+
# explicit merge directive ("合并"/"merge") IS the authorization.
|
|
30
|
+
# hooks/merge-authorization-prompt.sh (UserPromptSubmit) observes the
|
|
31
|
+
# harness-delivered human prompt and arms a session-scoped sentinel; at the
|
|
32
|
+
# would-deny moment this guard consumes it and ALLOWS platform merge shapes
|
|
33
|
+
# only (glab mr merge / gh pr merge / merge API / merge GraphQL). Two grant
|
|
34
|
+
# kinds:
|
|
35
|
+
# `armed` / `armed <id>` — ONE-SHOT (≤60 min), optionally bound to an
|
|
36
|
+
# MR/PR number ("merge !546").
|
|
37
|
+
# `armed batch <N>` — COUNTED batch (≤240 min from arming), armed by
|
|
38
|
+
# "批量合并 <N>": each platform merge consumes ONE
|
|
39
|
+
# unit; unbound by design (dependent-repo MRs do
|
|
40
|
+
# not exist yet when a dependency chain starts) —
|
|
41
|
+
# the duty to merge only the presented release
|
|
42
|
+
# plan stays prose (worktree-isolation 合并执行
|
|
43
|
+
# 协议). Any new user prompt revokes the rest.
|
|
44
|
+
# Direct default-branch advancement (git push main, git merge on main, …)
|
|
45
|
+
# is NEVER released by the valve — the sanctioned landing path is the MR.
|
|
46
|
+
# The sentinel is legitimately written only by the prompt hook; an agent
|
|
47
|
+
# forging it via Bash is deliberate circumvention, same declared
|
|
48
|
+
# out-of-scope class as the obfuscation exclusions below.
|
|
49
|
+
#
|
|
50
|
+
# Degrade semantics (per hooks/AGENTS.md):
|
|
51
|
+
# - jq or git missing → visible warning, NOT enforced (do not brick Bash).
|
|
52
|
+
# - Internal parse errors → fail-open (allow), same as the edit guard.
|
|
53
|
+
# - The deny itself is fail-closed for the matched command shapes: an agent
|
|
54
|
+
# cannot self-clear this gate. Release paths: the user's explicit merge
|
|
55
|
+
# directive (valve above) or a human disabling the hook via /hooks.
|
|
56
|
+
# - Valve failure modes (no session_id, unreadable/stale/foreign sentinel,
|
|
57
|
+
# malformed grant/count, session lock unavailable) fall back to deny —
|
|
58
|
+
# fail-closed.
|
|
59
|
+
# Enforcement is Claude-Code-hard only; hosts that ignore PreToolUse deny
|
|
60
|
+
# (e.g. Codex) get advisory coverage via bootstrap + worktree-isolation.
|
|
61
|
+
# NOT a security boundary: obfuscation (eval, subshell, interpreter -e,
|
|
62
|
+
# xargs) is out of scope — this catches the ROUTINE direct spellings.
|
|
63
|
+
# Also out of scope by the same declaration: branch names reaching push/merge
|
|
64
|
+
# through variable expansion or command substitution (`git push origin
|
|
65
|
+
# $BRANCH`, `$(echo main)`) — the guard cannot evaluate shell expansion and
|
|
66
|
+
# refusing every `$` token would over-block routine scripted feature pushes.
|
|
67
|
+
# `cd`/`git checkout`/`git switch` in EARLIER segments of the same command
|
|
68
|
+
# ARE tracked (they are routine spellings, not obfuscation).
|
|
69
|
+
# Redirections are stripped so routine plumbing (`… 2>&1 | tail`, `… >log`,
|
|
70
|
+
# `… main>/log` attached, `… origin main 2>&1` trailing) does not misparse (see
|
|
71
|
+
# the token-strip block below). Declared best-effort gaps in the SAME
|
|
72
|
+
# non-adversarial spirit — a cooperating developer never types these, each
|
|
73
|
+
# pinned by an allow-probe so a future tightening is a visible upgrade, and all
|
|
74
|
+
# PRE-EXISTING (the pre-redirection-fix guard allowed them too):
|
|
75
|
+
# 1. An `&`-bearing fd-dup redirect (`2>&1`, `1>&2`, `&>`) placed BEFORE the
|
|
76
|
+
# complete refspec: the `tr … '&' …` segment split (unchanged by this fix)
|
|
77
|
+
# tears the refspec off the command — `2>&1 git push main`,
|
|
78
|
+
# `git push 2>&1 origin main`. (`git push origin main 2>&1`, redirect AFTER
|
|
79
|
+
# the full refspec, is handled correctly.)
|
|
80
|
+
# 2. A digit-led redirect used as a command PREFIX that hides the command word
|
|
81
|
+
# (`10>/log git push main`, `2>/dev/null git push main`).
|
|
82
|
+
# 3. Heredoc bodies (`<<EOF`… whose data lines are walked as commands).
|
|
83
|
+
# Raw HTTP merge REST coverage reuses the SAME normalized segment and release
|
|
84
|
+
# valve as glab/gh; it is not a second shell tokenizer or grant state machine.
|
|
85
|
+
# Routine direct `curl` PUT spellings (`-X`/`--request`, upload-file implicit
|
|
86
|
+
# PUT) and `wget --method PUT` are classified for exact GitLab v4 and GitHub
|
|
87
|
+
# REST merge paths on any non-empty HTTP(S) host. Query/fragment are removed;
|
|
88
|
+
# path case is preserved and percent escapes are not decoded. Header, body,
|
|
89
|
+
# output, referer, DoH, proxy, and user-agent values are not URL operands.
|
|
90
|
+
# An unrecognized option adjacent to a merge-shaped value is ambiguous and
|
|
91
|
+
# cannot consume a grant. Repeated curl request options follow curl's
|
|
92
|
+
# last-option-wins rule; conflicting wget methods, curl `--next` with a changed
|
|
93
|
+
# method, and multiple merge URLs deny without consuming a grant.
|
|
94
|
+
# Deliberate command construction remains out of scope with the general
|
|
95
|
+
# non-security-boundary declaration above: dynamic/eval/interpreter/xargs URLs,
|
|
96
|
+
# external curl/wget config, and encoded path or command obfuscation. The raw
|
|
97
|
+
# HTTP allow/deny probes in test_guard_merge_authorization.sh pin each boundary.
|
|
98
|
+
|
|
99
|
+
# Tokenization below uses unquoted word-splitting on purpose; disable
|
|
100
|
+
# pathname expansion so a `*` in the command cannot glob the filesystem.
|
|
101
|
+
set -f
|
|
102
|
+
|
|
103
|
+
input=$(cat)
|
|
104
|
+
|
|
105
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
106
|
+
printf '{"systemMessage":"⚠️ merge-authorization guard degraded: jq not found; merge gate NOT enforced this session"}\n'
|
|
107
|
+
exit 0
|
|
108
|
+
fi
|
|
109
|
+
if ! command -v git >/dev/null 2>&1; then
|
|
110
|
+
printf '{"systemMessage":"⚠️ merge-authorization guard degraded: git not found; merge gate NOT enforced this session"}\n'
|
|
111
|
+
exit 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
cmd=$(printf '%s' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
115
|
+
[ -z "$cmd" ] && exit 0
|
|
116
|
+
cwd=$(printf '%s' "$input" | jq -r '.cwd // empty' 2>/dev/null)
|
|
117
|
+
[ -n "$cwd" ] && [ -d "$cwd" ] || cwd=$(pwd)
|
|
118
|
+
|
|
119
|
+
# Release-valve sentinel (armed by hooks/merge-authorization-prompt.sh on an
|
|
120
|
+
# explicit user merge directive; consumed below on platform merge shapes —
|
|
121
|
+
# one-shot grants whole, batch grants one unit at a time). KEEP IN SYNC with
|
|
122
|
+
# that script's path derivation and lock protocol.
|
|
123
|
+
sid=$(printf '%s' "$input" | jq -r '.session_id // empty' 2>/dev/null)
|
|
124
|
+
tpath=$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/null)
|
|
125
|
+
case "$sid" in */*|*..*) sid="" ;; esac # session_id is a path component
|
|
126
|
+
sentinel=""; lock_dir=""
|
|
127
|
+
if [ -n "$sid" ]; then
|
|
128
|
+
sentinel="${TMPDIR:-/tmp}/ccl-skills-merge-auth-$(id -u)/$sid"
|
|
129
|
+
lock_dir="${TMPDIR:-/tmp}/ccl-skills-merge-auth-$(id -u)/$sid.lock"
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# Per-session critical-section lock shared with the prompt hook (review P1):
|
|
133
|
+
# the guard's parse→consume→batch-re-arm sequence must not interleave with
|
|
134
|
+
# the prompt hook's revoke/arm, or a user's kill-switch message could be
|
|
135
|
+
# lost between the atomic consume (mv) and the batch re-create. Stale locks
|
|
136
|
+
# (≥1 min — critical sections are milliseconds) are broken.
|
|
137
|
+
acquire_lock() {
|
|
138
|
+
i=0
|
|
139
|
+
while ! mkdir "$lock_dir" 2>/dev/null; do
|
|
140
|
+
i=$((i+1))
|
|
141
|
+
if [ "$i" -ge 20 ]; then
|
|
142
|
+
if [ -z "$(find "$lock_dir" -mmin -1 2>/dev/null)" ]; then
|
|
143
|
+
rm -rf "$lock_dir" 2>/dev/null
|
|
144
|
+
mkdir "$lock_dir" 2>/dev/null && return 0
|
|
145
|
+
fi
|
|
146
|
+
return 1
|
|
147
|
+
fi
|
|
148
|
+
sleep 0.05
|
|
149
|
+
done
|
|
150
|
+
return 0
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
deny() {
|
|
154
|
+
jq -nc --arg r "$1" \
|
|
155
|
+
'{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:$r}}'
|
|
156
|
+
exit 0
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
DENY_TEXT_MR="合并授权闸:该命令会合并 MR/PR。合并需要用户明确下达合并指令——用户在下一条消息中单独回复\"合并\"或\"merge\"即可一次性放行本类命令;链式/多仓发布可单独回复\"批量合并 <N>\"(如:批量合并 30)一次授权 N 个平台合并(武装后 4 小时内有效,用户发送任何新消息即取消剩余额度)。均由 UserPromptSubmit 哨兵机器核验,agent 不能代替用户回复;在此之前把 MR 链接、分支、head SHA、CI 状态(批量场景为发布计划)展示给用户并停在待审状态。"
|
|
160
|
+
DENY_TEXT_GIT="合并授权闸:该命令会直接推进 main/默认分支(push/merge/pull 到默认分支)。该形态不适用用户回复\"合并\"的放行阀——落地必须走 MR 流程(push 功能分支 → MR → 用户授权后平台合并);人工确需直推可经 /hooks 关闭本闸。"
|
|
161
|
+
# Same deny, accurate reason. This闸 reads the command TEXT, so a `-C`/--git-dir/
|
|
162
|
+
# --work-tree target written as a shell variable cannot be expanded here; the branch
|
|
163
|
+
# context then falls back to the cwd (fail-closed, because that unknown path may be
|
|
164
|
+
# the default checkout). Tell the caller how to make it decidable instead of letting
|
|
165
|
+
# them read it as "the gate is broken" — merging main INTO a feature worktree is
|
|
166
|
+
# explicitly allowed, it just has to be legible.
|
|
167
|
+
DENY_TEXT_GIT_UNRESOLVED="合并授权闸:命令用 -C/--git-dir/--work-tree 指向了另一个仓库,但目标路径写成了 shell 变量,本闸读的是命令文本、展开不了,因此无法确认它不是默认分支检出——按闭式失败处理。若这是「把 main 合进功能分支/worktree」(允许的形态),把目标写成**字面绝对路径**(git -C /abs/path/to/worktree merge origin/main),或直接 cd 进该 worktree 再执行;若确实要推进 main/默认分支,仍按 MR 流程走。"
|
|
168
|
+
DENY_TEXT_AUTO="合并授权闸:该命令会开启 auto-merge / merge-when-pipeline-succeeds / 排队合并,或用 --admin 绕过平台检查。即便用户已授权合并,执行也必须一次性立即合并且不绕过检查(如 glab mr merge <iid> --auto-merge=false --yes),不得转 auto-merge/排队/--admin(见 worktree-isolation 合并执行协议);该形态不适用放行阀。"
|
|
169
|
+
DENY_TEXT_SPELL="合并授权闸:授权有效但命令拼写不满足一次性立即合并要求——glab 需显式 --auto-merge=false(pipeline 运行中裸 merge 会默认转 auto-merge),gh 需显式 --merge/--squash/--rebase 策略,merge REST API 需显式 -X PUT。授权未消费,按上述拼写改写命令直接重试即可(无需用户重新授权)。"
|
|
170
|
+
DENY_TEXT_TARGET="合并授权闸:用户授权指向了特定 MR/PR 编号,但该命令的合并对象与之不符或无法识别。授权未消费——请显式点名该编号(如 glab mr merge <授权编号> --auto-merge=false --yes)后重试;确需合并其他 MR 请让用户重新授权。"
|
|
171
|
+
DENY_TEXT_MULTI="合并授权闸:同一条命令内检测到多个平台合并调用。每条命令只放行一个合并——把命令拆开逐条执行(单个授权下每个合并由用户分别授权;批量授权下每条命令消费 1 个额度,无需用户再次回复)。"
|
|
172
|
+
DENY_TEXT_AMBIGUOUS="合并授权闸:检测到原始 HTTP 客户端、变更 method 的选项和 merge endpoint,但 method、transfer 边界、目标或动作数无法可靠关联。授权未消费——请改写成单个 curl/wget、单个明确 PUT method 和单个 merge URL 后重试。"
|
|
173
|
+
|
|
174
|
+
# Does any single quoted span of the raw command look like a GraphQL merge
|
|
175
|
+
# MUTATION? Per-span check (must contain `mutation` AND a merge-mutation
|
|
176
|
+
# name) so a compound command that merely MENTIONS the identifier in an
|
|
177
|
+
# unrelated quoted value (commit message, note body) cannot trip it.
|
|
178
|
+
graphql_merge_mutation() { # $1 = ERE of mutation names
|
|
179
|
+
printf '%s\n' "$cmd" | grep -Eo '"[^"]*"|'"'[^']*'" | grep -E 'mutation' | grep -Eq "$1"
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# Print the numeric MR/PR id when a raw HTTP URL is exactly one supported
|
|
183
|
+
# platform merge endpoint. The detector deliberately accepts any non-empty
|
|
184
|
+
# host (internal and public installations share authorization semantics),
|
|
185
|
+
# strips query/fragment without percent-decoding, and rejects path prefixes.
|
|
186
|
+
http_merge_id() { # $1 = normalized URL operand
|
|
187
|
+
hurl="$1"
|
|
188
|
+
case "$hurl" in
|
|
189
|
+
[Hh][Tt][Tt][Pp]://*|[Hh][Tt][Tt][Pp][Ss]://*) ;;
|
|
190
|
+
*) return 1 ;;
|
|
191
|
+
esac
|
|
192
|
+
authority_path="${hurl#*://}"
|
|
193
|
+
authority="${authority_path%%/*}"
|
|
194
|
+
[ -n "$authority" ] && [ "$authority_path" != "$authority" ] || return 1
|
|
195
|
+
hostport="${authority##*@}"
|
|
196
|
+
case "$hostport" in
|
|
197
|
+
\[*\]*) host="${hostport#\[}"; host="${host%%\]*}" ;;
|
|
198
|
+
*) host="${hostport%%:*}" ;;
|
|
199
|
+
esac
|
|
200
|
+
[ -n "$host" ] || return 1
|
|
201
|
+
hpath="/${authority_path#*/}"
|
|
202
|
+
hpath="${hpath%%\#*}"
|
|
203
|
+
hpath="${hpath%%\?*}"
|
|
204
|
+
mid=$(printf '%s\n' "$hpath" | sed -nE 's#^/api/v4/projects/[^/]+/merge_requests/([1-9][0-9]*)/merge/?$#\1#p')
|
|
205
|
+
if [ -z "$mid" ]; then
|
|
206
|
+
mid=$(printf '%s\n' "$hpath" | sed -nE 's#^/api/v3/repos/[^/]+/[^/]+/pulls/([1-9][0-9]*)/merge/?$#\1#p')
|
|
207
|
+
fi
|
|
208
|
+
if [ -z "$mid" ]; then
|
|
209
|
+
mid=$(printf '%s\n' "$hpath" | sed -nE 's#^/repos/[^/]+/[^/]+/pulls/([1-9][0-9]*)/merge/?$#\1#p')
|
|
210
|
+
fi
|
|
211
|
+
[ -n "$mid" ] || return 1
|
|
212
|
+
printf '%s\n' "$mid"
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
# Default branch of the repo at cwd; empty when cwd is not a git repo.
|
|
216
|
+
# origin/HEAD is the only per-repo authoritative signal, and it is frequently
|
|
217
|
+
# unset on cloned/CI repos (needs an explicit `git remote set-head`).
|
|
218
|
+
# Deliberately NO init.defaultBranch fallback: that is a new-repo template
|
|
219
|
+
# knob (often set globally on the host) and does not describe THIS repo's
|
|
220
|
+
# default — using it would silently mask the unresolved state. When the repo
|
|
221
|
+
# has an origin remote but origin/HEAD is unresolvable, the gate narrows to
|
|
222
|
+
# main|master and that degradation is made VISIBLE (warning below), not
|
|
223
|
+
# silent, or a develop/trunk-default repo bypasses the gate unnoticed.
|
|
224
|
+
default_branch=""
|
|
225
|
+
origin_exists=0
|
|
226
|
+
if git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then
|
|
227
|
+
git -C "$cwd" config --get remote.origin.url >/dev/null 2>&1 && origin_exists=1
|
|
228
|
+
default_branch=$(git -C "$cwd" symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')
|
|
229
|
+
fi
|
|
230
|
+
current_branch=$(git -C "$cwd" rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
231
|
+
# Hook-cwd baselines; git segments reset from these (a `git -C` overrides).
|
|
232
|
+
base_default_branch="$default_branch"
|
|
233
|
+
base_current_branch="$current_branch"
|
|
234
|
+
base_origin_exists="$origin_exists"
|
|
235
|
+
origin_flag="$origin_exists"
|
|
236
|
+
|
|
237
|
+
# Is this token the default-branch name? When the repo's default IS resolved
|
|
238
|
+
# (origin/HEAD), gate on that value alone — hardcoding main|master on top
|
|
239
|
+
# would over-block an ordinary non-default branch literally named `main`
|
|
240
|
+
# (common during trunk migrations). The main|master union is only the
|
|
241
|
+
# fallback for the unresolved case (which warns visibly below).
|
|
242
|
+
is_default_name() {
|
|
243
|
+
if [ -n "$default_branch" ]; then
|
|
244
|
+
[ "$1" = "$default_branch" ]
|
|
245
|
+
elif [ "$origin_flag" = 1 ]; then
|
|
246
|
+
# Origin exists but its default is unresolved: gate the COMMON
|
|
247
|
+
# default-branch names, not just main|master — dev/develop/trunk are
|
|
248
|
+
# integration branches in the wild and essentially never casual feature
|
|
249
|
+
# branches, so the over-block risk is negligible next to the bypass
|
|
250
|
+
# risk (and the visible warning below explains the narrowing).
|
|
251
|
+
case "$1" in
|
|
252
|
+
main|master|dev|develop|trunk) return 0 ;;
|
|
253
|
+
*) return 1 ;;
|
|
254
|
+
esac
|
|
255
|
+
else
|
|
256
|
+
# No origin remote (local-only repo): no remote MR flow to protect —
|
|
257
|
+
# keep the narrow main|master set so a local branch named dev/trunk
|
|
258
|
+
# is not blocked without any warning surface.
|
|
259
|
+
case "$1" in
|
|
260
|
+
main|master) return 0 ;;
|
|
261
|
+
*) return 1 ;;
|
|
262
|
+
esac
|
|
263
|
+
fi
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
# Quote handling, two-step: (1) quoted spans containing whitespace or shell
|
|
267
|
+
# metacharacters (prose: commit messages, MR titles) become QUOTED so
|
|
268
|
+
# `git commit -m "revert glab mr merge"` cannot false-positive; (2) remaining
|
|
269
|
+
# quotes around single words are stripped so `git push origin "main"` still
|
|
270
|
+
# resolves to the branch name instead of hiding behind the mask.
|
|
271
|
+
# Heredoc bodies stay a known best-effort gap.
|
|
272
|
+
# Stage 0 folds a backslash-escaped redirection metachar (`\<`, `\>`, `\&`) to a
|
|
273
|
+
# neutral letter: the shell passes it as a LITERAL word char, not syntax, so a
|
|
274
|
+
# refspec like `feature\>:main` (→ `feature>:main`, which targets `main`) or a
|
|
275
|
+
# bare `feature\> main` must not be read as a redirection later. Scoped to only
|
|
276
|
+
# `<>&` so an escaped command word (`\git`, a routine alias-bypass spelling)
|
|
277
|
+
# keeps its backslash for the `${1#\\}` normalization below and is unaffected.
|
|
278
|
+
# Order matters: fold escapes; strip query/fragment from a quoted single-word
|
|
279
|
+
# HTTP URL before the segment splitter can mistake its literal `&` for shell
|
|
280
|
+
# syntax; then unwrap single-word quotes (left-to-right pair consumption); then
|
|
281
|
+
# mask remaining metachar spans. A "span-with-whitespace" pattern run first
|
|
282
|
+
# would cross-pair a closing quote with the next opening one.
|
|
283
|
+
masked=$(printf '%s' "$cmd" | sed -E \
|
|
284
|
+
-e 's/\\([<>&])/X/g' \
|
|
285
|
+
-e 's/>\|/>/g' \
|
|
286
|
+
-e 's#"([Hh][Tt][Tt][Pp][Ss]?://[^"[:space:]?#]*)([?#][^"]*)"#"\1"#g' \
|
|
287
|
+
-e "s#'([Hh][Tt][Tt][Pp][Ss]?://[^'[:space:]?#]*)([?#][^']*)'#'\\1'#g" \
|
|
288
|
+
-e 's/"([^"[:space:];|&<>()]*)"/\1/g' \
|
|
289
|
+
-e "s/'([^'[:space:];|&<>()]*)'/\\1/g" \
|
|
290
|
+
-e 's/"[^"]*"/QUOTED/g' \
|
|
291
|
+
-e "s/'[^']*'/QUOTED/g")
|
|
292
|
+
# `>|` (clobber-override) is redirection-equivalent to `>`, but its `|` would be
|
|
293
|
+
# torn by the `tr ';|&(){}'` segment split below and strand the command word in
|
|
294
|
+
# a fragment (e.g. `git merge>|/log --ff-only origin/main` → the sync's flags
|
|
295
|
+
# split off, leaving a bare `git merge`). Fold it to `>` before the split. The
|
|
296
|
+
# `&`-bearing fd-dup operators (`2>&1`, `&>`) have the same tearing property but
|
|
297
|
+
# stay a declared best-effort gap — see the header — because normalizing them is
|
|
298
|
+
# ambiguous (the digit/`&` also carry fd meaning), whereas `>|`→`>` is exact.
|
|
299
|
+
|
|
300
|
+
# Walk simple-command segments (;, |, &&, ||, &, newlines, parens).
|
|
301
|
+
# Cross-segment state: `cd` moves the effective cwd for LATER segments
|
|
302
|
+
# (so `cd ../main-checkout && git push` is judged in the target repo), and
|
|
303
|
+
# `git checkout <branch>` / `git switch <branch>` moves the effective
|
|
304
|
+
# current branch (so `git checkout main && git merge feature` denies).
|
|
305
|
+
# The state lives inside the pipeline subshell — sequential by design.
|
|
306
|
+
eff_cwd="$cwd"
|
|
307
|
+
prev_cwd="" # last dir before the most recent cd/pushd (for `cd -`)
|
|
308
|
+
eff_branch="" # empty = ask the repo at eff_cwd
|
|
309
|
+
# Verdicts are TYPED: DENY_GIT (direct default-branch advancement — never
|
|
310
|
+
# released by the valve; emitting it breaks the walk, nothing can weaken it)
|
|
311
|
+
# vs DENY_MR (platform merge — valve-eligible; emitting it does NOT break,
|
|
312
|
+
# so a later DENY_GIT segment in the same compound command still registers).
|
|
313
|
+
# Collected via a temp file, not $(...): macOS bash 3.2 cannot parse case
|
|
314
|
+
# patterns inside command substitution. mktemp failure → fail-open (allow)
|
|
315
|
+
# with a VISIBLE degrade warning, same class as the jq/git degrades above —
|
|
316
|
+
# never a silent unenforced gate.
|
|
317
|
+
vfile=$(mktemp "${TMPDIR:-/tmp}/merge-guard-verdict.XXXXXX" 2>/dev/null) || {
|
|
318
|
+
printf '{"systemMessage":"⚠️ merge-authorization guard degraded: mktemp failed; merge gate NOT enforced for this command"}\n'
|
|
319
|
+
exit 0
|
|
320
|
+
}
|
|
321
|
+
printf '%s\n' "$masked" | tr ';|&(){}' '\n' | while IFS= read -r seg; do
|
|
322
|
+
# Strip leading whitespace and env VAR=x / transparent wrapper prefixes.
|
|
323
|
+
# Wrappers with their OWN arguments are walked properly: `timeout 30 git`,
|
|
324
|
+
# `nice -n 10 git`, `sudo -u bob git`, `env -i FOO=1 git` all land on the
|
|
325
|
+
# real command word instead of the wrapper's operand.
|
|
326
|
+
set -- $seg
|
|
327
|
+
# Reduce each token to the word the shell would hand the command, stripping
|
|
328
|
+
# REDIRECTIONS so they are not miscounted as git refspec args — the real
|
|
329
|
+
# defect was `git pull --ff-only origin main 2>&1 | tail -1` denying: the `&`
|
|
330
|
+
# split left `… origin main 2>` and `2>` counted as a third (non-default)
|
|
331
|
+
# refspec. Quote-masking already turned any quoted `>`/`<` into QUOTED, so a
|
|
332
|
+
# surviving operator here is real unquoted shell syntax. For each token with
|
|
333
|
+
# a `<`/`>`, split at the FIRST operator; `pre` is the word before it:
|
|
334
|
+
# • pre empty (operator-led `>file`, `<in`, bare `>`): a pure redirection →
|
|
335
|
+
# drop it; a bare operator also eats the following target word (`> file`).
|
|
336
|
+
# • pre has a non-digit (`main>/log`, `main2>/log`, `HEAD:main>/log`): a
|
|
337
|
+
# refspec/arg with an attached redirect → keep `pre`, drop the redirect.
|
|
338
|
+
# This is why `main>/log` still denies (keeps `main`) while `main2>/log`
|
|
339
|
+
# is allowed (keeps `main2`) — the shell lexes them exactly so.
|
|
340
|
+
# • pre all-digits (`2>`, `10>/dev/null`): a file descriptor ONLY after the
|
|
341
|
+
# git/glab/gh tool word (real plumbing like `2>&1`) → drop it; BEFORE the
|
|
342
|
+
# tool word an all-digit token is indistinguishable from a wrapper's
|
|
343
|
+
# numeric operand whose quotes were normalized away (`timeout '5'>/dev/null
|
|
344
|
+
# git …` → `timeout 5>/dev/null git …`), so keep it whole for the
|
|
345
|
+
# wrapper/command-word walk, or the wrapper would swallow `git`.
|
|
346
|
+
# KNOWN best-effort gaps (footgun reminder, not an adversarial boundary — see
|
|
347
|
+
# the header; each pinned by an allow-probe so a future tightening is visible):
|
|
348
|
+
# a DIGIT-led redirection used as a command PREFIX that hides the command word
|
|
349
|
+
# (`2>&1 git push…`, `10>/tmp/log git push…`), and heredoc bodies (`<<EOF`…).
|
|
350
|
+
rfiltered=""; rskip=0; seen_tool=0
|
|
351
|
+
for rtok in "$@"; do
|
|
352
|
+
if [ "$rskip" = 1 ]; then rskip=0; continue; fi
|
|
353
|
+
case "$rtok" in
|
|
354
|
+
*[\<\>]*)
|
|
355
|
+
pre="${rtok%%[<>]*}"; rest="${rtok#"$pre"}"
|
|
356
|
+
case "$pre" in
|
|
357
|
+
"")
|
|
358
|
+
# operator-led: bare operator eats its target word; else drop whole
|
|
359
|
+
case "$rtok" in
|
|
360
|
+
\>|\>\>|\<|\<\<|\<\<\<|\<\>|\>\|) rskip=1; continue ;;
|
|
361
|
+
*) continue ;;
|
|
362
|
+
esac ;;
|
|
363
|
+
*[!0-9]*)
|
|
364
|
+
# word + attached redirect → keep the word, drop the redirect.
|
|
365
|
+
# Deliberately NO rskip on a bare trailing operator (`main> file`):
|
|
366
|
+
# the space-separated form already denies on the pre-existing path
|
|
367
|
+
# (its target becomes a stray arg), so skipping the rskip loses
|
|
368
|
+
# nothing and stays fail-closed.
|
|
369
|
+
rfiltered="$rfiltered $pre"
|
|
370
|
+
# the kept word may itself BE the tool (`git>/tmp/out pull …`) — mark
|
|
371
|
+
# it before the `continue`, or a later `2>` stays unstripped and the
|
|
372
|
+
# pull parser miscounts it (false-deny of a valid sync)
|
|
373
|
+
bn="${pre##*/}"; bn="${bn#\\}"
|
|
374
|
+
case "$bn" in git|glab|gh|curl|wget) seen_tool=1 ;; esac
|
|
375
|
+
continue ;;
|
|
376
|
+
*)
|
|
377
|
+
# all-digit prefix: real fd only after the tool word
|
|
378
|
+
if [ "$seen_tool" = 1 ]; then
|
|
379
|
+
case "$rest" in
|
|
380
|
+
\>|\>\>|\<|\<\>|\>\|) rskip=1; continue ;;
|
|
381
|
+
*) continue ;;
|
|
382
|
+
esac
|
|
383
|
+
fi
|
|
384
|
+
# before the tool word → wrapper operand; keep whole (fall through)
|
|
385
|
+
;;
|
|
386
|
+
esac
|
|
387
|
+
;;
|
|
388
|
+
esac
|
|
389
|
+
bn="${rtok##*/}"; bn="${bn#\\}"
|
|
390
|
+
case "$bn" in git|glab|gh|curl|wget) seen_tool=1 ;; esac
|
|
391
|
+
rfiltered="$rfiltered $rtok"
|
|
392
|
+
done
|
|
393
|
+
set -- $rfiltered
|
|
394
|
+
[ $# -eq 0 ] && continue
|
|
395
|
+
while [ $# -gt 0 ]; do
|
|
396
|
+
case "$1" in
|
|
397
|
+
*=*) shift ;;
|
|
398
|
+
# Transparent prefixes: they execute the following word as the command.
|
|
399
|
+
# `exec`/`builtin` are POSIX special BUILTINS, not reserved words, so the
|
|
400
|
+
# reserved-word completeness argument below does not reach them — an
|
|
401
|
+
# earlier version of this fix claimed the class was closed while
|
|
402
|
+
# `exec git push origin main` still ALLOWed. `eval` stays out of scope by
|
|
403
|
+
# the header declaration (it takes a string to re-parse, not a command).
|
|
404
|
+
command|nohup|time|exec|builtin) shift ;;
|
|
405
|
+
# Leading shell keywords left by tokenizing on ;|&(){} — a loop/if body
|
|
406
|
+
# `for id in …; do glab mr merge …; done` splits to a `do glab …`
|
|
407
|
+
# segment (challenge R2 P0). Strip them so the routine loop spelling is
|
|
408
|
+
# still detected. (Dynamic merge COUNT under a loop stays a declared
|
|
409
|
+
# best-effort gap — see the not-a-security-boundary header.)
|
|
410
|
+
#
|
|
411
|
+
# This list is the COMPLETE set, derived from the POSIX reserved-word list
|
|
412
|
+
# (`! { } case do done elif else esac fi for if in then until while`) by
|
|
413
|
+
# asking which members can sit immediately before a simple command in a
|
|
414
|
+
# segment this tokenizer produces — NOT another word added because someone
|
|
415
|
+
# found one more bypass. `for`/`in`/`case` are followed by a word list, not
|
|
416
|
+
# a command; `fi`/`done`/`esac` terminate; `{`/`}` are already tokenizer
|
|
417
|
+
# delimiters. That leaves exactly these eight.
|
|
418
|
+
#
|
|
419
|
+
# An earlier version stripped only `do|then|else|elif`, so every one of
|
|
420
|
+
# these was a silent bypass of a gate whose whole job is to stop an
|
|
421
|
+
# unauthorized merge — `if <merge>; then …; fi` and `! <push to main>` are
|
|
422
|
+
# ordinary scripted spellings, not the eval/subshell obfuscation the header
|
|
423
|
+
# declares out of scope:
|
|
424
|
+
# if glab mr merge 546 --yes; then echo ok; fi -> was ALLOW, now DENY
|
|
425
|
+
# while glab mr merge 546 --yes; do echo x; done -> was ALLOW, now DENY
|
|
426
|
+
# ! git push origin main -> was ALLOW, now DENY
|
|
427
|
+
do|then|else|elif|if|while|until|'!') shift ;;
|
|
428
|
+
env)
|
|
429
|
+
shift
|
|
430
|
+
while [ $# -gt 0 ]; do
|
|
431
|
+
case "$1" in
|
|
432
|
+
-u|--unset) if [ $# -ge 2 ]; then shift 2; else shift; fi ;;
|
|
433
|
+
-*) shift ;;
|
|
434
|
+
*=*) shift ;;
|
|
435
|
+
*) break ;;
|
|
436
|
+
esac
|
|
437
|
+
done
|
|
438
|
+
;;
|
|
439
|
+
sudo|doas)
|
|
440
|
+
shift
|
|
441
|
+
while [ $# -gt 0 ]; do
|
|
442
|
+
case "$1" in
|
|
443
|
+
-u|-g|-h|-p) if [ $# -ge 2 ]; then shift 2; else shift; fi ;;
|
|
444
|
+
-*) shift ;;
|
|
445
|
+
*) break ;;
|
|
446
|
+
esac
|
|
447
|
+
done
|
|
448
|
+
;;
|
|
449
|
+
nice)
|
|
450
|
+
shift
|
|
451
|
+
while [ $# -gt 0 ]; do
|
|
452
|
+
case "$1" in
|
|
453
|
+
-n|--adjustment) if [ $# -ge 2 ]; then shift 2; else shift; fi ;;
|
|
454
|
+
-*) shift ;;
|
|
455
|
+
*) break ;;
|
|
456
|
+
esac
|
|
457
|
+
done
|
|
458
|
+
;;
|
|
459
|
+
timeout)
|
|
460
|
+
shift
|
|
461
|
+
while [ $# -gt 0 ]; do
|
|
462
|
+
case "$1" in
|
|
463
|
+
-k|--kill-after|-s|--signal) if [ $# -ge 2 ]; then shift 2; else shift; fi ;;
|
|
464
|
+
-*) shift ;;
|
|
465
|
+
*) break ;;
|
|
466
|
+
esac
|
|
467
|
+
done
|
|
468
|
+
[ $# -gt 0 ] && shift # the DURATION operand
|
|
469
|
+
;;
|
|
470
|
+
*) break ;;
|
|
471
|
+
esac
|
|
472
|
+
done
|
|
473
|
+
[ $# -eq 0 ] && continue
|
|
474
|
+
|
|
475
|
+
# Normalize the command word: `\git` and `/usr/bin/git` are routine
|
|
476
|
+
# spellings of the same tool, not obfuscation — match on the basename.
|
|
477
|
+
cmdword="${1#\\}"; cmdword="${cmdword##*/}"
|
|
478
|
+
|
|
479
|
+
case "$cmdword" in
|
|
480
|
+
cd|pushd)
|
|
481
|
+
t="${2:-}"
|
|
482
|
+
[ -z "$t" ] && { [ "$cmdword" = "cd" ] && { prev_cwd="$eff_cwd"; eff_cwd="$HOME"; }; eff_branch=""; continue; }
|
|
483
|
+
case "$t" in
|
|
484
|
+
/*) prev_cwd="$eff_cwd"; eff_cwd="$t" ;;
|
|
485
|
+
-)
|
|
486
|
+
# cd - : swap with the tracked previous dir (routine one-hop use);
|
|
487
|
+
# without one tracked, keep the current context.
|
|
488
|
+
if [ -n "$prev_cwd" ]; then
|
|
489
|
+
t="$eff_cwd"; eff_cwd="$prev_cwd"; prev_cwd="$t"
|
|
490
|
+
fi
|
|
491
|
+
;;
|
|
492
|
+
*) prev_cwd="$eff_cwd"; eff_cwd="$eff_cwd/$t" ;;
|
|
493
|
+
esac
|
|
494
|
+
eff_branch=""
|
|
495
|
+
continue
|
|
496
|
+
;;
|
|
497
|
+
popd)
|
|
498
|
+
# Single-level pushd/popd is the routine pattern; restore hook cwd.
|
|
499
|
+
prev_cwd="$eff_cwd"
|
|
500
|
+
eff_cwd="$cwd"
|
|
501
|
+
eff_branch=""
|
|
502
|
+
continue
|
|
503
|
+
;;
|
|
504
|
+
curl|wget)
|
|
505
|
+
tool="$cmdword"; shift
|
|
506
|
+
explicit_method=""; method_conflict=0; upload_seen=0; next_seen=0
|
|
507
|
+
operand_ambiguous=0; merge_count=0; first_mid=""
|
|
508
|
+
while [ $# -gt 0 ]; do
|
|
509
|
+
case "$1" in
|
|
510
|
+
-X|--request)
|
|
511
|
+
if [ "$tool" != curl ]; then
|
|
512
|
+
if [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
513
|
+
elif [ $# -ge 2 ]; then
|
|
514
|
+
next_method=$(printf '%s' "$2" | tr '[:lower:]' '[:upper:]')
|
|
515
|
+
explicit_method="$next_method"; shift 2
|
|
516
|
+
else method_conflict=1; shift
|
|
517
|
+
fi
|
|
518
|
+
;;
|
|
519
|
+
--method)
|
|
520
|
+
if [ "$tool" != wget ]; then
|
|
521
|
+
if [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
522
|
+
elif [ $# -ge 2 ]; then
|
|
523
|
+
next_method=$(printf '%s' "$2" | tr '[:lower:]' '[:upper:]')
|
|
524
|
+
if [ -n "$explicit_method" ] && [ "$explicit_method" != "$next_method" ]; then method_conflict=1; fi
|
|
525
|
+
explicit_method="$next_method"; shift 2
|
|
526
|
+
else method_conflict=1; shift
|
|
527
|
+
fi
|
|
528
|
+
;;
|
|
529
|
+
-X?*)
|
|
530
|
+
if [ "$tool" = curl ]; then
|
|
531
|
+
next_method=$(printf '%s' "${1#-X}" | tr '[:lower:]' '[:upper:]')
|
|
532
|
+
explicit_method="$next_method"
|
|
533
|
+
fi
|
|
534
|
+
shift
|
|
535
|
+
;;
|
|
536
|
+
--request=*)
|
|
537
|
+
if [ "$tool" = curl ]; then
|
|
538
|
+
next_method=$(printf '%s' "${1#*=}" | tr '[:lower:]' '[:upper:]')
|
|
539
|
+
explicit_method="$next_method"
|
|
540
|
+
fi
|
|
541
|
+
shift
|
|
542
|
+
;;
|
|
543
|
+
--method=*)
|
|
544
|
+
if [ "$tool" = wget ]; then
|
|
545
|
+
next_method=$(printf '%s' "${1#*=}" | tr '[:lower:]' '[:upper:]')
|
|
546
|
+
if [ -n "$explicit_method" ] && [ "$explicit_method" != "$next_method" ]; then method_conflict=1; fi
|
|
547
|
+
explicit_method="$next_method"
|
|
548
|
+
fi
|
|
549
|
+
shift
|
|
550
|
+
;;
|
|
551
|
+
-T|--upload-file)
|
|
552
|
+
[ "$tool" = curl ] && upload_seen=1
|
|
553
|
+
if [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
554
|
+
;;
|
|
555
|
+
-T?*) [ "$tool" = curl ] && upload_seen=1; shift ;;
|
|
556
|
+
--upload-file=*) [ "$tool" = curl ] && upload_seen=1; shift ;;
|
|
557
|
+
-O|--output-document)
|
|
558
|
+
if [ "$tool" = wget ] && [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
559
|
+
;;
|
|
560
|
+
--output-document=*) shift ;;
|
|
561
|
+
-s|--silent)
|
|
562
|
+
if [ "$tool" = curl ]; then
|
|
563
|
+
shift
|
|
564
|
+
else
|
|
565
|
+
if [ $# -ge 2 ] && http_merge_id "$2" >/dev/null; then operand_ambiguous=1; fi
|
|
566
|
+
shift
|
|
567
|
+
fi
|
|
568
|
+
;;
|
|
569
|
+
-x)
|
|
570
|
+
if [ "$tool" = curl ] && [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
571
|
+
;;
|
|
572
|
+
--doh-url|--proxy|--preproxy)
|
|
573
|
+
if [ "$tool" = curl ]; then
|
|
574
|
+
if [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
575
|
+
else
|
|
576
|
+
if [ $# -ge 2 ] && http_merge_id "$2" >/dev/null; then operand_ambiguous=1; fi
|
|
577
|
+
shift
|
|
578
|
+
fi
|
|
579
|
+
;;
|
|
580
|
+
-x?*) shift ;;
|
|
581
|
+
--doh-url=*|--proxy=*|--preproxy=*)
|
|
582
|
+
if [ "$tool" = curl ]; then
|
|
583
|
+
shift
|
|
584
|
+
else
|
|
585
|
+
if http_merge_id "${1#*=}" >/dev/null; then operand_ambiguous=1; fi
|
|
586
|
+
shift
|
|
587
|
+
fi
|
|
588
|
+
;;
|
|
589
|
+
-A|--user-agent)
|
|
590
|
+
if [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
591
|
+
;;
|
|
592
|
+
-A?*|--user-agent=*) shift ;;
|
|
593
|
+
-H|-d)
|
|
594
|
+
if [ "$tool" = curl ] && [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
595
|
+
;;
|
|
596
|
+
--header|--data|--data-ascii|--data-binary|--data-raw|--data-urlencode|--json|-o|--output|-e|--referer|--post-data|--post-file|--body-data|--body-file)
|
|
597
|
+
if [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
598
|
+
;;
|
|
599
|
+
-H?*|-d?*|-o?*|-e?*|--header=*|--data=*|--data-ascii=*|--data-binary=*|--data-raw=*|--data-urlencode=*|--json=*|--output=*|--referer=*|--post-data=*|--post-file=*|--body-data=*|--body-file=*) shift ;;
|
|
600
|
+
--next) [ "$tool" = curl ] && next_seen=1; shift ;;
|
|
601
|
+
--url)
|
|
602
|
+
if [ "$tool" = curl ] && [ $# -ge 2 ]; then
|
|
603
|
+
if candidate_mid=$(http_merge_id "$2"); then
|
|
604
|
+
merge_count=$((merge_count+1)); [ -n "$first_mid" ] || first_mid="$candidate_mid"
|
|
605
|
+
fi
|
|
606
|
+
fi
|
|
607
|
+
if [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
608
|
+
;;
|
|
609
|
+
--url=*)
|
|
610
|
+
if [ "$tool" = curl ] && candidate_mid=$(http_merge_id "${1#--url=}"); then
|
|
611
|
+
merge_count=$((merge_count+1)); [ -n "$first_mid" ] || first_mid="$candidate_mid"
|
|
612
|
+
fi
|
|
613
|
+
shift
|
|
614
|
+
;;
|
|
615
|
+
[Hh][Tt][Tt][Pp]://*|[Hh][Tt][Tt][Pp][Ss]://*)
|
|
616
|
+
if candidate_mid=$(http_merge_id "$1"); then
|
|
617
|
+
merge_count=$((merge_count+1)); [ -n "$first_mid" ] || first_mid="$candidate_mid"
|
|
618
|
+
fi
|
|
619
|
+
shift
|
|
620
|
+
;;
|
|
621
|
+
-*)
|
|
622
|
+
candidate_value=""
|
|
623
|
+
case "$1" in
|
|
624
|
+
*=*) candidate_value="${1#*=}" ;;
|
|
625
|
+
*) [ $# -ge 2 ] && candidate_value="$2" ;;
|
|
626
|
+
esac
|
|
627
|
+
if [ -n "$candidate_value" ] && http_merge_id "$candidate_value" >/dev/null; then
|
|
628
|
+
operand_ambiguous=1
|
|
629
|
+
fi
|
|
630
|
+
shift
|
|
631
|
+
;;
|
|
632
|
+
*) shift ;;
|
|
633
|
+
esac
|
|
634
|
+
done
|
|
635
|
+
method="$explicit_method"
|
|
636
|
+
[ -n "$method" ] || { [ "$upload_seen" = 1 ] && method=PUT || method=GET; }
|
|
637
|
+
if [ "$operand_ambiguous" = 1 ] && { [ "$method" = PUT ] || [ "$method_conflict" = 1 ]; }; then
|
|
638
|
+
echo DENY_HTTP_AMBIGUOUS
|
|
639
|
+
elif [ "$merge_count" -gt 0 ]; then
|
|
640
|
+
if [ "$method_conflict" = 1 ] || { [ "$next_seen" = 1 ] && { [ -n "$explicit_method" ] || [ "$upload_seen" = 1 ]; }; }; then
|
|
641
|
+
echo DENY_HTTP_AMBIGUOUS
|
|
642
|
+
else
|
|
643
|
+
if [ "$method" = PUT ]; then
|
|
644
|
+
echo "DENY_MR $first_mid SPELLOK"
|
|
645
|
+
[ "$merge_count" -gt 1 ] && echo "DENY_MR $first_mid SPELLOK"
|
|
646
|
+
fi
|
|
647
|
+
fi
|
|
648
|
+
fi
|
|
649
|
+
;;
|
|
650
|
+
glab|gh)
|
|
651
|
+
tool="$cmdword"; shift
|
|
652
|
+
# Skip global flags before the subcommand (`gh -R owner/repo pr merge`);
|
|
653
|
+
# value-taking globals also skip their value. `shift 2` is guarded so a
|
|
654
|
+
# trailing value-flag cannot leave $@ unchanged and spin the loop.
|
|
655
|
+
# retarget: an explicit -R/--repo/--hostname redirects the platform
|
|
656
|
+
# call away from the cwd repo — a number-bound grant must not release
|
|
657
|
+
# it (the bound number is only meaningful in the discussed repo).
|
|
658
|
+
retarget=0
|
|
659
|
+
while [ $# -gt 0 ]; do
|
|
660
|
+
case "$1" in
|
|
661
|
+
-R|--repo|--host|--hostname) retarget=1; if [ $# -ge 2 ]; then shift 2; else shift; fi ;;
|
|
662
|
+
-R=*|--repo=*|--host=*|--hostname=*) retarget=1; shift ;;
|
|
663
|
+
-*) shift ;;
|
|
664
|
+
*) break ;;
|
|
665
|
+
esac
|
|
666
|
+
done
|
|
667
|
+
# Each merge-executing SEGMENT emits exactly ONE verdict (hit=1 gate
|
|
668
|
+
# below): the valve's exactly-one-merge check counts DENY_MR lines,
|
|
669
|
+
# so double-emitting for one call (REST regex + GraphQL span check)
|
|
670
|
+
# would over-deny a legitimate single merge. Auto-merge/queued
|
|
671
|
+
# spellings become DENY_AUTO — NEVER released by the valve: even an
|
|
672
|
+
# authorized landing must merge immediately, not schedule (worktree-
|
|
673
|
+
# isolation 合并执行协议).
|
|
674
|
+
# hit: this segment executes a platform merge. auto: it schedules/
|
|
675
|
+
# queues or bypasses checks (never released). spell: SPELLOK when the
|
|
676
|
+
# spelling is guaranteed-immediate (glab explicit --auto-merge=false;
|
|
677
|
+
# gh explicit strategy; REST/GraphQL calls are immediate by API
|
|
678
|
+
# semantics). mid: the merge target id when statically extractable
|
|
679
|
+
# ("?" otherwise) — matched against a number-bound grant below.
|
|
680
|
+
hit=0; auto=0; spell=SPELLBAD; mid="?"; multi_seg=0
|
|
681
|
+
if [ "$tool" = "glab" ]; then
|
|
682
|
+
# `accept` is glab's documented alias of `mr merge` (same help text).
|
|
683
|
+
if [ "${1:-}" = "mr" ] && { [ "${2:-}" = "merge" ] || [ "${2:-}" = "accept" ]; }; then
|
|
684
|
+
hit=1; shift 2
|
|
685
|
+
while [ $# -gt 0 ]; do
|
|
686
|
+
case "$1" in
|
|
687
|
+
--auto-merge=false) spell=SPELLOK ;;
|
|
688
|
+
--auto-merge|--auto-merge=*|--when-pipeline-succeeds*) auto=1 ;;
|
|
689
|
+
-R|--repo|--host|--hostname) retarget=1; [ $# -ge 2 ] && shift ;;
|
|
690
|
+
-R=*|--repo=*|--host=*|--hostname=*) retarget=1 ;;
|
|
691
|
+
# value-taking flags: consume the value so it is not mistaken
|
|
692
|
+
# for the MR id positional (`glab mr merge --sha abc 546`).
|
|
693
|
+
--sha|-m|--message|--squash-message) [ $# -ge 2 ] && shift ;;
|
|
694
|
+
-*) : ;;
|
|
695
|
+
*)
|
|
696
|
+
if [ "$mid" = "?" ] && [ -z "${id_seen:-}" ]; then
|
|
697
|
+
id_seen=1
|
|
698
|
+
t="${1#!}"; t="${t##*#}"
|
|
699
|
+
case "$t" in
|
|
700
|
+
*[!0-9]*)
|
|
701
|
+
mid=$(printf '%s' "$t" | sed -n 's|.*/merge_requests/\([0-9][0-9]*\)$|\1|p')
|
|
702
|
+
[ -n "$mid" ] || mid="?"
|
|
703
|
+
;;
|
|
704
|
+
"") ;;
|
|
705
|
+
*) mid="$t" ;;
|
|
706
|
+
esac
|
|
707
|
+
fi
|
|
708
|
+
;;
|
|
709
|
+
esac
|
|
710
|
+
shift
|
|
711
|
+
done
|
|
712
|
+
unset id_seen
|
|
713
|
+
elif [ "${1:-}" = "api" ]; then
|
|
714
|
+
# Scan the MASKED segment: single-word quoted API paths survive the
|
|
715
|
+
# mask (quotes stripped), while prose values with whitespace (e.g.
|
|
716
|
+
# -f body="see merge_requests/9/merge") are already QUOTED and
|
|
717
|
+
# cannot false-positive here.
|
|
718
|
+
# Left boundary: path/URL starts ('/', '=', space, quote, start) —
|
|
719
|
+
# not a word char or '-', so `note=see-merge_requests/9/merge`
|
|
720
|
+
# (a mere reference inside a value) cannot trip it.
|
|
721
|
+
if printf '%s' "$seg" | grep -Eq '(^|[^a-zA-Z0-9_.-])merge_requests/[^ /]+/merge([^a-zA-Z_-]|$)'; then
|
|
722
|
+
hit=1
|
|
723
|
+
# REST release needs the explicit mutating method: glab/gh api
|
|
724
|
+
# default to GET, and a GET to the merge endpoint must not burn
|
|
725
|
+
# the one-shot grant (final-review P2).
|
|
726
|
+
printf '%s' "$seg" | grep -Eiq '(-X|--method)[= ]*(PUT|POST)' && spell=SPELLOK
|
|
727
|
+
mid=$(printf '%s' "$seg" | sed -n 's|.*[^a-zA-Z0-9_.-]merge_requests/\([0-9][0-9]*\)/merge.*|\1|p')
|
|
728
|
+
[ -n "$mid" ] || mid="?"
|
|
729
|
+
fi
|
|
730
|
+
# GraphQL merge mutation: quoted query bodies are prose-masked, so
|
|
731
|
+
# check quoted spans of the raw command (per-span, mutation-scoped)
|
|
732
|
+
# plus the masked segment for unquoted single-word forms. Gated on
|
|
733
|
+
# the SEGMENT actually calling a graphql endpoint, so a mutation
|
|
734
|
+
# string quoted inside an unrelated REST body (issue note, comment)
|
|
735
|
+
# cannot classify that segment as a merge (challenge round-2 P2).
|
|
736
|
+
if printf '%s' "$seg" | grep -qi 'graphql'; then
|
|
737
|
+
if printf '%s' "$seg" | grep -q 'mergeRequestAccept' \
|
|
738
|
+
|| graphql_merge_mutation 'mergeRequestAccept'; then
|
|
739
|
+
hit=1; spell=SPELLOK
|
|
740
|
+
# Multi-alias undercount (challenge R2 P0): a single GraphQL body
|
|
741
|
+
# can carry several aliased mergeRequestAccept fields → several
|
|
742
|
+
# platform merges. If more than one merge mutation appears, mark
|
|
743
|
+
# the segment multi so the exactly-one-per-command guard trips.
|
|
744
|
+
[ "$(printf '%s' "$cmd" | grep -o 'mergeRequestAccept' | grep -c .)" -gt 1 ] && multi_seg=1
|
|
745
|
+
fi
|
|
746
|
+
fi
|
|
747
|
+
if [ "$hit" = 1 ]; then
|
|
748
|
+
# REST auto-merge params (merge_when_pipeline_succeeds / auto_merge)
|
|
749
|
+
printf '%s' "$seg" | grep -Eq 'merge_when_pipeline_succeeds=(true|1)|auto_merge=(true|1)' && auto=1
|
|
750
|
+
fi
|
|
751
|
+
fi
|
|
752
|
+
else
|
|
753
|
+
if [ "${1:-}" = "pr" ] && [ "${2:-}" = "merge" ]; then
|
|
754
|
+
hit=1; shift 2
|
|
755
|
+
while [ $# -gt 0 ]; do
|
|
756
|
+
case "$1" in
|
|
757
|
+
--auto|--auto=true) auto=1 ;;
|
|
758
|
+
--admin) auto=1 ;; # bypasses checks/queue: never released
|
|
759
|
+
--merge|--squash|--rebase) spell=SPELLOK ;;
|
|
760
|
+
-R|--repo) retarget=1; [ $# -ge 2 ] && shift ;;
|
|
761
|
+
-R=*|--repo=*) retarget=1 ;;
|
|
762
|
+
# value-taking flags: consume the value so it is not mistaken
|
|
763
|
+
# for the PR id positional.
|
|
764
|
+
-b|--body|-F|--body-file|-t|--subject|--match-head-commit|-A|--author-email) [ $# -ge 2 ] && shift ;;
|
|
765
|
+
-*) : ;;
|
|
766
|
+
*)
|
|
767
|
+
if [ "$mid" = "?" ] && [ -z "${id_seen:-}" ]; then
|
|
768
|
+
id_seen=1
|
|
769
|
+
t="${1#!}"; t="${t##*#}"
|
|
770
|
+
case "$t" in
|
|
771
|
+
*[!0-9]*)
|
|
772
|
+
mid=$(printf '%s' "$t" | sed -n 's|.*/pull/\([0-9][0-9]*\)$|\1|p')
|
|
773
|
+
[ -n "$mid" ] || mid="?"
|
|
774
|
+
;;
|
|
775
|
+
"") ;;
|
|
776
|
+
*) mid="$t" ;;
|
|
777
|
+
esac
|
|
778
|
+
fi
|
|
779
|
+
;;
|
|
780
|
+
esac
|
|
781
|
+
shift
|
|
782
|
+
done
|
|
783
|
+
unset id_seen
|
|
784
|
+
elif [ "${1:-}" = "api" ]; then
|
|
785
|
+
# GitHub merge-API mirror of the glab path: pulls/<n>/merge.
|
|
786
|
+
if printf '%s' "$seg" | grep -Eq '(^|[^a-zA-Z0-9_.-])pulls/[^ /]+/merge([^a-zA-Z_-]|$)'; then
|
|
787
|
+
hit=1
|
|
788
|
+
# Same mutating-method requirement as the glab REST path.
|
|
789
|
+
printf '%s' "$seg" | grep -Eiq '(-X|--method)[= ]*(PUT|POST)' && spell=SPELLOK
|
|
790
|
+
mid=$(printf '%s' "$seg" | sed -n 's|.*[^a-zA-Z0-9_.-]pulls/\([0-9][0-9]*\)/merge.*|\1|p')
|
|
791
|
+
[ -n "$mid" ] || mid="?"
|
|
792
|
+
fi
|
|
793
|
+
# GraphQL merge mutations — segment-gated like the glab side.
|
|
794
|
+
if printf '%s' "$seg" | grep -qi 'graphql'; then
|
|
795
|
+
if printf '%s' "$seg" | grep -q 'mergePullRequest' \
|
|
796
|
+
|| graphql_merge_mutation 'mergePullRequest'; then
|
|
797
|
+
hit=1; spell=SPELLOK
|
|
798
|
+
# Multi-alias undercount (challenge R2 P0): see the glab side.
|
|
799
|
+
[ "$(printf '%s' "$cmd" | grep -o 'mergePullRequest' | grep -c .)" -gt 1 ] && multi_seg=1
|
|
800
|
+
fi
|
|
801
|
+
# enablePullRequestAutoMerge schedules an auto-merge: always AUTO.
|
|
802
|
+
if printf '%s' "$seg" | grep -q 'enablePullRequestAutoMerge' \
|
|
803
|
+
|| graphql_merge_mutation 'enablePullRequestAutoMerge'; then
|
|
804
|
+
hit=1; auto=1
|
|
805
|
+
fi
|
|
806
|
+
fi
|
|
807
|
+
fi
|
|
808
|
+
fi
|
|
809
|
+
if [ "$hit" = 1 ]; then
|
|
810
|
+
# Explicit repo retargeting makes the static id meaningless for a
|
|
811
|
+
# number-bound grant (546 in ANOTHER repo is a different MR): force
|
|
812
|
+
# the id unresolvable so bound grants deny (unbound grants keep the
|
|
813
|
+
# agent-side duty to target the discussed MR — documented residual).
|
|
814
|
+
[ "$retarget" = 1 ] && mid="?"
|
|
815
|
+
if [ "$auto" = 1 ]; then echo DENY_AUTO; else
|
|
816
|
+
echo "DENY_MR $mid $spell"
|
|
817
|
+
# A single segment carrying multiple aliased merge mutations emits a
|
|
818
|
+
# second DENY_MR so the >1 exactly-one-per-command guard denies it.
|
|
819
|
+
[ "$multi_seg" = 1 ] && echo "DENY_MR $mid $spell"
|
|
820
|
+
fi
|
|
821
|
+
fi
|
|
822
|
+
;;
|
|
823
|
+
git)
|
|
824
|
+
shift
|
|
825
|
+
# Walk git global options. `-C <path>` REDIRECTS the repo the command
|
|
826
|
+
# acts on — capture it so current/default-branch checks below evaluate
|
|
827
|
+
# THAT repo, not the effective cwd (else `git -C /path/to/main merge
|
|
828
|
+
# feat` from a feature worktree slips the on-default-branch checks).
|
|
829
|
+
gdir="$eff_cwd"; used_C=0; inline_pd=""; gd_path=""; wt_path=""
|
|
830
|
+
while [ $# -gt 0 ]; do
|
|
831
|
+
case "$1" in
|
|
832
|
+
-C)
|
|
833
|
+
if [ $# -ge 2 ]; then
|
|
834
|
+
case "$2" in /*) gdir="$2" ;; *) gdir="$gdir/$2" ;; esac
|
|
835
|
+
used_C=1
|
|
836
|
+
shift 2
|
|
837
|
+
else shift; fi
|
|
838
|
+
;;
|
|
839
|
+
-c)
|
|
840
|
+
# Inline config counts: `git -c push.default=matching push` must
|
|
841
|
+
# be judged with THAT value, not only the persisted repo config.
|
|
842
|
+
if [ $# -ge 2 ]; then
|
|
843
|
+
case "$2" in push.default=*) inline_pd="${2#push.default=}" ;; esac
|
|
844
|
+
shift 2
|
|
845
|
+
else shift; fi
|
|
846
|
+
;;
|
|
847
|
+
# --git-dir/--work-tree retarget the acted-on repo like -C does.
|
|
848
|
+
--git-dir=*) gd_path="${1#--git-dir=}"; shift ;;
|
|
849
|
+
--git-dir) if [ $# -ge 2 ]; then gd_path="$2"; shift 2; else shift; fi ;;
|
|
850
|
+
--work-tree=*) wt_path="${1#--work-tree=}"; shift ;;
|
|
851
|
+
--work-tree) if [ $# -ge 2 ]; then wt_path="$2"; shift 2; else shift; fi ;;
|
|
852
|
+
--*|-*) shift ;;
|
|
853
|
+
*) break ;;
|
|
854
|
+
esac
|
|
855
|
+
done
|
|
856
|
+
if [ -n "$wt_path" ] || [ -n "$gd_path" ]; then
|
|
857
|
+
t="${wt_path:-$gd_path}"
|
|
858
|
+
[ -z "$wt_path" ] && t="${t%/.git}" # …/.git → its checkout dir
|
|
859
|
+
case "$t" in /*) gdir="$t" ;; *) gdir="$gdir/$t" ;; esac
|
|
860
|
+
used_C=1
|
|
861
|
+
fi
|
|
862
|
+
# Per-segment branch context (reset each segment): baselines when the
|
|
863
|
+
# segment acts on the hook cwd, else ask the repo at gdir; a tracked
|
|
864
|
+
# `git checkout`/`git switch` overrides the current branch unless the
|
|
865
|
+
# segment -C-targets a different repo.
|
|
866
|
+
# When a segment REDIRECTS the repo but the target cannot be resolved, the
|
|
867
|
+
# branch context below silently falls back to the hook's cwd. That fallback is
|
|
868
|
+
# right (an unknown target may well BE the default checkout, so assuming
|
|
869
|
+
# otherwise would open the gate), but the resulting message then blames
|
|
870
|
+
# "this command advances main" for what is really "I could not tell which repo
|
|
871
|
+
# this is". The overwhelmingly common cause is an unexpanded shell variable —
|
|
872
|
+
# `git -C "$WT" merge origin/main` — because this guard reads the command text
|
|
873
|
+
# and cannot expand it. Tag it so the deny can say that instead.
|
|
874
|
+
deny_git_tag="DENY_GIT"
|
|
875
|
+
if [ "$gdir" = "$cwd" ]; then
|
|
876
|
+
default_branch="$base_default_branch"
|
|
877
|
+
current_branch="$base_current_branch"
|
|
878
|
+
origin_flag="$base_origin_exists"
|
|
879
|
+
elif git -C "$gdir" rev-parse --git-dir >/dev/null 2>&1; then
|
|
880
|
+
default_branch=$(git -C "$gdir" symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')
|
|
881
|
+
current_branch=$(git -C "$gdir" rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
882
|
+
origin_flag=0
|
|
883
|
+
git -C "$gdir" config --get remote.origin.url >/dev/null 2>&1 && origin_flag=1
|
|
884
|
+
else
|
|
885
|
+
default_branch="$base_default_branch"
|
|
886
|
+
current_branch="$base_current_branch"
|
|
887
|
+
origin_flag="$base_origin_exists"
|
|
888
|
+
[ "$used_C" = 1 ] && deny_git_tag="DENY_GIT_UNRESOLVED"
|
|
889
|
+
fi
|
|
890
|
+
if [ -n "$eff_branch" ] && [ "$used_C" = 0 ]; then
|
|
891
|
+
current_branch="$eff_branch"
|
|
892
|
+
fi
|
|
893
|
+
sub="${1:-}"; [ -n "$sub" ] && shift
|
|
894
|
+
case "$sub" in
|
|
895
|
+
checkout|switch)
|
|
896
|
+
# Track the branch move for LATER segments in this command.
|
|
897
|
+
[ "$used_C" = 1 ] && continue # affects another repo, not eff_cwd
|
|
898
|
+
nb=""
|
|
899
|
+
for t in "$@"; do
|
|
900
|
+
[ "$t" = "--" ] && break # `checkout -- <paths>`: no branch move
|
|
901
|
+
case "$t" in
|
|
902
|
+
-*) continue ;;
|
|
903
|
+
esac
|
|
904
|
+
nb="$t"; break
|
|
905
|
+
done
|
|
906
|
+
[ -n "$nb" ] && eff_branch="$nb"
|
|
907
|
+
continue
|
|
908
|
+
;;
|
|
909
|
+
push)
|
|
910
|
+
# Positional #1 is the remote; #2+ are refspecs. argi tracks that
|
|
911
|
+
# so `git push origin <feature>` counts as having a refspec while
|
|
912
|
+
# `git push` / `git push origin` stay refspec-less.
|
|
913
|
+
has_default_target=0; has_refspec=0; pushes_head=0; argi=0
|
|
914
|
+
for t in "$@"; do
|
|
915
|
+
case "$t" in
|
|
916
|
+
# --all/--mirror push every branch, unavoidably incl. the default.
|
|
917
|
+
--all|--mirror) has_default_target=1; continue ;;
|
|
918
|
+
-*) continue ;;
|
|
919
|
+
esac
|
|
920
|
+
argi=$((argi+1))
|
|
921
|
+
t="${t#+}" # force-push refspec prefix (+main, +HEAD:main)
|
|
922
|
+
case "$t" in
|
|
923
|
+
*:*)
|
|
924
|
+
has_refspec=1
|
|
925
|
+
dest="${t##*:}"; dest="${dest#refs/heads/}"
|
|
926
|
+
is_default_name "$dest" && has_default_target=1
|
|
927
|
+
;;
|
|
928
|
+
HEAD) has_refspec=1; pushes_head=1 ;;
|
|
929
|
+
*)
|
|
930
|
+
t="${t#refs/heads/}" # non-colon fully-qualified form
|
|
931
|
+
is_default_name "$t" && has_default_target=1
|
|
932
|
+
[ "$argi" -ge 2 ] && has_refspec=1
|
|
933
|
+
;;
|
|
934
|
+
esac
|
|
935
|
+
done
|
|
936
|
+
[ "$has_default_target" = 1 ] && { echo "$deny_git_tag"; break; }
|
|
937
|
+
# bare push / push origin / push origin HEAD while ON the default branch
|
|
938
|
+
if [ -n "$current_branch" ] && is_default_name "$current_branch"; then
|
|
939
|
+
{ [ "$has_refspec" = 0 ] || [ "$pushes_head" = 1 ]; } && { echo "$deny_git_tag"; break; }
|
|
940
|
+
fi
|
|
941
|
+
# Refspec-less push from a NON-default branch can still advance the
|
|
942
|
+
# default under non-simple push.default: `matching` pushes every
|
|
943
|
+
# same-named branch (incl. the default), and `upstream`/`tracking`
|
|
944
|
+
# pushes INTO whatever branch.<cur>.merge names.
|
|
945
|
+
if [ "$has_refspec" = 0 ]; then
|
|
946
|
+
pd=$(git -C "$gdir" config --get push.default 2>/dev/null)
|
|
947
|
+
[ -n "$inline_pd" ] && pd="$inline_pd"
|
|
948
|
+
[ "$pd" = "matching" ] && { echo "$deny_git_tag"; break; }
|
|
949
|
+
if [ "$pd" = "upstream" ] || [ "$pd" = "tracking" ]; then
|
|
950
|
+
up=$(git -C "$gdir" config --get "branch.$current_branch.merge" 2>/dev/null)
|
|
951
|
+
up="${up#refs/heads/}"
|
|
952
|
+
if [ -n "$up" ] && is_default_name "$up"; then echo "$deny_git_tag"; break; fi
|
|
953
|
+
fi
|
|
954
|
+
fi
|
|
955
|
+
;;
|
|
956
|
+
merge)
|
|
957
|
+
if [ -n "$current_branch" ] && is_default_name "$current_branch"; then
|
|
958
|
+
# carve-out: fast-forward-only sync from origin/<default> is allowed
|
|
959
|
+
ff_only=0; src_origin_default=0
|
|
960
|
+
for t in "$@"; do
|
|
961
|
+
[ "$t" = "--ff-only" ] && ff_only=1
|
|
962
|
+
case "$t" in
|
|
963
|
+
origin/*) is_default_name "${t#origin/}" && src_origin_default=1 ;;
|
|
964
|
+
esac
|
|
965
|
+
done
|
|
966
|
+
{ [ "$ff_only" = 1 ] && [ "$src_origin_default" = 1 ]; } || { echo "$deny_git_tag"; break; }
|
|
967
|
+
fi
|
|
968
|
+
;;
|
|
969
|
+
pull)
|
|
970
|
+
# pull = fetch + merge INTO the current branch. On the default
|
|
971
|
+
# branch: bare pull / pull <remote> / pull <remote> <default> is
|
|
972
|
+
# upstream sync (allowed); an explicit NON-default branch arg
|
|
973
|
+
# merges that branch into the default -> deny.
|
|
974
|
+
if [ -n "$current_branch" ] && is_default_name "$current_branch"; then
|
|
975
|
+
argn=0; deny_pull=0
|
|
976
|
+
for t in "$@"; do
|
|
977
|
+
case "$t" in
|
|
978
|
+
-*) continue ;;
|
|
979
|
+
esac
|
|
980
|
+
argn=$((argn+1))
|
|
981
|
+
if [ "$argn" -ge 2 ]; then
|
|
982
|
+
t="${t#+}"; t="${t#refs/heads/}"
|
|
983
|
+
src="${t%%:*}" # refspec src decides what merges in
|
|
984
|
+
is_default_name "$src" || deny_pull=1
|
|
985
|
+
fi
|
|
986
|
+
done
|
|
987
|
+
[ "$deny_pull" = 1 ] && { echo "$deny_git_tag"; break; }
|
|
988
|
+
fi
|
|
989
|
+
;;
|
|
990
|
+
esac
|
|
991
|
+
;;
|
|
992
|
+
esac
|
|
993
|
+
done >"$vfile"
|
|
994
|
+
verdicts=$(cat "$vfile" 2>/dev/null)
|
|
995
|
+
rm -f "$vfile"
|
|
996
|
+
|
|
997
|
+
# A genuine default-branch advance outranks an unresolved target: if any segment is
|
|
998
|
+
# unambiguously advancing the default branch, say that, not "I could not tell".
|
|
999
|
+
if printf '%s\n' "$verdicts" | grep -q '^DENY_GIT$'; then
|
|
1000
|
+
deny "$DENY_TEXT_GIT"
|
|
1001
|
+
fi
|
|
1002
|
+
if printf '%s\n' "$verdicts" | grep -q '^DENY_GIT_UNRESOLVED$'; then
|
|
1003
|
+
deny "$DENY_TEXT_GIT_UNRESOLVED"
|
|
1004
|
+
fi
|
|
1005
|
+
if printf '%s\n' "$verdicts" | grep -q '^DENY_AUTO'; then
|
|
1006
|
+
deny "$DENY_TEXT_AUTO"
|
|
1007
|
+
fi
|
|
1008
|
+
if printf '%s\n' "$verdicts" | grep -q '^DENY_HTTP_AMBIGUOUS'; then
|
|
1009
|
+
deny "$DENY_TEXT_AMBIGUOUS"
|
|
1010
|
+
fi
|
|
1011
|
+
# Exactly ONE platform merge per COMMAND: a compound command with several
|
|
1012
|
+
# merge calls is denied whole (grant intact). Under a one-shot grant the
|
|
1013
|
+
# split commands each need a fresh directive; under a batch grant each
|
|
1014
|
+
# split command consumes one unit.
|
|
1015
|
+
if [ "$(printf '%s\n' "$verdicts" | grep -c '^DENY_MR')" -gt 1 ]; then
|
|
1016
|
+
deny "$DENY_TEXT_MULTI"
|
|
1017
|
+
fi
|
|
1018
|
+
if printf '%s\n' "$verdicts" | grep -q '^DENY_MR'; then
|
|
1019
|
+
# Release valve: consume a fresh, uid-owned, session-scoped grant armed by
|
|
1020
|
+
# the user's explicit merge directive. Grant kinds (specs 007 + 008):
|
|
1021
|
+
# `armed` / `armed <id>` — one-shot, TTL 60 min, optionally id-bound.
|
|
1022
|
+
# `armed batch <N>` — counted batch, TTL 240 min anchored to the
|
|
1023
|
+
# ARMING time (decrement preserves mtime), one
|
|
1024
|
+
# unit per platform merge, unbound.
|
|
1025
|
+
# Every failure mode (no session_id, missing/foreign/stale sentinel,
|
|
1026
|
+
# malformed grant line or count) falls through to deny — fail-closed.
|
|
1027
|
+
mr_line=$(printf '%s\n' "$verdicts" | sed -n 's/^DENY_MR //p' | head -1)
|
|
1028
|
+
mr_id="${mr_line%% *}"; mr_spell="${mr_line##* }"
|
|
1029
|
+
# Everything from parse to consume/re-arm runs INSIDE the session lock so
|
|
1030
|
+
# a concurrent prompt-hook revoke/arm cannot be lost or mis-sequenced.
|
|
1031
|
+
# Lock unavailable → treated as no grant (fail-closed deny; grant intact,
|
|
1032
|
+
# the agent simply retries). The EXIT trap releases the lock on every
|
|
1033
|
+
# deny/allow path below.
|
|
1034
|
+
# Hygiene sweep (challenge R2 P2): a SIGKILL between mv and cleanup can
|
|
1035
|
+
# orphan .used.*/.rearm.* temp files and .lock dirs. Best-effort remove
|
|
1036
|
+
# any older than the stale-lock threshold so repeated kills cannot exhaust
|
|
1037
|
+
# inodes and wedge arming. Cheap, bounded to this session's auth dir.
|
|
1038
|
+
if [ -n "$sentinel" ]; then
|
|
1039
|
+
_adir=$(dirname "$sentinel")
|
|
1040
|
+
find "$_adir" -maxdepth 1 \( -name '*.used.*' -o -name '*.rearm.*' \) -mmin +1 -exec rm -f {} + 2>/dev/null
|
|
1041
|
+
find "$_adir" -maxdepth 1 -name '*.lock' -type d -mmin +1 -exec rm -rf {} + 2>/dev/null
|
|
1042
|
+
fi
|
|
1043
|
+
locked=0
|
|
1044
|
+
if [ -n "$sentinel" ] && [ -f "$sentinel" ] && acquire_lock; then
|
|
1045
|
+
locked=1
|
|
1046
|
+
trap 'rmdir "$lock_dir" 2>/dev/null' EXIT
|
|
1047
|
+
fi
|
|
1048
|
+
grant_kind=""; grant_num=""; batch_count=0; ttl_min=60
|
|
1049
|
+
if [ "$locked" = 1 ] && [ -f "$sentinel" ] && [ -O "$sentinel" ]; then
|
|
1050
|
+
grant_line=$(sed -n '1p' "$sentinel" 2>/dev/null)
|
|
1051
|
+
case "$grant_line" in
|
|
1052
|
+
"armed batch "*)
|
|
1053
|
+
batch_count="${grant_line#armed batch }"
|
|
1054
|
+
# Count must be a well-formed 1–999 integer (matches the prompt
|
|
1055
|
+
# hook's grammar); anything else is treated as no grant.
|
|
1056
|
+
case "$batch_count" in
|
|
1057
|
+
[1-9]|[1-9][0-9]|[1-9][0-9][0-9]) grant_kind=batch; ttl_min=240 ;;
|
|
1058
|
+
*) batch_count=0 ;;
|
|
1059
|
+
esac
|
|
1060
|
+
;;
|
|
1061
|
+
armed) grant_kind=oneshot ;;
|
|
1062
|
+
"armed "*)
|
|
1063
|
+
# Number-bound one-shot ("merge !546" arms `armed 546`): the
|
|
1064
|
+
# released command must merge THAT id.
|
|
1065
|
+
grant_num="${grant_line#armed }"
|
|
1066
|
+
case "$grant_num" in
|
|
1067
|
+
""|*[!0-9]*) grant_num="" ;; # malformed → no grant
|
|
1068
|
+
*) grant_kind=oneshot ;;
|
|
1069
|
+
esac
|
|
1070
|
+
;;
|
|
1071
|
+
esac
|
|
1072
|
+
fi
|
|
1073
|
+
if [ -n "$grant_kind" ] \
|
|
1074
|
+
&& [ -n "$(find "$sentinel" -mmin "-$ttl_min" 2>/dev/null)" ]; then
|
|
1075
|
+
# Pre-consume checks: deny WITHOUT consuming (agent fixes and retries).
|
|
1076
|
+
[ "$mr_spell" = "SPELLOK" ] || deny "$DENY_TEXT_SPELL"
|
|
1077
|
+
if [ -n "$grant_num" ] && [ "$mr_id" != "$grant_num" ]; then
|
|
1078
|
+
deny "$DENY_TEXT_TARGET"
|
|
1079
|
+
fi
|
|
1080
|
+
fi
|
|
1081
|
+
# Atomic consume: mv succeeds for exactly one contender, so two parallel
|
|
1082
|
+
# merge commands cannot both ride a single grant/unit.
|
|
1083
|
+
if [ -n "$grant_kind" ] \
|
|
1084
|
+
&& [ -n "$(find "$sentinel" -mmin "-$ttl_min" 2>/dev/null)" ] \
|
|
1085
|
+
&& mv "$sentinel" "$sentinel.used.$$" 2>/dev/null; then
|
|
1086
|
+
# Batch decrement: re-arm with count-1, PRESERVING the arming mtime so
|
|
1087
|
+
# the 4h TTL anchors to the user's directive, not the last merge (a
|
|
1088
|
+
# rolling window would extend the grant indefinitely). Publish is
|
|
1089
|
+
# atomic (review P2): write a temp file, stamp it from the consumed
|
|
1090
|
+
# grant, then mv into place — the decremented grant only ever becomes
|
|
1091
|
+
# visible already carrying the original arming mtime. ANY failure
|
|
1092
|
+
# (unwritable dir, touch -r failure) drops the remaining units —
|
|
1093
|
+
# fail-closed — and never publishes a fresh-mtime grant.
|
|
1094
|
+
remaining=0
|
|
1095
|
+
if [ "$grant_kind" = batch ] && [ "$batch_count" -gt 1 ]; then
|
|
1096
|
+
remaining=$((batch_count-1))
|
|
1097
|
+
rearm="$sentinel.rearm.$$"
|
|
1098
|
+
if printf 'armed batch %s\n' "$remaining" >"$rearm" 2>/dev/null \
|
|
1099
|
+
&& touch -r "$sentinel.used.$$" "$rearm" 2>/dev/null \
|
|
1100
|
+
&& mv "$rearm" "$sentinel" 2>/dev/null; then
|
|
1101
|
+
:
|
|
1102
|
+
else
|
|
1103
|
+
rm -f "$rearm" 2>/dev/null
|
|
1104
|
+
remaining=0
|
|
1105
|
+
fi
|
|
1106
|
+
fi
|
|
1107
|
+
rm -f "$sentinel.used.$$" 2>/dev/null
|
|
1108
|
+
# Host-aware emission: Claude Code supports permissionDecision "allow"
|
|
1109
|
+
# (skips the permission prompt). Other hosts that execute these hooks
|
|
1110
|
+
# (e.g. the codex plugin bridge) accept deny but REJECT "allow" — they
|
|
1111
|
+
# error the hook after the grant was already consumed. For them, emit
|
|
1112
|
+
# the advisory systemMessage only (no decision): the merge command then
|
|
1113
|
+
# proceeds through that host's own approval flow.
|
|
1114
|
+
# Nested-host guard (review P1 + challenge P1): codex spawned FROM a
|
|
1115
|
+
# Claude session inherits CLAUDECODE=1, and an env blocklist alone is
|
|
1116
|
+
# structurally best-effort — so "allow" additionally requires the
|
|
1117
|
+
# POSITIVE Claude-Code input signal: this hook invocation's own
|
|
1118
|
+
# transcript_path living under a .claude directory (Claude Code always
|
|
1119
|
+
# sends it; a codex bridge's input would not point into .claude).
|
|
1120
|
+
# Every misdetection direction degrades to advisory (a popup), never
|
|
1121
|
+
# to a host error that burns the consumed grant.
|
|
1122
|
+
claude_host=0
|
|
1123
|
+
if [ "${CLAUDECODE:-}" = "1" ] \
|
|
1124
|
+
&& [ -z "${CODEX_THREAD_ID:-}${CODEX_SANDBOX:-}${CODEX_CI:-}${CODEX_MANAGED_BY_NPM:-}${CODEX_HOME:-}" ]; then
|
|
1125
|
+
case "$tpath" in */.claude/*) claude_host=1 ;; esac
|
|
1126
|
+
fi
|
|
1127
|
+
if [ "$grant_kind" = batch ]; then
|
|
1128
|
+
if [ "$remaining" -gt 0 ]; then
|
|
1129
|
+
used_msg="✅ 合并授权闸:批量合并授权已消费 1 个额度,剩余 ${remaining} 个(自武装起 4 小时内有效;用户发送任何新消息即清除剩余额度)。"
|
|
1130
|
+
else
|
|
1131
|
+
used_msg="✅ 合并授权闸:批量合并授权已消费最后 1 个额度;再次合并需用户重新回复\"合并/merge\"或\"批量合并 <N>\"。"
|
|
1132
|
+
fi
|
|
1133
|
+
else
|
|
1134
|
+
used_msg="✅ 合并授权闸:用户合并指令一次性放行已消费;再次合并需用户重新回复\"合并/merge\"。"
|
|
1135
|
+
fi
|
|
1136
|
+
if [ "$claude_host" = 1 ]; then
|
|
1137
|
+
jq -nc --arg m "$used_msg" \
|
|
1138
|
+
'{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",permissionDecisionReason:"合并授权闸:检测到用户明确合并指令(授权额度已消费),放行平台合并命令。"},systemMessage:$m}'
|
|
1139
|
+
else
|
|
1140
|
+
jq -nc --arg m "$used_msg" \
|
|
1141
|
+
'{systemMessage:($m + "(本宿主不支持免弹窗放行,命令按宿主正常审批流继续。)")}'
|
|
1142
|
+
fi
|
|
1143
|
+
exit 0
|
|
1144
|
+
fi
|
|
1145
|
+
deny "$DENY_TEXT_MR"
|
|
1146
|
+
fi
|
|
1147
|
+
|
|
1148
|
+
# Visible-degrade warning (allow still stands): the repo has an origin remote
|
|
1149
|
+
# but its default branch could not be resolved, and this command touches
|
|
1150
|
+
# push/merge — tell the session the gate is narrowed to main|master instead
|
|
1151
|
+
# of silently half-enforcing. Non-push/merge commands stay quiet (no noise).
|
|
1152
|
+
if [ "$origin_exists" = 1 ] && [ -z "$default_branch" ] && printf '%s' "$masked" | grep -Eq '(^|[^[:alnum:]_-])git([^|;&]*[[:space:]])?(push|merge)([[:space:]]|$)'; then
|
|
1153
|
+
printf '{"systemMessage":"⚠️ merge-authorization guard: 无法解析该仓的默认分支(origin/HEAD 未设置);本闸按 main/master/dev/develop/trunk 兜底判定,其余名字的默认分支可能漏拦。修复:git remote set-head origin -a"}\n'
|
|
1154
|
+
fi
|
|
1155
|
+
|
|
1156
|
+
exit 0
|