ummaya 0.2.4 → 0.2.6

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 (482) hide show
  1. package/README.md +15 -2
  2. package/bin/ummaya +10 -1
  3. package/bun.lock +180 -244
  4. package/npm-shrinkwrap.json +760 -1760
  5. package/package.json +39 -22
  6. package/prompts/manifest.yaml +1 -1
  7. package/prompts/system_v1.md +1 -0
  8. package/pyproject.toml +27 -2
  9. package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
  10. package/src/ummaya/_canonical/__init__.py +2 -0
  11. package/src/ummaya/_canonical/baselines.yaml +113 -0
  12. package/src/ummaya/engine/engine.py +29 -132
  13. package/src/ummaya/evidence/__init__.py +21 -2
  14. package/src/ummaya/evidence/dataset_contract.py +193 -0
  15. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  16. package/src/ummaya/evidence/document_harness.py +313 -0
  17. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  18. package/src/ummaya/evidence/gates.py +70 -0
  19. package/src/ummaya/evidence/json_types.py +20 -0
  20. package/src/ummaya/evidence/models.py +88 -1
  21. package/src/ummaya/evidence/output_payload.py +89 -0
  22. package/src/ummaya/evidence/payload_documents.py +233 -0
  23. package/src/ummaya/evidence/route_contracts.py +224 -0
  24. package/src/ummaya/evidence/route_helpers.py +150 -0
  25. package/src/ummaya/evidence/runner.py +81 -212
  26. package/src/ummaya/evidence/source_provenance.py +246 -0
  27. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  28. package/src/ummaya/evidence/tool_layer.py +39 -0
  29. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  30. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  31. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  32. package/src/ummaya/ipc/frame_schema.py +5 -5
  33. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  34. package/src/ummaya/ipc/stdio.py +1109 -477
  35. package/src/ummaya/llm/client.py +102 -3
  36. package/src/ummaya/llm/config.py +8 -3
  37. package/src/ummaya/primitives/__init__.py +6 -2
  38. package/src/ummaya/primitives/delegation.py +1 -1
  39. package/src/ummaya/primitives/document.py +28 -0
  40. package/src/ummaya/settings.py +0 -3
  41. package/src/ummaya/tools/discovery_bridge.py +17 -1
  42. package/src/ummaya/tools/documents/__init__.py +297 -0
  43. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  44. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  45. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  46. package/src/ummaya/tools/documents/authoring.py +283 -0
  47. package/src/ummaya/tools/documents/baselines.py +132 -0
  48. package/src/ummaya/tools/documents/capability.py +331 -0
  49. package/src/ummaya/tools/documents/contracts.py +112 -0
  50. package/src/ummaya/tools/documents/conversion.py +521 -0
  51. package/src/ummaya/tools/documents/diff.py +275 -0
  52. package/src/ummaya/tools/documents/engines.py +163 -0
  53. package/src/ummaya/tools/documents/evaluation.py +291 -0
  54. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  55. package/src/ummaya/tools/documents/fixtures.py +174 -0
  56. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  57. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  58. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  59. package/src/ummaya/tools/documents/formats/base.py +41 -0
  60. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  61. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  62. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  63. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  64. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  65. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  66. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  67. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  68. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  69. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  70. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  71. package/src/ummaya/tools/documents/inspection.py +289 -0
  72. package/src/ummaya/tools/documents/intake.py +1079 -0
  73. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  74. package/src/ummaya/tools/documents/models.py +1598 -0
  75. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  76. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  77. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  78. package/src/ummaya/tools/documents/patch.py +170 -0
  79. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  80. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  81. package/src/ummaya/tools/documents/permissions.py +110 -0
  82. package/src/ummaya/tools/documents/planner.py +616 -0
  83. package/src/ummaya/tools/documents/registry.py +2733 -0
  84. package/src/ummaya/tools/documents/render.py +978 -0
  85. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  86. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  87. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  88. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  89. package/src/ummaya/tools/documents/reread.py +157 -0
  90. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  91. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  92. package/src/ummaya/tools/documents/scorecard.py +184 -0
  93. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  94. package/src/ummaya/tools/documents/style.py +48 -0
  95. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  96. package/src/ummaya/tools/documents/validate.py +347 -0
  97. package/src/ummaya/tools/executor.py +29 -0
  98. package/src/ummaya/tools/live_proxy.py +0 -3
  99. package/src/ummaya/tools/models.py +5 -1
  100. package/src/ummaya/tools/register_all.py +8 -0
  101. package/src/ummaya/tools/registry.py +10 -1
  102. package/src/ummaya/tools/routing/__init__.py +59 -0
  103. package/src/ummaya/tools/routing/builder.py +105 -0
  104. package/src/ummaya/tools/routing/cards.py +29 -0
  105. package/src/ummaya/tools/routing/decision_service.py +534 -0
  106. package/src/ummaya/tools/routing/decision_types.py +74 -0
  107. package/src/ummaya/tools/routing/feasibility.py +122 -0
  108. package/src/ummaya/tools/routing/intent.py +17 -0
  109. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  110. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  111. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  112. package/src/ummaya/tools/routing/intent_types.py +48 -0
  113. package/src/ummaya/tools/routing/lint.py +78 -0
  114. package/src/ummaya/tools/routing/metadata.py +174 -0
  115. package/src/ummaya/tools/routing/projection.py +340 -0
  116. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  117. package/src/ummaya/tools/routing/schema.py +81 -0
  118. package/src/ummaya/tools/routing/types.py +96 -0
  119. package/src/ummaya/tools/routing_index.py +2 -2
  120. package/src/ummaya/tools/search.py +34 -746
  121. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  122. package/tui/bun.lock +126 -305
  123. package/tui/package.json +35 -22
  124. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  125. package/tui/src/QueryEngine.ts +12 -8
  126. package/tui/src/bridge/inboundAttachments.ts +3 -3
  127. package/tui/src/cli/handlers/auth.ts +3 -12
  128. package/tui/src/cli/handlers/mcp.tsx +0 -1
  129. package/tui/src/cli/print.ts +8 -9
  130. package/tui/src/commands/insights.ts +1 -1
  131. package/tui/src/commands/install-github-app/types.ts +8 -30
  132. package/tui/src/commands/plugin/types.ts +6 -28
  133. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  134. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  135. package/tui/src/components/Feedback.tsx +1 -1
  136. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  137. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  138. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  139. package/tui/src/components/Spinner/types.ts +6 -28
  140. package/tui/src/components/agents/generateAgent.ts +1 -1
  141. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  142. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  143. package/tui/src/components/mcp/types.ts +16 -38
  144. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  145. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  146. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  147. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  148. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  149. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  150. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  151. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  152. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  153. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  154. package/tui/src/components/primitive/index.tsx +43 -1
  155. package/tui/src/components/primitive/types.ts +137 -0
  156. package/tui/src/components/ui/option.ts +4 -26
  157. package/tui/src/constants/common.ts +0 -2
  158. package/tui/src/constants/prompts.ts +4 -3
  159. package/tui/src/constants/querySource.ts +4 -26
  160. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  161. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  162. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  163. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  164. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  165. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  166. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  167. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  168. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  169. package/tui/src/ink/ink.tsx +33 -14
  170. package/tui/src/ink/reconciler.ts +2 -3
  171. package/tui/src/ink/render-to-screen.ts +30 -10
  172. package/tui/src/ipc/bridge.ts +62 -15
  173. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  174. package/tui/src/ipc/codec.ts +3 -3
  175. package/tui/src/ipc/frames.generated.ts +12 -12
  176. package/tui/src/ipc/llmClient.ts +151 -27
  177. package/tui/src/ipc/schema/frame.schema.json +1 -1
  178. package/tui/src/keybindings/defaultBindings.ts +4 -0
  179. package/tui/src/main.tsx +32 -15
  180. package/tui/src/native-ts/file-index/index.ts +33 -3
  181. package/tui/src/observability/surface.ts +2 -2
  182. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  183. package/tui/src/projectOnboardingState.ts +7 -6
  184. package/tui/src/query/chatMessageTypes.ts +18 -0
  185. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  186. package/tui/src/query/deps.ts +1 -1
  187. package/tui/src/query/messageGuards.ts +106 -0
  188. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  189. package/tui/src/query/run.ts +1075 -0
  190. package/tui/src/query/supportBoundary.ts +168 -0
  191. package/tui/src/query/toolResultErrors.ts +103 -0
  192. package/tui/src/query/toolRunner.ts +687 -0
  193. package/tui/src/query/unavailableToolRepair.ts +118 -0
  194. package/tui/src/query.ts +9 -2186
  195. package/tui/src/screens/REPL.tsx +40 -29
  196. package/tui/src/services/api/adapterManifest.ts +4 -0
  197. package/tui/src/services/api/backendChat/events.ts +117 -0
  198. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  199. package/tui/src/services/api/backendChat/frame.ts +9 -0
  200. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  201. package/tui/src/services/api/backendChat/types.ts +62 -0
  202. package/tui/src/services/api/backendChat.ts +1 -0
  203. package/tui/src/services/api/client.ts +65 -2
  204. package/tui/src/services/api/errorUtils.ts +5 -5
  205. package/tui/src/services/api/errors.ts +1 -1
  206. package/tui/src/services/api/logging.ts +1 -1
  207. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  208. package/tui/src/services/api/ummaya/messages.ts +255 -0
  209. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  210. package/tui/src/services/api/ummaya/provider.ts +200 -0
  211. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  212. package/tui/src/services/api/ummaya/request.ts +200 -0
  213. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  214. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  215. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  216. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  217. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  218. package/tui/src/services/api/ummaya/types.ts +110 -0
  219. package/tui/src/services/api/ummaya/usage.ts +30 -0
  220. package/tui/src/services/api/ummaya.ts +26 -418
  221. package/tui/src/services/api/withRetry.ts +1 -1
  222. package/tui/src/services/awaySummary.ts +2 -2
  223. package/tui/src/services/claudeAiLimits.ts +1 -1
  224. package/tui/src/services/compact/autoCompact.ts +1 -1
  225. package/tui/src/services/compact/compact.ts +1 -1
  226. package/tui/src/services/lsp/types.ts +8 -30
  227. package/tui/src/services/tips/types.ts +6 -28
  228. package/tui/src/services/tokenEstimation.ts +1 -1
  229. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  230. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  231. package/tui/src/services/tools/toolExecution.ts +94 -1
  232. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  233. package/tui/src/store/session-store.ts +10 -36
  234. package/tui/src/stubs/any-stub.ts +15 -10
  235. package/tui/src/stubs/color-diff-napi.ts +37 -23
  236. package/tui/src/stubs/globals.d.ts +3 -3
  237. package/tui/src/stubs/macro-preload.ts +23 -12
  238. package/tui/src/tools/AdapterTool/AdapterTool.ts +1207 -714
  239. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  240. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  241. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  242. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  243. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  244. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  245. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  246. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  247. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  248. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  249. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  250. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  251. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  252. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  253. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  254. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  255. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  256. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  257. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  258. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  259. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  260. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  261. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  262. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  263. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  264. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  265. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  266. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  267. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  268. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  269. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  270. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  271. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  272. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  273. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  274. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  275. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  276. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  277. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  278. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  279. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  280. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  281. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  282. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  283. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  284. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  285. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  286. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  287. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  288. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  289. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  290. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  291. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  292. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  293. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  294. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  295. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  296. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  297. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  298. package/tui/src/tools/BashTool/call.ts +202 -0
  299. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  300. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  301. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  302. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  303. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  304. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  305. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  306. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  307. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  308. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  309. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  310. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  311. package/tui/src/tools/BashTool/schemas.ts +65 -0
  312. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  313. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  314. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  315. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  316. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  317. package/tui/src/tools/BriefTool/upload.ts +1 -1
  318. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  319. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  320. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  321. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  322. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  323. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  324. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  325. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  326. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  327. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  328. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  329. package/tui/src/tools/FileEditTool/call.ts +228 -0
  330. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  331. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  332. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  333. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  334. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  335. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  336. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +25 -32
  337. package/tui/src/tools/LookupPrimitive/prompt.ts +0 -2
  338. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  339. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  340. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  341. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  342. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  343. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  344. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  345. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  346. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  347. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  348. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  349. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  350. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  351. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  352. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  353. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  354. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  355. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  356. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  357. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  358. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  359. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  360. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +1 -11
  361. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  362. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  363. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +27 -10
  364. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  365. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  366. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  367. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  368. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  369. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  370. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  371. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  372. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  373. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  374. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  375. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  376. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  377. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  378. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  379. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  380. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  381. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  382. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  383. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  384. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  385. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  386. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  387. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  388. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  389. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +2 -1
  390. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  391. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  392. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  393. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  394. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  395. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  396. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  397. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  398. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  399. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  400. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  401. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  402. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  403. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  404. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  405. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  406. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  407. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  408. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  409. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  410. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  411. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  412. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  413. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  414. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  415. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  416. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  417. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  418. package/tui/src/tools/_shared/rootPrimitiveInput.ts +1 -0
  419. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  420. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  421. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  422. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  423. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  424. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  425. package/tui/src/tools/_shared/toolChoiceRepair.ts +55 -860
  426. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  427. package/tui/src/tools.ts +39 -190
  428. package/tui/src/types/fileSuggestion.ts +4 -26
  429. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  430. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  431. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  432. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  433. package/tui/src/types/message.ts +80 -102
  434. package/tui/src/types/messageQueueTypes.ts +6 -28
  435. package/tui/src/types/notebook.ts +16 -38
  436. package/tui/src/types/statusLine.ts +4 -26
  437. package/tui/src/types/tools.ts +24 -46
  438. package/tui/src/types/utils.ts +6 -28
  439. package/tui/src/upstreamproxy/relay.ts +7 -3
  440. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  441. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  442. package/tui/src/utils/auth.ts +129 -139
  443. package/tui/src/utils/bash/ast.ts +23 -23
  444. package/tui/src/utils/bash/bashParser.ts +5 -5
  445. package/tui/src/utils/billing.ts +1 -1
  446. package/tui/src/utils/claudeDesktop.ts +4 -4
  447. package/tui/src/utils/collapseReadSearch.ts +3 -3
  448. package/tui/src/utils/cronTasks.ts +1 -1
  449. package/tui/src/utils/execFileNoThrow.ts +1 -1
  450. package/tui/src/utils/filePersistence/types.ts +16 -38
  451. package/tui/src/utils/forkedAgent.ts +1 -1
  452. package/tui/src/utils/gracefulShutdown.ts +4 -4
  453. package/tui/src/utils/heapDumpService.ts +12 -8
  454. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  455. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  456. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  457. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  458. package/tui/src/utils/messages.ts +18 -0
  459. package/tui/src/utils/migrateSessions.ts +3 -3
  460. package/tui/src/utils/model/model.ts +6 -6
  461. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  462. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  463. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  464. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  465. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  466. package/tui/src/utils/protectedNamespace.ts +5 -3
  467. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  468. package/tui/src/utils/ripgrep.ts +16 -7
  469. package/tui/src/utils/sessionTitle.ts +1 -1
  470. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  471. package/tui/src/utils/shell/prefix.ts +1 -1
  472. package/tui/src/utils/sideQuery.ts +1 -1
  473. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  474. package/tui/src/utils/teleport.tsx +1 -1
  475. package/uv.lock +426 -45
  476. package/tui/src/services/api/claude.ts +0 -3540
  477. package/tui/src/tools/_shared/directPublicDataGuard.ts +0 -362
  478. package/tui/src/tools/_shared/kmaAnalysisGuard.ts +0 -197
  479. package/tui/src/tools/_shared/kmaAviationGuard.ts +0 -70
  480. package/tui/src/tools/_shared/nmcAedGuard.ts +0 -234
  481. package/tui/src/tools/_shared/protectedCheckGuard.ts +0 -207
  482. package/tui/src/tools/_shared/textToolCallGuard.ts +0 -91
@@ -0,0 +1,283 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from enum import StrEnum
7
+ from hashlib import sha256
8
+ from typing import Final, assert_never
9
+
10
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer, model_validator
11
+
12
+ from ummaya.tools.documents.models import DocumentToolResult, ToolResultStatus
13
+
14
+ _SHA256_PATTERN: Final[str] = r"^[a-f0-9]{64}$"
15
+ _REDACTED_DOCUMENT_CONTENT: Final[str] = "[redacted-document-content]"
16
+ _RAW_DOCUMENT_MARKERS: Final[tuple[str, ...]] = (
17
+ "%pdf",
18
+ "raw document bytes",
19
+ "/users/",
20
+ "\\users\\",
21
+ )
22
+ _COMMON_PII_PATTERNS: Final[tuple[tuple[re.Pattern[str], str], ...]] = (
23
+ (re.compile(r"\b\d{6}-\d{7}\b"), "[redacted-rrn]"),
24
+ (re.compile(r"\b01[016789]-\d{3,4}-\d{4}\b"), "[redacted-phone]"),
25
+ (re.compile(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"), "[redacted-email]"),
26
+ )
27
+
28
+
29
+ class StrictAuthoringModel(BaseModel):
30
+ model_config = ConfigDict(frozen=True, extra="forbid", strict=True)
31
+
32
+
33
+ class EvidenceSourceKind(StrEnum):
34
+ user_provided = "user_provided"
35
+ document_derived = "document_derived"
36
+ policy_derived = "policy_derived"
37
+
38
+
39
+ class ApprovalDecisionKind(StrEnum):
40
+ approved = "approved"
41
+ edited = "edited"
42
+ leave_blank = "leave_blank"
43
+ cancel = "cancel"
44
+
45
+
46
+ class AuthoringState(StrEnum):
47
+ needs_input = "needs_input"
48
+ draft_ready_for_approval = "draft_ready_for_approval"
49
+ approved_for_mutation = "approved_for_mutation"
50
+ blocked_missing_evidence = "blocked_missing_evidence"
51
+
52
+
53
+ class AmbiguityClassification(StrEnum):
54
+ blocking = "blocking"
55
+ non_blocking_engineering = "non_blocking_engineering"
56
+
57
+
58
+ class AuthoringEvidenceItem(StrictAuthoringModel):
59
+ evidence_id: str = Field(min_length=1)
60
+ source_kind: EvidenceSourceKind
61
+ summary: str = Field(min_length=1, max_length=1200)
62
+ source_ref: str | None = Field(default=None, min_length=1, max_length=300)
63
+ redacted_excerpt: str | None = Field(default=None, min_length=1, max_length=2000)
64
+
65
+ @field_serializer("summary", "source_ref", "redacted_excerpt", when_used="json")
66
+ def _serialize_redacted_text(self, value: str | None) -> str | None:
67
+ if value is None:
68
+ return None
69
+ return redact_authoring_text(value)
70
+
71
+
72
+ class SocraticQuestion(StrictAuthoringModel):
73
+ question_id: str = Field(min_length=1)
74
+ target_id: str = Field(min_length=1)
75
+ prompt: str = Field(min_length=1, max_length=800)
76
+ required: bool
77
+
78
+
79
+ class UserAnswer(StrictAuthoringModel):
80
+ answer_id: str = Field(min_length=1)
81
+ question_id: str = Field(min_length=1)
82
+ response_summary: str = Field(min_length=1, max_length=1200)
83
+ evidence_refs: tuple[str, ...] = Field(min_length=1)
84
+
85
+ @field_serializer("response_summary", when_used="json")
86
+ def _serialize_response_summary(self, value: str) -> str:
87
+ return redact_authoring_text(value)
88
+
89
+
90
+ class DraftClaim(StrictAuthoringModel):
91
+ claim_id: str = Field(min_length=1)
92
+ text: str = Field(min_length=1, max_length=2000)
93
+ evidence_refs: tuple[str, ...] = Field(min_length=1)
94
+
95
+ @field_serializer("text", when_used="json")
96
+ def _serialize_text(self, value: str) -> str:
97
+ return redact_authoring_text(value)
98
+
99
+
100
+ class DraftCandidate(StrictAuthoringModel):
101
+ draft_id: str = Field(min_length=1)
102
+ target_id: str = Field(min_length=1)
103
+ draft_text: str = Field(min_length=1, max_length=8000)
104
+ draft_sha256: str = Field(pattern=_SHA256_PATTERN)
105
+ claims: tuple[DraftClaim, ...] = Field(min_length=1)
106
+ evidence_items: tuple[AuthoringEvidenceItem, ...] = ()
107
+
108
+ @field_serializer("draft_text", when_used="json")
109
+ def _serialize_draft_text(self, value: str) -> str:
110
+ return redact_authoring_text(value)
111
+
112
+ @model_validator(mode="after")
113
+ def _validate_draft_hash_and_claim_refs(self) -> DraftCandidate:
114
+ if self.draft_sha256 != hash_authoring_text(self.draft_text):
115
+ raise ValueError("draft_sha256 must match draft_text")
116
+ if self.evidence_items:
117
+ _require_known_evidence_refs(self.claims, self.evidence_items)
118
+ return self
119
+
120
+
121
+ class ApprovalDecision(StrictAuthoringModel):
122
+ approval_id: str = Field(min_length=1)
123
+ draft_id: str = Field(min_length=1)
124
+ decision: ApprovalDecisionKind
125
+ draft_sha256: str = Field(pattern=_SHA256_PATTERN)
126
+ approved_text_sha256: str | None = Field(default=None, pattern=_SHA256_PATTERN)
127
+
128
+ @model_validator(mode="after")
129
+ def _validate_approved_text_hash(self) -> ApprovalDecision:
130
+ match self.decision:
131
+ case ApprovalDecisionKind.approved | ApprovalDecisionKind.edited:
132
+ if self.approved_text_sha256 is None:
133
+ raise ValueError("approved decisions require approved_text_sha256")
134
+ case ApprovalDecisionKind.leave_blank | ApprovalDecisionKind.cancel:
135
+ if self.approved_text_sha256 is not None:
136
+ raise ValueError("blank or cancel decisions cannot carry approved_text_sha256")
137
+ case unreachable:
138
+ assert_never(unreachable)
139
+ return self
140
+
141
+
142
+ class AmbiguityRecord(StrictAuthoringModel):
143
+ ambiguity_id: str = Field(min_length=1)
144
+ classification: AmbiguityClassification
145
+ evidence_path: str | None = Field(default=None, min_length=1)
146
+ reviewer_verdict_id: str | None = Field(default=None, min_length=1)
147
+ required_next_question: str | None = Field(default=None, min_length=1, max_length=800)
148
+
149
+ @field_serializer("evidence_path", "required_next_question", when_used="json")
150
+ def _serialize_redacted_metadata(self, value: str | None) -> str | None:
151
+ if value is None:
152
+ return None
153
+ return redact_authoring_text(value)
154
+
155
+
156
+ class AuthoringClosureVerdict(StrictAuthoringModel):
157
+ state: AuthoringState
158
+ target_id: str = Field(min_length=1)
159
+ evidence_items: tuple[AuthoringEvidenceItem, ...] = ()
160
+ questions: tuple[SocraticQuestion, ...] = ()
161
+ answers: tuple[UserAnswer, ...] = ()
162
+ draft: DraftCandidate | None = None
163
+ approval: ApprovalDecision | None = None
164
+ ambiguities: tuple[AmbiguityRecord, ...] = ()
165
+
166
+ @model_validator(mode="after")
167
+ def _validate_state_contract(self) -> AuthoringClosureVerdict:
168
+ _validate_answer_refs(self.answers, self.questions, self.evidence_items)
169
+ if self.draft is not None:
170
+ _require_known_evidence_refs(self.draft.claims, self.evidence_items)
171
+ _validate_closure_state(self)
172
+ return self
173
+
174
+
175
+ class DocumentAuthoringResult(DocumentToolResult):
176
+ authoring: AuthoringClosureVerdict
177
+
178
+ @model_validator(mode="after")
179
+ def _validate_authoring_status(self) -> DocumentAuthoringResult:
180
+ match self.authoring.state:
181
+ case AuthoringState.needs_input | AuthoringState.draft_ready_for_approval:
182
+ if self.status is not ToolResultStatus.needs_input:
183
+ raise ValueError(
184
+ f"{self.authoring.state.value} authoring results require status needs_input"
185
+ )
186
+ case AuthoringState.approved_for_mutation:
187
+ if self.status is not ToolResultStatus.ok:
188
+ raise ValueError("approved_for_mutation authoring results require status ok")
189
+ case AuthoringState.blocked_missing_evidence:
190
+ if self.status is not ToolResultStatus.blocked:
191
+ raise ValueError(
192
+ "blocked_missing_evidence authoring results require status blocked"
193
+ )
194
+ case unreachable:
195
+ assert_never(unreachable)
196
+ return self
197
+
198
+
199
+ def hash_authoring_text(value: str) -> str:
200
+ return sha256(value.encode("utf-8")).hexdigest()
201
+
202
+
203
+ def redact_authoring_text(value: str) -> str:
204
+ lowered = value.lower()
205
+ if any(marker in lowered for marker in _RAW_DOCUMENT_MARKERS):
206
+ return _REDACTED_DOCUMENT_CONTENT
207
+ redacted = value
208
+ for pattern, replacement in _COMMON_PII_PATTERNS:
209
+ redacted = pattern.sub(replacement, redacted)
210
+ return redacted
211
+
212
+
213
+ def _require_known_evidence_refs(
214
+ claims: tuple[DraftClaim, ...],
215
+ evidence_items: tuple[AuthoringEvidenceItem, ...],
216
+ ) -> None:
217
+ known_ids = {item.evidence_id for item in evidence_items}
218
+ for claim in claims:
219
+ unknown_refs = tuple(ref for ref in claim.evidence_refs if ref not in known_ids)
220
+ if unknown_refs:
221
+ raise ValueError(f"unknown evidence reference: {unknown_refs[0]}")
222
+
223
+
224
+ def _validate_answer_refs(
225
+ answers: tuple[UserAnswer, ...],
226
+ questions: tuple[SocraticQuestion, ...],
227
+ evidence_items: tuple[AuthoringEvidenceItem, ...],
228
+ ) -> None:
229
+ known_questions = {question.question_id for question in questions}
230
+ known_evidence = {item.evidence_id for item in evidence_items}
231
+ for answer in answers:
232
+ if answer.question_id not in known_questions:
233
+ raise ValueError("answers must reference known questions")
234
+ if known_evidence:
235
+ unknown_refs = tuple(ref for ref in answer.evidence_refs if ref not in known_evidence)
236
+ if unknown_refs:
237
+ raise ValueError(f"unknown answer evidence reference: {unknown_refs[0]}")
238
+
239
+
240
+ def _validate_closure_state(verdict: AuthoringClosureVerdict) -> None:
241
+ match verdict.state:
242
+ case AuthoringState.needs_input | AuthoringState.blocked_missing_evidence:
243
+ _validate_question_waiting_state(verdict)
244
+ case AuthoringState.draft_ready_for_approval:
245
+ _validate_draft_ready_state(verdict)
246
+ case AuthoringState.approved_for_mutation:
247
+ _validate_approved_state(verdict)
248
+ case unreachable:
249
+ assert_never(unreachable)
250
+
251
+
252
+ def _validate_question_waiting_state(verdict: AuthoringClosureVerdict) -> None:
253
+ if not verdict.questions:
254
+ raise ValueError(f"{verdict.state.value} requires questions")
255
+ if verdict.draft is not None:
256
+ raise ValueError(f"{verdict.state.value} cannot carry draft")
257
+ if verdict.approval is not None:
258
+ raise ValueError(f"{verdict.state.value} cannot carry approval")
259
+
260
+
261
+ def _validate_draft_ready_state(verdict: AuthoringClosureVerdict) -> None:
262
+ if verdict.draft is None:
263
+ raise ValueError("draft_ready_for_approval requires draft")
264
+ if verdict.approval is not None:
265
+ raise ValueError("draft_ready_for_approval cannot carry approval")
266
+
267
+
268
+ def _validate_approved_state(verdict: AuthoringClosureVerdict) -> None:
269
+ if verdict.draft is None:
270
+ raise ValueError("approved_for_mutation requires draft")
271
+ if verdict.approval is None:
272
+ raise ValueError("approved_for_mutation requires approval")
273
+ match verdict.approval.decision:
274
+ case ApprovalDecisionKind.approved | ApprovalDecisionKind.edited:
275
+ pass
276
+ case ApprovalDecisionKind.leave_blank | ApprovalDecisionKind.cancel:
277
+ raise ValueError("approved_for_mutation requires an approval decision")
278
+ case unreachable:
279
+ assert_never(unreachable)
280
+ if verdict.approval.draft_id != verdict.draft.draft_id:
281
+ raise ValueError("approval draft_id must match draft")
282
+ if verdict.approval.draft_sha256 != verdict.draft.draft_sha256:
283
+ raise ValueError("approval draft_sha256 must match draft")
@@ -0,0 +1,132 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Public-form conformance baseline models and fixture loader."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from importlib import resources
7
+ from pathlib import Path
8
+ from typing import Literal, cast
9
+
10
+ import yaml
11
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
12
+
13
+ from ummaya.tools.documents.models import DocumentFormat, MetadataValue
14
+
15
+ CONFORMANCE_BASELINE_FIXTURE_PATH = (
16
+ Path(__file__).resolve().parents[4]
17
+ / "tests"
18
+ / "fixtures"
19
+ / "documents"
20
+ / "public_forms"
21
+ / "baselines.yaml"
22
+ )
23
+
24
+
25
+ class BaselineField(BaseModel):
26
+ """Required field declared by a public-form conformance baseline."""
27
+
28
+ model_config = ConfigDict(frozen=True, extra="forbid")
29
+
30
+ field_id: str = Field(min_length=1)
31
+ label: str = Field(min_length=1)
32
+ path: str = Field(min_length=1)
33
+
34
+
35
+ class BaselineTextAnchor(BaseModel):
36
+ """Protected text or label that must remain present at a known anchor."""
37
+
38
+ model_config = ConfigDict(frozen=True, extra="forbid")
39
+
40
+ text: str = Field(min_length=1)
41
+ anchor: str = Field(min_length=1)
42
+
43
+
44
+ class BaselineTableGeometry(BaseModel):
45
+ """Expected row and column geometry for a protected public-form table."""
46
+
47
+ model_config = ConfigDict(frozen=True, extra="forbid")
48
+
49
+ table_id: str = Field(min_length=1)
50
+ anchor: str = Field(min_length=1)
51
+ rows: int = Field(ge=1)
52
+ columns: int = Field(ge=1)
53
+
54
+
55
+ class ConformanceBaseline(BaseModel):
56
+ """Format-specific public-form conformance rule set."""
57
+
58
+ model_config = ConfigDict(frozen=True, extra="forbid")
59
+
60
+ template_id: str = Field(min_length=1)
61
+ schema_id: str = Field(min_length=1)
62
+ format: DocumentFormat
63
+ authoritative_standard: str = Field(min_length=1)
64
+ authority_refs: tuple[str, ...] = Field(min_length=1)
65
+ supports_conformance: bool
66
+ unsupported_reason: str | None = None
67
+ expected_page_count: int | None = Field(default=None, ge=1)
68
+ required_fields: tuple[BaselineField, ...] = ()
69
+ protected_text: tuple[BaselineTextAnchor, ...] = ()
70
+ required_labels: tuple[BaselineTextAnchor, ...] = ()
71
+ table_geometries: tuple[BaselineTableGeometry, ...] = ()
72
+ signature_regions: tuple[BaselineTextAnchor, ...] = ()
73
+ metadata_exact_matches: dict[str, MetadataValue] = Field(default_factory=dict)
74
+
75
+ @model_validator(mode="after")
76
+ def _enforce_unsupported_reason(self) -> ConformanceBaseline:
77
+ if not self.supports_conformance and not self.unsupported_reason:
78
+ raise ValueError("unsupported conformance baselines require unsupported_reason")
79
+ return self
80
+
81
+
82
+ class ConformanceBaselineCatalog(BaseModel):
83
+ """Offline catalog of public-form conformance baselines."""
84
+
85
+ model_config = ConfigDict(frozen=True, extra="forbid")
86
+
87
+ version: Literal[1]
88
+ catalog_id: str = Field(min_length=1)
89
+ source_policy: Literal["offline_fixtures_only"]
90
+ live_network_allowed: Literal[False]
91
+ baselines: tuple[ConformanceBaseline, ...] = Field(min_length=1)
92
+
93
+ @model_validator(mode="after")
94
+ def _require_unique_template_ids(self) -> ConformanceBaselineCatalog:
95
+ template_ids = [baseline.template_id for baseline in self.baselines]
96
+ if len(set(template_ids)) != len(template_ids):
97
+ raise ValueError("template_id values must be unique")
98
+ return self
99
+
100
+ def by_template_id(self, template_id: str) -> ConformanceBaseline:
101
+ """Return one baseline by stable template ID."""
102
+ for baseline in self.baselines:
103
+ if baseline.template_id == template_id:
104
+ return baseline
105
+ raise KeyError(f"Unknown public-form conformance baseline: {template_id}")
106
+
107
+
108
+ def load_conformance_baselines(
109
+ path: Path = CONFORMANCE_BASELINE_FIXTURE_PATH,
110
+ ) -> ConformanceBaselineCatalog:
111
+ """Load checked-in public-form conformance baselines from YAML."""
112
+ raw = yaml.safe_load(_read_conformance_baseline_text(path))
113
+ if not isinstance(raw, dict):
114
+ raise ValueError(f"Conformance baseline manifest must be a YAML object: {path}")
115
+ return ConformanceBaselineCatalog.model_validate(cast(dict[str, object], raw))
116
+
117
+
118
+ def _read_conformance_baseline_text(path: Path) -> str:
119
+ if path.is_file():
120
+ return path.read_text(encoding="utf-8")
121
+
122
+ try:
123
+ bundled = resources.files("ummaya._canonical").joinpath("baselines.yaml")
124
+ with resources.as_file(bundled) as resource_path:
125
+ if Path(resource_path).is_file():
126
+ return Path(resource_path).read_text(encoding="utf-8")
127
+ except (FileNotFoundError, ModuleNotFoundError, AttributeError):
128
+ pass
129
+
130
+ raise FileNotFoundError(
131
+ f"Conformance baseline manifest not found in source tree or bundled wheel resource: {path}"
132
+ )