@posthog/wizard 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/bin.js +62 -6
- package/dist/bin.js.map +1 -1
- package/dist/src/lib/helper-functions.d.ts +1 -0
- package/dist/src/lib/helper-functions.js +6 -0
- package/dist/src/lib/helper-functions.js.map +1 -0
- package/dist/src/mcp.d.ts +9 -0
- package/dist/src/mcp.js +70 -0
- package/dist/src/mcp.js.map +1 -0
- package/dist/src/nextjs/docs.js +2 -0
- package/dist/src/nextjs/docs.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +6 -4
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/react/docs.js +1 -0
- package/dist/src/react/docs.js.map +1 -1
- package/dist/src/react/react-wizard.js +5 -2
- package/dist/src/react/react-wizard.js.map +1 -1
- package/dist/src/react-native/react-native-wizard.js +5 -2
- package/dist/src/react-native/react-native-wizard.js.map +1 -1
- package/dist/src/run.d.ts +1 -1
- package/dist/src/run.js +1 -4
- package/dist/src/run.js.map +1 -1
- package/dist/src/steps/__tests__/add-editor-rules.test.js +0 -10
- package/dist/src/steps/__tests__/add-editor-rules.test.js.map +1 -1
- package/dist/src/steps/add-editor-rules.d.ts +1 -2
- package/dist/src/steps/add-editor-rules.js +1 -22
- package/dist/src/steps/add-editor-rules.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.d.ts +7 -0
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.js +8 -0
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.js.map +1 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.d.ts +1 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.js +318 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.js.map +1 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/cursor.test.d.ts +1 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/cursor.test.js +443 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/__tests__/cursor.test.js.map +1 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.d.ts +40 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.js +119 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.js.map +1 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.d.ts +40 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js +112 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js.map +1 -0
- package/dist/src/steps/add-mcp-server-to-clients/defaults.d.ts +35 -0
- package/dist/src/steps/add-mcp-server-to-clients/defaults.js +29 -0
- package/dist/src/steps/add-mcp-server-to-clients/defaults.js.map +1 -0
- package/dist/src/steps/add-mcp-server-to-clients/index.d.ts +15 -0
- package/dist/src/steps/add-mcp-server-to-clients/index.js +145 -0
- package/dist/src/steps/add-mcp-server-to-clients/index.js.map +1 -0
- package/dist/src/steps/index.d.ts +2 -0
- package/dist/src/steps/index.js +2 -0
- package/dist/src/steps/index.js.map +1 -1
- package/dist/src/svelte/docs.js +2 -1
- package/dist/src/svelte/docs.js.map +1 -1
- package/dist/src/svelte/svelte-wizard.js +5 -2
- package/dist/src/svelte/svelte-wizard.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +1 -1
- package/dist/src/utils/clack-utils.js +3 -3
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/package.json +3 -2
package/dist/src/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/run.ts"],"names":[],"mappings":";;;;;AA6BA,
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/run.ts"],"names":[],"mappings":"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","sourcesContent":["import { abortIfCancelled } from './utils/clack-utils';\n\nimport { runNextjsWizard } from './nextjs/nextjs-wizard';\nimport type { CloudRegion, WizardOptions } from './utils/types';\n\nimport { getIntegrationDescription, Integration } from './lib/constants';\nimport { readEnvironment } from './utils/environment';\nimport clack from './utils/clack';\nimport path from 'path';\nimport { INTEGRATION_CONFIG, INTEGRATION_ORDER } from './lib/config';\nimport { runReactWizard } from './react/react-wizard';\nimport { analytics } from './utils/analytics';\nimport { runSvelteWizard } from './svelte/svelte-wizard';\nimport { runReactNativeWizard } from './react-native/react-native-wizard';\nimport { EventEmitter } from 'events';\nimport chalk from 'chalk';\n\nEventEmitter.defaultMaxListeners = 50;\n\ntype Args = {\n integration?: Integration;\n debug?: boolean;\n forceInstall?: boolean;\n installDir?: string;\n region?: CloudRegion;\n default?: boolean;\n signup?: boolean;\n};\n\nexport async function runWizard(argv: Args) {\n const finalArgs = {\n ...argv,\n ...readEnvironment(),\n };\n\n const wizardOptions: WizardOptions = {\n debug: finalArgs.debug ?? false,\n forceInstall: finalArgs.forceInstall ?? false,\n installDir: finalArgs.installDir\n ? path.join(process.cwd(), finalArgs.installDir)\n : process.cwd(),\n cloudRegion: finalArgs.region ?? undefined,\n default: finalArgs.default ?? false,\n signup: finalArgs.signup ?? false,\n };\n\n clack.intro(`Welcome to the PostHog setup wizard ✨`);\n\n const integration =\n finalArgs.integration ?? (await getIntegrationForSetup(wizardOptions));\n\n analytics.setTag('integration', integration);\n\n try {\n switch (integration) {\n case Integration.nextjs:\n await runNextjsWizard(wizardOptions);\n break;\n case Integration.react:\n await runReactWizard(wizardOptions);\n break;\n case Integration.svelte:\n await runSvelteWizard(wizardOptions);\n break;\n case Integration.reactNative:\n await runReactNativeWizard(wizardOptions);\n break;\n default:\n clack.log.error('No setup wizard selected!');\n }\n } catch (error) {\n clack.log.error(\n `Something went wrong. You can read the documentation for PostHog at ${chalk.cyan(\n `${INTEGRATION_CONFIG[integration].docsUrl}`,\n )} to setup PostHog manually.`,\n );\n process.exit(1);\n }\n}\n\nasync function detectIntegration(\n options: Pick<WizardOptions, 'installDir'>,\n): Promise<Integration | undefined> {\n const integrationConfigs = Object.entries(INTEGRATION_CONFIG).sort(\n ([a], [b]) =>\n INTEGRATION_ORDER.indexOf(a as Integration) -\n INTEGRATION_ORDER.indexOf(b as Integration),\n );\n\n for (const [integration, config] of integrationConfigs) {\n const detected = await config.detect(options);\n if (detected) {\n return integration as Integration;\n }\n }\n}\n\nasync function getIntegrationForSetup(\n options: Pick<WizardOptions, 'installDir'>,\n) {\n const detectedIntegration = await detectIntegration(options);\n\n if (detectedIntegration) {\n clack.log.success(\n `Detected integration: ${getIntegrationDescription(detectedIntegration)}`,\n );\n return detectedIntegration;\n }\n\n const integration: Integration = await abortIfCancelled(\n clack.select({\n message: 'What do you want to set up?',\n options: [\n { value: Integration.nextjs, label: 'Next.js' },\n { value: Integration.react, label: 'React' },\n { value: Integration.svelte, label: 'Svelte' },\n { value: Integration.reactNative, label: 'React Native' },\n ],\n }),\n );\n\n return integration;\n}\n"]}
|
|
@@ -204,15 +204,5 @@ A given feature flag should be used in as few places as possible. Do not increas
|
|
|
204
204
|
// Check if success message was logged
|
|
205
205
|
expect(infoMock).toHaveBeenCalledWith(`Added Cursor rules to ${chalk_1.default.bold.cyan('.cursor/rules/posthog-integration.mdc')}`);
|
|
206
206
|
});
|
|
207
|
-
it('should not install rules when user declines', async () => {
|
|
208
|
-
process.env.CURSOR_TRACE_ID = 'test-trace-id';
|
|
209
|
-
selectMock.mockResolvedValue(false);
|
|
210
|
-
await (0, add_editor_rules_1.addEditorRulesStep)(mockOptions);
|
|
211
|
-
expect(mkdirMock).not.toHaveBeenCalled();
|
|
212
|
-
expect(readFileMock).not.toHaveBeenCalled();
|
|
213
|
-
expect(writeFileMock).not.toHaveBeenCalled();
|
|
214
|
-
expect(captureMock).not.toHaveBeenCalled();
|
|
215
|
-
expect(infoMock).not.toHaveBeenCalled();
|
|
216
|
-
});
|
|
217
207
|
});
|
|
218
208
|
//# sourceMappingURL=add-editor-rules.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-editor-rules.test.js","sourceRoot":"","sources":["../../../../src/steps/__tests__/add-editor-rules.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport path from 'path';\nimport { addEditorRulesStep } from '../add-editor-rules';\nimport { analytics } from '../../utils/analytics';\nimport clack from '../../utils/clack';\nimport { Integration } from '../../lib/constants';\nimport chalk from 'chalk';\n\n// Mock dependencies\njest.mock('fs', () => ({\n promises: {\n mkdir: jest.fn(),\n readFile: jest.fn(),\n writeFile: jest.fn(),\n },\n}));\n\njest.mock('../../utils/analytics', () => ({\n analytics: {\n capture: jest.fn(),\n setTag: jest.fn(),\n shutdown: jest.fn().mockResolvedValue(undefined),\n },\n}));\n\njest.mock('../../utils/clack', () => ({\n log: {\n info: jest.fn(),\n },\n select: jest.fn().mockResolvedValue(true),\n isCancel: jest.fn((value: unknown): value is symbol => false),\n cancel: jest.fn(),\n}));\n\ndescribe('addEditorRules', () => {\n const mockOptions = {\n installDir: '/test/dir',\n rulesName: 'react-rules.md',\n integration: 'react' as Integration,\n };\n\n const originalEnv = process.env;\n const mkdirMock = fs.promises.mkdir as jest.Mock;\n const readFileMock = fs.promises.readFile as jest.Mock;\n const writeFileMock = fs.promises.writeFile as jest.Mock;\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const captureMock = analytics.capture as jest.Mock;\n const infoMock = clack.log.info as jest.Mock;\n const selectMock = clack.select as jest.Mock;\n const isCancelMock = clack.isCancel as unknown as jest.Mock;\n const cancelMock = clack.cancel as jest.Mock;\n\n beforeEach(() => {\n // Reset all mocks before each test\n jest.clearAllMocks();\n // Clear mock implementations\n (fs.promises.mkdir as jest.Mock).mockReset();\n (fs.promises.readFile as jest.Mock).mockReset();\n (fs.promises.writeFile as jest.Mock).mockReset();\n selectMock.mockReset();\n selectMock.mockResolvedValue(true); // Default to \"Yes\" for the prompt\n isCancelMock.mockReset();\n isCancelMock.mockReturnValue(false);\n cancelMock.mockReset();\n process.env = { ...originalEnv };\n });\n\n afterAll(() => {\n process.env = originalEnv;\n });\n\n it('should not install rules when CURSOR_TRACE_ID is not set', async () => {\n delete process.env.CURSOR_TRACE_ID;\n\n await addEditorRulesStep(mockOptions);\n\n expect(mkdirMock).not.toHaveBeenCalled();\n expect(readFileMock).not.toHaveBeenCalled();\n expect(writeFileMock).not.toHaveBeenCalled();\n expect(captureMock).not.toHaveBeenCalled();\n expect(infoMock).not.toHaveBeenCalled();\n });\n\n it('should install rules when CURSOR_TRACE_ID is set', async () => {\n process.env.CURSOR_TRACE_ID = 'test-trace-id';\n\n const mockFrameworkRules = 'framework rules {universal} content';\n const mockUniversalRules = 'universal rules content';\n const expectedCombinedRules =\n 'framework rules universal rules content content';\n\n (fs.promises.readFile as jest.Mock)\n .mockImplementationOnce(() => Promise.resolve(mockFrameworkRules))\n .mockImplementationOnce(() => Promise.resolve(mockUniversalRules));\n\n await addEditorRulesStep(mockOptions);\n\n // Check if directory was created\n expect(mkdirMock).toHaveBeenCalledWith(\n path.join('/test/dir', '.cursor', 'rules'),\n { recursive: true },\n );\n\n // Check if correct files were read\n expect(readFileMock).toHaveBeenCalledTimes(2);\n expect(readFileMock).toHaveBeenNthCalledWith(\n 1,\n expect.stringMatching(/react-rules\\.md$/),\n 'utf8',\n );\n expect(readFileMock).toHaveBeenNthCalledWith(\n 2,\n expect.stringMatching(/universal\\.md$/),\n 'utf8',\n );\n\n // Check if combined rules were written correctly\n expect(writeFileMock).toHaveBeenCalledWith(\n path.join('/test/dir', '.cursor', 'rules', 'posthog-integration.mdc'),\n expectedCombinedRules,\n 'utf8',\n );\n\n // Check if analytics were captured\n expect(captureMock).toHaveBeenCalledWith('wizard interaction', {\n action: 'added editor rules',\n integration: mockOptions.integration,\n });\n\n // Check if success message was logged\n expect(infoMock).toHaveBeenCalledWith(\n `Added Cursor rules to ${chalk.bold.cyan(\n '.cursor/rules/posthog-integration.mdc',\n )}`,\n );\n });\n\n it('should handle file system errors gracefully', async () => {\n process.env.CURSOR_TRACE_ID = 'test-trace-id';\n const mockError = new Error('File not found');\n\n // Mock readFile to throw an error\n (fs.promises.readFile as jest.Mock).mockRejectedValue(mockError);\n\n await expect(addEditorRulesStep(mockOptions)).rejects.toThrow(mockError);\n\n expect(writeFileMock).not.toHaveBeenCalled();\n expect(captureMock).not.toHaveBeenCalled();\n expect(infoMock).not.toHaveBeenCalled();\n });\n\n it('should handle missing rules files gracefully', async () => {\n process.env.CURSOR_TRACE_ID = 'test-trace-id';\n const mockError = new Error('File system error');\n\n // Mock mkdir to throw an error\n (fs.promises.mkdir as jest.Mock).mockRejectedValue(mockError);\n\n await expect(addEditorRulesStep(mockOptions)).rejects.toThrow(mockError);\n\n expect(writeFileMock).not.toHaveBeenCalled();\n expect(captureMock).not.toHaveBeenCalled();\n expect(infoMock).not.toHaveBeenCalled();\n });\n\n it('should correctly substitute universal rules with realistic content', async () => {\n process.env.CURSOR_TRACE_ID = 'test-trace-id';\n\n const mockFrameworkRules = `---\ndescription: apply when interacting with PostHog/analytics tasks\nglobs: \nalwaysApply: true\n---\n\n{universal}\n\n# Framework-specific rules\n- Rule 1\n- Rule 2`;\n\n const mockUniversalRules = `Never hallucinate an API key. Instead, always use the API key populated in the .env file.\n\n# Feature flags\n\nA given feature flag should be used in as few places as possible. Do not increase the risk of undefined behavior by scattering the same feature flag across multiple areas of code.`;\n\n const expectedCombinedRules = `---\ndescription: apply when interacting with PostHog/analytics tasks\nglobs: \nalwaysApply: true\n---\n\nNever hallucinate an API key. Instead, always use the API key populated in the .env file.\n\n# Feature flags\n\nA given feature flag should be used in as few places as possible. Do not increase the risk of undefined behavior by scattering the same feature flag across multiple areas of code.\n\n# Framework-specific rules\n- Rule 1\n- Rule 2`;\n\n (fs.promises.readFile as jest.Mock)\n .mockImplementationOnce(() => Promise.resolve(mockFrameworkRules))\n .mockImplementationOnce(() => Promise.resolve(mockUniversalRules));\n\n await addEditorRulesStep(mockOptions);\n\n // Check if directory was created\n expect(mkdirMock).toHaveBeenCalledWith(\n path.join('/test/dir', '.cursor', 'rules'),\n { recursive: true },\n );\n\n // Check if correct files were read\n expect(readFileMock).toHaveBeenCalledWith(\n expect.stringMatching(/react-rules\\.md$/),\n 'utf8',\n );\n expect(readFileMock).toHaveBeenCalledWith(\n expect.stringMatching(/universal\\.md$/),\n 'utf8',\n );\n\n // Check if combined rules were written correctly\n expect(writeFileMock).toHaveBeenCalledWith(\n path.join('/test/dir', '.cursor', 'rules', 'posthog-integration.mdc'),\n expectedCombinedRules,\n 'utf8',\n );\n\n // Check if analytics were captured\n expect(captureMock).toHaveBeenCalledWith('wizard interaction', {\n action: 'added editor rules',\n integration: mockOptions.integration,\n });\n\n // Check if success message was logged\n expect(infoMock).toHaveBeenCalledWith(\n `Added Cursor rules to ${chalk.bold.cyan(\n '.cursor/rules/posthog-integration.mdc',\n )}`,\n );\n });\n\n it('should not install rules when user declines', async () => {\n process.env.CURSOR_TRACE_ID = 'test-trace-id';\n selectMock.mockResolvedValue(false);\n\n await addEditorRulesStep(mockOptions);\n\n expect(mkdirMock).not.toHaveBeenCalled();\n expect(readFileMock).not.toHaveBeenCalled();\n expect(writeFileMock).not.toHaveBeenCalled();\n expect(captureMock).not.toHaveBeenCalled();\n expect(infoMock).not.toHaveBeenCalled();\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"add-editor-rules.test.js","sourceRoot":"","sources":["../../../../src/steps/__tests__/add-editor-rules.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport path from 'path';\nimport { addEditorRulesStep } from '../add-editor-rules';\nimport { analytics } from '../../utils/analytics';\nimport clack from '../../utils/clack';\nimport { Integration } from '../../lib/constants';\nimport chalk from 'chalk';\n\n// Mock dependencies\njest.mock('fs', () => ({\n promises: {\n mkdir: jest.fn(),\n readFile: jest.fn(),\n writeFile: jest.fn(),\n },\n}));\n\njest.mock('../../utils/analytics', () => ({\n analytics: {\n capture: jest.fn(),\n setTag: jest.fn(),\n shutdown: jest.fn().mockResolvedValue(undefined),\n },\n}));\n\njest.mock('../../utils/clack', () => ({\n log: {\n info: jest.fn(),\n },\n select: jest.fn().mockResolvedValue(true),\n isCancel: jest.fn((value: unknown): value is symbol => false),\n cancel: jest.fn(),\n}));\n\ndescribe('addEditorRules', () => {\n const mockOptions = {\n installDir: '/test/dir',\n rulesName: 'react-rules.md',\n integration: 'react' as Integration,\n };\n\n const originalEnv = process.env;\n const mkdirMock = fs.promises.mkdir as jest.Mock;\n const readFileMock = fs.promises.readFile as jest.Mock;\n const writeFileMock = fs.promises.writeFile as jest.Mock;\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const captureMock = analytics.capture as jest.Mock;\n const infoMock = clack.log.info as jest.Mock;\n const selectMock = clack.select as jest.Mock;\n const isCancelMock = clack.isCancel as unknown as jest.Mock;\n const cancelMock = clack.cancel as jest.Mock;\n\n beforeEach(() => {\n // Reset all mocks before each test\n jest.clearAllMocks();\n // Clear mock implementations\n (fs.promises.mkdir as jest.Mock).mockReset();\n (fs.promises.readFile as jest.Mock).mockReset();\n (fs.promises.writeFile as jest.Mock).mockReset();\n selectMock.mockReset();\n selectMock.mockResolvedValue(true); // Default to \"Yes\" for the prompt\n isCancelMock.mockReset();\n isCancelMock.mockReturnValue(false);\n cancelMock.mockReset();\n process.env = { ...originalEnv };\n });\n\n afterAll(() => {\n process.env = originalEnv;\n });\n\n it('should not install rules when CURSOR_TRACE_ID is not set', async () => {\n delete process.env.CURSOR_TRACE_ID;\n\n await addEditorRulesStep(mockOptions);\n\n expect(mkdirMock).not.toHaveBeenCalled();\n expect(readFileMock).not.toHaveBeenCalled();\n expect(writeFileMock).not.toHaveBeenCalled();\n expect(captureMock).not.toHaveBeenCalled();\n expect(infoMock).not.toHaveBeenCalled();\n });\n\n it('should install rules when CURSOR_TRACE_ID is set', async () => {\n process.env.CURSOR_TRACE_ID = 'test-trace-id';\n\n const mockFrameworkRules = 'framework rules {universal} content';\n const mockUniversalRules = 'universal rules content';\n const expectedCombinedRules =\n 'framework rules universal rules content content';\n\n (fs.promises.readFile as jest.Mock)\n .mockImplementationOnce(() => Promise.resolve(mockFrameworkRules))\n .mockImplementationOnce(() => Promise.resolve(mockUniversalRules));\n\n await addEditorRulesStep(mockOptions);\n\n // Check if directory was created\n expect(mkdirMock).toHaveBeenCalledWith(\n path.join('/test/dir', '.cursor', 'rules'),\n { recursive: true },\n );\n\n // Check if correct files were read\n expect(readFileMock).toHaveBeenCalledTimes(2);\n expect(readFileMock).toHaveBeenNthCalledWith(\n 1,\n expect.stringMatching(/react-rules\\.md$/),\n 'utf8',\n );\n expect(readFileMock).toHaveBeenNthCalledWith(\n 2,\n expect.stringMatching(/universal\\.md$/),\n 'utf8',\n );\n\n // Check if combined rules were written correctly\n expect(writeFileMock).toHaveBeenCalledWith(\n path.join('/test/dir', '.cursor', 'rules', 'posthog-integration.mdc'),\n expectedCombinedRules,\n 'utf8',\n );\n\n // Check if analytics were captured\n expect(captureMock).toHaveBeenCalledWith('wizard interaction', {\n action: 'added editor rules',\n integration: mockOptions.integration,\n });\n\n // Check if success message was logged\n expect(infoMock).toHaveBeenCalledWith(\n `Added Cursor rules to ${chalk.bold.cyan(\n '.cursor/rules/posthog-integration.mdc',\n )}`,\n );\n });\n\n it('should handle file system errors gracefully', async () => {\n process.env.CURSOR_TRACE_ID = 'test-trace-id';\n const mockError = new Error('File not found');\n\n // Mock readFile to throw an error\n (fs.promises.readFile as jest.Mock).mockRejectedValue(mockError);\n\n await expect(addEditorRulesStep(mockOptions)).rejects.toThrow(mockError);\n\n expect(writeFileMock).not.toHaveBeenCalled();\n expect(captureMock).not.toHaveBeenCalled();\n expect(infoMock).not.toHaveBeenCalled();\n });\n\n it('should handle missing rules files gracefully', async () => {\n process.env.CURSOR_TRACE_ID = 'test-trace-id';\n const mockError = new Error('File system error');\n\n // Mock mkdir to throw an error\n (fs.promises.mkdir as jest.Mock).mockRejectedValue(mockError);\n\n await expect(addEditorRulesStep(mockOptions)).rejects.toThrow(mockError);\n\n expect(writeFileMock).not.toHaveBeenCalled();\n expect(captureMock).not.toHaveBeenCalled();\n expect(infoMock).not.toHaveBeenCalled();\n });\n\n it('should correctly substitute universal rules with realistic content', async () => {\n process.env.CURSOR_TRACE_ID = 'test-trace-id';\n\n const mockFrameworkRules = `---\ndescription: apply when interacting with PostHog/analytics tasks\nglobs: \nalwaysApply: true\n---\n\n{universal}\n\n# Framework-specific rules\n- Rule 1\n- Rule 2`;\n\n const mockUniversalRules = `Never hallucinate an API key. Instead, always use the API key populated in the .env file.\n\n# Feature flags\n\nA given feature flag should be used in as few places as possible. Do not increase the risk of undefined behavior by scattering the same feature flag across multiple areas of code.`;\n\n const expectedCombinedRules = `---\ndescription: apply when interacting with PostHog/analytics tasks\nglobs: \nalwaysApply: true\n---\n\nNever hallucinate an API key. Instead, always use the API key populated in the .env file.\n\n# Feature flags\n\nA given feature flag should be used in as few places as possible. Do not increase the risk of undefined behavior by scattering the same feature flag across multiple areas of code.\n\n# Framework-specific rules\n- Rule 1\n- Rule 2`;\n\n (fs.promises.readFile as jest.Mock)\n .mockImplementationOnce(() => Promise.resolve(mockFrameworkRules))\n .mockImplementationOnce(() => Promise.resolve(mockUniversalRules));\n\n await addEditorRulesStep(mockOptions);\n\n // Check if directory was created\n expect(mkdirMock).toHaveBeenCalledWith(\n path.join('/test/dir', '.cursor', 'rules'),\n { recursive: true },\n );\n\n // Check if correct files were read\n expect(readFileMock).toHaveBeenCalledWith(\n expect.stringMatching(/react-rules\\.md$/),\n 'utf8',\n );\n expect(readFileMock).toHaveBeenCalledWith(\n expect.stringMatching(/universal\\.md$/),\n 'utf8',\n );\n\n // Check if combined rules were written correctly\n expect(writeFileMock).toHaveBeenCalledWith(\n path.join('/test/dir', '.cursor', 'rules', 'posthog-integration.mdc'),\n expectedCombinedRules,\n 'utf8',\n );\n\n // Check if analytics were captured\n expect(captureMock).toHaveBeenCalledWith('wizard interaction', {\n action: 'added editor rules',\n integration: mockOptions.integration,\n });\n\n // Check if success message was logged\n expect(infoMock).toHaveBeenCalledWith(\n `Added Cursor rules to ${chalk.bold.cyan(\n '.cursor/rules/posthog-integration.mdc',\n )}`,\n );\n });\n});\n"]}
|
|
@@ -3,7 +3,6 @@ type AddEditorRulesStepOptions = {
|
|
|
3
3
|
installDir: string;
|
|
4
4
|
rulesName: string;
|
|
5
5
|
integration: Integration;
|
|
6
|
-
default?: boolean;
|
|
7
6
|
};
|
|
8
|
-
export declare const addEditorRulesStep: ({ installDir, rulesName, integration,
|
|
7
|
+
export declare const addEditorRulesStep: ({ installDir, rulesName, integration, }: AddEditorRulesStepOptions) => Promise<boolean>;
|
|
9
8
|
export {};
|
|
@@ -43,30 +43,9 @@ const path_1 = __importDefault(require("path"));
|
|
|
43
43
|
const analytics_1 = require("../utils/analytics");
|
|
44
44
|
const clack_1 = __importDefault(require("../utils/clack"));
|
|
45
45
|
const telemetry_1 = require("../telemetry");
|
|
46
|
-
const
|
|
47
|
-
const addEditorRulesStep = async ({ installDir, rulesName, integration, default: defaultAddEditorRules, }) => {
|
|
46
|
+
const addEditorRulesStep = async ({ installDir, rulesName, integration, }) => {
|
|
48
47
|
// Add rules file if in Cursor environment
|
|
49
48
|
if (process.env.CURSOR_TRACE_ID) {
|
|
50
|
-
const addEditorRules = defaultAddEditorRules
|
|
51
|
-
? true
|
|
52
|
-
: await (0, clack_utils_1.abortIfCancelled)(clack_1.default.select({
|
|
53
|
-
message: 'Would you like to have PostHog added to your Cursor rules?',
|
|
54
|
-
options: [
|
|
55
|
-
{
|
|
56
|
-
label: 'Yes, please!',
|
|
57
|
-
value: true,
|
|
58
|
-
hint: 'Add PostHog to your Cursor rules',
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
label: 'No, thanks',
|
|
62
|
-
value: false,
|
|
63
|
-
hint: 'Skip adding PostHog to your Cursor rules',
|
|
64
|
-
},
|
|
65
|
-
],
|
|
66
|
-
}), integration);
|
|
67
|
-
if (!addEditorRules) {
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
49
|
return (0, telemetry_1.traceStep)('add-editor-rules', async () => {
|
|
71
50
|
const docsDir = path_1.default.join(installDir, '.cursor', 'rules');
|
|
72
51
|
await fs.promises.mkdir(docsDir, { recursive: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-editor-rules.js","sourceRoot":"","sources":["../../../src/steps/add-editor-rules.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,kDAA0B;AAC1B,gDAAwB;AAExB,kDAA+C;AAC/C,2DAAmC;AACnC,4CAAyC;
|
|
1
|
+
{"version":3,"file":"add-editor-rules.js","sourceRoot":"","sources":["../../../src/steps/add-editor-rules.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,kDAA0B;AAC1B,gDAAwB;AAExB,kDAA+C;AAC/C,2DAAmC;AACnC,4CAAyC;AAQlC,MAAM,kBAAkB,GAAG,KAAK,EAAE,EACvC,UAAU,EACV,SAAS,EACT,WAAW,GACe,EAAoB,EAAE;IAChD,0CAA0C;IAC1C,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;QAChC,OAAO,IAAA,qBAAS,EAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YAE1D,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAEtD,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAC/C,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EACvD,MAAM,CACP,CAAC;YACF,MAAM,kBAAkB,GAAG,cAAI,CAAC,IAAI,CAClC,SAAS,EACT,IAAI,EACJ,OAAO,EACP,OAAO,EACP,cAAc,CACf,CAAC;YAEF,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAC/C,kBAAkB,EAClB,MAAM,CACP,CAAC;YAEF,+DAA+D;YAC/D,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,CAC1C,aAAa,EACb,cAAc,CACf,CAAC;YACF,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;YAEjE,2BAA2B;YAC3B,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;YAE/D,qBAAS,CAAC,OAAO,CAAC,oBAAoB,EAAE;gBACtC,MAAM,EAAE,oBAAoB;gBAC5B,WAAW;aACZ,CAAC,CAAC;YAEH,eAAK,CAAC,GAAG,CAAC,IAAI,CACZ,yBAAyB,eAAK,CAAC,IAAI,CAAC,IAAI,CACtC,uCAAuC,CACxC,EAAE,CACJ,CAAC;YAEF,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAvDW,QAAA,kBAAkB,sBAuD7B","sourcesContent":["import * as fs from 'fs';\nimport chalk from 'chalk';\nimport path from 'path';\nimport { Integration } from '../lib/constants';\nimport { analytics } from '../utils/analytics';\nimport clack from '../utils/clack';\nimport { traceStep } from '../telemetry';\n\ntype AddEditorRulesStepOptions = {\n installDir: string;\n rulesName: string;\n integration: Integration;\n};\n\nexport const addEditorRulesStep = async ({\n installDir,\n rulesName,\n integration,\n}: AddEditorRulesStepOptions): Promise<boolean> => {\n // Add rules file if in Cursor environment\n if (process.env.CURSOR_TRACE_ID) {\n return traceStep('add-editor-rules', async () => {\n const docsDir = path.join(installDir, '.cursor', 'rules');\n\n await fs.promises.mkdir(docsDir, { recursive: true });\n\n const frameworkRules = await fs.promises.readFile(\n path.join(__dirname, '..', 'utils', 'rules', rulesName),\n 'utf8',\n );\n const universalRulesPath = path.join(\n __dirname,\n '..',\n 'utils',\n 'rules',\n 'universal.md',\n );\n\n const universalRules = await fs.promises.readFile(\n universalRulesPath,\n 'utf8',\n );\n\n // Replace {universal} placeholder with universal rules content\n const combinedRules = frameworkRules.replace(\n '{universal}',\n universalRules,\n );\n const targetPath = path.join(docsDir, 'posthog-integration.mdc');\n\n // Write the combined rules\n await fs.promises.writeFile(targetPath, combinedRules, 'utf8');\n\n analytics.capture('wizard interaction', {\n action: 'added editor rules',\n integration,\n });\n\n clack.log.info(\n `Added Cursor rules to ${chalk.bold.cyan(\n `.cursor/rules/posthog-integration.mdc`,\n )}`,\n );\n\n return true;\n });\n }\n\n return false;\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MCPClient.js","sourceRoot":"","sources":["../../../../src/steps/add-mcp-server-to-clients/MCPClient.ts"],"names":[],"mappings":";;;AAAA,MAAsB,SAAS;IAC7B,IAAI,CAAS;CAKd;AAND,8BAMC","sourcesContent":["export abstract class MCPClient {\n name: string;\n abstract isServerInstalled(): Promise<boolean>;\n abstract addServer(apiKey: string): Promise<void>;\n abstract removeServer(): Promise<void>;\n abstract isClientSupported(): boolean;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const claude_1 = require("../claude");
|
|
40
|
+
const defaults_1 = require("../../defaults");
|
|
41
|
+
jest.mock('fs', () => ({
|
|
42
|
+
promises: {
|
|
43
|
+
mkdir: jest.fn(),
|
|
44
|
+
readFile: jest.fn(),
|
|
45
|
+
writeFile: jest.fn(),
|
|
46
|
+
},
|
|
47
|
+
existsSync: jest.fn(),
|
|
48
|
+
}));
|
|
49
|
+
jest.mock('os', () => ({
|
|
50
|
+
homedir: jest.fn(),
|
|
51
|
+
}));
|
|
52
|
+
jest.mock('../../defaults', () => ({
|
|
53
|
+
DefaultMCPClientConfig: {
|
|
54
|
+
parse: jest.fn(),
|
|
55
|
+
},
|
|
56
|
+
getDefaultServerConfig: jest.fn(),
|
|
57
|
+
}));
|
|
58
|
+
describe('ClaudeMCPClient', () => {
|
|
59
|
+
let client;
|
|
60
|
+
const mockHomeDir = '/mock/home';
|
|
61
|
+
const mockApiKey = 'test-api-key';
|
|
62
|
+
const mockServerConfig = {
|
|
63
|
+
command: 'npx',
|
|
64
|
+
args: ['-y', 'mcp-remote@latest'],
|
|
65
|
+
env: { POSTHOG_AUTH_HEADER: `Bearer ${mockApiKey}` },
|
|
66
|
+
};
|
|
67
|
+
const mkdirMock = fs.promises.mkdir;
|
|
68
|
+
const readFileMock = fs.promises.readFile;
|
|
69
|
+
const writeFileMock = fs.promises.writeFile;
|
|
70
|
+
const existsSyncMock = fs.existsSync;
|
|
71
|
+
const homedirMock = os.homedir;
|
|
72
|
+
const getDefaultServerConfigMock = defaults_1.getDefaultServerConfig;
|
|
73
|
+
const originalPlatform = process.platform;
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
client = new claude_1.ClaudeMCPClient();
|
|
76
|
+
jest.clearAllMocks();
|
|
77
|
+
homedirMock.mockReturnValue(mockHomeDir);
|
|
78
|
+
getDefaultServerConfigMock.mockReturnValue(mockServerConfig);
|
|
79
|
+
// Mock the Zod schema parse method
|
|
80
|
+
const { DefaultMCPClientConfig } = require('../../defaults');
|
|
81
|
+
DefaultMCPClientConfig.parse.mockImplementation((data) => data);
|
|
82
|
+
});
|
|
83
|
+
afterEach(() => {
|
|
84
|
+
Object.defineProperty(process, 'platform', {
|
|
85
|
+
value: originalPlatform,
|
|
86
|
+
writable: true,
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('constructor', () => {
|
|
90
|
+
it('should set the correct name', () => {
|
|
91
|
+
expect(client.name).toBe('Claude Desktop');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('isClientSupported', () => {
|
|
95
|
+
it('should return true for macOS', () => {
|
|
96
|
+
Object.defineProperty(process, 'platform', {
|
|
97
|
+
value: 'darwin',
|
|
98
|
+
writable: true,
|
|
99
|
+
});
|
|
100
|
+
expect(client.isClientSupported()).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
it('should return true for Windows', () => {
|
|
103
|
+
Object.defineProperty(process, 'platform', {
|
|
104
|
+
value: 'win32',
|
|
105
|
+
writable: true,
|
|
106
|
+
});
|
|
107
|
+
expect(client.isClientSupported()).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
it('should return false for Linux', () => {
|
|
110
|
+
Object.defineProperty(process, 'platform', {
|
|
111
|
+
value: 'linux',
|
|
112
|
+
writable: true,
|
|
113
|
+
});
|
|
114
|
+
expect(client.isClientSupported()).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
it('should return false for other platforms', () => {
|
|
117
|
+
Object.defineProperty(process, 'platform', {
|
|
118
|
+
value: 'freebsd',
|
|
119
|
+
writable: true,
|
|
120
|
+
});
|
|
121
|
+
expect(client.isClientSupported()).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe('getConfigPath', () => {
|
|
125
|
+
it('should return correct path for macOS', () => {
|
|
126
|
+
Object.defineProperty(process, 'platform', {
|
|
127
|
+
value: 'darwin',
|
|
128
|
+
writable: true,
|
|
129
|
+
});
|
|
130
|
+
const configPath = client.getConfigPath();
|
|
131
|
+
expect(configPath).toBe(path.join(mockHomeDir, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'));
|
|
132
|
+
});
|
|
133
|
+
it('should return correct path for Windows', () => {
|
|
134
|
+
Object.defineProperty(process, 'platform', {
|
|
135
|
+
value: 'win32',
|
|
136
|
+
writable: true,
|
|
137
|
+
});
|
|
138
|
+
const mockAppData = 'C:\\Users\\Test\\AppData\\Roaming';
|
|
139
|
+
process.env.APPDATA = mockAppData;
|
|
140
|
+
const configPath = client.getConfigPath();
|
|
141
|
+
expect(configPath).toBe(path.join(mockAppData, 'Claude', 'claude_desktop_config.json'));
|
|
142
|
+
});
|
|
143
|
+
it('should throw error for unsupported platform', () => {
|
|
144
|
+
Object.defineProperty(process, 'platform', {
|
|
145
|
+
value: 'linux',
|
|
146
|
+
writable: true,
|
|
147
|
+
});
|
|
148
|
+
expect(() => client.getConfigPath()).toThrow('Unsupported platform: linux');
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe('isServerInstalled', () => {
|
|
152
|
+
beforeEach(() => {
|
|
153
|
+
Object.defineProperty(process, 'platform', {
|
|
154
|
+
value: 'darwin',
|
|
155
|
+
writable: true,
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
it('should return false when config file does not exist', async () => {
|
|
159
|
+
existsSyncMock.mockReturnValue(false);
|
|
160
|
+
const result = await client.isServerInstalled();
|
|
161
|
+
expect(result).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
it('should return false when config file exists but posthog server is not configured', async () => {
|
|
164
|
+
existsSyncMock.mockReturnValue(true);
|
|
165
|
+
const configData = {
|
|
166
|
+
mcpServers: {
|
|
167
|
+
otherServer: mockServerConfig,
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
readFileMock.mockResolvedValue(JSON.stringify(configData));
|
|
171
|
+
const result = await client.isServerInstalled();
|
|
172
|
+
expect(result).toBe(false);
|
|
173
|
+
});
|
|
174
|
+
it('should return true when posthog server is configured', async () => {
|
|
175
|
+
existsSyncMock.mockReturnValue(true);
|
|
176
|
+
const configData = {
|
|
177
|
+
mcpServers: {
|
|
178
|
+
posthog: mockServerConfig,
|
|
179
|
+
otherServer: mockServerConfig,
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
readFileMock.mockResolvedValue(JSON.stringify(configData));
|
|
183
|
+
const result = await client.isServerInstalled();
|
|
184
|
+
expect(result).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
it('should return false when config file is invalid JSON', async () => {
|
|
187
|
+
existsSyncMock.mockReturnValue(true);
|
|
188
|
+
readFileMock.mockResolvedValue('invalid json');
|
|
189
|
+
const result = await client.isServerInstalled();
|
|
190
|
+
expect(result).toBe(false);
|
|
191
|
+
});
|
|
192
|
+
it('should return false when readFile throws an error', async () => {
|
|
193
|
+
existsSyncMock.mockReturnValue(true);
|
|
194
|
+
readFileMock.mockRejectedValue(new Error('File read error'));
|
|
195
|
+
const result = await client.isServerInstalled();
|
|
196
|
+
expect(result).toBe(false);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
describe('addServer', () => {
|
|
200
|
+
beforeEach(() => {
|
|
201
|
+
Object.defineProperty(process, 'platform', {
|
|
202
|
+
value: 'darwin',
|
|
203
|
+
writable: true,
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
it('should create config directory and add server when config file does not exist', async () => {
|
|
207
|
+
existsSyncMock.mockReturnValue(false);
|
|
208
|
+
await client.addServer(mockApiKey);
|
|
209
|
+
const expectedConfigPath = path.join(mockHomeDir, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
210
|
+
const expectedConfigDir = path.dirname(expectedConfigPath);
|
|
211
|
+
expect(mkdirMock).toHaveBeenCalledWith(expectedConfigDir, {
|
|
212
|
+
recursive: true,
|
|
213
|
+
});
|
|
214
|
+
expect(writeFileMock).toHaveBeenCalledWith(expectedConfigPath, JSON.stringify({
|
|
215
|
+
mcpServers: {
|
|
216
|
+
posthog: mockServerConfig,
|
|
217
|
+
},
|
|
218
|
+
}, null, 2), 'utf8');
|
|
219
|
+
});
|
|
220
|
+
it('should merge with existing config when config file exists', async () => {
|
|
221
|
+
existsSyncMock.mockReturnValue(true);
|
|
222
|
+
const existingConfig = {
|
|
223
|
+
mcpServers: {
|
|
224
|
+
existingServer: {
|
|
225
|
+
command: 'existing',
|
|
226
|
+
args: [],
|
|
227
|
+
env: {},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
readFileMock.mockResolvedValue(JSON.stringify(existingConfig));
|
|
232
|
+
await client.addServer(mockApiKey);
|
|
233
|
+
expect(writeFileMock).toHaveBeenCalledWith(expect.any(String), JSON.stringify({
|
|
234
|
+
mcpServers: {
|
|
235
|
+
existingServer: existingConfig.mcpServers.existingServer,
|
|
236
|
+
posthog: mockServerConfig,
|
|
237
|
+
},
|
|
238
|
+
}, null, 2), 'utf8');
|
|
239
|
+
});
|
|
240
|
+
it('should create new config when existing config is invalid', async () => {
|
|
241
|
+
existsSyncMock.mockReturnValue(true);
|
|
242
|
+
readFileMock.mockResolvedValue('invalid json');
|
|
243
|
+
await client.addServer(mockApiKey);
|
|
244
|
+
expect(writeFileMock).toHaveBeenCalledWith(expect.any(String), JSON.stringify({
|
|
245
|
+
mcpServers: {
|
|
246
|
+
posthog: mockServerConfig,
|
|
247
|
+
},
|
|
248
|
+
}, null, 2), 'utf8');
|
|
249
|
+
});
|
|
250
|
+
it('should call getDefaultServerConfig with the provided API key', async () => {
|
|
251
|
+
existsSyncMock.mockReturnValue(false);
|
|
252
|
+
await client.addServer(mockApiKey);
|
|
253
|
+
expect(getDefaultServerConfigMock).toHaveBeenCalledWith(mockApiKey);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
describe('removeServer', () => {
|
|
257
|
+
beforeEach(() => {
|
|
258
|
+
Object.defineProperty(process, 'platform', {
|
|
259
|
+
value: 'darwin',
|
|
260
|
+
writable: true,
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
it('should do nothing when config file does not exist', async () => {
|
|
264
|
+
existsSyncMock.mockReturnValue(false);
|
|
265
|
+
await client.removeServer();
|
|
266
|
+
expect(readFileMock).not.toHaveBeenCalled();
|
|
267
|
+
expect(writeFileMock).not.toHaveBeenCalled();
|
|
268
|
+
});
|
|
269
|
+
it('should remove posthog server from config', async () => {
|
|
270
|
+
existsSyncMock.mockReturnValue(true);
|
|
271
|
+
const configWithPosthog = {
|
|
272
|
+
mcpServers: {
|
|
273
|
+
posthog: mockServerConfig,
|
|
274
|
+
otherServer: {
|
|
275
|
+
command: 'other',
|
|
276
|
+
args: [],
|
|
277
|
+
env: {},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
readFileMock.mockResolvedValue(JSON.stringify(configWithPosthog));
|
|
282
|
+
await client.removeServer();
|
|
283
|
+
expect(writeFileMock).toHaveBeenCalledWith(expect.any(String), JSON.stringify({
|
|
284
|
+
mcpServers: {
|
|
285
|
+
otherServer: configWithPosthog.mcpServers.otherServer,
|
|
286
|
+
},
|
|
287
|
+
}, null, 2), 'utf8');
|
|
288
|
+
});
|
|
289
|
+
it('should do nothing when posthog server is not in config', async () => {
|
|
290
|
+
existsSyncMock.mockReturnValue(true);
|
|
291
|
+
const configWithoutPosthog = {
|
|
292
|
+
mcpServers: {
|
|
293
|
+
otherServer: {
|
|
294
|
+
command: 'other',
|
|
295
|
+
args: [],
|
|
296
|
+
env: {},
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
readFileMock.mockResolvedValue(JSON.stringify(configWithoutPosthog));
|
|
301
|
+
await client.removeServer();
|
|
302
|
+
expect(writeFileMock).not.toHaveBeenCalled();
|
|
303
|
+
});
|
|
304
|
+
it('should handle invalid JSON gracefully', async () => {
|
|
305
|
+
existsSyncMock.mockReturnValue(true);
|
|
306
|
+
readFileMock.mockResolvedValue('invalid json');
|
|
307
|
+
await client.removeServer();
|
|
308
|
+
expect(writeFileMock).not.toHaveBeenCalled();
|
|
309
|
+
});
|
|
310
|
+
it('should handle file read errors gracefully', async () => {
|
|
311
|
+
existsSyncMock.mockReturnValue(true);
|
|
312
|
+
readFileMock.mockRejectedValue(new Error('File read error'));
|
|
313
|
+
await client.removeServer();
|
|
314
|
+
expect(writeFileMock).not.toHaveBeenCalled();
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
//# sourceMappingURL=claude.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.test.js","sourceRoot":"","sources":["../../../../../../src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { ClaudeMCPClient } from '../claude';\nimport { getDefaultServerConfig } from '../../defaults';\n\njest.mock('fs', () => ({\n promises: {\n mkdir: jest.fn(),\n readFile: jest.fn(),\n writeFile: jest.fn(),\n },\n existsSync: jest.fn(),\n}));\n\njest.mock('os', () => ({\n homedir: jest.fn(),\n}));\n\njest.mock('../../defaults', () => ({\n DefaultMCPClientConfig: {\n parse: jest.fn(),\n },\n getDefaultServerConfig: jest.fn(),\n}));\n\ndescribe('ClaudeMCPClient', () => {\n let client: ClaudeMCPClient;\n const mockHomeDir = '/mock/home';\n const mockApiKey = 'test-api-key';\n const mockServerConfig = {\n command: 'npx',\n args: ['-y', 'mcp-remote@latest'],\n env: { POSTHOG_AUTH_HEADER: `Bearer ${mockApiKey}` },\n };\n\n const mkdirMock = fs.promises.mkdir as jest.Mock;\n const readFileMock = fs.promises.readFile as jest.Mock;\n const writeFileMock = fs.promises.writeFile as jest.Mock;\n const existsSyncMock = fs.existsSync as jest.Mock;\n const homedirMock = os.homedir as jest.Mock;\n const getDefaultServerConfigMock = getDefaultServerConfig as jest.Mock;\n\n const originalPlatform = process.platform;\n\n beforeEach(() => {\n client = new ClaudeMCPClient();\n jest.clearAllMocks();\n homedirMock.mockReturnValue(mockHomeDir);\n getDefaultServerConfigMock.mockReturnValue(mockServerConfig);\n\n // Mock the Zod schema parse method\n const { DefaultMCPClientConfig } = require('../../defaults');\n DefaultMCPClientConfig.parse.mockImplementation((data: any) => data);\n });\n\n afterEach(() => {\n Object.defineProperty(process, 'platform', {\n value: originalPlatform,\n writable: true,\n });\n });\n\n describe('constructor', () => {\n it('should set the correct name', () => {\n expect(client.name).toBe('Claude Desktop');\n });\n });\n\n describe('isClientSupported', () => {\n it('should return true for macOS', () => {\n Object.defineProperty(process, 'platform', {\n value: 'darwin',\n writable: true,\n });\n expect(client.isClientSupported()).toBe(true);\n });\n\n it('should return true for Windows', () => {\n Object.defineProperty(process, 'platform', {\n value: 'win32',\n writable: true,\n });\n expect(client.isClientSupported()).toBe(true);\n });\n\n it('should return false for Linux', () => {\n Object.defineProperty(process, 'platform', {\n value: 'linux',\n writable: true,\n });\n expect(client.isClientSupported()).toBe(false);\n });\n\n it('should return false for other platforms', () => {\n Object.defineProperty(process, 'platform', {\n value: 'freebsd',\n writable: true,\n });\n expect(client.isClientSupported()).toBe(false);\n });\n });\n\n describe('getConfigPath', () => {\n it('should return correct path for macOS', () => {\n Object.defineProperty(process, 'platform', {\n value: 'darwin',\n writable: true,\n });\n\n const configPath = (client as any).getConfigPath();\n expect(configPath).toBe(\n path.join(\n mockHomeDir,\n 'Library',\n 'Application Support',\n 'Claude',\n 'claude_desktop_config.json',\n ),\n );\n });\n\n it('should return correct path for Windows', () => {\n Object.defineProperty(process, 'platform', {\n value: 'win32',\n writable: true,\n });\n\n const mockAppData = 'C:\\\\Users\\\\Test\\\\AppData\\\\Roaming';\n process.env.APPDATA = mockAppData;\n\n const configPath = (client as any).getConfigPath();\n expect(configPath).toBe(\n path.join(mockAppData, 'Claude', 'claude_desktop_config.json'),\n );\n });\n\n it('should throw error for unsupported platform', () => {\n Object.defineProperty(process, 'platform', {\n value: 'linux',\n writable: true,\n });\n\n expect(() => (client as any).getConfigPath()).toThrow(\n 'Unsupported platform: linux',\n );\n });\n });\n\n describe('isServerInstalled', () => {\n beforeEach(() => {\n Object.defineProperty(process, 'platform', {\n value: 'darwin',\n writable: true,\n });\n });\n\n it('should return false when config file does not exist', async () => {\n existsSyncMock.mockReturnValue(false);\n\n const result = await client.isServerInstalled();\n expect(result).toBe(false);\n });\n\n it('should return false when config file exists but posthog server is not configured', async () => {\n existsSyncMock.mockReturnValue(true);\n const configData = {\n mcpServers: {\n otherServer: mockServerConfig,\n },\n };\n readFileMock.mockResolvedValue(JSON.stringify(configData));\n\n const result = await client.isServerInstalled();\n expect(result).toBe(false);\n });\n\n it('should return true when posthog server is configured', async () => {\n existsSyncMock.mockReturnValue(true);\n const configData = {\n mcpServers: {\n posthog: mockServerConfig,\n otherServer: mockServerConfig,\n },\n };\n readFileMock.mockResolvedValue(JSON.stringify(configData));\n\n const result = await client.isServerInstalled();\n expect(result).toBe(true);\n });\n\n it('should return false when config file is invalid JSON', async () => {\n existsSyncMock.mockReturnValue(true);\n readFileMock.mockResolvedValue('invalid json');\n\n const result = await client.isServerInstalled();\n expect(result).toBe(false);\n });\n\n it('should return false when readFile throws an error', async () => {\n existsSyncMock.mockReturnValue(true);\n readFileMock.mockRejectedValue(new Error('File read error'));\n\n const result = await client.isServerInstalled();\n expect(result).toBe(false);\n });\n });\n\n describe('addServer', () => {\n beforeEach(() => {\n Object.defineProperty(process, 'platform', {\n value: 'darwin',\n writable: true,\n });\n });\n\n it('should create config directory and add server when config file does not exist', async () => {\n existsSyncMock.mockReturnValue(false);\n\n await client.addServer(mockApiKey);\n\n const expectedConfigPath = path.join(\n mockHomeDir,\n 'Library',\n 'Application Support',\n 'Claude',\n 'claude_desktop_config.json',\n );\n const expectedConfigDir = path.dirname(expectedConfigPath);\n\n expect(mkdirMock).toHaveBeenCalledWith(expectedConfigDir, {\n recursive: true,\n });\n expect(writeFileMock).toHaveBeenCalledWith(\n expectedConfigPath,\n JSON.stringify(\n {\n mcpServers: {\n posthog: mockServerConfig,\n },\n },\n null,\n 2,\n ),\n 'utf8',\n );\n });\n\n it('should merge with existing config when config file exists', async () => {\n existsSyncMock.mockReturnValue(true);\n const existingConfig = {\n mcpServers: {\n existingServer: {\n command: 'existing',\n args: [],\n env: {},\n },\n },\n };\n readFileMock.mockResolvedValue(JSON.stringify(existingConfig));\n\n await client.addServer(mockApiKey);\n\n expect(writeFileMock).toHaveBeenCalledWith(\n expect.any(String),\n JSON.stringify(\n {\n mcpServers: {\n existingServer: existingConfig.mcpServers.existingServer,\n posthog: mockServerConfig,\n },\n },\n null,\n 2,\n ),\n 'utf8',\n );\n });\n\n it('should create new config when existing config is invalid', async () => {\n existsSyncMock.mockReturnValue(true);\n readFileMock.mockResolvedValue('invalid json');\n\n await client.addServer(mockApiKey);\n\n expect(writeFileMock).toHaveBeenCalledWith(\n expect.any(String),\n JSON.stringify(\n {\n mcpServers: {\n posthog: mockServerConfig,\n },\n },\n null,\n 2,\n ),\n 'utf8',\n );\n });\n\n it('should call getDefaultServerConfig with the provided API key', async () => {\n existsSyncMock.mockReturnValue(false);\n\n await client.addServer(mockApiKey);\n\n expect(getDefaultServerConfigMock).toHaveBeenCalledWith(mockApiKey);\n });\n });\n\n describe('removeServer', () => {\n beforeEach(() => {\n Object.defineProperty(process, 'platform', {\n value: 'darwin',\n writable: true,\n });\n });\n\n it('should do nothing when config file does not exist', async () => {\n existsSyncMock.mockReturnValue(false);\n\n await client.removeServer();\n\n expect(readFileMock).not.toHaveBeenCalled();\n expect(writeFileMock).not.toHaveBeenCalled();\n });\n\n it('should remove posthog server from config', async () => {\n existsSyncMock.mockReturnValue(true);\n const configWithPosthog = {\n mcpServers: {\n posthog: mockServerConfig,\n otherServer: {\n command: 'other',\n args: [],\n env: {},\n },\n },\n };\n readFileMock.mockResolvedValue(JSON.stringify(configWithPosthog));\n\n await client.removeServer();\n\n expect(writeFileMock).toHaveBeenCalledWith(\n expect.any(String),\n JSON.stringify(\n {\n mcpServers: {\n otherServer: configWithPosthog.mcpServers.otherServer,\n },\n },\n null,\n 2,\n ),\n 'utf8',\n );\n });\n\n it('should do nothing when posthog server is not in config', async () => {\n existsSyncMock.mockReturnValue(true);\n const configWithoutPosthog = {\n mcpServers: {\n otherServer: {\n command: 'other',\n args: [],\n env: {},\n },\n },\n };\n readFileMock.mockResolvedValue(JSON.stringify(configWithoutPosthog));\n\n await client.removeServer();\n\n expect(writeFileMock).not.toHaveBeenCalled();\n });\n\n it('should handle invalid JSON gracefully', async () => {\n existsSyncMock.mockReturnValue(true);\n readFileMock.mockResolvedValue('invalid json');\n\n await client.removeServer();\n\n expect(writeFileMock).not.toHaveBeenCalled();\n });\n\n it('should handle file read errors gracefully', async () => {\n existsSyncMock.mockReturnValue(true);\n readFileMock.mockRejectedValue(new Error('File read error'));\n\n await client.removeServer();\n\n expect(writeFileMock).not.toHaveBeenCalled();\n });\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|