@iaforged/context-code 2.1.7 → 2.1.8

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 (408) hide show
  1. package/dist/src/Task.js +1 -1
  2. package/dist/src/constants/oauth.js +1 -1
  3. package/dist/src/context/mailbox.js +1 -1
  4. package/dist/src/context/voice.js +1 -1
  5. package/dist/src/hooks/useTerminalSize.js +1 -1
  6. package/dist/src/ink/Ansi.js +1 -1
  7. package/dist/src/ink/clearTerminal.js +1 -1
  8. package/dist/src/ink/colorize.js +1 -1
  9. package/dist/src/ink/components/App.js +1 -1
  10. package/dist/src/ink/components/Button.js +1 -1
  11. package/dist/src/ink/components/ClockContext.js +1 -1
  12. package/dist/src/ink/components/CursorDeclarationContext.js +1 -1
  13. package/dist/src/ink/components/Link.js +1 -1
  14. package/dist/src/ink/components/StdinContext.js +1 -1
  15. package/dist/src/ink/components/TerminalFocusContext.js +1 -1
  16. package/dist/src/ink/dom.js +1 -1
  17. package/dist/src/ink/events/keyboard-event.js +1 -1
  18. package/dist/src/ink/hit-test.js +1 -1
  19. package/dist/src/ink/hooks/use-animation-frame.js +1 -1
  20. package/dist/src/ink/hooks/use-app.js +1 -1
  21. package/dist/src/ink/hooks/use-input.js +1 -1
  22. package/dist/src/ink/hooks/use-interval.js +1 -1
  23. package/dist/src/ink/hooks/use-selection.js +1 -1
  24. package/dist/src/ink/hooks/use-tab-status.js +1 -1
  25. package/dist/src/ink/hooks/use-terminal-focus.js +1 -1
  26. package/dist/src/ink/hooks/use-terminal-title.js +1 -1
  27. package/dist/src/ink/hooks/use-terminal-viewport.js +1 -1
  28. package/dist/src/ink/ink.js +1 -1
  29. package/dist/src/ink/layout/yoga.js +1 -1
  30. package/dist/src/ink/line-width-cache.js +1 -1
  31. package/dist/src/ink/log-update.js +1 -1
  32. package/dist/src/ink/measure-text.js +1 -1
  33. package/dist/src/ink/output.js +1 -1
  34. package/dist/src/ink/parse-keypress.js +1 -1
  35. package/dist/src/ink/reconciler.js +1 -1
  36. package/dist/src/ink/render-border.js +1 -1
  37. package/dist/src/ink/render-node-to-output.js +1 -1
  38. package/dist/src/ink/render-to-screen.js +1 -1
  39. package/dist/src/ink/renderer.js +1 -1
  40. package/dist/src/ink/root.js +1 -1
  41. package/dist/src/ink/screen.js +1 -1
  42. package/dist/src/ink/searchHighlight.js +1 -1
  43. package/dist/src/ink/selection.js +1 -1
  44. package/dist/src/ink/squash-text-nodes.js +1 -1
  45. package/dist/src/ink/stringWidth.js +1 -1
  46. package/dist/src/ink/tabstops.js +1 -1
  47. package/dist/src/ink/terminal.js +1 -1
  48. package/dist/src/ink/termio/osc.js +1 -1
  49. package/dist/src/ink/termio/parser.js +1 -1
  50. package/dist/src/ink/termio/tokenize.js +1 -1
  51. package/dist/src/ink/useTerminalNotification.js +1 -1
  52. package/dist/src/ink/warn.js +1 -1
  53. package/dist/src/ink/widest-line.js +1 -1
  54. package/dist/src/ink/wrap-text.js +1 -1
  55. package/dist/src/ink/wrapAnsi.js +1 -1
  56. package/dist/src/native-ts/yoga-layout/index.js +1 -1
  57. package/dist/src/schemas/hooks.js +1 -1
  58. package/dist/src/services/SessionMemory/sessionMemoryUtils.js +1 -1
  59. package/dist/src/services/api/client.js +1 -1
  60. package/dist/src/services/api/dumpPrompts.js +1 -1
  61. package/dist/src/services/api/errorUtils.js +1 -1
  62. package/dist/src/services/api/promptCacheBreakDetection.js +1 -1
  63. package/dist/src/services/api/withRetry.js +1 -1
  64. package/dist/src/services/autoDream/consolidationLock.js +1 -1
  65. package/dist/src/services/mcp/elicitationHandler.js +1 -1
  66. package/dist/src/services/mcp/mcpStringUtils.js +1 -1
  67. package/dist/src/services/mcp/oauthPort.js +1 -1
  68. package/dist/src/services/mcp/vscodeSdkMcp.js +1 -1
  69. package/dist/src/services/oauth/client.js +1 -1
  70. package/dist/src/services/oauth/getOauthProfile.js +1 -1
  71. package/dist/src/services/objetivo/types.js +1 -1
  72. package/dist/src/services/rateLimitMocking.js +1 -1
  73. package/dist/src/services/remoteManagedSettings/syncCacheState.js +1 -1
  74. package/dist/src/skills/bundledSkills.js +1 -1
  75. package/dist/src/tasks/DreamTask/DreamTask.js +1 -1
  76. package/dist/src/tools/AgentTool/agentMemory.js +1 -1
  77. package/dist/src/tools/AgentTool/forkSubagent.js +1 -1
  78. package/dist/src/tools/BashTool/BashToolResultMessage.js +1 -1
  79. package/dist/src/tools/BashTool/UI.js +1 -1
  80. package/dist/src/tools/BashTool/sedEditParser.js +1 -1
  81. package/dist/src/tools/BashTool/utils.js +1 -1
  82. package/dist/src/tools/FileReadTool/imageProcessor.js +1 -1
  83. package/dist/src/tools/FileReadTool/prompt.js +1 -1
  84. package/dist/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.js +1 -1
  85. package/dist/src/tools/ListMcpResourcesTool/UI.js +1 -1
  86. package/dist/src/tools/MCPTool/MCPTool.js +1 -1
  87. package/dist/src/tools/MCPTool/UI.js +1 -1
  88. package/dist/src/tools/McpAuthTool/McpAuthTool.js +1 -1
  89. package/dist/src/tools/NotebookEditTool/prompt.js +1 -1
  90. package/dist/src/tools/PowerShellTool/PowerShellTool.js +1 -1
  91. package/dist/src/tools/PowerShellTool/UI.js +1 -1
  92. package/dist/src/tools/PowerShellTool/gitSafety.js +1 -1
  93. package/dist/src/tools/PowerShellTool/modeValidation.js +1 -1
  94. package/dist/src/tools/PowerShellTool/pathValidation.js +1 -1
  95. package/dist/src/tools/PowerShellTool/powershellPermissions.js +1 -1
  96. package/dist/src/tools/PowerShellTool/powershellSecurity.js +1 -1
  97. package/dist/src/tools/PowerShellTool/prompt.js +1 -1
  98. package/dist/src/tools/PowerShellTool/readOnlyValidation.js +1 -1
  99. package/dist/src/tools/REPLTool/constants.js +1 -1
  100. package/dist/src/tools/REPLTool/primitiveTools.js +1 -1
  101. package/dist/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.js +1 -1
  102. package/dist/src/tools/ReadMcpResourceTool/UI.js +1 -1
  103. package/dist/src/tools/ScheduleCronTool/prompt.js +1 -1
  104. package/dist/src/tools/SkillTool/prompt.js +1 -1
  105. package/dist/src/tools/TodoWriteTool/TodoWriteTool.js +1 -1
  106. package/dist/src/tools/ToolSearchTool/prompt.js +1 -1
  107. package/dist/src/tools/WebSearchTool/prompt.js +1 -1
  108. package/dist/src/tools/shared/gitOperationTracking.js +1 -1
  109. package/dist/src/types/permissions.js +1 -1
  110. package/dist/src/utils/Cursor.js +1 -1
  111. package/dist/src/utils/QueryGuard.js +1 -1
  112. package/dist/src/utils/Shell.js +1 -1
  113. package/dist/src/utils/ShellCommand.js +1 -1
  114. package/dist/src/utils/activityManager.js +1 -1
  115. package/dist/src/utils/advisor.js +1 -1
  116. package/dist/src/utils/appleTerminalBackup.js +1 -1
  117. package/dist/src/utils/argumentSubstitution.js +1 -1
  118. package/dist/src/utils/authFileDescriptor.js +1 -1
  119. package/dist/src/utils/autoUpdater.js +1 -1
  120. package/dist/src/utils/background/remote/preconditions.js +1 -1
  121. package/dist/src/utils/background/remote/remoteSession.js +1 -1
  122. package/dist/src/utils/bash/ShellSnapshot.js +1 -1
  123. package/dist/src/utils/bash/ast.js +1 -1
  124. package/dist/src/utils/bash/bashParser.js +1 -1
  125. package/dist/src/utils/bash/bashPipeCommand.js +1 -1
  126. package/dist/src/utils/bash/parser.js +1 -1
  127. package/dist/src/utils/bash/shellQuote.js +1 -1
  128. package/dist/src/utils/bash/shellQuoting.js +1 -1
  129. package/dist/src/utils/billing.js +1 -1
  130. package/dist/src/utils/caCerts.js +1 -1
  131. package/dist/src/utils/claudeInChrome/common.js +1 -1
  132. package/dist/src/utils/claudeInChrome/setupPortable.js +1 -1
  133. package/dist/src/utils/claudemd.js +1 -1
  134. package/dist/src/utils/collapseBackgroundBashNotifications.js +1 -1
  135. package/dist/src/utils/collapseReadSearch.js +1 -1
  136. package/dist/src/utils/completionCache.js +1 -1
  137. package/dist/src/utils/computerUse/common.js +1 -1
  138. package/dist/src/utils/concurrentSessions.js +1 -1
  139. package/dist/src/utils/context.js +1 -1
  140. package/dist/src/utils/cron.js +1 -1
  141. package/dist/src/utils/cronTasks.js +1 -1
  142. package/dist/src/utils/cwd.js +1 -1
  143. package/dist/src/utils/debug.js +1 -1
  144. package/dist/src/utils/debugFilter.js +1 -1
  145. package/dist/src/utils/detectRepository.js +1 -1
  146. package/dist/src/utils/diagLogs.js +1 -1
  147. package/dist/src/utils/diff.js +1 -1
  148. package/dist/src/utils/directMemberMessage.js +1 -1
  149. package/dist/src/utils/doctorDiagnostic.js +1 -1
  150. package/dist/src/utils/dxt/helpers.js +1 -1
  151. package/dist/src/utils/dxt/zip.js +1 -1
  152. package/dist/src/utils/earlyInput.js +1 -1
  153. package/dist/src/utils/editor.js +1 -1
  154. package/dist/src/utils/effort.js +1 -1
  155. package/dist/src/utils/embeddedTools.js +1 -1
  156. package/dist/src/utils/envDynamic.js +1 -1
  157. package/dist/src/utils/envUtils.js +1 -1
  158. package/dist/src/utils/execFileNoThrowPortable.js +1 -1
  159. package/dist/src/utils/execSyncWrapper.js +1 -1
  160. package/dist/src/utils/exportRenderer.js +1 -1
  161. package/dist/src/utils/extraUsage.js +1 -1
  162. package/dist/src/utils/fastMode.js +1 -1
  163. package/dist/src/utils/fileOperationAnalytics.js +1 -1
  164. package/dist/src/utils/fileRead.js +1 -1
  165. package/dist/src/utils/findExecutable.js +1 -1
  166. package/dist/src/utils/format.js +1 -1
  167. package/dist/src/utils/frontmatterParser.js +1 -1
  168. package/dist/src/utils/fsOperations.js +1 -1
  169. package/dist/src/utils/fullscreen.js +1 -1
  170. package/dist/src/utils/genericProcessUtils.js +1 -1
  171. package/dist/src/utils/getWorktreePaths.js +1 -1
  172. package/dist/src/utils/git/gitConfigParser.js +1 -1
  173. package/dist/src/utils/git/gitFilesystem.js +1 -1
  174. package/dist/src/utils/git/gitignore.js +1 -1
  175. package/dist/src/utils/gitDiff.js +1 -1
  176. package/dist/src/utils/gitSettings.js +1 -1
  177. package/dist/src/utils/glob.js +1 -1
  178. package/dist/src/utils/gracefulShutdown.js +1 -1
  179. package/dist/src/utils/groupToolUses.js +1 -1
  180. package/dist/src/utils/handlePromptSubmit.js +1 -1
  181. package/dist/src/utils/hash.js +1 -1
  182. package/dist/src/utils/hooks/fileChangedWatcher.js +1 -1
  183. package/dist/src/utils/hooks/hooksSettings.js +1 -1
  184. package/dist/src/utils/hooks/registerSkillHooks.js +1 -1
  185. package/dist/src/utils/hooks/sessionHooks.js +1 -1
  186. package/dist/src/utils/http.js +1 -1
  187. package/dist/src/utils/hyperlink.js +1 -1
  188. package/dist/src/utils/ide.js +1 -1
  189. package/dist/src/utils/idePathConversion.js +1 -1
  190. package/dist/src/utils/imagePaste.js +1 -1
  191. package/dist/src/utils/imageResizer.js +1 -1
  192. package/dist/src/utils/imageStore.js +1 -1
  193. package/dist/src/utils/inProcessTeammateHelpers.js +1 -1
  194. package/dist/src/utils/ink.js +1 -1
  195. package/dist/src/utils/jetbrains.js +1 -1
  196. package/dist/src/utils/json.js +1 -1
  197. package/dist/src/utils/listSessionsImpl.js +1 -1
  198. package/dist/src/utils/localInstaller.js +1 -1
  199. package/dist/src/utils/lockfile.js +1 -1
  200. package/dist/src/utils/logoV2Utils.js +1 -1
  201. package/dist/src/utils/markdown.js +1 -1
  202. package/dist/src/utils/mcp/dateTimeParser.js +1 -1
  203. package/dist/src/utils/mcpOutputStorage.js +1 -1
  204. package/dist/src/utils/mcpValidation.js +1 -1
  205. package/dist/src/utils/memoize.js +1 -1
  206. package/dist/src/utils/memory/types.js +1 -1
  207. package/dist/src/utils/memoryFileDetection.js +1 -1
  208. package/dist/src/utils/messageQueueManager.js +1 -1
  209. package/dist/src/utils/messages/mappers.js +1 -1
  210. package/dist/src/utils/messages/systemInit.js +1 -1
  211. package/dist/src/utils/model/antModels.js +1 -1
  212. package/dist/src/utils/model/check1mAccess.js +1 -1
  213. package/dist/src/utils/model/contextWindowUpgradeCheck.js +1 -1
  214. package/dist/src/utils/model/model.js +1 -1
  215. package/dist/src/utils/model/modelAllowlist.js +1 -1
  216. package/dist/src/utils/model/modelCapabilities.js +1 -1
  217. package/dist/src/utils/model/modelOptions.js +1 -1
  218. package/dist/src/utils/model/modelStrings.js +1 -1
  219. package/dist/src/utils/model/providerModels.js +1 -1
  220. package/dist/src/utils/model/providerProfiles.js +1 -1
  221. package/dist/src/utils/model/providerProfilesDb.js +1 -1
  222. package/dist/src/utils/model/providerSwitch.js +1 -1
  223. package/dist/src/utils/model/providers.js +1 -1
  224. package/dist/src/utils/modelCost.js +1 -1
  225. package/dist/src/utils/modifiers.js +1 -1
  226. package/dist/src/utils/mtls.js +1 -1
  227. package/dist/src/utils/nativeInstaller/download.js +1 -1
  228. package/dist/src/utils/nativeInstaller/installer.js +1 -1
  229. package/dist/src/utils/nativeInstaller/packageManagers.js +1 -1
  230. package/dist/src/utils/nativeInstaller/pidLock.js +1 -1
  231. package/dist/src/utils/notebook.js +1 -1
  232. package/dist/src/utils/pasteStore.js +1 -1
  233. package/dist/src/utils/path.js +1 -1
  234. package/dist/src/utils/permissions/PermissionMode.js +1 -1
  235. package/dist/src/utils/permissions/PermissionPromptToolResultSchema.js +1 -1
  236. package/dist/src/utils/permissions/PermissionUpdate.js +1 -1
  237. package/dist/src/utils/permissions/PermissionUpdateSchema.js +1 -1
  238. package/dist/src/utils/permissions/autoModeState.js +1 -1
  239. package/dist/src/utils/permissions/bypassPermissionsKillswitch.js +1 -1
  240. package/dist/src/utils/permissions/filesystem.js +1 -1
  241. package/dist/src/utils/permissions/getNextPermissionMode.js +1 -1
  242. package/dist/src/utils/permissions/pathValidation.js +1 -1
  243. package/dist/src/utils/permissions/permissionRuleParser.js +1 -1
  244. package/dist/src/utils/permissions/permissionsDb.js +1 -1
  245. package/dist/src/utils/permissions/permissionsLoader.js +1 -1
  246. package/dist/src/utils/permissions/shellRuleMatching.js +1 -1
  247. package/dist/src/utils/planModeV2.js +1 -1
  248. package/dist/src/utils/plans.js +1 -1
  249. package/dist/src/utils/platform.js +1 -1
  250. package/dist/src/utils/plugins/addDirPluginSettings.js +1 -1
  251. package/dist/src/utils/plugins/cacheUtils.js +1 -1
  252. package/dist/src/utils/plugins/dependencyResolver.js +1 -1
  253. package/dist/src/utils/plugins/fetchTelemetry.js +1 -1
  254. package/dist/src/utils/plugins/gitAvailability.js +1 -1
  255. package/dist/src/utils/plugins/hintRecommendation.js +1 -1
  256. package/dist/src/utils/plugins/installedPluginsManager.js +1 -1
  257. package/dist/src/utils/plugins/loadPluginAgents.js +1 -1
  258. package/dist/src/utils/plugins/loadPluginCommands.js +1 -1
  259. package/dist/src/utils/plugins/loadPluginHooks.js +1 -1
  260. package/dist/src/utils/plugins/loadPluginOutputStyles.js +1 -1
  261. package/dist/src/utils/plugins/lspPluginIntegration.js +1 -1
  262. package/dist/src/utils/plugins/lspRecommendation.js +1 -1
  263. package/dist/src/utils/plugins/managedPlugins.js +1 -1
  264. package/dist/src/utils/plugins/marketplaceHelpers.js +1 -1
  265. package/dist/src/utils/plugins/marketplaceManager.js +1 -1
  266. package/dist/src/utils/plugins/mcpPluginIntegration.js +1 -1
  267. package/dist/src/utils/plugins/mcpbHandler.js +1 -1
  268. package/dist/src/utils/plugins/officialMarketplaceGcs.js +1 -1
  269. package/dist/src/utils/plugins/officialMarketplaceStartupCheck.js +1 -1
  270. package/dist/src/utils/plugins/orphanedPluginFilter.js +1 -1
  271. package/dist/src/utils/plugins/performStartupChecks.js +1 -1
  272. package/dist/src/utils/plugins/pluginAutoupdate.js +1 -1
  273. package/dist/src/utils/plugins/pluginBlocklist.js +1 -1
  274. package/dist/src/utils/plugins/pluginDirectories.js +1 -1
  275. package/dist/src/utils/plugins/pluginFlagging.js +1 -1
  276. package/dist/src/utils/plugins/pluginInstallationHelpers.js +1 -1
  277. package/dist/src/utils/plugins/pluginLoader.js +1 -1
  278. package/dist/src/utils/plugins/pluginOptionsStorage.js +1 -1
  279. package/dist/src/utils/plugins/pluginPolicy.js +1 -1
  280. package/dist/src/utils/plugins/pluginStartupCheck.js +1 -1
  281. package/dist/src/utils/plugins/pluginVersioning.js +1 -1
  282. package/dist/src/utils/plugins/reconciler.js +1 -1
  283. package/dist/src/utils/plugins/refresh.js +1 -1
  284. package/dist/src/utils/plugins/schemas.js +1 -1
  285. package/dist/src/utils/plugins/walkPluginMarkdown.js +1 -1
  286. package/dist/src/utils/plugins/zipCache.js +1 -1
  287. package/dist/src/utils/powershell/parser.js +1 -1
  288. package/dist/src/utils/processUserInput/processBashCommand.js +1 -1
  289. package/dist/src/utils/processUserInput/processSlashCommand.js +1 -1
  290. package/dist/src/utils/processUserInput/processTextPrompt.js +1 -1
  291. package/dist/src/utils/processUserInput/processUserInput.js +1 -1
  292. package/dist/src/utils/profilerBase.js +1 -1
  293. package/dist/src/utils/promptCategory.js +1 -1
  294. package/dist/src/utils/promptEditor.js +1 -1
  295. package/dist/src/utils/promptShellExecution.js +1 -1
  296. package/dist/src/utils/proxy.js +1 -1
  297. package/dist/src/utils/queryHelpers.js +1 -1
  298. package/dist/src/utils/queryProfiler.js +1 -1
  299. package/dist/src/utils/queueProcessor.js +1 -1
  300. package/dist/src/utils/readFileInRange.js +1 -1
  301. package/dist/src/utils/releaseNotes.js +1 -1
  302. package/dist/src/utils/renderOptions.js +1 -1
  303. package/dist/src/utils/ripgrep.js +1 -1
  304. package/dist/src/utils/sandbox/sandbox-adapter.js +1 -1
  305. package/dist/src/utils/sdkEventQueue.js +1 -1
  306. package/dist/src/utils/secureStorage/index.js +1 -1
  307. package/dist/src/utils/secureStorage/macOsKeychainHelpers.js +1 -1
  308. package/dist/src/utils/secureStorage/macOsKeychainStorage.js +1 -1
  309. package/dist/src/utils/secureStorage/plainTextStorage.js +1 -1
  310. package/dist/src/utils/secureStorage/sqliteStorage.js +1 -1
  311. package/dist/src/utils/sessionEnvironment.js +1 -1
  312. package/dist/src/utils/sessionIngressAuth.js +1 -1
  313. package/dist/src/utils/sessionRestore.js +1 -1
  314. package/dist/src/utils/sessionStart.js +1 -1
  315. package/dist/src/utils/sessionTitle.js +1 -1
  316. package/dist/src/utils/settings/managedPath.js +1 -1
  317. package/dist/src/utils/settings/mdm/rawRead.js +1 -1
  318. package/dist/src/utils/settings/mdm/settings.js +1 -1
  319. package/dist/src/utils/settings/permissionValidation.js +1 -1
  320. package/dist/src/utils/settings/pluginOnlyPolicy.js +1 -1
  321. package/dist/src/utils/settings/schemaOutput.js +1 -1
  322. package/dist/src/utils/settings/settings.js +1 -1
  323. package/dist/src/utils/settings/types.js +1 -1
  324. package/dist/src/utils/settings/validateEditTool.js +1 -1
  325. package/dist/src/utils/settings/validation.js +1 -1
  326. package/dist/src/utils/shell/bashProvider.js +1 -1
  327. package/dist/src/utils/shell/powershellDetection.js +1 -1
  328. package/dist/src/utils/shell/powershellProvider.js +1 -1
  329. package/dist/src/utils/shell/readOnlyCommandValidation.js +1 -1
  330. package/dist/src/utils/shell/resolveDefaultShell.js +1 -1
  331. package/dist/src/utils/shell/shellToolUtils.js +1 -1
  332. package/dist/src/utils/shell/specPrefix.js +1 -1
  333. package/dist/src/utils/shellConfig.js +1 -1
  334. package/dist/src/utils/sideQuestion.js +1 -1
  335. package/dist/src/utils/skills/skillChangeDetector.js +1 -1
  336. package/dist/src/utils/slashCommandParsing.js +1 -1
  337. package/dist/src/utils/sliceAnsi.js +1 -1
  338. package/dist/src/utils/slowOperations.js +1 -1
  339. package/dist/src/utils/standaloneAgent.js +1 -1
  340. package/dist/src/utils/startupProfiler.js +1 -1
  341. package/dist/src/utils/staticRender.js +1 -1
  342. package/dist/src/utils/status.js +1 -1
  343. package/dist/src/utils/statusNoticeDefinitions.js +1 -1
  344. package/dist/src/utils/suggestions/commandSuggestions.js +1 -1
  345. package/dist/src/utils/suggestions/directoryCompletion.js +1 -1
  346. package/dist/src/utils/suggestions/shellHistoryCompletion.js +1 -1
  347. package/dist/src/utils/suggestions/skillUsageTracking.js +1 -1
  348. package/dist/src/utils/suggestions/slackChannelSuggestions.js +1 -1
  349. package/dist/src/utils/swarm/backends/detection.js +1 -1
  350. package/dist/src/utils/swarm/permissionSync.js +1 -1
  351. package/dist/src/utils/swarm/reconnection.js +1 -1
  352. package/dist/src/utils/swarm/spawnUtils.js +1 -91
  353. package/dist/src/utils/swarm/teammateInit.js +1 -1
  354. package/dist/src/utils/systemDirectories.js +1 -1
  355. package/dist/src/utils/systemPrompt.js +1 -1
  356. package/dist/src/utils/systemTheme.js +1 -1
  357. package/dist/src/utils/task/TaskOutput.js +1 -1
  358. package/dist/src/utils/task/diskOutput.js +1 -1
  359. package/dist/src/utils/tasks.js +1 -1
  360. package/dist/src/utils/teamDiscovery.js +1 -1
  361. package/dist/src/utils/teamMemoryOps.js +1 -1
  362. package/dist/src/utils/teammateMailbox.js +1 -1
  363. package/dist/src/utils/telemetry/betaSessionTracing.js +1 -1
  364. package/dist/src/utils/telemetry/bigqueryExporter.js +1 -1
  365. package/dist/src/utils/telemetry/events.js +1 -1
  366. package/dist/src/utils/telemetry/instrumentation.js +1 -1
  367. package/dist/src/utils/telemetry/logger.js +1 -1
  368. package/dist/src/utils/telemetry/perfettoTracing.js +1 -1
  369. package/dist/src/utils/telemetry/pluginTelemetry.js +1 -1
  370. package/dist/src/utils/telemetry/sessionTracing.js +1 -1
  371. package/dist/src/utils/telemetryAttributes.js +1 -1
  372. package/dist/src/utils/teleport/api.js +1 -1
  373. package/dist/src/utils/teleport/environments.js +1 -1
  374. package/dist/src/utils/teleport/gitBundle.js +1 -1
  375. package/dist/src/utils/teleport.js +1 -1
  376. package/dist/src/utils/tempfile.js +1 -1
  377. package/dist/src/utils/terminal.js +1 -1
  378. package/dist/src/utils/terminalPanel.js +1 -1
  379. package/dist/src/utils/textHighlighting.js +1 -1
  380. package/dist/src/utils/theme.js +1 -1
  381. package/dist/src/utils/themes/bootstrap.js +1 -1
  382. package/dist/src/utils/themes/loader.js +1 -1
  383. package/dist/src/utils/thinking.js +1 -1
  384. package/dist/src/utils/tmuxSocket.js +1 -1
  385. package/dist/src/utils/tokens.js +1 -1
  386. package/dist/src/utils/toolPool.js +1 -1
  387. package/dist/src/utils/toolResultStorage.js +1 -1
  388. package/dist/src/utils/transcriptSearch.js +1 -1
  389. package/dist/src/utils/truncate.js +1 -1
  390. package/dist/src/utils/ultraplan/keyword.js +1 -1
  391. package/dist/src/utils/unaryLogging.js +1 -1
  392. package/dist/src/utils/undercover.js +1 -1
  393. package/dist/src/utils/user.js +1 -1
  394. package/dist/src/utils/userPromptKeywords.js +1 -1
  395. package/dist/src/utils/which.js +1 -1
  396. package/dist/src/utils/windowsPaths.js +1 -1
  397. package/dist/src/utils/worktree.js +1 -1
  398. package/dist/src/utils/zodToJsonSchema.js +1 -1
  399. package/dist/src/vim/operators.js +1 -1
  400. package/dist/src/vim/textObjects.js +1 -1
  401. package/dist/src/vim/transitions.js +1 -1
  402. package/dist/src/voice/voiceModeEnabled.js +1 -1
  403. package/dist/src/webapp/auth.js +1 -1
  404. package/dist/src/webapp/tunnel.js +1 -1
  405. package/dist/src/whatsapp/bridge.js +1 -1
  406. package/dist/src/whatsapp/mirror.js +1 -1
  407. package/dist/webapp/main-MTQLKGXD.js +1 -1
  408. package/package.json +1 -1
@@ -1 +1 @@
1
- import{join as a}from"path";import{getFeatureValue_CACHED_MAY_BE_STALE as t}from"../../services/analytics/growthbook.js";import{logEvent as l}from"../../services/analytics/index.js";import{getGlobalConfig as e,saveGlobalConfig as i}from"../config.js";import{logForDebugging as o}from"../debug.js";import{isEnvTruthy as c}from"../envUtils.js";import{toError as n}from"../errors.js";import{logError as s}from"../log.js";import{checkGitAvailable as r,markGitUnavailable as f}from"./gitAvailability.js";import{isSourceAllowedByPolicy as p}from"./marketplaceHelpers.js";import{addMarketplaceSource as u,getMarketplacesCacheDir as k,loadKnownMarketplacesConfig as A,saveKnownMarketplacesConfig as d}from"./marketplaceManager.js";import{OFFICIAL_MARKETPLACE_NAME as _,OFFICIAL_MARKETPLACE_SOURCE as m}from"./officialMarketplace.js";import{fetchOfficialMarketplaceFromGcs as I}from"./officialMarketplaceGcs.js";export function isOfficialMarketplaceAutoInstallDisabled(){return c(process.env.CONTEXT_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL)||c(process.env.CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL)}export const RETRY_CONFIG={MAX_ATTEMPTS:10,INITIAL_DELAY_MS:36e5,BACKOFF_MULTIPLIER:2,MAX_DELAY_MS:6048e5};function calculateNextRetryDelay(a){const t=RETRY_CONFIG.INITIAL_DELAY_MS*Math.pow(RETRY_CONFIG.BACKOFF_MULTIPLIER,a);return Math.min(t,RETRY_CONFIG.MAX_DELAY_MS)}export async function checkAndInstallOfficialMarketplace(){const c=e();if(!function(a){if(!a.officialMarketplaceAutoInstallAttempted)return!0;if(a.officialMarketplaceAutoInstalled)return!1;const t=a.officialMarketplaceAutoInstallFailReason,l=a.officialMarketplaceAutoInstallRetryCount||0,e=a.officialMarketplaceAutoInstallNextRetryTime,i=Date.now();return!(l>=RETRY_CONFIG.MAX_ATTEMPTS||"policy_blocked"===t||e&&i<e||"unknown"!==t&&"git_unavailable"!==t&&"gcs_unavailable"!==t&&void 0!==t)}(c)){const a=c.officialMarketplaceAutoInstallFailReason??"already_attempted";return o(`Official marketplace auto-install skipped: ${a}`),{installed:!1,skipped:!0,reason:a}}try{if(isOfficialMarketplaceAutoInstallDisabled())return o("Official marketplace auto-install disabled via env var, skipping"),i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"policy_blocked"})),l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,policy_blocked:!0}),{installed:!1,skipped:!0,reason:"policy_blocked"};if((await A())[_])return o(`Official marketplace '${_}' already installed, skipping`),i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!0})),{installed:!1,skipped:!0,reason:"already_installed"};if(!p(m))return o("Official marketplace blocked by enterprise policy, skipping"),i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"policy_blocked"})),l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,policy_blocked:!0}),{installed:!1,skipped:!0,reason:"policy_blocked"};const e=k(),f=a(e,_);if(null!==await I(f,e)){const a=await A();return a[_]={source:m,installLocation:f,lastUpdated:(new Date).toISOString()},await d(a),i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!0,officialMarketplaceAutoInstallFailReason:void 0,officialMarketplaceAutoInstallRetryCount:void 0,officialMarketplaceAutoInstallLastAttemptTime:void 0,officialMarketplaceAutoInstallNextRetryTime:void 0})),l("tengu_official_marketplace_auto_install",{installed:!0,skipped:!1,via_gcs:!0}),{installed:!0,skipped:!1}}if(!t("tengu_plugin_official_mkt_git_fallback",!0)){o("Official marketplace GCS failed; git fallback disabled by flag — skipping install");const a=(c.officialMarketplaceAutoInstallRetryCount||0)+1,t=Date.now(),e=t+calculateNextRetryDelay(a);return i(l=>({...l,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"gcs_unavailable",officialMarketplaceAutoInstallRetryCount:a,officialMarketplaceAutoInstallLastAttemptTime:t,officialMarketplaceAutoInstallNextRetryTime:e})),l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,gcs_unavailable:!0,retry_count:a}),{installed:!1,skipped:!0,reason:"gcs_unavailable"}}if(!await r()){o("Git not available, skipping official marketplace auto-install");const a=(c.officialMarketplaceAutoInstallRetryCount||0)+1,t=Date.now(),e=calculateNextRetryDelay(a),r=t+e;let f=!1;try{i(l=>({...l,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"git_unavailable",officialMarketplaceAutoInstallRetryCount:a,officialMarketplaceAutoInstallLastAttemptTime:t,officialMarketplaceAutoInstallNextRetryTime:r}))}catch(a){f=!0;const t=n(a);s(t),o(`Failed to save marketplace auto-install git_unavailable state: ${a}`,{level:"error"})}return l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,git_unavailable:!0,retry_count:a}),{installed:!1,skipped:!0,reason:"git_unavailable",configSaveFailed:f}}o("Attempting to auto-install official marketplace"),await u(m),o("Successfully auto-installed official marketplace");const M=c.officialMarketplaceAutoInstallRetryCount||0;return i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!0,officialMarketplaceAutoInstallFailReason:void 0,officialMarketplaceAutoInstallRetryCount:void 0,officialMarketplaceAutoInstallLastAttemptTime:void 0,officialMarketplaceAutoInstallNextRetryTime:void 0})),l("tengu_official_marketplace_auto_install",{installed:!0,skipped:!1,retry_count:M}),{installed:!0,skipped:!1}}catch(a){const t=a instanceof Error?a.message:String(a);if(t.includes("xcrun: error:"))return f(),o("Official marketplace auto-install: git is a non-functional macOS xcrun shim, treating as git_unavailable"),l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,git_unavailable:!0,macos_xcrun_shim:!0}),{installed:!1,skipped:!0,reason:"git_unavailable"};o(`Failed to auto-install official marketplace: ${t}`,{level:"error"}),s(n(a));const e=(c.officialMarketplaceAutoInstallRetryCount||0)+1,r=Date.now(),p=calculateNextRetryDelay(e),u=r+p;let k=!1;try{i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"unknown",officialMarketplaceAutoInstallRetryCount:e,officialMarketplaceAutoInstallLastAttemptTime:r,officialMarketplaceAutoInstallNextRetryTime:u}))}catch(a){k=!0;const t=n(a);s(t),o(`Failed to save marketplace auto-install failure state: ${a}`,{level:"error"})}return l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,failed:!0,retry_count:e}),{installed:!1,skipped:!0,reason:"unknown",configSaveFailed:k}}}
1
+ import{join as a}from"path";import{getFeatureValue_CACHED_MAY_BE_STALE as t}from"../../services/analytics/growthbook.js";import{logEvent as l}from"../../services/analytics/index.js";import{getGlobalConfig as e,saveGlobalConfig as i}from"../config.js";import{logForDebugging as o}from"../debug.js";import{isEnvTruthy as c}from"../envUtils.js";import{toError as n}from"../errors.js";import{logError as r}from"../log.js";import{checkGitAvailable as s,markGitUnavailable as f}from"./gitAvailability.js";import{isSourceAllowedByPolicy as p}from"./marketplaceHelpers.js";import{addMarketplaceSource as u,getMarketplacesCacheDir as k,loadKnownMarketplacesConfig as d,saveKnownMarketplacesConfig as A}from"./marketplaceManager.js";import{OFFICIAL_MARKETPLACE_NAME as _,OFFICIAL_MARKETPLACE_SOURCE as m}from"./officialMarketplace.js";import{fetchOfficialMarketplaceFromGcs as I}from"./officialMarketplaceGcs.js";export function isOfficialMarketplaceAutoInstallDisabled(){return c(process.env.CONTEXT_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL)||c(process.env.CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL)}export const RETRY_CONFIG={MAX_ATTEMPTS:10,INITIAL_DELAY_MS:36e5,BACKOFF_MULTIPLIER:2,MAX_DELAY_MS:6048e5};function calculateNextRetryDelay(a){const t=RETRY_CONFIG.INITIAL_DELAY_MS*Math.pow(RETRY_CONFIG.BACKOFF_MULTIPLIER,a);return Math.min(t,RETRY_CONFIG.MAX_DELAY_MS)}export async function checkAndInstallOfficialMarketplace(){const c=e();if(!function(a){if(!a.officialMarketplaceAutoInstallAttempted)return!0;if(a.officialMarketplaceAutoInstalled)return!1;const t=a.officialMarketplaceAutoInstallFailReason,l=a.officialMarketplaceAutoInstallRetryCount||0,e=a.officialMarketplaceAutoInstallNextRetryTime,i=Date.now();return!(l>=RETRY_CONFIG.MAX_ATTEMPTS||"policy_blocked"===t||e&&i<e||"unknown"!==t&&"git_unavailable"!==t&&"gcs_unavailable"!==t&&void 0!==t)}(c)){const a=c.officialMarketplaceAutoInstallFailReason??"already_attempted";return o(`Official marketplace auto-install skipped: ${a}`),{installed:!1,skipped:!0,reason:a}}try{if(isOfficialMarketplaceAutoInstallDisabled())return o("Official marketplace auto-install disabled via env var, skipping"),i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"policy_blocked"})),l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,policy_blocked:!0}),{installed:!1,skipped:!0,reason:"policy_blocked"};if((await d())[_])return o(`Official marketplace '${_}' already installed, skipping`),i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!0})),{installed:!1,skipped:!0,reason:"already_installed"};if(!p(m))return o("Official marketplace blocked by enterprise policy, skipping"),i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"policy_blocked"})),l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,policy_blocked:!0}),{installed:!1,skipped:!0,reason:"policy_blocked"};const e=k(),f=a(e,_);if(null!==await I(f,e)){const a=await d();return a[_]={source:m,installLocation:f,lastUpdated:(new Date).toISOString()},await A(a),i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!0,officialMarketplaceAutoInstallFailReason:void 0,officialMarketplaceAutoInstallRetryCount:void 0,officialMarketplaceAutoInstallLastAttemptTime:void 0,officialMarketplaceAutoInstallNextRetryTime:void 0})),l("tengu_official_marketplace_auto_install",{installed:!0,skipped:!1,via_gcs:!0}),{installed:!0,skipped:!1}}if(!t("tengu_plugin_official_mkt_git_fallback",!0)){o("Official marketplace GCS failed; git fallback disabled by flag — skipping install");const a=(c.officialMarketplaceAutoInstallRetryCount||0)+1,t=Date.now(),e=t+calculateNextRetryDelay(a);return i(l=>({...l,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"gcs_unavailable",officialMarketplaceAutoInstallRetryCount:a,officialMarketplaceAutoInstallLastAttemptTime:t,officialMarketplaceAutoInstallNextRetryTime:e})),l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,gcs_unavailable:!0,retry_count:a}),{installed:!1,skipped:!0,reason:"gcs_unavailable"}}if(!await s()){o("Git not available, skipping official marketplace auto-install");const a=(c.officialMarketplaceAutoInstallRetryCount||0)+1,t=Date.now(),e=calculateNextRetryDelay(a),s=t+e;let f=!1;try{i(l=>({...l,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"git_unavailable",officialMarketplaceAutoInstallRetryCount:a,officialMarketplaceAutoInstallLastAttemptTime:t,officialMarketplaceAutoInstallNextRetryTime:s}))}catch(a){f=!0;const t=n(a);r(t),o(`Failed to save marketplace auto-install git_unavailable state: ${a}`,{level:"error"})}return l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,git_unavailable:!0,retry_count:a}),{installed:!1,skipped:!0,reason:"git_unavailable",configSaveFailed:f}}o("Attempting to auto-install official marketplace"),await u(m),o("Successfully auto-installed official marketplace");const M=c.officialMarketplaceAutoInstallRetryCount||0;return i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!0,officialMarketplaceAutoInstallFailReason:void 0,officialMarketplaceAutoInstallRetryCount:void 0,officialMarketplaceAutoInstallLastAttemptTime:void 0,officialMarketplaceAutoInstallNextRetryTime:void 0})),l("tengu_official_marketplace_auto_install",{installed:!0,skipped:!1,retry_count:M}),{installed:!0,skipped:!1}}catch(a){const t=a instanceof Error?a.message:String(a);if(t.includes("xcrun: error:"))return f(),o("Official marketplace auto-install: git is a non-functional macOS xcrun shim, treating as git_unavailable"),l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,git_unavailable:!0,macos_xcrun_shim:!0}),{installed:!1,skipped:!0,reason:"git_unavailable"};o(`Failed to auto-install official marketplace: ${t}`,{level:"error"}),r(n(a));const e=(c.officialMarketplaceAutoInstallRetryCount||0)+1,s=Date.now(),p=calculateNextRetryDelay(e),u=s+p;let k=!1;try{i(a=>({...a,officialMarketplaceAutoInstallAttempted:!0,officialMarketplaceAutoInstalled:!1,officialMarketplaceAutoInstallFailReason:"unknown",officialMarketplaceAutoInstallRetryCount:e,officialMarketplaceAutoInstallLastAttemptTime:s,officialMarketplaceAutoInstallNextRetryTime:u}))}catch(a){k=!0;const t=n(a);r(t),o(`Failed to save marketplace auto-install failure state: ${a}`,{level:"error"})}return l("tengu_official_marketplace_auto_install",{installed:!1,skipped:!0,failed:!0,retry_count:e}),{installed:!1,skipped:!0,reason:"unknown",configSaveFailed:k}}}
@@ -1 +1 @@
1
- import{dirname as r,isAbsolute as o,join as e,normalize as n,relative as t,sep as a}from"path";import{ripGrep as i}from"../ripgrep.js";import{getPluginsDirectory as s}from"./pluginDirectories.js";let l=null;export async function getGlobExclusionsForPluginCache(c){const p=n(e(s(),"cache"));if(c&&!function(r,o){const e=normalizeForCompare(r),n=normalizeForCompare(o);return e===n||e===a||n===a||e.startsWith(n+a)||n.startsWith(e+a)}(c,p))return[];if(null!==l)return l;try{const e=await i(["--files","--hidden","--no-ignore","--max-depth","4","--glob",".orphaned_at"],p,(new AbortController).signal);return l=e.map(e=>{const n=r(e);return`!**/${(o(n)?t(p,n):n).replace(/\\/g,"/")}/**`}),l}catch{return l=[],l}}export function clearPluginCacheExclusions(){l=null}function normalizeForCompare(r){const o=n(r);return"win32"===process.platform?o.toLowerCase():o}
1
+ import{dirname as r,isAbsolute as o,join as n,normalize as t,relative as e,sep as i}from"path";import{ripGrep as a}from"../ripgrep.js";import{getPluginsDirectory as l}from"./pluginDirectories.js";let c=null;export async function getGlobExclusionsForPluginCache(s){const u=t(n(l(),"cache"));if(s&&!function(r,o){const n=normalizeForCompare(r),t=normalizeForCompare(o);return n===t||n===i||t===i||n.startsWith(t+i)||t.startsWith(n+i)}(s,u))return[];if(null!==c)return c;try{const n=await a(["--files","--hidden","--no-ignore","--max-depth","4","--glob",".orphaned_at"],u,(new AbortController).signal);return c=n.map(n=>{const t=r(n);return`!**/${(o(t)?e(u,t):t).replace(/\\/g,"/")}/**`}),c}catch{return c=[],c}}export function clearPluginCacheExclusions(){c=null}function normalizeForCompare(r){const o=t(r);return"win32"===process.platform?o.toLowerCase():o}
@@ -1 +1 @@
1
- import{performBackgroundPluginInstallations as a}from"../../services/plugins/PluginInstallationManager.js";import{checkHasTrustDialogAccepted as e}from"../config.js";import{logForDebugging as r}from"../debug.js";import{clearMarketplacesCache as s,registerSeedMarketplaces as t}from"./marketplaceManager.js";import{clearPluginCache as i}from"./pluginLoader.js";export async function performStartupChecks(n){if(r("performStartupChecks called"),e())try{r("Starting background plugin installations"),await t()&&(s(),i("performStartupChecks: seed marketplaces changed"),n(a=>a.plugins.needsRefresh?a:{...a,plugins:{...a.plugins,needsRefresh:!0}})),await a(n)}catch(a){r(`Error initiating background plugin installations: ${a}`)}else r("Trust not accepted for current directory - skipping plugin installations")}
1
+ import{performBackgroundPluginInstallations as r}from"../../services/plugins/PluginInstallationManager.js";import{checkHasTrustDialogAccepted as t}from"../config.js";import{logForDebugging as e}from"../debug.js";import{clearMarketplacesCache as i,registerSeedMarketplaces as n}from"./marketplaceManager.js";import{clearPluginCache as a}from"./pluginLoader.js";export async function performStartupChecks(s){if(e("performStartupChecks called"),t())try{e("Starting background plugin installations");await n()&&(i(),a("performStartupChecks: seed marketplaces changed"),s(r=>r.plugins.needsRefresh?r:{...r,plugins:{...r.plugins,needsRefresh:!0}})),await r(s)}catch(r){e(`Error initiating background plugin installations: ${r}`)}else e("Trust not accepted for current directory - skipping plugin installations")}
@@ -1 +1 @@
1
- import{updatePluginOp as e}from"../../services/plugins/pluginOperations.js";import{shouldSkipPluginAutoupdate as t}from"../config.js";import{logForDebugging as a}from"../debug.js";import{errorMessage as n}from"../errors.js";import{logError as r}from"../log.js";import{getPendingUpdatesDetails as l,hasPendingUpdates as s,isInstallationRelevantToCurrentProject as o,loadInstalledPluginsFromDisk as i}from"./installedPluginsManager.js";import{getDeclaredMarketplaces as u,loadKnownMarketplacesConfig as p,refreshMarketplace as d}from"./marketplaceManager.js";import{parsePluginIdentifier as c}from"./pluginIdentifier.js";import{isMarketplaceAutoUpdate as g}from"./schemas.js";let f=null,m=null;export function onPluginsAutoUpdated(e){return f=e,null!==m&&m.length>0&&(e(m),m=null),()=>{f=null}}export function getAutoUpdatedPluginNames(){return s()?l().map(e=>c(e.pluginId).name):[]}export async function updatePluginsForMarketplaces(t){const r=i(),l=Object.keys(r.plugins);return 0===l.length?[]:(await Promise.allSettled(l.map(async l=>{const{marketplace:s}=c(l);if(!s||!t.has(s.toLowerCase()))return null;const i=r.plugins[l];if(!i||0===i.length)return null;const u=i.filter(o);return 0===u.length?null:async function(t,r){let l=!1;for(const{scope:s}of r)try{const n=await e(t,s);n.success&&!n.alreadyUpToDate?(l=!0,a(`Plugin autoupdate: updated ${t} from ${n.oldVersion} to ${n.newVersion}`)):n.alreadyUpToDate||a(`Plugin autoupdate: failed to update ${t}: ${n.message}`,{level:"warn"})}catch(e){a(`Plugin autoupdate: error updating ${t}: ${n(e)}`,{level:"warn"})}return l?t:null}(l,u)}))).filter(e=>"fulfilled"===e.status&&null!==e.value).map(e=>e.value)}export function autoUpdateMarketplacesAndPluginsInBackground(){(async()=>{if(t())a("Plugin autoupdate: skipped (auto-updater disabled)");else try{const e=await async function(){const e=await p(),t=u(),a=new Set;for(const[n,r]of Object.entries(e)){const e=t[n]?.autoUpdate;(void 0!==e?e:g(n,r))&&a.add(n.toLowerCase())}return a}();if(0===e.size)return;const t=(await Promise.allSettled(Array.from(e).map(async e=>{try{await d(e,void 0,{disableCredentialHelper:!0})}catch(t){a(`Plugin autoupdate: failed to refresh marketplace ${e}: ${n(t)}`,{level:"warn"})}}))).filter(e=>"rejected"===e.status);t.length>0&&a(`Plugin autoupdate: ${t.length} marketplace refresh(es) failed`,{level:"warn"}),a("Plugin autoupdate: checking installed plugins");const r=await async function(e){return updatePluginsForMarketplaces(e)}(e);r.length>0&&(f?f(r):m=r)}catch(e){r(e)}})()}
1
+ import{updatePluginOp as e}from"../../services/plugins/pluginOperations.js";import{shouldSkipPluginAutoupdate as t}from"../config.js";import{logForDebugging as a}from"../debug.js";import{errorMessage as n}from"../errors.js";import{logError as r}from"../log.js";import{getPendingUpdatesDetails as l,hasPendingUpdates as o,isInstallationRelevantToCurrentProject as u,loadInstalledPluginsFromDisk as i}from"./installedPluginsManager.js";import{getDeclaredMarketplaces as s,loadKnownMarketplacesConfig as p,refreshMarketplace as c}from"./marketplaceManager.js";import{parsePluginIdentifier as d}from"./pluginIdentifier.js";import{isMarketplaceAutoUpdate as f}from"./schemas.js";let g=null,m=null;export function onPluginsAutoUpdated(e){return g=e,null!==m&&m.length>0&&(e(m),m=null),()=>{g=null}}export function getAutoUpdatedPluginNames(){return o()?l().map(e=>d(e.pluginId).name):[]}export async function updatePluginsForMarketplaces(t){const r=i(),l=Object.keys(r.plugins);if(0===l.length)return[];return(await Promise.allSettled(l.map(async l=>{const{marketplace:o}=d(l);if(!o||!t.has(o.toLowerCase()))return null;const i=r.plugins[l];if(!i||0===i.length)return null;const s=i.filter(u);return 0===s.length?null:async function(t,r){let l=!1;for(const{scope:o}of r)try{const n=await e(t,o);n.success&&!n.alreadyUpToDate?(l=!0,a(`Plugin autoupdate: updated ${t} from ${n.oldVersion} to ${n.newVersion}`)):n.alreadyUpToDate||a(`Plugin autoupdate: failed to update ${t}: ${n.message}`,{level:"warn"})}catch(e){a(`Plugin autoupdate: error updating ${t}: ${n(e)}`,{level:"warn"})}return l?t:null}(l,s)}))).filter(e=>"fulfilled"===e.status&&null!==e.value).map(e=>e.value)}export function autoUpdateMarketplacesAndPluginsInBackground(){(async()=>{if(t())a("Plugin autoupdate: skipped (auto-updater disabled)");else try{const e=await async function(){const e=await p(),t=s(),a=new Set;for(const[n,r]of Object.entries(e)){const e=t[n]?.autoUpdate;(void 0!==e?e:f(n,r))&&a.add(n.toLowerCase())}return a}();if(0===e.size)return;const t=(await Promise.allSettled(Array.from(e).map(async e=>{try{await c(e,void 0,{disableCredentialHelper:!0})}catch(t){a(`Plugin autoupdate: failed to refresh marketplace ${e}: ${n(t)}`,{level:"warn"})}}))).filter(e=>"rejected"===e.status);t.length>0&&a(`Plugin autoupdate: ${t.length} marketplace refresh(es) failed`,{level:"warn"}),a("Plugin autoupdate: checking installed plugins");const r=await async function(e){return updatePluginsForMarketplaces(e)}(e);r.length>0&&(g?g(r):m=r)}catch(e){r(e)}})()}
@@ -1 +1 @@
1
- import{uninstallPluginOp as e}from"../../services/plugins/pluginOperations.js";import{logForDebugging as s}from"../debug.js";import{errorMessage as t}from"../errors.js";import{loadInstalledPluginsV2 as n}from"./installedPluginsManager.js";import{getMarketplace as o,loadKnownMarketplacesConfigSafe as i}from"./marketplaceManager.js";import{addFlaggedPlugin as a,getFlaggedPlugins as l,loadFlaggedPlugins as r}from"./pluginFlagging.js";export function detectDelistedPlugins(e,s,t){const n=new Set(s.plugins.map(e=>e.name)),o=`@${t}`,i=[];for(const s of Object.keys(e.plugins)){if(!s.endsWith(o))continue;const e=s.slice(0,-o.length);n.has(e)||i.push(s)}return i}export async function detectAndUninstallDelistedPlugins(){await r();const c=n(),g=l(),u=await i(),p=[];for(const n of Object.keys(u))try{const i=await o(n);if(!i.forceRemoveDeletedPlugins)continue;const l=detectDelistedPlugins(c,i,n);for(const n of l){if(n in g)continue;const o=c.plugins[n]??[];if(o.some(e=>"user"===e.scope||"project"===e.scope||"local"===e.scope)){for(const i of o){const{scope:o}=i;if("user"===o||"project"===o||"local"===o)try{await e(n,o)}catch(e){s(`Failed to auto-uninstall delisted plugin ${n} from ${o}: ${t(e)}`,{level:"error"})}}await a(n),p.push(n)}}}catch(e){s(`Failed to check for delisted plugins in "${n}": ${t(e)}`,{level:"warn"})}return p}
1
+ import{uninstallPluginOp as e}from"../../services/plugins/pluginOperations.js";import{logForDebugging as t}from"../debug.js";import{errorMessage as o}from"../errors.js";import{loadInstalledPluginsV2 as n}from"./installedPluginsManager.js";import{getMarketplace as s,loadKnownMarketplacesConfigSafe as i}from"./marketplaceManager.js";import{addFlaggedPlugin as r,getFlaggedPlugins as c,loadFlaggedPlugins as l}from"./pluginFlagging.js";export function detectDelistedPlugins(e,t,o){const n=new Set(t.plugins.map(e=>e.name)),s=`@${o}`,i=[];for(const t of Object.keys(e.plugins)){if(!t.endsWith(s))continue;const e=t.slice(0,-s.length);n.has(e)||i.push(t)}return i}export async function detectAndUninstallDelistedPlugins(){await l();const a=n(),p=c(),u=await i(),f=[];for(const n of Object.keys(u))try{const i=await s(n);if(!i.forceRemoveDeletedPlugins)continue;const c=detectDelistedPlugins(a,i,n);for(const n of c){if(n in p)continue;const s=a.plugins[n]??[];if(s.some(e=>"user"===e.scope||"project"===e.scope||"local"===e.scope)){for(const i of s){const{scope:s}=i;if("user"===s||"project"===s||"local"===s)try{await e(n,s)}catch(e){t(`Failed to auto-uninstall delisted plugin ${n} from ${s}: ${o(e)}`,{level:"error"})}}await r(n),f.push(n)}}}catch(e){t(`Failed to check for delisted plugins in "${n}": ${o(e)}`,{level:"warn"})}return f}
@@ -1 +1 @@
1
- import{mkdirSync as t}from"fs";import{readdir as r,rm as e,stat as i}from"fs/promises";import{delimiter as s,join as a}from"path";import{getUseCoworkPlugins as o}from"../../bootstrap/state.js";import{logForDebugging as n}from"../debug.js";import{getClaudeConfigHomeDir as c,isEnvTruthy as l}from"../envUtils.js";import{errorMessage as p,isFsInaccessible as u}from"../errors.js";import{formatFileSize as D}from"../format.js";import{expandTilde as g}from"../permissions/pathValidation.js";export function getPluginsDirectory(){const t=process.env.CONTEXT_CODE_PLUGIN_CACHE_DIR??process.env.CLAUDE_CODE_PLUGIN_CACHE_DIR;return t?g(t):a(c(),o()||l(process.env.CONTEXT_CODE_USE_COWORK_PLUGINS)||l(process.env.CLAUDE_CODE_USE_COWORK_PLUGINS)?"cowork_plugins":"plugins")}export function getPluginSeedDirs(){const t=process.env.CONTEXT_CODE_PLUGIN_SEED_DIR??process.env.CLAUDE_CODE_PLUGIN_SEED_DIR;return t?t.split(s).filter(Boolean).map(g):[]}export function pluginDataDirPath(t){return a(getPluginsDirectory(),"data",function(t){return t.replace(/[^a-zA-Z0-9\-_]/g,"-")}(t))}export function getPluginDataDir(r){const e=pluginDataDirPath(r);return t(e,{recursive:!0}),e}export async function getPluginDataDirSize(t){const e=pluginDataDirPath(t);let s=0;const walk=async t=>{for(const e of await r(t,{withFileTypes:!0})){const r=a(t,e.name);if(e.isDirectory())await walk(r);else try{s+=(await i(r)).size}catch{}}};try{await walk(e)}catch(t){if(u(t))return null;throw t}return 0===s?null:{bytes:s,human:D(s)}}export async function deletePluginDataDir(t){const r=pluginDataDirPath(t);try{await e(r,{recursive:!0,force:!0})}catch(t){n(`Failed to delete plugin data dir ${r}: ${p(t)}`,{level:"warn"})}}
1
+ import{mkdirSync as t}from"fs";import{readdir as r,rm as e,stat as o}from"fs/promises";import{delimiter as i,join as n}from"path";import{getUseCoworkPlugins as s}from"../../bootstrap/state.js";import{logForDebugging as a}from"../debug.js";import{getClaudeConfigHomeDir as c,isEnvTruthy as p}from"../envUtils.js";import{errorMessage as u,isFsInaccessible as D}from"../errors.js";import{formatFileSize as l}from"../format.js";import{expandTilde as _}from"../permissions/pathValidation.js";const f="cowork_plugins";export function getPluginsDirectory(){const t=process.env.CONTEXT_CODE_PLUGIN_CACHE_DIR??process.env.CLAUDE_CODE_PLUGIN_CACHE_DIR;return t?_(t):n(c(),s()||p(process.env.CONTEXT_CODE_USE_COWORK_PLUGINS)||p(process.env.CLAUDE_CODE_USE_COWORK_PLUGINS)?f:"plugins")}export function getPluginSeedDirs(){const t=process.env.CONTEXT_CODE_PLUGIN_SEED_DIR??process.env.CLAUDE_CODE_PLUGIN_SEED_DIR;return t?t.split(i).filter(Boolean).map(_):[]}export function pluginDataDirPath(t){return n(getPluginsDirectory(),"data",function(t){return t.replace(/[^a-zA-Z0-9\-_]/g,"-")}(t))}export function getPluginDataDir(r){const e=pluginDataDirPath(r);return t(e,{recursive:!0}),e}export async function getPluginDataDirSize(t){const e=pluginDataDirPath(t);let i=0;const walk=async t=>{for(const e of await r(t,{withFileTypes:!0})){const r=n(t,e.name);if(e.isDirectory())await walk(r);else try{i+=(await o(r)).size}catch{}}};try{await walk(e)}catch(t){if(D(t))return null;throw t}return 0===i?null:{bytes:i,human:l(i)}}export async function deletePluginDataDir(t){const r=pluginDataDirPath(t);try{await e(r,{recursive:!0,force:!0})}catch(t){a(`Failed to delete plugin data dir ${r}: ${u(t)}`,{level:"warn"})}}
@@ -1 +1 @@
1
- import{randomBytes as t}from"crypto";import{readFile as e,rename as n,unlink as i,writeFile as o}from"fs/promises";import{join as s}from"path";import{logForDebugging as a}from"../debug.js";import{getFsImplementation as r}from"../fsOperations.js";import{logError as g}from"../log.js";import{jsonParse as l,jsonStringify as c}from"../slowOperations.js";import{getPluginsDirectory as u}from"./pluginDirectories.js";let f=null;function getFlaggedPluginsPath(){return s(u(),"flagged-plugins.json")}async function readFromDisk(){try{return function(t){const e=l(t);if("object"!=typeof e||null===e||!("plugins"in e)||"object"!=typeof e.plugins||null===e.plugins)return{};const n=e.plugins,i={};for(const[t,e]of Object.entries(n))if(e&&"object"==typeof e&&"flaggedAt"in e&&"string"==typeof e.flaggedAt){const n={flaggedAt:e.flaggedAt};"seenAt"in e&&"string"==typeof e.seenAt&&(n.seenAt=e.seenAt),i[t]=n}return i}(await e(getFlaggedPluginsPath(),{encoding:"utf-8"}))}catch{return{}}}async function writeToDisk(e){const s=getFlaggedPluginsPath(),a=`${s}.${t(8).toString("hex")}.tmp`;try{await r().mkdir(u());const t=c({plugins:e},null,2);await o(a,t,{encoding:"utf-8",mode:384}),await n(a,s),f=e}catch(t){g(t);try{await i(a)}catch{}}}export async function loadFlaggedPlugins(){const t=await readFromDisk(),e=Date.now();let n=!1;for(const[i,o]of Object.entries(t))o.seenAt&&e-new Date(o.seenAt).getTime()>=1728e5&&(delete t[i],n=!0);f=t,n&&await writeToDisk(t)}export function getFlaggedPlugins(){return f??{}}export async function addFlaggedPlugin(t){null===f&&(f=await readFromDisk());const e={...f,[t]:{flaggedAt:(new Date).toISOString()}};await writeToDisk(e),a(`Flagged plugin: ${t}`)}export async function markFlaggedPluginsSeen(t){null===f&&(f=await readFromDisk());const e=(new Date).toISOString();let n=!1;const i={...f};for(const o of t){const t=i[o];t&&!t.seenAt&&(i[o]={...t,seenAt:e},n=!0)}n&&await writeToDisk(i)}export async function removeFlaggedPlugin(t){if(null===f&&(f=await readFromDisk()),!(t in f))return;const{[t]:e,...n}=f;f=n,await writeToDisk(n)}
1
+ import{randomBytes as t}from"crypto";import{readFile as e,rename as n,unlink as o,writeFile as i}from"fs/promises";import{join as r}from"path";import{logForDebugging as a}from"../debug.js";import{getFsImplementation as s}from"../fsOperations.js";import{logError as g}from"../log.js";import{jsonParse as l,jsonStringify as c}from"../slowOperations.js";import{getPluginsDirectory as u}from"./pluginDirectories.js";let f=null;function getFlaggedPluginsPath(){return r(u(),"flagged-plugins.json")}async function readFromDisk(){try{return function(t){const e=l(t);if("object"!=typeof e||null===e||!("plugins"in e)||"object"!=typeof e.plugins||null===e.plugins)return{};const n=e.plugins,o={};for(const[t,e]of Object.entries(n))if(e&&"object"==typeof e&&"flaggedAt"in e&&"string"==typeof e.flaggedAt){const n={flaggedAt:e.flaggedAt};"seenAt"in e&&"string"==typeof e.seenAt&&(n.seenAt=e.seenAt),o[t]=n}return o}(await e(getFlaggedPluginsPath(),{encoding:"utf-8"}))}catch{return{}}}async function writeToDisk(e){const r=getFlaggedPluginsPath(),a=`${r}.${t(8).toString("hex")}.tmp`;try{await s().mkdir(u());const t=c({plugins:e},null,2);await i(a,t,{encoding:"utf-8",mode:384}),await n(a,r),f=e}catch(t){g(t);try{await o(a)}catch{}}}export async function loadFlaggedPlugins(){const t=await readFromDisk(),e=Date.now();let n=!1;for(const[o,i]of Object.entries(t))i.seenAt&&e-new Date(i.seenAt).getTime()>=1728e5&&(delete t[o],n=!0);f=t,n&&await writeToDisk(t)}export function getFlaggedPlugins(){return f??{}}export async function addFlaggedPlugin(t){null===f&&(f=await readFromDisk());const e={...f,[t]:{flaggedAt:(new Date).toISOString()}};await writeToDisk(e),a(`Flagged plugin: ${t}`)}export async function markFlaggedPluginsSeen(t){null===f&&(f=await readFromDisk());const e=(new Date).toISOString();let n=!1;const o={...f};for(const i of t){const t=o[i];t&&!t.seenAt&&(o[i]={...t,seenAt:e},n=!0)}n&&await writeToDisk(o)}export async function removeFlaggedPlugin(t){if(null===f&&(f=await readFromDisk()),!(t in f))return;const{[t]:e,...n}=f;f=n,await writeToDisk(n)}
@@ -1 +1 @@
1
- import{randomBytes as e}from"crypto";import{rename as t,rm as a}from"fs/promises";import{dirname as n,join as r,resolve as s,sep as i}from"path";import{logEvent as o}from"../../services/analytics/index.js";import{getCwd as l}from"../cwd.js";import{toError as c}from"../errors.js";import{getFsImplementation as u}from"../fsOperations.js";import{logError as p}from"../log.js";import{getSettingsForSource as m,updateSettingsForSource as d}from"../settings/settings.js";import{buildPluginTelemetryFields as g}from"../telemetry/pluginTelemetry.js";import{clearAllCaches as f}from"./cacheUtils.js";import{formatDependencyCountSuffix as y,getEnabledPluginIdsForScope as h,resolveDependencyClosure as k}from"./dependencyResolver.js";import{addInstalledPlugin as w,getGitCommitSha as P}from"./installedPluginsManager.js";import{getManagedPluginNames as b}from"./managedPlugins.js";import{getMarketplaceCacheOnly as v,getPluginById as I}from"./marketplaceManager.js";import{isOfficialMarketplaceName as $,parsePluginIdentifier as j,scopeToSettingSource as C}from"./pluginIdentifier.js";import{cachePlugin as S,getVersionedCachePath as D,getVersionedZipCachePath as O}from"./pluginLoader.js";import{isPluginBlockedByPolicy as x}from"./pluginPolicy.js";import{calculatePluginVersion as N}from"./pluginVersioning.js";import{isLocalPluginSource as R}from"./schemas.js";import{convertDirectoryToZipInPlace as T,isPluginZipCacheEnabled as _}from"./zipCache.js";export function getCurrentTimestamp(){return(new Date).toISOString()}export function validatePathWithinBase(e,t){const a=s(e,t),n=s(e)+i;if(!a.startsWith(n)&&a!==s(e))throw new Error(`Path traversal detected: "${t}" would escape the base directory`);return a}export async function cacheAndRegisterPlugin(s,o,l="user",c,p){const m="string"==typeof o.source&&p?p:o.source,d=await S(m,{manifest:o}),g=p||d.path,f=d.gitCommitSha??await P(g),y=getCurrentTimestamp(),h=await N(s,o.source,d.manifest,g,o.version,d.gitCommitSha),k=D(s,h);let b=d.path;if(d.path!==k){await u().mkdir(n(k)),await a(k,{recursive:!0,force:!0});const s=d.path.endsWith(i)?d.path:d.path+i;if(k.startsWith(s)){const a=r(n(d.path),`.claude-plugin-temp-${Date.now()}-${e(4).toString("hex")}`);await t(d.path,a),await u().mkdir(n(k)),await t(a,k)}else await t(d.path,k);b=k}if(_()){const e=O(s,h);await T(b,e),b=e}return w(s,{version:h,installedAt:y,lastUpdated:y,installPath:b,gitCommitSha:f},l,c),b}export function registerPluginInstallation(e,t="user",a){const n=getCurrentTimestamp();w(e.pluginId,{version:e.version||"unknown",installedAt:n,lastUpdated:n,installPath:e.installPath},t,a)}export function parsePluginId(e){const t=e.split("@");return 2===t.length&&t[0]&&t[1]?{name:t[0],marketplace:t[1]}:null}export function formatResolutionError(e){switch(e.reason){case"cycle":return`Dependency cycle: ${e.chain.join(" → ")}`;case"cross-marketplace":{const t=j(e.dependency).marketplace,a=t?`marketplace "${t}"`:"a different marketplace",n=t?` Add "${t}" to allowCrossMarketplaceDependenciesOn in the ROOT marketplace's marketplace.json (the marketplace of the plugin you're installing — only its allowlist applies; no transitive trust).`:"";return`Dependency "${e.dependency}" (required by ${e.requiredBy}) is in ${a}, which is not in the allowlist — cross-marketplace dependencies are blocked by default. Install it manually first.${n}`}case"not-found":{const{marketplace:t}=j(e.missing);return t?`Dependency "${e.missing}" (required by ${e.requiredBy}) not found. Is the "${t}" marketplace added?`:`Dependency "${e.missing}" (required by ${e.requiredBy}) not found in any configured marketplace`}}}export async function installResolvedPlugin({pluginId:e,entry:t,scope:a,marketplaceInstallLocation:n}){const r=C(a);if(x(e))return{ok:!1,reason:"blocked-by-policy",pluginName:t.name};const s=new Map;if(R(t.source)&&!n)return{ok:!1,reason:"local-source-no-location",pluginName:t.name};n&&s.set(e,{entry:t,marketplaceInstallLocation:n});const i=j(e).marketplace,o=new Set((i?(await v(i))?.allowCrossMarketplaceDependenciesOn:void 0)??[]),c=await k(e,async a=>{if(s.has(a))return s.get(a).entry;if(a===e)return t;const n=await I(a);return n&&s.set(a,n),n?.entry??null},h(r),o);if(!c.ok)return{ok:!1,reason:"resolution-failed",resolution:c};for(const a of c.closure)if(a!==e&&x(a))return{ok:!1,reason:"dependency-blocked-by-policy",pluginName:t.name,blockedDependency:a};const u={};for(const e of c.closure)u[e]=!0;const{error:p}=d(r,{enabledPlugins:{...m(r)?.enabledPlugins,...u}});if(p)return{ok:!1,reason:"settings-write-failed",message:p.message};const g="user"!==a?l():void 0;for(const n of c.closure){let r,i=s.get(n);if(!i&&n===e){const e=(await I(n))?.marketplaceInstallLocation;e&&(i={entry:t,marketplaceInstallLocation:e})}if(!i)continue;const{source:o}=i.entry;R(o)&&(r=validatePathWithinBase(i.marketplaceInstallLocation,o)),await cacheAndRegisterPlugin(n,i.entry,a,g,r)}f();const w=y(c.closure.filter(t=>t!==e));return{ok:!0,closure:c.closure,depNote:w}}export async function installPluginFromMarketplace({pluginId:e,entry:t,marketplaceName:a,scope:n="user",trigger:r="user"}){try{const s=await I(e),i=s?.marketplaceInstallLocation,l=await installResolvedPlugin({pluginId:e,entry:t,scope:n,marketplaceInstallLocation:i});if(!l.ok)switch(l.reason){case"local-source-no-location":return{success:!1,error:`Cannot install local plugin "${l.pluginName}" without marketplace install location`};case"settings-write-failed":return{success:!1,error:`Failed to update settings: ${l.message}`};case"resolution-failed":return{success:!1,error:formatResolutionError(l.resolution)};case"blocked-by-policy":return{success:!1,error:`Plugin "${l.pluginName}" is blocked by your organization's policy and cannot be installed`};case"dependency-blocked-by-policy":return{success:!1,error:`Cannot install "${l.pluginName}": dependency "${l.blockedDependency}" is blocked by your organization's policy`}}return o("tengu_plugin_installed",{_PROTO_plugin_name:t.name,_PROTO_marketplace_name:a,plugin_id:$(a)?e:"third-party",trigger:r,install_source:"hint"===r?"ui-suggestion":"ui-discover",...g(t.name,a,b()),...t.version&&{version:t.version}}),{success:!0,message:`✓ Installed ${t.name}${l.depNote}. Run /reload-plugins to activate.`}}catch(e){const t=e instanceof Error?e.message:String(e);return p(c(e)),{success:!1,error:`Failed to install: ${t}`}}}
1
+ import{randomBytes as e}from"crypto";import{rename as t,rm as n}from"fs/promises";import{dirname as r,join as a,resolve as o,sep as i}from"path";import{logEvent as s}from"../../services/analytics/index.js";import{getCwd as l}from"../cwd.js";import{toError as c}from"../errors.js";import{getFsImplementation as p}from"../fsOperations.js";import{logError as u}from"../log.js";import{getSettingsForSource as m,updateSettingsForSource as d}from"../settings/settings.js";import{buildPluginTelemetryFields as g}from"../telemetry/pluginTelemetry.js";import{clearAllCaches as f}from"./cacheUtils.js";import{formatDependencyCountSuffix as y,getEnabledPluginIdsForScope as h,resolveDependencyClosure as k}from"./dependencyResolver.js";import{addInstalledPlugin as w,getGitCommitSha as b}from"./installedPluginsManager.js";import{getManagedPluginNames as $}from"./managedPlugins.js";import{getMarketplaceCacheOnly as P,getPluginById as j}from"./marketplaceManager.js";import{isOfficialMarketplaceName as v,parsePluginIdentifier as I,scopeToSettingSource as C}from"./pluginIdentifier.js";import{cachePlugin as R,getVersionedCachePath as x,getVersionedZipCachePath as D}from"./pluginLoader.js";import{isPluginBlockedByPolicy as O}from"./pluginPolicy.js";import{calculatePluginVersion as _}from"./pluginVersioning.js";import{isLocalPluginSource as N}from"./schemas.js";import{convertDirectoryToZipInPlace as L,isPluginZipCacheEnabled as S}from"./zipCache.js";export function getCurrentTimestamp(){return(new Date).toISOString()}export function validatePathWithinBase(e,t){const n=o(e,t),r=o(e)+i;if(!n.startsWith(r)&&n!==o(e))throw new Error(`Path traversal detected: "${t}" would escape the base directory`);return n}export async function cacheAndRegisterPlugin(o,s,l="user",c,u){const m="string"==typeof s.source&&u?u:s.source,d=await R(m,{manifest:s}),g=u||d.path,f=d.gitCommitSha??await b(g),y=getCurrentTimestamp(),h=await _(o,s.source,d.manifest,g,s.version,d.gitCommitSha),k=x(o,h);let $=d.path;if(d.path!==k){await p().mkdir(r(k)),await n(k,{recursive:!0,force:!0});const o=d.path.endsWith(i)?d.path:d.path+i;if(k.startsWith(o)){const n=a(r(d.path),`.claude-plugin-temp-${Date.now()}-${e(4).toString("hex")}`);await t(d.path,n),await p().mkdir(r(k)),await t(n,k)}else await t(d.path,k);$=k}if(S()){const e=D(o,h);await L($,e),$=e}return w(o,{version:h,installedAt:y,lastUpdated:y,installPath:$,gitCommitSha:f},l,c),$}export function registerPluginInstallation(e,t="user",n){const r=getCurrentTimestamp();w(e.pluginId,{version:e.version||"unknown",installedAt:r,lastUpdated:r,installPath:e.installPath},t,n)}export function parsePluginId(e){const t=e.split("@");return 2===t.length&&t[0]&&t[1]?{name:t[0],marketplace:t[1]}:null}export function formatResolutionError(e){switch(e.reason){case"cycle":return`Dependency cycle: ${e.chain.join(" → ")}`;case"cross-marketplace":{const t=I(e.dependency).marketplace,n=t?`marketplace "${t}"`:"a different marketplace",r=t?` Add "${t}" to allowCrossMarketplaceDependenciesOn in the ROOT marketplace's marketplace.json (the marketplace of the plugin you're installing — only its allowlist applies; no transitive trust).`:"";return`Dependency "${e.dependency}" (required by ${e.requiredBy}) is in ${n}, which is not in the allowlist — cross-marketplace dependencies are blocked by default. Install it manually first.${r}`}case"not-found":{const{marketplace:t}=I(e.missing);return t?`Dependency "${e.missing}" (required by ${e.requiredBy}) not found. Is the "${t}" marketplace added?`:`Dependency "${e.missing}" (required by ${e.requiredBy}) not found in any configured marketplace`}}}export async function installResolvedPlugin({pluginId:e,entry:t,scope:n,marketplaceInstallLocation:r}){const a=C(n);if(O(e))return{ok:!1,reason:"blocked-by-policy",pluginName:t.name};const o=new Map;if(N(t.source)&&!r)return{ok:!1,reason:"local-source-no-location",pluginName:t.name};r&&o.set(e,{entry:t,marketplaceInstallLocation:r});const i=I(e).marketplace,s=new Set((i?(await P(i))?.allowCrossMarketplaceDependenciesOn:void 0)??[]),c=await k(e,async n=>{if(o.has(n))return o.get(n).entry;if(n===e)return t;const r=await j(n);return r&&o.set(n,r),r?.entry??null},h(a),s);if(!c.ok)return{ok:!1,reason:"resolution-failed",resolution:c};for(const n of c.closure)if(n!==e&&O(n))return{ok:!1,reason:"dependency-blocked-by-policy",pluginName:t.name,blockedDependency:n};const p={};for(const e of c.closure)p[e]=!0;const{error:u}=d(a,{enabledPlugins:{...m(a)?.enabledPlugins,...p}});if(u)return{ok:!1,reason:"settings-write-failed",message:u.message};const g="user"!==n?l():void 0;for(const r of c.closure){let a,i=o.get(r);if(!i&&r===e){const e=(await j(r))?.marketplaceInstallLocation;e&&(i={entry:t,marketplaceInstallLocation:e})}if(!i)continue;const{source:s}=i.entry;N(s)&&(a=validatePathWithinBase(i.marketplaceInstallLocation,s)),await cacheAndRegisterPlugin(r,i.entry,n,g,a)}f();const w=y(c.closure.filter(t=>t!==e));return{ok:!0,closure:c.closure,depNote:w}}export async function installPluginFromMarketplace({pluginId:e,entry:t,marketplaceName:n,scope:r="user",trigger:a="user"}){try{const o=await j(e),i=o?.marketplaceInstallLocation,l=await installResolvedPlugin({pluginId:e,entry:t,scope:r,marketplaceInstallLocation:i});if(!l.ok)switch(l.reason){case"local-source-no-location":return{success:!1,error:`Cannot install local plugin "${l.pluginName}" without marketplace install location`};case"settings-write-failed":return{success:!1,error:`Failed to update settings: ${l.message}`};case"resolution-failed":return{success:!1,error:formatResolutionError(l.resolution)};case"blocked-by-policy":return{success:!1,error:`Plugin "${l.pluginName}" is blocked by your organization's policy and cannot be installed`};case"dependency-blocked-by-policy":return{success:!1,error:`Cannot install "${l.pluginName}": dependency "${l.blockedDependency}" is blocked by your organization's policy`}}return s("tengu_plugin_installed",{_PROTO_plugin_name:t.name,_PROTO_marketplace_name:n,plugin_id:v(n)?e:"third-party",trigger:a,install_source:"hint"===a?"ui-suggestion":"ui-discover",...g(t.name,n,$()),...t.version&&{version:t.version}}),{success:!0,message:`✓ Installed ${t.name}${l.depNote}. Run /reload-plugins to activate.`}}catch(e){const t=e instanceof Error?e.message:String(e);return u(c(e)),{success:!1,error:`Failed to install: ${t}`}}}
@@ -1 +1 @@
1
- import{copyFile as e,readdir as t,readFile as a,readlink as n,realpath as o,rename as s,rm as r,rmdir as i,stat as l,symlink as c}from"fs/promises";import u from"lodash-es/memoize.js";import{basename as m,dirname as p,join as f,relative as h,resolve as d,sep as g}from"path";import{getInlinePlugins as y}from"../../bootstrap/state.js";import{BUILTIN_MARKETPLACE_NAME as P,getBuiltinPlugins as w}from"../../plugins/builtinPlugins.js";import{logForDebugging as $}from"../debug.js";import{isEnvTruthy as k}from"../envUtils.js";import{errorMessage as v,getErrnoPath as b,isENOENT as S,isFsInaccessible as C,toError as E}from"../errors.js";import{execFileNoThrow as A,execFileNoThrowWithCwd as j}from"../execFileNoThrow.js";import{pathExists as x}from"../file.js";import{getFsImplementation as F}from"../fsOperations.js";import{gitExe as O}from"../git.js";import{lazySchema as N}from"../lazySchema.js";import{logError as I}from"../log.js";import{getSettings_DEPRECATED as _}from"../settings/settings.js";import{clearPluginSettingsBase as T,getPluginSettingsBase as L,resetSettingsCache as D,setPluginSettingsBase as M}from"../settings/settingsCache.js";import{SettingsSchema as V}from"../settings/types.js";import{jsonParse as Z,jsonStringify as U}from"../slowOperations.js";import{getAddDirEnabledPlugins as z}from"./addDirPluginSettings.js";import{verifyAndDemote as H}from"./dependencyResolver.js";import{classifyFetchError as R,logPluginFetch as B}from"./fetchTelemetry.js";import{checkGitAvailable as G}from"./gitAvailability.js";import{getInMemoryInstalledPlugins as W}from"./installedPluginsManager.js";import{getManagedPluginNames as J}from"./managedPlugins.js";import{formatSourceForDisplay as K,getBlockedMarketplaces as X,getStrictKnownMarketplaces as q,isSourceAllowedByPolicy as Y,isSourceInBlocklist as Q}from"./marketplaceHelpers.js";import{getMarketplaceCacheOnly as ee,getPluginByIdCacheOnly as te,loadKnownMarketplacesConfigSafe as ae}from"./marketplaceManager.js";import{getPluginSeedDirs as ne,getPluginsDirectory as oe}from"./pluginDirectories.js";import{parsePluginIdentifier as se}from"./pluginIdentifier.js";import{validatePathWithinBase as re}from"./pluginInstallationHelpers.js";import{calculatePluginVersion as ie}from"./pluginVersioning.js";import{PluginHooksSchema as le,PluginIdSchema as ce,PluginManifestSchema as ue}from"./schemas.js";import{convertDirectoryToZipInPlace as me,extractZipToDirectory as pe,getSessionPluginCachePath as fe,isPluginZipCacheEnabled as he}from"./zipCache.js";export function getPluginCachePath(){return f(oe(),"cache")}export function getVersionedCachePathIn(e,t,a){const{name:n,marketplace:o}=se(t),s=(o||"unknown").replace(/[^a-zA-Z0-9\-_]/g,"-"),r=(n||t).replace(/[^a-zA-Z0-9\-_]/g,"-"),i=a.replace(/[^a-zA-Z0-9\-_.]/g,"-");return f(e,"cache",s,r,i)}export function getVersionedCachePath(e,t){return getVersionedCachePathIn(oe(),e,t)}export function getVersionedZipCachePath(e,t){return`${getVersionedCachePath(e,t)}.zip`}async function probeSeedCache(e,a){for(const n of ne()){const o=getVersionedCachePathIn(n,e,a);try{if((await t(o)).length>0)return o}catch{}}return null}export async function probeSeedCacheAnyVersion(e){for(const a of ne()){const n=p(getVersionedCachePathIn(a,e,"_"));try{const e=await t(n);if(1!==e.length)continue;const a=f(n,e[0]);if((await t(a)).length>0)return a}catch{}}return null}export function getLegacyCachePath(e){const t=getPluginCachePath();return f(t,e.replace(/[^a-zA-Z0-9\-_]/g,"-"))}export async function resolvePluginPath(e,t){if(t){const a=getVersionedCachePath(e,t);if(await x(a))return a}const a=getLegacyCachePath(se(e).name||e);return await x(a)?a:t?getVersionedCachePath(e,t):a}export async function copyDir(a,s){await F().mkdir(s);const r=await t(a,{withFileTypes:!0});for(const t of r){const r=f(a,t.name),i=f(s,t.name);if(t.isDirectory())await copyDir(r,i);else if(t.isFile())await e(r,i);else if(t.isSymbolicLink()){const e=await n(r);let t,l;try{t=await o(r)}catch{await c(e,i);continue}try{l=await o(a)}catch{l=a}const u=l.endsWith(g)?l:l+g;if(t.startsWith(u)||t===l){const e=h(l,t),a=f(s,e),n=h(p(i),a);await c(n,i)}else await c(t,i)}}}export async function copyPluginToVersionedCache(e,a,n,o,s){const l=he(),c=getVersionedCachePath(a,n),u=getVersionedZipCachePath(a,n);if(l){if(await x(u))return $(`Plugin ${a} version ${n} already cached at ${u}`),u}else if(await x(c)){if((await t(c)).length>0)return $(`Plugin ${a} version ${n} already cached at ${c}`),c;$(`Removing empty cache directory for ${a} at ${c}`),await i(c)}const m=await probeSeedCache(a,n);if(m)return $(`Using seed cache for ${a}@${n} at ${m}`),m;if(await F().mkdir(p(c)),o&&"string"==typeof o.source&&s){const e=re(s,o.source);$(`Copying source directory ${o.source} for plugin ${a}`);try{await copyDir(e,c)}catch(t){if(S(t)&&b(t)===e)throw new Error(`Plugin source directory not found: ${e} (from entry.source: ${o.source})`);throw t}}else $(`Copying plugin ${a} to versioned cache (fallback to full copy)`),await copyDir(e,c);const h=f(c,".git");if(await r(h,{recursive:!0,force:!0}),0===(await t(c)).length)throw new Error(`Failed to copy plugin ${a} to versioned cache: destination is empty after copy`);return l?(await me(c,u),$(`Successfully cached plugin ${a} as ZIP at ${u}`),u):($(`Successfully cached plugin ${a} at ${c}`),c)}function validateGitUrl(e){try{const t=new URL(e);if(!["https:","http:","file:"].includes(t.protocol)&&!/^git@[a-zA-Z0-9.-]+:/.test(e))throw new Error(`Invalid git URL protocol: ${t.protocol}. Only HTTPS, HTTP, file:// and SSH (git@) URLs are supported.`);return e}catch{if(/^git@[a-zA-Z0-9.-]+:/.test(e))return e;throw new Error(`Invalid git URL: ${e}`)}}export async function installFromNpm(e,t,a={}){const n=f(oe(),"npm-cache");await F().mkdir(n);const o=a.version?`${e}@${a.version}`:e,s=f(n,"node_modules",e);if(!await x(s)){$(`Installing npm package ${o} to cache`);const e=["install",o,"--prefix",n];a.registry&&e.push("--registry",a.registry);const t=await A("npm",e,{useCwd:!1});if(0!==t.code)throw new Error(`Failed to install npm package: ${t.stderr}`)}await copyDir(s,t),$(`Copied npm package ${e} from cache to ${t}`)}export async function gitClone(e,t,a,n){const o=["clone","--depth","1","--recurse-submodules","--shallow-submodules"];a&&o.push("--branch",a),n&&o.push("--no-checkout"),o.push(e,t);const s=performance.now(),r=await A(O(),o);if(0!==r.code)throw B("plugin_clone",e,"failure",performance.now()-s,R(r.stderr)),new Error(`Failed to clone repository: ${r.stderr}`);if(n){if(0!==(await j(O(),["fetch","--depth","1","origin",n],{cwd:t})).code){$(`Shallow fetch of SHA ${n} failed, falling back to unshallow fetch`);const a=await j(O(),["fetch","--unshallow"],{cwd:t});if(0!==a.code)throw B("plugin_clone",e,"failure",performance.now()-s,R(a.stderr)),new Error(`Failed to fetch commit ${n}: ${a.stderr}`)}const a=await j(O(),["checkout",n],{cwd:t});if(0!==a.code)throw B("plugin_clone",e,"failure",performance.now()-s,R(a.stderr)),new Error(`Failed to checkout commit ${n}: ${a.stderr}`)}B("plugin_clone",e,"success",performance.now()-s)}async function installFromGit(e,t,a,n){const o=validateGitUrl(e);await gitClone(o,t,a,n),$(`Cloned repository from ${o}${a?` (ref: ${a})`:""} to ${t}`)}export async function installFromGitSubdir(e,t,a,n,o){if(!await G())throw new Error("git-subdir plugin source requires git to be installed and on PATH. Install git (version 2.25 or later for sparse-checkout cone mode) and try again.");const i=function(e){return/^[a-zA-Z0-9-_.]+\/[a-zA-Z0-9-_.]+$/.test(e)?k(process.env.CONTEXT_CODE_REMOTE)||k(process.env.CLAUDE_CODE_REMOTE)?`https://github.com/${e}.git`:`git@github.com:${e}.git`:validateGitUrl(e)}(e),l=`${t}.clone`,c=["clone","--depth","1","--filter=tree:0","--no-checkout"];n&&c.push("--branch",n),c.push(i,l);const u=await A(O(),c);if(0!==u.code)throw new Error(`Failed to clone repository for git-subdir source: ${u.stderr}`);try{const r=await j(O(),["sparse-checkout","set","--cone","--",a],{cwd:l});if(0!==r.code)throw new Error(`git sparse-checkout set failed (git >= 2.25 required for cone mode): ${r.stderr}`);let c;if(o){if(0!==(await j(O(),["fetch","--depth","1","origin",o],{cwd:l})).code){$(`Shallow fetch of SHA ${o} failed for git-subdir, falling back to unshallow fetch`);const e=await j(O(),["fetch","--unshallow"],{cwd:l});if(0!==e.code)throw new Error(`Failed to fetch commit ${o}: ${e.stderr}`)}const e=await j(O(),["checkout",o],{cwd:l});if(0!==e.code)throw new Error(`Failed to checkout commit ${o}: ${e.stderr}`);c=o}else{const[e,t]=await Promise.all([j(O(),["checkout","HEAD"],{cwd:l}),j(O(),["rev-parse","HEAD"],{cwd:l})]);if(0!==e.code)throw new Error(`git checkout after sparse-checkout failed: ${e.stderr}`);0===t.code&&(c=t.stdout.trim())}const u=re(l,a);try{await s(u,t)}catch(e){if(S(e))throw new Error(`Subdirectory '${a}' not found in repository ${i}${n?` (ref: ${n})`:""}. Check that the path is correct and exists at the specified ref/sha.`);throw e}return $(`Extracted subdir ${a} from ${i}${n?` ref=${n}`:""}${c?` sha=${c}`:""} to ${t}`),c}finally{await r(l,{recursive:!0,force:!0})}}export function generateTemporaryCacheNameForPlugin(e){const t=Date.now(),a=Math.random().toString(36).substring(2,8);let n;if("string"==typeof e)n="local";else switch(e.source){case"npm":n="npm";break;case"pip":n="pip";break;case"github":n="github";break;case"url":n="git";break;case"git-subdir":n="subdir";break;default:n="unknown"}return`temp_${n}_${t}_${a}`}export async function cachePlugin(e,t){const n=getPluginCachePath();await F().mkdir(n);const o=generateTemporaryCacheNameForPlugin(e),i=f(n,o);let l,c=!1;try{if($(`Caching plugin from source: ${U(e)} to temporary path ${i}`),c=!0,"string"==typeof e)await async function(e,t){if(!await x(e))throw new Error(`Source path does not exist: ${e}`);await copyDir(e,t);const a=f(t,".git");await r(a,{recursive:!0,force:!0})}(e,i);else switch(e.source){case"npm":await installFromNpm(e.package,i,{registry:e.registry,version:e.version});break;case"github":await async function(e,t,a,n){if(!/^[a-zA-Z0-9-_.]+\/[a-zA-Z0-9-_.]+$/.test(e))throw new Error(`Invalid GitHub repository format: ${e}. Expected format: owner/repo`);return installFromGit(k(process.env.CONTEXT_CODE_REMOTE)||k(process.env.CLAUDE_CODE_REMOTE)?`https://github.com/${e}.git`:`git@github.com:${e}.git`,t,a,n)}(e.repo,i,e.ref,e.sha);break;case"url":await installFromGit(e.url,i,e.ref,e.sha);break;case"git-subdir":l=await installFromGitSubdir(e.url,i,e.path,e.ref,e.sha);break;case"pip":throw new Error("Python package plugins are not yet supported");default:throw new Error("Unsupported plugin source type")}}catch(e){if(c&&await x(i)){$(`Cleaning up failed installation at ${i}`);try{await r(i,{recursive:!0,force:!0})}catch(e){$(`Failed to clean up installation: ${e}`,{level:"error"})}}throw e}const u=f(i,".claude-plugin","plugin.json"),m=f(i,"plugin.json");let p;if(await x(u))try{const e=await a(u,{encoding:"utf-8"}),t=Z(e),n=ue().safeParse(t);if(!n.success){const e=n.error.issues.map(e=>`${e.path.join(".")}: ${e.message}`).join(", ");throw $(`Invalid manifest at ${u}: ${e}`,{level:"error"}),new Error(`Plugin has an invalid manifest file at ${u}. Validation errors: ${e}`)}p=n.data}catch(e){if(e instanceof Error&&e.message.includes("invalid manifest file"))throw e;const t=v(e);throw $(`Failed to parse manifest at ${u}: ${t}`,{level:"error"}),new Error(`Plugin has a corrupt manifest file at ${u}. JSON parse error: ${t}`)}else if(await x(m))try{const e=await a(m,{encoding:"utf-8"}),t=Z(e),n=ue().safeParse(t);if(!n.success){const e=n.error.issues.map(e=>`${e.path.join(".")}: ${e.message}`).join(", ");throw $(`Invalid legacy manifest at ${m}: ${e}`,{level:"error"}),new Error(`Plugin has an invalid manifest file at ${m}. Validation errors: ${e}`)}p=n.data}catch(e){if(e instanceof Error&&e.message.includes("invalid manifest file"))throw e;const t=v(e);throw $(`Failed to parse legacy manifest at ${m}: ${t}`,{level:"error"}),new Error(`Plugin has a corrupt manifest file at ${m}. JSON parse error: ${t}`)}else p=t?.manifest||{name:o,description:`Plugin cached from ${"string"==typeof e?e:e.source}`};const h=p.name.replace(/[^a-zA-Z0-9-_]/g,"-"),d=f(n,h);return await x(d)&&($(`Removing old cached version at ${d}`),await r(d,{recursive:!0,force:!0})),await s(i,d),$(`Successfully cached plugin ${p.name} to ${d}`),{path:d,manifest:p,...l&&{gitCommitSha:l}}}export async function loadPluginManifest(e,t,n){if(!await x(e))return{name:t,description:`Plugin from ${n}`};try{const n=await a(e,{encoding:"utf-8"}),o=Z(n),s=ue().safeParse(o);if(s.success)return s.data;const r=s.error.issues.map(e=>e.path.length>0?`${e.path.join(".")}: ${e.message}`:e.message).join(", ");throw $(`Plugin ${t} has an invalid manifest file at ${e}. Validation errors: ${r}`,{level:"error"}),new Error(`Plugin ${t} has an invalid manifest file at ${e}.\n\nValidation errors: ${r}`)}catch(a){if(a instanceof Error&&a.message.includes("invalid manifest file"))throw a;const n=v(a);throw $(`Plugin ${t} has a corrupt manifest file at ${e}. Parse error: ${n}`,{level:"error"}),new Error(`Plugin ${t} has a corrupt manifest file at ${e}.\n\nJSON parse error: ${n}`)}}async function loadPluginHooks(e,t){if(!await x(e))throw new Error(`Hooks file not found at ${e} for plugin ${t}. If the manifest declares hooks, the file must exist.`);const n=await a(e,{encoding:"utf-8"}),o=Z(n);return le().parse(o).hooks}async function validatePluginPaths(e,t,a,n,o,s,r,i){const l=await Promise.all(e.map(async e=>{const a=f(t,e);return{relPath:e,fullPath:a,exists:await x(a)}})),c=[];for(const{relPath:e,fullPath:t,exists:u}of l)u?c.push(t):($(`${s} path ${e} ${r} not found at ${t} for ${a}`,{level:"warn"}),I(new Error(`Plugin component file not found: ${t} for ${a}`)),i.push({type:"path-not-found",source:n,plugin:a,path:t,component:o}));return c}export async function createPluginFromPath(e,t,n,s,r=!0){const i=[],l=f(e,".claude-plugin","plugin.json"),c=await loadPluginManifest(l,s,t),u={name:c.name,manifest:c,path:e,source:t,repository:t,enabled:n},[m,p,h,d]=await Promise.all([!c.commands&&x(f(e,"commands")),!c.agents&&x(f(e,"agents")),!c.skills&&x(f(e,"skills")),!c.outputStyles&&x(f(e,"output-styles"))]),g=f(e,"commands");if(m&&(u.commandsPath=g),c.commands){const a=Object.values(c.commands)[0];if("object"==typeof c.commands&&!Array.isArray(c.commands)&&a&&"object"==typeof a&&("source"in a||"content"in a)){const a={},n=[],o=Object.entries(c.commands),s=await Promise.all(o.map(async([t,a])=>{if(!a||"object"!=typeof a)return{commandName:t,metadata:a,kind:"skip"};if(a.source){const n=f(e,a.source);return{commandName:t,metadata:a,kind:"source",fullPath:n,exists:await x(n)}}return a.content?{commandName:t,metadata:a,kind:"content"}:{commandName:t,metadata:a,kind:"skip"}}));for(const e of s)"skip"!==e.kind&&("content"!==e.kind?e.exists?(n.push(e.fullPath),a[e.commandName]=e.metadata):($(`Command ${e.commandName} path ${e.metadata.source} specified in manifest but not found at ${e.fullPath} for ${c.name}`,{level:"warn"}),I(new Error(`Plugin component file not found: ${e.fullPath} for ${c.name}`)),i.push({type:"path-not-found",source:t,plugin:c.name,path:e.fullPath,component:"commands"})):a[e.commandName]=e.metadata);n.length>0&&(u.commandsPaths=n),Object.keys(a).length>0&&(u.commandsMetadata=a)}else{const a=Array.isArray(c.commands)?c.commands:[c.commands],n=await Promise.all(a.map(async t=>{if("string"!=typeof t)return{cmdPath:t,kind:"invalid"};const a=f(e,t);return{cmdPath:t,kind:"path",fullPath:a,exists:await x(a)}})),o=[];for(const e of n)"invalid"!==e.kind?e.exists?o.push(e.fullPath):($(`Command path ${e.cmdPath} specified in manifest but not found at ${e.fullPath} for ${c.name}`,{level:"warn"}),I(new Error(`Plugin component file not found: ${e.fullPath} for ${c.name}`)),i.push({type:"path-not-found",source:t,plugin:c.name,path:e.fullPath,component:"commands"})):$(`Unexpected command format in manifest for ${c.name}`,{level:"error"});o.length>0&&(u.commandsPaths=o)}}const y=f(e,"agents");if(p&&(u.agentsPath=y),c.agents){const a=Array.isArray(c.agents)?c.agents:[c.agents],n=await validatePluginPaths(a,e,c.name,t,"agents","Agent","specified in manifest but",i);n.length>0&&(u.agentsPaths=n)}const P=f(e,"skills");if(h&&(u.skillsPath=P),c.skills){const a=Array.isArray(c.skills)?c.skills:[c.skills],n=await validatePluginPaths(a,e,c.name,t,"skills","Skill","specified in manifest but",i);n.length>0&&(u.skillsPaths=n)}const w=f(e,"output-styles");if(d&&(u.outputStylesPath=w),c.outputStyles){const a=Array.isArray(c.outputStyles)?c.outputStyles:[c.outputStyles],n=await validatePluginPaths(a,e,c.name,t,"output-styles","Output style","specified in manifest but",i);n.length>0&&(u.outputStylesPaths=n)}let k;const b=new Set,S=f(e,"hooks","hooks.json");if(await x(S))try{k=await loadPluginHooks(S,c.name);try{b.add(await o(S))}catch{b.add(S)}$(`Loaded hooks from standard location for plugin ${c.name}: ${S}`)}catch(e){const a=v(e);$(`Failed to load hooks for ${c.name}: ${a}`,{level:"error"}),I(E(e)),i.push({type:"hook-load-failed",source:t,plugin:c.name,hookPath:S,reason:a})}if(c.hooks){const a=Array.isArray(c.hooks)?c.hooks:[c.hooks];for(const n of a)if("string"==typeof n){const a=f(e,n);if(!await x(a)){$(`Hooks file ${n} specified in manifest but not found at ${a} for ${c.name}`,{level:"error"}),I(new Error(`Plugin component file not found: ${a} for ${c.name}`)),i.push({type:"path-not-found",source:t,plugin:c.name,path:a,component:"hooks"});continue}let s;try{s=await o(a)}catch{s=a}if(b.has(s)){if($(`Skipping duplicate hooks file for plugin ${c.name}: ${n} (resolves to already-loaded file: ${s})`),r){const e=`Duplicate hooks file detected: ${n} resolves to already-loaded file ${s}. The standard hooks/hooks.json is loaded automatically, so manifest.hooks should only reference additional hook files.`;I(new Error(e)),i.push({type:"hook-load-failed",source:t,plugin:c.name,hookPath:a,reason:e})}continue}try{const o=await loadPluginHooks(a,c.name);try{k=mergeHooksSettings(k,o),b.add(s),$(`Loaded and merged hooks from manifest for plugin ${c.name}: ${n}`)}catch(e){const o=v(e);$(`Failed to merge hooks from ${n} for ${c.name}: ${o}`,{level:"error"}),I(E(e)),i.push({type:"hook-load-failed",source:t,plugin:c.name,hookPath:a,reason:`Failed to merge: ${o}`})}}catch(e){const o=v(e);$(`Failed to load hooks from ${n} for ${c.name}: ${o}`,{level:"error"}),I(E(e)),i.push({type:"hook-load-failed",source:t,plugin:c.name,hookPath:a,reason:o})}}else"object"==typeof n&&(k=mergeHooksSettings(k,n))}k&&(u.hooksConfig=k);const A=await async function(e,t){const n=f(e,"settings.json");try{const e=await a(n,{encoding:"utf-8"}),s=Z(e);if("object"==typeof(o=s)&&null!==o&&!Array.isArray(o)){const e=parsePluginSettings(s);if(e)return $(`Loaded settings from settings.json for plugin ${t.name}`),e}}catch(e){C(e)||$(`Failed to parse settings.json for plugin ${t.name}: ${e}`,{level:"warn"})}var o;if(t.settings){const e=parsePluginSettings(t.settings);if(e)return $(`Loaded settings from manifest for plugin ${t.name}`),e}}(e,c);return A&&(u.settings=A),{plugin:u,errors:i}}const de=N(()=>V().pick({agent:!0}).strip());function parsePluginSettings(e){const t=de().safeParse(e);if(!t.success)return;const a=t.data;return 0!==Object.keys(a).length?a:void 0}function mergeHooksSettings(e,t){if(!e)return t;const a={...e};for(const[e,n]of Object.entries(t))a[e]?a[e]=[...a[e]||[],...n]:a[e]=n;return a}async function loadPluginsFromMarketplaces({cacheOnly:e}){const t=_(),a={...z(),...t.enabledPlugins||{}},n=[],o=[],s=Object.entries(a).filter(([e,t])=>{if(!ce().safeParse(e).success||void 0===t)return!1;const{marketplace:a}=se(e);return a!==P}),i=await ae(),c=q(),u=X(),m=null!==c||null!==u&&u.length>0,p=new Set(s.map(([e])=>se(e).marketplace).filter(e=>!!e)),h=new Map;await Promise.all([...p].map(async e=>{h.set(e,await ee(e))}));const d=W(),g=await Promise.allSettled(s.map(async([t,a])=>{const{name:n,marketplace:s}=se(t),u=i[s];if(!u&&m)return o.push({type:"marketplace-blocked-by-policy",source:t,plugin:n,marketplace:s,blockedByBlocklist:null===c,allowedSources:(c??[]).map(e=>K(e))}),null;if(u&&!Y(u.source)){const e=Q(u.source),a=q()||[];return o.push({type:"marketplace-blocked-by-policy",source:t,plugin:n,marketplace:s,blockedByBlocklist:e,allowedSources:e?[]:a.map(e=>K(e))}),null}let p=null;const g=h.get(s);if(g&&u){const e=g.plugins.find(e=>e.name===n);e&&(p={entry:e,marketplaceInstallLocation:u.installLocation})}else p=await te(t);if(!p)return o.push({type:"plugin-not-found",source:t,pluginId:n,marketplace:s}),null;const y=d.plugins[t]?.[0];return e?async function(e,t,a,n,o,s){let r;if("string"==typeof e.source){let n;try{n=(await l(t)).isDirectory()?t:f(t,"..")}catch{return o.push({type:"plugin-cache-miss",source:a,plugin:e.name,installPath:t}),null}r=f(n,e.source)}else{if(!s||!await x(s))return o.push({type:"plugin-cache-miss",source:a,plugin:e.name,installPath:s??"(not recorded)"}),null;r=s}if(he()&&r.endsWith(".zip")){const n=await fe(),s=f(n,a.replace(/[^a-zA-Z0-9@\-_]/g,"-"));try{await pe(r,s),r=s}catch(t){return $(`Failed to extract plugin ZIP ${r}: ${t}`,{level:"error"}),o.push({type:"plugin-cache-miss",source:a,plugin:e.name,installPath:r}),null}}return finishLoadingPluginFromPath(e,a,n,o,r)}(p.entry,p.marketplaceInstallLocation,t,!0===a,o,y?.installPath):async function(e,t,a,n,o,s){let i;if($(`Loading plugin ${e.name} from source: ${U(e.source)}`),"string"==typeof e.source){const n=(await l(t)).isDirectory()?t:f(t,".."),s=f(n,e.source);if(!await x(s)){const e=new Error(`Plugin path not found: ${s}`);return $(`Plugin path not found: ${s}`,{level:"error"}),I(e),o.push({type:"generic-error",source:a,error:`Plugin directory not found at path: ${s}. Check that the marketplace entry has the correct path.`}),null}try{const t=f(s,".claude-plugin","plugin.json");let o;try{o=await loadPluginManifest(t,e.name,e.source)}catch{}const r=await ie(a,e.source,o,n,e.version);i=await copyPluginToVersionedCache(s,a,r,e,n),$(`Resolved local plugin ${e.name} to versioned cache: ${i}`)}catch(t){const a=v(t);$(`Failed to copy plugin ${e.name} to versioned cache: ${a}. Using marketplace path.`,{level:"warn"}),i=s}}else try{const t=await ie(a,e.source,void 0,void 0,s??e.version,"sha"in e.source?e.source.sha:void 0),n=getVersionedCachePath(a,t),o=getVersionedZipCachePath(a,t);if(he()&&await x(o))$(`Using versioned cached plugin ZIP ${e.name} from ${o}`),i=o;else if(await x(n))$(`Using versioned cached plugin ${e.name} from ${n}`),i=n;else{const n=await probeSeedCache(a,t)??("unknown"===t?await probeSeedCacheAnyVersion(a):null);if(n)i=n,$(`Using seed cache for external plugin ${e.name} at ${n}`);else{const n=await cachePlugin(e.source,{manifest:{name:e.name}}),o="unknown"!==t?t:await ie(a,e.source,n.manifest,n.path,s??e.version,n.gitCommitSha);i=await copyPluginToVersionedCache(n.path,a,o,e,void 0),n.path!==i&&await r(n.path,{recursive:!0,force:!0})}}}catch(t){const n=v(t);return $(`Failed to cache plugin ${e.name}: ${n}`,{level:"error"}),I(E(t)),o.push({type:"generic-error",source:a,error:`Failed to download/cache plugin ${e.name}: ${n}`}),null}if(he()&&i.endsWith(".zip")){const t=await fe(),n=f(t,a.replace(/[^a-zA-Z0-9@\-_]/g,"-"));try{await pe(i,n),$(`Extracted plugin ZIP to session dir: ${n}`),i=n}catch(e){throw $(`Failed to extract plugin ZIP ${i}, deleting corrupt file: ${e}`),await r(i,{force:!0}).catch(()=>{}),e}}return finishLoadingPluginFromPath(e,a,n,o,i)}(p.entry,p.marketplaceInstallLocation,t,!0===a,o,y?.version)}));for(const[e,t]of g.entries())if("fulfilled"===t.status&&t.value)n.push(t.value);else if("rejected"===t.status){const a=E(t.reason);I(a);const n=s[e][0];o.push({type:"generic-error",source:n,plugin:n.split("@")[0],error:a.message})}return{plugins:n,errors:o}}async function finishLoadingPluginFromPath(e,t,a,n,o){const s=[],r=f(o,".claude-plugin","plugin.json"),i=await x(r),{plugin:l,errors:c}=await createPluginFromPath(o,t,a,e.name,e.strict??!0);if(s.push(...c),"object"==typeof e.source&&"sha"in e.source&&e.source.sha&&(l.sha=e.source.sha),i){if(!e.strict&&i&&(e.commands||e.agents||e.skills||e.hooks||e.outputStyles)){const a=new Error(`Plugin ${e.name} has both plugin.json and marketplace manifest entries for commands/agents/skills/hooks/outputStyles. This is a conflict.`);return $(`Plugin ${e.name} has both plugin.json and marketplace manifest entries for commands/agents/skills/hooks/outputStyles. This is a conflict.`,{level:"error"}),I(a),n.push({type:"generic-error",source:t,error:`Plugin ${e.name} has conflicting manifests: both plugin.json and marketplace entry specify components. Set strict: true in marketplace entry or remove component specs from one location.`}),null}if(i){if(e.commands){const a=Object.values(e.commands)[0];if("object"==typeof e.commands&&!Array.isArray(e.commands)&&a&&"object"==typeof a&&("source"in a||"content"in a)){const a={...l.commandsMetadata||{}},n=[],r=Object.entries(e.commands),i=await Promise.all(r.map(async([e,t])=>{if(!t||"object"!=typeof t||!t.source)return{commandName:e,metadata:t,skip:!0};const a=f(o,t.source);return{commandName:e,metadata:t,skip:!1,fullPath:a,exists:await x(a)}}));for(const o of i)o.skip||(o.exists?(n.push(o.fullPath),a[o.commandName]=o.metadata):($(`Command ${o.commandName} path ${o.metadata.source} from marketplace entry not found at ${o.fullPath} for ${e.name}`,{level:"warn"}),I(new Error(`Plugin component file not found: ${o.fullPath} for ${e.name}`)),s.push({type:"path-not-found",source:t,plugin:e.name,path:o.fullPath,component:"commands"})));n.length>0&&(l.commandsPaths=[...l.commandsPaths||[],...n],l.commandsMetadata=a)}else{const a=Array.isArray(e.commands)?e.commands:[e.commands],n=await Promise.all(a.map(async e=>{if("string"!=typeof e)return{cmdPath:e,kind:"invalid"};const t=f(o,e);return{cmdPath:e,kind:"path",fullPath:t,exists:await x(t)}})),r=[];for(const a of n)"invalid"!==a.kind?a.exists?r.push(a.fullPath):($(`Command path ${a.cmdPath} from marketplace entry not found at ${a.fullPath} for ${e.name}`,{level:"warn"}),I(new Error(`Plugin component file not found: ${a.fullPath} for ${e.name}`)),s.push({type:"path-not-found",source:t,plugin:e.name,path:a.fullPath,component:"commands"})):$(`Unexpected command format in marketplace entry for ${e.name}`,{level:"error"});r.length>0&&(l.commandsPaths=[...l.commandsPaths||[],...r])}}if(e.agents){const a=Array.isArray(e.agents)?e.agents:[e.agents],n=await validatePluginPaths(a,o,e.name,t,"agents","Agent","from marketplace entry",s);n.length>0&&(l.agentsPaths=[...l.agentsPaths||[],...n])}if(e.skills){const a=Array.isArray(e.skills)?e.skills:[e.skills],n=await validatePluginPaths(a,o,e.name,t,"skills","Skill","from marketplace entry",s);n.length>0&&(l.skillsPaths=[...l.skillsPaths||[],...n])}if(e.outputStyles){const a=Array.isArray(e.outputStyles)?e.outputStyles:[e.outputStyles],n=await validatePluginPaths(a,o,e.name,t,"output-styles","Output style","from marketplace entry",s);n.length>0&&(l.outputStylesPaths=[...l.outputStylesPaths||[],...n])}e.hooks&&(l.hooksConfig={...l.hooksConfig||{},...e.hooks})}}else{if(l.manifest={...e,id:void 0,source:void 0,strict:void 0},l.name=l.manifest.name,e.commands){const a=Object.values(e.commands)[0];if("object"==typeof e.commands&&!Array.isArray(e.commands)&&a&&"object"==typeof a&&("source"in a||"content"in a)){const a={},n=[],r=Object.entries(e.commands),i=await Promise.all(r.map(async([e,t])=>{if(!t||"object"!=typeof t||!t.source)return{commandName:e,metadata:t,skip:!0};const a=f(o,t.source);return{commandName:e,metadata:t,skip:!1,fullPath:a,exists:await x(a)}}));for(const o of i)o.skip||(o.exists?(n.push(o.fullPath),a[o.commandName]=o.metadata):($(`Command ${o.commandName} path ${o.metadata.source} from marketplace entry not found at ${o.fullPath} for ${e.name}`,{level:"warn"}),I(new Error(`Plugin component file not found: ${o.fullPath} for ${e.name}`)),s.push({type:"path-not-found",source:t,plugin:e.name,path:o.fullPath,component:"commands"})));n.length>0&&(l.commandsPaths=n,l.commandsMetadata=a)}else{const a=Array.isArray(e.commands)?e.commands:[e.commands],n=await Promise.all(a.map(async e=>{if("string"!=typeof e)return{cmdPath:e,kind:"invalid"};const t=f(o,e);return{cmdPath:e,kind:"path",fullPath:t,exists:await x(t)}})),r=[];for(const a of n)"invalid"!==a.kind?a.exists?r.push(a.fullPath):($(`Command path ${a.cmdPath} from marketplace entry not found at ${a.fullPath} for ${e.name}`,{level:"warn"}),I(new Error(`Plugin component file not found: ${a.fullPath} for ${e.name}`)),s.push({type:"path-not-found",source:t,plugin:e.name,path:a.fullPath,component:"commands"})):$(`Unexpected command format in marketplace entry for ${e.name}`,{level:"error"});r.length>0&&(l.commandsPaths=r)}}if(e.agents){const a=Array.isArray(e.agents)?e.agents:[e.agents],n=await validatePluginPaths(a,o,e.name,t,"agents","Agent","from marketplace entry",s);n.length>0&&(l.agentsPaths=n)}if(e.skills){$(`Processing ${Array.isArray(e.skills)?e.skills.length:1} skill paths for plugin ${e.name}`);const a=Array.isArray(e.skills)?e.skills:[e.skills],n=await Promise.all(a.map(async e=>{const t=f(o,e);return{skillPath:e,fullPath:t,exists:await x(t)}})),r=[];for(const{skillPath:a,fullPath:o,exists:i}of n)$(`Checking skill path: ${a} -> ${o} (exists: ${i})`),i?r.push(o):($(`Skill path ${a} from marketplace entry not found at ${o} for ${e.name}`,{level:"warn"}),I(new Error(`Plugin component file not found: ${o} for ${e.name}`)),s.push({type:"path-not-found",source:t,plugin:e.name,path:o,component:"skills"}));$(`Found ${r.length} valid skill paths for plugin ${e.name}, setting skillsPaths`),r.length>0&&(l.skillsPaths=r)}else $(`Plugin ${e.name} has no entry.skills defined`);if(e.outputStyles){const a=Array.isArray(e.outputStyles)?e.outputStyles:[e.outputStyles],n=await validatePluginPaths(a,o,e.name,t,"output-styles","Output style","from marketplace entry",s);n.length>0&&(l.outputStylesPaths=n)}e.hooks&&(l.hooksConfig=e.hooks)}return n.push(...s),l}async function loadSessionOnlyPlugins(e){if(0===e.length)return{plugins:[],errors:[]};const t=[],a=[];for(const[n,o]of e.entries())try{const e=d(o);if(!await x(e)){$(`Plugin path does not exist: ${e}, skipping`,{level:"warn"}),a.push({type:"path-not-found",source:`inline[${n}]`,path:e,component:"commands"});continue}const s=m(e),{plugin:r,errors:i}=await createPluginFromPath(e,`${s}@inline`,!0,s);r.source=`${r.name}@inline`,r.repository=`${r.name}@inline`,t.push(r),a.push(...i),$(`Loaded inline plugin from path: ${r.name}`)}catch(e){const t=v(e);$(`Failed to load session plugin from ${o}: ${t}`,{level:"warn"}),a.push({type:"generic-error",source:`inline[${n}]`,error:`Failed to load plugin: ${t}`})}return t.length>0&&$(`Loaded ${t.length} session-only plugins from --plugin-dir`),{plugins:t,errors:a}}export function mergePluginSources(e){const t=[],a=e.managedNames,n=e.session.filter(e=>!a?.has(e.name)||($(`Plugin "${e.name}" from --plugin-dir is blocked by managed settings`,{level:"warn"}),t.push({type:"generic-error",source:e.source,plugin:e.name,error:`--plugin-dir copy of "${e.name}" ignored: plugin is locked by managed settings`}),!1)),o=new Set(n.map(e=>e.name)),s=e.marketplace.filter(e=>!o.has(e.name)||($(`Plugin "${e.name}" from --plugin-dir overrides installed version`),!1));return{plugins:[...n,...s,...e.builtin],errors:t}}export const loadAllPlugins=u(async()=>{const e=await assemblePluginLoadResult(()=>loadPluginsFromMarketplaces({cacheOnly:!1}));return loadAllPluginsCacheOnly.cache?.set(void 0,Promise.resolve(e)),e});export const loadAllPluginsCacheOnly=u(async()=>k(process.env.CONTEXT_CODE_SYNC_PLUGIN_INSTALL)||k(process.env.CLAUDE_CODE_SYNC_PLUGIN_INSTALL)?loadAllPlugins():assemblePluginLoadResult(()=>loadPluginsFromMarketplaces({cacheOnly:!0})));async function assemblePluginLoadResult(e){const t=y(),[a,n]=await Promise.all([e(),t.length>0?loadSessionOnlyPlugins(t):Promise.resolve({plugins:[],errors:[]})]),o=w(),{plugins:s,errors:r}=mergePluginSources({session:n.plugins,marketplace:a.plugins,builtin:[...o.enabled,...o.disabled],managedNames:J()}),i=[...a.errors,...n.errors,...r],{demoted:l,errors:c}=H(s);for(const e of s)l.has(e.source)&&(e.enabled=!1);i.push(...c);const u=s.filter(e=>e.enabled);return $(`Found ${s.length} plugins (${u.length} enabled, ${s.length-u.length} disabled)`),cachePluginSettings(u),{enabled:u,disabled:s.filter(e=>!e.enabled),errors:i}}export function clearPluginCache(e){e&&$(`clearPluginCache: invalidating loadAllPlugins cache (${e})`),loadAllPlugins.cache?.clear?.(),loadAllPluginsCacheOnly.cache?.clear?.(),void 0!==L()&&D(),T()}export function cachePluginSettings(e){const t=function(e){let t;for(const a of e)if(a.settings){t||(t={});for(const[e,n]of Object.entries(a.settings))e in t&&$(`Plugin "${a.name}" overrides setting "${e}" (previously set by another plugin)`),t[e]=n}return t}(e);M(t),t&&Object.keys(t).length>0&&(D(),$(`Cached plugin settings with keys: ${Object.keys(t).join(", ")}`))}
1
+ import{copyFile as e,readdir as t,readFile as a,readlink as n,realpath as o,rename as r,rm as s,rmdir as i,stat as l,symlink as c}from"fs/promises";import u from"lodash-es/memoize.js";import{basename as m,dirname as p,join as f,relative as h,resolve as d,sep as g}from"path";import{getInlinePlugins as y}from"../../bootstrap/state.js";import{BUILTIN_MARKETPLACE_NAME as w,getBuiltinPlugins as $}from"../../plugins/builtinPlugins.js";import{logForDebugging as P}from"../debug.js";import{isEnvTruthy as k}from"../envUtils.js";import{errorMessage as v,getErrnoPath as b,isENOENT as j,isFsInaccessible as S,toError as C}from"../errors.js";import{execFileNoThrow as A,execFileNoThrowWithCwd as E}from"../execFileNoThrow.js";import{pathExists as x}from"../file.js";import{getFsImplementation as F}from"../fsOperations.js";import{gitExe as O}from"../git.js";import{lazySchema as _}from"../lazySchema.js";import{logError as N}from"../log.js";import{getSettings_DEPRECATED as L}from"../settings/settings.js";import{clearPluginSettingsBase as T,getPluginSettingsBase as I,resetSettingsCache as D,setPluginSettingsBase as V}from"../settings/settingsCache.js";import{SettingsSchema as U}from"../settings/types.js";import{jsonParse as Z,jsonStringify as z}from"../slowOperations.js";import{getAddDirEnabledPlugins as H}from"./addDirPluginSettings.js";import{verifyAndDemote as M}from"./dependencyResolver.js";import{classifyFetchError as R,logPluginFetch as G}from"./fetchTelemetry.js";import{checkGitAvailable as B}from"./gitAvailability.js";import{getInMemoryInstalledPlugins as W}from"./installedPluginsManager.js";import{getManagedPluginNames as J}from"./managedPlugins.js";import{formatSourceForDisplay as X,getBlockedMarketplaces as q,getStrictKnownMarketplaces as Y,isSourceAllowedByPolicy as K,isSourceInBlocklist as Q}from"./marketplaceHelpers.js";import{getMarketplaceCacheOnly as ee,getPluginByIdCacheOnly as te,loadKnownMarketplacesConfigSafe as ae}from"./marketplaceManager.js";import{getPluginSeedDirs as ne,getPluginsDirectory as oe}from"./pluginDirectories.js";import{parsePluginIdentifier as re}from"./pluginIdentifier.js";import{validatePathWithinBase as se}from"./pluginInstallationHelpers.js";import{calculatePluginVersion as ie}from"./pluginVersioning.js";import{PluginHooksSchema as le,PluginIdSchema as ce,PluginManifestSchema as ue}from"./schemas.js";import{convertDirectoryToZipInPlace as me,extractZipToDirectory as pe,getSessionPluginCachePath as fe,isPluginZipCacheEnabled as he}from"./zipCache.js";export function getPluginCachePath(){return f(oe(),"cache")}export function getVersionedCachePathIn(e,t,a){const{name:n,marketplace:o}=re(t),r=(o||"unknown").replace(/[^a-zA-Z0-9\-_]/g,"-"),s=(n||t).replace(/[^a-zA-Z0-9\-_]/g,"-"),i=a.replace(/[^a-zA-Z0-9\-_.]/g,"-");return f(e,"cache",r,s,i)}export function getVersionedCachePath(e,t){return getVersionedCachePathIn(oe(),e,t)}export function getVersionedZipCachePath(e,t){return`${getVersionedCachePath(e,t)}.zip`}async function probeSeedCache(e,a){for(const n of ne()){const o=getVersionedCachePathIn(n,e,a);try{if((await t(o)).length>0)return o}catch{}}return null}export async function probeSeedCacheAnyVersion(e){for(const a of ne()){const n=p(getVersionedCachePathIn(a,e,"_"));try{const e=await t(n);if(1!==e.length)continue;const a=f(n,e[0]);if((await t(a)).length>0)return a}catch{}}return null}export function getLegacyCachePath(e){const t=getPluginCachePath();return f(t,e.replace(/[^a-zA-Z0-9\-_]/g,"-"))}export async function resolvePluginPath(e,t){if(t){const a=getVersionedCachePath(e,t);if(await x(a))return a}const a=getLegacyCachePath(re(e).name||e);return await x(a)?a:t?getVersionedCachePath(e,t):a}export async function copyDir(a,r){await F().mkdir(r);const s=await t(a,{withFileTypes:!0});for(const t of s){const s=f(a,t.name),i=f(r,t.name);if(t.isDirectory())await copyDir(s,i);else if(t.isFile())await e(s,i);else if(t.isSymbolicLink()){const e=await n(s);let t,l;try{t=await o(s)}catch{await c(e,i);continue}try{l=await o(a)}catch{l=a}const u=l.endsWith(g)?l:l+g;if(t.startsWith(u)||t===l){const e=h(l,t),a=f(r,e),n=h(p(i),a);await c(n,i)}else await c(t,i)}}}export async function copyPluginToVersionedCache(e,a,n,o,r){const l=he(),c=getVersionedCachePath(a,n),u=getVersionedZipCachePath(a,n);if(l){if(await x(u))return P(`Plugin ${a} version ${n} already cached at ${u}`),u}else if(await x(c)){if((await t(c)).length>0)return P(`Plugin ${a} version ${n} already cached at ${c}`),c;P(`Removing empty cache directory for ${a} at ${c}`),await i(c)}const m=await probeSeedCache(a,n);if(m)return P(`Using seed cache for ${a}@${n} at ${m}`),m;if(await F().mkdir(p(c)),o&&"string"==typeof o.source&&r){const e=se(r,o.source);P(`Copying source directory ${o.source} for plugin ${a}`);try{await copyDir(e,c)}catch(t){if(j(t)&&b(t)===e)throw new Error(`Plugin source directory not found: ${e} (from entry.source: ${o.source})`);throw t}}else P(`Copying plugin ${a} to versioned cache (fallback to full copy)`),await copyDir(e,c);const h=f(c,".git");await s(h,{recursive:!0,force:!0});if(0===(await t(c)).length)throw new Error(`Failed to copy plugin ${a} to versioned cache: destination is empty after copy`);return l?(await me(c,u),P(`Successfully cached plugin ${a} as ZIP at ${u}`),u):(P(`Successfully cached plugin ${a} at ${c}`),c)}function validateGitUrl(e){try{const t=new URL(e);if(!["https:","http:","file:"].includes(t.protocol)&&!/^git@[a-zA-Z0-9.-]+:/.test(e))throw new Error(`Invalid git URL protocol: ${t.protocol}. Only HTTPS, HTTP, file:// and SSH (git@) URLs are supported.`);return e}catch{if(/^git@[a-zA-Z0-9.-]+:/.test(e))return e;throw new Error(`Invalid git URL: ${e}`)}}export async function installFromNpm(e,t,a={}){const n=f(oe(),"npm-cache");await F().mkdir(n);const o=a.version?`${e}@${a.version}`:e,r=f(n,"node_modules",e);if(!await x(r)){P(`Installing npm package ${o} to cache`);const e=["install",o,"--prefix",n];a.registry&&e.push("--registry",a.registry);const t=await A("npm",e,{useCwd:!1});if(0!==t.code)throw new Error(`Failed to install npm package: ${t.stderr}`)}await copyDir(r,t),P(`Copied npm package ${e} from cache to ${t}`)}export async function gitClone(e,t,a,n){const o=["clone","--depth","1","--recurse-submodules","--shallow-submodules"];a&&o.push("--branch",a),n&&o.push("--no-checkout"),o.push(e,t);const r=performance.now(),s=await A(O(),o);if(0!==s.code)throw G("plugin_clone",e,"failure",performance.now()-r,R(s.stderr)),new Error(`Failed to clone repository: ${s.stderr}`);if(n){if(0!==(await E(O(),["fetch","--depth","1","origin",n],{cwd:t})).code){P(`Shallow fetch of SHA ${n} failed, falling back to unshallow fetch`);const a=await E(O(),["fetch","--unshallow"],{cwd:t});if(0!==a.code)throw G("plugin_clone",e,"failure",performance.now()-r,R(a.stderr)),new Error(`Failed to fetch commit ${n}: ${a.stderr}`)}const a=await E(O(),["checkout",n],{cwd:t});if(0!==a.code)throw G("plugin_clone",e,"failure",performance.now()-r,R(a.stderr)),new Error(`Failed to checkout commit ${n}: ${a.stderr}`)}G("plugin_clone",e,"success",performance.now()-r)}async function installFromGit(e,t,a,n){const o=validateGitUrl(e);await gitClone(o,t,a,n);P(`Cloned repository from ${o}${a?` (ref: ${a})`:""} to ${t}`)}export async function installFromGitSubdir(e,t,a,n,o){if(!await B())throw new Error("git-subdir plugin source requires git to be installed and on PATH. Install git (version 2.25 or later for sparse-checkout cone mode) and try again.");const i=function(e){return/^[a-zA-Z0-9-_.]+\/[a-zA-Z0-9-_.]+$/.test(e)?k(process.env.CONTEXT_CODE_REMOTE)||k(process.env.CLAUDE_CODE_REMOTE)?`https://github.com/${e}.git`:`git@github.com:${e}.git`:validateGitUrl(e)}(e),l=`${t}.clone`,c=["clone","--depth","1","--filter=tree:0","--no-checkout"];n&&c.push("--branch",n),c.push(i,l);const u=await A(O(),c);if(0!==u.code)throw new Error(`Failed to clone repository for git-subdir source: ${u.stderr}`);try{const e=await E(O(),["sparse-checkout","set","--cone","--",a],{cwd:l});if(0!==e.code)throw new Error(`git sparse-checkout set failed (git >= 2.25 required for cone mode): ${e.stderr}`);let s;if(o){if(0!==(await E(O(),["fetch","--depth","1","origin",o],{cwd:l})).code){P(`Shallow fetch of SHA ${o} failed for git-subdir, falling back to unshallow fetch`);const e=await E(O(),["fetch","--unshallow"],{cwd:l});if(0!==e.code)throw new Error(`Failed to fetch commit ${o}: ${e.stderr}`)}const e=await E(O(),["checkout",o],{cwd:l});if(0!==e.code)throw new Error(`Failed to checkout commit ${o}: ${e.stderr}`);s=o}else{const[e,t]=await Promise.all([E(O(),["checkout","HEAD"],{cwd:l}),E(O(),["rev-parse","HEAD"],{cwd:l})]);if(0!==e.code)throw new Error(`git checkout after sparse-checkout failed: ${e.stderr}`);0===t.code&&(s=t.stdout.trim())}const c=se(l,a);try{await r(c,t)}catch(e){if(j(e))throw new Error(`Subdirectory '${a}' not found in repository ${i}${n?` (ref: ${n})`:""}. Check that the path is correct and exists at the specified ref/sha.`);throw e}const u=n?` ref=${n}`:"";return P(`Extracted subdir ${a} from ${i}${u}${s?` sha=${s}`:""} to ${t}`),s}finally{await s(l,{recursive:!0,force:!0})}}export function generateTemporaryCacheNameForPlugin(e){const t=Date.now(),a=Math.random().toString(36).substring(2,8);let n;if("string"==typeof e)n="local";else switch(e.source){case"npm":n="npm";break;case"pip":n="pip";break;case"github":n="github";break;case"url":n="git";break;case"git-subdir":n="subdir";break;default:n="unknown"}return`temp_${n}_${t}_${a}`}export async function cachePlugin(e,t){const n=getPluginCachePath();await F().mkdir(n);const o=generateTemporaryCacheNameForPlugin(e),i=f(n,o);let l,c=!1;try{if(P(`Caching plugin from source: ${z(e)} to temporary path ${i}`),c=!0,"string"==typeof e)await async function(e,t){if(!await x(e))throw new Error(`Source path does not exist: ${e}`);await copyDir(e,t);const a=f(t,".git");await s(a,{recursive:!0,force:!0})}(e,i);else switch(e.source){case"npm":await installFromNpm(e.package,i,{registry:e.registry,version:e.version});break;case"github":await async function(e,t,a,n){if(!/^[a-zA-Z0-9-_.]+\/[a-zA-Z0-9-_.]+$/.test(e))throw new Error(`Invalid GitHub repository format: ${e}. Expected format: owner/repo`);return installFromGit(k(process.env.CONTEXT_CODE_REMOTE)||k(process.env.CLAUDE_CODE_REMOTE)?`https://github.com/${e}.git`:`git@github.com:${e}.git`,t,a,n)}(e.repo,i,e.ref,e.sha);break;case"url":await installFromGit(e.url,i,e.ref,e.sha);break;case"git-subdir":l=await installFromGitSubdir(e.url,i,e.path,e.ref,e.sha);break;case"pip":throw new Error("Python package plugins are not yet supported");default:throw new Error("Unsupported plugin source type")}}catch(e){if(c&&await x(i)){P(`Cleaning up failed installation at ${i}`);try{await s(i,{recursive:!0,force:!0})}catch(e){P(`Failed to clean up installation: ${e}`,{level:"error"})}}throw e}const u=f(i,".claude-plugin","plugin.json"),m=f(i,"plugin.json");let p;if(await x(u))try{const e=await a(u,{encoding:"utf-8"}),t=Z(e),n=ue().safeParse(t);if(!n.success){const e=n.error.issues.map(e=>`${e.path.join(".")}: ${e.message}`).join(", ");throw P(`Invalid manifest at ${u}: ${e}`,{level:"error"}),new Error(`Plugin has an invalid manifest file at ${u}. Validation errors: ${e}`)}p=n.data}catch(e){if(e instanceof Error&&e.message.includes("invalid manifest file"))throw e;const t=v(e);throw P(`Failed to parse manifest at ${u}: ${t}`,{level:"error"}),new Error(`Plugin has a corrupt manifest file at ${u}. JSON parse error: ${t}`)}else if(await x(m))try{const e=await a(m,{encoding:"utf-8"}),t=Z(e),n=ue().safeParse(t);if(!n.success){const e=n.error.issues.map(e=>`${e.path.join(".")}: ${e.message}`).join(", ");throw P(`Invalid legacy manifest at ${m}: ${e}`,{level:"error"}),new Error(`Plugin has an invalid manifest file at ${m}. Validation errors: ${e}`)}p=n.data}catch(e){if(e instanceof Error&&e.message.includes("invalid manifest file"))throw e;const t=v(e);throw P(`Failed to parse legacy manifest at ${m}: ${t}`,{level:"error"}),new Error(`Plugin has a corrupt manifest file at ${m}. JSON parse error: ${t}`)}else p=t?.manifest||{name:o,description:`Plugin cached from ${"string"==typeof e?e:e.source}`};const h=p.name.replace(/[^a-zA-Z0-9-_]/g,"-"),d=f(n,h);return await x(d)&&(P(`Removing old cached version at ${d}`),await s(d,{recursive:!0,force:!0})),await r(i,d),P(`Successfully cached plugin ${p.name} to ${d}`),{path:d,manifest:p,...l&&{gitCommitSha:l}}}export async function loadPluginManifest(e,t,n){if(!await x(e))return{name:t,description:`Plugin from ${n}`};try{const n=await a(e,{encoding:"utf-8"}),o=Z(n),r=ue().safeParse(o);if(r.success)return r.data;const s=r.error.issues.map(e=>e.path.length>0?`${e.path.join(".")}: ${e.message}`:e.message).join(", ");throw P(`Plugin ${t} has an invalid manifest file at ${e}. Validation errors: ${s}`,{level:"error"}),new Error(`Plugin ${t} has an invalid manifest file at ${e}.\n\nValidation errors: ${s}`)}catch(a){if(a instanceof Error&&a.message.includes("invalid manifest file"))throw a;const n=v(a);throw P(`Plugin ${t} has a corrupt manifest file at ${e}. Parse error: ${n}`,{level:"error"}),new Error(`Plugin ${t} has a corrupt manifest file at ${e}.\n\nJSON parse error: ${n}`)}}async function loadPluginHooks(e,t){if(!await x(e))throw new Error(`Hooks file not found at ${e} for plugin ${t}. If the manifest declares hooks, the file must exist.`);const n=await a(e,{encoding:"utf-8"}),o=Z(n);return le().parse(o).hooks}async function validatePluginPaths(e,t,a,n,o,r,s,i){const l=await Promise.all(e.map(async e=>{const a=f(t,e);return{relPath:e,fullPath:a,exists:await x(a)}})),c=[];for(const{relPath:e,fullPath:t,exists:u}of l)u?c.push(t):(P(`${r} path ${e} ${s} not found at ${t} for ${a}`,{level:"warn"}),N(new Error(`Plugin component file not found: ${t} for ${a}`)),i.push({type:"path-not-found",source:n,plugin:a,path:t,component:o}));return c}export async function createPluginFromPath(e,t,n,r,s=!0){const i=[],l=f(e,".claude-plugin","plugin.json"),c=await loadPluginManifest(l,r,t),u={name:c.name,manifest:c,path:e,source:t,repository:t,enabled:n},[m,p,h,d]=await Promise.all([!c.commands&&x(f(e,"commands")),!c.agents&&x(f(e,"agents")),!c.skills&&x(f(e,"skills")),!c.outputStyles&&x(f(e,"output-styles"))]),g=f(e,"commands");if(m&&(u.commandsPath=g),c.commands){const a=Object.values(c.commands)[0];if("object"==typeof c.commands&&!Array.isArray(c.commands)&&a&&"object"==typeof a&&("source"in a||"content"in a)){const a={},n=[],o=Object.entries(c.commands),r=await Promise.all(o.map(async([t,a])=>{if(!a||"object"!=typeof a)return{commandName:t,metadata:a,kind:"skip"};if(a.source){const n=f(e,a.source);return{commandName:t,metadata:a,kind:"source",fullPath:n,exists:await x(n)}}return a.content?{commandName:t,metadata:a,kind:"content"}:{commandName:t,metadata:a,kind:"skip"}}));for(const e of r)"skip"!==e.kind&&("content"!==e.kind?e.exists?(n.push(e.fullPath),a[e.commandName]=e.metadata):(P(`Command ${e.commandName} path ${e.metadata.source} specified in manifest but not found at ${e.fullPath} for ${c.name}`,{level:"warn"}),N(new Error(`Plugin component file not found: ${e.fullPath} for ${c.name}`)),i.push({type:"path-not-found",source:t,plugin:c.name,path:e.fullPath,component:"commands"})):a[e.commandName]=e.metadata);n.length>0&&(u.commandsPaths=n),Object.keys(a).length>0&&(u.commandsMetadata=a)}else{const a=Array.isArray(c.commands)?c.commands:[c.commands],n=await Promise.all(a.map(async t=>{if("string"!=typeof t)return{cmdPath:t,kind:"invalid"};const a=f(e,t);return{cmdPath:t,kind:"path",fullPath:a,exists:await x(a)}})),o=[];for(const e of n)"invalid"!==e.kind?e.exists?o.push(e.fullPath):(P(`Command path ${e.cmdPath} specified in manifest but not found at ${e.fullPath} for ${c.name}`,{level:"warn"}),N(new Error(`Plugin component file not found: ${e.fullPath} for ${c.name}`)),i.push({type:"path-not-found",source:t,plugin:c.name,path:e.fullPath,component:"commands"})):P(`Unexpected command format in manifest for ${c.name}`,{level:"error"});o.length>0&&(u.commandsPaths=o)}}const y=f(e,"agents");if(p&&(u.agentsPath=y),c.agents){const a=Array.isArray(c.agents)?c.agents:[c.agents],n=await validatePluginPaths(a,e,c.name,t,"agents","Agent","specified in manifest but",i);n.length>0&&(u.agentsPaths=n)}const w=f(e,"skills");if(h&&(u.skillsPath=w),c.skills){const a=Array.isArray(c.skills)?c.skills:[c.skills],n=await validatePluginPaths(a,e,c.name,t,"skills","Skill","specified in manifest but",i);n.length>0&&(u.skillsPaths=n)}const $=f(e,"output-styles");if(d&&(u.outputStylesPath=$),c.outputStyles){const a=Array.isArray(c.outputStyles)?c.outputStyles:[c.outputStyles],n=await validatePluginPaths(a,e,c.name,t,"output-styles","Output style","specified in manifest but",i);n.length>0&&(u.outputStylesPaths=n)}let k;const b=new Set,j=f(e,"hooks","hooks.json");if(await x(j))try{k=await loadPluginHooks(j,c.name);try{b.add(await o(j))}catch{b.add(j)}P(`Loaded hooks from standard location for plugin ${c.name}: ${j}`)}catch(e){const a=v(e);P(`Failed to load hooks for ${c.name}: ${a}`,{level:"error"}),N(C(e)),i.push({type:"hook-load-failed",source:t,plugin:c.name,hookPath:j,reason:a})}if(c.hooks){const a=Array.isArray(c.hooks)?c.hooks:[c.hooks];for(const n of a)if("string"==typeof n){const a=f(e,n);if(!await x(a)){P(`Hooks file ${n} specified in manifest but not found at ${a} for ${c.name}`,{level:"error"}),N(new Error(`Plugin component file not found: ${a} for ${c.name}`)),i.push({type:"path-not-found",source:t,plugin:c.name,path:a,component:"hooks"});continue}let r;try{r=await o(a)}catch{r=a}if(b.has(r)){if(P(`Skipping duplicate hooks file for plugin ${c.name}: ${n} (resolves to already-loaded file: ${r})`),s){const e=`Duplicate hooks file detected: ${n} resolves to already-loaded file ${r}. The standard hooks/hooks.json is loaded automatically, so manifest.hooks should only reference additional hook files.`;N(new Error(e)),i.push({type:"hook-load-failed",source:t,plugin:c.name,hookPath:a,reason:e})}continue}try{const e=await loadPluginHooks(a,c.name);try{k=mergeHooksSettings(k,e),b.add(r),P(`Loaded and merged hooks from manifest for plugin ${c.name}: ${n}`)}catch(e){const o=v(e);P(`Failed to merge hooks from ${n} for ${c.name}: ${o}`,{level:"error"}),N(C(e)),i.push({type:"hook-load-failed",source:t,plugin:c.name,hookPath:a,reason:`Failed to merge: ${o}`})}}catch(e){const o=v(e);P(`Failed to load hooks from ${n} for ${c.name}: ${o}`,{level:"error"}),N(C(e)),i.push({type:"hook-load-failed",source:t,plugin:c.name,hookPath:a,reason:o})}}else"object"==typeof n&&(k=mergeHooksSettings(k,n))}k&&(u.hooksConfig=k);const A=await async function(e,t){const n=f(e,"settings.json");try{const e=await a(n,{encoding:"utf-8"}),r=Z(e);if("object"==typeof(o=r)&&null!==o&&!Array.isArray(o)){const e=parsePluginSettings(r);if(e)return P(`Loaded settings from settings.json for plugin ${t.name}`),e}}catch(e){S(e)||P(`Failed to parse settings.json for plugin ${t.name}: ${e}`,{level:"warn"})}var o;if(t.settings){const e=parsePluginSettings(t.settings);if(e)return P(`Loaded settings from manifest for plugin ${t.name}`),e}return}(e,c);return A&&(u.settings=A),{plugin:u,errors:i}}const de=_(()=>U().pick({agent:!0}).strip());function parsePluginSettings(e){const t=de().safeParse(e);if(!t.success)return;const a=t.data;return 0!==Object.keys(a).length?a:void 0}function mergeHooksSettings(e,t){if(!e)return t;const a={...e};for(const[e,n]of Object.entries(t))a[e]?a[e]=[...a[e]||[],...n]:a[e]=n;return a}async function loadPluginsFromMarketplaces({cacheOnly:e}){const t=L(),a={...H(),...t.enabledPlugins||{}},n=[],o=[],r=Object.entries(a).filter(([e,t])=>{if(!ce().safeParse(e).success||void 0===t)return!1;const{marketplace:a}=re(e);return a!==w}),i=await ae(),c=Y(),u=q(),m=null!==c||null!==u&&u.length>0,p=new Set(r.map(([e])=>re(e).marketplace).filter(e=>!!e)),h=new Map;await Promise.all([...p].map(async e=>{h.set(e,await ee(e))}));const d=W(),g=await Promise.allSettled(r.map(async([t,a])=>{const{name:n,marketplace:r}=re(t),u=i[r];if(!u&&m)return o.push({type:"marketplace-blocked-by-policy",source:t,plugin:n,marketplace:r,blockedByBlocklist:null===c,allowedSources:(c??[]).map(e=>X(e))}),null;if(u&&!K(u.source)){const e=Q(u.source),a=Y()||[];return o.push({type:"marketplace-blocked-by-policy",source:t,plugin:n,marketplace:r,blockedByBlocklist:e,allowedSources:e?[]:a.map(e=>X(e))}),null}let p=null;const g=h.get(r);if(g&&u){const e=g.plugins.find(e=>e.name===n);e&&(p={entry:e,marketplaceInstallLocation:u.installLocation})}else p=await te(t);if(!p)return o.push({type:"plugin-not-found",source:t,pluginId:n,marketplace:r}),null;const y=d.plugins[t]?.[0];return e?async function(e,t,a,n,o,r){let s;if("string"==typeof e.source){let n;try{n=(await l(t)).isDirectory()?t:f(t,"..")}catch{return o.push({type:"plugin-cache-miss",source:a,plugin:e.name,installPath:t}),null}s=f(n,e.source)}else{if(!r||!await x(r))return o.push({type:"plugin-cache-miss",source:a,plugin:e.name,installPath:r??"(not recorded)"}),null;s=r}if(he()&&s.endsWith(".zip")){const t=await fe(),n=f(t,a.replace(/[^a-zA-Z0-9@\-_]/g,"-"));try{await pe(s,n),s=n}catch(t){return P(`Failed to extract plugin ZIP ${s}: ${t}`,{level:"error"}),o.push({type:"plugin-cache-miss",source:a,plugin:e.name,installPath:s}),null}}return finishLoadingPluginFromPath(e,a,n,o,s)}(p.entry,p.marketplaceInstallLocation,t,!0===a,o,y?.installPath):async function(e,t,a,n,o,r){let i;if(P(`Loading plugin ${e.name} from source: ${z(e.source)}`),"string"==typeof e.source){const n=(await l(t)).isDirectory()?t:f(t,".."),r=f(n,e.source);if(!await x(r)){const e=new Error(`Plugin path not found: ${r}`);return P(`Plugin path not found: ${r}`,{level:"error"}),N(e),o.push({type:"generic-error",source:a,error:`Plugin directory not found at path: ${r}. Check that the marketplace entry has the correct path.`}),null}try{const t=f(r,".claude-plugin","plugin.json");let o;try{o=await loadPluginManifest(t,e.name,e.source)}catch{}const s=await ie(a,e.source,o,n,e.version);i=await copyPluginToVersionedCache(r,a,s,e,n),P(`Resolved local plugin ${e.name} to versioned cache: ${i}`)}catch(t){const a=v(t);P(`Failed to copy plugin ${e.name} to versioned cache: ${a}. Using marketplace path.`,{level:"warn"}),i=r}}else try{const t=await ie(a,e.source,void 0,void 0,r??e.version,"sha"in e.source?e.source.sha:void 0),n=getVersionedCachePath(a,t),o=getVersionedZipCachePath(a,t);if(he()&&await x(o))P(`Using versioned cached plugin ZIP ${e.name} from ${o}`),i=o;else if(await x(n))P(`Using versioned cached plugin ${e.name} from ${n}`),i=n;else{const n=await probeSeedCache(a,t)??("unknown"===t?await probeSeedCacheAnyVersion(a):null);if(n)i=n,P(`Using seed cache for external plugin ${e.name} at ${n}`);else{const n=await cachePlugin(e.source,{manifest:{name:e.name}}),o="unknown"!==t?t:await ie(a,e.source,n.manifest,n.path,r??e.version,n.gitCommitSha);i=await copyPluginToVersionedCache(n.path,a,o,e,void 0),n.path!==i&&await s(n.path,{recursive:!0,force:!0})}}}catch(t){const n=v(t);return P(`Failed to cache plugin ${e.name}: ${n}`,{level:"error"}),N(C(t)),o.push({type:"generic-error",source:a,error:`Failed to download/cache plugin ${e.name}: ${n}`}),null}if(he()&&i.endsWith(".zip")){const e=await fe(),t=f(e,a.replace(/[^a-zA-Z0-9@\-_]/g,"-"));try{await pe(i,t),P(`Extracted plugin ZIP to session dir: ${t}`),i=t}catch(e){throw P(`Failed to extract plugin ZIP ${i}, deleting corrupt file: ${e}`),await s(i,{force:!0}).catch(()=>{}),e}}return finishLoadingPluginFromPath(e,a,n,o,i)}(p.entry,p.marketplaceInstallLocation,t,!0===a,o,y?.version)}));for(const[e,t]of g.entries())if("fulfilled"===t.status&&t.value)n.push(t.value);else if("rejected"===t.status){const a=C(t.reason);N(a);const n=r[e][0];o.push({type:"generic-error",source:n,plugin:n.split("@")[0],error:a.message})}return{plugins:n,errors:o}}async function finishLoadingPluginFromPath(e,t,a,n,o){const r=[],s=f(o,".claude-plugin","plugin.json"),i=await x(s),{plugin:l,errors:c}=await createPluginFromPath(o,t,a,e.name,e.strict??!0);if(r.push(...c),"object"==typeof e.source&&"sha"in e.source&&e.source.sha&&(l.sha=e.source.sha),i){if(!e.strict&&i&&(e.commands||e.agents||e.skills||e.hooks||e.outputStyles)){const a=new Error(`Plugin ${e.name} has both plugin.json and marketplace manifest entries for commands/agents/skills/hooks/outputStyles. This is a conflict.`);return P(`Plugin ${e.name} has both plugin.json and marketplace manifest entries for commands/agents/skills/hooks/outputStyles. This is a conflict.`,{level:"error"}),N(a),n.push({type:"generic-error",source:t,error:`Plugin ${e.name} has conflicting manifests: both plugin.json and marketplace entry specify components. Set strict: true in marketplace entry or remove component specs from one location.`}),null}if(i){if(e.commands){const a=Object.values(e.commands)[0];if("object"==typeof e.commands&&!Array.isArray(e.commands)&&a&&"object"==typeof a&&("source"in a||"content"in a)){const a={...l.commandsMetadata||{}},n=[],s=Object.entries(e.commands),i=await Promise.all(s.map(async([e,t])=>{if(!t||"object"!=typeof t||!t.source)return{commandName:e,metadata:t,skip:!0};const a=f(o,t.source);return{commandName:e,metadata:t,skip:!1,fullPath:a,exists:await x(a)}}));for(const o of i)o.skip||(o.exists?(n.push(o.fullPath),a[o.commandName]=o.metadata):(P(`Command ${o.commandName} path ${o.metadata.source} from marketplace entry not found at ${o.fullPath} for ${e.name}`,{level:"warn"}),N(new Error(`Plugin component file not found: ${o.fullPath} for ${e.name}`)),r.push({type:"path-not-found",source:t,plugin:e.name,path:o.fullPath,component:"commands"})));n.length>0&&(l.commandsPaths=[...l.commandsPaths||[],...n],l.commandsMetadata=a)}else{const a=Array.isArray(e.commands)?e.commands:[e.commands],n=await Promise.all(a.map(async e=>{if("string"!=typeof e)return{cmdPath:e,kind:"invalid"};const t=f(o,e);return{cmdPath:e,kind:"path",fullPath:t,exists:await x(t)}})),s=[];for(const a of n)"invalid"!==a.kind?a.exists?s.push(a.fullPath):(P(`Command path ${a.cmdPath} from marketplace entry not found at ${a.fullPath} for ${e.name}`,{level:"warn"}),N(new Error(`Plugin component file not found: ${a.fullPath} for ${e.name}`)),r.push({type:"path-not-found",source:t,plugin:e.name,path:a.fullPath,component:"commands"})):P(`Unexpected command format in marketplace entry for ${e.name}`,{level:"error"});s.length>0&&(l.commandsPaths=[...l.commandsPaths||[],...s])}}if(e.agents){const a=Array.isArray(e.agents)?e.agents:[e.agents],n=await validatePluginPaths(a,o,e.name,t,"agents","Agent","from marketplace entry",r);n.length>0&&(l.agentsPaths=[...l.agentsPaths||[],...n])}if(e.skills){const a=Array.isArray(e.skills)?e.skills:[e.skills],n=await validatePluginPaths(a,o,e.name,t,"skills","Skill","from marketplace entry",r);n.length>0&&(l.skillsPaths=[...l.skillsPaths||[],...n])}if(e.outputStyles){const a=Array.isArray(e.outputStyles)?e.outputStyles:[e.outputStyles],n=await validatePluginPaths(a,o,e.name,t,"output-styles","Output style","from marketplace entry",r);n.length>0&&(l.outputStylesPaths=[...l.outputStylesPaths||[],...n])}e.hooks&&(l.hooksConfig={...l.hooksConfig||{},...e.hooks})}}else{if(l.manifest={...e,id:void 0,source:void 0,strict:void 0},l.name=l.manifest.name,e.commands){const a=Object.values(e.commands)[0];if("object"==typeof e.commands&&!Array.isArray(e.commands)&&a&&"object"==typeof a&&("source"in a||"content"in a)){const a={},n=[],s=Object.entries(e.commands),i=await Promise.all(s.map(async([e,t])=>{if(!t||"object"!=typeof t||!t.source)return{commandName:e,metadata:t,skip:!0};const a=f(o,t.source);return{commandName:e,metadata:t,skip:!1,fullPath:a,exists:await x(a)}}));for(const o of i)o.skip||(o.exists?(n.push(o.fullPath),a[o.commandName]=o.metadata):(P(`Command ${o.commandName} path ${o.metadata.source} from marketplace entry not found at ${o.fullPath} for ${e.name}`,{level:"warn"}),N(new Error(`Plugin component file not found: ${o.fullPath} for ${e.name}`)),r.push({type:"path-not-found",source:t,plugin:e.name,path:o.fullPath,component:"commands"})));n.length>0&&(l.commandsPaths=n,l.commandsMetadata=a)}else{const a=Array.isArray(e.commands)?e.commands:[e.commands],n=await Promise.all(a.map(async e=>{if("string"!=typeof e)return{cmdPath:e,kind:"invalid"};const t=f(o,e);return{cmdPath:e,kind:"path",fullPath:t,exists:await x(t)}})),s=[];for(const a of n)"invalid"!==a.kind?a.exists?s.push(a.fullPath):(P(`Command path ${a.cmdPath} from marketplace entry not found at ${a.fullPath} for ${e.name}`,{level:"warn"}),N(new Error(`Plugin component file not found: ${a.fullPath} for ${e.name}`)),r.push({type:"path-not-found",source:t,plugin:e.name,path:a.fullPath,component:"commands"})):P(`Unexpected command format in marketplace entry for ${e.name}`,{level:"error"});s.length>0&&(l.commandsPaths=s)}}if(e.agents){const a=Array.isArray(e.agents)?e.agents:[e.agents],n=await validatePluginPaths(a,o,e.name,t,"agents","Agent","from marketplace entry",r);n.length>0&&(l.agentsPaths=n)}if(e.skills){P(`Processing ${Array.isArray(e.skills)?e.skills.length:1} skill paths for plugin ${e.name}`);const a=Array.isArray(e.skills)?e.skills:[e.skills],n=await Promise.all(a.map(async e=>{const t=f(o,e);return{skillPath:e,fullPath:t,exists:await x(t)}})),s=[];for(const{skillPath:a,fullPath:o,exists:i}of n)P(`Checking skill path: ${a} -> ${o} (exists: ${i})`),i?s.push(o):(P(`Skill path ${a} from marketplace entry not found at ${o} for ${e.name}`,{level:"warn"}),N(new Error(`Plugin component file not found: ${o} for ${e.name}`)),r.push({type:"path-not-found",source:t,plugin:e.name,path:o,component:"skills"}));P(`Found ${s.length} valid skill paths for plugin ${e.name}, setting skillsPaths`),s.length>0&&(l.skillsPaths=s)}else P(`Plugin ${e.name} has no entry.skills defined`);if(e.outputStyles){const a=Array.isArray(e.outputStyles)?e.outputStyles:[e.outputStyles],n=await validatePluginPaths(a,o,e.name,t,"output-styles","Output style","from marketplace entry",r);n.length>0&&(l.outputStylesPaths=n)}e.hooks&&(l.hooksConfig=e.hooks)}return n.push(...r),l}async function loadSessionOnlyPlugins(e){if(0===e.length)return{plugins:[],errors:[]};const t=[],a=[];for(const[n,o]of e.entries())try{const e=d(o);if(!await x(e)){P(`Plugin path does not exist: ${e}, skipping`,{level:"warn"}),a.push({type:"path-not-found",source:`inline[${n}]`,path:e,component:"commands"});continue}const r=m(e),{plugin:s,errors:i}=await createPluginFromPath(e,`${r}@inline`,!0,r);s.source=`${s.name}@inline`,s.repository=`${s.name}@inline`,t.push(s),a.push(...i),P(`Loaded inline plugin from path: ${s.name}`)}catch(e){const t=v(e);P(`Failed to load session plugin from ${o}: ${t}`,{level:"warn"}),a.push({type:"generic-error",source:`inline[${n}]`,error:`Failed to load plugin: ${t}`})}return t.length>0&&P(`Loaded ${t.length} session-only plugins from --plugin-dir`),{plugins:t,errors:a}}export function mergePluginSources(e){const t=[],a=e.managedNames,n=e.session.filter(e=>!a?.has(e.name)||(P(`Plugin "${e.name}" from --plugin-dir is blocked by managed settings`,{level:"warn"}),t.push({type:"generic-error",source:e.source,plugin:e.name,error:`--plugin-dir copy of "${e.name}" ignored: plugin is locked by managed settings`}),!1)),o=new Set(n.map(e=>e.name)),r=e.marketplace.filter(e=>!o.has(e.name)||(P(`Plugin "${e.name}" from --plugin-dir overrides installed version`),!1));return{plugins:[...n,...r,...e.builtin],errors:t}}export const loadAllPlugins=u(async()=>{const e=await assemblePluginLoadResult(()=>loadPluginsFromMarketplaces({cacheOnly:!1}));return loadAllPluginsCacheOnly.cache?.set(void 0,Promise.resolve(e)),e});export const loadAllPluginsCacheOnly=u(async()=>k(process.env.CONTEXT_CODE_SYNC_PLUGIN_INSTALL)||k(process.env.CLAUDE_CODE_SYNC_PLUGIN_INSTALL)?loadAllPlugins():assemblePluginLoadResult(()=>loadPluginsFromMarketplaces({cacheOnly:!0})));async function assemblePluginLoadResult(e){const t=y(),[a,n]=await Promise.all([e(),t.length>0?loadSessionOnlyPlugins(t):Promise.resolve({plugins:[],errors:[]})]),o=$(),{plugins:r,errors:s}=mergePluginSources({session:n.plugins,marketplace:a.plugins,builtin:[...o.enabled,...o.disabled],managedNames:J()}),i=[...a.errors,...n.errors,...s],{demoted:l,errors:c}=M(r);for(const e of r)l.has(e.source)&&(e.enabled=!1);i.push(...c);const u=r.filter(e=>e.enabled);return P(`Found ${r.length} plugins (${u.length} enabled, ${r.length-u.length} disabled)`),cachePluginSettings(u),{enabled:u,disabled:r.filter(e=>!e.enabled),errors:i}}export function clearPluginCache(e){e&&P(`clearPluginCache: invalidating loadAllPlugins cache (${e})`),loadAllPlugins.cache?.clear?.(),loadAllPluginsCacheOnly.cache?.clear?.(),void 0!==I()&&D(),T()}export function cachePluginSettings(e){const t=function(e){let t;for(const a of e)if(a.settings){t||(t={});for(const[e,n]of Object.entries(a.settings))e in t&&P(`Plugin "${a.name}" overrides setting "${e}" (previously set by another plugin)`),t[e]=n}return t}(e);V(t),t&&Object.keys(t).length>0&&(D(),P(`Cached plugin settings with keys: ${Object.keys(t).join(", ")}`))}
@@ -1 +1 @@
1
- import e from"lodash-es/memoize.js";import{logForDebugging as t}from"../debug.js";import{logError as n}from"../log.js";import{getSecureStorage as i}from"../secureStorage/index.js";import{getSettings_DEPRECATED as r,updateSettingsForSource as s}from"../settings/settings.js";import{validateUserConfig as o}from"./mcpbHandler.js";import{getPluginDataDir as g}from"./pluginDirectories.js";export function getPluginStorageId(e){return e.source}export const loadPluginOptions=e(e=>{const t=r(),n=t.pluginConfigs?.[e]?.options??{},s=i();return{...n,...s.read()?.pluginSecrets?.[e]??{}}});export function clearPluginOptionsCache(){loadPluginOptions.cache?.clear?.()}export function savePluginOptions(e,o,g){const l={},c={};for(const[e,t]of Object.entries(o))!0===g[e]?.sensitive?c[e]=String(t):l[e]=t;const u=new Set(Object.keys(c)),a=new Set(Object.keys(l)),p=i(),f=p.read()?.pluginSecrets?.[e]??void 0,d=f?Object.fromEntries(Object.entries(f).filter(([e])=>!a.has(e))):void 0,b=d&&f&&Object.keys(d).length!==Object.keys(f).length;if(Object.keys(c).length>0||b){const i=p.read()??{};i.pluginSecrets||(i.pluginSecrets={}),i.pluginSecrets[e]={...d,...c};const r=p.update(i);if(!r.success){const t=new Error(`Failed to save sensitive plugin options for ${e} to secure storage`);throw n(t),t}r.warning&&t(`Plugin secrets save warning: ${r.warning}`,{level:"warn"})}const O=r(),m=O.pluginConfigs?.[e]?.options??{},v=Object.keys(m).filter(e=>u.has(e));if(Object.keys(l).length>0||v.length>0){O.pluginConfigs||(O.pluginConfigs={}),O.pluginConfigs[e]||(O.pluginConfigs[e]={});const t=Object.fromEntries(v.map(e=>[e,void 0]));O.pluginConfigs[e].options={...l,...t};const i=s("userSettings",O);if(i.error)throw n(i.error),new Error(`Failed to save plugin options for ${e}: ${i.error.message}`)}clearPluginOptionsCache()}export function deletePluginOptions(e){const n=r();if(n.pluginConfigs?.[e]){const n={[e]:void 0},{error:i}=s("userSettings",{pluginConfigs:n});i&&t(`deletePluginOptions: failed to clear settings.pluginConfigs[${e}]: ${i.message}`,{level:"warn"})}const o=i(),g=o.read();if(g?.pluginSecrets){const n=`${e}/`,i=Object.entries(g.pluginSecrets).filter(([t])=>t!==e&&!t.startsWith(n));i.length!==Object.keys(g.pluginSecrets).length&&(o.update({...g,pluginSecrets:i.length>0?Object.fromEntries(i):void 0}).success||t(`deletePluginOptions: failed to clear pluginSecrets for ${e} from keychain`,{level:"warn"}))}clearPluginOptionsCache()}export function getUnconfiguredOptions(e){const t=e.manifest.userConfig;if(!t||0===Object.keys(t).length)return{};const n=loadPluginOptions(getPluginStorageId(e));if(o(n,t).valid)return{};const i={};for(const[e,r]of Object.entries(t))o({[e]:n[e]},{[e]:r}).valid||(i[e]=r);return i}export function substitutePluginVariables(e,t){const normalize=e=>"win32"===process.platform?e.replace(/\\/g,"/"):e;let n=e.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g,()=>normalize(t.path));if(t.source){const e=t.source;n=n.replace(/\$\{CLAUDE_PLUGIN_DATA\}/g,()=>normalize(g(e)))}return n}export function substituteUserConfigVariables(e,t){return e.replace(/\$\{user_config\.([^}]+)\}/g,(e,n)=>{const i=t[n];if(void 0===i)throw new Error(`Missing required user configuration value: ${n}. This should have been validated before variable substitution.`);return String(i)})}export function substituteUserConfigInContent(e,t,n){return e.replace(/\$\{user_config\.([^}]+)\}/g,(e,i)=>{if(!0===n[i]?.sensitive)return`[sensitive option '${i}' not available in skill content]`;const r=t[i];return void 0===r?e:String(r)})}
1
+ import e from"lodash-es/memoize.js";import{logForDebugging as t}from"../debug.js";import{logError as n}from"../log.js";import{getSecureStorage as i}from"../secureStorage/index.js";import{getSettings_DEPRECATED as r,updateSettingsForSource as s}from"../settings/settings.js";import{validateUserConfig as o}from"./mcpbHandler.js";import{getPluginDataDir as l}from"./pluginDirectories.js";export function getPluginStorageId(e){return e.source}export const loadPluginOptions=e(e=>{const t=r(),n=t.pluginConfigs?.[e]?.options??{},s=i();return{...n,...s.read()?.pluginSecrets?.[e]??{}}});export function clearPluginOptionsCache(){loadPluginOptions.cache?.clear?.()}export function savePluginOptions(e,o,l){const c={},g={};for(const[e,t]of Object.entries(o))!0===l[e]?.sensitive?g[e]=String(t):c[e]=t;const u=new Set(Object.keys(g)),a=new Set(Object.keys(c)),p=i(),f=p.read()?.pluginSecrets?.[e]??void 0,d=f?Object.fromEntries(Object.entries(f).filter(([e])=>!a.has(e))):void 0,O=d&&f&&Object.keys(d).length!==Object.keys(f).length;if(Object.keys(g).length>0||O){const i=p.read()??{};i.pluginSecrets||(i.pluginSecrets={}),i.pluginSecrets[e]={...d,...g};const r=p.update(i);if(!r.success){const t=new Error(`Failed to save sensitive plugin options for ${e} to secure storage`);throw n(t),t}r.warning&&t(`Plugin secrets save warning: ${r.warning}`,{level:"warn"})}const b=r(),m=b.pluginConfigs?.[e]?.options??{},h=Object.keys(m).filter(e=>u.has(e));if(Object.keys(c).length>0||h.length>0){b.pluginConfigs||(b.pluginConfigs={}),b.pluginConfigs[e]||(b.pluginConfigs[e]={});const t=Object.fromEntries(h.map(e=>[e,void 0]));b.pluginConfigs[e].options={...c,...t};const i=s("userSettings",b);if(i.error)throw n(i.error),new Error(`Failed to save plugin options for ${e}: ${i.error.message}`)}clearPluginOptionsCache()}export function deletePluginOptions(e){const n=r();if(n.pluginConfigs?.[e]){const n={[e]:void 0},{error:i}=s("userSettings",{pluginConfigs:n});i&&t(`deletePluginOptions: failed to clear settings.pluginConfigs[${e}]: ${i.message}`,{level:"warn"})}const o=i(),l=o.read();if(l?.pluginSecrets){const n=`${e}/`,i=Object.entries(l.pluginSecrets).filter(([t])=>t!==e&&!t.startsWith(n));if(i.length!==Object.keys(l.pluginSecrets).length){o.update({...l,pluginSecrets:i.length>0?Object.fromEntries(i):void 0}).success||t(`deletePluginOptions: failed to clear pluginSecrets for ${e} from keychain`,{level:"warn"})}}clearPluginOptionsCache()}export function getUnconfiguredOptions(e){const t=e.manifest.userConfig;if(!t||0===Object.keys(t).length)return{};const n=loadPluginOptions(getPluginStorageId(e));if(o(n,t).valid)return{};const i={};for(const[e,r]of Object.entries(t)){o({[e]:n[e]},{[e]:r}).valid||(i[e]=r)}return i}export function substitutePluginVariables(e,t){const normalize=e=>"win32"===process.platform?e.replace(/\\/g,"/"):e;let n=e.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g,()=>normalize(t.path));if(t.source){const e=t.source;n=n.replace(/\$\{CLAUDE_PLUGIN_DATA\}/g,()=>normalize(l(e)))}return n}export function substituteUserConfigVariables(e,t){return e.replace(/\$\{user_config\.([^}]+)\}/g,(e,n)=>{const i=t[n];if(void 0===i)throw new Error(`Missing required user configuration value: ${n}. This should have been validated before variable substitution.`);return String(i)})}export function substituteUserConfigInContent(e,t,n){return e.replace(/\$\{user_config\.([^}]+)\}/g,(e,i)=>{if(!0===n[i]?.sensitive)return`[sensitive option '${i}' not available in skill content]`;const r=t[i];return void 0===r?e:String(r)})}
@@ -1 +1 @@
1
- import{getSettingsForSource as t}from"../settings/settings.js";export function isPluginBlockedByPolicy(e){const i=t("policySettings")?.enabledPlugins;return!1===i?.[e]}
1
+ import{getSettingsForSource as t}from"../settings/settings.js";export function isPluginBlockedByPolicy(i){const n=t("policySettings")?.enabledPlugins;return!1===n?.[i]}
@@ -1 +1 @@
1
- import{join as e}from"path";import{getCwd as n}from"../cwd.js";import{logForDebugging as t}from"../debug.js";import{logError as s}from"../log.js";import{getInitialSettings as i,getSettingsForSource as o,updateSettingsForSource as r}from"../settings/settings.js";import{getAddDirEnabledPlugins as l}from"./addDirPluginSettings.js";import{getInMemoryInstalledPlugins as a,migrateFromEnabledPlugins as c}from"./installedPluginsManager.js";import{getPluginById as u}from"./marketplaceManager.js";import{SETTING_SOURCE_TO_SCOPE as g,scopeToSettingSource as p}from"./pluginIdentifier.js";import{cacheAndRegisterPlugin as d,registerPluginInstallation as f}from"./pluginInstallationHelpers.js";import{isLocalPluginSource as m}from"./schemas.js";export async function checkEnabledPlugins(){const e=i(),n=[],t=l();for(const[e,s]of Object.entries(t))e.includes("@")&&s&&n.push(e);if(e.enabledPlugins)for(const[t,s]of Object.entries(e.enabledPlugins)){if(!t.includes("@"))continue;const e=n.indexOf(t);s?-1===e&&n.push(t):-1!==e&&n.splice(e,1)}return n}export function getPluginEditableScopes(){const e=new Map,n=l();for(const[t,s]of Object.entries(n))t.includes("@")&&(!0===s?e.set(t,"flag"):!1===s&&e.delete(t));const s=[{scope:"managed",source:"policySettings"},{scope:"user",source:"userSettings"},{scope:"project",source:"projectSettings"},{scope:"local",source:"localSettings"},{scope:"flag",source:"flagSettings"}];for(const{scope:i,source:r}of s){const s=o(r);if(s?.enabledPlugins)for(const[o,l]of Object.entries(s.enabledPlugins))o.includes("@")&&(o in n&&n[o]!==l&&t(`Plugin ${o} from --add-dir (${n[o]}) overridden by ${r} (${l})`),!0===l?e.set(o,i):!1===l&&e.delete(o))}return t(`Found ${e.size} enabled plugins with scopes: ${Array.from(e.entries()).map(([e,n])=>`${e}(${n})`).join(", ")}`),e}export function isPersistableScope(e){return"flag"!==e}export function settingSourceToScope(e){return g[e]}export async function getInstalledPlugins(){c().catch(e=>{s(e)});const e=a(),n=Object.keys(e.plugins);return t(`Found ${n.length} installed plugins`),n}export async function findMissingPlugins(e){try{const n=await getInstalledPlugins(),s=e.filter(e=>!n.includes(e)),i=await Promise.all(s.map(async e=>{try{return{pluginId:e,found:null!=await u(e)}}catch(n){return t(`Failed to check plugin ${e} in marketplace: ${n}`),{pluginId:e,found:!1}}}));return i.filter(({found:e})=>e).map(({pluginId:e})=>e)}catch(e){return s(e),[]}}export async function installSelectedPlugins(t,i,l="user"){const a="user"!==l?n():void 0,c=p(l),g=o(c),P={...g?.enabledPlugins},S=[],b=[];for(let n=0;n<t.length;n++){const o=t[n];if(o){i&&i(o,n+1,t.length);try{const n=await u(o);if(!n){b.push({name:o,error:"Plugin not found in any marketplace"});continue}const{entry:t,marketplaceInstallLocation:s}=n;m(t.source)?f({pluginId:o,installPath:e(s,t.source),version:t.version},l,a):await d(o,t,l,a),P[o]=!0,S.push(o)}catch(e){const n=e instanceof Error?e.message:String(e);b.push({name:o,error:n}),s(e)}}}return r(c,{...g,enabledPlugins:P}),{installed:S,failed:b}}
1
+ import{join as e}from"path";import{getCwd as n}from"../cwd.js";import{logForDebugging as t}from"../debug.js";import{logError as s}from"../log.js";import{getInitialSettings as o,getSettingsForSource as i,updateSettingsForSource as r}from"../settings/settings.js";import{getAddDirEnabledPlugins as l}from"./addDirPluginSettings.js";import{getInMemoryInstalledPlugins as c,migrateFromEnabledPlugins as a}from"./installedPluginsManager.js";import{getPluginById as u}from"./marketplaceManager.js";import{SETTING_SOURCE_TO_SCOPE as p,scopeToSettingSource as g}from"./pluginIdentifier.js";import{cacheAndRegisterPlugin as f,registerPluginInstallation as d}from"./pluginInstallationHelpers.js";import{isLocalPluginSource as m}from"./schemas.js";export async function checkEnabledPlugins(){const e=o(),n=[],t=l();for(const[e,s]of Object.entries(t))e.includes("@")&&s&&n.push(e);if(e.enabledPlugins)for(const[t,s]of Object.entries(e.enabledPlugins)){if(!t.includes("@"))continue;const e=n.indexOf(t);s?-1===e&&n.push(t):-1!==e&&n.splice(e,1)}return n}export function getPluginEditableScopes(){const e=new Map,n=l();for(const[t,s]of Object.entries(n))t.includes("@")&&(!0===s?e.set(t,"flag"):!1===s&&e.delete(t));const s=[{scope:"managed",source:"policySettings"},{scope:"user",source:"userSettings"},{scope:"project",source:"projectSettings"},{scope:"local",source:"localSettings"},{scope:"flag",source:"flagSettings"}];for(const{scope:o,source:r}of s){const s=i(r);if(s?.enabledPlugins)for(const[i,l]of Object.entries(s.enabledPlugins))i.includes("@")&&(i in n&&n[i]!==l&&t(`Plugin ${i} from --add-dir (${n[i]}) overridden by ${r} (${l})`),!0===l?e.set(i,o):!1===l&&e.delete(i))}return t(`Found ${e.size} enabled plugins with scopes: ${Array.from(e.entries()).map(([e,n])=>`${e}(${n})`).join(", ")}`),e}export function isPersistableScope(e){return"flag"!==e}export function settingSourceToScope(e){return p[e]}export async function getInstalledPlugins(){a().catch(e=>{s(e)});const e=c(),n=Object.keys(e.plugins);return t(`Found ${n.length} installed plugins`),n}export async function findMissingPlugins(e){try{const n=await getInstalledPlugins(),s=e.filter(e=>!n.includes(e)),o=await Promise.all(s.map(async e=>{try{const n=await u(e);return{pluginId:e,found:null!=n}}catch(n){return t(`Failed to check plugin ${e} in marketplace: ${n}`),{pluginId:e,found:!1}}}));return o.filter(({found:e})=>e).map(({pluginId:e})=>e)}catch(e){return s(e),[]}}export async function installSelectedPlugins(t,o,l="user"){const c="user"!==l?n():void 0,a=g(l),p=i(a),P={...p?.enabledPlugins},h=[],j=[];for(let n=0;n<t.length;n++){const i=t[n];if(i){o&&o(i,n+1,t.length);try{const n=await u(i);if(!n){j.push({name:i,error:"Plugin not found in any marketplace"});continue}const{entry:t,marketplaceInstallLocation:s}=n;m(t.source)?d({pluginId:i,installPath:e(s,t.source),version:t.version},l,c):await f(i,t,l,c),P[i]=!0,h.push(i)}catch(e){const n=e instanceof Error?e.message:String(e);j.push({name:i,error:n}),s(e)}}}return r(a,{...p,enabledPlugins:P}),{installed:h,failed:j}}
@@ -1 +1 @@
1
- import{createHash as r}from"crypto";import{logForDebugging as t}from"../debug.js";import{getHeadForDir as n}from"../git/gitFilesystem.js";export async function calculatePluginVersion(n,e,i,o,s,u){if(i?.version)return t(`Using manifest version for ${n}: ${i.version}`),i.version;if(s)return t(`Using provided version for ${n}: ${s}`),s;if(u){const i=u.substring(0,12);if("object"==typeof e&&"git-subdir"===e.source){const o=e.path.replace(/\\/g,"/").replace(/^\.\//,"").replace(/\/+$/,""),s=`${i}-${r("sha256").update(o).digest("hex").substring(0,8)}`;return t(`Using git-subdir SHA+path version for ${n}: ${s} (path=${o})`),s}return t(`Using pre-resolved git SHA for ${n}: ${i}`),i}if(o){const r=await getGitCommitSha(o);if(r){const e=r.substring(0,12);return t(`Using git SHA for ${n}: ${e}`),e}}return t(`No version found for ${n}, using 'unknown'`),"unknown"}export function getGitCommitSha(r){return n(r)}export function getVersionFromPath(r){const t=r.split("/").filter(Boolean),n=t.findIndex((r,n)=>"cache"===r&&"plugins"===t[n-1]);if(-1===n)return null;const e=t.slice(n+1);return e.length>=3&&e[2]||null}export function isVersionedPath(r){return null!==getVersionFromPath(r)}
1
+ import{createHash as r}from"crypto";import{logForDebugging as n}from"../debug.js";import{getHeadForDir as t}from"../git/gitFilesystem.js";export async function calculatePluginVersion(t,i,e,o,s,u){if(e?.version)return n(`Using manifest version for ${t}: ${e.version}`),e.version;if(s)return n(`Using provided version for ${t}: ${s}`),s;if(u){const e=u.substring(0,12);if("object"==typeof i&&"git-subdir"===i.source){const o=i.path.replace(/\\/g,"/").replace(/^\.\//,"").replace(/\/+$/,""),s=`${e}-${r("sha256").update(o).digest("hex").substring(0,8)}`;return n(`Using git-subdir SHA+path version for ${t}: ${s} (path=${o})`),s}return n(`Using pre-resolved git SHA for ${t}: ${e}`),e}if(o){const r=await getGitCommitSha(o);if(r){const i=r.substring(0,12);return n(`Using git SHA for ${t}: ${i}`),i}}return n(`No version found for ${t}, using 'unknown'`),"unknown"}export function getGitCommitSha(r){return t(r)}export function getVersionFromPath(r){const n=r.split("/").filter(Boolean),t=n.findIndex((r,t)=>"cache"===r&&"plugins"===n[t-1]);if(-1===t)return null;const i=n.slice(t+1);return i.length>=3&&i[2]||null}export function isVersionedPath(r){return null!==getVersionFromPath(r)}
@@ -1 +1 @@
1
- import e from"lodash-es/isEqual.js";import{isAbsolute as a,resolve as o}from"path";import{getOriginalCwd as r}from"../../bootstrap/state.js";import{logForDebugging as t}from"../debug.js";import{errorMessage as s}from"../errors.js";import{pathExists as n}from"../file.js";import{findCanonicalGitRoot as i}from"../git.js";import{logError as c}from"../log.js";import{addMarketplaceSource as l,getDeclaredMarketplaces as p,loadKnownMarketplacesConfig as u}from"./marketplaceManager.js";import{isLocalMarketplaceSource as m}from"./schemas.js";export function diffMarketplaces(a,o,r){const t=[],s=[],n=[];for(const[i,c]of Object.entries(a)){const a=o[i],l=normalizeSource(c.source,r?.projectRoot);a?c.sourceIsFallback||e(l,a.source)?n.push(i):s.push({name:i,declaredSource:l,materializedSource:a.source}):t.push(i)}return{missing:t,sourceChanged:s,upToDate:n}}export async function reconcileMarketplaces(e){const a=p();if(0===Object.keys(a).length)return{installed:[],updated:[],failed:[],upToDate:[],skipped:[]};let o;try{o=await u()}catch(e){c(e),o={}}const i=diffMarketplaces(a,o,{projectRoot:r()}),d=[...i.missing.map(e=>({name:e,source:normalizeSource(a[e].source),action:"install"})),...i.sourceChanged.map(({name:e,declaredSource:a})=>({name:e,source:a,action:"update"}))],f=[],g=[];for(const a of d)e?.skip?.(a.name,a.source)?f.push(a.name):"update"!==a.action||!m(a.source)||await n(a.source.path)?g.push(a):(t(`[reconcile] '${a.name}' declared path does not exist; keeping materialized entry`),f.push(a.name));if(0===g.length)return{installed:[],updated:[],failed:[],upToDate:i.upToDate,skipped:f};t(`[reconcile] ${g.length} marketplace(s): ${g.map(e=>`${e.name}(${e.action})`).join(", ")}`);const h=[],k=[],j=[];for(let o=0;o<g.length;o++){const{name:r,source:t,action:n}=g[o];e?.onProgress?.({type:"installing",name:r,action:n,index:o+1,total:g.length});try{const a=await l(t);"install"===n?h.push(r):k.push(r),e?.onProgress?.({type:"installed",name:r,alreadyMaterialized:a.alreadyMaterialized})}catch(a){const o=s(a);j.push({name:r,error:o}),e?.onProgress?.({type:"failed",name:r,error:o}),c(a)}}return{installed:h,updated:k,failed:j,upToDate:i.upToDate,skipped:f}}function normalizeSource(e,t){if(("directory"===e.source||"file"===e.source)&&!a(e.path)){const a=t??r(),s=i(a);return{...e,path:o(s??a,e.path)}}return e}
1
+ import e from"lodash-es/isEqual.js";import{isAbsolute as t,resolve as o}from"path";import{getOriginalCwd as r}from"../../bootstrap/state.js";import{logForDebugging as a}from"../debug.js";import{errorMessage as s}from"../errors.js";import{pathExists as n}from"../file.js";import{findCanonicalGitRoot as i}from"../git.js";import{logError as c}from"../log.js";import{addMarketplaceSource as p,getDeclaredMarketplaces as l,loadKnownMarketplacesConfig as u}from"./marketplaceManager.js";import{isLocalMarketplaceSource as m}from"./schemas.js";export function diffMarketplaces(t,o,r){const a=[],s=[],n=[];for(const[i,c]of Object.entries(t)){const t=o[i],p=normalizeSource(c.source,r?.projectRoot);t?c.sourceIsFallback||e(p,t.source)?n.push(i):s.push({name:i,declaredSource:p,materializedSource:t.source}):a.push(i)}return{missing:a,sourceChanged:s,upToDate:n}}export async function reconcileMarketplaces(e){const t=l();if(0===Object.keys(t).length)return{installed:[],updated:[],failed:[],upToDate:[],skipped:[]};let o;try{o=await u()}catch(e){c(e),o={}}const i=diffMarketplaces(t,o,{projectRoot:r()}),d=[...i.missing.map(e=>({name:e,source:normalizeSource(t[e].source),action:"install"})),...i.sourceChanged.map(({name:e,declaredSource:t})=>({name:e,source:t,action:"update"}))],f=[],h=[];for(const t of d)e?.skip?.(t.name,t.source)?f.push(t.name):"update"!==t.action||!m(t.source)||await n(t.source.path)?h.push(t):(a(`[reconcile] '${t.name}' declared path does not exist; keeping materialized entry`),f.push(t.name));if(0===h.length)return{installed:[],updated:[],failed:[],upToDate:i.upToDate,skipped:f};a(`[reconcile] ${h.length} marketplace(s): ${h.map(e=>`${e.name}(${e.action})`).join(", ")}`);const g=[],j=[],k=[];for(let t=0;t<h.length;t++){const{name:o,source:r,action:a}=h[t];e?.onProgress?.({type:"installing",name:o,action:a,index:t+1,total:h.length});try{const t=await p(r);"install"===a?g.push(o):j.push(o),e?.onProgress?.({type:"installed",name:o,alreadyMaterialized:t.alreadyMaterialized})}catch(t){const r=s(t);k.push({name:o,error:r}),e?.onProgress?.({type:"failed",name:o,error:r}),c(t)}}return{installed:g,updated:j,failed:k,upToDate:i.upToDate,skipped:f}}function normalizeSource(e,a){if(("directory"===e.source||"file"===e.source)&&!t(e.path)){const t=a??r(),s=i(t);return{...e,path:o(s??t,e.path)}}return e}
@@ -1 +1 @@
1
- import{getOriginalCwd as e}from"../../bootstrap/state.js";import{reinitializeLspServerManager as r}from"../../services/lsp/manager.js";import{getAgentDefinitionsWithOverrides as s}from"../../tools/AgentTool/loadAgentsDir.js";import{logForDebugging as o}from"../debug.js";import{errorMessage as n}from"../errors.js";import{logError as t}from"../log.js";import{clearAllCaches as l}from"./cacheUtils.js";import{getPluginCommands as i}from"./loadPluginCommands.js";import{loadPluginHooks as a}from"./loadPluginHooks.js";import{loadPluginLspServers as g}from"./lspPluginIntegration.js";import{loadPluginMcpServers as c}from"./mcpPluginIntegration.js";import{clearPluginCacheExclusions as u}from"./orphanedPluginFilter.js";import{loadAllPlugins as m}from"./pluginLoader.js";export async function refreshActivePlugins(p){o("refreshActivePlugins: clearing all plugin caches"),l(),u();const d=await m(),[h,f]=await Promise.all([i(),s(e())]),{enabled:P,disabled:j,errors:v}=d,[b,y]=await Promise.all([Promise.all(P.map(async e=>{if(e.mcpServers)return Object.keys(e.mcpServers).length;const r=await c(e,v);return r&&(e.mcpServers=r),r?Object.keys(r).length:0})),Promise.all(P.map(async e=>{if(e.lspServers)return Object.keys(e.lspServers).length;const r=await g(e,v);return r&&(e.lspServers=r),r?Object.keys(r).length:0}))]),k=b.reduce((e,r)=>e+r,0),A=y.reduce((e,r)=>e+r,0);p(e=>({...e,plugins:{...e.plugins,enabled:P,disabled:j,commands:h,errors:mergePluginErrors(e.plugins.errors,v),needsRefresh:!1},agentDefinitions:f,mcp:{...e.mcp,pluginReconnectKey:e.mcp.pluginReconnectKey+1}})),r();let S=!1;try{await a()}catch(e){S=!0,t(e),o(`refreshActivePlugins: loadPluginHooks failed: ${n(e)}`)}const $=P.reduce((e,r)=>r.hooksConfig?e+Object.values(r.hooksConfig).reduce((e,r)=>e+(r?.reduce((e,r)=>e+r.hooks.length,0)??0),0):e,0);return o(`refreshActivePlugins: ${P.length} enabled, ${h.length} commands, ${f.allAgents.length} agents, ${$} hooks, ${k} MCP, ${A} LSP`),{enabled_count:P.length,disabled_count:j.length,command_count:h.length,agent_count:f.allAgents.length,hook_count:$,mcp_count:k,lsp_count:A,error_count:v.length+(S?1:0),agentDefinitions:f,pluginCommands:h}}function mergePluginErrors(e,r){const s=e.filter(e=>"lsp-manager"===e.source||e.source.startsWith("plugin:")),o=new Set(r.map(errorKey));return[...s.filter(e=>!o.has(errorKey(e))),...r]}function errorKey(e){return"generic-error"===e.type?`generic-error:${e.source}:${e.error}`:`${e.type}:${e.source}`}
1
+ import{getOriginalCwd as e}from"../../bootstrap/state.js";import{reinitializeLspServerManager as r}from"../../services/lsp/manager.js";import{getAgentDefinitionsWithOverrides as o}from"../../tools/AgentTool/loadAgentsDir.js";import{logForDebugging as n}from"../debug.js";import{errorMessage as t}from"../errors.js";import{logError as s}from"../log.js";import{clearAllCaches as i}from"./cacheUtils.js";import{getPluginCommands as l}from"./loadPluginCommands.js";import{loadPluginHooks as a}from"./loadPluginHooks.js";import{loadPluginLspServers as c}from"./lspPluginIntegration.js";import{loadPluginMcpServers as g}from"./mcpPluginIntegration.js";import{clearPluginCacheExclusions as m}from"./orphanedPluginFilter.js";import{loadAllPlugins as u}from"./pluginLoader.js";export async function refreshActivePlugins(p){n("refreshActivePlugins: clearing all plugin caches"),i(),m();const f=await u(),[d,h]=await Promise.all([l(),o(e())]),{enabled:j,disabled:P,errors:y}=f,[b,v]=await Promise.all([Promise.all(j.map(async e=>{if(e.mcpServers)return Object.keys(e.mcpServers).length;const r=await g(e,y);return r&&(e.mcpServers=r),r?Object.keys(r).length:0})),Promise.all(j.map(async e=>{if(e.lspServers)return Object.keys(e.lspServers).length;const r=await c(e,y);return r&&(e.lspServers=r),r?Object.keys(r).length:0}))]),k=b.reduce((e,r)=>e+r,0),$=v.reduce((e,r)=>e+r,0);p(e=>({...e,plugins:{...e.plugins,enabled:j,disabled:P,commands:d,errors:mergePluginErrors(e.plugins.errors,y),needsRefresh:!1},agentDefinitions:h,mcp:{...e.mcp,pluginReconnectKey:e.mcp.pluginReconnectKey+1}})),r();let A=!1;try{await a()}catch(e){A=!0,s(e),n(`refreshActivePlugins: loadPluginHooks failed: ${t(e)}`)}const S=j.reduce((e,r)=>r.hooksConfig?e+Object.values(r.hooksConfig).reduce((e,r)=>e+(r?.reduce((e,r)=>e+r.hooks.length,0)??0),0):e,0);return n(`refreshActivePlugins: ${j.length} enabled, ${d.length} commands, ${h.allAgents.length} agents, ${S} hooks, ${k} MCP, ${$} LSP`),{enabled_count:j.length,disabled_count:P.length,command_count:d.length,agent_count:h.allAgents.length,hook_count:S,mcp_count:k,lsp_count:$,error_count:y.length+(A?1:0),agentDefinitions:h,pluginCommands:d}}function mergePluginErrors(e,r){const o=e.filter(e=>"lsp-manager"===e.source||e.source.startsWith("plugin:")),n=new Set(r.map(errorKey));return[...o.filter(e=>!n.has(errorKey(e))),...r]}function errorKey(e){return"generic-error"===e.type?`generic-error:${e.source}:${e.error}`:`${e.type}:${e.source}`}
@@ -1 +1 @@
1
- import{z as e}from"zod/v4";import{HooksSchema as t}from"../../schemas/hooks.js";import{McpServerConfigSchema as i}from"../../services/mcp/types.js";import{lazySchema as o}from"../lazySchema.js";export const ALLOWED_OFFICIAL_MARKETPLACE_NAMES=new Set(["claude-code-marketplace","claude-code-plugins","claude-plugins-official","anthropic-marketplace","anthropic-plugins","agent-skills","life-sciences","knowledge-work-plugins"]);const a=new Set(["knowledge-work-plugins"]);export function isMarketplaceAutoUpdate(e,t){const i=e.toLowerCase();return t.autoUpdate??(ALLOWED_OFFICIAL_MARKETPLACE_NAMES.has(i)&&!a.has(i))}export const BLOCKED_OFFICIAL_NAME_PATTERN=/(?:official[^a-z0-9]*(contextcompany|claude)|(?:contextcompany|claude)[^a-z0-9]*official|^(?:contextcompany|claude)[^a-z0-9]*(marketplace|plugins|official))/i;const r=/[^\u0020-\u007E]/;export function isBlockedOfficialName(e){return!ALLOWED_OFFICIAL_MARKETPLACE_NAMES.has(e.toLowerCase())&&(!!r.test(e)||BLOCKED_OFFICIAL_NAME_PATTERN.test(e))}export const OFFICIAL_GITHUB_ORG="anthropics";export function validateOfficialNameSource(e,t){const i=e.toLowerCase();if(!ALLOWED_OFFICIAL_MARKETPLACE_NAMES.has(i))return null;if("github"===t.source)return(t.repo||"").toLowerCase().startsWith("anthropics/")?null:`The name '${e}' is reserved for official ContextCompany marketplaces. Only repositories from 'github.com/anthropics/' can use this name.`;if("git"===t.source&&t.url){const i=t.url.toLowerCase(),o=i.includes("github.com/anthropics/"),a=i.includes("git@github.com:anthropics/");return o||a?null:`The name '${e}' is reserved for official ContextCompany marketplaces. Only repositories from 'github.com/anthropics/' can use this name.`}return`The name '${e}' is reserved for official ContextCompany marketplaces and can only be used with GitHub sources from the 'anthropics' organization.`}const n=o(()=>e.string().startsWith("./")),s=o(()=>n().endsWith(".json")),c=o(()=>e.union([n().refine(e=>e.endsWith(".mcpb")||e.endsWith(".dxt"),{message:"MCPB file path must end with .mcpb or .dxt"}).describe("Path to MCPB file relative to plugin root"),e.string().url().refine(e=>e.endsWith(".mcpb")||e.endsWith(".dxt"),{message:"MCPB URL must end with .mcpb or .dxt"}).describe("URL to MCPB file")])),l=o(()=>n().endsWith(".md")),d=o(()=>e.union([l(),n()])),p=o(()=>e.string().min(1,"Marketplace must have a name").refine(e=>!e.includes(" "),{message:'Marketplace name cannot contain spaces. Use kebab-case (e.g., "my-marketplace")'}).refine(e=>!e.includes("/")&&!e.includes("\\")&&!e.includes("..")&&"."!==e,{message:'Marketplace name cannot contain path separators (/ or \\), ".." sequences, or be "."'}).refine(e=>!isBlockedOfficialName(e),{message:"Marketplace name impersonates an official ContextCompany/Claude marketplace"}).refine(e=>"inline"!==e.toLowerCase(),{message:'Marketplace name "inline" is reserved for --plugin-dir session plugins'}).refine(e=>"builtin"!==e.toLowerCase(),{message:'Marketplace name "builtin" is reserved for built-in plugins'}));export const PluginAuthorSchema=o(()=>e.object({name:e.string().min(1,"Author name cannot be empty").describe("Display name of the plugin author or organization"),email:e.string().optional().describe("Contact email for support or feedback"),url:e.string().optional().describe("Website, GitHub profile, or organization URL")}));const u=o(()=>e.object({name:e.string().min(1,"Plugin name cannot be empty").refine(e=>!e.includes(" "),{message:'Plugin name cannot contain spaces. Use kebab-case (e.g., "my-plugin")'}).describe("Unique identifier for the plugin, used for namespacing (prefer kebab-case)"),version:e.string().optional().describe("Semantic version (e.g., 1.2.3) following semver.org specification"),description:e.string().optional().describe("Brief, user-facing explanation of what the plugin provides"),author:PluginAuthorSchema().optional().describe("Information about the plugin creator or maintainer"),homepage:e.string().url().optional().describe("Plugin homepage or documentation URL"),repository:e.string().optional().describe("Source code repository URL"),license:e.string().optional().describe("SPDX license identifier (e.g., MIT, Apache-2.0)"),keywords:e.array(e.string()).optional().describe("Tags for plugin discovery and categorization"),dependencies:e.array(DependencyRefSchema()).optional().describe('Plugins that must be enabled for this plugin to function. Bare names (no "@marketplace") are resolved against the declaring plugin\'s own marketplace.')}));export const PluginHooksSchema=o(()=>e.object({description:e.string().optional().describe("Brief, user-facing explanation of what these hooks provide"),hooks:e.lazy(()=>t()).describe("The hooks provided by the plugin, in the same format as the one used for settings")}));const g=o(()=>e.object({hooks:e.union([s().describe("Path to file with additional hooks (in addition to those in hooks/hooks.json, if it exists), relative to the plugin root"),e.lazy(()=>t()).describe("Additional hooks (in addition to those in hooks/hooks.json, if it exists)"),e.array(e.union([s().describe("Path to file with additional hooks (in addition to those in hooks/hooks.json, if it exists), relative to the plugin root"),e.lazy(()=>t()).describe("Additional hooks (in addition to those in hooks/hooks.json, if it exists)")]))])}));export const CommandMetadataSchema=o(()=>e.object({source:d().optional().describe("Path to command markdown file, relative to plugin root"),content:e.string().optional().describe("Inline markdown content for the command"),description:e.string().optional().describe("Command description override"),argumentHint:e.string().optional().describe('Hint for command arguments (e.g., "[file]")'),model:e.string().optional().describe("Default model for this command"),allowedTools:e.array(e.string()).optional().describe("Tools allowed when command runs")}).refine(e=>e.source&&!e.content||!e.source&&e.content,{message:'Command must have either "source" (file path) or "content" (inline markdown), but not both'}));const m=o(()=>e.object({commands:e.union([d().describe("Path to additional command file or skill directory (in addition to those in the commands/ directory, if it exists), relative to the plugin root"),e.array(d().describe("Path to additional command file or skill directory (in addition to those in the commands/ directory, if it exists), relative to the plugin root")).describe("List of paths to additional command files or skill directories"),e.record(e.string(),CommandMetadataSchema()).describe('Object mapping of command names to their metadata and source files. Command name becomes the slash command name (e.g., "about" → "/plugin:about")')])})),h=o(()=>e.object({agents:e.union([l().describe("Path to additional agent file (in addition to those in the agents/ directory, if it exists), relative to the plugin root"),e.array(l().describe("Path to additional agent file (in addition to those in the agents/ directory, if it exists), relative to the plugin root")).describe("List of paths to additional agent files")])})),b=o(()=>e.object({skills:e.union([n().describe("Path to additional skill directory (in addition to those in the skills/ directory, if it exists), relative to the plugin root"),e.array(n().describe("Path to additional skill directory (in addition to those in the skills/ directory, if it exists), relative to the plugin root")).describe("List of paths to additional skill directories")])})),f=o(()=>e.object({outputStyles:e.union([n().describe("Path to additional output styles directory or file (in addition to those in the output-styles/ directory, if it exists), relative to the plugin root"),e.array(n().describe("Path to additional output styles directory or file (in addition to those in the output-styles/ directory, if it exists), relative to the plugin root")).describe("List of paths to additional output styles directories or files")])})),y=o(()=>e.string().min(1)),k=o(()=>e.string().min(2).refine(e=>e.startsWith("."),{message:'File extensions must start with dot (e.g., ".ts", not "ts")'})),v=o(()=>e.object({mcpServers:e.union([s().describe("MCP servers to include in the plugin (in addition to those in the .mcp.json file, if it exists)"),c().describe("Path or URL to MCPB file containing MCP server configuration"),e.record(e.string(),i()).describe("MCP server configurations keyed by server name"),e.array(e.union([s().describe("Path to MCP servers configuration file"),c().describe("Path or URL to MCPB file"),e.record(e.string(),i()).describe("Inline MCP server configurations")])).describe("Array of MCP server configurations (paths, MCPB files, or inline definitions)")])})),P=o(()=>e.object({type:e.enum(["string","number","boolean","directory","file"]).describe("Type of the configuration value"),title:e.string().describe("Human-readable label shown in the config dialog"),description:e.string().describe("Help text shown beneath the field in the config dialog"),required:e.boolean().optional().describe("If true, validation fails when this field is empty"),default:e.union([e.string(),e.number(),e.boolean(),e.array(e.string())]).optional().describe("Default value used when the user provides nothing"),multiple:e.boolean().optional().describe("For string type: allow an array of strings"),sensitive:e.boolean().optional().describe("If true, masks dialog input and stores value in secure storage (keychain/credentials file) instead of settings.json"),min:e.number().optional().describe("Minimum value (number type only)"),max:e.number().optional().describe("Maximum value (number type only)")}).strict()),S=o(()=>e.object({userConfig:e.record(e.string().regex(/^[A-Za-z_]\w*$/,"Option keys must be valid identifiers (letters, digits, underscore; no leading digit) — they become CLAUDE_PLUGIN_OPTION_<KEY> env vars in hooks"),P()).optional().describe("User-configurable values this plugin needs. Prompted at enable time. Non-sensitive values saved to settings.json; sensitive values to secure storage (macOS keychain or .credentials.json). Available as ${user_config.KEY} in MCP/LSP server config, hook commands, and (non-sensitive only) skill/agent content. Note: sensitive values share a single keychain entry with OAuth tokens — keep secret counts small to stay under the ~2KB stdin-safe limit (see INC-3028).")})),w=o(()=>e.object({channels:e.array(e.object({server:e.string().min(1).describe("Name of the MCP server this channel binds to. Must match a key in this plugin's mcpServers."),displayName:e.string().optional().describe('Human-readable name shown in the config dialog title (e.g., "Telegram"). Defaults to the server name.'),userConfig:e.record(e.string(),P()).optional().describe("Fields to prompt the user for when enabling this plugin in assistant mode. Saved values are substituted into ${user_config.KEY} references in the mcpServers env.")}).strict()).describe("Channels this plugin provides. Each entry declares an MCP server as a message channel and optionally specifies user configuration to prompt for at enable time.")}));export const LspServerConfigSchema=o(()=>e.strictObject({command:e.string().min(1).refine(e=>!(e.includes(" ")&&!e.startsWith("/")),{message:"Command should not contain spaces. Use args array for arguments."}).describe('Command to execute the LSP server (e.g., "typescript-language-server")'),args:e.array(y()).optional().describe("Command-line arguments to pass to the server"),extensionToLanguage:e.record(k(),y()).refine(e=>Object.keys(e).length>0,{message:"extensionToLanguage must have at least one mapping"}).describe("Mapping from file extension to LSP language ID. File extensions and languages are derived from this mapping."),transport:e.enum(["stdio","socket"]).default("stdio").describe("Communication transport mechanism"),env:e.record(e.string(),e.string()).optional().describe("Environment variables to set when starting the server"),initializationOptions:e.unknown().optional().describe("Initialization options passed to the server during initialization"),settings:e.unknown().optional().describe("Settings passed to the server via workspace/didChangeConfiguration"),workspaceFolder:e.string().optional().describe("Workspace folder path to use for the server"),startupTimeout:e.number().int().positive().optional().describe("Maximum time to wait for server startup (milliseconds)"),shutdownTimeout:e.number().int().positive().optional().describe("Maximum time to wait for graceful shutdown (milliseconds)"),restartOnCrash:e.boolean().optional().describe("Whether to restart the server if it crashes"),maxRestarts:e.number().int().nonnegative().optional().describe("Maximum number of restart attempts before giving up")}));const C=o(()=>e.object({lspServers:e.union([s().describe("Path to .lsp.json configuration file relative to plugin root"),e.record(e.string(),LspServerConfigSchema()).describe("LSP server configurations keyed by server name"),e.array(e.union([s().describe("Path to LSP configuration file"),e.record(e.string(),LspServerConfigSchema()).describe("Inline LSP server configurations")])).describe("Array of LSP server configurations (paths or inline definitions)")])})),x=o(()=>e.string().refine(e=>!e.includes("..")&&!e.includes("//"),"Package name cannot contain path traversal patterns").refine(e=>/^@[a-z0-9][a-z0-9-._]*\/[a-z0-9][a-z0-9-._]*$/.test(e)||/^[a-z0-9][a-z0-9-._]*$/.test(e),"Invalid npm package name format")),M=o(()=>e.object({settings:e.record(e.string(),e.unknown()).optional().describe("Settings to merge when plugin is enabled. Only allowlisted keys are kept (currently: agent)")}));export const PluginManifestSchema=o(()=>e.object({...u().shape,...g().partial().shape,...m().partial().shape,...h().partial().shape,...b().partial().shape,...f().partial().shape,...w().partial().shape,...v().partial().shape,...C().partial().shape,...M().partial().shape,...S().partial().shape}));export const MarketplaceSourceSchema=o(()=>e.discriminatedUnion("source",[e.object({source:e.literal("url"),url:e.string().url().describe("Direct URL to marketplace.json file"),headers:e.record(e.string(),e.string()).optional().describe("Custom HTTP headers (e.g., for authentication)")}),e.object({source:e.literal("github"),repo:e.string().describe("GitHub repository in owner/repo format"),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),path:e.string().optional().describe("Path to marketplace.json within repo (defaults to .claude-plugin/marketplace.json)"),sparsePaths:e.array(e.string()).optional().describe('Directories to include via git sparse-checkout (cone mode). Use for monorepos where the marketplace lives in a subdirectory. Example: [".claude-plugin", "plugins"]. If omitted, the full repository is cloned.')}),e.object({source:e.literal("git"),url:e.string().describe("Full git repository URL"),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),path:e.string().optional().describe("Path to marketplace.json within repo (defaults to .claude-plugin/marketplace.json)"),sparsePaths:e.array(e.string()).optional().describe('Directories to include via git sparse-checkout (cone mode). Use for monorepos where the marketplace lives in a subdirectory. Example: [".claude-plugin", "plugins"]. If omitted, the full repository is cloned.')}),e.object({source:e.literal("npm"),package:x().describe("NPM package containing marketplace.json")}),e.object({source:e.literal("file"),path:e.string().describe("Local file path to marketplace.json")}),e.object({source:e.literal("directory"),path:e.string().describe("Local directory containing .claude-plugin/marketplace.json")}),e.object({source:e.literal("hostPattern"),hostPattern:e.string().describe('Regex pattern to match the host/domain extracted from any marketplace source type. For github sources, matches against "github.com". For git sources (SSH or HTTPS), extracts the hostname from the URL. Use in strictKnownMarketplaces to allow all marketplaces from a specific host (e.g., "^github\\.mycompany\\.com$").')}),e.object({source:e.literal("pathPattern"),pathPattern:e.string().describe('Regex pattern matched against the .path field of file and directory sources. Use in strictKnownMarketplaces to allow filesystem-based marketplaces alongside hostPattern restrictions for network sources. Use ".*" to allow all filesystem paths, or a narrower pattern (e.g., "^/opt/approved/") to restrict to specific directories.')}),e.object({source:e.literal("settings"),name:p().refine(e=>!ALLOWED_OFFICIAL_MARKETPLACE_NAMES.has(e.toLowerCase()),{message:"Reserved official marketplace names cannot be used with settings sources. validateOfficialNameSource only accepts github/git sources from anthropics/* for these names; a settings source would be rejected after loadAndCacheMarketplace has already written to disk with cleanupNeeded=false."}).describe("Marketplace name. Must match the extraKnownMarketplaces key (enforced); the synthetic manifest is written under this name. Same validation as PluginMarketplaceSchema plus reserved-name rejection — validateOfficialNameSource runs after the disk write, too late to clean up."),plugins:e.array(j()).describe("Plugin entries declared inline in settings.json"),owner:PluginAuthorSchema().optional()}).describe("Inline marketplace manifest defined directly in settings.json. The reconciler writes a synthetic marketplace.json to the cache; diffMarketplaces detects edits via isEqual on the stored source (the plugins array is inside this object, so edits surface as sourceChanged).")]));export const gitSha=o(()=>e.string().length(40).regex(/^[a-f0-9]{40}$/,"Must be a full 40-character lowercase git commit SHA"));export const PluginSourceSchema=o(()=>e.union([n().describe("Path to the plugin root, relative to the marketplace root (the directory containing .claude-plugin/, not .claude-plugin/ itself)"),e.object({source:e.literal("npm"),package:x().or(e.string()).describe("Package name (or url, or local path, or anything else that can be passed to `npm` as a package)"),version:e.string().optional().describe("Specific version or version range (e.g., ^1.0.0, ~2.1.0)"),registry:e.string().url().optional().describe("Custom NPM registry URL (defaults to using system default, likely npmjs.org)")}).describe("NPM package as plugin source"),e.object({source:e.literal("pip"),package:e.string().describe("Python package name as it appears on PyPI"),version:e.string().optional().describe("Version specifier (e.g., ==1.0.0, >=2.0.0, <3.0.0)"),registry:e.string().url().optional().describe("Custom PyPI registry URL (defaults to using system default, likely pypi.org)")}).describe("Python package as plugin source"),e.object({source:e.literal("url"),url:e.string().describe("Full git repository URL (https:// or git@)"),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),sha:gitSha().optional().describe("Specific commit SHA to use")}),e.object({source:e.literal("github"),repo:e.string().describe("GitHub repository in owner/repo format"),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),sha:gitSha().optional().describe("Specific commit SHA to use")}),e.object({source:e.literal("git-subdir"),url:e.string().describe("Git repository: GitHub owner/repo shorthand, https://, or git@ URL"),path:e.string().min(1).describe('Subdirectory within the repo containing the plugin (e.g., "tools/claude-plugin"). Cloned sparsely using partial clone (--filter=tree:0) to minimize bandwidth for monorepos.'),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),sha:gitSha().optional().describe("Specific commit SHA to use")}).describe("Plugin located in a subdirectory of a larger repository (monorepo). Only the specified subdirectory is materialized; the rest of the repo is not downloaded.")]));const j=o(()=>e.object({name:e.string().min(1,"Plugin name cannot be empty").refine(e=>!e.includes(" "),{message:'Plugin name cannot contain spaces. Use kebab-case (e.g., "my-plugin")'}).describe("Plugin name as it appears in the target repository"),source:PluginSourceSchema().describe("Where to fetch the plugin from. Must be a remote source — relative paths have no marketplace repository to resolve against."),description:e.string().optional(),version:e.string().optional(),strict:e.boolean().optional()}).refine(e=>"string"!=typeof e.source,{message:'Plugins in a settings-sourced marketplace must use remote sources (github, git-subdir, npm, url, pip). Relative-path sources like "./foo" have no marketplace repository to resolve against.'}));export function isLocalPluginSource(e){return"string"==typeof e&&e.startsWith("./")}export function isLocalMarketplaceSource(e){return"file"===e.source||"directory"===e.source}export const PluginMarketplaceEntrySchema=o(()=>PluginManifestSchema().partial().extend({name:e.string().min(1,"Plugin name cannot be empty").refine(e=>!e.includes(" "),{message:'Plugin name cannot contain spaces. Use kebab-case (e.g., "my-plugin")'}).describe("Unique identifier matching the plugin name"),source:PluginSourceSchema().describe("Where to fetch the plugin from"),category:e.string().optional().describe('Category for organizing plugins (e.g., "productivity", "development")'),tags:e.array(e.string()).optional().describe("Tags for searchability and discovery"),strict:e.boolean().optional().default(!0).describe("Require the plugin manifest to be present in the plugin folder. If false, the marketplace entry provides the manifest.")}));export const PluginMarketplaceSchema=o(()=>e.object({name:p(),owner:PluginAuthorSchema().describe("Marketplace maintainer or curator information"),plugins:e.array(PluginMarketplaceEntrySchema()).describe("Collection of available plugins in this marketplace"),forceRemoveDeletedPlugins:e.boolean().optional().describe("When true, plugins removed from this marketplace will be automatically uninstalled and flagged for users"),metadata:e.object({pluginRoot:e.string().optional().describe("Base path for relative plugin sources"),version:e.string().optional().describe("Marketplace version"),description:e.string().optional().describe("Marketplace description")}).optional().describe("Optional marketplace metadata"),allowCrossMarketplaceDependenciesOn:e.array(e.string()).optional().describe("Marketplace names whose plugins may be auto-installed as dependencies. Only the root marketplace's allowlist applies — no transitive trust.")}));export const PluginIdSchema=o(()=>e.string().regex(/^[a-z0-9][-a-z0-9._]*@[a-z0-9][-a-z0-9._]*$/i,"Plugin ID must be in format: plugin@marketplace"));const L=/^[a-z0-9][-a-z0-9._]*(@[a-z0-9][-a-z0-9._]*)?(@\^[^@]*)?$/i;export const DependencyRefSchema=o(()=>e.union([e.string().regex(L,"Dependency must be a plugin name, optionally qualified with @marketplace").transform(e=>e.replace(/@\^[^@]*$/,"")),e.object({name:e.string().min(1).regex(/^[a-z0-9][-a-z0-9._]*$/i),marketplace:e.string().min(1).regex(/^[a-z0-9][-a-z0-9._]*$/i).optional()}).loose().transform(e=>e.marketplace?`${e.name}@${e.marketplace}`:e.name)]));export const SettingsPluginEntrySchema=o(()=>e.union([PluginIdSchema(),e.object({id:PluginIdSchema().describe('Plugin identifier (e.g., "formatter@tools")'),version:e.string().optional().describe('Version constraint (e.g., "^2.0.0")'),required:e.boolean().optional().describe("If true, cannot be disabled"),config:e.record(e.string(),e.unknown()).optional().describe("Plugin-specific configuration")})]));export const InstalledPluginSchema=o(()=>e.object({version:e.string().describe("Currently installed version"),installedAt:e.string().describe("ISO 8601 timestamp of installation"),lastUpdated:e.string().optional().describe("ISO 8601 timestamp of last update"),installPath:e.string().describe("Absolute path to the installed plugin directory"),gitCommitSha:e.string().optional().describe("Git commit SHA for git-based plugins (for version tracking)")}));export const InstalledPluginsFileSchemaV1=o(()=>e.object({version:e.literal(1).describe("Schema version 1"),plugins:e.record(PluginIdSchema(),InstalledPluginSchema()).describe("Map of plugin IDs to their installation metadata")}));export const PluginScopeSchema=o(()=>e.enum(["managed","user","project","local"]));export const PluginInstallationEntrySchema=o(()=>e.object({scope:PluginScopeSchema().describe("Installation scope"),projectPath:e.string().optional().describe("Project path (required for project/local scopes)"),installPath:e.string().describe("Absolute path to the versioned plugin directory"),version:e.string().optional().describe("Currently installed version"),installedAt:e.string().optional().describe("ISO 8601 timestamp of installation"),lastUpdated:e.string().optional().describe("ISO 8601 timestamp of last update"),gitCommitSha:e.string().optional().describe("Git commit SHA for git-based plugins")}));export const InstalledPluginsFileSchemaV2=o(()=>e.object({version:e.literal(2).describe("Schema version 2"),plugins:e.record(PluginIdSchema(),e.array(PluginInstallationEntrySchema())).describe("Map of plugin IDs to arrays of installation entries")}));export const InstalledPluginsFileSchema=o(()=>e.union([InstalledPluginsFileSchemaV1(),InstalledPluginsFileSchemaV2()]));export const KnownMarketplaceSchema=o(()=>e.object({source:MarketplaceSourceSchema().describe("Where to fetch the marketplace from"),installLocation:e.string().describe("Local cache path where marketplace manifest is stored"),lastUpdated:e.string().describe("ISO 8601 timestamp of last marketplace refresh"),autoUpdate:e.boolean().optional().describe("Whether to automatically update this marketplace and its installed plugins on startup")}));export const KnownMarketplacesFileSchema=o(()=>e.record(e.string(),KnownMarketplaceSchema()));
1
+ import{z as e}from"zod/v4";import{HooksSchema as t}from"../../schemas/hooks.js";import{McpServerConfigSchema as i}from"../../services/mcp/types.js";import{lazySchema as o}from"../lazySchema.js";export const ALLOWED_OFFICIAL_MARKETPLACE_NAMES=new Set(["claude-code-marketplace","claude-code-plugins","claude-plugins-official","anthropic-marketplace","anthropic-plugins","agent-skills","life-sciences","knowledge-work-plugins"]);const a=new Set(["knowledge-work-plugins"]);export function isMarketplaceAutoUpdate(e,t){const i=e.toLowerCase();return t.autoUpdate??(ALLOWED_OFFICIAL_MARKETPLACE_NAMES.has(i)&&!a.has(i))}export const BLOCKED_OFFICIAL_NAME_PATTERN=/(?:official[^a-z0-9]*(contextcompany|claude)|(?:contextcompany|claude)[^a-z0-9]*official|^(?:contextcompany|claude)[^a-z0-9]*(marketplace|plugins|official))/i;const r=/[^\u0020-\u007E]/;export function isBlockedOfficialName(e){return!ALLOWED_OFFICIAL_MARKETPLACE_NAMES.has(e.toLowerCase())&&(!!r.test(e)||BLOCKED_OFFICIAL_NAME_PATTERN.test(e))}export const OFFICIAL_GITHUB_ORG="anthropics";export function validateOfficialNameSource(e,t){const i=e.toLowerCase();if(!ALLOWED_OFFICIAL_MARKETPLACE_NAMES.has(i))return null;if("github"===t.source){return(t.repo||"").toLowerCase().startsWith("anthropics/")?null:`The name '${e}' is reserved for official ContextCompany marketplaces. Only repositories from 'github.com/anthropics/' can use this name.`}if("git"===t.source&&t.url){const i=t.url.toLowerCase(),o=i.includes("github.com/anthropics/"),a=i.includes("git@github.com:anthropics/");return o||a?null:`The name '${e}' is reserved for official ContextCompany marketplaces. Only repositories from 'github.com/anthropics/' can use this name.`}return`The name '${e}' is reserved for official ContextCompany marketplaces and can only be used with GitHub sources from the 'anthropics' organization.`}const n=o(()=>e.string().startsWith("./")),s=o(()=>n().endsWith(".json")),l=o(()=>e.union([n().refine(e=>e.endsWith(".mcpb")||e.endsWith(".dxt"),{message:"MCPB file path must end with .mcpb or .dxt"}).describe("Path to MCPB file relative to plugin root"),e.string().url().refine(e=>e.endsWith(".mcpb")||e.endsWith(".dxt"),{message:"MCPB URL must end with .mcpb or .dxt"}).describe("URL to MCPB file")])),c=o(()=>n().endsWith(".md")),d=o(()=>e.union([c(),n()])),p=o(()=>e.string().min(1,"Marketplace must have a name").refine(e=>!e.includes(" "),{message:'Marketplace name cannot contain spaces. Use kebab-case (e.g., "my-marketplace")'}).refine(e=>!e.includes("/")&&!e.includes("\\")&&!e.includes("..")&&"."!==e,{message:'Marketplace name cannot contain path separators (/ or \\), ".." sequences, or be "."'}).refine(e=>!isBlockedOfficialName(e),{message:"Marketplace name impersonates an official ContextCompany/Claude marketplace"}).refine(e=>"inline"!==e.toLowerCase(),{message:'Marketplace name "inline" is reserved for --plugin-dir session plugins'}).refine(e=>"builtin"!==e.toLowerCase(),{message:'Marketplace name "builtin" is reserved for built-in plugins'}));export const PluginAuthorSchema=o(()=>e.object({name:e.string().min(1,"Author name cannot be empty").describe("Display name of the plugin author or organization"),email:e.string().optional().describe("Contact email for support or feedback"),url:e.string().optional().describe("Website, GitHub profile, or organization URL")}));const u=o(()=>e.object({name:e.string().min(1,"Plugin name cannot be empty").refine(e=>!e.includes(" "),{message:'Plugin name cannot contain spaces. Use kebab-case (e.g., "my-plugin")'}).describe("Unique identifier for the plugin, used for namespacing (prefer kebab-case)"),version:e.string().optional().describe("Semantic version (e.g., 1.2.3) following semver.org specification"),description:e.string().optional().describe("Brief, user-facing explanation of what the plugin provides"),author:PluginAuthorSchema().optional().describe("Information about the plugin creator or maintainer"),homepage:e.string().url().optional().describe("Plugin homepage or documentation URL"),repository:e.string().optional().describe("Source code repository URL"),license:e.string().optional().describe("SPDX license identifier (e.g., MIT, Apache-2.0)"),keywords:e.array(e.string()).optional().describe("Tags for plugin discovery and categorization"),dependencies:e.array(DependencyRefSchema()).optional().describe('Plugins that must be enabled for this plugin to function. Bare names (no "@marketplace") are resolved against the declaring plugin\'s own marketplace.')}));export const PluginHooksSchema=o(()=>e.object({description:e.string().optional().describe("Brief, user-facing explanation of what these hooks provide"),hooks:e.lazy(()=>t()).describe("The hooks provided by the plugin, in the same format as the one used for settings")}));const g=o(()=>e.object({hooks:e.union([s().describe("Path to file with additional hooks (in addition to those in hooks/hooks.json, if it exists), relative to the plugin root"),e.lazy(()=>t()).describe("Additional hooks (in addition to those in hooks/hooks.json, if it exists)"),e.array(e.union([s().describe("Path to file with additional hooks (in addition to those in hooks/hooks.json, if it exists), relative to the plugin root"),e.lazy(()=>t()).describe("Additional hooks (in addition to those in hooks/hooks.json, if it exists)")]))])}));export const CommandMetadataSchema=o(()=>e.object({source:d().optional().describe("Path to command markdown file, relative to plugin root"),content:e.string().optional().describe("Inline markdown content for the command"),description:e.string().optional().describe("Command description override"),argumentHint:e.string().optional().describe('Hint for command arguments (e.g., "[file]")'),model:e.string().optional().describe("Default model for this command"),allowedTools:e.array(e.string()).optional().describe("Tools allowed when command runs")}).refine(e=>e.source&&!e.content||!e.source&&e.content,{message:'Command must have either "source" (file path) or "content" (inline markdown), but not both'}));const m=o(()=>e.object({commands:e.union([d().describe("Path to additional command file or skill directory (in addition to those in the commands/ directory, if it exists), relative to the plugin root"),e.array(d().describe("Path to additional command file or skill directory (in addition to those in the commands/ directory, if it exists), relative to the plugin root")).describe("List of paths to additional command files or skill directories"),e.record(e.string(),CommandMetadataSchema()).describe('Object mapping of command names to their metadata and source files. Command name becomes the slash command name (e.g., "about" → "/plugin:about")')])})),h=o(()=>e.object({agents:e.union([c().describe("Path to additional agent file (in addition to those in the agents/ directory, if it exists), relative to the plugin root"),e.array(c().describe("Path to additional agent file (in addition to those in the agents/ directory, if it exists), relative to the plugin root")).describe("List of paths to additional agent files")])})),b=o(()=>e.object({skills:e.union([n().describe("Path to additional skill directory (in addition to those in the skills/ directory, if it exists), relative to the plugin root"),e.array(n().describe("Path to additional skill directory (in addition to those in the skills/ directory, if it exists), relative to the plugin root")).describe("List of paths to additional skill directories")])})),f=o(()=>e.object({outputStyles:e.union([n().describe("Path to additional output styles directory or file (in addition to those in the output-styles/ directory, if it exists), relative to the plugin root"),e.array(n().describe("Path to additional output styles directory or file (in addition to those in the output-styles/ directory, if it exists), relative to the plugin root")).describe("List of paths to additional output styles directories or files")])})),y=o(()=>e.string().min(1)),k=o(()=>e.string().min(2).refine(e=>e.startsWith("."),{message:'File extensions must start with dot (e.g., ".ts", not "ts")'})),v=o(()=>e.object({mcpServers:e.union([s().describe("MCP servers to include in the plugin (in addition to those in the .mcp.json file, if it exists)"),l().describe("Path or URL to MCPB file containing MCP server configuration"),e.record(e.string(),i()).describe("MCP server configurations keyed by server name"),e.array(e.union([s().describe("Path to MCP servers configuration file"),l().describe("Path or URL to MCPB file"),e.record(e.string(),i()).describe("Inline MCP server configurations")])).describe("Array of MCP server configurations (paths, MCPB files, or inline definitions)")])})),P=o(()=>e.object({type:e.enum(["string","number","boolean","directory","file"]).describe("Type of the configuration value"),title:e.string().describe("Human-readable label shown in the config dialog"),description:e.string().describe("Help text shown beneath the field in the config dialog"),required:e.boolean().optional().describe("If true, validation fails when this field is empty"),default:e.union([e.string(),e.number(),e.boolean(),e.array(e.string())]).optional().describe("Default value used when the user provides nothing"),multiple:e.boolean().optional().describe("For string type: allow an array of strings"),sensitive:e.boolean().optional().describe("If true, masks dialog input and stores value in secure storage (keychain/credentials file) instead of settings.json"),min:e.number().optional().describe("Minimum value (number type only)"),max:e.number().optional().describe("Maximum value (number type only)")}).strict()),S=o(()=>e.object({userConfig:e.record(e.string().regex(/^[A-Za-z_]\w*$/,"Option keys must be valid identifiers (letters, digits, underscore; no leading digit) — they become CLAUDE_PLUGIN_OPTION_<KEY> env vars in hooks"),P()).optional().describe("User-configurable values this plugin needs. Prompted at enable time. Non-sensitive values saved to settings.json; sensitive values to secure storage (macOS keychain or .credentials.json). Available as ${user_config.KEY} in MCP/LSP server config, hook commands, and (non-sensitive only) skill/agent content. Note: sensitive values share a single keychain entry with OAuth tokens — keep secret counts small to stay under the ~2KB stdin-safe limit (see INC-3028).")})),w=o(()=>e.object({channels:e.array(e.object({server:e.string().min(1).describe("Name of the MCP server this channel binds to. Must match a key in this plugin's mcpServers."),displayName:e.string().optional().describe('Human-readable name shown in the config dialog title (e.g., "Telegram"). Defaults to the server name.'),userConfig:e.record(e.string(),P()).optional().describe("Fields to prompt the user for when enabling this plugin in assistant mode. Saved values are substituted into ${user_config.KEY} references in the mcpServers env.")}).strict()).describe("Channels this plugin provides. Each entry declares an MCP server as a message channel and optionally specifies user configuration to prompt for at enable time.")}));export const LspServerConfigSchema=o(()=>e.strictObject({command:e.string().min(1).refine(e=>!(e.includes(" ")&&!e.startsWith("/")),{message:"Command should not contain spaces. Use args array for arguments."}).describe('Command to execute the LSP server (e.g., "typescript-language-server")'),args:e.array(y()).optional().describe("Command-line arguments to pass to the server"),extensionToLanguage:e.record(k(),y()).refine(e=>Object.keys(e).length>0,{message:"extensionToLanguage must have at least one mapping"}).describe("Mapping from file extension to LSP language ID. File extensions and languages are derived from this mapping."),transport:e.enum(["stdio","socket"]).default("stdio").describe("Communication transport mechanism"),env:e.record(e.string(),e.string()).optional().describe("Environment variables to set when starting the server"),initializationOptions:e.unknown().optional().describe("Initialization options passed to the server during initialization"),settings:e.unknown().optional().describe("Settings passed to the server via workspace/didChangeConfiguration"),workspaceFolder:e.string().optional().describe("Workspace folder path to use for the server"),startupTimeout:e.number().int().positive().optional().describe("Maximum time to wait for server startup (milliseconds)"),shutdownTimeout:e.number().int().positive().optional().describe("Maximum time to wait for graceful shutdown (milliseconds)"),restartOnCrash:e.boolean().optional().describe("Whether to restart the server if it crashes"),maxRestarts:e.number().int().nonnegative().optional().describe("Maximum number of restart attempts before giving up")}));const x=o(()=>e.object({lspServers:e.union([s().describe("Path to .lsp.json configuration file relative to plugin root"),e.record(e.string(),LspServerConfigSchema()).describe("LSP server configurations keyed by server name"),e.array(e.union([s().describe("Path to LSP configuration file"),e.record(e.string(),LspServerConfigSchema()).describe("Inline LSP server configurations")])).describe("Array of LSP server configurations (paths or inline definitions)")])})),C=o(()=>e.string().refine(e=>!e.includes("..")&&!e.includes("//"),"Package name cannot contain path traversal patterns").refine(e=>/^@[a-z0-9][a-z0-9-._]*\/[a-z0-9][a-z0-9-._]*$/.test(e)||/^[a-z0-9][a-z0-9-._]*$/.test(e),"Invalid npm package name format")),j=o(()=>e.object({settings:e.record(e.string(),e.unknown()).optional().describe("Settings to merge when plugin is enabled. Only allowlisted keys are kept (currently: agent)")}));export const PluginManifestSchema=o(()=>e.object({...u().shape,...g().partial().shape,...m().partial().shape,...h().partial().shape,...b().partial().shape,...f().partial().shape,...w().partial().shape,...v().partial().shape,...x().partial().shape,...j().partial().shape,...S().partial().shape}));export const MarketplaceSourceSchema=o(()=>e.discriminatedUnion("source",[e.object({source:e.literal("url"),url:e.string().url().describe("Direct URL to marketplace.json file"),headers:e.record(e.string(),e.string()).optional().describe("Custom HTTP headers (e.g., for authentication)")}),e.object({source:e.literal("github"),repo:e.string().describe("GitHub repository in owner/repo format"),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),path:e.string().optional().describe("Path to marketplace.json within repo (defaults to .claude-plugin/marketplace.json)"),sparsePaths:e.array(e.string()).optional().describe('Directories to include via git sparse-checkout (cone mode). Use for monorepos where the marketplace lives in a subdirectory. Example: [".claude-plugin", "plugins"]. If omitted, the full repository is cloned.')}),e.object({source:e.literal("git"),url:e.string().describe("Full git repository URL"),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),path:e.string().optional().describe("Path to marketplace.json within repo (defaults to .claude-plugin/marketplace.json)"),sparsePaths:e.array(e.string()).optional().describe('Directories to include via git sparse-checkout (cone mode). Use for monorepos where the marketplace lives in a subdirectory. Example: [".claude-plugin", "plugins"]. If omitted, the full repository is cloned.')}),e.object({source:e.literal("npm"),package:C().describe("NPM package containing marketplace.json")}),e.object({source:e.literal("file"),path:e.string().describe("Local file path to marketplace.json")}),e.object({source:e.literal("directory"),path:e.string().describe("Local directory containing .claude-plugin/marketplace.json")}),e.object({source:e.literal("hostPattern"),hostPattern:e.string().describe('Regex pattern to match the host/domain extracted from any marketplace source type. For github sources, matches against "github.com". For git sources (SSH or HTTPS), extracts the hostname from the URL. Use in strictKnownMarketplaces to allow all marketplaces from a specific host (e.g., "^github\\.mycompany\\.com$").')}),e.object({source:e.literal("pathPattern"),pathPattern:e.string().describe('Regex pattern matched against the .path field of file and directory sources. Use in strictKnownMarketplaces to allow filesystem-based marketplaces alongside hostPattern restrictions for network sources. Use ".*" to allow all filesystem paths, or a narrower pattern (e.g., "^/opt/approved/") to restrict to specific directories.')}),e.object({source:e.literal("settings"),name:p().refine(e=>!ALLOWED_OFFICIAL_MARKETPLACE_NAMES.has(e.toLowerCase()),{message:"Reserved official marketplace names cannot be used with settings sources. validateOfficialNameSource only accepts github/git sources from anthropics/* for these names; a settings source would be rejected after loadAndCacheMarketplace has already written to disk with cleanupNeeded=false."}).describe("Marketplace name. Must match the extraKnownMarketplaces key (enforced); the synthetic manifest is written under this name. Same validation as PluginMarketplaceSchema plus reserved-name rejection — validateOfficialNameSource runs after the disk write, too late to clean up."),plugins:e.array(M()).describe("Plugin entries declared inline in settings.json"),owner:PluginAuthorSchema().optional()}).describe("Inline marketplace manifest defined directly in settings.json. The reconciler writes a synthetic marketplace.json to the cache; diffMarketplaces detects edits via isEqual on the stored source (the plugins array is inside this object, so edits surface as sourceChanged).")]));export const gitSha=o(()=>e.string().length(40).regex(/^[a-f0-9]{40}$/,"Must be a full 40-character lowercase git commit SHA"));export const PluginSourceSchema=o(()=>e.union([n().describe("Path to the plugin root, relative to the marketplace root (the directory containing .claude-plugin/, not .claude-plugin/ itself)"),e.object({source:e.literal("npm"),package:C().or(e.string()).describe("Package name (or url, or local path, or anything else that can be passed to `npm` as a package)"),version:e.string().optional().describe("Specific version or version range (e.g., ^1.0.0, ~2.1.0)"),registry:e.string().url().optional().describe("Custom NPM registry URL (defaults to using system default, likely npmjs.org)")}).describe("NPM package as plugin source"),e.object({source:e.literal("pip"),package:e.string().describe("Python package name as it appears on PyPI"),version:e.string().optional().describe("Version specifier (e.g., ==1.0.0, >=2.0.0, <3.0.0)"),registry:e.string().url().optional().describe("Custom PyPI registry URL (defaults to using system default, likely pypi.org)")}).describe("Python package as plugin source"),e.object({source:e.literal("url"),url:e.string().describe("Full git repository URL (https:// or git@)"),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),sha:gitSha().optional().describe("Specific commit SHA to use")}),e.object({source:e.literal("github"),repo:e.string().describe("GitHub repository in owner/repo format"),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),sha:gitSha().optional().describe("Specific commit SHA to use")}),e.object({source:e.literal("git-subdir"),url:e.string().describe("Git repository: GitHub owner/repo shorthand, https://, or git@ URL"),path:e.string().min(1).describe('Subdirectory within the repo containing the plugin (e.g., "tools/claude-plugin"). Cloned sparsely using partial clone (--filter=tree:0) to minimize bandwidth for monorepos.'),ref:e.string().optional().describe('Git branch or tag to use (e.g., "main", "v1.0.0"). Defaults to repository default branch.'),sha:gitSha().optional().describe("Specific commit SHA to use")}).describe("Plugin located in a subdirectory of a larger repository (monorepo). Only the specified subdirectory is materialized; the rest of the repo is not downloaded.")]));const M=o(()=>e.object({name:e.string().min(1,"Plugin name cannot be empty").refine(e=>!e.includes(" "),{message:'Plugin name cannot contain spaces. Use kebab-case (e.g., "my-plugin")'}).describe("Plugin name as it appears in the target repository"),source:PluginSourceSchema().describe("Where to fetch the plugin from. Must be a remote source — relative paths have no marketplace repository to resolve against."),description:e.string().optional(),version:e.string().optional(),strict:e.boolean().optional()}).refine(e=>"string"!=typeof e.source,{message:'Plugins in a settings-sourced marketplace must use remote sources (github, git-subdir, npm, url, pip). Relative-path sources like "./foo" have no marketplace repository to resolve against.'}));export function isLocalPluginSource(e){return"string"==typeof e&&e.startsWith("./")}export function isLocalMarketplaceSource(e){return"file"===e.source||"directory"===e.source}export const PluginMarketplaceEntrySchema=o(()=>PluginManifestSchema().partial().extend({name:e.string().min(1,"Plugin name cannot be empty").refine(e=>!e.includes(" "),{message:'Plugin name cannot contain spaces. Use kebab-case (e.g., "my-plugin")'}).describe("Unique identifier matching the plugin name"),source:PluginSourceSchema().describe("Where to fetch the plugin from"),category:e.string().optional().describe('Category for organizing plugins (e.g., "productivity", "development")'),tags:e.array(e.string()).optional().describe("Tags for searchability and discovery"),strict:e.boolean().optional().default(!0).describe("Require the plugin manifest to be present in the plugin folder. If false, the marketplace entry provides the manifest.")}));export const PluginMarketplaceSchema=o(()=>e.object({name:p(),owner:PluginAuthorSchema().describe("Marketplace maintainer or curator information"),plugins:e.array(PluginMarketplaceEntrySchema()).describe("Collection of available plugins in this marketplace"),forceRemoveDeletedPlugins:e.boolean().optional().describe("When true, plugins removed from this marketplace will be automatically uninstalled and flagged for users"),metadata:e.object({pluginRoot:e.string().optional().describe("Base path for relative plugin sources"),version:e.string().optional().describe("Marketplace version"),description:e.string().optional().describe("Marketplace description")}).optional().describe("Optional marketplace metadata"),allowCrossMarketplaceDependenciesOn:e.array(e.string()).optional().describe("Marketplace names whose plugins may be auto-installed as dependencies. Only the root marketplace's allowlist applies — no transitive trust.")}));export const PluginIdSchema=o(()=>e.string().regex(/^[a-z0-9][-a-z0-9._]*@[a-z0-9][-a-z0-9._]*$/i,"Plugin ID must be in format: plugin@marketplace"));const L=/^[a-z0-9][-a-z0-9._]*(@[a-z0-9][-a-z0-9._]*)?(@\^[^@]*)?$/i;export const DependencyRefSchema=o(()=>e.union([e.string().regex(L,"Dependency must be a plugin name, optionally qualified with @marketplace").transform(e=>e.replace(/@\^[^@]*$/,"")),e.object({name:e.string().min(1).regex(/^[a-z0-9][-a-z0-9._]*$/i),marketplace:e.string().min(1).regex(/^[a-z0-9][-a-z0-9._]*$/i).optional()}).loose().transform(e=>e.marketplace?`${e.name}@${e.marketplace}`:e.name)]));export const SettingsPluginEntrySchema=o(()=>e.union([PluginIdSchema(),e.object({id:PluginIdSchema().describe('Plugin identifier (e.g., "formatter@tools")'),version:e.string().optional().describe('Version constraint (e.g., "^2.0.0")'),required:e.boolean().optional().describe("If true, cannot be disabled"),config:e.record(e.string(),e.unknown()).optional().describe("Plugin-specific configuration")})]));export const InstalledPluginSchema=o(()=>e.object({version:e.string().describe("Currently installed version"),installedAt:e.string().describe("ISO 8601 timestamp of installation"),lastUpdated:e.string().optional().describe("ISO 8601 timestamp of last update"),installPath:e.string().describe("Absolute path to the installed plugin directory"),gitCommitSha:e.string().optional().describe("Git commit SHA for git-based plugins (for version tracking)")}));export const InstalledPluginsFileSchemaV1=o(()=>e.object({version:e.literal(1).describe("Schema version 1"),plugins:e.record(PluginIdSchema(),InstalledPluginSchema()).describe("Map of plugin IDs to their installation metadata")}));export const PluginScopeSchema=o(()=>e.enum(["managed","user","project","local"]));export const PluginInstallationEntrySchema=o(()=>e.object({scope:PluginScopeSchema().describe("Installation scope"),projectPath:e.string().optional().describe("Project path (required for project/local scopes)"),installPath:e.string().describe("Absolute path to the versioned plugin directory"),version:e.string().optional().describe("Currently installed version"),installedAt:e.string().optional().describe("ISO 8601 timestamp of installation"),lastUpdated:e.string().optional().describe("ISO 8601 timestamp of last update"),gitCommitSha:e.string().optional().describe("Git commit SHA for git-based plugins")}));export const InstalledPluginsFileSchemaV2=o(()=>e.object({version:e.literal(2).describe("Schema version 2"),plugins:e.record(PluginIdSchema(),e.array(PluginInstallationEntrySchema())).describe("Map of plugin IDs to arrays of installation entries")}));export const InstalledPluginsFileSchema=o(()=>e.union([InstalledPluginsFileSchemaV1(),InstalledPluginsFileSchemaV2()]));export const KnownMarketplaceSchema=o(()=>e.object({source:MarketplaceSourceSchema().describe("Where to fetch the marketplace from"),installLocation:e.string().describe("Local cache path where marketplace manifest is stored"),lastUpdated:e.string().describe("ISO 8601 timestamp of last marketplace refresh"),autoUpdate:e.boolean().optional().describe("Whether to automatically update this marketplace and its installed plugins on startup")}));export const KnownMarketplacesFileSchema=o(()=>e.record(e.string(),KnownMarketplaceSchema()));
@@ -1 +1 @@
1
- import{join as i}from"path";import{logForDebugging as a}from"../debug.js";import{getFsImplementation as e}from"../fsOperations.js";const o=/^skill\.md$/i;export async function walkPluginMarkdown(t,n,s={}){const r=e(),m=s.logLabel??"plugin";await async function scan(e,t){try{const a=await r.readdir(e);if(s.stopAtSkillDir&&a.some(i=>i.isFile()&&o.test(i.name)))return void await Promise.all(a.map(a=>a.isFile()&&a.name.toLowerCase().endsWith(".md")?n(i(e,a.name),t):void 0));await Promise.all(a.map(a=>{const o=i(e,a.name);return a.isDirectory()?scan(o,[...t,a.name]):a.isFile()&&a.name.toLowerCase().endsWith(".md")?n(o,t):void 0}))}catch(i){a(`Failed to scan ${m} directory ${e}: ${i}`,{level:"error"})}}(t,[])}
1
+ import{join as i}from"path";import{logForDebugging as a}from"../debug.js";import{getFsImplementation as e}from"../fsOperations.js";const o=/^skill\.md$/i;export async function walkPluginMarkdown(t,r,n={}){const s=e(),m=n.logLabel??"plugin";await async function scan(e,t){try{const a=await s.readdir(e);if(n.stopAtSkillDir&&a.some(i=>i.isFile()&&o.test(i.name)))return void await Promise.all(a.map(a=>a.isFile()&&a.name.toLowerCase().endsWith(".md")?r(i(e,a.name),t):void 0));await Promise.all(a.map(a=>{const o=i(e,a.name);return a.isDirectory()?scan(o,[...t,a.name]):a.isFile()&&a.name.toLowerCase().endsWith(".md")?r(o,t):void 0}))}catch(i){a(`Failed to scan ${m} directory ${e}: ${i}`,{level:"error"})}}(t,[])}