Files
NetMesh/electron/plugins/terminalProviderService.test.cjs

776 lines
28 KiB
JavaScript
Raw Normal View History

"use strict";
const assert = require("node:assert/strict");
const test = require("node:test");
const { RPC_ERRORS, PluginRpcError } = require("./rpcRouter.cjs");
const {
MAX_TERMINAL_PROVIDERS_PER_REQUEST,
PluginTerminalProviderService,
normalizeTerminalSessionEvent,
} = require("./terminalProviderService.cjs");
function provider(pluginId, id, kind) {
return {
pluginId,
pluginVersion: "1.0.0",
pluginDisplayName: pluginId,
provider: { id, kind, label: id },
};
}
function setup(options = {}) {
const providers = options.providers ?? [
provider("com.example.beta", "com.example.beta.completion", "terminal.completion"),
provider("com.example.alpha", "com.example.alpha.completion", "terminal.completion"),
provider("com.example.alpha", "com.example.alpha.decoration", "terminal.decoration"),
provider("com.example.alpha", "com.example.alpha.interceptor", "terminal.interceptor.input"),
];
const calls = [];
const notifications = [];
const permissionCalls = [];
const active = new Set(options.activePluginIds ?? []);
let contributionListener = null;
const contributionService = {
listProviders({ kind } = {}) {
return kind == null ? providers : providers.filter((entry) => entry.provider.kind === kind);
},
async activateProvider(providerId) {
calls.push(["activate", providerId]);
const entry = providers.find((candidate) => candidate.provider.id === providerId);
if (!entry) throw new PluginRpcError(RPC_ERRORS.notFound, "missing provider");
if (options.activateProvider) return options.activateProvider(entry);
active.add(entry.pluginId);
return {
plugin: {
id: entry.pluginId,
activeVersion: entry.pluginVersion,
manifest: {
id: entry.pluginId,
permissions: {
required: ["provider.terminal", "terminal.complete", "terminal.output", "terminal.decorate"],
},
},
},
provider: entry.provider,
identity: {
pluginId: entry.pluginId,
pluginVersion: entry.pluginVersion,
runtimeId: `runtime:${entry.pluginId}`,
runtimeKind: "browser",
securityPrincipal: `principal:${entry.pluginId}`,
},
};
},
onDidChange(listener) {
contributionListener = listener;
return Object.freeze({ dispose() { contributionListener = null; } });
},
};
const runtimeSupervisor = {
async request(pluginId, method, params, requestOptions) {
calls.push(["request", pluginId, method, params, requestOptions]);
if (options.request) return options.request(pluginId, method, params, requestOptions);
return {
requestId: params.requestId,
status: "ok",
result: { items: [{ text: params.providerId, displayText: params.providerId, score: 1 }] },
};
},
getRuntimeIdentity(pluginId) {
if (options.getRuntimeIdentity) return options.getRuntimeIdentity(pluginId, active);
return active.has(pluginId) ? {
pluginId,
pluginVersion: "1.0.0",
runtimeId: `runtime:${pluginId}`,
runtimeKind: "browser",
securityPrincipal: `principal:${pluginId}`,
} : null;
},
async notify(pluginId, method, params, notifyOptions) {
notifications.push([pluginId, method, params, notifyOptions]);
},
};
const permissionEngine = {
async authorize(context, descriptor) {
permissionCalls.push([context, descriptor]);
if (options.authorize) return options.authorize(context, descriptor);
return { scope: "existing" };
},
};
return {
calls,
notifications,
permissionCalls,
emitContributionChange() { contributionListener?.(); },
service: new PluginTerminalProviderService({ contributionService, permissionEngine, runtimeSupervisor }),
};
}
const session = {
sessionId: "session-1",
hostId: "host-1",
workspaceId: "workspace-1",
protocol: "ssh",
status: "connected",
cwd: "/srv/app",
title: "app",
shellType: "posix",
cols: 120,
rows: 40,
alternateScreen: false,
};
function completionPayload(input = "git") {
return { input, cursor: input.length, hostOs: "linux", cwdSource: null, maximum: 100 };
}
test("terminal Provider registry ranks declared providers deterministically and excludes raw interceptors", () => {
const { service } = setup();
assert.deepEqual(
service.listProviders({
kind: "terminal.completion",
preferredProviderIds: ["com.example.beta.completion"],
}).map((entry) => entry.provider.id),
["com.example.beta.completion", "com.example.alpha.completion"],
);
assert.throws(
() => service.listProviders({ kind: "terminal.interceptor.input" }),
(error) => error?.code === RPC_ERRORS.unsupported,
);
});
test("terminal Provider invocation lazily activates, forwards deadlines, and freezes bounded results", async () => {
const { calls, notifications, permissionCalls, service } = setup();
const result = await service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
operation: "provideCompletions",
requestId: "request-1",
payload: { session, value: { input: "git st" } },
deadlineMs: 250,
});
assert.deepEqual(result, {
pluginId: "com.example.alpha",
pluginVersion: "1.0.0",
runtimeId: "runtime:com.example.alpha",
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
requestId: "request-1",
status: "ok",
result: {
items: [{
text: "com.example.alpha.completion",
displayText: "com.example.alpha.completion",
score: 1,
}],
},
});
assert.equal(Object.isFrozen(result), true);
assert.equal(Object.isFrozen(result.result.items), true);
assert.deepEqual(calls[0], ["activate", "com.example.alpha.completion"]);
assert.equal(calls[1][1], "com.example.alpha");
assert.equal(calls[1][2], "provider.invoke");
assert.equal(calls[1][3].kind, "terminal.completion");
assert.equal(calls[1][3].deadlineMs, 250);
assert.equal(calls[1][4].timeoutMs, 250);
assert.equal(calls[1][4].expectedIdentity.runtimeId, "runtime:com.example.alpha");
assert.deepEqual(permissionCalls.map((call) => call[1].permission), [
"provider.terminal",
"terminal.complete",
]);
assert.equal(permissionCalls[0][0].runtimeId, "runtime:com.example.alpha");
assert.equal(permissionCalls[0][1].sessionId, session.sessionId);
assert.deepEqual(notifications, [[
"com.example.alpha",
"plugin.terminal.event",
{ type: "snapshot", session },
{ expectedIdentity: {
pluginId: "com.example.alpha",
pluginVersion: "1.0.0",
runtimeId: "runtime:com.example.alpha",
runtimeKind: "browser",
securityPrincipal: "principal:com.example.alpha",
} },
]]);
});
test("terminal Provider cancellation releases a request while lazy activation is pending", async () => {
let releaseActivation;
let activationStarted;
const started = new Promise((resolve) => { activationStarted = resolve; });
const activationGate = new Promise((resolve) => { releaseActivation = resolve; });
const fixture = setup({
async activateProvider(entry) {
activationStarted();
await activationGate;
return {
plugin: {
id: entry.pluginId,
activeVersion: entry.pluginVersion,
manifest: {
id: entry.pluginId,
permissions: { required: ["provider.terminal", "terminal.complete"] },
},
},
provider: entry.provider,
identity: {
pluginId: entry.pluginId,
pluginVersion: entry.pluginVersion,
runtimeId: `runtime:${entry.pluginId}`,
runtimeKind: "browser",
securityPrincipal: `principal:${entry.pluginId}`,
},
};
},
});
const controller = new AbortController();
const pending = fixture.service.provide({
kind: "terminal.completion",
operation: "provideCompletions",
session,
payload: completionPayload(),
}, { signal: controller.signal });
await started;
controller.abort();
const result = await pending;
assert.equal(result.length, 2);
assert.equal(result.every((entry) => entry.status === "cancelled"), true);
assert.equal(fixture.calls.some((call) => call[0] === "request"), false);
releaseActivation();
});
test("terminal session snapshots preserve built-in and namespaced protocol identities", async () => {
for (const protocol of ["mosh", "et", "com.example.transport"]) {
const { service } = setup();
const result = await service.provide({
kind: "terminal.completion",
operation: "provideCompletions",
session: { ...session, protocol },
payload: completionPayload(),
});
assert.equal(result[0].status, "ok");
}
});
test("terminal session snapshots reject malformed protocol identities", async () => {
const { service } = setup();
await assert.rejects(
service.provide({
kind: "terminal.completion",
operation: "provideCompletions",
session: { ...session, protocol: "bad protocol" },
}),
/protocol is invalid/,
);
});
test("terminal Provider invocation rejects kind drift and malformed or oversized results", async () => {
const mismatch = setup();
await assert.rejects(
mismatch.service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.decoration",
operation: "provide",
requestId: "request-kind",
}),
(error) => error?.code === RPC_ERRORS.failedPrecondition,
);
const malformed = setup({
request: async (_pluginId, _method, params) => ({
requestId: `${params.requestId}-wrong`,
status: "ok",
result: null,
}),
});
await assert.rejects(
malformed.service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
operation: "provide",
requestId: "request-mismatch",
}),
(error) => error?.code === RPC_ERRORS.dataLoss,
);
const oversized = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result: "x".repeat(128 * 1024),
}),
});
await assert.rejects(
oversized.service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
operation: "provide",
requestId: "request-oversized",
}),
(error) => error?.code === RPC_ERRORS.dataLoss,
);
});
test("terminal completion and decoration results use main-process operation validation", async () => {
for (const [kind, operation, payload, result] of [
["terminal.completion", "provideCompletions", completionPayload(), {
items: [{ text: "git status", displayText: "git status", description: "Status", score: 10 }],
}],
["terminal.decoration", "provideDecorations", { reason: "session-state" }, {
rules: [{ id: "error", label: "Error", patterns: ["\\berror\\b"], color: "#ff0000" }],
}],
]) {
const fixture = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result,
}),
providers: [provider("com.example.alpha", `com.example.alpha.${kind}`, kind)],
});
const response = await fixture.service.provide({ kind, operation, session, payload });
assert.equal(response[0].status, "ok", kind);
}
for (const [kind, payload, result] of [
["terminal.completion", completionPayload(), { items: [{ label: "hidden command" }] }],
["terminal.completion", completionPayload(), {
items: [{ text: "rm -rf -- /", displayText: "Refresh index" }],
}],
["terminal.decoration", { reason: "session-state" }, {
rules: [{ id: "invalid", label: "Invalid", patterns: [], color: "red" }],
}],
]) {
const fixture = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result,
}),
providers: [provider("com.example.alpha", `com.example.alpha.${kind}`, kind)],
});
const response = await fixture.service.provide({
kind,
operation: kind === "terminal.completion" ? "provideCompletions" : "provideDecorations",
session,
payload,
});
assert.equal(response[0].status, "failed", kind);
assert.equal(response[0].error.code, RPC_ERRORS.dataLoss, kind);
}
await assert.rejects(
setup().service.provide({
kind: "terminal.completion",
operation: "provideLinks",
session,
payload: completionPayload(),
}),
(error) => error?.code === RPC_ERRORS.invalidArgument,
);
});
test("terminal link and hover results are validated against the host line", async () => {
for (const [kind, result] of [
["terminal.link", { links: [{ start: 0, length: 4, uri: "https://example.com" }] }],
["terminal.hover", { hovers: [{ start: 0, length: 4, contents: "Details" }] }],
]) {
const fixture = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result,
}),
providers: [provider("com.example.alpha", `com.example.alpha.${kind}`, kind)],
});
const response = await fixture.service.provide({
kind,
operation: kind === "terminal.link" ? "provideLinks" : "provideHovers",
session,
payload: { line: "test", bufferLineNumber: 1 },
});
assert.equal(response[0].status, "ok");
}
const invalid = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result: { links: [{ start: 0, length: 99, uri: "javascript:alert(1)" }] },
}),
providers: [provider("com.example.alpha", "com.example.alpha.links", "terminal.link")],
});
const response = await invalid.service.provide({
kind: "terminal.link",
operation: "provideLinks",
session,
payload: { line: "test", bufferLineNumber: 1 },
});
assert.equal(response[0].status, "failed");
assert.equal(response[0].error.code, RPC_ERRORS.dataLoss);
});
test("terminal matcher, semantic, prompt, background, and theme results use operation-specific validation", async () => {
const cases = [
["terminal.matcher", "provideMatches", { lines: [{ lineId: "line-1", line: "failed", bufferLineNumber: 1 }] }, {
matches: [{ lineId: "line-1", start: 0, length: 6, label: "Failure", severity: "error", color: "#ff0000" }],
}],
["terminal.semantic", "provideSemantics", { command: "deploy" }, {
classification: "deployment",
destructive: true,
annotations: [{ text: "production", color: "#ff0000" }],
}],
["terminal.prompt", "provideAnnotations", { reason: "commandCompleted" }, {
annotations: [{ text: "venv", color: "#00ff00" }],
}],
["terminal.background", "provideBackgrounds", { reason: "runtime-created" }, {
layers: [{ id: "tint", color: "#102030", opacity: 0.25 }],
refreshAfterMs: 250,
}],
["terminal.theme", "provideTheme", { reason: "theme-changed", currentTheme: {
type: "dark",
colors: Object.fromEntries([
"background", "foreground", "cursor", "selection",
"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white",
"brightBlack", "brightRed", "brightGreen", "brightYellow",
"brightBlue", "brightMagenta", "brightCyan", "brightWhite",
].map((key) => [key, "#000000"])),
} }, {
colors: { background: "#102030", foreground: "#f0f0f0", cursor: "#abcdef" },
}],
];
for (const [kind, operation, payload, result] of cases) {
const fixture = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result,
}),
providers: [provider("com.example.alpha", `com.example.alpha.${kind}`, kind)],
});
const response = await fixture.service.provide({
kind,
operation,
session,
payload,
});
assert.equal(response[0].status, "ok", kind);
}
const invalid = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result: { layers: [{ id: "cover", color: "#000000", opacity: 1 }] },
}),
providers: [provider("com.example.alpha", "com.example.alpha.background", "terminal.background")],
});
const response = await invalid.service.provide({
kind: "terminal.background",
operation: "provideBackgrounds",
session,
payload: { reason: "runtime-created" },
});
assert.equal(response[0].status, "failed");
assert.equal(response[0].error.code, RPC_ERRORS.dataLoss);
const invalidMatcher = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result: { matches: [{ lineId: "other", start: 0, length: 1, label: "Hidden" }] },
}),
providers: [provider("com.example.alpha", "com.example.alpha.matcher", "terminal.matcher")],
});
const matcherResponse = await invalidMatcher.service.provide({
kind: "terminal.matcher",
operation: "provideMatches",
session,
payload: { lines: [{ lineId: "line-1", line: "failed", bufferLineNumber: 1 }] },
});
assert.equal(matcherResponse[0].status, "failed");
assert.equal(matcherResponse[0].error.code, RPC_ERRORS.dataLoss);
const invalidRefresh = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result: { layers: [], refreshAfterMs: 10 },
}),
providers: [provider("com.example.alpha", "com.example.alpha.background", "terminal.background")],
});
const refreshResponse = await invalidRefresh.service.provide({
kind: "terminal.background",
operation: "provideBackgrounds",
session,
payload: { reason: "runtime-created" },
});
assert.equal(refreshResponse[0].status, "failed");
assert.equal(refreshResponse[0].error.code, RPC_ERRORS.dataLoss);
const oversizedMatcherBatch = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result: { matches: [] },
}),
providers: [provider("com.example.alpha", "com.example.alpha.matcher", "terminal.matcher")],
});
await assert.rejects(
oversizedMatcherBatch.service.provide({
kind: "terminal.matcher",
operation: "provideMatches",
session,
payload: {
lines: Array.from({ length: 13 }, (_, index) => ({
lineId: `line-${index}`,
line: "x".repeat(8_192),
bufferLineNumber: index + 1,
})),
},
}),
(error) => error?.code === RPC_ERRORS.invalidArgument,
);
const missingBackgroundColor = setup({
request: async (_pluginId, _method, params) => ({
requestId: params.requestId,
status: "ok",
result: { layers: [{ id: "missing-color", opacity: 0.1 }] },
}),
providers: [provider("com.example.alpha", "com.example.alpha.background", "terminal.background")],
});
const missingColorResponse = await missingBackgroundColor.service.provide({
kind: "terminal.background",
operation: "provideBackgrounds",
session,
payload: { reason: "runtime-created" },
});
assert.equal(missingColorResponse[0].status, "failed");
assert.equal(missingColorResponse[0].error.code, RPC_ERRORS.dataLoss);
});
test("terminal Provider invocation authorizes optional permissions before sending session data", async () => {
const fixture = setup({
authorize: async (_context, descriptor) => {
if (descriptor.permission === "terminal.complete") {
throw new PluginRpcError(RPC_ERRORS.permissionDenied, "permission denied");
}
return { scope: "existing" };
},
});
await assert.rejects(
fixture.service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
operation: "provide",
requestId: "request-denied",
payload: { session },
}),
(error) => error?.code === RPC_ERRORS.permissionDenied,
);
assert.deepEqual(fixture.permissionCalls.map((call) => call[1].permission), [
"provider.terminal",
"terminal.complete",
]);
assert.deepEqual(fixture.notifications, []);
assert.equal(fixture.calls.some((call) => call[0] === "request"), false);
});
test("terminal Provider fan-out contains failures and preserves deterministic registry order", async () => {
const { calls, service } = setup({
request: async (pluginId, _method, params) => {
if (pluginId === "com.example.alpha") {
throw new PluginRpcError(RPC_ERRORS.unavailable, "alpha unavailable");
}
return { requestId: params.requestId, status: "ok", result: { items: [{ text: "beta", score: 1 }] } };
},
});
const results = await service.provide({
kind: "terminal.completion",
operation: "provideCompletions",
session,
payload: { ...completionPayload("be"), session: { sessionId: "spoofed" } },
preferredProviderIds: ["com.example.beta.completion"],
deadlineMs: 300,
});
assert.equal(results.length, 2);
assert.equal(results[0].providerId, "com.example.beta.completion");
assert.equal(results[0].status, "ok");
assert.equal(results[1].providerId, "com.example.alpha.completion");
assert.equal(results[1].status, "failed");
assert.equal(results[1].error.code, RPC_ERRORS.unavailable);
const forwarded = calls.find((call) => call[0] === "request");
assert.equal(forwarded[3].payload.input, "be");
assert.equal(forwarded[3].payload.session.sessionId, session.sessionId);
});
test("terminal lifecycle delivery targets only active Provider runtimes and strips sensitive command text", async () => {
const { notifications, service } = setup({ activePluginIds: ["com.example.alpha"] });
const beforeAuthorization = await service.publishSessionEvent({
type: "connected",
session,
});
assert.deepEqual(beforeAuthorization, [
{ pluginId: "com.example.alpha", delivered: false },
{ pluginId: "com.example.beta", delivered: false },
]);
assert.deepEqual(notifications, []);
await service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
operation: "provide",
requestId: "authorize-lifecycle",
payload: { session },
});
notifications.length = 0;
const deliveries = await service.publishSessionEvent({
type: "commandSubmitted",
session,
command: "export TOKEN=secret",
});
assert.deepEqual(deliveries, [
{ pluginId: "com.example.alpha", delivered: true },
{ pluginId: "com.example.beta", delivered: false },
]);
assert.equal(notifications.length, 1);
assert.equal(notifications[0][0], "com.example.alpha");
assert.equal(notifications[0][1], "plugin.terminal.event");
assert.equal(Object.hasOwn(notifications[0][2], "command"), false);
assert.equal(Object.isFrozen(notifications[0][2].session), true);
await service.publishSessionEvent({
type: "commandCompleted",
session,
command: "export TOKEN=secret",
output: "secret",
});
assert.equal(Object.hasOwn(notifications.at(-1)[2], "command"), false);
assert.equal(Object.hasOwn(notifications.at(-1)[2], "output"), false);
await service.publishSessionEvent({
type: "disconnected",
session: { ...session, status: "disconnected" },
exitCode: 0xC0000005,
});
assert.equal(notifications.at(-1)[2].exitCode, 0xC0000005);
assert.deepEqual(normalizeTerminalSessionEvent({ type: "disposed", session }), {
type: "disposed",
session,
});
});
test("terminal lifecycle preserves signed and unsigned wide platform exit statuses", () => {
assert.deepEqual(normalizeTerminalSessionEvent({
type: "disconnected",
session: { ...session, status: "disconnected" },
exitCode: 0xC0000005,
}).exitCode, 0xC0000005);
assert.deepEqual(normalizeTerminalSessionEvent({
type: "disconnected",
session: { ...session, status: "disconnected" },
exitCode: -1073741819,
}).exitCode, -1073741819);
for (const exitCode of [1.5, Number.NaN, Number.POSITIVE_INFINITY, Number.MAX_SAFE_INTEGER + 1]) {
assert.throws(() => normalizeTerminalSessionEvent({
type: "disconnected",
session: { ...session, status: "disconnected" },
exitCode,
}), /exit code is invalid/);
}
});
test("one-use Provider grants never authorize later lifecycle delivery", async () => {
const { notifications, service } = setup({
authorize: async () => ({ scope: "once" }),
});
await service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
operation: "provide",
requestId: "one-use-lifecycle",
payload: { session },
});
notifications.length = 0;
const deliveries = await service.publishSessionEvent({ type: "cwdChanged", session });
assert.deepEqual(deliveries, [
{ pluginId: "com.example.alpha", delivered: false },
{ pluginId: "com.example.beta", delivered: false },
]);
assert.deepEqual(notifications, []);
});
test("failed and cancelled Provider results never authorize later lifecycle delivery", async () => {
for (const status of ["failed", "cancelled"]) {
const { notifications, service } = setup({
request: async (_pluginId, _method, params) => status === "failed"
? {
requestId: params.requestId,
status,
error: { code: RPC_ERRORS.internal, message: "provider failed" },
}
: { requestId: params.requestId, status },
});
const result = await service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
operation: "provide",
requestId: `unsuccessful-${status}`,
payload: { session },
});
assert.equal(result.status, status);
notifications.length = 0;
const deliveries = await service.publishSessionEvent({ type: "resized", session });
assert.deepEqual(deliveries, [
{ pluginId: "com.example.alpha", delivered: false },
{ pluginId: "com.example.beta", delivered: false },
]);
assert.deepEqual(notifications, []);
}
});
test("terminal lifecycle cleanup removes authorizations for unavailable providers and disposed sessions", async () => {
const providers = [provider("com.example.alpha", "com.example.alpha.completion", "terminal.completion")];
const { emitContributionChange, service } = setup({ providers });
await service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
operation: "provide",
requestId: "authorize-cleanup",
payload: { session },
});
assert.equal(service.lifecycleAuthorizations.size, 1);
providers.length = 0;
emitContributionChange();
assert.equal(service.lifecycleAuthorizations.size, 0);
providers.push(provider("com.example.alpha", "com.example.alpha.completion", "terminal.completion"));
await service.invokeProvider({
providerId: "com.example.alpha.completion",
kind: "terminal.completion",
operation: "provide",
requestId: "authorize-dispose",
payload: { session },
});
assert.equal(service.lifecycleAuthorizations.size, 1);
await service.publishSessionEvent({ type: "disposed", session });
assert.equal(service.lifecycleAuthorizations.size, 0);
});
test("terminal Provider fan-out enforces the per-request Provider quota", async () => {
const providers = Array.from({ length: MAX_TERMINAL_PROVIDERS_PER_REQUEST + 5 }, (_, index) => provider(
`com.example.provider${String(index).padStart(2, "0")}`,
`com.example.provider${String(index).padStart(2, "0")}.completion`,
"terminal.completion",
));
const { calls, service } = setup({ providers });
const results = await service.provide({
kind: "terminal.completion",
operation: "provideCompletions",
session,
payload: completionPayload(),
});
assert.equal(results.length, MAX_TERMINAL_PROVIDERS_PER_REQUEST);
assert.equal(calls.filter((call) => call[0] === "request").length, MAX_TERMINAL_PROVIDERS_PER_REQUEST);
});