talkops-opscloud 0.3.0b1__py3-none-any.whl

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 (309) hide show
  1. opscloud/__init__.py +5 -0
  2. opscloud/__main__.py +6 -0
  3. opscloud/_constants.py +53 -0
  4. opscloud/_debug.py +145 -0
  5. opscloud/_debug_buffer.py +250 -0
  6. opscloud/_textual_patches.py +367 -0
  7. opscloud/_version.py +15 -0
  8. opscloud/agent/__init__.py +27 -0
  9. opscloud/agent/config.py +168 -0
  10. opscloud/agent/factory.py +1103 -0
  11. opscloud/approval_mode.py +44 -0
  12. opscloud/backend/__init__.py +49 -0
  13. opscloud/backend/composite.py +89 -0
  14. opscloud/backend/local.py +183 -0
  15. opscloud/backend/registry.py +79 -0
  16. opscloud/backend/sandbox_config.py +107 -0
  17. opscloud/backend/sandbox_factory.py +432 -0
  18. opscloud/built_in_skills/remember/SKILL.md +124 -0
  19. opscloud/built_in_skills/skill-creator/SKILL.md +348 -0
  20. opscloud/built_in_skills/skill-creator/scripts/init_skill.py +371 -0
  21. opscloud/built_in_skills/skill-creator/scripts/quick_validate.py +165 -0
  22. opscloud/cli/__init__.py +1 -0
  23. opscloud/cli/commands/__init__.py +15 -0
  24. opscloud/cli/commands/auth.py +45 -0
  25. opscloud/cli/commands/doctor.py +100 -0
  26. opscloud/cli/commands/mcp.py +137 -0
  27. opscloud/cli/commands/threads.py +51 -0
  28. opscloud/cli/interactive.py +154 -0
  29. opscloud/cli/main.py +903 -0
  30. opscloud/cli/non_interactive.py +425 -0
  31. opscloud/cli/server_manager.py +58 -0
  32. opscloud/commands/__init__.py +19 -0
  33. opscloud/commands/_base.py +110 -0
  34. opscloud/commands/_guards.py +52 -0
  35. opscloud/commands/_router.py +146 -0
  36. opscloud/commands/_types.py +36 -0
  37. opscloud/commands/core/__init__.py +47 -0
  38. opscloud/commands/core/auth.py +94 -0
  39. opscloud/commands/core/bug.py +46 -0
  40. opscloud/commands/core/clear.py +106 -0
  41. opscloud/commands/core/cloud.py +185 -0
  42. opscloud/commands/core/compact.py +128 -0
  43. opscloud/commands/core/config_cmd.py +120 -0
  44. opscloud/commands/core/context.py +220 -0
  45. opscloud/commands/core/cost.py +44 -0
  46. opscloud/commands/core/doctor.py +535 -0
  47. opscloud/commands/core/effort.py +108 -0
  48. opscloud/commands/core/exit_cmd.py +41 -0
  49. opscloud/commands/core/fast.py +148 -0
  50. opscloud/commands/core/help_cmd.py +94 -0
  51. opscloud/commands/core/mcp.py +134 -0
  52. opscloud/commands/core/model.py +109 -0
  53. opscloud/commands/core/permissions.py +196 -0
  54. opscloud/commands/core/plugins.py +92 -0
  55. opscloud/commands/core/pool.py +108 -0
  56. opscloud/commands/core/resume.py +97 -0
  57. opscloud/commands/core/skills.py +178 -0
  58. opscloud/commands/power/__init__.py +51 -0
  59. opscloud/commands/power/agents.py +98 -0
  60. opscloud/commands/power/btw.py +85 -0
  61. opscloud/commands/power/copy.py +97 -0
  62. opscloud/commands/power/goal.py +548 -0
  63. opscloud/commands/power/loop.py +295 -0
  64. opscloud/commands/power/memory.py +287 -0
  65. opscloud/commands/power/review.py +152 -0
  66. opscloud/commands/power/rubric.py +287 -0
  67. opscloud/commands/power/runtime.py +321 -0
  68. opscloud/commands/power/skill_creator.py +70 -0
  69. opscloud/commands/power/skill_invoke.py +165 -0
  70. opscloud/commands/power/tasks.py +209 -0
  71. opscloud/commands/power/trace.py +117 -0
  72. opscloud/commands/power/ui_toggles.py +135 -0
  73. opscloud/commands/power/version.py +52 -0
  74. opscloud/commands/registry.py +176 -0
  75. opscloud/config/__init__.py +114 -0
  76. opscloud/config/adapters/__init__.py +5 -0
  77. opscloud/config/adapters/postgres.py +776 -0
  78. opscloud/config/adapters/sqlite.py +769 -0
  79. opscloud/config/aws.py +248 -0
  80. opscloud/config/cloud_profiles.py +437 -0
  81. opscloud/config/env_vars.py +81 -0
  82. opscloud/config/langsmith.py +319 -0
  83. opscloud/config/manifest.py +817 -0
  84. opscloud/config/metadata.py +205 -0
  85. opscloud/config/paths.py +604 -0
  86. opscloud/config/plugins.py +130 -0
  87. opscloud/config/settings.py +834 -0
  88. opscloud/config/store.py +453 -0
  89. opscloud/config/store_factory.py +97 -0
  90. opscloud/config/toml_config.py +562 -0
  91. opscloud/editor.py +173 -0
  92. opscloud/exceptions.py +65 -0
  93. opscloud/file_ops.py +217 -0
  94. opscloud/hooks/__init__.py +139 -0
  95. opscloud/hooks/env.py +44 -0
  96. opscloud/hooks/interrupt.py +121 -0
  97. opscloud/hooks/models/__init__.py +109 -0
  98. opscloud/hooks/models/adapters.py +19 -0
  99. opscloud/hooks/models/config.py +79 -0
  100. opscloud/hooks/models/domain.py +434 -0
  101. opscloud/hooks/models/transport.py +37 -0
  102. opscloud/hooks/tools.py +231 -0
  103. opscloud/input.py +48 -0
  104. opscloud/integrations/__init__.py +80 -0
  105. opscloud/integrations/base.py +153 -0
  106. opscloud/integrations/content_filter.py +119 -0
  107. opscloud/integrations/event_bus.py +480 -0
  108. opscloud/integrations/hooks.py +238 -0
  109. opscloud/integrations/identity.py +181 -0
  110. opscloud/integrations/notifications.py +134 -0
  111. opscloud/integrations/stream_bridge.py +397 -0
  112. opscloud/integrations/thread_store.py +81 -0
  113. opscloud/json_types.py +20 -0
  114. opscloud/mcp/__init__.py +57 -0
  115. opscloud/mcp/config.py +203 -0
  116. opscloud/mcp/discovery.py +229 -0
  117. opscloud/mcp/mcp_info.py +109 -0
  118. opscloud/mcp/middleware.py +102 -0
  119. opscloud/mcp/preload.py +505 -0
  120. opscloud/mcp/raw_config.py +149 -0
  121. opscloud/mcp/semantic_profiler.py +305 -0
  122. opscloud/mcp/session_manager.py +727 -0
  123. opscloud/mcp/trust.py +105 -0
  124. opscloud/memory/__init__.py +27 -0
  125. opscloud/memory/branch.py +61 -0
  126. opscloud/memory/guard.py +19 -0
  127. opscloud/memory/onboarding.py +120 -0
  128. opscloud/memory/registry.py +134 -0
  129. opscloud/memory/store.py +223 -0
  130. opscloud/middleware/__init__.py +106 -0
  131. opscloud/middleware/_repository_bounds.py +459 -0
  132. opscloud/middleware/ask_user.py +152 -0
  133. opscloud/middleware/auto_mode.py +60 -0
  134. opscloud/middleware/auto_mode_hitl.py +2434 -0
  135. opscloud/middleware/compaction.py +566 -0
  136. opscloud/middleware/configurable_model.py +233 -0
  137. opscloud/middleware/cost_tracking.py +1021 -0
  138. opscloud/middleware/glm_stall_recovery.py +109 -0
  139. opscloud/middleware/goal_criteria.py +1234 -0
  140. opscloud/middleware/goal_state_notice.py +712 -0
  141. opscloud/middleware/goal_tools.py +407 -0
  142. opscloud/middleware/headless_mcp_guard.py +88 -0
  143. opscloud/middleware/jev_model_router.py +1018 -0
  144. opscloud/middleware/local_context.py +460 -0
  145. opscloud/middleware/mcp_context.py +151 -0
  146. opscloud/middleware/mcp_middleware.py +146 -0
  147. opscloud/middleware/memory_guard.py +393 -0
  148. opscloud/middleware/model_retry.py +205 -0
  149. opscloud/middleware/registry.py +137 -0
  150. opscloud/middleware/reliable_rubric.py +709 -0
  151. opscloud/middleware/resume_state.py +91 -0
  152. opscloud/middleware/server_hooks.py +1189 -0
  153. opscloud/middleware/shell_allow_list.py +90 -0
  154. opscloud/middleware/skills.py +382 -0
  155. opscloud/middleware/subagent_artifacts.py +84 -0
  156. opscloud/middleware/subagent_telemetry.py +261 -0
  157. opscloud/middleware/subagents.py +243 -0
  158. opscloud/middleware/tool_filter.py +384 -0
  159. opscloud/middleware/unified_system_message.py +62 -0
  160. opscloud/model/__init__.py +37 -0
  161. opscloud/model/config.py +2992 -0
  162. opscloud/model/factory.py +477 -0
  163. opscloud/model/pool.py +459 -0
  164. opscloud/model/reasoning.py +282 -0
  165. opscloud/offload.py +173 -0
  166. opscloud/output.py +64 -0
  167. opscloud/plugins/__init__.py +189 -0
  168. opscloud/plugins/_json.py +22 -0
  169. opscloud/plugins/adapters/__init__.py +13 -0
  170. opscloud/plugins/adapters/agents.py +112 -0
  171. opscloud/plugins/adapters/commands.py +190 -0
  172. opscloud/plugins/adapters/mcp.py +363 -0
  173. opscloud/plugins/adapters/skills.py +132 -0
  174. opscloud/plugins/commands_cli.py +541 -0
  175. opscloud/plugins/discovery.py +512 -0
  176. opscloud/plugins/manifest.py +335 -0
  177. opscloud/plugins/marketplace.py +893 -0
  178. opscloud/plugins/models.py +334 -0
  179. opscloud/plugins/project_plugins.py +317 -0
  180. opscloud/plugins/protocol.py +31 -0
  181. opscloud/plugins/store.py +905 -0
  182. opscloud/plugins/substitution.py +122 -0
  183. opscloud/project_utils.py +145 -0
  184. opscloud/prompts/__init__.py +37 -0
  185. opscloud/prompts/system.py +483 -0
  186. opscloud/prompts/templates/system_prompt.md +166 -0
  187. opscloud/prompts/types.py +54 -0
  188. opscloud/rubrics/__init__.py +42 -0
  189. opscloud/rubrics/evaluator.py +404 -0
  190. opscloud/rubrics/evidence_extractor.py +229 -0
  191. opscloud/rubrics/generator.py +239 -0
  192. opscloud/rubrics/jev_compiler.py +175 -0
  193. opscloud/rubrics/jev_grader.py +297 -0
  194. opscloud/rubrics/middleware.py +8 -0
  195. opscloud/schema/__init__.py +107 -0
  196. opscloud/schema/interrupts.py +981 -0
  197. opscloud/security/__init__.py +91 -0
  198. opscloud/security/approval_mode.py +528 -0
  199. opscloud/security/approval_mode_source.py +230 -0
  200. opscloud/security/cli_ast_evaluator.py +552 -0
  201. opscloud/security/jev_classifier.py +651 -0
  202. opscloud/security/shell_safety.py +340 -0
  203. opscloud/security/unicode_security.py +439 -0
  204. opscloud/security/url_validation.py +160 -0
  205. opscloud/server/__init__.py +13 -0
  206. opscloud/server/_server_config.py +158 -0
  207. opscloud/server/server.py +242 -0
  208. opscloud/server/server_graph.py +93 -0
  209. opscloud/skills/__init__.py +91 -0
  210. opscloud/skills/commands.py +1099 -0
  211. opscloud/skills/invocation.py +200 -0
  212. opscloud/skills/load.py +388 -0
  213. opscloud/skills/loader.py +23 -0
  214. opscloud/skills/merge.py +65 -0
  215. opscloud/skills/registry.py +263 -0
  216. opscloud/skills/sources.py +174 -0
  217. opscloud/skills/trust.py +417 -0
  218. opscloud/state/__init__.py +142 -0
  219. opscloud/state/base.py +154 -0
  220. opscloud/state/cloud_context.py +262 -0
  221. opscloud/state/goal_channels.py +124 -0
  222. opscloud/state/goal_state_limits.py +175 -0
  223. opscloud/state/resume_state.py +58 -0
  224. opscloud/state/service_context.py +281 -0
  225. opscloud/state/session.py +957 -0
  226. opscloud/state/state_migration.py +86 -0
  227. opscloud/subagents/__init__.py +30 -0
  228. opscloud/subagents/loader.py +331 -0
  229. opscloud/subagents/subagents_parser.py +117 -0
  230. opscloud/subagents/types.py +25 -0
  231. opscloud/tools/__init__.py +36 -0
  232. opscloud/tools/catalog.py +37 -0
  233. opscloud/tools/display.py +24 -0
  234. opscloud/tools/fetch_url.py +176 -0
  235. opscloud/tools/goal_tools.py +423 -0
  236. opscloud/tools/registry.py +105 -0
  237. opscloud/tools/thread.py +32 -0
  238. opscloud/tools/web_search.py +215 -0
  239. opscloud/ui/__init__.py +119 -0
  240. opscloud/ui/app.py +5400 -0
  241. opscloud/ui/app.tcss +479 -0
  242. opscloud/ui/clipboard.py +147 -0
  243. opscloud/ui/command_registry.py +482 -0
  244. opscloud/ui/message_store.py +152 -0
  245. opscloud/ui/permission_store.py +360 -0
  246. opscloud/ui/preferences.py +113 -0
  247. opscloud/ui/prompt_manager.py +96 -0
  248. opscloud/ui/remote_client.py +505 -0
  249. opscloud/ui/textual_adapter.py +1269 -0
  250. opscloud/ui/theme.py +728 -0
  251. opscloud/ui/ui_help.py +415 -0
  252. opscloud/ui/widgets/__init__.py +383 -0
  253. opscloud/ui/widgets/_ask_user_types.py +81 -0
  254. opscloud/ui/widgets/_copy_spans.py +52 -0
  255. opscloud/ui/widgets/_inline_prompt.py +290 -0
  256. opscloud/ui/widgets/_js_eval_display.py +139 -0
  257. opscloud/ui/widgets/_links.py +175 -0
  258. opscloud/ui/widgets/_tool_stream.py +308 -0
  259. opscloud/ui/widgets/agent_selector.py +297 -0
  260. opscloud/ui/widgets/approval.py +741 -0
  261. opscloud/ui/widgets/ask_user.py +539 -0
  262. opscloud/ui/widgets/auth.py +695 -0
  263. opscloud/ui/widgets/auth_manager.py +214 -0
  264. opscloud/ui/widgets/auto_mode_notice.py +146 -0
  265. opscloud/ui/widgets/autocomplete.py +709 -0
  266. opscloud/ui/widgets/chat_input.py +805 -0
  267. opscloud/ui/widgets/cloud_selector.py +528 -0
  268. opscloud/ui/widgets/config_manager.py +652 -0
  269. opscloud/ui/widgets/debug_console.py +1269 -0
  270. opscloud/ui/widgets/devops_renderers.py +184 -0
  271. opscloud/ui/widgets/diff.py +237 -0
  272. opscloud/ui/widgets/effort_selector.py +166 -0
  273. opscloud/ui/widgets/goal_review.py +612 -0
  274. opscloud/ui/widgets/goal_status.py +57 -0
  275. opscloud/ui/widgets/infra_panel.py +141 -0
  276. opscloud/ui/widgets/install_confirm.py +114 -0
  277. opscloud/ui/widgets/loading.py +170 -0
  278. opscloud/ui/widgets/mcp_viewer.py +1204 -0
  279. opscloud/ui/widgets/messages.py +4461 -0
  280. opscloud/ui/widgets/model_selector.py +863 -0
  281. opscloud/ui/widgets/notification_center.py +108 -0
  282. opscloud/ui/widgets/notification_settings.py +119 -0
  283. opscloud/ui/widgets/operation_card.py +106 -0
  284. opscloud/ui/widgets/permissions_manager.py +667 -0
  285. opscloud/ui/widgets/plugin_manager.py +1212 -0
  286. opscloud/ui/widgets/pool_selector.py +376 -0
  287. opscloud/ui/widgets/preamble.py +53 -0
  288. opscloud/ui/widgets/skills_viewer.py +432 -0
  289. opscloud/ui/widgets/status.py +1037 -0
  290. opscloud/ui/widgets/subagent_panel.py +927 -0
  291. opscloud/ui/widgets/theme_selector.py +232 -0
  292. opscloud/ui/widgets/thread_selector.py +358 -0
  293. opscloud/ui/widgets/toast.py +31 -0
  294. opscloud/ui/widgets/tool_display.py +325 -0
  295. opscloud/ui/widgets/tool_renderers.py +234 -0
  296. opscloud/ui/widgets/tool_widgets.py +278 -0
  297. opscloud/ui/widgets/welcome.py +421 -0
  298. opscloud/ui/widgets/welcome_popup.py +102 -0
  299. opscloud/utils/__init__.py +24 -0
  300. opscloud/utils/cost_estimation.py +169 -0
  301. opscloud/utils/git.py +390 -0
  302. opscloud/utils/logger.py +571 -0
  303. opscloud/utils/session_stats.py +115 -0
  304. opscloud/utils/startup_error.py +37 -0
  305. talkops_opscloud-0.3.0b1.dist-info/METADATA +449 -0
  306. talkops_opscloud-0.3.0b1.dist-info/RECORD +309 -0
  307. talkops_opscloud-0.3.0b1.dist-info/WHEEL +4 -0
  308. talkops_opscloud-0.3.0b1.dist-info/entry_points.txt +2 -0
  309. talkops_opscloud-0.3.0b1.dist-info/licenses/LICENSE +175 -0
@@ -0,0 +1,121 @@
1
+ """Client↔server interrupt transport for Hooks v2 server-owned events."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any, Literal
6
+
7
+ from pydantic import BaseModel, ConfigDict, TypeAdapter
8
+
9
+ from opscloud.hooks.models.adapters import HOOK_INVOCATION_RESPONSE_ADAPTER
10
+ from opscloud.hooks.models.transport import (
11
+ HookInvocationRequest,
12
+ HookInvocationResponse,
13
+ )
14
+
15
+ if TYPE_CHECKING:
16
+ from uuid import UUID
17
+
18
+ HOOK_INVOCATION_INTERRUPT_TYPE: Literal["hook_invocation"] = "hook_invocation"
19
+
20
+
21
+ class HookInvocationInterrupt(BaseModel):
22
+ """LangGraph interrupt envelope for a server-owned hook invocation."""
23
+
24
+ model_config = ConfigDict(extra="forbid")
25
+
26
+ type: Literal["hook_invocation"] = HOOK_INVOCATION_INTERRUPT_TYPE
27
+ request: HookInvocationRequest
28
+
29
+
30
+ HOOK_INVOCATION_INTERRUPT_ADAPTER: TypeAdapter[HookInvocationInterrupt] = TypeAdapter(HookInvocationInterrupt)
31
+
32
+ type HookResumeValue = dict[str, Any]
33
+
34
+
35
+ def build_hook_interrupt_payload(request: HookInvocationRequest) -> dict[str, Any]:
36
+ """Serialize a hook invocation request for `interrupt()`.
37
+
38
+ Args:
39
+ request: Versioned server-owned invocation request.
40
+
41
+ Returns:
42
+ JSON-compatible interrupt payload with a stable `type` discriminator.
43
+ """
44
+ return HOOK_INVOCATION_INTERRUPT_ADAPTER.dump_python(
45
+ HookInvocationInterrupt(request=request),
46
+ mode="json",
47
+ )
48
+
49
+
50
+ def parse_hook_interrupt_payload(value: object) -> HookInvocationRequest | None:
51
+ """Parse a hook invocation interrupt payload when present.
52
+
53
+ Args:
54
+ value: Raw interrupt value from LangGraph.
55
+
56
+ Returns:
57
+ The embedded request, or None when value is not a hook interrupt.
58
+ """
59
+ if not isinstance(value, dict) or value.get("type") != HOOK_INVOCATION_INTERRUPT_TYPE:
60
+ return None
61
+ interrupt_data = HOOK_INVOCATION_INTERRUPT_ADAPTER.validate_python(value)
62
+ return interrupt_data.request
63
+
64
+
65
+ def build_hook_resume_value(response: HookInvocationResponse) -> HookResumeValue:
66
+ """Serialize a hook invocation response for `Command(resume=...)`.
67
+
68
+ Args:
69
+ response: Decision returned by the client runtime.
70
+
71
+ Returns:
72
+ JSON-compatible resume value for the matching interrupt id.
73
+ """
74
+ return HOOK_INVOCATION_RESPONSE_ADAPTER.dump_python(response, mode="json")
75
+
76
+
77
+ def parse_hook_resume_value(
78
+ value: object,
79
+ *,
80
+ invocation_id: UUID,
81
+ snapshot_id: str,
82
+ ) -> HookInvocationResponse:
83
+ """Validate a resumed hook response against the outstanding request.
84
+
85
+ Args:
86
+ value: Resume payload returned by the client.
87
+ invocation_id: Expected invocation id from the request.
88
+ snapshot_id: Expected configuration snapshot id.
89
+
90
+ Returns:
91
+ Validated hook invocation response.
92
+
93
+ Raises:
94
+ ValueError: If the resume payload is not a JSON object or if the
95
+ invocation_id or snapshot_id does not match expectations.
96
+ """
97
+ if not isinstance(value, dict):
98
+ msg = "Hook resume payload must be a JSON object"
99
+ raise ValueError(msg)
100
+ response = HOOK_INVOCATION_RESPONSE_ADAPTER.validate_python(value)
101
+ if response.invocation_id != invocation_id:
102
+ msg = f"Resume invocation id {response.invocation_id} does not match {invocation_id}"
103
+ raise ValueError(msg)
104
+ if response.snapshot_id != snapshot_id:
105
+ msg = f"Resume snapshot id {response.snapshot_id} does not match {snapshot_id}"
106
+ raise ValueError(msg)
107
+ return response
108
+
109
+
110
+ def is_hook_interrupt_payload(value: object) -> bool:
111
+ """Return whether value looks like a Hooks v2 invocation interrupt.
112
+
113
+ Args:
114
+ value: Any interrupt payload value to check.
115
+
116
+ Returns:
117
+ True if the value is a dict with type 'hook_invocation', False otherwise.
118
+ """
119
+ return (
120
+ isinstance(value, dict) and value.get("type") == HOOK_INVOCATION_INTERRUPT_TYPE
121
+ )
@@ -0,0 +1,109 @@
1
+ """Hook domain and transport models."""
2
+
3
+ from opscloud.hooks.models.domain import (
4
+ AgentIdentity,
5
+ BackgroundTaskSnapshot,
6
+ BaseHookDecision,
7
+ CompactTrigger,
8
+ EffortLevel,
9
+ HookContext,
10
+ HookDecision,
11
+ HookDiagnostic,
12
+ HookDomainEvent,
13
+ HookEffect,
14
+ HookEvent,
15
+ HookInvocation,
16
+ HookOwner,
17
+ NotificationDecision,
18
+ NotificationEvent,
19
+ OpscloudNotification,
20
+ OpscloudNotificationKind,
21
+ PermissionEffect,
22
+ PermissionRequestDecision,
23
+ PermissionRequestEvent,
24
+ PostToolUseDecision,
25
+ PostToolUseEvent,
26
+ PostToolUseFailureDecision,
27
+ PostToolUseFailureEvent,
28
+ PreCompactDecision,
29
+ PreCompactEvent,
30
+ PreToolUseDecision,
31
+ PreToolUseEvent,
32
+ SessionCronSnapshot,
33
+ SessionEndCause,
34
+ SessionEndDecision,
35
+ SessionEndEvent,
36
+ SessionStartCause,
37
+ SessionStartDecision,
38
+ SessionStartEvent,
39
+ StopDecision,
40
+ StopEvent,
41
+ SubagentStartDecision,
42
+ SubagentStartEvent,
43
+ SubagentStopDecision,
44
+ SubagentStopEvent,
45
+ ToolCallData,
46
+ UserPromptSubmitDecision,
47
+ UserPromptSubmitEvent,
48
+ )
49
+ from opscloud.hooks.models.config import (
50
+ CommandHandlerSpec,
51
+ HooksConfig,
52
+ MatcherGroup,
53
+ )
54
+ from opscloud.hooks.models.transport import (
55
+ HookInvocationRequest,
56
+ HookInvocationResponse,
57
+ )
58
+
59
+ __all__ = [
60
+ "AgentIdentity",
61
+ "BackgroundTaskSnapshot",
62
+ "BaseHookDecision",
63
+ "CommandHandlerSpec",
64
+ "CompactTrigger",
65
+ "EffortLevel",
66
+ "HookContext",
67
+ "HookDecision",
68
+ "HookDiagnostic",
69
+ "HookDomainEvent",
70
+ "HookEffect",
71
+ "HookEvent",
72
+ "HookInvocation",
73
+ "HookInvocationRequest",
74
+ "HookInvocationResponse",
75
+ "HookOwner",
76
+ "HooksConfig",
77
+ "MatcherGroup",
78
+ "NotificationDecision",
79
+ "NotificationEvent",
80
+ "OpscloudNotification",
81
+ "OpscloudNotificationKind",
82
+ "PermissionEffect",
83
+ "PermissionRequestDecision",
84
+ "PermissionRequestEvent",
85
+ "PostToolUseDecision",
86
+ "PostToolUseEvent",
87
+ "PostToolUseFailureDecision",
88
+ "PostToolUseFailureEvent",
89
+ "PreCompactDecision",
90
+ "PreCompactEvent",
91
+ "PreToolUseDecision",
92
+ "PreToolUseEvent",
93
+ "SessionCronSnapshot",
94
+ "SessionEndCause",
95
+ "SessionEndDecision",
96
+ "SessionEndEvent",
97
+ "SessionStartCause",
98
+ "SessionStartDecision",
99
+ "SessionStartEvent",
100
+ "StopDecision",
101
+ "StopEvent",
102
+ "SubagentStartDecision",
103
+ "SubagentStartEvent",
104
+ "SubagentStopDecision",
105
+ "SubagentStopEvent",
106
+ "ToolCallData",
107
+ "UserPromptSubmitDecision",
108
+ "UserPromptSubmitEvent",
109
+ ]
@@ -0,0 +1,19 @@
1
+ """Cached runtime validators for hook model boundaries."""
2
+
3
+ from pydantic import TypeAdapter
4
+
5
+ from opscloud.hooks.models.domain import (
6
+ HookDecision,
7
+ HookDomainEvent,
8
+ HookInvocation,
9
+ )
10
+ from opscloud.hooks.models.transport import (
11
+ HookInvocationRequest,
12
+ HookInvocationResponse,
13
+ )
14
+
15
+ HOOK_DOMAIN_EVENT_ADAPTER: TypeAdapter[HookDomainEvent] = TypeAdapter(HookDomainEvent)
16
+ HOOK_INVOCATION_ADAPTER: TypeAdapter[HookInvocation] = TypeAdapter(HookInvocation)
17
+ HOOK_DECISION_ADAPTER: TypeAdapter[HookDecision] = TypeAdapter(HookDecision)
18
+ HOOK_INVOCATION_REQUEST_ADAPTER: TypeAdapter[HookInvocationRequest] = TypeAdapter(HookInvocationRequest)
19
+ HOOK_INVOCATION_RESPONSE_ADAPTER: TypeAdapter[HookInvocationResponse] = TypeAdapter(HookInvocationResponse)
@@ -0,0 +1,79 @@
1
+ """Validated hook configuration models for declarative Hooks v2 specifications."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Literal
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
8
+
9
+ from opscloud.hooks.models.domain import HookEvent
10
+
11
+
12
+ class _ConfigModel(BaseModel):
13
+ """Base model for hook configuration objects."""
14
+
15
+ model_config = ConfigDict(extra="ignore", populate_by_name=True)
16
+
17
+
18
+ class CommandHandlerSpec(_ConfigModel):
19
+ """Configuration for a command hook handler.
20
+
21
+ Currently supports `type: "command"`. Commands can run shell expressions
22
+ or direct executable arguments via `argv`.
23
+ """
24
+
25
+ type: Literal["command"]
26
+ command: str
27
+ argv: list[str] | None = None
28
+ timeout: float | None = Field(default=None, gt=0, allow_inf_nan=False)
29
+ status_message: str | None = Field(default=None, alias="statusMessage")
30
+ async_: bool | None = Field(default=None, alias="async")
31
+
32
+ @field_validator("argv", mode="after")
33
+ @classmethod
34
+ def _normalize_argv(cls, value: list[str] | None) -> list[str] | None:
35
+ """Validate that argv is a non-empty list of strings if provided.
36
+
37
+ Args:
38
+ value: Provided argv list or None.
39
+
40
+ Returns:
41
+ Validated list of string arguments.
42
+
43
+ Raises:
44
+ ValueError: If argv is empty, contains non-strings, or has an empty executable.
45
+ """
46
+ if value is None:
47
+ return None
48
+ if not value or not all(isinstance(part, str) for part in value):
49
+ msg = "argv must be a non-empty list of strings when provided."
50
+ raise ValueError(msg)
51
+ if not value[0].strip():
52
+ msg = "argv[0] must be a non-empty executable path."
53
+ raise ValueError(msg)
54
+ return value
55
+
56
+
57
+ HandlerSpec = CommandHandlerSpec
58
+
59
+
60
+ class MatcherGroup(_ConfigModel):
61
+ """A matcher pattern and its ordered hook handlers.
62
+
63
+ Attributes:
64
+ matcher: Tool name pattern (e.g. 'Bash', 'aws_*', 'Write') or regex.
65
+ hooks: List of handler specifications to execute on match.
66
+ """
67
+
68
+ matcher: str | None = None
69
+ hooks: list[HandlerSpec]
70
+
71
+
72
+ class HooksConfig(_ConfigModel):
73
+ """Top-level configuration grouped by hook lifecycle event.
74
+
75
+ Attributes:
76
+ hooks: Mapping from lifecycle HookEvent to list of MatcherGroups.
77
+ """
78
+
79
+ hooks: dict[HookEvent, list[MatcherGroup]]