@oh-my-pi/pi-coding-agent 13.16.5 → 13.17.0
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.
- package/CHANGELOG.md +45 -0
- package/package.json +7 -7
- package/src/cli/args.ts +7 -0
- package/src/cli/classify-install-target.ts +50 -0
- package/src/cli/plugin-cli.ts +245 -31
- package/src/commands/plugin.ts +3 -0
- package/src/config/settings-schema.ts +12 -13
- package/src/cursor.ts +66 -1
- package/src/discovery/claude-plugins.ts +95 -5
- package/src/discovery/helpers.ts +168 -41
- package/src/discovery/plugin-dir-roots.ts +28 -0
- package/src/discovery/substitute-plugin-root.ts +29 -0
- package/src/extensibility/plugins/index.ts +1 -0
- package/src/extensibility/plugins/marketplace/cache.ts +136 -0
- package/src/extensibility/plugins/marketplace/fetcher.ts +354 -0
- package/src/extensibility/plugins/marketplace/index.ts +6 -0
- package/src/extensibility/plugins/marketplace/manager.ts +528 -0
- package/src/extensibility/plugins/marketplace/registry.ts +181 -0
- package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
- package/src/extensibility/plugins/marketplace/types.ts +177 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/local-protocol.ts +2 -19
- package/src/internal-urls/parse.ts +72 -0
- package/src/internal-urls/router.ts +2 -18
- package/src/lsp/config.ts +9 -0
- package/src/main.ts +50 -1
- package/src/modes/components/plugin-selector.ts +86 -0
- package/src/modes/components/settings-defs.ts +0 -4
- package/src/modes/controllers/mcp-command-controller.ts +14 -0
- package/src/modes/controllers/selector-controller.ts +104 -13
- package/src/modes/interactive-mode.ts +4 -0
- package/src/modes/types.ts +1 -0
- package/src/prompts/agents/reviewer.md +3 -4
- package/src/sdk.ts +0 -7
- package/src/slash-commands/builtin-registry.ts +273 -0
- package/src/tools/bash-skill-urls.ts +48 -5
- package/src/tools/read.ts +15 -9
- package/src/web/search/code-search.ts +2 -179
- package/src/web/search/index.ts +2 -3
- package/src/web/search/types.ts +1 -5
package/src/main.ts
CHANGED
|
@@ -11,8 +11,9 @@ import * as os from "node:os";
|
|
|
11
11
|
import * as path from "node:path";
|
|
12
12
|
import { createInterface } from "node:readline/promises";
|
|
13
13
|
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
14
|
-
import { $env, getProjectDir, logger, postmortem, setProjectDir, VERSION } from "@oh-my-pi/pi-utils";
|
|
14
|
+
import { $env, getConfigDirName, getProjectDir, logger, postmortem, setProjectDir, VERSION } from "@oh-my-pi/pi-utils";
|
|
15
15
|
import chalk from "chalk";
|
|
16
|
+
import { invalidate as invalidateFsCache } from "./capability/fs";
|
|
16
17
|
import type { Args } from "./cli/args";
|
|
17
18
|
import { processFileArguments } from "./cli/file-processor";
|
|
18
19
|
import { buildInitialMessage } from "./cli/initial-message";
|
|
@@ -23,8 +24,16 @@ import { ModelRegistry, ModelsConfigFile } from "./config/model-registry";
|
|
|
23
24
|
import { resolveCliModel, resolveModelRoleValue, resolveModelScope, type ScopedModel } from "./config/model-resolver";
|
|
24
25
|
import { Settings, settings } from "./config/settings";
|
|
25
26
|
import { initializeWithSettings } from "./discovery";
|
|
27
|
+
import { clearClaudePluginRootsCache, injectPluginDirRoots, preloadPluginRoots } from "./discovery/helpers";
|
|
26
28
|
import { exportFromFile } from "./export/html";
|
|
27
29
|
import type { ExtensionUIContext } from "./extensibility/extensions/types";
|
|
30
|
+
import {
|
|
31
|
+
getInstalledPluginsRegistryPath,
|
|
32
|
+
getMarketplacesCacheDir,
|
|
33
|
+
getMarketplacesRegistryPath,
|
|
34
|
+
getPluginsCacheDir,
|
|
35
|
+
MarketplaceManager,
|
|
36
|
+
} from "./extensibility/plugins/marketplace";
|
|
28
37
|
import type { MCPManager } from "./mcp";
|
|
29
38
|
import { InteractiveMode, runAcpMode, runPrintMode, runRpcMode } from "./modes";
|
|
30
39
|
import { initTheme, stopThemeWatcher } from "./modes/theme/theme";
|
|
@@ -639,6 +648,46 @@ export async function runRootCommand(parsed: Args, rawArgs: string[]): Promise<v
|
|
|
639
648
|
sessionManager = await SessionManager.open(selectedPath);
|
|
640
649
|
}
|
|
641
650
|
|
|
651
|
+
// Wire --plugin-dir and preload plugin roots for sync consumers (LSP config)
|
|
652
|
+
const home = os.homedir();
|
|
653
|
+
if (parsedArgs.pluginDirs && parsedArgs.pluginDirs.length > 0) {
|
|
654
|
+
await logger.timeAsync("injectPluginDirRoots", () => injectPluginDirRoots(home, parsedArgs.pluginDirs!));
|
|
655
|
+
} else {
|
|
656
|
+
await logger.timeAsync("preloadPluginRoots", () => preloadPluginRoots(home));
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Background marketplace auto-update — never blocks startup.
|
|
660
|
+
const autoUpdate = settings.get("marketplace.autoUpdate");
|
|
661
|
+
if (autoUpdate !== "off") {
|
|
662
|
+
void (async () => {
|
|
663
|
+
try {
|
|
664
|
+
const mgr = new MarketplaceManager({
|
|
665
|
+
marketplacesRegistryPath: getMarketplacesRegistryPath(),
|
|
666
|
+
installedRegistryPath: getInstalledPluginsRegistryPath(),
|
|
667
|
+
marketplacesCacheDir: getMarketplacesCacheDir(),
|
|
668
|
+
pluginsCacheDir: getPluginsCacheDir(),
|
|
669
|
+
clearPluginRootsCache: () => {
|
|
670
|
+
const h = os.homedir();
|
|
671
|
+
invalidateFsCache(path.join(h, ".claude", "plugins", "installed_plugins.json"));
|
|
672
|
+
invalidateFsCache(path.join(h, getConfigDirName(), "plugins", "installed_plugins.json"));
|
|
673
|
+
clearClaudePluginRootsCache();
|
|
674
|
+
},
|
|
675
|
+
});
|
|
676
|
+
await mgr.refreshStaleMarketplaces();
|
|
677
|
+
const updates = await mgr.checkForUpdates();
|
|
678
|
+
if (updates.length === 0) return;
|
|
679
|
+
if (autoUpdate === "auto") {
|
|
680
|
+
await mgr.upgradeAllPlugins();
|
|
681
|
+
logger.debug(`Auto-upgraded ${updates.length} marketplace plugin(s)`);
|
|
682
|
+
} else {
|
|
683
|
+
logger.debug(`${updates.length} marketplace plugin update(s) available \u2014 /marketplace upgrade`);
|
|
684
|
+
}
|
|
685
|
+
} catch {
|
|
686
|
+
// Silently ignore — network failure, corrupt data, offline.
|
|
687
|
+
}
|
|
688
|
+
})();
|
|
689
|
+
}
|
|
690
|
+
|
|
642
691
|
const { options: sessionOptions } = await logger.timeAsync("buildSessionOptions", () =>
|
|
643
692
|
buildSessionOptions(parsedArgs, scopedModels, sessionManager, modelRegistry),
|
|
644
693
|
);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive marketplace plugin selector.
|
|
3
|
+
*
|
|
4
|
+
* Shows available plugins from all configured marketplaces in a SelectList.
|
|
5
|
+
* Selecting a plugin triggers installation. Esc cancels.
|
|
6
|
+
*/
|
|
7
|
+
import { Container, type SelectItem, SelectList } from "@oh-my-pi/pi-tui";
|
|
8
|
+
import { getSelectListTheme } from "../theme/theme";
|
|
9
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
10
|
+
|
|
11
|
+
export interface PluginSelectorCallbacks {
|
|
12
|
+
onSelect: (pluginName: string, marketplace: string) => void;
|
|
13
|
+
onCancel: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface PluginItem {
|
|
17
|
+
plugin: { name: string; version?: string; description?: string };
|
|
18
|
+
marketplace: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class PluginSelectorComponent extends Container {
|
|
22
|
+
#selectList: SelectList;
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
marketplaceCount: number,
|
|
26
|
+
plugins: PluginItem[],
|
|
27
|
+
installedIds: Set<string>,
|
|
28
|
+
callbacks: PluginSelectorCallbacks,
|
|
29
|
+
) {
|
|
30
|
+
super();
|
|
31
|
+
|
|
32
|
+
const items: SelectItem[] = plugins.map(({ plugin, marketplace }) => {
|
|
33
|
+
const id = `${plugin.name}@${marketplace}`;
|
|
34
|
+
const installed = installedIds.has(id);
|
|
35
|
+
const version = plugin.version ? `@${plugin.version}` : "";
|
|
36
|
+
const status = installed ? " [installed]" : "";
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
value: id,
|
|
40
|
+
label: `${plugin.name}${version}${status}`,
|
|
41
|
+
description: plugin.description,
|
|
42
|
+
hint: marketplace,
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (items.length === 0) {
|
|
47
|
+
items.push({
|
|
48
|
+
value: "__empty__",
|
|
49
|
+
label: "No plugins available",
|
|
50
|
+
description:
|
|
51
|
+
marketplaceCount === 0
|
|
52
|
+
? "Add a marketplace first: /marketplace add <source>"
|
|
53
|
+
: "Configured marketplaces have no plugins",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.addChild(new DynamicBorder());
|
|
58
|
+
|
|
59
|
+
this.#selectList = new SelectList(items, Math.min(items.length, 20), getSelectListTheme());
|
|
60
|
+
|
|
61
|
+
this.#selectList.onSelect = item => {
|
|
62
|
+
if (item.value === "__empty__") return;
|
|
63
|
+
const [name, marketplace] = splitPluginId(item.value);
|
|
64
|
+
if (name && marketplace) {
|
|
65
|
+
callbacks.onSelect(name, marketplace);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
this.#selectList.onCancel = () => {
|
|
70
|
+
callbacks.onCancel();
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
this.addChild(this.#selectList);
|
|
74
|
+
this.addChild(new DynamicBorder());
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getSelectList(): SelectList {
|
|
78
|
+
return this.#selectList;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function splitPluginId(id: string): [string, string] | [null, null] {
|
|
83
|
+
const atIdx = id.lastIndexOf("@");
|
|
84
|
+
if (atIdx <= 0) return [null, null];
|
|
85
|
+
return [id.slice(0, atIdx), id.slice(atIdx + 1)];
|
|
86
|
+
}
|
|
@@ -312,10 +312,6 @@ const OPTION_PROVIDERS: Partial<Record<SettingPath, OptionProvider>> = {
|
|
|
312
312
|
{ value: "synthetic", label: "Synthetic", description: "Requires SYNTHETIC_API_KEY" },
|
|
313
313
|
{ value: "parallel", label: "Parallel", description: "Requires PARALLEL_API_KEY" },
|
|
314
314
|
],
|
|
315
|
-
"providers.codeSearch": [
|
|
316
|
-
{ value: "exa", label: "Exa", description: "Uses Exa public MCP code search" },
|
|
317
|
-
{ value: "grep", label: "grep.app", description: "Uses Vercel grep.app public code search" },
|
|
318
|
-
],
|
|
319
315
|
"providers.image": [
|
|
320
316
|
{ value: "auto", label: "Auto", description: "Priority: OpenRouter > Gemini" },
|
|
321
317
|
{ value: "gemini", label: "Gemini", description: "Requires GEMINI_API_KEY" },
|
|
@@ -793,6 +793,20 @@ export class MCPCommandController {
|
|
|
793
793
|
}
|
|
794
794
|
}
|
|
795
795
|
|
|
796
|
+
// refreshMCPTools preserves the prior MCP tool selection, so tools from
|
|
797
|
+
// brand-new servers are registered in the registry but never activated.
|
|
798
|
+
// Explicitly activate the newly added server's tools now.
|
|
799
|
+
if (isConnected && this.ctx.mcpManager) {
|
|
800
|
+
const serverTools = this.ctx.mcpManager.getTools().filter(t => t.mcpServerName === name);
|
|
801
|
+
if (serverTools.length > 0) {
|
|
802
|
+
const currentActive = this.ctx.session.getActiveToolNames();
|
|
803
|
+
const toActivate = serverTools.map(t => t.name).filter(n => this.ctx.session.getToolByName(n));
|
|
804
|
+
if (toActivate.length > 0) {
|
|
805
|
+
await this.ctx.session.setActiveToolsByName([...new Set([...currentActive, ...toActivate])]);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
796
810
|
// Show success message
|
|
797
811
|
const scopeLabel = scope === "user" ? "user" : "project";
|
|
798
812
|
const lines = ["", theme.fg("success", `✓ Added server "${name}" to ${scopeLabel} config`), ""];
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
2
|
+
import * as path from "node:path";
|
|
1
3
|
import { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
4
|
import { getOAuthProviders, type OAuthProvider } from "@oh-my-pi/pi-ai";
|
|
3
5
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
4
6
|
import { Input, Loader, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
5
|
-
import { getAgentDbPath, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
7
|
+
import { getAgentDbPath, getConfigDirName, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
8
|
+
import { invalidate as invalidateFsCache } from "../../capability/fs";
|
|
6
9
|
import { getRoleInfo } from "../../config/model-registry";
|
|
7
10
|
import { settings } from "../../config/settings";
|
|
8
11
|
import { DebugSelectorComponent } from "../../debug";
|
|
9
12
|
import { disableProvider, enableProvider } from "../../discovery";
|
|
13
|
+
import { clearClaudePluginRootsCache } from "../../discovery/helpers";
|
|
14
|
+
import {
|
|
15
|
+
getInstalledPluginsRegistryPath,
|
|
16
|
+
getMarketplacesCacheDir,
|
|
17
|
+
getMarketplacesRegistryPath,
|
|
18
|
+
getPluginsCacheDir,
|
|
19
|
+
MarketplaceManager,
|
|
20
|
+
} from "../../extensibility/plugins/marketplace";
|
|
10
21
|
import {
|
|
11
22
|
getAvailableThemes,
|
|
12
23
|
getSymbolTheme,
|
|
@@ -19,13 +30,7 @@ import {
|
|
|
19
30
|
import type { InteractiveModeContext } from "../../modes/types";
|
|
20
31
|
import { type SessionInfo, SessionManager } from "../../session/session-manager";
|
|
21
32
|
import { FileSessionStorage } from "../../session/session-storage";
|
|
22
|
-
import {
|
|
23
|
-
isCodeSearchProviderId,
|
|
24
|
-
isSearchProviderPreference,
|
|
25
|
-
setPreferredCodeSearchProvider,
|
|
26
|
-
setPreferredImageProvider,
|
|
27
|
-
setPreferredSearchProvider,
|
|
28
|
-
} from "../../tools";
|
|
33
|
+
import { isSearchProviderPreference, setPreferredImageProvider, setPreferredSearchProvider } from "../../tools";
|
|
29
34
|
import { setSessionTerminalTitle } from "../../utils/title-generator";
|
|
30
35
|
import { AgentDashboard } from "../components/agent-dashboard";
|
|
31
36
|
import { AssistantMessageComponent } from "../components/assistant-message";
|
|
@@ -33,6 +38,7 @@ import { ExtensionDashboard } from "../components/extensions";
|
|
|
33
38
|
import { HistorySearchComponent } from "../components/history-search";
|
|
34
39
|
import { ModelSelectorComponent } from "../components/model-selector";
|
|
35
40
|
import { OAuthSelectorComponent } from "../components/oauth-selector";
|
|
41
|
+
import { PluginSelectorComponent } from "../components/plugin-selector";
|
|
36
42
|
import { SessionSelectorComponent } from "../components/session-selector";
|
|
37
43
|
import { SettingsSelectorComponent } from "../components/settings-selector";
|
|
38
44
|
import { ToolExecutionComponent } from "../components/tool-execution";
|
|
@@ -355,11 +361,6 @@ export class SelectorController {
|
|
|
355
361
|
setPreferredSearchProvider(value);
|
|
356
362
|
}
|
|
357
363
|
break;
|
|
358
|
-
case "providers.codeSearch":
|
|
359
|
-
if (typeof value === "string" && isCodeSearchProviderId(value)) {
|
|
360
|
-
setPreferredCodeSearchProvider(value);
|
|
361
|
-
}
|
|
362
|
-
break;
|
|
363
364
|
case "providers.image":
|
|
364
365
|
if (value === "auto" || value === "gemini" || value === "openrouter") {
|
|
365
366
|
setPreferredImageProvider(value);
|
|
@@ -425,6 +426,96 @@ export class SelectorController {
|
|
|
425
426
|
});
|
|
426
427
|
}
|
|
427
428
|
|
|
429
|
+
async showPluginSelector(mode: "install" | "uninstall" = "install"): Promise<void> {
|
|
430
|
+
const mgr = new MarketplaceManager({
|
|
431
|
+
marketplacesRegistryPath: getMarketplacesRegistryPath(),
|
|
432
|
+
installedRegistryPath: getInstalledPluginsRegistryPath(),
|
|
433
|
+
marketplacesCacheDir: getMarketplacesCacheDir(),
|
|
434
|
+
pluginsCacheDir: getPluginsCacheDir(),
|
|
435
|
+
clearPluginRootsCache: () => {
|
|
436
|
+
const home = os.homedir();
|
|
437
|
+
invalidateFsCache(path.join(home, ".claude", "plugins", "installed_plugins.json"));
|
|
438
|
+
invalidateFsCache(path.join(home, getConfigDirName(), "plugins", "installed_plugins.json"));
|
|
439
|
+
clearClaudePluginRootsCache();
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
const [marketplaces, installed] = await Promise.all([mgr.listMarketplaces(), mgr.listInstalledPlugins()]);
|
|
444
|
+
const installedIds = new Set(installed.map(p => p.id));
|
|
445
|
+
|
|
446
|
+
if (mode === "uninstall") {
|
|
447
|
+
// Show only installed plugins for uninstall
|
|
448
|
+
const items = installed.map(p => {
|
|
449
|
+
const entry = p.entries[0];
|
|
450
|
+
const atIdx = p.id.lastIndexOf("@");
|
|
451
|
+
const pluginName = atIdx > 0 ? p.id.slice(0, atIdx) : p.id;
|
|
452
|
+
const mkt = atIdx > 0 ? p.id.slice(atIdx + 1) : "unknown";
|
|
453
|
+
return {
|
|
454
|
+
plugin: { name: pluginName, version: entry?.version, description: undefined as string | undefined },
|
|
455
|
+
marketplace: mkt,
|
|
456
|
+
};
|
|
457
|
+
});
|
|
458
|
+
this.showSelector(done => {
|
|
459
|
+
const selector = new PluginSelectorComponent(marketplaces.length, items, new Set(), {
|
|
460
|
+
onSelect: async (name, marketplace) => {
|
|
461
|
+
done();
|
|
462
|
+
const pluginId = `${name}@${marketplace}`;
|
|
463
|
+
this.ctx.showStatus(`Uninstalling ${pluginId}...`);
|
|
464
|
+
this.ctx.ui.requestRender();
|
|
465
|
+
try {
|
|
466
|
+
await mgr.uninstallPlugin(pluginId);
|
|
467
|
+
this.ctx.showStatus(`Uninstalled ${pluginId}`);
|
|
468
|
+
} catch (err) {
|
|
469
|
+
this.ctx.showStatus(`Uninstall failed: ${err}`);
|
|
470
|
+
}
|
|
471
|
+
this.ctx.ui.requestRender();
|
|
472
|
+
},
|
|
473
|
+
onCancel: () => {
|
|
474
|
+
done();
|
|
475
|
+
this.ctx.ui.requestRender();
|
|
476
|
+
},
|
|
477
|
+
});
|
|
478
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
479
|
+
});
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Install mode: show all available plugins from all marketplaces
|
|
484
|
+
const allPlugins: Array<{
|
|
485
|
+
plugin: { name: string; version?: string; description?: string };
|
|
486
|
+
marketplace: string;
|
|
487
|
+
}> = [];
|
|
488
|
+
for (const mkt of marketplaces) {
|
|
489
|
+
const plugins = await mgr.listAvailablePlugins(mkt.name);
|
|
490
|
+
for (const plugin of plugins) {
|
|
491
|
+
allPlugins.push({ plugin, marketplace: mkt.name });
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
this.showSelector(done => {
|
|
496
|
+
const selector = new PluginSelectorComponent(marketplaces.length, allPlugins, installedIds, {
|
|
497
|
+
onSelect: async (name, marketplace) => {
|
|
498
|
+
done();
|
|
499
|
+
this.ctx.showStatus(`Installing ${name} from ${marketplace}...`);
|
|
500
|
+
this.ctx.ui.requestRender();
|
|
501
|
+
try {
|
|
502
|
+
const force = installedIds.has(`${name}@${marketplace}`);
|
|
503
|
+
await mgr.installPlugin(name, marketplace, { force });
|
|
504
|
+
this.ctx.showStatus(`Installed ${name} from ${marketplace}`);
|
|
505
|
+
} catch (err) {
|
|
506
|
+
this.ctx.showStatus(`Install failed: ${err}`);
|
|
507
|
+
}
|
|
508
|
+
this.ctx.ui.requestRender();
|
|
509
|
+
},
|
|
510
|
+
onCancel: () => {
|
|
511
|
+
done();
|
|
512
|
+
this.ctx.ui.requestRender();
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
return { component: selector, focus: selector.getSelectList() };
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
428
519
|
showUserMessageSelector(): void {
|
|
429
520
|
const userMessages = this.ctx.session.getUserMessagesForBranching();
|
|
430
521
|
|
|
@@ -1243,6 +1243,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1243
1243
|
this.#selectorController.showModelSelector(options);
|
|
1244
1244
|
}
|
|
1245
1245
|
|
|
1246
|
+
showPluginSelector(mode?: "install" | "uninstall"): void {
|
|
1247
|
+
void this.#selectorController.showPluginSelector(mode);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1246
1250
|
showUserMessageSelector(): void {
|
|
1247
1251
|
this.#selectorController.showUserMessageSelector();
|
|
1248
1252
|
}
|
package/src/modes/types.ts
CHANGED
|
@@ -198,6 +198,7 @@ export interface InteractiveModeContext {
|
|
|
198
198
|
showExtensionsDashboard(): void;
|
|
199
199
|
showAgentsDashboard(): void;
|
|
200
200
|
showModelSelector(options?: { temporaryOnly?: boolean }): void;
|
|
201
|
+
showPluginSelector(mode?: "install" | "uninstall"): void;
|
|
201
202
|
showUserMessageSelector(): void;
|
|
202
203
|
showTreeSelector(): void;
|
|
203
204
|
showSessionSelector(): void;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: reviewer
|
|
3
3
|
description: "Code review specialist for quality/security analysis"
|
|
4
4
|
tools: read, grep, find, bash, lsp, fetch, web_search, ast_grep, report_finding
|
|
5
|
-
spawns: explore
|
|
5
|
+
spawns: explore
|
|
6
6
|
model: pi/slow
|
|
7
7
|
thinking-level: high
|
|
8
8
|
blocking: true
|
|
@@ -62,9 +62,8 @@ Your goal is to identify bugs the author would want fixed before merge.
|
|
|
62
62
|
<procedure>
|
|
63
63
|
1. Run `git diff` (or `gh pr diff <number>`) to view patch
|
|
64
64
|
2. Read modified files for full context
|
|
65
|
-
3.
|
|
66
|
-
4. Call `
|
|
67
|
-
5. Call `submit_result` with verdict
|
|
65
|
+
3. Call `report_finding` per issue
|
|
66
|
+
4. Call `submit_result` with verdict
|
|
68
67
|
|
|
69
68
|
Bash is read-only: `git diff`, `git log`, `git show`, `gh pr diff`. You **MUST NOT** make file edits or trigger builds.
|
|
70
69
|
</procedure>
|
package/src/sdk.ts
CHANGED
|
@@ -106,14 +106,12 @@ import {
|
|
|
106
106
|
GrepTool,
|
|
107
107
|
getSearchTools,
|
|
108
108
|
HIDDEN_TOOLS,
|
|
109
|
-
isCodeSearchProviderId,
|
|
110
109
|
isSearchProviderPreference,
|
|
111
110
|
loadSshTool,
|
|
112
111
|
PythonTool,
|
|
113
112
|
ReadTool,
|
|
114
113
|
ResolveTool,
|
|
115
114
|
renderSearchToolBm25Description,
|
|
116
|
-
setPreferredCodeSearchProvider,
|
|
117
115
|
setPreferredImageProvider,
|
|
118
116
|
setPreferredSearchProvider,
|
|
119
117
|
type Tool,
|
|
@@ -667,11 +665,6 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
667
665
|
setPreferredSearchProvider(webSearchProvider);
|
|
668
666
|
}
|
|
669
667
|
|
|
670
|
-
const codeSearchProvider = settings.get("providers.codeSearch");
|
|
671
|
-
if (typeof codeSearchProvider === "string" && isCodeSearchProviderId(codeSearchProvider)) {
|
|
672
|
-
setPreferredCodeSearchProvider(codeSearchProvider);
|
|
673
|
-
}
|
|
674
|
-
|
|
675
668
|
const imageProvider = settings.get("providers.image");
|
|
676
669
|
if (imageProvider === "auto" || imageProvider === "gemini" || imageProvider === "openrouter") {
|
|
677
670
|
setPreferredImageProvider(imageProvider);
|