ummaya 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (534) hide show
  1. package/README.md +17 -3
  2. package/bin/ummaya +10 -1
  3. package/npm-shrinkwrap.json +253 -2
  4. package/package.json +5 -1
  5. package/prompts/manifest.yaml +2 -2
  6. package/prompts/session_guidance_v1.md +3 -1
  7. package/prompts/system_v1.md +9 -7
  8. package/pyproject.toml +26 -7
  9. package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
  10. package/src/ummaya/_canonical/__init__.py +2 -0
  11. package/src/ummaya/context/builder.py +17 -11
  12. package/src/ummaya/engine/engine.py +30 -113
  13. package/src/ummaya/engine/query.py +20 -0
  14. package/src/ummaya/evidence/__init__.py +44 -0
  15. package/src/ummaya/evidence/__main__.py +7 -0
  16. package/src/ummaya/evidence/dataset_contract.py +193 -0
  17. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  18. package/src/ummaya/evidence/document_harness.py +313 -0
  19. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  20. package/src/ummaya/evidence/gates.py +70 -0
  21. package/src/ummaya/evidence/json_types.py +20 -0
  22. package/src/ummaya/evidence/models.py +145 -0
  23. package/src/ummaya/evidence/output_payload.py +89 -0
  24. package/src/ummaya/evidence/payload_documents.py +233 -0
  25. package/src/ummaya/evidence/route_contracts.py +224 -0
  26. package/src/ummaya/evidence/route_helpers.py +150 -0
  27. package/src/ummaya/evidence/runner.py +177 -0
  28. package/src/ummaya/evidence/source_provenance.py +246 -0
  29. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  30. package/src/ummaya/evidence/task_registry.py +264 -0
  31. package/src/ummaya/evidence/tool_layer.py +39 -0
  32. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  33. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  34. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  35. package/src/ummaya/ipc/frame_schema.py +52 -5
  36. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  37. package/src/ummaya/ipc/stdio.py +2282 -417
  38. package/src/ummaya/llm/client.py +234 -59
  39. package/src/ummaya/llm/config.py +8 -3
  40. package/src/ummaya/llm/reasoning.py +84 -0
  41. package/src/ummaya/primitives/__init__.py +6 -2
  42. package/src/ummaya/primitives/delegation.py +1 -1
  43. package/src/ummaya/primitives/document.py +28 -0
  44. package/src/ummaya/settings.py +0 -3
  45. package/src/ummaya/tools/discovery_bridge.py +34 -2
  46. package/src/ummaya/tools/documents/__init__.py +297 -0
  47. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  48. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  49. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  50. package/src/ummaya/tools/documents/authoring.py +283 -0
  51. package/src/ummaya/tools/documents/baselines.py +114 -0
  52. package/src/ummaya/tools/documents/capability.py +331 -0
  53. package/src/ummaya/tools/documents/contracts.py +112 -0
  54. package/src/ummaya/tools/documents/conversion.py +521 -0
  55. package/src/ummaya/tools/documents/diff.py +275 -0
  56. package/src/ummaya/tools/documents/engines.py +163 -0
  57. package/src/ummaya/tools/documents/evaluation.py +291 -0
  58. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  59. package/src/ummaya/tools/documents/fixtures.py +174 -0
  60. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  61. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  62. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  63. package/src/ummaya/tools/documents/formats/base.py +41 -0
  64. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  65. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  66. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  67. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  68. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  69. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  70. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  71. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  72. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  73. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  74. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  75. package/src/ummaya/tools/documents/inspection.py +289 -0
  76. package/src/ummaya/tools/documents/intake.py +1079 -0
  77. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  78. package/src/ummaya/tools/documents/models.py +1598 -0
  79. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  80. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  81. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  82. package/src/ummaya/tools/documents/patch.py +170 -0
  83. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  84. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  85. package/src/ummaya/tools/documents/permissions.py +110 -0
  86. package/src/ummaya/tools/documents/planner.py +616 -0
  87. package/src/ummaya/tools/documents/registry.py +2733 -0
  88. package/src/ummaya/tools/documents/render.py +978 -0
  89. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  90. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  91. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  92. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  93. package/src/ummaya/tools/documents/reread.py +157 -0
  94. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  95. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  96. package/src/ummaya/tools/documents/scorecard.py +184 -0
  97. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  98. package/src/ummaya/tools/documents/style.py +48 -0
  99. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  100. package/src/ummaya/tools/documents/validate.py +347 -0
  101. package/src/ummaya/tools/executor.py +61 -12
  102. package/src/ummaya/tools/geocoding/kakao_client.py +1 -2
  103. package/src/ummaya/tools/kma/apihub_catalog.py +984 -1
  104. package/src/ummaya/tools/kma/apihub_structured_adapter.py +86 -6
  105. package/src/ummaya/tools/kma/apihub_url_adapter.py +593 -0
  106. package/src/ummaya/tools/kma/apihub_url_catalog.py +296 -0
  107. package/src/ummaya/tools/live_proxy.py +0 -3
  108. package/src/ummaya/tools/location_adapters.py +8 -6
  109. package/src/ummaya/tools/manifest_metadata.py +16 -3
  110. package/src/ummaya/tools/models.py +5 -1
  111. package/src/ummaya/tools/mvp_surface.py +2 -2
  112. package/src/ummaya/tools/nmc/emergency_search.py +8 -6
  113. package/src/ummaya/tools/register_all.py +17 -0
  114. package/src/ummaya/tools/registry.py +10 -1
  115. package/src/ummaya/tools/resolve_location.py +4 -4
  116. package/src/ummaya/tools/routing/__init__.py +59 -0
  117. package/src/ummaya/tools/routing/builder.py +105 -0
  118. package/src/ummaya/tools/routing/cards.py +29 -0
  119. package/src/ummaya/tools/routing/decision_service.py +534 -0
  120. package/src/ummaya/tools/routing/decision_types.py +74 -0
  121. package/src/ummaya/tools/routing/feasibility.py +122 -0
  122. package/src/ummaya/tools/routing/intent.py +17 -0
  123. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  124. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  125. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  126. package/src/ummaya/tools/routing/intent_types.py +48 -0
  127. package/src/ummaya/tools/routing/lint.py +78 -0
  128. package/src/ummaya/tools/routing/metadata.py +174 -0
  129. package/src/ummaya/tools/routing/projection.py +340 -0
  130. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  131. package/src/ummaya/tools/routing/schema.py +81 -0
  132. package/src/ummaya/tools/routing/types.py +96 -0
  133. package/src/ummaya/tools/routing_index.py +2 -2
  134. package/src/ummaya/tools/search.py +40 -106
  135. package/src/ummaya/tools/verified_data_go_kr/_manifest.py +115 -25
  136. package/src/ummaya/tools/verified_data_go_kr/airkorea_air_quality.py +109 -4
  137. package/src/ummaya/tools/verified_data_go_kr/nmc_aed_site.py +108 -2
  138. package/src/ummaya/tools/verified_data_go_kr/pps_bid_public_info.py +174 -9
  139. package/src/ummaya/tools/verified_data_go_kr/tago_bus_arrival.py +66 -3
  140. package/src/ummaya/tools/verified_data_go_kr/tago_bus_location.py +12 -2
  141. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route.py +8 -2
  142. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route_station.py +114 -0
  143. package/src/ummaya/tools/verified_data_go_kr/tago_bus_station.py +14 -3
  144. package/src/ummaya/tools/verify_canonical_map.py +21 -0
  145. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  146. package/tui/package.json +1 -2
  147. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  148. package/tui/src/QueryEngine.ts +12 -4
  149. package/tui/src/bridge/inboundAttachments.ts +3 -3
  150. package/tui/src/cli/handlers/auth.ts +4 -13
  151. package/tui/src/cli/handlers/mcp.tsx +3 -3
  152. package/tui/src/cli/print.ts +69 -18
  153. package/tui/src/cli/update.ts +13 -13
  154. package/tui/src/commands/copy/index.ts +1 -1
  155. package/tui/src/commands/cost/cost.ts +2 -2
  156. package/tui/src/commands/init-verifiers.ts +5 -5
  157. package/tui/src/commands/init.ts +30 -30
  158. package/tui/src/commands/insights.ts +44 -44
  159. package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
  160. package/tui/src/commands/install-github-app/setupGitHubActions.ts +3 -3
  161. package/tui/src/commands/install-github-app/types.ts +8 -30
  162. package/tui/src/commands/install.tsx +5 -5
  163. package/tui/src/commands/mcp/addCommand.ts +5 -5
  164. package/tui/src/commands/mcp/xaaIdpCommand.ts +2 -2
  165. package/tui/src/commands/plugin/ManageMarketplaces.tsx +2 -2
  166. package/tui/src/commands/plugin/types.ts +6 -28
  167. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  168. package/tui/src/commands/reasoning/index.ts +13 -0
  169. package/tui/src/commands/reasoning/reasoning.tsx +177 -0
  170. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  171. package/tui/src/commands/thinkback/thinkback.tsx +3 -3
  172. package/tui/src/commands.ts +2 -0
  173. package/tui/src/components/Feedback.tsx +1 -1
  174. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  175. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  176. package/tui/src/components/Messages.tsx +2 -1
  177. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  178. package/tui/src/components/Spinner/types.ts +6 -28
  179. package/tui/src/components/Spinner.tsx +2 -2
  180. package/tui/src/components/agents/generateAgent.ts +1 -1
  181. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  182. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  183. package/tui/src/components/design-system/LoadingState.tsx +2 -2
  184. package/tui/src/components/mcp/types.ts +16 -38
  185. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  186. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  187. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  188. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  189. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  190. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  191. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  192. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  193. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  194. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  195. package/tui/src/components/primitive/index.tsx +43 -1
  196. package/tui/src/components/primitive/types.ts +137 -0
  197. package/tui/src/components/ui/option.ts +4 -26
  198. package/tui/src/constants/common.ts +0 -2
  199. package/tui/src/constants/prompts.ts +4 -3
  200. package/tui/src/constants/querySource.ts +4 -26
  201. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  202. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  203. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  204. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  205. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  206. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  207. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  208. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  209. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  210. package/tui/src/ink/ink.tsx +33 -14
  211. package/tui/src/ink/reconciler.ts +2 -3
  212. package/tui/src/ink/render-to-screen.ts +30 -10
  213. package/tui/src/ipc/bridge.ts +62 -15
  214. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  215. package/tui/src/ipc/codec.ts +29 -3
  216. package/tui/src/ipc/frames.generated.ts +407 -312
  217. package/tui/src/ipc/llmClient.ts +279 -76
  218. package/tui/src/ipc/llmTypes.ts +16 -1
  219. package/tui/src/ipc/schema/frame.schema.json +1 -3475
  220. package/tui/src/keybindings/defaultBindings.ts +4 -0
  221. package/tui/src/main.tsx +32 -11
  222. package/tui/src/native-ts/file-index/index.ts +33 -3
  223. package/tui/src/observability/surface.ts +2 -2
  224. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  225. package/tui/src/projectOnboardingState.ts +7 -6
  226. package/tui/src/query/chatMessageTypes.ts +18 -0
  227. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  228. package/tui/src/query/deps.ts +1 -1
  229. package/tui/src/query/messageGuards.ts +106 -0
  230. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  231. package/tui/src/query/run.ts +1075 -0
  232. package/tui/src/query/supportBoundary.ts +168 -0
  233. package/tui/src/query/toolResultErrors.ts +103 -0
  234. package/tui/src/query/toolRunner.ts +687 -0
  235. package/tui/src/query/unavailableToolRepair.ts +118 -0
  236. package/tui/src/query.ts +9 -1721
  237. package/tui/src/screens/REPL.tsx +42 -31
  238. package/tui/src/services/api/adapterManifest.ts +4 -0
  239. package/tui/src/services/api/backendChat/events.ts +117 -0
  240. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  241. package/tui/src/services/api/backendChat/frame.ts +9 -0
  242. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  243. package/tui/src/services/api/backendChat/types.ts +62 -0
  244. package/tui/src/services/api/backendChat.ts +1 -0
  245. package/tui/src/services/api/client.ts +98 -14
  246. package/tui/src/services/api/errorUtils.ts +5 -5
  247. package/tui/src/services/api/errors.ts +1 -1
  248. package/tui/src/services/api/logging.ts +1 -1
  249. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  250. package/tui/src/services/api/ummaya/messages.ts +255 -0
  251. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  252. package/tui/src/services/api/ummaya/provider.ts +200 -0
  253. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  254. package/tui/src/services/api/ummaya/request.ts +200 -0
  255. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  256. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  257. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  258. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  259. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  260. package/tui/src/services/api/ummaya/types.ts +110 -0
  261. package/tui/src/services/api/ummaya/usage.ts +30 -0
  262. package/tui/src/services/api/ummaya.ts +26 -364
  263. package/tui/src/services/api/withRetry.ts +1 -1
  264. package/tui/src/services/awaySummary.ts +2 -2
  265. package/tui/src/services/claudeAiLimits.ts +1 -1
  266. package/tui/src/services/compact/autoCompact.ts +1 -1
  267. package/tui/src/services/compact/compact.ts +1 -1
  268. package/tui/src/services/lsp/types.ts +8 -30
  269. package/tui/src/services/tips/types.ts +6 -28
  270. package/tui/src/services/tokenEstimation.ts +1 -1
  271. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  272. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  273. package/tui/src/services/tools/toolExecution.ts +94 -1
  274. package/tui/src/skills/bundled/stuck.ts +12 -12
  275. package/tui/src/state/AppStateStore.ts +7 -0
  276. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  277. package/tui/src/store/session-store.ts +10 -36
  278. package/tui/src/stubs/any-stub.ts +15 -10
  279. package/tui/src/stubs/color-diff-napi.ts +37 -23
  280. package/tui/src/stubs/globals.d.ts +3 -3
  281. package/tui/src/stubs/macro-preload.ts +23 -12
  282. package/tui/src/tools/AdapterTool/AdapterTool.ts +1239 -163
  283. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  284. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  285. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  286. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  287. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  288. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  289. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  290. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  291. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  292. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  293. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  294. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  295. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  296. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  297. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  298. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  299. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  300. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  301. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  302. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  303. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  304. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  305. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  306. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  307. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  308. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  309. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  310. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  311. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  312. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  313. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  314. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  315. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  316. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  317. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  318. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  319. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  320. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  321. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  322. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  323. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  324. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  325. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  326. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  327. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  328. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  329. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  330. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  331. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  332. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  333. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  334. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  335. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  336. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  337. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  338. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  339. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  340. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  341. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  342. package/tui/src/tools/BashTool/call.ts +202 -0
  343. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  344. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  345. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  346. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  347. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  348. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  349. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  350. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  351. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  352. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  353. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  354. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  355. package/tui/src/tools/BashTool/schemas.ts +65 -0
  356. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  357. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  358. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  359. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  360. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  361. package/tui/src/tools/BriefTool/upload.ts +1 -1
  362. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  363. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  364. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  365. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  366. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  367. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  368. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  369. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  370. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  371. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  372. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  373. package/tui/src/tools/FileEditTool/call.ts +228 -0
  374. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  375. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  376. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  377. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  378. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  379. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  380. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +48 -29
  381. package/tui/src/tools/LookupPrimitive/prompt.ts +6 -7
  382. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  383. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  384. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  385. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  386. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  387. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  388. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  389. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  390. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  391. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  392. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  393. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  394. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  395. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  396. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  397. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  398. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  399. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  400. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  401. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  402. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  403. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  404. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +30 -19
  405. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  406. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  407. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +51 -18
  408. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  409. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  410. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  411. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  412. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  413. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  414. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  415. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  416. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  417. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  418. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  419. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  420. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  421. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  422. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  423. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  424. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  425. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  426. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  427. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  428. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  429. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  430. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  431. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  432. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  433. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +27 -10
  434. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  435. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  436. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  437. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  438. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  439. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  440. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  441. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  442. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  443. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  444. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  445. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  446. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  447. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  448. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  449. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  450. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  451. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  452. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  453. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  454. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  455. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  456. package/tui/src/tools/_shared/citizenUserText.ts +49 -0
  457. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  458. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  459. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  460. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  461. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  462. package/tui/src/tools/_shared/locationInputRepair.ts +112 -0
  463. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  464. package/tui/src/tools/_shared/rootPrimitiveInput.ts +68 -0
  465. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  466. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  467. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  468. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  469. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  470. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  471. package/tui/src/tools/_shared/toolChoiceRepair.ts +61 -0
  472. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  473. package/tui/src/tools.ts +39 -190
  474. package/tui/src/types/fileSuggestion.ts +4 -26
  475. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  476. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  477. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  478. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  479. package/tui/src/types/message.ts +80 -102
  480. package/tui/src/types/messageQueueTypes.ts +6 -28
  481. package/tui/src/types/notebook.ts +16 -38
  482. package/tui/src/types/statusLine.ts +4 -26
  483. package/tui/src/types/tools.ts +24 -46
  484. package/tui/src/types/utils.ts +6 -28
  485. package/tui/src/upstreamproxy/relay.ts +7 -3
  486. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  487. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  488. package/tui/src/utils/attachments.ts +1 -1
  489. package/tui/src/utils/auth.ts +129 -139
  490. package/tui/src/utils/bash/ast.ts +23 -23
  491. package/tui/src/utils/bash/bashParser.ts +5 -5
  492. package/tui/src/utils/billing.ts +1 -1
  493. package/tui/src/utils/collapseReadSearch.ts +3 -3
  494. package/tui/src/utils/cronTasks.ts +1 -1
  495. package/tui/src/utils/execFileNoThrow.ts +1 -1
  496. package/tui/src/utils/filePersistence/types.ts +16 -38
  497. package/tui/src/utils/forkedAgent.ts +1 -1
  498. package/tui/src/utils/gracefulShutdown.ts +4 -4
  499. package/tui/src/utils/heapDumpService.ts +12 -8
  500. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  501. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  502. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  503. package/tui/src/utils/kExaoneReasoning.ts +138 -0
  504. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  505. package/tui/src/utils/messages.ts +19 -0
  506. package/tui/src/utils/migrateSessions.ts +3 -3
  507. package/tui/src/utils/model/model.ts +6 -6
  508. package/tui/src/utils/multiToolLayout.ts +13 -0
  509. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  510. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  511. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  512. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  513. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  514. package/tui/src/utils/processUserInput/processSlashCommand.tsx +2 -2
  515. package/tui/src/utils/processUserInput/processUserInput.ts +26 -0
  516. package/tui/src/utils/protectedNamespace.ts +5 -3
  517. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  518. package/tui/src/utils/ripgrep.ts +16 -7
  519. package/tui/src/utils/sessionTitle.ts +1 -1
  520. package/tui/src/utils/settings/applySettingsChange.ts +4 -0
  521. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  522. package/tui/src/utils/settings/types.ts +9 -3
  523. package/tui/src/utils/shell/prefix.ts +1 -1
  524. package/tui/src/utils/sideQuery.ts +1 -1
  525. package/tui/src/utils/stats.ts +1 -1
  526. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  527. package/tui/src/utils/teleport.tsx +1 -1
  528. package/uv.lock +394 -22
  529. package/assets/copilot-gate-logo.svg +0 -58
  530. package/assets/govon-logo.svg +0 -40
  531. package/src/ummaya/eval/__init__.py +0 -5
  532. package/src/ummaya/eval/retrieval.py +0 -713
  533. package/tui/src/services/api/claude.ts +0 -3510
  534. package/tui/src/utils/messageStream.ts +0 -186
@@ -1,22 +1,10 @@
1
1
  import { feature } from 'bun:bundle'
2
- import { extname, isAbsolute, resolve } from 'path'
3
- import {
4
- fileHistoryEnabled,
5
- fileHistoryTrackEdit,
6
- } from 'src/utils/fileHistory.js'
7
2
  import { z } from 'zod/v4'
8
- import { buildTool, type ToolDef, type ToolUseContext } from '../../Tool.js'
9
- import type { NotebookCell, NotebookContent } from '../../types/notebook.js'
10
- import { getCwd } from '../../utils/cwd.js'
11
- import { isENOENT } from '../../utils/errors.js'
12
- import { getFileModificationTime, writeTextContent } from '../../utils/file.js'
13
- import { readFileSyncWithMetadata } from '../../utils/fileRead.js'
14
- import { safeParseJSON } from '../../utils/json.js'
3
+ import { buildTool, type ToolDef } from '../../Tool.js'
15
4
  import { lazySchema } from '../../utils/lazySchema.js'
16
- import { parseCellId } from '../../utils/notebook.js'
17
5
  import { checkWritePermissionForTool } from '../../utils/permissions/filesystem.js'
18
6
  import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js'
19
- import { jsonParse, jsonStringify } from '../../utils/slowOperations.js'
7
+ import { callNotebookEditTool } from './call.js'
20
8
  import { NOTEBOOK_EDIT_TOOL_NAME } from './constants.js'
21
9
  import { DESCRIPTION, PROMPT } from './prompt.js'
22
10
  import {
@@ -26,6 +14,7 @@ import {
26
14
  renderToolUseMessage,
27
15
  renderToolUseRejectedMessage,
28
16
  } from './UI.js'
17
+ import { validateNotebookEditInput } from './validateInput.js'
29
18
 
30
19
  export const inputSchema = lazySchema(() =>
31
20
  z.strictObject({
@@ -173,318 +162,10 @@ export const NotebookEditTool = buildTool({
173
162
  renderToolUseRejectedMessage,
174
163
  renderToolUseErrorMessage,
175
164
  renderToolResultMessage,
176
- async validateInput(
177
- { notebook_path, cell_type, cell_id, edit_mode = 'replace' },
178
- toolUseContext: ToolUseContext,
179
- ) {
180
- const fullPath = isAbsolute(notebook_path)
181
- ? notebook_path
182
- : resolve(getCwd(), notebook_path)
183
-
184
- // SECURITY: Skip filesystem operations for UNC paths to prevent NTLM credential leaks.
185
- if (fullPath.startsWith('\\\\') || fullPath.startsWith('//')) {
186
- return { result: true }
187
- }
188
-
189
- if (extname(fullPath) !== '.ipynb') {
190
- return {
191
- result: false,
192
- message:
193
- 'File must be a Jupyter notebook (.ipynb file). For editing other file types, use the FileEdit tool.',
194
- errorCode: 2,
195
- }
196
- }
197
-
198
- if (
199
- edit_mode !== 'replace' &&
200
- edit_mode !== 'insert' &&
201
- edit_mode !== 'delete'
202
- ) {
203
- return {
204
- result: false,
205
- message: 'Edit mode must be replace, insert, or delete.',
206
- errorCode: 4,
207
- }
208
- }
209
-
210
- if (edit_mode === 'insert' && !cell_type) {
211
- return {
212
- result: false,
213
- message: 'Cell type is required when using edit_mode=insert.',
214
- errorCode: 5,
215
- }
216
- }
217
-
218
- // Require Read-before-Edit (matches FileEditTool/FileWriteTool). Without
219
- // this, the model could edit a notebook it never saw, or edit against a
220
- // stale view after an external change — silent data loss.
221
- const readTimestamp = toolUseContext.readFileState.get(fullPath)
222
- if (!readTimestamp) {
223
- return {
224
- result: false,
225
- message:
226
- 'File has not been read yet. Read it first before writing to it.',
227
- errorCode: 9,
228
- }
229
- }
230
- if (getFileModificationTime(fullPath) > readTimestamp.timestamp) {
231
- return {
232
- result: false,
233
- message:
234
- 'File has been modified since read, either by the user or by a linter. Read it again before attempting to write it.',
235
- errorCode: 10,
236
- }
237
- }
238
-
239
- let content: string
240
- try {
241
- content = readFileSyncWithMetadata(fullPath).content
242
- } catch (e) {
243
- if (isENOENT(e)) {
244
- return {
245
- result: false,
246
- message: 'Notebook file does not exist.',
247
- errorCode: 1,
248
- }
249
- }
250
- throw e
251
- }
252
- const notebook = safeParseJSON(content) as NotebookContent | null
253
- if (!notebook) {
254
- return {
255
- result: false,
256
- message: 'Notebook is not valid JSON.',
257
- errorCode: 6,
258
- }
259
- }
260
- if (!cell_id) {
261
- if (edit_mode !== 'insert') {
262
- return {
263
- result: false,
264
- message: 'Cell ID must be specified when not inserting a new cell.',
265
- errorCode: 7,
266
- }
267
- }
268
- } else {
269
- // First try to find the cell by its actual ID
270
- const cellIndex = notebook.cells.findIndex(cell => cell.id === cell_id)
271
-
272
- if (cellIndex === -1) {
273
- // If not found, try to parse as a numeric index (cell-N format)
274
- const parsedCellIndex = parseCellId(cell_id)
275
- if (parsedCellIndex !== undefined) {
276
- if (!notebook.cells[parsedCellIndex]) {
277
- return {
278
- result: false,
279
- message: `Cell with index ${parsedCellIndex} does not exist in notebook.`,
280
- errorCode: 7,
281
- }
282
- }
283
- } else {
284
- return {
285
- result: false,
286
- message: `Cell with ID "${cell_id}" not found in notebook.`,
287
- errorCode: 8,
288
- }
289
- }
290
- }
291
- }
292
-
293
- return { result: true }
165
+ async validateInput(input, toolUseContext) {
166
+ return validateNotebookEditInput(input, toolUseContext)
294
167
  },
295
- async call(
296
- {
297
- notebook_path,
298
- new_source,
299
- cell_id,
300
- cell_type,
301
- edit_mode: originalEditMode,
302
- },
303
- { readFileState, updateFileHistoryState },
304
- _,
305
- parentMessage,
306
- ) {
307
- const fullPath = isAbsolute(notebook_path)
308
- ? notebook_path
309
- : resolve(getCwd(), notebook_path)
310
-
311
- if (fileHistoryEnabled()) {
312
- await fileHistoryTrackEdit(
313
- updateFileHistoryState,
314
- fullPath,
315
- parentMessage.uuid,
316
- )
317
- }
318
-
319
- try {
320
- // readFileSyncWithMetadata gives content + encoding + line endings in
321
- // one safeResolvePath + readFileSync pass, replacing the previous
322
- // detectFileEncoding + readFile + detectLineEndings chain (each of
323
- // which redid safeResolvePath and/or a 4KB readSync).
324
- const { content, encoding, lineEndings } =
325
- readFileSyncWithMetadata(fullPath)
326
- // Must use non-memoized jsonParse here: safeParseJSON caches by content
327
- // string and returns a shared object reference, but we mutate the
328
- // notebook in place below (cells.splice, targetCell.source = ...).
329
- // Using the memoized version poisons the cache for validateInput() and
330
- // any subsequent call() with the same file content.
331
- let notebook: NotebookContent
332
- try {
333
- notebook = jsonParse(content) as NotebookContent
334
- } catch {
335
- return {
336
- data: {
337
- new_source,
338
- cell_type: cell_type ?? 'code',
339
- language: 'python',
340
- edit_mode: 'replace',
341
- error: 'Notebook is not valid JSON.',
342
- cell_id,
343
- notebook_path: fullPath,
344
- original_file: '',
345
- updated_file: '',
346
- },
347
- }
348
- }
349
-
350
- let cellIndex
351
- if (!cell_id) {
352
- cellIndex = 0 // Default to inserting at the beginning if no cell_id is provided
353
- } else {
354
- // First try to find the cell by its actual ID
355
- cellIndex = notebook.cells.findIndex(cell => cell.id === cell_id)
356
-
357
- // If not found, try to parse as a numeric index (cell-N format)
358
- if (cellIndex === -1) {
359
- const parsedCellIndex = parseCellId(cell_id)
360
- if (parsedCellIndex !== undefined) {
361
- cellIndex = parsedCellIndex
362
- }
363
- }
364
-
365
- if (originalEditMode === 'insert') {
366
- cellIndex += 1 // Insert after the cell with this ID
367
- }
368
- }
369
-
370
- // Convert replace to insert if trying to replace one past the end
371
- let edit_mode = originalEditMode
372
- if (edit_mode === 'replace' && cellIndex === notebook.cells.length) {
373
- edit_mode = 'insert'
374
- if (!cell_type) {
375
- cell_type = 'code' // Default to code if no cell_type specified
376
- }
377
- }
378
-
379
- const language = notebook.metadata.language_info?.name ?? 'python'
380
- let new_cell_id = undefined
381
- if (
382
- notebook.nbformat > 4 ||
383
- (notebook.nbformat === 4 && notebook.nbformat_minor >= 5)
384
- ) {
385
- if (edit_mode === 'insert') {
386
- new_cell_id = Math.random().toString(36).substring(2, 15)
387
- } else if (cell_id !== null) {
388
- new_cell_id = cell_id
389
- }
390
- }
391
-
392
- if (edit_mode === 'delete') {
393
- // Delete the specified cell
394
- notebook.cells.splice(cellIndex, 1)
395
- } else if (edit_mode === 'insert') {
396
- let new_cell: NotebookCell
397
- if (cell_type === 'markdown') {
398
- new_cell = {
399
- cell_type: 'markdown',
400
- id: new_cell_id,
401
- source: new_source,
402
- metadata: {},
403
- }
404
- } else {
405
- new_cell = {
406
- cell_type: 'code',
407
- id: new_cell_id,
408
- source: new_source,
409
- metadata: {},
410
- execution_count: null,
411
- outputs: [],
412
- }
413
- }
414
- // Insert the new cell
415
- notebook.cells.splice(cellIndex, 0, new_cell)
416
- } else {
417
- // Find the specified cell
418
- const targetCell = notebook.cells[cellIndex]! // validateInput ensures cell_number is in bounds
419
- targetCell.source = new_source
420
- if (targetCell.cell_type === 'code') {
421
- // Reset execution count and clear outputs since cell was modified
422
- targetCell.execution_count = null
423
- targetCell.outputs = []
424
- }
425
- if (cell_type && cell_type !== targetCell.cell_type) {
426
- targetCell.cell_type = cell_type
427
- }
428
- }
429
- // Write back to file
430
- const IPYNB_INDENT = 1
431
- const updatedContent = jsonStringify(notebook, null, IPYNB_INDENT)
432
- writeTextContent(fullPath, updatedContent, encoding, lineEndings)
433
- // Update readFileState with post-write mtime (matches FileEditTool/
434
- // FileWriteTool). offset:undefined breaks FileReadTool's dedup match —
435
- // without this, Read→NotebookEdit→Read in the same millisecond would
436
- // return the file_unchanged stub against stale in-context content.
437
- readFileState.set(fullPath, {
438
- content: updatedContent,
439
- timestamp: getFileModificationTime(fullPath),
440
- offset: undefined,
441
- limit: undefined,
442
- })
443
- const data = {
444
- new_source,
445
- cell_type: cell_type ?? 'code',
446
- language,
447
- edit_mode: edit_mode ?? 'replace',
448
- cell_id: new_cell_id || undefined,
449
- error: '',
450
- notebook_path: fullPath,
451
- original_file: content,
452
- updated_file: updatedContent,
453
- }
454
- return {
455
- data,
456
- }
457
- } catch (error) {
458
- if (error instanceof Error) {
459
- const data = {
460
- new_source,
461
- cell_type: cell_type ?? 'code',
462
- language: 'python',
463
- edit_mode: 'replace',
464
- error: error.message,
465
- cell_id,
466
- notebook_path: fullPath,
467
- original_file: '',
468
- updated_file: '',
469
- }
470
- return {
471
- data,
472
- }
473
- }
474
- const data = {
475
- new_source,
476
- cell_type: cell_type ?? 'code',
477
- language: 'python',
478
- edit_mode: 'replace',
479
- error: 'Unknown error occurred while editing notebook',
480
- cell_id,
481
- notebook_path: fullPath,
482
- original_file: '',
483
- updated_file: '',
484
- }
485
- return {
486
- data,
487
- }
488
- }
168
+ async call(input, context, _, parentMessage) {
169
+ return callNotebookEditTool(input, context, parentMessage)
489
170
  },
490
171
  } satisfies ToolDef<InputSchema, Output>)
@@ -0,0 +1,254 @@
1
+ import { isAbsolute, resolve } from 'path'
2
+ import type { ToolResult, ToolUseContext } from '../../Tool.js'
3
+ import type { AssistantMessage } from '../../types/message.js'
4
+ import { getCwd } from '../../utils/cwd.js'
5
+ import { getFileModificationTime, writeTextContent } from '../../utils/file.js'
6
+ import { readFileSyncWithMetadata } from '../../utils/fileRead.js'
7
+ import { jsonParse, jsonStringify } from '../../utils/slowOperations.js'
8
+ import { documentDerivativeMutationValidationForResolvedTarget } from '../DocumentPrimitive/documentMutationGuard.js'
9
+ import { isNotebookDocument, type NotebookCellRecord } from './notebookModel.js'
10
+ import type { NotebookEditInput } from './validateInput.js'
11
+
12
+ export type NotebookEditOutput = {
13
+ new_source: string
14
+ cell_id?: string
15
+ cell_type: 'code' | 'markdown'
16
+ language: string
17
+ edit_mode: string
18
+ error?: string
19
+ notebook_path: string
20
+ original_file: string
21
+ updated_file: string
22
+ }
23
+
24
+ export async function callNotebookEditTool(
25
+ {
26
+ notebook_path,
27
+ new_source,
28
+ cell_id,
29
+ cell_type,
30
+ edit_mode: originalEditMode,
31
+ }: NotebookEditInput,
32
+ { readFileState, updateFileHistoryState }: ToolUseContext,
33
+ parentMessage: AssistantMessage,
34
+ ): Promise<ToolResult<NotebookEditOutput>> {
35
+ const fullPath = isAbsolute(notebook_path)
36
+ ? notebook_path
37
+ : resolve(getCwd(), notebook_path)
38
+ const documentValidation =
39
+ documentDerivativeMutationValidationForResolvedTarget(fullPath)
40
+ if (documentValidation !== null) throw new Error(documentValidation.message)
41
+
42
+ const { fileHistoryEnabled, fileHistoryTrackEdit } = await import(
43
+ '../../utils/fileHistory.js'
44
+ )
45
+ if (fileHistoryEnabled()) {
46
+ await fileHistoryTrackEdit(
47
+ updateFileHistoryState,
48
+ fullPath,
49
+ parentMessage.uuid,
50
+ )
51
+ }
52
+
53
+ try {
54
+ const { content, encoding, lineEndings } =
55
+ readFileSyncWithMetadata(fullPath)
56
+ const parsed: unknown = jsonParse(content)
57
+ if (!isNotebookDocument(parsed)) {
58
+ return invalidNotebookResult(new_source, cell_type, cell_id, fullPath)
59
+ }
60
+
61
+ const notebook = parsed
62
+ let cellIndex = resolveCellIndex(
63
+ notebook.cells,
64
+ cell_id,
65
+ originalEditMode,
66
+ )
67
+
68
+ let editMode = originalEditMode
69
+ if (editMode === 'replace' && cellIndex === notebook.cells.length) {
70
+ editMode = 'insert'
71
+ if (!cell_type) {
72
+ cell_type = 'code'
73
+ }
74
+ }
75
+
76
+ const language = notebook.metadata.language_info?.name ?? 'python'
77
+ const newCellId = resolveNewCellId(
78
+ notebook.nbformat,
79
+ notebook.nbformat_minor,
80
+ editMode,
81
+ cell_id,
82
+ )
83
+
84
+ if (editMode === 'delete') {
85
+ notebook.cells.splice(cellIndex, 1)
86
+ } else if (editMode === 'insert') {
87
+ notebook.cells.splice(
88
+ cellIndex,
89
+ 0,
90
+ createNotebookCell(cell_type, newCellId, new_source),
91
+ )
92
+ } else {
93
+ const targetCell = notebook.cells[cellIndex]
94
+ if (targetCell === undefined) {
95
+ throw new Error('Notebook cell index is out of bounds')
96
+ }
97
+ targetCell.source = new_source
98
+ if (targetCell.cell_type === 'code') {
99
+ targetCell.execution_count = null
100
+ targetCell.outputs = []
101
+ }
102
+ if (cell_type && cell_type !== targetCell.cell_type) {
103
+ targetCell.cell_type = cell_type
104
+ }
105
+ }
106
+
107
+ const updatedContent = jsonStringify(notebook, null, 1)
108
+ writeTextContent(fullPath, updatedContent, encoding, lineEndings)
109
+ readFileState.set(fullPath, {
110
+ content: updatedContent,
111
+ timestamp: getFileModificationTime(fullPath),
112
+ offset: undefined,
113
+ limit: undefined,
114
+ })
115
+
116
+ return {
117
+ data: {
118
+ new_source,
119
+ cell_type: cell_type ?? 'code',
120
+ language,
121
+ edit_mode: editMode ?? 'replace',
122
+ cell_id: newCellId,
123
+ error: '',
124
+ notebook_path: fullPath,
125
+ original_file: content,
126
+ updated_file: updatedContent,
127
+ },
128
+ }
129
+ } catch (error) {
130
+ if (error instanceof Error) {
131
+ return {
132
+ data: buildErrorOutput(
133
+ new_source,
134
+ cell_type,
135
+ cell_id,
136
+ fullPath,
137
+ error.message,
138
+ ),
139
+ }
140
+ }
141
+ return {
142
+ data: buildErrorOutput(
143
+ new_source,
144
+ cell_type,
145
+ cell_id,
146
+ fullPath,
147
+ 'Unknown error occurred while editing notebook',
148
+ ),
149
+ }
150
+ }
151
+ }
152
+
153
+ function resolveCellIndex(
154
+ cells: NotebookCellRecord[],
155
+ cellId: string | undefined,
156
+ originalEditMode: 'replace' | 'insert' | 'delete' | undefined,
157
+ ): number {
158
+ if (!cellId) {
159
+ return 0
160
+ }
161
+
162
+ let cellIndex = cells.findIndex(cell => cell.id === cellId)
163
+ if (cellIndex === -1) {
164
+ const parsedCellIndex = parseNotebookCellId(cellId)
165
+ if (parsedCellIndex !== undefined) {
166
+ cellIndex = parsedCellIndex
167
+ }
168
+ }
169
+
170
+ return originalEditMode === 'insert' ? cellIndex + 1 : cellIndex
171
+ }
172
+
173
+ function parseNotebookCellId(cellId: string): number | undefined {
174
+ const match = cellId.match(/^cell-(\d+)$/u)
175
+ const indexValue = match?.[1]
176
+ if (indexValue === undefined) return undefined
177
+ return Number.parseInt(indexValue, 10)
178
+ }
179
+
180
+ function resolveNewCellId(
181
+ nbformat: number,
182
+ nbformatMinor: number,
183
+ editMode: 'replace' | 'insert' | 'delete' | undefined,
184
+ cellId: string | undefined,
185
+ ): string | undefined {
186
+ if (nbformat <= 4 && (nbformat !== 4 || nbformatMinor < 5)) {
187
+ return undefined
188
+ }
189
+ if (editMode === 'insert') {
190
+ return Math.random().toString(36).substring(2, 15)
191
+ }
192
+ return cellId
193
+ }
194
+
195
+ function createNotebookCell(
196
+ cellType: 'code' | 'markdown' | undefined,
197
+ newCellId: string | undefined,
198
+ newSource: string,
199
+ ): NotebookCellRecord {
200
+ if (cellType === 'markdown') {
201
+ return {
202
+ cell_type: 'markdown',
203
+ id: newCellId,
204
+ source: newSource,
205
+ metadata: {},
206
+ }
207
+ }
208
+
209
+ return {
210
+ cell_type: 'code',
211
+ id: newCellId,
212
+ source: newSource,
213
+ metadata: {},
214
+ execution_count: null,
215
+ outputs: [],
216
+ }
217
+ }
218
+
219
+ function invalidNotebookResult(
220
+ newSource: string,
221
+ cellType: 'code' | 'markdown' | undefined,
222
+ cellId: string | undefined,
223
+ notebookPath: string,
224
+ ): ToolResult<NotebookEditOutput> {
225
+ return {
226
+ data: buildErrorOutput(
227
+ newSource,
228
+ cellType,
229
+ cellId,
230
+ notebookPath,
231
+ 'Notebook is not valid JSON.',
232
+ ),
233
+ }
234
+ }
235
+
236
+ function buildErrorOutput(
237
+ newSource: string,
238
+ cellType: 'code' | 'markdown' | undefined,
239
+ cellId: string | undefined,
240
+ notebookPath: string,
241
+ error: string,
242
+ ): NotebookEditOutput {
243
+ return {
244
+ new_source: newSource,
245
+ cell_type: cellType ?? 'code',
246
+ language: 'python',
247
+ edit_mode: 'replace',
248
+ error,
249
+ cell_id: cellId,
250
+ notebook_path: notebookPath,
251
+ original_file: '',
252
+ updated_file: '',
253
+ }
254
+ }
@@ -0,0 +1,51 @@
1
+ export type NotebookCellRecord = {
2
+ cell_type: 'code' | 'markdown'
3
+ id?: string
4
+ source: string | string[]
5
+ metadata: Record<string, unknown>
6
+ execution_count?: number | null
7
+ outputs?: unknown[]
8
+ }
9
+
10
+ export type NotebookDocument = {
11
+ cells: NotebookCellRecord[]
12
+ metadata: {
13
+ language_info?: {
14
+ name?: string
15
+ }
16
+ }
17
+ nbformat: number
18
+ nbformat_minor: number
19
+ }
20
+
21
+ export function isNotebookDocument(value: unknown): value is NotebookDocument {
22
+ if (!isRecord(value)) return false
23
+
24
+ const cells = value.cells
25
+ const metadata = value.metadata
26
+ return (
27
+ Array.isArray(cells) &&
28
+ cells.every(isNotebookCellRecord) &&
29
+ isRecord(metadata) &&
30
+ typeof value.nbformat === 'number' &&
31
+ typeof value.nbformat_minor === 'number'
32
+ )
33
+ }
34
+
35
+ function isNotebookCellRecord(value: unknown): value is NotebookCellRecord {
36
+ if (!isRecord(value)) return false
37
+
38
+ const cellType = value.cell_type
39
+ const source = value.source
40
+ return (
41
+ (cellType === 'code' || cellType === 'markdown') &&
42
+ (typeof source === 'string' ||
43
+ (Array.isArray(source) &&
44
+ source.every(item => typeof item === 'string'))) &&
45
+ isRecord(value.metadata)
46
+ )
47
+ }
48
+
49
+ function isRecord(value: unknown): value is Record<string, unknown> {
50
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
51
+ }