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,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
+ }