1 import * as vscode from "vscode";
2 import { ChatViewProvider } from "./chatView";
3 import { RegistryAgent } from "./catalog";
4 import { fetchCatalog, installAgent, installedKeys, setDefaultAgent } from "./registry";
5
6 export function activate(context: vscode.ExtensionContext): void {
7 const provider = new ChatViewProvider(context);
8
9 context.subscriptions.push(
10 vscode.window.registerWebviewViewProvider(ChatViewProvider.viewType, provider, {
11 webviewOptions: { retainContextWhenHidden: true }
12 })
13 );
14
15 context.subscriptions.push(
16 vscode.commands.registerCommand("sigit.openChat", async () => {
17 await vscode.commands.executeCommand("sigit.chat.focus");
18 provider.reveal();
19 }),
20 vscode.commands.registerCommand("sigit.newSession", () => provider.newSession()),
21 vscode.commands.registerCommand("sigit.selectAgent", () => provider.selectAgent()),
22 vscode.commands.registerCommand("sigit.restartAgent", () => provider.restart()),
23 vscode.commands.registerCommand("sigit.browseRegistry", () => browseRegistry(context, provider)),
24 vscode.commands.registerCommand("sigit.refreshRegistry", () => refreshRegistry(context))
25 );
26 }
27
28 export function deactivate(): void {
29 // Resources are tied to context.subscriptions and disposed automatically.
30 }
31
32 /** Fetch the catalog, let the user pick an agent, and install it. */
33 async function browseRegistry(
34 context: vscode.ExtensionContext,
35 provider: ChatViewProvider
36 ): Promise<void> {
37 let agents: RegistryAgent[];
38 try {
39 const result = await vscode.window.withProgress(
40 { location: vscode.ProgressLocation.Notification, title: "Fetching ACP registry…" },
41 () => fetchCatalog(context)
42 );
43 agents = result.agents;
44 if (result.fromCache) {
45 void vscode.window.showWarningMessage(
46 `Showing cached registry — fetch failed: ${result.error}`
47 );
48 }
49 } catch (err) {
50 void vscode.window.showErrorMessage(`Could not load the ACP registry: ${(err as Error).message}`);
51 return;
52 }
53
54 if (agents.length === 0) {
55 void vscode.window.showInformationMessage("The ACP registry is empty.");
56 return;
57 }
58
59 const installed = installedKeys();
60 const tag = (agent: RegistryAgent): string => {
61 const parts: string[] = [agent.distribution];
62 if (agent.version) {
63 parts.unshift(`v${agent.version}`);
64 }
65 if (agent.manualInstall) {
66 parts.push("manual install");
67 }
68 if (installed.has(agent.key)) {
69 parts.push("installed");
70 }
71 return parts.join(" · ");
72 };
73 const picked = await vscode.window.showQuickPick(
74 agents.map((agent) => ({
75 label: installed.has(agent.key) ? `$(check) ${agent.name}` : agent.name,
76 description: `${agent.key} · ${tag(agent)}`,
77 detail: agent.description ?? `${agent.command} ${agent.args.join(" ")}`.trim(),
78 agent
79 })),
80 { placeHolder: "Select an ACP agent to install", matchOnDescription: true, matchOnDetail: true }
81 );
82 if (!picked) {
83 return;
84 }
85
86 const agent = picked.agent;
87 if (!installed.has(agent.key)) {
88 const added = await installAgent(agent);
89 if (added && agent.manualInstall && agent.install) {
90 void vscode.window.showWarningMessage(`Installed "${agent.name}". ${agent.install}`);
91 } else if (added) {
92 void vscode.window.showInformationMessage(
93 `Installed "${agent.name}" — launches via ${agent.distribution}.`
94 );
95 }
96 }
97
98 await offerToUse(agent, provider);
99 }
100
101 /** After install, offer to switch to the agent and/or make it the default. */
102 async function offerToUse(agent: RegistryAgent, provider: ChatViewProvider): Promise<void> {
103 const useNow = "Use now";
104 const setDefault = "Set as default";
105 const choice = await vscode.window.showInformationMessage(
106 `Use "${agent.name}"?`,
107 useNow,
108 setDefault
109 );
110 if (choice === setDefault) {
111 await setDefaultAgent(agent.key);
112 }
113 if (choice === useNow || choice === setDefault) {
114 await provider.useAgent(agent.key);
115 }
116 }
117
118 /** Force a fresh fetch of the registry and report how many agents are available. */
119 async function refreshRegistry(context: vscode.ExtensionContext): Promise<void> {
120 try {
121 const result = await vscode.window.withProgress(
122 { location: vscode.ProgressLocation.Notification, title: "Refreshing ACP registry…" },
123 () => fetchCatalog(context)
124 );
125 if (result.fromCache) {
126 void vscode.window.showWarningMessage(`Registry refresh failed: ${result.error}`);
127 } else {
128 void vscode.window.showInformationMessage(
129 `ACP registry refreshed — ${result.agents.length} agent(s) available.`
130 );
131 }
132 } catch (err) {
133 void vscode.window.showErrorMessage(`Could not refresh the ACP registry: ${(err as Error).message}`);
134 }
135 }