ummaya 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/README.md +15 -2
  2. package/bin/ummaya +10 -1
  3. package/npm-shrinkwrap.json +253 -2
  4. package/package.json +5 -1
  5. package/prompts/manifest.yaml +1 -1
  6. package/prompts/system_v1.md +1 -0
  7. package/pyproject.toml +26 -2
  8. package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
  9. package/src/ummaya/_canonical/__init__.py +2 -0
  10. package/src/ummaya/engine/engine.py +29 -132
  11. package/src/ummaya/evidence/__init__.py +21 -2
  12. package/src/ummaya/evidence/dataset_contract.py +193 -0
  13. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  14. package/src/ummaya/evidence/document_harness.py +313 -0
  15. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  16. package/src/ummaya/evidence/gates.py +70 -0
  17. package/src/ummaya/evidence/json_types.py +20 -0
  18. package/src/ummaya/evidence/models.py +88 -1
  19. package/src/ummaya/evidence/output_payload.py +89 -0
  20. package/src/ummaya/evidence/payload_documents.py +233 -0
  21. package/src/ummaya/evidence/route_contracts.py +224 -0
  22. package/src/ummaya/evidence/route_helpers.py +150 -0
  23. package/src/ummaya/evidence/runner.py +81 -212
  24. package/src/ummaya/evidence/source_provenance.py +246 -0
  25. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  26. package/src/ummaya/evidence/tool_layer.py +39 -0
  27. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  28. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  29. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  30. package/src/ummaya/ipc/frame_schema.py +5 -5
  31. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  32. package/src/ummaya/ipc/stdio.py +1109 -477
  33. package/src/ummaya/llm/client.py +102 -3
  34. package/src/ummaya/llm/config.py +8 -3
  35. package/src/ummaya/primitives/__init__.py +6 -2
  36. package/src/ummaya/primitives/delegation.py +1 -1
  37. package/src/ummaya/primitives/document.py +28 -0
  38. package/src/ummaya/settings.py +0 -3
  39. package/src/ummaya/tools/discovery_bridge.py +17 -1
  40. package/src/ummaya/tools/documents/__init__.py +297 -0
  41. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  42. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  43. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  44. package/src/ummaya/tools/documents/authoring.py +283 -0
  45. package/src/ummaya/tools/documents/baselines.py +114 -0
  46. package/src/ummaya/tools/documents/capability.py +331 -0
  47. package/src/ummaya/tools/documents/contracts.py +112 -0
  48. package/src/ummaya/tools/documents/conversion.py +521 -0
  49. package/src/ummaya/tools/documents/diff.py +275 -0
  50. package/src/ummaya/tools/documents/engines.py +163 -0
  51. package/src/ummaya/tools/documents/evaluation.py +291 -0
  52. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  53. package/src/ummaya/tools/documents/fixtures.py +174 -0
  54. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  55. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  56. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  57. package/src/ummaya/tools/documents/formats/base.py +41 -0
  58. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  59. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  60. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  61. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  62. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  63. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  64. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  65. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  66. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  67. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  68. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  69. package/src/ummaya/tools/documents/inspection.py +289 -0
  70. package/src/ummaya/tools/documents/intake.py +1079 -0
  71. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  72. package/src/ummaya/tools/documents/models.py +1598 -0
  73. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  74. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  75. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  76. package/src/ummaya/tools/documents/patch.py +170 -0
  77. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  78. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  79. package/src/ummaya/tools/documents/permissions.py +110 -0
  80. package/src/ummaya/tools/documents/planner.py +616 -0
  81. package/src/ummaya/tools/documents/registry.py +2733 -0
  82. package/src/ummaya/tools/documents/render.py +978 -0
  83. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  84. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  85. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  86. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  87. package/src/ummaya/tools/documents/reread.py +157 -0
  88. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  89. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  90. package/src/ummaya/tools/documents/scorecard.py +184 -0
  91. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  92. package/src/ummaya/tools/documents/style.py +48 -0
  93. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  94. package/src/ummaya/tools/documents/validate.py +347 -0
  95. package/src/ummaya/tools/executor.py +29 -0
  96. package/src/ummaya/tools/live_proxy.py +0 -3
  97. package/src/ummaya/tools/models.py +5 -1
  98. package/src/ummaya/tools/register_all.py +8 -0
  99. package/src/ummaya/tools/registry.py +10 -1
  100. package/src/ummaya/tools/routing/__init__.py +59 -0
  101. package/src/ummaya/tools/routing/builder.py +105 -0
  102. package/src/ummaya/tools/routing/cards.py +29 -0
  103. package/src/ummaya/tools/routing/decision_service.py +534 -0
  104. package/src/ummaya/tools/routing/decision_types.py +74 -0
  105. package/src/ummaya/tools/routing/feasibility.py +122 -0
  106. package/src/ummaya/tools/routing/intent.py +17 -0
  107. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  108. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  109. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  110. package/src/ummaya/tools/routing/intent_types.py +48 -0
  111. package/src/ummaya/tools/routing/lint.py +78 -0
  112. package/src/ummaya/tools/routing/metadata.py +174 -0
  113. package/src/ummaya/tools/routing/projection.py +340 -0
  114. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  115. package/src/ummaya/tools/routing/schema.py +81 -0
  116. package/src/ummaya/tools/routing/types.py +96 -0
  117. package/src/ummaya/tools/routing_index.py +2 -2
  118. package/src/ummaya/tools/search.py +34 -746
  119. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  120. package/tui/package.json +1 -1
  121. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  122. package/tui/src/QueryEngine.ts +12 -8
  123. package/tui/src/bridge/inboundAttachments.ts +3 -3
  124. package/tui/src/cli/handlers/auth.ts +3 -12
  125. package/tui/src/cli/print.ts +7 -7
  126. package/tui/src/commands/insights.ts +1 -1
  127. package/tui/src/commands/install-github-app/types.ts +8 -30
  128. package/tui/src/commands/plugin/types.ts +6 -28
  129. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  130. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  131. package/tui/src/components/Feedback.tsx +1 -1
  132. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  133. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  134. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  135. package/tui/src/components/Spinner/types.ts +6 -28
  136. package/tui/src/components/agents/generateAgent.ts +1 -1
  137. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  138. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  139. package/tui/src/components/mcp/types.ts +16 -38
  140. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  141. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  142. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  143. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  144. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  145. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  146. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  147. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  148. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  149. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  150. package/tui/src/components/primitive/index.tsx +43 -1
  151. package/tui/src/components/primitive/types.ts +137 -0
  152. package/tui/src/components/ui/option.ts +4 -26
  153. package/tui/src/constants/common.ts +0 -2
  154. package/tui/src/constants/prompts.ts +4 -3
  155. package/tui/src/constants/querySource.ts +4 -26
  156. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  157. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  158. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  159. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  160. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  161. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  162. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  163. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  164. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  165. package/tui/src/ink/ink.tsx +33 -14
  166. package/tui/src/ink/reconciler.ts +2 -3
  167. package/tui/src/ink/render-to-screen.ts +30 -10
  168. package/tui/src/ipc/bridge.ts +62 -15
  169. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  170. package/tui/src/ipc/codec.ts +3 -3
  171. package/tui/src/ipc/frames.generated.ts +12 -12
  172. package/tui/src/ipc/llmClient.ts +151 -27
  173. package/tui/src/ipc/schema/frame.schema.json +1 -1
  174. package/tui/src/keybindings/defaultBindings.ts +4 -0
  175. package/tui/src/main.tsx +29 -11
  176. package/tui/src/native-ts/file-index/index.ts +33 -3
  177. package/tui/src/observability/surface.ts +2 -2
  178. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  179. package/tui/src/projectOnboardingState.ts +7 -6
  180. package/tui/src/query/chatMessageTypes.ts +18 -0
  181. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  182. package/tui/src/query/deps.ts +1 -1
  183. package/tui/src/query/messageGuards.ts +106 -0
  184. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  185. package/tui/src/query/run.ts +1075 -0
  186. package/tui/src/query/supportBoundary.ts +168 -0
  187. package/tui/src/query/toolResultErrors.ts +103 -0
  188. package/tui/src/query/toolRunner.ts +687 -0
  189. package/tui/src/query/unavailableToolRepair.ts +118 -0
  190. package/tui/src/query.ts +9 -2186
  191. package/tui/src/screens/REPL.tsx +40 -29
  192. package/tui/src/services/api/adapterManifest.ts +4 -0
  193. package/tui/src/services/api/backendChat/events.ts +117 -0
  194. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  195. package/tui/src/services/api/backendChat/frame.ts +9 -0
  196. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  197. package/tui/src/services/api/backendChat/types.ts +62 -0
  198. package/tui/src/services/api/backendChat.ts +1 -0
  199. package/tui/src/services/api/client.ts +65 -2
  200. package/tui/src/services/api/errorUtils.ts +5 -5
  201. package/tui/src/services/api/errors.ts +1 -1
  202. package/tui/src/services/api/logging.ts +1 -1
  203. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  204. package/tui/src/services/api/ummaya/messages.ts +255 -0
  205. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  206. package/tui/src/services/api/ummaya/provider.ts +200 -0
  207. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  208. package/tui/src/services/api/ummaya/request.ts +200 -0
  209. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  210. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  211. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  212. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  213. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  214. package/tui/src/services/api/ummaya/types.ts +110 -0
  215. package/tui/src/services/api/ummaya/usage.ts +30 -0
  216. package/tui/src/services/api/ummaya.ts +26 -418
  217. package/tui/src/services/api/withRetry.ts +1 -1
  218. package/tui/src/services/awaySummary.ts +2 -2
  219. package/tui/src/services/claudeAiLimits.ts +1 -1
  220. package/tui/src/services/compact/autoCompact.ts +1 -1
  221. package/tui/src/services/compact/compact.ts +1 -1
  222. package/tui/src/services/lsp/types.ts +8 -30
  223. package/tui/src/services/tips/types.ts +6 -28
  224. package/tui/src/services/tokenEstimation.ts +1 -1
  225. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  226. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  227. package/tui/src/services/tools/toolExecution.ts +94 -1
  228. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  229. package/tui/src/store/session-store.ts +10 -36
  230. package/tui/src/stubs/any-stub.ts +15 -10
  231. package/tui/src/stubs/color-diff-napi.ts +37 -23
  232. package/tui/src/stubs/globals.d.ts +3 -3
  233. package/tui/src/stubs/macro-preload.ts +23 -12
  234. package/tui/src/tools/AdapterTool/AdapterTool.ts +1207 -714
  235. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  236. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  237. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  238. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  239. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  240. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  241. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  242. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  243. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  244. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  245. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  246. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  247. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  248. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  249. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  250. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  251. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  252. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  253. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  254. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  255. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  256. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  257. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  258. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  259. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  260. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  261. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  262. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  263. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  264. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  265. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  266. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  267. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  268. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  269. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  270. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  271. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  272. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  273. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  274. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  275. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  276. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  277. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  278. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  279. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  280. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  281. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  282. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  283. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  284. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  285. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  286. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  287. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  288. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  289. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  290. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  291. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  292. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  293. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  294. package/tui/src/tools/BashTool/call.ts +202 -0
  295. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  296. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  297. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  298. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  299. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  300. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  301. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  302. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  303. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  304. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  305. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  306. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  307. package/tui/src/tools/BashTool/schemas.ts +65 -0
  308. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  309. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  310. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  311. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  312. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  313. package/tui/src/tools/BriefTool/upload.ts +1 -1
  314. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  315. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  316. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  317. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  318. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  319. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  320. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  321. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  322. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  323. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  324. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  325. package/tui/src/tools/FileEditTool/call.ts +228 -0
  326. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  327. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  328. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  329. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  330. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  331. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  332. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +25 -32
  333. package/tui/src/tools/LookupPrimitive/prompt.ts +0 -2
  334. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  335. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  336. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  337. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  338. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  339. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  340. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  341. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  342. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  343. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  344. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  345. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  346. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  347. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  348. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  349. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  350. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  351. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  352. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  353. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  354. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  355. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  356. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +1 -11
  357. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  358. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  359. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +27 -10
  360. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  361. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  362. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  363. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  364. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  365. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  366. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  367. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  368. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  369. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  370. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  371. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  372. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  373. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  374. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  375. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  376. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  377. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  378. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  379. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  380. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  381. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  382. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  383. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  384. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  385. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +2 -1
  386. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  387. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  388. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  389. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  390. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  391. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  392. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  393. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  394. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  395. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  396. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  397. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  398. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  399. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  400. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  401. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  402. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  403. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  404. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  405. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  406. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  407. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  408. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  409. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  410. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  411. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  412. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  413. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  414. package/tui/src/tools/_shared/rootPrimitiveInput.ts +1 -0
  415. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  416. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  417. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  418. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  419. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  420. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  421. package/tui/src/tools/_shared/toolChoiceRepair.ts +55 -860
  422. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  423. package/tui/src/tools.ts +39 -190
  424. package/tui/src/types/fileSuggestion.ts +4 -26
  425. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  426. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  427. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  428. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  429. package/tui/src/types/message.ts +80 -102
  430. package/tui/src/types/messageQueueTypes.ts +6 -28
  431. package/tui/src/types/notebook.ts +16 -38
  432. package/tui/src/types/statusLine.ts +4 -26
  433. package/tui/src/types/tools.ts +24 -46
  434. package/tui/src/types/utils.ts +6 -28
  435. package/tui/src/upstreamproxy/relay.ts +7 -3
  436. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  437. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  438. package/tui/src/utils/auth.ts +129 -139
  439. package/tui/src/utils/bash/ast.ts +23 -23
  440. package/tui/src/utils/bash/bashParser.ts +5 -5
  441. package/tui/src/utils/billing.ts +1 -1
  442. package/tui/src/utils/collapseReadSearch.ts +3 -3
  443. package/tui/src/utils/cronTasks.ts +1 -1
  444. package/tui/src/utils/execFileNoThrow.ts +1 -1
  445. package/tui/src/utils/filePersistence/types.ts +16 -38
  446. package/tui/src/utils/forkedAgent.ts +1 -1
  447. package/tui/src/utils/gracefulShutdown.ts +4 -4
  448. package/tui/src/utils/heapDumpService.ts +12 -8
  449. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  450. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  451. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  452. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  453. package/tui/src/utils/messages.ts +18 -0
  454. package/tui/src/utils/migrateSessions.ts +3 -3
  455. package/tui/src/utils/model/model.ts +6 -6
  456. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  457. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  458. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  459. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  460. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  461. package/tui/src/utils/protectedNamespace.ts +5 -3
  462. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  463. package/tui/src/utils/ripgrep.ts +16 -7
  464. package/tui/src/utils/sessionTitle.ts +1 -1
  465. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  466. package/tui/src/utils/shell/prefix.ts +1 -1
  467. package/tui/src/utils/sideQuery.ts +1 -1
  468. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  469. package/tui/src/utils/teleport.tsx +1 -1
  470. package/uv.lock +400 -14
  471. package/tui/src/services/api/claude.ts +0 -3540
  472. package/tui/src/tools/_shared/directPublicDataGuard.ts +0 -362
  473. package/tui/src/tools/_shared/kmaAnalysisGuard.ts +0 -197
  474. package/tui/src/tools/_shared/kmaAviationGuard.ts +0 -70
  475. package/tui/src/tools/_shared/nmcAedGuard.ts +0 -234
  476. package/tui/src/tools/_shared/protectedCheckGuard.ts +0 -207
  477. package/tui/src/tools/_shared/textToolCallGuard.ts +0 -91
@@ -0,0 +1,176 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ from __future__ import annotations
3
+
4
+ import re
5
+ from collections.abc import Iterable
6
+ from typing import Literal
7
+ from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
8
+
9
+ RedactionCategory = Literal[
10
+ "auth_header",
11
+ "cookie",
12
+ "service_key",
13
+ "token",
14
+ "pii",
15
+ "private_document",
16
+ ]
17
+ PromptInjectionState = Literal["detected", "not_detected"]
18
+
19
+ _AUTH_HEADER_PATTERN = re.compile(r"\bAuthorization\s*:\s*[^\n\r;]+", re.IGNORECASE)
20
+ _AUTH_ASSIGNMENT_PATTERN = re.compile(
21
+ r"\bauthorization\s*=\s*[^\s&;\n\r]+",
22
+ re.IGNORECASE,
23
+ )
24
+ _COOKIE_PATTERN = re.compile(r"\bCookie\s*:\s*[^;\n\r]+;?\s*", re.IGNORECASE)
25
+ _COOKIE_ASSIGNMENT_PATTERN = re.compile(
26
+ r"\bcookie\s*=\s*[^\s&;\n\r]+",
27
+ re.IGNORECASE,
28
+ )
29
+ _SERVICE_KEY_PATTERN = re.compile(
30
+ r"\b(?:serviceKey|authKey)\s*=\s*[^\s&]+",
31
+ re.IGNORECASE,
32
+ )
33
+ _TOKEN_PATTERN = re.compile(
34
+ r"\b(?:UMMAYA_[A-Z0-9_]*TOKEN|"
35
+ r"[A-Z0-9_]*(?:API|AUTH|ACCESS|REFRESH|SESSION)[_-]?KEY|"
36
+ r"(?:session|access|refresh|id)[_-]?token)\s*=\s*[^\s&]+|"
37
+ r"\bBearer\s+[A-Za-z0-9._~+/=-]+",
38
+ re.IGNORECASE,
39
+ )
40
+ _GENERIC_TOKEN_ASSIGNMENT_PATTERN = re.compile(
41
+ r"\b(?:token|secret|api[_-]?key|access[_-]?token|session[_-]?token|"
42
+ r"refresh[_-]?token|id[_-]?token|client[_-]?secret)\s*=\s*[^\s&;\n\r]+",
43
+ re.IGNORECASE,
44
+ )
45
+ _EMAIL_PATTERN = re.compile(r"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b", re.IGNORECASE)
46
+ _KOREAN_RRN_PATTERN = re.compile(r"\b\d{6}-[1-4]\d{6}\b")
47
+ _PHONE_PATTERN = re.compile(r"\b01[016789]-?\d{3,4}-?\d{4}\b")
48
+ _PRIVATE_DOCUMENT_PATTERN = re.compile(
49
+ r"-----BEGIN [A-Z ]*PRIVATE KEY-----|raw private document|private document bytes",
50
+ re.IGNORECASE,
51
+ )
52
+ _PROMPT_INJECTION_PATTERNS: tuple[re.Pattern[str], ...] = (
53
+ re.compile(r"ignore\s+(?:all\s+)?previous\s+instructions", re.IGNORECASE),
54
+ re.compile(r"change\s+(?:the\s+)?permission\s+policy", re.IGNORECASE),
55
+ re.compile(r"bypass\s+(?:permissions?|approval|policy)", re.IGNORECASE),
56
+ re.compile(r"treat\s+this\s+as\s+(?:a\s+)?system\s+instruction", re.IGNORECASE),
57
+ )
58
+ _SECRET_QUERY_KEYS = frozenset(
59
+ {
60
+ "access_token",
61
+ "api_key",
62
+ "apikey",
63
+ "auth",
64
+ "authkey",
65
+ "authorization",
66
+ "cookie",
67
+ "id_token",
68
+ "key",
69
+ "refresh_token",
70
+ "servicekey",
71
+ "session",
72
+ "session_token",
73
+ "token",
74
+ }
75
+ )
76
+
77
+
78
+ def redact_source_url(value: str | None) -> tuple[str | None, tuple[RedactionCategory, ...]]:
79
+ if value is None:
80
+ return None, ()
81
+ categories: list[RedactionCategory] = []
82
+ try:
83
+ parsed = urlsplit(value)
84
+ except ValueError:
85
+ return redact_source_text(value)
86
+ query_items: list[tuple[str, str]] = []
87
+ for key, item_value in parse_qsl(parsed.query, keep_blank_values=True):
88
+ lowered_key = key.lower()
89
+ if lowered_key in _SECRET_QUERY_KEYS:
90
+ categories.append(
91
+ "service_key" if lowered_key in {"authkey", "servicekey"} else "token"
92
+ )
93
+ continue
94
+ redacted_value, item_categories = redact_source_text(item_value)
95
+ categories.extend(item_categories)
96
+ query_items.append((key, redacted_value or ""))
97
+ rebuilt = urlunsplit(
98
+ (
99
+ parsed.scheme,
100
+ parsed.netloc,
101
+ parsed.path,
102
+ urlencode(query_items),
103
+ parsed.fragment,
104
+ )
105
+ )
106
+ redacted_text, text_categories = redact_source_text(rebuilt)
107
+ categories.extend(text_categories)
108
+ return redacted_text, ordered_redaction_categories(categories)
109
+
110
+
111
+ def redact_source_text(value: str | None) -> tuple[str | None, tuple[RedactionCategory, ...]]:
112
+ if value is None:
113
+ return None, ()
114
+ categories = list(redaction_categories_for_text(value))
115
+ redacted = _AUTH_HEADER_PATTERN.sub("[REDACTED_AUTH_HEADER]", value)
116
+ redacted = _AUTH_ASSIGNMENT_PATTERN.sub("[REDACTED_AUTH_HEADER]", redacted)
117
+ redacted = _COOKIE_PATTERN.sub("[REDACTED_COOKIE] ", redacted)
118
+ redacted = _COOKIE_ASSIGNMENT_PATTERN.sub("[REDACTED_COOKIE]", redacted)
119
+ redacted = _SERVICE_KEY_PATTERN.sub("[REDACTED_SERVICE_KEY]", redacted)
120
+ redacted = _TOKEN_PATTERN.sub("[REDACTED_TOKEN]", redacted)
121
+ redacted = _GENERIC_TOKEN_ASSIGNMENT_PATTERN.sub("[REDACTED_TOKEN]", redacted)
122
+ redacted = _EMAIL_PATTERN.sub("[REDACTED_PII]", redacted)
123
+ redacted = _KOREAN_RRN_PATTERN.sub("[REDACTED_PII]", redacted)
124
+ redacted = _PHONE_PATTERN.sub("[REDACTED_PII]", redacted)
125
+ redacted = _PRIVATE_DOCUMENT_PATTERN.sub("[REDACTED_PRIVATE_DOCUMENT]", redacted)
126
+ return re.sub(r"[ \t]{2,}", " ", redacted).strip(), ordered_redaction_categories(categories)
127
+
128
+
129
+ def detect_prompt_injection(value: str) -> PromptInjectionState:
130
+ return (
131
+ "detected"
132
+ if any(pattern.search(value) for pattern in _PROMPT_INJECTION_PATTERNS)
133
+ else "not_detected"
134
+ )
135
+
136
+
137
+ def redaction_categories_for_text(value: str) -> tuple[RedactionCategory, ...]:
138
+ categories: list[RedactionCategory] = []
139
+ if _AUTH_HEADER_PATTERN.search(value):
140
+ categories.append("auth_header")
141
+ if _AUTH_ASSIGNMENT_PATTERN.search(value):
142
+ categories.append("auth_header")
143
+ if _COOKIE_PATTERN.search(value):
144
+ categories.append("cookie")
145
+ if _COOKIE_ASSIGNMENT_PATTERN.search(value):
146
+ categories.append("cookie")
147
+ if _SERVICE_KEY_PATTERN.search(value):
148
+ categories.append("service_key")
149
+ if _TOKEN_PATTERN.search(value):
150
+ categories.append("token")
151
+ if _GENERIC_TOKEN_ASSIGNMENT_PATTERN.search(value):
152
+ categories.append("token")
153
+ if (
154
+ _EMAIL_PATTERN.search(value)
155
+ or _KOREAN_RRN_PATTERN.search(value)
156
+ or _PHONE_PATTERN.search(value)
157
+ ):
158
+ categories.append("pii")
159
+ if _PRIVATE_DOCUMENT_PATTERN.search(value):
160
+ categories.append("private_document")
161
+ return ordered_redaction_categories(categories)
162
+
163
+
164
+ def ordered_redaction_categories(
165
+ categories: Iterable[RedactionCategory],
166
+ ) -> tuple[RedactionCategory, ...]:
167
+ order: tuple[RedactionCategory, ...] = (
168
+ "auth_header",
169
+ "cookie",
170
+ "service_key",
171
+ "token",
172
+ "pii",
173
+ "private_document",
174
+ )
175
+ present = set(categories)
176
+ return tuple(category for category in order if category in present)
@@ -0,0 +1,39 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+
6
+ from ummaya.evidence.models import RouteTraceRecord
7
+ from ummaya.evidence.tool_layer_models import ToolLayerEvidenceEvent
8
+
9
+
10
+ @dataclass(frozen=True, slots=True)
11
+ class ToolLayerEvidenceJoinError(ValueError):
12
+ """Raised when a tool-layer artifact cannot be joined to route evidence."""
13
+
14
+ event_id: str
15
+
16
+ def __str__(self) -> str:
17
+ return f"tool-layer event does not join to route evidence: {self.event_id}"
18
+
19
+
20
+ def build_tool_layer_events(
21
+ route_trace_records: tuple[RouteTraceRecord, ...],
22
+ *,
23
+ observed_events: tuple[ToolLayerEvidenceEvent, ...] = (),
24
+ ) -> tuple[ToolLayerEvidenceEvent, ...]:
25
+ """Return validated tool-layer artifacts without synthesizing sample events."""
26
+
27
+ if not observed_events:
28
+ return ()
29
+
30
+ route_keys = {
31
+ (record.scenario_id, record.trace_id, record.correlation_id)
32
+ for record in route_trace_records
33
+ if record.trace_kind == "scenario_route"
34
+ }
35
+ for event in observed_events:
36
+ event_key = (event.scenario_id, event.trace_id, event.correlation_id)
37
+ if event_key not in route_keys:
38
+ raise ToolLayerEvidenceJoinError(event_id=event.event_id)
39
+ return observed_events
@@ -0,0 +1,151 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Tool-layer Evidence Fabric event models."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Literal, Self, assert_never
7
+
8
+ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
9
+ from pydantic_core import PydanticCustomError
10
+
11
+ ToolLayerExposureState = Literal[
12
+ "always-loaded",
13
+ "deferred-searchable",
14
+ "permission-gated-callable",
15
+ "hidden",
16
+ "unsupported",
17
+ ]
18
+ ToolLayerTrustTier = Literal[0, 1, 2, 3, 4, 5]
19
+ ToolLayerPermissionDecision = Literal[
20
+ "not_required",
21
+ "approved",
22
+ "denied",
23
+ "blocked_pending_approval",
24
+ "policy_preapproved",
25
+ ]
26
+ ToolLayerResultStatus = Literal["succeeded", "failed", "blocked"]
27
+ ToolLayerBlockedState = Literal[
28
+ "not_blocked",
29
+ "blocked_by_permission",
30
+ "blocked_by_policy",
31
+ "blocked_by_missing_source",
32
+ "blocked_by_unsupported",
33
+ ]
34
+ ToolLayerRenderFrame = Literal[
35
+ "permission_prompt",
36
+ "tool_call",
37
+ "tool_result",
38
+ "blocked_state",
39
+ ]
40
+ ToolLayerPromptInjectionState = Literal["detected", "not_detected"]
41
+ ToolLayerSourceTrust = Literal["trusted", "untrusted"]
42
+ ToolLayerSourceInstructionVisibility = Literal["evidence_only"]
43
+
44
+
45
+ def _validation_error(code: str, message: str) -> PydanticCustomError:
46
+ return PydanticCustomError(code, message)
47
+
48
+
49
+ class ToolLayerEvidenceEvent(BaseModel):
50
+ """One recovered Claude Code support-tool exposure and provenance event."""
51
+
52
+ model_config = ConfigDict(frozen=True, extra="forbid")
53
+
54
+ event_id: str = Field(min_length=1)
55
+ scenario_id: str = Field(min_length=1)
56
+ trace_id: str = Field(min_length=1)
57
+ correlation_id: str = Field(min_length=1)
58
+ frame_hash: str = Field(min_length=64, max_length=64)
59
+ render_frame: ToolLayerRenderFrame
60
+ selected_tool: str = Field(min_length=1)
61
+ exposure_state: ToolLayerExposureState
62
+ trust_tier: ToolLayerTrustTier
63
+ permission_decision: ToolLayerPermissionDecision
64
+ source_url: str | None
65
+ source_local_handle: str | None
66
+ source_citation_id: str = Field(min_length=1)
67
+ provenance_id: str = Field(min_length=1)
68
+ source_trust: ToolLayerSourceTrust
69
+ source_prompt_injection: ToolLayerPromptInjectionState
70
+ source_instruction_visibility: ToolLayerSourceInstructionVisibility = "evidence_only"
71
+ result_status: ToolLayerResultStatus
72
+ result_summary: str | None
73
+ error_summary: str | None
74
+ blocked_state: ToolLayerBlockedState
75
+
76
+ @field_validator("frame_hash")
77
+ @classmethod
78
+ def _validate_frame_hash(cls, value: str) -> str:
79
+ if len(value) != 64 or any(ch not in "0123456789abcdef" for ch in value):
80
+ raise _validation_error(
81
+ "tool_layer_frame_hash", "frame_hash must be lowercase SHA-256 hex"
82
+ )
83
+ return value
84
+
85
+ @field_validator("source_url", "source_local_handle", "source_citation_id", "provenance_id")
86
+ @classmethod
87
+ def _reject_model_visible_leakage_keys(cls, value: str | None) -> str | None:
88
+ if value is not None and ("adapter_id" in value or "expected_tool" in value):
89
+ raise _validation_error(
90
+ "tool_layer_model_visible_leakage",
91
+ "tool-layer evidence cannot carry model-visible leakage keys",
92
+ )
93
+ return value
94
+
95
+ @field_validator("result_summary", "error_summary")
96
+ @classmethod
97
+ def _reject_empty_summary(cls, value: str | None) -> str | None:
98
+ if value is not None and not value.strip():
99
+ raise _validation_error(
100
+ "tool_layer_blank_summary", "tool-layer summaries cannot be blank"
101
+ )
102
+ return value
103
+
104
+ @model_validator(mode="after")
105
+ def _requires_source_reference(self) -> Self:
106
+ if self.source_url is None and self.source_local_handle is None:
107
+ raise _validation_error(
108
+ "tool_layer_missing_source",
109
+ "tool-layer evidence requires source_url or source_local_handle",
110
+ )
111
+ return self
112
+
113
+ @model_validator(mode="after")
114
+ def _requires_status_payload(self) -> Self:
115
+ match self.result_status:
116
+ case "succeeded":
117
+ if self.result_summary is None:
118
+ raise _validation_error(
119
+ "tool_layer_missing_result_summary",
120
+ "succeeded tool-layer event requires result_summary",
121
+ )
122
+ if self.error_summary is not None:
123
+ raise _validation_error(
124
+ "tool_layer_unexpected_error_summary",
125
+ "succeeded tool-layer event cannot carry error_summary",
126
+ )
127
+ if self.blocked_state != "not_blocked":
128
+ raise _validation_error(
129
+ "tool_layer_unexpected_blocked_state",
130
+ "succeeded tool-layer event must not be blocked",
131
+ )
132
+ case "failed":
133
+ if self.error_summary is None:
134
+ raise _validation_error(
135
+ "tool_layer_failed_without_error",
136
+ "failed tool-layer event requires error_summary",
137
+ )
138
+ case "blocked":
139
+ if self.error_summary is None:
140
+ raise _validation_error(
141
+ "tool_layer_blocked_without_error",
142
+ "blocked tool-layer event requires error_summary",
143
+ )
144
+ if self.blocked_state == "not_blocked":
145
+ raise _validation_error(
146
+ "tool_layer_blocked_without_state",
147
+ "blocked tool-layer event requires a blocked_state",
148
+ )
149
+ case unreachable:
150
+ assert_never(unreachable)
151
+ return self
@@ -47,6 +47,7 @@ import importlib
47
47
  import json
48
48
  import logging
49
49
  import os
50
+ import re
50
51
  from datetime import UTC, datetime
51
52
  from typing import IO, Any, Literal
52
53
 
@@ -255,7 +256,7 @@ def _build_entries( # noqa: C901, ANN401 — three-source walker, refactor defe
255
256
  except Exception:
256
257
  tools_list = []
257
258
 
258
- root_primitive_tool_ids = frozenset({"locate", "find", "check", "send"})
259
+ root_primitive_tool_ids = frozenset({"locate", "find", "check", "send", "document"})
259
260
 
260
261
  for tool in tools_list:
261
262
  tool_id_opt: str | None = tool.id if hasattr(tool, "id") else getattr(tool, "tool_id", None)
@@ -371,24 +372,39 @@ def _verify_family_llm_description(
371
372
  """Build model-facing prose for a verify-family manifest entry."""
372
373
 
373
374
  metadata = metadata or {}
374
- tool_id = str(metadata.get("tool_id") or family).strip()
375
375
  name = str(metadata.get("name_ko") or family).strip()
376
- scope_rules = str(metadata.get("scope_rules") or "").strip()
376
+ scope_rules = _safe_verify_scope_rules(str(metadata.get("scope_rules") or "").strip())
377
377
  scope_clause = f" {scope_rules}" if scope_rules else ""
378
378
  return (
379
- f"Internal check-family surface for {name} (family_hint='{family}', "
380
- f"bridged adapter id '{tool_id}'). Use this only through the core check "
381
- "primitive before a downstream protected find/send action needs delegated "
382
- "authorization. Params must follow input_schema_json exactly: scope_list "
383
- "contains '<verb>:<adapter_family>.<action>' scope strings, purpose_ko is "
384
- "the Korean citizen-facing consent purpose, and purpose_en is the audit-log "
379
+ f"Internal check-family surface for {name} (family_hint='{family}'). "
380
+ "Use this only through the core check primitive before a downstream "
381
+ "protected find/send action needs delegated authorization. Params must "
382
+ "follow input_schema_json exactly: scope_list contains "
383
+ "'<verb>:<adapter_family>.<action>' scope strings, purpose_ko is the "
384
+ "Korean citizen-facing consent purpose, and purpose_en is the audit-log "
385
385
  "English purpose. The manifest entry stays source_mode='internal' because "
386
386
  "the agency citation is emitted by the verify response transparency stamp, "
387
- "while the pre-call tool schema remains stable for the TUI and LLM loop."
387
+ "while the pre-call tool schema remains stable for the TUI and LLM loop. "
388
+ "Do not mention internal mock bridge identifiers in citizen-facing prose."
388
389
  f"{scope_clause}"
389
390
  )
390
391
 
391
392
 
393
+ def _safe_verify_scope_rules(scope_rules: str) -> str:
394
+ if not scope_rules:
395
+ return ""
396
+ safe_sentences: list[str] = []
397
+ for sentence in re.split(r"(?<=[.!?])\s+", scope_rules):
398
+ candidate = sentence.strip()
399
+ if not candidate:
400
+ continue
401
+ lowered = candidate.lower()
402
+ if "mock_verify" in lowered or "tool_id" in lowered:
403
+ continue
404
+ safe_sentences.append(candidate)
405
+ return " ".join(safe_sentences)
406
+
407
+
392
408
  def _string_list(value: object) -> list[str]:
393
409
  """Return non-empty strings from a loosely typed metadata list."""
394
410
 
@@ -0,0 +1,185 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ import uuid
7
+ from pathlib import Path
8
+ from typing import Final
9
+
10
+ _DOCUMENT_WRITE_REQUEST_RE: Final = re.compile(
11
+ r"(작성|수정|편집|채우|채워|입력|변경|저장|write|edit|fill|apply|save)",
12
+ re.IGNORECASE,
13
+ )
14
+ _DOCUMENT_SAVE_REQUEST_RE: Final = re.compile(
15
+ r"(저장|내보내|export|save)",
16
+ re.IGNORECASE,
17
+ )
18
+ _DOCUMENT_READ_ONLY_INSPECT_RE: Final = re.compile(
19
+ r"(구조.{0,30}빈칸.{0,30}확인|빈칸.{0,30}확인|구조.{0,30}확인|"
20
+ r"확인해\s*줘|검토만|inspect|read[- ]?only)",
21
+ re.IGNORECASE,
22
+ )
23
+ _DOCUMENT_MUTATION_PROHIBITION_RE: Final = re.compile(
24
+ r"(절대.{0,40}(?:수정|저장|작성|채우|입력|변경).{0,40}"
25
+ r"(?:하지\s*마|하지\s*말|금지)|"
26
+ r"(?:수정|저장|작성|채우|입력|변경).{0,30}(?:하지\s*마|하지\s*말)|"
27
+ r"(?:do not|don't).{0,40}(?:modify|save|write|edit|fill))",
28
+ re.IGNORECASE,
29
+ )
30
+ _QUESTION_FIRST_AUTHORING_RE: Final = re.compile(
31
+ r"(근거가\s*부족하면\s*먼저\s*질문|먼저\s*(?:확인|파악|검토|질문|물어)|"
32
+ r"초안을?\s*먼저|아직.{0,40}(?:쓰지\s*마|작성하지\s*마|저장하지\s*마|"
33
+ r"반영하지\s*마)|문서에는\s*쓰지\s*마)",
34
+ re.IGNORECASE,
35
+ )
36
+ _DOCUMENT_MUTATION_PARAM_KEYS: Final[frozenset[str]] = frozenset(
37
+ {
38
+ "approved_draft_id",
39
+ "destination_display_name",
40
+ "destination_path",
41
+ "dry_run",
42
+ "patches",
43
+ "styles",
44
+ "template_id",
45
+ }
46
+ )
47
+ _DOCUMENT_INTERNAL_USER_QUERY_KEY: Final = "__ummaya_user_query"
48
+ _DOCUMENT_ROOT_SYNTHESIS_KEYS: Final[frozenset[str]] = frozenset(
49
+ {_DOCUMENT_INTERNAL_USER_QUERY_KEY}
50
+ )
51
+ _DOCUMENT_EXPLICIT_LOCAL_PATH_RE: Final = re.compile(
52
+ r"(?P<path>(?:~|/)[^\s\"'<>]+?\."
53
+ r"(?:hwpx|hwp|docx|pdf|xlsx|pptx|odt|ods|odp|doc|xls|ppt|csv|txt|md|json|xml|html))",
54
+ re.IGNORECASE,
55
+ )
56
+
57
+
58
+ def _normalize_document_root_call_for_user_intent(
59
+ fname: str,
60
+ args_obj: dict[str, object],
61
+ latest_user_utt: str,
62
+ ) -> dict[str, object]:
63
+ if fname != "document" or args_obj.get("tool_id") != "document":
64
+ return args_obj
65
+ params_obj = args_obj.get("params")
66
+ if not isinstance(params_obj, dict):
67
+ return args_obj
68
+
69
+ intent_text = _document_intent_text(params_obj, latest_user_utt)
70
+ synthesized_params = _synthesize_document_read_params(params_obj, intent_text)
71
+ if synthesized_params is not None:
72
+ return {**args_obj, "params": synthesized_params}
73
+
74
+ normalized_params = dict(params_obj)
75
+ normalized_params.pop(_DOCUMENT_INTERNAL_USER_QUERY_KEY, None)
76
+ _normalize_document_path_from_user_query(normalized_params, intent_text)
77
+ if _is_explicit_read_only_inspect_intent(intent_text):
78
+ read_only_params = _strip_mutation_params(normalized_params)
79
+ read_only_params["operation"] = "inspect"
80
+ read_only_params["instruction"] = intent_text
81
+ return {**args_obj, "params": read_only_params}
82
+
83
+ operation = str(params_obj.get("operation") or "").casefold()
84
+ changed = normalized_params != params_obj
85
+ if (
86
+ operation in {"fill", "save"}
87
+ and intent_text
88
+ and _DOCUMENT_WRITE_REQUEST_RE.search(intent_text)
89
+ ):
90
+ if _DOCUMENT_SAVE_REQUEST_RE.search(intent_text):
91
+ normalized_params["operation"] = "save"
92
+ normalized_params["instruction"] = intent_text
93
+ return {**args_obj, "params": normalized_params}
94
+ if operation not in {"inspect", "extract"}:
95
+ return {**args_obj, "params": normalized_params} if changed else args_obj
96
+ if _should_keep_read_only_for_question_first_authoring(intent_text):
97
+ return {**args_obj, "params": normalized_params} if changed else args_obj
98
+ if not intent_text or not _DOCUMENT_WRITE_REQUEST_RE.search(intent_text):
99
+ return {**args_obj, "params": normalized_params} if changed else args_obj
100
+
101
+ normalized_params["operation"] = (
102
+ "save" if _DOCUMENT_SAVE_REQUEST_RE.search(intent_text) else "fill"
103
+ )
104
+ normalized_params["instruction"] = intent_text
105
+ return {**args_obj, "params": normalized_params}
106
+
107
+
108
+ def _document_intent_text(params_obj: dict[str, object], latest_user_utt: str) -> str:
109
+ internal_user_query = params_obj.get(_DOCUMENT_INTERNAL_USER_QUERY_KEY)
110
+ if isinstance(internal_user_query, str) and internal_user_query.strip():
111
+ return internal_user_query.strip()
112
+ return latest_user_utt
113
+
114
+
115
+ def _synthesize_document_read_params(
116
+ params_obj: dict[str, object],
117
+ intent_text: str,
118
+ ) -> dict[str, object] | None:
119
+ if (
120
+ not intent_text
121
+ or isinstance(params_obj.get("document"), dict)
122
+ or set(params_obj) - _DOCUMENT_ROOT_SYNTHESIS_KEYS
123
+ ):
124
+ return None
125
+ local_path = _first_existing_document_path(intent_text, None)
126
+ if local_path is None:
127
+ return None
128
+ document_format = local_path.suffix.removeprefix(".").lower()
129
+ return {
130
+ "correlation_id": f"document-intent-{uuid.uuid4().hex}",
131
+ "document": {"path": str(local_path), "expected_format": document_format},
132
+ "operation": "inspect",
133
+ "instruction": intent_text,
134
+ }
135
+
136
+
137
+ def _normalize_document_path_from_user_query(
138
+ normalized_params: dict[str, object],
139
+ intent_text: str,
140
+ ) -> None:
141
+ if not intent_text:
142
+ return
143
+ document_obj = normalized_params.get("document")
144
+ if not isinstance(document_obj, dict):
145
+ return
146
+ current_path = document_obj.get("path")
147
+ if isinstance(current_path, str) and Path(current_path).expanduser().exists():
148
+ return
149
+ expected_format = document_obj.get("expected_format")
150
+ expected_suffix = f".{expected_format}".lower() if isinstance(expected_format, str) else None
151
+ explicit_path = _first_existing_document_path(intent_text, expected_suffix)
152
+ if explicit_path is None:
153
+ return
154
+ normalized_params["document"] = {
155
+ **document_obj,
156
+ "path": str(explicit_path),
157
+ }
158
+
159
+
160
+ def _first_existing_document_path(intent_text: str, expected_suffix: str | None) -> Path | None:
161
+ for match in _DOCUMENT_EXPLICIT_LOCAL_PATH_RE.finditer(intent_text):
162
+ candidate = Path(match.group("path").rstrip(".,;:)]})")).expanduser()
163
+ if expected_suffix is not None and candidate.suffix.lower() != expected_suffix:
164
+ continue
165
+ if candidate.exists():
166
+ return candidate.resolve()
167
+ return None
168
+
169
+
170
+ def _should_keep_read_only_for_question_first_authoring(intent_text: str) -> bool:
171
+ return bool(intent_text and _QUESTION_FIRST_AUTHORING_RE.search(intent_text))
172
+
173
+
174
+ def _is_explicit_read_only_inspect_intent(intent_text: str) -> bool:
175
+ return bool(
176
+ intent_text
177
+ and _DOCUMENT_READ_ONLY_INSPECT_RE.search(intent_text)
178
+ and _DOCUMENT_MUTATION_PROHIBITION_RE.search(intent_text)
179
+ )
180
+
181
+
182
+ def _strip_mutation_params(params_obj: dict[str, object]) -> dict[str, object]:
183
+ return {
184
+ key: value for key, value in params_obj.items() if key not in _DOCUMENT_MUTATION_PARAM_KEYS
185
+ }
@@ -528,7 +528,7 @@ class ToolResultEnvelope(BaseModel):
528
528
 
529
529
  model_config = ConfigDict(frozen=True, extra="allow", populate_by_name=True)
530
530
 
531
- kind: Literal["find", "locate", "send", "check"] = Field(
531
+ kind: Literal["find", "locate", "send", "check", "document"] = Field(
532
532
  description="Primitive kind discriminator per Spec 031."
533
533
  )
534
534
 
@@ -576,7 +576,7 @@ class WorkerStatusFrame(_BaseFrame):
576
576
  role_id: str = Field(
577
577
  description="Specialist label (e.g., transport-specialist, health-specialist)."
578
578
  )
579
- current_primitive: Literal["find", "locate", "send", "check"] = Field(
579
+ current_primitive: Literal["find", "locate", "send", "check", "document"] = Field(
580
580
  description="Primitive currently being invoked by this worker."
581
581
  )
582
582
  status: Literal["idle", "running", "waiting_permission", "error"] = Field(
@@ -599,7 +599,7 @@ class PermissionRequestFrame(_BaseFrame):
599
599
  description="ULID; round-trips in the matching permission_response frame."
600
600
  )
601
601
  worker_id: str = Field(description="Worker requesting permission.")
602
- primitive_kind: Literal["find", "locate", "send", "check"] = Field(
602
+ primitive_kind: Literal["find", "locate", "send", "check", "document"] = Field(
603
603
  description="The primitive the worker wants to invoke."
604
604
  )
605
605
  description_ko: str = Field(description="Korean-language description shown to the citizen.")
@@ -669,7 +669,7 @@ class PermissionResponseFrame(_BaseFrame):
669
669
  # `layer: 1, tool_name: 'unknown'` (UI-C-1 spec violation: Layer 2/3
670
670
  # submits were colour-coded green like a Layer 1 verify).
671
671
  # Both fields are optional so legacy backends remain wire-compatible.
672
- primitive_kind: Literal["find", "locate", "send", "check"] | None = Field(
672
+ primitive_kind: Literal["find", "locate", "send", "check", "document"] | None = Field(
673
673
  default=None,
674
674
  description=(
675
675
  "The primitive that was authorised. The TUI feeds this into "
@@ -1220,7 +1220,7 @@ class AdapterManifestEntry(BaseModel):
1220
1220
  max_length=80,
1221
1221
  description="Human-readable display name; bilingual permitted.",
1222
1222
  )
1223
- primitive: Literal["find", "send", "check", "locate"] = Field(
1223
+ primitive: Literal["find", "send", "check", "locate", "document"] = Field(
1224
1224
  description="Primitive verb the adapter is registered under (I6).",
1225
1225
  )
1226
1226
  policy_authority_url: str | None = Field(