ummaya 0.2.3 → 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 (534) hide show
  1. package/README.md +17 -3
  2. package/bin/ummaya +10 -1
  3. package/npm-shrinkwrap.json +253 -2
  4. package/package.json +5 -1
  5. package/prompts/manifest.yaml +2 -2
  6. package/prompts/session_guidance_v1.md +3 -1
  7. package/prompts/system_v1.md +9 -7
  8. package/pyproject.toml +26 -7
  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/context/builder.py +17 -11
  12. package/src/ummaya/engine/engine.py +30 -113
  13. package/src/ummaya/engine/query.py +20 -0
  14. package/src/ummaya/evidence/__init__.py +44 -0
  15. package/src/ummaya/evidence/__main__.py +7 -0
  16. package/src/ummaya/evidence/dataset_contract.py +193 -0
  17. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  18. package/src/ummaya/evidence/document_harness.py +313 -0
  19. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  20. package/src/ummaya/evidence/gates.py +70 -0
  21. package/src/ummaya/evidence/json_types.py +20 -0
  22. package/src/ummaya/evidence/models.py +145 -0
  23. package/src/ummaya/evidence/output_payload.py +89 -0
  24. package/src/ummaya/evidence/payload_documents.py +233 -0
  25. package/src/ummaya/evidence/route_contracts.py +224 -0
  26. package/src/ummaya/evidence/route_helpers.py +150 -0
  27. package/src/ummaya/evidence/runner.py +177 -0
  28. package/src/ummaya/evidence/source_provenance.py +246 -0
  29. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  30. package/src/ummaya/evidence/task_registry.py +264 -0
  31. package/src/ummaya/evidence/tool_layer.py +39 -0
  32. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  33. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  34. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  35. package/src/ummaya/ipc/frame_schema.py +52 -5
  36. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  37. package/src/ummaya/ipc/stdio.py +2282 -417
  38. package/src/ummaya/llm/client.py +234 -59
  39. package/src/ummaya/llm/config.py +8 -3
  40. package/src/ummaya/llm/reasoning.py +84 -0
  41. package/src/ummaya/primitives/__init__.py +6 -2
  42. package/src/ummaya/primitives/delegation.py +1 -1
  43. package/src/ummaya/primitives/document.py +28 -0
  44. package/src/ummaya/settings.py +0 -3
  45. package/src/ummaya/tools/discovery_bridge.py +34 -2
  46. package/src/ummaya/tools/documents/__init__.py +297 -0
  47. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  48. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  49. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  50. package/src/ummaya/tools/documents/authoring.py +283 -0
  51. package/src/ummaya/tools/documents/baselines.py +114 -0
  52. package/src/ummaya/tools/documents/capability.py +331 -0
  53. package/src/ummaya/tools/documents/contracts.py +112 -0
  54. package/src/ummaya/tools/documents/conversion.py +521 -0
  55. package/src/ummaya/tools/documents/diff.py +275 -0
  56. package/src/ummaya/tools/documents/engines.py +163 -0
  57. package/src/ummaya/tools/documents/evaluation.py +291 -0
  58. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  59. package/src/ummaya/tools/documents/fixtures.py +174 -0
  60. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  61. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  62. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  63. package/src/ummaya/tools/documents/formats/base.py +41 -0
  64. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  65. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  66. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  67. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  68. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  69. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  70. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  71. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  72. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  73. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  74. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  75. package/src/ummaya/tools/documents/inspection.py +289 -0
  76. package/src/ummaya/tools/documents/intake.py +1079 -0
  77. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  78. package/src/ummaya/tools/documents/models.py +1598 -0
  79. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  80. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  81. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  82. package/src/ummaya/tools/documents/patch.py +170 -0
  83. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  84. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  85. package/src/ummaya/tools/documents/permissions.py +110 -0
  86. package/src/ummaya/tools/documents/planner.py +616 -0
  87. package/src/ummaya/tools/documents/registry.py +2733 -0
  88. package/src/ummaya/tools/documents/render.py +978 -0
  89. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  90. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  91. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  92. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  93. package/src/ummaya/tools/documents/reread.py +157 -0
  94. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  95. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  96. package/src/ummaya/tools/documents/scorecard.py +184 -0
  97. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  98. package/src/ummaya/tools/documents/style.py +48 -0
  99. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  100. package/src/ummaya/tools/documents/validate.py +347 -0
  101. package/src/ummaya/tools/executor.py +61 -12
  102. package/src/ummaya/tools/geocoding/kakao_client.py +1 -2
  103. package/src/ummaya/tools/kma/apihub_catalog.py +984 -1
  104. package/src/ummaya/tools/kma/apihub_structured_adapter.py +86 -6
  105. package/src/ummaya/tools/kma/apihub_url_adapter.py +593 -0
  106. package/src/ummaya/tools/kma/apihub_url_catalog.py +296 -0
  107. package/src/ummaya/tools/live_proxy.py +0 -3
  108. package/src/ummaya/tools/location_adapters.py +8 -6
  109. package/src/ummaya/tools/manifest_metadata.py +16 -3
  110. package/src/ummaya/tools/models.py +5 -1
  111. package/src/ummaya/tools/mvp_surface.py +2 -2
  112. package/src/ummaya/tools/nmc/emergency_search.py +8 -6
  113. package/src/ummaya/tools/register_all.py +17 -0
  114. package/src/ummaya/tools/registry.py +10 -1
  115. package/src/ummaya/tools/resolve_location.py +4 -4
  116. package/src/ummaya/tools/routing/__init__.py +59 -0
  117. package/src/ummaya/tools/routing/builder.py +105 -0
  118. package/src/ummaya/tools/routing/cards.py +29 -0
  119. package/src/ummaya/tools/routing/decision_service.py +534 -0
  120. package/src/ummaya/tools/routing/decision_types.py +74 -0
  121. package/src/ummaya/tools/routing/feasibility.py +122 -0
  122. package/src/ummaya/tools/routing/intent.py +17 -0
  123. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  124. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  125. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  126. package/src/ummaya/tools/routing/intent_types.py +48 -0
  127. package/src/ummaya/tools/routing/lint.py +78 -0
  128. package/src/ummaya/tools/routing/metadata.py +174 -0
  129. package/src/ummaya/tools/routing/projection.py +340 -0
  130. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  131. package/src/ummaya/tools/routing/schema.py +81 -0
  132. package/src/ummaya/tools/routing/types.py +96 -0
  133. package/src/ummaya/tools/routing_index.py +2 -2
  134. package/src/ummaya/tools/search.py +40 -106
  135. package/src/ummaya/tools/verified_data_go_kr/_manifest.py +115 -25
  136. package/src/ummaya/tools/verified_data_go_kr/airkorea_air_quality.py +109 -4
  137. package/src/ummaya/tools/verified_data_go_kr/nmc_aed_site.py +108 -2
  138. package/src/ummaya/tools/verified_data_go_kr/pps_bid_public_info.py +174 -9
  139. package/src/ummaya/tools/verified_data_go_kr/tago_bus_arrival.py +66 -3
  140. package/src/ummaya/tools/verified_data_go_kr/tago_bus_location.py +12 -2
  141. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route.py +8 -2
  142. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route_station.py +114 -0
  143. package/src/ummaya/tools/verified_data_go_kr/tago_bus_station.py +14 -3
  144. package/src/ummaya/tools/verify_canonical_map.py +21 -0
  145. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  146. package/tui/package.json +1 -2
  147. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  148. package/tui/src/QueryEngine.ts +12 -4
  149. package/tui/src/bridge/inboundAttachments.ts +3 -3
  150. package/tui/src/cli/handlers/auth.ts +4 -13
  151. package/tui/src/cli/handlers/mcp.tsx +3 -3
  152. package/tui/src/cli/print.ts +69 -18
  153. package/tui/src/cli/update.ts +13 -13
  154. package/tui/src/commands/copy/index.ts +1 -1
  155. package/tui/src/commands/cost/cost.ts +2 -2
  156. package/tui/src/commands/init-verifiers.ts +5 -5
  157. package/tui/src/commands/init.ts +30 -30
  158. package/tui/src/commands/insights.ts +44 -44
  159. package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
  160. package/tui/src/commands/install-github-app/setupGitHubActions.ts +3 -3
  161. package/tui/src/commands/install-github-app/types.ts +8 -30
  162. package/tui/src/commands/install.tsx +5 -5
  163. package/tui/src/commands/mcp/addCommand.ts +5 -5
  164. package/tui/src/commands/mcp/xaaIdpCommand.ts +2 -2
  165. package/tui/src/commands/plugin/ManageMarketplaces.tsx +2 -2
  166. package/tui/src/commands/plugin/types.ts +6 -28
  167. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  168. package/tui/src/commands/reasoning/index.ts +13 -0
  169. package/tui/src/commands/reasoning/reasoning.tsx +177 -0
  170. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  171. package/tui/src/commands/thinkback/thinkback.tsx +3 -3
  172. package/tui/src/commands.ts +2 -0
  173. package/tui/src/components/Feedback.tsx +1 -1
  174. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  175. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  176. package/tui/src/components/Messages.tsx +2 -1
  177. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  178. package/tui/src/components/Spinner/types.ts +6 -28
  179. package/tui/src/components/Spinner.tsx +2 -2
  180. package/tui/src/components/agents/generateAgent.ts +1 -1
  181. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  182. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  183. package/tui/src/components/design-system/LoadingState.tsx +2 -2
  184. package/tui/src/components/mcp/types.ts +16 -38
  185. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  186. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  187. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  188. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  189. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  190. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  191. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  192. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  193. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  194. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  195. package/tui/src/components/primitive/index.tsx +43 -1
  196. package/tui/src/components/primitive/types.ts +137 -0
  197. package/tui/src/components/ui/option.ts +4 -26
  198. package/tui/src/constants/common.ts +0 -2
  199. package/tui/src/constants/prompts.ts +4 -3
  200. package/tui/src/constants/querySource.ts +4 -26
  201. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  202. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  203. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  204. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  205. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  206. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  207. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  208. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  209. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  210. package/tui/src/ink/ink.tsx +33 -14
  211. package/tui/src/ink/reconciler.ts +2 -3
  212. package/tui/src/ink/render-to-screen.ts +30 -10
  213. package/tui/src/ipc/bridge.ts +62 -15
  214. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  215. package/tui/src/ipc/codec.ts +29 -3
  216. package/tui/src/ipc/frames.generated.ts +407 -312
  217. package/tui/src/ipc/llmClient.ts +279 -76
  218. package/tui/src/ipc/llmTypes.ts +16 -1
  219. package/tui/src/ipc/schema/frame.schema.json +1 -3475
  220. package/tui/src/keybindings/defaultBindings.ts +4 -0
  221. package/tui/src/main.tsx +32 -11
  222. package/tui/src/native-ts/file-index/index.ts +33 -3
  223. package/tui/src/observability/surface.ts +2 -2
  224. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  225. package/tui/src/projectOnboardingState.ts +7 -6
  226. package/tui/src/query/chatMessageTypes.ts +18 -0
  227. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  228. package/tui/src/query/deps.ts +1 -1
  229. package/tui/src/query/messageGuards.ts +106 -0
  230. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  231. package/tui/src/query/run.ts +1075 -0
  232. package/tui/src/query/supportBoundary.ts +168 -0
  233. package/tui/src/query/toolResultErrors.ts +103 -0
  234. package/tui/src/query/toolRunner.ts +687 -0
  235. package/tui/src/query/unavailableToolRepair.ts +118 -0
  236. package/tui/src/query.ts +9 -1721
  237. package/tui/src/screens/REPL.tsx +42 -31
  238. package/tui/src/services/api/adapterManifest.ts +4 -0
  239. package/tui/src/services/api/backendChat/events.ts +117 -0
  240. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  241. package/tui/src/services/api/backendChat/frame.ts +9 -0
  242. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  243. package/tui/src/services/api/backendChat/types.ts +62 -0
  244. package/tui/src/services/api/backendChat.ts +1 -0
  245. package/tui/src/services/api/client.ts +98 -14
  246. package/tui/src/services/api/errorUtils.ts +5 -5
  247. package/tui/src/services/api/errors.ts +1 -1
  248. package/tui/src/services/api/logging.ts +1 -1
  249. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  250. package/tui/src/services/api/ummaya/messages.ts +255 -0
  251. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  252. package/tui/src/services/api/ummaya/provider.ts +200 -0
  253. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  254. package/tui/src/services/api/ummaya/request.ts +200 -0
  255. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  256. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  257. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  258. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  259. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  260. package/tui/src/services/api/ummaya/types.ts +110 -0
  261. package/tui/src/services/api/ummaya/usage.ts +30 -0
  262. package/tui/src/services/api/ummaya.ts +26 -364
  263. package/tui/src/services/api/withRetry.ts +1 -1
  264. package/tui/src/services/awaySummary.ts +2 -2
  265. package/tui/src/services/claudeAiLimits.ts +1 -1
  266. package/tui/src/services/compact/autoCompact.ts +1 -1
  267. package/tui/src/services/compact/compact.ts +1 -1
  268. package/tui/src/services/lsp/types.ts +8 -30
  269. package/tui/src/services/tips/types.ts +6 -28
  270. package/tui/src/services/tokenEstimation.ts +1 -1
  271. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  272. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  273. package/tui/src/services/tools/toolExecution.ts +94 -1
  274. package/tui/src/skills/bundled/stuck.ts +12 -12
  275. package/tui/src/state/AppStateStore.ts +7 -0
  276. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  277. package/tui/src/store/session-store.ts +10 -36
  278. package/tui/src/stubs/any-stub.ts +15 -10
  279. package/tui/src/stubs/color-diff-napi.ts +37 -23
  280. package/tui/src/stubs/globals.d.ts +3 -3
  281. package/tui/src/stubs/macro-preload.ts +23 -12
  282. package/tui/src/tools/AdapterTool/AdapterTool.ts +1239 -163
  283. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  284. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  285. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  286. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  287. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  288. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  289. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  290. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  291. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  292. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  293. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  294. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  295. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  296. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  297. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  298. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  299. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  300. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  301. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  302. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  303. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  304. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  305. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  306. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  307. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  308. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  309. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  310. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  311. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  312. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  313. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  314. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  315. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  316. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  317. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  318. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  319. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  320. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  321. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  322. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  323. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  324. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  325. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  326. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  327. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  328. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  329. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  330. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  331. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  332. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  333. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  334. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  335. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  336. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  337. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  338. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  339. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  340. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  341. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  342. package/tui/src/tools/BashTool/call.ts +202 -0
  343. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  344. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  345. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  346. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  347. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  348. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  349. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  350. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  351. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  352. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  353. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  354. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  355. package/tui/src/tools/BashTool/schemas.ts +65 -0
  356. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  357. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  358. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  359. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  360. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  361. package/tui/src/tools/BriefTool/upload.ts +1 -1
  362. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  363. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  364. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  365. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  366. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  367. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  368. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  369. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  370. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  371. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  372. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  373. package/tui/src/tools/FileEditTool/call.ts +228 -0
  374. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  375. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  376. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  377. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  378. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  379. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  380. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +48 -29
  381. package/tui/src/tools/LookupPrimitive/prompt.ts +6 -7
  382. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  383. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  384. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  385. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  386. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  387. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  388. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  389. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  390. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  391. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  392. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  393. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  394. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  395. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  396. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  397. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  398. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  399. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  400. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  401. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  402. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  403. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  404. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +30 -19
  405. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  406. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  407. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +51 -18
  408. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  409. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  410. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  411. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  412. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  413. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  414. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  415. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  416. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  417. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  418. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  419. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  420. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  421. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  422. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  423. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  424. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  425. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  426. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  427. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  428. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  429. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  430. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  431. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  432. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  433. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +27 -10
  434. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  435. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  436. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  437. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  438. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  439. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  440. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  441. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  442. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  443. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  444. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  445. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  446. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  447. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  448. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  449. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  450. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  451. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  452. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  453. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  454. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  455. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  456. package/tui/src/tools/_shared/citizenUserText.ts +49 -0
  457. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  458. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  459. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  460. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  461. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  462. package/tui/src/tools/_shared/locationInputRepair.ts +112 -0
  463. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  464. package/tui/src/tools/_shared/rootPrimitiveInput.ts +68 -0
  465. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  466. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  467. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  468. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  469. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  470. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  471. package/tui/src/tools/_shared/toolChoiceRepair.ts +61 -0
  472. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  473. package/tui/src/tools.ts +39 -190
  474. package/tui/src/types/fileSuggestion.ts +4 -26
  475. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  476. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  477. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  478. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  479. package/tui/src/types/message.ts +80 -102
  480. package/tui/src/types/messageQueueTypes.ts +6 -28
  481. package/tui/src/types/notebook.ts +16 -38
  482. package/tui/src/types/statusLine.ts +4 -26
  483. package/tui/src/types/tools.ts +24 -46
  484. package/tui/src/types/utils.ts +6 -28
  485. package/tui/src/upstreamproxy/relay.ts +7 -3
  486. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  487. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  488. package/tui/src/utils/attachments.ts +1 -1
  489. package/tui/src/utils/auth.ts +129 -139
  490. package/tui/src/utils/bash/ast.ts +23 -23
  491. package/tui/src/utils/bash/bashParser.ts +5 -5
  492. package/tui/src/utils/billing.ts +1 -1
  493. package/tui/src/utils/collapseReadSearch.ts +3 -3
  494. package/tui/src/utils/cronTasks.ts +1 -1
  495. package/tui/src/utils/execFileNoThrow.ts +1 -1
  496. package/tui/src/utils/filePersistence/types.ts +16 -38
  497. package/tui/src/utils/forkedAgent.ts +1 -1
  498. package/tui/src/utils/gracefulShutdown.ts +4 -4
  499. package/tui/src/utils/heapDumpService.ts +12 -8
  500. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  501. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  502. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  503. package/tui/src/utils/kExaoneReasoning.ts +138 -0
  504. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  505. package/tui/src/utils/messages.ts +19 -0
  506. package/tui/src/utils/migrateSessions.ts +3 -3
  507. package/tui/src/utils/model/model.ts +6 -6
  508. package/tui/src/utils/multiToolLayout.ts +13 -0
  509. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  510. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  511. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  512. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  513. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  514. package/tui/src/utils/processUserInput/processSlashCommand.tsx +2 -2
  515. package/tui/src/utils/processUserInput/processUserInput.ts +26 -0
  516. package/tui/src/utils/protectedNamespace.ts +5 -3
  517. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  518. package/tui/src/utils/ripgrep.ts +16 -7
  519. package/tui/src/utils/sessionTitle.ts +1 -1
  520. package/tui/src/utils/settings/applySettingsChange.ts +4 -0
  521. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  522. package/tui/src/utils/settings/types.ts +9 -3
  523. package/tui/src/utils/shell/prefix.ts +1 -1
  524. package/tui/src/utils/sideQuery.ts +1 -1
  525. package/tui/src/utils/stats.ts +1 -1
  526. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  527. package/tui/src/utils/teleport.tsx +1 -1
  528. package/uv.lock +394 -22
  529. package/assets/copilot-gate-logo.svg +0 -58
  530. package/assets/govon-logo.svg +0 -40
  531. package/src/ummaya/eval/__init__.py +0 -5
  532. package/src/ummaya/eval/retrieval.py +0 -713
  533. package/tui/src/services/api/claude.ts +0 -3510
  534. package/tui/src/utils/messageStream.ts +0 -186
@@ -0,0 +1,244 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ from __future__ import annotations
4
+
5
+ import tempfile
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import TYPE_CHECKING, Final
9
+
10
+ from ummaya.tools.documents.adapter_registry import (
11
+ DocumentAdapterRegistry,
12
+ UnsupportedDocumentAdapterError,
13
+ )
14
+ from ummaya.tools.documents.authoring import hash_authoring_text
15
+ from ummaya.tools.documents.conversion import (
16
+ DocumentConversionRegistry,
17
+ UnsupportedDocumentConversionError,
18
+ )
19
+ from ummaya.tools.documents.models import (
20
+ BlockedReason,
21
+ DocumentArtifact,
22
+ DocumentExtraction,
23
+ DocumentFormat,
24
+ DocumentToolResult,
25
+ )
26
+ from ummaya.tools.documents.runtime_authoring_bundle import (
27
+ IssuedAuthoringDraft,
28
+ approved_patch_bundle_matches_issued_draft,
29
+ issued_authoring_bundle,
30
+ issued_authoring_draft_id,
31
+ )
32
+ from ummaya.tools.documents.tool_defs import unsupported_document_tool_result
33
+
34
+ if TYPE_CHECKING:
35
+ from ummaya.tools.documents.tool_defs import DocumentFieldPatch
36
+
37
+ _NARRATIVE_TERMS: Final[tuple[str, ...]] = (
38
+ "자기소개",
39
+ "지원동기",
40
+ "성장과정",
41
+ "사업계획",
42
+ "계획",
43
+ "경험",
44
+ "수상",
45
+ "문항",
46
+ "motivation",
47
+ "selfintro",
48
+ "businessplan",
49
+ )
50
+
51
+
52
+ @dataclass(frozen=True, slots=True)
53
+ class EditableDerivativePreview:
54
+ document_format: DocumentFormat
55
+ extraction: DocumentExtraction
56
+
57
+
58
+ def preview_editable_derivative(
59
+ source: DocumentArtifact,
60
+ *,
61
+ correlation_id: str,
62
+ derivative_format: DocumentFormat,
63
+ conversion_registry: DocumentConversionRegistry,
64
+ adapter_registry: DocumentAdapterRegistry,
65
+ ) -> EditableDerivativePreview | DocumentToolResult:
66
+ try:
67
+ engine = conversion_registry.require(source.format, derivative_format)
68
+ except UnsupportedDocumentConversionError:
69
+ return unsupported_document_tool_result(
70
+ tool_id="document",
71
+ correlation_id=correlation_id,
72
+ artifact_refs=(source.artifact_id,),
73
+ message=_missing_conversion_message(source.format, derivative_format),
74
+ )
75
+ try:
76
+ payload = engine.convert_for_edit(source)
77
+ except ValueError as exc:
78
+ return unsupported_document_tool_result(
79
+ tool_id="document",
80
+ correlation_id=correlation_id,
81
+ artifact_refs=(source.artifact_id,),
82
+ message=f"Document conversion failed before authoring planning: {exc}",
83
+ reason=BlockedReason.validation_failed,
84
+ )
85
+ try:
86
+ adapter = adapter_registry.require_promoted(derivative_format)
87
+ except UnsupportedDocumentAdapterError:
88
+ return unsupported_document_tool_result(
89
+ tool_id="document",
90
+ correlation_id=correlation_id,
91
+ artifact_refs=(source.artifact_id,),
92
+ message=(
93
+ f"No promoted {derivative_format.value} adapter is registered for "
94
+ "authoring planning."
95
+ ),
96
+ )
97
+ with tempfile.TemporaryDirectory(prefix="ummaya-authoring-preview-") as temp_root:
98
+ preview_path = Path(temp_root) / f"preview.{derivative_format.value}"
99
+ preview_path.write_bytes(payload)
100
+ extraction = adapter.inspect(preview_path, artifact_id=correlation_id)
101
+ return EditableDerivativePreview(document_format=derivative_format, extraction=extraction)
102
+
103
+
104
+ def unapproved_narrative_patch_targets(
105
+ patches: tuple[DocumentFieldPatch, ...],
106
+ *,
107
+ extraction: DocumentExtraction | None,
108
+ approved_draft_id: str | None,
109
+ approved_draft_sha256: str | None,
110
+ issued_drafts: tuple[IssuedAuthoringDraft, ...],
111
+ ) -> tuple[str, ...]:
112
+ narrative_patches = _string_narrative_patches(patches, extraction=extraction)
113
+ if approved_patch_bundle_matches_issued_draft(
114
+ narrative_patches,
115
+ approved_draft_id=approved_draft_id,
116
+ approved_draft_sha256=approved_draft_sha256,
117
+ issued_drafts=issued_drafts,
118
+ ):
119
+ return ()
120
+ blocked_targets: list[str] = []
121
+ for patch in patches:
122
+ if not _patch_targets_narrative_content(patch, extraction=extraction):
123
+ continue
124
+ if _approved_patch_matches_issued_draft(
125
+ patch,
126
+ approved_draft_id=approved_draft_id,
127
+ approved_draft_sha256=approved_draft_sha256,
128
+ issued_drafts=issued_drafts,
129
+ ):
130
+ continue
131
+ blocked_targets.append(patch.target_path)
132
+ return tuple(blocked_targets)
133
+
134
+
135
+ def issue_authoring_drafts_for_unapproved_patches(
136
+ patches: tuple[DocumentFieldPatch, ...],
137
+ *,
138
+ extraction: DocumentExtraction | None,
139
+ ) -> tuple[IssuedAuthoringDraft, ...]:
140
+ drafts: list[IssuedAuthoringDraft] = []
141
+ narrative_patches: list[DocumentFieldPatch] = []
142
+ for patch in patches:
143
+ if not isinstance(patch.value, str):
144
+ continue
145
+ if not _patch_targets_narrative_content(patch, extraction=extraction):
146
+ continue
147
+ narrative_patches.append(patch)
148
+ draft_sha256 = hash_authoring_text(patch.value)
149
+ drafts.append(
150
+ IssuedAuthoringDraft(
151
+ draft_id=issued_authoring_draft_id(
152
+ target_path=patch.target_path,
153
+ draft_sha256=draft_sha256,
154
+ ),
155
+ target_path=patch.target_path,
156
+ draft_sha256=draft_sha256,
157
+ target_paths=(patch.target_path,),
158
+ )
159
+ )
160
+ if len(narrative_patches) > 1:
161
+ return (issued_authoring_bundle(tuple(narrative_patches)), *drafts)
162
+ return tuple(drafts)
163
+
164
+
165
+ def _approved_patch_matches_issued_draft(
166
+ patch: DocumentFieldPatch,
167
+ *,
168
+ approved_draft_id: str | None,
169
+ approved_draft_sha256: str | None,
170
+ issued_drafts: tuple[IssuedAuthoringDraft, ...],
171
+ ) -> bool:
172
+ if not isinstance(patch.value, str):
173
+ return False
174
+ if approved_draft_id is None or approved_draft_sha256 is None:
175
+ return False
176
+ if hash_authoring_text(patch.value) != approved_draft_sha256:
177
+ return False
178
+ for draft in issued_drafts:
179
+ if (
180
+ draft.draft_id == approved_draft_id
181
+ and draft.target_path == patch.target_path
182
+ and draft.draft_sha256 == approved_draft_sha256
183
+ ):
184
+ return True
185
+ return False
186
+
187
+
188
+ def _string_narrative_patches(
189
+ patches: tuple[DocumentFieldPatch, ...],
190
+ *,
191
+ extraction: DocumentExtraction | None,
192
+ ) -> tuple[DocumentFieldPatch, ...]:
193
+ return tuple(
194
+ patch
195
+ for patch in patches
196
+ if isinstance(patch.value, str)
197
+ and _patch_targets_narrative_content(patch, extraction=extraction)
198
+ )
199
+
200
+
201
+ def _patch_targets_narrative_content(
202
+ patch: DocumentFieldPatch,
203
+ *,
204
+ extraction: DocumentExtraction | None,
205
+ ) -> bool:
206
+ patch_key = _normalize_authoring_key(patch.target_path)
207
+ if extraction is None:
208
+ return _has_narrative_term(patch_key)
209
+ for field in extraction.fields:
210
+ field_keys = {
211
+ _normalize_authoring_key(field.field_id),
212
+ _normalize_authoring_key(field.label),
213
+ _normalize_authoring_key(field.path),
214
+ }
215
+ if patch_key not in field_keys:
216
+ continue
217
+ return any(_has_narrative_term(field_key) for field_key in field_keys)
218
+ return _has_narrative_term(patch_key)
219
+
220
+
221
+ def _has_narrative_term(value: str) -> bool:
222
+ return any(term in value for term in _NARRATIVE_TERMS)
223
+
224
+
225
+ def _normalize_authoring_key(value: str) -> str:
226
+ return "".join(character for character in value.casefold() if character.isalnum())
227
+
228
+
229
+ def _missing_conversion_message(
230
+ source_format: DocumentFormat,
231
+ derivative_format: DocumentFormat,
232
+ ) -> str:
233
+ if source_format is DocumentFormat.hwp:
234
+ return (
235
+ "HWP binary direct writing is blocked. HWP to HWPX conversion is "
236
+ "required before editing legacy HWP files. Direct HWP binary working "
237
+ "copies remain blocked. Use a HWPX or DOCX editable template, or "
238
+ "register a vetted local HWP to HWPX conversion engine."
239
+ )
240
+ return (
241
+ f"Document conversion is required before planning edits for "
242
+ f"{source_format.value} files, but no promoted "
243
+ f"{source_format.value}->{derivative_format.value} conversion engine is registered."
244
+ )
@@ -0,0 +1,76 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from hashlib import sha256
7
+ from typing import TYPE_CHECKING
8
+
9
+ from ummaya.tools.documents.authoring import hash_authoring_text
10
+
11
+ if TYPE_CHECKING:
12
+ from ummaya.tools.documents.tool_defs import DocumentFieldPatch
13
+
14
+
15
+ @dataclass(frozen=True, slots=True)
16
+ class IssuedAuthoringDraft:
17
+ draft_id: str
18
+ target_path: str
19
+ draft_sha256: str
20
+ target_paths: tuple[str, ...] = ()
21
+
22
+
23
+ def issued_authoring_draft_id(*, target_path: str, draft_sha256: str) -> str:
24
+ token = sha256(f"{target_path}\0{draft_sha256}".encode()).hexdigest()[:24]
25
+ return f"draft-{token}"
26
+
27
+
28
+ def approved_patch_bundle_matches_issued_draft(
29
+ patches: tuple[DocumentFieldPatch, ...],
30
+ *,
31
+ approved_draft_id: str | None,
32
+ approved_draft_sha256: str | None,
33
+ issued_drafts: tuple[IssuedAuthoringDraft, ...],
34
+ ) -> bool:
35
+ if len(patches) < 2 or approved_draft_id is None or approved_draft_sha256 is None:
36
+ return False
37
+ draft_sha256 = _authoring_bundle_sha256(patches)
38
+ if draft_sha256 != approved_draft_sha256:
39
+ return False
40
+ target_paths = tuple(patch.target_path for patch in patches)
41
+ return any(
42
+ draft.draft_id == approved_draft_id
43
+ and draft.draft_sha256 == approved_draft_sha256
44
+ and draft.target_paths == target_paths
45
+ for draft in issued_drafts
46
+ )
47
+
48
+
49
+ def issued_authoring_bundle(
50
+ patches: tuple[DocumentFieldPatch, ...],
51
+ ) -> IssuedAuthoringDraft:
52
+ target_paths = tuple(patch.target_path for patch in patches)
53
+ draft_sha256 = _authoring_bundle_sha256(patches)
54
+ bundle_target = _authoring_bundle_target_path(target_paths)
55
+ return IssuedAuthoringDraft(
56
+ draft_id=issued_authoring_draft_id(
57
+ target_path=bundle_target,
58
+ draft_sha256=draft_sha256,
59
+ ),
60
+ target_path=bundle_target,
61
+ draft_sha256=draft_sha256,
62
+ target_paths=target_paths,
63
+ )
64
+
65
+
66
+ def _authoring_bundle_sha256(patches: tuple[DocumentFieldPatch, ...]) -> str:
67
+ return hash_authoring_text(
68
+ "\0".join(
69
+ f"{patch.target_path}\0{hash_authoring_text(str(patch.value))}" for patch in patches
70
+ )
71
+ )
72
+
73
+
74
+ def _authoring_bundle_target_path(target_paths: tuple[str, ...]) -> str:
75
+ token = sha256("\0".join(target_paths).encode()).hexdigest()[:24]
76
+ return f"bundle:{token}"
@@ -0,0 +1,184 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Promotion scorecards for Public AX document capabilities."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from decimal import Decimal
7
+ from typing import Final, Literal
8
+
9
+ from pydantic import BaseModel, ConfigDict, Field
10
+
11
+ from ummaya.tools.documents.baselines import ConformanceBaseline
12
+ from ummaya.tools.documents.models import DocumentExtraction, TableBlock
13
+
14
+ ScoreDimension = Literal[
15
+ "extraction_fidelity",
16
+ "write_fidelity",
17
+ "style_layout_control",
18
+ "deterministic_round_trip",
19
+ "public_form_validation",
20
+ "security_privacy",
21
+ "license_maintenance_tool_usability",
22
+ ]
23
+
24
+ SCORECARD_WEIGHTS: Final[dict[ScoreDimension, int]] = {
25
+ "extraction_fidelity": 20,
26
+ "write_fidelity": 20,
27
+ "style_layout_control": 15,
28
+ "deterministic_round_trip": 15,
29
+ "public_form_validation": 15,
30
+ "security_privacy": 10,
31
+ "license_maintenance_tool_usability": 5,
32
+ }
33
+
34
+
35
+ class CapabilityScorecard(BaseModel):
36
+ """Evidence-backed promotion score for one format engine."""
37
+
38
+ model_config = ConfigDict(frozen=True, extra="forbid")
39
+
40
+ extraction_fidelity: int = Field(
41
+ ge=0,
42
+ le=SCORECARD_WEIGHTS["extraction_fidelity"],
43
+ )
44
+ write_fidelity: int = Field(
45
+ ge=0,
46
+ le=SCORECARD_WEIGHTS["write_fidelity"],
47
+ )
48
+ style_layout_control: int = Field(
49
+ ge=0,
50
+ le=SCORECARD_WEIGHTS["style_layout_control"],
51
+ )
52
+ deterministic_round_trip: int = Field(
53
+ ge=0,
54
+ le=SCORECARD_WEIGHTS["deterministic_round_trip"],
55
+ )
56
+ public_form_validation: int = Field(
57
+ ge=0,
58
+ le=SCORECARD_WEIGHTS["public_form_validation"],
59
+ )
60
+ security_privacy: int = Field(
61
+ ge=0,
62
+ le=SCORECARD_WEIGHTS["security_privacy"],
63
+ )
64
+ license_maintenance_tool_usability: int = Field(
65
+ ge=0,
66
+ le=SCORECARD_WEIGHTS["license_maintenance_tool_usability"],
67
+ )
68
+
69
+ security_gate_passed: bool = True
70
+ write_hard_gates_passed: bool = True
71
+ critical_security_findings: tuple[str, ...] = Field(default_factory=tuple)
72
+ evidence_refs: tuple[str, ...] = Field(default_factory=tuple)
73
+
74
+ @property
75
+ def total_score(self) -> int:
76
+ """Return the weighted 100-point total for this scorecard."""
77
+ return (
78
+ self.extraction_fidelity
79
+ + self.write_fidelity
80
+ + self.style_layout_control
81
+ + self.deterministic_round_trip
82
+ + self.public_form_validation
83
+ + self.security_privacy
84
+ + self.license_maintenance_tool_usability
85
+ )
86
+
87
+
88
+ class PublicFormMetricScore(BaseModel):
89
+ """Semantic and structural public-form metric bundle."""
90
+
91
+ model_config = ConfigDict(frozen=True, extra="forbid")
92
+
93
+ paragraph_block_f1: Decimal = Field(ge=0, le=1)
94
+ table_cell_f1: Decimal = Field(ge=0, le=1)
95
+ image_reference_f1: Decimal = Field(ge=0, le=1)
96
+ metadata_exact_match: Decimal = Field(ge=0, le=1)
97
+ aggregate_score: Decimal = Field(ge=0, le=1)
98
+
99
+
100
+ def compute_public_form_metrics(
101
+ extraction: DocumentExtraction,
102
+ baseline: ConformanceBaseline,
103
+ ) -> PublicFormMetricScore:
104
+ """Compute the offline semantic metrics used by public-form validation."""
105
+ paragraph_f1 = _paragraph_f1(extraction, baseline)
106
+ table_f1 = _table_cell_f1(extraction, baseline)
107
+ image_f1 = Decimal("1")
108
+ metadata_match = _metadata_exact_match(extraction, baseline)
109
+ return PublicFormMetricScore(
110
+ paragraph_block_f1=paragraph_f1,
111
+ table_cell_f1=table_f1,
112
+ image_reference_f1=image_f1,
113
+ metadata_exact_match=metadata_match,
114
+ aggregate_score=_macro_average((paragraph_f1, table_f1, image_f1, metadata_match)),
115
+ )
116
+
117
+
118
+ def _paragraph_f1(extraction: DocumentExtraction, baseline: ConformanceBaseline) -> Decimal:
119
+ expected = {
120
+ item.text
121
+ for item in (
122
+ *baseline.protected_text,
123
+ *baseline.required_labels,
124
+ *baseline.signature_regions,
125
+ )
126
+ }
127
+ observed = {paragraph.text for paragraph in extraction.paragraphs}
128
+ observed.update(cell.text for table in extraction.tables for cell in table.cells)
129
+ return _set_f1(expected, observed)
130
+
131
+
132
+ def _table_cell_f1(extraction: DocumentExtraction, baseline: ConformanceBaseline) -> Decimal:
133
+ expected = {
134
+ (geometry.table_id, row, column)
135
+ for geometry in baseline.table_geometries
136
+ for row in range(geometry.rows)
137
+ for column in range(geometry.columns)
138
+ }
139
+ observed = {
140
+ (table.block_id, cell.row_index, cell.column_index)
141
+ for table in extraction.tables
142
+ for cell in table.cells
143
+ }
144
+ return _set_f1(expected, observed)
145
+
146
+
147
+ def _metadata_exact_match(
148
+ extraction: DocumentExtraction,
149
+ baseline: ConformanceBaseline,
150
+ ) -> Decimal:
151
+ expected = dict(baseline.metadata_exact_matches)
152
+ if baseline.expected_page_count is not None:
153
+ expected["page_count"] = baseline.expected_page_count
154
+ if not expected:
155
+ return Decimal("1")
156
+ matches = sum(1 for key, value in expected.items() if extraction.metadata.get(key) == value)
157
+ return Decimal(matches) / Decimal(len(expected))
158
+
159
+
160
+ def _set_f1[F1Item](expected: set[F1Item], observed: set[F1Item]) -> Decimal:
161
+ if not expected and not observed:
162
+ return Decimal("1")
163
+ if not expected or not observed:
164
+ return Decimal("0")
165
+ matches = len(expected & observed)
166
+ if matches == 0:
167
+ return Decimal("0")
168
+ precision = Decimal(matches) / Decimal(len(observed))
169
+ recall = Decimal(matches) / Decimal(len(expected))
170
+ return (Decimal("2") * precision * recall) / (precision + recall)
171
+
172
+
173
+ def _macro_average(values: tuple[Decimal, Decimal, Decimal, Decimal]) -> Decimal:
174
+ return sum(values, Decimal("0")) / Decimal(len(values))
175
+
176
+
177
+ def table_shape(table: TableBlock | None) -> tuple[int, int]:
178
+ """Return the row and column shape for a normalized table block."""
179
+ if table is None or not table.cells:
180
+ return 0, 0
181
+ return (
182
+ max(cell.row_index + cell.row_span for cell in table.cells),
183
+ max(cell.column_index + cell.column_span for cell in table.cells),
184
+ )
@@ -0,0 +1,193 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from collections.abc import Mapping
7
+ from typing import Final
8
+
9
+ from ummaya.tools.documents.models import FormSlot, ScalarValue
10
+
11
+ _NEEDS_INPUT_PREFIX: Final[str] = "needs_input:"
12
+ _BLOCKED_MISSING_EVIDENCE_PREFIX: Final[str] = "blocked_missing_evidence:"
13
+ _DRAFT_REQUIRES_APPROVAL_PREFIX: Final[str] = "draft_requires_approval:"
14
+
15
+ _FABRICATION_TERMS: Final[tuple[str, ...]] = (
16
+ "대충",
17
+ "그럴듯",
18
+ "그럴싸",
19
+ "적당히",
20
+ "임의로",
21
+ )
22
+ _AUTHORING_TERMS: Final[tuple[str, ...]] = (
23
+ "작성",
24
+ "써줘",
25
+ "써",
26
+ "완성",
27
+ "채워",
28
+ "기입",
29
+ "해줘",
30
+ )
31
+ _NARRATIVE_TERMS: Final[tuple[str, ...]] = (
32
+ "자기소개",
33
+ "지원동기",
34
+ "성장과정",
35
+ "경험",
36
+ "경력",
37
+ "수상",
38
+ "사업계획",
39
+ "계획",
40
+ "시장",
41
+ "예산",
42
+ "성과",
43
+ "목표",
44
+ "제안내용",
45
+ "문항",
46
+ "에세이",
47
+ )
48
+
49
+
50
+ def apply_socratic_fill_gate(
51
+ slot: FormSlot,
52
+ *,
53
+ instruction: str,
54
+ session_context: Mapping[str, ScalarValue],
55
+ explicit_value_provided: bool,
56
+ context_value_provided: bool,
57
+ broad_autonomous_fill: bool,
58
+ ) -> FormSlot:
59
+ if explicit_value_provided:
60
+ return _with_provenance(slot, "user_provided_explicit_value")
61
+ if slot.protected:
62
+ return slot
63
+ if _is_document_derived_candidate(slot):
64
+ return _with_provenance(slot, "document_derived")
65
+ if _instruction_requests_fabrication(instruction) and _slot_is_empty(slot):
66
+ return _with_socratic_evidence(
67
+ slot,
68
+ prefix=_BLOCKED_MISSING_EVIDENCE_PREFIX,
69
+ candidate_value=None,
70
+ )
71
+ if _is_narrative_slot(slot) and _slot_is_empty(slot):
72
+ return _gate_narrative_slot(
73
+ slot,
74
+ session_context=session_context,
75
+ context_value_provided=context_value_provided,
76
+ )
77
+ if broad_autonomous_fill and _slot_is_empty(slot):
78
+ if context_value_provided:
79
+ return _with_provenance(slot, "user_provided_context")
80
+ return _with_socratic_evidence(slot, prefix=_NEEDS_INPUT_PREFIX, candidate_value=None)
81
+ return slot
82
+
83
+
84
+ def socratic_slot_requires_input(slot: FormSlot) -> bool:
85
+ return slot.evidence_text is not None and slot.evidence_text.startswith(
86
+ (
87
+ _NEEDS_INPUT_PREFIX,
88
+ _BLOCKED_MISSING_EVIDENCE_PREFIX,
89
+ _DRAFT_REQUIRES_APPROVAL_PREFIX,
90
+ )
91
+ )
92
+
93
+
94
+ def _gate_narrative_slot(
95
+ slot: FormSlot,
96
+ *,
97
+ session_context: Mapping[str, ScalarValue],
98
+ context_value_provided: bool,
99
+ ) -> FormSlot:
100
+ if not context_value_provided:
101
+ return _with_socratic_evidence(slot, prefix=_NEEDS_INPUT_PREFIX, candidate_value=None)
102
+ if _context_has_approval(slot, session_context):
103
+ return slot.model_copy(update={"evidence_text": "approved_user_draft"})
104
+ return _with_socratic_evidence(
105
+ slot,
106
+ prefix=_DRAFT_REQUIRES_APPROVAL_PREFIX,
107
+ candidate_value=None,
108
+ )
109
+
110
+
111
+ def _with_socratic_evidence(
112
+ slot: FormSlot,
113
+ *,
114
+ prefix: str,
115
+ candidate_value: ScalarValue,
116
+ ) -> FormSlot:
117
+ return slot.model_copy(
118
+ update={
119
+ "candidate_value": candidate_value,
120
+ "evidence_text": f"{prefix}{_question_for_slot(slot)}",
121
+ }
122
+ )
123
+
124
+
125
+ def _with_provenance(slot: FormSlot, evidence_text: str) -> FormSlot:
126
+ if slot.candidate_value is None or slot.evidence_text is not None:
127
+ return slot
128
+ return slot.model_copy(update={"evidence_text": evidence_text})
129
+
130
+
131
+ def _question_for_slot(slot: FormSlot) -> str:
132
+ return f"{slot.label} 항목을 작성할 사용자 제공 근거를 알려주세요."
133
+
134
+
135
+ def _is_document_derived_candidate(slot: FormSlot) -> bool:
136
+ if slot.candidate_value is None:
137
+ return False
138
+ slot_key = _slot_key(slot)
139
+ if ("주차" in slot_key or "week" in slot_key) and slot.current_value is not None:
140
+ return True
141
+ return (
142
+ "활동기간" in slot_key or "활동일시" in slot_key or "period" in slot_key
143
+ ) and slot.current_value is not None
144
+
145
+
146
+ def _is_narrative_slot(slot: FormSlot) -> bool:
147
+ slot_key = _slot_key(slot)
148
+ return any(term in slot_key for term in _NARRATIVE_TERMS)
149
+
150
+
151
+ def _instruction_requests_fabrication(instruction: str) -> bool:
152
+ instruction_key = _normalize_key(instruction)
153
+ return any(term in instruction_key for term in _FABRICATION_TERMS) and any(
154
+ term in instruction_key for term in _AUTHORING_TERMS
155
+ )
156
+
157
+
158
+ def _context_has_approval(
159
+ slot: FormSlot,
160
+ session_context: Mapping[str, ScalarValue],
161
+ ) -> bool:
162
+ approval_keys = _approval_keys_for_slot(slot)
163
+ for key, value in session_context.items():
164
+ if _normalize_key(key) not in approval_keys:
165
+ continue
166
+ if value is True:
167
+ return True
168
+ if isinstance(value, str) and _normalize_key(value) in {"승인", "approved", "approve"}:
169
+ return True
170
+ return False
171
+
172
+
173
+ def _approval_keys_for_slot(slot: FormSlot) -> set[str]:
174
+ keys: set[str] = set()
175
+ for label in (slot.slot_id, slot.label, slot.source_anchor.format_path):
176
+ normalized = _normalize_key(label)
177
+ keys.add(f"approved{normalized}")
178
+ keys.add(f"approval{normalized}")
179
+ keys.add(f"승인{normalized}")
180
+ return keys
181
+
182
+
183
+ def _slot_is_empty(slot: FormSlot) -> bool:
184
+ value = slot.current_value
185
+ return value is None or (isinstance(value, str) and value.strip() == "")
186
+
187
+
188
+ def _slot_key(slot: FormSlot) -> str:
189
+ return _normalize_key(f"{slot.slot_id} {slot.label} {slot.source_anchor.format_path}")
190
+
191
+
192
+ def _normalize_key(value: str) -> str:
193
+ return re.sub(r"[^0-9a-z가-힣]+", "", value.casefold())