@oh-my-pi/pi-coding-agent 17.2.10 → 17.2.12

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 (247) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/{CHANGELOG-rhwzpexa.md → CHANGELOG-k9ghy5sn.md} +53 -0
  3. package/dist/cli.js +10775 -10762
  4. package/dist/types/advisor/runtime.d.ts +1 -1
  5. package/dist/types/capability/mcp.d.ts +11 -0
  6. package/dist/types/capability/skill.d.ts +6 -0
  7. package/dist/types/cli/command-help.d.ts +3 -0
  8. package/dist/types/commands/share.d.ts +25 -0
  9. package/dist/types/commit/agentic/index.d.ts +3 -1
  10. package/dist/types/commit/execute.d.ts +32 -0
  11. package/dist/types/commit/index.d.ts +2 -1
  12. package/dist/types/commit/pipeline.d.ts +7 -1
  13. package/dist/types/config/custom-models.d.ts +31 -0
  14. package/dist/types/config/model-config-values.d.ts +19 -0
  15. package/dist/types/config/model-patch.d.ts +93 -0
  16. package/dist/types/config/model-provider-discovery.d.ts +51 -0
  17. package/dist/types/config/model-registry.d.ts +9 -52
  18. package/dist/types/config/settings-schema.d.ts +1 -34
  19. package/dist/types/config/settings.d.ts +5 -3
  20. package/dist/types/debug/raw-sse-buffer.d.ts +9 -0
  21. package/dist/types/discovery/agent-plugin-format.d.ts +136 -0
  22. package/dist/types/discovery/agent-plugins.d.ts +1 -0
  23. package/dist/types/discovery/contained-path.d.ts +33 -0
  24. package/dist/types/discovery/index.d.ts +1 -0
  25. package/dist/types/eval/executor-base.d.ts +8 -2
  26. package/dist/types/eval/kernel-session-registry.d.ts +60 -0
  27. package/dist/types/export/share.d.ts +1 -1
  28. package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
  29. package/dist/types/extensibility/extensions/loader.d.ts +7 -0
  30. package/dist/types/extensibility/extensions/types.d.ts +11 -0
  31. package/dist/types/extensibility/shared-events.d.ts +3 -2
  32. package/dist/types/extensibility/skills.d.ts +5 -0
  33. package/dist/types/lsp/diagnostics.d.ts +96 -0
  34. package/dist/types/lsp/index.d.ts +7 -128
  35. package/dist/types/lsp/servers.d.ts +72 -0
  36. package/dist/types/lsp/tool.d.ts +42 -0
  37. package/dist/types/lsp/workspace-diagnostics.d.ts +12 -0
  38. package/dist/types/lsp/writethrough.d.ts +33 -0
  39. package/dist/types/mcp/transports/header-policy.d.ts +46 -0
  40. package/dist/types/mcp/types.d.ts +15 -0
  41. package/dist/types/modes/components/agent-hub-projection.d.ts +2 -7
  42. package/dist/types/modes/components/agent-hub-renderer.d.ts +0 -7
  43. package/dist/types/modes/components/agent-hub.d.ts +2 -0
  44. package/dist/types/modes/components/agent-transcript-viewer.d.ts +2 -0
  45. package/dist/types/modes/components/chat-transcript-builder.d.ts +2 -0
  46. package/dist/types/modes/components/custom-editor.d.ts +1 -2
  47. package/dist/types/modes/components/status-line/types.d.ts +2 -0
  48. package/dist/types/modes/components/tool-execution.d.ts +2 -0
  49. package/dist/types/modes/theme/color.d.ts +19 -0
  50. package/dist/types/modes/theme/loader.d.ts +19 -0
  51. package/dist/types/modes/theme/schema.d.ts +175 -0
  52. package/dist/types/modes/theme/symbols.d.ts +28 -0
  53. package/dist/types/modes/theme/theme-class.d.ts +244 -0
  54. package/dist/types/modes/theme/theme.d.ts +9 -280
  55. package/dist/types/modes/theme/tui-adapters.d.ts +13 -0
  56. package/dist/types/modes/utils/transcript-render-helpers.d.ts +3 -2
  57. package/dist/types/registry/agent-registry.d.ts +1 -3
  58. package/dist/types/secrets/index.d.ts +26 -2
  59. package/dist/types/secrets/message-transform.d.ts +40 -0
  60. package/dist/types/secrets/obfuscator.d.ts +0 -108
  61. package/dist/types/secrets/placeholder-scan.d.ts +95 -0
  62. package/dist/types/secrets/placeholder.d.ts +94 -0
  63. package/dist/types/secrets/replacement.d.ts +82 -0
  64. package/dist/types/session/agent-session-events.d.ts +2 -2
  65. package/dist/types/session/agent-session-types.d.ts +6 -0
  66. package/dist/types/session/agent-session.d.ts +2 -2
  67. package/dist/types/session/messages.d.ts +1 -0
  68. package/dist/types/session/prewalk.d.ts +3 -1
  69. package/dist/types/session/session-handoff.d.ts +3 -3
  70. package/dist/types/session/session-manager.d.ts +32 -0
  71. package/dist/types/session/session-provider-boundary.d.ts +1 -1
  72. package/dist/types/session/session-tools.d.ts +8 -0
  73. package/dist/types/session/turn-recovery.d.ts +9 -4
  74. package/dist/types/slash-commands/builtin-collaboration.d.ts +2 -0
  75. package/dist/types/slash-commands/builtin-completions.d.ts +36 -0
  76. package/dist/types/slash-commands/builtin-control.d.ts +2 -0
  77. package/dist/types/slash-commands/builtin-lifecycle.d.ts +3 -0
  78. package/dist/types/slash-commands/builtin-marketplace.d.ts +11 -0
  79. package/dist/types/slash-commands/builtin-modes.d.ts +5 -0
  80. package/dist/types/slash-commands/builtin-registry.d.ts +1 -1
  81. package/dist/types/slash-commands/builtin-session.d.ts +2 -0
  82. package/dist/types/task/index.d.ts +2 -0
  83. package/dist/types/tools/gh-common.d.ts +69 -0
  84. package/dist/types/tools/gh-pr-checkout.d.ts +84 -0
  85. package/dist/types/tools/gh-pr-diff.d.ts +102 -0
  86. package/dist/types/tools/gh-run-watch.d.ts +78 -0
  87. package/dist/types/tools/gh-search.d.ts +61 -0
  88. package/dist/types/tools/gh-types.d.ts +340 -0
  89. package/dist/types/tools/gh-view.d.ts +88 -0
  90. package/dist/types/tools/gh.d.ts +4 -201
  91. package/dist/types/tools/read-archive.d.ts +16 -0
  92. package/dist/types/tools/read-format.d.ts +104 -0
  93. package/dist/types/tools/read-path-resolution.d.ts +19 -0
  94. package/dist/types/tools/read-pdf-images.d.ts +12 -0
  95. package/dist/types/tools/read-renderer.d.ts +24 -0
  96. package/dist/types/tools/read-selector.d.ts +27 -0
  97. package/dist/types/tools/read-sqlite.d.ts +16 -0
  98. package/dist/types/tools/read-summary.d.ts +19 -0
  99. package/dist/types/tools/read.d.ts +1 -23
  100. package/dist/types/tools/shell-tokenize.d.ts +18 -1
  101. package/dist/types/utils/changelog.d.ts +0 -5
  102. package/package.json +13 -13
  103. package/scripts/legacy-pi-virtual-module.ts +4 -1
  104. package/src/advisor/runtime.ts +12 -7
  105. package/src/capability/mcp.ts +11 -0
  106. package/src/capability/skill.ts +6 -0
  107. package/src/cli/command-help.ts +4 -0
  108. package/src/cli/gallery-cli.ts +1 -1
  109. package/src/cli-commands.ts +5 -0
  110. package/src/commands/commit.ts +16 -3
  111. package/src/commands/share.ts +71 -0
  112. package/src/commit/agentic/index.ts +39 -21
  113. package/src/commit/execute.ts +56 -0
  114. package/src/commit/index.ts +2 -1
  115. package/src/commit/pipeline.ts +20 -7
  116. package/src/config/custom-models.ts +188 -0
  117. package/src/config/model-config-values.ts +128 -0
  118. package/src/config/model-discovery.ts +1 -1
  119. package/src/config/model-patch.ts +252 -0
  120. package/src/config/model-provider-discovery.ts +132 -0
  121. package/src/config/model-registry.ts +84 -704
  122. package/src/config/settings-schema.ts +2 -33
  123. package/src/config/settings.ts +53 -3
  124. package/src/debug/raw-sse-buffer.ts +20 -0
  125. package/src/discovery/agent-plugin-format.ts +551 -0
  126. package/src/discovery/agent-plugins.ts +341 -0
  127. package/src/discovery/claude-plugins.ts +21 -5
  128. package/src/discovery/contained-path.ts +75 -0
  129. package/src/discovery/helpers.ts +23 -9
  130. package/src/discovery/index.ts +1 -0
  131. package/src/discovery/omp-plugins.ts +20 -7
  132. package/src/edit/hashline/diff.ts +5 -1
  133. package/src/eval/executor-base.ts +39 -6
  134. package/src/eval/jl/executor.ts +82 -371
  135. package/src/eval/kernel-session-registry.ts +398 -0
  136. package/src/eval/py/executor.ts +53 -261
  137. package/src/eval/rb/executor.ts +36 -279
  138. package/src/exec/non-interactive-env.ts +1 -0
  139. package/src/export/share.ts +2 -1
  140. package/src/extensibility/custom-tools/types.ts +2 -2
  141. package/src/extensibility/extensions/loader.ts +78 -14
  142. package/src/extensibility/extensions/runner.ts +6 -0
  143. package/src/extensibility/extensions/types.ts +12 -0
  144. package/src/extensibility/plugins/marketplace/manager.ts +2 -1
  145. package/src/extensibility/shared-events.ts +3 -2
  146. package/src/extensibility/skills.ts +9 -0
  147. package/src/internal-urls/skill-protocol.ts +14 -0
  148. package/src/internal-urls/vault-protocol.ts +2 -2
  149. package/src/launch/client.ts +11 -1
  150. package/src/launch/protocol.ts +7 -2
  151. package/src/lsp/diagnostics.ts +516 -0
  152. package/src/lsp/index.ts +20 -2819
  153. package/src/lsp/servers.ts +296 -0
  154. package/src/lsp/tool.ts +1352 -0
  155. package/src/lsp/workspace-diagnostics.ts +170 -0
  156. package/src/lsp/writethrough.ts +561 -0
  157. package/src/main.ts +3 -2
  158. package/src/mcp/config.ts +3 -0
  159. package/src/mcp/manager.ts +12 -9
  160. package/src/mcp/transports/header-policy.ts +95 -0
  161. package/src/mcp/transports/http.ts +35 -52
  162. package/src/mcp/transports/sse.ts +20 -27
  163. package/src/mcp/types.ts +15 -0
  164. package/src/modes/acp/acp-agent.ts +15 -4
  165. package/src/modes/components/agent-dashboard.ts +2 -0
  166. package/src/modes/components/agent-hub-projection.ts +2 -2
  167. package/src/modes/components/agent-hub-renderer.ts +3 -7
  168. package/src/modes/components/agent-hub.ts +5 -0
  169. package/src/modes/components/agent-transcript-viewer.ts +3 -0
  170. package/src/modes/components/chat-transcript-builder.ts +3 -0
  171. package/src/modes/components/custom-editor.ts +0 -9
  172. package/src/modes/components/status-line/component.ts +1 -0
  173. package/src/modes/components/status-line/segments.ts +6 -4
  174. package/src/modes/components/status-line/types.ts +2 -0
  175. package/src/modes/components/tool-execution.ts +13 -16
  176. package/src/modes/components/tree-selector.ts +62 -3
  177. package/src/modes/controllers/command-controller.ts +8 -2
  178. package/src/modes/controllers/event-controller.ts +15 -15
  179. package/src/modes/controllers/input-controller.ts +20 -2
  180. package/src/modes/controllers/selector-controller.ts +1 -0
  181. package/src/modes/theme/color.ts +133 -0
  182. package/src/modes/theme/loader.ts +178 -0
  183. package/src/modes/theme/schema.ts +263 -0
  184. package/src/modes/theme/symbols.ts +1000 -0
  185. package/src/modes/theme/theme-class.ts +611 -0
  186. package/src/modes/theme/theme.ts +27 -2453
  187. package/src/modes/theme/tui-adapters.ts +279 -0
  188. package/src/modes/utils/transcript-render-helpers.ts +4 -2
  189. package/src/modes/utils/ui-helpers.ts +1 -0
  190. package/src/registry/agent-registry.ts +2 -2
  191. package/src/sdk.ts +6 -49
  192. package/src/secrets/index.ts +51 -6
  193. package/src/secrets/message-transform.ts +287 -0
  194. package/src/secrets/obfuscator.ts +39 -1303
  195. package/src/secrets/placeholder-scan.ts +506 -0
  196. package/src/secrets/placeholder.ts +309 -0
  197. package/src/secrets/replacement.ts +216 -0
  198. package/src/session/agent-session-events.ts +2 -2
  199. package/src/session/agent-session-types.ts +6 -0
  200. package/src/session/agent-session.ts +146 -21
  201. package/src/session/indexed-session-storage.ts +7 -2
  202. package/src/session/messages.ts +1 -0
  203. package/src/session/prewalk.ts +57 -17
  204. package/src/session/session-advisors.ts +32 -34
  205. package/src/session/session-context.ts +3 -5
  206. package/src/session/session-handoff.ts +39 -16
  207. package/src/session/session-manager.ts +67 -3
  208. package/src/session/session-provider-boundary.ts +3 -6
  209. package/src/session/session-tools.ts +37 -3
  210. package/src/session/todo-tracker.ts +11 -1
  211. package/src/session/turn-recovery.ts +115 -84
  212. package/src/slash-commands/builtin-collaboration.ts +504 -0
  213. package/src/slash-commands/builtin-completions.ts +291 -0
  214. package/src/slash-commands/builtin-control.ts +78 -0
  215. package/src/slash-commands/builtin-lifecycle.ts +506 -0
  216. package/src/slash-commands/builtin-marketplace.ts +567 -0
  217. package/src/slash-commands/builtin-modes.ts +518 -0
  218. package/src/slash-commands/builtin-registry.ts +21 -2996
  219. package/src/slash-commands/builtin-session.ts +592 -0
  220. package/src/task/executor.ts +17 -14
  221. package/src/task/index.ts +21 -6
  222. package/src/tools/bash-skill-urls.ts +15 -0
  223. package/src/tools/bash.ts +10 -11
  224. package/src/tools/debug.ts +1 -1
  225. package/src/tools/gh-common.ts +288 -0
  226. package/src/tools/gh-pr-checkout.ts +679 -0
  227. package/src/tools/gh-pr-diff.ts +473 -0
  228. package/src/tools/gh-run-watch.ts +1015 -0
  229. package/src/tools/gh-search.ts +500 -0
  230. package/src/tools/gh-types.ts +379 -0
  231. package/src/tools/gh-view.ts +612 -0
  232. package/src/tools/gh.ts +109 -3821
  233. package/src/tools/jtd-to-json-schema.ts +123 -21
  234. package/src/tools/read-archive.ts +209 -0
  235. package/src/tools/read-format.ts +593 -0
  236. package/src/tools/read-path-resolution.ts +36 -0
  237. package/src/tools/read-pdf-images.ts +250 -0
  238. package/src/tools/read-renderer.ts +289 -0
  239. package/src/tools/read-selector.ts +84 -0
  240. package/src/tools/read-sqlite.ts +215 -0
  241. package/src/tools/read-summary.ts +199 -0
  242. package/src/tools/read.ts +82 -1824
  243. package/src/tools/shell-tokenize.ts +99 -1
  244. package/src/utils/changelog.ts +1 -1
  245. package/src/utils/title-generator.ts +3 -1
  246. package/src/web/search/providers/exa.ts +1 -1
  247. package/src/web/search/providers/zai.ts +12 -3
@@ -0,0 +1,567 @@
1
+ import { reset as resetCapabilities } from "../capability";
2
+ import {
3
+ clearPluginRootsAndCaches,
4
+ resolveActiveProjectRegistryPath,
5
+ resolveOrDefaultProjectRegistryPath,
6
+ } from "../discovery/helpers.js";
7
+ import { PluginManager } from "../extensibility/plugins";
8
+ import {
9
+ getInstalledPluginsRegistryPath,
10
+ getMarketplacesCacheDir,
11
+ getMarketplacesRegistryPath,
12
+ getPluginsCacheDir,
13
+ MarketplaceManager,
14
+ } from "../extensibility/plugins/marketplace";
15
+ import { MCPCommandController } from "../modes/controllers/mcp-command-controller";
16
+ import type { InteractiveModeContext } from "../modes/types";
17
+ import { refreshAgentDiscovery } from "../task";
18
+ import { createMarketplaceManager } from "./helpers/marketplace-manager";
19
+ import { commandConsumed, errorMessage, parseSubcommand, usage } from "./helpers/parse";
20
+ import { parseMarketplaceInstallArgs, parsePluginScopeArgs } from "./marketplace-install-parser";
21
+ import type { SlashCommandSpec } from "./types";
22
+
23
+ /**
24
+ * Reload the interactive session's plugin runtime: invalidate fs/plugin-root
25
+ * caches, rediscover skills, file slash commands, and task agents, reset the
26
+ * capability cache, and reconnect MCP servers (rebinding the session's MCP
27
+ * tools). Shared by `/reload-plugins`'s TUI handler and the `handle`-adapter's
28
+ * `reloadPlugins` hook so both honor the command's documented reload scope.
29
+ */
30
+ export async function reloadTuiPluginState(ctx: InteractiveModeContext): Promise<void> {
31
+ const projectPath = await resolveActiveProjectRegistryPath(ctx.sessionManager.getCwd());
32
+ clearPluginRootsAndCaches(projectPath ? [projectPath] : undefined);
33
+ await refreshAgentDiscovery(ctx.sessionManager.getCwd());
34
+ await ctx.refreshSkillState();
35
+ await ctx.refreshSlashCommandState();
36
+ resetCapabilities();
37
+ if (ctx.mcpManager) {
38
+ await new MCPCommandController(ctx).reloadServers();
39
+ }
40
+ }
41
+
42
+ export const BUILTIN_MARKETPLACE_SLASH_COMMANDS: ReadonlyArray<SlashCommandSpec> = [
43
+ {
44
+ name: "marketplace",
45
+ description: "Manage marketplace plugin sources and installed plugins",
46
+ acpDescription: "Manage plugins from marketplaces",
47
+ acpInputHint: "<subcommand>",
48
+ subcommands: [
49
+ { name: "add", description: "Add a marketplace source", usage: "<source>" },
50
+ { name: "remove", description: "Remove a marketplace source", usage: "<name>" },
51
+ { name: "update", description: "Update marketplace catalog(s)", usage: "[name]" },
52
+ { name: "list", description: "List configured marketplaces" },
53
+ { name: "discover", description: "Browse available plugins", usage: "[marketplace]" },
54
+ {
55
+ name: "install",
56
+ description: "Install a plugin (interactive browser if no args)",
57
+ usage: "[--force] [name@marketplace]",
58
+ },
59
+ { name: "uninstall", description: "Uninstall a plugin (selector if no args)", usage: "[name@marketplace]" },
60
+ { name: "installed", description: "List installed marketplace plugins" },
61
+ { name: "upgrade", description: "Upgrade outdated plugins", usage: "[name@marketplace]" },
62
+ { name: "help", description: "Show usage guide" },
63
+ ],
64
+ allowArgs: true,
65
+ handle: async (command, runtime) => {
66
+ const { verb, rest } = parseSubcommand(command.args);
67
+ if (!verb) {
68
+ try {
69
+ const manager = await createMarketplaceManager(runtime);
70
+ const marketplaces = await manager.listMarketplaces();
71
+ if (marketplaces.length === 0) {
72
+ await runtime.output(
73
+ "No marketplaces configured.\n\nGet started:\n /marketplace add anthropics/claude-plugins-official\n\nThen browse with /marketplace discover",
74
+ );
75
+ } else {
76
+ const lines = marketplaces.map(m => ` ${m.name} ${m.sourceUri}`);
77
+ await runtime.output(
78
+ `Marketplaces:\n${lines.join("\n")}\n\nUse /marketplace discover to browse plugins, or /marketplace help for all commands`,
79
+ );
80
+ }
81
+ return commandConsumed();
82
+ } catch (err) {
83
+ return usage(`Marketplace error: ${errorMessage(err)}`, runtime);
84
+ }
85
+ }
86
+ if (verb === "help") {
87
+ await runtime.output(
88
+ [
89
+ "Marketplace commands:",
90
+ " /marketplace List configured marketplaces",
91
+ " /marketplace add <source> Add a marketplace (e.g. owner/repo)",
92
+ " /marketplace remove <name> Remove a marketplace",
93
+ " /marketplace update [name] Re-fetch catalog(s)",
94
+ " /marketplace list List configured marketplaces",
95
+ " /marketplace discover [marketplace] Browse available plugins",
96
+ " /marketplace install <name@marketplace> Install a plugin",
97
+ " /marketplace uninstall <name@marketplace> Uninstall a plugin",
98
+ " /marketplace installed List installed plugins",
99
+ " /marketplace upgrade [name@marketplace] Upgrade plugin(s)",
100
+ "",
101
+ "Quick start:",
102
+ " /marketplace add anthropics/claude-plugins-official",
103
+ ].join("\n"),
104
+ );
105
+ return commandConsumed();
106
+ }
107
+ if ((verb === "install" || verb === "uninstall") && !rest) {
108
+ return usage(
109
+ "Interactive plugin pickers are TUI-only. Pass an explicit name@marketplace argument.",
110
+ runtime,
111
+ );
112
+ }
113
+ try {
114
+ const manager = await createMarketplaceManager(runtime);
115
+ switch (verb) {
116
+ case "add": {
117
+ if (!rest) return usage("Usage: /marketplace add <source>", runtime);
118
+ const entry = await manager.addMarketplace(rest);
119
+ await runtime.output(`Added marketplace: ${entry.name}`);
120
+ return commandConsumed();
121
+ }
122
+ case "remove":
123
+ case "rm": {
124
+ if (!rest) return usage("Usage: /marketplace remove <name>", runtime);
125
+ await manager.removeMarketplace(rest);
126
+ await runtime.output(`Removed marketplace: ${rest}`);
127
+ return commandConsumed();
128
+ }
129
+ case "update": {
130
+ if (rest) {
131
+ await manager.updateMarketplace(rest);
132
+ await runtime.output(`Updated marketplace: ${rest}`);
133
+ } else {
134
+ const results = await manager.updateAllMarketplaces();
135
+ await runtime.output(`Updated ${results.length} marketplace(s)`);
136
+ }
137
+ return commandConsumed();
138
+ }
139
+ case "list": {
140
+ const marketplaces = await manager.listMarketplaces();
141
+ if (marketplaces.length === 0) {
142
+ await runtime.output("No marketplaces configured.");
143
+ } else {
144
+ const lines = marketplaces.map(m => ` ${m.name} ${m.sourceUri}`);
145
+ await runtime.output(`Marketplaces:\n${lines.join("\n")}`);
146
+ }
147
+ return commandConsumed();
148
+ }
149
+ case "discover": {
150
+ const plugins = await manager.listAvailablePlugins(rest || undefined);
151
+ if (plugins.length === 0) {
152
+ const marketplaces = await manager.listMarketplaces();
153
+ await runtime.output(
154
+ marketplaces.length === 0
155
+ ? "No marketplaces configured. Try:\n /marketplace add anthropics/claude-plugins-official"
156
+ : "No plugins available in configured marketplaces",
157
+ );
158
+ return commandConsumed();
159
+ }
160
+ const lines = ["Available plugins:"];
161
+ for (const plugin of plugins) {
162
+ lines.push(` - ${plugin.name}${plugin.version ? `@${plugin.version}` : ""}`);
163
+ if (plugin.description) lines.push(` ${plugin.description}`);
164
+ }
165
+ await runtime.output(lines.join("\n"));
166
+ return commandConsumed();
167
+ }
168
+ case "install": {
169
+ const parsed = parseMarketplaceInstallArgs(rest);
170
+ if ("error" in parsed) return usage(parsed.error, runtime);
171
+ const atIndex = parsed.installSpec.lastIndexOf("@");
172
+ const pluginName = parsed.installSpec.slice(0, atIndex);
173
+ const marketplace = parsed.installSpec.slice(atIndex + 1);
174
+ await manager.installPlugin(pluginName, marketplace, { force: parsed.force, scope: parsed.scope });
175
+ await runtime.reloadPlugins();
176
+ await runtime.output(`Installed ${pluginName} from ${marketplace}`);
177
+ return commandConsumed();
178
+ }
179
+ case "uninstall": {
180
+ const parsed = parsePluginScopeArgs(
181
+ rest,
182
+ "Usage: /marketplace uninstall [--scope user|project] <name@marketplace>",
183
+ );
184
+ if ("error" in parsed) return usage(parsed.error, runtime);
185
+ await manager.uninstallPlugin(parsed.pluginId, parsed.scope);
186
+ await runtime.reloadPlugins();
187
+ await runtime.output(`Uninstalled ${parsed.pluginId}`);
188
+ return commandConsumed();
189
+ }
190
+ case "installed": {
191
+ const installed = await manager.listInstalledPlugins();
192
+ if (installed.length === 0) {
193
+ await runtime.output("No marketplace plugins installed");
194
+ } else {
195
+ const lines = installed.map(
196
+ p => ` ${p.id} [${p.scope}]${p.shadowedBy ? " [shadowed]" : ""} (${p.entries.length} entry)`,
197
+ );
198
+ await runtime.output(`Installed plugins:\n${lines.join("\n")}`);
199
+ }
200
+ return commandConsumed();
201
+ }
202
+ case "upgrade": {
203
+ if (rest) {
204
+ const parsed = parsePluginScopeArgs(
205
+ rest,
206
+ "Usage: /marketplace upgrade [--scope user|project] <name@marketplace>",
207
+ );
208
+ if ("error" in parsed) return usage(parsed.error, runtime);
209
+ const result = await manager.upgradePlugin(parsed.pluginId, parsed.scope);
210
+ await runtime.reloadPlugins();
211
+ await runtime.output(`Upgraded ${parsed.pluginId} to ${result.version}`);
212
+ return commandConsumed();
213
+ }
214
+ const results = await manager.upgradeAllPlugins();
215
+ if (results.length === 0) {
216
+ await runtime.output("All marketplace plugins are up to date");
217
+ } else {
218
+ await runtime.reloadPlugins();
219
+ const lines = results.map(r => ` ${r.pluginId}: ${r.from} -> ${r.to}`);
220
+ await runtime.output(`Upgraded ${results.length} plugin(s):\n${lines.join("\n")}`);
221
+ }
222
+ return commandConsumed();
223
+ }
224
+ default:
225
+ return usage(
226
+ `Unknown /marketplace subcommand: ${verb}. Use /marketplace help for available commands.`,
227
+ runtime,
228
+ );
229
+ }
230
+ } catch (err) {
231
+ return usage(`Marketplace error: ${errorMessage(err)}`, runtime);
232
+ }
233
+ },
234
+ handleTui: async (command, runtime) => {
235
+ runtime.ctx.editor.setText("");
236
+ const args = command.args.trim().split(/\s+/);
237
+ const sub = args[0] || "install";
238
+ const rest = args.slice(1).join(" ").trim();
239
+
240
+ // /marketplace (no args) or /marketplace install (no args) → interactive browser
241
+ if ((sub === "install" && !rest) || (!args[0] && !command.args.trim())) {
242
+ try {
243
+ runtime.ctx.showPluginSelector("install");
244
+ } catch (err) {
245
+ runtime.ctx.showStatus(`Marketplace error: ${err}`);
246
+ }
247
+ return;
248
+ }
249
+
250
+ const mgr = new MarketplaceManager({
251
+ marketplacesRegistryPath: getMarketplacesRegistryPath(),
252
+ installedRegistryPath: getInstalledPluginsRegistryPath(),
253
+ projectInstalledRegistryPath: await resolveOrDefaultProjectRegistryPath(
254
+ runtime.ctx.sessionManager.getCwd(),
255
+ ),
256
+ marketplacesCacheDir: getMarketplacesCacheDir(),
257
+ pluginsCacheDir: getPluginsCacheDir(),
258
+ clearPluginRootsCache: clearPluginRootsAndCaches,
259
+ });
260
+
261
+ try {
262
+ switch (sub) {
263
+ case "add": {
264
+ if (!rest) {
265
+ runtime.ctx.showStatus("Usage: /marketplace add <source>");
266
+ return;
267
+ }
268
+ const entry = await mgr.addMarketplace(rest);
269
+ runtime.ctx.showStatus(`Added marketplace: ${entry.name}`);
270
+ break;
271
+ }
272
+ case "remove":
273
+ case "rm": {
274
+ if (!rest) {
275
+ runtime.ctx.showStatus("Usage: /marketplace remove <name>");
276
+ return;
277
+ }
278
+ await mgr.removeMarketplace(rest);
279
+ runtime.ctx.showStatus(`Removed marketplace: ${rest}`);
280
+ break;
281
+ }
282
+ case "update": {
283
+ if (rest) {
284
+ await mgr.updateMarketplace(rest);
285
+ runtime.ctx.showStatus(`Updated marketplace: ${rest}`);
286
+ } else {
287
+ const results = await mgr.updateAllMarketplaces();
288
+ runtime.ctx.showStatus(`Updated ${results.length} marketplace(s)`);
289
+ }
290
+ break;
291
+ }
292
+ case "discover": {
293
+ const plugins = await mgr.listAvailablePlugins(rest || undefined);
294
+ if (plugins.length === 0) {
295
+ const marketplaces = await mgr.listMarketplaces();
296
+ if (marketplaces.length === 0) {
297
+ runtime.ctx.showStatus(
298
+ "No marketplaces configured. Try:\n /marketplace add anthropics/claude-plugins-official",
299
+ );
300
+ } else {
301
+ runtime.ctx.showStatus("No plugins available in configured marketplaces");
302
+ }
303
+ } else {
304
+ const lines = plugins.map(
305
+ p =>
306
+ ` ${p.name}${p.version ? `@${p.version}` : ""}${p.description ? ` - ${p.description}` : ""}`,
307
+ );
308
+ runtime.ctx.showStatus(`Available plugins:\n${lines.join("\n")}`);
309
+ }
310
+ break;
311
+ }
312
+ case "install": {
313
+ // Parse: /marketplace install [--force] [--scope user|project] name@marketplace
314
+ const parsed = parseMarketplaceInstallArgs(rest);
315
+ if ("error" in parsed) {
316
+ runtime.ctx.showStatus(parsed.error);
317
+ return;
318
+ }
319
+ const atIdx = parsed.installSpec.lastIndexOf("@");
320
+ const name = parsed.installSpec.slice(0, atIdx);
321
+ const marketplace = parsed.installSpec.slice(atIdx + 1);
322
+ await mgr.installPlugin(name, marketplace, { force: parsed.force, scope: parsed.scope });
323
+ runtime.ctx.showStatus(`Installed ${name} from ${marketplace}`);
324
+ break;
325
+ }
326
+ case "uninstall": {
327
+ if (!rest) {
328
+ // No args → open interactive uninstall selector
329
+ runtime.ctx.showPluginSelector("uninstall");
330
+ return;
331
+ }
332
+ const uninstArgs = parsePluginScopeArgs(
333
+ rest,
334
+ "Usage: /marketplace uninstall [--scope user|project] <name@marketplace>",
335
+ );
336
+ if ("error" in uninstArgs) {
337
+ runtime.ctx.showStatus(uninstArgs.error);
338
+ return;
339
+ }
340
+ await mgr.uninstallPlugin(uninstArgs.pluginId, uninstArgs.scope);
341
+ runtime.ctx.showStatus(`Uninstalled ${uninstArgs.pluginId}`);
342
+ break;
343
+ }
344
+ case "installed": {
345
+ const installed = await mgr.listInstalledPlugins();
346
+ if (installed.length === 0) {
347
+ runtime.ctx.showStatus("No marketplace plugins installed");
348
+ } else {
349
+ const lines = installed.map(
350
+ p => ` ${p.id} [${p.scope}]${p.shadowedBy ? " [shadowed]" : ""} (${p.entries.length} entry)`,
351
+ );
352
+ runtime.ctx.showStatus(`Installed plugins:\n${lines.join("\n")}`);
353
+ }
354
+ break;
355
+ }
356
+ case "upgrade": {
357
+ if (rest) {
358
+ const upArgs = parsePluginScopeArgs(
359
+ rest,
360
+ "Usage: /marketplace upgrade [--scope user|project] <name@marketplace>",
361
+ );
362
+ if ("error" in upArgs) {
363
+ runtime.ctx.showStatus(upArgs.error);
364
+ return;
365
+ }
366
+ const result = await mgr.upgradePlugin(upArgs.pluginId, upArgs.scope);
367
+ runtime.ctx.showStatus(`Upgraded ${upArgs.pluginId} to ${result.version}`);
368
+ } else {
369
+ const results = await mgr.upgradeAllPlugins();
370
+ if (results.length === 0) {
371
+ runtime.ctx.showStatus("All marketplace plugins are up to date");
372
+ } else {
373
+ const lines = results.map(r => ` ${r.pluginId}: ${r.from} -> ${r.to}`);
374
+ runtime.ctx.showStatus(`Upgraded ${results.length} plugin(s):\n${lines.join("\n")}`);
375
+ }
376
+ }
377
+ break;
378
+ }
379
+ case "help": {
380
+ runtime.ctx.showStatus(
381
+ [
382
+ "Marketplace commands:",
383
+ " /marketplace Browse and install plugins",
384
+ " /marketplace add <source> Add a marketplace (e.g. owner/repo)",
385
+ " /marketplace remove <name> Remove a marketplace",
386
+ " /marketplace update [name] Re-fetch catalog(s)",
387
+ " /marketplace list List configured marketplaces",
388
+ " /marketplace discover [marketplace] Browse available plugins",
389
+ " /marketplace install <name@marketplace> Install a plugin",
390
+ " /marketplace uninstall <name@marketplace> Uninstall a plugin",
391
+ " /marketplace installed List installed plugins",
392
+ " /marketplace upgrade [name@marketplace] Upgrade plugin(s)",
393
+ "",
394
+ "Quick start:",
395
+ " /marketplace add anthropics/claude-plugins-official",
396
+ " /marketplace (opens interactive browser)",
397
+ ].join("\n"),
398
+ );
399
+ break;
400
+ }
401
+ default: {
402
+ const marketplaces = await mgr.listMarketplaces();
403
+ if (marketplaces.length === 0) {
404
+ runtime.ctx.showStatus(
405
+ "No marketplaces configured.\n\nGet started:\n /marketplace add anthropics/claude-plugins-official\n\nThen browse plugins with /marketplace or /marketplace discover",
406
+ );
407
+ } else {
408
+ const lines = marketplaces.map(m => ` ${m.name} ${m.sourceUri}`);
409
+ runtime.ctx.showStatus(
410
+ `Marketplaces:\n${lines.join("\n")}\n\nUse /marketplace discover to browse plugins, or /marketplace help for all commands`,
411
+ );
412
+ }
413
+ break;
414
+ }
415
+ }
416
+ } catch (err) {
417
+ const msg = err instanceof Error ? err.message : String(err);
418
+ runtime.ctx.showStatus(`Marketplace error: ${msg}`);
419
+ }
420
+ },
421
+ },
422
+ {
423
+ name: "plugins",
424
+ description: "View and manage installed plugins",
425
+ acpDescription: "Manage plugins",
426
+ acpInputHint: "[list|enable|disable]",
427
+ subcommands: [
428
+ { name: "list", description: "List all installed plugins (npm + marketplace)" },
429
+ { name: "enable", description: "Enable a marketplace plugin", usage: "<name@marketplace>" },
430
+ { name: "disable", description: "Disable a marketplace plugin", usage: "<name@marketplace>" },
431
+ ],
432
+ allowArgs: true,
433
+ handle: async (command, runtime) => {
434
+ const { verb, rest } = parseSubcommand(command.args);
435
+ try {
436
+ if (verb === "enable" || verb === "disable") {
437
+ const parsed = parsePluginScopeArgs(
438
+ rest,
439
+ `Usage: /plugins ${verb} [--scope user|project] <name@marketplace>`,
440
+ );
441
+ if ("error" in parsed) return usage(parsed.error, runtime);
442
+ const manager = await createMarketplaceManager(runtime);
443
+ const isEnable = verb === "enable";
444
+ await manager.setPluginEnabled(parsed.pluginId, isEnable, parsed.scope);
445
+ await runtime.reloadPlugins();
446
+ await runtime.output(`${isEnable ? "Enabled" : "Disabled"} ${parsed.pluginId}`);
447
+ return commandConsumed();
448
+ }
449
+ // Default: list
450
+ const lines: string[] = [];
451
+ const npmManager = new PluginManager();
452
+ const npmPlugins = await npmManager.list();
453
+ if (npmPlugins.length > 0) {
454
+ lines.push("npm plugins:");
455
+ for (const plugin of npmPlugins) {
456
+ const status = plugin.enabled === false ? " (disabled)" : "";
457
+ lines.push(` ${plugin.name}@${plugin.version}${status}`);
458
+ }
459
+ }
460
+
461
+ const marketplaceManager = await createMarketplaceManager(runtime);
462
+ const marketplacePlugins = await marketplaceManager.listInstalledPlugins();
463
+ if (marketplacePlugins.length > 0) {
464
+ if (lines.length > 0) lines.push("");
465
+ lines.push("marketplace plugins:");
466
+ for (const plugin of marketplacePlugins) {
467
+ const entry = plugin.entries[0];
468
+ const status = entry?.enabled === false ? " (disabled)" : "";
469
+ const shadowed = plugin.shadowedBy ? " [shadowed]" : "";
470
+ lines.push(` ${plugin.id} v${entry?.version ?? "?"}${status} [${plugin.scope}]${shadowed}`);
471
+ }
472
+ }
473
+
474
+ await runtime.output(lines.length === 0 ? "No plugins installed" : lines.join("\n"));
475
+ return commandConsumed();
476
+ } catch (err) {
477
+ return usage(`Plugin error: ${errorMessage(err)}`, runtime);
478
+ }
479
+ },
480
+ handleTui: async (command, runtime) => {
481
+ runtime.ctx.editor.setText("");
482
+ const args = command.args.trim().split(/\s+/);
483
+ const sub = args[0] || "list";
484
+ const rest = args.slice(1).join(" ").trim();
485
+
486
+ try {
487
+ const mgr = new MarketplaceManager({
488
+ marketplacesRegistryPath: getMarketplacesRegistryPath(),
489
+ installedRegistryPath: getInstalledPluginsRegistryPath(),
490
+ projectInstalledRegistryPath: await resolveOrDefaultProjectRegistryPath(
491
+ runtime.ctx.sessionManager.getCwd(),
492
+ ),
493
+ marketplacesCacheDir: getMarketplacesCacheDir(),
494
+ pluginsCacheDir: getPluginsCacheDir(),
495
+ clearPluginRootsCache: clearPluginRootsAndCaches,
496
+ });
497
+
498
+ switch (sub) {
499
+ case "enable":
500
+ case "disable": {
501
+ const parsed = parsePluginScopeArgs(
502
+ rest ?? "",
503
+ `Usage: /plugins ${sub} [--scope user|project] <name@marketplace>`,
504
+ );
505
+ if ("error" in parsed) {
506
+ runtime.ctx.showStatus(parsed.error);
507
+ return;
508
+ }
509
+ const isEnable = sub === "enable";
510
+ await mgr.setPluginEnabled(parsed.pluginId, isEnable, parsed.scope);
511
+ runtime.ctx.showStatus(`${isEnable ? "Enabled" : "Disabled"} ${parsed.pluginId}`);
512
+ break;
513
+ }
514
+ default: {
515
+ const lines: string[] = [];
516
+
517
+ const npm = new PluginManager();
518
+ const npmPlugins = await npm.list();
519
+ if (npmPlugins.length > 0) {
520
+ lines.push("npm plugins:");
521
+ for (const p of npmPlugins) {
522
+ const status = p.enabled === false ? " (disabled)" : "";
523
+ lines.push(` ${p.name}@${p.version}${status}`);
524
+ }
525
+ }
526
+
527
+ const mktPlugins = await mgr.listInstalledPlugins();
528
+ if (mktPlugins.length > 0) {
529
+ if (lines.length > 0) lines.push("");
530
+ lines.push("marketplace plugins:");
531
+ for (const p of mktPlugins) {
532
+ const entry = p.entries[0];
533
+ const status = entry?.enabled === false ? " (disabled)" : "";
534
+ const shadowed = p.shadowedBy ? " [shadowed]" : "";
535
+ lines.push(` ${p.id} v${entry?.version ?? "?"}${status} [${p.scope}]${shadowed}`);
536
+ }
537
+ }
538
+
539
+ if (lines.length === 0) {
540
+ runtime.ctx.showStatus("No plugins installed");
541
+ } else {
542
+ runtime.ctx.showStatus(lines.join("\n"));
543
+ }
544
+ break;
545
+ }
546
+ }
547
+ } catch (err) {
548
+ runtime.ctx.showStatus(`Plugin error: ${err}`);
549
+ }
550
+ },
551
+ },
552
+ {
553
+ name: "reload-plugins",
554
+ description: "Reload all plugins (skills, commands, hooks, tools, agents, MCP)",
555
+ acpDescription: "Reload all plugins",
556
+ handle: async (_command, runtime) => {
557
+ await runtime.reloadPlugins();
558
+ await runtime.output("Plugins reloaded.");
559
+ return commandConsumed();
560
+ },
561
+ handleTui: async (_command, runtime) => {
562
+ await reloadTuiPluginState(runtime.ctx);
563
+ runtime.ctx.showStatus("Plugins reloaded.");
564
+ runtime.ctx.editor.setText("");
565
+ },
566
+ },
567
+ ];