@posthog/wizard 1.32.1 → 1.34.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/dist/src/android/android-wizard-agent.js +2 -0
- package/dist/src/android/android-wizard-agent.js.map +1 -1
- package/dist/src/angular/angular-wizard-agent.js +2 -1
- package/dist/src/angular/angular-wizard-agent.js.map +1 -1
- package/dist/src/astro/astro-wizard-agent.js +2 -1
- package/dist/src/astro/astro-wizard-agent.js.map +1 -1
- package/dist/src/django/django-wizard-agent.js +4 -1
- package/dist/src/django/django-wizard-agent.js.map +1 -1
- package/dist/src/fastapi/fastapi-wizard-agent.js +4 -1
- package/dist/src/fastapi/fastapi-wizard-agent.js.map +1 -1
- package/dist/src/flask/flask-wizard-agent.js +4 -1
- package/dist/src/flask/flask-wizard-agent.js.map +1 -1
- package/dist/src/laravel/laravel-wizard-agent.js +2 -0
- package/dist/src/laravel/laravel-wizard-agent.js.map +1 -1
- package/dist/src/lib/__tests__/package-manager-detection.test.d.ts +1 -0
- package/dist/src/lib/__tests__/package-manager-detection.test.js +195 -0
- package/dist/src/lib/__tests__/package-manager-detection.test.js.map +1 -0
- package/dist/src/lib/__tests__/wizard-tools.test.d.ts +1 -0
- package/dist/src/lib/__tests__/wizard-tools.test.js +200 -0
- package/dist/src/lib/__tests__/wizard-tools.test.js.map +1 -0
- package/dist/src/lib/agent-interface.d.ts +2 -0
- package/dist/src/lib/agent-interface.js +12 -9
- package/dist/src/lib/agent-interface.js.map +1 -1
- package/dist/src/lib/agent-runner.js +7 -4
- package/dist/src/lib/agent-runner.js.map +1 -1
- package/dist/src/lib/constants.d.ts +3 -1
- package/dist/src/lib/constants.js +2 -0
- package/dist/src/lib/constants.js.map +1 -1
- package/dist/src/lib/framework-config.d.ts +15 -2
- package/dist/src/lib/framework-config.js +8 -1
- package/dist/src/lib/framework-config.js.map +1 -1
- package/dist/src/lib/package-manager-detection.d.ts +37 -0
- package/dist/src/lib/package-manager-detection.js +183 -0
- package/dist/src/lib/package-manager-detection.js.map +1 -0
- package/dist/src/lib/registry.js +4 -0
- package/dist/src/lib/registry.js.map +1 -1
- package/dist/src/lib/wizard-tools.d.ts +40 -0
- package/dist/src/lib/{env-file-tools.js → wizard-tools.js} +95 -46
- package/dist/src/lib/wizard-tools.js.map +1 -0
- package/dist/src/nextjs/nextjs-wizard-agent.js +2 -1
- package/dist/src/nextjs/nextjs-wizard-agent.js.map +1 -1
- package/dist/src/nuxt/nuxt-wizard-agent.js +2 -1
- package/dist/src/nuxt/nuxt-wizard-agent.js.map +1 -1
- package/dist/src/python/python-wizard-agent.js +4 -1
- package/dist/src/python/python-wizard-agent.js.map +1 -1
- package/dist/src/rails/rails-wizard-agent.d.ts +8 -0
- package/dist/src/rails/rails-wizard-agent.js +90 -0
- package/dist/src/rails/rails-wizard-agent.js.map +1 -0
- package/dist/src/rails/utils.d.ts +37 -0
- package/dist/src/rails/utils.js +187 -0
- package/dist/src/rails/utils.js.map +1 -0
- package/dist/src/react-native/react-native-wizard-agent.js +2 -1
- package/dist/src/react-native/react-native-wizard-agent.js.map +1 -1
- package/dist/src/react-router/react-router-wizard-agent.js +2 -1
- package/dist/src/react-router/react-router-wizard-agent.js.map +1 -1
- package/dist/src/ruby/ruby-wizard-agent.d.ts +7 -0
- package/dist/src/ruby/ruby-wizard-agent.js +113 -0
- package/dist/src/ruby/ruby-wizard-agent.js.map +1 -0
- package/dist/src/ruby/utils.d.ts +25 -0
- package/dist/src/ruby/utils.js +158 -0
- package/dist/src/ruby/utils.js.map +1 -0
- package/dist/src/run.js +13 -3
- package/dist/src/run.js.map +1 -1
- package/dist/src/svelte/svelte-wizard-agent.js +2 -1
- package/dist/src/svelte/svelte-wizard-agent.js.map +1 -1
- package/dist/src/swift/swift-wizard-agent.js +2 -0
- package/dist/src/swift/swift-wizard-agent.js.map +1 -1
- package/dist/src/tanstack-router/tanstack-router-wizard-agent.js +2 -1
- package/dist/src/tanstack-router/tanstack-router-wizard-agent.js.map +1 -1
- package/dist/src/tanstack-start/tanstack-start-wizard-agent.js +2 -1
- package/dist/src/tanstack-start/tanstack-start-wizard-agent.js.map +1 -1
- package/dist/src/vue/vue-wizard-agent.js +2 -1
- package/dist/src/vue/vue-wizard-agent.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/lib/env-file-tools.d.ts +0 -11
- package/dist/src/lib/env-file-tools.js.map +0 -1
|
@@ -0,0 +1,195 @@
|
|
|
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 package_manager_detection_1 = require("../package-manager-detection");
|
|
40
|
+
jest.mock('../../utils/debug');
|
|
41
|
+
jest.mock('../../telemetry', () => ({
|
|
42
|
+
traceStep: (_name, fn) => fn(),
|
|
43
|
+
}));
|
|
44
|
+
jest.mock('../../utils/analytics', () => ({
|
|
45
|
+
analytics: { setTag: jest.fn() },
|
|
46
|
+
}));
|
|
47
|
+
function makeTmpDir() {
|
|
48
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'pm-detect-'));
|
|
49
|
+
}
|
|
50
|
+
function cleanup(dir) {
|
|
51
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
52
|
+
}
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Node.js detection
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
describe('detectNodePackageManagers', () => {
|
|
57
|
+
let tmpDir;
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
tmpDir = makeTmpDir();
|
|
60
|
+
});
|
|
61
|
+
afterEach(() => cleanup(tmpDir));
|
|
62
|
+
it('returns empty when no lockfile exists', async () => {
|
|
63
|
+
const result = await (0, package_manager_detection_1.detectNodePackageManagers)(tmpDir);
|
|
64
|
+
expect(result.detected).toHaveLength(0);
|
|
65
|
+
expect(result.primary).toBeNull();
|
|
66
|
+
expect(result.recommendation).toContain('No lockfile found');
|
|
67
|
+
});
|
|
68
|
+
it('detects npm via package-lock.json', async () => {
|
|
69
|
+
fs.writeFileSync(path.join(tmpDir, 'package-lock.json'), '{}');
|
|
70
|
+
const result = await (0, package_manager_detection_1.detectNodePackageManagers)(tmpDir);
|
|
71
|
+
expect(result.detected).toHaveLength(1);
|
|
72
|
+
expect(result.primary?.name).toBe('npm');
|
|
73
|
+
expect(result.primary?.installCommand).toBe('npm add');
|
|
74
|
+
expect(result.recommendation).toContain('npm');
|
|
75
|
+
});
|
|
76
|
+
it('detects pnpm via pnpm-lock.yaml', async () => {
|
|
77
|
+
fs.writeFileSync(path.join(tmpDir, 'pnpm-lock.yaml'), '');
|
|
78
|
+
const result = await (0, package_manager_detection_1.detectNodePackageManagers)(tmpDir);
|
|
79
|
+
expect(result.detected).toHaveLength(1);
|
|
80
|
+
expect(result.primary?.name).toBe('pnpm');
|
|
81
|
+
expect(result.primary?.installCommand).toBe('pnpm add');
|
|
82
|
+
});
|
|
83
|
+
it('detects yarn v1 via yarn.lock', async () => {
|
|
84
|
+
fs.writeFileSync(path.join(tmpDir, 'yarn.lock'), '# yarn lockfile v1\n');
|
|
85
|
+
const result = await (0, package_manager_detection_1.detectNodePackageManagers)(tmpDir);
|
|
86
|
+
expect(result.detected).toHaveLength(1);
|
|
87
|
+
expect(result.primary?.name).toBe('yarn');
|
|
88
|
+
expect(result.primary?.label).toContain('V1');
|
|
89
|
+
});
|
|
90
|
+
it('detects yarn v2+ via yarn.lock with __metadata', async () => {
|
|
91
|
+
fs.writeFileSync(path.join(tmpDir, 'yarn.lock'), '__metadata:\n version: 8\n');
|
|
92
|
+
const result = await (0, package_manager_detection_1.detectNodePackageManagers)(tmpDir);
|
|
93
|
+
expect(result.detected).toHaveLength(1);
|
|
94
|
+
expect(result.primary?.name).toBe('yarn');
|
|
95
|
+
expect(result.primary?.label).toContain('V2');
|
|
96
|
+
});
|
|
97
|
+
it('detects bun via bun.lockb', async () => {
|
|
98
|
+
fs.writeFileSync(path.join(tmpDir, 'bun.lockb'), '');
|
|
99
|
+
const result = await (0, package_manager_detection_1.detectNodePackageManagers)(tmpDir);
|
|
100
|
+
expect(result.detected).toHaveLength(1);
|
|
101
|
+
expect(result.primary?.name).toBe('bun');
|
|
102
|
+
expect(result.primary?.installCommand).toBe('bun add');
|
|
103
|
+
});
|
|
104
|
+
it('detects multiple package managers', async () => {
|
|
105
|
+
fs.writeFileSync(path.join(tmpDir, 'package-lock.json'), '{}');
|
|
106
|
+
fs.writeFileSync(path.join(tmpDir, 'pnpm-lock.yaml'), '');
|
|
107
|
+
const result = await (0, package_manager_detection_1.detectNodePackageManagers)(tmpDir);
|
|
108
|
+
expect(result.detected.length).toBeGreaterThanOrEqual(2);
|
|
109
|
+
expect(result.recommendation).toContain('Multiple');
|
|
110
|
+
});
|
|
111
|
+
it('includes runCommand in detected entries', async () => {
|
|
112
|
+
fs.writeFileSync(path.join(tmpDir, 'package-lock.json'), '{}');
|
|
113
|
+
const result = await (0, package_manager_detection_1.detectNodePackageManagers)(tmpDir);
|
|
114
|
+
expect(result.primary?.runCommand).toBe('npm run');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
// Python detection
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
describe('detectPythonPackageManagers', () => {
|
|
121
|
+
let tmpDir;
|
|
122
|
+
beforeEach(() => {
|
|
123
|
+
tmpDir = makeTmpDir();
|
|
124
|
+
});
|
|
125
|
+
afterEach(() => cleanup(tmpDir));
|
|
126
|
+
it('detects uv via uv.lock', async () => {
|
|
127
|
+
fs.writeFileSync(path.join(tmpDir, 'uv.lock'), '');
|
|
128
|
+
const result = await (0, package_manager_detection_1.detectPythonPackageManagers)(tmpDir);
|
|
129
|
+
expect(result.primary?.name).toBe('uv');
|
|
130
|
+
expect(result.primary?.installCommand).toBe('uv add');
|
|
131
|
+
expect(result.primary?.runCommand).toBe('uv run');
|
|
132
|
+
});
|
|
133
|
+
it('detects poetry via pyproject.toml [tool.poetry]', async () => {
|
|
134
|
+
fs.writeFileSync(path.join(tmpDir, 'pyproject.toml'), '[tool.poetry]\nname = "test"\n');
|
|
135
|
+
const result = await (0, package_manager_detection_1.detectPythonPackageManagers)(tmpDir);
|
|
136
|
+
expect(result.primary?.name).toBe('poetry');
|
|
137
|
+
expect(result.primary?.installCommand).toBe('poetry add');
|
|
138
|
+
});
|
|
139
|
+
it('detects poetry via poetry.lock', async () => {
|
|
140
|
+
fs.writeFileSync(path.join(tmpDir, 'poetry.lock'), '');
|
|
141
|
+
const result = await (0, package_manager_detection_1.detectPythonPackageManagers)(tmpDir);
|
|
142
|
+
expect(result.primary?.name).toBe('poetry');
|
|
143
|
+
});
|
|
144
|
+
it('detects pdm via pyproject.toml [tool.pdm]', async () => {
|
|
145
|
+
fs.writeFileSync(path.join(tmpDir, 'pyproject.toml'), '[tool.pdm]\n');
|
|
146
|
+
const result = await (0, package_manager_detection_1.detectPythonPackageManagers)(tmpDir);
|
|
147
|
+
expect(result.primary?.name).toBe('pdm');
|
|
148
|
+
});
|
|
149
|
+
it('detects pipenv via Pipfile', async () => {
|
|
150
|
+
fs.writeFileSync(path.join(tmpDir, 'Pipfile'), '');
|
|
151
|
+
const result = await (0, package_manager_detection_1.detectPythonPackageManagers)(tmpDir);
|
|
152
|
+
expect(result.primary?.name).toBe('pipenv');
|
|
153
|
+
expect(result.primary?.installCommand).toBe('pipenv install');
|
|
154
|
+
});
|
|
155
|
+
it('detects conda via environment.yml', async () => {
|
|
156
|
+
fs.writeFileSync(path.join(tmpDir, 'environment.yml'), '');
|
|
157
|
+
const result = await (0, package_manager_detection_1.detectPythonPackageManagers)(tmpDir);
|
|
158
|
+
expect(result.primary?.name).toBe('conda');
|
|
159
|
+
});
|
|
160
|
+
it('detects pip via requirements.txt', async () => {
|
|
161
|
+
fs.writeFileSync(path.join(tmpDir, 'requirements.txt'), 'flask==2.0\n');
|
|
162
|
+
const result = await (0, package_manager_detection_1.detectPythonPackageManagers)(tmpDir);
|
|
163
|
+
expect(result.primary?.name).toBe('pip');
|
|
164
|
+
expect(result.primary?.installCommand).toBe('pip install');
|
|
165
|
+
});
|
|
166
|
+
it('falls back to unknown when no markers exist', async () => {
|
|
167
|
+
const result = await (0, package_manager_detection_1.detectPythonPackageManagers)(tmpDir);
|
|
168
|
+
expect(result.primary?.name).toBe('pip');
|
|
169
|
+
expect(result.primary?.label).toContain('default');
|
|
170
|
+
});
|
|
171
|
+
it('returns a recommendation string', async () => {
|
|
172
|
+
fs.writeFileSync(path.join(tmpDir, 'uv.lock'), '');
|
|
173
|
+
const result = await (0, package_manager_detection_1.detectPythonPackageManagers)(tmpDir);
|
|
174
|
+
expect(result.recommendation).toContain('uv');
|
|
175
|
+
expect(result.recommendation).toContain('uv add');
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// Static helpers
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
describe('static package manager helpers', () => {
|
|
182
|
+
it.each([
|
|
183
|
+
{ fn: package_manager_detection_1.composerPackageManager, name: 'composer' },
|
|
184
|
+
{ fn: package_manager_detection_1.swiftPackageManager, name: 'spm' },
|
|
185
|
+
{ fn: package_manager_detection_1.gradlePackageManager, name: 'gradle' },
|
|
186
|
+
])('$name returns valid PackageManagerInfo', async ({ fn }) => {
|
|
187
|
+
const result = await fn();
|
|
188
|
+
expect(result.detected).toHaveLength(1);
|
|
189
|
+
expect(result.primary).toBe(result.detected[0]);
|
|
190
|
+
expect(result.primary?.name).toBeTruthy();
|
|
191
|
+
expect(result.primary?.installCommand).toBeTruthy();
|
|
192
|
+
expect(result.recommendation).toBeTruthy();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
//# sourceMappingURL=package-manager-detection.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-manager-detection.test.js","sourceRoot":"","sources":["../../../../src/lib/__tests__/package-manager-detection.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 {\n detectNodePackageManagers,\n detectPythonPackageManagers,\n composerPackageManager,\n swiftPackageManager,\n gradlePackageManager,\n} from '../package-manager-detection';\n\njest.mock('../../utils/debug');\njest.mock('../../telemetry', () => ({\n traceStep: (_name: string, fn: () => unknown) => fn(),\n}));\njest.mock('../../utils/analytics', () => ({\n analytics: { setTag: jest.fn() },\n}));\n\nfunction makeTmpDir(): string {\n return fs.mkdtempSync(path.join(os.tmpdir(), 'pm-detect-'));\n}\n\nfunction cleanup(dir: string): void {\n fs.rmSync(dir, { recursive: true, force: true });\n}\n\n// ---------------------------------------------------------------------------\n// Node.js detection\n// ---------------------------------------------------------------------------\n\ndescribe('detectNodePackageManagers', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n });\n afterEach(() => cleanup(tmpDir));\n\n it('returns empty when no lockfile exists', async () => {\n const result = await detectNodePackageManagers(tmpDir);\n expect(result.detected).toHaveLength(0);\n expect(result.primary).toBeNull();\n expect(result.recommendation).toContain('No lockfile found');\n });\n\n it('detects npm via package-lock.json', async () => {\n fs.writeFileSync(path.join(tmpDir, 'package-lock.json'), '{}');\n const result = await detectNodePackageManagers(tmpDir);\n expect(result.detected).toHaveLength(1);\n expect(result.primary?.name).toBe('npm');\n expect(result.primary?.installCommand).toBe('npm add');\n expect(result.recommendation).toContain('npm');\n });\n\n it('detects pnpm via pnpm-lock.yaml', async () => {\n fs.writeFileSync(path.join(tmpDir, 'pnpm-lock.yaml'), '');\n const result = await detectNodePackageManagers(tmpDir);\n expect(result.detected).toHaveLength(1);\n expect(result.primary?.name).toBe('pnpm');\n expect(result.primary?.installCommand).toBe('pnpm add');\n });\n\n it('detects yarn v1 via yarn.lock', async () => {\n fs.writeFileSync(path.join(tmpDir, 'yarn.lock'), '# yarn lockfile v1\\n');\n const result = await detectNodePackageManagers(tmpDir);\n expect(result.detected).toHaveLength(1);\n expect(result.primary?.name).toBe('yarn');\n expect(result.primary?.label).toContain('V1');\n });\n\n it('detects yarn v2+ via yarn.lock with __metadata', async () => {\n fs.writeFileSync(\n path.join(tmpDir, 'yarn.lock'),\n '__metadata:\\n version: 8\\n',\n );\n const result = await detectNodePackageManagers(tmpDir);\n expect(result.detected).toHaveLength(1);\n expect(result.primary?.name).toBe('yarn');\n expect(result.primary?.label).toContain('V2');\n });\n\n it('detects bun via bun.lockb', async () => {\n fs.writeFileSync(path.join(tmpDir, 'bun.lockb'), '');\n const result = await detectNodePackageManagers(tmpDir);\n expect(result.detected).toHaveLength(1);\n expect(result.primary?.name).toBe('bun');\n expect(result.primary?.installCommand).toBe('bun add');\n });\n\n it('detects multiple package managers', async () => {\n fs.writeFileSync(path.join(tmpDir, 'package-lock.json'), '{}');\n fs.writeFileSync(path.join(tmpDir, 'pnpm-lock.yaml'), '');\n const result = await detectNodePackageManagers(tmpDir);\n expect(result.detected.length).toBeGreaterThanOrEqual(2);\n expect(result.recommendation).toContain('Multiple');\n });\n\n it('includes runCommand in detected entries', async () => {\n fs.writeFileSync(path.join(tmpDir, 'package-lock.json'), '{}');\n const result = await detectNodePackageManagers(tmpDir);\n expect(result.primary?.runCommand).toBe('npm run');\n });\n});\n\n// ---------------------------------------------------------------------------\n// Python detection\n// ---------------------------------------------------------------------------\n\ndescribe('detectPythonPackageManagers', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n });\n afterEach(() => cleanup(tmpDir));\n\n it('detects uv via uv.lock', async () => {\n fs.writeFileSync(path.join(tmpDir, 'uv.lock'), '');\n const result = await detectPythonPackageManagers(tmpDir);\n expect(result.primary?.name).toBe('uv');\n expect(result.primary?.installCommand).toBe('uv add');\n expect(result.primary?.runCommand).toBe('uv run');\n });\n\n it('detects poetry via pyproject.toml [tool.poetry]', async () => {\n fs.writeFileSync(\n path.join(tmpDir, 'pyproject.toml'),\n '[tool.poetry]\\nname = \"test\"\\n',\n );\n const result = await detectPythonPackageManagers(tmpDir);\n expect(result.primary?.name).toBe('poetry');\n expect(result.primary?.installCommand).toBe('poetry add');\n });\n\n it('detects poetry via poetry.lock', async () => {\n fs.writeFileSync(path.join(tmpDir, 'poetry.lock'), '');\n const result = await detectPythonPackageManagers(tmpDir);\n expect(result.primary?.name).toBe('poetry');\n });\n\n it('detects pdm via pyproject.toml [tool.pdm]', async () => {\n fs.writeFileSync(path.join(tmpDir, 'pyproject.toml'), '[tool.pdm]\\n');\n const result = await detectPythonPackageManagers(tmpDir);\n expect(result.primary?.name).toBe('pdm');\n });\n\n it('detects pipenv via Pipfile', async () => {\n fs.writeFileSync(path.join(tmpDir, 'Pipfile'), '');\n const result = await detectPythonPackageManagers(tmpDir);\n expect(result.primary?.name).toBe('pipenv');\n expect(result.primary?.installCommand).toBe('pipenv install');\n });\n\n it('detects conda via environment.yml', async () => {\n fs.writeFileSync(path.join(tmpDir, 'environment.yml'), '');\n const result = await detectPythonPackageManagers(tmpDir);\n expect(result.primary?.name).toBe('conda');\n });\n\n it('detects pip via requirements.txt', async () => {\n fs.writeFileSync(path.join(tmpDir, 'requirements.txt'), 'flask==2.0\\n');\n const result = await detectPythonPackageManagers(tmpDir);\n expect(result.primary?.name).toBe('pip');\n expect(result.primary?.installCommand).toBe('pip install');\n });\n\n it('falls back to unknown when no markers exist', async () => {\n const result = await detectPythonPackageManagers(tmpDir);\n expect(result.primary?.name).toBe('pip');\n expect(result.primary?.label).toContain('default');\n });\n\n it('returns a recommendation string', async () => {\n fs.writeFileSync(path.join(tmpDir, 'uv.lock'), '');\n const result = await detectPythonPackageManagers(tmpDir);\n expect(result.recommendation).toContain('uv');\n expect(result.recommendation).toContain('uv add');\n });\n});\n\n// ---------------------------------------------------------------------------\n// Static helpers\n// ---------------------------------------------------------------------------\n\ndescribe('static package manager helpers', () => {\n it.each([\n { fn: composerPackageManager, name: 'composer' },\n { fn: swiftPackageManager, name: 'spm' },\n { fn: gradlePackageManager, name: 'gradle' },\n ])('$name returns valid PackageManagerInfo', async ({ fn }) => {\n const result = await fn();\n expect(result.detected).toHaveLength(1);\n expect(result.primary).toBe(result.detected[0]);\n expect(result.primary?.name).toBeTruthy();\n expect(result.primary?.installCommand).toBeTruthy();\n expect(result.recommendation).toBeTruthy();\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,200 @@
|
|
|
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 wizard_tools_1 = require("../wizard-tools");
|
|
40
|
+
function makeTmpDir() {
|
|
41
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'wizard-tools-'));
|
|
42
|
+
}
|
|
43
|
+
function cleanup(dir) {
|
|
44
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
45
|
+
}
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// resolveEnvPath
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
describe('resolveEnvPath', () => {
|
|
50
|
+
it('resolves a relative path within the working directory', () => {
|
|
51
|
+
const result = (0, wizard_tools_1.resolveEnvPath)('/project', '.env.local');
|
|
52
|
+
expect(result).toBe(path.resolve('/project', '.env.local'));
|
|
53
|
+
});
|
|
54
|
+
it('resolves nested paths', () => {
|
|
55
|
+
const result = (0, wizard_tools_1.resolveEnvPath)('/project', 'config/.env');
|
|
56
|
+
expect(result).toBe(path.resolve('/project', 'config/.env'));
|
|
57
|
+
});
|
|
58
|
+
it('rejects path traversal with ../', () => {
|
|
59
|
+
expect(() => (0, wizard_tools_1.resolveEnvPath)('/project', '../etc/passwd')).toThrow('Path traversal rejected');
|
|
60
|
+
});
|
|
61
|
+
it('rejects absolute paths outside working directory', () => {
|
|
62
|
+
expect(() => (0, wizard_tools_1.resolveEnvPath)('/project', '/etc/passwd')).toThrow('Path traversal rejected');
|
|
63
|
+
});
|
|
64
|
+
it('allows the working directory itself', () => {
|
|
65
|
+
// edge case: filePath resolves to exactly workingDirectory
|
|
66
|
+
expect(() => (0, wizard_tools_1.resolveEnvPath)('/project', '.')).not.toThrow();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// parseEnvKeys
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
describe('parseEnvKeys', () => {
|
|
73
|
+
it('parses simple KEY=value lines', () => {
|
|
74
|
+
const keys = (0, wizard_tools_1.parseEnvKeys)('FOO=bar\nBAZ=qux\n');
|
|
75
|
+
expect(keys).toEqual(new Set(['FOO', 'BAZ']));
|
|
76
|
+
});
|
|
77
|
+
it('ignores comments', () => {
|
|
78
|
+
const keys = (0, wizard_tools_1.parseEnvKeys)('# COMMENT=ignored\nFOO=bar\n');
|
|
79
|
+
expect(keys).toEqual(new Set(['FOO']));
|
|
80
|
+
});
|
|
81
|
+
it('ignores blank lines', () => {
|
|
82
|
+
const keys = (0, wizard_tools_1.parseEnvKeys)('\n\nFOO=bar\n\n');
|
|
83
|
+
expect(keys).toEqual(new Set(['FOO']));
|
|
84
|
+
});
|
|
85
|
+
it('handles keys with leading whitespace', () => {
|
|
86
|
+
const keys = (0, wizard_tools_1.parseEnvKeys)(' FOO=bar\n');
|
|
87
|
+
expect(keys).toEqual(new Set(['FOO']));
|
|
88
|
+
});
|
|
89
|
+
it('handles keys with spaces around =', () => {
|
|
90
|
+
const keys = (0, wizard_tools_1.parseEnvKeys)('FOO =bar\n');
|
|
91
|
+
expect(keys).toEqual(new Set(['FOO']));
|
|
92
|
+
});
|
|
93
|
+
it('handles keys with underscores and numbers', () => {
|
|
94
|
+
const keys = (0, wizard_tools_1.parseEnvKeys)('MY_KEY_2=value\n');
|
|
95
|
+
expect(keys).toEqual(new Set(['MY_KEY_2']));
|
|
96
|
+
});
|
|
97
|
+
it('returns empty set for empty content', () => {
|
|
98
|
+
const keys = (0, wizard_tools_1.parseEnvKeys)('');
|
|
99
|
+
expect(keys).toEqual(new Set());
|
|
100
|
+
});
|
|
101
|
+
it('ignores lines without = sign', () => {
|
|
102
|
+
const keys = (0, wizard_tools_1.parseEnvKeys)('not a key value pair\nFOO=bar\n');
|
|
103
|
+
expect(keys).toEqual(new Set(['FOO']));
|
|
104
|
+
});
|
|
105
|
+
it('parses keys with quoted values', () => {
|
|
106
|
+
const keys = (0, wizard_tools_1.parseEnvKeys)('FOO="bar baz"\nBAR=\'single\'\n');
|
|
107
|
+
expect(keys).toEqual(new Set(['FOO', 'BAR']));
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// mergeEnvValues
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
describe('mergeEnvValues', () => {
|
|
114
|
+
it('appends new keys to empty content', () => {
|
|
115
|
+
const result = (0, wizard_tools_1.mergeEnvValues)('', { FOO: 'bar' });
|
|
116
|
+
expect(result).toBe('FOO=bar\n');
|
|
117
|
+
});
|
|
118
|
+
it('appends new keys to existing content', () => {
|
|
119
|
+
const result = (0, wizard_tools_1.mergeEnvValues)('EXISTING=val\n', { NEW: 'added' });
|
|
120
|
+
expect(result).toBe('EXISTING=val\nNEW=added\n');
|
|
121
|
+
});
|
|
122
|
+
it('updates existing keys in-place', () => {
|
|
123
|
+
const result = (0, wizard_tools_1.mergeEnvValues)('FOO=old\nBAR=keep\n', { FOO: 'new' });
|
|
124
|
+
expect(result).toBe('FOO=new\nBAR=keep\n');
|
|
125
|
+
});
|
|
126
|
+
it('handles mixed update and append', () => {
|
|
127
|
+
const result = (0, wizard_tools_1.mergeEnvValues)('FOO=old\n', {
|
|
128
|
+
FOO: 'updated',
|
|
129
|
+
BAR: 'new',
|
|
130
|
+
});
|
|
131
|
+
expect(result).toBe('FOO=updated\nBAR=new\n');
|
|
132
|
+
});
|
|
133
|
+
it('adds newline before appending if content lacks trailing newline', () => {
|
|
134
|
+
const result = (0, wizard_tools_1.mergeEnvValues)('FOO=bar', { BAZ: 'qux' });
|
|
135
|
+
expect(result).toBe('FOO=bar\nBAZ=qux\n');
|
|
136
|
+
});
|
|
137
|
+
it('handles multiple new keys', () => {
|
|
138
|
+
const result = (0, wizard_tools_1.mergeEnvValues)('', { A: '1', B: '2', C: '3' });
|
|
139
|
+
expect(result).toContain('A=1\n');
|
|
140
|
+
expect(result).toContain('B=2\n');
|
|
141
|
+
expect(result).toContain('C=3\n');
|
|
142
|
+
});
|
|
143
|
+
it('handles values containing = signs', () => {
|
|
144
|
+
const result = (0, wizard_tools_1.mergeEnvValues)('', {
|
|
145
|
+
DB_URL: 'postgres://host:5432/db?opt=1',
|
|
146
|
+
});
|
|
147
|
+
expect(result).toBe('DB_URL=postgres://host:5432/db?opt=1\n');
|
|
148
|
+
});
|
|
149
|
+
it('updates a value containing = signs', () => {
|
|
150
|
+
const result = (0, wizard_tools_1.mergeEnvValues)('DB_URL=old://host\n', {
|
|
151
|
+
DB_URL: 'postgres://new:5432/db?opt=1',
|
|
152
|
+
});
|
|
153
|
+
expect(result).toBe('DB_URL=postgres://new:5432/db?opt=1\n');
|
|
154
|
+
});
|
|
155
|
+
it('updates a key whose old value contains the key name', () => {
|
|
156
|
+
const result = (0, wizard_tools_1.mergeEnvValues)('FOO=FOO_old_value\n', { FOO: 'new' });
|
|
157
|
+
expect(result).toBe('FOO=new\n');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
// ensureGitignoreCoverage
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
describe('ensureGitignoreCoverage', () => {
|
|
164
|
+
let tmpDir;
|
|
165
|
+
beforeEach(() => {
|
|
166
|
+
tmpDir = makeTmpDir();
|
|
167
|
+
});
|
|
168
|
+
afterEach(() => cleanup(tmpDir));
|
|
169
|
+
it('creates .gitignore if it does not exist', () => {
|
|
170
|
+
(0, wizard_tools_1.ensureGitignoreCoverage)(tmpDir, '.env.local');
|
|
171
|
+
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');
|
|
172
|
+
expect(content).toBe('.env.local\n');
|
|
173
|
+
});
|
|
174
|
+
it('appends entry to existing .gitignore', () => {
|
|
175
|
+
fs.writeFileSync(path.join(tmpDir, '.gitignore'), 'node_modules\n');
|
|
176
|
+
(0, wizard_tools_1.ensureGitignoreCoverage)(tmpDir, '.env.local');
|
|
177
|
+
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');
|
|
178
|
+
expect(content).toBe('node_modules\n.env.local\n');
|
|
179
|
+
});
|
|
180
|
+
it('appends with newline if .gitignore lacks trailing newline', () => {
|
|
181
|
+
fs.writeFileSync(path.join(tmpDir, '.gitignore'), 'node_modules');
|
|
182
|
+
(0, wizard_tools_1.ensureGitignoreCoverage)(tmpDir, '.env');
|
|
183
|
+
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');
|
|
184
|
+
expect(content).toBe('node_modules\n.env\n');
|
|
185
|
+
});
|
|
186
|
+
it('does not duplicate an existing entry', () => {
|
|
187
|
+
fs.writeFileSync(path.join(tmpDir, '.gitignore'), '.env.local\n');
|
|
188
|
+
(0, wizard_tools_1.ensureGitignoreCoverage)(tmpDir, '.env.local');
|
|
189
|
+
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');
|
|
190
|
+
expect(content).toBe('.env.local\n');
|
|
191
|
+
});
|
|
192
|
+
it('handles entry with surrounding whitespace in .gitignore', () => {
|
|
193
|
+
fs.writeFileSync(path.join(tmpDir, '.gitignore'), ' .env.local \n');
|
|
194
|
+
(0, wizard_tools_1.ensureGitignoreCoverage)(tmpDir, '.env.local');
|
|
195
|
+
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');
|
|
196
|
+
// Should not duplicate — the trim check should match
|
|
197
|
+
expect(content).toBe(' .env.local \n');
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
//# sourceMappingURL=wizard-tools.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard-tools.test.js","sourceRoot":"","sources":["../../../../src/lib/__tests__/wizard-tools.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 {\n resolveEnvPath,\n ensureGitignoreCoverage,\n parseEnvKeys,\n mergeEnvValues,\n} from '../wizard-tools';\n\nfunction makeTmpDir(): string {\n return fs.mkdtempSync(path.join(os.tmpdir(), 'wizard-tools-'));\n}\n\nfunction cleanup(dir: string): void {\n fs.rmSync(dir, { recursive: true, force: true });\n}\n\n// ---------------------------------------------------------------------------\n// resolveEnvPath\n// ---------------------------------------------------------------------------\n\ndescribe('resolveEnvPath', () => {\n it('resolves a relative path within the working directory', () => {\n const result = resolveEnvPath('/project', '.env.local');\n expect(result).toBe(path.resolve('/project', '.env.local'));\n });\n\n it('resolves nested paths', () => {\n const result = resolveEnvPath('/project', 'config/.env');\n expect(result).toBe(path.resolve('/project', 'config/.env'));\n });\n\n it('rejects path traversal with ../', () => {\n expect(() => resolveEnvPath('/project', '../etc/passwd')).toThrow(\n 'Path traversal rejected',\n );\n });\n\n it('rejects absolute paths outside working directory', () => {\n expect(() => resolveEnvPath('/project', '/etc/passwd')).toThrow(\n 'Path traversal rejected',\n );\n });\n\n it('allows the working directory itself', () => {\n // edge case: filePath resolves to exactly workingDirectory\n expect(() => resolveEnvPath('/project', '.')).not.toThrow();\n });\n});\n\n// ---------------------------------------------------------------------------\n// parseEnvKeys\n// ---------------------------------------------------------------------------\n\ndescribe('parseEnvKeys', () => {\n it('parses simple KEY=value lines', () => {\n const keys = parseEnvKeys('FOO=bar\\nBAZ=qux\\n');\n expect(keys).toEqual(new Set(['FOO', 'BAZ']));\n });\n\n it('ignores comments', () => {\n const keys = parseEnvKeys('# COMMENT=ignored\\nFOO=bar\\n');\n expect(keys).toEqual(new Set(['FOO']));\n });\n\n it('ignores blank lines', () => {\n const keys = parseEnvKeys('\\n\\nFOO=bar\\n\\n');\n expect(keys).toEqual(new Set(['FOO']));\n });\n\n it('handles keys with leading whitespace', () => {\n const keys = parseEnvKeys(' FOO=bar\\n');\n expect(keys).toEqual(new Set(['FOO']));\n });\n\n it('handles keys with spaces around =', () => {\n const keys = parseEnvKeys('FOO =bar\\n');\n expect(keys).toEqual(new Set(['FOO']));\n });\n\n it('handles keys with underscores and numbers', () => {\n const keys = parseEnvKeys('MY_KEY_2=value\\n');\n expect(keys).toEqual(new Set(['MY_KEY_2']));\n });\n\n it('returns empty set for empty content', () => {\n const keys = parseEnvKeys('');\n expect(keys).toEqual(new Set());\n });\n\n it('ignores lines without = sign', () => {\n const keys = parseEnvKeys('not a key value pair\\nFOO=bar\\n');\n expect(keys).toEqual(new Set(['FOO']));\n });\n\n it('parses keys with quoted values', () => {\n const keys = parseEnvKeys('FOO=\"bar baz\"\\nBAR=\\'single\\'\\n');\n expect(keys).toEqual(new Set(['FOO', 'BAR']));\n });\n});\n\n// ---------------------------------------------------------------------------\n// mergeEnvValues\n// ---------------------------------------------------------------------------\n\ndescribe('mergeEnvValues', () => {\n it('appends new keys to empty content', () => {\n const result = mergeEnvValues('', { FOO: 'bar' });\n expect(result).toBe('FOO=bar\\n');\n });\n\n it('appends new keys to existing content', () => {\n const result = mergeEnvValues('EXISTING=val\\n', { NEW: 'added' });\n expect(result).toBe('EXISTING=val\\nNEW=added\\n');\n });\n\n it('updates existing keys in-place', () => {\n const result = mergeEnvValues('FOO=old\\nBAR=keep\\n', { FOO: 'new' });\n expect(result).toBe('FOO=new\\nBAR=keep\\n');\n });\n\n it('handles mixed update and append', () => {\n const result = mergeEnvValues('FOO=old\\n', {\n FOO: 'updated',\n BAR: 'new',\n });\n expect(result).toBe('FOO=updated\\nBAR=new\\n');\n });\n\n it('adds newline before appending if content lacks trailing newline', () => {\n const result = mergeEnvValues('FOO=bar', { BAZ: 'qux' });\n expect(result).toBe('FOO=bar\\nBAZ=qux\\n');\n });\n\n it('handles multiple new keys', () => {\n const result = mergeEnvValues('', { A: '1', B: '2', C: '3' });\n expect(result).toContain('A=1\\n');\n expect(result).toContain('B=2\\n');\n expect(result).toContain('C=3\\n');\n });\n\n it('handles values containing = signs', () => {\n const result = mergeEnvValues('', {\n DB_URL: 'postgres://host:5432/db?opt=1',\n });\n expect(result).toBe('DB_URL=postgres://host:5432/db?opt=1\\n');\n });\n\n it('updates a value containing = signs', () => {\n const result = mergeEnvValues('DB_URL=old://host\\n', {\n DB_URL: 'postgres://new:5432/db?opt=1',\n });\n expect(result).toBe('DB_URL=postgres://new:5432/db?opt=1\\n');\n });\n\n it('updates a key whose old value contains the key name', () => {\n const result = mergeEnvValues('FOO=FOO_old_value\\n', { FOO: 'new' });\n expect(result).toBe('FOO=new\\n');\n });\n});\n\n// ---------------------------------------------------------------------------\n// ensureGitignoreCoverage\n// ---------------------------------------------------------------------------\n\ndescribe('ensureGitignoreCoverage', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n });\n afterEach(() => cleanup(tmpDir));\n\n it('creates .gitignore if it does not exist', () => {\n ensureGitignoreCoverage(tmpDir, '.env.local');\n const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');\n expect(content).toBe('.env.local\\n');\n });\n\n it('appends entry to existing .gitignore', () => {\n fs.writeFileSync(path.join(tmpDir, '.gitignore'), 'node_modules\\n');\n ensureGitignoreCoverage(tmpDir, '.env.local');\n const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');\n expect(content).toBe('node_modules\\n.env.local\\n');\n });\n\n it('appends with newline if .gitignore lacks trailing newline', () => {\n fs.writeFileSync(path.join(tmpDir, '.gitignore'), 'node_modules');\n ensureGitignoreCoverage(tmpDir, '.env');\n const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');\n expect(content).toBe('node_modules\\n.env\\n');\n });\n\n it('does not duplicate an existing entry', () => {\n fs.writeFileSync(path.join(tmpDir, '.gitignore'), '.env.local\\n');\n ensureGitignoreCoverage(tmpDir, '.env.local');\n const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');\n expect(content).toBe('.env.local\\n');\n });\n\n it('handles entry with surrounding whitespace in .gitignore', () => {\n fs.writeFileSync(path.join(tmpDir, '.gitignore'), ' .env.local \\n');\n ensureGitignoreCoverage(tmpDir, '.env.local');\n const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf8');\n // Should not duplicate — the trim check should match\n expect(content).toBe(' .env.local \\n');\n });\n});\n"]}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import clack from '../utils/clack';
|
|
6
6
|
import type { WizardOptions } from '../utils/types';
|
|
7
|
+
import type { PackageManagerDetector } from './package-manager-detection';
|
|
7
8
|
type McpServersConfig = any;
|
|
8
9
|
export declare const AgentSignals: {
|
|
9
10
|
/** Signal emitted when the agent reports progress to the user */
|
|
@@ -38,6 +39,7 @@ export type AgentConfig = {
|
|
|
38
39
|
additionalMcpServers?: Record<string, {
|
|
39
40
|
url: string;
|
|
40
41
|
}>;
|
|
42
|
+
detectPackageManager: PackageManagerDetector;
|
|
41
43
|
};
|
|
42
44
|
/**
|
|
43
45
|
* Internal configuration object returned by initializeAgent
|
|
@@ -18,7 +18,7 @@ const analytics_1 = require("../utils/analytics");
|
|
|
18
18
|
const constants_1 = require("./constants");
|
|
19
19
|
const urls_1 = require("../utils/urls");
|
|
20
20
|
const safe_tools_1 = require("./safe-tools");
|
|
21
|
-
const
|
|
21
|
+
const wizard_tools_1 = require("./wizard-tools");
|
|
22
22
|
// Dynamic import cache for ESM module
|
|
23
23
|
let _sdkModule = null;
|
|
24
24
|
async function getSDKModule() {
|
|
@@ -151,7 +151,7 @@ function matchesAllowedPrefix(command) {
|
|
|
151
151
|
* - PostHog skill installation commands from MCP
|
|
152
152
|
*/
|
|
153
153
|
function wizardCanUseTool(toolName, input) {
|
|
154
|
-
// Block direct reads/writes of .env files — use
|
|
154
|
+
// Block direct reads/writes of .env files — use wizard-tools MCP instead
|
|
155
155
|
if (toolName === 'Read' || toolName === 'Write' || toolName === 'Edit') {
|
|
156
156
|
const filePath = typeof input.file_path === 'string' ? input.file_path : '';
|
|
157
157
|
const basename = path_1.default.basename(filePath);
|
|
@@ -159,7 +159,7 @@ function wizardCanUseTool(toolName, input) {
|
|
|
159
159
|
(0, debug_1.logToFile)(`Denying ${toolName} on env file: ${filePath}`);
|
|
160
160
|
return {
|
|
161
161
|
behavior: 'deny',
|
|
162
|
-
message: `Direct ${toolName} of ${basename} is not allowed. Use the
|
|
162
|
+
message: `Direct ${toolName} of ${basename} is not allowed. Use the wizard-tools MCP server (check_env_keys / set_env_values) to read or modify environment variables.`,
|
|
163
163
|
};
|
|
164
164
|
}
|
|
165
165
|
return { behavior: 'allow', updatedInput: input };
|
|
@@ -173,7 +173,7 @@ function wizardCanUseTool(toolName, input) {
|
|
|
173
173
|
(0, debug_1.logToFile)(`Denying Grep on env file: ${grepPath}`);
|
|
174
174
|
return {
|
|
175
175
|
behavior: 'deny',
|
|
176
|
-
message: `Grep on ${path_1.default.basename(grepPath)} is not allowed. Use the
|
|
176
|
+
message: `Grep on ${path_1.default.basename(grepPath)} is not allowed. Use the wizard-tools MCP server (check_env_keys) to check environment variables.`,
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
179
|
return { behavior: 'allow', updatedInput: input };
|
|
@@ -292,13 +292,16 @@ async function initializeAgent(config, options) {
|
|
|
292
292
|
},
|
|
293
293
|
...Object.fromEntries(Object.entries(config.additionalMcpServers ?? {}).map(([name, { url }]) => [name, { type: 'http', url }])),
|
|
294
294
|
};
|
|
295
|
-
// Add in-process
|
|
296
|
-
const
|
|
297
|
-
|
|
295
|
+
// Add in-process wizard tools (env files, package manager detection)
|
|
296
|
+
const wizardToolsServer = await (0, wizard_tools_1.createWizardToolsServer)({
|
|
297
|
+
workingDirectory: config.workingDirectory,
|
|
298
|
+
detectPackageManager: config.detectPackageManager,
|
|
299
|
+
});
|
|
300
|
+
mcpServers['wizard-tools'] = wizardToolsServer;
|
|
298
301
|
const agentRunConfig = {
|
|
299
302
|
workingDirectory: config.workingDirectory,
|
|
300
303
|
mcpServers,
|
|
301
|
-
model: 'claude-
|
|
304
|
+
model: 'anthropic/claude-sonnet-4-6',
|
|
302
305
|
};
|
|
303
306
|
(0, debug_1.logToFile)('Agent config:', {
|
|
304
307
|
workingDirectory: agentRunConfig.workingDirectory,
|
|
@@ -408,7 +411,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config) {
|
|
|
408
411
|
'Bash',
|
|
409
412
|
'ListMcpResourcesTool',
|
|
410
413
|
'Skill',
|
|
411
|
-
...
|
|
414
|
+
...wizard_tools_1.WIZARD_TOOL_NAMES,
|
|
412
415
|
];
|
|
413
416
|
const response = query({
|
|
414
417
|
prompt: createPromptStream(),
|