ummaya 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (482) hide show
  1. package/README.md +15 -2
  2. package/bin/ummaya +10 -1
  3. package/bun.lock +180 -244
  4. package/npm-shrinkwrap.json +760 -1760
  5. package/package.json +39 -22
  6. package/prompts/manifest.yaml +1 -1
  7. package/prompts/system_v1.md +1 -0
  8. package/pyproject.toml +27 -2
  9. package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
  10. package/src/ummaya/_canonical/__init__.py +2 -0
  11. package/src/ummaya/_canonical/baselines.yaml +113 -0
  12. package/src/ummaya/engine/engine.py +29 -132
  13. package/src/ummaya/evidence/__init__.py +21 -2
  14. package/src/ummaya/evidence/dataset_contract.py +193 -0
  15. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  16. package/src/ummaya/evidence/document_harness.py +313 -0
  17. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  18. package/src/ummaya/evidence/gates.py +70 -0
  19. package/src/ummaya/evidence/json_types.py +20 -0
  20. package/src/ummaya/evidence/models.py +88 -1
  21. package/src/ummaya/evidence/output_payload.py +89 -0
  22. package/src/ummaya/evidence/payload_documents.py +233 -0
  23. package/src/ummaya/evidence/route_contracts.py +224 -0
  24. package/src/ummaya/evidence/route_helpers.py +150 -0
  25. package/src/ummaya/evidence/runner.py +81 -212
  26. package/src/ummaya/evidence/source_provenance.py +246 -0
  27. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  28. package/src/ummaya/evidence/tool_layer.py +39 -0
  29. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  30. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  31. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  32. package/src/ummaya/ipc/frame_schema.py +5 -5
  33. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  34. package/src/ummaya/ipc/stdio.py +1109 -477
  35. package/src/ummaya/llm/client.py +102 -3
  36. package/src/ummaya/llm/config.py +8 -3
  37. package/src/ummaya/primitives/__init__.py +6 -2
  38. package/src/ummaya/primitives/delegation.py +1 -1
  39. package/src/ummaya/primitives/document.py +28 -0
  40. package/src/ummaya/settings.py +0 -3
  41. package/src/ummaya/tools/discovery_bridge.py +17 -1
  42. package/src/ummaya/tools/documents/__init__.py +297 -0
  43. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  44. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  45. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  46. package/src/ummaya/tools/documents/authoring.py +283 -0
  47. package/src/ummaya/tools/documents/baselines.py +132 -0
  48. package/src/ummaya/tools/documents/capability.py +331 -0
  49. package/src/ummaya/tools/documents/contracts.py +112 -0
  50. package/src/ummaya/tools/documents/conversion.py +521 -0
  51. package/src/ummaya/tools/documents/diff.py +275 -0
  52. package/src/ummaya/tools/documents/engines.py +163 -0
  53. package/src/ummaya/tools/documents/evaluation.py +291 -0
  54. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  55. package/src/ummaya/tools/documents/fixtures.py +174 -0
  56. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  57. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  58. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  59. package/src/ummaya/tools/documents/formats/base.py +41 -0
  60. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  61. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  62. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  63. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  64. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  65. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  66. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  67. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  68. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  69. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  70. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  71. package/src/ummaya/tools/documents/inspection.py +289 -0
  72. package/src/ummaya/tools/documents/intake.py +1079 -0
  73. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  74. package/src/ummaya/tools/documents/models.py +1598 -0
  75. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  76. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  77. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  78. package/src/ummaya/tools/documents/patch.py +170 -0
  79. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  80. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  81. package/src/ummaya/tools/documents/permissions.py +110 -0
  82. package/src/ummaya/tools/documents/planner.py +616 -0
  83. package/src/ummaya/tools/documents/registry.py +2733 -0
  84. package/src/ummaya/tools/documents/render.py +978 -0
  85. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  86. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  87. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  88. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  89. package/src/ummaya/tools/documents/reread.py +157 -0
  90. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  91. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  92. package/src/ummaya/tools/documents/scorecard.py +184 -0
  93. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  94. package/src/ummaya/tools/documents/style.py +48 -0
  95. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  96. package/src/ummaya/tools/documents/validate.py +347 -0
  97. package/src/ummaya/tools/executor.py +29 -0
  98. package/src/ummaya/tools/live_proxy.py +0 -3
  99. package/src/ummaya/tools/models.py +5 -1
  100. package/src/ummaya/tools/register_all.py +8 -0
  101. package/src/ummaya/tools/registry.py +10 -1
  102. package/src/ummaya/tools/routing/__init__.py +59 -0
  103. package/src/ummaya/tools/routing/builder.py +105 -0
  104. package/src/ummaya/tools/routing/cards.py +29 -0
  105. package/src/ummaya/tools/routing/decision_service.py +534 -0
  106. package/src/ummaya/tools/routing/decision_types.py +74 -0
  107. package/src/ummaya/tools/routing/feasibility.py +122 -0
  108. package/src/ummaya/tools/routing/intent.py +17 -0
  109. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  110. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  111. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  112. package/src/ummaya/tools/routing/intent_types.py +48 -0
  113. package/src/ummaya/tools/routing/lint.py +78 -0
  114. package/src/ummaya/tools/routing/metadata.py +174 -0
  115. package/src/ummaya/tools/routing/projection.py +340 -0
  116. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  117. package/src/ummaya/tools/routing/schema.py +81 -0
  118. package/src/ummaya/tools/routing/types.py +96 -0
  119. package/src/ummaya/tools/routing_index.py +2 -2
  120. package/src/ummaya/tools/search.py +34 -746
  121. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  122. package/tui/bun.lock +126 -305
  123. package/tui/package.json +35 -22
  124. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  125. package/tui/src/QueryEngine.ts +12 -8
  126. package/tui/src/bridge/inboundAttachments.ts +3 -3
  127. package/tui/src/cli/handlers/auth.ts +3 -12
  128. package/tui/src/cli/handlers/mcp.tsx +0 -1
  129. package/tui/src/cli/print.ts +8 -9
  130. package/tui/src/commands/insights.ts +1 -1
  131. package/tui/src/commands/install-github-app/types.ts +8 -30
  132. package/tui/src/commands/plugin/types.ts +6 -28
  133. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  134. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  135. package/tui/src/components/Feedback.tsx +1 -1
  136. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  137. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  138. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  139. package/tui/src/components/Spinner/types.ts +6 -28
  140. package/tui/src/components/agents/generateAgent.ts +1 -1
  141. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  142. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  143. package/tui/src/components/mcp/types.ts +16 -38
  144. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  145. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  146. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  147. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  148. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  149. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  150. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  151. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  152. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  153. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  154. package/tui/src/components/primitive/index.tsx +43 -1
  155. package/tui/src/components/primitive/types.ts +137 -0
  156. package/tui/src/components/ui/option.ts +4 -26
  157. package/tui/src/constants/common.ts +0 -2
  158. package/tui/src/constants/prompts.ts +4 -3
  159. package/tui/src/constants/querySource.ts +4 -26
  160. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  161. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  162. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  163. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  164. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  165. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  166. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  167. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  168. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  169. package/tui/src/ink/ink.tsx +33 -14
  170. package/tui/src/ink/reconciler.ts +2 -3
  171. package/tui/src/ink/render-to-screen.ts +30 -10
  172. package/tui/src/ipc/bridge.ts +62 -15
  173. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  174. package/tui/src/ipc/codec.ts +3 -3
  175. package/tui/src/ipc/frames.generated.ts +12 -12
  176. package/tui/src/ipc/llmClient.ts +151 -27
  177. package/tui/src/ipc/schema/frame.schema.json +1 -1
  178. package/tui/src/keybindings/defaultBindings.ts +4 -0
  179. package/tui/src/main.tsx +32 -15
  180. package/tui/src/native-ts/file-index/index.ts +33 -3
  181. package/tui/src/observability/surface.ts +2 -2
  182. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  183. package/tui/src/projectOnboardingState.ts +7 -6
  184. package/tui/src/query/chatMessageTypes.ts +18 -0
  185. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  186. package/tui/src/query/deps.ts +1 -1
  187. package/tui/src/query/messageGuards.ts +106 -0
  188. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  189. package/tui/src/query/run.ts +1075 -0
  190. package/tui/src/query/supportBoundary.ts +168 -0
  191. package/tui/src/query/toolResultErrors.ts +103 -0
  192. package/tui/src/query/toolRunner.ts +687 -0
  193. package/tui/src/query/unavailableToolRepair.ts +118 -0
  194. package/tui/src/query.ts +9 -2186
  195. package/tui/src/screens/REPL.tsx +40 -29
  196. package/tui/src/services/api/adapterManifest.ts +4 -0
  197. package/tui/src/services/api/backendChat/events.ts +117 -0
  198. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  199. package/tui/src/services/api/backendChat/frame.ts +9 -0
  200. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  201. package/tui/src/services/api/backendChat/types.ts +62 -0
  202. package/tui/src/services/api/backendChat.ts +1 -0
  203. package/tui/src/services/api/client.ts +65 -2
  204. package/tui/src/services/api/errorUtils.ts +5 -5
  205. package/tui/src/services/api/errors.ts +1 -1
  206. package/tui/src/services/api/logging.ts +1 -1
  207. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  208. package/tui/src/services/api/ummaya/messages.ts +255 -0
  209. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  210. package/tui/src/services/api/ummaya/provider.ts +200 -0
  211. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  212. package/tui/src/services/api/ummaya/request.ts +200 -0
  213. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  214. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  215. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  216. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  217. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  218. package/tui/src/services/api/ummaya/types.ts +110 -0
  219. package/tui/src/services/api/ummaya/usage.ts +30 -0
  220. package/tui/src/services/api/ummaya.ts +26 -418
  221. package/tui/src/services/api/withRetry.ts +1 -1
  222. package/tui/src/services/awaySummary.ts +2 -2
  223. package/tui/src/services/claudeAiLimits.ts +1 -1
  224. package/tui/src/services/compact/autoCompact.ts +1 -1
  225. package/tui/src/services/compact/compact.ts +1 -1
  226. package/tui/src/services/lsp/types.ts +8 -30
  227. package/tui/src/services/tips/types.ts +6 -28
  228. package/tui/src/services/tokenEstimation.ts +1 -1
  229. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  230. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  231. package/tui/src/services/tools/toolExecution.ts +94 -1
  232. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  233. package/tui/src/store/session-store.ts +10 -36
  234. package/tui/src/stubs/any-stub.ts +15 -10
  235. package/tui/src/stubs/color-diff-napi.ts +37 -23
  236. package/tui/src/stubs/globals.d.ts +3 -3
  237. package/tui/src/stubs/macro-preload.ts +23 -12
  238. package/tui/src/tools/AdapterTool/AdapterTool.ts +1207 -714
  239. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  240. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  241. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  242. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  243. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  244. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  245. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  246. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  247. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  248. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  249. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  250. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  251. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  252. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  253. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  254. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  255. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  256. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  257. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  258. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  259. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  260. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  261. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  262. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  263. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  264. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  265. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  266. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  267. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  268. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  269. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  270. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  271. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  272. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  273. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  274. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  275. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  276. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  277. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  278. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  279. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  280. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  281. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  282. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  283. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  284. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  285. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  286. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  287. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  288. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  289. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  290. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  291. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  292. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  293. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  294. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  295. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  296. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  297. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  298. package/tui/src/tools/BashTool/call.ts +202 -0
  299. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  300. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  301. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  302. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  303. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  304. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  305. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  306. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  307. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  308. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  309. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  310. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  311. package/tui/src/tools/BashTool/schemas.ts +65 -0
  312. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  313. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  314. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  315. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  316. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  317. package/tui/src/tools/BriefTool/upload.ts +1 -1
  318. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  319. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  320. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  321. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  322. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  323. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  324. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  325. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  326. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  327. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  328. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  329. package/tui/src/tools/FileEditTool/call.ts +228 -0
  330. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  331. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  332. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  333. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  334. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  335. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  336. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +25 -32
  337. package/tui/src/tools/LookupPrimitive/prompt.ts +0 -2
  338. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  339. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  340. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  341. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  342. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  343. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  344. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  345. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  346. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  347. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  348. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  349. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  350. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  351. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  352. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  353. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  354. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  355. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  356. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  357. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  358. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  359. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  360. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +1 -11
  361. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  362. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  363. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +27 -10
  364. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  365. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  366. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  367. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  368. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  369. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  370. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  371. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  372. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  373. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  374. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  375. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  376. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  377. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  378. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  379. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  380. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  381. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  382. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  383. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  384. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  385. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  386. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  387. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  388. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  389. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +2 -1
  390. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  391. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  392. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  393. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  394. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  395. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  396. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  397. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  398. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  399. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  400. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  401. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  402. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  403. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  404. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  405. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  406. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  407. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  408. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  409. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  410. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  411. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  412. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  413. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  414. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  415. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  416. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  417. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  418. package/tui/src/tools/_shared/rootPrimitiveInput.ts +1 -0
  419. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  420. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  421. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  422. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  423. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  424. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  425. package/tui/src/tools/_shared/toolChoiceRepair.ts +55 -860
  426. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  427. package/tui/src/tools.ts +39 -190
  428. package/tui/src/types/fileSuggestion.ts +4 -26
  429. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  430. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  431. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  432. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  433. package/tui/src/types/message.ts +80 -102
  434. package/tui/src/types/messageQueueTypes.ts +6 -28
  435. package/tui/src/types/notebook.ts +16 -38
  436. package/tui/src/types/statusLine.ts +4 -26
  437. package/tui/src/types/tools.ts +24 -46
  438. package/tui/src/types/utils.ts +6 -28
  439. package/tui/src/upstreamproxy/relay.ts +7 -3
  440. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  441. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  442. package/tui/src/utils/auth.ts +129 -139
  443. package/tui/src/utils/bash/ast.ts +23 -23
  444. package/tui/src/utils/bash/bashParser.ts +5 -5
  445. package/tui/src/utils/billing.ts +1 -1
  446. package/tui/src/utils/claudeDesktop.ts +4 -4
  447. package/tui/src/utils/collapseReadSearch.ts +3 -3
  448. package/tui/src/utils/cronTasks.ts +1 -1
  449. package/tui/src/utils/execFileNoThrow.ts +1 -1
  450. package/tui/src/utils/filePersistence/types.ts +16 -38
  451. package/tui/src/utils/forkedAgent.ts +1 -1
  452. package/tui/src/utils/gracefulShutdown.ts +4 -4
  453. package/tui/src/utils/heapDumpService.ts +12 -8
  454. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  455. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  456. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  457. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  458. package/tui/src/utils/messages.ts +18 -0
  459. package/tui/src/utils/migrateSessions.ts +3 -3
  460. package/tui/src/utils/model/model.ts +6 -6
  461. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  462. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  463. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  464. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  465. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  466. package/tui/src/utils/protectedNamespace.ts +5 -3
  467. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  468. package/tui/src/utils/ripgrep.ts +16 -7
  469. package/tui/src/utils/sessionTitle.ts +1 -1
  470. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  471. package/tui/src/utils/shell/prefix.ts +1 -1
  472. package/tui/src/utils/sideQuery.ts +1 -1
  473. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  474. package/tui/src/utils/teleport.tsx +1 -1
  475. package/uv.lock +426 -45
  476. package/tui/src/services/api/claude.ts +0 -3540
  477. package/tui/src/tools/_shared/directPublicDataGuard.ts +0 -362
  478. package/tui/src/tools/_shared/kmaAnalysisGuard.ts +0 -197
  479. package/tui/src/tools/_shared/kmaAviationGuard.ts +0 -70
  480. package/tui/src/tools/_shared/nmcAedGuard.ts +0 -234
  481. package/tui/src/tools/_shared/protectedCheckGuard.ts +0 -207
  482. package/tui/src/tools/_shared/textToolCallGuard.ts +0 -91
@@ -0,0 +1,291 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Candidate-engine evaluation loop for the Public AX document harness."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from pathlib import Path
7
+ from typing import Literal, cast
8
+
9
+ import yaml
10
+ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
11
+
12
+ from ummaya.tools.documents.capability import (
13
+ CapabilityOperation,
14
+ DocumentFormat,
15
+ FormatCapabilityProfile,
16
+ PromotionOperation,
17
+ evaluate_capability_promotion,
18
+ )
19
+ from ummaya.tools.documents.scorecard import CapabilityScorecard
20
+
21
+ GateState = Literal["pass", "fail", "defer"]
22
+ DependencyPermissionBoundary = Literal["document_primitive_only", "not_applicable"]
23
+ DependencyReason = Literal[
24
+ "dependency_gate_failed",
25
+ "dependency_gate_deferred",
26
+ "license_gate_failed",
27
+ "license_gate_deferred",
28
+ ]
29
+ CandidateDecisionReason = str
30
+ DataGoKrUsageScope = Literal[
31
+ "semantic_structure_evaluation",
32
+ "table_extraction_evaluation",
33
+ "image_reference_evaluation",
34
+ "summary_rewrite_evaluation",
35
+ ]
36
+ SemanticMetricComponent = Literal[
37
+ "paragraph_block_f1",
38
+ "table_cell_f1",
39
+ "image_reference_f1",
40
+ "metadata_exact_match",
41
+ ]
42
+
43
+
44
+ class CandidateLicenseGate(BaseModel):
45
+ """License review gate for one candidate engine."""
46
+
47
+ model_config = ConfigDict(frozen=True, extra="forbid")
48
+
49
+ spdx: str = Field(min_length=1)
50
+ gate: GateState
51
+ notes: str = Field(min_length=1)
52
+
53
+
54
+ class CandidateDependencyGate(BaseModel):
55
+ """Runtime dependency review gate for one candidate engine."""
56
+
57
+ model_config = ConfigDict(frozen=True, extra="forbid")
58
+
59
+ runtime_dependency: bool
60
+ gate: GateState
61
+ notes: str = Field(min_length=1)
62
+ requires_adr: bool = False
63
+ adr_ref: str | None = None
64
+ permission_boundary: DependencyPermissionBoundary = "not_applicable"
65
+ local_only_execution: bool = True
66
+ package_ref: str | None = None
67
+
68
+ @model_validator(mode="after")
69
+ def _enforce_runtime_bridge_gate(self) -> CandidateDependencyGate:
70
+ if self.gate == "pass" and not self.local_only_execution:
71
+ raise ValueError("local_only_execution must be true for passed dependency gates")
72
+ if not self.requires_adr:
73
+ return self
74
+ if self.adr_ref is None:
75
+ raise ValueError("requires_adr dependency gates require adr_ref")
76
+ if not self.adr_ref.startswith("docs/adr/ADR-"):
77
+ raise ValueError("adr_ref must point at docs/adr/ADR-*.md")
78
+ if self.permission_boundary != "document_primitive_only":
79
+ raise ValueError(
80
+ "requires_adr document bridges must use document_primitive_only permission"
81
+ )
82
+ if self.package_ref is None:
83
+ raise ValueError("requires_adr dependency gates require package_ref")
84
+ return self
85
+
86
+
87
+ class CandidateProfile(BaseModel):
88
+ """Fixture-backed candidate profile evaluated by the promotion loop."""
89
+
90
+ model_config = ConfigDict(frozen=True, extra="forbid")
91
+
92
+ format: DocumentFormat
93
+ engine_id: str = Field(min_length=1, max_length=128, pattern=r"^[A-Za-z0-9_.-]+$")
94
+ supported_operations: tuple[CapabilityOperation, ...] = Field(min_length=1)
95
+ evaluate_operations: tuple[PromotionOperation, ...] = Field(min_length=1)
96
+ license: CandidateLicenseGate
97
+ dependency: CandidateDependencyGate
98
+ scorecard: CapabilityScorecard
99
+ evidence_refs: tuple[str, ...]
100
+ decision_note: str = Field(min_length=1)
101
+ operation_notes: dict[PromotionOperation, str] = Field(default_factory=dict)
102
+
103
+ @field_validator("supported_operations", "evaluate_operations")
104
+ @classmethod
105
+ def _operations_are_unique(cls, operations: tuple[str, ...]) -> tuple[str, ...]:
106
+ if len(set(operations)) != len(operations):
107
+ raise ValueError("operations must be unique")
108
+ return operations
109
+
110
+ @field_validator("evidence_refs")
111
+ @classmethod
112
+ def _evidence_is_offline(cls, evidence_refs: tuple[str, ...]) -> tuple[str, ...]:
113
+ if not evidence_refs:
114
+ raise ValueError("evidence_refs must not be empty")
115
+ if any(ref.startswith("live:") for ref in evidence_refs):
116
+ raise ValueError("live evidence refs are forbidden")
117
+ return evidence_refs
118
+
119
+
120
+ class CandidateProfileManifest(BaseModel):
121
+ """Offline manifest of candidate engine profiles."""
122
+
123
+ model_config = ConfigDict(frozen=True, extra="forbid")
124
+
125
+ version: Literal[1]
126
+ run_id: str = Field(min_length=1)
127
+ created_at: str = Field(min_length=1)
128
+ source_policy: Literal["offline_fixtures_only"]
129
+ live_network_allowed: Literal[False]
130
+ profiles: tuple[CandidateProfile, ...] = Field(min_length=1)
131
+
132
+
133
+ class CandidateDecision(BaseModel):
134
+ """One operation-level candidate evaluation decision."""
135
+
136
+ model_config = ConfigDict(frozen=True, extra="forbid")
137
+
138
+ format: DocumentFormat
139
+ engine_id: str
140
+ operation: PromotionOperation
141
+ promoted: bool
142
+ score: int
143
+ required_score: int
144
+ reasons: tuple[CandidateDecisionReason, ...]
145
+ dependency_gate_passed: bool
146
+ license_gate_passed: bool
147
+ decision_note: str
148
+ evidence_refs: tuple[str, ...]
149
+
150
+
151
+ class CandidateEvaluationRun(BaseModel):
152
+ """Result of evaluating every candidate operation in a manifest."""
153
+
154
+ model_config = ConfigDict(frozen=True, extra="forbid")
155
+
156
+ run_id: str
157
+ live_network_allowed: Literal[False]
158
+ decisions: tuple[CandidateDecision, ...]
159
+
160
+
161
+ class DataGoKrMetadataRecord(BaseModel):
162
+ """One offline metadata record for semantic public-document evaluation."""
163
+
164
+ model_config = ConfigDict(frozen=True, extra="forbid")
165
+
166
+ record_id: str = Field(min_length=1)
167
+ provider: str = Field(min_length=1)
168
+ expected_semantic_fields: tuple[str, ...] = Field(min_length=1)
169
+ negative_assertion: str = Field(min_length=1)
170
+
171
+
172
+ class DataGoKrMetadataSnapshot(BaseModel):
173
+ """Offline data.go.kr corpus metadata used as evaluation context only."""
174
+
175
+ model_config = ConfigDict(frozen=True, extra="forbid")
176
+
177
+ version: Literal[1]
178
+ snapshot_id: str = Field(min_length=1)
179
+ created_at: str = Field(min_length=1)
180
+ source_policy: Literal["offline_metadata_snapshot"]
181
+ live_network_allowed: Literal[False]
182
+ dataset_name: str = Field(min_length=1)
183
+ source_ref: str = Field(min_length=1)
184
+ redistribution_status: Literal["metadata_only"]
185
+ authoritative_layout_oracle: Literal[False]
186
+ usage_scope: tuple[DataGoKrUsageScope, ...] = Field(min_length=1)
187
+ metric_components: tuple[SemanticMetricComponent, ...] = Field(min_length=1)
188
+ aggregate_threshold: float = Field(ge=0, le=1)
189
+ records: tuple[DataGoKrMetadataRecord, ...] = Field(min_length=1)
190
+
191
+ @model_validator(mode="after")
192
+ def _require_macro_average_components(self) -> DataGoKrMetadataSnapshot:
193
+ required: tuple[SemanticMetricComponent, ...] = (
194
+ "paragraph_block_f1",
195
+ "table_cell_f1",
196
+ "image_reference_f1",
197
+ "metadata_exact_match",
198
+ )
199
+ if self.metric_components != required:
200
+ raise ValueError("metric_components must match the FR-037 macro-average order")
201
+ return self
202
+
203
+
204
+ def load_candidate_profiles(path: Path) -> CandidateProfileManifest:
205
+ """Load candidate profiles from an offline YAML fixture."""
206
+ raw = _load_yaml_mapping(path)
207
+ return CandidateProfileManifest.model_validate(raw)
208
+
209
+
210
+ def evaluate_candidate_profiles(
211
+ manifest: CandidateProfileManifest,
212
+ ) -> CandidateEvaluationRun:
213
+ """Evaluate profile operations through dependency, license, and score gates."""
214
+ decisions: list[CandidateDecision] = []
215
+ for profile in manifest.profiles:
216
+ capability_profile = FormatCapabilityProfile(
217
+ format=profile.format,
218
+ engine_id=profile.engine_id,
219
+ supported_operations=profile.supported_operations,
220
+ evidence_refs=profile.evidence_refs,
221
+ )
222
+ for operation in profile.evaluate_operations:
223
+ promotion = evaluate_capability_promotion(
224
+ capability_profile,
225
+ operation,
226
+ profile.scorecard,
227
+ )
228
+ reasons: list[str] = list(promotion.reasons)
229
+ dependency_reason = _gate_reason(
230
+ profile.dependency.gate,
231
+ failed_reason="dependency_gate_failed",
232
+ deferred_reason="dependency_gate_deferred",
233
+ )
234
+ license_reason = _gate_reason(
235
+ profile.license.gate,
236
+ failed_reason="license_gate_failed",
237
+ deferred_reason="license_gate_deferred",
238
+ )
239
+ dependency_gate_passed = dependency_reason is None
240
+ license_gate_passed = license_reason is None
241
+ if dependency_reason is not None:
242
+ reasons.append(dependency_reason)
243
+ if license_reason is not None:
244
+ reasons.append(license_reason)
245
+
246
+ decisions.append(
247
+ CandidateDecision(
248
+ format=profile.format,
249
+ engine_id=profile.engine_id,
250
+ operation=operation,
251
+ promoted=promotion.promoted and dependency_gate_passed and license_gate_passed,
252
+ score=promotion.score,
253
+ required_score=promotion.required_score,
254
+ reasons=tuple(reasons),
255
+ dependency_gate_passed=dependency_gate_passed,
256
+ license_gate_passed=license_gate_passed,
257
+ decision_note=profile.operation_notes.get(operation, profile.decision_note),
258
+ evidence_refs=profile.evidence_refs,
259
+ )
260
+ )
261
+ return CandidateEvaluationRun(
262
+ run_id=manifest.run_id,
263
+ live_network_allowed=manifest.live_network_allowed,
264
+ decisions=tuple(decisions),
265
+ )
266
+
267
+
268
+ def load_data_go_kr_metadata_snapshot(path: Path) -> DataGoKrMetadataSnapshot:
269
+ """Load the offline data.go.kr semantic-evaluation metadata snapshot."""
270
+ raw = _load_yaml_mapping(path)
271
+ return DataGoKrMetadataSnapshot.model_validate(raw)
272
+
273
+
274
+ def _gate_reason(
275
+ gate: GateState,
276
+ *,
277
+ failed_reason: str,
278
+ deferred_reason: str,
279
+ ) -> str | None:
280
+ if gate == "pass":
281
+ return None
282
+ if gate == "defer":
283
+ return deferred_reason
284
+ return failed_reason
285
+
286
+
287
+ def _load_yaml_mapping(path: Path) -> dict[str, object]:
288
+ loaded = yaml.safe_load(path.read_text(encoding="utf-8"))
289
+ if not isinstance(loaded, dict):
290
+ raise ValueError(f"YAML fixture must be an object: {path}")
291
+ return cast(dict[str, object], loaded)
@@ -0,0 +1,108 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ from __future__ import annotations
3
+
4
+ import re
5
+
6
+ _SAVE_CLAUSE_RE = re.compile(
7
+ r"\s*,?\s*(?:저장|내보내|export|save)\s*(?:은|는|:|=)?.*$",
8
+ re.IGNORECASE,
9
+ )
10
+ _UPDATE_TAIL_RE = re.compile(
11
+ r"\s*(?:로|으로)\s*(?:(?:알아서|내용에\s*맞게)\s*)?"
12
+ r"(?:갱신|변경|수정|작성|입력|채우|해줘).*$",
13
+ re.IGNORECASE,
14
+ )
15
+ _NEXT_LABEL_BOUNDARY_RE = r"(?=,\s*[^,.\n]{2,80}?(?:에는|엔|에|은|는|:|=)\s*[\"'“”‘’]?)"
16
+ _COMMAND_BOUNDARY_RE = r"(?=\s*(?:만\s*)?(?:넣|입력|작성|채우|수정|변경|갱신))"
17
+ _VALUE_END_RE = rf"(?:{_NEXT_LABEL_BOUNDARY_RE}|{_COMMAND_BOUNDARY_RE}|[.!?。\n]|$)"
18
+ _LABEL_PART_RE = re.compile(r"[0-9A-Za-z가-힣]+")
19
+ _LABEL_PART_SEPARATOR_RE = r"[\s·ㆍ‧\-_]*"
20
+ _LABEL_VALUE_SUFFIX_RE = r"(?:값|내용|value)?\s*"
21
+
22
+
23
+ def explicit_keyed_value_for_label(label: str, instruction: str) -> str | None:
24
+ if not _is_meaningful_explicit_label(label):
25
+ return None
26
+ label_pattern = _explicit_label_pattern(label)
27
+ quoted_value = _quoted_keyed_value_for_label(label, instruction)
28
+ if quoted_value is not None:
29
+ return quoted_value
30
+ adjacent_blank_match = re.search(
31
+ rf"{label_pattern}\s*"
32
+ r"(?:옆|다음|우측|오른쪽)?\s*"
33
+ r"(?:빈\s*칸|칸|필드|항목)?\s*"
34
+ r"(?:에는|엔|에)\s*"
35
+ rf"(?P<value>.+?){_VALUE_END_RE}",
36
+ instruction,
37
+ flags=re.IGNORECASE,
38
+ )
39
+ if adjacent_blank_match is not None:
40
+ value = _clean_explicit_keyed_value(adjacent_blank_match.group("value"))
41
+ return value or None
42
+ field_word_match = re.search(
43
+ rf"{label_pattern}\s*(?:은|는|이|가)?\s*(?:필드|칸|항목)?\s*"
44
+ r"(?:은|는|이|가|을|를)?\s*"
45
+ r"(?P<value>[^.!?。\n]+?)\s*(?:로|으로)\s*"
46
+ r"(?:작성|입력|채우|수정|변경|갱신)",
47
+ instruction,
48
+ flags=re.IGNORECASE,
49
+ )
50
+ if field_word_match is not None:
51
+ value = _clean_explicit_keyed_value(field_word_match.group("value"))
52
+ return value or None
53
+ match = re.search(
54
+ rf"{label_pattern}\s*(?:은|는|:|=)\s*(?P<value>[^.!?。\n]+[.!?。]?)",
55
+ instruction,
56
+ flags=re.IGNORECASE,
57
+ )
58
+ if match is not None:
59
+ value = _clean_explicit_keyed_value(match.group("value"))
60
+ return value or None
61
+ return None
62
+
63
+
64
+ def _quoted_keyed_value_for_label(label: str, instruction: str) -> str | None:
65
+ label_pattern = _explicit_label_pattern(label)
66
+ match = re.search(
67
+ rf"{label_pattern}\s*"
68
+ r"(?:옆|다음|우측|오른쪽)?\s*"
69
+ r"(?:빈\s*칸|칸|필드|항목)?\s*"
70
+ rf"{_LABEL_VALUE_SUFFIX_RE}"
71
+ r"(?:에는|엔|에|은|는|:|=)\s*"
72
+ r"(?P<quote>[\"'“”‘’])(?P<value>.*?)(?P=quote)",
73
+ instruction,
74
+ flags=re.IGNORECASE,
75
+ )
76
+ if match is None:
77
+ return None
78
+ value = _clean_quoted_keyed_value(match.group("value"))
79
+ return value or None
80
+
81
+
82
+ def _explicit_label_pattern(label: str) -> str:
83
+ parts = _LABEL_PART_RE.findall(label)
84
+ if not parts:
85
+ return re.escape(label)
86
+ return _LABEL_PART_SEPARATOR_RE.join(re.escape(part) for part in parts)
87
+
88
+
89
+ def _is_meaningful_explicit_label(label: str) -> bool:
90
+ label_key = _normalize_key(label)
91
+ if len(label_key) < 2:
92
+ return False
93
+ return any("a" <= char <= "z" or "가" <= char <= "힣" for char in label_key)
94
+
95
+
96
+ def _clean_explicit_keyed_value(value: str) -> str:
97
+ cleaned = _SAVE_CLAUSE_RE.sub("", value).strip()
98
+ cleaned = _UPDATE_TAIL_RE.sub("", cleaned).strip()
99
+ cleaned = re.sub(r"\s*(?:을|를)$", "", cleaned).strip()
100
+ return cleaned.strip(" ,;:)]})\"'“”‘’")
101
+
102
+
103
+ def _clean_quoted_keyed_value(value: str) -> str:
104
+ return value.strip().strip(" ,;:)]})\"'“”‘’")
105
+
106
+
107
+ def _normalize_key(value: str) -> str:
108
+ return re.sub(r"[^0-9a-z가-힣]+", "", value.casefold())
@@ -0,0 +1,174 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Offline fixture manifest helpers for document harness tests."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from pathlib import Path
7
+ from typing import Literal, cast
8
+
9
+ import yaml
10
+ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
11
+
12
+ SupportedFixtureFormat = Literal["hwpx", "hwp", "docx", "pdf", "xlsx", "pptx"]
13
+ FixtureAuthoringFlow = Literal[
14
+ "read_only",
15
+ "public_form_fill",
16
+ "socratic_narrative",
17
+ "blocked_hostile",
18
+ ]
19
+ FixtureCoverageTag = Literal[
20
+ "form_blanks",
21
+ "self_introduction",
22
+ "business_plan",
23
+ "protected_fields",
24
+ "missing_evidence",
25
+ "approved_draft_mutation",
26
+ "direct_hwp_blocked",
27
+ ]
28
+ RedistributionStatus = Literal[
29
+ "owned",
30
+ "public_domain",
31
+ "open_license",
32
+ "metadata_only",
33
+ "not_redistributable",
34
+ ]
35
+
36
+ DEFAULT_FIXTURE_MANIFEST_PATH = (
37
+ Path(__file__).resolve().parents[4]
38
+ / "tests"
39
+ / "fixtures"
40
+ / "documents"
41
+ / "corpus_manifest.yaml"
42
+ )
43
+
44
+
45
+ class DocumentFixtureEntry(BaseModel):
46
+ """One offline fixture declared in the document corpus manifest."""
47
+
48
+ model_config = ConfigDict(frozen=True, extra="forbid")
49
+
50
+ fixture_id: str = Field(min_length=1)
51
+ format: SupportedFixtureFormat
52
+ path: str = Field(min_length=1)
53
+ source: str = Field(min_length=1)
54
+ redistribution_status: RedistributionStatus
55
+ size_bytes: int | None = Field(default=None, ge=0)
56
+ sha256: str | None = Field(
57
+ default=None,
58
+ min_length=64,
59
+ max_length=64,
60
+ pattern=r"^[0-9a-f]{64}$",
61
+ )
62
+ authoring_flow: FixtureAuthoringFlow = "read_only"
63
+ expected_authoring_flow: tuple[str, ...] = ()
64
+ expected_fields: tuple[str, ...] = ()
65
+ expected_narrative_prompts: tuple[str, ...] = ()
66
+ expected_layout_anchors: tuple[str, ...] = ()
67
+ protected_field_expectations: tuple[str, ...] = ()
68
+ coverage_tags: tuple[FixtureCoverageTag, ...] = ()
69
+ negative_case: str | None = None
70
+
71
+ @field_validator(
72
+ "expected_authoring_flow",
73
+ "expected_fields",
74
+ "expected_narrative_prompts",
75
+ "expected_layout_anchors",
76
+ "protected_field_expectations",
77
+ "coverage_tags",
78
+ )
79
+ @classmethod
80
+ def _tuple_values_are_unique(cls, values: tuple[str, ...]) -> tuple[str, ...]:
81
+ if len(set(values)) != len(values):
82
+ raise ValueError("fixture metadata tuple values must be unique")
83
+ return values
84
+
85
+
86
+ class DocumentFixtureGroups(BaseModel):
87
+ """Fixture groups separated by expected safety posture."""
88
+
89
+ model_config = ConfigDict(frozen=True, extra="forbid")
90
+
91
+ benign: tuple[DocumentFixtureEntry, ...] = ()
92
+ public_forms: tuple[DocumentFixtureEntry, ...] = ()
93
+ narrative_authoring: tuple[DocumentFixtureEntry, ...] = ()
94
+ hostile: tuple[DocumentFixtureEntry, ...] = ()
95
+
96
+
97
+ class DocumentFixtureManifest(BaseModel):
98
+ """Offline document fixture manifest."""
99
+
100
+ model_config = ConfigDict(frozen=True, extra="forbid")
101
+
102
+ version: Literal[1]
103
+ manifest_id: str = Field(min_length=1)
104
+ created_at: str = Field(min_length=1)
105
+ source_policy: Literal["offline_fixtures_only"]
106
+ live_network_allowed: Literal[False]
107
+ formats: tuple[SupportedFixtureFormat, ...] = Field(min_length=1)
108
+ fixture_groups: DocumentFixtureGroups
109
+ requirements: dict[str, str]
110
+
111
+ @model_validator(mode="after")
112
+ def _require_known_format_groups(self) -> DocumentFixtureManifest:
113
+ declared = set(self.formats)
114
+ for entry in (
115
+ *self.fixture_groups.benign,
116
+ *self.fixture_groups.public_forms,
117
+ *self.fixture_groups.narrative_authoring,
118
+ *self.fixture_groups.hostile,
119
+ ):
120
+ if entry.format not in declared:
121
+ raise ValueError(
122
+ f"Fixture {entry.fixture_id!r} uses undeclared format {entry.format!r}"
123
+ )
124
+ return self
125
+
126
+ @model_validator(mode="after")
127
+ def _require_matrix_metadata(self) -> DocumentFixtureManifest:
128
+ for entry in (
129
+ *self.fixture_groups.public_forms,
130
+ *self.fixture_groups.narrative_authoring,
131
+ ):
132
+ _require_common_matrix_metadata(entry)
133
+ for entry in self.fixture_groups.public_forms:
134
+ _require_public_form_matrix_metadata(entry)
135
+ for entry in self.fixture_groups.narrative_authoring:
136
+ _require_narrative_matrix_metadata(entry)
137
+ return self
138
+
139
+
140
+ def load_fixture_manifest(
141
+ path: Path = DEFAULT_FIXTURE_MANIFEST_PATH,
142
+ ) -> DocumentFixtureManifest:
143
+ """Load and validate the offline document fixture manifest."""
144
+ raw = yaml.safe_load(path.read_text(encoding="utf-8"))
145
+ if not isinstance(raw, dict):
146
+ raise ValueError(f"Fixture manifest must be a YAML object: {path}")
147
+ return DocumentFixtureManifest.model_validate(cast(dict[str, object], raw))
148
+
149
+
150
+ def _require_common_matrix_metadata(entry: DocumentFixtureEntry) -> None:
151
+ if entry.size_bytes is None:
152
+ raise ValueError(f"Fixture {entry.fixture_id!r} must declare size_bytes")
153
+ if entry.sha256 is None:
154
+ raise ValueError(f"Fixture {entry.fixture_id!r} must declare sha256")
155
+ if not entry.expected_authoring_flow:
156
+ raise ValueError(f"Fixture {entry.fixture_id!r} must declare expected_authoring_flow")
157
+ if not entry.protected_field_expectations:
158
+ raise ValueError(f"Fixture {entry.fixture_id!r} must declare protected_field_expectations")
159
+ if not entry.coverage_tags:
160
+ raise ValueError(f"Fixture {entry.fixture_id!r} must declare coverage_tags")
161
+
162
+
163
+ def _require_public_form_matrix_metadata(entry: DocumentFixtureEntry) -> None:
164
+ if entry.authoring_flow != "public_form_fill":
165
+ raise ValueError(f"Public form fixture {entry.fixture_id!r} has wrong flow")
166
+ if not entry.expected_fields:
167
+ raise ValueError(f"Public form fixture {entry.fixture_id!r} needs fields")
168
+
169
+
170
+ def _require_narrative_matrix_metadata(entry: DocumentFixtureEntry) -> None:
171
+ if entry.authoring_flow != "socratic_narrative":
172
+ raise ValueError(f"Narrative fixture {entry.fixture_id!r} has wrong flow")
173
+ if not entry.expected_narrative_prompts:
174
+ raise ValueError(f"Narrative fixture {entry.fixture_id!r} needs narrative prompts")