ummaya 0.2.4 → 0.2.5

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