@iaforged/context-code 2.1.7 → 2.2.4

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 (411) hide show
  1. package/dist/src/Task.js +1 -1
  2. package/dist/src/commands/login/login.js +1 -1
  3. package/dist/src/components/ConsoleOAuthFlow.js +1 -1
  4. package/dist/src/constants/oauth.js +1 -1
  5. package/dist/src/context/mailbox.js +1 -1
  6. package/dist/src/context/voice.js +1 -1
  7. package/dist/src/hooks/useTerminalSize.js +1 -1
  8. package/dist/src/ink/Ansi.js +1 -1
  9. package/dist/src/ink/clearTerminal.js +1 -1
  10. package/dist/src/ink/colorize.js +1 -1
  11. package/dist/src/ink/components/App.js +1 -1
  12. package/dist/src/ink/components/Button.js +1 -1
  13. package/dist/src/ink/components/ClockContext.js +1 -1
  14. package/dist/src/ink/components/CursorDeclarationContext.js +1 -1
  15. package/dist/src/ink/components/Link.js +1 -1
  16. package/dist/src/ink/components/StdinContext.js +1 -1
  17. package/dist/src/ink/components/TerminalFocusContext.js +1 -1
  18. package/dist/src/ink/dom.js +1 -1
  19. package/dist/src/ink/events/keyboard-event.js +1 -1
  20. package/dist/src/ink/hit-test.js +1 -1
  21. package/dist/src/ink/hooks/use-animation-frame.js +1 -1
  22. package/dist/src/ink/hooks/use-app.js +1 -1
  23. package/dist/src/ink/hooks/use-input.js +1 -1
  24. package/dist/src/ink/hooks/use-interval.js +1 -1
  25. package/dist/src/ink/hooks/use-selection.js +1 -1
  26. package/dist/src/ink/hooks/use-tab-status.js +1 -1
  27. package/dist/src/ink/hooks/use-terminal-focus.js +1 -1
  28. package/dist/src/ink/hooks/use-terminal-title.js +1 -1
  29. package/dist/src/ink/hooks/use-terminal-viewport.js +1 -1
  30. package/dist/src/ink/ink.js +1 -1
  31. package/dist/src/ink/layout/yoga.js +1 -1
  32. package/dist/src/ink/line-width-cache.js +1 -1
  33. package/dist/src/ink/log-update.js +1 -1
  34. package/dist/src/ink/measure-text.js +1 -1
  35. package/dist/src/ink/output.js +1 -1
  36. package/dist/src/ink/parse-keypress.js +1 -1
  37. package/dist/src/ink/reconciler.js +1 -1
  38. package/dist/src/ink/render-border.js +1 -1
  39. package/dist/src/ink/render-node-to-output.js +1 -1
  40. package/dist/src/ink/render-to-screen.js +1 -1
  41. package/dist/src/ink/renderer.js +1 -1
  42. package/dist/src/ink/root.js +1 -1
  43. package/dist/src/ink/screen.js +1 -1
  44. package/dist/src/ink/searchHighlight.js +1 -1
  45. package/dist/src/ink/selection.js +1 -1
  46. package/dist/src/ink/squash-text-nodes.js +1 -1
  47. package/dist/src/ink/stringWidth.js +1 -1
  48. package/dist/src/ink/tabstops.js +1 -1
  49. package/dist/src/ink/terminal.js +1 -1
  50. package/dist/src/ink/termio/osc.js +1 -1
  51. package/dist/src/ink/termio/parser.js +1 -1
  52. package/dist/src/ink/termio/tokenize.js +1 -1
  53. package/dist/src/ink/useTerminalNotification.js +1 -1
  54. package/dist/src/ink/warn.js +1 -1
  55. package/dist/src/ink/widest-line.js +1 -1
  56. package/dist/src/ink/wrap-text.js +1 -1
  57. package/dist/src/ink/wrapAnsi.js +1 -1
  58. package/dist/src/native-ts/yoga-layout/index.js +1 -1
  59. package/dist/src/schemas/hooks.js +1 -1
  60. package/dist/src/services/SessionMemory/sessionMemoryUtils.js +1 -1
  61. package/dist/src/services/api/client.js +1 -1
  62. package/dist/src/services/api/dumpPrompts.js +1 -1
  63. package/dist/src/services/api/errorUtils.js +1 -1
  64. package/dist/src/services/api/promptCacheBreakDetection.js +1 -1
  65. package/dist/src/services/api/withRetry.js +1 -1
  66. package/dist/src/services/autoDream/consolidationLock.js +1 -1
  67. package/dist/src/services/mcp/elicitationHandler.js +1 -1
  68. package/dist/src/services/mcp/mcpStringUtils.js +1 -1
  69. package/dist/src/services/mcp/oauthPort.js +1 -1
  70. package/dist/src/services/mcp/vscodeSdkMcp.js +1 -1
  71. package/dist/src/services/oauth/client.js +1 -1
  72. package/dist/src/services/oauth/getOauthProfile.js +1 -1
  73. package/dist/src/services/objetivo/types.js +1 -1
  74. package/dist/src/services/rateLimitMocking.js +1 -1
  75. package/dist/src/services/remoteManagedSettings/syncCacheState.js +1 -1
  76. package/dist/src/skills/bundledSkills.js +1 -1
  77. package/dist/src/tasks/DreamTask/DreamTask.js +1 -1
  78. package/dist/src/tools/AgentTool/agentMemory.js +1 -1
  79. package/dist/src/tools/AgentTool/forkSubagent.js +1 -1
  80. package/dist/src/tools/BashTool/BashToolResultMessage.js +1 -1
  81. package/dist/src/tools/BashTool/UI.js +1 -1
  82. package/dist/src/tools/BashTool/sedEditParser.js +1 -1
  83. package/dist/src/tools/BashTool/utils.js +1 -1
  84. package/dist/src/tools/FileReadTool/imageProcessor.js +1 -1
  85. package/dist/src/tools/FileReadTool/prompt.js +1 -1
  86. package/dist/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.js +1 -1
  87. package/dist/src/tools/ListMcpResourcesTool/UI.js +1 -1
  88. package/dist/src/tools/MCPTool/MCPTool.js +1 -1
  89. package/dist/src/tools/MCPTool/UI.js +1 -1
  90. package/dist/src/tools/McpAuthTool/McpAuthTool.js +1 -1
  91. package/dist/src/tools/NotebookEditTool/prompt.js +1 -1
  92. package/dist/src/tools/PowerShellTool/PowerShellTool.js +1 -1
  93. package/dist/src/tools/PowerShellTool/UI.js +1 -1
  94. package/dist/src/tools/PowerShellTool/gitSafety.js +1 -1
  95. package/dist/src/tools/PowerShellTool/modeValidation.js +1 -1
  96. package/dist/src/tools/PowerShellTool/pathValidation.js +1 -1
  97. package/dist/src/tools/PowerShellTool/powershellPermissions.js +1 -1
  98. package/dist/src/tools/PowerShellTool/powershellSecurity.js +1 -1
  99. package/dist/src/tools/PowerShellTool/prompt.js +1 -1
  100. package/dist/src/tools/PowerShellTool/readOnlyValidation.js +1 -1
  101. package/dist/src/tools/REPLTool/constants.js +1 -1
  102. package/dist/src/tools/REPLTool/primitiveTools.js +1 -1
  103. package/dist/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.js +1 -1
  104. package/dist/src/tools/ReadMcpResourceTool/UI.js +1 -1
  105. package/dist/src/tools/ScheduleCronTool/prompt.js +1 -1
  106. package/dist/src/tools/SkillTool/prompt.js +1 -1
  107. package/dist/src/tools/TodoWriteTool/TodoWriteTool.js +1 -1
  108. package/dist/src/tools/ToolSearchTool/prompt.js +1 -1
  109. package/dist/src/tools/WebSearchTool/prompt.js +1 -1
  110. package/dist/src/tools/shared/gitOperationTracking.js +1 -1
  111. package/dist/src/types/permissions.js +1 -1
  112. package/dist/src/utils/Cursor.js +1 -1
  113. package/dist/src/utils/QueryGuard.js +1 -1
  114. package/dist/src/utils/Shell.js +1 -1
  115. package/dist/src/utils/ShellCommand.js +1 -1
  116. package/dist/src/utils/activityManager.js +1 -1
  117. package/dist/src/utils/advisor.js +1 -1
  118. package/dist/src/utils/appleTerminalBackup.js +1 -1
  119. package/dist/src/utils/argumentSubstitution.js +1 -1
  120. package/dist/src/utils/authFileDescriptor.js +1 -1
  121. package/dist/src/utils/autoUpdater.js +1 -1
  122. package/dist/src/utils/background/remote/preconditions.js +1 -1
  123. package/dist/src/utils/background/remote/remoteSession.js +1 -1
  124. package/dist/src/utils/bash/ShellSnapshot.js +1 -1
  125. package/dist/src/utils/bash/ast.js +1 -1
  126. package/dist/src/utils/bash/bashParser.js +1 -1
  127. package/dist/src/utils/bash/bashPipeCommand.js +1 -1
  128. package/dist/src/utils/bash/parser.js +1 -1
  129. package/dist/src/utils/bash/shellQuote.js +1 -1
  130. package/dist/src/utils/bash/shellQuoting.js +1 -1
  131. package/dist/src/utils/billing.js +1 -1
  132. package/dist/src/utils/caCerts.js +1 -1
  133. package/dist/src/utils/claudeInChrome/common.js +1 -1
  134. package/dist/src/utils/claudeInChrome/setupPortable.js +1 -1
  135. package/dist/src/utils/claudemd.js +1 -1
  136. package/dist/src/utils/collapseBackgroundBashNotifications.js +1 -1
  137. package/dist/src/utils/collapseReadSearch.js +1 -1
  138. package/dist/src/utils/completionCache.js +1 -1
  139. package/dist/src/utils/computerUse/common.js +1 -1
  140. package/dist/src/utils/concurrentSessions.js +1 -1
  141. package/dist/src/utils/context.js +1 -1
  142. package/dist/src/utils/cron.js +1 -1
  143. package/dist/src/utils/cronTasks.js +1 -1
  144. package/dist/src/utils/cwd.js +1 -1
  145. package/dist/src/utils/debug.js +1 -1
  146. package/dist/src/utils/debugFilter.js +1 -1
  147. package/dist/src/utils/detectRepository.js +1 -1
  148. package/dist/src/utils/diagLogs.js +1 -1
  149. package/dist/src/utils/diff.js +1 -1
  150. package/dist/src/utils/directMemberMessage.js +1 -1
  151. package/dist/src/utils/doctorDiagnostic.js +1 -1
  152. package/dist/src/utils/dxt/helpers.js +1 -1
  153. package/dist/src/utils/dxt/zip.js +1 -1
  154. package/dist/src/utils/earlyInput.js +1 -1
  155. package/dist/src/utils/editor.js +1 -1
  156. package/dist/src/utils/effort.js +1 -1
  157. package/dist/src/utils/embeddedTools.js +1 -1
  158. package/dist/src/utils/envDynamic.js +1 -1
  159. package/dist/src/utils/envUtils.js +1 -1
  160. package/dist/src/utils/execFileNoThrowPortable.js +1 -1
  161. package/dist/src/utils/execSyncWrapper.js +1 -1
  162. package/dist/src/utils/exportRenderer.js +1 -1
  163. package/dist/src/utils/extraUsage.js +1 -1
  164. package/dist/src/utils/fastMode.js +1 -1
  165. package/dist/src/utils/fileOperationAnalytics.js +1 -1
  166. package/dist/src/utils/fileRead.js +1 -1
  167. package/dist/src/utils/findExecutable.js +1 -1
  168. package/dist/src/utils/format.js +1 -1
  169. package/dist/src/utils/frontmatterParser.js +1 -1
  170. package/dist/src/utils/fsOperations.js +1 -1
  171. package/dist/src/utils/fullscreen.js +1 -1
  172. package/dist/src/utils/genericProcessUtils.js +1 -1
  173. package/dist/src/utils/getWorktreePaths.js +1 -1
  174. package/dist/src/utils/git/gitConfigParser.js +1 -1
  175. package/dist/src/utils/git/gitFilesystem.js +1 -1
  176. package/dist/src/utils/git/gitignore.js +1 -1
  177. package/dist/src/utils/gitDiff.js +1 -1
  178. package/dist/src/utils/gitSettings.js +1 -1
  179. package/dist/src/utils/glob.js +1 -1
  180. package/dist/src/utils/gracefulShutdown.js +1 -1
  181. package/dist/src/utils/groupToolUses.js +1 -1
  182. package/dist/src/utils/handlePromptSubmit.js +1 -1
  183. package/dist/src/utils/hash.js +1 -1
  184. package/dist/src/utils/hooks/fileChangedWatcher.js +1 -1
  185. package/dist/src/utils/hooks/hooksSettings.js +1 -1
  186. package/dist/src/utils/hooks/registerSkillHooks.js +1 -1
  187. package/dist/src/utils/hooks/sessionHooks.js +1 -1
  188. package/dist/src/utils/http.js +1 -1
  189. package/dist/src/utils/hyperlink.js +1 -1
  190. package/dist/src/utils/ide.js +1 -1
  191. package/dist/src/utils/idePathConversion.js +1 -1
  192. package/dist/src/utils/imagePaste.js +1 -1
  193. package/dist/src/utils/imageResizer.js +1 -1
  194. package/dist/src/utils/imageStore.js +1 -1
  195. package/dist/src/utils/inProcessTeammateHelpers.js +1 -1
  196. package/dist/src/utils/ink.js +1 -1
  197. package/dist/src/utils/jetbrains.js +1 -1
  198. package/dist/src/utils/json.js +1 -1
  199. package/dist/src/utils/listSessionsImpl.js +1 -1
  200. package/dist/src/utils/localInstaller.js +1 -1
  201. package/dist/src/utils/lockfile.js +1 -1
  202. package/dist/src/utils/logoV2Utils.js +1 -1
  203. package/dist/src/utils/markdown.js +1 -1
  204. package/dist/src/utils/mcp/dateTimeParser.js +1 -1
  205. package/dist/src/utils/mcpOutputStorage.js +1 -1
  206. package/dist/src/utils/mcpValidation.js +1 -1
  207. package/dist/src/utils/memoize.js +1 -1
  208. package/dist/src/utils/memory/types.js +1 -1
  209. package/dist/src/utils/memoryFileDetection.js +1 -1
  210. package/dist/src/utils/messageQueueManager.js +1 -1
  211. package/dist/src/utils/messages/mappers.js +1 -1
  212. package/dist/src/utils/messages/systemInit.js +1 -1
  213. package/dist/src/utils/model/antModels.js +1 -1
  214. package/dist/src/utils/model/check1mAccess.js +1 -1
  215. package/dist/src/utils/model/contextWindowUpgradeCheck.js +1 -1
  216. package/dist/src/utils/model/model.js +1 -1
  217. package/dist/src/utils/model/modelAllowlist.js +1 -1
  218. package/dist/src/utils/model/modelCapabilities.js +1 -1
  219. package/dist/src/utils/model/modelOptions.js +1 -1
  220. package/dist/src/utils/model/modelStrings.js +1 -1
  221. package/dist/src/utils/model/providerBaseUrls.js +1 -1
  222. package/dist/src/utils/model/providerCatalog.js +1 -1
  223. package/dist/src/utils/model/providerModels.js +1 -1
  224. package/dist/src/utils/model/providerProfiles.js +1 -1
  225. package/dist/src/utils/model/providerProfilesDb.js +1 -1
  226. package/dist/src/utils/model/providerSwitch.js +1 -1
  227. package/dist/src/utils/model/providers.js +1 -1
  228. package/dist/src/utils/modelCost.js +1 -1
  229. package/dist/src/utils/modifiers.js +1 -1
  230. package/dist/src/utils/mtls.js +1 -1
  231. package/dist/src/utils/nativeInstaller/download.js +1 -1
  232. package/dist/src/utils/nativeInstaller/installer.js +1 -1
  233. package/dist/src/utils/nativeInstaller/packageManagers.js +1 -1
  234. package/dist/src/utils/nativeInstaller/pidLock.js +1 -1
  235. package/dist/src/utils/notebook.js +1 -1
  236. package/dist/src/utils/pasteStore.js +1 -1
  237. package/dist/src/utils/path.js +1 -1
  238. package/dist/src/utils/permissions/PermissionMode.js +1 -1
  239. package/dist/src/utils/permissions/PermissionPromptToolResultSchema.js +1 -1
  240. package/dist/src/utils/permissions/PermissionUpdate.js +1 -1
  241. package/dist/src/utils/permissions/PermissionUpdateSchema.js +1 -1
  242. package/dist/src/utils/permissions/autoModeState.js +1 -1
  243. package/dist/src/utils/permissions/bypassPermissionsKillswitch.js +1 -1
  244. package/dist/src/utils/permissions/filesystem.js +1 -1
  245. package/dist/src/utils/permissions/getNextPermissionMode.js +1 -1
  246. package/dist/src/utils/permissions/pathValidation.js +1 -1
  247. package/dist/src/utils/permissions/permissionRuleParser.js +1 -1
  248. package/dist/src/utils/permissions/permissionsDb.js +1 -1
  249. package/dist/src/utils/permissions/permissionsLoader.js +1 -1
  250. package/dist/src/utils/permissions/shellRuleMatching.js +1 -1
  251. package/dist/src/utils/planModeV2.js +1 -1
  252. package/dist/src/utils/plans.js +1 -1
  253. package/dist/src/utils/platform.js +1 -1
  254. package/dist/src/utils/plugins/addDirPluginSettings.js +1 -1
  255. package/dist/src/utils/plugins/cacheUtils.js +1 -1
  256. package/dist/src/utils/plugins/dependencyResolver.js +1 -1
  257. package/dist/src/utils/plugins/fetchTelemetry.js +1 -1
  258. package/dist/src/utils/plugins/gitAvailability.js +1 -1
  259. package/dist/src/utils/plugins/hintRecommendation.js +1 -1
  260. package/dist/src/utils/plugins/installedPluginsManager.js +1 -1
  261. package/dist/src/utils/plugins/loadPluginAgents.js +1 -1
  262. package/dist/src/utils/plugins/loadPluginCommands.js +1 -1
  263. package/dist/src/utils/plugins/loadPluginHooks.js +1 -1
  264. package/dist/src/utils/plugins/loadPluginOutputStyles.js +1 -1
  265. package/dist/src/utils/plugins/lspPluginIntegration.js +1 -1
  266. package/dist/src/utils/plugins/lspRecommendation.js +1 -1
  267. package/dist/src/utils/plugins/managedPlugins.js +1 -1
  268. package/dist/src/utils/plugins/marketplaceHelpers.js +1 -1
  269. package/dist/src/utils/plugins/marketplaceManager.js +1 -1
  270. package/dist/src/utils/plugins/mcpPluginIntegration.js +1 -1
  271. package/dist/src/utils/plugins/mcpbHandler.js +1 -1
  272. package/dist/src/utils/plugins/officialMarketplaceGcs.js +1 -1
  273. package/dist/src/utils/plugins/officialMarketplaceStartupCheck.js +1 -1
  274. package/dist/src/utils/plugins/orphanedPluginFilter.js +1 -1
  275. package/dist/src/utils/plugins/performStartupChecks.js +1 -1
  276. package/dist/src/utils/plugins/pluginAutoupdate.js +1 -1
  277. package/dist/src/utils/plugins/pluginBlocklist.js +1 -1
  278. package/dist/src/utils/plugins/pluginDirectories.js +1 -1
  279. package/dist/src/utils/plugins/pluginFlagging.js +1 -1
  280. package/dist/src/utils/plugins/pluginInstallationHelpers.js +1 -1
  281. package/dist/src/utils/plugins/pluginLoader.js +1 -1
  282. package/dist/src/utils/plugins/pluginOptionsStorage.js +1 -1
  283. package/dist/src/utils/plugins/pluginPolicy.js +1 -1
  284. package/dist/src/utils/plugins/pluginStartupCheck.js +1 -1
  285. package/dist/src/utils/plugins/pluginVersioning.js +1 -1
  286. package/dist/src/utils/plugins/reconciler.js +1 -1
  287. package/dist/src/utils/plugins/refresh.js +1 -1
  288. package/dist/src/utils/plugins/schemas.js +1 -1
  289. package/dist/src/utils/plugins/walkPluginMarkdown.js +1 -1
  290. package/dist/src/utils/plugins/zipCache.js +1 -1
  291. package/dist/src/utils/powershell/parser.js +1 -1
  292. package/dist/src/utils/processUserInput/processBashCommand.js +1 -1
  293. package/dist/src/utils/processUserInput/processSlashCommand.js +1 -1
  294. package/dist/src/utils/processUserInput/processTextPrompt.js +1 -1
  295. package/dist/src/utils/processUserInput/processUserInput.js +1 -1
  296. package/dist/src/utils/profilerBase.js +1 -1
  297. package/dist/src/utils/promptCategory.js +1 -1
  298. package/dist/src/utils/promptEditor.js +1 -1
  299. package/dist/src/utils/promptShellExecution.js +1 -1
  300. package/dist/src/utils/proxy.js +1 -1
  301. package/dist/src/utils/queryHelpers.js +1 -1
  302. package/dist/src/utils/queryProfiler.js +1 -1
  303. package/dist/src/utils/queueProcessor.js +1 -1
  304. package/dist/src/utils/readFileInRange.js +1 -1
  305. package/dist/src/utils/releaseNotes.js +1 -1
  306. package/dist/src/utils/renderOptions.js +1 -1
  307. package/dist/src/utils/ripgrep.js +1 -1
  308. package/dist/src/utils/sandbox/sandbox-adapter.js +1 -1
  309. package/dist/src/utils/sdkEventQueue.js +1 -1
  310. package/dist/src/utils/secureStorage/index.js +1 -1
  311. package/dist/src/utils/secureStorage/macOsKeychainHelpers.js +1 -1
  312. package/dist/src/utils/secureStorage/macOsKeychainStorage.js +1 -1
  313. package/dist/src/utils/secureStorage/plainTextStorage.js +1 -1
  314. package/dist/src/utils/secureStorage/sqliteStorage.js +1 -1
  315. package/dist/src/utils/sessionEnvironment.js +1 -1
  316. package/dist/src/utils/sessionIngressAuth.js +1 -1
  317. package/dist/src/utils/sessionRestore.js +1 -1
  318. package/dist/src/utils/sessionStart.js +1 -1
  319. package/dist/src/utils/sessionTitle.js +1 -1
  320. package/dist/src/utils/settings/managedPath.js +1 -1
  321. package/dist/src/utils/settings/mdm/rawRead.js +1 -1
  322. package/dist/src/utils/settings/mdm/settings.js +1 -1
  323. package/dist/src/utils/settings/permissionValidation.js +1 -1
  324. package/dist/src/utils/settings/pluginOnlyPolicy.js +1 -1
  325. package/dist/src/utils/settings/schemaOutput.js +1 -1
  326. package/dist/src/utils/settings/settings.js +1 -1
  327. package/dist/src/utils/settings/types.js +1 -1
  328. package/dist/src/utils/settings/validateEditTool.js +1 -1
  329. package/dist/src/utils/settings/validation.js +1 -1
  330. package/dist/src/utils/shell/bashProvider.js +1 -1
  331. package/dist/src/utils/shell/powershellDetection.js +1 -1
  332. package/dist/src/utils/shell/powershellProvider.js +1 -1
  333. package/dist/src/utils/shell/readOnlyCommandValidation.js +1 -1
  334. package/dist/src/utils/shell/resolveDefaultShell.js +1 -1
  335. package/dist/src/utils/shell/shellToolUtils.js +1 -1
  336. package/dist/src/utils/shell/specPrefix.js +1 -1
  337. package/dist/src/utils/shellConfig.js +1 -1
  338. package/dist/src/utils/sideQuestion.js +1 -1
  339. package/dist/src/utils/skills/skillChangeDetector.js +1 -1
  340. package/dist/src/utils/slashCommandParsing.js +1 -1
  341. package/dist/src/utils/sliceAnsi.js +1 -1
  342. package/dist/src/utils/slowOperations.js +1 -1
  343. package/dist/src/utils/standaloneAgent.js +1 -1
  344. package/dist/src/utils/startupProfiler.js +1 -1
  345. package/dist/src/utils/staticRender.js +1 -1
  346. package/dist/src/utils/status.js +1 -1
  347. package/dist/src/utils/statusNoticeDefinitions.js +1 -1
  348. package/dist/src/utils/suggestions/commandSuggestions.js +1 -1
  349. package/dist/src/utils/suggestions/directoryCompletion.js +1 -1
  350. package/dist/src/utils/suggestions/shellHistoryCompletion.js +1 -1
  351. package/dist/src/utils/suggestions/skillUsageTracking.js +1 -1
  352. package/dist/src/utils/suggestions/slackChannelSuggestions.js +1 -1
  353. package/dist/src/utils/swarm/backends/detection.js +1 -1
  354. package/dist/src/utils/swarm/permissionSync.js +1 -1
  355. package/dist/src/utils/swarm/reconnection.js +1 -1
  356. package/dist/src/utils/swarm/spawnUtils.js +1 -91
  357. package/dist/src/utils/swarm/teammateInit.js +1 -1
  358. package/dist/src/utils/systemDirectories.js +1 -1
  359. package/dist/src/utils/systemPrompt.js +1 -1
  360. package/dist/src/utils/systemTheme.js +1 -1
  361. package/dist/src/utils/task/TaskOutput.js +1 -1
  362. package/dist/src/utils/task/diskOutput.js +1 -1
  363. package/dist/src/utils/tasks.js +1 -1
  364. package/dist/src/utils/teamDiscovery.js +1 -1
  365. package/dist/src/utils/teamMemoryOps.js +1 -1
  366. package/dist/src/utils/teammateMailbox.js +1 -1
  367. package/dist/src/utils/telemetry/betaSessionTracing.js +1 -1
  368. package/dist/src/utils/telemetry/bigqueryExporter.js +1 -1
  369. package/dist/src/utils/telemetry/events.js +1 -1
  370. package/dist/src/utils/telemetry/instrumentation.js +1 -1
  371. package/dist/src/utils/telemetry/logger.js +1 -1
  372. package/dist/src/utils/telemetry/perfettoTracing.js +1 -1
  373. package/dist/src/utils/telemetry/pluginTelemetry.js +1 -1
  374. package/dist/src/utils/telemetry/sessionTracing.js +1 -1
  375. package/dist/src/utils/telemetryAttributes.js +1 -1
  376. package/dist/src/utils/teleport/api.js +1 -1
  377. package/dist/src/utils/teleport/environments.js +1 -1
  378. package/dist/src/utils/teleport/gitBundle.js +1 -1
  379. package/dist/src/utils/teleport.js +1 -1
  380. package/dist/src/utils/tempfile.js +1 -1
  381. package/dist/src/utils/terminal.js +1 -1
  382. package/dist/src/utils/terminalPanel.js +1 -1
  383. package/dist/src/utils/textHighlighting.js +1 -1
  384. package/dist/src/utils/theme.js +1 -1
  385. package/dist/src/utils/themes/bootstrap.js +1 -1
  386. package/dist/src/utils/themes/loader.js +1 -1
  387. package/dist/src/utils/thinking.js +1 -1
  388. package/dist/src/utils/tmuxSocket.js +1 -1
  389. package/dist/src/utils/tokens.js +1 -1
  390. package/dist/src/utils/toolPool.js +1 -1
  391. package/dist/src/utils/toolResultStorage.js +1 -1
  392. package/dist/src/utils/transcriptSearch.js +1 -1
  393. package/dist/src/utils/truncate.js +1 -1
  394. package/dist/src/utils/ultraplan/keyword.js +1 -1
  395. package/dist/src/utils/unaryLogging.js +1 -1
  396. package/dist/src/utils/undercover.js +1 -1
  397. package/dist/src/utils/user.js +1 -1
  398. package/dist/src/utils/userPromptKeywords.js +1 -1
  399. package/dist/src/utils/which.js +1 -1
  400. package/dist/src/utils/windowsPaths.js +1 -1
  401. package/dist/src/utils/worktree.js +1 -1
  402. package/dist/src/utils/zodToJsonSchema.js +1 -1
  403. package/dist/src/vim/operators.js +1 -1
  404. package/dist/src/vim/textObjects.js +1 -1
  405. package/dist/src/vim/transitions.js +1 -1
  406. package/dist/src/voice/voiceModeEnabled.js +1 -1
  407. package/dist/src/webapp/auth.js +1 -1
  408. package/dist/src/webapp/tunnel.js +1 -1
  409. package/dist/src/whatsapp/bridge.js +1 -1
  410. package/dist/src/whatsapp/mirror.js +1 -1
  411. package/package.json +41 -3
@@ -1 +1 @@
1
- import{homedir as e}from"os";import{isAbsolute as a,resolve as t}from"path";import{getCwd as n}from"../../utils/cwd.js";import{getFsImplementation as r,safeResolvePath as o}from"../../utils/fsOperations.js";import{containsPathTraversal as s,getDirectoryForPath as i}from"../../utils/path.js";import{allWorkingDirectories as l,checkEditableInternalPath as p,checkPathSafetyForAutoEdit as c,checkReadableInternalPath as h,matchingRuleForInput as d,pathInAllowedWorkingPath as u}from"../../utils/permissions/filesystem.js";import{createReadRuleSuggestion as m}from"../../utils/permissions/PermissionUpdate.js";import{isDangerousRemovalPath as f,isPathInSandboxWriteAllowlist as w}from"../../utils/permissions/pathValidation.js";import{getPlatform as y}from"../../utils/platform.js";import{isNullRedirectionTarget as P,isPowerShellParameter as k}from"../../utils/powershell/parser.js";import{COMMON_SWITCHES as v,COMMON_VALUE_PARAMS as g}from"./commonParameters.js";import{resolveToCanonical as b}from"./readOnlyValidation.js";const x=/[*?[\]]/,R={"set-content":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-force","-whatif","-confirm","-usetransaction","-nonewline","-asbytestream"],knownValueParams:["-value","-filter","-include","-exclude","-credential","-encoding","-stream"]},"add-content":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-force","-whatif","-confirm","-usetransaction","-nonewline","-asbytestream"],knownValueParams:["-value","-filter","-include","-exclude","-credential","-encoding","-stream"]},"remove-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-recurse","-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential","-stream"]},"clear-content":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential","-stream"]},"out-file":{operationType:"write",pathParams:["-filepath","-path","-literalpath","-pspath","-lp"],knownSwitches:["-append","-force","-noclobber","-nonewline","-whatif","-confirm"],knownValueParams:["-inputobject","-encoding","-width"]},"tee-object":{operationType:"write",pathParams:["-filepath","-path","-literalpath","-pspath","-lp"],knownSwitches:["-append"],knownValueParams:["-inputobject","-variable","-encoding"]},"export-csv":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-append","-force","-noclobber","-notypeinformation","-includetypeinformation","-useculture","-noheader","-whatif","-confirm"],knownValueParams:["-inputobject","-delimiter","-encoding","-quotefields","-usequotes"]},"export-clixml":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-noclobber","-whatif","-confirm"],knownValueParams:["-inputobject","-depth","-encoding"]},"new-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],leafOnlyPathParams:["-name"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-itemtype","-value","-credential","-type"]},"copy-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp","-destination"],knownSwitches:["-container","-force","-passthru","-recurse","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential","-fromsession","-tosession"]},"move-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp","-destination"],knownSwitches:["-force","-passthru","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential"]},"rename-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-passthru","-whatif","-confirm","-usetransaction"],knownValueParams:["-newname","-credential","-filter","-include","-exclude"]},"set-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-passthru","-whatif","-confirm","-usetransaction"],knownValueParams:["-value","-credential","-filter","-include","-exclude"]},"get-content":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-usetransaction","-wait","-raw","-asbytestream"],knownValueParams:["-readcount","-totalcount","-tail","-first","-head","-last","-filter","-include","-exclude","-credential","-delimiter","-encoding","-stream"]},"get-childitem":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-recurse","-force","-name","-usetransaction","-followsymlink","-directory","-file","-hidden","-readonly","-system"],knownValueParams:["-filter","-include","-exclude","-depth","-attributes","-credential"]},"get-item":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential","-stream"]},"get-itemproperty":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-usetransaction"],knownValueParams:["-name","-filter","-include","-exclude","-credential"]},"get-itempropertyvalue":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-usetransaction"],knownValueParams:["-name","-filter","-include","-exclude","-credential"]},"get-filehash":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:[],knownValueParams:["-algorithm","-inputstream"]},"get-acl":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-audit","-allcentralaccesspolicies","-usetransaction"],knownValueParams:["-inputobject","-filter","-include","-exclude"]},"format-hex":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-raw"],knownValueParams:["-inputobject","-encoding","-count","-offset"]},"test-path":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-isvalid","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-pathtype","-credential","-olderthan","-newerthan"]},"resolve-path":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-relative","-usetransaction","-force"],knownValueParams:["-credential","-relativebasepath"]},"convert-path":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-usetransaction"],knownValueParams:[]},"select-string":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-simplematch","-casesensitive","-quiet","-list","-notmatch","-allmatches","-noemphasis","-raw"],knownValueParams:["-inputobject","-pattern","-include","-exclude","-encoding","-context","-culture"]},"set-location":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-usetransaction"],knownValueParams:["-stackname"]},"push-location":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-usetransaction"],knownValueParams:["-stackname"]},"pop-location":{operationType:"read",pathParams:[],knownSwitches:["-passthru","-usetransaction"],knownValueParams:["-stackname"]},"select-xml":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:[],knownValueParams:["-xml","-content","-xpath","-namespace"]},"get-winevent":{operationType:"read",pathParams:["-path"],knownSwitches:["-force","-oldest"],knownValueParams:["-listlog","-logname","-listprovider","-providername","-maxevents","-computername","-credential","-filterxpath","-filterxml","-filterhashtable"]},"invoke-webrequest":{operationType:"write",pathParams:["-outfile","-infile"],positionalSkip:1,optionalWrite:!0,knownSwitches:["-allowinsecureredirect","-allowunencryptedauthentication","-disablekeepalive","-nobodyprogress","-passthru","-preservefileauthorizationmetadata","-resume","-skipcertificatecheck","-skipheadervalidation","-skiphttperrorcheck","-usebasicparsing","-usedefaultcredentials"],knownValueParams:["-uri","-method","-body","-contenttype","-headers","-maximumredirection","-maximumretrycount","-proxy","-proxycredential","-retryintervalsec","-sessionvariable","-timeoutsec","-token","-transferencoding","-useragent","-websession","-credential","-authentication","-certificate","-certificatethumbprint","-form","-httpversion"]},"invoke-restmethod":{operationType:"write",pathParams:["-outfile","-infile"],positionalSkip:1,optionalWrite:!0,knownSwitches:["-allowinsecureredirect","-allowunencryptedauthentication","-disablekeepalive","-followrellink","-nobodyprogress","-passthru","-preservefileauthorizationmetadata","-resume","-skipcertificatecheck","-skipheadervalidation","-skiphttperrorcheck","-usebasicparsing","-usedefaultcredentials"],knownValueParams:["-uri","-method","-body","-contenttype","-headers","-maximumfollowrellink","-maximumredirection","-maximumretrycount","-proxy","-proxycredential","-responseheaderstvariable","-retryintervalsec","-sessionvariable","-statuscodevariable","-timeoutsec","-token","-transferencoding","-useragent","-websession","-credential","-authentication","-certificate","-certificatethumbprint","-form","-httpversion"]},"expand-archive":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp","-destinationpath"],knownSwitches:["-force","-passthru","-whatif","-confirm"],knownValueParams:[]},"compress-archive":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp","-destinationpath"],knownSwitches:["-force","-update","-passthru","-whatif","-confirm"],knownValueParams:["-compressionlevel"]},"set-itemproperty":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-name","-value","-type","-filter","-include","-exclude","-credential","-inputobject"]},"new-itemproperty":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-name","-value","-propertytype","-type","-filter","-include","-exclude","-credential"]},"remove-itemproperty":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-name","-filter","-include","-exclude","-credential"]},"clear-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential"]},"export-alias":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-append","-force","-noclobber","-passthru","-whatif","-confirm"],knownValueParams:["-name","-description","-scope","-as"]}};function matchesParam(e,a){for(const t of a)if(t===e||e.length>1&&t.startsWith(e))return!0;return!1}function hasComplexColonValue(e){return e.includes(",")||e.startsWith("(")||e.startsWith("[")||e.includes("`")||e.includes("@(")||e.startsWith("@{")||e.includes("$")}function formatDirectoryList(e){const a=e.length;return a<=5?e.map(e=>`'${e}'`).join(", "):`${e.slice(0,5).map(e=>`'${e}'`).join(", ")}, and ${a-5} more`}function expandTilde(a){return"~"===a||a.startsWith("~/")||a.startsWith("~\\")?e()+a.slice(1):a}export function isDangerousRemovalRawPath(e){const a=expandTilde(e.replace(/^['"]|['"]$/g,"")).replace(/\\/g,"/");return f(a)}export function dangerousRemovalDeny(e){return{behavior:"deny",message:`Remove-Item on system path '${e}' is blocked. This path is protected from removal.`,decisionReason:{type:"other",reason:"Removal targets a protected system path"}}}function isPathAllowed(e,a,t,n){const r="read"===t?"read":"edit",o=d(e,a,r,"deny");if(null!==o)return{allowed:!1,decisionReason:{type:"rule",rule:o}};if("read"!==t){const a=p(e,{});if("allow"===a.behavior)return{allowed:!0,decisionReason:a.decisionReason}}if("read"!==t){const a=c(e,n);if(!a.safe)return{allowed:!1,decisionReason:{type:"safetyCheck",reason:a.message,classifierApprovable:a.classifierApprovable}}}const s=u(e,a,n);if(s&&("read"===t||"acceptEdits"===a.mode))return{allowed:!0};if("read"===t){const a=h(e,{});if("allow"===a.behavior)return{allowed:!0,decisionReason:a.decisionReason}}if("read"!==t&&!s&&w(e))return{allowed:!0,decisionReason:{type:"other",reason:"Path is in sandbox write allowlist"}};const i=d(e,a,r,"allow");return null!==i?{allowed:!0,decisionReason:{type:"rule",rule:i}}:{allowed:!1}}function checkDenyRuleForGuessedPath(e,n,s,i){if(!e||e.includes("\0"))return null;const l=expandTilde(e),p=a(l)?l:t(n,l),{resolvedPath:c}=o(r(),p),h=d(c,s,"read"===i?"read":"edit","deny");return h?{resolvedPath:c,rule:h}:null}function validatePath(e,n,i,l){const p=expandTilde(e.replace(/^['"]|['"]$/g,"")).replace(/\\/g,"/");if(p.includes("`")){const e=checkDenyRuleForGuessedPath(p.replace(/`/g,""),n,i,l);return e?{allowed:!1,resolvedPath:e.resolvedPath,decisionReason:{type:"rule",rule:e.rule}}:{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"Backtick escape characters in paths cannot be statically validated and require manual approval"}}}if(p.includes("::")){const e=checkDenyRuleForGuessedPath(p.slice(p.indexOf("::")+2),n,i,l);return e?{allowed:!1,resolvedPath:e.resolvedPath,decisionReason:{type:"rule",rule:e.rule}}:{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"Module-qualified provider paths (::) cannot be statically validated and require manual approval"}}}if(p.startsWith("//")||/DavWWWRoot/i.test(p)||/@SSL@/i.test(p))return{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"UNC paths are blocked because they can trigger network requests and credential leakage"}};if(p.includes("$")||p.includes("%"))return{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"Variable expansion syntax in paths requires manual approval"}};if(("windows"===y()?/^[a-z0-9]{2,}:/i:/^[a-z0-9]+:/i).test(p))return{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:`Path '${p}' uses a non-filesystem provider and requires manual approval`}};if(x.test(p)){if("write"===l||"create"===l)return{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"Glob patterns are not allowed in write operations. Please specify an exact file path."}};if(s(p)){const e=a(p)?p:t(n,p),{resolvedPath:s,isCanonical:c}=o(r(),e),h=isPathAllowed(s,i,l,c?[s]:void 0);return{allowed:h.allowed,resolvedPath:s,decisionReason:h.decisionReason}}const e=function(e){const a=e.match(x);if(!a||void 0===a.index)return e;const t=e.substring(0,a.index),n=Math.max(t.lastIndexOf("/"),t.lastIndexOf("\\"));return-1===n?".":t.substring(0,n+1)||"/"}(p),c=a(e)?e:t(n,e),{resolvedPath:h}=o(r(),c),u=d(h,i,"read"===l?"read":"edit","deny");return null!==u?{allowed:!1,resolvedPath:h,decisionReason:{type:"rule",rule:u}}:{allowed:!1,resolvedPath:h,decisionReason:{type:"other",reason:"Glob patterns in paths cannot be statically validated — symlinks inside the glob expansion are not examined. Requires manual approval."}}}const c=a(p)?p:t(n,p),{resolvedPath:h,isCanonical:u}=o(r(),c),m=isPathAllowed(h,i,l,u?[h]:void 0);return{allowed:m.allowed,resolvedPath:h,decisionReason:m.decisionReason}}const T=new Set(["StringConstant","Parameter"]);function extractPathsFromCommand(e){const a=b(e.name),t=R[a];if(!t)return{paths:[],operationType:"read",hasUnvalidatablePathArg:!1,optionalWrite:!1};const n=[...t.knownSwitches,...v],r=[...t.knownValueParams,...g],o=[],s=e.args,i=e.elementTypes;let l=!1,p=0;const c=t.positionalSkip??0;function checkArgElementType(e){if(!i)return;const a=i[e+1];a&&!T.has(a)&&(l=!0)}for(let e=0;e<s.length;e++){const a=s[e];if(!a)continue;const h=i?i[e+1]:void 0;if(k(a,h)){const p="-"+a.slice(1),c=p.indexOf(":",1),h=(c>0?p.substring(0,c):p).toLowerCase();if(matchesParam(h,t.pathParams)){let t;if(c>0){const e=a.substring(c+1);hasComplexColonValue(e)?l=!0:t=e}else{const a=s[e+1],n=i?i[e+2]:void 0;a&&!k(a,n)&&(t=a,checkArgElementType(e+1),e++)}t&&o.push(t)}else if(t.leafOnlyPathParams&&matchesParam(h,t.leafOnlyPathParams)){let t;if(c>0){const e=a.substring(c+1);hasComplexColonValue(e)?l=!0:t=e}else{const a=s[e+1],n=i?i[e+2]:void 0;a&&!k(a,n)&&(t=a,checkArgElementType(e+1),e++)}void 0!==t&&(t.includes("/")||t.includes("\\")||"."===t||".."===t?l=!0:o.push(t))}else if(matchesParam(h,n));else if(matchesParam(h,r))if(c>0)hasComplexColonValue(a.substring(c+1))&&(l=!0);else{const a=s[e+1],t=i?i[e+2]:void 0;a&&!k(a,t)&&(checkArgElementType(e+1),e++)}else if(l=!0,c>0){const e=a.substring(c+1);hasComplexColonValue(e)||o.push(e)}continue}p<c?p++:(p++,checkArgElementType(e),o.push(a))}return{paths:o,operationType:t.operationType,hasUnvalidatablePathArg:l,optionalWrite:t.optionalWrite??!1}}export function checkPathConstraints(e,a,t,n=!1){if(!a.valid)return{behavior:"passthrough",message:"Cannot validate paths for unparsed command"};let r;for(const e of a.statements){const a=checkPathConstraintsForStatement(e,t,n);if("deny"===a.behavior)return a;"ask"!==a.behavior||r||(r=a)}return r??{behavior:"passthrough",message:"All path constraints validated successfully"}}function checkPathConstraintsForStatement(e,a,t=!1){const r=n();let o;t&&(o={behavior:"ask",message:"Compound command changes working directory (Set-Location/Push-Location/Pop-Location/New-PSDrive) — relative paths cannot be validated against the original cwd and require manual approval",decisionReason:{type:"other",reason:"Compound command contains cd with path operation — manual approval required to prevent path resolution bypass"}});let s,p=!1;for(const t of e.commands){if("CommandAst"!==t.elementType){p=!0,s=t.text;continue}const{paths:e,operationType:n,hasUnvalidatablePathArg:c,optionalWrite:h}=extractPathsFromCommand(t);if(p){const e=b(t.name);if(void 0!==s){const t=checkDenyRuleForGuessedPath(s.replace(/^['"]|['"]$/g,""),r,a,n);if(t)return{behavior:"deny",message:`${e} targeting '${t.resolvedPath}' was blocked by a deny rule`,decisionReason:{type:"rule",rule:t.rule}}}o??={behavior:"ask",message:`${e} receives its path from a pipeline expression source that cannot be statically validated and requires manual approval`}}if(c){const e=b(t.name);o??={behavior:"ask",message:`${e} uses a parameter or complex path expression (array literal, subexpression, unknown parameter, etc.) that cannot be statically validated and requires manual approval`}}if("read"!==n&&!h&&0===e.length&&R[b(t.name)]){const e=b(t.name);o??={behavior:"ask",message:`${e} is a write operation but no target path could be determined; requires manual approval`};continue}const d="remove-item"===b(t.name);for(const s of e){if(d&&isDangerousRemovalRawPath(s))return dangerousRemovalDeny(s);const{allowed:e,resolvedPath:p,decisionReason:c}=validatePath(s,r,a,n);if(d&&f(p))return dangerousRemovalDeny(p);if(!e){const e=b(t.name),r=formatDirectoryList(Array.from(l(a))),s="other"===c?.type||"safetyCheck"===c?.type?c.reason:`${e} targeting '${p}' was blocked. For security, Context Code may only access files in the allowed working directories for this session: ${r}.`;if("rule"===c?.type)return{behavior:"deny",message:s,decisionReason:c};const h=[];if(p)if("read"===n){const e=m(i(p),"session");e&&h.push(e)}else h.push({type:"addDirectories",directories:[i(p)],destination:"session"});"write"!==n&&"create"!==n||h.push({type:"setMode",mode:"acceptEdits",destination:"session"}),o??={behavior:"ask",message:s,blockedPath:p,decisionReason:c,suggestions:h}}}}if(e.nestedCommands)for(const t of e.nestedCommands){const{paths:e,operationType:n,hasUnvalidatablePathArg:s,optionalWrite:c}=extractPathsFromCommand(t);if(s){const e=b(t.name);o??={behavior:"ask",message:`${e} uses a parameter or complex path expression (array literal, subexpression, unknown parameter, etc.) that cannot be statically validated and requires manual approval`}}if("read"!==n&&!c&&0===e.length&&R[b(t.name)]){const e=b(t.name);o??={behavior:"ask",message:`${e} is a write operation but no target path could be determined; requires manual approval`};continue}const h="remove-item"===b(t.name);for(const s of e){if(h&&isDangerousRemovalRawPath(s))return dangerousRemovalDeny(s);const{allowed:e,resolvedPath:p,decisionReason:c}=validatePath(s,r,a,n);if(h&&f(p))return dangerousRemovalDeny(p);if(!e){const e=b(t.name),r=formatDirectoryList(Array.from(l(a))),s="other"===c?.type||"safetyCheck"===c?.type?c.reason:`${e} targeting '${p}' was blocked. For security, Context Code may only access files in the allowed working directories for this session: ${r}.`;if("rule"===c?.type)return{behavior:"deny",message:s,decisionReason:c};const h=[];if(p)if("read"===n){const e=m(i(p),"session");e&&h.push(e)}else h.push({type:"addDirectories",directories:[i(p)],destination:"session"});"write"!==n&&"create"!==n||h.push({type:"setMode",mode:"acceptEdits",destination:"session"}),o??={behavior:"ask",message:s,blockedPath:p,decisionReason:c,suggestions:h}}}p&&(o??={behavior:"ask",message:`${b(t.name)} appears inside a control-flow or chain statement where piped expression sources cannot be statically validated and requires manual approval`})}if(e.nestedCommands)for(const t of e.nestedCommands)if(t.redirections)for(const e of t.redirections){if(e.isMerging)continue;if(!e.target)continue;if(P(e.target))continue;const{allowed:t,resolvedPath:n,decisionReason:s}=validatePath(e.target,r,a,"create");if(!t){const e=formatDirectoryList(Array.from(l(a))),t="other"===s?.type||"safetyCheck"===s?.type?s.reason:`Output redirection to '${n}' was blocked. For security, Context Code may only write to files in the allowed working directories for this session: ${e}.`;if("rule"===s?.type)return{behavior:"deny",message:t,decisionReason:s};o??={behavior:"ask",message:t,blockedPath:n,decisionReason:s,suggestions:[{type:"addDirectories",directories:[i(n)],destination:"session"}]}}}if(e.redirections)for(const t of e.redirections){if(t.isMerging)continue;if(!t.target)continue;if(P(t.target))continue;const{allowed:e,resolvedPath:n,decisionReason:s}=validatePath(t.target,r,a,"create");if(!e){const e=formatDirectoryList(Array.from(l(a))),t="other"===s?.type||"safetyCheck"===s?.type?s.reason:`Output redirection to '${n}' was blocked. For security, Context Code may only write to files in the allowed working directories for this session: ${e}.`;if("rule"===s?.type)return{behavior:"deny",message:t,decisionReason:s};o??={behavior:"ask",message:t,blockedPath:n,decisionReason:s,suggestions:[{type:"addDirectories",directories:[i(n)],destination:"session"}]}}}return o??{behavior:"passthrough",message:"All path constraints validated successfully"}}
1
+ import{homedir as e}from"os";import{isAbsolute as a,resolve as t}from"path";import{getCwd as n}from"../../utils/cwd.js";import{getFsImplementation as r,safeResolvePath as o}from"../../utils/fsOperations.js";import{containsPathTraversal as i,getDirectoryForPath as s}from"../../utils/path.js";import{allWorkingDirectories as l,checkEditableInternalPath as p,checkPathSafetyForAutoEdit as c,checkReadableInternalPath as h,matchingRuleForInput as d,pathInAllowedWorkingPath as u}from"../../utils/permissions/filesystem.js";import{createReadRuleSuggestion as m}from"../../utils/permissions/PermissionUpdate.js";import{isDangerousRemovalPath as f,isPathInSandboxWriteAllowlist as w}from"../../utils/permissions/pathValidation.js";import{getPlatform as y}from"../../utils/platform.js";import{isNullRedirectionTarget as k,isPowerShellParameter as v}from"../../utils/powershell/parser.js";import{COMMON_SWITCHES as P,COMMON_VALUE_PARAMS as g}from"./commonParameters.js";import{resolveToCanonical as b}from"./readOnlyValidation.js";const x=/[*?[\]]/,R={"set-content":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-force","-whatif","-confirm","-usetransaction","-nonewline","-asbytestream"],knownValueParams:["-value","-filter","-include","-exclude","-credential","-encoding","-stream"]},"add-content":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-force","-whatif","-confirm","-usetransaction","-nonewline","-asbytestream"],knownValueParams:["-value","-filter","-include","-exclude","-credential","-encoding","-stream"]},"remove-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-recurse","-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential","-stream"]},"clear-content":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential","-stream"]},"out-file":{operationType:"write",pathParams:["-filepath","-path","-literalpath","-pspath","-lp"],knownSwitches:["-append","-force","-noclobber","-nonewline","-whatif","-confirm"],knownValueParams:["-inputobject","-encoding","-width"]},"tee-object":{operationType:"write",pathParams:["-filepath","-path","-literalpath","-pspath","-lp"],knownSwitches:["-append"],knownValueParams:["-inputobject","-variable","-encoding"]},"export-csv":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-append","-force","-noclobber","-notypeinformation","-includetypeinformation","-useculture","-noheader","-whatif","-confirm"],knownValueParams:["-inputobject","-delimiter","-encoding","-quotefields","-usequotes"]},"export-clixml":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-noclobber","-whatif","-confirm"],knownValueParams:["-inputobject","-depth","-encoding"]},"new-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],leafOnlyPathParams:["-name"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-itemtype","-value","-credential","-type"]},"copy-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp","-destination"],knownSwitches:["-container","-force","-passthru","-recurse","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential","-fromsession","-tosession"]},"move-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp","-destination"],knownSwitches:["-force","-passthru","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential"]},"rename-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-passthru","-whatif","-confirm","-usetransaction"],knownValueParams:["-newname","-credential","-filter","-include","-exclude"]},"set-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-passthru","-whatif","-confirm","-usetransaction"],knownValueParams:["-value","-credential","-filter","-include","-exclude"]},"get-content":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-usetransaction","-wait","-raw","-asbytestream"],knownValueParams:["-readcount","-totalcount","-tail","-first","-head","-last","-filter","-include","-exclude","-credential","-delimiter","-encoding","-stream"]},"get-childitem":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-recurse","-force","-name","-usetransaction","-followsymlink","-directory","-file","-hidden","-readonly","-system"],knownValueParams:["-filter","-include","-exclude","-depth","-attributes","-credential"]},"get-item":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential","-stream"]},"get-itemproperty":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-usetransaction"],knownValueParams:["-name","-filter","-include","-exclude","-credential"]},"get-itempropertyvalue":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-usetransaction"],knownValueParams:["-name","-filter","-include","-exclude","-credential"]},"get-filehash":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:[],knownValueParams:["-algorithm","-inputstream"]},"get-acl":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-audit","-allcentralaccesspolicies","-usetransaction"],knownValueParams:["-inputobject","-filter","-include","-exclude"]},"format-hex":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-raw"],knownValueParams:["-inputobject","-encoding","-count","-offset"]},"test-path":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-isvalid","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-pathtype","-credential","-olderthan","-newerthan"]},"resolve-path":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-relative","-usetransaction","-force"],knownValueParams:["-credential","-relativebasepath"]},"convert-path":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-usetransaction"],knownValueParams:[]},"select-string":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-simplematch","-casesensitive","-quiet","-list","-notmatch","-allmatches","-noemphasis","-raw"],knownValueParams:["-inputobject","-pattern","-include","-exclude","-encoding","-context","-culture"]},"set-location":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-usetransaction"],knownValueParams:["-stackname"]},"push-location":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-usetransaction"],knownValueParams:["-stackname"]},"pop-location":{operationType:"read",pathParams:[],knownSwitches:["-passthru","-usetransaction"],knownValueParams:["-stackname"]},"select-xml":{operationType:"read",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:[],knownValueParams:["-xml","-content","-xpath","-namespace"]},"get-winevent":{operationType:"read",pathParams:["-path"],knownSwitches:["-force","-oldest"],knownValueParams:["-listlog","-logname","-listprovider","-providername","-maxevents","-computername","-credential","-filterxpath","-filterxml","-filterhashtable"]},"invoke-webrequest":{operationType:"write",pathParams:["-outfile","-infile"],positionalSkip:1,optionalWrite:!0,knownSwitches:["-allowinsecureredirect","-allowunencryptedauthentication","-disablekeepalive","-nobodyprogress","-passthru","-preservefileauthorizationmetadata","-resume","-skipcertificatecheck","-skipheadervalidation","-skiphttperrorcheck","-usebasicparsing","-usedefaultcredentials"],knownValueParams:["-uri","-method","-body","-contenttype","-headers","-maximumredirection","-maximumretrycount","-proxy","-proxycredential","-retryintervalsec","-sessionvariable","-timeoutsec","-token","-transferencoding","-useragent","-websession","-credential","-authentication","-certificate","-certificatethumbprint","-form","-httpversion"]},"invoke-restmethod":{operationType:"write",pathParams:["-outfile","-infile"],positionalSkip:1,optionalWrite:!0,knownSwitches:["-allowinsecureredirect","-allowunencryptedauthentication","-disablekeepalive","-followrellink","-nobodyprogress","-passthru","-preservefileauthorizationmetadata","-resume","-skipcertificatecheck","-skipheadervalidation","-skiphttperrorcheck","-usebasicparsing","-usedefaultcredentials"],knownValueParams:["-uri","-method","-body","-contenttype","-headers","-maximumfollowrellink","-maximumredirection","-maximumretrycount","-proxy","-proxycredential","-responseheaderstvariable","-retryintervalsec","-sessionvariable","-statuscodevariable","-timeoutsec","-token","-transferencoding","-useragent","-websession","-credential","-authentication","-certificate","-certificatethumbprint","-form","-httpversion"]},"expand-archive":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp","-destinationpath"],knownSwitches:["-force","-passthru","-whatif","-confirm"],knownValueParams:[]},"compress-archive":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp","-destinationpath"],knownSwitches:["-force","-update","-passthru","-whatif","-confirm"],knownValueParams:["-compressionlevel"]},"set-itemproperty":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-passthru","-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-name","-value","-type","-filter","-include","-exclude","-credential","-inputobject"]},"new-itemproperty":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-name","-value","-propertytype","-type","-filter","-include","-exclude","-credential"]},"remove-itemproperty":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-name","-filter","-include","-exclude","-credential"]},"clear-item":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-force","-whatif","-confirm","-usetransaction"],knownValueParams:["-filter","-include","-exclude","-credential"]},"export-alias":{operationType:"write",pathParams:["-path","-literalpath","-pspath","-lp"],knownSwitches:["-append","-force","-noclobber","-passthru","-whatif","-confirm"],knownValueParams:["-name","-description","-scope","-as"]}};function matchesParam(e,a){for(const t of a)if(t===e||e.length>1&&t.startsWith(e))return!0;return!1}function hasComplexColonValue(e){return e.includes(",")||e.startsWith("(")||e.startsWith("[")||e.includes("`")||e.includes("@(")||e.startsWith("@{")||e.includes("$")}function formatDirectoryList(e){const a=e.length;if(a<=5)return e.map(e=>`'${e}'`).join(", ");return`${e.slice(0,5).map(e=>`'${e}'`).join(", ")}, and ${a-5} more`}function expandTilde(a){return"~"===a||a.startsWith("~/")||a.startsWith("~\\")?e()+a.slice(1):a}export function isDangerousRemovalRawPath(e){const a=expandTilde(e.replace(/^['"]|['"]$/g,"")).replace(/\\/g,"/");return f(a)}export function dangerousRemovalDeny(e){return{behavior:"deny",message:`Remove-Item on system path '${e}' is blocked. This path is protected from removal.`,decisionReason:{type:"other",reason:"Removal targets a protected system path"}}}function isPathAllowed(e,a,t,n){const r="read"===t?"read":"edit",o=d(e,a,r,"deny");if(null!==o)return{allowed:!1,decisionReason:{type:"rule",rule:o}};if("read"!==t){const a=p(e,{});if("allow"===a.behavior)return{allowed:!0,decisionReason:a.decisionReason}}if("read"!==t){const a=c(e,n);if(!a.safe)return{allowed:!1,decisionReason:{type:"safetyCheck",reason:a.message,classifierApprovable:a.classifierApprovable}}}const i=u(e,a,n);if(i&&("read"===t||"acceptEdits"===a.mode))return{allowed:!0};if("read"===t){const a=h(e,{});if("allow"===a.behavior)return{allowed:!0,decisionReason:a.decisionReason}}if("read"!==t&&!i&&w(e))return{allowed:!0,decisionReason:{type:"other",reason:"Path is in sandbox write allowlist"}};const s=d(e,a,r,"allow");return null!==s?{allowed:!0,decisionReason:{type:"rule",rule:s}}:{allowed:!1}}function checkDenyRuleForGuessedPath(e,n,i,s){if(!e||e.includes("\0"))return null;const l=expandTilde(e),p=a(l)?l:t(n,l),{resolvedPath:c}=o(r(),p),h=d(c,i,"read"===s?"read":"edit","deny");return h?{resolvedPath:c,rule:h}:null}function validatePath(e,n,s,l){const p=expandTilde(e.replace(/^['"]|['"]$/g,"")).replace(/\\/g,"/");if(p.includes("`")){const e=checkDenyRuleForGuessedPath(p.replace(/`/g,""),n,s,l);return e?{allowed:!1,resolvedPath:e.resolvedPath,decisionReason:{type:"rule",rule:e.rule}}:{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"Backtick escape characters in paths cannot be statically validated and require manual approval"}}}if(p.includes("::")){const e=checkDenyRuleForGuessedPath(p.slice(p.indexOf("::")+2),n,s,l);return e?{allowed:!1,resolvedPath:e.resolvedPath,decisionReason:{type:"rule",rule:e.rule}}:{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"Module-qualified provider paths (::) cannot be statically validated and require manual approval"}}}if(p.startsWith("//")||/DavWWWRoot/i.test(p)||/@SSL@/i.test(p))return{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"UNC paths are blocked because they can trigger network requests and credential leakage"}};if(p.includes("$")||p.includes("%"))return{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"Variable expansion syntax in paths requires manual approval"}};if(("windows"===y()?/^[a-z0-9]{2,}:/i:/^[a-z0-9]+:/i).test(p))return{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:`Path '${p}' uses a non-filesystem provider and requires manual approval`}};if(x.test(p)){if("write"===l||"create"===l)return{allowed:!1,resolvedPath:p,decisionReason:{type:"other",reason:"Glob patterns are not allowed in write operations. Please specify an exact file path."}};if(i(p)){const e=a(p)?p:t(n,p),{resolvedPath:i,isCanonical:c}=o(r(),e),h=isPathAllowed(i,s,l,c?[i]:void 0);return{allowed:h.allowed,resolvedPath:i,decisionReason:h.decisionReason}}const e=function(e){const a=e.match(x);if(!a||void 0===a.index)return e;const t=e.substring(0,a.index),n=Math.max(t.lastIndexOf("/"),t.lastIndexOf("\\"));return-1===n?".":t.substring(0,n+1)||"/"}(p),c=a(e)?e:t(n,e),{resolvedPath:h}=o(r(),c),u=d(h,s,"read"===l?"read":"edit","deny");return null!==u?{allowed:!1,resolvedPath:h,decisionReason:{type:"rule",rule:u}}:{allowed:!1,resolvedPath:h,decisionReason:{type:"other",reason:"Glob patterns in paths cannot be statically validated — symlinks inside the glob expansion are not examined. Requires manual approval."}}}const c=a(p)?p:t(n,p),{resolvedPath:h,isCanonical:u}=o(r(),c),m=isPathAllowed(h,s,l,u?[h]:void 0);return{allowed:m.allowed,resolvedPath:h,decisionReason:m.decisionReason}}const T=new Set(["StringConstant","Parameter"]);function extractPathsFromCommand(e){const a=b(e.name),t=R[a];if(!t)return{paths:[],operationType:"read",hasUnvalidatablePathArg:!1,optionalWrite:!1};const n=[...t.knownSwitches,...P],r=[...t.knownValueParams,...g],o=[],i=e.args,s=e.elementTypes;let l=!1,p=0;const c=t.positionalSkip??0;function checkArgElementType(e){if(!s)return;const a=s[e+1];a&&!T.has(a)&&(l=!0)}for(let e=0;e<i.length;e++){const a=i[e];if(!a)continue;const h=s?s[e+1]:void 0;if(v(a,h)){const p="-"+a.slice(1),c=p.indexOf(":",1),h=(c>0?p.substring(0,c):p).toLowerCase();if(matchesParam(h,t.pathParams)){let t;if(c>0){const e=a.substring(c+1);hasComplexColonValue(e)?l=!0:t=e}else{const a=i[e+1],n=s?s[e+2]:void 0;a&&!v(a,n)&&(t=a,checkArgElementType(e+1),e++)}t&&o.push(t)}else if(t.leafOnlyPathParams&&matchesParam(h,t.leafOnlyPathParams)){let t;if(c>0){const e=a.substring(c+1);hasComplexColonValue(e)?l=!0:t=e}else{const a=i[e+1],n=s?s[e+2]:void 0;a&&!v(a,n)&&(t=a,checkArgElementType(e+1),e++)}void 0!==t&&(t.includes("/")||t.includes("\\")||"."===t||".."===t?l=!0:o.push(t))}else if(matchesParam(h,n));else if(matchesParam(h,r))if(c>0){hasComplexColonValue(a.substring(c+1))&&(l=!0)}else{const a=i[e+1],t=s?s[e+2]:void 0;a&&!v(a,t)&&(checkArgElementType(e+1),e++)}else if(l=!0,c>0){const e=a.substring(c+1);hasComplexColonValue(e)||o.push(e)}continue}p<c?p++:(p++,checkArgElementType(e),o.push(a))}return{paths:o,operationType:t.operationType,hasUnvalidatablePathArg:l,optionalWrite:t.optionalWrite??!1}}export function checkPathConstraints(e,a,t,n=!1){if(!a.valid)return{behavior:"passthrough",message:"Cannot validate paths for unparsed command"};let r;for(const e of a.statements){const a=checkPathConstraintsForStatement(e,t,n);if("deny"===a.behavior)return a;"ask"!==a.behavior||r||(r=a)}return r??{behavior:"passthrough",message:"All path constraints validated successfully"}}function checkPathConstraintsForStatement(e,a,t=!1){const r=n();let o;t&&(o={behavior:"ask",message:"Compound command changes working directory (Set-Location/Push-Location/Pop-Location/New-PSDrive) — relative paths cannot be validated against the original cwd and require manual approval",decisionReason:{type:"other",reason:"Compound command contains cd with path operation — manual approval required to prevent path resolution bypass"}});let i,p=!1;for(const t of e.commands){if("CommandAst"!==t.elementType){p=!0,i=t.text;continue}const{paths:e,operationType:n,hasUnvalidatablePathArg:c,optionalWrite:h}=extractPathsFromCommand(t);if(p){const e=b(t.name);if(void 0!==i){const t=checkDenyRuleForGuessedPath(i.replace(/^['"]|['"]$/g,""),r,a,n);if(t)return{behavior:"deny",message:`${e} targeting '${t.resolvedPath}' was blocked by a deny rule`,decisionReason:{type:"rule",rule:t.rule}}}o??={behavior:"ask",message:`${e} receives its path from a pipeline expression source that cannot be statically validated and requires manual approval`}}if(c){const e=b(t.name);o??={behavior:"ask",message:`${e} uses a parameter or complex path expression (array literal, subexpression, unknown parameter, etc.) that cannot be statically validated and requires manual approval`}}if("read"!==n&&!h&&0===e.length&&R[b(t.name)]){const e=b(t.name);o??={behavior:"ask",message:`${e} is a write operation but no target path could be determined; requires manual approval`};continue}const d="remove-item"===b(t.name);for(const i of e){if(d&&isDangerousRemovalRawPath(i))return dangerousRemovalDeny(i);const{allowed:e,resolvedPath:p,decisionReason:c}=validatePath(i,r,a,n);if(d&&f(p))return dangerousRemovalDeny(p);if(!e){const e=b(t.name),r=formatDirectoryList(Array.from(l(a))),i="other"===c?.type||"safetyCheck"===c?.type?c.reason:`${e} targeting '${p}' was blocked. For security, Context Code may only access files in the allowed working directories for this session: ${r}.`;if("rule"===c?.type)return{behavior:"deny",message:i,decisionReason:c};const h=[];if(p)if("read"===n){const e=m(s(p),"session");e&&h.push(e)}else h.push({type:"addDirectories",directories:[s(p)],destination:"session"});"write"!==n&&"create"!==n||h.push({type:"setMode",mode:"acceptEdits",destination:"session"}),o??={behavior:"ask",message:i,blockedPath:p,decisionReason:c,suggestions:h}}}}if(e.nestedCommands)for(const t of e.nestedCommands){const{paths:e,operationType:n,hasUnvalidatablePathArg:i,optionalWrite:c}=extractPathsFromCommand(t);if(i){const e=b(t.name);o??={behavior:"ask",message:`${e} uses a parameter or complex path expression (array literal, subexpression, unknown parameter, etc.) that cannot be statically validated and requires manual approval`}}if("read"!==n&&!c&&0===e.length&&R[b(t.name)]){const e=b(t.name);o??={behavior:"ask",message:`${e} is a write operation but no target path could be determined; requires manual approval`};continue}const h="remove-item"===b(t.name);for(const i of e){if(h&&isDangerousRemovalRawPath(i))return dangerousRemovalDeny(i);const{allowed:e,resolvedPath:p,decisionReason:c}=validatePath(i,r,a,n);if(h&&f(p))return dangerousRemovalDeny(p);if(!e){const e=b(t.name),r=formatDirectoryList(Array.from(l(a))),i="other"===c?.type||"safetyCheck"===c?.type?c.reason:`${e} targeting '${p}' was blocked. For security, Context Code may only access files in the allowed working directories for this session: ${r}.`;if("rule"===c?.type)return{behavior:"deny",message:i,decisionReason:c};const h=[];if(p)if("read"===n){const e=m(s(p),"session");e&&h.push(e)}else h.push({type:"addDirectories",directories:[s(p)],destination:"session"});"write"!==n&&"create"!==n||h.push({type:"setMode",mode:"acceptEdits",destination:"session"}),o??={behavior:"ask",message:i,blockedPath:p,decisionReason:c,suggestions:h}}}p&&(o??={behavior:"ask",message:`${b(t.name)} appears inside a control-flow or chain statement where piped expression sources cannot be statically validated and requires manual approval`})}if(e.nestedCommands)for(const t of e.nestedCommands)if(t.redirections)for(const e of t.redirections){if(e.isMerging)continue;if(!e.target)continue;if(k(e.target))continue;const{allowed:t,resolvedPath:n,decisionReason:i}=validatePath(e.target,r,a,"create");if(!t){const e=formatDirectoryList(Array.from(l(a))),t="other"===i?.type||"safetyCheck"===i?.type?i.reason:`Output redirection to '${n}' was blocked. For security, Context Code may only write to files in the allowed working directories for this session: ${e}.`;if("rule"===i?.type)return{behavior:"deny",message:t,decisionReason:i};o??={behavior:"ask",message:t,blockedPath:n,decisionReason:i,suggestions:[{type:"addDirectories",directories:[s(n)],destination:"session"}]}}}if(e.redirections)for(const t of e.redirections){if(t.isMerging)continue;if(!t.target)continue;if(k(t.target))continue;const{allowed:e,resolvedPath:n,decisionReason:i}=validatePath(t.target,r,a,"create");if(!e){const e=formatDirectoryList(Array.from(l(a))),t="other"===i?.type||"safetyCheck"===i?.type?i.reason:`Output redirection to '${n}' was blocked. For security, Context Code may only write to files in the allowed working directories for this session: ${e}.`;if("rule"===i?.type)return{behavior:"deny",message:t,decisionReason:i};o??={behavior:"ask",message:t,blockedPath:n,decisionReason:i,suggestions:[{type:"addDirectories",directories:[s(n)],destination:"session"}]}}}return o??{behavior:"passthrough",message:"All path constraints validated successfully"}}
@@ -1 +1 @@
1
- import{resolve as e}from"path";import{getCwd as t}from"../../utils/cwd.js";import{isCurrentDirectoryBareGitRepo as s}from"../../utils/git.js";import{createPermissionRequestMessage as n,getRuleByContentsForToolName as o}from"../../utils/permissions/permissions.js";import{matchWildcardPattern as a,parsePermissionRule as i,suggestionForExactCommand as r}from"../../utils/permissions/shellRuleMatching.js";import{classifyCommandName as m,deriveSecurityFlags as l,getAllCommandNames as c,getFileRedirections as u,PS_TOKENIZER_DASH_CHARS as h,parsePowerShellCommand as d,stripModulePrefix as p}from"../../utils/powershell/parser.js";import{containsVulnerableUncPath as f}from"../../utils/shell/readOnlyCommandValidation.js";import{isDotGitPathPS as g,isGitInternalPathPS as v}from"./gitSafety.js";import{checkPermissionMode as y,isSymlinkCreatingCommand as b}from"./modeValidation.js";import{checkPathConstraints as w,dangerousRemovalDeny as x,isDangerousRemovalRawPath as C}from"./pathValidation.js";import{powershellCommandIsSafe as R}from"./powershellSecurity.js";import{argLeaksValue as k,isAllowlistedCommand as P,isCwdChangingCmdlet as S,isProvablySafeStatement as A,isReadOnlyCommand as E,isSafeOutputCommand as T,resolveToCanonical as F}from"./readOnlyValidation.js";import{POWERSHELL_TOOL_NAME as q}from"./toolName.js";const D=/^\$[\w:]+\s*(?:[+\-*/%]|\?\?)?\s*=\s*/,I=new Set(["new-item","set-content","add-content","out-file","copy-item","move-item","rename-item","expand-archive","invoke-webrequest","invoke-restmethod","tee-object","export-csv","export-clixml"]),M=new Set(["tar","tar.exe","bsdtar","bsdtar.exe","unzip","unzip.exe","7z","7z.exe","7za","7za.exe","gzip","gzip.exe","gunzip","gunzip.exe","expand-archive"]);async function extractCommandName(e){const t=e.trim();if(!t)return"";const s=await d(t);return c(s)[0]??""}export function powershellPermissionRule(e){return i(e)}function suggestionForExactCommand(e){return e.includes("\n")||e.includes("*")?[]:r(q,e)}function filterRulesByContentsMatchingInput(e,t,s,n){const o=e.command.trim();function strEquals(e,t){return e.toLowerCase()===t.toLowerCase()}function strStartsWith(e,t){return e.toLowerCase().startsWith(t.toLowerCase())}function stripModulePrefixForRule(e){return"allow"===n?e:p(e)}const i=o.split(/\s+/)[0]??"",r=p(i),m=F(r),l=o.slice(i.length).replace(/^\s+/," "),c=m+l;return Array.from(t.entries()).filter(([e])=>{const t=powershellPermissionRule(e);function matchesCommand(e){switch(t.type){case"exact":return strEquals(t.command,e);case"prefix":switch(s){case"exact":return strEquals(t.prefix,e);case"prefix":return!!strEquals(e,t.prefix)||strStartsWith(e,t.prefix+" ")}break;case"wildcard":return"exact"!==s&&a(t.pattern,e,!0)}}if(matchesCommand(o))return!0;if(matchesCommand(c))return!0;if("exact"===t.type){const e=t.command.split(/\s+/)[0]??"";if(F(stripModulePrefixForRule(e))===m&&strEquals(t.command.slice(e.length).replace(/^\s+/," "),l))return!0}else if("prefix"===t.type){const e=t.prefix.split(/\s+/)[0]??"";if(F(stripModulePrefixForRule(e))===m){const n=t.prefix.slice(e.length).replace(/^\s+/," "),o=m+n;if("exact"===s){if(strEquals(o,c))return!0}else if(strEquals(c,o)||strStartsWith(c,o+" "))return!0}}else if("wildcard"===t.type){const e=t.pattern.split(/\s+/)[0]??"";if(F(stripModulePrefixForRule(e))===m&&"exact"!==s){const s=t.pattern.slice(e.length).replace(/^\s+/," ");if(a(m+s,c,!0))return!0}}return!1}).map(([,e])=>e)}function matchingRulesForInput(e,t,s){return{matchingDenyRules:filterRulesByContentsMatchingInput(e,o(t,q,"deny"),s,"deny"),matchingAskRules:filterRulesByContentsMatchingInput(e,o(t,q,"ask"),s,"ask"),matchingAllowRules:filterRulesByContentsMatchingInput(e,o(t,q,"allow"),s,"allow")}}export function powershellToolCheckExactMatchPermission(e,t){const s=e.command.trim(),{matchingDenyRules:o,matchingAskRules:a,matchingAllowRules:i}=matchingRulesForInput(e,t,"exact");if(void 0!==o[0])return{behavior:"deny",message:`Permission to use ${q} with command ${s} has been denied.`,decisionReason:{type:"rule",rule:o[0]}};if(void 0!==a[0])return{behavior:"ask",message:n(q),decisionReason:{type:"rule",rule:a[0]}};if(void 0!==i[0])return{behavior:"allow",updatedInput:e,decisionReason:{type:"rule",rule:i[0]}};const r={type:"other",reason:"This command requires approval"};return{behavior:"passthrough",message:n(q,r),decisionReason:r,suggestions:suggestionForExactCommand(s)}}export function powershellToolCheckPermission(e,t){const s=e.command.trim(),o=powershellToolCheckExactMatchPermission(e,t);if("deny"===o.behavior||"ask"===o.behavior)return o;const{matchingDenyRules:a,matchingAskRules:i,matchingAllowRules:r}=matchingRulesForInput(e,t,"prefix");if(void 0!==a[0])return{behavior:"deny",message:`Permission to use ${q} with command ${s} has been denied.`,decisionReason:{type:"rule",rule:a[0]}};if(void 0!==i[0])return{behavior:"ask",message:n(q),decisionReason:{type:"rule",rule:i[0]}};if("allow"===o.behavior)return o;if(void 0!==r[0])return{behavior:"allow",updatedInput:e,decisionReason:{type:"rule",rule:r[0]}};const m={type:"other",reason:"This command requires approval"};return{behavior:"passthrough",message:n(q,m),decisionReason:m,suggestions:suggestionForExactCommand(s)}}export async function powershellToolHasPermission(o,a){const i=a.getAppState().toolPermissionContext,r=o.command.trim();if(!r)return{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Empty command is safe"}};const c=await d(r),p=powershellToolCheckExactMatchPermission(o,i);if("deny"===p.behavior)return p;const{matchingDenyRules:$,matchingAskRules:O}=matchingRulesForInput(o,i,"prefix");if(void 0!==$[0])return{behavior:"deny",message:`Permission to use ${q} with command ${r} has been denied.`,decisionReason:{type:"rule",rule:$[0]}};let j=null;if(void 0!==O[0]&&(j={behavior:"ask",message:n(q),decisionReason:{type:"rule",rule:O[0]}}),null===j&&f(r)&&(j={behavior:"ask",message:"Command contains a UNC path that could trigger network requests"}),"allow"===p.behavior&&!c.valid&&null===j&&"application"!==m(r.split(/\s+/)[0]??""))return p;if(!c.valid){const e=r.replace(/`[\r\n]+\s*/g,"").replace(/`/g,"");for(const t of e.split(/[;|\n\r{}()&]+/)){const e=t.trim();if(!e)continue;if(e===r&&!/^\$[\w:]/.test(e)&&!/^[&.]\s/.test(e))continue;let s,n=e;for(;s=n.match(D);)n=n.slice(s[0].length);n=n.replace(/^[&.]\s+/,"");const o=n.split(/\s+/)[0]??"",a=o.replace(/^['"]|['"]$/g,""),m=a+n.slice(o.length);if("remove-item"===F(a))for(const e of n.split(/\s+/).slice(1))if(!h.has(e[0]??"")&&C(e))return x(e);const{matchingDenyRules:l}=matchingRulesForInput({command:m},i,"prefix");if(void 0!==l[0])return{behavior:"deny",message:`Permission to use ${q} with command ${r} has been denied.`,decisionReason:{type:"rule",rule:l[0]}}}if(null!==j)return j;const t={type:"other",reason:`Command contains malformed syntax that cannot be parsed: ${c.errors[0]?.message??"unknown error"}`};return{behavior:"ask",decisionReason:t,message:n(q,t)}}const N=await async function(e,t){if(!e.valid)return[{text:t,element:{name:await extractCommandName(t),nameType:"unknown",elementType:"CommandAst",args:[],text:t},statement:null,isSafeOutput:!1}];const s=[];for(const t of e.statements){for(const e of t.commands)"CommandAst"===e.elementType&&s.push({text:e.text,element:e,statement:t,isSafeOutput:"application"!==e.nameType&&T(e.name)&&0===e.args.length});if(t.nestedCommands)for(const e of t.nestedCommands)s.push({text:e.text,element:e,statement:t,isSafeOutput:"application"!==e.nameType&&T(e.name)&&0===e.args.length})}return s.length>0?s:[{text:t,element:{name:await extractCommandName(t),nameType:"unknown",elementType:"CommandAst",args:[],text:t},statement:null,isSafeOutput:!1}]}(c,r),z=[];null!==j&&z.push(j);const L=R(r,c);if("passthrough"!==L.behavior){const e={type:"other",reason:"ask"===L.behavior&&L.message?L.message:"This command contains patterns that could pose security risks and requires approval"};z.push({behavior:"ask",message:n(q,e),decisionReason:e,suggestions:suggestionForExactCommand(r)})}if(c.hasUsingStatements){const e={type:"other",reason:"Command contains a `using` statement that may load external code (module or assembly)"};z.push({behavior:"ask",message:n(q,e),decisionReason:e,suggestions:suggestionForExactCommand(r)})}if(c.hasScriptRequirements){const e={type:"other",reason:"Command contains a `#Requires` directive that may trigger module loading"};z.push({behavior:"ask",message:n(q,e),decisionReason:e,suggestions:suggestionForExactCommand(r)})}const H=/^(?:[\w.]+\\)?(env|hklm|hkcu|function|alias|variable|cert|wsman|registry)::?/i;function providerOrUncDecisionForArg(e){const t=function(e){let t=e;if(t.length>0&&h.has(t[0])){const e=t.indexOf(":",1);e>0&&(t=t.substring(e+1))}return t.replace(/`/g,"")}(e);return H.test(t)?{behavior:"ask",message:`Command argument '${e}' uses a non-filesystem provider path and requires approval`}:f(t)?{behavior:"ask",message:`Command argument '${e}' contains a UNC path that could trigger network requests`}:null}e:for(const e of c.statements){for(const t of e.commands)if("CommandAst"===t.elementType)for(const e of t.args){const t=providerOrUncDecisionForArg(e);if(null!==t){z.push(t);break e}}if(e.nestedCommands)for(const t of e.nestedCommands)for(const e of t.args){const t=providerOrUncDecisionForArg(e);if(null!==t){z.push(t);break e}}}for(const{text:e,element:t}of N){const s=""!==t.name?[t.name,...t.args].join(" "):null,o={command:e},{matchingDenyRules:a,matchingAskRules:m}=matchingRulesForInput(o,i,"prefix");let l=a[0],c=m[0];if(void 0===l&&null!==s){const{matchingDenyRules:e,matchingAskRules:t}=matchingRulesForInput({command:s},i,"prefix");l=e[0],void 0===c&&(c=t[0])}void 0!==l?z.push({behavior:"deny",message:`Permission to use ${q} with command ${r} has been denied.`,decisionReason:{type:"rule",rule:l}}):void 0!==c&&z.push({behavior:"ask",message:n(q),decisionReason:{type:"rule",rule:c}})}const B=N.length>1&&N.some(({element:e})=>S(e.name)),U=N.length>1&&N.some(({element:e})=>b(e)),V=N.some(({element:e})=>"git"===F(e.name));if(B&&V&&z.push({behavior:"ask",message:"Compound commands with cd/Set-Location and git require approval to prevent bare repository attacks"}),V&&s()&&z.push({behavior:"ask",message:"Git command in a directory with bare-repository indicators (HEAD, objects/, refs/ in cwd without .git/HEAD). Git may execute hooks from cwd."}),V){const e=N.some(({element:e,statement:t})=>{for(const t of e.redirections??[])if(v(t.target))return!0;const s=F(e.name);if(!I.has(s))return!1;if(e.args.flatMap(e=>e.split(",")).some(e=>v(e)))return!0;if(null!==t)for(const e of t.commands)if("CommandAst"!==e.elementType&&v(e.text))return!0;return!1}),t=u(c).some(e=>v(e.target));(e||t)&&z.push({behavior:"ask",message:"Command writes to a git-internal path (HEAD, objects/, refs/, hooks/, .git/) and runs git. This could plant a malicious hook that git then executes."}),N.some(({element:e})=>M.has(e.name.toLowerCase()))&&z.push({behavior:"ask",message:"Compound command extracts an archive and runs git. Archive contents may plant bare-repository indicators (HEAD, hooks/, refs/) that git then treats as the repository root."})}(N.some(({element:e})=>{for(const t of e.redirections??[])if(g(t.target))return!0;const t=F(e.name);return!!I.has(t)&&e.args.flatMap(e=>e.split(",")).some(g)})||u(c).some(e=>g(e.target)))&&z.push({behavior:"ask",message:"Command writes to .git/ — hooks or config planted there execute on the next git operation."});const W=w(o,c,i,B);"passthrough"!==W.behavior&&z.push(W),"allow"===p.behavior&&void 0!==N[0]&&N.every(e=>"application"!==e.element.nameType&&!k(e.text,e.element))&&z.push(p),E(r,c)&&z.push({behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Command is read-only and safe to execute"}}),u(c).length>0&&z.push({behavior:"ask",message:"Command contains file redirections that could write to arbitrary paths",suggestions:suggestionForExactCommand(r)});const G=y(o,c,i);"passthrough"!==G.behavior&&z.push(G);const _=z.find(e=>"deny"===e.behavior);if(void 0!==_)return _;const K=z.find(e=>"ask"===e.behavior);if(void 0!==K)return K;const Z=z.find(e=>"allow"===e.behavior);if(void 0!==Z)return Z;const J=N.filter(({element:s,isSafeOutput:n})=>{if(n)return!1;if("application"===s.nameType)return!0;if("set-location"===F(s.name)&&s.args.length>0){const n=s.args.find(e=>0===e.length||!h.has(e[0]));if(n&&e(t(),n)===t())return!1}return!0}),Q=[],X=new Set;for(const{text:e,element:t,statement:s}of J){const n=powershellToolCheckPermission({command:e},i);if("deny"===n.behavior)return{behavior:"deny",message:`Permission to use ${q} with command ${r} has been denied.`,decisionReason:n.decisionReason};if("ask"!==n.behavior){if("allow"!==n.behavior||"application"===t.nameType||U)if("allow"!==n.behavior){if(null===s||B||U||!A(s)||!P(t,e)){if(null!==s&&!B&&!U&&"allow"===y({command:e},{valid:!0,errors:[],variables:c.variables,hasStopParsing:c.hasStopParsing,originalCommand:e,statements:[s]},i).behavior)continue;null!==s&&X.add(s),Q.push(e)}}else null!==s&&X.add(s),Q.push(e);else if(k(e,t)){null!==s&&X.add(s),Q.push(e);continue}}else null!==s&&X.add(s),Q.push(e)}for(const e of c.statements)A(e)||X.has(e)||Q.push(e.text);if(0===Q.length)return l(c).hasScriptBlocks?{behavior:"ask",message:n(q),decisionReason:{type:"other",reason:"Pipeline consists of output-formatting cmdlets with script blocks — block content cannot be verified"}}:{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"All pipeline commands are individually allowed"}};const Y={type:"other",reason:"This command requires approval"},ee=[];for(const e of Q)ee.push(...suggestionForExactCommand(e));return{behavior:"passthrough",message:n(q,Y),decisionReason:Y,suggestions:ee}}
1
+ import{resolve as e}from"path";import{getCwd as t}from"../../utils/cwd.js";import{isCurrentDirectoryBareGitRepo as s}from"../../utils/git.js";import{createPermissionRequestMessage as n,getRuleByContentsForToolName as o}from"../../utils/permissions/permissions.js";import{matchWildcardPattern as a,parsePermissionRule as r,suggestionForExactCommand as i}from"../../utils/permissions/shellRuleMatching.js";import{classifyCommandName as m,deriveSecurityFlags as l,getAllCommandNames as c,getFileRedirections as u,PS_TOKENIZER_DASH_CHARS as p,parsePowerShellCommand as h,stripModulePrefix as d}from"../../utils/powershell/parser.js";import{containsVulnerableUncPath as f}from"../../utils/shell/readOnlyCommandValidation.js";import{isDotGitPathPS as g,isGitInternalPathPS as v}from"./gitSafety.js";import{checkPermissionMode as y,isSymlinkCreatingCommand as b}from"./modeValidation.js";import{checkPathConstraints as x,dangerousRemovalDeny as w,isDangerousRemovalRawPath as R}from"./pathValidation.js";import{powershellCommandIsSafe as k}from"./powershellSecurity.js";import{argLeaksValue as C,isAllowlistedCommand as A,isCwdChangingCmdlet as E,isProvablySafeStatement as F,isReadOnlyCommand as T,isSafeOutputCommand as P,resolveToCanonical as S}from"./readOnlyValidation.js";import{POWERSHELL_TOOL_NAME as q}from"./toolName.js";const $=/^\$[\w:]+\s*(?:[+\-*/%]|\?\?)?\s*=\s*/,j=new Set(["new-item","set-content","add-content","out-file","copy-item","move-item","rename-item","expand-archive","invoke-webrequest","invoke-restmethod","tee-object","export-csv","export-clixml"]),I=new Set(["tar","tar.exe","bsdtar","bsdtar.exe","unzip","unzip.exe","7z","7z.exe","7za","7za.exe","gzip","gzip.exe","gunzip","gunzip.exe","expand-archive"]);async function extractCommandName(e){const t=e.trim();if(!t)return"";const s=await h(t);return c(s)[0]??""}export function powershellPermissionRule(e){return r(e)}function suggestionForExactCommand(e){return e.includes("\n")||e.includes("*")?[]:i(q,e)}function filterRulesByContentsMatchingInput(e,t,s,n){const o=e.command.trim();function strEquals(e,t){return e.toLowerCase()===t.toLowerCase()}function strStartsWith(e,t){return e.toLowerCase().startsWith(t.toLowerCase())}function stripModulePrefixForRule(e){return"allow"===n?e:d(e)}const r=o.split(/\s+/)[0]??"",i=d(r),m=S(i),l=o.slice(r.length).replace(/^\s+/," "),c=m+l;return Array.from(t.entries()).filter(([e])=>{const t=powershellPermissionRule(e);function matchesCommand(e){switch(t.type){case"exact":return strEquals(t.command,e);case"prefix":switch(s){case"exact":return strEquals(t.prefix,e);case"prefix":return!!strEquals(e,t.prefix)||strStartsWith(e,t.prefix+" ")}break;case"wildcard":return"exact"!==s&&a(t.pattern,e,!0)}}if(matchesCommand(o))return!0;if(matchesCommand(c))return!0;if("exact"===t.type){const e=t.command.split(/\s+/)[0]??"";if(S(stripModulePrefixForRule(e))===m){if(strEquals(t.command.slice(e.length).replace(/^\s+/," "),l))return!0}}else if("prefix"===t.type){const e=t.prefix.split(/\s+/)[0]??"";if(S(stripModulePrefixForRule(e))===m){const n=t.prefix.slice(e.length).replace(/^\s+/," "),o=m+n;if("exact"===s){if(strEquals(o,c))return!0}else if(strEquals(c,o)||strStartsWith(c,o+" "))return!0}}else if("wildcard"===t.type){const e=t.pattern.split(/\s+/)[0]??"";if(S(stripModulePrefixForRule(e))===m&&"exact"!==s){const s=t.pattern.slice(e.length).replace(/^\s+/," ");if(a(m+s,c,!0))return!0}}return!1}).map(([,e])=>e)}function matchingRulesForInput(e,t,s){return{matchingDenyRules:filterRulesByContentsMatchingInput(e,o(t,q,"deny"),s,"deny"),matchingAskRules:filterRulesByContentsMatchingInput(e,o(t,q,"ask"),s,"ask"),matchingAllowRules:filterRulesByContentsMatchingInput(e,o(t,q,"allow"),s,"allow")}}export function powershellToolCheckExactMatchPermission(e,t){const s=e.command.trim(),{matchingDenyRules:o,matchingAskRules:a,matchingAllowRules:r}=matchingRulesForInput(e,t,"exact");if(void 0!==o[0])return{behavior:"deny",message:`Permission to use ${q} with command ${s} has been denied.`,decisionReason:{type:"rule",rule:o[0]}};if(void 0!==a[0])return{behavior:"ask",message:n(q),decisionReason:{type:"rule",rule:a[0]}};if(void 0!==r[0])return{behavior:"allow",updatedInput:e,decisionReason:{type:"rule",rule:r[0]}};const i={type:"other",reason:"This command requires approval"};return{behavior:"passthrough",message:n(q,i),decisionReason:i,suggestions:suggestionForExactCommand(s)}}export function powershellToolCheckPermission(e,t){const s=e.command.trim(),o=powershellToolCheckExactMatchPermission(e,t);if("deny"===o.behavior||"ask"===o.behavior)return o;const{matchingDenyRules:a,matchingAskRules:r,matchingAllowRules:i}=matchingRulesForInput(e,t,"prefix");if(void 0!==a[0])return{behavior:"deny",message:`Permission to use ${q} with command ${s} has been denied.`,decisionReason:{type:"rule",rule:a[0]}};if(void 0!==r[0])return{behavior:"ask",message:n(q),decisionReason:{type:"rule",rule:r[0]}};if("allow"===o.behavior)return o;if(void 0!==i[0])return{behavior:"allow",updatedInput:e,decisionReason:{type:"rule",rule:i[0]}};const m={type:"other",reason:"This command requires approval"};return{behavior:"passthrough",message:n(q,m),decisionReason:m,suggestions:suggestionForExactCommand(s)}}export async function powershellToolHasPermission(o,a){const r=a.getAppState().toolPermissionContext,i=o.command.trim();if(!i)return{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Empty command is safe"}};const c=await h(i),d=powershellToolCheckExactMatchPermission(o,r);if("deny"===d.behavior)return d;const{matchingDenyRules:D,matchingAskRules:M}=matchingRulesForInput(o,r,"prefix");if(void 0!==D[0])return{behavior:"deny",message:`Permission to use ${q} with command ${i} has been denied.`,decisionReason:{type:"rule",rule:D[0]}};let O=null;if(void 0!==M[0]&&(O={behavior:"ask",message:n(q),decisionReason:{type:"rule",rule:M[0]}}),null===O&&f(i)&&(O={behavior:"ask",message:"Command contains a UNC path that could trigger network requests"}),"allow"===d.behavior&&!c.valid&&null===O&&"application"!==m(i.split(/\s+/)[0]??""))return d;if(!c.valid){const e=i.replace(/`[\r\n]+\s*/g,"").replace(/`/g,"");for(const t of e.split(/[;|\n\r{}()&]+/)){const e=t.trim();if(!e)continue;if(e===i&&!/^\$[\w:]/.test(e)&&!/^[&.]\s/.test(e))continue;let s,n=e;for(;s=n.match($);)n=n.slice(s[0].length);n=n.replace(/^[&.]\s+/,"");const o=n.split(/\s+/)[0]??"",a=o.replace(/^['"]|['"]$/g,""),m=a+n.slice(o.length);if("remove-item"===S(a))for(const e of n.split(/\s+/).slice(1))if(!p.has(e[0]??"")&&R(e))return w(e);const{matchingDenyRules:l}=matchingRulesForInput({command:m},r,"prefix");if(void 0!==l[0])return{behavior:"deny",message:`Permission to use ${q} with command ${i} has been denied.`,decisionReason:{type:"rule",rule:l[0]}}}if(null!==O)return O;const t={type:"other",reason:`Command contains malformed syntax that cannot be parsed: ${c.errors[0]?.message??"unknown error"}`};return{behavior:"ask",decisionReason:t,message:n(q,t)}}const z=await async function(e,t){if(!e.valid)return[{text:t,element:{name:await extractCommandName(t),nameType:"unknown",elementType:"CommandAst",args:[],text:t},statement:null,isSafeOutput:!1}];const s=[];for(const t of e.statements){for(const e of t.commands)"CommandAst"===e.elementType&&s.push({text:e.text,element:e,statement:t,isSafeOutput:"application"!==e.nameType&&P(e.name)&&0===e.args.length});if(t.nestedCommands)for(const e of t.nestedCommands)s.push({text:e.text,element:e,statement:t,isSafeOutput:"application"!==e.nameType&&P(e.name)&&0===e.args.length})}return s.length>0?s:[{text:t,element:{name:await extractCommandName(t),nameType:"unknown",elementType:"CommandAst",args:[],text:t},statement:null,isSafeOutput:!1}]}(c,i),L=[];null!==O&&L.push(O);const N=k(i,c);if("passthrough"!==N.behavior){const e={type:"other",reason:"ask"===N.behavior&&N.message?N.message:"This command contains patterns that could pose security risks and requires approval"};L.push({behavior:"ask",message:n(q,e),decisionReason:e,suggestions:suggestionForExactCommand(i)})}if(c.hasUsingStatements){const e={type:"other",reason:"Command contains a `using` statement that may load external code (module or assembly)"};L.push({behavior:"ask",message:n(q,e),decisionReason:e,suggestions:suggestionForExactCommand(i)})}if(c.hasScriptRequirements){const e={type:"other",reason:"Command contains a `#Requires` directive that may trigger module loading"};L.push({behavior:"ask",message:n(q,e),decisionReason:e,suggestions:suggestionForExactCommand(i)})}const U=/^(?:[\w.]+\\)?(env|hklm|hkcu|function|alias|variable|cert|wsman|registry)::?/i;function providerOrUncDecisionForArg(e){const t=function(e){let t=e;if(t.length>0&&p.has(t[0])){const e=t.indexOf(":",1);e>0&&(t=t.substring(e+1))}return t.replace(/`/g,"")}(e);return U.test(t)?{behavior:"ask",message:`Command argument '${e}' uses a non-filesystem provider path and requires approval`}:f(t)?{behavior:"ask",message:`Command argument '${e}' contains a UNC path that could trigger network requests`}:null}e:for(const e of c.statements){for(const t of e.commands)if("CommandAst"===t.elementType)for(const e of t.args){const t=providerOrUncDecisionForArg(e);if(null!==t){L.push(t);break e}}if(e.nestedCommands)for(const t of e.nestedCommands)for(const e of t.args){const t=providerOrUncDecisionForArg(e);if(null!==t){L.push(t);break e}}}for(const{text:e,element:t}of z){const s=""!==t.name?[t.name,...t.args].join(" "):null,o={command:e},{matchingDenyRules:a,matchingAskRules:m}=matchingRulesForInput(o,r,"prefix");let l=a[0],c=m[0];if(void 0===l&&null!==s){const{matchingDenyRules:e,matchingAskRules:t}=matchingRulesForInput({command:s},r,"prefix");l=e[0],void 0===c&&(c=t[0])}void 0!==l?L.push({behavior:"deny",message:`Permission to use ${q} with command ${i} has been denied.`,decisionReason:{type:"rule",rule:l}}):void 0!==c&&L.push({behavior:"ask",message:n(q),decisionReason:{type:"rule",rule:c}})}const B=z.length>1&&z.some(({element:e})=>E(e.name)),H=z.length>1&&z.some(({element:e})=>b(e)),V=z.some(({element:e})=>"git"===S(e.name));if(B&&V&&L.push({behavior:"ask",message:"Compound commands with cd/Set-Location and git require approval to prevent bare repository attacks"}),V&&s()&&L.push({behavior:"ask",message:"Git command in a directory with bare-repository indicators (HEAD, objects/, refs/ in cwd without .git/HEAD). Git may execute hooks from cwd."}),V){const e=z.some(({element:e,statement:t})=>{for(const t of e.redirections??[])if(v(t.target))return!0;const s=S(e.name);if(!j.has(s))return!1;if(e.args.flatMap(e=>e.split(",")).some(e=>v(e)))return!0;if(null!==t)for(const e of t.commands)if("CommandAst"!==e.elementType&&v(e.text))return!0;return!1}),t=u(c).some(e=>v(e.target));(e||t)&&L.push({behavior:"ask",message:"Command writes to a git-internal path (HEAD, objects/, refs/, hooks/, .git/) and runs git. This could plant a malicious hook that git then executes."});z.some(({element:e})=>I.has(e.name.toLowerCase()))&&L.push({behavior:"ask",message:"Compound command extracts an archive and runs git. Archive contents may plant bare-repository indicators (HEAD, hooks/, refs/) that git then treats as the repository root."})}(z.some(({element:e})=>{for(const t of e.redirections??[])if(g(t.target))return!0;const t=S(e.name);return!!j.has(t)&&e.args.flatMap(e=>e.split(",")).some(g)})||u(c).some(e=>g(e.target)))&&L.push({behavior:"ask",message:"Command writes to .git/ — hooks or config planted there execute on the next git operation."});const W=x(o,c,r,B);"passthrough"!==W.behavior&&L.push(W),"allow"===d.behavior&&void 0!==z[0]&&z.every(e=>"application"!==e.element.nameType&&!C(e.text,e.element))&&L.push(d),T(i,c)&&L.push({behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"Command is read-only and safe to execute"}});u(c).length>0&&L.push({behavior:"ask",message:"Command contains file redirections that could write to arbitrary paths",suggestions:suggestionForExactCommand(i)});const G=y(o,c,r);"passthrough"!==G.behavior&&L.push(G);const J=L.find(e=>"deny"===e.behavior);if(void 0!==J)return J;const K=L.find(e=>"ask"===e.behavior);if(void 0!==K)return K;const Q=L.find(e=>"allow"===e.behavior);if(void 0!==Q)return Q;const X=z.filter(({element:s,isSafeOutput:n})=>{if(n)return!1;if("application"===s.nameType)return!0;if("set-location"===S(s.name)&&s.args.length>0){const n=s.args.find(e=>0===e.length||!p.has(e[0]));if(n&&e(t(),n)===t())return!1}return!0}),Y=[],Z=new Set;for(const{text:e,element:t,statement:s}of X){const n=powershellToolCheckPermission({command:e},r);if("deny"===n.behavior)return{behavior:"deny",message:`Permission to use ${q} with command ${i} has been denied.`,decisionReason:n.decisionReason};if("ask"!==n.behavior){if("allow"!==n.behavior||"application"===t.nameType||H)if("allow"!==n.behavior){if(null===s||B||H||!F(s)||!A(t,e)){if(null!==s&&!B&&!H){if("allow"===y({command:e},{valid:!0,errors:[],variables:c.variables,hasStopParsing:c.hasStopParsing,originalCommand:e,statements:[s]},r).behavior)continue}null!==s&&Z.add(s),Y.push(e)}}else null!==s&&Z.add(s),Y.push(e);else if(C(e,t)){null!==s&&Z.add(s),Y.push(e);continue}}else null!==s&&Z.add(s),Y.push(e)}for(const e of c.statements)F(e)||Z.has(e)||Y.push(e.text);if(0===Y.length)return l(c).hasScriptBlocks?{behavior:"ask",message:n(q),decisionReason:{type:"other",reason:"Pipeline consists of output-formatting cmdlets with script blocks — block content cannot be verified"}}:{behavior:"allow",updatedInput:o,decisionReason:{type:"other",reason:"All pipeline commands are individually allowed"}};const _={type:"other",reason:"This command requires approval"},ee=[];for(const e of Y)ee.push(...suggestionForExactCommand(e));return{behavior:"passthrough",message:n(q,_),decisionReason:_,suggestions:ee}}
@@ -1 +1 @@
1
- import{DANGEROUS_SCRIPT_BLOCK_CMDLETS as e,FILEPATH_EXECUTION_CMDLETS as s,MODULE_LOADING_CMDLETS as a}from"../../utils/powershell/dangerousCmdlets.js";import{COMMON_ALIASES as t,commandHasArgAbbreviation as o,deriveSecurityFlags as r,getAllCommands as n,getVariablesByScope as i,hasCommandNamed as c}from"../../utils/powershell/parser.js";import{isClmAllowedType as h}from"./clmTypes.js";const m=new Set(["pwsh","pwsh.exe","powershell","powershell.exe"]);function isPowerShellExecutable(e){const s=e.toLowerCase();if(m.has(s))return!0;const a=Math.max(s.lastIndexOf("/"),s.lastIndexOf("\\"));return a>=0&&m.has(s.slice(a+1))}const u=new Set(["/","–","—","―"]);function psExeHasParamAbbreviation(e,s,a){if(o(e,s,a))return!0;const t={...e,args:e.args.map(e=>e.length>0&&u.has(e[0])?"-"+e.slice(1):e)};return o(t,s,a)}function checkInvokeExpression(e){return c(e,"Invoke-Expression")?{behavior:"ask",message:"Command uses Invoke-Expression which can execute arbitrary code"}:{behavior:"passthrough"}}function checkDynamicCommandName(e){for(const s of n(e)){if("CommandAst"!==s.elementType)continue;const e=s.elementTypes?.[0];if(void 0!==e&&"StringConstant"!==e)return{behavior:"ask",message:"Command name is a dynamic expression which cannot be statically validated"}}return{behavior:"passthrough"}}function checkEncodedCommand(e){for(const s of n(e))if(isPowerShellExecutable(s.name)&&psExeHasParamAbbreviation(s,"-encodedcommand","-e"))return{behavior:"ask",message:"Command uses encoded parameters which obscure intent"};return{behavior:"passthrough"}}function checkPwshCommandOrFile(e){for(const s of n(e))if(isPowerShellExecutable(s.name))return{behavior:"ask",message:"Command spawns a nested PowerShell process which cannot be validated"};return{behavior:"passthrough"}}const l=new Set(["invoke-webrequest","iwr","invoke-restmethod","irm","new-object","start-bitstransfer"]);function isDownloader(e){return l.has(e.toLowerCase())}function isIex(e){const s=e.toLowerCase();return"invoke-expression"===s||"iex"===s}function checkDownloadCradles(e){for(const s of e.statements){const e=s.commands;if(e.length<2)continue;const a=e.some(e=>isDownloader(e.name)),t=e.some(e=>isIex(e.name));if(a&&t)return{behavior:"ask",message:"Command downloads and executes remote code"}}const s=n(e);return s.some(e=>isDownloader(e.name))&&s.some(e=>isIex(e.name))?{behavior:"ask",message:"Command downloads and executes remote code"}:{behavior:"passthrough"}}function checkDownloadUtilities(e){for(const s of n(e)){const e=s.name.toLowerCase();if("start-bitstransfer"===e)return{behavior:"ask",message:"Command downloads files via BITS transfer"};if(("certutil"===e||"certutil.exe"===e)&&s.args.some(e=>{const s=e.toLowerCase();return"-urlcache"===s||"/urlcache"===s}))return{behavior:"ask",message:"Command uses certutil to download from a URL"};if(("bitsadmin"===e||"bitsadmin.exe"===e)&&s.args.some(e=>"/transfer"===e.toLowerCase()))return{behavior:"ask",message:"Command downloads files via BITS transfer"}}return{behavior:"passthrough"}}function checkAddType(e){return c(e,"Add-Type")?{behavior:"ask",message:"Command compiles and loads .NET code"}:{behavior:"passthrough"}}function checkComObject(e){for(const s of n(e)){if("new-object"!==s.name.toLowerCase())continue;if(psExeHasParamAbbreviation(s,"-comobject","-com"))return{behavior:"ask",message:"Command instantiates a COM object which may have execution capabilities"};let e;for(let a=0;a<s.args.length;a++){const t=s.args[a],o=t.toLowerCase();if(o.startsWith("-t")&&o.includes(":")){const s=t.indexOf(":"),a=o.slice(0,s);if("-typename".startsWith(a)){e=t.slice(s+1);break}}if(o.startsWith("-t")&&"-typename".startsWith(o)&&void 0!==s.args[a+1]){e=s.args[a+1];break}}if(void 0===e){const a=new Set(["-argumentlist","-comobject","-property"]),t=new Set(["-strict"]);for(let o=0;o<s.args.length;o++){const r=s.args[o];if(r.startsWith("-")){const e=r.toLowerCase();if(e.startsWith("-t")&&"-typename".startsWith(e)){o++;continue}if(e.includes(":"))continue;if(t.has(e))continue;if(a.has(e)){o++;continue}continue}e=r;break}}if(void 0!==e&&!h(e))return{behavior:"ask",message:`New-Object instantiates .NET type '${e}' outside the ConstrainedLanguage allowlist`}}return{behavior:"passthrough"}}function checkDangerousFilePathExecution(e){for(const a of n(e)){const e=a.name.toLowerCase(),o=t[e]?.toLowerCase()??e;if(s.has(o)){if(psExeHasParamAbbreviation(a,"-filepath","-f")||psExeHasParamAbbreviation(a,"-literalpath","-l"))return{behavior:"ask",message:`${a.name} -FilePath executes an arbitrary script file`};for(let e=0;e<a.args.length;e++){const s=a.elementTypes?.[e+1],t=a.args[e];if("StringConstant"===s&&t&&!t.startsWith("-"))return{behavior:"ask",message:`${a.name} with positional string argument binds to -FilePath and executes a script file`}}}}return{behavior:"passthrough"}}function checkForEachMemberName(e){for(const s of n(e)){const e=s.name.toLowerCase();if("foreach-object"===(t[e]?.toLowerCase()??e)){if(psExeHasParamAbbreviation(s,"-membername","-m"))return{behavior:"ask",message:"ForEach-Object -MemberName invokes methods by string name which cannot be validated"};for(let e=0;e<s.args.length;e++){const a=s.elementTypes?.[e+1],t=s.args[e];if("StringConstant"===a&&t&&!t.startsWith("-"))return{behavior:"ask",message:"ForEach-Object with positional string argument binds to -MemberName and invokes methods by name"}}}}return{behavior:"passthrough"}}function checkStartProcess(e){for(const s of n(e)){const e=s.name.toLowerCase();if("start-process"===e||"saps"===e||"start"===e){if(psExeHasParamAbbreviation(s,"-Verb","-v")&&s.args.some(e=>"runas"===e.toLowerCase()))return{behavior:"ask",message:"Command requests elevated privileges"};if(s.children)for(let e=0;e<s.args.length;e++){const a=s.args[e].replace(/`/g,"");if(!/^[-\u2013\u2014\u2015/]v[a-z]*:/i.test(a))continue;const t=s.children[e];if(t)for(const e of t)if("runas"===e.text.replace(/['"`\s]/g,"").toLowerCase())return{behavior:"ask",message:"Command requests elevated privileges"}}if(s.args.some(e=>{const s=e.replace(/`/g,"");return/^[-\u2013\u2014\u2015/]v[a-z]*:['"` ]*runas['"` ]*$/i.test(s)}))return{behavior:"ask",message:"Command requests elevated privileges"};for(const e of s.args)if(isPowerShellExecutable(e.replace(/^['"]|['"]$/g,"")))return{behavior:"ask",message:"Start-Process launches a nested PowerShell process which cannot be validated"}}}return{behavior:"passthrough"}}const d=new Set(["where-object","sort-object","select-object","group-object","format-table","format-list","format-wide","format-custom"]);function checkScriptBlockInjection(s){if(!r(s).hasScriptBlocks)return{behavior:"passthrough"};for(const a of n(s)){const s=a.name.toLowerCase();if(e.has(s))return{behavior:"ask",message:"Command contains script block with dangerous cmdlet that may execute arbitrary code"}}return n(s).every(e=>{const s=e.name.toLowerCase();if(d.has(s))return!0;const a=t[s];return!(!a||!d.has(a.toLowerCase()))})?{behavior:"passthrough"}:{behavior:"ask",message:"Command contains script block that may execute arbitrary code"}}function checkSubExpressions(e){return r(e).hasSubExpressions?{behavior:"ask",message:"Command contains subexpressions $()"}:{behavior:"passthrough"}}function checkExpandableStrings(e){return r(e).hasExpandableStrings?{behavior:"ask",message:"Command contains expandable strings with embedded expressions"}:{behavior:"passthrough"}}function checkSplatting(e){return r(e).hasSplatting?{behavior:"ask",message:"Command uses splatting (@variable)"}:{behavior:"passthrough"}}function checkStopParsing(e){return r(e).hasStopParsing?{behavior:"ask",message:"Command uses stop-parsing token (--%)"}:{behavior:"passthrough"}}function checkMemberInvocations(e){return r(e).hasMemberInvocations?{behavior:"ask",message:"Command invokes .NET methods"}:{behavior:"passthrough"}}function checkTypeLiterals(e){for(const s of e.typeLiterals??[])if(!h(s))return{behavior:"ask",message:`Command uses .NET type [${s}] outside the ConstrainedLanguage allowlist`};return{behavior:"passthrough"}}function checkInvokeItem(e){for(const s of n(e)){const e=s.name.toLowerCase();if("invoke-item"===e||"ii"===e)return{behavior:"ask",message:"Invoke-Item opens files with the default handler (ShellExecute). On executable files this runs arbitrary code."}}return{behavior:"passthrough"}}const f=new Set(["register-scheduledtask","new-scheduledtask","new-scheduledtaskaction","set-scheduledtask"]);function checkScheduledTask(e){for(const s of n(e)){const e=s.name.toLowerCase();if(f.has(e))return{behavior:"ask",message:`${s.name} creates or modifies a scheduled task (persistence primitive)`};if(("schtasks"===e||"schtasks.exe"===e)&&s.args.some(e=>{const s=e.toLowerCase();return"/create"===s||"/change"===s||"-create"===s||"-change"===s}))return{behavior:"ask",message:"schtasks with create/change modifies scheduled tasks (persistence primitive)"}}return{behavior:"passthrough"}}const b=new Set(["set-item","si","new-item","ni","remove-item","ri","del","rm","rd","rmdir","erase","clear-item","cli","set-content","add-content","ac"]);function checkEnvVarManipulation(e){const s=i(e,"env");if(0===s.length)return{behavior:"passthrough"};for(const s of n(e))if(b.has(s.name.toLowerCase()))return{behavior:"ask",message:"Command modifies environment variables"};return r(e).hasAssignments&&s.length>0?{behavior:"ask",message:"Command modifies environment variables"}:{behavior:"passthrough"}}function checkModuleLoading(e){for(const s of n(e)){const e=s.name.toLowerCase();if(a.has(e))return{behavior:"ask",message:"Command loads, installs, or downloads a PowerShell module or script, which can execute arbitrary code"}}return{behavior:"passthrough"}}const g=new Set(["set-alias","sal","new-alias","nal","set-variable","sv","new-variable","nv"]);function checkRuntimeStateManipulation(e){for(const s of n(e)){const e=s.name.toLowerCase(),a=e.includes("\\")?e.slice(e.lastIndexOf("\\")+1):e;if(g.has(a))return{behavior:"ask",message:"Command creates or modifies an alias or variable that can affect future command resolution"}}return{behavior:"passthrough"}}const p=new Set(["invoke-wmimethod","iwmi","invoke-cimmethod"]);function checkWmiProcessSpawn(e){for(const s of n(e)){const e=s.name.toLowerCase();if(p.has(e))return{behavior:"ask",message:`${s.name} can spawn arbitrary processes via WMI/CIM (Win32_Process Create)`}}return{behavior:"passthrough"}}export function powershellCommandIsSafe(e,s){if(!s.valid)return{behavior:"ask",message:"Could not parse command for security analysis"};const a=[checkInvokeExpression,checkDynamicCommandName,checkEncodedCommand,checkPwshCommandOrFile,checkDownloadCradles,checkDownloadUtilities,checkAddType,checkComObject,checkDangerousFilePathExecution,checkInvokeItem,checkScheduledTask,checkForEachMemberName,checkStartProcess,checkScriptBlockInjection,checkSubExpressions,checkExpandableStrings,checkSplatting,checkStopParsing,checkMemberInvocations,checkTypeLiterals,checkEnvVarManipulation,checkModuleLoading,checkRuntimeStateManipulation,checkWmiProcessSpawn];for(const e of a){const a=e(s);if("ask"===a.behavior)return a}return{behavior:"passthrough"}}
1
+ import{DANGEROUS_SCRIPT_BLOCK_CMDLETS as e,FILEPATH_EXECUTION_CMDLETS as s,MODULE_LOADING_CMDLETS as a}from"../../utils/powershell/dangerousCmdlets.js";import{COMMON_ALIASES as t,commandHasArgAbbreviation as o,deriveSecurityFlags as r,getAllCommands as n,getVariablesByScope as i,hasCommandNamed as c}from"../../utils/powershell/parser.js";import{isClmAllowedType as h}from"./clmTypes.js";const m=new Set(["pwsh","pwsh.exe","powershell","powershell.exe"]);function isPowerShellExecutable(e){const s=e.toLowerCase();if(m.has(s))return!0;const a=Math.max(s.lastIndexOf("/"),s.lastIndexOf("\\"));return a>=0&&m.has(s.slice(a+1))}const u=new Set(["/","–","—","―"]);function psExeHasParamAbbreviation(e,s,a){if(o(e,s,a))return!0;const t={...e,args:e.args.map(e=>e.length>0&&u.has(e[0])?"-"+e.slice(1):e)};return o(t,s,a)}function checkInvokeExpression(e){return c(e,"Invoke-Expression")?{behavior:"ask",message:"Command uses Invoke-Expression which can execute arbitrary code"}:{behavior:"passthrough"}}function checkDynamicCommandName(e){for(const s of n(e)){if("CommandAst"!==s.elementType)continue;const e=s.elementTypes?.[0];if(void 0!==e&&"StringConstant"!==e)return{behavior:"ask",message:"Command name is a dynamic expression which cannot be statically validated"}}return{behavior:"passthrough"}}function checkEncodedCommand(e){for(const s of n(e))if(isPowerShellExecutable(s.name)&&psExeHasParamAbbreviation(s,"-encodedcommand","-e"))return{behavior:"ask",message:"Command uses encoded parameters which obscure intent"};return{behavior:"passthrough"}}function checkPwshCommandOrFile(e){for(const s of n(e))if(isPowerShellExecutable(s.name))return{behavior:"ask",message:"Command spawns a nested PowerShell process which cannot be validated"};return{behavior:"passthrough"}}const l=new Set(["invoke-webrequest","iwr","invoke-restmethod","irm","new-object","start-bitstransfer"]);function isDownloader(e){return l.has(e.toLowerCase())}function isIex(e){const s=e.toLowerCase();return"invoke-expression"===s||"iex"===s}function checkDownloadCradles(e){for(const s of e.statements){const e=s.commands;if(e.length<2)continue;const a=e.some(e=>isDownloader(e.name)),t=e.some(e=>isIex(e.name));if(a&&t)return{behavior:"ask",message:"Command downloads and executes remote code"}}const s=n(e);return s.some(e=>isDownloader(e.name))&&s.some(e=>isIex(e.name))?{behavior:"ask",message:"Command downloads and executes remote code"}:{behavior:"passthrough"}}function checkDownloadUtilities(e){for(const s of n(e)){const e=s.name.toLowerCase();if("start-bitstransfer"===e)return{behavior:"ask",message:"Command downloads files via BITS transfer"};if("certutil"===e||"certutil.exe"===e){if(s.args.some(e=>{const s=e.toLowerCase();return"-urlcache"===s||"/urlcache"===s}))return{behavior:"ask",message:"Command uses certutil to download from a URL"}}if(("bitsadmin"===e||"bitsadmin.exe"===e)&&s.args.some(e=>"/transfer"===e.toLowerCase()))return{behavior:"ask",message:"Command downloads files via BITS transfer"}}return{behavior:"passthrough"}}function checkAddType(e){return c(e,"Add-Type")?{behavior:"ask",message:"Command compiles and loads .NET code"}:{behavior:"passthrough"}}function checkComObject(e){for(const s of n(e)){if("new-object"!==s.name.toLowerCase())continue;if(psExeHasParamAbbreviation(s,"-comobject","-com"))return{behavior:"ask",message:"Command instantiates a COM object which may have execution capabilities"};let e;for(let a=0;a<s.args.length;a++){const t=s.args[a],o=t.toLowerCase();if(o.startsWith("-t")&&o.includes(":")){const s=t.indexOf(":"),a=o.slice(0,s);if("-typename".startsWith(a)){e=t.slice(s+1);break}}if(o.startsWith("-t")&&"-typename".startsWith(o)&&void 0!==s.args[a+1]){e=s.args[a+1];break}}if(void 0===e){const a=new Set(["-argumentlist","-comobject","-property"]),t=new Set(["-strict"]);for(let o=0;o<s.args.length;o++){const r=s.args[o];if(r.startsWith("-")){const e=r.toLowerCase();if(e.startsWith("-t")&&"-typename".startsWith(e)){o++;continue}if(e.includes(":"))continue;if(t.has(e))continue;if(a.has(e)){o++;continue}continue}e=r;break}}if(void 0!==e&&!h(e))return{behavior:"ask",message:`New-Object instantiates .NET type '${e}' outside the ConstrainedLanguage allowlist`}}return{behavior:"passthrough"}}function checkDangerousFilePathExecution(e){for(const a of n(e)){const e=a.name.toLowerCase(),o=t[e]?.toLowerCase()??e;if(s.has(o)){if(psExeHasParamAbbreviation(a,"-filepath","-f")||psExeHasParamAbbreviation(a,"-literalpath","-l"))return{behavior:"ask",message:`${a.name} -FilePath executes an arbitrary script file`};for(let e=0;e<a.args.length;e++){const s=a.elementTypes?.[e+1],t=a.args[e];if("StringConstant"===s&&t&&!t.startsWith("-"))return{behavior:"ask",message:`${a.name} with positional string argument binds to -FilePath and executes a script file`}}}}return{behavior:"passthrough"}}function checkForEachMemberName(e){for(const s of n(e)){const e=s.name.toLowerCase();if("foreach-object"===(t[e]?.toLowerCase()??e)){if(psExeHasParamAbbreviation(s,"-membername","-m"))return{behavior:"ask",message:"ForEach-Object -MemberName invokes methods by string name which cannot be validated"};for(let e=0;e<s.args.length;e++){const a=s.elementTypes?.[e+1],t=s.args[e];if("StringConstant"===a&&t&&!t.startsWith("-"))return{behavior:"ask",message:"ForEach-Object with positional string argument binds to -MemberName and invokes methods by name"}}}}return{behavior:"passthrough"}}function checkStartProcess(e){for(const s of n(e)){const e=s.name.toLowerCase();if("start-process"===e||"saps"===e||"start"===e){if(psExeHasParamAbbreviation(s,"-Verb","-v")&&s.args.some(e=>"runas"===e.toLowerCase()))return{behavior:"ask",message:"Command requests elevated privileges"};if(s.children)for(let e=0;e<s.args.length;e++){const a=s.args[e].replace(/`/g,"");if(!/^[-\u2013\u2014\u2015/]v[a-z]*:/i.test(a))continue;const t=s.children[e];if(t)for(const e of t)if("runas"===e.text.replace(/['"`\s]/g,"").toLowerCase())return{behavior:"ask",message:"Command requests elevated privileges"}}if(s.args.some(e=>{const s=e.replace(/`/g,"");return/^[-\u2013\u2014\u2015/]v[a-z]*:['"` ]*runas['"` ]*$/i.test(s)}))return{behavior:"ask",message:"Command requests elevated privileges"};for(const e of s.args){if(isPowerShellExecutable(e.replace(/^['"]|['"]$/g,"")))return{behavior:"ask",message:"Start-Process launches a nested PowerShell process which cannot be validated"}}}}return{behavior:"passthrough"}}const d=new Set(["where-object","sort-object","select-object","group-object","format-table","format-list","format-wide","format-custom"]);function checkScriptBlockInjection(s){if(!r(s).hasScriptBlocks)return{behavior:"passthrough"};for(const a of n(s)){const s=a.name.toLowerCase();if(e.has(s))return{behavior:"ask",message:"Command contains script block with dangerous cmdlet that may execute arbitrary code"}}return n(s).every(e=>{const s=e.name.toLowerCase();if(d.has(s))return!0;const a=t[s];return!(!a||!d.has(a.toLowerCase()))})?{behavior:"passthrough"}:{behavior:"ask",message:"Command contains script block that may execute arbitrary code"}}function checkSubExpressions(e){return r(e).hasSubExpressions?{behavior:"ask",message:"Command contains subexpressions $()"}:{behavior:"passthrough"}}function checkExpandableStrings(e){return r(e).hasExpandableStrings?{behavior:"ask",message:"Command contains expandable strings with embedded expressions"}:{behavior:"passthrough"}}function checkSplatting(e){return r(e).hasSplatting?{behavior:"ask",message:"Command uses splatting (@variable)"}:{behavior:"passthrough"}}function checkStopParsing(e){return r(e).hasStopParsing?{behavior:"ask",message:"Command uses stop-parsing token (--%)"}:{behavior:"passthrough"}}function checkMemberInvocations(e){return r(e).hasMemberInvocations?{behavior:"ask",message:"Command invokes .NET methods"}:{behavior:"passthrough"}}function checkTypeLiterals(e){for(const s of e.typeLiterals??[])if(!h(s))return{behavior:"ask",message:`Command uses .NET type [${s}] outside the ConstrainedLanguage allowlist`};return{behavior:"passthrough"}}function checkInvokeItem(e){for(const s of n(e)){const e=s.name.toLowerCase();if("invoke-item"===e||"ii"===e)return{behavior:"ask",message:"Invoke-Item opens files with the default handler (ShellExecute). On executable files this runs arbitrary code."}}return{behavior:"passthrough"}}const f=new Set(["register-scheduledtask","new-scheduledtask","new-scheduledtaskaction","set-scheduledtask"]);function checkScheduledTask(e){for(const s of n(e)){const e=s.name.toLowerCase();if(f.has(e))return{behavior:"ask",message:`${s.name} creates or modifies a scheduled task (persistence primitive)`};if(("schtasks"===e||"schtasks.exe"===e)&&s.args.some(e=>{const s=e.toLowerCase();return"/create"===s||"/change"===s||"-create"===s||"-change"===s}))return{behavior:"ask",message:"schtasks with create/change modifies scheduled tasks (persistence primitive)"}}return{behavior:"passthrough"}}const b=new Set(["set-item","si","new-item","ni","remove-item","ri","del","rm","rd","rmdir","erase","clear-item","cli","set-content","add-content","ac"]);function checkEnvVarManipulation(e){const s=i(e,"env");if(0===s.length)return{behavior:"passthrough"};for(const s of n(e))if(b.has(s.name.toLowerCase()))return{behavior:"ask",message:"Command modifies environment variables"};return r(e).hasAssignments&&s.length>0?{behavior:"ask",message:"Command modifies environment variables"}:{behavior:"passthrough"}}function checkModuleLoading(e){for(const s of n(e)){const e=s.name.toLowerCase();if(a.has(e))return{behavior:"ask",message:"Command loads, installs, or downloads a PowerShell module or script, which can execute arbitrary code"}}return{behavior:"passthrough"}}const g=new Set(["set-alias","sal","new-alias","nal","set-variable","sv","new-variable","nv"]);function checkRuntimeStateManipulation(e){for(const s of n(e)){const e=s.name.toLowerCase(),a=e.includes("\\")?e.slice(e.lastIndexOf("\\")+1):e;if(g.has(a))return{behavior:"ask",message:"Command creates or modifies an alias or variable that can affect future command resolution"}}return{behavior:"passthrough"}}const p=new Set(["invoke-wmimethod","iwmi","invoke-cimmethod"]);function checkWmiProcessSpawn(e){for(const s of n(e)){const e=s.name.toLowerCase();if(p.has(e))return{behavior:"ask",message:`${s.name} can spawn arbitrary processes via WMI/CIM (Win32_Process Create)`}}return{behavior:"passthrough"}}export function powershellCommandIsSafe(e,s){if(!s.valid)return{behavior:"ask",message:"Could not parse command for security analysis"};const a=[checkInvokeExpression,checkDynamicCommandName,checkEncodedCommand,checkPwshCommandOrFile,checkDownloadCradles,checkDownloadUtilities,checkAddType,checkComObject,checkDangerousFilePathExecution,checkInvokeItem,checkScheduledTask,checkForEachMemberName,checkStartProcess,checkScriptBlockInjection,checkSubExpressions,checkExpandableStrings,checkSplatting,checkStopParsing,checkMemberInvocations,checkTypeLiterals,checkEnvVarManipulation,checkModuleLoading,checkRuntimeStateManipulation,checkWmiProcessSpawn];for(const e of a){const a=e(s);if("ask"===a.behavior)return a}return{behavior:"passthrough"}}
@@ -1 +1 @@
1
- import{isEnvTruthy as e}from"../../utils/envUtils.js";import{getMaxOutputLength as t}from"../../utils/shell/outputLimits.js";import{getPowerShellEdition as n}from"../../utils/shell/powershellDetection.js";import{getDefaultBashTimeoutMs as o,getMaxBashTimeoutMs as i}from"../../utils/timeouts.js";import{FILE_EDIT_TOOL_NAME as a}from"../FileEditTool/constants.js";import{FILE_READ_TOOL_NAME as s}from"../FileReadTool/prompt.js";import{FILE_WRITE_TOOL_NAME as r}from"../FileWriteTool/prompt.js";import{GLOB_TOOL_NAME as l}from"../GlobTool/prompt.js";import{GREP_TOOL_NAME as c}from"../GrepTool/prompt.js";import{POWERSHELL_TOOL_NAME as d}from"./toolName.js";export function getDefaultTimeoutMs(){return o()}export function getMaxTimeoutMs(){return i()}export async function getPrompt(){const o=e(process.env.CONTEXT_CODE_DISABLE_BACKGROUND_TASKS)||e(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS)?null:" - You can use the `run_in_background` parameter to run the command in the background. Only use this if you don't need the result immediately and are OK being notified when the command completes later. You do not need to check the output right away - you'll be notified when it finishes.",i=e(process.env.CONTEXT_CODE_DISABLE_BACKGROUND_TASKS)||e(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS)?null:" - Avoid unnecessary `Start-Sleep` commands:\n - Do not sleep between commands that can run immediately — just run them.\n - If your command is long running and you would like to be notified when it finishes — simply run your command using `run_in_background`. There is no need to sleep in this case.\n - Do not retry failing commands in a sleep loop — diagnose the root cause or consider an alternative approach.\n - If waiting for a background task you started with `run_in_background`, you will be notified when it completes — do not poll.\n - If you must poll an external process, use a check command rather than sleeping first.\n - If you must sleep, keep the duration short (1-5 seconds) to avoid blocking the user.";return`Executes a given PowerShell command with optional timeout. Working directory persists between commands; shell state (variables, functions) does not.\n\nIMPORTANT: This tool is for terminal operations via PowerShell: git, npm, docker, and PS cmdlets. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.\n\n${function(e){return"desktop"===e?"PowerShell edition: Windows PowerShell 5.1 (powershell.exe)\n - Pipeline chain operators `&&` and `||` are NOT available — they cause a parser error. To run B only if A succeeds: `A; if ($?) { B }`. To chain unconditionally: `A; B`.\n - Ternary (`?:`), null-coalescing (`??`), and null-conditional (`?.`) operators are NOT available. Use `if/else` and explicit `$null -eq` checks instead.\n - Avoid `2>&1` on native executables. In 5.1, redirecting a native command's stderr inside PowerShell wraps each line in an ErrorRecord (NativeCommandError) and sets `$?` to `$false` even when the exe returned exit code 0. stderr is already captured for you — don't redirect it.\n - Default file encoding is UTF-16 LE (with BOM). When writing files other tools will read, pass `-Encoding utf8` to `Out-File`/`Set-Content`.\n - `ConvertFrom-Json` returns a PSCustomObject, not a hashtable. `-AsHashtable` is not available.":"core"===e?"PowerShell edition: PowerShell 7+ (pwsh)\n - Pipeline chain operators `&&` and `||` ARE available and work like bash. Prefer `cmd1 && cmd2` over `cmd1; cmd2` when cmd2 should only run if cmd1 succeeds.\n - Ternary (`$cond ? $a : $b`), null-coalescing (`??`), and null-conditional (`?.`) operators are available.\n - Default file encoding is UTF-8 without BOM.":"PowerShell edition: unknown — assume Windows PowerShell 5.1 for compatibility\n - Do NOT use `&&`, `||`, ternary `?:`, null-coalescing `??`, or null-conditional `?.`. These are PowerShell 7+ only and parser-error on 5.1.\n - To chain commands conditionally: `A; if ($?) { B }`. Unconditionally: `A; B`."}(await n())}\n\nBefore executing the command, please follow these steps:\n\n1. Directory Verification:\n - If the command will create new directories or files, first use \`Get-ChildItem\` (or \`ls\`) to verify the parent directory exists and is the correct location\n\n2. Command Execution:\n - Always quote file paths that contain spaces with double quotes\n - Capture the output of the command.\n\nPowerShell Syntax Notes:\n - Variables use $ prefix: $myVar = "value"\n - Escape character is backtick (\`), not backslash\n - Use Verb-Noun cmdlet naming: Get-ChildItem, Set-Location, New-Item, Remove-Item\n - Common aliases: ls (Get-ChildItem), cd (Set-Location), cat (Get-Content), rm (Remove-Item)\n - Pipe operator | works similarly to bash but passes objects, not text\n - Use Select-Object, Where-Object, ForEach-Object for filtering and transformation\n - String interpolation: "Hello $name" or "Hello $($obj.Property)"\n - Registry access uses PSDrive prefixes: \`HKLM:\\SOFTWARE\\...\`, \`HKCU:\\...\` — NOT raw \`HKEY_LOCAL_MACHINE\\...\`\n - Environment variables: read with \`$env:NAME\`, set with \`$env:NAME = "value"\` (NOT \`Set-Variable\` or bash \`export\`)\n - Call native exe with spaces in path via call operator: \`& "C:\\Program Files\\App\\app.exe" arg1 arg2\`\n\nInteractive and blocking commands (will hang — this tool runs with -NonInteractive):\n - NEVER use \`Read-Host\`, \`Get-Credential\`, \`Out-GridView\`, \`$Host.UI.PromptForChoice\`, or \`pause\`\n - Destructive cmdlets (\`Remove-Item\`, \`Stop-Process\`, \`Clear-Content\`, etc.) may prompt for confirmation. Add \`-Confirm:$false\` when you intend the action to proceed. Use \`-Force\` for read-only/hidden items.\n - Never use \`git rebase -i\`, \`git add -i\`, or other commands that open an interactive editor\n\nPassing multiline strings (commit messages, file content) to native executables:\n - Use a single-quoted here-string so PowerShell does not expand \`$\` or backticks inside. The closing \`'@\` MUST be at column 0 (no leading whitespace) on its own line — indenting it is a parse error:\n<example>\ngit commit -m @'\nCommit message here.\nSecond line with $literal dollar signs.\n'@\n</example>\n - Use \`@'...'@\` (single-quoted, literal) not \`@"..."@\` (double-quoted, interpolated) unless you need variable expansion\n - For arguments containing \`-\`, \`@\`, or other characters PowerShell parses as operators, use the stop-parsing token: \`git log --% --format=%H\`\n\nUsage notes:\n - The command argument is required.\n - You can specify an optional timeout in milliseconds (up to ${getMaxTimeoutMs()}ms / ${getMaxTimeoutMs()/6e4} minutes). If not specified, commands will timeout after ${getDefaultTimeoutMs()}ms (${getDefaultTimeoutMs()/6e4} minutes).\n - It is very helpful if you write a clear, concise description of what this command does.\n - If the output exceeds ${t()} characters, output will be truncated before being returned to you.\n${o?o+"\n":""} - Avoid using PowerShell to run commands that have dedicated tools, unless explicitly instructed:\n - File search: Use ${l} (NOT Get-ChildItem -Recurse)\n - Content search: Use ${c} (NOT Select-String)\n - Read files: Use ${s} (NOT Get-Content)\n - Edit files: Use ${a}\n - Write files: Use ${r} (NOT Set-Content/Out-File)\n - Communication: Output text directly (NOT Write-Output/Write-Host)\n - When issuing multiple commands:\n - If the commands are independent and can run in parallel, make multiple ${d} tool calls in a single message.\n - If the commands depend on each other and must run sequentially, chain them in a single ${d} call (see edition-specific chaining syntax above).\n - Use \`;\` only when you need to run commands sequentially but don't care if earlier commands fail.\n - DO NOT use newlines to separate commands (newlines are ok in quoted strings and here-strings)\n - Do NOT prefix commands with \`cd\` or \`Set-Location\` -- the working directory is already set to the correct project directory automatically.\n${i?i+"\n":""} - For git commands:\n - Prefer to create a new commit rather than amending an existing commit.\n - Before running destructive operations (e.g., git reset --hard, git push --force, git checkout --), consider whether there is a safer alternative that achieves the same goal. Only use destructive operations when they are truly the best approach.\n - Never skip hooks (--no-verify) or bypass signing (--no-gpg-sign, -c commit.gpgsign=false) unless the user has explicitly asked for it. If a hook fails, investigate and fix the underlying issue.`}
1
+ import{isEnvTruthy as e}from"../../utils/envUtils.js";import{getMaxOutputLength as t}from"../../utils/shell/outputLimits.js";import{getPowerShellEdition as n}from"../../utils/shell/powershellDetection.js";import{getDefaultBashTimeoutMs as o,getMaxBashTimeoutMs as i}from"../../utils/timeouts.js";import{FILE_EDIT_TOOL_NAME as a}from"../FileEditTool/constants.js";import{FILE_READ_TOOL_NAME as r}from"../FileReadTool/prompt.js";import{FILE_WRITE_TOOL_NAME as s}from"../FileWriteTool/prompt.js";import{GLOB_TOOL_NAME as l}from"../GlobTool/prompt.js";import{GREP_TOOL_NAME as c}from"../GrepTool/prompt.js";import{POWERSHELL_TOOL_NAME as d}from"./toolName.js";export function getDefaultTimeoutMs(){return o()}export function getMaxTimeoutMs(){return i()}export async function getPrompt(){const o=e(process.env.CONTEXT_CODE_DISABLE_BACKGROUND_TASKS)||e(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS)?null:" - You can use the `run_in_background` parameter to run the command in the background. Only use this if you don't need the result immediately and are OK being notified when the command completes later. You do not need to check the output right away - you'll be notified when it finishes.",i=e(process.env.CONTEXT_CODE_DISABLE_BACKGROUND_TASKS)||e(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS)?null:" - Avoid unnecessary `Start-Sleep` commands:\n - Do not sleep between commands that can run immediately — just run them.\n - If your command is long running and you would like to be notified when it finishes — simply run your command using `run_in_background`. There is no need to sleep in this case.\n - Do not retry failing commands in a sleep loop — diagnose the root cause or consider an alternative approach.\n - If waiting for a background task you started with `run_in_background`, you will be notified when it completes — do not poll.\n - If you must poll an external process, use a check command rather than sleeping first.\n - If you must sleep, keep the duration short (1-5 seconds) to avoid blocking the user.";return`Executes a given PowerShell command with optional timeout. Working directory persists between commands; shell state (variables, functions) does not.\n\nIMPORTANT: This tool is for terminal operations via PowerShell: git, npm, docker, and PS cmdlets. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.\n\n${function(e){return"desktop"===e?"PowerShell edition: Windows PowerShell 5.1 (powershell.exe)\n - Pipeline chain operators `&&` and `||` are NOT available — they cause a parser error. To run B only if A succeeds: `A; if ($?) { B }`. To chain unconditionally: `A; B`.\n - Ternary (`?:`), null-coalescing (`??`), and null-conditional (`?.`) operators are NOT available. Use `if/else` and explicit `$null -eq` checks instead.\n - Avoid `2>&1` on native executables. In 5.1, redirecting a native command's stderr inside PowerShell wraps each line in an ErrorRecord (NativeCommandError) and sets `$?` to `$false` even when the exe returned exit code 0. stderr is already captured for you — don't redirect it.\n - Default file encoding is UTF-16 LE (with BOM). When writing files other tools will read, pass `-Encoding utf8` to `Out-File`/`Set-Content`.\n - `ConvertFrom-Json` returns a PSCustomObject, not a hashtable. `-AsHashtable` is not available.":"core"===e?"PowerShell edition: PowerShell 7+ (pwsh)\n - Pipeline chain operators `&&` and `||` ARE available and work like bash. Prefer `cmd1 && cmd2` over `cmd1; cmd2` when cmd2 should only run if cmd1 succeeds.\n - Ternary (`$cond ? $a : $b`), null-coalescing (`??`), and null-conditional (`?.`) operators are available.\n - Default file encoding is UTF-8 without BOM.":"PowerShell edition: unknown — assume Windows PowerShell 5.1 for compatibility\n - Do NOT use `&&`, `||`, ternary `?:`, null-coalescing `??`, or null-conditional `?.`. These are PowerShell 7+ only and parser-error on 5.1.\n - To chain commands conditionally: `A; if ($?) { B }`. Unconditionally: `A; B`."}(await n())}\n\nBefore executing the command, please follow these steps:\n\n1. Directory Verification:\n - If the command will create new directories or files, first use \`Get-ChildItem\` (or \`ls\`) to verify the parent directory exists and is the correct location\n\n2. Command Execution:\n - Always quote file paths that contain spaces with double quotes\n - Capture the output of the command.\n\nPowerShell Syntax Notes:\n - Variables use $ prefix: $myVar = "value"\n - Escape character is backtick (\`), not backslash\n - Use Verb-Noun cmdlet naming: Get-ChildItem, Set-Location, New-Item, Remove-Item\n - Common aliases: ls (Get-ChildItem), cd (Set-Location), cat (Get-Content), rm (Remove-Item)\n - Pipe operator | works similarly to bash but passes objects, not text\n - Use Select-Object, Where-Object, ForEach-Object for filtering and transformation\n - String interpolation: "Hello $name" or "Hello $($obj.Property)"\n - Registry access uses PSDrive prefixes: \`HKLM:\\SOFTWARE\\...\`, \`HKCU:\\...\` — NOT raw \`HKEY_LOCAL_MACHINE\\...\`\n - Environment variables: read with \`$env:NAME\`, set with \`$env:NAME = "value"\` (NOT \`Set-Variable\` or bash \`export\`)\n - Call native exe with spaces in path via call operator: \`& "C:\\Program Files\\App\\app.exe" arg1 arg2\`\n\nInteractive and blocking commands (will hang — this tool runs with -NonInteractive):\n - NEVER use \`Read-Host\`, \`Get-Credential\`, \`Out-GridView\`, \`$Host.UI.PromptForChoice\`, or \`pause\`\n - Destructive cmdlets (\`Remove-Item\`, \`Stop-Process\`, \`Clear-Content\`, etc.) may prompt for confirmation. Add \`-Confirm:$false\` when you intend the action to proceed. Use \`-Force\` for read-only/hidden items.\n - Never use \`git rebase -i\`, \`git add -i\`, or other commands that open an interactive editor\n\nPassing multiline strings (commit messages, file content) to native executables:\n - Use a single-quoted here-string so PowerShell does not expand \`$\` or backticks inside. The closing \`'@\` MUST be at column 0 (no leading whitespace) on its own line — indenting it is a parse error:\n<example>\ngit commit -m @'\nCommit message here.\nSecond line with $literal dollar signs.\n'@\n</example>\n - Use \`@'...'@\` (single-quoted, literal) not \`@"..."@\` (double-quoted, interpolated) unless you need variable expansion\n - For arguments containing \`-\`, \`@\`, or other characters PowerShell parses as operators, use the stop-parsing token: \`git log --% --format=%H\`\n\nUsage notes:\n - The command argument is required.\n - You can specify an optional timeout in milliseconds (up to ${getMaxTimeoutMs()}ms / ${getMaxTimeoutMs()/6e4} minutes). If not specified, commands will timeout after ${getDefaultTimeoutMs()}ms (${getDefaultTimeoutMs()/6e4} minutes).\n - It is very helpful if you write a clear, concise description of what this command does.\n - If the output exceeds ${t()} characters, output will be truncated before being returned to you.\n${o?o+"\n":""} - Avoid using PowerShell to run commands that have dedicated tools, unless explicitly instructed:\n - File search: Use ${l} (NOT Get-ChildItem -Recurse)\n - Content search: Use ${c} (NOT Select-String)\n - Read files: Use ${r} (NOT Get-Content)\n - Edit files: Use ${a}\n - Write files: Use ${s} (NOT Set-Content/Out-File)\n - Communication: Output text directly (NOT Write-Output/Write-Host)\n - When issuing multiple commands:\n - If the commands are independent and can run in parallel, make multiple ${d} tool calls in a single message.\n - If the commands depend on each other and must run sequentially, chain them in a single ${d} call (see edition-specific chaining syntax above).\n - Use \`;\` only when you need to run commands sequentially but don't care if earlier commands fail.\n - DO NOT use newlines to separate commands (newlines are ok in quoted strings and here-strings)\n - Do NOT prefix commands with \`cd\` or \`Set-Location\` -- the working directory is already set to the correct project directory automatically.\n${i?i+"\n":""} - For git commands:\n - Prefer to create a new commit rather than amending an existing commit.\n - Before running destructive operations (e.g., git reset --hard, git push --force, git checkout --), consider whether there is a safer alternative that achieves the same goal. Only use destructive operations when they are truly the best approach.\n - Never skip hooks (--no-verify) or bypass signing (--no-gpg-sign, -c commit.gpgsign=false) unless the user has explicitly asked for it. If a hook fails, investigate and fix the underlying issue.`}
@@ -1 +1 @@
1
- import{getPlatform as e}from"../../utils/platform.js";import{COMMON_ALIASES as a,deriveSecurityFlags as t,getPipelineSegments as s,isNullRedirectionTarget as n,isPowerShellParameter as r}from"../../utils/powershell/parser.js";import{DOCKER_READ_ONLY_COMMANDS as l,EXTERNAL_READONLY_COMMANDS as o,GH_READ_ONLY_COMMANDS as i,GIT_READ_ONLY_COMMANDS as c,validateFlags as g}from"../../utils/shell/readOnlyCommandValidation.js";import{COMMON_PARAMETERS as u}from"./commonParameters.js";const f=new Set(["--version","--info","--list-runtimes","--list-sdks"]);export function argLeaksValue(e,a){const t=(a?.elementTypes??[]).slice(1),s=a?.args??[],n=a?.children;for(let e=0;e<t.length;e++){if("StringConstant"!==t[e]&&"Parameter"!==t[e]){if(!/[$(@{[]/.test(s[e]??""))continue;return!0}if("Parameter"===t[e]){const a=n?.[e];if(a){if(a.some(e=>"StringConstant"!==e.type))return!0}else{const a=s[e]??"",t=a.indexOf(":");if(t>0&&/[$(@{[]/.test(a.slice(t+1)))return!0}}}return!1}export const CMDLET_ALLOWLIST=Object.assign(Object.create(null),{"get-childitem":{safeFlags:["-Path","-LiteralPath","-Filter","-Include","-Exclude","-Recurse","-Depth","-Name","-Force","-Attributes","-Directory","-File","-Hidden","-ReadOnly","-System"]},"get-content":{safeFlags:["-Path","-LiteralPath","-TotalCount","-Head","-Tail","-Raw","-Encoding","-Delimiter","-ReadCount"]},"get-item":{safeFlags:["-Path","-LiteralPath","-Force","-Stream"]},"get-itemproperty":{safeFlags:["-Path","-LiteralPath","-Name"]},"test-path":{safeFlags:["-Path","-LiteralPath","-PathType","-Filter","-Include","-Exclude","-IsValid","-NewerThan","-OlderThan"]},"resolve-path":{safeFlags:["-Path","-LiteralPath","-Relative"]},"get-filehash":{safeFlags:["-Path","-LiteralPath","-Algorithm","-InputStream"]},"get-acl":{safeFlags:["-Path","-LiteralPath","-Audit","-Filter","-Include","-Exclude"]},"set-location":{safeFlags:["-Path","-LiteralPath","-PassThru","-StackName"]},"push-location":{safeFlags:["-Path","-LiteralPath","-PassThru","-StackName"]},"pop-location":{safeFlags:["-PassThru","-StackName"]},"select-string":{safeFlags:["-Path","-LiteralPath","-Pattern","-InputObject","-SimpleMatch","-CaseSensitive","-Quiet","-List","-NotMatch","-AllMatches","-Encoding","-Context","-Raw","-NoEmphasis"]},"convertto-json":{safeFlags:["-InputObject","-Depth","-Compress","-EnumsAsStrings","-AsArray"]},"convertfrom-json":{safeFlags:["-InputObject","-Depth","-AsHashtable","-NoEnumerate"]},"convertto-csv":{safeFlags:["-InputObject","-Delimiter","-NoTypeInformation","-NoHeader","-UseQuotes"]},"convertfrom-csv":{safeFlags:["-InputObject","-Delimiter","-Header","-UseCulture"]},"convertto-xml":{safeFlags:["-InputObject","-Depth","-As","-NoTypeInformation"]},"convertto-html":{safeFlags:["-InputObject","-Property","-Head","-Title","-Body","-Pre","-Post","-As","-Fragment"]},"format-hex":{safeFlags:["-Path","-LiteralPath","-InputObject","-Encoding","-Count","-Offset"]},"get-member":{safeFlags:["-InputObject","-MemberType","-Name","-Static","-View","-Force"]},"get-unique":{safeFlags:["-InputObject","-AsString","-CaseInsensitive","-OnType"]},"compare-object":{safeFlags:["-ReferenceObject","-DifferenceObject","-Property","-SyncWindow","-CaseSensitive","-Culture","-ExcludeDifferent","-IncludeEqual","-PassThru"]},"join-string":{safeFlags:["-InputObject","-Property","-Separator","-OutputPrefix","-OutputSuffix","-SingleQuote","-DoubleQuote","-FormatString"]},"get-random":{safeFlags:["-InputObject","-Minimum","-Maximum","-Count","-SetSeed","-Shuffle"]},"convert-path":{safeFlags:["-Path","-LiteralPath"]},"join-path":{safeFlags:["-Path","-ChildPath","-AdditionalChildPath"]},"split-path":{safeFlags:["-Path","-LiteralPath","-Qualifier","-NoQualifier","-Parent","-Leaf","-LeafBase","-Extension","-IsAbsolute"]},"get-hotfix":{safeFlags:["-Id","-Description"]},"get-itempropertyvalue":{safeFlags:["-Path","-LiteralPath","-Name"]},"get-psprovider":{safeFlags:["-PSProvider"]},"get-process":{safeFlags:["-Name","-Id","-Module","-FileVersionInfo","-IncludeUserName"]},"get-service":{safeFlags:["-Name","-DisplayName","-DependentServices","-RequiredServices","-Include","-Exclude"]},"get-computerinfo":{allowAllFlags:!0},"get-host":{allowAllFlags:!0},"get-date":{safeFlags:["-Date","-Format","-UFormat","-DisplayHint","-AsUTC"]},"get-location":{safeFlags:["-PSProvider","-PSDrive","-Stack","-StackName"]},"get-psdrive":{safeFlags:["-Name","-PSProvider","-Scope"]},"get-module":{safeFlags:["-Name","-ListAvailable","-All","-FullyQualifiedName","-PSEdition"]},"get-alias":{safeFlags:["-Name","-Definition","-Scope","-Exclude"]},"get-history":{safeFlags:["-Id","-Count"]},"get-culture":{allowAllFlags:!0},"get-uiculture":{allowAllFlags:!0},"get-timezone":{safeFlags:["-Name","-Id","-ListAvailable"]},"get-uptime":{allowAllFlags:!0},"write-output":{safeFlags:["-InputObject","-NoEnumerate"],additionalCommandIsDangerousCallback:argLeaksValue},"write-host":{safeFlags:["-Object","-NoNewline","-Separator","-ForegroundColor","-BackgroundColor"],additionalCommandIsDangerousCallback:argLeaksValue},"start-sleep":{safeFlags:["-Seconds","-Milliseconds","-Duration"],additionalCommandIsDangerousCallback:argLeaksValue},"format-table":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"format-list":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"format-wide":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"format-custom":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"measure-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"select-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"sort-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"group-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"where-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"out-string":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"out-host":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"get-netadapter":{safeFlags:["-Name","-InterfaceDescription","-InterfaceIndex","-Physical"]},"get-netipaddress":{safeFlags:["-InterfaceIndex","-InterfaceAlias","-AddressFamily","-Type"]},"get-netipconfiguration":{safeFlags:["-InterfaceIndex","-InterfaceAlias","-Detailed","-All"]},"get-netroute":{safeFlags:["-InterfaceIndex","-InterfaceAlias","-AddressFamily","-DestinationPrefix"]},"get-dnsclientcache":{safeFlags:["-Entry","-Name","-Type","-Status","-Section","-Data"]},"get-dnsclient":{safeFlags:["-InterfaceIndex","-InterfaceAlias"]},"get-eventlog":{safeFlags:["-LogName","-Newest","-After","-Before","-EntryType","-Index","-InstanceId","-Message","-Source","-UserName","-AsBaseObject","-List"]},"get-winevent":{safeFlags:["-LogName","-ListLog","-ListProvider","-ProviderName","-Path","-MaxEvents","-FilterXPath","-Force","-Oldest"]},"get-cimclass":{safeFlags:["-ClassName","-Namespace","-MethodName","-PropertyName","-QualifierName"]},git:{},gh:{},docker:{},ipconfig:{safeFlags:["/all","/displaydns","/allcompartments"],additionalCommandIsDangerousCallback:(e,a)=>(a?.args??[]).some(e=>!e.startsWith("/")&&!e.startsWith("-"))},netstat:{safeFlags:["-a","-b","-e","-f","-n","-o","-p","-q","-r","-s","-t","-x","-y"]},systeminfo:{safeFlags:["/FO","/NH"]},tasklist:{safeFlags:["/M","/SVC","/V","/FI","/FO","/NH"]},"where.exe":{allowAllFlags:!0},hostname:{safeFlags:["-a","-d","-f","-i","-I","-s","-y","-A"],additionalCommandIsDangerousCallback:(e,a)=>(a?.args??[]).some(e=>!e.startsWith("-"))},whoami:{safeFlags:["/user","/groups","/claims","/priv","/logonid","/all","/fo","/nh"]},ver:{allowAllFlags:!0},arp:{safeFlags:["-a","-g","-v","-N"]},route:{safeFlags:["print","PRINT","-4","-6"],additionalCommandIsDangerousCallback:(e,a)=>{if(!a)return!0;const t=a.args.find(e=>!e.startsWith("-"));return"print"!==t?.toLowerCase()}},getmac:{safeFlags:["/FO","/NH","/V"]},file:{safeFlags:["-b","--brief","-i","--mime","-L","--dereference","--mime-type","--mime-encoding","-z","--uncompress","-p","--preserve-date","-k","--keep-going","-r","--raw","-v","--version","-0","--print0","-s","--special-files","-l","-F","--separator","-e","-P","-N","--no-pad","-E","--extension"]},tree:{safeFlags:["/F","/A","/Q","/L"]},findstr:{safeFlags:["/B","/E","/L","/R","/S","/I","/X","/V","/N","/M","/O","/P","/C","/G","/D","/A"]},dotnet:{}});const m=new Set(["out-null"]),d=new Set(["format-table","format-list","format-wide","format-custom","measure-object","select-object","sort-object","group-object","where-object","out-string","out-host"]),p=new Set(["where.exe"]),h=/\.(exe|cmd|bat|com)$/;export function resolveToCanonical(e){let t=e.toLowerCase();t.includes("\\")||t.includes("/")||(t=t.replace(h,""));const s=a[t];return s?s.toLowerCase():t}export function isCwdChangingCmdlet(a){const t=resolveToCanonical(a);return"set-location"===t||"push-location"===t||"pop-location"===t||"new-psdrive"===t||"windows"===e()&&("ndr"===t||"mount"===t)}export function isSafeOutputCommand(e){const a=resolveToCanonical(e);return m.has(a)}export function isAllowlistedPipelineTail(e,a){const t=resolveToCanonical(e.name);return!!d.has(t)&&isAllowlistedCommand(e,a)}export function isProvablySafeStatement(e){if("PipelineAst"!==e.statementType)return!1;if(0===e.commands.length)return!1;for(const a of e.commands)if("CommandAst"!==a.elementType)return!1;return!0}export function hasSyncSecurityConcerns(e){const a=e.trim();return!!(a&&(/\$\(/.test(a)||/(?:^|[^\w.])@\w+/.test(a)||/\.\w+\s*\(/.test(a)||/\$\w+\s*[+\-*/]?=/.test(a)||/--%/.test(a)||/\\\\/.test(a)||/(?<!:)\/\//.test(a)||/::/.test(a)))}export function isReadOnlyCommand(e,a){if(!e.trim())return!1;if(!a)return!1;if(!a.valid)return!1;const r=t(a);if(r.hasScriptBlocks||r.hasSubExpressions||r.hasExpandableStrings||r.hasSplatting||r.hasMemberInvocations||r.hasAssignments||r.hasStopParsing)return!1;const l=s(a);if(0===l.length)return!1;if(l.reduce((e,a)=>e+a.commands.length,0)>1&&l.some(e=>e.commands.some(e=>isCwdChangingCmdlet(e.name))))return!1;for(const a of l){if(!a||0===a.commands.length)return!1;if(a.redirections.length>0&&a.redirections.some(e=>!e.isMerging&&!n(e.target)))return!1;const t=a.commands[0];if(!t)return!1;if(!isAllowlistedCommand(t,e))return!1;for(let t=1;t<a.commands.length;t++){const s=a.commands[t];if(!s||"application"===s.nameType)return!1;if(!(isSafeOutputCommand(s.name)&&0===s.args.length||isAllowlistedCommand(s,e)))return!1}if(a.nestedCommands&&a.nestedCommands.length>0)return!1}return!0}export function isAllowlistedCommand(e,a){if("application"===e.nameType){const a=e.text.split(/\s/,1)[0]?.toLowerCase()??"";if(!p.has(a))return!1}const t=function(e){const a=e.toLowerCase(),t=CMDLET_ALLOWLIST[a];if(t)return t;const s=resolveToCanonical(a);return s!==a?CMDLET_ALLOWLIST[s]:void 0}(e.name);if(!t)return!1;if(t.regex&&!t.regex.test(a))return!1;if(t.additionalCommandIsDangerousCallback?.(a,e))return!1;if(!e.elementTypes)return!1;for(let a=1;a<e.elementTypes.length;a++){const t=e.elementTypes[a];if("StringConstant"!==t&&"Parameter"!==t){if(!/[$(@{[]/.test(e.args[a-1]??""))continue;return!1}if("Parameter"===t){const t=e.children?.[a-1];if(t){if(t.some(e=>"StringConstant"!==e.type))return!1}else{const t=e.args[a-1]??"",s=t.indexOf(":");if(s>0&&/[$(@{[]/.test(t.slice(s+1)))return!1}}}const s=resolveToCanonical(e.name);if("git"===s||"gh"===s||"docker"===s||"dotnet"===s)return function(e,a){switch(e){case"git":return function(e){if(0===e.length)return!0;for(const a of e)if(a.includes("$"))return!1;let a=0;for(;a<e.length;){const t=e[a];if(!t||!t.startsWith("-"))break;for(const e of I)if(t.length>e.length&&t.startsWith(e)&&("-C"===e||"-"!==t[e.length]))return!1;const s=t.includes("="),n=s?t.split("=")[0]||"":t;if(C.has(n))return!1;!s&&F.has(n)?a+=2:a++}if(a>=e.length)return!0;const t=e[a]?.toLowerCase()||"",s=a+1<e.length&&e[a+1]?.toLowerCase()||"",n=`git ${t}`;let r=c[`git ${t} ${s}`],l=2;if(r||(r=c[n],l=1),!r)return!1;const o=e.slice(a+l);if("ls-remote"===t)for(const e of o)if(!e.startsWith("-")&&(e.includes("://")||e.includes("@")||e.includes(":")||e.includes("$")))return!1;return(!r.additionalCommandIsDangerousCallback||!r.additionalCommandIsDangerousCallback("",o))&&g(o,0,r,{commandName:"git"})}(a);case"gh":return function(e){if("ant"!==process.env.USER_TYPE)return!1;if(0===e.length)return!0;let a,t=0;if(e.length>=2){const s=`gh ${e[0]?.toLowerCase()} ${e[1]?.toLowerCase()}`;a=i[s],t=2}if(!a&&e.length>=1){const s=`gh ${e[0]?.toLowerCase()}`;a=i[s],t=1}if(!a)return!1;const s=e.slice(t);for(const e of s)if(e.includes("$"))return!1;return(!a.additionalCommandIsDangerousCallback||!a.additionalCommandIsDangerousCallback("",s))&&g(s,0,a)}(a);case"docker":return function(e){if(0===e.length)return!0;for(const a of e)if(a.includes("$"))return!1;const a=`docker ${e[0]?.toLowerCase()}`;if(o.includes(a))return!0;const t=l[a];if(!t)return!1;const s=e.slice(1);return(!t.additionalCommandIsDangerousCallback||!t.additionalCommandIsDangerousCallback("",s))&&g(s,0,t)}(a);case"dotnet":return function(e){if(0===e.length)return!1;for(const a of e)if(!f.has(a.toLowerCase()))return!1;return!0}(a);default:return!1}}(s,e.args);const n=s.includes("-");if(t.allowAllFlags)return!0;if(!t.safeFlags||0===t.safeFlags.length)return!e.args.some((a,t)=>n?r(a,e.elementTypes?.[t+1]):a.startsWith("-")||"win32"===process.platform&&a.startsWith("/"));for(let a=0;a<e.args.length;a++){const s=e.args[a];if(n?r(s,e.elementTypes?.[a+1]):s.startsWith("-")||"win32"===process.platform&&s.startsWith("/")){let e=n?"-"+s.slice(1):s;const a=e.indexOf(":");a>0&&(e=e.substring(0,a));const r=e.toLowerCase();if(n&&u.has(r))continue;if(!t.safeFlags.some(e=>e.toLowerCase()===r))return!1}}return!0}const C=new Set(["-c","-C","--exec-path","--config-env","--git-dir","--work-tree","--attr-source"]),F=new Set(["-c","-C","--exec-path","--config-env","--git-dir","--work-tree","--namespace","--super-prefix","--shallow-file"]),I=["-c","-C"];
1
+ import{getPlatform as e}from"../../utils/platform.js";import{COMMON_ALIASES as t,deriveSecurityFlags as a,getPipelineSegments as s,isNullRedirectionTarget as n,isPowerShellParameter as r}from"../../utils/powershell/parser.js";import{DOCKER_READ_ONLY_COMMANDS as l,EXTERNAL_READONLY_COMMANDS as o,GH_READ_ONLY_COMMANDS as i,GIT_READ_ONLY_COMMANDS as c,validateFlags as u}from"../../utils/shell/readOnlyCommandValidation.js";import{COMMON_PARAMETERS as g}from"./commonParameters.js";const f=new Set(["--version","--info","--list-runtimes","--list-sdks"]);export function argLeaksValue(e,t){const a=(t?.elementTypes??[]).slice(1),s=t?.args??[],n=t?.children;for(let e=0;e<a.length;e++){if("StringConstant"!==a[e]&&"Parameter"!==a[e]){if(!/[$(@{[]/.test(s[e]??""))continue;return!0}if("Parameter"===a[e]){const t=n?.[e];if(t){if(t.some(e=>"StringConstant"!==e.type))return!0}else{const t=s[e]??"",a=t.indexOf(":");if(a>0&&/[$(@{[]/.test(t.slice(a+1)))return!0}}}return!1}export const CMDLET_ALLOWLIST=Object.assign(Object.create(null),{"get-childitem":{safeFlags:["-Path","-LiteralPath","-Filter","-Include","-Exclude","-Recurse","-Depth","-Name","-Force","-Attributes","-Directory","-File","-Hidden","-ReadOnly","-System"]},"get-content":{safeFlags:["-Path","-LiteralPath","-TotalCount","-Head","-Tail","-Raw","-Encoding","-Delimiter","-ReadCount"]},"get-item":{safeFlags:["-Path","-LiteralPath","-Force","-Stream"]},"get-itemproperty":{safeFlags:["-Path","-LiteralPath","-Name"]},"test-path":{safeFlags:["-Path","-LiteralPath","-PathType","-Filter","-Include","-Exclude","-IsValid","-NewerThan","-OlderThan"]},"resolve-path":{safeFlags:["-Path","-LiteralPath","-Relative"]},"get-filehash":{safeFlags:["-Path","-LiteralPath","-Algorithm","-InputStream"]},"get-acl":{safeFlags:["-Path","-LiteralPath","-Audit","-Filter","-Include","-Exclude"]},"set-location":{safeFlags:["-Path","-LiteralPath","-PassThru","-StackName"]},"push-location":{safeFlags:["-Path","-LiteralPath","-PassThru","-StackName"]},"pop-location":{safeFlags:["-PassThru","-StackName"]},"select-string":{safeFlags:["-Path","-LiteralPath","-Pattern","-InputObject","-SimpleMatch","-CaseSensitive","-Quiet","-List","-NotMatch","-AllMatches","-Encoding","-Context","-Raw","-NoEmphasis"]},"convertto-json":{safeFlags:["-InputObject","-Depth","-Compress","-EnumsAsStrings","-AsArray"]},"convertfrom-json":{safeFlags:["-InputObject","-Depth","-AsHashtable","-NoEnumerate"]},"convertto-csv":{safeFlags:["-InputObject","-Delimiter","-NoTypeInformation","-NoHeader","-UseQuotes"]},"convertfrom-csv":{safeFlags:["-InputObject","-Delimiter","-Header","-UseCulture"]},"convertto-xml":{safeFlags:["-InputObject","-Depth","-As","-NoTypeInformation"]},"convertto-html":{safeFlags:["-InputObject","-Property","-Head","-Title","-Body","-Pre","-Post","-As","-Fragment"]},"format-hex":{safeFlags:["-Path","-LiteralPath","-InputObject","-Encoding","-Count","-Offset"]},"get-member":{safeFlags:["-InputObject","-MemberType","-Name","-Static","-View","-Force"]},"get-unique":{safeFlags:["-InputObject","-AsString","-CaseInsensitive","-OnType"]},"compare-object":{safeFlags:["-ReferenceObject","-DifferenceObject","-Property","-SyncWindow","-CaseSensitive","-Culture","-ExcludeDifferent","-IncludeEqual","-PassThru"]},"join-string":{safeFlags:["-InputObject","-Property","-Separator","-OutputPrefix","-OutputSuffix","-SingleQuote","-DoubleQuote","-FormatString"]},"get-random":{safeFlags:["-InputObject","-Minimum","-Maximum","-Count","-SetSeed","-Shuffle"]},"convert-path":{safeFlags:["-Path","-LiteralPath"]},"join-path":{safeFlags:["-Path","-ChildPath","-AdditionalChildPath"]},"split-path":{safeFlags:["-Path","-LiteralPath","-Qualifier","-NoQualifier","-Parent","-Leaf","-LeafBase","-Extension","-IsAbsolute"]},"get-hotfix":{safeFlags:["-Id","-Description"]},"get-itempropertyvalue":{safeFlags:["-Path","-LiteralPath","-Name"]},"get-psprovider":{safeFlags:["-PSProvider"]},"get-process":{safeFlags:["-Name","-Id","-Module","-FileVersionInfo","-IncludeUserName"]},"get-service":{safeFlags:["-Name","-DisplayName","-DependentServices","-RequiredServices","-Include","-Exclude"]},"get-computerinfo":{allowAllFlags:!0},"get-host":{allowAllFlags:!0},"get-date":{safeFlags:["-Date","-Format","-UFormat","-DisplayHint","-AsUTC"]},"get-location":{safeFlags:["-PSProvider","-PSDrive","-Stack","-StackName"]},"get-psdrive":{safeFlags:["-Name","-PSProvider","-Scope"]},"get-module":{safeFlags:["-Name","-ListAvailable","-All","-FullyQualifiedName","-PSEdition"]},"get-alias":{safeFlags:["-Name","-Definition","-Scope","-Exclude"]},"get-history":{safeFlags:["-Id","-Count"]},"get-culture":{allowAllFlags:!0},"get-uiculture":{allowAllFlags:!0},"get-timezone":{safeFlags:["-Name","-Id","-ListAvailable"]},"get-uptime":{allowAllFlags:!0},"write-output":{safeFlags:["-InputObject","-NoEnumerate"],additionalCommandIsDangerousCallback:argLeaksValue},"write-host":{safeFlags:["-Object","-NoNewline","-Separator","-ForegroundColor","-BackgroundColor"],additionalCommandIsDangerousCallback:argLeaksValue},"start-sleep":{safeFlags:["-Seconds","-Milliseconds","-Duration"],additionalCommandIsDangerousCallback:argLeaksValue},"format-table":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"format-list":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"format-wide":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"format-custom":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"measure-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"select-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"sort-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"group-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"where-object":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"out-string":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"out-host":{allowAllFlags:!0,additionalCommandIsDangerousCallback:argLeaksValue},"get-netadapter":{safeFlags:["-Name","-InterfaceDescription","-InterfaceIndex","-Physical"]},"get-netipaddress":{safeFlags:["-InterfaceIndex","-InterfaceAlias","-AddressFamily","-Type"]},"get-netipconfiguration":{safeFlags:["-InterfaceIndex","-InterfaceAlias","-Detailed","-All"]},"get-netroute":{safeFlags:["-InterfaceIndex","-InterfaceAlias","-AddressFamily","-DestinationPrefix"]},"get-dnsclientcache":{safeFlags:["-Entry","-Name","-Type","-Status","-Section","-Data"]},"get-dnsclient":{safeFlags:["-InterfaceIndex","-InterfaceAlias"]},"get-eventlog":{safeFlags:["-LogName","-Newest","-After","-Before","-EntryType","-Index","-InstanceId","-Message","-Source","-UserName","-AsBaseObject","-List"]},"get-winevent":{safeFlags:["-LogName","-ListLog","-ListProvider","-ProviderName","-Path","-MaxEvents","-FilterXPath","-Force","-Oldest"]},"get-cimclass":{safeFlags:["-ClassName","-Namespace","-MethodName","-PropertyName","-QualifierName"]},git:{},gh:{},docker:{},ipconfig:{safeFlags:["/all","/displaydns","/allcompartments"],additionalCommandIsDangerousCallback:(e,t)=>(t?.args??[]).some(e=>!e.startsWith("/")&&!e.startsWith("-"))},netstat:{safeFlags:["-a","-b","-e","-f","-n","-o","-p","-q","-r","-s","-t","-x","-y"]},systeminfo:{safeFlags:["/FO","/NH"]},tasklist:{safeFlags:["/M","/SVC","/V","/FI","/FO","/NH"]},"where.exe":{allowAllFlags:!0},hostname:{safeFlags:["-a","-d","-f","-i","-I","-s","-y","-A"],additionalCommandIsDangerousCallback:(e,t)=>(t?.args??[]).some(e=>!e.startsWith("-"))},whoami:{safeFlags:["/user","/groups","/claims","/priv","/logonid","/all","/fo","/nh"]},ver:{allowAllFlags:!0},arp:{safeFlags:["-a","-g","-v","-N"]},route:{safeFlags:["print","PRINT","-4","-6"],additionalCommandIsDangerousCallback:(e,t)=>{if(!t)return!0;const a=t.args.find(e=>!e.startsWith("-"));return"print"!==a?.toLowerCase()}},getmac:{safeFlags:["/FO","/NH","/V"]},file:{safeFlags:["-b","--brief","-i","--mime","-L","--dereference","--mime-type","--mime-encoding","-z","--uncompress","-p","--preserve-date","-k","--keep-going","-r","--raw","-v","--version","-0","--print0","-s","--special-files","-l","-F","--separator","-e","-P","-N","--no-pad","-E","--extension"]},tree:{safeFlags:["/F","/A","/Q","/L"]},findstr:{safeFlags:["/B","/E","/L","/R","/S","/I","/X","/V","/N","/M","/O","/P","/C","/G","/D","/A"]},dotnet:{}});const m=new Set(["out-null"]),d=new Set(["format-table","format-list","format-wide","format-custom","measure-object","select-object","sort-object","group-object","where-object","out-string","out-host"]),p=new Set(["where.exe"]),h=/\.(exe|cmd|bat|com)$/;export function resolveToCanonical(e){let a=e.toLowerCase();a.includes("\\")||a.includes("/")||(a=a.replace(h,""));const s=t[a];return s?s.toLowerCase():a}export function isCwdChangingCmdlet(t){const a=resolveToCanonical(t);return"set-location"===a||"push-location"===a||"pop-location"===a||"new-psdrive"===a||"windows"===e()&&("ndr"===a||"mount"===a)}export function isSafeOutputCommand(e){const t=resolveToCanonical(e);return m.has(t)}export function isAllowlistedPipelineTail(e,t){const a=resolveToCanonical(e.name);return!!d.has(a)&&isAllowlistedCommand(e,t)}export function isProvablySafeStatement(e){if("PipelineAst"!==e.statementType)return!1;if(0===e.commands.length)return!1;for(const t of e.commands)if("CommandAst"!==t.elementType)return!1;return!0}export function hasSyncSecurityConcerns(e){const t=e.trim();return!!t&&(!!/\$\(/.test(t)||(!!/(?:^|[^\w.])@\w+/.test(t)||(!!/\.\w+\s*\(/.test(t)||(!!/\$\w+\s*[+\-*/]?=/.test(t)||(!!/--%/.test(t)||(!(!/\\\\/.test(t)&&!/(?<!:)\/\//.test(t))||!!/::/.test(t)))))))}export function isReadOnlyCommand(e,t){if(!e.trim())return!1;if(!t)return!1;if(!t.valid)return!1;const r=a(t);if(r.hasScriptBlocks||r.hasSubExpressions||r.hasExpandableStrings||r.hasSplatting||r.hasMemberInvocations||r.hasAssignments||r.hasStopParsing)return!1;const l=s(t);if(0===l.length)return!1;if(l.reduce((e,t)=>e+t.commands.length,0)>1){if(l.some(e=>e.commands.some(e=>isCwdChangingCmdlet(e.name))))return!1}for(const t of l){if(!t||0===t.commands.length)return!1;if(t.redirections.length>0){if(t.redirections.some(e=>!e.isMerging&&!n(e.target)))return!1}const a=t.commands[0];if(!a)return!1;if(!isAllowlistedCommand(a,e))return!1;for(let a=1;a<t.commands.length;a++){const s=t.commands[a];if(!s||"application"===s.nameType)return!1;if((!isSafeOutputCommand(s.name)||0!==s.args.length)&&!isAllowlistedCommand(s,e))return!1}if(t.nestedCommands&&t.nestedCommands.length>0)return!1}return!0}export function isAllowlistedCommand(e,t){if("application"===e.nameType){const t=e.text.split(/\s/,1)[0]?.toLowerCase()??"";if(!p.has(t))return!1}const a=function(e){const t=e.toLowerCase(),a=CMDLET_ALLOWLIST[t];if(a)return a;const s=resolveToCanonical(t);return s!==t?CMDLET_ALLOWLIST[s]:void 0}(e.name);if(!a)return!1;if(a.regex&&!a.regex.test(t))return!1;if(a.additionalCommandIsDangerousCallback?.(t,e))return!1;if(!e.elementTypes)return!1;for(let t=1;t<e.elementTypes.length;t++){const a=e.elementTypes[t];if("StringConstant"!==a&&"Parameter"!==a){if(!/[$(@{[]/.test(e.args[t-1]??""))continue;return!1}if("Parameter"===a){const a=e.children?.[t-1];if(a){if(a.some(e=>"StringConstant"!==e.type))return!1}else{const a=e.args[t-1]??"",s=a.indexOf(":");if(s>0&&/[$(@{[]/.test(a.slice(s+1)))return!1}}}const s=resolveToCanonical(e.name);if("git"===s||"gh"===s||"docker"===s||"dotnet"===s)return function(e,t){switch(e){case"git":return function(e){if(0===e.length)return!0;for(const t of e)if(t.includes("$"))return!1;let t=0;for(;t<e.length;){const a=e[t];if(!a||!a.startsWith("-"))break;for(const e of I)if(a.length>e.length&&a.startsWith(e)&&("-C"===e||"-"!==a[e.length]))return!1;const s=a.includes("="),n=s?a.split("=")[0]||"":a;if(C.has(n))return!1;!s&&F.has(n)?t+=2:t++}if(t>=e.length)return!0;const a=e[t]?.toLowerCase()||"",s=t+1<e.length&&e[t+1]?.toLowerCase()||"",n=`git ${a}`;let r=c[`git ${a} ${s}`],l=2;r||(r=c[n],l=1);if(!r)return!1;const o=e.slice(t+l);if("ls-remote"===a)for(const e of o)if(!e.startsWith("-")&&(e.includes("://")||e.includes("@")||e.includes(":")||e.includes("$")))return!1;if(r.additionalCommandIsDangerousCallback&&r.additionalCommandIsDangerousCallback("",o))return!1;return u(o,0,r,{commandName:"git"})}(t);case"gh":return function(e){if("ant"!==process.env.USER_TYPE)return!1;if(0===e.length)return!0;let t,a=0;if(e.length>=2){const s=`gh ${e[0]?.toLowerCase()} ${e[1]?.toLowerCase()}`;t=i[s],a=2}if(!t&&e.length>=1){const s=`gh ${e[0]?.toLowerCase()}`;t=i[s],a=1}if(!t)return!1;const s=e.slice(a);for(const e of s)if(e.includes("$"))return!1;if(t.additionalCommandIsDangerousCallback&&t.additionalCommandIsDangerousCallback("",s))return!1;return u(s,0,t)}(t);case"docker":return function(e){if(0===e.length)return!0;for(const t of e)if(t.includes("$"))return!1;const t=`docker ${e[0]?.toLowerCase()}`;if(o.includes(t))return!0;const a=l[t];if(!a)return!1;const s=e.slice(1);if(a.additionalCommandIsDangerousCallback&&a.additionalCommandIsDangerousCallback("",s))return!1;return u(s,0,a)}(t);case"dotnet":return function(e){if(0===e.length)return!1;for(const t of e)if(!f.has(t.toLowerCase()))return!1;return!0}(t);default:return!1}}(s,e.args);const n=s.includes("-");if(a.allowAllFlags)return!0;if(!a.safeFlags||0===a.safeFlags.length){return!e.args.some((t,a)=>n?r(t,e.elementTypes?.[a+1]):t.startsWith("-")||"win32"===process.platform&&t.startsWith("/"))}for(let t=0;t<e.args.length;t++){const s=e.args[t];if(n?r(s,e.elementTypes?.[t+1]):s.startsWith("-")||"win32"===process.platform&&s.startsWith("/")){let e=n?"-"+s.slice(1):s;const t=e.indexOf(":");t>0&&(e=e.substring(0,t));const r=e.toLowerCase();if(n&&g.has(r))continue;if(!a.safeFlags.some(e=>e.toLowerCase()===r))return!1}}return!0}const C=new Set(["-c","-C","--exec-path","--config-env","--git-dir","--work-tree","--attr-source"]),F=new Set(["-c","-C","--exec-path","--config-env","--git-dir","--work-tree","--namespace","--super-prefix","--shallow-file"]),I=["-c","-C"];
@@ -1 +1 @@
1
- import{isEnvDefinedFalsy as o,isEnvTruthy as s}from"../../utils/envUtils.js";import{AGENT_TOOL_NAME as E}from"../AgentTool/constants.js";import{BASH_TOOL_NAME as t}from"../BashTool/toolName.js";import{FILE_EDIT_TOOL_NAME as r}from"../FileEditTool/constants.js";import{FILE_READ_TOOL_NAME as _}from"../FileReadTool/prompt.js";import{FILE_WRITE_TOOL_NAME as e}from"../FileWriteTool/prompt.js";import{GLOB_TOOL_NAME as O}from"../GlobTool/prompt.js";import{GREP_TOOL_NAME as T}from"../GrepTool/prompt.js";import{NOTEBOOK_EDIT_TOOL_NAME as p}from"../NotebookEditTool/constants.js";export const REPL_TOOL_NAME="REPL";export function isReplModeEnabled(){return!(o(process.env.CONTEXT_CODE_REPL)||o(process.env.CLAUDE_CODE_REPL)||!s(process.env.CONTEXT_REPL_MODE)&&!s(process.env.CLAUDE_REPL_MODE)&&("ant"!==process.env.USER_TYPE||"cli"!==process.env.CLAUDE_CODE_ENTRYPOINT))}export const REPL_ONLY_TOOLS=new Set([_,e,r,O,T,t,p,E]);
1
+ import{isEnvDefinedFalsy as o,isEnvTruthy as t}from"../../utils/envUtils.js";import{AGENT_TOOL_NAME as r}from"../AgentTool/constants.js";import{BASH_TOOL_NAME as s}from"../BashTool/toolName.js";import{FILE_EDIT_TOOL_NAME as e}from"../FileEditTool/constants.js";import{FILE_READ_TOOL_NAME as p}from"../FileReadTool/prompt.js";import{FILE_WRITE_TOOL_NAME as E}from"../FileWriteTool/prompt.js";import{GLOB_TOOL_NAME as m}from"../GlobTool/prompt.js";import{GREP_TOOL_NAME as n}from"../GrepTool/prompt.js";import{NOTEBOOK_EDIT_TOOL_NAME as i}from"../NotebookEditTool/constants.js";export const REPL_TOOL_NAME="REPL";export function isReplModeEnabled(){return!o(process.env.CONTEXT_CODE_REPL)&&!o(process.env.CLAUDE_CODE_REPL)&&(!(!t(process.env.CONTEXT_REPL_MODE)&&!t(process.env.CLAUDE_REPL_MODE))||"ant"===process.env.USER_TYPE&&"cli"===process.env.CLAUDE_CODE_ENTRYPOINT)}export const REPL_ONLY_TOOLS=new Set([p,E,e,m,n,s,i,r]);
@@ -1 +1 @@
1
- import{AgentTool as o}from"../AgentTool/AgentTool.js";import{BashTool as l}from"../BashTool/BashTool.js";import{FileEditTool as e}from"../FileEditTool/FileEditTool.js";import{FileReadTool as i}from"../FileReadTool/FileReadTool.js";import{FileWriteTool as t}from"../FileWriteTool/FileWriteTool.js";import{GlobTool as r}from"../GlobTool/GlobTool.js";import{GrepTool as T}from"../GrepTool/GrepTool.js";import{NotebookEditTool as s}from"../NotebookEditTool/NotebookEditTool.js";let m;export function getReplPrimitiveTools(){return m??=[i,t,e,r,T,l,s,o]}
1
+ import{AgentTool as o}from"../AgentTool/AgentTool.js";import{BashTool as l}from"../BashTool/BashTool.js";import{FileEditTool as i}from"../FileEditTool/FileEditTool.js";import{FileReadTool as r}from"../FileReadTool/FileReadTool.js";import{FileWriteTool as t}from"../FileWriteTool/FileWriteTool.js";import{GlobTool as e}from"../GlobTool/GlobTool.js";import{GrepTool as m}from"../GrepTool/GrepTool.js";import{NotebookEditTool as T}from"../NotebookEditTool/NotebookEditTool.js";let p;export function getReplPrimitiveTools(){return p??=[r,t,i,e,m,l,T,o]}
@@ -1 +1 @@
1
- import{ReadResourceResultSchema as e}from"@modelcontextprotocol/sdk/types.js";import{z as r}from"zod/v4";import{ensureConnectedClient as t}from"../../services/mcp/client.js";import{buildTool as o}from"../../Tool.js";import{lazySchema as s}from"../../utils/lazySchema.js";import{getBinaryBlobSavedMessage as i,persistBinaryContent as a}from"../../utils/mcpOutputStorage.js";import{jsonStringify as n}from"../../utils/slowOperations.js";import{isOutputLineTruncated as c}from"../../utils/terminal.js";import{DESCRIPTION as m,PROMPT as u}from"./prompt.js";import{renderToolResultMessage as p,renderToolUseMessage as l,userFacingName as d}from"./UI.js";export const inputSchema=s(()=>r.object({server:r.string().describe("The MCP server name"),uri:r.string().describe("The resource URI to read")}));export const outputSchema=s(()=>r.object({contents:r.array(r.object({uri:r.string().describe("Resource URI"),mimeType:r.string().optional().describe("MIME type of the content"),text:r.string().optional().describe("Text content of the resource"),blobSavedTo:r.string().optional().describe("Path where binary blob content was saved")}))}));export const ReadMcpResourceTool=o({isConcurrencySafe:()=>!0,isReadOnly:()=>!0,toAutoClassifierInput:e=>`${e.server} ${e.uri}`,shouldDefer:!0,name:"ReadMcpResourceTool",searchHint:"read a specific MCP resource by URI",maxResultSizeChars:1e5,description:async()=>m,prompt:async()=>u,get inputSchema(){return inputSchema()},get outputSchema(){return outputSchema()},async call(r,{options:{mcpClients:o}}){const{server:s,uri:n}=r,c=o.find(e=>e.name===s);if(!c)throw new Error(`Server "${s}" not found. Available servers: ${o.map(e=>e.name).join(", ")}`);if("connected"!==c.type)throw new Error(`Server "${s}" is not connected`);if(!c.capabilities?.resources)throw new Error(`Server "${s}" does not support resources`);const m=await t(c),u=await m.client.request({method:"resources/read",params:{uri:n}},e);return{data:{contents:await Promise.all(u.contents.map(async(e,r)=>{if("text"in e)return{uri:e.uri,mimeType:e.mimeType,text:e.text};if(!("blob"in e)||"string"!=typeof e.blob)return{uri:e.uri,mimeType:e.mimeType};const t=`mcp-resource-${Date.now()}-${r}-${Math.random().toString(36).slice(2,8)}`,o=await a(Buffer.from(e.blob,"base64"),e.mimeType,t);return"error"in o?{uri:e.uri,mimeType:e.mimeType,text:`Binary content could not be saved to disk: ${o.error}`}:{uri:e.uri,mimeType:e.mimeType,blobSavedTo:o.filepath,text:i(o.filepath,e.mimeType,o.size,`[Resource from ${s} at ${e.uri}] `)}}))}}},renderToolUseMessage:l,userFacingName:d,renderToolResultMessage:p,isResultTruncated:e=>c(n(e)),mapToolResultToToolResultBlockParam:(e,r)=>({tool_use_id:r,type:"tool_result",content:n(e)})});
1
+ import{ReadResourceResultSchema as e}from"@modelcontextprotocol/sdk/types.js";import{z as r}from"zod/v4";import{ensureConnectedClient as t}from"../../services/mcp/client.js";import{buildTool as o}from"../../Tool.js";import{lazySchema as i}from"../../utils/lazySchema.js";import{getBinaryBlobSavedMessage as s,persistBinaryContent as n}from"../../utils/mcpOutputStorage.js";import{jsonStringify as a}from"../../utils/slowOperations.js";import{isOutputLineTruncated as c}from"../../utils/terminal.js";import{DESCRIPTION as m,PROMPT as p}from"./prompt.js";import{renderToolResultMessage as u,renderToolUseMessage as l,userFacingName as d}from"./UI.js";export const inputSchema=i(()=>r.object({server:r.string().describe("The MCP server name"),uri:r.string().describe("The resource URI to read")}));export const outputSchema=i(()=>r.object({contents:r.array(r.object({uri:r.string().describe("Resource URI"),mimeType:r.string().optional().describe("MIME type of the content"),text:r.string().optional().describe("Text content of the resource"),blobSavedTo:r.string().optional().describe("Path where binary blob content was saved")}))}));export const ReadMcpResourceTool=o({isConcurrencySafe:()=>!0,isReadOnly:()=>!0,toAutoClassifierInput:e=>`${e.server} ${e.uri}`,shouldDefer:!0,name:"ReadMcpResourceTool",searchHint:"read a specific MCP resource by URI",maxResultSizeChars:1e5,description:async()=>m,prompt:async()=>p,get inputSchema(){return inputSchema()},get outputSchema(){return outputSchema()},async call(r,{options:{mcpClients:o}}){const{server:i,uri:a}=r,c=o.find(e=>e.name===i);if(!c)throw new Error(`Server "${i}" not found. Available servers: ${o.map(e=>e.name).join(", ")}`);if("connected"!==c.type)throw new Error(`Server "${i}" is not connected`);if(!c.capabilities?.resources)throw new Error(`Server "${i}" does not support resources`);const m=await t(c),p=await m.client.request({method:"resources/read",params:{uri:a}},e);return{data:{contents:await Promise.all(p.contents.map(async(e,r)=>{if("text"in e)return{uri:e.uri,mimeType:e.mimeType,text:e.text};if(!("blob"in e)||"string"!=typeof e.blob)return{uri:e.uri,mimeType:e.mimeType};const t=`mcp-resource-${Date.now()}-${r}-${Math.random().toString(36).slice(2,8)}`,o=await n(Buffer.from(e.blob,"base64"),e.mimeType,t);return"error"in o?{uri:e.uri,mimeType:e.mimeType,text:`Binary content could not be saved to disk: ${o.error}`}:{uri:e.uri,mimeType:e.mimeType,blobSavedTo:o.filepath,text:s(o.filepath,e.mimeType,o.size,`[Resource from ${i} at ${e.uri}] `)}}))}}},renderToolUseMessage:l,userFacingName:d,renderToolResultMessage:u,isResultTruncated:e=>c(a(e)),mapToolResultToToolResultBlockParam:(e,r)=>({tool_use_id:r,type:"tool_result",content:a(e)})});
@@ -1 +1 @@
1
- import{jsx as e}from"react/jsx-runtime";import{MessageResponse as r}from"../../components/MessageResponse.js";import{OutputLine as o}from"../../components/shell/OutputLine.js";import{Box as s,Text as n}from"../../ink.js";import{jsonStringify as t}from"../../utils/slowOperations.js";export function renderToolUseMessage(e){return e.uri&&e.server?`Read resource "${e.uri}" from server "${e.server}"`:null}export function userFacingName(){return"readMcpResource"}export function renderToolResultMessage(i,u,{verbose:c}){if(!i||!i.contents||0===i.contents.length)return e(s,{justifyContent:"space-between",overflowX:"hidden",width:"100%",children:e(r,{height:1,children:e(n,{dimColor:!0,children:"(No content)"})})});const a=t(i,null,2);return e(o,{content:a,verbose:c})}
1
+ import{jsx as e}from"react/jsx-runtime";import{MessageResponse as r}from"../../components/MessageResponse.js";import{OutputLine as o}from"../../components/shell/OutputLine.js";import{Box as n,Text as t}from"../../ink.js";import{jsonStringify as s}from"../../utils/slowOperations.js";export function renderToolUseMessage(e){return e.uri&&e.server?`Read resource "${e.uri}" from server "${e.server}"`:null}export function userFacingName(){return"readMcpResource"}export function renderToolResultMessage(i,u,{verbose:c}){if(!i||!i.contents||0===i.contents.length)return e(n,{justifyContent:"space-between",overflowX:"hidden",width:"100%",children:e(r,{height:1,children:e(t,{dimColor:!0,children:"(No content)"})})});const l=s(i,null,2);return e(o,{content:l,verbose:c})}
@@ -1 +1 @@
1
- import{feature as e}from"bun:bundle";import{getFeatureValue_CACHED_WITH_REFRESH as t}from"../../services/analytics/growthbook.js";import{DEFAULT_CRON_JITTER_CONFIG as n}from"../../utils/cronTasks.js";import{isEnvTruthy as o}from"../../utils/envUtils.js";const s=3e5;export const DEFAULT_MAX_AGE_DAYS=n.recurringMaxAgeMs/864e5;export function isKairosCronEnabled(){return!!e("AGENT_TRIGGERS")&&!o(process.env.CONTEXT_CODE_DISABLE_CRON)&&!o(process.env.CLAUDE_CODE_DISABLE_CRON)&&t("tengu_kairos_cron",!0,s)}export function isDurableCronEnabled(){return t("tengu_kairos_cron_durable",!0,s)}export const CRON_CREATE_TOOL_NAME="CronCreate";export const CRON_DELETE_TOOL_NAME="CronDelete";export const CRON_LIST_TOOL_NAME="CronList";export function buildCronCreateDescription(e){return e?"Schedule a prompt to run at a future time — either recurring on a cron schedule, or once at a specific time. Pass durable: true to persist to .claude/scheduled_tasks.json; otherwise session-only.":"Schedule a prompt to run at a future time within this Claude session — either recurring on a cron schedule, or once at a specific time."}export function buildCronCreatePrompt(e){return`Schedule a prompt to be enqueued at a future time. Use for both recurring schedules and one-shot reminders.\n\nUses standard 5-field cron in the user's local timezone: minute hour day-of-month month day-of-week. "0 9 * * *" means 9am local — no timezone conversion needed.\n\n## One-shot tasks (recurring: false)\n\nFor "remind me at X" or "at <time>, do Y" requests — fire once then auto-delete.\nPin minute/hour/day-of-month/month to specific values:\n "remind me at 2:30pm today to check the deploy" → cron: "30 14 <today_dom> <today_month> *", recurring: false\n "tomorrow morning, run the smoke test" → cron: "57 8 <tomorrow_dom> <tomorrow_month> *", recurring: false\n\n## Recurring jobs (recurring: true, the default)\n\nFor "every N minutes" / "every hour" / "weekdays at 9am" requests:\n "*/5 * * * *" (every 5 min), "0 * * * *" (hourly), "0 9 * * 1-5" (weekdays at 9am local)\n\n## Avoid the :00 and :30 minute marks when the task allows it\n\nEvery user who asks for "9am" gets \`0 9\`, and every user who asks for "hourly" gets \`0 *\` — which means requests from across the planet land on the API at the same instant. When the user's request is approximate, pick a minute that is NOT 0 or 30:\n "every morning around 9" → "57 8 * * *" or "3 9 * * *" (not "0 9 * * *")\n "hourly" → "7 * * * *" (not "0 * * * *")\n "in an hour or so, remind me to..." → pick whatever minute you land on, don't round\n\nOnly use minute 0 or 30 when the user names that exact time and clearly means it ("at 9:00 sharp", "at half past", coordinating with a meeting). When in doubt, nudge a few minutes early or late — the user will not notice, and the fleet will.\n\n${e?'## Durability\n\nBy default (durable: false) the job lives only in this Claude session — nothing is written to disk, and the job is gone when Claude exits. Pass durable: true to write to .claude/scheduled_tasks.json so the job survives restarts. Only use durable: true when the user explicitly asks for the task to persist ("keep doing this every day", "set this up permanently"). Most "remind me in 5 minutes" / "check back in an hour" requests should stay session-only.':"## Session-only\n\nJobs live only in this Claude session — nothing is written to disk, and the job is gone when Claude exits."}\n\n## Runtime behavior\n\nJobs only fire while the REPL is idle (not mid-query). ${e?"Durable jobs persist to .claude/scheduled_tasks.json and survive session restarts — on next launch they resume automatically. One-shot durable tasks that were missed while the REPL was closed are surfaced for catch-up. Session-only jobs die with the process. ":""}The scheduler adds a small deterministic jitter on top of whatever you pick: recurring tasks fire up to 10% of their period late (max 15 min); one-shot tasks landing on :00 or :30 fire up to 90 s early. Picking an off-minute is still the bigger lever.\n\nRecurring tasks auto-expire after ${DEFAULT_MAX_AGE_DAYS} days — they fire one final time, then are deleted. This bounds session lifetime. Tell the user about the ${DEFAULT_MAX_AGE_DAYS}-day limit when scheduling recurring jobs.\n\nReturns a job ID you can pass to CronDelete.`}export const CRON_DELETE_DESCRIPTION="Cancel a scheduled cron job by ID";export function buildCronDeletePrompt(e){return e?"Cancel a cron job previously scheduled with CronCreate. Removes it from .claude/scheduled_tasks.json (durable jobs) or the in-memory session store (session-only jobs).":"Cancel a cron job previously scheduled with CronCreate. Removes it from the in-memory session store."}export const CRON_LIST_DESCRIPTION="List scheduled cron jobs";export function buildCronListPrompt(e){return e?"List all cron jobs scheduled via CronCreate, both durable (.claude/scheduled_tasks.json) and session-only.":"List all cron jobs scheduled via CronCreate in this session."}
1
+ import{feature as e}from"../../recovery/bunBundleShim.js";import{getFeatureValue_CACHED_WITH_REFRESH as t}from"../../services/analytics/growthbook.js";import{DEFAULT_CRON_JITTER_CONFIG as n}from"../../utils/cronTasks.js";import{isEnvTruthy as o}from"../../utils/envUtils.js";const s=3e5;export const DEFAULT_MAX_AGE_DAYS=n.recurringMaxAgeMs/864e5;export function isKairosCronEnabled(){return!!e("AGENT_TRIGGERS")&&(!o(process.env.CONTEXT_CODE_DISABLE_CRON)&&!o(process.env.CLAUDE_CODE_DISABLE_CRON)&&t("tengu_kairos_cron",!0,s))}export function isDurableCronEnabled(){return t("tengu_kairos_cron_durable",!0,s)}export const CRON_CREATE_TOOL_NAME="CronCreate";export const CRON_DELETE_TOOL_NAME="CronDelete";export const CRON_LIST_TOOL_NAME="CronList";export function buildCronCreateDescription(e){return e?"Schedule a prompt to run at a future time — either recurring on a cron schedule, or once at a specific time. Pass durable: true to persist to .claude/scheduled_tasks.json; otherwise session-only.":"Schedule a prompt to run at a future time within this Claude session — either recurring on a cron schedule, or once at a specific time."}export function buildCronCreatePrompt(e){return`Schedule a prompt to be enqueued at a future time. Use for both recurring schedules and one-shot reminders.\n\nUses standard 5-field cron in the user's local timezone: minute hour day-of-month month day-of-week. "0 9 * * *" means 9am local — no timezone conversion needed.\n\n## One-shot tasks (recurring: false)\n\nFor "remind me at X" or "at <time>, do Y" requests — fire once then auto-delete.\nPin minute/hour/day-of-month/month to specific values:\n "remind me at 2:30pm today to check the deploy" → cron: "30 14 <today_dom> <today_month> *", recurring: false\n "tomorrow morning, run the smoke test" → cron: "57 8 <tomorrow_dom> <tomorrow_month> *", recurring: false\n\n## Recurring jobs (recurring: true, the default)\n\nFor "every N minutes" / "every hour" / "weekdays at 9am" requests:\n "*/5 * * * *" (every 5 min), "0 * * * *" (hourly), "0 9 * * 1-5" (weekdays at 9am local)\n\n## Avoid the :00 and :30 minute marks when the task allows it\n\nEvery user who asks for "9am" gets \`0 9\`, and every user who asks for "hourly" gets \`0 *\` — which means requests from across the planet land on the API at the same instant. When the user's request is approximate, pick a minute that is NOT 0 or 30:\n "every morning around 9" → "57 8 * * *" or "3 9 * * *" (not "0 9 * * *")\n "hourly" → "7 * * * *" (not "0 * * * *")\n "in an hour or so, remind me to..." → pick whatever minute you land on, don't round\n\nOnly use minute 0 or 30 when the user names that exact time and clearly means it ("at 9:00 sharp", "at half past", coordinating with a meeting). When in doubt, nudge a few minutes early or late — the user will not notice, and the fleet will.\n\n${e?'## Durability\n\nBy default (durable: false) the job lives only in this Claude session — nothing is written to disk, and the job is gone when Claude exits. Pass durable: true to write to .claude/scheduled_tasks.json so the job survives restarts. Only use durable: true when the user explicitly asks for the task to persist ("keep doing this every day", "set this up permanently"). Most "remind me in 5 minutes" / "check back in an hour" requests should stay session-only.':"## Session-only\n\nJobs live only in this Claude session — nothing is written to disk, and the job is gone when Claude exits."}\n\n## Runtime behavior\n\nJobs only fire while the REPL is idle (not mid-query). ${e?"Durable jobs persist to .claude/scheduled_tasks.json and survive session restarts — on next launch they resume automatically. One-shot durable tasks that were missed while the REPL was closed are surfaced for catch-up. Session-only jobs die with the process. ":""}The scheduler adds a small deterministic jitter on top of whatever you pick: recurring tasks fire up to 10% of their period late (max 15 min); one-shot tasks landing on :00 or :30 fire up to 90 s early. Picking an off-minute is still the bigger lever.\n\nRecurring tasks auto-expire after ${DEFAULT_MAX_AGE_DAYS} days — they fire one final time, then are deleted. This bounds session lifetime. Tell the user about the ${DEFAULT_MAX_AGE_DAYS}-day limit when scheduling recurring jobs.\n\nReturns a job ID you can pass to CronDelete.`}export const CRON_DELETE_DESCRIPTION="Cancel a scheduled cron job by ID";export function buildCronDeletePrompt(e){return e?"Cancel a cron job previously scheduled with CronCreate. Removes it from .claude/scheduled_tasks.json (durable jobs) or the in-memory session store (session-only jobs).":"Cancel a cron job previously scheduled with CronCreate. Removes it from the in-memory session store."}export const CRON_LIST_DESCRIPTION="List scheduled cron jobs";export function buildCronListPrompt(e){return e?"List all cron jobs scheduled via CronCreate, both durable (.claude/scheduled_tasks.json) and session-only.":"List all cron jobs scheduled via CronCreate in this session."}
@@ -1 +1 @@
1
- import{memoize as t}from"lodash-es";import{getCommandName as e,getSkillToolCommands as n,getSlashCommandToolSkills as o}from"src/commands.js";import{COMMAND_NAME_TAG as s}from"../../constants/xml.js";import{stringWidth as i}from"../../ink/stringWidth.js";import{logEvent as r}from"../../services/analytics/index.js";import{count as l}from"../../utils/array.js";import{logForDebugging as a}from"../../utils/debug.js";import{toError as m}from"../../utils/errors.js";import{truncate as c}from"../../utils/format.js";import{logError as u}from"../../utils/log.js";export const SKILL_BUDGET_CONTEXT_PERCENT=.01;export const CHARS_PER_TOKEN=4;export const DEFAULT_CHAR_BUDGET=8e3;export const MAX_LISTING_DESC_CHARS=250;export function getCharBudget(t){return Number(process.env.SLASH_COMMAND_TOOL_CHAR_BUDGET)?Number(process.env.SLASH_COMMAND_TOOL_CHAR_BUDGET):t?Math.floor(4*t*.01):8e3}function getCommandDescription(t){const e=t.whenToUse?`${t.description} - ${t.whenToUse}`:t.description;return e.length>250?e.slice(0,249)+"…":e}function formatCommandDescription(t){const n=e(t);return t.name!==n&&"prompt"===t.type&&"plugin"===t.source&&a(`Skill prompt: showing "${t.name}" (userFacingName="${n}")`),`- ${t.name}: ${getCommandDescription(t)}`}export function formatCommandsWithinBudget(t,e){if(0===t.length)return"";const n=getCharBudget(e),o=t.map(t=>({cmd:t,full:formatCommandDescription(t)})),s=o.reduce((t,e)=>t+i(e.full),0)+(o.length-1);if(s<=n)return o.map(t=>t.full).join("\n");const a=new Set,m=[];for(let e=0;e<t.length;e++){const n=t[e];"prompt"===n.type&&"bundled"===n.source?a.add(e):m.push(n)}const u=o.reduce((t,e,n)=>a.has(n)?t+i(e.full)+1:t,0),d=n-u;if(0===m.length)return o.map(t=>t.full).join("\n");const h=d-(m.reduce((t,e)=>t+i(e.name)+4,0)+(m.length-1)),g=Math.floor(h/m.length);if(g<20)return"ant"===process.env.USER_TYPE&&r("tengu_skill_descriptions_truncated",{skill_count:t.length,budget:n,full_total:s,truncation_mode:"names_only",max_desc_length:g,bundled_count:a.size,bundled_chars:u}),t.map((t,e)=>a.has(e)?o[e].full:`- ${t.name}`).join("\n");const p=l(m,t=>i(getCommandDescription(t))>g);return"ant"===process.env.USER_TYPE&&r("tengu_skill_descriptions_truncated",{skill_count:t.length,budget:n,full_total:s,truncation_mode:"description_trimmed",max_desc_length:g,truncated_count:p,bundled_count:a.size,bundled_chars:u}),t.map((t,e)=>{if(a.has(e))return o[e].full;const n=getCommandDescription(t);return`- ${t.name}: ${c(n,g)}`}).join("\n")}export const getPrompt=t(async t=>`Execute a skill within the main conversation\n\nWhen users ask you to perform tasks, check if any of the available skills match. Skills provide specialized capabilities and domain knowledge.\n\nWhen users reference a "slash command" or "/<something>" (e.g., "/commit", "/review-pr"), they are referring to a skill. Use this tool to invoke it.\n\nHow to invoke:\n- Use this tool with the skill name and optional arguments\n- Examples:\n - \`skill: "pdf"\` - invoke the pdf skill\n - \`skill: "commit", args: "-m 'Fix bug'"\` - invoke with arguments\n - \`skill: "review-pr", args: "123"\` - invoke with arguments\n - \`skill: "ms-office-suite:pdf"\` - invoke using fully qualified name\n\nImportant:\n- Available skills are listed in system-reminder messages in the conversation\n- When a skill matches the user's request, this is a BLOCKING REQUIREMENT: invoke the relevant Skill tool BEFORE generating any other response about the task\n- NEVER mention a skill without actually calling this tool\n- Do not invoke a skill that is already running\n- Do not use this tool for built-in CLI commands (like /help, /clear, etc.)\n- If you see a <${s}> tag in the current conversation turn, the skill has ALREADY been loaded - follow the instructions directly instead of calling this tool again\n`);export async function getSkillToolInfo(t){const e=await n(t);return{totalCommands:e.length,includedCommands:e.length}}export function getLimitedSkillToolCommands(t){return n(t)}export function clearPromptCache(){getPrompt.cache?.clear?.()}export async function getSkillInfo(t){try{const e=await o(t);return{totalSkills:e.length,includedSkills:e.length}}catch(t){return u(m(t)),{totalSkills:0,includedSkills:0}}}
1
+ import{memoize as t}from"lodash-es";import{getCommandName as e,getSkillToolCommands as n,getSlashCommandToolSkills as o}from"../../commands.js";import{COMMAND_NAME_TAG as i}from"../../constants/xml.js";import{stringWidth as s}from"../../ink/stringWidth.js";import{logEvent as r}from"../../services/analytics/index.js";import{count as l}from"../../utils/array.js";import{logForDebugging as a}from"../../utils/debug.js";import{toError as m}from"../../utils/errors.js";import{truncate as c}from"../../utils/format.js";import{logError as u}from"../../utils/log.js";export const SKILL_BUDGET_CONTEXT_PERCENT=.01;export const CHARS_PER_TOKEN=4;export const DEFAULT_CHAR_BUDGET=8e3;export const MAX_LISTING_DESC_CHARS=250;export function getCharBudget(t){return Number(process.env.SLASH_COMMAND_TOOL_CHAR_BUDGET)?Number(process.env.SLASH_COMMAND_TOOL_CHAR_BUDGET):t?Math.floor(4*t*.01):8e3}function getCommandDescription(t){const e=t.whenToUse?`${t.description} - ${t.whenToUse}`:t.description;return e.length>250?e.slice(0,249)+"…":e}function formatCommandDescription(t){const n=e(t);return t.name!==n&&"prompt"===t.type&&"plugin"===t.source&&a(`Skill prompt: showing "${t.name}" (userFacingName="${n}")`),`- ${t.name}: ${getCommandDescription(t)}`}export function formatCommandsWithinBudget(t,e){if(0===t.length)return"";const n=getCharBudget(e),o=t.map(t=>({cmd:t,full:formatCommandDescription(t)})),i=o.reduce((t,e)=>t+s(e.full),0)+(o.length-1);if(i<=n)return o.map(t=>t.full).join("\n");const a=new Set,m=[];for(let e=0;e<t.length;e++){const n=t[e];"prompt"===n.type&&"bundled"===n.source?a.add(e):m.push(n)}const u=o.reduce((t,e,n)=>a.has(n)?t+s(e.full)+1:t,0),d=n-u;if(0===m.length)return o.map(t=>t.full).join("\n");const h=d-(m.reduce((t,e)=>t+s(e.name)+4,0)+(m.length-1)),p=Math.floor(h/m.length);if(p<20)return"ant"===process.env.USER_TYPE&&r("tengu_skill_descriptions_truncated",{skill_count:t.length,budget:n,full_total:i,truncation_mode:"names_only",max_desc_length:p,bundled_count:a.size,bundled_chars:u}),t.map((t,e)=>a.has(e)?o[e].full:`- ${t.name}`).join("\n");const g=l(m,t=>s(getCommandDescription(t))>p);return"ant"===process.env.USER_TYPE&&r("tengu_skill_descriptions_truncated",{skill_count:t.length,budget:n,full_total:i,truncation_mode:"description_trimmed",max_desc_length:p,truncated_count:g,bundled_count:a.size,bundled_chars:u}),t.map((t,e)=>{if(a.has(e))return o[e].full;const n=getCommandDescription(t);return`- ${t.name}: ${c(n,p)}`}).join("\n")}export const getPrompt=t(async t=>`Execute a skill within the main conversation\n\nWhen users ask you to perform tasks, check if any of the available skills match. Skills provide specialized capabilities and domain knowledge.\n\nWhen users reference a "slash command" or "/<something>" (e.g., "/commit", "/review-pr"), they are referring to a skill. Use this tool to invoke it.\n\nHow to invoke:\n- Use this tool with the skill name and optional arguments\n- Examples:\n - \`skill: "pdf"\` - invoke the pdf skill\n - \`skill: "commit", args: "-m 'Fix bug'"\` - invoke with arguments\n - \`skill: "review-pr", args: "123"\` - invoke with arguments\n - \`skill: "ms-office-suite:pdf"\` - invoke using fully qualified name\n\nImportant:\n- Available skills are listed in system-reminder messages in the conversation\n- When a skill matches the user's request, this is a BLOCKING REQUIREMENT: invoke the relevant Skill tool BEFORE generating any other response about the task\n- NEVER mention a skill without actually calling this tool\n- Do not invoke a skill that is already running\n- Do not use this tool for built-in CLI commands (like /help, /clear, etc.)\n- If you see a <${i}> tag in the current conversation turn, the skill has ALREADY been loaded - follow the instructions directly instead of calling this tool again\n`);export async function getSkillToolInfo(t){const e=await n(t);return{totalCommands:e.length,includedCommands:e.length}}export function getLimitedSkillToolCommands(t){return n(t)}export function clearPromptCache(){getPrompt.cache?.clear?.()}export async function getSkillInfo(t){try{const e=await o(t);return{totalSkills:e.length,includedSkills:e.length}}catch(t){return u(m(t)),{totalSkills:0,includedSkills:0}}}
@@ -1 +1 @@
1
- import{feature as e}from"bun:bundle";import{z as t}from"zod/v4";import{getSessionId as o}from"../../bootstrap/state.js";import{getFeatureValue_CACHED_MAY_BE_STALE as s}from"../../services/analytics/growthbook.js";import{buildTool as a}from"../../Tool.js";import{lazySchema as i}from"../../utils/lazySchema.js";import{isTodoV2Enabled as r}from"../../utils/tasks.js";import{TodoListSchema as n}from"../../utils/todo/types.js";import{VERIFICATION_AGENT_TYPE as d}from"../AgentTool/constants.js";import{TODO_WRITE_TOOL_NAME as l}from"./constants.js";import{DESCRIPTION as u,PROMPT as c}from"./prompt.js";const m=i(()=>t.strictObject({todos:n().describe("The updated todo list")})),p=i(()=>t.object({oldTodos:n().describe("The todo list before the update"),newTodos:n().describe("The todo list after the update"),verificationNudgeNeeded:t.boolean().optional()}));export const TodoWriteTool=a({name:l,searchHint:"manage the session task checklist",maxResultSizeChars:1e5,strict:!0,description:async()=>u,prompt:async()=>c,get inputSchema(){return m()},get outputSchema(){return p()},userFacingName:()=>"",shouldDefer:!0,isEnabled:()=>!r(),toAutoClassifierInput:e=>`${e.todos.length} items`,checkPermissions:async e=>({behavior:"allow",updatedInput:e}),renderToolUseMessage:()=>null,async call({todos:t},a){const i=a.getAppState(),r=a.agentId??o(),n=i.todos[r]??[],d=t.every(e=>"completed"===e.status),l=d?[]:t;let u=!1;return e("VERIFICATION_AGENT")&&s("tengu_hive_evidence",!1)&&!a.agentId&&d&&t.length>=3&&!t.some(e=>/verif/i.test(e.content))&&(u=!0),a.setAppState(e=>({...e,todos:{...e.todos,[r]:l}})),{data:{oldTodos:n,newTodos:t,verificationNudgeNeeded:u}}},mapToolResultToToolResultBlockParam:({verificationNudgeNeeded:e},t)=>({tool_use_id:t,type:"tool_result",content:"Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable"+(e?`\n\nNOTE: You just closed out 3+ tasks and none of them was a verification step. Before writing your final summary, spawn the verification agent (subagent_type="${d}"). You cannot self-assign PARTIAL by listing caveats in your summary — only the verifier issues a verdict.`:"")})});
1
+ import{feature as e}from"../../recovery/bunBundleShim.js";import{z as t}from"zod/v4";import{getSessionId as o}from"../../bootstrap/state.js";import{getFeatureValue_CACHED_MAY_BE_STALE as s}from"../../services/analytics/growthbook.js";import{buildTool as i}from"../../Tool.js";import{lazySchema as r}from"../../utils/lazySchema.js";import{isTodoV2Enabled as a}from"../../utils/tasks.js";import{TodoListSchema as n}from"../../utils/todo/types.js";import{VERIFICATION_AGENT_TYPE as d}from"../AgentTool/constants.js";import{TODO_WRITE_TOOL_NAME as c}from"./constants.js";import{DESCRIPTION as l,PROMPT as u}from"./prompt.js";const m=r(()=>t.strictObject({todos:n().describe("The updated todo list")})),p=r(()=>t.object({oldTodos:n().describe("The todo list before the update"),newTodos:n().describe("The todo list after the update"),verificationNudgeNeeded:t.boolean().optional()}));export const TodoWriteTool=i({name:c,searchHint:"manage the session task checklist",maxResultSizeChars:1e5,strict:!0,description:async()=>l,prompt:async()=>u,get inputSchema(){return m()},get outputSchema(){return p()},userFacingName:()=>"",shouldDefer:!0,isEnabled:()=>!a(),toAutoClassifierInput:e=>`${e.todos.length} items`,checkPermissions:async e=>({behavior:"allow",updatedInput:e}),renderToolUseMessage:()=>null,async call({todos:t},i){const r=i.getAppState(),a=i.agentId??o(),n=r.todos[a]??[],d=t.every(e=>"completed"===e.status),c=d?[]:t;let l=!1;return e("VERIFICATION_AGENT")&&s("tengu_hive_evidence",!1)&&!i.agentId&&d&&t.length>=3&&!t.some(e=>/verif/i.test(e.content))&&(l=!0),i.setAppState(e=>({...e,todos:{...e.todos,[a]:c}})),{data:{oldTodos:n,newTodos:t,verificationNudgeNeeded:l}}},mapToolResultToToolResultBlockParam:({verificationNudgeNeeded:e},t)=>({tool_use_id:t,type:"tool_result",content:"Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable"+(e?`\n\nNOTE: You just closed out 3+ tasks and none of them was a verification step. Before writing your final summary, spawn the verification agent (subagent_type="${d}"). You cannot self-assign PARTIAL by listing caveats in your summary — only the verifier issues a verdict.`:"")})});
@@ -1 +1 @@
1
- import{createRequire as e}from"module";const t=e(import.meta.url);import{feature as o}from"bun:bundle";import{isReplBridgeActive as n}from"../../bootstrap/state.js";import{getFeatureValue_CACHED_MAY_BE_STALE as s}from"../../services/analytics/growthbook.js";import{AGENT_TOOL_NAME as a}from"../AgentTool/constants.js";const r=o("KAIROS")||o("KAIROS_BRIEF")?t("../BriefTool/prompt.js").BRIEF_TOOL_NAME:null,i=o("KAIROS")?t("../SendUserFileTool/prompt.js").SEND_USER_FILE_TOOL_NAME:null;export{TOOL_SEARCH_TOOL_NAME}from"./constants.js";import{TOOL_SEARCH_TOOL_NAME as l}from"./constants.js";export function isDeferredTool(e){return!0!==e.alwaysLoad&&(!0===e.isMcp||e.name!==l&&((!o("FORK_SUBAGENT")||e.name!==a||!t("../AgentTool/forkSubagent.js").isForkSubagentEnabled())&&!((o("KAIROS")||o("KAIROS_BRIEF"))&&r&&e.name===r||o("KAIROS")&&i&&e.name===i&&n()||!0!==e.shouldDefer)))}export function formatDeferredToolLine(e){return e.name}export function getPrompt(){return"Fetches full schema definitions for deferred tools so they can be called.\n\n"+("ant"===process.env.USER_TYPE||s("tengu_glacier_2xr",!1)?"Deferred tools appear by name in <system-reminder> messages.":"Deferred tools appear by name in <available-deferred-tools> messages.")+' Until fetched, only the name is known — there is no parameter schema, so the tool cannot be invoked. This tool takes a query, matches it against the deferred tool list, and returns the matched tools\' complete JSONSchema definitions inside a <functions> block. Once a tool\'s schema appears in that result, it is callable exactly like any tool defined at the top of the prompt.\n\nResult format: each matched tool appears as one <function>{"description": "...", "name": "...", "parameters": {...}}</function> line inside the <functions> block — the same encoding as the tool list at the top of this prompt.\n\nQuery forms:\n- "select:Read,Edit,Grep" — fetch these exact tools by name\n- "notebook jupyter" — keyword search, up to max_results best matches\n- "+slack send" — require "slack" in the name, rank by remaining terms'}
1
+ import{feature as e}from"../../recovery/bunBundleShim.js";import{createRequire as t}from"module";const o=t(import.meta.url);import{isReplBridgeActive as n}from"../../bootstrap/state.js";import{getFeatureValue_CACHED_MAY_BE_STALE as r}from"../../services/analytics/growthbook.js";import{AGENT_TOOL_NAME as s}from"../AgentTool/constants.js";const a=e("KAIROS")||e("KAIROS_BRIEF")?o("../BriefTool/prompt.js").BRIEF_TOOL_NAME:null,i=e("KAIROS")?o("../SendUserFileTool/prompt.js").SEND_USER_FILE_TOOL_NAME:null;export{TOOL_SEARCH_TOOL_NAME}from"./constants.js";import{TOOL_SEARCH_TOOL_NAME as l}from"./constants.js";export function isDeferredTool(t){if(!0===t.alwaysLoad)return!1;if(!0===t.isMcp)return!0;if(t.name===l)return!1;if(e("FORK_SUBAGENT")&&t.name===s){if(o("../AgentTool/forkSubagent.js").isForkSubagentEnabled())return!1}return(!e("KAIROS")&&!e("KAIROS_BRIEF")||!a||t.name!==a)&&(!(e("KAIROS")&&i&&t.name===i&&n())&&!0===t.shouldDefer)}export function formatDeferredToolLine(e){return e.name}export function getPrompt(){return"Fetches full schema definitions for deferred tools so they can be called.\n\n"+("ant"===process.env.USER_TYPE||r("tengu_glacier_2xr",!1)?"Deferred tools appear by name in <system-reminder> messages.":"Deferred tools appear by name in <available-deferred-tools> messages.")+' Until fetched, only the name is known — there is no parameter schema, so the tool cannot be invoked. This tool takes a query, matches it against the deferred tool list, and returns the matched tools\' complete JSONSchema definitions inside a <functions> block. Once a tool\'s schema appears in that result, it is callable exactly like any tool defined at the top of the prompt.\n\nResult format: each matched tool appears as one <function>{"description": "...", "name": "...", "parameters": {...}}</function> line inside the <functions> block — the same encoding as the tool list at the top of this prompt.\n\nQuery forms:\n- "select:Read,Edit,Grep" — fetch these exact tools by name\n- "notebook jupyter" — keyword search, up to max_results best matches\n- "+slack send" — require "slack" in the name, rank by remaining terms'}
@@ -1 +1 @@
1
- import{getLocalMonthYear as e}from"src/constants/common.js";export const WEB_SEARCH_TOOL_NAME="WebSearch";export function getWebSearchPrompt(){return`\n- Allows Claude to search the web and use the results to inform responses\n- Provides up-to-date information for current events and recent data\n- Returns search result information formatted as search result blocks, including links as markdown hyperlinks\n- Use this tool for accessing information beyond Claude's knowledge cutoff\n- Searches are performed automatically within a single API call\n\nCRITICAL REQUIREMENT - You MUST follow this:\n - After answering the user's question, you MUST include a "Sources:" section at the end of your response\n - In the Sources section, list all relevant URLs from the search results as markdown hyperlinks: [Title](URL)\n - This is MANDATORY - never skip including sources in your response\n - Example format:\n\n [Your answer here]\n\n Sources:\n - [Source Title 1](https://example.com/1)\n - [Source Title 2](https://example.com/2)\n\nUsage notes:\n - Domain filtering is supported to include or block specific websites\n - Web search is only available in the US\n\nIMPORTANT - Use the correct year in search queries:\n - The current month is ${e()}. You MUST use this year when searching for recent information, documentation, or current events.\n - Example: If the user asks for "latest React docs", search for "React documentation" with the current year, NOT last year\n`}
1
+ import{getLocalMonthYear as e}from"../../constants/common.js";export const WEB_SEARCH_TOOL_NAME="WebSearch";export function getWebSearchPrompt(){return`\n- Allows Claude to search the web and use the results to inform responses\n- Provides up-to-date information for current events and recent data\n- Returns search result information formatted as search result blocks, including links as markdown hyperlinks\n- Use this tool for accessing information beyond Claude's knowledge cutoff\n- Searches are performed automatically within a single API call\n\nCRITICAL REQUIREMENT - You MUST follow this:\n - After answering the user's question, you MUST include a "Sources:" section at the end of your response\n - In the Sources section, list all relevant URLs from the search results as markdown hyperlinks: [Title](URL)\n - This is MANDATORY - never skip including sources in your response\n - Example format:\n\n [Your answer here]\n\n Sources:\n - [Source Title 1](https://example.com/1)\n - [Source Title 2](https://example.com/2)\n\nUsage notes:\n - Domain filtering is supported to include or block specific websites\n - Web search is only available in the US\n\nIMPORTANT - Use the correct year in search queries:\n - The current month is ${e()}. You MUST use this year when searching for recent information, documentation, or current events.\n - Example: If the user asks for "latest React docs", search for "React documentation" with the current year, NOT last year\n`}