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,268 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Promoted text and web-export document engines."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import html
7
+ import re
8
+ from html.parser import HTMLParser
9
+ from pathlib import Path
10
+ from typing import NoReturn
11
+
12
+ from ummaya.tools.documents.engines import DocumentMutationBlockedError
13
+ from ummaya.tools.documents.models import (
14
+ BlockedReason,
15
+ DocumentExtraction,
16
+ DocumentFormat,
17
+ DocumentPatch,
18
+ DocumentPatchOperation,
19
+ KnownDocumentFormat,
20
+ MetadataValue,
21
+ OperationType,
22
+ ParagraphBlock,
23
+ )
24
+ from ummaya.tools.documents.tool_defs import DocumentFieldPatch
25
+
26
+ _TEXT_BODY_TARGET = "/text/body"
27
+ _TEXT_LINE_RE = re.compile(r"^/text/lines/(?P<index>[1-9][0-9]*)$")
28
+ _RTF_UNICODE_RE = re.compile(r"\\u(?P<code>-?[0-9]+).")
29
+ _RTF_CONTROL_RE = re.compile(r"\\[a-zA-Z]+-?[0-9]* ?")
30
+ _TEXT_WEB_FORMATS = (
31
+ DocumentFormat.html,
32
+ DocumentFormat.htm,
33
+ DocumentFormat.txt,
34
+ DocumentFormat.rtf,
35
+ DocumentFormat.md,
36
+ )
37
+
38
+
39
+ class TextWebDocumentEngine:
40
+ """Bounded writer for UTF-8 text, Markdown, HTML, HTM, and RTF exports."""
41
+
42
+ render_engine_id = "text-web-structural-svg"
43
+ render_artifact_extension = "svg"
44
+ render_mime_type = "image/svg+xml"
45
+
46
+ def __init__(self, document_format: DocumentFormat) -> None:
47
+ if document_format not in _TEXT_WEB_FORMATS:
48
+ raise ValueError(f"unsupported text-web document format: {document_format.value}")
49
+ self.document_format = document_format
50
+ self.engine_id = f"text-web-{document_format.value}"
51
+
52
+ def inspect(self, path: Path, *, artifact_id: str) -> DocumentExtraction:
53
+ """Extract visible text lines from a promoted text/web document."""
54
+ raw_text = path.read_text(encoding="utf-8", errors="replace")
55
+ visible_text = _visible_text(raw_text, document_format=self.document_format)
56
+ return DocumentExtraction(
57
+ artifact_id=artifact_id,
58
+ paragraphs=_paragraphs_from_text(visible_text, source_name=path.name),
59
+ metadata=_metadata(path, document_format=self.document_format),
60
+ )
61
+
62
+ def apply_patch(self, path: Path, patch: DocumentPatch) -> bytes:
63
+ """Apply bounded text replacement and return derivative document bytes."""
64
+ raw_text = path.read_text(encoding="utf-8", errors="replace")
65
+ visible_text = _visible_text(raw_text, document_format=self.document_format)
66
+ for operation in patch.operations:
67
+ visible_text = _apply_text_operation(visible_text, operation)
68
+ output = _serialize_text_web(visible_text, document_format=self.document_format)
69
+ return output.encode("utf-8")
70
+
71
+ def render(self, path: Path, *, artifact_id: str, output_dir: Path) -> tuple[bytes, ...]:
72
+ """Render visible text as structural SVG evidence."""
73
+ _ = output_dir
74
+ extraction = self.inspect(path, artifact_id=artifact_id)
75
+ lines = [paragraph.text for paragraph in extraction.paragraphs]
76
+ return (_render_lines_svg(lines, title=f"{self.document_format.value.upper()} document"),)
77
+
78
+
79
+ class TextWebDocumentAdapter:
80
+ """Format adapter for promoted text and web-export engines."""
81
+
82
+ adapter_id = "text-web-document-adapter"
83
+ known_formats: tuple[KnownDocumentFormat, ...] = (
84
+ KnownDocumentFormat.html,
85
+ KnownDocumentFormat.htm,
86
+ KnownDocumentFormat.txt,
87
+ KnownDocumentFormat.rtf,
88
+ KnownDocumentFormat.md,
89
+ )
90
+ promoted_formats: tuple[DocumentFormat, ...] = _TEXT_WEB_FORMATS
91
+
92
+ def __init__(self, engines: dict[DocumentFormat, TextWebDocumentEngine] | None = None) -> None:
93
+ self._engines = engines or {
94
+ document_format: TextWebDocumentEngine(document_format)
95
+ for document_format in _TEXT_WEB_FORMATS
96
+ }
97
+
98
+ def inspect(self, path: Path, *, artifact_id: str) -> DocumentExtraction:
99
+ """Inspect a text/web artifact using its suffix-selected engine."""
100
+ return self._engine_for_path(path).inspect(path, artifact_id=artifact_id)
101
+
102
+ def normalize_fill_patches(
103
+ self,
104
+ patches: tuple[DocumentFieldPatch, ...],
105
+ *,
106
+ extraction: DocumentExtraction | None,
107
+ ) -> tuple[DocumentFieldPatch, ...]:
108
+ """Return text/web patches unchanged; `/text/*` paths are native."""
109
+ _ = extraction
110
+ return patches
111
+
112
+ def _engine_for_path(self, path: Path) -> TextWebDocumentEngine:
113
+ try:
114
+ document_format = DocumentFormat(path.suffix.lower().lstrip("."))
115
+ except ValueError as exc:
116
+ raise DocumentMutationBlockedError(
117
+ BlockedReason.unsupported_format,
118
+ f"Unsupported text/web suffix: {path.suffix}",
119
+ ) from exc
120
+ engine = self._engines.get(document_format)
121
+ if engine is None:
122
+ raise DocumentMutationBlockedError(
123
+ BlockedReason.unsupported_format,
124
+ f"Unsupported text/web suffix: {path.suffix}",
125
+ )
126
+ return engine
127
+
128
+
129
+ class _VisibleHTMLParser(HTMLParser):
130
+ def __init__(self) -> None:
131
+ super().__init__()
132
+ self._chunks: list[str] = []
133
+
134
+ def handle_data(self, data: str) -> None:
135
+ stripped = data.strip()
136
+ if stripped:
137
+ self._chunks.append(stripped)
138
+
139
+ def visible_text(self) -> str:
140
+ return "\n".join(self._chunks)
141
+
142
+
143
+ def _visible_text(raw_text: str, *, document_format: DocumentFormat) -> str:
144
+ if document_format in {DocumentFormat.html, DocumentFormat.htm}:
145
+ parser = _VisibleHTMLParser()
146
+ parser.feed(raw_text)
147
+ return parser.visible_text()
148
+ if document_format is DocumentFormat.rtf:
149
+ return _strip_minimal_rtf(raw_text)
150
+ return raw_text
151
+
152
+
153
+ def _apply_text_operation(text: str, operation: DocumentPatchOperation) -> str:
154
+ if operation.operation_type not in {OperationType.replace_text, OperationType.set_field_value}:
155
+ _raise_unsupported_operation(operation)
156
+ value = operation.value
157
+ if value is None:
158
+ _raise_unsupported_operation(operation)
159
+ replacement = str(value)
160
+ if operation.target_path == _TEXT_BODY_TARGET:
161
+ return replacement
162
+ match = _TEXT_LINE_RE.fullmatch(operation.target_path)
163
+ if match is None:
164
+ _raise_unsupported_operation(operation)
165
+ lines = text.splitlines(keepends=True)
166
+ line_index = int(match.group("index")) - 1
167
+ if line_index >= len(lines):
168
+ _raise_unsupported_operation(operation)
169
+ newline = "\n" if lines[line_index].endswith("\n") else ""
170
+ lines[line_index] = replacement.rstrip("\n") + newline
171
+ return "".join(lines)
172
+
173
+
174
+ def _serialize_text_web(text: str, *, document_format: DocumentFormat) -> str:
175
+ if document_format in {DocumentFormat.html, DocumentFormat.htm}:
176
+ escaped = html.escape(text).replace("\n", "<br/>\n")
177
+ return f"<!doctype html>\n<html><body><p>{escaped}</p></body></html>\n"
178
+ if document_format is DocumentFormat.rtf:
179
+ return _rtf_payload_from_text(text)
180
+ return text
181
+
182
+
183
+ def _paragraphs_from_text(text: str, *, source_name: str) -> list[ParagraphBlock]:
184
+ lines = [line.strip() for line in text.splitlines() if line.strip()]
185
+ if not lines and text.strip():
186
+ lines = [text.strip()]
187
+ return [
188
+ ParagraphBlock(
189
+ block_id=f"text-line-{index}",
190
+ text=line,
191
+ source_path=f"/text/lines/{index}",
192
+ )
193
+ for index, line in enumerate(lines, start=1)
194
+ ] or [
195
+ ParagraphBlock(
196
+ block_id="text-line-1",
197
+ text="",
198
+ source_path=f"{source_name}:/text/lines/1",
199
+ )
200
+ ]
201
+
202
+
203
+ def _strip_minimal_rtf(raw_text: str) -> str:
204
+ without_unicode = _RTF_UNICODE_RE.sub(lambda match: _rtf_codepoint(match), raw_text)
205
+ stripped = without_unicode.replace("{", "").replace("}", "")
206
+ stripped = _RTF_CONTROL_RE.sub("", stripped)
207
+ return "\n".join(line.strip() for line in stripped.splitlines() if line.strip())
208
+
209
+
210
+ def _rtf_codepoint(match: re.Match[str]) -> str:
211
+ value = int(match.group("code"))
212
+ if value < 0:
213
+ value += 65536
214
+ return chr(value)
215
+
216
+
217
+ def _rtf_payload_from_text(text: str) -> str:
218
+ encoded_chars: list[str] = []
219
+ for char in text:
220
+ if char == "\n":
221
+ encoded_chars.append(r"\par ")
222
+ elif char in {"\\", "{", "}"}:
223
+ encoded_chars.append(f"\\{char}")
224
+ elif ord(char) > 127:
225
+ codepoint = ord(char)
226
+ if codepoint > 32767:
227
+ codepoint -= 65536
228
+ encoded_chars.append(rf"\u{codepoint}?")
229
+ else:
230
+ encoded_chars.append(char)
231
+ return r"{\rtf1\ansi\uc1 " + "".join(encoded_chars).strip() + "}\n"
232
+
233
+
234
+ def _metadata(path: Path, *, document_format: DocumentFormat) -> dict[str, MetadataValue]:
235
+ return {
236
+ "adapter_id": "text-web-document-adapter",
237
+ "engine_id": f"text-web-{document_format.value}",
238
+ "format": document_format.value,
239
+ "source_name": path.name,
240
+ "mutation_policy": "bounded_text_web_write_render_save",
241
+ "render_oracle": "text-web-structural-svg",
242
+ }
243
+
244
+
245
+ def _render_lines_svg(lines: list[str], *, title: str) -> bytes:
246
+ escaped_title = html.escape(title)
247
+ safe_lines = [html.escape(line) for line in lines if line]
248
+ height = max(160, 72 + len(safe_lines) * 28)
249
+ text_nodes = [
250
+ f'<text x="32" y="{84 + index * 28}" font-size="16" font-family="sans-serif">{line}</text>'
251
+ for index, line in enumerate(safe_lines)
252
+ ]
253
+ svg = (
254
+ f'<svg xmlns="http://www.w3.org/2000/svg" width="960" height="{height}" '
255
+ f'viewBox="0 0 960 {height}">'
256
+ '<rect width="100%" height="100%" fill="#ffffff"/>'
257
+ f'<text x="32" y="40" font-size="22" font-family="sans-serif" '
258
+ f'font-weight="700">{escaped_title}</text>' + "".join(text_nodes) + "</svg>"
259
+ )
260
+ return svg.encode("utf-8")
261
+
262
+
263
+ def _raise_unsupported_operation(operation: DocumentPatchOperation) -> NoReturn:
264
+ raise DocumentMutationBlockedError(
265
+ BlockedReason.unsupported_operation,
266
+ f"Text/web operation is not supported: "
267
+ f"{operation.operation_type.value} {operation.target_path}",
268
+ )
@@ -0,0 +1,178 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Local HWP-to-HWPX bridge diagnostics.
3
+
4
+ This module does not register converters. It reports whether a local candidate
5
+ can satisfy the explicit `DocumentConversionEngine` environment boundary.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import os
12
+ from collections.abc import Mapping, Sequence
13
+ from pathlib import Path
14
+ from shutil import which
15
+ from typing import Literal
16
+
17
+ from pydantic import BaseModel, ConfigDict, Field
18
+
19
+ from ummaya.tools.documents.models import DocumentFormat
20
+
21
+ HWP_CONVERTER_ENV = "UMMAYA_HWP_TO_HWPX_CONVERTER"
22
+ HWP_CONVERTER_ARGS_ENV = "UMMAYA_HWP_TO_HWPX_CONVERTER_ARGS_JSON"
23
+ HWP_CONVERTER_ENGINE_ID_ENV = "UMMAYA_HWP_TO_HWPX_CONVERTER_ENGINE_ID"
24
+ HWP_CONVERTER_TIMEOUT_ENV = "UMMAYA_HWP_TO_HWPX_CONVERTER_TIMEOUT_SECONDS"
25
+ HWPFORGE_CANDIDATE_ID = "hwpforge-cli-convert-hwp5"
26
+ HWPFORGE_HWP5_TO_HWPX_ARGS = (
27
+ "--json",
28
+ "convert-hwp5",
29
+ "{source}",
30
+ "--output",
31
+ "{output}",
32
+ )
33
+ HWPXJS_CANDIDATE_ID = "hwpxjs-cli-convert-hwp"
34
+ HWPXJS_HWP_TO_HWPX_ARGS = ("convert:hwp", "{source}", "{output}")
35
+ _HWPFORGE_SOURCE_REF = "upstream:hwpforge-cli-v0.6.0-convert-hwp5"
36
+ _HWPXJS_SOURCE_REF = "upstream:ssabro-hwpxjs-v0.4.0"
37
+ _ADR_REF = "adr:docs/adr/ADR-011-hwp-conversion-bridge.md"
38
+
39
+ BridgeProbeStatus = Literal["configured", "available", "missing", "misconfigured"]
40
+
41
+
42
+ class HwpToHwpxBridgeProbeReport(BaseModel):
43
+ """Current local availability of the HWP-to-HWPX bridge candidate."""
44
+
45
+ model_config = ConfigDict(frozen=True, extra="forbid")
46
+
47
+ candidate_id: str = Field(min_length=1)
48
+ status: BridgeProbeStatus
49
+ source_format: DocumentFormat
50
+ output_format: DocumentFormat
51
+ executable: Path | None
52
+ recommended_args: tuple[str, ...]
53
+ recommended_env: dict[str, str]
54
+ reasons: tuple[str, ...]
55
+ evidence_refs: tuple[str, ...]
56
+
57
+
58
+ def probe_hwp_to_hwpx_bridge(
59
+ *,
60
+ env: Mapping[str, str] | None = None,
61
+ search_path: Sequence[str] | None = None,
62
+ ) -> HwpToHwpxBridgeProbeReport:
63
+ """Report whether a local HwpForge CLI bridge is configured or discoverable."""
64
+ active_env = os.environ if env is None else env
65
+ configured = active_env.get(HWP_CONVERTER_ENV)
66
+ if configured:
67
+ configured_path = Path(configured).expanduser().resolve(strict=False)
68
+ if _is_executable_file(configured_path):
69
+ return _report(
70
+ candidate_id=active_env.get(HWP_CONVERTER_ENGINE_ID_ENV, HWPFORGE_CANDIDATE_ID),
71
+ status="configured",
72
+ executable=configured_path,
73
+ recommended_args=_configured_args_or_default(active_env),
74
+ reasons=("explicit_hwp_bridge_configured",),
75
+ evidence_refs=(_ADR_REF,),
76
+ )
77
+ return _report(
78
+ candidate_id=active_env.get(HWP_CONVERTER_ENGINE_ID_ENV, HWPFORGE_CANDIDATE_ID),
79
+ status="misconfigured",
80
+ executable=configured_path,
81
+ recommended_args=_configured_args_or_default(active_env),
82
+ reasons=("explicit_hwp_bridge_not_executable",),
83
+ evidence_refs=(_ADR_REF,),
84
+ )
85
+
86
+ discovered_hwpxjs = _find_executable("hwpxjs", active_env=active_env, search_path=search_path)
87
+ if discovered_hwpxjs is not None:
88
+ return _report(
89
+ candidate_id=HWPXJS_CANDIDATE_ID,
90
+ status="available",
91
+ executable=discovered_hwpxjs,
92
+ recommended_args=HWPXJS_HWP_TO_HWPX_ARGS,
93
+ reasons=("hwpxjs_cli_found_for_default_registration",),
94
+ evidence_refs=(_HWPXJS_SOURCE_REF, _ADR_REF),
95
+ )
96
+
97
+ discovered = _find_executable("hwpforge", active_env=active_env, search_path=search_path)
98
+ if discovered is None:
99
+ return _report(
100
+ candidate_id=HWPFORGE_CANDIDATE_ID,
101
+ status="missing",
102
+ executable=None,
103
+ recommended_args=HWPFORGE_HWP5_TO_HWPX_ARGS,
104
+ reasons=("hwpforge_cli_not_found",),
105
+ evidence_refs=(_HWPFORGE_SOURCE_REF, _ADR_REF),
106
+ )
107
+ return _report(
108
+ candidate_id=HWPFORGE_CANDIDATE_ID,
109
+ status="available",
110
+ executable=discovered,
111
+ recommended_args=HWPFORGE_HWP5_TO_HWPX_ARGS,
112
+ reasons=("hwpforge_cli_found_but_not_registered",),
113
+ evidence_refs=(_HWPFORGE_SOURCE_REF, _ADR_REF),
114
+ )
115
+
116
+
117
+ def _find_executable(
118
+ name: str,
119
+ *,
120
+ active_env: Mapping[str, str],
121
+ search_path: Sequence[str] | None,
122
+ ) -> Path | None:
123
+ path_env = os.pathsep.join(search_path) if search_path is not None else active_env.get("PATH")
124
+ if not path_env:
125
+ return None
126
+ found = which(name, path=path_env)
127
+ if found is None:
128
+ return None
129
+ candidate = Path(found).expanduser().resolve(strict=False)
130
+ if not _is_executable_file(candidate):
131
+ return None
132
+ return candidate
133
+
134
+
135
+ def _is_executable_file(path: Path) -> bool:
136
+ return path.exists() and path.is_file() and os.access(path, os.X_OK)
137
+
138
+
139
+ def _configured_args_or_default(active_env: Mapping[str, str]) -> tuple[str, ...]:
140
+ raw = active_env.get(HWP_CONVERTER_ARGS_ENV)
141
+ if not raw:
142
+ return HWPFORGE_HWP5_TO_HWPX_ARGS
143
+ try:
144
+ decoded = json.loads(raw)
145
+ except json.JSONDecodeError:
146
+ return HWPFORGE_HWP5_TO_HWPX_ARGS
147
+ if not isinstance(decoded, list) or not all(isinstance(item, str) for item in decoded):
148
+ return HWPFORGE_HWP5_TO_HWPX_ARGS
149
+ return tuple(decoded)
150
+
151
+
152
+ def _report(
153
+ *,
154
+ candidate_id: str,
155
+ status: BridgeProbeStatus,
156
+ executable: Path | None,
157
+ recommended_args: tuple[str, ...],
158
+ reasons: tuple[str, ...],
159
+ evidence_refs: tuple[str, ...],
160
+ ) -> HwpToHwpxBridgeProbeReport:
161
+ recommended_env = {
162
+ HWP_CONVERTER_ARGS_ENV: json.dumps(list(recommended_args)),
163
+ HWP_CONVERTER_ENGINE_ID_ENV: candidate_id,
164
+ HWP_CONVERTER_TIMEOUT_ENV: "120",
165
+ }
166
+ if executable is not None:
167
+ recommended_env[HWP_CONVERTER_ENV] = str(executable)
168
+ return HwpToHwpxBridgeProbeReport(
169
+ candidate_id=candidate_id,
170
+ status=status,
171
+ source_format=DocumentFormat.hwp,
172
+ output_format=DocumentFormat.hwpx,
173
+ executable=executable,
174
+ recommended_args=recommended_args,
175
+ recommended_env=recommended_env,
176
+ reasons=reasons,
177
+ evidence_refs=evidence_refs,
178
+ )
@@ -0,0 +1,141 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ from __future__ import annotations
3
+
4
+ from typing import Final, Literal
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field
7
+
8
+ RhwpHardGateFailure = Literal[
9
+ "license_unverified",
10
+ "api_surface_unverified",
11
+ "artifact_size_unverified",
12
+ "local_only_execution_unverified",
13
+ "hwp_write_capability_unverified",
14
+ "sanitized_hwp_round_trip_missing",
15
+ "render_comparison_missing",
16
+ ]
17
+ RhwpPromotionState = Literal["blocked", "ready_for_fixture_round_trip"]
18
+
19
+ _PERMISSIVE_LICENSES: Final[frozenset[str]] = frozenset(
20
+ {
21
+ "MIT",
22
+ "Apache-2.0",
23
+ "MIT OR Apache-2.0",
24
+ "Apache-2.0 OR MIT",
25
+ }
26
+ )
27
+ _MAX_REVIEWED_ARTIFACT_SIZE_BYTES: Final[int] = 25 * 1024 * 1024
28
+ _GATE_SCORES: Final[dict[RhwpHardGateFailure, int]] = {
29
+ "license_unverified": 10,
30
+ "api_surface_unverified": 15,
31
+ "artifact_size_unverified": 10,
32
+ "local_only_execution_unverified": 20,
33
+ "hwp_write_capability_unverified": 15,
34
+ "sanitized_hwp_round_trip_missing": 20,
35
+ "render_comparison_missing": 10,
36
+ }
37
+ _GATE_MESSAGES: Final[dict[RhwpHardGateFailure, str]] = {
38
+ "license_unverified": "license evidence is missing or not permissive",
39
+ "api_surface_unverified": "local API surface evidence is missing",
40
+ "artifact_size_unverified": "reviewed artifact size evidence is missing",
41
+ "local_only_execution_unverified": "local-only execution evidence is missing",
42
+ "hwp_write_capability_unverified": "HWP write capability evidence is missing",
43
+ "sanitized_hwp_round_trip_missing": "sanitized HWP round-trip fixture evidence is missing",
44
+ "render_comparison_missing": "render comparison evidence is missing",
45
+ }
46
+
47
+
48
+ class RhwpCandidateEvidence(BaseModel):
49
+ model_config = ConfigDict(frozen=True, extra="forbid")
50
+
51
+ version: str = Field(min_length=1)
52
+ license_spdx: str | None = None
53
+ package_ref: str | None = Field(default=None, min_length=1)
54
+ artifact_size_bytes: int | None = Field(default=None, ge=1)
55
+ local_only_execution: bool | None = None
56
+ api_surface_refs: tuple[str, ...] = Field(default_factory=tuple)
57
+ supports_hwp_read: bool = True
58
+ supports_hwp_write: bool = True
59
+ supports_hwpx_read: bool = True
60
+ supports_hwpx_write: bool = True
61
+ sanitized_hwp_round_trip_fixture_refs: tuple[str, ...] = Field(default_factory=tuple)
62
+ render_comparison_refs: tuple[str, ...] = Field(default_factory=tuple)
63
+ source_refs: tuple[str, ...] = Field(min_length=1)
64
+ known_risk_refs: tuple[str, ...] = Field(default_factory=tuple)
65
+
66
+
67
+ class RhwpCandidateEvaluation(BaseModel):
68
+ model_config = ConfigDict(frozen=True, extra="forbid")
69
+
70
+ engine_id: Literal["rhwp-direct-hwp"]
71
+ version: str
72
+ promotion_state: RhwpPromotionState
73
+ write_enabled: bool
74
+ total_score: int = Field(ge=0, le=100)
75
+ required_score: Literal[100]
76
+ hard_gate_failures: tuple[RhwpHardGateFailure, ...]
77
+ user_facing_summary: str
78
+ source_refs: tuple[str, ...]
79
+ known_risk_refs: tuple[str, ...]
80
+
81
+
82
+ def evaluate_rhwp_candidate(evidence: RhwpCandidateEvidence) -> RhwpCandidateEvaluation:
83
+ failures = _hard_gate_failures(evidence)
84
+ total_score = 100 - sum(_GATE_SCORES[failure] for failure in failures)
85
+ write_enabled = not failures
86
+ promotion_state: RhwpPromotionState = (
87
+ "ready_for_fixture_round_trip" if write_enabled else "blocked"
88
+ )
89
+ return RhwpCandidateEvaluation(
90
+ engine_id="rhwp-direct-hwp",
91
+ version=evidence.version,
92
+ promotion_state=promotion_state,
93
+ write_enabled=write_enabled,
94
+ total_score=total_score,
95
+ required_score=100,
96
+ hard_gate_failures=failures,
97
+ user_facing_summary=_user_facing_summary(failures),
98
+ source_refs=evidence.source_refs,
99
+ known_risk_refs=evidence.known_risk_refs,
100
+ )
101
+
102
+
103
+ def build_hwp_direct_write_candidate_result(
104
+ evidence: RhwpCandidateEvidence,
105
+ ) -> RhwpCandidateEvaluation:
106
+ return evaluate_rhwp_candidate(evidence)
107
+
108
+
109
+ def _hard_gate_failures(
110
+ evidence: RhwpCandidateEvidence,
111
+ ) -> tuple[RhwpHardGateFailure, ...]:
112
+ failures: list[RhwpHardGateFailure] = []
113
+ if evidence.license_spdx not in _PERMISSIVE_LICENSES:
114
+ failures.append("license_unverified")
115
+ if not evidence.api_surface_refs:
116
+ failures.append("api_surface_unverified")
117
+ if not _artifact_size_is_reviewed(evidence.artifact_size_bytes):
118
+ failures.append("artifact_size_unverified")
119
+ if evidence.local_only_execution is not True:
120
+ failures.append("local_only_execution_unverified")
121
+ if not (evidence.supports_hwp_read and evidence.supports_hwp_write):
122
+ failures.append("hwp_write_capability_unverified")
123
+ if not evidence.sanitized_hwp_round_trip_fixture_refs:
124
+ failures.append("sanitized_hwp_round_trip_missing")
125
+ if not evidence.render_comparison_refs:
126
+ failures.append("render_comparison_missing")
127
+ return tuple(failures)
128
+
129
+
130
+ def _artifact_size_is_reviewed(size: int | None) -> bool:
131
+ return size is not None and 0 < size <= _MAX_REVIEWED_ARTIFACT_SIZE_BYTES
132
+
133
+
134
+ def _user_facing_summary(failures: tuple[RhwpHardGateFailure, ...]) -> str:
135
+ if not failures:
136
+ return (
137
+ "Direct HWP binary writing is ready for promotion evidence review; "
138
+ "the candidate must still run through the document primitive fixture suite."
139
+ )
140
+ reasons = "; ".join(_GATE_MESSAGES[failure] for failure in failures)
141
+ return f"Direct HWP binary writing remains blocked because {reasons}."