feat(providers): add opt-in Hoplite and searchable provider grid (#6953)

Preserve the bundled Hoplite ACP adapter and provisioning transformer, activate it only after Add, and provide a searchable provider grid. Restore the contributor's original icon without the copyright mark.

Co-authored-by: Odin Glynn-Martin <odin.glynn@icloud.com>
This commit is contained in:
Mohamed Boudra
2026-10-15 21:25:23 +07:00
committed by GitHub
co-authored by Odin Glynn-Martin
parent e08389065c
commit 16bb179e67
51 changed files with 1126 additions and 196 deletions
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="1.394 1.679 8.494 7.828" fill="currentColor"><path d="M8.237 7.813C8.276 7.789 8.327 7.796 8.358 7.83L9.741 9.346C9.797 9.407 9.754 9.506 9.671 9.507H8.977C8.924 9.507 8.881 9.463 8.881 9.41V9.125C8.881 9.089 8.861 9.057 8.83 9.04L7.589 8.379C7.524 8.344 7.521 8.251 7.584 8.212L8.237 7.813ZM3.944 1.679C4.502 1.679 5.052 1.82 5.54 2.09L5.962 2.323C6.024 2.358 6.029 2.446 5.97 2.486L5.091 3.09C5.065 3.108 5.05 3.137 5.05 3.169V3.495C5.05 3.529 5.032 3.561 5.003 3.578L4.68 3.769C4.594 3.82 4.498 3.722 4.549 3.637L4.592 3.566C4.63 3.502 4.584 3.421 4.51 3.421H4.028C3.925 3.421 3.894 3.562 3.989 3.604L4.377 3.775C4.448 3.806 4.455 3.904 4.389 3.944L3.77 4.323C3.755 4.332 3.737 4.337 3.72 4.337H3.361C3.309 4.337 3.268 4.379 3.268 4.431C3.268 4.484 3.309 4.526 3.361 4.526H3.779C3.797 4.526 3.814 4.521 3.829 4.513L7.599 2.272C8.135 1.954 8.815 2.008 9.294 2.407C9.307 2.418 9.314 2.434 9.314 2.451V2.729C9.315 2.812 9.413 2.856 9.475 2.8L9.728 2.57C9.789 2.514 9.888 2.558 9.888 2.641V5.812C9.888 5.865 9.845 5.908 9.792 5.908H9.359C9.331 5.908 9.303 5.895 9.285 5.873L8.374 4.773C8.337 4.728 8.268 4.728 8.229 4.771L7.468 5.625C7.429 5.669 7.438 5.737 7.487 5.769L9.038 6.776C9.098 6.815 9.096 6.903 9.035 6.939L6.618 8.363C6.556 8.4 6.478 8.358 6.474 8.286L6.439 7.633C6.437 7.578 6.48 7.532 6.535 7.532H6.925C6.948 7.532 6.971 7.523 6.988 7.508L7.211 7.31C7.276 7.252 7.236 7.144 7.148 7.142L5.991 7.118H1.49C1.437 7.118 1.394 7.075 1.394 7.022V3.308C1.394 3.255 1.437 3.212 1.49 3.212H2.544C2.597 3.212 2.64 3.169 2.64 3.116V2.969C2.64 2.916 2.597 2.873 2.544 2.873H1.461C1.366 2.873 1.329 2.75 1.408 2.697L2.134 2.221C2.672 1.867 3.301 1.679 3.944 1.679Z"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+7
View File
@@ -0,0 +1,7 @@
import type { PluginServerContext } from "@getpaseo/plugin/server";
import { createHopliteProvider } from "./server/provider.js";
export default function contribute(server: PluginServerContext) {
server.registerProvider(createHopliteProvider());
return () => {};
}
@@ -0,0 +1 @@
{ "id": "hoplite-provider", "requirements": { "paseo": ">=0.11.0" } }
@@ -0,0 +1,17 @@
import { runAcpProvider } from "@getpaseo/plugin/server/acp";
import type { ProviderRegistration } from "@getpaseo/plugin/server/provider";
import { runPhaseTransformer } from "./run-phase.js";
export function createHopliteProvider(): ProviderRegistration {
return {
requiresConfiguration: true,
...runAcpProvider({
id: "hoplite",
label: "Hoplite",
description: "Hoplite's coding agent through the local `hoplite acp` bridge",
icon: "icon.svg",
command: ["hoplite", "acp"],
transformers: [runPhaseTransformer],
}),
};
}
@@ -0,0 +1,74 @@
import { describe, expect, it } from "vitest";
import { runPhaseTransformer } from "./run-phase.js";
const context = { sessionId: "session-1" };
// Frames captured from `hoplite acp` 3.0.0.
function runPhase(phase: string | null, label: string | null) {
return {
method: "_hoplite/run_phase",
params: {
sessionId: "thr_c75d39f7d7624256af918eeee2f4941b",
runId: "run_eb213b97bd3147afb2927fbc27f87180",
phase,
label,
startedAt: phase === null ? null : "2026-10-04T17:51:46.311Z",
},
};
}
describe("runPhaseTransformer", () => {
it("shows a provisioning phase as one running workspace item per run", () => {
const update = runPhaseTransformer.notification?.(
runPhase("fetching_repository", "Cloning repository"),
context,
);
expect(update).toEqual({
type: "timeline",
item: {
type: "tool_call",
id: "hoplite-run-phase:run_eb213b97bd3147afb2927fbc27f87180",
callId: "hoplite-run-phase:run_eb213b97bd3147afb2927fbc27f87180",
name: "Hoplite workspace",
detail: { type: "plain_text", label: "Cloning repository", icon: "wrench" },
status: "running",
error: null,
},
});
});
it("completes the same item when the run leaves provisioning", () => {
const update = runPhaseTransformer.notification?.(runPhase(null, null), context);
expect(update).toMatchObject({
type: "timeline",
item: {
id: "hoplite-run-phase:run_eb213b97bd3147afb2927fbc27f87180",
status: "completed",
detail: { label: "Workspace ready" },
},
});
});
it("falls back to the phase name when Hoplite sends no label", () => {
const update = runPhaseTransformer.notification?.(
runPhase("configuring_workspace", null),
context,
);
expect(update).toMatchObject({ item: { detail: { label: "configuring_workspace" } } });
});
it("ignores other vendor notifications and malformed phases", () => {
expect(
runPhaseTransformer.notification?.({ method: "_hoplite/other", params: {} }, context),
).toBeNull();
expect(
runPhaseTransformer.notification?.(
{ method: "_hoplite/run_phase", params: { phase: "x" } },
context,
),
).toBeNull();
});
});
@@ -0,0 +1,39 @@
import type { AcpTransformer } from "@getpaseo/plugin/server/acp";
import { z } from "zod";
// Hoplite provisions a cloud workspace before the first agent output of a run and reports each
// step as `_hoplite/run_phase`. A null phase ends provisioning for that run.
const runPhaseSchema = z.object({
runId: z.string().min(1),
phase: z.string().nullable(),
label: z.string().nullable(),
});
const RUN_PHASE_METHOD = "_hoplite/run_phase";
export const runPhaseTransformer: AcpTransformer = {
notification(notification) {
if (notification.method !== RUN_PHASE_METHOD) return null;
const params = runPhaseSchema.safeParse(notification.params);
if (!params.success) return null;
const { runId, phase, label } = params.data;
const id = `hoplite-run-phase:${runId}`;
const running = phase !== null;
return {
type: "timeline",
item: {
type: "tool_call",
id,
callId: id,
name: "Hoplite workspace",
detail: {
type: "plain_text",
label: running ? (label ?? phase) : "Workspace ready",
icon: "wrench",
},
status: running ? "running" : "completed",
error: null,
},
};
},
};