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,435 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """ODF document engines backed by odfdo.
3
+
4
+ These engines intentionally cover bounded public-form operations first:
5
+ paragraph values in ODT, sheet cells in ODS, and text frames in ODP. Full layout
6
+ oracle rendering remains a separate LibreOffice bridge gate.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import html
12
+ import re
13
+ from collections.abc import Sequence
14
+ from io import BytesIO
15
+ from pathlib import Path
16
+ from typing import NoReturn, Protocol, cast
17
+
18
+ from odfdo import Document as OdfDocument
19
+
20
+ from ummaya.tools.documents.engines import DocumentMutationBlockedError
21
+ from ummaya.tools.documents.models import (
22
+ BlockedReason,
23
+ DocumentExtraction,
24
+ DocumentFormat,
25
+ DocumentPatch,
26
+ DocumentPatchOperation,
27
+ KnownDocumentFormat,
28
+ MetadataValue,
29
+ OperationType,
30
+ ParagraphBlock,
31
+ TableBlock,
32
+ TableCell,
33
+ )
34
+ from ummaya.tools.documents.tool_defs import DocumentFieldPatch
35
+
36
+ _ODT_PARAGRAPH_RE = re.compile(r"^/odf/text/p\[(?P<index>[1-9][0-9]*)]$")
37
+ _ODS_CELL_RE = re.compile(r"^/odf/sheets/(?P<sheet>[^/]+)/cells/(?P<cell>[A-Z]{1,3}[1-9][0-9]*)$")
38
+ _ODP_FRAME_RE = re.compile(r"^/odf/slides/(?P<slide>[1-9][0-9]*)/frames/(?P<index>[1-9][0-9]*)$")
39
+
40
+
41
+ class _OdfDocument(Protocol):
42
+ @property
43
+ def body(self) -> object:
44
+ """Return the odfdo document body."""
45
+
46
+ def save(self, target: BytesIO | Path, *, pretty: bool = False) -> None:
47
+ """Save the document to bytes or a filesystem path."""
48
+
49
+
50
+ class _OdfParagraph(Protocol):
51
+ @property
52
+ def text(self) -> str:
53
+ """Return paragraph text."""
54
+
55
+ @text.setter
56
+ def text(self, value: str) -> None:
57
+ """Set paragraph text."""
58
+
59
+
60
+ class _OdfCell(Protocol):
61
+ @property
62
+ def value(self) -> object:
63
+ """Return cell value."""
64
+
65
+
66
+ class _OdfTable(Protocol):
67
+ @property
68
+ def name(self) -> str | None:
69
+ """Return table name."""
70
+
71
+ def get_cells(self) -> Sequence[Sequence[_OdfCell]]:
72
+ """Return table cells."""
73
+
74
+
75
+ class _OdfTablesBody(Protocol):
76
+ def get_tables(self) -> Sequence[_OdfTable]:
77
+ """Return body tables."""
78
+
79
+
80
+ class _OdfTextBody(_OdfTablesBody, Protocol):
81
+ def get_paragraphs(self) -> Sequence[object]:
82
+ """Return text paragraphs."""
83
+
84
+ def get_paragraph(self, *, position: int) -> _OdfParagraph:
85
+ """Return one text paragraph."""
86
+
87
+
88
+ class _OdfSheet(Protocol):
89
+ def set_value(self, address: str, value: str) -> None:
90
+ """Set one sheet cell value."""
91
+
92
+
93
+ class _OdfSpreadsheetBody(_OdfTablesBody, Protocol):
94
+ def get_sheet(self, *, name: str) -> _OdfSheet:
95
+ """Return one sheet by name."""
96
+
97
+
98
+ class _OdfFrame(Protocol):
99
+ def set_text_box(self, value: str) -> None:
100
+ """Set frame text box content."""
101
+
102
+
103
+ class _OdfPresentationBody(Protocol):
104
+ def get_frames(self) -> Sequence[_OdfFrame]:
105
+ """Return presentation text frames."""
106
+
107
+
108
+ class OdfdoTextDocumentEngine:
109
+ """Bounded ODT text document engine."""
110
+
111
+ document_format = DocumentFormat.odt
112
+ engine_id = "odfdo-odt"
113
+ render_engine_id = "odfdo-structural-svg"
114
+ render_artifact_extension = "svg"
115
+ render_mime_type = "image/svg+xml"
116
+
117
+ def inspect(self, path: Path, *, artifact_id: str) -> DocumentExtraction:
118
+ """Extract ODT paragraphs and tables into DocumentIR blocks."""
119
+ document = cast(_OdfDocument, OdfDocument(path))
120
+ body = cast(_OdfTextBody, document.body)
121
+ paragraphs = [
122
+ ParagraphBlock(
123
+ block_id=f"odt-p-{index}",
124
+ text=str(paragraph).strip(),
125
+ source_path=f"/odf/text/p[{index}]",
126
+ )
127
+ for index, paragraph in enumerate(body.get_paragraphs(), start=1)
128
+ if str(paragraph).strip()
129
+ ]
130
+ tables = _tables_from_body(body, artifact_prefix="odt")
131
+ return DocumentExtraction(
132
+ artifact_id=artifact_id,
133
+ paragraphs=paragraphs,
134
+ tables=tables,
135
+ metadata=_metadata(path, document_format=DocumentFormat.odt),
136
+ )
137
+
138
+ def apply_patch(self, path: Path, patch: DocumentPatch) -> bytes:
139
+ """Apply bounded paragraph mutations and return derivative ODT bytes."""
140
+ document = cast(_OdfDocument, OdfDocument(path))
141
+ for operation in patch.operations:
142
+ _apply_odt_operation(document, operation)
143
+ return _save_odf_document(document)
144
+
145
+ def render(self, path: Path, *, artifact_id: str, output_dir: Path) -> tuple[bytes, ...]:
146
+ """Render a reviewer-readable structural SVG page."""
147
+ _ = output_dir
148
+ extraction = self.inspect(path, artifact_id=artifact_id)
149
+ lines = [paragraph.text for paragraph in extraction.paragraphs]
150
+ for table in extraction.tables:
151
+ lines.extend(cell.text for cell in table.cells if cell.text)
152
+ return (_render_lines_svg(lines, title="ODT document"),)
153
+
154
+
155
+ class OdfdoSpreadsheetDocumentEngine:
156
+ """Bounded ODS spreadsheet engine."""
157
+
158
+ document_format = DocumentFormat.ods
159
+ engine_id = "odfdo-ods"
160
+ render_engine_id = "odfdo-structural-svg"
161
+ render_artifact_extension = "svg"
162
+ render_mime_type = "image/svg+xml"
163
+
164
+ def inspect(self, path: Path, *, artifact_id: str) -> DocumentExtraction:
165
+ """Extract ODS sheet cells into table blocks."""
166
+ document = cast(_OdfDocument, OdfDocument(path))
167
+ tables = _tables_from_body(document.body, artifact_prefix="ods")
168
+ return DocumentExtraction(
169
+ artifact_id=artifact_id,
170
+ tables=tables,
171
+ metadata=_metadata(path, document_format=DocumentFormat.ods),
172
+ )
173
+
174
+ def apply_patch(self, path: Path, patch: DocumentPatch) -> bytes:
175
+ """Apply bounded sheet cell mutations and return derivative ODS bytes."""
176
+ document = cast(_OdfDocument, OdfDocument(path))
177
+ for operation in patch.operations:
178
+ _apply_ods_operation(document, operation)
179
+ return _save_odf_document(document)
180
+
181
+ def render(self, path: Path, *, artifact_id: str, output_dir: Path) -> tuple[bytes, ...]:
182
+ """Render reviewer-readable sheet cells as structural SVG."""
183
+ _ = output_dir
184
+ extraction = self.inspect(path, artifact_id=artifact_id)
185
+ lines = [
186
+ f"{cell.source_path}: {cell.text}"
187
+ for table in extraction.tables
188
+ for cell in table.cells
189
+ if cell.text
190
+ ]
191
+ return (_render_lines_svg(lines, title="ODS spreadsheet"),)
192
+
193
+
194
+ class OdfdoPresentationDocumentEngine:
195
+ """Bounded ODP presentation engine."""
196
+
197
+ document_format = DocumentFormat.odp
198
+ engine_id = "odfdo-odp"
199
+ render_engine_id = "odfdo-structural-svg"
200
+ render_artifact_extension = "svg"
201
+ render_mime_type = "image/svg+xml"
202
+
203
+ def inspect(self, path: Path, *, artifact_id: str) -> DocumentExtraction:
204
+ """Extract ODP text frames into paragraph blocks."""
205
+ document = cast(_OdfDocument, OdfDocument(path))
206
+ body = cast(_OdfPresentationBody, document.body)
207
+ paragraphs = [
208
+ ParagraphBlock(
209
+ block_id=f"odp-frame-{index}",
210
+ text=str(frame).strip(),
211
+ source_path=f"/odf/slides/1/frames/{index}",
212
+ )
213
+ for index, frame in enumerate(body.get_frames(), start=1)
214
+ if str(frame).strip()
215
+ ]
216
+ return DocumentExtraction(
217
+ artifact_id=artifact_id,
218
+ paragraphs=paragraphs,
219
+ metadata=_metadata(path, document_format=DocumentFormat.odp),
220
+ )
221
+
222
+ def apply_patch(self, path: Path, patch: DocumentPatch) -> bytes:
223
+ """Apply bounded text-frame mutations and return derivative ODP bytes."""
224
+ document = cast(_OdfDocument, OdfDocument(path))
225
+ for operation in patch.operations:
226
+ _apply_odp_operation(document, operation)
227
+ return _save_odf_document(document)
228
+
229
+ def render(self, path: Path, *, artifact_id: str, output_dir: Path) -> tuple[bytes, ...]:
230
+ """Render reviewer-readable slide text as structural SVG."""
231
+ _ = output_dir
232
+ extraction = self.inspect(path, artifact_id=artifact_id)
233
+ lines = [paragraph.text for paragraph in extraction.paragraphs]
234
+ return (_render_lines_svg(lines, title="ODP presentation"),)
235
+
236
+
237
+ type _OdfEngine = (
238
+ OdfdoTextDocumentEngine | OdfdoSpreadsheetDocumentEngine | OdfdoPresentationDocumentEngine
239
+ )
240
+
241
+
242
+ class OdfdoDocumentAdapter:
243
+ """Format adapter for promoted odfdo-backed ODF engines."""
244
+
245
+ adapter_id = "odfdo-document-adapter"
246
+ known_formats: tuple[KnownDocumentFormat, ...] = (
247
+ KnownDocumentFormat.odt,
248
+ KnownDocumentFormat.ods,
249
+ KnownDocumentFormat.odp,
250
+ )
251
+ promoted_formats: tuple[DocumentFormat, ...] = (
252
+ DocumentFormat.odt,
253
+ DocumentFormat.ods,
254
+ DocumentFormat.odp,
255
+ )
256
+
257
+ def __init__(
258
+ self,
259
+ *,
260
+ text_engine: OdfdoTextDocumentEngine | None = None,
261
+ spreadsheet_engine: OdfdoSpreadsheetDocumentEngine | None = None,
262
+ presentation_engine: OdfdoPresentationDocumentEngine | None = None,
263
+ ) -> None:
264
+ self._engines: dict[DocumentFormat, _OdfEngine] = {
265
+ DocumentFormat.odt: text_engine or OdfdoTextDocumentEngine(),
266
+ DocumentFormat.ods: spreadsheet_engine or OdfdoSpreadsheetDocumentEngine(),
267
+ DocumentFormat.odp: presentation_engine or OdfdoPresentationDocumentEngine(),
268
+ }
269
+
270
+ def inspect(self, path: Path, *, artifact_id: str) -> DocumentExtraction:
271
+ """Inspect an ODF package with the engine that matches the file suffix."""
272
+ return self._engine_for_path(path).inspect(path, artifact_id=artifact_id)
273
+
274
+ def normalize_fill_patches(
275
+ self,
276
+ patches: tuple[DocumentFieldPatch, ...],
277
+ *,
278
+ extraction: DocumentExtraction | None,
279
+ ) -> tuple[DocumentFieldPatch, ...]:
280
+ """Return ODF patches unchanged; native paths are already stable."""
281
+ _ = extraction
282
+ return patches
283
+
284
+ def _engine_for_path(
285
+ self,
286
+ path: Path,
287
+ ) -> _OdfEngine:
288
+ try:
289
+ document_format = DocumentFormat(path.suffix.lower().lstrip("."))
290
+ except ValueError as exc:
291
+ raise DocumentMutationBlockedError(
292
+ BlockedReason.unsupported_format,
293
+ f"Unsupported ODF suffix: {path.suffix}",
294
+ ) from exc
295
+ engine = self._engines.get(document_format)
296
+ if engine is None:
297
+ raise DocumentMutationBlockedError(
298
+ BlockedReason.unsupported_format,
299
+ f"Unsupported ODF suffix: {path.suffix}",
300
+ )
301
+ return engine
302
+
303
+
304
+ def _apply_odt_operation(document: _OdfDocument, operation: DocumentPatchOperation) -> None:
305
+ if operation.operation_type not in {OperationType.replace_text, OperationType.set_field_value}:
306
+ _raise_unsupported_operation(operation)
307
+ match = _ODT_PARAGRAPH_RE.fullmatch(operation.target_path)
308
+ if match is None:
309
+ _raise_unsupported_operation(operation)
310
+ body = cast(_OdfTextBody, document.body)
311
+ paragraph = body.get_paragraph(position=int(match.group("index")) - 1)
312
+ paragraph.text = _string_value(operation)
313
+
314
+
315
+ def _apply_ods_operation(document: _OdfDocument, operation: DocumentPatchOperation) -> None:
316
+ if operation.operation_type not in {
317
+ OperationType.set_table_cell,
318
+ OperationType.set_field_value,
319
+ }:
320
+ _raise_unsupported_operation(operation)
321
+ match = _ODS_CELL_RE.fullmatch(operation.target_path)
322
+ if match is None:
323
+ _raise_unsupported_operation(operation)
324
+ body = cast(_OdfSpreadsheetBody, document.body)
325
+ sheet = body.get_sheet(name=match.group("sheet"))
326
+ sheet.set_value(match.group("cell"), _string_value(operation))
327
+
328
+
329
+ def _apply_odp_operation(document: _OdfDocument, operation: DocumentPatchOperation) -> None:
330
+ if operation.operation_type not in {OperationType.replace_text, OperationType.set_field_value}:
331
+ _raise_unsupported_operation(operation)
332
+ match = _ODP_FRAME_RE.fullmatch(operation.target_path)
333
+ if match is None:
334
+ _raise_unsupported_operation(operation)
335
+ body = cast(_OdfPresentationBody, document.body)
336
+ frames = body.get_frames()
337
+ frame_index = int(match.group("index")) - 1
338
+ if frame_index >= len(frames):
339
+ _raise_unsupported_operation(operation)
340
+ frames[frame_index].set_text_box(_string_value(operation))
341
+
342
+
343
+ def _string_value(operation: DocumentPatchOperation) -> str:
344
+ value = operation.value
345
+ if value is None:
346
+ _raise_unsupported_operation(operation)
347
+ return str(value)
348
+
349
+
350
+ def _raise_unsupported_operation(operation: DocumentPatchOperation) -> NoReturn:
351
+ raise DocumentMutationBlockedError(
352
+ BlockedReason.unsupported_operation,
353
+ f"ODF operation is not supported: {operation.operation_type.value} {operation.target_path}",
354
+ )
355
+
356
+
357
+ def _tables_from_body(body: object, *, artifact_prefix: str) -> list[TableBlock]:
358
+ if not hasattr(body, "get_tables"):
359
+ return []
360
+ tables: list[TableBlock] = []
361
+ tables_body = cast(_OdfTablesBody, body)
362
+ for table_index, table in enumerate(tables_body.get_tables(), start=1):
363
+ table_name = str(table.name or f"Table{table_index}")
364
+ cells: list[TableCell] = []
365
+ for row_index, row in enumerate(table.get_cells()):
366
+ for column_index, cell in enumerate(row):
367
+ value = cell.value
368
+ text = "" if value is None else str(value)
369
+ address = f"{_column_name(column_index)}{row_index + 1}"
370
+ cells.append(
371
+ TableCell(
372
+ row_index=row_index,
373
+ column_index=column_index,
374
+ text=text,
375
+ source_path=f"/odf/sheets/{table_name}/cells/{address}",
376
+ field_path=f"/odf/sheets/{table_name}/cells/{address}",
377
+ )
378
+ )
379
+ tables.append(
380
+ TableBlock(
381
+ block_id=f"{artifact_prefix}-table-{table_index}",
382
+ source_path=f"/odf/sheets/{table_name}",
383
+ cells=cells,
384
+ )
385
+ )
386
+ return tables
387
+
388
+
389
+ def _column_name(index: int) -> str:
390
+ value = index + 1
391
+ letters = ""
392
+ while value:
393
+ value, remainder = divmod(value - 1, 26)
394
+ letters = chr(65 + remainder) + letters
395
+ return letters
396
+
397
+
398
+ def _metadata(path: Path, *, document_format: DocumentFormat) -> dict[str, MetadataValue]:
399
+ return {
400
+ "adapter_id": "odfdo-document-adapter",
401
+ "engine_id": f"odfdo-{document_format.value}",
402
+ "format": document_format.value,
403
+ "source_name": path.name,
404
+ "mutation_policy": "bounded_odfdo_write_render_save",
405
+ "render_oracle": "odfdo-structural-svg",
406
+ "layout_oracle_gate": "libreoffice_headless_deferred",
407
+ }
408
+
409
+
410
+ def _save_odf_document(document: _OdfDocument) -> bytes:
411
+ output = BytesIO()
412
+ document.save(output)
413
+ return output.getvalue()
414
+
415
+
416
+ def _render_lines_svg(lines: list[str], *, title: str) -> bytes:
417
+ escaped_title = html.escape(title)
418
+ safe_lines = [html.escape(line) for line in lines if line]
419
+ height = max(160, 72 + len(safe_lines) * 28)
420
+ text_nodes = [
421
+ f'<text x="32" y="{84 + index * 28}" font-size="16" font-family="sans-serif">{line}</text>'
422
+ for index, line in enumerate(safe_lines[:40])
423
+ ]
424
+ svg = (
425
+ f'<svg xmlns="http://www.w3.org/2000/svg" width="900" height="{height}" '
426
+ f'viewBox="0 0 900 {height}">'
427
+ '<rect width="100%" height="100%" fill="#ffffff"/>'
428
+ '<rect x="20" y="20" width="860" height="'
429
+ f'{height - 40}" fill="#ffffff" stroke="#222222" stroke-width="1"/>'
430
+ f'<text x="32" y="52" font-size="20" font-family="sans-serif" '
431
+ f'font-weight="700">{escaped_title}</text>'
432
+ f"{''.join(text_nodes)}"
433
+ "</svg>"
434
+ )
435
+ return svg.encode("utf-8")