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,202 @@
1
+ import type { CanUseToolFn } from 'src/hooks/useCanUseTool.js';
2
+ import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent } from '../../services/analytics/index.js';
3
+ import type { ToolCallProgress, ToolUseContext } from '../../Tool.js';
4
+ import type { AssistantMessage } from '../../types/message.js';
5
+ import type { BashProgress } from '../../types/tools.js';
6
+ import { extractClaudeCodeHints } from '../../utils/claudeCodeHints.js';
7
+ import { detectCodeIndexingFromCommand } from '../../utils/codeIndexing.js';
8
+ import { ShellError } from '../../utils/errors.js';
9
+ import { EndTruncatingAccumulator } from '../../utils/stringUtils.js';
10
+ import { maybeRecordPluginHint } from '../../utils/plugins/hintRecommendation.js';
11
+ import type { ExecResult } from '../../utils/ShellCommand.js';
12
+ import { resetShellCwdIfOutsideProject } from './cwdReset.js';
13
+ import { resizeShellImageOutput, stdErrAppendShellResetMessage, stripEmptyLines, isImageOutput } from './shellOutputUtils.js';
14
+ import { interpretCommandResult } from './commandSemantics.js';
15
+ import { trackGitOperations } from '../shared/gitOperationTracking.js';
16
+ import { runShellCommand } from './shellExecution.js';
17
+ import { persistLargeShellOutput } from './outputPersistence.js';
18
+ import { applySedEdit } from './sedEditExecution.js';
19
+ import { isSilentBashCommand } from './commandClassification.js';
20
+ import type { BashToolInput, Out } from './schemas.js';
21
+ import { annotateShellStderrWithSandboxFailures } from './sandboxPolicy.js';
22
+
23
+ const EOL = '\n';
24
+
25
+ export async function callBashTool(
26
+ input: BashToolInput,
27
+ toolUseContext: ToolUseContext,
28
+ _canUseTool?: CanUseToolFn,
29
+ parentMessage?: AssistantMessage,
30
+ onProgress?: ToolCallProgress<BashProgress>
31
+ ): Promise<{ readonly data: Out }> {
32
+ if (input._simulatedSedEdit) {
33
+ return applySedEdit(input._simulatedSedEdit, toolUseContext, parentMessage);
34
+ }
35
+ const { abortController, getAppState, setAppState, setToolJSX } = toolUseContext;
36
+ const stdoutAccumulator = new EndTruncatingAccumulator();
37
+ let stderrForShellReset = '';
38
+ let interpretationResult: ReturnType<typeof interpretCommandResult> | undefined;
39
+ let wasInterrupted = false;
40
+ const isMainThread = !toolUseContext.agentId;
41
+ const preventCwdChanges = !isMainThread;
42
+ const { execResult } = await consumeBashCommand({
43
+ input,
44
+ toolUseContext,
45
+ preventCwdChanges,
46
+ isMainThread,
47
+ onProgress
48
+ });
49
+ try {
50
+ trackGitOperations(input.command, execResult.code, execResult.stdout);
51
+ const isInterrupt = execResult.interrupted && abortController.signal.reason === 'interrupt';
52
+ stdoutAccumulator.append((execResult.stdout || '').trimEnd() + EOL);
53
+ interpretationResult = interpretCommandResult(input.command, execResult.code, execResult.stdout || '', '');
54
+ if (execResult.stdout && execResult.stdout.includes(".git/index.lock': File exists")) {
55
+ logEvent('tengu_git_index_lock_error', {});
56
+ }
57
+ if (interpretationResult.isError && !isInterrupt && execResult.code !== 0) {
58
+ stdoutAccumulator.append(`Exit code ${execResult.code}`);
59
+ }
60
+ if (!preventCwdChanges) {
61
+ const appState = getAppState();
62
+ if (resetShellCwdIfOutsideProject(appState.toolPermissionContext)) {
63
+ stderrForShellReset = stdErrAppendShellResetMessage('');
64
+ }
65
+ }
66
+ const outputWithSbFailures = annotateShellStderrWithSandboxFailures(input.command, execResult.stdout || '');
67
+ if (execResult.preSpawnError) {
68
+ throw new Error(execResult.preSpawnError);
69
+ }
70
+ if (interpretationResult.isError && !isInterrupt) {
71
+ throw new ShellError('', outputWithSbFailures, execResult.code, execResult.interrupted);
72
+ }
73
+ wasInterrupted = execResult.interrupted;
74
+ } finally {
75
+ if (setToolJSX) setToolJSX(null);
76
+ }
77
+ const stdout = stdoutAccumulator.toString();
78
+ const persisted = await persistLargeShellOutput(execResult);
79
+ logShellExecution(input.command, stdout, execResult.code, wasInterrupted);
80
+ let strippedStdout = stripEmptyLines(stdout);
81
+ const extracted = extractClaudeCodeHints(strippedStdout, input.command);
82
+ strippedStdout = extracted.stripped;
83
+ if (isMainThread && extracted.hints.length > 0) {
84
+ for (const hint of extracted.hints) maybeRecordPluginHint(hint);
85
+ }
86
+ const imageResult = await normalizeImageOutput(strippedStdout, execResult.outputFilePath, persisted.size);
87
+ return {
88
+ data: {
89
+ stdout: imageResult.stdout,
90
+ stderr: stderrForShellReset,
91
+ interrupted: wasInterrupted,
92
+ isImage: imageResult.isImage,
93
+ returnCodeInterpretation: interpretationResult?.message,
94
+ noOutputExpected: isSilentBashCommand(input.command),
95
+ backgroundTaskId: execResult.backgroundTaskId,
96
+ backgroundedByUser: execResult.backgroundedByUser,
97
+ assistantAutoBackgrounded: execResult.assistantAutoBackgrounded,
98
+ dangerouslyDisableSandbox: 'dangerouslyDisableSandbox' in input ? input.dangerouslyDisableSandbox : undefined,
99
+ persistedOutputPath: persisted.path,
100
+ persistedOutputSize: persisted.size
101
+ }
102
+ };
103
+ }
104
+
105
+ type ConsumeInput = {
106
+ readonly input: BashToolInput;
107
+ readonly toolUseContext: ToolUseContext;
108
+ readonly preventCwdChanges: boolean;
109
+ readonly isMainThread: boolean;
110
+ readonly onProgress?: ToolCallProgress<BashProgress>;
111
+ };
112
+
113
+ type ConsumeResult = {
114
+ readonly execResult: ExecResult;
115
+ };
116
+
117
+ async function consumeBashCommand({
118
+ input,
119
+ toolUseContext,
120
+ preventCwdChanges,
121
+ isMainThread,
122
+ onProgress
123
+ }: ConsumeInput): Promise<ConsumeResult> {
124
+ const commandGenerator = runShellCommand({
125
+ input,
126
+ abortController: toolUseContext.abortController,
127
+ setAppState: toolUseContext.setAppStateForTasks ?? toolUseContext.setAppState,
128
+ setToolJSX: toolUseContext.setToolJSX,
129
+ preventCwdChanges,
130
+ isMainThread,
131
+ toolUseId: toolUseContext.toolUseId,
132
+ agentId: toolUseContext.agentId
133
+ });
134
+ let progressCounter = 0;
135
+ let generatorResult;
136
+ do {
137
+ generatorResult = await commandGenerator.next();
138
+ if (!generatorResult.done && onProgress) {
139
+ const progress = generatorResult.value;
140
+ onProgress({
141
+ toolUseID: `bash-progress-${progressCounter++}`,
142
+ data: {
143
+ type: 'bash_progress',
144
+ output: progress.output,
145
+ fullOutput: progress.fullOutput,
146
+ elapsedTimeSeconds: progress.elapsedTimeSeconds,
147
+ totalLines: progress.totalLines,
148
+ totalBytes: progress.totalBytes,
149
+ taskId: progress.taskId,
150
+ timeoutMs: progress.timeoutMs
151
+ }
152
+ });
153
+ }
154
+ } while (!generatorResult.done);
155
+ return {
156
+ execResult: generatorResult.value
157
+ };
158
+ }
159
+
160
+ function logShellExecution(command: string, stdout: string, code: number, interrupted: boolean): void {
161
+ const commandType = command.split(' ')[0];
162
+ logEvent('tengu_bash_tool_command_executed', {
163
+ command_type: commandType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
164
+ stdout_length: stdout.length,
165
+ stderr_length: 0,
166
+ exit_code: code,
167
+ interrupted
168
+ });
169
+ const codeIndexingTool = detectCodeIndexingFromCommand(command);
170
+ if (codeIndexingTool) {
171
+ logEvent('tengu_code_indexing_tool_used', {
172
+ tool: codeIndexingTool as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
173
+ source: 'cli' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
174
+ success: code === 0
175
+ });
176
+ }
177
+ }
178
+
179
+ type ImageOutput = {
180
+ readonly stdout: string;
181
+ readonly isImage: boolean;
182
+ };
183
+
184
+ async function normalizeImageOutput(stdout: string, outputFilePath?: string, persistedOutputSize?: number): Promise<ImageOutput> {
185
+ if (!isImageOutput(stdout)) {
186
+ return {
187
+ stdout,
188
+ isImage: false
189
+ };
190
+ }
191
+ const resized = await resizeShellImageOutput(stdout, outputFilePath, persistedOutputSize);
192
+ if (resized) {
193
+ return {
194
+ stdout: resized,
195
+ isImage: true
196
+ };
197
+ }
198
+ return {
199
+ stdout,
200
+ isImage: false
201
+ };
202
+ }
@@ -0,0 +1,35 @@
1
+ import { createRequire } from 'node:module'
2
+ import type { CanUseToolFn } from 'src/hooks/useCanUseTool.js'
3
+ import type { ToolCallProgress, ToolUseContext } from '../../Tool.js'
4
+ import type { AssistantMessage } from '../../types/message.js'
5
+ import type { BashProgress } from '../../types/tools.js'
6
+ import type { BashToolInput, Out } from './schemas.js'
7
+
8
+ type BashCallRuntime = {
9
+ readonly callBashTool: (
10
+ input: BashToolInput,
11
+ toolUseContext: ToolUseContext,
12
+ canUseTool?: CanUseToolFn,
13
+ parentMessage?: AssistantMessage,
14
+ onProgress?: ToolCallProgress<BashProgress>,
15
+ ) => Promise<{ readonly data: Out }>
16
+ }
17
+
18
+ const requireModule = createRequire(import.meta.url)
19
+ let cachedRuntime: BashCallRuntime | undefined
20
+
21
+ function isBashCallRuntime(value: unknown): value is BashCallRuntime {
22
+ if (typeof value !== 'object' || value === null) return false
23
+ const module = value as Partial<Record<keyof BashCallRuntime, unknown>>
24
+ return typeof module.callBashTool === 'function'
25
+ }
26
+
27
+ export function loadBashCallRuntime(): BashCallRuntime {
28
+ if (cachedRuntime !== undefined) return cachedRuntime
29
+ const loaded: unknown = requireModule('./call.js')
30
+ if (!isBashCallRuntime(loaded)) {
31
+ throw new Error('Bash call module did not expose expected lifecycle')
32
+ }
33
+ cachedRuntime = loaded
34
+ return loaded
35
+ }
@@ -0,0 +1,151 @@
1
+ import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from '../../services/analytics/index.js';
2
+ import { splitCommand_DEPRECATED, splitCommandWithOperators } from '../../utils/bash/commands.js';
3
+
4
+ const BASH_SEARCH_COMMANDS = new Set(['find', 'grep', 'rg', 'ag', 'ack', 'locate', 'which', 'whereis']);
5
+ const BASH_READ_COMMANDS = new Set(['cat', 'head', 'tail', 'less', 'more', 'wc', 'stat', 'file', 'strings', 'jq', 'awk', 'cut', 'sort', 'uniq', 'tr']);
6
+ const BASH_LIST_COMMANDS = new Set(['ls', 'tree', 'du']);
7
+ const BASH_SEMANTIC_NEUTRAL_COMMANDS = new Set(['echo', 'printf', 'true', 'false', ':']);
8
+ const BASH_SILENT_COMMANDS = new Set(['mv', 'cp', 'rm', 'mkdir', 'rmdir', 'chmod', 'chown', 'chgrp', 'touch', 'ln', 'cd', 'export', 'unset', 'wait']);
9
+ const DISALLOWED_AUTO_BACKGROUND_COMMANDS = ['sleep'];
10
+ const COMMON_BACKGROUND_COMMANDS = ['npm', 'yarn', 'pnpm', 'node', 'python', 'python3', 'go', 'cargo', 'make', 'docker', 'terraform', 'webpack', 'vite', 'jest', 'pytest', 'curl', 'wget', 'build', 'test', 'serve', 'watch', 'dev'] as const;
11
+
12
+ type SearchReadClassification = {
13
+ readonly isSearch: boolean;
14
+ readonly isRead: boolean;
15
+ readonly isList: boolean;
16
+ };
17
+
18
+ const NOT_SEARCH_OR_READ: SearchReadClassification = {
19
+ isSearch: false,
20
+ isRead: false,
21
+ isList: false
22
+ };
23
+
24
+ export function isSearchOrReadBashCommand(command: string): SearchReadClassification {
25
+ let partsWithOperators: string[];
26
+ try {
27
+ partsWithOperators = splitCommandWithOperators(command);
28
+ } catch (error) {
29
+ if (error instanceof Error) {
30
+ return NOT_SEARCH_OR_READ;
31
+ }
32
+ throw error;
33
+ }
34
+ if (partsWithOperators.length === 0) {
35
+ return NOT_SEARCH_OR_READ;
36
+ }
37
+ let hasSearch = false;
38
+ let hasRead = false;
39
+ let hasList = false;
40
+ let hasNonNeutralCommand = false;
41
+ let skipNextAsRedirectTarget = false;
42
+ for (const part of partsWithOperators) {
43
+ if (skipNextAsRedirectTarget) {
44
+ skipNextAsRedirectTarget = false;
45
+ continue;
46
+ }
47
+ if (part === '>' || part === '>>' || part === '>&') {
48
+ skipNextAsRedirectTarget = true;
49
+ continue;
50
+ }
51
+ if (part === '||' || part === '&&' || part === '|' || part === ';') {
52
+ continue;
53
+ }
54
+ const baseCommand = part.trim().split(/\s+/)[0];
55
+ if (!baseCommand || BASH_SEMANTIC_NEUTRAL_COMMANDS.has(baseCommand)) {
56
+ continue;
57
+ }
58
+ hasNonNeutralCommand = true;
59
+ const isPartSearch = BASH_SEARCH_COMMANDS.has(baseCommand);
60
+ const isPartRead = BASH_READ_COMMANDS.has(baseCommand);
61
+ const isPartList = BASH_LIST_COMMANDS.has(baseCommand);
62
+ if (!isPartSearch && !isPartRead && !isPartList) {
63
+ return NOT_SEARCH_OR_READ;
64
+ }
65
+ if (isPartSearch) hasSearch = true;
66
+ if (isPartRead) hasRead = true;
67
+ if (isPartList) hasList = true;
68
+ }
69
+ if (!hasNonNeutralCommand) {
70
+ return NOT_SEARCH_OR_READ;
71
+ }
72
+ return {
73
+ isSearch: hasSearch,
74
+ isRead: hasRead,
75
+ isList: hasList
76
+ };
77
+ }
78
+
79
+ export function isSilentBashCommand(command: string): boolean {
80
+ let partsWithOperators: string[];
81
+ try {
82
+ partsWithOperators = splitCommandWithOperators(command);
83
+ } catch (error) {
84
+ if (error instanceof Error) {
85
+ return false;
86
+ }
87
+ throw error;
88
+ }
89
+ if (partsWithOperators.length === 0) {
90
+ return false;
91
+ }
92
+ let hasNonFallbackCommand = false;
93
+ let lastOperator: string | null = null;
94
+ let skipNextAsRedirectTarget = false;
95
+ for (const part of partsWithOperators) {
96
+ if (skipNextAsRedirectTarget) {
97
+ skipNextAsRedirectTarget = false;
98
+ continue;
99
+ }
100
+ if (part === '>' || part === '>>' || part === '>&') {
101
+ skipNextAsRedirectTarget = true;
102
+ continue;
103
+ }
104
+ if (part === '||' || part === '&&' || part === '|' || part === ';') {
105
+ lastOperator = part;
106
+ continue;
107
+ }
108
+ const baseCommand = part.trim().split(/\s+/)[0];
109
+ if (!baseCommand || (lastOperator === '||' && BASH_SEMANTIC_NEUTRAL_COMMANDS.has(baseCommand))) {
110
+ continue;
111
+ }
112
+ hasNonFallbackCommand = true;
113
+ if (!BASH_SILENT_COMMANDS.has(baseCommand)) {
114
+ return false;
115
+ }
116
+ }
117
+ return hasNonFallbackCommand;
118
+ }
119
+
120
+ export function isAutobackgroundingAllowed(command: string): boolean {
121
+ const parts = splitCommand_DEPRECATED(command);
122
+ if (parts.length === 0) return true;
123
+ const baseCommand = parts[0]?.trim();
124
+ if (!baseCommand) return true;
125
+ return !DISALLOWED_AUTO_BACKGROUND_COMMANDS.includes(baseCommand);
126
+ }
127
+
128
+ export function detectBlockedSleepPattern(command: string): string | null {
129
+ const parts = splitCommand_DEPRECATED(command);
130
+ if (parts.length === 0) return null;
131
+ const first = parts[0]?.trim() ?? '';
132
+ const match = /^sleep\s+(\d+)\s*$/.exec(first);
133
+ const secondsText = match?.[1];
134
+ if (!secondsText) return null;
135
+ const seconds = parseInt(secondsText, 10);
136
+ if (seconds < 2) return null;
137
+ const rest = parts.slice(1).join(' ').trim();
138
+ return rest ? `sleep ${seconds} followed by: ${rest}` : `standalone sleep ${seconds}`;
139
+ }
140
+
141
+ export function getCommandTypeForLogging(command: string): AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS {
142
+ const parts = splitCommand_DEPRECATED(command);
143
+ if (parts.length === 0) return 'other' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS;
144
+ for (const part of parts) {
145
+ const baseCommand = part.split(' ')[0] || '';
146
+ if (COMMON_BACKGROUND_COMMANDS.includes(baseCommand as (typeof COMMON_BACKGROUND_COMMANDS)[number])) {
147
+ return baseCommand as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS;
148
+ }
149
+ }
150
+ return 'other' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS;
151
+ }
@@ -0,0 +1,40 @@
1
+ import { createRequire } from 'node:module'
2
+
3
+ type SearchReadClassification = {
4
+ readonly isSearch: boolean
5
+ readonly isRead: boolean
6
+ readonly isList: boolean
7
+ }
8
+
9
+ type BashCommandClassificationRuntime = {
10
+ readonly isSearchOrReadBashCommand: (
11
+ command: string,
12
+ ) => SearchReadClassification
13
+ readonly detectBlockedSleepPattern: (command: string) => string | null
14
+ }
15
+
16
+ const requireModule = createRequire(import.meta.url)
17
+ let cachedRuntime: BashCommandClassificationRuntime | undefined
18
+
19
+ function isBashCommandClassificationRuntime(
20
+ value: unknown,
21
+ ): value is BashCommandClassificationRuntime {
22
+ if (typeof value !== 'object' || value === null) return false
23
+ const module = value as Partial<
24
+ Record<keyof BashCommandClassificationRuntime, unknown>
25
+ >
26
+ return (
27
+ typeof module.isSearchOrReadBashCommand === 'function' &&
28
+ typeof module.detectBlockedSleepPattern === 'function'
29
+ )
30
+ }
31
+
32
+ export function loadBashCommandClassificationRuntime(): BashCommandClassificationRuntime {
33
+ if (cachedRuntime !== undefined) return cachedRuntime
34
+ const loaded: unknown = requireModule('./commandClassification.js')
35
+ if (!isBashCommandClassificationRuntime(loaded)) {
36
+ throw new Error('Bash command classification module shape mismatch')
37
+ }
38
+ cachedRuntime = loaded
39
+ return loaded
40
+ }
@@ -0,0 +1,33 @@
1
+ import { createRequire } from 'node:module'
2
+ import type { ToolPermissionContext } from '../../Tool.js'
3
+
4
+ type CwdResetRuntime = {
5
+ readonly resetCwdIfOutsideProject: (
6
+ toolPermissionContext: ToolPermissionContext,
7
+ ) => boolean
8
+ }
9
+
10
+ const requireModule = createRequire(import.meta.url)
11
+ let cachedRuntime: CwdResetRuntime | undefined
12
+
13
+ function isCwdResetRuntime(value: unknown): value is CwdResetRuntime {
14
+ if (typeof value !== 'object' || value === null) return false
15
+ const module = value as Partial<Record<keyof CwdResetRuntime, unknown>>
16
+ return typeof module.resetCwdIfOutsideProject === 'function'
17
+ }
18
+
19
+ function loadCwdResetRuntime(): CwdResetRuntime {
20
+ if (cachedRuntime !== undefined) return cachedRuntime
21
+ const loaded: unknown = requireModule('./utils.js')
22
+ if (!isCwdResetRuntime(loaded)) {
23
+ throw new Error('Bash utility module did not expose cwd reset helper')
24
+ }
25
+ cachedRuntime = loaded
26
+ return loaded
27
+ }
28
+
29
+ export function resetShellCwdIfOutsideProject(
30
+ toolPermissionContext: ToolPermissionContext,
31
+ ): boolean {
32
+ return loadCwdResetRuntime().resetCwdIfOutsideProject(toolPermissionContext)
33
+ }
@@ -0,0 +1,11 @@
1
+ const MAX_LINES_TO_SHOW = 3
2
+
3
+ export function isShellOutputLineTruncated(content: string): boolean {
4
+ let position = 0
5
+ for (let line = 0; line <= MAX_LINES_TO_SHOW; line++) {
6
+ position = content.indexOf('\n', position)
7
+ if (position === -1) return false
8
+ position++
9
+ }
10
+ return position < content.length
11
+ }
@@ -3,6 +3,9 @@ import type { ToolPermissionContext } from '../../Tool.js'
3
3
  import { splitCommand_DEPRECATED } from '../../utils/bash/commands.js'
4
4
  import type { PermissionResult } from '../../utils/permissions/PermissionResult.js'
5
5
  import type { BashTool } from './BashTool.js'
6
+ import { getDestructiveCommandWarning } from './destructiveCommandWarning.js'
7
+ import { getBypassImmuneShellPermissionResult } from './shellPermissionGauntlet.js'
8
+ import { BASH_TOOL_NAME } from './toolName.js'
6
9
 
7
10
  const ACCEPT_EDITS_ALLOWED_COMMANDS = [
8
11
  'mkdir',
@@ -73,8 +76,17 @@ export function checkPermissionMode(
73
76
  input: z.infer<typeof BashTool.inputSchema>,
74
77
  toolPermissionContext: ToolPermissionContext,
75
78
  ): PermissionResult {
76
- // Skip if in bypass mode (handled elsewhere)
77
79
  if (toolPermissionContext.mode === 'bypassPermissions') {
80
+ const bypassImmuneResult = getBypassImmuneShellPermissionResult(
81
+ input.command,
82
+ BASH_TOOL_NAME,
83
+ toolPermissionContext,
84
+ getDestructiveCommandWarning,
85
+ )
86
+ if (bypassImmuneResult !== null) {
87
+ return bypassImmuneResult
88
+ }
89
+
78
90
  return {
79
91
  behavior: 'passthrough',
80
92
  message: 'Bypass mode is handled in main permission flow',
@@ -0,0 +1,42 @@
1
+ import { copyFile, link, stat as fsStat, truncate as fsTruncate } from 'fs/promises';
2
+ import { ensureToolResultsDir, getToolResultPath } from '../../utils/toolResultStorage.js';
3
+ import type { ExecResult } from '../../utils/ShellCommand.js';
4
+
5
+ const MAX_PERSISTED_SIZE = 64 * 1024 * 1024;
6
+
7
+ type PersistedOutput = {
8
+ readonly path?: string;
9
+ readonly size?: number;
10
+ };
11
+
12
+ export async function persistLargeShellOutput(result: ExecResult): Promise<PersistedOutput> {
13
+ if (!result.outputFilePath || !result.outputTaskId) {
14
+ return {};
15
+ }
16
+ try {
17
+ const fileStat = await fsStat(result.outputFilePath);
18
+ await ensureToolResultsDir();
19
+ const dest = getToolResultPath(result.outputTaskId, false);
20
+ if (fileStat.size > MAX_PERSISTED_SIZE) {
21
+ await fsTruncate(result.outputFilePath, MAX_PERSISTED_SIZE);
22
+ }
23
+ try {
24
+ await link(result.outputFilePath, dest);
25
+ } catch (error) {
26
+ if (error instanceof Error) {
27
+ await copyFile(result.outputFilePath, dest);
28
+ } else {
29
+ throw error;
30
+ }
31
+ }
32
+ return {
33
+ path: dest,
34
+ size: fileStat.size
35
+ };
36
+ } catch (error) {
37
+ if (error instanceof Error) {
38
+ return {};
39
+ }
40
+ throw error;
41
+ }
42
+ }
@@ -0,0 +1,66 @@
1
+ import { feature } from 'bun:bundle';
2
+ import type { ToolUseContext, ValidationResult } from '../../Tool.js';
3
+ import type { PermissionResult } from '../../utils/permissions/PermissionResult.js';
4
+ import { parseForSecurity } from '../../utils/bash/ast.js';
5
+ import { bashToolHasPermission, commandHasAnyCd, matchWildcardPattern, permissionRuleExtractPrefix } from './bashPermissions.js';
6
+ import { checkReadOnlyConstraints } from './readOnlyValidation.js';
7
+ import { getDestructiveCommandWarning } from './destructiveCommandWarning.js';
8
+ import { getBypassImmuneShellPermissionResult } from './shellPermissionGauntlet.js';
9
+ import { BASH_TOOL_NAME } from './toolName.js';
10
+ import { detectBlockedSleepPattern } from './commandClassification.js';
11
+ import { isBackgroundTasksDisabled } from './schemas.js';
12
+ import type { BashToolInput } from './schemas.js';
13
+
14
+ export async function validateBashInput(input: BashToolInput): Promise<ValidationResult> {
15
+ if (feature('MONITOR_TOOL') && !isBackgroundTasksDisabled && !input.run_in_background) {
16
+ const sleepPattern = detectBlockedSleepPattern(input.command);
17
+ if (sleepPattern !== null) {
18
+ return {
19
+ result: false,
20
+ message: `Blocked: ${sleepPattern}. Run blocking commands in the background with run_in_background: true — you'll get a completion notification when done. For streaming events (watching logs, polling APIs), use the Monitor tool. If you genuinely need a delay (rate limiting, deliberate pacing), keep it under 2 seconds.`,
21
+ errorCode: 10
22
+ };
23
+ }
24
+ }
25
+ return {
26
+ result: true
27
+ };
28
+ }
29
+
30
+ export function isBashReadOnly(input: BashToolInput): boolean {
31
+ const compoundCommandHasCd = commandHasAnyCd(input.command);
32
+ const result = checkReadOnlyConstraints(input, compoundCommandHasCd);
33
+ return result.behavior === 'allow';
34
+ }
35
+
36
+ export async function prepareBashPermissionMatcher({
37
+ command
38
+ }: BashToolInput): Promise<(pattern: string) => boolean> {
39
+ const parsed = await parseForSecurity(command);
40
+ if (parsed.kind !== 'simple') {
41
+ return () => true;
42
+ }
43
+ const subcommands = parsed.commands.map(c => c.argv.join(' '));
44
+ return pattern => {
45
+ const prefix = permissionRuleExtractPrefix(pattern);
46
+ return subcommands.some(cmd => {
47
+ if (prefix !== null) {
48
+ return cmd === prefix || cmd.startsWith(`${prefix} `);
49
+ }
50
+ return matchWildcardPattern(pattern, cmd);
51
+ });
52
+ };
53
+ }
54
+
55
+ export async function checkBashPermissions(input: BashToolInput, context: ToolUseContext): Promise<PermissionResult> {
56
+ const bypassImmuneResult = getBypassImmuneShellPermissionResult(
57
+ input.command,
58
+ BASH_TOOL_NAME,
59
+ context.getAppState().toolPermissionContext,
60
+ getDestructiveCommandWarning
61
+ );
62
+ if (bypassImmuneResult !== null) {
63
+ return bypassImmuneResult;
64
+ }
65
+ return bashToolHasPermission(input, context);
66
+ }
@@ -0,0 +1,44 @@
1
+ import { createRequire } from 'node:module'
2
+ import type { ToolUseContext, ValidationResult } from '../../Tool.js'
3
+ import type { PermissionResult } from '../../utils/permissions/PermissionResult.js'
4
+ import type { BashToolInput } from './schemas.js'
5
+
6
+ type BashPermissionRuntime = {
7
+ readonly validateBashInput: (
8
+ input: BashToolInput,
9
+ ) => Promise<ValidationResult>
10
+ readonly isBashReadOnly: (input: BashToolInput) => boolean
11
+ readonly prepareBashPermissionMatcher: (
12
+ input: BashToolInput,
13
+ ) => Promise<(pattern: string) => boolean>
14
+ readonly checkBashPermissions: (
15
+ input: BashToolInput,
16
+ context: ToolUseContext,
17
+ ) => Promise<PermissionResult>
18
+ }
19
+
20
+ const requireModule = createRequire(import.meta.url)
21
+ let cachedRuntime: BashPermissionRuntime | undefined
22
+
23
+ function isBashPermissionRuntime(
24
+ value: unknown,
25
+ ): value is BashPermissionRuntime {
26
+ if (typeof value !== 'object' || value === null) return false
27
+ const module = value as Partial<Record<keyof BashPermissionRuntime, unknown>>
28
+ return (
29
+ typeof module.validateBashInput === 'function' &&
30
+ typeof module.isBashReadOnly === 'function' &&
31
+ typeof module.prepareBashPermissionMatcher === 'function' &&
32
+ typeof module.checkBashPermissions === 'function'
33
+ )
34
+ }
35
+
36
+ export function loadBashPermissionRuntime(): BashPermissionRuntime {
37
+ if (cachedRuntime !== undefined) return cachedRuntime
38
+ const loaded: unknown = requireModule('./permissionClassification.js')
39
+ if (!isBashPermissionRuntime(loaded)) {
40
+ throw new Error('Bash permission module did not expose expected functions')
41
+ }
42
+ cachedRuntime = loaded
43
+ return loaded
44
+ }