controlzero 1.13.1__tar.gz → 1.13.2__tar.gz

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 (291) hide show
  1. {controlzero-1.13.1 → controlzero-1.13.2}/CHANGELOG.md +25 -0
  2. {controlzero-1.13.1 → controlzero-1.13.2}/PKG-INFO +1 -1
  3. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/__init__.py +1 -1
  4. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/main.py +76 -10
  5. {controlzero-1.13.1 → controlzero-1.13.2}/pyproject.toml +1 -1
  6. controlzero-1.13.2/tests/test_kiro_cli_v210_hooks.py +110 -0
  7. {controlzero-1.13.1 → controlzero-1.13.2}/.gitignore +0 -0
  8. {controlzero-1.13.1 → controlzero-1.13.2}/Dockerfile.test +0 -0
  9. {controlzero-1.13.1 → controlzero-1.13.2}/LICENSE +0 -0
  10. {controlzero-1.13.1 → controlzero-1.13.2}/README.md +0 -0
  11. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/__main__.py +0 -0
  12. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/__init__.py +0 -0
  13. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/_messages.py +0 -0
  14. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/action_aliases.py +0 -0
  15. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/action_validator.py +0 -0
  16. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/bundle.py +0 -0
  17. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/condition_ops.py +0 -0
  18. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/credential_hook.py +0 -0
  19. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/credential_scanner.py +0 -0
  20. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/credentials_data/__init__.py +0 -0
  21. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/credentials_data/built_in.yaml +0 -0
  22. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/dlp_scanner.py +0 -0
  23. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/enforcer.py +0 -0
  24. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/hook_extractors.py +0 -0
  25. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/io_capture_producer.py +0 -0
  26. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/source_labels.py +0 -0
  27. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/tool_extractors.json +0 -0
  28. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/_internal/types.py +0 -0
  29. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/audit_local.py +0 -0
  30. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/audit_remote.py +0 -0
  31. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/canonical.py +0 -0
  32. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/__init__.py +0 -0
  33. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/__main__.py +0 -0
  34. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/_secrets.py +0 -0
  35. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/agent_config.py +0 -0
  36. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/console.py +0 -0
  37. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/debug_bundle.py +0 -0
  38. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/doctor.py +0 -0
  39. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/exec_cmd.py +0 -0
  40. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hook_entry.py +0 -0
  41. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/__init__.py +0 -0
  42. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/antigravity.py +0 -0
  43. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/base.py +0 -0
  44. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/claude_code.py +0 -0
  45. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/codex_cli.py +0 -0
  46. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/cursor.py +0 -0
  47. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/cursor_cli.py +0 -0
  48. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/gemini_cli.py +0 -0
  49. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/kiro.py +0 -0
  50. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/hosts/unknown.py +0 -0
  51. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/kiro_adapter.py +0 -0
  52. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/migrate.py +0 -0
  53. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/output.py +0 -0
  54. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/spool_cmd.py +0 -0
  55. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/telemetry_consent.py +0 -0
  56. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/antigravity/hooks.json +0 -0
  57. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/antigravity.yaml +0 -0
  58. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/autogen.yaml +0 -0
  59. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/claude-code.yaml +0 -0
  60. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/codex-cli.yaml +0 -0
  61. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/cost-cap.yaml +0 -0
  62. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/crewai.yaml +0 -0
  63. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/cursor.yaml +0 -0
  64. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/gemini-cli.yaml +0 -0
  65. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/generic.yaml +0 -0
  66. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/kiro/ide-file-save.kiro.hook +0 -0
  67. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/kiro/ide-pre-tool-use.kiro.hook +0 -0
  68. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/kiro/ide-prompt-submit.kiro.hook +0 -0
  69. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/kiro/kiro.yaml +0 -0
  70. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/langchain.yaml +0 -0
  71. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/mcp.yaml +0 -0
  72. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/templates/rag.yaml +0 -0
  73. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/cli/update_cmd.py +0 -0
  74. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/client.py +0 -0
  75. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/device.py +0 -0
  76. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/enrollment.py +0 -0
  77. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/error_codes.py +0 -0
  78. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/error_codes.yaml +0 -0
  79. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/errors.py +0 -0
  80. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hitl/__init__.py +0 -0
  81. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hitl/grant_protocol.py +0 -0
  82. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hitl/mock.py +0 -0
  83. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hitl/pending_approval.py +0 -0
  84. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hitl/secret_leak_guard.py +0 -0
  85. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hitl/status.py +0 -0
  86. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hook_integrity.py +0 -0
  87. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hooks/__init__.py +0 -0
  88. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hooks/tool_output_handler.py +0 -0
  89. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/hosted_policy.py +0 -0
  90. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/__init__.py +0 -0
  91. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/anthropic.py +0 -0
  92. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/autogen.py +0 -0
  93. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/braintrust.py +0 -0
  94. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/crewai/__init__.py +0 -0
  95. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/crewai/agent.py +0 -0
  96. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/crewai/crew.py +0 -0
  97. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/crewai/task.py +0 -0
  98. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/crewai/tool.py +0 -0
  99. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/google.py +0 -0
  100. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/google_adk/__init__.py +0 -0
  101. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/google_adk/agent.py +0 -0
  102. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/google_adk/tool.py +0 -0
  103. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/langchain/__init__.py +0 -0
  104. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/langchain/agent.py +0 -0
  105. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/langchain/callbacks.py +0 -0
  106. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/langchain/chain.py +0 -0
  107. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/langchain/graph.py +0 -0
  108. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/langchain/modern.py +0 -0
  109. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/langchain/tool.py +0 -0
  110. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/langfuse.py +0 -0
  111. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/litellm.py +0 -0
  112. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/openai.py +0 -0
  113. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/pydantic_ai.py +0 -0
  114. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/integrations/vercel_ai.py +0 -0
  115. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/layout_migration.py +0 -0
  116. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/policy_loader.py +0 -0
  117. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/secrets/__init__.py +0 -0
  118. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/secrets/reference.py +0 -0
  119. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/secrets/resolver.py +0 -0
  120. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/secrets/secretstr.py +0 -0
  121. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/__init__.py +0 -0
  122. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_compress.py +0 -0
  123. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_constants.py +0 -0
  124. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_crc32c.py +0 -0
  125. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_crypto.py +0 -0
  126. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_frame.py +0 -0
  127. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_keyring.py +0 -0
  128. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_metrics.py +0 -0
  129. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_spool.py +0 -0
  130. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_state.py +0 -0
  131. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/_uploader.py +0 -0
  132. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/spool/cz-audit-v1.dict +0 -0
  133. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/tamper.py +0 -0
  134. {controlzero-1.13.1 → controlzero-1.13.2}/controlzero/tracecontext.py +0 -0
  135. {controlzero-1.13.1 → controlzero-1.13.2}/examples/hello_world.py +0 -0
  136. {controlzero-1.13.1 → controlzero-1.13.2}/tests/_fixtures/antigravity-envelope-expected.json +0 -0
  137. {controlzero-1.13.1 → controlzero-1.13.2}/tests/_fixtures/jcs_args_hash_vectors.json +0 -0
  138. {controlzero-1.13.1 → controlzero-1.13.2}/tests/conftest.py +0 -0
  139. {controlzero-1.13.1 → controlzero-1.13.2}/tests/integrations/__init__.py +0 -0
  140. {controlzero-1.13.1 → controlzero-1.13.2}/tests/integrations/test_google.py +0 -0
  141. {controlzero-1.13.1 → controlzero-1.13.2}/tests/parity/action_aliases.json +0 -0
  142. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/__init__.py +0 -0
  143. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/conftest.py +0 -0
  144. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_cli.py +0 -0
  145. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_concurrency.py +0 -0
  146. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_conformance.py +0 -0
  147. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_core.py +0 -0
  148. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_crash.py +0 -0
  149. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_diskfull.py +0 -0
  150. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_durable_default_tamper.py +0 -0
  151. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_keychain_dek.py +0 -0
  152. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_sink_wiring.py +0 -0
  153. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_transcript_localack.py +0 -0
  154. {controlzero-1.13.1 → controlzero-1.13.2}/tests/spool/test_spool_uploader.py +0 -0
  155. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_action_aliases.py +0 -0
  156. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_action_canonicalization.py +0 -0
  157. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_action_validator_t86.py +0 -0
  158. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_adapter_interface.py +0 -0
  159. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_agent_name_env.py +0 -0
  160. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_agy_docs_no_exit2_1373.py +0 -0
  161. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_antigravity_adapter.py +0 -0
  162. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_antigravity_envelope_parity.py +0 -0
  163. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_antigravity_ga_blockers_1248.py +0 -0
  164. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_antigravity_hook_check.py +0 -0
  165. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_antigravity_install.py +0 -0
  166. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_antigravity_posttooluse_observe_58.py +0 -0
  167. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_antigravity_tool_vocab_1303.py +0 -0
  168. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_api_key_mask.py +0 -0
  169. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_audit_project_id_attribution_pr2.py +0 -0
  170. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_audit_remote.py +0 -0
  171. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_audit_remote_io_capture.py +0 -0
  172. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_audit_remote_sdk_version.py +0 -0
  173. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_audit_sink_isolation.py +0 -0
  174. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_bundle_cache_freshness_1303.py +0 -0
  175. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_bundle_parser.py +0 -0
  176. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_bundle_translate.py +0 -0
  177. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_canonical_phase1a.py +0 -0
  178. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_capability_matrix_doc.py +0 -0
  179. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_carve_out.py +0 -0
  180. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_debug_bundle.py +0 -0
  181. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_extractor_integration.py +0 -0
  182. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_hook.py +0 -0
  183. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_hook_entry.py +0 -0
  184. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_hosted_refresh.py +0 -0
  185. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_init.py +0 -0
  186. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_init_templates.py +0 -0
  187. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_tail.py +0 -0
  188. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_test.py +0 -0
  189. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cli_validate.py +0 -0
  190. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_coding_agent_hooks.py +0 -0
  191. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_condition_operators_1495.py +0 -0
  192. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_conditions.py +0 -0
  193. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_config_format_parity_1303.py +0 -0
  194. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_conformance.py +0 -0
  195. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_console.py +0 -0
  196. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_credential_hook.py +0 -0
  197. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_cursor_adapter.py +0 -0
  198. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_default_action.py +0 -0
  199. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_deny_rule_reconciliation_1011.py +0 -0
  200. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_device.py +0 -0
  201. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_dlp_mask.py +0 -0
  202. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_dlp_scanner.py +0 -0
  203. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_doctor.py +0 -0
  204. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_engine_version_consistency.py +0 -0
  205. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_enrollment.py +0 -0
  206. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_env_dump_438.py +0 -0
  207. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_epic_1247_bryan_acceptance.py +0 -0
  208. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_error_codes.py +0 -0
  209. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_errors_e_codes.py +0 -0
  210. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_fail_closed_eval.py +0 -0
  211. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_failopen_1303.py +0 -0
  212. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_glob_matching.py +0 -0
  213. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_5d_email_install.py +0 -0
  214. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_6a_cli_flag.py +0 -0
  215. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_6a_exceptions.py +0 -0
  216. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_6a_get_secret_hitl.py +0 -0
  217. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_6a_mock_backend.py +0 -0
  218. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_6a_pending_approval.py +0 -0
  219. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_6a_request_approval.py +0 -0
  220. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_6a_secret_leak_guard.py +0 -0
  221. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_6a_wait.py +0 -0
  222. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_conformance.py +0 -0
  223. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_phase2b_protocol.py +0 -0
  224. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_reason_codes.py +0 -0
  225. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hitl_validator_keys.py +0 -0
  226. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hook_extractors.py +0 -0
  227. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hook_integrity.py +0 -0
  228. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hook_mask_failclosed.py +0 -0
  229. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hosted_local_audit_1247.py +0 -0
  230. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hosted_local_shadow_warn_1265.py +0 -0
  231. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hosted_policy_e2e.py +0 -0
  232. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hosts_adapter.py +0 -0
  233. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hybrid_mode_strict.py +0 -0
  234. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_hybrid_mode_warn.py +0 -0
  235. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_install_hook_command.py +0 -0
  236. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_install_hooks.py +0 -0
  237. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_io_capture_producer.py +0 -0
  238. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_kiro_adapter.py +0 -0
  239. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_kiro_cli_e2e.py +0 -0
  240. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_kiro_cli_hook_pin_1265.py +0 -0
  241. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_kiro_hook_templates.py +0 -0
  242. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_kiro_install.py +0 -0
  243. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_layout_migration_t101.py +0 -0
  244. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_layout_parity_t102.py +0 -0
  245. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_local_mode_dict.py +0 -0
  246. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_local_mode_file_json.py +0 -0
  247. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_local_mode_file_yaml.py +0 -0
  248. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_localized_reason.py +0 -0
  249. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_log_fallback_stderr.py +0 -0
  250. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_log_options_ignored_hosted.py +0 -0
  251. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_log_rotation.py +0 -0
  252. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_migrate.py +0 -0
  253. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_min_sdk_version_gate.py +0 -0
  254. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_multi_client_per_project_175.py +0 -0
  255. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_no_policy_no_key.py +0 -0
  256. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_observe_mode_1247.py +0 -0
  257. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_package_rename_shim.py +0 -0
  258. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_part3_active_policy_count_1303.py +0 -0
  259. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_per_client_isolation_1011.py +0 -0
  260. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_policy_engine_version_phase1b.py +0 -0
  261. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_policy_freshness.py +0 -0
  262. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_policy_load_failclosed_f3.py +0 -0
  263. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_policy_settings.py +0 -0
  264. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_policy_source_audit.py +0 -0
  265. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_pr4_install_messaging.py +0 -0
  266. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_pr4_output.py +0 -0
  267. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_pr4_status.py +0 -0
  268. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_probe_audit_isolation.py +0 -0
  269. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_quarantine.py +0 -0
  270. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_reason_code.py +0 -0
  271. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_refresh.py +0 -0
  272. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_secrets.py +0 -0
  273. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_secrets_reference_resolver.py +0 -0
  274. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_shell_semantic_class.py +0 -0
  275. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_source_labels.py +0 -0
  276. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_sql_semantic_class.py +0 -0
  277. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_synthetic_policy_id_t79.py +0 -0
  278. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_t103_precedence.py +0 -0
  279. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_t104_cache_gc.py +0 -0
  280. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_t108_local_override_audit.py +0 -0
  281. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_t96_single_audit_log.py +0 -0
  282. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_t99_install_prefetch_bundle.py +0 -0
  283. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_tamper.py +0 -0
  284. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_tamper_behavior.py +0 -0
  285. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_tamper_hook.py +0 -0
  286. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_telemetry_consent.py +0 -0
  287. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_tracecontext.py +0 -0
  288. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_unsafe_int_boundary.py +0 -0
  289. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_update_cmd.py +0 -0
  290. {controlzero-1.13.1 → controlzero-1.13.2}/tests/test_upgrade_nudge.py +0 -0
  291. {controlzero-1.13.1 → controlzero-1.13.2}/tools/cz-kiro-adapter +0 -0
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.13.2 (2026-06-28): kiro-cli 2.10 install crash + cross-adapter hook hardening
4
+
5
+ ### Fixed
6
+
7
+ - **kiro-cli Windows / non-UTF-8 install crash (Ken Lee report).** `controlzero
8
+ kiro init` captured kiro-cli's output in text mode using the OS locale codec, so
9
+ kiro-cli's UTF-8 output crashed the install's subprocess reader thread on
10
+ non-UTF-8 Windows locales (Korean CP949, Japanese SJIS, Chinese GBK). That crash
11
+ could leave the governance agent not set as default, so `kiro-cli chat` then ran
12
+ the built-in default agent ungoverned (no hooks, no audit). All kiro-cli
13
+ shell-outs now decode as UTF-8 (`errors="replace"`) and never crash the install.
14
+ - **Codex hook-trust requirement surfaced at install.** Codex trust-gates the
15
+ non-managed `~/.codex/hooks.json` by hash and SKIPS it until trusted; the
16
+ installer now prints a loud ACTION-REQUIRED step (run `/hooks`, trust the Control
17
+ Zero hook, re-trust after every upgrade) instead of implying it enforces.
18
+ - **Gemini defensive hooks gate.** The installer writes `hooksConfig.enabled=true`
19
+ so an admin/older build with hooks gated off does not silently run ungoverned.
20
+
21
+ ### Notes
22
+
23
+ - kiro-cli 2.10 was verified live to FIRE embedded agent-config `preToolUse` hooks;
24
+ the canonical tool-name matchers (`execute_bash`/`fs_write`/`fs_read`/`use_aws`)
25
+ and the `"*"` all-tools token are correct on 2.10 (both new `shell` and legacy
26
+ `execute_bash` names match).
27
+
3
28
  ## 1.13.1 (2026-06-27): shell semantic-class enforcement
4
29
 
5
30
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: controlzero
3
- Version: 1.13.1
3
+ Version: 1.13.2
4
4
  Summary: AI agent governance: policies, audit, and observability for tool calls. Works locally with no signup.
5
5
  Project-URL: Homepage, https://controlzero.ai
6
6
  Project-URL: Documentation, https://docs.controlzero.ai
@@ -41,7 +41,7 @@ from controlzero.hitl.grant_protocol import (
41
41
  from controlzero.policy_loader import load_policy
42
42
  from controlzero.secrets import SecretRef, SecretStr, secret_ref
43
43
 
44
- __version__ = "1.13.1"
44
+ __version__ = "1.13.2"
45
45
 
46
46
  __all__ = [
47
47
  "Client",
@@ -3737,12 +3737,30 @@ def install_gemini_cli(force: bool, merge: bool, settings: Optional[str], api_ke
3737
3737
  ]
3738
3738
  before_tool.append(new_block)
3739
3739
 
3740
+ # Defensive gate (cross-adapter drift audit, 2026-06-28): the Gemini CLI
3741
+ # hooks subsystem is gated by hooksConfig.enabled. It defaults to true on
3742
+ # current builds, but an admin policy or an older/disabled build can leave
3743
+ # it off -- in which case our BeforeTool hook is silently never invoked
3744
+ # (enforcement off, verify still green). Write the gate explicitly and make
3745
+ # sure our hook is not in hooksConfig.disabled. Writing an unknown key is a
3746
+ # harmless no-op on builds that do not read it, so this only ever helps.
3747
+ hooks_config = existing.get("hooksConfig")
3748
+ if not isinstance(hooks_config, dict):
3749
+ hooks_config = {}
3750
+ existing["hooksConfig"] = hooks_config
3751
+ hooks_config["enabled"] = True
3752
+ disabled = hooks_config.get("disabled")
3753
+ if isinstance(disabled, list):
3754
+ hooks_config["disabled"] = [
3755
+ d for d in disabled if "controlzero" not in str(d)
3756
+ ]
3757
+
3740
3758
  settings_path.write_text(
3741
3759
  json.dumps(existing, indent=2) + "\n",
3742
3760
  encoding="utf-8",
3743
3761
  )
3744
3762
  _record_hook_baseline(settings_path)
3745
- click.echo(f"Updated {settings_path} (added BeforeTool hook)")
3763
+ click.echo(f"Updated {settings_path} (added BeforeTool hook + hooksConfig.enabled)")
3746
3764
  click.echo("")
3747
3765
  click.echo("[Control Zero] Installed successfully.")
3748
3766
  click.echo("")
@@ -3972,13 +3990,26 @@ def install_codex_cli(force: bool, merge: bool, config: Optional[str], api_key:
3972
3990
  click.echo("")
3973
3991
  click.echo("[Control Zero] Installed successfully.")
3974
3992
  click.echo("")
3993
+ # Codex trust-gates command hooks BY HASH: ~/.codex/hooks.json is a
3994
+ # NON-managed hook, so Codex marks it "for review" and SKIPS it until the
3995
+ # user trusts it -- until then NO tool call is governed (enforcement is
3996
+ # silently OFF), and it re-locks on every upgrade that changes the hook
3997
+ # command/hash. This is the #1 silent-non-enforcement trap on Codex, so
3998
+ # surface it loudly. (developers.openai.com/codex/hooks; openai/codex#27833.)
3999
+ click.echo("[Control Zero] ACTION REQUIRED -- trust the hook or it will NOT run:")
4000
+ click.echo(" 1. Open Codex: codex")
4001
+ click.echo(" 2. Run /hooks and TRUST the Control Zero PreToolUse hook.")
4002
+ click.echo(" Until trusted, Codex SKIPS the hook and tools run UNGOVERNED.")
4003
+ click.echo(" 3. Re-trust after every Control Zero upgrade (the hook hash changes).")
4004
+ click.echo("")
3975
4005
  _print_posture_summary(hosted, "codex-cli", posture_default_action, posture_rule_count)
3976
4006
  if not hosted:
3977
4007
  click.echo("")
3978
- click.echo("Test it:")
3979
- click.echo(" 1. Open Codex CLI in any project: codex")
3980
- click.echo(" 2. Every tool call will show '[Control Zero] Allowed: <tool>'")
3981
- click.echo(" 3. Add deny rules, then watch blocked tools show '[Control Zero] <reason>'")
4008
+ click.echo("Verify it ACTUALLY enforces (not just installed):")
4009
+ click.echo(" 1. In Codex, after trusting the hook, add a deny rule and try that tool.")
4010
+ click.echo(" 2. A governed call shows '[Control Zero] Allowed: <tool>'; a blocked one")
4011
+ click.echo(" shows '[Control Zero] <reason>'. If you see NEITHER, the hook is")
4012
+ click.echo(" untrusted/skipped -- re-run /hooks and trust it.")
3982
4013
  click.echo("")
3983
4014
  click.echo(f"Edit your policy: {GLOBAL_POLICY_PATH}")
3984
4015
  click.echo(f"Audit log: {GLOBAL_AUDIT_PATH}")
@@ -4315,6 +4346,8 @@ def _cursor_enforcement_probe(installed_cmd: str) -> tuple:
4315
4346
  shell=True,
4316
4347
  input=json.dumps(payload),
4317
4348
  text=True,
4349
+ encoding="utf-8",
4350
+ errors="replace",
4318
4351
  capture_output=True,
4319
4352
  env=probe_env,
4320
4353
  timeout=15,
@@ -5241,9 +5274,19 @@ _KIRO_V3_AGENT_NAME = "controlzero"
5241
5274
  _KIRO_V3_AGENT_DESCRIPTION = "Control Zero governance"
5242
5275
  # kiro-cli's built-in default agent -- what the default is restored to on uninstall.
5243
5276
  _KIRO_V3_BUILTIN_DEFAULT_AGENT = "kiro_default"
5244
- # Internal Kiro tool names for the BLOCKING preToolUse trigger. NOT "*"/"shell":
5245
- # execute_bash (shell), fs_write (write/edit/delete), fs_read (read/list/search),
5246
- # use_aws (aws cli). postToolUse is observe-only so it uses a "*" catch-all.
5277
+ # Internal Kiro tool names for the BLOCKING preToolUse trigger. The matcher is
5278
+ # evaluated against kiro-cli's CANONICAL internal tool names (execute_bash /
5279
+ # fs_write / fs_read / use_aws); kiro normalizes the simplified aliases
5280
+ # (shell / write / read / aws) to these, so the canonical matchers fire on every
5281
+ # kiro-cli version (verified against current kiro docs + #4810/#4867 by the
5282
+ # 2026-06-28 cross-adapter drift audit). postToolUse is observe-only and uses
5283
+ # the documented "*" all-tools token. Pinned by
5284
+ # tests/test_kiro_cli_v210_hooks.py -- do NOT rewrite into a "shell|..."
5285
+ # alternation on the belief a tool rename broke them: it did not.
5286
+ #
5287
+ # NOTE: the Ken Lee kiro-cli 2.10 hooks-not-firing report is a SEPARATE issue
5288
+ # (install-time encoding/locale + the Kiro IDE >=1.0.0 legacy-schema drift),
5289
+ # NOT a preToolUse tool-name rename. Do not conflate.
5247
5290
  _KIRO_V3_PRE_TOOL_MATCHERS = ("execute_bash", "fs_write", "fs_read", "use_aws")
5248
5291
 
5249
5292
 
@@ -5290,9 +5333,21 @@ def _kiro_v3_set_default_agent(agent_name: str) -> tuple:
5290
5333
  ["kiro-cli", "agent", "set-default", agent_name],
5291
5334
  capture_output=True,
5292
5335
  text=True,
5336
+ # Decode kiro-cli's UTF-8 output as UTF-8, NOT the OS locale codec.
5337
+ # Without this, text=True uses locale.getpreferredencoding() -- e.g.
5338
+ # CP949 on Korean Windows, SJIS on Japanese, GBK on Chinese -- and
5339
+ # kiro-cli's em-dash/arrow output (byte 0xe2...) crashes the
5340
+ # subprocess reader thread (UnicodeDecodeError). errors="replace"
5341
+ # keeps any stray non-UTF-8 byte from ever crashing the install.
5342
+ encoding="utf-8",
5343
+ errors="replace",
5293
5344
  timeout=15,
5294
5345
  )
5295
- except (OSError, subprocess.SubprocessError) as e:
5346
+ # Honor the "NEVER raises" contract: a best-effort kiro-cli shell-out must
5347
+ # not crash `kiro init`. OSError/SubprocessError cover absent/failed
5348
+ # kiro-cli; the broad guard also covers a decode/runtime surprise so the
5349
+ # caller can turn it into a loud WARNING instead of a traceback.
5350
+ except Exception as e: # noqa: BLE001 -- best-effort, see docstring
5296
5351
  return False, str(e)
5297
5352
  detail = ((proc.stdout or "") + (proc.stderr or "")).strip()
5298
5353
  return proc.returncode == 0, detail
@@ -5319,9 +5374,14 @@ def _kiro_v3_create_agent_from_default() -> tuple:
5319
5374
  ],
5320
5375
  capture_output=True,
5321
5376
  text=True,
5377
+ # See _kiro_v3_set_default_agent: decode as UTF-8 (not the OS locale
5378
+ # codec) so non-ASCII kiro-cli output cannot crash the install on
5379
+ # CP949/SJIS/GBK Windows.
5380
+ encoding="utf-8",
5381
+ errors="replace",
5322
5382
  timeout=15,
5323
5383
  )
5324
- except (OSError, subprocess.SubprocessError) as e:
5384
+ except Exception as e: # noqa: BLE001 -- best-effort, NEVER raises (docstring)
5325
5385
  return False, str(e)
5326
5386
  detail = ((proc.stdout or "") + (proc.stderr or "")).strip()
5327
5387
  return proc.returncode == 0, detail
@@ -6005,6 +6065,8 @@ def _kiro_cli_enforcement_probe(installed_cmd: str) -> tuple:
6005
6065
  shell=True,
6006
6066
  input=json.dumps(payload),
6007
6067
  text=True,
6068
+ encoding="utf-8",
6069
+ errors="replace",
6008
6070
  capture_output=True,
6009
6071
  env=probe_env,
6010
6072
  timeout=15,
@@ -6169,6 +6231,8 @@ def kiro_verify(settings: Optional[str]) -> None:
6169
6231
  shell=True,
6170
6232
  input=json.dumps(payload),
6171
6233
  text=True,
6234
+ encoding="utf-8",
6235
+ errors="replace",
6172
6236
  capture_output=True,
6173
6237
  env=env,
6174
6238
  )
@@ -6178,6 +6242,8 @@ def kiro_verify(settings: Optional[str]) -> None:
6178
6242
  "--policy", str(pol)],
6179
6243
  input=json.dumps(payload),
6180
6244
  text=True,
6245
+ encoding="utf-8",
6246
+ errors="replace",
6181
6247
  capture_output=True,
6182
6248
  env=env,
6183
6249
  )
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "controlzero"
7
- version = "1.13.1"
7
+ version = "1.13.2"
8
8
  description = "AI agent governance: policies, audit, and observability for tool calls. Works locally with no signup."
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
@@ -0,0 +1,110 @@
1
+ """Regression tests for the kiro-cli install hardening (Ken Lee, 2026-06-28).
2
+
3
+ The Ken Lee kiro-cli 2.10 report had TWO themes; this file guards the part that
4
+ is a confirmed, code-level defect: the CP949 / locale ENCODING crash. The
5
+ 2026-06-28 cross-adapter drift audit verified the preToolUse MATCHERS were NOT
6
+ the cause (kiro normalizes the simplified tool aliases shell/write/read/aws to
7
+ the canonical names execute_bash/fs_write/fs_read/use_aws, so the canonical
8
+ matchers fire on every kiro-cli version -- kiro #4810/#4867). These tests pin
9
+ the canonical matchers so they are never "fixed" into an alias alternation, and
10
+ guard the encoding fix.
11
+
12
+ ENCODING bug: the kiro-cli shell-outs captured output in text mode using the OS
13
+ locale codec, so kiro-cli's UTF-8 output (em-dash / arrow, byte 0xe2...) crashed
14
+ the subprocess reader thread on non-UTF-8 Windows locales (Korean CP949,
15
+ Japanese SJIS, Chinese GBK). All kiro-cli shell-outs now decode as
16
+ encoding="utf-8", errors="replace" and honor the "NEVER raises" contract.
17
+ """
18
+
19
+ import re
20
+ import subprocess
21
+
22
+ from controlzero.cli import main as m
23
+
24
+
25
+ # ---------------------------------------------------------------------------
26
+ # Matchers: pin the canonical set (audit-verified correct) so it is never
27
+ # rewritten into an alias alternation on a mistaken "rename broke it" belief.
28
+ # ---------------------------------------------------------------------------
29
+ def test_pretooluse_matchers_are_the_canonical_kiro_tool_names():
30
+ assert m._KIRO_V3_PRE_TOOL_MATCHERS == (
31
+ "execute_bash",
32
+ "fs_write",
33
+ "fs_read",
34
+ "use_aws",
35
+ )
36
+
37
+
38
+ def test_pretooluse_matchers_are_valid_regex_and_match_their_canonical_tool():
39
+ """Each canonical matcher is a valid regex (a malformed matcher silently
40
+ never fires) and matches its own tool name."""
41
+ for tool in m._KIRO_V3_PRE_TOOL_MATCHERS:
42
+ re.compile(tool) # raises re.error if invalid
43
+ assert re.search(tool, tool)
44
+
45
+
46
+ def test_posttooluse_uses_the_documented_all_tools_token():
47
+ """postToolUse is observe-only and uses kiro's documented "*" all-tools
48
+ token (special-cased by kiro, not a raw regex)."""
49
+ hooks = m._kiro_v3_canonical_hooks()
50
+ assert hooks["postToolUse"][0]["matcher"] == "*"
51
+ # preToolUse entries are the canonical names.
52
+ pre_matchers = [h["matcher"] for h in hooks["preToolUse"]]
53
+ assert pre_matchers == list(m._KIRO_V3_PRE_TOOL_MATCHERS)
54
+
55
+
56
+ # ---------------------------------------------------------------------------
57
+ # Encoding: kiro-cli shell-outs decode as UTF-8 and never crash the install.
58
+ # ---------------------------------------------------------------------------
59
+ def test_set_default_agent_decodes_utf8_not_locale_codec(monkeypatch):
60
+ """encoding='utf-8', errors='replace' so kiro-cli's non-ASCII output cannot
61
+ crash the reader thread on CP949/SJIS/GBK Windows."""
62
+ seen = {}
63
+
64
+ class FakeProc:
65
+ returncode = 0
66
+ stdout = "set-default ok"
67
+ stderr = ""
68
+
69
+ def fake_run(*args, **kwargs):
70
+ seen.update(kwargs)
71
+ return FakeProc()
72
+
73
+ monkeypatch.setattr(subprocess, "run", fake_run)
74
+ ok, _detail = m._kiro_v3_set_default_agent("controlzero")
75
+ assert ok is True
76
+ assert seen.get("encoding") == "utf-8"
77
+ assert seen.get("errors") == "replace"
78
+
79
+
80
+ def test_create_agent_from_default_decodes_utf8(monkeypatch):
81
+ seen = {}
82
+
83
+ class FakeProc:
84
+ returncode = 0
85
+ stdout = ""
86
+ stderr = ""
87
+
88
+ def fake_run(*args, **kwargs):
89
+ seen.update(kwargs)
90
+ return FakeProc()
91
+
92
+ monkeypatch.setattr(subprocess, "run", fake_run)
93
+ ok, _detail = m._kiro_v3_create_agent_from_default()
94
+ assert ok is True
95
+ assert seen.get("encoding") == "utf-8"
96
+ assert seen.get("errors") == "replace"
97
+
98
+
99
+ def test_set_default_agent_never_raises_on_any_subprocess_error(monkeypatch):
100
+ """The 'NEVER raises' contract: a decode/runtime surprise must become a
101
+ (False, detail) the caller turns into a loud WARNING, not a traceback that
102
+ aborts `kiro init` (the Thread-2 _readerthread crash Ken saw)."""
103
+
104
+ def boom(*args, **kwargs):
105
+ raise UnicodeDecodeError("cp949", b"\xe2", 0, 1, "illegal multibyte sequence")
106
+
107
+ monkeypatch.setattr(subprocess, "run", boom)
108
+ ok, detail = m._kiro_v3_set_default_agent("controlzero")
109
+ assert ok is False
110
+ assert detail # carries the error string for the WARNING
File without changes
File without changes
File without changes