2.24.1 (#453)
* 2.24.1 - Updated dependencies - MCP Server: better compatibility with Windows - MCP Server: allow using a custom root for better flexibility - Version Check: use package.json version instead of number of commits - Prettier: reformatted some files - Add SSH_AUTH_SOCK to dev passThroughEnv to solve SSH issues; handle execSync errors - Use GIT_SSH to fix SSH issues on Windows - Updated Stripe version - Updated application version from 2.24.0 to 2.24.1 in package.json. - Enhanced error handling in billing services to include error causes for better debugging.
This commit is contained in:
committed by
GitHub
parent
f3ac595d06
commit
ca585e09be
@@ -0,0 +1,74 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { MigrationsTool } from '../migrations';
|
||||
|
||||
const { crossExecFileSyncMock } = vi.hoisted(() => ({
|
||||
crossExecFileSyncMock: vi.fn(() => Buffer.from('ok')),
|
||||
}));
|
||||
|
||||
vi.mock('../../lib/process-utils', () => ({
|
||||
crossExecFileSync: crossExecFileSyncMock,
|
||||
}));
|
||||
|
||||
describe('MigrationsTool', () => {
|
||||
beforeEach(() => {
|
||||
crossExecFileSyncMock.mockClear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Reset to default
|
||||
MigrationsTool.setRootPath(process.cwd());
|
||||
});
|
||||
|
||||
it('uses crossExecFileSync args for CreateMigration with safe name', () => {
|
||||
MigrationsTool.CreateMigration('add_users_table');
|
||||
|
||||
expect(crossExecFileSyncMock).toHaveBeenCalledWith(
|
||||
'pnpm',
|
||||
['--filter', 'web', 'supabase', 'migrations', 'new', 'add_users_table'],
|
||||
{ cwd: process.cwd() },
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects unsafe migration names', () => {
|
||||
expect(() => MigrationsTool.CreateMigration('foo && rm -rf /')).toThrow(
|
||||
'Migration name must contain only letters, numbers, hyphens, or underscores',
|
||||
);
|
||||
|
||||
expect(crossExecFileSyncMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('uses crossExecFileSync args for Diff', () => {
|
||||
MigrationsTool.Diff();
|
||||
|
||||
expect(crossExecFileSyncMock).toHaveBeenCalledWith(
|
||||
'pnpm',
|
||||
['--filter', 'web', 'supabase', 'db', 'diff'],
|
||||
{ cwd: process.cwd() },
|
||||
);
|
||||
});
|
||||
|
||||
it('uses custom rootPath after setRootPath', () => {
|
||||
MigrationsTool.setRootPath('/custom/project');
|
||||
|
||||
MigrationsTool.CreateMigration('test_migration');
|
||||
|
||||
expect(crossExecFileSyncMock).toHaveBeenCalledWith(
|
||||
'pnpm',
|
||||
['--filter', 'web', 'supabase', 'migrations', 'new', 'test_migration'],
|
||||
{ cwd: '/custom/project' },
|
||||
);
|
||||
});
|
||||
|
||||
it('uses custom rootPath for Diff after setRootPath', () => {
|
||||
MigrationsTool.setRootPath('/custom/project');
|
||||
|
||||
MigrationsTool.Diff();
|
||||
|
||||
expect(crossExecFileSyncMock).toHaveBeenCalledWith(
|
||||
'pnpm',
|
||||
['--filter', 'web', 'supabase', 'db', 'diff'],
|
||||
{ cwd: '/custom/project' },
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -12,9 +12,15 @@ interface ComponentInfo {
|
||||
}
|
||||
|
||||
export class ComponentsTool {
|
||||
private static _rootPath = process.cwd();
|
||||
|
||||
static setRootPath(path: string) {
|
||||
this._rootPath = path;
|
||||
}
|
||||
|
||||
static async getComponents(): Promise<ComponentInfo[]> {
|
||||
const packageJsonPath = join(
|
||||
process.cwd(),
|
||||
this._rootPath,
|
||||
'packages',
|
||||
'ui',
|
||||
'package.json',
|
||||
@@ -179,7 +185,7 @@ export class ComponentsTool {
|
||||
|
||||
static async getComponentContent(componentName: string): Promise<string> {
|
||||
const packageJsonPath = join(
|
||||
process.cwd(),
|
||||
this._rootPath,
|
||||
'packages',
|
||||
'ui',
|
||||
'package.json',
|
||||
@@ -193,7 +199,7 @@ export class ComponentsTool {
|
||||
throw new Error(`Component "${componentName}" not found in exports`);
|
||||
}
|
||||
|
||||
const fullPath = join(process.cwd(), 'packages', 'ui', filePath);
|
||||
const fullPath = join(this._rootPath, 'packages', 'ui', filePath);
|
||||
return readFile(fullPath, 'utf8');
|
||||
}
|
||||
|
||||
@@ -337,7 +343,11 @@ export class ComponentsTool {
|
||||
}
|
||||
}
|
||||
|
||||
export function registerComponentsTools(server: McpServer) {
|
||||
export function registerComponentsTools(server: McpServer, rootPath?: string) {
|
||||
if (rootPath) {
|
||||
ComponentsTool.setRootPath(rootPath);
|
||||
}
|
||||
|
||||
createGetComponentsTool(server);
|
||||
createGetComponentContentTool(server);
|
||||
createComponentsSearchTool(server);
|
||||
|
||||
@@ -1116,7 +1116,11 @@ export class DatabaseTool {
|
||||
}
|
||||
}
|
||||
|
||||
export function registerDatabaseTools(server: McpServer) {
|
||||
export function registerDatabaseTools(server: McpServer, rootPath?: string) {
|
||||
if (rootPath) {
|
||||
DatabaseTool.ROOT_PATH = rootPath;
|
||||
}
|
||||
|
||||
createGetSchemaFilesTool(server);
|
||||
createGetSchemaContentTool(server);
|
||||
createGetSchemasByTopicTool(server);
|
||||
@@ -1126,7 +1130,10 @@ export function registerDatabaseTools(server: McpServer) {
|
||||
createSearchFunctionsTool(server);
|
||||
}
|
||||
|
||||
export function registerDatabaseResources(server: McpServer) {
|
||||
export function registerDatabaseResources(
|
||||
server: McpServer,
|
||||
_rootPath?: string,
|
||||
) {
|
||||
createDatabaseSummaryTool(server);
|
||||
createDatabaseTablesListTool(server);
|
||||
createGetTableInfoTool(server);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { access, readFile, readdir } from 'node:fs/promises';
|
||||
import { Socket } from 'node:net';
|
||||
import { join } from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import { execFileAsync } from '../../lib/process-utils';
|
||||
import { type KitDbServiceDeps, createKitDbService } from './kit-db.service';
|
||||
import {
|
||||
KitDbMigrateInputSchema,
|
||||
@@ -17,15 +16,13 @@ import {
|
||||
KitDbStatusOutputSchema,
|
||||
} from './schema';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
type TextContent = {
|
||||
type: 'text';
|
||||
text: string;
|
||||
};
|
||||
|
||||
export function registerKitDbTools(server: McpServer) {
|
||||
const service = createKitDbService(createKitDbDeps());
|
||||
export function registerKitDbTools(server: McpServer, rootPath?: string) {
|
||||
const service = createKitDbService(createKitDbDeps(rootPath));
|
||||
|
||||
server.registerTool(
|
||||
'kit_db_status',
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import { execFileAsync } from '../../lib/process-utils';
|
||||
import {
|
||||
type DepsUpgradeAdvisorDeps,
|
||||
createDepsUpgradeAdvisorService,
|
||||
@@ -11,12 +10,13 @@ import {
|
||||
DepsUpgradeAdvisorOutputSchema,
|
||||
} from './schema';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
export function registerDepsUpgradeAdvisorTool(server: McpServer) {
|
||||
export function registerDepsUpgradeAdvisorTool(
|
||||
server: McpServer,
|
||||
rootPath?: string,
|
||||
) {
|
||||
return registerDepsUpgradeAdvisorToolWithDeps(
|
||||
server,
|
||||
createDepsUpgradeAdvisorDeps(),
|
||||
createDepsUpgradeAdvisorDeps(rootPath),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -63,9 +63,9 @@ export function registerDepsUpgradeAdvisorToolWithDeps(
|
||||
);
|
||||
}
|
||||
|
||||
function createDepsUpgradeAdvisorDeps(): DepsUpgradeAdvisorDeps {
|
||||
const rootPath = process.cwd();
|
||||
|
||||
function createDepsUpgradeAdvisorDeps(
|
||||
rootPath = process.cwd(),
|
||||
): DepsUpgradeAdvisorDeps {
|
||||
return {
|
||||
async executeCommand(command, args) {
|
||||
try {
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { execFile, spawn } from 'node:child_process';
|
||||
import { access, readFile } from 'node:fs/promises';
|
||||
import { Socket } from 'node:net';
|
||||
import { join } from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import {
|
||||
execFileAsync,
|
||||
findProcessesByName,
|
||||
getPortProcess,
|
||||
killProcess,
|
||||
spawnDetached,
|
||||
} from '../../lib/process-utils';
|
||||
import {
|
||||
DEFAULT_PORT_CONFIG,
|
||||
type KitDevServiceDeps,
|
||||
@@ -21,10 +26,8 @@ import {
|
||||
KitMailboxStatusOutputSchema,
|
||||
} from './schema';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
export function registerKitDevTools(server: McpServer) {
|
||||
const service = createKitDevService(createKitDevDeps());
|
||||
export function registerKitDevTools(server: McpServer, rootPath?: string) {
|
||||
const service = createKitDevService(createKitDevDeps(rootPath));
|
||||
|
||||
server.registerTool(
|
||||
'kit_dev_start',
|
||||
@@ -235,13 +238,7 @@ export function createKitDevDeps(rootPath = process.cwd()): KitDevServiceDeps {
|
||||
};
|
||||
},
|
||||
async spawnDetached(command: string, args: string[]) {
|
||||
const child = spawn(command, args, {
|
||||
cwd: rootPath,
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
|
||||
child.unref();
|
||||
const child = spawnDetached(command, args, { cwd: rootPath });
|
||||
|
||||
if (!child.pid) {
|
||||
throw new Error(`Failed to spawn ${command}`);
|
||||
@@ -264,42 +261,7 @@ export function createKitDevDeps(rootPath = process.cwd()): KitDevServiceDeps {
|
||||
return response.json();
|
||||
},
|
||||
async getPortProcess(port: number) {
|
||||
try {
|
||||
const result = await execFileAsync(
|
||||
'lsof',
|
||||
['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-Fpc'],
|
||||
{
|
||||
cwd: rootPath,
|
||||
},
|
||||
);
|
||||
|
||||
const pidLine = result.stdout
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.find((line) => line.startsWith('p'));
|
||||
|
||||
const commandLine = result.stdout
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.find((line) => line.startsWith('c'));
|
||||
|
||||
if (!pidLine || !commandLine) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pid = Number(pidLine.slice(1));
|
||||
|
||||
if (!Number.isFinite(pid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
pid,
|
||||
command: commandLine.slice(1),
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
return getPortProcess(port, rootPath);
|
||||
},
|
||||
async isProcessRunning(pid: number) {
|
||||
try {
|
||||
@@ -310,44 +272,10 @@ export function createKitDevDeps(rootPath = process.cwd()): KitDevServiceDeps {
|
||||
}
|
||||
},
|
||||
async findProcessesByName(pattern: string) {
|
||||
try {
|
||||
const result = await execFileAsync('pgrep', ['-fl', pattern], {
|
||||
cwd: rootPath,
|
||||
});
|
||||
|
||||
return result.stdout
|
||||
.split('\n')
|
||||
.filter(Boolean)
|
||||
.map((line) => {
|
||||
const spaceIdx = line.indexOf(' ');
|
||||
|
||||
if (spaceIdx <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pid = Number(line.slice(0, spaceIdx));
|
||||
const command = line.slice(spaceIdx + 1).trim();
|
||||
|
||||
if (!Number.isFinite(pid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return { pid, command };
|
||||
})
|
||||
.filter((p): p is { pid: number; command: string } => p !== null);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
return findProcessesByName(pattern, rootPath);
|
||||
},
|
||||
async killProcess(pid: number, signal = 'SIGTERM') {
|
||||
try {
|
||||
// Kill the entire process group (negative PID) since services
|
||||
// are spawned detached and become process group leaders.
|
||||
process.kill(-pid, signal);
|
||||
} catch {
|
||||
// Fall back to killing the individual process if group kill fails.
|
||||
process.kill(pid, signal);
|
||||
}
|
||||
return killProcess(pid, signal);
|
||||
},
|
||||
async sleep(ms: number) {
|
||||
await new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
@@ -17,8 +17,11 @@ type TextContent = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
export function registerKitEmailTemplatesTools(server: McpServer) {
|
||||
const service = createKitEmailsService(createKitEmailsDeps());
|
||||
export function registerKitEmailTemplatesTools(
|
||||
server: McpServer,
|
||||
rootPath?: string,
|
||||
) {
|
||||
const service = createKitEmailsService(createKitEmailsDeps(rootPath));
|
||||
|
||||
server.registerTool(
|
||||
'kit_email_templates_list',
|
||||
|
||||
54
packages/mcp-server/src/tools/env/__tests__/find-workspace-root.test.ts
vendored
Normal file
54
packages/mcp-server/src/tools/env/__tests__/find-workspace-root.test.ts
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
|
||||
import { findWorkspaceRoot } from '../scanner';
|
||||
|
||||
describe('findWorkspaceRoot', () => {
|
||||
let tmp: string;
|
||||
|
||||
beforeEach(() => {
|
||||
tmp = join(tmpdir(), `fwr-test-${Date.now()}`);
|
||||
mkdirSync(tmp, { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rmSync(tmp, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('returns directory containing pnpm-workspace.yaml', () => {
|
||||
writeFileSync(join(tmp, 'pnpm-workspace.yaml'), '');
|
||||
|
||||
expect(findWorkspaceRoot(tmp)).toBe(tmp);
|
||||
});
|
||||
|
||||
it('walks up to find workspace root from nested dir', () => {
|
||||
const nested = join(tmp, 'packages', 'foo', 'src');
|
||||
mkdirSync(nested, { recursive: true });
|
||||
writeFileSync(join(tmp, 'pnpm-workspace.yaml'), '');
|
||||
|
||||
expect(findWorkspaceRoot(nested)).toBe(tmp);
|
||||
});
|
||||
|
||||
it('returns startPath when no workspace file found within depth', () => {
|
||||
const deep = join(tmp, 'a', 'b', 'c', 'd', 'e', 'f', 'g');
|
||||
mkdirSync(deep, { recursive: true });
|
||||
writeFileSync(join(tmp, 'pnpm-workspace.yaml'), '');
|
||||
|
||||
// 7 levels deep, limit is 6 — should NOT find it
|
||||
expect(findWorkspaceRoot(deep)).toBe(deep);
|
||||
});
|
||||
|
||||
it('returns startPath when no workspace file exists at all', () => {
|
||||
expect(findWorkspaceRoot(tmp)).toBe(tmp);
|
||||
});
|
||||
|
||||
it('finds root at exact depth boundary (5 levels up)', () => {
|
||||
const nested = join(tmp, 'a', 'b', 'c', 'd', 'e');
|
||||
mkdirSync(nested, { recursive: true });
|
||||
writeFileSync(join(tmp, 'pnpm-workspace.yaml'), '');
|
||||
|
||||
expect(findWorkspaceRoot(nested)).toBe(tmp);
|
||||
});
|
||||
});
|
||||
4
packages/mcp-server/src/tools/env/index.ts
vendored
4
packages/mcp-server/src/tools/env/index.ts
vendored
@@ -23,8 +23,8 @@ type TextContent = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
export function registerKitEnvTools(server: McpServer) {
|
||||
const service = createKitEnvService(createKitEnvDeps());
|
||||
export function registerKitEnvTools(server: McpServer, rootPath?: string) {
|
||||
const service = createKitEnvService(createKitEnvDeps(rootPath));
|
||||
|
||||
server.registerTool(
|
||||
'kit_env_schema',
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { Socket } from 'node:net';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import { execFileAsync } from '../../lib/process-utils';
|
||||
import {
|
||||
type KitMailboxDeps,
|
||||
createKitMailboxService,
|
||||
@@ -16,15 +15,13 @@ import {
|
||||
KitEmailsSetReadStatusOutputSchema,
|
||||
} from './schema';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
type TextContent = {
|
||||
type: 'text';
|
||||
text: string;
|
||||
};
|
||||
|
||||
export function registerKitEmailsTools(server: McpServer) {
|
||||
const service = createKitMailboxService(createKitMailboxDeps());
|
||||
export function registerKitEmailsTools(server: McpServer, rootPath?: string) {
|
||||
const service = createKitMailboxService(createKitMailboxDeps(rootPath));
|
||||
|
||||
server.registerTool(
|
||||
'kit_emails_list',
|
||||
|
||||
@@ -1,33 +1,60 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { execSync } from 'node:child_process';
|
||||
import { readFile, readdir } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { z } from 'zod/v3';
|
||||
|
||||
import { crossExecFileSync } from '../lib/process-utils';
|
||||
|
||||
export class MigrationsTool {
|
||||
private static _rootPath = process.cwd();
|
||||
|
||||
static setRootPath(path: string) {
|
||||
this._rootPath = path;
|
||||
}
|
||||
|
||||
private static get MIGRATIONS_DIR() {
|
||||
return join(this._rootPath, 'apps', 'web', 'supabase', 'migrations');
|
||||
}
|
||||
|
||||
static GetMigrations() {
|
||||
return readdir(
|
||||
join(process.cwd(), 'apps', 'web', 'supabase', 'migrations'),
|
||||
);
|
||||
return readdir(this.MIGRATIONS_DIR);
|
||||
}
|
||||
|
||||
static getMigrationContent(path: string) {
|
||||
return readFile(
|
||||
join(process.cwd(), 'apps', 'web', 'supabase', 'migrations', path),
|
||||
'utf8',
|
||||
);
|
||||
return readFile(join(this.MIGRATIONS_DIR, path), 'utf8');
|
||||
}
|
||||
|
||||
static CreateMigration(name: string) {
|
||||
return execSync(`pnpm --filter web supabase migrations new ${name}`);
|
||||
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
||||
throw new Error(
|
||||
'Migration name must contain only letters, numbers, hyphens, or underscores',
|
||||
);
|
||||
}
|
||||
|
||||
return crossExecFileSync(
|
||||
'pnpm',
|
||||
['--filter', 'web', 'supabase', 'migrations', 'new', name],
|
||||
{ cwd: this._rootPath },
|
||||
);
|
||||
}
|
||||
|
||||
static Diff() {
|
||||
return execSync(`pnpm --filter web supabase db diff`);
|
||||
return crossExecFileSync(
|
||||
'pnpm',
|
||||
['--filter', 'web', 'supabase', 'db', 'diff'],
|
||||
{ cwd: this._rootPath },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function registerGetMigrationsTools(server: McpServer) {
|
||||
export function registerGetMigrationsTools(
|
||||
server: McpServer,
|
||||
rootPath?: string,
|
||||
) {
|
||||
if (rootPath) {
|
||||
MigrationsTool.setRootPath(rootPath);
|
||||
}
|
||||
|
||||
createGetMigrationsTool(server);
|
||||
createGetMigrationContentTool(server);
|
||||
createCreateMigrationTool(server);
|
||||
@@ -89,7 +116,7 @@ function createGetMigrationContentTool(server: McpServer) {
|
||||
'get_migration_content',
|
||||
{
|
||||
description:
|
||||
'📜 Get migration file content (HISTORICAL) - For current state use get_schema_content instead',
|
||||
'Get migration file content (HISTORICAL) - For current state use get_schema_content instead',
|
||||
inputSchema: {
|
||||
state: z.object({
|
||||
path: z.string(),
|
||||
@@ -103,7 +130,7 @@ function createGetMigrationContentTool(server: McpServer) {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `📜 MIGRATION FILE: ${state.path} (HISTORICAL)\n\nNote: This shows historical changes. For current database state, use get_schema_content instead.\n\n${content}`,
|
||||
text: `MIGRATION FILE: ${state.path} (HISTORICAL)\n\nNote: This shows historical changes. For current database state, use get_schema_content instead.\n\n${content}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -116,7 +143,7 @@ function createGetMigrationsTool(server: McpServer) {
|
||||
'get_migrations',
|
||||
{
|
||||
description:
|
||||
'📜 Get migration files (HISTORICAL CHANGES) - Use schema files for current state instead',
|
||||
'Get migration files (HISTORICAL CHANGES) - Use schema files for current state instead',
|
||||
},
|
||||
async () => {
|
||||
const migrations = await MigrationsTool.GetMigrations();
|
||||
@@ -125,7 +152,7 @@ function createGetMigrationsTool(server: McpServer) {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `📜 MIGRATION FILES (HISTORICAL CHANGES)\n\nNote: For current database state, use get_schema_files instead. Migrations show historical changes.\n\n${migrations.join('\n')}`,
|
||||
text: `MIGRATION FILES (HISTORICAL CHANGES)\n\nNote: For current database state, use get_schema_files instead. Migrations show historical changes.\n\n${migrations.join('\n')}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -967,7 +967,11 @@ export class PRDManager {
|
||||
}
|
||||
|
||||
// MCP Server Tool Registration
|
||||
export function registerPRDTools(server: McpServer) {
|
||||
export function registerPRDTools(server: McpServer, rootPath?: string) {
|
||||
if (rootPath) {
|
||||
PRDManager.setRootPath(rootPath);
|
||||
}
|
||||
|
||||
createListPRDsTool(server);
|
||||
createGetPRDTool(server);
|
||||
createCreatePRDTool(server);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { access, readFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import { execFileAsync } from '../../lib/process-utils';
|
||||
import {
|
||||
type KitPrerequisitesDeps,
|
||||
createKitPrerequisitesService,
|
||||
@@ -13,9 +12,10 @@ import {
|
||||
KitPrerequisitesOutputSchema,
|
||||
} from './schema';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
export function registerKitPrerequisitesTool(server: McpServer) {
|
||||
export function registerKitPrerequisitesTool(
|
||||
server: McpServer,
|
||||
rootPath?: string,
|
||||
) {
|
||||
return server.registerTool(
|
||||
'kit_prerequisites',
|
||||
{
|
||||
@@ -28,7 +28,7 @@ export function registerKitPrerequisitesTool(server: McpServer) {
|
||||
|
||||
try {
|
||||
const service = createKitPrerequisitesService(
|
||||
createKitPrerequisitesDeps(),
|
||||
createKitPrerequisitesDeps(rootPath),
|
||||
);
|
||||
|
||||
const result = await service.check(parsedInput);
|
||||
@@ -57,9 +57,9 @@ export function registerKitPrerequisitesTool(server: McpServer) {
|
||||
);
|
||||
}
|
||||
|
||||
function createKitPrerequisitesDeps(): KitPrerequisitesDeps {
|
||||
const rootPath = process.cwd();
|
||||
|
||||
function createKitPrerequisitesDeps(
|
||||
rootPath = process.cwd(),
|
||||
): KitPrerequisitesDeps {
|
||||
return {
|
||||
async getVariantFamily() {
|
||||
const variant = await resolveVariant(rootPath);
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import { execFileAsync } from '../../lib/process-utils';
|
||||
import {
|
||||
type RunChecksDeps,
|
||||
createRunChecksService,
|
||||
} from './run-checks.service';
|
||||
import { RunChecksInputSchema, RunChecksOutputSchema } from './schema';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
export function registerRunChecksTool(server: McpServer) {
|
||||
const service = createRunChecksService(createRunChecksDeps());
|
||||
export function registerRunChecksTool(server: McpServer, rootPath?: string) {
|
||||
const service = createRunChecksService(createRunChecksDeps(rootPath));
|
||||
|
||||
return server.registerTool(
|
||||
'run_checks',
|
||||
|
||||
@@ -21,8 +21,14 @@ interface ScriptInfo {
|
||||
}
|
||||
|
||||
export class ScriptsTool {
|
||||
private static _rootPath = process.cwd();
|
||||
|
||||
static setRootPath(path: string) {
|
||||
this._rootPath = path;
|
||||
}
|
||||
|
||||
static async getScripts(): Promise<ScriptInfo[]> {
|
||||
const packageJsonPath = join(process.cwd(), 'package.json');
|
||||
const packageJsonPath = join(this._rootPath, 'package.json');
|
||||
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
|
||||
|
||||
const scripts: ScriptInfo[] = [];
|
||||
@@ -41,7 +47,7 @@ export class ScriptsTool {
|
||||
}
|
||||
|
||||
static async getScriptDetails(scriptName: string): Promise<ScriptInfo> {
|
||||
const packageJsonPath = join(process.cwd(), 'package.json');
|
||||
const packageJsonPath = join(this._rootPath, 'package.json');
|
||||
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
|
||||
|
||||
const command = packageJson.scripts[scriptName];
|
||||
@@ -234,7 +240,11 @@ export class ScriptsTool {
|
||||
}
|
||||
}
|
||||
|
||||
export function registerScriptsTools(server: McpServer) {
|
||||
export function registerScriptsTools(server: McpServer, rootPath?: string) {
|
||||
if (rootPath) {
|
||||
ScriptsTool.setRootPath(rootPath);
|
||||
}
|
||||
|
||||
createGetScriptsTool(server);
|
||||
createGetScriptDetailsTool(server);
|
||||
createGetHealthcheckScriptsTool(server);
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { access, readFile, stat } from 'node:fs/promises';
|
||||
import { Socket } from 'node:net';
|
||||
import { join } from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import { execFileAsync } from '../../lib/process-utils';
|
||||
import {
|
||||
type KitStatusDeps,
|
||||
createKitStatusService,
|
||||
} from './kit-status.service';
|
||||
import { KitStatusInputSchema, KitStatusOutputSchema } from './schema';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
export function registerKitStatusTool(server: McpServer) {
|
||||
export function registerKitStatusTool(server: McpServer, rootPath?: string) {
|
||||
return server.registerTool(
|
||||
'kit_status',
|
||||
{
|
||||
@@ -25,7 +22,7 @@ export function registerKitStatusTool(server: McpServer) {
|
||||
const parsedInput = KitStatusInputSchema.parse(input);
|
||||
|
||||
try {
|
||||
const service = createKitStatusService(createKitStatusDeps());
|
||||
const service = createKitStatusService(createKitStatusDeps(rootPath));
|
||||
const status = await service.getStatus(parsedInput);
|
||||
|
||||
return {
|
||||
@@ -54,9 +51,7 @@ export function registerKitStatusTool(server: McpServer) {
|
||||
);
|
||||
}
|
||||
|
||||
function createKitStatusDeps(): KitStatusDeps {
|
||||
const rootPath = process.cwd();
|
||||
|
||||
function createKitStatusDeps(rootPath = process.cwd()): KitStatusDeps {
|
||||
return {
|
||||
rootPath,
|
||||
async readJsonFile(path: string): Promise<unknown> {
|
||||
|
||||
@@ -27,8 +27,13 @@ type TextContent = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
export function registerKitTranslationsTools(server: McpServer) {
|
||||
const service = createKitTranslationsService(createKitTranslationsDeps());
|
||||
export function registerKitTranslationsTools(
|
||||
server: McpServer,
|
||||
rootPath?: string,
|
||||
) {
|
||||
const service = createKitTranslationsService(
|
||||
createKitTranslationsDeps(rootPath),
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'kit_translations_list',
|
||||
|
||||
Reference in New Issue
Block a user