@posthog/wizard 0.6.0 → 0.7.1
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/dist/src/lib/config.d.ts +3 -3
- package/dist/src/lib/config.js +3 -3
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/constants.d.ts +2 -1
- package/dist/src/lib/constants.js +3 -4
- package/dist/src/lib/constants.js.map +1 -1
- package/dist/src/lib/messages.d.ts +7 -1
- package/dist/src/lib/messages.js +19 -4
- package/dist/src/lib/messages.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +11 -5
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/react/react-wizard.js +5 -4
- package/dist/src/react/react-wizard.js.map +1 -1
- package/dist/src/react-native/react-native-wizard.js +3 -3
- package/dist/src/react-native/react-native-wizard.js.map +1 -1
- package/dist/src/run.js +2 -0
- package/dist/src/run.js.map +1 -1
- package/dist/src/steps/__tests__/add-editor-rules.test.d.ts +1 -0
- package/dist/src/steps/__tests__/add-editor-rules.test.js +218 -0
- package/dist/src/steps/__tests__/add-editor-rules.test.js.map +1 -0
- package/dist/src/steps/__tests__/create-pr.test.d.ts +1 -0
- package/dist/src/steps/__tests__/create-pr.test.js +193 -0
- package/dist/src/steps/__tests__/create-pr.test.js.map +1 -0
- package/dist/src/steps/add-editor-rules.d.ts +9 -0
- package/dist/src/{utils/rules → steps}/add-editor-rules.js +10 -10
- package/dist/src/steps/add-editor-rules.js.map +1 -0
- package/dist/src/steps/add-or-update-environment-variables.d.ts +10 -0
- package/dist/src/steps/add-or-update-environment-variables.js +194 -0
- package/dist/src/steps/add-or-update-environment-variables.js.map +1 -0
- package/dist/src/steps/create-pr.d.ts +27 -0
- package/dist/src/steps/create-pr.js +305 -0
- package/dist/src/steps/create-pr.js.map +1 -0
- package/dist/src/steps/index.d.ts +4 -0
- package/dist/src/steps/index.js +21 -0
- package/dist/src/steps/index.js.map +1 -0
- package/dist/src/steps/run-prettier.d.ts +5 -0
- package/dist/src/steps/run-prettier.js +93 -0
- package/dist/src/steps/run-prettier.js.map +1 -0
- package/dist/src/svelte/svelte-wizard.js +6 -5
- package/dist/src/svelte/svelte-wizard.js.map +1 -1
- package/dist/src/utils/__tests__/clack-utils.test.d.ts +1 -0
- package/dist/src/utils/__tests__/clack-utils.test.js +128 -0
- package/dist/src/utils/__tests__/clack-utils.test.js.map +1 -0
- package/dist/src/utils/clack-utils.d.ts +0 -4
- package/dist/src/utils/clack-utils.js +0 -49
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/environment.d.ts +0 -6
- package/dist/src/utils/environment.js +0 -100
- package/dist/src/utils/environment.js.map +1 -1
- package/dist/src/utils/file-utils.js +1 -1
- package/dist/src/utils/file-utils.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/utils/rules/add-editor-rules.d.ts +0 -9
- package/dist/src/utils/rules/add-editor-rules.js.map +0 -1
- package/dist/src/utils/rules/add-editor-rules.ts +0 -86
|
@@ -0,0 +1,218 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path_1 = __importDefault(require("path"));
|
|
41
|
+
const add_editor_rules_1 = require("../add-editor-rules");
|
|
42
|
+
const analytics_1 = require("../../utils/analytics");
|
|
43
|
+
const clack_1 = __importDefault(require("../../utils/clack"));
|
|
44
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
45
|
+
// Mock dependencies
|
|
46
|
+
jest.mock('fs', () => ({
|
|
47
|
+
promises: {
|
|
48
|
+
mkdir: jest.fn(),
|
|
49
|
+
readFile: jest.fn(),
|
|
50
|
+
writeFile: jest.fn(),
|
|
51
|
+
},
|
|
52
|
+
}));
|
|
53
|
+
jest.mock('../../utils/analytics', () => ({
|
|
54
|
+
analytics: {
|
|
55
|
+
capture: jest.fn(),
|
|
56
|
+
setTag: jest.fn(),
|
|
57
|
+
shutdown: jest.fn().mockResolvedValue(undefined),
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
60
|
+
jest.mock('../../utils/clack', () => ({
|
|
61
|
+
log: {
|
|
62
|
+
info: jest.fn(),
|
|
63
|
+
},
|
|
64
|
+
select: jest.fn().mockResolvedValue(true),
|
|
65
|
+
isCancel: jest.fn((value) => false),
|
|
66
|
+
cancel: jest.fn(),
|
|
67
|
+
}));
|
|
68
|
+
describe('addEditorRules', () => {
|
|
69
|
+
const mockOptions = {
|
|
70
|
+
installDir: '/test/dir',
|
|
71
|
+
rulesName: 'react-rules.md',
|
|
72
|
+
integration: 'react',
|
|
73
|
+
};
|
|
74
|
+
const originalEnv = process.env;
|
|
75
|
+
const mkdirMock = fs.promises.mkdir;
|
|
76
|
+
const readFileMock = fs.promises.readFile;
|
|
77
|
+
const writeFileMock = fs.promises.writeFile;
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
79
|
+
const captureMock = analytics_1.analytics.capture;
|
|
80
|
+
const infoMock = clack_1.default.log.info;
|
|
81
|
+
const selectMock = clack_1.default.select;
|
|
82
|
+
const isCancelMock = clack_1.default.isCancel;
|
|
83
|
+
const cancelMock = clack_1.default.cancel;
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
// Reset all mocks before each test
|
|
86
|
+
jest.clearAllMocks();
|
|
87
|
+
// Clear mock implementations
|
|
88
|
+
fs.promises.mkdir.mockReset();
|
|
89
|
+
fs.promises.readFile.mockReset();
|
|
90
|
+
fs.promises.writeFile.mockReset();
|
|
91
|
+
selectMock.mockReset();
|
|
92
|
+
selectMock.mockResolvedValue(true); // Default to "Yes" for the prompt
|
|
93
|
+
isCancelMock.mockReset();
|
|
94
|
+
isCancelMock.mockReturnValue(false);
|
|
95
|
+
cancelMock.mockReset();
|
|
96
|
+
process.env = { ...originalEnv };
|
|
97
|
+
});
|
|
98
|
+
afterAll(() => {
|
|
99
|
+
process.env = originalEnv;
|
|
100
|
+
});
|
|
101
|
+
it('should not install rules when CURSOR_TRACE_ID is not set', async () => {
|
|
102
|
+
delete process.env.CURSOR_TRACE_ID;
|
|
103
|
+
await (0, add_editor_rules_1.addEditorRulesStep)(mockOptions);
|
|
104
|
+
expect(mkdirMock).not.toHaveBeenCalled();
|
|
105
|
+
expect(readFileMock).not.toHaveBeenCalled();
|
|
106
|
+
expect(writeFileMock).not.toHaveBeenCalled();
|
|
107
|
+
expect(captureMock).not.toHaveBeenCalled();
|
|
108
|
+
expect(infoMock).not.toHaveBeenCalled();
|
|
109
|
+
});
|
|
110
|
+
it('should install rules when CURSOR_TRACE_ID is set', async () => {
|
|
111
|
+
process.env.CURSOR_TRACE_ID = 'test-trace-id';
|
|
112
|
+
const mockFrameworkRules = 'framework rules {universal} content';
|
|
113
|
+
const mockUniversalRules = 'universal rules content';
|
|
114
|
+
const expectedCombinedRules = 'framework rules universal rules content content';
|
|
115
|
+
fs.promises.readFile
|
|
116
|
+
.mockImplementationOnce(() => Promise.resolve(mockFrameworkRules))
|
|
117
|
+
.mockImplementationOnce(() => Promise.resolve(mockUniversalRules));
|
|
118
|
+
await (0, add_editor_rules_1.addEditorRulesStep)(mockOptions);
|
|
119
|
+
// Check if directory was created
|
|
120
|
+
expect(mkdirMock).toHaveBeenCalledWith(path_1.default.join('/test/dir', '.cursor', 'rules'), { recursive: true });
|
|
121
|
+
// Check if correct files were read
|
|
122
|
+
expect(readFileMock).toHaveBeenCalledTimes(2);
|
|
123
|
+
expect(readFileMock).toHaveBeenNthCalledWith(1, expect.stringMatching(/react-rules\.md$/), 'utf8');
|
|
124
|
+
expect(readFileMock).toHaveBeenNthCalledWith(2, expect.stringMatching(/universal\.md$/), 'utf8');
|
|
125
|
+
// Check if combined rules were written correctly
|
|
126
|
+
expect(writeFileMock).toHaveBeenCalledWith(path_1.default.join('/test/dir', '.cursor', 'rules', 'posthog-integration.mdc'), expectedCombinedRules, 'utf8');
|
|
127
|
+
// Check if analytics were captured
|
|
128
|
+
expect(captureMock).toHaveBeenCalledWith('wizard interaction', {
|
|
129
|
+
action: 'added editor rules',
|
|
130
|
+
integration: mockOptions.integration,
|
|
131
|
+
});
|
|
132
|
+
// Check if success message was logged
|
|
133
|
+
expect(infoMock).toHaveBeenCalledWith(`Added Cursor rules to ${chalk_1.default.bold.cyan('.cursor/rules/posthog-integration.mdc')}`);
|
|
134
|
+
});
|
|
135
|
+
it('should handle file system errors gracefully', async () => {
|
|
136
|
+
process.env.CURSOR_TRACE_ID = 'test-trace-id';
|
|
137
|
+
const mockError = new Error('File not found');
|
|
138
|
+
// Mock readFile to throw an error
|
|
139
|
+
fs.promises.readFile.mockRejectedValue(mockError);
|
|
140
|
+
await expect((0, add_editor_rules_1.addEditorRulesStep)(mockOptions)).rejects.toThrow(mockError);
|
|
141
|
+
expect(writeFileMock).not.toHaveBeenCalled();
|
|
142
|
+
expect(captureMock).not.toHaveBeenCalled();
|
|
143
|
+
expect(infoMock).not.toHaveBeenCalled();
|
|
144
|
+
});
|
|
145
|
+
it('should handle missing rules files gracefully', async () => {
|
|
146
|
+
process.env.CURSOR_TRACE_ID = 'test-trace-id';
|
|
147
|
+
const mockError = new Error('File system error');
|
|
148
|
+
// Mock mkdir to throw an error
|
|
149
|
+
fs.promises.mkdir.mockRejectedValue(mockError);
|
|
150
|
+
await expect((0, add_editor_rules_1.addEditorRulesStep)(mockOptions)).rejects.toThrow(mockError);
|
|
151
|
+
expect(writeFileMock).not.toHaveBeenCalled();
|
|
152
|
+
expect(captureMock).not.toHaveBeenCalled();
|
|
153
|
+
expect(infoMock).not.toHaveBeenCalled();
|
|
154
|
+
});
|
|
155
|
+
it('should correctly substitute universal rules with realistic content', async () => {
|
|
156
|
+
process.env.CURSOR_TRACE_ID = 'test-trace-id';
|
|
157
|
+
const mockFrameworkRules = `---
|
|
158
|
+
description: apply when interacting with PostHog/analytics tasks
|
|
159
|
+
globs:
|
|
160
|
+
alwaysApply: true
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
{universal}
|
|
164
|
+
|
|
165
|
+
# Framework-specific rules
|
|
166
|
+
- Rule 1
|
|
167
|
+
- Rule 2`;
|
|
168
|
+
const mockUniversalRules = `Never hallucinate an API key. Instead, always use the API key populated in the .env file.
|
|
169
|
+
|
|
170
|
+
# Feature flags
|
|
171
|
+
|
|
172
|
+
A 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.`;
|
|
173
|
+
const expectedCombinedRules = `---
|
|
174
|
+
description: apply when interacting with PostHog/analytics tasks
|
|
175
|
+
globs:
|
|
176
|
+
alwaysApply: true
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
Never hallucinate an API key. Instead, always use the API key populated in the .env file.
|
|
180
|
+
|
|
181
|
+
# Feature flags
|
|
182
|
+
|
|
183
|
+
A 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.
|
|
184
|
+
|
|
185
|
+
# Framework-specific rules
|
|
186
|
+
- Rule 1
|
|
187
|
+
- Rule 2`;
|
|
188
|
+
fs.promises.readFile
|
|
189
|
+
.mockImplementationOnce(() => Promise.resolve(mockFrameworkRules))
|
|
190
|
+
.mockImplementationOnce(() => Promise.resolve(mockUniversalRules));
|
|
191
|
+
await (0, add_editor_rules_1.addEditorRulesStep)(mockOptions);
|
|
192
|
+
// Check if directory was created
|
|
193
|
+
expect(mkdirMock).toHaveBeenCalledWith(path_1.default.join('/test/dir', '.cursor', 'rules'), { recursive: true });
|
|
194
|
+
// Check if correct files were read
|
|
195
|
+
expect(readFileMock).toHaveBeenCalledWith(expect.stringMatching(/react-rules\.md$/), 'utf8');
|
|
196
|
+
expect(readFileMock).toHaveBeenCalledWith(expect.stringMatching(/universal\.md$/), 'utf8');
|
|
197
|
+
// Check if combined rules were written correctly
|
|
198
|
+
expect(writeFileMock).toHaveBeenCalledWith(path_1.default.join('/test/dir', '.cursor', 'rules', 'posthog-integration.mdc'), expectedCombinedRules, 'utf8');
|
|
199
|
+
// Check if analytics were captured
|
|
200
|
+
expect(captureMock).toHaveBeenCalledWith('wizard interaction', {
|
|
201
|
+
action: 'added editor rules',
|
|
202
|
+
integration: mockOptions.integration,
|
|
203
|
+
});
|
|
204
|
+
// Check if success message was logged
|
|
205
|
+
expect(infoMock).toHaveBeenCalledWith(`Added Cursor rules to ${chalk_1.default.bold.cyan('.cursor/rules/posthog-integration.mdc')}`);
|
|
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
|
+
});
|
|
218
|
+
//# sourceMappingURL=add-editor-rules.test.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,193 @@
|
|
|
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 childProcess = __importStar(require("node:child_process"));
|
|
37
|
+
const create_pr_1 = require("../create-pr");
|
|
38
|
+
// Mock dependencies
|
|
39
|
+
jest.mock('node:child_process', () => ({
|
|
40
|
+
exec: jest.fn(),
|
|
41
|
+
}));
|
|
42
|
+
describe('Git operations', () => {
|
|
43
|
+
const execMock = childProcess.exec;
|
|
44
|
+
const testDir = '/test/dir';
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
jest.clearAllMocks();
|
|
47
|
+
});
|
|
48
|
+
describe('getCurrentBranch', () => {
|
|
49
|
+
it('should return the current branch name on success', async () => {
|
|
50
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
51
|
+
callback(null, 'main', '');
|
|
52
|
+
return {};
|
|
53
|
+
});
|
|
54
|
+
const result = await (0, create_pr_1.getCurrentBranch)(testDir);
|
|
55
|
+
expect(result).toEqual({ success: true, data: 'main' });
|
|
56
|
+
expect(execMock).toHaveBeenCalledWith('git rev-parse --abbrev-ref HEAD', { cwd: testDir }, expect.any(Function));
|
|
57
|
+
});
|
|
58
|
+
it('should return error on failure', async () => {
|
|
59
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
60
|
+
callback(new Error('git error'), '', 'Failed to get branch');
|
|
61
|
+
return {};
|
|
62
|
+
});
|
|
63
|
+
const result = await (0, create_pr_1.getCurrentBranch)(testDir);
|
|
64
|
+
expect(result).toEqual({ success: false, error: 'Failed to get branch' });
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('checkForEnvFiles', () => {
|
|
68
|
+
it('should return true when .env files are found', async () => {
|
|
69
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
70
|
+
callback(null, '.env\n.env.local', '');
|
|
71
|
+
return {};
|
|
72
|
+
});
|
|
73
|
+
const result = await (0, create_pr_1.checkForEnvFiles)(testDir);
|
|
74
|
+
expect(result).toEqual({ success: true, data: true });
|
|
75
|
+
});
|
|
76
|
+
it('should return false when no .env files are found', async () => {
|
|
77
|
+
const error = new Error('No match');
|
|
78
|
+
error.code = 1;
|
|
79
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
80
|
+
callback(error, '', 'command failed with exit code 1');
|
|
81
|
+
return {};
|
|
82
|
+
});
|
|
83
|
+
const result = await (0, create_pr_1.checkForEnvFiles)(testDir);
|
|
84
|
+
expect(result).toEqual({
|
|
85
|
+
success: false,
|
|
86
|
+
error: 'command failed with exit code 1',
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
it('should handle grep errors correctly', async () => {
|
|
90
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
91
|
+
callback(new Error('grep error'), '', 'Some other error');
|
|
92
|
+
return {};
|
|
93
|
+
});
|
|
94
|
+
const result = await (0, create_pr_1.checkForEnvFiles)(testDir);
|
|
95
|
+
expect(result).toEqual({ success: false, error: 'Some other error' });
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('checkBranchExists', () => {
|
|
99
|
+
it('should return success when branch does not exist', async () => {
|
|
100
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
101
|
+
callback(new Error('branch not found'), '', 'fatal: not a valid ref');
|
|
102
|
+
return {};
|
|
103
|
+
});
|
|
104
|
+
const result = await (0, create_pr_1.checkBranchExists)('new-branch', testDir);
|
|
105
|
+
expect(result).toEqual({ success: true, data: true });
|
|
106
|
+
});
|
|
107
|
+
it('should return failure when branch exists', async () => {
|
|
108
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
109
|
+
callback(null, 'ref exists', '');
|
|
110
|
+
return {};
|
|
111
|
+
});
|
|
112
|
+
const result = await (0, create_pr_1.checkBranchExists)('existing-branch', testDir);
|
|
113
|
+
expect(result).toEqual({ success: false, data: false });
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe('createGitHubPR', () => {
|
|
117
|
+
it('should create PR successfully', async () => {
|
|
118
|
+
const prUrl = 'https://github.com/org/repo/pull/1';
|
|
119
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
120
|
+
callback(null, prUrl, '');
|
|
121
|
+
return {};
|
|
122
|
+
});
|
|
123
|
+
const result = await (0, create_pr_1.createGitHubPR)('main', 'feature', 'title', 'body', testDir);
|
|
124
|
+
expect(result).toEqual({ success: true, data: prUrl });
|
|
125
|
+
expect(execMock).toHaveBeenCalledWith('gh pr create --base main --head feature --title "title" --body "body"', { cwd: testDir }, expect.any(Function));
|
|
126
|
+
});
|
|
127
|
+
it('should handle PR creation failure', async () => {
|
|
128
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
129
|
+
callback(new Error('PR creation failed'), '', 'Authentication failed');
|
|
130
|
+
return {};
|
|
131
|
+
});
|
|
132
|
+
const result = await (0, create_pr_1.createGitHubPR)('main', 'feature', 'title', 'body', testDir);
|
|
133
|
+
expect(result).toEqual({
|
|
134
|
+
success: false,
|
|
135
|
+
error: 'Authentication failed',
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
describe('Git operations', () => {
|
|
140
|
+
const testCases = [
|
|
141
|
+
{
|
|
142
|
+
fn: create_pr_1.createBranch,
|
|
143
|
+
args: ['new-branch', testDir],
|
|
144
|
+
command: 'git checkout -b new-branch',
|
|
145
|
+
name: 'createBranch',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
fn: create_pr_1.stageChanges,
|
|
149
|
+
args: [testDir],
|
|
150
|
+
command: 'git add .',
|
|
151
|
+
name: 'stageChanges',
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
fn: create_pr_1.commitChanges,
|
|
155
|
+
args: ['commit message', testDir],
|
|
156
|
+
command: 'git commit -m "commit message"',
|
|
157
|
+
name: 'commitChanges',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
fn: create_pr_1.pushBranch,
|
|
161
|
+
args: ['branch-name', testDir],
|
|
162
|
+
command: 'git push -u origin branch-name',
|
|
163
|
+
name: 'pushBranch',
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
fn: create_pr_1.checkGitHubAuth,
|
|
167
|
+
args: [testDir],
|
|
168
|
+
command: 'gh auth status',
|
|
169
|
+
name: 'checkGitHubAuth',
|
|
170
|
+
},
|
|
171
|
+
];
|
|
172
|
+
testCases.forEach(({ fn, args, command, name }) => {
|
|
173
|
+
it(`${name} should execute correctly`, async () => {
|
|
174
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
175
|
+
callback(null, 'success', '');
|
|
176
|
+
return {};
|
|
177
|
+
});
|
|
178
|
+
const result = await fn(...args);
|
|
179
|
+
expect(result).toEqual({ success: true, data: 'success' });
|
|
180
|
+
expect(execMock).toHaveBeenCalledWith(command, { cwd: testDir }, expect.any(Function));
|
|
181
|
+
});
|
|
182
|
+
it(`${name} should handle errors`, async () => {
|
|
183
|
+
execMock.mockImplementation((_cmd, _opts, callback) => {
|
|
184
|
+
callback(new Error('operation failed'), '', 'Command failed');
|
|
185
|
+
return {};
|
|
186
|
+
});
|
|
187
|
+
const result = await fn(...args);
|
|
188
|
+
expect(result).toEqual({ success: false, error: 'Command failed' });
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
//# sourceMappingURL=create-pr.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-pr.test.js","sourceRoot":"","sources":["../../../../src/steps/__tests__/create-pr.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as childProcess from 'node:child_process';\nimport type { ExecException } from 'node:child_process';\nimport {\n checkBranchExists,\n checkForEnvFiles,\n checkGitHubAuth,\n commitChanges,\n createBranch,\n createGitHubPR,\n getCurrentBranch,\n pushBranch,\n stageChanges,\n} from '../create-pr';\n\n// Mock dependencies\njest.mock('node:child_process', () => ({\n exec: jest.fn(),\n}));\n\ntype ExecCallback = (\n error: ExecException | null,\n stdout: string,\n stderr: string,\n) => void;\n\ntype TestCase = {\n fn: (...args: any[]) => Promise<any>;\n args: readonly any[];\n command: string;\n name: string;\n};\n\ndescribe('Git operations', () => {\n const execMock = childProcess.exec as unknown as jest.Mock;\n const testDir = '/test/dir';\n\n beforeEach(() => {\n jest.clearAllMocks();\n });\n\n describe('getCurrentBranch', () => {\n it('should return the current branch name on success', async () => {\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(null, 'main', '');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await getCurrentBranch(testDir);\n expect(result).toEqual({ success: true, data: 'main' });\n expect(execMock).toHaveBeenCalledWith(\n 'git rev-parse --abbrev-ref HEAD',\n { cwd: testDir },\n expect.any(Function),\n );\n });\n\n it('should return error on failure', async () => {\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(new Error('git error'), '', 'Failed to get branch');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await getCurrentBranch(testDir);\n expect(result).toEqual({ success: false, error: 'Failed to get branch' });\n });\n });\n\n describe('checkForEnvFiles', () => {\n it('should return true when .env files are found', async () => {\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(null, '.env\\n.env.local', '');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await checkForEnvFiles(testDir);\n expect(result).toEqual({ success: true, data: true });\n });\n\n it('should return false when no .env files are found', async () => {\n const error = new Error('No match') as ExecException;\n error.code = 1;\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(error, '', 'command failed with exit code 1');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await checkForEnvFiles(testDir);\n expect(result).toEqual({\n success: false,\n error: 'command failed with exit code 1',\n });\n });\n\n it('should handle grep errors correctly', async () => {\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(new Error('grep error'), '', 'Some other error');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await checkForEnvFiles(testDir);\n expect(result).toEqual({ success: false, error: 'Some other error' });\n });\n });\n\n describe('checkBranchExists', () => {\n it('should return success when branch does not exist', async () => {\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(new Error('branch not found'), '', 'fatal: not a valid ref');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await checkBranchExists('new-branch', testDir);\n expect(result).toEqual({ success: true, data: true });\n });\n\n it('should return failure when branch exists', async () => {\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(null, 'ref exists', '');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await checkBranchExists('existing-branch', testDir);\n expect(result).toEqual({ success: false, data: false });\n });\n });\n\n describe('createGitHubPR', () => {\n it('should create PR successfully', async () => {\n const prUrl = 'https://github.com/org/repo/pull/1';\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(null, prUrl, '');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await createGitHubPR(\n 'main',\n 'feature',\n 'title',\n 'body',\n testDir,\n );\n expect(result).toEqual({ success: true, data: prUrl });\n expect(execMock).toHaveBeenCalledWith(\n 'gh pr create --base main --head feature --title \"title\" --body \"body\"',\n { cwd: testDir },\n expect.any(Function),\n );\n });\n\n it('should handle PR creation failure', async () => {\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(\n new Error('PR creation failed'),\n '',\n 'Authentication failed',\n );\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await createGitHubPR(\n 'main',\n 'feature',\n 'title',\n 'body',\n testDir,\n );\n expect(result).toEqual({\n success: false,\n error: 'Authentication failed',\n });\n });\n });\n\n describe('Git operations', () => {\n const testCases: TestCase[] = [\n {\n fn: createBranch,\n args: ['new-branch', testDir] as const,\n command: 'git checkout -b new-branch',\n name: 'createBranch',\n },\n {\n fn: stageChanges,\n args: [testDir] as const,\n command: 'git add .',\n name: 'stageChanges',\n },\n {\n fn: commitChanges,\n args: ['commit message', testDir] as const,\n command: 'git commit -m \"commit message\"',\n name: 'commitChanges',\n },\n {\n fn: pushBranch,\n args: ['branch-name', testDir] as const,\n command: 'git push -u origin branch-name',\n name: 'pushBranch',\n },\n {\n fn: checkGitHubAuth,\n args: [testDir] as const,\n command: 'gh auth status',\n name: 'checkGitHubAuth',\n },\n ];\n\n testCases.forEach(({ fn, args, command, name }) => {\n it(`${name} should execute correctly`, async () => {\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(null, 'success', '');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await fn(...args);\n expect(result).toEqual({ success: true, data: 'success' });\n expect(execMock).toHaveBeenCalledWith(\n command,\n { cwd: testDir },\n expect.any(Function),\n );\n });\n\n it(`${name} should handle errors`, async () => {\n execMock.mockImplementation(\n (_cmd: string, _opts: any, callback: ExecCallback) => {\n callback(new Error('operation failed'), '', 'Command failed');\n return {} as childProcess.ChildProcess;\n },\n );\n\n const result = await fn(...args);\n expect(result).toEqual({ success: false, error: 'Command failed' });\n });\n });\n });\n});\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Integration } from '../lib/constants';
|
|
2
|
+
type AddEditorRulesStepOptions = {
|
|
3
|
+
installDir: string;
|
|
4
|
+
rulesName: string;
|
|
5
|
+
integration: Integration;
|
|
6
|
+
default?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare const addEditorRulesStep: ({ installDir, rulesName, integration, default: defaultAddEditorRules, }: AddEditorRulesStepOptions) => Promise<boolean>;
|
|
9
|
+
export {};
|
|
@@ -36,15 +36,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
39
|
+
exports.addEditorRulesStep = void 0;
|
|
40
40
|
const fs = __importStar(require("fs"));
|
|
41
41
|
const chalk_1 = __importDefault(require("chalk"));
|
|
42
42
|
const path_1 = __importDefault(require("path"));
|
|
43
|
-
const analytics_1 = require("../analytics");
|
|
44
|
-
const clack_1 = __importDefault(require("../clack"));
|
|
45
|
-
const telemetry_1 = require("
|
|
46
|
-
const clack_utils_1 = require("../clack-utils");
|
|
47
|
-
const
|
|
43
|
+
const analytics_1 = require("../utils/analytics");
|
|
44
|
+
const clack_1 = __importDefault(require("../utils/clack"));
|
|
45
|
+
const telemetry_1 = require("../telemetry");
|
|
46
|
+
const clack_utils_1 = require("../utils/clack-utils");
|
|
47
|
+
const addEditorRulesStep = async ({ installDir, rulesName, integration, default: defaultAddEditorRules, }) => {
|
|
48
48
|
// Add rules file if in Cursor environment
|
|
49
49
|
if (process.env.CURSOR_TRACE_ID) {
|
|
50
50
|
const addEditorRules = defaultAddEditorRules
|
|
@@ -68,8 +68,8 @@ const addEditorRules = async ({ installDir, rulesName, integration, default: def
|
|
|
68
68
|
return (0, telemetry_1.traceStep)('add-editor-rules', async () => {
|
|
69
69
|
const docsDir = path_1.default.join(installDir, '.cursor', 'rules');
|
|
70
70
|
await fs.promises.mkdir(docsDir, { recursive: true });
|
|
71
|
-
const frameworkRules = await fs.promises.readFile(path_1.default.join(__dirname, rulesName), 'utf8');
|
|
72
|
-
const universalRulesPath = path_1.default.join(__dirname, 'universal.md');
|
|
71
|
+
const frameworkRules = await fs.promises.readFile(path_1.default.join(__dirname, '..', 'utils', 'rules', rulesName), 'utf8');
|
|
72
|
+
const universalRulesPath = path_1.default.join(__dirname, '..', 'utils', 'rules', 'universal.md');
|
|
73
73
|
const universalRules = await fs.promises.readFile(universalRulesPath, 'utf8');
|
|
74
74
|
// Replace {universal} placeholder with universal rules content
|
|
75
75
|
const combinedRules = frameworkRules.replace('{universal}', universalRules);
|
|
@@ -80,11 +80,11 @@ const addEditorRules = async ({ installDir, rulesName, integration, default: def
|
|
|
80
80
|
action: 'added editor rules',
|
|
81
81
|
integration,
|
|
82
82
|
});
|
|
83
|
-
clack_1.default.log.info(`Added Cursor rules to ${chalk_1.default.bold.cyan(
|
|
83
|
+
clack_1.default.log.info(`Added Cursor rules to ${chalk_1.default.bold.cyan(`.cursor/rules/posthog-integration.mdc`)}`);
|
|
84
84
|
return true;
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
return false;
|
|
88
88
|
};
|
|
89
|
-
exports.
|
|
89
|
+
exports.addEditorRulesStep = addEditorRulesStep;
|
|
90
90
|
//# sourceMappingURL=add-editor-rules.js.map
|
|
@@ -0,0 +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;AACzC,sDAAwD;AASjD,MAAM,kBAAkB,GAAG,KAAK,EAAE,EACvC,UAAU,EACV,SAAS,EACT,WAAW,EACX,OAAO,EAAE,qBAAqB,GACJ,EAAoB,EAAE;IAChD,0CAA0C;IAC1C,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;QAChC,MAAM,cAAc,GAAY,qBAAqB;YACnD,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,MAAM,IAAA,8BAAgB,EACpB,eAAK,CAAC,MAAM,CAAC;gBACX,OAAO,EACL,4DAA4D;gBAC9D,OAAO,EAAE;oBACP;wBACE,KAAK,EAAE,cAAc;wBACrB,KAAK,EAAE,IAAI;qBACZ;oBACD;wBACE,KAAK,EAAE,YAAY;wBACnB,KAAK,EAAE,KAAK;qBACb;iBACF;aACF,CAAC,CACH,CAAC;QAEN,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,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;AA/EW,QAAA,kBAAkB,sBA+E7B","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';\nimport { abortIfCancelled } from '../utils/clack-utils';\n\ntype AddEditorRulesStepOptions = {\n installDir: string;\n rulesName: string;\n integration: Integration;\n default?: boolean;\n};\n\nexport const addEditorRulesStep = async ({\n installDir,\n rulesName,\n integration,\n default: defaultAddEditorRules,\n}: AddEditorRulesStepOptions): Promise<boolean> => {\n // Add rules file if in Cursor environment\n if (process.env.CURSOR_TRACE_ID) {\n const addEditorRules: boolean = defaultAddEditorRules\n ? true\n : await abortIfCancelled(\n clack.select({\n message:\n 'Would you like to have PostHog added to your Cursor rules?',\n options: [\n {\n label: 'Yes, please!',\n value: true,\n },\n {\n label: 'No, thanks',\n value: false,\n },\n ],\n }),\n );\n\n if (!addEditorRules) {\n return false;\n }\n\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,10 @@
|
|
|
1
|
+
import type { Integration } from '../lib/constants';
|
|
2
|
+
export declare function addOrUpdateEnvironmentVariablesStep({ installDir, variables, integration, }: {
|
|
3
|
+
installDir: string;
|
|
4
|
+
variables: Record<string, string>;
|
|
5
|
+
integration: Integration;
|
|
6
|
+
}): Promise<{
|
|
7
|
+
relativeEnvFilePath: string;
|
|
8
|
+
addedEnvVariables: boolean;
|
|
9
|
+
addedGitignore: boolean;
|
|
10
|
+
}>;
|