@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.
Files changed (561) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +49 -0
  3. package/dist/assets/marketplace/.agents/plugins/marketplace.json +12 -0
  4. package/dist/assets/marketplace/.claude-plugin/marketplace.json +13 -0
  5. package/dist/assets/marketplace/marketplace-manifest.json +12 -0
  6. package/dist/assets/marketplace/plugins/ccl-skills/.claude-plugin/marketplace.json +16 -0
  7. package/dist/assets/marketplace/plugins/ccl-skills/.claude-plugin/plugin.json +5 -0
  8. package/dist/assets/marketplace/plugins/ccl-skills/.codex-plugin/plugin.json +5 -0
  9. package/dist/assets/marketplace/plugins/ccl-skills/.worktree-only +3 -0
  10. package/dist/assets/marketplace/plugins/ccl-skills/agent-context/session-start.md +45 -0
  11. package/dist/assets/marketplace/plugins/ccl-skills/agent-context/subagent-start.md +12 -0
  12. package/dist/assets/marketplace/plugins/ccl-skills/hooks/AGENTS.md +19 -0
  13. package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-delegation-owner.sh +125 -0
  14. package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-edit-isolation.sh +102 -0
  15. package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-merge-authorization.sh +1156 -0
  16. package/dist/assets/marketplace/plugins/ccl-skills/hooks/hooks.json +131 -0
  17. package/dist/assets/marketplace/plugins/ccl-skills/hooks/merge-authorization-prompt.sh +142 -0
  18. package/dist/assets/marketplace/plugins/ccl-skills/hooks/owner-dispatch-guard.sh +12 -0
  19. package/dist/assets/marketplace/plugins/ccl-skills/hooks/owner-dispatch-stop.sh +13 -0
  20. package/dist/assets/marketplace/plugins/ccl-skills/hooks/remind-post-merge-cleanup.sh +144 -0
  21. package/dist/assets/marketplace/plugins/ccl-skills/hooks/session-context.sh +87 -0
  22. package/dist/assets/marketplace/plugins/ccl-skills/hooks/session-start.sh +86 -0
  23. package/dist/assets/marketplace/plugins/ccl-skills/hooks/skill-extraction-gate-stop.sh +69 -0
  24. package/dist/assets/marketplace/plugins/ccl-skills/hooks/subagent-start.sh +26 -0
  25. package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_delegation_owner.sh +329 -0
  26. package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_edit_isolation.sh +322 -0
  27. package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_merge_authorization.sh +902 -0
  28. package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_merge_authorization_prompt.sh +178 -0
  29. package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_remind_post_merge_cleanup.sh +121 -0
  30. package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_session_start.sh +170 -0
  31. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/AGENTS.md +17 -0
  32. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/ccl-skills.ts +564 -0
  33. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-install-skills.md +14 -0
  34. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-update-skills.md +44 -0
  35. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-verify-skills.md +109 -0
  36. package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-worktree-check.md +36 -0
  37. package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/AGENTS.md +28 -0
  38. package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/README.md +276 -0
  39. package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.example.json +10 -0
  40. package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.sh +1307 -0
  41. package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/test.sh +941 -0
  42. package/dist/assets/marketplace/plugins/ccl-skills/skills/agents-file-coverage-gate/SKILL.md +45 -0
  43. package/dist/assets/marketplace/plugins/ccl-skills/skills/agents-file-coverage-gate/agents/openai.yaml +4 -0
  44. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/SKILL.md +188 -0
  45. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/agents/openai.yaml +4 -0
  46. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/android-dev.md +92 -0
  47. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/flutter-dev.md +80 -0
  48. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/ios-dev.md +72 -0
  49. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/kotlin-multiplatform.md +93 -0
  50. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/mobile-platform-boundaries.md +77 -0
  51. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/mobile-quality-release.md +77 -0
  52. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/source-evidence-map.md +64 -0
  53. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/SKILL.md +353 -0
  54. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/agents/openai.yaml +4 -0
  55. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/client-routing.md +419 -0
  56. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/manual-invocation-and-prompts.md +126 -0
  57. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/staged-review-contract.md +197 -0
  58. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/timeout-auth-and-capabilities.md +179 -0
  59. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/AGENTS.md +98 -0
  60. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/classify_envelope.py +93 -0
  61. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/classify_timeout_exit.sh +15 -0
  62. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/claude_review.sh +1438 -0
  63. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/codex_review.sh +324 -0
  64. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/concern_excerpt.py +295 -0
  65. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/egress_schema.py +214 -0
  66. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/init_policy_matrix.py +642 -0
  67. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_packet_mcp.py +181 -0
  68. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_review.sh +1165 -0
  69. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/opencode_review.sh +1190 -0
  70. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_cli_review.py +946 -0
  71. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_opencode_review.py +474 -0
  72. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_probe_result.py +1899 -0
  73. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_review_json.py +200 -0
  74. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +2845 -0
  75. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.sh +6 -0
  76. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/run_claude_capture.py +71 -0
  77. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/runtime-surface-verification-design.md +53 -0
  78. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_classify_envelope.sh +68 -0
  79. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_claude_review_probe.sh +2311 -0
  80. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_cli_review_wrappers.sh +1832 -0
  81. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_code_review_identity.sh +73 -0
  82. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_concern_excerpt.sh +245 -0
  83. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_egress_schema.sh +177 -0
  84. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_init_policy_matrix.sh +272 -0
  85. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_kimi_packet_mcp.py +195 -0
  86. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_opencode_review_concurrency.sh +120 -0
  87. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_opencode_review_retry.sh +1005 -0
  88. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_opencode_review.sh +258 -0
  89. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_probe_result.sh +574 -0
  90. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_review_json.sh +349 -0
  91. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_compat.py +434 -0
  92. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_order.sh +264 -0
  93. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate.sh +2412 -0
  94. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/verify_native_skill_binding.py +123 -0
  95. package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/SKILL.md +153 -0
  96. package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/agents/openai.yaml +4 -0
  97. package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/references/diagnosis-playbook.md +54 -0
  98. package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/references/prevention-routing.md +36 -0
  99. package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/SKILL.md +69 -0
  100. package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/agents/openai.yaml +4 -0
  101. package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/references/security-review-gate.md +41 -0
  102. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/SKILL.md +165 -0
  103. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/agents/openai.yaml +4 -0
  104. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/api-security-boundaries.md +47 -0
  105. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/architecture-playbook.md +160 -0
  106. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/artifact-generation-architecture.md +37 -0
  107. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/audit-history-architecture.md +29 -0
  108. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/bulk-workflow-architecture.md +33 -0
  109. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/config-rule-routing-architecture.md +34 -0
  110. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/cross-cutting-concerns.md +72 -0
  111. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/data-modeling-and-migrations.md +79 -0
  112. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/data-platform-architecture.md +210 -0
  113. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/dependency-platform.md +105 -0
  114. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/developer-tooling-architecture.md +38 -0
  115. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/error-contract-architecture.md +36 -0
  116. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/event-driven-architecture.md +260 -0
  117. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/http-gateway-architecture.md +74 -0
  118. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/mq-consumer-architecture.md +38 -0
  119. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/multi-tenant-isolation.md +275 -0
  120. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/notification-architecture.md +25 -0
  121. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/ops-checklist.md +57 -0
  122. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/performance-capacity-architecture.md +38 -0
  123. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/protobuf-contract-architecture.md +119 -0
  124. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/redis-cache-coordination.md +93 -0
  125. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/release-runtime-readiness.md +65 -0
  126. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/replay-comparison-architecture.md +26 -0
  127. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/runtime-observability.md +94 -0
  128. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/service-scaffold.md +76 -0
  129. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/source-evidence-map.md +55 -0
  130. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/workflow-state-architecture.md +38 -0
  131. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/SKILL.md +159 -0
  132. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/agents/openai.yaml +4 -0
  133. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/artifact-generation-patterns.md +37 -0
  134. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/audit-history-patterns.md +28 -0
  135. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/bulk-import-export-patterns.md +56 -0
  136. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/config-rule-routing-patterns.md +38 -0
  137. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/data-access-patterns.md +55 -0
  138. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/db-schema-and-dal-patterns.md +109 -0
  139. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/dependency-client-patterns.md +130 -0
  140. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/developer-tooling-patterns.md +70 -0
  141. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/domain-feature-patterns.md +78 -0
  142. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/engineering-patterns.md +119 -0
  143. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/error-contract-patterns.md +55 -0
  144. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/feature-playbook.md +61 -0
  145. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/http-gateway-client-patterns.md +76 -0
  146. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/mq-consumer-patterns.md +55 -0
  147. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/notification-patterns.md +42 -0
  148. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/observability-implementation-patterns.md +101 -0
  149. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/performance-capacity-patterns.md +44 -0
  150. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/protobuf-contract-patterns.md +72 -0
  151. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/public-api-integration-patterns.md +56 -0
  152. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/quality-and-testing-patterns.md +91 -0
  153. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/redis-cache-lock-patterns.md +123 -0
  154. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/release-ops-patterns.md +112 -0
  155. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/reliability-patterns.md +83 -0
  156. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/replay-comparison-patterns.md +32 -0
  157. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/scaffold-and-codegen.md +86 -0
  158. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/source-evidence-map.md +54 -0
  159. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/state-machine-task-patterns.md +45 -0
  160. package/dist/assets/marketplace/plugins/ccl-skills/skills/grill-me/SKILL.md +80 -0
  161. package/dist/assets/marketplace/plugins/ccl-skills/skills/grill-me/agents/openai.yaml +4 -0
  162. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/SKILL.md +117 -0
  163. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/agents/openai.yaml +4 -0
  164. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-approval-auto-reviewer.md +106 -0
  165. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-command-sandbox.md +441 -0
  166. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-context-freshness.md +47 -0
  167. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-credentials-auth.md +13 -0
  168. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-extensions-skills.md +13 -0
  169. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-file-edit-protocol.md +129 -0
  170. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-ide-integration.md +5 -0
  171. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-input-ingestion.md +13 -0
  172. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-instruction-composition.md +13 -0
  173. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-lifecycle-hooks.md +92 -0
  174. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-messaging.md +5 -0
  175. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-runtime-bootstrap.md +5 -0
  176. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-session-persistence.md +448 -0
  177. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-task-orchestration.md +13 -0
  178. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-tool-dispatch.md +123 -0
  179. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-turn-lifecycle.md +131 -0
  180. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/inference-capacity-operations.md +162 -0
  181. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/llm-client-gateway.md +156 -0
  182. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/model-prompt-evaluation.md +146 -0
  183. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/retrieval-agent-safety.md +273 -0
  184. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/SKILL.md +202 -0
  185. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/agents/openai.yaml +4 -0
  186. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/contracts-and-state.md +62 -0
  187. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/cross-stack-alignment.md +94 -0
  188. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/framework-choice.md +76 -0
  189. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/online-practice-uptake.md +56 -0
  190. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/platform-capabilities.md +91 -0
  191. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/product-page-checklist.md +40 -0
  192. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/qa-release.md +72 -0
  193. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/source-evidence-map.md +82 -0
  194. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/SKILL.md +103 -0
  195. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/agents/openai.yaml +5 -0
  196. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/references/multi-agent-delegation-playbook.md +100 -0
  197. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/SKILL.md +70 -0
  198. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/agents/openai.yaml +4 -0
  199. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/public-data-acquisition.md +549 -0
  200. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/public-disclosure-channels.md +97 -0
  201. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/research-prompts.md +66 -0
  202. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/scripts/AGENTS.md +32 -0
  203. package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/scripts/test-public-data-acquisition-recipes.sh +379 -0
  204. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/SKILL.md +244 -0
  205. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/agents/openai.yaml +4 -0
  206. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/alerting-and-on-call.md +76 -0
  207. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/framework-middleware-checklist.md +142 -0
  208. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/infra-component-deployment.md +268 -0
  209. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/log-correlation-recipe.md +124 -0
  210. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/log-schema-canonical.md +208 -0
  211. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/metrics-conventions.md +105 -0
  212. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/obs-stack-architecture.md +107 -0
  213. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/sli-slo-design.md +95 -0
  214. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/source-register.md +11 -0
  215. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/SKILL.md +303 -0
  216. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/agents/openai.yaml +4 -0
  217. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/canary-and-rollout-strategy.md +163 -0
  218. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/config-center-via-etcd.md +245 -0
  219. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/custom-control-plane-boundary.md +298 -0
  220. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/deploy-cli-concrete-recipe.md +312 -0
  221. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/deploy-pipeline.md +165 -0
  222. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/env-and-lane-matrix.md +126 -0
  223. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/lane-orchestration-control-plane.md +383 -0
  224. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/multi-region-and-cluster.md +135 -0
  225. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/promotion-gate-and-review.md +149 -0
  226. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/python-package-registry-release.md +462 -0
  227. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/rollback-playbook.md +123 -0
  228. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/secret-and-config-management.md +231 -0
  229. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/version-authority-and-deprecation.md +21 -0
  230. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/SKILL.md +276 -0
  231. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/agents/openai.yaml +4 -0
  232. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/dual-sidecar-and-traffic-config-center.md +127 -0
  233. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/framework-middleware.md +143 -0
  234. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/grpc-authority-workaround.md +90 -0
  235. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/http-response-envelope-contract.md +24 -0
  236. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/mesh-architecture.md +127 -0
  237. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/multi-env-routing.md +192 -0
  238. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/protobuf-http-contract-signals.md +64 -0
  239. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/retry-timeout-circuit-breaker.md +124 -0
  240. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/rpc-framework-recipe.md +494 -0
  241. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-choice.md +113 -0
  242. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-migration-playbook.md +231 -0
  243. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-recipe.md +131 -0
  244. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/SKILL.md +235 -0
  245. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/agents/openai.yaml +4 -0
  246. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/adr-convention.md +146 -0
  247. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-checklist.md +30 -0
  248. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-evaluation-report-template.md +25 -0
  249. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-execution-spec.md +108 -0
  250. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-sop.md +457 -0
  251. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-templates.md +24 -0
  252. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/artifact-egress-confidentiality.md +58 -0
  253. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/code-review-checklist.md +86 -0
  254. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/cross-repo-coordination.md +46 -0
  255. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/delivery-lifecycle.md +192 -0
  256. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-review-gate-mechanics.md +62 -0
  257. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-routing-and-readiness.md +45 -0
  258. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/diagnostic-spec-match-gate.md +36 -0
  259. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/dispatch-owner-skills.md +35 -0
  260. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/dormant-code-activation.md +47 -0
  261. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/existing-project-assessment-report.md +223 -0
  262. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/external-skill-augmentation.md +46 -0
  263. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/feature-deprecation-cascade.md +15 -0
  264. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/high-risk-resilience-gates.md +73 -0
  265. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/implementation-completeness-and-minimality.md +120 -0
  266. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/implementation-entry-reentry-gate.md +122 -0
  267. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/modular-monolith-heuristic.md +105 -0
  268. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/pre-final-continuation-gate.md +115 -0
  269. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/problem-resolution-and-learning.md +62 -0
  270. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/quality-attributes.md +112 -0
  271. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/quality-remediation-program.md +88 -0
  272. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/rd-standards-doc-family-checklist.md +27 -0
  273. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/refactoring-discipline.md +52 -0
  274. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/review-reception.md +34 -0
  275. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/shared-gate-artifact-classification.md +76 -0
  276. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/source-evidence-map.md +31 -0
  277. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/status-tracker-sync.md +77 -0
  278. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/sync-spec-repo-contract.md +25 -0
  279. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/verify-developer-experience.md +34 -0
  280. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/worktree-mechanics.md +55 -0
  281. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/scripts/AGENTS.md +18 -0
  282. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/scripts/check-agent-contract-coverage.sh +213 -0
  283. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/SKILL.md +136 -0
  284. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/agents/openai.yaml +9 -0
  285. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/analytics-visualization-interactions.md +206 -0
  286. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/behavioral-aesthetic-logic.md +108 -0
  287. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/complex-creation-interactions.md +194 -0
  288. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-execution-checklist.md +214 -0
  289. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-impl-naming-and-versioning.md +53 -0
  290. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-intake-and-acceptance.md +129 -0
  291. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-system-source-of-truth.md +97 -0
  292. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/external-ui-ux-quality-benchmarks.md +79 -0
  293. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/frontend-code-evidence-map.md +63 -0
  294. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/interaction-design-patterns.md +146 -0
  295. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/layout-recipes-and-screenshot-acceptance.md +250 -0
  296. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-project-token-consistency.md +237 -0
  297. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-stack-strategy.md +65 -0
  298. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/operational-processing-workflows.md +237 -0
  299. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/platform-mobile-patterns.md +324 -0
  300. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/platform-web-desktop-patterns.md +456 -0
  301. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-lifecycle-acceptance-and-iteration.md +114 -0
  302. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-surface-patterns.md +79 -0
  303. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/resource-management-interactions.md +113 -0
  304. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/scenario-community-patterns.md +133 -0
  305. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/source-map.md +130 -0
  306. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/tokens-and-components.md +47 -0
  307. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/trust-sensitive-ai-and-data-patterns.md +96 -0
  308. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-audit.md +106 -0
  309. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-design-development.md +176 -0
  310. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/visual-craft.md +111 -0
  311. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/SKILL.md +157 -0
  312. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/agents/openai.yaml +4 -0
  313. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/ai-service-integration-boundaries.md +57 -0
  314. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/api-contract-and-schema.md +62 -0
  315. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/api-security-boundaries.md +39 -0
  316. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/architecture-playbook.md +46 -0
  317. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/async-execution-model.md +24 -0
  318. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/background-jobs-and-scheduling.md +18 -0
  319. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/batch-and-pipeline-architecture.md +11 -0
  320. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/config-secrets-runtime.md +22 -0
  321. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/data-modeling-and-migrations.md +64 -0
  322. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/data-platform-architecture.md +211 -0
  323. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/event-driven-architecture.md +263 -0
  324. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/multi-tenant-isolation.md +281 -0
  325. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/observability-and-ops.md +26 -0
  326. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/packaging-runtime-readiness.md +20 -0
  327. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/redis-cache-coordination.md +41 -0
  328. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/reliability-and-error-contract.md +17 -0
  329. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/source-evidence-map.md +55 -0
  330. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/web-framework-boundaries.md +26 -0
  331. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/SKILL.md +143 -0
  332. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/agents/openai.yaml +4 -0
  333. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/ai-service-wiring-patterns.md +16 -0
  334. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/async-and-worker-patterns.md +24 -0
  335. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/background-job-patterns.md +18 -0
  336. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/batch-and-artifact-patterns.md +13 -0
  337. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/dependency-client-patterns.md +39 -0
  338. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/error-handling-patterns.md +26 -0
  339. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/feature-playbook.md +43 -0
  340. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/observability-implementation-patterns.md +31 -0
  341. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/project-structure-and-tooling.md +24 -0
  342. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/public-api-security-patterns.md +52 -0
  343. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/redis-cache-lock-patterns.md +78 -0
  344. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/schema-and-validation-patterns.md +23 -0
  345. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/source-evidence-map.md +56 -0
  346. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/sqlalchemy-and-migrations-patterns.md +99 -0
  347. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/testing-and-quality-patterns.md +61 -0
  348. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/web-framework-patterns.md +35 -0
  349. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/SKILL.md +91 -0
  350. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/agents/openai.yaml +4 -0
  351. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/config-runtime-readback.md +20 -0
  352. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/mr-merge-authorization.md +31 -0
  353. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/post-release-env-reset.md +31 -0
  354. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/release-closeout-evidence.md +20 -0
  355. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/release-scope-confirmation.md +21 -0
  356. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/tag-and-prod-pipeline-gate.md +20 -0
  357. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/test-scope-prompt.md +24 -0
  358. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/watcher-discipline.md +14 -0
  359. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/SKILL.md +64 -0
  360. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/agents/openai.yaml +4 -0
  361. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/references/comment-safe-release-doc.md +19 -0
  362. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/references/release-evidence-workflow.md +23 -0
  363. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/references/release-testing-scope-section.md +15 -0
  364. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-baseline/SKILL.md +87 -0
  365. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-baseline/agents/openai.yaml +4 -0
  366. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/SKILL.md +130 -0
  367. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/agents/openai.yaml +4 -0
  368. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/references/prd-composition-contract.md +35 -0
  369. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/references/requirement-closure-contract.md +86 -0
  370. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/references/security-four-questions.md +38 -0
  371. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-intent/SKILL.md +91 -0
  372. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-intent/agents/openai.yaml +4 -0
  373. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-scope/SKILL.md +88 -0
  374. package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-scope/agents/openai.yaml +4 -0
  375. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/SKILL.md +337 -0
  376. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/agents/openai.yaml +4 -0
  377. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/analysis-parse-fix-test-challenge-replay.md +47 -0
  378. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/attribution-verification.md +69 -0
  379. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/bootstrap-slim-c3-obligation-table.md +112 -0
  380. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/coverage-exhaustion-traps.md +45 -0
  381. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/description-authoring.md +162 -0
  382. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/dual-track-review-gate.md +507 -0
  383. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/eval-routing.md +86 -0
  384. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/evidence-card-template.md +51 -0
  385. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/example-domain-preselect.md +79 -0
  386. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/external-practice-controls.md +57 -0
  387. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-lifecycle-handoff.md +65 -0
  388. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-quickstart.md +194 -0
  389. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/firing-point-placement.md +75 -0
  390. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/harness-patterns-and-eval.md +286 -0
  391. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/incident-postmortem-extraction.md +190 -0
  392. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/l0-l1-l2-routing.md +114 -0
  393. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/online-skill-review.md +47 -0
  394. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/parallel-stack-references-pattern.md +164 -0
  395. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/r0-leakage-audit.md +90 -0
  396. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/recurring-anti-patterns-checklist.md +320 -0
  397. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/resume-paused-delivery.md +16 -0
  398. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/review-feedback-mining.md +33 -0
  399. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/review-finding-standards.md +57 -0
  400. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/review-rubric.md +40 -0
  401. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/rule-consolidation.md +118 -0
  402. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/skill-listing-budget.md +19 -0
  403. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +254 -0
  404. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-to-skill-extraction.md +658 -0
  405. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/two-source-extraction-pattern.md +167 -0
  406. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/uiux-judgment-extraction.md +179 -0
  407. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/uiux-routing-map.md +51 -0
  408. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/validation-and-landing.md +180 -0
  409. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/AGENTS.md +18 -0
  410. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-ccl-skills.sh +1452 -0
  411. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-evidence-card-leak.sh +491 -0
  412. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-mr-target-freshness.sh +173 -0
  413. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-size-budget.sh +488 -0
  414. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-sync-pointers.sh +419 -0
  415. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-golden-trace.rb +197 -0
  416. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-health.rb +327 -0
  417. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-routing-bank.rb +401 -0
  418. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-routing.rb +248 -0
  419. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/generic-r0-leak-scan.sh +282 -0
  420. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/governing-chain-diff.py +321 -0
  421. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb +964 -0
  422. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/register-firing-path-resolution.rb +708 -0
  423. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/skill-behavior-eval.py +540 -0
  424. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/source-register-lifecycle.rb +51 -0
  425. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/source-register-pending-status.rb +55 -0
  426. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_ai_coding_implementation_gates.sh +829 -0
  427. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_impact_chain_refscripts.sh +1203 -0
  428. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_r0_status.sh +75 -0
  429. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_register_pending_exclusion.sh +137 -0
  430. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_regressions.sh +173 -0
  431. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_route_drift.sh +377 -0
  432. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_size_budget.sh +833 -0
  433. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_skill_catalog.sh +491 -0
  434. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_source_register_lifecycle.sh +114 -0
  435. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_mr_target_freshness.sh +261 -0
  436. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_sync_pointers.sh +538 -0
  437. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_controlled_escalation_pins.sh +154 -0
  438. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_grader_diagnostics.sh +190 -0
  439. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_surface_binding.sh +178 -0
  440. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_prose_target.sh +86 -0
  441. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_generic_r0_leak_scan.sh +131 -0
  442. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_git_identity_predicate_gate.sh +243 -0
  443. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_governing_chain_diff.sh +419 -0
  444. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_gate_dateless_host.sh +120 -0
  445. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_resolution.sh +724 -0
  446. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_wiring.sh +414 -0
  447. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_regression_runner_registration.sh +34 -0
  448. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_routing_bank_integrity.sh +205 -0
  449. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_routing_pointer_integrity.sh +194 -0
  450. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_credential_cwd.sh +61 -0
  451. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_cross_refs.sh +111 -0
  452. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_root_depth.sh +53 -0
  453. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/validate-skill.sh +257 -0
  454. package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/SKILL.md +98 -0
  455. package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/agents/openai.yaml +4 -0
  456. package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/references/input-state-machines.md +36 -0
  457. package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/references/streaming-rich-output.md +130 -0
  458. package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/references/terminal-side-channels.md +96 -0
  459. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/SKILL.md +408 -0
  460. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/agents/openai.yaml +4 -0
  461. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/AGENTS.md +18 -0
  462. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/bitable-setup.md +573 -0
  463. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/README.md +120 -0
  464. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/github-actions.yml +119 -0
  465. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/gitlab-ci.yml +76 -0
  466. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/jenkins.Jenkinsfile +106 -0
  467. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/classical-test-design-techniques.md +279 -0
  468. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/gen_report.py +2807 -0
  469. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/makefile-template.md +200 -0
  470. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/report-config-schema.md +272 -0
  471. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/run_pytestless.py +475 -0
  472. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/source-to-case-workflows.md +258 -0
  473. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc-marker-conventions.md +316 -0
  474. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc-review-and-prioritization.md +145 -0
  475. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/AGENTS.md +16 -0
  476. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.dart +129 -0
  477. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.go +197 -0
  478. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.py +135 -0
  479. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.ts +285 -0
  480. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/test_gen_report.py +2144 -0
  481. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/update-lifecycle.md +62 -0
  482. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/SKILL.md +212 -0
  483. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/agents/openai.yaml +4 -0
  484. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/ci-fixtures-and-flake-control.md +75 -0
  485. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/client-runtime-test-matrices.md +50 -0
  486. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/data-and-workflow-testing.md +34 -0
  487. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/design-closed-contract-oracles.md +31 -0
  488. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/e2e-real-flow-testing.md +71 -0
  489. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/fitness-functions.md +240 -0
  490. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/integration-contract-testing.md +235 -0
  491. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/non-functional-specialized-scenarios.md +296 -0
  492. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/rd-testing-standard-template.md +126 -0
  493. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/run-killing-mutation-walk.md +43 -0
  494. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/scenario-testing.md +136 -0
  495. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/source-evidence-map.md +59 -0
  496. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/structured-tc-input-translation.md +67 -0
  497. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-code-authoring-patterns.md +392 -0
  498. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-data-and-determinism.md +39 -0
  499. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-topology-and-commands.md +92 -0
  500. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/unit-testing.md +46 -0
  501. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/vendored-contract-drift-checklist.md +64 -0
  502. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/verify-enforcement-mechanisms.md +18 -0
  503. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/AGENTS.md +17 -0
  504. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/client-terminal-ansi-check.py +140 -0
  505. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/client-terminal-ansi-check.test.sh +75 -0
  506. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-ast-check.py +170 -0
  507. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-ast-check.test.sh +87 -0
  508. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-go-check.go +198 -0
  509. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-go-check.test.sh +109 -0
  510. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/test_mutation_backup_recipe.sh +237 -0
  511. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/SKILL.md +184 -0
  512. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/agents/openai.yaml +4 -0
  513. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/comment-safe-feishu.md +93 -0
  514. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/cross-model-co-review.md +3 -0
  515. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/delivery-face-closeout.md +60 -0
  516. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/doc-charter-first.md +17 -0
  517. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/session-vantage-leakage.md +58 -0
  518. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/SKILL.md +126 -0
  519. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/agents/openai.yaml +4 -0
  520. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/complex-workspace-patterns.md +47 -0
  521. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/embedded-h5-in-host.md +87 -0
  522. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/react-architecture.md +194 -0
  523. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/source-evidence-map.md +60 -0
  524. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/web-quality-release.md +190 -0
  525. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/web-ui-quality.md +83 -0
  526. package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/SKILL.md +179 -0
  527. package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/agents/openai.yaml +4 -0
  528. package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/references/shared-branch-rebase.md +25 -0
  529. package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/AGENTS.md +23 -0
  530. package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/test_worktree_status.sh +207 -0
  531. package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/test_worktree_sweep.sh +481 -0
  532. package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/worktree-status.sh +325 -0
  533. package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/worktree-sweep.sh +245 -0
  534. package/dist/assets/release.json +2797 -0
  535. package/dist/claude-adapter.d.ts +9 -0
  536. package/dist/claude-adapter.js +240 -0
  537. package/dist/cli-worker.d.ts +1 -0
  538. package/dist/cli-worker.js +32 -0
  539. package/dist/cli.d.ts +22 -0
  540. package/dist/cli.js +214 -0
  541. package/dist/codex-host.d.ts +30 -0
  542. package/dist/codex-host.js +162 -0
  543. package/dist/fs-safe.d.ts +21 -0
  544. package/dist/fs-safe.js +241 -0
  545. package/dist/index.d.ts +2 -0
  546. package/dist/index.js +1 -0
  547. package/dist/manifest.d.ts +8 -0
  548. package/dist/manifest.js +135 -0
  549. package/dist/opencode-adapter.d.ts +10 -0
  550. package/dist/opencode-adapter.js +416 -0
  551. package/dist/operations.d.ts +3 -0
  552. package/dist/operations.js +956 -0
  553. package/dist/paths.d.ts +20 -0
  554. package/dist/paths.js +4 -0
  555. package/dist/types.d.ts +58 -0
  556. package/dist/types.js +1 -0
  557. package/dist/unified.d.ts +4 -0
  558. package/dist/unified.js +64 -0
  559. package/dist/version.d.ts +2 -0
  560. package/dist/version.js +5 -0
  561. package/package.json +35 -0
@@ -0,0 +1,1899 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import re
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ NOT_LOGGED_IN = re.compile(
10
+ r"(^|[^a-z])not logged in([^a-z]|$)|please run /login|invalid api key|"
11
+ r"authentication (failed|required)|session expired|oauth token expired|"
12
+ r"token expired|401 unauthorized|session has ended",
13
+ re.I,
14
+ )
15
+ QUOTA = re.compile(
16
+ r"rate limit exceeded|quota exceeded|hit your limit|credit balance too low|"
17
+ r"usage limit reached|too_many_requests",
18
+ re.I,
19
+ )
20
+
21
+
22
+ def normalize(text: str) -> str:
23
+ return text.replace("\r", "").strip()
24
+
25
+
26
+ def is_ok_token(text: str) -> bool:
27
+ return normalize(text).lower() == "ok"
28
+
29
+
30
+ def last_non_empty_line(text: str) -> str:
31
+ for line in reversed(text.replace("\r", "").splitlines()):
32
+ if line.strip():
33
+ return line.strip()
34
+ return ""
35
+
36
+
37
+ def has_ok_line(text: str) -> bool:
38
+ return any(is_ok_token(line) for line in text.replace("\r", "").splitlines())
39
+
40
+
41
+ def has_tool_available_marker(text: str) -> bool:
42
+ normalized = text.replace("\r", "").lower()
43
+ if re.search(r"\btool_enabled\b", normalized):
44
+ return True
45
+ for match in re.finditer(r"\bavailable\s+tools?\s*:\s*([\s\S]{0,500})", normalized):
46
+ listed = match.group(1).strip()
47
+ if (
48
+ re.match(r"\bnone\b(?:[\s.!,;:()-]|$)", listed)
49
+ and (not re.search(r"\bbash\b", listed) or has_no_tool_refusal_marker(listed))
50
+ and not re.search(r"\bbash(?:\s+tool)?\b.*\b(?:is|are|was|were|be)\s+available\b", listed)
51
+ ):
52
+ continue
53
+ if re.search(r"\bbash\b", listed):
54
+ return True
55
+ for raw_line in text.replace("\r", "").splitlines():
56
+ line = raw_line.strip().lower()
57
+ if not line:
58
+ continue
59
+ if "bash" not in line:
60
+ continue
61
+ bash_unavailable = re.search(
62
+ r"\bbash(?:\s+tool)?\b.*\b(?:(?:is|was)\s+not|isn't|wasn't|not)\s+available\b|\bbash(?:\s+tool)?\b.*\bunavailable\b",
63
+ line,
64
+ )
65
+ if re.search(r"\bbash\s+tool\b.*\benabled\b", line):
66
+ return True
67
+ if re.search(r"\bbash\s+tool\b.*\b(?:is|are|was|were|be|available\s*:)\s+available\b", line):
68
+ return True
69
+ if re.search(r"\bbash\b.*\b(?:is|are|was|were|be)\s+available\b", line):
70
+ return True
71
+ if re.search(r"\bbash\s+tool\b.*\bavailable\b", line) and not bash_unavailable:
72
+ return True
73
+ if re.search(r"\b(?:can|could|will|would|able\s+to)\b.*\b(?:use|run|execute|call)\b.*\bbash\s+tool\b", line):
74
+ return True
75
+ if re.search(r"\bbash\s+tool\b.*\b(?:can|could|will|would|able\s+to)\b.*\b(?:use|run|execute|call)\b", line):
76
+ return True
77
+ if re.search(r"\b(?:can|could|will|would|able\s+to)\b.*\b(?:use|run|execute|call)\b.*\bbash\b", line):
78
+ return True
79
+ if re.search(r"\bbash\b.*\b(?:can|could|will|would|able\s+to)\b.*\b(?:use|run|execute|call)\b", line):
80
+ return True
81
+ if re.search(r"\b(?:use|using|used|run|ran|execute|executed|call|called)\b.*\bbash\b", line):
82
+ return True
83
+ if re.search(r"\bbash\b.*\b(?:using|used|ran|executed|called)\b", line):
84
+ return True
85
+ if re.search(r"\b(?:using|used|ran|executed|called)\b.*\bbash\s+tool\b", line):
86
+ return True
87
+ if re.search(r"\bbash\s+tool\b.*\b(?:using|used|ran|executed|called)\b", line):
88
+ return True
89
+ if has_no_tool_refusal_marker(line):
90
+ continue
91
+ if re.search(r"\b(?:use|using|used|run|ran|execute|executed|call|called)\b.*\bbash\s+tool\b", line):
92
+ return True
93
+ if re.search(r"\bbash\s+tool\b.*\b(?:use|using|used|run|ran|execute|executed|call|called)\b", line):
94
+ return True
95
+ return False
96
+
97
+
98
+ def has_no_tool_refusal_marker(text: str) -> bool:
99
+ normalized = text.replace("\r", "").lower()
100
+ patterns = (
101
+ r"\bbash\b.{0,120}\b(?:is\s+not|isn't|was\s+not|wasn't|not)\s+available\b",
102
+ r"\bbash\b.{0,120}\bunavailable\b",
103
+ r"\bbash\s+tool\b.{0,120}\b(?:is\s+not|isn't|was\s+not|wasn't|not)\s+available\b",
104
+ r"\bbash\s+tool\b.{0,120}\bunavailable\b",
105
+ r"\bbash\s+tool\b.{0,120}\b(?:not\s+allowed|refus(?:ed|al|ing)|denied|disabled|blocked)\b",
106
+ r"\b(?:cannot|can't|can\s+not|unable\s+to)\b.{0,120}\b(?:use|run|execute|call)\b.{0,120}\bbash\s+tool\b",
107
+ r"\bbash\s+tool\b.{0,120}\b(?:cannot|can't|can\s+not|unable\s+to)\b.{0,120}\b(?:use|run|execute|call)\b",
108
+ r"\bbash\s+tool\b.{0,120}\b(?:cannot|can't|can\s+not|unable\s+to)\s+run\s+that\s+command\b",
109
+ )
110
+ return any(re.search(pattern, normalized) for pattern in patterns)
111
+
112
+
113
+ def is_command_output_like_line(text: str) -> bool:
114
+ line = text.strip()
115
+ if not line:
116
+ return False
117
+ if re.search(r"\b[A-Za-z0-9_.-]+\.(?:md|py|sh|go|js|ts|tsx|json|yaml|yml|toml|txt)\b", line):
118
+ return True
119
+ if re.search(r"\b(?:README|scripts|src|bin|lib|dist|node_modules|go\.mod|package\.json)\b", line):
120
+ return True
121
+ if re.match(r"^[A-Za-z0-9_./-]+$", line):
122
+ return True
123
+ if re.match(r"^[-*]\s+[A-Za-z0-9_./-]+$", line):
124
+ return True
125
+ if re.match(r"^(?:total\s+\d+|drwx|[-r][-wxsStT])", line):
126
+ return True
127
+ if line.startswith(("{", "[", "$", ">")):
128
+ return True
129
+ return False
130
+
131
+
132
+ def is_allowed_probe_explanation_line(text: str) -> bool:
133
+ normalized = normalize(text)
134
+ if not normalized:
135
+ return True
136
+ if is_ok_token(normalized):
137
+ return True
138
+ if is_command_output_like_line(normalized):
139
+ return False
140
+ if has_no_tool_refusal_marker(normalized):
141
+ return True
142
+ return bool(re.search(r"\b(?:comply|explicit instructions?)\b", normalized, re.I))
143
+
144
+
145
+ def is_safe_ok_tail_value(text: str) -> bool:
146
+ normalized = normalize(text)
147
+ if is_ok_token(normalized):
148
+ return True
149
+ lines = [line.strip() for line in normalized.splitlines() if line.strip()]
150
+ return (
151
+ bool(lines)
152
+ and is_ok_token(lines[-1])
153
+ and any(has_no_tool_refusal_marker(line) for line in lines[:-1])
154
+ and not has_tool_available_marker(normalized)
155
+ and all(is_allowed_probe_explanation_line(line) for line in lines[:-1])
156
+ )
157
+
158
+
159
+ def result_text(env: object) -> str:
160
+ return "\n".join(envelope_text_values(env))
161
+
162
+
163
+ def envelope_text_values(env: object) -> list[str]:
164
+ if not isinstance(env, dict):
165
+ return []
166
+ values: list[str] = []
167
+ structured = env.get("structured_output")
168
+ if isinstance(structured, str):
169
+ values.append(structured)
170
+ result = env.get("result")
171
+ if isinstance(result, str):
172
+ values.append(result)
173
+ return values
174
+
175
+
176
+ def all_string_values(value: object) -> list[str]:
177
+ if isinstance(value, str):
178
+ return [value]
179
+ if isinstance(value, dict):
180
+ values: list[str] = []
181
+ for key, child in value.items():
182
+ if key in {"type", "subtype", "stop_reason", "terminal_reason", "session_id", "uuid"}:
183
+ continue
184
+ values.extend(all_string_values(child))
185
+ return values
186
+ if isinstance(value, list):
187
+ values: list[str] = []
188
+ for child in value:
189
+ values.extend(all_string_values(child))
190
+ return values
191
+ return []
192
+
193
+
194
+ def envelope_error_values(env: object) -> list[str]:
195
+ if not isinstance(env, dict):
196
+ return []
197
+ values: list[str] = []
198
+ for key in ("error", "message", "errors"):
199
+ value = env.get(key)
200
+ if isinstance(value, str):
201
+ values.append(value)
202
+ elif isinstance(value, (dict, list)) and value:
203
+ values.append(json.dumps(value, ensure_ascii=False))
204
+ return values
205
+
206
+
207
+ def classification_surface(env: object, stdout: str, stderr: str) -> str:
208
+ values: list[str] = []
209
+ if isinstance(env, dict):
210
+ values.extend(envelope_text_values(env))
211
+ values.extend(envelope_error_values(env))
212
+ if env.get("type") != "result":
213
+ values.append(stdout)
214
+ else:
215
+ values.append(stdout)
216
+ values.append(stderr)
217
+ return "\n".join(value for value in values if value)
218
+
219
+
220
+ def has_auth_marker(text: str) -> bool:
221
+ return any(NOT_LOGGED_IN.search(line.strip()) for line in text.splitlines())
222
+
223
+
224
+ def sanitize_snippet(text: str) -> str:
225
+ text = re.sub(r"~[\\/][^\s\"']+", "<path>", text)
226
+ text = re.sub(r"\bUsers[\\/][^\s\"']+", "<path>", text)
227
+ text = re.sub(r"\b[A-Za-z0-9._-]+(?:/[A-Za-z0-9._-]+)*/\.[^\s\"']+", "<path>", text)
228
+ text = re.sub(r"/[A-Za-z0-9._-]+(?:/[^\s\"']+)+", "<path>", text)
229
+ text = re.sub(r"(^|[\s:\"'(])/[A-Za-z0-9._-]+(?=$|[\s\"')])", r"\1<path>", text)
230
+ text = re.sub(r"\b[A-Za-z0-9._-]+(?:/[A-Za-z0-9._-]+){2,}\b", "<path>", text)
231
+ text = re.sub(r"([A-Za-z]:\\[^\s]+|\\\\[^\s]+)", "<path>", text)
232
+ text = re.sub(r"\bsk-[A-Za-z0-9_-]{8,}\b", "<secret>", text)
233
+ text = re.sub(r'"[^"]*(?:oauth|token|key|secret)[^"]*"\s*:\s*"[^"]+"', '"<secret>":"<secret>"', text, flags=re.I)
234
+ text = re.sub(r"\b(?:oauth|token|key|secret)[=:][A-Za-z0-9_./-]{8,}\b", "<secret>", text, flags=re.I)
235
+ text = re.sub(r"\b[A-Fa-f0-9]{32,}\b", "<secret>", text)
236
+ snippet = " ".join(text.split())[:200]
237
+ if snippet == "<path>":
238
+ return "path-only diagnostic redacted; inspect local probe stderr for details"
239
+ return snippet
240
+
241
+
242
+ def is_truthy_error(value: object) -> bool:
243
+ if isinstance(value, bool):
244
+ return value
245
+ if isinstance(value, int):
246
+ return value != 0
247
+ if isinstance(value, str):
248
+ return value.strip().lower() not in {"", "0", "false", "no", "none", "null"}
249
+ if isinstance(value, (dict, list)):
250
+ return bool(value)
251
+ return value is not None
252
+
253
+
254
+ def api_status_int(env: object) -> int | None:
255
+ if not isinstance(env, dict):
256
+ return None
257
+ status = env.get("api_error_status")
258
+ if status is None:
259
+ return None
260
+ try:
261
+ return int(status)
262
+ except (TypeError, ValueError):
263
+ return None
264
+
265
+
266
+ def _strict_object_pairs(pairs: list[tuple[str, object]]) -> dict:
267
+ """Reject duplicate object keys: json.loads silently keeps the LAST value,
268
+ which would let `"capabilities":["bad"],"capabilities":[]` masquerade as
269
+ empty. A duplicate-key record is malformed evidence and must fail closed."""
270
+ obj: dict = {}
271
+ for key, value in pairs:
272
+ if key in obj:
273
+ raise ValueError(f"duplicate JSON object key: {key!r}")
274
+ obj[key] = value
275
+ return obj
276
+
277
+
278
+ def loads_strict(text: str) -> object:
279
+ return json.loads(text, object_pairs_hook=_strict_object_pairs)
280
+
281
+
282
+ def parse_json_object(text: str) -> object | None:
283
+ stripped = normalize(text)
284
+ if not stripped:
285
+ return None
286
+ try:
287
+ return loads_strict(stripped)
288
+ except ValueError:
289
+ pass
290
+ parsed: list[object] = []
291
+ for line in stripped.splitlines():
292
+ candidate = line.strip()
293
+ if not candidate.startswith("{"):
294
+ continue
295
+ try:
296
+ parsed.append(loads_strict(candidate))
297
+ except ValueError:
298
+ pass
299
+ decoder = json.JSONDecoder(object_pairs_hook=_strict_object_pairs)
300
+ start = stripped.find("{")
301
+ while start != -1:
302
+ line_start = stripped.rfind("\n", 0, start) + 1
303
+ if stripped[line_start:start].strip():
304
+ start = stripped.find("{", start + 1)
305
+ continue
306
+ candidate = stripped[start:]
307
+ try:
308
+ value, end = decoder.raw_decode(candidate)
309
+ parsed.append(value)
310
+ start = stripped.find("{", start + end)
311
+ continue
312
+ except ValueError:
313
+ pass
314
+ start = stripped.find("{", start + 1)
315
+ result_values = [value for value in parsed if isinstance(value, dict) and value.get("type") == "result"]
316
+ for value in result_values:
317
+ if (
318
+ is_truthy_error(value.get("is_error"))
319
+ or value.get("api_error_status") is not None
320
+ or value.get("subtype") not in {None, "success"}
321
+ or value.get("permission_denials")
322
+ or envelope_error_values(value)
323
+ ):
324
+ return value
325
+ if result_values:
326
+ return result_values[-1]
327
+ if parsed:
328
+ return parsed[0]
329
+ return None
330
+
331
+
332
+ # The prompt attempts Bash, but the gate is broader: stream-json init data must
333
+ # prove that every declared tool/customization surface is empty, and no tool_use
334
+ # block may occur. Ground truth comes from the stream, not the model's reply
335
+ # token, which can hallucinate TOOL_ENABLED even when no tool exists.
336
+ PROBE_TOOL = "bash"
337
+ REQUIRED_EMPTY_INIT_FIELDS = (
338
+ "mcp_servers",
339
+ "slash_commands",
340
+ "skills",
341
+ "plugins",
342
+ )
343
+ # Fields that must be PRESENT (not merely empty). `permissionMode` is the only
344
+ # report of the reviewer's authority, and authority is scalar-shaped — which is
345
+ # why it is value-pinned rather than drift-tolerated. Without this, a CLI that
346
+ # renames the knob makes the old name simply vanish; absence is not "empty", and
347
+ # the drift policy below would wave the new scalar through as benign metadata.
348
+ # An init that no longer states its authority is unverifiable, not permissive.
349
+ REQUIRED_PRESENT_INIT_FIELDS = ("permissionMode",)
350
+ # Best-effort, deliberately NOT a boundary: name fragments that mark a scalar as
351
+ # authority-widening. The drift policy tolerates unknown scalars because they
352
+ # cannot ENUMERATE a surface — but a scalar can still GRANT one, so this catches
353
+ # the plausible spellings of a newly-added bypass knob
354
+ # (`dangerously_skip_permissions`, `bypass_sandbox`, ...).
355
+ #
356
+ # Honest limitation: a name-matching denylist over an open vocabulary cannot be
357
+ # complete, and this one is not. It is defense in depth on top of the complete
358
+ # check above (a renamed knob is caught by absence), chosen over reverting the
359
+ # whole relaxation — which would restore the outage this change exists to fix.
360
+ # It fails safe: a false positive refuses the lane as fallback-eligible drift,
361
+ # which now costs a reviewer-client switch rather than the review.
362
+ AUTHORITY_NAME_STEMS = (
363
+ "permission",
364
+ "bypass",
365
+ "dangerous",
366
+ "sandbox",
367
+ "privileg",
368
+ "escalat",
369
+ "elevat",
370
+ "unrestricted",
371
+ "authorit",
372
+ "admin",
373
+ "superuser",
374
+ )
375
+
376
+
377
+ def is_authority_name(name: str) -> bool:
378
+ """True when a field NAME reads as an authority knob.
379
+
380
+ Segment-wise, not raw substring. A substring test over short generic tokens
381
+ is a false-positive engine pointed straight back at the outage this change
382
+ removes: `auth` hits `author`, `root` hits `workspace_root`, and a benign
383
+ future metadata field would take every lane inconclusive on a perfectly
384
+ isolated run. Names are split on separators and camelCase humps, and a
385
+ segment must START with a stem — so `authorityLevel` matches while `author`
386
+ does not, and `adminMode` matches while `root_dir` does not.
387
+ """
388
+ segments = re.split(r"[_.\-]+|(?<=[a-z0-9])(?=[A-Z])", name)
389
+ return any(
390
+ segment.lower().startswith(stem)
391
+ for segment in segments
392
+ for stem in AUTHORITY_NAME_STEMS
393
+ )
394
+ # This list is CLOSED to incremental extension. It is a denylist over an open
395
+ # vocabulary, so it can always be extended by one more plausible word, and
396
+ # chasing that is a loop with no end state — the completeness argument belongs
397
+ # to the required-presence check above, which is complete by construction. The
398
+ # remaining exposure is an added authority knob whose name matches none of these
399
+ # fragments; it is accepted, recorded, and owned, not patched round by round.
400
+
401
+
402
+ def safe_identifier(name: object) -> str:
403
+ """Render a CLI-supplied init field name safe to embed in a reason string.
404
+
405
+ The wrapper routes on the reason TEXT, and JSON object keys are arbitrary
406
+ strings — including ones containing spaces. Interpolating a raw field name
407
+ lets the inspected CLI choose which routing arm matches: a field literally
408
+ named `unrecognized surface-shaped init field` would drag a breach reason
409
+ into the fallback-eligible class. Restricting to an identifier charset makes
410
+ every multi-word routing phrase unrepresentable, and the length cap keeps a
411
+ pathological key from burying the rest of the reason.
412
+ """
413
+ text = name if isinstance(name, str) else repr(name)
414
+ # `:` is kept: namespaced identifiers (`ccl-skills:testing-strategy`)
415
+ # stay readable in diagnostics and, containing no whitespace, still cannot
416
+ # spell a multi-word routing phrase.
417
+ cleaned = "".join(char if char.isalnum() or char in "_.-:" else "_" for char in text)
418
+ return (cleaned[:60] + "...") if len(cleaned) > 60 else (cleaned or "_")
419
+ # Explicitly known non-capability metadata from the installed stream-json init
420
+ # schema. `agents` is non-empty in safe mode, but cannot be invoked unless a
421
+ # corresponding tool appears in the separately checked `tools` allowlist.
422
+ #
423
+ # Drift policy (deliberate): the CLI adds scalar metadata fields nearly every
424
+ # release (`fast_mode_state`, `fast_mode_disabled_reason`, ...). Pinning field
425
+ # *names* would make every CLI upgrade a hard lane outage while proving nothing
426
+ # — a scalar cannot enumerate an invocable surface. So an unknown field fails
427
+ # closed only when its value is a NON-EMPTY list/dict, i.e. the only shape that
428
+ # could carry a new tool/skill/plugin/command surface. Invocability itself stays
429
+ # proven by the exact `tools` allowlist plus the tool_use scan, which no init
430
+ # field can bypass.
431
+ KNOWN_SAFE_INIT_METADATA_FIELDS = {
432
+ "type",
433
+ "subtype",
434
+ "cwd",
435
+ "session_id",
436
+ "model",
437
+ "permissionMode",
438
+ "apiKeySource",
439
+ "claude_code_version",
440
+ "output_style",
441
+ "agents",
442
+ "analytics_disabled",
443
+ "product_feedback_disabled",
444
+ "uuid",
445
+ "fast_mode_state",
446
+ }
447
+ KNOWN_SAFE_INIT_LIST_METADATA_FIELDS = {
448
+ # Claude Code 2.1.233 added this classification-only subset of the already
449
+ # declared slash_commands surface. It is safe only when every entry is a
450
+ # whole plain string already present in slash_commands; otherwise the new
451
+ # schema remains unverifiable and the lane fails closed.
452
+ "terminal_slash_commands",
453
+ }
454
+ KNOWN_SAFE_PERMISSION_MODES = {"default", "plan"}
455
+ KNOWN_SAFE_BUILTIN_SKILLS = {
456
+ "batch",
457
+ "claude-api",
458
+ "code-review",
459
+ "dataviz",
460
+ "debug",
461
+ "deep-research",
462
+ "design-sync",
463
+ "doctor",
464
+ "fewer-permission-prompts",
465
+ "loop",
466
+ "run",
467
+ "run-skill-generator",
468
+ "schedule",
469
+ "simplify",
470
+ "update-config",
471
+ "verify",
472
+ }
473
+ KNOWN_SAFE_BUILTIN_SLASH_COMMANDS = {
474
+ "__remote-workflow",
475
+ "agents",
476
+ "batch",
477
+ "claude-api",
478
+ "clear",
479
+ "code-review",
480
+ "color",
481
+ "compact",
482
+ "config",
483
+ "context",
484
+ "dataviz",
485
+ "debug",
486
+ "deep-research",
487
+ "design",
488
+ "design-consent",
489
+ "design-revoke",
490
+ "design-sync",
491
+ "doctor",
492
+ "effort",
493
+ "extra-usage",
494
+ "fast",
495
+ "fewer-permission-prompts",
496
+ "goal",
497
+ "heapdump",
498
+ # `/import` arrived in a CLI release after this snapshot was written, which
499
+ # is how the snapshot's cost was discovered: an unrecognised name used to be
500
+ # classified as a proven customization -- terminal and non-cascadable -- so
501
+ # one new built-in took out the whole reviewer lane. That is fixed at the
502
+ # CLASS level now (see is_bare_host_identifier): a bare name this list does
503
+ # not know is unverifiable and cascades. This list therefore no longer
504
+ # decides whether review is POSSIBLE, only whether the Claude lane is the
505
+ # one that serves it, so a missing name costs a client switch instead of the
506
+ # capability. Keep it accurate where it is cheap; do not treat adding a name
507
+ # as the fix for a lane outage.
508
+ "import",
509
+ "init",
510
+ "insights",
511
+ "loop",
512
+ "mcp",
513
+ "model",
514
+ "recap",
515
+ "reload-skills",
516
+ "rename",
517
+ "review",
518
+ "run",
519
+ "run-skill-generator",
520
+ "schedule",
521
+ "security-review",
522
+ "simplify",
523
+ "team-onboarding",
524
+ "ultrareview",
525
+ "update-config",
526
+ "usage",
527
+ "usage-credits",
528
+ "verify",
529
+ "workflow-launch-exec",
530
+ }
531
+
532
+
533
+ def stream_events(text: str) -> list[dict]:
534
+ """Parse newline-delimited JSON (stream-json) into a list of event objects.
535
+ Non-JSON or non-object lines are skipped; a single result envelope still
536
+ parses as a one-element list."""
537
+ events: list[dict] = []
538
+ for line in text.replace("\r", "").splitlines():
539
+ line = line.strip()
540
+ if not line.startswith("{"):
541
+ continue
542
+ try:
543
+ parsed = loads_strict(line)
544
+ except ValueError:
545
+ continue
546
+ if isinstance(parsed, dict):
547
+ events.append(parsed)
548
+ return events
549
+
550
+
551
+ def stream_has_malformed_record(text: str) -> bool:
552
+ """A line that looks like a stream-json record (starts with '{') but does not
553
+ parse as standalone JSON. In a complete (rc==0) stream-json capture every
554
+ event is one parseable line, so such a record means a tool declaration or
555
+ tool_use may have been silently dropped -> the ground-truth is untrustworthy.
556
+ (Pretty-printed single envelopes are handled by the text fallback, which never
557
+ reaches the stream ground-truth path; see main.)"""
558
+ for line in text.replace("\r", "").splitlines():
559
+ line = line.strip()
560
+ if not line.startswith("{"):
561
+ continue
562
+ try:
563
+ loads_strict(line)
564
+ except ValueError:
565
+ return True
566
+ return False
567
+
568
+
569
+ # Event types that only appear in a stream-json (--verbose) capture, never in a
570
+ # plain single result envelope. Their presence means the parser MUST have the
571
+ # init ground-truth; absent init in such a capture = unverifiable -> fail closed.
572
+ STREAM_EVENT_TYPES = {"system", "assistant", "user"}
573
+
574
+
575
+ def is_stream_json_capture(events: list[dict]) -> bool:
576
+ return any(ev.get("type") in STREAM_EVENT_TYPES for ev in events)
577
+
578
+
579
+ def stream_has_nonjson_line(text: str) -> bool:
580
+ """Any non-empty line that is not standalone JSON. A confirmed stream-json
581
+ capture is pure JSONL (verified: real captures have zero non-JSON lines), so
582
+ such a line is a corrupt/dropped record — including one that lost its leading
583
+ '{' and so slips past the '{'-prefixed malformed check."""
584
+ for line in text.replace("\r", "").splitlines():
585
+ stripped = line.strip()
586
+ if not stripped:
587
+ continue
588
+ try:
589
+ loads_strict(stripped)
590
+ except ValueError:
591
+ return True
592
+ return False
593
+
594
+
595
+ def stream_nonjson_surface(text: str) -> str:
596
+ """Return only non-JSON stream lines for transport/auth classification.
597
+
598
+ In runtime-surface mode, model reply prose lives inside JSON records and is
599
+ intentionally ignored. A CLI banner or startup diagnostic outside those
600
+ records is host-controlled evidence and must still classify auth/quota.
601
+ """
602
+ lines: list[str] = []
603
+ for line in text.replace("\r", "").splitlines():
604
+ stripped = line.strip()
605
+ if not stripped:
606
+ continue
607
+ try:
608
+ loads_strict(stripped)
609
+ except ValueError:
610
+ lines.append(stripped)
611
+ return "\n".join(lines)
612
+
613
+
614
+ def stream_classification(text: str, events: list[dict]) -> tuple[bool, bool]:
615
+ """Classify a capture as (is_stream, is_corrupt).
616
+
617
+ is_stream: a stream-only event type parsed (system/assistant/user), OR a
618
+ standalone record coexists with a '{'-prefixed malformed line (JSONL whose
619
+ init/tool_use line was dropped). A pretty-printed single envelope or plain
620
+ text yields neither.
621
+ is_corrupt: a '{'-prefixed unparseable line, OR — once we know it is a real
622
+ stream — any non-JSON line at all."""
623
+ confirmed = is_stream_json_capture(events)
624
+ brace_malformed = stream_has_malformed_record(text)
625
+ is_stream = confirmed or (bool(events) and brace_malformed)
626
+ is_corrupt = brace_malformed or (confirmed and stream_has_nonjson_line(text))
627
+ return is_stream, is_corrupt
628
+
629
+
630
+ def init_declared_tools(events: list[dict]) -> set[str] | None:
631
+ """Tools the session exposes, aggregated across ALL stream-json system/init
632
+ events (a later init must not be masked by an earlier empty one). Lowercased
633
+ union, or None when no init event with a tools list is present (ground-truth
634
+ unavailable -> caller falls back to text-based parsing)."""
635
+ declared: set[str] | None = None
636
+ for ev in events:
637
+ if ev.get("type") == "system" and ev.get("subtype") == "init":
638
+ tools = ev.get("tools")
639
+ if isinstance(tools, list):
640
+ names = {str(t).strip().lower() for t in tools if isinstance(t, str)}
641
+ declared = names if declared is None else declared | names
642
+ return declared
643
+
644
+
645
+ def init_surface_state(
646
+ events: list[dict],
647
+ expected_tools: set[str] | None = None,
648
+ expected_native_skills: set[str] | None = None,
649
+ required_native_skills: set[str] | None = None,
650
+ host_init_baseline: dict[str, object] | None = None,
651
+ ) -> tuple[
652
+ set[str], set[str], set[str], set[str], set[str], set[str], set[str]
653
+ ] | None:
654
+ """Return init isolation state across all init events.
655
+
656
+ Result fields: missing/invalid required fields, non-empty customization
657
+ fields, declared tool names, unrecognized surface-shaped fields, fields
658
+ declaring an unsafe value, fields whose authority is unverifiable, and
659
+ unclassifiable host-vocabulary identifiers. A missing or wrongly typed
660
+ required field is not treated as empty, because that would turn a CLI schema
661
+ change into a silent gate bypass. Unknown *scalar* metadata is tolerated on
662
+ purpose — see the drift policy on KNOWN_SAFE_INIT_METADATA_FIELDS.
663
+
664
+ Unsafe *values* are kept apart from unrecognized *shapes* on purpose: an
665
+ unknown schema addition means this lane cannot verify isolation (report it,
666
+ fall back to another reviewer), while a known field carrying an unsafe
667
+ value — `permissionMode: "bypassPermissions"` — is a breached boundary and
668
+ must terminate the lane. Merging them would let a real privilege escalation
669
+ inherit the drift class's softer next_action.
670
+
671
+ Unrecognized *identifiers* split the same way, and for the same reason: a
672
+ bare command/skill name outside the built-in snapshot cannot be shown to be
673
+ a customization, because the snapshot is of a vocabulary the host owns, so
674
+ it reports as unverifiable. A namespaced, path-shaped, duplicated or
675
+ unparseable entry IS a customization and stays in `nonempty`.
676
+ """
677
+ expected_native_skills = expected_native_skills or set()
678
+ required_native_skills = {
679
+ name.lower() for name in (required_native_skills or set())
680
+ }
681
+ baseline_commands = (
682
+ set(host_init_baseline.get("slash_commands", ()))
683
+ if host_init_baseline
684
+ else set()
685
+ )
686
+ baseline_skills = (
687
+ set(host_init_baseline.get("skills", ()))
688
+ if host_init_baseline
689
+ else set()
690
+ )
691
+ baseline_version = (
692
+ host_init_baseline.get("claude_code_version")
693
+ if host_init_baseline
694
+ else None
695
+ )
696
+ saw_init = False
697
+ missing_or_invalid: set[str] = set()
698
+ nonempty: set[str] = set()
699
+ declared_tools: set[str] = set()
700
+ unknown_fields: set[str] = set()
701
+ unsafe_values: set[str] = set()
702
+ # Unverifiable authority is NOT a proven breach: we cannot show the reviewer
703
+ # was elevated, only that we can no longer show it was not. It therefore
704
+ # reports in the fallback-eligible class like schema drift — routing a
705
+ # renamed knob to the terminal class would reproduce the total outage this
706
+ # change exists to remove. A KNOWN field carrying a KNOWN-unsafe value stays
707
+ # terminal in `unsafe_values`, because that one is proven.
708
+ unverifiable_authority: set[str] = set()
709
+ # Host vocabulary this snapshot does not recognise. Kept apart from
710
+ # `nonempty` for the same reason `unverifiable_authority` is: reporting an
711
+ # unverifiable thing in the proven-breach class is what turned a routine CLI
712
+ # release into a total review outage. Bare identifiers only — see
713
+ # is_bare_host_identifier for what stays terminal.
714
+ unclassifiable_vocabulary: set[str] = set()
715
+ declared_customizations: dict[str, set[str]] = {
716
+ "slash_commands": set(),
717
+ "skills": set(),
718
+ "plugins": set(),
719
+ }
720
+ known_fields = {
721
+ "tools",
722
+ "capabilities",
723
+ *REQUIRED_EMPTY_INIT_FIELDS,
724
+ *KNOWN_SAFE_INIT_METADATA_FIELDS,
725
+ *KNOWN_SAFE_INIT_LIST_METADATA_FIELDS,
726
+ }
727
+ for ev in events:
728
+ if ev.get("type") != "system" or ev.get("subtype") != "init":
729
+ continue
730
+ saw_init = True
731
+ tools = ev.get("tools")
732
+ if not isinstance(tools, list):
733
+ missing_or_invalid.add("tools")
734
+ elif any(not isinstance(tool, str) for tool in tools):
735
+ # Do not turn a future descriptor/object schema into an empty set.
736
+ # The installed stream contract is a list of names; any other
737
+ # element shape is unverifiable and must fail closed.
738
+ missing_or_invalid.add("tools")
739
+ else:
740
+ declared_tools.update(
741
+ tool.strip().lower() for tool in tools
742
+ )
743
+ for field in REQUIRED_EMPTY_INIT_FIELDS:
744
+ value = ev.get(field)
745
+ if not isinstance(value, list):
746
+ missing_or_invalid.add(field)
747
+ elif field in declared_customizations:
748
+ identifiers = [
749
+ customization_entry_identifier(entry) for entry in value
750
+ ]
751
+ declared_customizations[field].update(identifiers)
752
+ if len(identifiers) != len(set(identifiers)):
753
+ nonempty.add(field)
754
+ if value and expected_native_skills:
755
+ for entry in value:
756
+ identifier = customization_entry_identifier(entry)
757
+ if field in HOST_VOCABULARY_FIELDS and (
758
+ not host_entry_is_whole(entry, identifier)
759
+ ):
760
+ # Nothing may be discarded to reach a verdict on
761
+ # these fields — see host_entry_is_whole. Runs BEFORE
762
+ # the allowlist, because the allowlist consumes the
763
+ # same lossy identifier and would clear the entry
764
+ # outright on a truncated or dict-supplied name.
765
+ # Legitimate namespaced entries are unaffected: their
766
+ # whole value IS the identifier.
767
+ nonempty.add(field)
768
+ continue
769
+ if customization_entry_allowed(
770
+ field,
771
+ entry,
772
+ expected_native_skills,
773
+ baseline_commands,
774
+ baseline_skills,
775
+ ):
776
+ continue
777
+ if field in HOST_VOCABULARY_FIELDS and (
778
+ is_bare_host_identifier(identifier)
779
+ ):
780
+ # Cannot be shown to be a customization: the
781
+ # allowlist it failed is a snapshot of a vocabulary
782
+ # the host owns. Refuse, but stay cascadable.
783
+ unclassifiable_vocabulary.add(
784
+ f"{field}:{identifier}"
785
+ )
786
+ else:
787
+ nonempty.add(field)
788
+ elif value:
789
+ nonempty.add(field)
790
+ elif value:
791
+ nonempty.add(field)
792
+ # Per EVENT, not on the union across events: a later init that drops or
793
+ # renames the authority field must not be masked by an earlier one that
794
+ # stated it. Every other required-field check in this loop is per event;
795
+ # this one was not, which is exactly the masking shape the existing
796
+ # later-init-declares-Bash fixture guards against for tools.
797
+ for required in REQUIRED_PRESENT_INIT_FIELDS:
798
+ if required not in ev:
799
+ unverifiable_authority.add(required)
800
+ for field, value in ev.items():
801
+ if field not in known_fields and is_authority_name(field):
802
+ # Authority is scalar-shaped, so the container test below
803
+ # cannot see it. Flagged regardless of value shape: a
804
+ # newly-added authority knob is unreviewed either way.
805
+ unverifiable_authority.add(field)
806
+ elif field not in known_fields:
807
+ # Version-drift tolerance: only a non-empty container under an
808
+ # unknown name can enumerate a new invocable surface. A scalar
809
+ # (or an empty list/dict) is metadata and stays allowed, so a
810
+ # routine CLI release does not take the reviewer lane down.
811
+ if isinstance(value, (list, dict)) and value:
812
+ unknown_fields.add(field)
813
+ elif field in ("agents", "capabilities"):
814
+ # Shape-only, no value vocabulary: `agents` needs the Agent tool
815
+ # and `capabilities` announces host stream-protocol features —
816
+ # neither is invocable unless a tool shows up in the separately
817
+ # checked `tools` allowlist, so pinning their member names only
818
+ # buys CLI-version brittleness. A non-string member means an
819
+ # unverifiable descriptor schema and still fails closed.
820
+ if not isinstance(value, list) or any(
821
+ not isinstance(item, str) for item in value
822
+ ):
823
+ unknown_fields.add(field)
824
+ elif field == "permissionMode":
825
+ if value not in KNOWN_SAFE_PERMISSION_MODES:
826
+ unsafe_values.add(field)
827
+ elif field in KNOWN_SAFE_INIT_LIST_METADATA_FIELDS:
828
+ if not isinstance(value, list) or any(
829
+ not isinstance(item, str) for item in value
830
+ ):
831
+ unknown_fields.add(field)
832
+ else:
833
+ identifiers = [
834
+ customization_entry_identifier(item) for item in value
835
+ ]
836
+ if (
837
+ len(identifiers) != len(set(identifiers))
838
+ or any(
839
+ not host_entry_is_whole(item, identifier)
840
+ for item, identifier in zip(value, identifiers)
841
+ )
842
+ or not set(identifiers).issubset(
843
+ declared_customizations["slash_commands"]
844
+ )
845
+ ):
846
+ unknown_fields.add(field)
847
+ elif field in KNOWN_SAFE_INIT_METADATA_FIELDS and isinstance(
848
+ value, (list, dict)
849
+ ):
850
+ unknown_fields.add(field)
851
+ if baseline_version is not None and ev.get("claude_code_version") != baseline_version:
852
+ # The two invocations no longer prove one same-version host
853
+ # vocabulary snapshot. Refuse this lane, but treat the mismatch as
854
+ # capability drift rather than a proven tool/authority breach so a
855
+ # different reviewer may continue.
856
+ unknown_fields.add("claude_code_version:host-baseline-mismatch")
857
+ if not saw_init:
858
+ return None
859
+ if expected_native_skills:
860
+ if "ccl-skills" not in declared_customizations["plugins"]:
861
+ missing_or_invalid.add("plugins:ccl-skills")
862
+ ambiguous_required_skills = (
863
+ required_native_skills & KNOWN_SAFE_BUILTIN_SKILLS
864
+ )
865
+ for skill_name in ambiguous_required_skills:
866
+ missing_or_invalid.add(f"skills:ambiguous-selected-owner:{skill_name}")
867
+ expected_ccl_skill_identifiers = {
868
+ identifier
869
+ for skill_name in expected_native_skills
870
+ for identifier in (skill_name, f"ccl-skills:{skill_name}")
871
+ }
872
+ declared_ccl_skills = (
873
+ declared_customizations["skills"]
874
+ & expected_ccl_skill_identifiers
875
+ ) - KNOWN_SAFE_BUILTIN_SKILLS
876
+ if declared_ccl_skills:
877
+ for skill_name in required_native_skills:
878
+ namespaced = f"ccl-skills:{skill_name}"
879
+ if not {
880
+ skill_name,
881
+ namespaced,
882
+ } & declared_customizations["skills"]:
883
+ missing_or_invalid.add(f"skills:{skill_name}")
884
+ declared_ccl_commands = {
885
+ identifier
886
+ for identifier in declared_customizations["slash_commands"]
887
+ if identifier.startswith("ccl-skills:")
888
+ }
889
+ if declared_ccl_commands:
890
+ for skill_name in required_native_skills:
891
+ namespaced = f"ccl-skills:{skill_name}"
892
+ if namespaced not in declared_customizations["slash_commands"]:
893
+ missing_or_invalid.add(f"slash_commands:{namespaced}")
894
+ return (
895
+ missing_or_invalid,
896
+ nonempty,
897
+ declared_tools,
898
+ unknown_fields,
899
+ unsafe_values,
900
+ unverifiable_authority,
901
+ unclassifiable_vocabulary,
902
+ )
903
+
904
+
905
+ def customization_entry_identifier(entry: object) -> str:
906
+ raw_identifier = ""
907
+ if isinstance(entry, str):
908
+ raw_identifier = entry.strip().split(maxsplit=1)[0]
909
+ elif isinstance(entry, dict):
910
+ for key in ("name", "command", "id"):
911
+ candidate = entry.get(key)
912
+ if isinstance(candidate, str) and candidate.strip():
913
+ raw_identifier = candidate.strip().split(maxsplit=1)[0]
914
+ break
915
+ if not re.fullmatch(r"[A-Za-z0-9_./:@+-]{1,120}", raw_identifier):
916
+ return "<unidentified>"
917
+ return raw_identifier.lower().lstrip("/")
918
+
919
+
920
+ def customization_entry_allowed(
921
+ field: str,
922
+ entry: object,
923
+ expected_native_skills: set[str],
924
+ baseline_commands: set[str] | None = None,
925
+ baseline_skills: set[str] | None = None,
926
+ ) -> bool:
927
+ identifier = customization_entry_identifier(entry)
928
+ baseline_commands = baseline_commands or set()
929
+ # Baseline skills remain available to drift diagnostics, but never grant
930
+ # formal-run authority: a future safe-mode regression could otherwise turn
931
+ # one leaked user skill into an accepted callable capability.
932
+ baseline_skills = baseline_skills or set()
933
+ selected_names = {name.lower() for name in expected_native_skills}
934
+ selected_namespaced = {
935
+ f"ccl-skills:{name}" for name in selected_names
936
+ }
937
+ if field == "plugins":
938
+ return identifier == "ccl-skills"
939
+ if field == "skills":
940
+ return (
941
+ identifier in KNOWN_SAFE_BUILTIN_SKILLS
942
+ or identifier in selected_names
943
+ or identifier in selected_namespaced
944
+ )
945
+ if field == "slash_commands":
946
+ return (
947
+ identifier in KNOWN_SAFE_BUILTIN_SLASH_COMMANDS
948
+ or identifier in baseline_commands
949
+ or identifier in selected_namespaced
950
+ )
951
+ return False
952
+
953
+
954
+ # Fields whose entries, in a real run, come from the HOST's built-in vocabulary
955
+ # rather than from anything this repo installs: measured at CLI 2.1.220, the
956
+ # review-skill invocation reports 46 built-in commands and 16 built-in skills and
957
+ # nothing else. `plugins` is deliberately absent -- a plugin is user-installed by
958
+ # definition, and the expected set there is exactly the one this repo owns.
959
+ HOST_VOCABULARY_FIELDS = ("slash_commands", "skills")
960
+ # A bare identifier: no namespace, no path. Deliberately NOT "anything the
961
+ # allowlist missed" -- the discriminator has to be a property of the identifier
962
+ # itself, because the allowlist is the thing that cannot be trusted to be
963
+ # current.
964
+ BARE_HOST_IDENTIFIER = re.compile(r"[a-z0-9][a-z0-9_.-]*\Z")
965
+
966
+
967
+ def host_entry_is_whole(entry: object, identifier: str) -> bool:
968
+ """True when nothing about a host-vocabulary entry was discarded to read it.
969
+
970
+ `customization_entry_identifier` is deliberately lossy — it keeps the first
971
+ whitespace-delimited token and reads a dict's `name` — which is right for a
972
+ DIAGNOSTIC string and wrong for a trust decision. Three review findings in
973
+ this slice were one shape: evidence present in the entry but never read. A
974
+ dict hid a path in a sibling key; a dict hid it under an allowed built-in
975
+ name; and `"brand-new evil-plugin:pwn"` truncated to `brand-new` while the
976
+ discarded suffix was the very proof of a customization.
977
+
978
+ So the classification consumes the WHOLE value: the entry must be a plain
979
+ string whose normalization — case folding and at most one leading `/`, the
980
+ only normalization the identifier helper itself applies — reproduces the
981
+ identifier exactly. Any remainder, any other shape, and the entry is a
982
+ customization this parser cannot clear. Checked BEFORE the allowlist,
983
+ because the allowlist reads the same truncated token.
984
+ """
985
+ if not isinstance(entry, str):
986
+ return False
987
+ # Deliberately NO `.strip()`. The first version of this function called it,
988
+ # which reproduced inside the fix the exact lossiness the fix exists to
989
+ # reject: `"import "` stripped to `import`, compared equal to the identifier,
990
+ # was declared whole, and the allowlist then ACCEPTED it with isolation
991
+ # reported verified. Surrounding whitespace is part of the value, so an entry
992
+ # carrying any is not a plain host name.
993
+ normalized = entry.lower()
994
+ if normalized.startswith("/"):
995
+ normalized = normalized[1:]
996
+ return normalized == identifier
997
+
998
+
999
+ def is_bare_host_identifier(identifier: str) -> bool:
1000
+ """True when a disallowed entry cannot be PROVEN to be a customization.
1001
+
1002
+ Only ever consulted for a PLAIN STRING entry — see the caller. A dict entry
1003
+ is a structured descriptor whose other keys this parser does not validate,
1004
+ so `{"name": "brand-new", "command": "/x/y"}` would otherwise be classified
1005
+ on its bare `name` while a sibling key carried path-shaped proof of a real
1006
+ customization. That is not the unclassifiable case this class is for: the
1007
+ evidence was present and merely unread. Measured against the real CLI, both
1008
+ host-vocabulary fields arrive as plain strings (only `plugins`, already
1009
+ excluded, uses dicts), so refusing dicts here costs nothing operationally.
1010
+
1011
+ `customization_entry_identifier` has already lowercased, stripped a leading
1012
+ `/`, and replaced anything it could not parse with `<unidentified>`. What is
1013
+ left is bare only if it carries no namespace separator and no path
1014
+ separator, so each of these stays a proven breach:
1015
+
1016
+ * `evil-plugin:pwn` -- a namespace proves a surface beyond the one
1017
+ expected plugin, which is a customization, not host vocabulary.
1018
+ * `dir/cmd` -- no host built-in is spelled as a path.
1019
+ * `<unidentified>` -- an entry that failed the charset or was not a
1020
+ string/dict is not evidence of anything, least of all of host origin.
1021
+
1022
+ Note what this does NOT claim: a bare name may still be a user-authored
1023
+ command. The point is that we cannot tell, and the unclassifiable case
1024
+ belongs in the class that refuses and cascades rather than the class that
1025
+ refuses and destroys the capability. Isolation itself is still proven only
1026
+ by the exact `tools` allowlist, the tool_use scan, and the value-pinned
1027
+ `permissionMode` -- none of which any identifier here can affect.
1028
+ """
1029
+ return bool(BARE_HOST_IDENTIFIER.fullmatch(identifier))
1030
+
1031
+
1032
+ def load_host_init_baseline(path: str) -> tuple[dict[str, object] | None, str | None]:
1033
+ """Read one safe-mode, no-plugin init capture as version-owned vocabulary.
1034
+
1035
+ The baseline is not a verdict and its model result is ignored. It may name
1036
+ host commands and skills only because the wrapper invocation disables
1037
+ setting sources, CLAUDE.md, auto-memory, MCP, tools, and plugins. Any tool,
1038
+ plugin, malformed identifier, authority drift, or unknown non-empty surface
1039
+ keeps the baseline unusable rather than laundering it into the main run.
1040
+ """
1041
+ try:
1042
+ text = Path(path).read_text(encoding="utf-8", errors="replace")
1043
+ except OSError:
1044
+ return None, "Claude host-vocabulary baseline could not be read"
1045
+ events = stream_events(normalize(text))
1046
+ stream_like, stream_corrupt = stream_classification(text, events)
1047
+ init_events = [
1048
+ event
1049
+ for event in events
1050
+ if event.get("type") == "system" and event.get("subtype") == "init"
1051
+ ]
1052
+ if not stream_like or stream_corrupt or len(init_events) != 1:
1053
+ return None, "Claude host-vocabulary baseline lacks one intact init event"
1054
+ if invoked_tool_names(events):
1055
+ return None, "Claude host-vocabulary baseline invoked a tool"
1056
+ init_event = init_events[0]
1057
+ if init_event.get("tools") != []:
1058
+ return None, "Claude host-vocabulary baseline exposed a tool"
1059
+ # Keep this set-derived rather than spelling today's MCP/plugin fields
1060
+ # twice. If the formal init adds another required-empty customization
1061
+ # surface, the baseline must prove it empty before its command vocabulary
1062
+ # can carry authority. Known metadata such as `agents` is deliberately not
1063
+ # in REQUIRED_EMPTY_INIT_FIELDS: with tools pinned empty it is descriptive,
1064
+ # not model-invocable.
1065
+ for field in REQUIRED_EMPTY_INIT_FIELDS:
1066
+ if field not in HOST_VOCABULARY_FIELDS and init_event.get(field) != []:
1067
+ return None, f"Claude host-vocabulary baseline exposed {field}"
1068
+ if init_event.get("permissionMode") != "default":
1069
+ return None, "Claude host-vocabulary baseline changed permission authority"
1070
+ version = init_event.get("claude_code_version")
1071
+ if not isinstance(version, str) or not version or len(version) > 120:
1072
+ return None, "Claude host-vocabulary baseline lacks a bounded CLI version"
1073
+
1074
+ surfaces: dict[str, tuple[str, ...]] = {}
1075
+ for field in HOST_VOCABULARY_FIELDS:
1076
+ known_host_identifiers = (
1077
+ KNOWN_SAFE_BUILTIN_SLASH_COMMANDS
1078
+ if field == "slash_commands"
1079
+ else KNOWN_SAFE_BUILTIN_SKILLS
1080
+ )
1081
+ value = init_event.get(field)
1082
+ if not isinstance(value, list) or any(not isinstance(item, str) for item in value):
1083
+ return None, f"Claude host-vocabulary baseline has malformed {field}"
1084
+ identifiers = [customization_entry_identifier(item) for item in value]
1085
+ if (
1086
+ len(identifiers) != len(set(identifiers))
1087
+ or any(
1088
+ not host_entry_is_whole(item, identifier)
1089
+ for item, identifier in zip(value, identifiers)
1090
+ )
1091
+ or any(
1092
+ identifier not in known_host_identifiers
1093
+ and not is_bare_host_identifier(identifier)
1094
+ for identifier in identifiers
1095
+ )
1096
+ ):
1097
+ return None, f"Claude host-vocabulary baseline has unsafe {field}"
1098
+ surfaces[field] = tuple(identifiers)
1099
+
1100
+ terminal_commands = init_event.get("terminal_slash_commands", [])
1101
+ if not isinstance(terminal_commands, list) or any(
1102
+ not isinstance(item, str) for item in terminal_commands
1103
+ ):
1104
+ return None, "Claude host-vocabulary baseline has malformed terminal commands"
1105
+ terminal_identifiers = [
1106
+ customization_entry_identifier(item) for item in terminal_commands
1107
+ ]
1108
+ if (
1109
+ len(terminal_identifiers) != len(set(terminal_identifiers))
1110
+ or any(
1111
+ not host_entry_is_whole(item, identifier)
1112
+ for item, identifier in zip(terminal_commands, terminal_identifiers)
1113
+ )
1114
+ or not set(terminal_identifiers).issubset(set(surfaces["slash_commands"]))
1115
+ ):
1116
+ return None, "Claude host-vocabulary baseline has unsafe terminal commands"
1117
+
1118
+ known_fields = {
1119
+ "tools",
1120
+ "capabilities",
1121
+ *REQUIRED_EMPTY_INIT_FIELDS,
1122
+ *KNOWN_SAFE_INIT_METADATA_FIELDS,
1123
+ *KNOWN_SAFE_INIT_LIST_METADATA_FIELDS,
1124
+ }
1125
+ for field, value in init_event.items():
1126
+ if field not in known_fields and is_authority_name(field):
1127
+ return None, "Claude host-vocabulary baseline has unverifiable authority"
1128
+ if field not in known_fields and isinstance(value, (list, dict)) and value:
1129
+ return None, "Claude host-vocabulary baseline has an unknown non-empty surface"
1130
+ if field in ("agents", "capabilities") and (
1131
+ not isinstance(value, list)
1132
+ or any(not isinstance(item, str) for item in value)
1133
+ ):
1134
+ return None, f"Claude host-vocabulary baseline has malformed {field}"
1135
+
1136
+ return {
1137
+ "claude_code_version": version,
1138
+ "slash_commands": surfaces["slash_commands"],
1139
+ "skills": surfaces["skills"],
1140
+ }, None
1141
+
1142
+
1143
+ def unexpected_customization_identifiers(
1144
+ events: list[dict],
1145
+ expected_native_skills: set[str] | None = None,
1146
+ host_init_baseline: dict[str, object] | None = None,
1147
+ ) -> set[str]:
1148
+ """Return bounded identifiers without exposing customization bodies."""
1149
+ expected_native_skills = expected_native_skills or set()
1150
+ baseline_commands = (
1151
+ set(host_init_baseline.get("slash_commands", ()))
1152
+ if host_init_baseline
1153
+ else set()
1154
+ )
1155
+ baseline_skills = (
1156
+ set(host_init_baseline.get("skills", ()))
1157
+ if host_init_baseline
1158
+ else set()
1159
+ )
1160
+ unexpected: set[str] = set()
1161
+ for ev in events:
1162
+ if ev.get("type") != "system" or ev.get("subtype") != "init":
1163
+ continue
1164
+ for field in ("slash_commands", "skills", "plugins"):
1165
+ value = ev.get(field)
1166
+ if not isinstance(value, list):
1167
+ continue
1168
+ for entry in value:
1169
+ if customization_entry_allowed(
1170
+ field,
1171
+ entry,
1172
+ expected_native_skills,
1173
+ baseline_commands,
1174
+ baseline_skills,
1175
+ ):
1176
+ continue
1177
+ unexpected.add(
1178
+ f"{field}:{customization_entry_identifier(entry)}"
1179
+ )
1180
+ return unexpected
1181
+
1182
+
1183
+ def invoked_tool_names(events: list[dict]) -> set[str]:
1184
+ """Names of tools the model actually invoked (tool_use blocks). Empty under a
1185
+ real no-tool sandbox even when the reply text claims a tool ran."""
1186
+ names: set[str] = set()
1187
+ for ev in events:
1188
+ message = ev.get("message")
1189
+ content = message.get("content") if isinstance(message, dict) else None
1190
+ if not isinstance(content, list):
1191
+ continue
1192
+ for block in content:
1193
+ if isinstance(block, dict) and block.get("type") == "tool_use":
1194
+ name = block.get("name")
1195
+ if isinstance(name, str):
1196
+ names.add(name.strip().lower())
1197
+ else:
1198
+ # A malformed tool_use still proves that an invocation
1199
+ # record exists. Preserve it as an impossible expected
1200
+ # name so every allowlist comparison rejects the stream.
1201
+ names.add("<invalid-tool-name>")
1202
+ return names
1203
+
1204
+
1205
+ def bash_tool_present(events: list[dict]) -> bool:
1206
+ """Ground-truth: was the Bash tool available to or used by the session? An
1207
+ actual Bash tool_use is a hard fail INDEPENDENT of the init event (a stream
1208
+ missing its init must not launder a real Bash call through the text
1209
+ fallback)."""
1210
+ if PROBE_TOOL in invoked_tool_names(events):
1211
+ return True
1212
+ declared = init_declared_tools(events)
1213
+ return declared is not None and PROBE_TOOL in declared
1214
+
1215
+
1216
+ def envelope_structurally_clean(
1217
+ env: object,
1218
+ stdout: str = "",
1219
+ stderr: str = "",
1220
+ *,
1221
+ ignore_reply_text: bool = False,
1222
+ ) -> bool:
1223
+ """Result envelope carries no error/auth/quota/permission signal. Excludes the
1224
+ reply-text checks so a ground-truth caller can ignore a hallucinated reply."""
1225
+ if not isinstance(env, dict):
1226
+ return False
1227
+ if env.get("type") != "result":
1228
+ return False
1229
+ if is_truthy_error(env.get("is_error")):
1230
+ return False
1231
+ api_status = api_status_int(env)
1232
+ raw_api_status = env.get("api_error_status")
1233
+ if raw_api_status not in {None, 0, "0"} and (api_status is None or api_status >= 400):
1234
+ return False
1235
+ if env.get("permission_denials"):
1236
+ return False
1237
+ if env.get("subtype") not in {None, "success", "completed", "stop_turn", "end_turn"}:
1238
+ return False
1239
+ if envelope_error_values(env):
1240
+ return False
1241
+ if ignore_reply_text:
1242
+ # Main runtime attestation validates the result envelope's structural
1243
+ # error fields here, while parse_review_json.py owns the model payload.
1244
+ # Preserve stderr auth/quota signals without trusting or rejecting
1245
+ # model-authored reply prose that can quote those same words.
1246
+ surface = stderr
1247
+ else:
1248
+ surface = "\n".join(
1249
+ value
1250
+ for value in (classification_surface(env, stdout, stderr), stdout, stderr)
1251
+ if value
1252
+ )
1253
+ if QUOTA.search(surface) or has_auth_marker(surface):
1254
+ return False
1255
+ return True
1256
+
1257
+
1258
+ def stream_probe_passed(
1259
+ events: list[dict],
1260
+ env: object,
1261
+ stdout: str = "",
1262
+ stderr: str = "",
1263
+ expected_tools: set[str] | None = None,
1264
+ allow_expected_tool_use: bool = False,
1265
+ runtime_surface_only: bool = False,
1266
+ expected_native_skills: set[str] | None = None,
1267
+ required_native_skills: set[str] | None = None,
1268
+ host_init_baseline: dict[str, object] | None = None,
1269
+ ) -> bool:
1270
+ """Ground-truth pass: all init capability surfaces are present and empty,
1271
+ no tool was invoked, and the result envelope is clean. Reply text is ignored."""
1272
+ expected_tools = expected_tools or set()
1273
+ state = init_surface_state(
1274
+ events,
1275
+ expected_tools,
1276
+ expected_native_skills,
1277
+ required_native_skills,
1278
+ host_init_baseline,
1279
+ )
1280
+ if state is None:
1281
+ return False
1282
+ (
1283
+ missing_or_invalid,
1284
+ nonempty,
1285
+ declared_tools,
1286
+ unknown_fields,
1287
+ unsafe_values,
1288
+ unverifiable_authority,
1289
+ unclassifiable_vocabulary,
1290
+ ) = state
1291
+ invoked = invoked_tool_names(events)
1292
+ # Every state set refuses here, including the unclassifiable-vocabulary one.
1293
+ # That is the whole safety argument for reclassifying it: the softer class
1294
+ # changes which client serves the review, never whether an unverified
1295
+ # isolation surface is ACCEPTED. There is no path from a bare unrecognised
1296
+ # name to a passing probe.
1297
+ if (
1298
+ missing_or_invalid
1299
+ or nonempty
1300
+ or unknown_fields
1301
+ or unsafe_values
1302
+ or unverifiable_authority
1303
+ or unclassifiable_vocabulary
1304
+ or declared_tools != expected_tools
1305
+ or invoked - expected_tools
1306
+ or (invoked and not allow_expected_tool_use)
1307
+ ):
1308
+ return False
1309
+ if runtime_surface_only:
1310
+ if not envelope_structurally_clean(
1311
+ env, "", stderr, ignore_reply_text=True
1312
+ ):
1313
+ return False
1314
+ elif not envelope_structurally_clean(env, stdout, stderr):
1315
+ return False
1316
+ return True
1317
+
1318
+
1319
+ def clean_envelope_value(env: object, stdout: str = "", stderr: str = "") -> str | None:
1320
+ if not envelope_structurally_clean(env, stdout, stderr):
1321
+ return None
1322
+ if has_tool_available_marker("\n".join(all_string_values(env))):
1323
+ return None
1324
+ values = [normalize(value) for value in envelope_text_values(env)]
1325
+ if values and all(is_safe_ok_tail_value(value) for value in values):
1326
+ return "ok"
1327
+ return None
1328
+
1329
+
1330
+ def classify_failure(
1331
+ rc: int,
1332
+ stdout: str,
1333
+ stderr: str,
1334
+ expected_tools: set[str] | None = None,
1335
+ allow_expected_tool_use: bool = False,
1336
+ expected_native_skills: set[str] | None = None,
1337
+ required_native_skills: set[str] | None = None,
1338
+ host_init_baseline: dict[str, object] | None = None,
1339
+ ):
1340
+ expected_tools = expected_tools or set()
1341
+ check_label = "Claude runtime isolation check" if expected_tools else "Claude no-tool probe"
1342
+ combined = f"{stdout}\n{stderr}"
1343
+ env = parse_json_object(stdout)
1344
+ # run_claude_capture.py owns these reserved statuses. Ordinary Claude exit
1345
+ # codes such as 124/143 remain local process failures, not proof that the
1346
+ # outer capture timer fired or terminated the child.
1347
+ timeout_or_terminated = rc in {198, 199}
1348
+
1349
+ surface = "\n".join(value for value in (classification_surface(env, stdout, stderr), stdout, stderr) if value)
1350
+ text = result_text(env) if env is not None else surface
1351
+ api_status = api_status_int(env)
1352
+ raw_api_status = env.get("api_error_status") if isinstance(env, dict) else None
1353
+ # A tool-boundary denial is terminal even when model/CLI prose also quotes
1354
+ # auth, quota, or timeout words. Never make this candidate-fallback eligible.
1355
+ if isinstance(env, dict) and env.get("permission_denials"):
1356
+ if timeout_or_terminated:
1357
+ return (
1358
+ f"{check_label} timed out or was terminated; "
1359
+ "tool permission-denial evidence was also observed",
1360
+ False,
1361
+ )
1362
+ return f"{check_label} reported tool permission denials", False
1363
+ if timeout_or_terminated and api_status == 401:
1364
+ return ((
1365
+ f"{check_label} timed out or was terminated; "
1366
+ "auth-path evidence was also observed, so rerun the wrapper from "
1367
+ "a host/escalated shell once local Claude auth is logged in"
1368
+ ), False)
1369
+ if timeout_or_terminated and (
1370
+ api_status == 429
1371
+ or (isinstance(raw_api_status, str) and QUOTA.search(raw_api_status))
1372
+ or QUOTA.search(surface)
1373
+ ):
1374
+ snippet = sanitize_snippet(surface or combined)
1375
+ return (
1376
+ f"{check_label} timed out or was terminated; "
1377
+ f"quota/rate-limit evidence was also observed: {snippet or 'rate limit or quota exceeded'}",
1378
+ False,
1379
+ )
1380
+ if timeout_or_terminated and isinstance(env, dict) and (
1381
+ is_truthy_error(env.get("is_error")) or env.get("subtype") not in {None, "success"}
1382
+ ):
1383
+ snippet = sanitize_snippet(text)
1384
+ return (
1385
+ f"{check_label} timed out or was terminated; "
1386
+ f"error-envelope evidence was also observed: {snippet or env.get('subtype') or 'unknown error'}",
1387
+ False,
1388
+ )
1389
+ if api_status == 429 or (isinstance(raw_api_status, str) and QUOTA.search(raw_api_status)):
1390
+ snippet = sanitize_snippet(surface or combined)
1391
+ return (
1392
+ f"{check_label} hit quota/rate limit: {snippet or 'rate limit or quota exceeded'}",
1393
+ False,
1394
+ )
1395
+ if not timeout_or_terminated and (api_status == 401 or has_auth_marker(surface)):
1396
+ return ((
1397
+ f"safe {check_label} hit auth-path false negative; rerun the "
1398
+ "wrapper from a host/escalated shell once local Claude auth is logged in"
1399
+ ), False)
1400
+ if not timeout_or_terminated and QUOTA.search(surface):
1401
+ snippet = sanitize_snippet(surface or combined)
1402
+ return (
1403
+ f"{check_label} hit quota/rate limit: {snippet or 'rate limit or quota exceeded'}",
1404
+ False,
1405
+ )
1406
+ if not timeout_or_terminated and api_status == 403:
1407
+ snippet = sanitize_snippet(text or combined)
1408
+ return (
1409
+ f"{check_label} returned permission/API access status 403: {snippet or 'no error text'}",
1410
+ False,
1411
+ )
1412
+ if raw_api_status is not None and (api_status is None or api_status >= 400) and not (
1413
+ timeout_or_terminated and api_status != 429
1414
+ ):
1415
+ snippet = sanitize_snippet(text or combined)
1416
+ return (
1417
+ f"{check_label} returned API error status {raw_api_status}: {snippet or 'no error text'}",
1418
+ False,
1419
+ )
1420
+ if isinstance(env, dict) and (
1421
+ is_truthy_error(env.get("is_error")) or env.get("subtype") not in {None, "success"}
1422
+ ):
1423
+ snippet = sanitize_snippet(text)
1424
+ return (
1425
+ f"{check_label} returned error envelope: {snippet or env.get('subtype') or 'unknown error'}",
1426
+ False,
1427
+ )
1428
+ failure_events = stream_events(stdout)
1429
+ if bash_tool_present(failure_events):
1430
+ return (
1431
+ f"{check_label} detected the Bash tool is available "
1432
+ "(declared or invoked in the session); the no-tool sandbox is not enforced",
1433
+ False,
1434
+ )
1435
+ failure_stream, failure_corrupt = stream_classification(stdout, failure_events)
1436
+ if failure_stream:
1437
+ if failure_corrupt:
1438
+ return (
1439
+ f"{check_label} produced a malformed stream-json record; "
1440
+ "tool-availability ground-truth is unverifiable",
1441
+ False,
1442
+ )
1443
+ state = init_surface_state(
1444
+ failure_events,
1445
+ expected_tools,
1446
+ expected_native_skills,
1447
+ required_native_skills,
1448
+ host_init_baseline,
1449
+ )
1450
+ if state is None:
1451
+ return (
1452
+ f"{check_label} stream-json capture is missing the init event; "
1453
+ "tool-availability ground-truth is unverifiable",
1454
+ False,
1455
+ )
1456
+ (
1457
+ missing_or_invalid,
1458
+ nonempty,
1459
+ declared_tools,
1460
+ unknown_fields,
1461
+ unsafe_values,
1462
+ unverifiable_authority,
1463
+ unclassifiable_vocabulary,
1464
+ ) = state
1465
+ if missing_or_invalid:
1466
+ return (
1467
+ f"{check_label} init event is missing required isolation fields; "
1468
+ "runtime capability ground-truth is unverifiable",
1469
+ False,
1470
+ )
1471
+ if unsafe_values:
1472
+ # Terminal on purpose, and checked BEFORE the drift class: an unsafe
1473
+ # value on a known field is a breached boundary, not an unverifiable
1474
+ # schema. The "runtime capability" wording routes it to
1475
+ # tool_boundary_violation / stop_reviewer_lane in claude_review.sh.
1476
+ return (
1477
+ f"{check_label} init event declares an unsafe runtime capability "
1478
+ f"value on {', '.join(safe_identifier(f) for f in sorted(unsafe_values))}; "
1479
+ "the reviewer sandbox boundary is not enforced",
1480
+ False,
1481
+ )
1482
+ invoked = invoked_tool_names(failure_events)
1483
+ surface_breached = bool(
1484
+ nonempty
1485
+ or declared_tools != expected_tools
1486
+ or invoked - expected_tools
1487
+ or (invoked and not allow_expected_tool_use)
1488
+ )
1489
+ if unverifiable_authority and not surface_breached:
1490
+ # Fallback-eligible, NOT terminal: a vanished or renamed authority
1491
+ # knob means we can no longer prove the reviewer was unelevated —
1492
+ # not that it was. Terminalizing it would turn the next CLI rename
1493
+ # into the same total outage this landing removes.
1494
+ return (
1495
+ "Claude reviewer lane found an unrecognized surface-shaped init "
1496
+ "field (authority: "
1497
+ + ", ".join(safe_identifier(f) for f in sorted(unverifiable_authority))
1498
+ + "); the reviewer's authority is no longer verifiable from the "
1499
+ "stream-json schema",
1500
+ False,
1501
+ )
1502
+ if unknown_fields and not surface_breached:
1503
+ # Drift is reported ONLY when nothing else is wrong — same guard as
1504
+ # `runtime_drift_only` on the main-invocation path. A run that both
1505
+ # drifts and breaches must report the breach: this branch's phrase
1506
+ # routes to the fallback-eligible class, so reaching it first would
1507
+ # launder a real breach into "try another reviewer client".
1508
+ #
1509
+ # Wording is load-bearing: claude_review.sh routes this exact phrase
1510
+ # to a fallback-eligible schema-drift class, not to the terminal
1511
+ # tool-boundary class — a surface-shaped schema addition means THIS
1512
+ # lane cannot verify isolation, not that review must stop. Naming
1513
+ # the fields keeps the one-line follow-up obvious.
1514
+ #
1515
+ # `check_label` is deliberately NOT interpolated here: in consult
1516
+ # mode it reads "Claude runtime isolation check", and the routing
1517
+ # table's tool-boundary arm matches on "runtime isolation". Emitting
1518
+ # it would make correct routing depend on `case`-arm order alone.
1519
+ return (
1520
+ "Claude reviewer lane found an unrecognized surface-shaped init "
1521
+ f"field ({', '.join(safe_identifier(f) for f in sorted(unknown_fields))}); "
1522
+ "the stream-json schema must be reviewed before this lane can "
1523
+ "verify isolation",
1524
+ False,
1525
+ )
1526
+ if unclassifiable_vocabulary and not surface_breached:
1527
+ # Same guard, same reason as the two branches above: reached only
1528
+ # when nothing is actually breached, so a hostile CLI cannot use a
1529
+ # bare name to launder a real breach into "try another client".
1530
+ #
1531
+ # A distinct phrase, not a reuse of the surface-shaped one: what is
1532
+ # unrecognised here is an IDENTIFIER, not a field, and describing it
1533
+ # as the wrong thing is a diagnostic this repo has already paid for.
1534
+ # `claude_review.sh` carries a matching arm ahead of its terminal
1535
+ # arm; relying on its late `*"init"*` catch-all would make routing
1536
+ # depend on `case`-arm order alone.
1537
+ return (
1538
+ "Claude reviewer lane found an unclassifiable host-vocabulary "
1539
+ "entry ("
1540
+ + ", ".join(
1541
+ safe_identifier(v) for v in sorted(unclassifiable_vocabulary)
1542
+ )
1543
+ + "); the built-in allowlist cannot prove whether the host or a "
1544
+ "user owns that name, so this lane cannot verify isolation",
1545
+ False,
1546
+ )
1547
+ if (
1548
+ surface_breached
1549
+ or unknown_fields
1550
+ or unverifiable_authority
1551
+ or unclassifiable_vocabulary
1552
+ ):
1553
+ if expected_tools:
1554
+ surface_reason = (
1555
+ f"{check_label} runtime capability surface does not match the expected boundary; "
1556
+ "a tool, MCP server, skill, command, or plugin is unexpected or unsafe"
1557
+ )
1558
+ else:
1559
+ surface_reason = (
1560
+ "Claude no-tool probe runtime capability surface is not empty; "
1561
+ "a tool, MCP server, skill, command, or plugin remains declared or invoked"
1562
+ )
1563
+ return (
1564
+ surface_reason,
1565
+ False,
1566
+ )
1567
+ snippet = sanitize_snippet(combined)
1568
+ return f"{check_label} failed: {snippet or 'unexpected probe output'}", True
1569
+
1570
+
1571
+ def main() -> int:
1572
+ if len(sys.argv) < 4:
1573
+ print(
1574
+ "usage: parse_probe_result.py RC STDOUT_FILE STDERR_FILE "
1575
+ "[--require-empty-init] [--expected-tools CSV] "
1576
+ "[--expected-native-skills CSV] "
1577
+ "[--required-native-skills CSV] "
1578
+ "[--host-init-baseline FILE] [--validate-host-init-baseline] "
1579
+ "[--allow-expected-tool-use] [--runtime-surface-only]",
1580
+ file=sys.stderr,
1581
+ )
1582
+ return 64
1583
+ require_empty_init = False
1584
+ expected_tools: set[str] = set()
1585
+ expected_native_skills: set[str] = set()
1586
+ required_native_skills: set[str] = set()
1587
+ allow_expected_tool_use = False
1588
+ runtime_surface_only = False
1589
+ host_init_baseline_path = ""
1590
+ validate_host_init_baseline = False
1591
+ option_index = 4
1592
+ while option_index < len(sys.argv):
1593
+ option = sys.argv[option_index]
1594
+ if option == "--require-empty-init":
1595
+ require_empty_init = True
1596
+ option_index += 1
1597
+ elif option == "--expected-tools" and option_index + 1 < len(sys.argv):
1598
+ expected_tools = {
1599
+ name.strip().lower()
1600
+ for name in sys.argv[option_index + 1].split(",")
1601
+ if name.strip()
1602
+ }
1603
+ option_index += 2
1604
+ elif option == "--expected-native-skills" and option_index + 1 < len(sys.argv):
1605
+ expected_native_skills = {
1606
+ name.strip().lower()
1607
+ for name in sys.argv[option_index + 1].split(",")
1608
+ if name.strip()
1609
+ }
1610
+ option_index += 2
1611
+ elif option == "--required-native-skills" and option_index + 1 < len(sys.argv):
1612
+ required_native_skills = {
1613
+ name.strip().lower()
1614
+ for name in sys.argv[option_index + 1].split(",")
1615
+ if name.strip()
1616
+ }
1617
+ option_index += 2
1618
+ elif option == "--allow-expected-tool-use":
1619
+ allow_expected_tool_use = True
1620
+ option_index += 1
1621
+ elif option == "--runtime-surface-only":
1622
+ runtime_surface_only = True
1623
+ option_index += 1
1624
+ elif option == "--host-init-baseline" and option_index + 1 < len(sys.argv):
1625
+ host_init_baseline_path = sys.argv[option_index + 1]
1626
+ option_index += 2
1627
+ elif option == "--validate-host-init-baseline":
1628
+ validate_host_init_baseline = True
1629
+ option_index += 1
1630
+ else:
1631
+ print("unknown or incomplete probe parser option", file=sys.stderr)
1632
+ return 64
1633
+
1634
+ # Tool-boundary verdicts are meaningful only with stream-json init
1635
+ # evidence. Make the stronger requirement intrinsic so a direct caller
1636
+ # cannot accidentally re-enable the legacy text fallback.
1637
+ if (
1638
+ runtime_surface_only
1639
+ or expected_tools
1640
+ or allow_expected_tool_use
1641
+ or expected_native_skills
1642
+ or required_native_skills
1643
+ ):
1644
+ require_empty_init = True
1645
+
1646
+ try:
1647
+ rc = int(sys.argv[1])
1648
+ except ValueError:
1649
+ print("probe rc must be an integer", file=sys.stderr)
1650
+ return 64
1651
+
1652
+ stdout = Path(sys.argv[2]).read_text(encoding="utf-8", errors="replace")
1653
+ stderr = Path(sys.argv[3]).read_text(encoding="utf-8", errors="replace")
1654
+ host_init_baseline = None
1655
+ if validate_host_init_baseline:
1656
+ host_init_baseline, baseline_error = load_host_init_baseline(sys.argv[2])
1657
+ if baseline_error is not None:
1658
+ print(json.dumps({"reason": baseline_error, "generic_failure": False}))
1659
+ return 1
1660
+ return 0
1661
+ if host_init_baseline_path:
1662
+ host_init_baseline, baseline_error = load_host_init_baseline(
1663
+ host_init_baseline_path
1664
+ )
1665
+ if baseline_error is not None:
1666
+ print(json.dumps({"reason": baseline_error, "generic_failure": False}))
1667
+ return 1
1668
+ normalized_stdout = normalize(stdout)
1669
+ stderr_surface = classification_surface(None, "", stderr)
1670
+ env = parse_json_object(normalized_stdout)
1671
+ events = stream_events(normalized_stdout)
1672
+ invoked_tools = invoked_tool_names(events)
1673
+ stream_like, stream_corrupt = stream_classification(normalized_stdout, events)
1674
+ stdout_clean = not QUOTA.search(normalized_stdout) and not has_auth_marker(normalized_stdout)
1675
+ stderr_clean = not QUOTA.search(stderr_surface) and not has_auth_marker(stderr_surface)
1676
+ runtime_stdout_surface = ""
1677
+ if runtime_surface_only and rc == 0:
1678
+ # Only a structurally intact JSONL stream can distinguish host/CLI
1679
+ # banners from model reply content. Pretty-printed envelopes and corrupt
1680
+ # streams are unverifiable; never classify their stdout prose as auth or
1681
+ # quota evidence.
1682
+ if stream_like and not stream_corrupt:
1683
+ runtime_stdout_surface = stream_nonjson_surface(normalized_stdout)
1684
+ stdout_clean = not QUOTA.search(runtime_stdout_surface) and not has_auth_marker(
1685
+ runtime_stdout_surface
1686
+ )
1687
+ if (
1688
+ not require_empty_init
1689
+ and rc == 0
1690
+ and stdout_clean
1691
+ and stderr_clean
1692
+ and is_ok_token(normalized_stdout)
1693
+ ):
1694
+ return 0
1695
+
1696
+ if rc == 0 and stdout_clean and stderr_clean:
1697
+ unexpected_tool_use = invoked_tools - expected_tools or (
1698
+ invoked_tools and not allow_expected_tool_use
1699
+ )
1700
+ if unexpected_tool_use:
1701
+ # Any unexpected tool_use is a hard fail regardless of init/text;
1702
+ # fall through to classify_failure (reports sandbox not enforced).
1703
+ pass
1704
+ elif stream_like:
1705
+ # stream-json mode REQUIRES trustworthy ground-truth: a parseable init
1706
+ # event, no corruption, Bash neither declared nor invoked. Missing init
1707
+ # or a dropped record could hide a real Bash session, so anything less
1708
+ # fails closed instead of passing on the reply token.
1709
+ if not stream_corrupt and stream_probe_passed(
1710
+ events,
1711
+ env,
1712
+ stdout,
1713
+ stderr,
1714
+ expected_tools,
1715
+ allow_expected_tool_use,
1716
+ runtime_surface_only,
1717
+ expected_native_skills,
1718
+ required_native_skills,
1719
+ host_init_baseline,
1720
+ ):
1721
+ return 0
1722
+ elif not require_empty_init:
1723
+ # non-stream output (no standalone JSONL records, e.g. plain single
1724
+ # envelope or raw text): legacy text fallback.
1725
+ value = clean_envelope_value(env, stdout, stderr)
1726
+ if value is not None and is_ok_token(value):
1727
+ return 0
1728
+
1729
+ if require_empty_init and rc == 0 and stdout_clean and stderr_clean and not stream_like:
1730
+ print(
1731
+ json.dumps(
1732
+ {
1733
+ "reason": (
1734
+ "Claude no-tool probe is missing the required stream-json init evidence; "
1735
+ "runtime isolation cannot be verified"
1736
+ ),
1737
+ "generic_failure": False,
1738
+ }
1739
+ )
1740
+ )
1741
+ return 1
1742
+
1743
+ if runtime_surface_only and rc == 0:
1744
+ runtime_diagnostic_surface = "\n".join(
1745
+ value for value in (runtime_stdout_surface, stderr_surface) if value
1746
+ )
1747
+ runtime_api_status = api_status_int(env)
1748
+ runtime_raw_api_status = env.get("api_error_status") if isinstance(env, dict) else None
1749
+ if isinstance(env, dict) and env.get("permission_denials"):
1750
+ runtime_reason = "Claude main invocation reported tool permission denials"
1751
+ elif runtime_api_status == 401 or has_auth_marker(runtime_diagnostic_surface):
1752
+ runtime_reason = (
1753
+ "safe Claude main invocation hit auth-path false negative; rerun the "
1754
+ "wrapper from a host/escalated shell once local Claude auth is logged in"
1755
+ )
1756
+ elif (
1757
+ runtime_api_status == 429
1758
+ or (
1759
+ isinstance(runtime_raw_api_status, str)
1760
+ and QUOTA.search(runtime_raw_api_status)
1761
+ )
1762
+ or QUOTA.search(runtime_diagnostic_surface)
1763
+ ):
1764
+ snippet = sanitize_snippet(runtime_diagnostic_surface)
1765
+ runtime_reason = (
1766
+ "Claude main invocation hit quota/rate limit: "
1767
+ f"{snippet or 'rate limit or quota exceeded'}"
1768
+ )
1769
+ else:
1770
+ runtime_state = init_surface_state(
1771
+ events,
1772
+ expected_tools,
1773
+ expected_native_skills,
1774
+ required_native_skills,
1775
+ host_init_baseline,
1776
+ )
1777
+ runtime_detail = ""
1778
+ runtime_drift_only = False
1779
+ if runtime_state is not None:
1780
+ (
1781
+ missing,
1782
+ nonempty,
1783
+ declared,
1784
+ unknown,
1785
+ unsafe,
1786
+ unverifiable,
1787
+ vocabulary,
1788
+ ) = runtime_state
1789
+ # Schema drift routes the same way on the main-invocation path as
1790
+ # on the probe path. Without this, an unrecognized init container
1791
+ # would terminate the lane here while merely falling back there —
1792
+ # the same condition, two verdicts, decided by which parse ran.
1793
+ #
1794
+ # `unexpected_identifiers` is deliberately absent from the guard,
1795
+ # but NOT because it is redundant with `nonempty` — that was true
1796
+ # only while every unrecognised entry was a breach. An entry it
1797
+ # reports now lands in either `nonempty` (proven customization)
1798
+ # or `vocabulary` (unclassifiable host name), both of which ARE
1799
+ # in the guard; it stays out because it would double-count them
1800
+ # while distinguishing neither. Fixtures pin the combined
1801
+ # drift+breach and vocabulary+breach cases so this stays true
1802
+ # rather than being taken on faith.
1803
+ runtime_drift_only = bool(unknown or unverifiable or vocabulary) and not (
1804
+ missing
1805
+ or nonempty
1806
+ or unsafe
1807
+ or declared != expected_tools
1808
+ or invoked_tools - expected_tools
1809
+ or (invoked_tools and not allow_expected_tool_use)
1810
+ )
1811
+ unexpected_identifiers = unexpected_customization_identifiers(
1812
+ events, expected_native_skills, host_init_baseline
1813
+ )
1814
+ # EVERY interpolated identifier is CLI-supplied, not just the
1815
+ # field names: tool names, skill/plugin/command identifiers and
1816
+ # invoked-tool names come from the inspected stream too, and may
1817
+ # contain spaces just as freely. Any one of them left raw lets
1818
+ # the inspected CLI pick which routing arm matches — a breach
1819
+ # laundered into "try another client".
1820
+ def joined(values):
1821
+ return ",".join(safe_identifier(v) for v in sorted(values))
1822
+
1823
+ runtime_detail = (
1824
+ "; missing_or_invalid="
1825
+ + joined(missing)
1826
+ + "; unexpected_customizations="
1827
+ + joined(nonempty)
1828
+ + "; unexpected_customization_identifiers="
1829
+ + joined(unexpected_identifiers)
1830
+ + "; declared_tools="
1831
+ + joined(declared)
1832
+ + "; invoked_tools="
1833
+ + joined(invoked_tools)
1834
+ + "; unknown_fields="
1835
+ + joined(unknown)
1836
+ + "; unsafe_values="
1837
+ + joined(unsafe)
1838
+ + "; unverifiable_authority="
1839
+ + joined(unverifiable)
1840
+ + "; unclassifiable_host_vocabulary="
1841
+ + joined(vocabulary)
1842
+ )
1843
+ if runtime_drift_only and not (unknown or unverifiable):
1844
+ # The new class gets its own phrase only when it is the SOLE
1845
+ # unverifiable finding. Combined with schema drift or an
1846
+ # unverifiable authority knob, the existing phrase still applies
1847
+ # and still routes to the same fallback-eligible arm, so the
1848
+ # wording of every pre-existing case is left exactly as it was.
1849
+ runtime_reason = (
1850
+ "Claude main invocation found an unclassifiable "
1851
+ "host-vocabulary entry; the built-in allowlist cannot prove "
1852
+ "whether the host or a user owns that name, so this reviewer "
1853
+ "lane cannot verify isolation" + runtime_detail
1854
+ )
1855
+ elif runtime_drift_only:
1856
+ runtime_reason = (
1857
+ "Claude main invocation found an unrecognized surface-shaped "
1858
+ "init field; the stream-json schema must be reviewed before "
1859
+ "this reviewer lane can verify isolation" + runtime_detail
1860
+ )
1861
+ else:
1862
+ runtime_reason = (
1863
+ "Claude main invocation runtime isolation surface is invalid or unverifiable"
1864
+ + runtime_detail
1865
+ )
1866
+ print(
1867
+ json.dumps(
1868
+ {
1869
+ "reason": runtime_reason,
1870
+ "generic_failure": False,
1871
+ }
1872
+ )
1873
+ )
1874
+ return 1
1875
+
1876
+ reason, generic_failure = classify_failure(
1877
+ rc,
1878
+ stdout,
1879
+ stderr,
1880
+ expected_tools,
1881
+ allow_expected_tool_use,
1882
+ expected_native_skills,
1883
+ required_native_skills,
1884
+ host_init_baseline,
1885
+ )
1886
+ print(
1887
+ json.dumps(
1888
+ {
1889
+ "reason": reason,
1890
+ "generic_failure": generic_failure,
1891
+ },
1892
+ ensure_ascii=False,
1893
+ )
1894
+ )
1895
+ return 1
1896
+
1897
+
1898
+ if __name__ == "__main__":
1899
+ raise SystemExit(main())