fix: remove gemini support since google discontinued it

This commit is contained in:
Haileyesus
2026-07-06 17:01:29 +03:00
parent 6daae87443
commit 4e423f5fa2
100 changed files with 247 additions and 3799 deletions

View File

@@ -257,34 +257,15 @@ test('providerMcpService handles opencode MCP config and capability validation',
});
/**
* This test covers Gemini/Cursor MCP JSON formats and user/project scope persistence.
* This test covers Cursor MCP JSON format and user/project scope persistence.
*/
test('providerMcpService handles gemini and cursor MCP JSON config formats', { concurrency: false }, async () => {
test('providerMcpService handles cursor MCP JSON config formats', { concurrency: false }, async () => {
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-gc-'));
const workspacePath = path.join(tempRoot, 'workspace');
await fs.mkdir(workspacePath, { recursive: true });
const restoreHomeDir = patchHomeDir(tempRoot);
try {
await providerMcpService.upsertProviderMcpServer('gemini', {
name: 'gemini-stdio',
scope: 'user',
transport: 'stdio',
command: 'node',
args: ['server.js'],
env: { TOKEN: '$TOKEN' },
cwd: './server',
});
await providerMcpService.upsertProviderMcpServer('gemini', {
name: 'gemini-http',
scope: 'project',
transport: 'http',
url: 'https://gemini.example.com/mcp',
headers: { Authorization: 'Bearer token' },
workspacePath,
});
await providerMcpService.upsertProviderMcpServer('cursor', {
name: 'cursor-stdio',
scope: 'project',
@@ -303,15 +284,6 @@ test('providerMcpService handles gemini and cursor MCP JSON config formats', { c
headers: { API_KEY: 'value' },
});
const geminiUserConfig = await readJson(path.join(tempRoot, '.gemini', 'settings.json'));
const geminiUserServer = (geminiUserConfig.mcpServers as Record<string, unknown>)['gemini-stdio'] as Record<string, unknown>;
assert.equal(geminiUserServer.command, 'node');
assert.equal(geminiUserServer.type, undefined);
const geminiProjectConfig = await readJson(path.join(workspacePath, '.gemini', 'settings.json'));
const geminiProjectServer = (geminiProjectConfig.mcpServers as Record<string, unknown>)['gemini-http'] as Record<string, unknown>;
assert.equal(geminiProjectServer.type, 'http');
const cursorUserConfig = await readJson(path.join(tempRoot, '.cursor', 'mcp.json'));
const cursorHttpServer = (cursorUserConfig.mcpServers as Record<string, unknown>)['cursor-http'] as Record<string, unknown>;
assert.equal(cursorHttpServer.url, 'http://localhost:3333/mcp');
@@ -341,7 +313,7 @@ test('providerMcpService global adder writes to all providers and rejects unsupp
workspacePath,
});
assert.equal(globalResult.length, 5);
assert.equal(globalResult.length, 4);
assert.ok(globalResult.every((entry) => entry.created === true));
const claudeProject = await readJson(path.join(workspacePath, '.mcp.json'));
@@ -350,9 +322,6 @@ test('providerMcpService global adder writes to all providers and rejects unsupp
const codexProject = TOML.parse(await fs.readFile(path.join(workspacePath, '.codex', 'config.toml'), 'utf8')) as Record<string, unknown>;
assert.ok((codexProject.mcp_servers as Record<string, unknown>)['global-http']);
const geminiProject = await readJson(path.join(workspacePath, '.gemini', 'settings.json'));
assert.ok((geminiProject.mcpServers as Record<string, unknown>)['global-http']);
const opencodeProject = await readJson(path.join(workspacePath, 'opencode.json'));
assert.ok((opencodeProject.mcp as Record<string, unknown>)['global-http']);

View File

@@ -30,6 +30,7 @@ test('OpenCode models provider formats frontend labels from provider-prefixed id
'opencode/nemotron-3-super-free',
'anthropic/claude-3-5-sonnet-20241022',
'anthropic/claude-opus-4-7-fast',
'google/model-alpha',
'openai/gpt-5.4-mini-fast',
'openai/gpt-5.5-pro',
'newprovider/alpha-v12-special-20261231',
@@ -104,6 +105,12 @@ anthropic/claude-sonnet-5
}
}
}
google/model-alpha
{
"id": "model-alpha",
"providerID": "google",
"name": "Model Alpha"
}
`);
const definition = buildOpenCodeDefinitionFromVerboseModels(models);

View File

@@ -1,13 +1,9 @@
import assert from 'node:assert/strict';
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import test from 'node:test';
import { ClaudeSessionsProvider } from '@/modules/providers/list/claude/claude-sessions.provider.js';
import { CodexSessionsProvider, extractCodexUserImages } from '@/modules/providers/list/codex/codex-sessions.provider.js';
import { CursorSessionsProvider } from '@/modules/providers/list/cursor/cursor-sessions.provider.js';
import { getGeminiJsonlSessionMessages } from '@/modules/providers/list/gemini/gemini-sessions.provider.js';
import { appendImagesInputTag } from '@/shared/image-attachments.js';
const SESSION_ID = 'session-1';
@@ -127,58 +123,6 @@ test('codex history: normalized user entries keep their images', () => {
assert.deepEqual(messages[0].images, [{ path: '.cloudcli/assets/a.png' }]);
});
// ---------------------------------------------------------------- Gemini
test('gemini history: <images_input> tag is stripped and paths attached', async () => {
const tempDir = await mkdtemp(path.join(os.tmpdir(), 'gemini-image-history-'));
const jsonlPath = path.join(tempDir, 'session.jsonl');
try {
const taggedPrompt = appendImagesInputTag('Compare these designs', [
{ path: '.cloudcli/assets/1-a.png' },
{ path: '.cloudcli/assets/2-b.png' },
]);
const lines = [
JSON.stringify({ type: 'user', id: 'm1', content: taggedPrompt, timestamp: '2026-07-03T10:00:00.000Z' }),
JSON.stringify({ type: 'gemini', id: 'm2', content: 'They differ in spacing.', timestamp: '2026-07-03T10:00:05.000Z' }),
];
await writeFile(jsonlPath, `${lines.join('\n')}\n`, 'utf8');
const { messages } = await getGeminiJsonlSessionMessages(jsonlPath);
assert.equal(messages.length, 2);
assert.equal(messages[0].message.role, 'user');
assert.equal(messages[0].message.content, 'Compare these designs');
assert.deepEqual(messages[0].images, [
{ path: '.cloudcli/assets/1-a.png' },
{ path: '.cloudcli/assets/2-b.png' },
]);
// Assistant text is left untouched.
assert.equal(messages[1].message.role, 'assistant');
assert.equal(messages[1].images, undefined);
} finally {
await rm(tempDir, { recursive: true, force: true });
}
});
test('gemini history: prompts without a tag are unchanged', async () => {
const tempDir = await mkdtemp(path.join(os.tmpdir(), 'gemini-image-history-'));
const jsonlPath = path.join(tempDir, 'session.jsonl');
try {
await writeFile(
jsonlPath,
`${JSON.stringify({ type: 'user', id: 'm1', content: 'plain prompt', timestamp: '2026-07-03T10:00:00.000Z' })}\n`,
'utf8',
);
const { messages } = await getGeminiJsonlSessionMessages(jsonlPath);
assert.equal(messages.length, 1);
assert.equal(messages[0].message.content, 'plain prompt');
assert.equal(messages[0].images, undefined);
} finally {
await rm(tempDir, { recursive: true, force: true });
}
});
// ---------------------------------------------------------------- Cursor
test('cursor history: <images_input> inside user_query is stripped and attached', () => {

View File

@@ -170,13 +170,13 @@ test('provider model cache is persisted across service instances', async () => {
cachePath,
resolveProvider: () => ({
models: {
getSupportedModels: async () => createModels('gemini-cached'),
getCurrentActiveModel: async () => createCurrentActiveModel('gemini-active'),
changeActiveModel: async (input) => createSessionActiveModelChange('gemini', input),
getSupportedModels: async () => createModels('cursor-cached'),
getCurrentActiveModel: async () => createCurrentActiveModel('cursor-active'),
changeActiveModel: async (input) => createSessionActiveModelChange('cursor', input),
},
}),
});
await writer.getProviderModels('gemini');
await writer.getProviderModels('cursor');
const reader = createProviderModelsService({
cachePath,
@@ -185,13 +185,13 @@ test('provider model cache is persisted across service instances', async () => {
getSupportedModels: async () => {
throw new Error('loader should not be called for persisted cache hits');
},
getCurrentActiveModel: async () => createCurrentActiveModel('gemini-active'),
changeActiveModel: async (input) => createSessionActiveModelChange('gemini', input),
getCurrentActiveModel: async () => createCurrentActiveModel('cursor-active'),
changeActiveModel: async (input) => createSessionActiveModelChange('cursor', input),
},
}),
});
const models = await reader.getProviderModels('gemini');
assert.equal(models.models.DEFAULT, 'gemini-cached');
const models = await reader.getProviderModels('cursor');
assert.equal(models.models.DEFAULT, 'cursor-cached');
assert.equal(models.cache.source, 'disk');
} finally {
await rm(tempRoot, { recursive: true, force: true });

View File

@@ -444,34 +444,22 @@ test('providerSkillsService lists opencode project and user compatibility skills
});
/**
* This test covers Gemini and Cursor skill directory rules, including shared
* This test covers Cursor skill directory rules, including shared
* `.agents/skills` project support.
*/
test('providerSkillsService lists gemini and cursor skills from their configured directories', { concurrency: false }, async () => {
test('providerSkillsService lists cursor skills from its configured directories', { concurrency: false }, async () => {
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-skills-gc-'));
const workspacePath = path.join(tempRoot, 'workspace');
await fs.mkdir(workspacePath, { recursive: true });
const restoreHomeDir = patchHomeDir(tempRoot);
try {
await writeSkill(
path.join(tempRoot, '.gemini', 'skills'),
'gemini-user-dir',
'gemini-user',
'Gemini user skill',
);
await writeSkill(
path.join(tempRoot, '.agents', 'skills'),
'agents-user-dir',
'agents-user',
'Agents user skill',
);
await writeSkill(
path.join(workspacePath, '.gemini', 'skills'),
'gemini-project-dir',
'gemini-project',
'Gemini project skill',
);
await writeSkill(
path.join(workspacePath, '.agents', 'skills'),
'agents-project-dir',
@@ -491,14 +479,6 @@ test('providerSkillsService lists gemini and cursor skills from their configured
'Cursor user skill',
);
const geminiSkills = await providerSkillsService.listProviderSkills('gemini', { workspacePath });
const geminiByName = new Map(geminiSkills.map((skill) => [skill.name, skill]));
assert.equal(geminiByName.get('gemini-user')?.scope, 'user');
assert.equal(geminiByName.get('agents-user')?.scope, 'user');
assert.equal(geminiByName.get('gemini-project')?.scope, 'project');
assert.equal(geminiByName.get('agents-project')?.scope, 'project');
assert.equal(geminiByName.get('gemini-project')?.command, '/gemini-project');
const cursorSkills = await providerSkillsService.listProviderSkills('cursor', { workspacePath });
const cursorByName = new Map(cursorSkills.map((skill) => [skill.name, skill]));
assert.equal(cursorByName.get('agents-project')?.scope, 'project');
@@ -515,7 +495,7 @@ test('providerSkillsService lists gemini and cursor skills from their configured
* This test covers managed global skill creation for providers that own a
* writable user skill directory.
*/
test('providerSkillsService adds global skills for claude, codex, gemini, and cursor', { concurrency: false }, async () => {
test('providerSkillsService adds global skills for claude, codex, and cursor', { concurrency: false }, async () => {
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-skills-create-'));
const restoreHomeDir = patchHomeDir(tempRoot);
@@ -618,22 +598,6 @@ test('providerSkillsService adds global skills for claude, codex, gemini, and cu
);
await assert.rejects(fs.stat(pendingBatchSkillPath), { code: 'ENOENT' });
const createdGeminiSkills = await providerSkillsService.addProviderSkills('gemini', {
entries: [
{
directoryName: 'gemini-global-dir',
content: '---\nname: gemini-global\ndescription: Gemini global skill\n---\n\nGemini body.\n',
},
],
});
const createdGeminiSkill = createdGeminiSkills[0];
assert.ok(createdGeminiSkill);
assert.equal(createdGeminiSkill.command, '/gemini-global');
assert.equal(
createdGeminiSkill.sourcePath.endsWith(path.join('.gemini', 'skills', 'gemini-global-dir', 'SKILL.md')),
true,
);
const createdCursorSkills = await providerSkillsService.addProviderSkills('cursor', {
entries: [
{
@@ -656,9 +620,6 @@ test('providerSkillsService adds global skills for claude, codex, gemini, and cu
const listedCodexSkills = await providerSkillsService.listProviderSkills('codex');
assert.equal(listedCodexSkills.some((skill) => skill.name === 'replacement'), true);
const listedGeminiSkills = await providerSkillsService.listProviderSkills('gemini');
assert.equal(listedGeminiSkills.some((skill) => skill.name === 'gemini-global'), true);
const listedCursorSkills = await providerSkillsService.listProviderSkills('cursor');
assert.equal(listedCursorSkills.some((skill) => skill.name === 'cursor-global'), true);