@pennyfarthing/core 9.4.0 → 10.0.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/cli/commands/cyclist.d.ts +1 -1
- package/dist/cli/commands/cyclist.d.ts.map +1 -1
- package/dist/cli/commands/cyclist.js +15 -25
- package/dist/cli/commands/cyclist.js.map +1 -1
- package/dist/cli/commands/cyclist.test.js +12 -8
- package/dist/cli/commands/cyclist.test.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +149 -15
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/e2e-fresh-install.test.d.ts +19 -0
- package/dist/cli/commands/e2e-fresh-install.test.d.ts.map +1 -0
- package/dist/cli/commands/e2e-fresh-install.test.js +395 -0
- package/dist/cli/commands/e2e-fresh-install.test.js.map +1 -0
- package/dist/cli/commands/e2e-upgrade.test.d.ts +22 -0
- package/dist/cli/commands/e2e-upgrade.test.d.ts.map +1 -0
- package/dist/cli/commands/e2e-upgrade.test.js +562 -0
- package/dist/cli/commands/e2e-upgrade.test.js.map +1 -0
- package/dist/cli/commands/init-consolidation.test.d.ts +17 -0
- package/dist/cli/commands/init-consolidation.test.d.ts.map +1 -0
- package/dist/cli/commands/init-consolidation.test.js +217 -0
- package/dist/cli/commands/init-consolidation.test.js.map +1 -0
- package/dist/cli/commands/init.js +18 -15
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/persona-config-consolidation.test.d.ts +18 -0
- package/dist/cli/commands/persona-config-consolidation.test.d.ts.map +1 -0
- package/dist/cli/commands/persona-config-consolidation.test.js +230 -0
- package/dist/cli/commands/persona-config-consolidation.test.js.map +1 -0
- package/dist/cli/commands/theme.js +2 -2
- package/dist/cli/commands/theme.js.map +1 -1
- package/dist/cli/commands/uninstall.d.ts.map +1 -1
- package/dist/cli/commands/uninstall.js +2 -1
- package/dist/cli/commands/uninstall.js.map +1 -1
- package/dist/cli/commands/update-consolidation.test.d.ts +19 -0
- package/dist/cli/commands/update-consolidation.test.d.ts.map +1 -0
- package/dist/cli/commands/update-consolidation.test.js +572 -0
- package/dist/cli/commands/update-consolidation.test.js.map +1 -0
- package/dist/cli/commands/update.d.ts +25 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +128 -11
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/utils/manifest.d.ts +3 -3
- package/dist/cli/utils/manifest.d.ts.map +1 -1
- package/dist/cli/utils/manifest.js +21 -12
- package/dist/cli/utils/manifest.js.map +1 -1
- package/dist/cli/utils/settings-consolidation.test.d.ts +13 -0
- package/dist/cli/utils/settings-consolidation.test.d.ts.map +1 -0
- package/dist/cli/utils/settings-consolidation.test.js +227 -0
- package/dist/cli/utils/settings-consolidation.test.js.map +1 -0
- package/dist/cli/utils/settings.d.ts +11 -0
- package/dist/cli/utils/settings.d.ts.map +1 -1
- package/dist/cli/utils/settings.js +59 -6
- package/dist/cli/utils/settings.js.map +1 -1
- package/dist/cli/utils/themes.d.ts +3 -3
- package/dist/cli/utils/themes.d.ts.map +1 -1
- package/dist/cli/utils/themes.js +14 -12
- package/dist/cli/utils/themes.js.map +1 -1
- package/dist/cli/utils/themes.test.d.ts +2 -2
- package/dist/cli/utils/themes.test.js +29 -13
- package/dist/cli/utils/themes.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E test for MSSCI-14373: Fresh repo install
|
|
3
|
+
*
|
|
4
|
+
* This test runs `pennyfarthing init --force` in a fresh temp directory
|
|
5
|
+
* with a simulated node_modules tree (symlinked to the real pennyfarthing-dist),
|
|
6
|
+
* then validates the complete installation using `pennyfarthing doctor --json`.
|
|
7
|
+
*
|
|
8
|
+
* Acceptance Criteria:
|
|
9
|
+
* AC1: Test creates a fresh empty git repo in a temp directory
|
|
10
|
+
* AC2: Runs `pennyfarthing init` in that repo
|
|
11
|
+
* AC3: Validates the installation with `pennyfarthing doctor` (should pass)
|
|
12
|
+
* AC4: Exercises the just scripts: dev, test, build
|
|
13
|
+
* AC5: Iteratively adjusts and restarts if scripts fail
|
|
14
|
+
* AC6: Cleans up the temp repo afterward
|
|
15
|
+
*
|
|
16
|
+
* Run with: cd packages/core && npm run build && npm test
|
|
17
|
+
*/
|
|
18
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
19
|
+
import assert from 'node:assert';
|
|
20
|
+
import { existsSync, mkdirSync, rmSync, readFileSync, lstatSync, readdirSync, statSync, symlinkSync, writeFileSync, } from 'fs';
|
|
21
|
+
import { join, resolve, dirname } from 'path';
|
|
22
|
+
import { tmpdir } from 'os';
|
|
23
|
+
import { execSync, spawnSync } from 'child_process';
|
|
24
|
+
import { fileURLToPath } from 'url';
|
|
25
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
26
|
+
const __dirname = dirname(__filename);
|
|
27
|
+
// Path to the CLI binary (compiled JS)
|
|
28
|
+
const CLI_BIN = resolve(__dirname, '../../../bin/pennyfarthing.js');
|
|
29
|
+
// Path to the real pennyfarthing-dist (for creating fake node_modules)
|
|
30
|
+
// From dist/cli/commands/ → packages/core/dist/cli/commands/ → 5 levels up to repo root
|
|
31
|
+
const REAL_PENNYFARTHING_DIST = resolve(__dirname, '../../../../../pennyfarthing-dist');
|
|
32
|
+
// ─── Helpers ───────────────────────────────────────────────────────
|
|
33
|
+
function createTestDir() {
|
|
34
|
+
const dir = join(tmpdir(), `pf-e2e-fresh-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
35
|
+
mkdirSync(dir, { recursive: true });
|
|
36
|
+
return dir;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Create a fake node_modules tree that symlinks to the real pennyfarthing-dist.
|
|
40
|
+
* This simulates what `npm install pennyfarthing` would produce.
|
|
41
|
+
*/
|
|
42
|
+
function setupNodeModules(testDir) {
|
|
43
|
+
const targetDir = join(testDir, 'node_modules/@pennyfarthing/core');
|
|
44
|
+
mkdirSync(targetDir, { recursive: true });
|
|
45
|
+
// Symlink to the real pennyfarthing-dist so init can find templates, commands, etc.
|
|
46
|
+
symlinkSync(REAL_PENNYFARTHING_DIST, join(targetDir, 'pennyfarthing-dist'));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Initialize a git repo in the test directory so hooks can be installed.
|
|
50
|
+
*/
|
|
51
|
+
function initGitRepo(testDir) {
|
|
52
|
+
execSync('git init', { cwd: testDir, stdio: 'pipe' });
|
|
53
|
+
// Create an initial commit so git is fully initialized
|
|
54
|
+
writeFileSync(join(testDir, '.gitkeep'), '');
|
|
55
|
+
execSync('git add .gitkeep && git commit -m "init"', {
|
|
56
|
+
cwd: testDir,
|
|
57
|
+
stdio: 'pipe',
|
|
58
|
+
env: {
|
|
59
|
+
...process.env,
|
|
60
|
+
GIT_AUTHOR_NAME: 'Test',
|
|
61
|
+
GIT_AUTHOR_EMAIL: 'test@test.com',
|
|
62
|
+
GIT_COMMITTER_NAME: 'Test',
|
|
63
|
+
GIT_COMMITTER_EMAIL: 'test@test.com',
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Run the pennyfarthing CLI in the test directory.
|
|
69
|
+
*/
|
|
70
|
+
function runCLI(testDir, args) {
|
|
71
|
+
const result = spawnSync('node', [CLI_BIN, ...args], {
|
|
72
|
+
cwd: testDir,
|
|
73
|
+
stdio: 'pipe',
|
|
74
|
+
timeout: 30000,
|
|
75
|
+
env: {
|
|
76
|
+
...process.env,
|
|
77
|
+
// Ensure we don't pick up the real project's node_modules
|
|
78
|
+
NODE_PATH: '',
|
|
79
|
+
// Disable chalk/ANSI colors so --json output is parseable
|
|
80
|
+
FORCE_COLOR: '0',
|
|
81
|
+
NO_COLOR: '1',
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
stdout: result.stdout?.toString() || '',
|
|
86
|
+
stderr: result.stderr?.toString() || '',
|
|
87
|
+
status: result.status,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Extract JSON array from doctor --json output.
|
|
92
|
+
* Doctor outputs header text (Pennyfarthing Health Check, etc.) before the JSON
|
|
93
|
+
* when --json is used. We need to extract just the JSON array.
|
|
94
|
+
*/
|
|
95
|
+
function extractDoctorJson(stdout) {
|
|
96
|
+
// Find the first '[' which starts the JSON array
|
|
97
|
+
const jsonStart = stdout.indexOf('[');
|
|
98
|
+
if (jsonStart === -1) {
|
|
99
|
+
throw new Error(`No JSON array found in doctor output: ${stdout.slice(0, 200)}`);
|
|
100
|
+
}
|
|
101
|
+
return JSON.parse(stdout.slice(jsonStart));
|
|
102
|
+
}
|
|
103
|
+
// ─── Constants for verification ───────────────────────────────────
|
|
104
|
+
const CORE_AGENTS = [
|
|
105
|
+
'dev', 'tea', 'sm', 'reviewer', 'architect',
|
|
106
|
+
'pm', 'tech-writer', 'ux-designer', 'devops', 'orchestrator'
|
|
107
|
+
];
|
|
108
|
+
const DIRECTORY_SYMLINKS = [
|
|
109
|
+
{ name: 'agents', link: '.pennyfarthing/agents' },
|
|
110
|
+
{ name: 'guides', link: '.pennyfarthing/guides' },
|
|
111
|
+
{ name: 'output-styles', link: '.pennyfarthing/output-styles' },
|
|
112
|
+
{ name: 'personas', link: '.pennyfarthing/personas' },
|
|
113
|
+
{ name: 'scripts', link: '.pennyfarthing/scripts' },
|
|
114
|
+
{ name: 'workflows', link: '.pennyfarthing/workflows' },
|
|
115
|
+
];
|
|
116
|
+
// ─── Test Suites ──────────────────────────────────────────────────
|
|
117
|
+
describe('MSSCI-14373: E2E fresh repo install', () => {
|
|
118
|
+
let testDir;
|
|
119
|
+
beforeEach(() => {
|
|
120
|
+
testDir = createTestDir();
|
|
121
|
+
setupNodeModules(testDir);
|
|
122
|
+
initGitRepo(testDir);
|
|
123
|
+
});
|
|
124
|
+
afterEach(() => {
|
|
125
|
+
// AC6: Cleans up the temp repo afterward
|
|
126
|
+
if (existsSync(testDir)) {
|
|
127
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
// ─── AC1: Create fresh git repo ────────────────────────────────
|
|
131
|
+
describe('AC1: Test creates a fresh empty git repo in a temp directory', () => {
|
|
132
|
+
it('should have a valid git repo in the test directory', () => {
|
|
133
|
+
assert.ok(existsSync(join(testDir, '.git')), 'Test dir should be a git repo');
|
|
134
|
+
});
|
|
135
|
+
it('should have node_modules with pennyfarthing symlink', () => {
|
|
136
|
+
const distPath = join(testDir, 'node_modules/@pennyfarthing/core/pennyfarthing-dist');
|
|
137
|
+
assert.ok(existsSync(distPath), 'Fake node_modules should contain pennyfarthing-dist');
|
|
138
|
+
assert.ok(lstatSync(distPath).isSymbolicLink(), 'pennyfarthing-dist should be a symlink');
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
// ─── AC2: Run pennyfarthing init ───────────────────────────────
|
|
142
|
+
describe('AC2: Runs pennyfarthing init in that repo', () => {
|
|
143
|
+
it('should complete init --force without error', () => {
|
|
144
|
+
const result = runCLI(testDir, ['init', '--force']);
|
|
145
|
+
assert.strictEqual(result.status, 0, `Init should exit 0, got ${result.status}.\nStdout: ${result.stdout}\nStderr: ${result.stderr}`);
|
|
146
|
+
});
|
|
147
|
+
it('should create all required directories', () => {
|
|
148
|
+
runCLI(testDir, ['init', '--force']);
|
|
149
|
+
const expectedDirs = [
|
|
150
|
+
'.claude',
|
|
151
|
+
'.pennyfarthing',
|
|
152
|
+
'.pennyfarthing/project/commands',
|
|
153
|
+
'.pennyfarthing/project/skills',
|
|
154
|
+
'.pennyfarthing/project/docs',
|
|
155
|
+
'.pennyfarthing/project/hooks',
|
|
156
|
+
'sprint',
|
|
157
|
+
'.pennyfarthing/sidecars',
|
|
158
|
+
'.session',
|
|
159
|
+
];
|
|
160
|
+
for (const dir of expectedDirs) {
|
|
161
|
+
assert.ok(existsSync(join(testDir, dir)), `Directory ${dir} should exist after init`);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
it('should create .pennyfarthing/ symlinks to node_modules', () => {
|
|
165
|
+
runCLI(testDir, ['init', '--force']);
|
|
166
|
+
for (const { name, link } of DIRECTORY_SYMLINKS) {
|
|
167
|
+
const linkPath = join(testDir, link);
|
|
168
|
+
assert.ok(existsSync(linkPath), `Symlink ${link} should exist`);
|
|
169
|
+
assert.ok(lstatSync(linkPath).isSymbolicLink(), `${link} should be a symlink (not a copy)`);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
it('should copy commands as real directory (not symlink)', () => {
|
|
173
|
+
runCLI(testDir, ['init', '--force']);
|
|
174
|
+
const commandsDir = join(testDir, '.claude/commands');
|
|
175
|
+
assert.ok(existsSync(commandsDir), '.claude/commands should exist');
|
|
176
|
+
assert.ok(!lstatSync(commandsDir).isSymbolicLink(), '.claude/commands should be a real directory (not a symlink)');
|
|
177
|
+
// Should have at least some command files
|
|
178
|
+
const files = readdirSync(commandsDir);
|
|
179
|
+
assert.ok(files.length > 0, '.claude/commands should contain files');
|
|
180
|
+
assert.ok(files.some(f => f.endsWith('.md')), '.claude/commands should contain .md files');
|
|
181
|
+
});
|
|
182
|
+
it('should copy skills as real directory (not symlink)', () => {
|
|
183
|
+
runCLI(testDir, ['init', '--force']);
|
|
184
|
+
const skillsDir = join(testDir, '.claude/skills');
|
|
185
|
+
assert.ok(existsSync(skillsDir), '.claude/skills should exist');
|
|
186
|
+
assert.ok(!lstatSync(skillsDir).isSymbolicLink(), '.claude/skills should be a real directory (not a symlink)');
|
|
187
|
+
// Should have at least one skill subdirectory
|
|
188
|
+
const entries = readdirSync(skillsDir);
|
|
189
|
+
assert.ok(entries.length > 0, '.claude/skills should contain skill directories');
|
|
190
|
+
});
|
|
191
|
+
it('should create agent sidecars for all 10 core agents', () => {
|
|
192
|
+
runCLI(testDir, ['init', '--force']);
|
|
193
|
+
const sidecarFiles = ['patterns.md', 'gotchas.md', 'decisions.md'];
|
|
194
|
+
for (const agent of CORE_AGENTS) {
|
|
195
|
+
const sidecarDir = join(testDir, `.pennyfarthing/sidecars/${agent}`);
|
|
196
|
+
assert.ok(existsSync(sidecarDir), `Sidecar dir for ${agent} should exist`);
|
|
197
|
+
for (const file of sidecarFiles) {
|
|
198
|
+
assert.ok(existsSync(join(sidecarDir, file)), `Sidecar ${file} for ${agent} should exist`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
it('should install git hooks', () => {
|
|
203
|
+
runCLI(testDir, ['init', '--force']);
|
|
204
|
+
const hooks = ['pre-commit', 'pre-push', 'post-merge'];
|
|
205
|
+
for (const hook of hooks) {
|
|
206
|
+
const hookPath = join(testDir, '.git/hooks', hook);
|
|
207
|
+
assert.ok(existsSync(hookPath), `Git hook ${hook} should be installed`);
|
|
208
|
+
// Check executable
|
|
209
|
+
const stats = statSync(hookPath);
|
|
210
|
+
const isExecutable = (stats.mode & 0o111) !== 0;
|
|
211
|
+
assert.ok(isExecutable, `Git hook ${hook} should be executable`);
|
|
212
|
+
// Check it's a pennyfarthing hook
|
|
213
|
+
const content = readFileSync(hookPath, 'utf8');
|
|
214
|
+
assert.ok(content.includes('pennyfarthing'), `Git hook ${hook} should contain pennyfarthing marker`);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
it('should generate template files under .pennyfarthing/', () => {
|
|
218
|
+
runCLI(testDir, ['init', '--force']);
|
|
219
|
+
const expectedTemplateFiles = [
|
|
220
|
+
'.pennyfarthing/persona-config.yaml',
|
|
221
|
+
'.pennyfarthing/preferences.yaml',
|
|
222
|
+
'.pennyfarthing/project/docs/agent-scopes.yaml',
|
|
223
|
+
'.pennyfarthing/project/pennyfarthing-settings.yaml',
|
|
224
|
+
'.pennyfarthing/project/hooks/setup-env.sh',
|
|
225
|
+
];
|
|
226
|
+
for (const file of expectedTemplateFiles) {
|
|
227
|
+
assert.ok(existsSync(join(testDir, file)), `Template file ${file} should exist after init`);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
it('should generate shared-context.md at .claude/project/docs/', () => {
|
|
231
|
+
runCLI(testDir, ['init', '--force']);
|
|
232
|
+
assert.ok(existsSync(join(testDir, '.claude/project/docs/shared-context.md')), 'shared-context.md should be at .claude/project/docs/ (user-owned file)');
|
|
233
|
+
});
|
|
234
|
+
it('should make setup-env.sh executable', () => {
|
|
235
|
+
runCLI(testDir, ['init', '--force']);
|
|
236
|
+
const setupEnvPath = join(testDir, '.pennyfarthing/project/hooks/setup-env.sh');
|
|
237
|
+
assert.ok(existsSync(setupEnvPath), 'setup-env.sh should exist');
|
|
238
|
+
const stats = statSync(setupEnvPath);
|
|
239
|
+
const isExecutable = (stats.mode & 0o111) !== 0;
|
|
240
|
+
assert.ok(isExecutable, 'setup-env.sh should be executable');
|
|
241
|
+
});
|
|
242
|
+
it('should write manifest at .pennyfarthing/manifest.json', () => {
|
|
243
|
+
runCLI(testDir, ['init', '--force']);
|
|
244
|
+
const manifestPath = join(testDir, '.pennyfarthing/manifest.json');
|
|
245
|
+
assert.ok(existsSync(manifestPath), 'Manifest should exist at .pennyfarthing/');
|
|
246
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
247
|
+
assert.strictEqual(manifest.installationType, 'symlink', 'Install type should be symlink');
|
|
248
|
+
assert.ok(manifest.version, 'Manifest should have a version');
|
|
249
|
+
assert.ok(manifest.projectName, 'Manifest should have a project name');
|
|
250
|
+
assert.ok(manifest.nodeModulesPath.includes('pennyfarthing-dist'), 'Manifest should reference node_modules path');
|
|
251
|
+
// managedPaths should include .pennyfarthing/* paths (not .claude/agents etc.)
|
|
252
|
+
assert.ok(manifest.managedPaths.includes('.claude/commands'), 'managedPaths should include .claude/commands');
|
|
253
|
+
assert.ok(manifest.managedPaths.includes('.claude/skills'), 'managedPaths should include .claude/skills');
|
|
254
|
+
assert.ok(manifest.managedPaths.some((p) => p.startsWith('.pennyfarthing/')), 'managedPaths should include .pennyfarthing/ paths');
|
|
255
|
+
assert.ok(!manifest.managedPaths.includes('.claude/agents'), 'managedPaths should NOT include legacy .claude/agents');
|
|
256
|
+
});
|
|
257
|
+
it('should NOT write manifest at .claude/manifest.json', () => {
|
|
258
|
+
runCLI(testDir, ['init', '--force']);
|
|
259
|
+
assert.ok(!existsSync(join(testDir, '.claude/manifest.json')), 'Manifest should NOT be at .claude/manifest.json (legacy location)');
|
|
260
|
+
});
|
|
261
|
+
it('should create settings.local.json with symlink', () => {
|
|
262
|
+
runCLI(testDir, ['init', '--force']);
|
|
263
|
+
const pennyfarthingSettings = join(testDir, '.pennyfarthing/settings.local.json');
|
|
264
|
+
const claudeSettings = join(testDir, '.claude/settings.local.json');
|
|
265
|
+
assert.ok(existsSync(pennyfarthingSettings), 'settings.local.json should exist at .pennyfarthing/');
|
|
266
|
+
assert.ok(existsSync(claudeSettings), '.claude/settings.local.json should exist');
|
|
267
|
+
assert.ok(lstatSync(claudeSettings).isSymbolicLink(), '.claude/settings.local.json should be a symlink to .pennyfarthing/');
|
|
268
|
+
// Verify settings content has required hooks
|
|
269
|
+
const settings = JSON.parse(readFileSync(pennyfarthingSettings, 'utf8'));
|
|
270
|
+
assert.ok(settings.hooks, 'Settings should have hooks');
|
|
271
|
+
assert.ok(settings.hooks.SessionStart, 'Settings should have SessionStart hooks');
|
|
272
|
+
assert.ok(settings.hooks.PostToolUse, 'Settings should have PostToolUse hooks');
|
|
273
|
+
assert.ok(settings.hooks.Stop, 'Settings should have Stop hooks');
|
|
274
|
+
assert.ok(settings.hooks.PreToolUse, 'Settings should have PreToolUse hooks');
|
|
275
|
+
});
|
|
276
|
+
it('should update .gitignore with pennyfarthing entries', () => {
|
|
277
|
+
runCLI(testDir, ['init', '--force']);
|
|
278
|
+
const gitignorePath = join(testDir, '.gitignore');
|
|
279
|
+
assert.ok(existsSync(gitignorePath), '.gitignore should exist');
|
|
280
|
+
const content = readFileSync(gitignorePath, 'utf8');
|
|
281
|
+
assert.ok(content.includes('# Pennyfarthing runtime'), '.gitignore should contain Pennyfarthing section');
|
|
282
|
+
assert.ok(content.includes('.session/*'), '.gitignore should exclude .session/');
|
|
283
|
+
assert.ok(content.includes('.claude/settings.local.json'), '.gitignore should exclude settings.local.json');
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
// ─── AC3: Validate with doctor ─────────────────────────────────
|
|
287
|
+
describe('AC3: Validates the installation with pennyfarthing doctor', () => {
|
|
288
|
+
it('should pass doctor check with no failures', () => {
|
|
289
|
+
// First run init
|
|
290
|
+
const initResult = runCLI(testDir, ['init', '--force']);
|
|
291
|
+
assert.strictEqual(initResult.status, 0, 'Init should succeed first');
|
|
292
|
+
// Then run doctor
|
|
293
|
+
const doctorResult = runCLI(testDir, ['doctor', '--json']);
|
|
294
|
+
assert.strictEqual(doctorResult.status, 0, `Doctor should exit 0 (no failures).\nStdout: ${doctorResult.stdout}\nStderr: ${doctorResult.stderr}`);
|
|
295
|
+
// Parse JSON output and verify no failures
|
|
296
|
+
const results = extractDoctorJson(doctorResult.stdout);
|
|
297
|
+
const failures = results.filter((r) => r.status === 'fail');
|
|
298
|
+
assert.strictEqual(failures.length, 0, `Doctor should have 0 failures, got ${failures.length}: ${JSON.stringify(failures, null, 2)}`);
|
|
299
|
+
});
|
|
300
|
+
it('doctor should show manifest as passing', () => {
|
|
301
|
+
runCLI(testDir, ['init', '--force']);
|
|
302
|
+
const doctorResult = runCLI(testDir, ['doctor', '--json']);
|
|
303
|
+
const results = extractDoctorJson(doctorResult.stdout);
|
|
304
|
+
const manifestCheck = results.find((r) => r.name === 'manifest/exists');
|
|
305
|
+
assert.ok(manifestCheck, 'Doctor should check manifest');
|
|
306
|
+
assert.strictEqual(manifestCheck.status, 'pass', 'Manifest check should pass');
|
|
307
|
+
});
|
|
308
|
+
it('doctor should show directory symlinks as passing', () => {
|
|
309
|
+
runCLI(testDir, ['init', '--force']);
|
|
310
|
+
const doctorResult = runCLI(testDir, ['doctor', '--json']);
|
|
311
|
+
const results = extractDoctorJson(doctorResult.stdout);
|
|
312
|
+
// Check the 6 directory symlinks (agents, guides, output-styles, personas, scripts, workflows)
|
|
313
|
+
// Note: commands and skills are intentionally copied (not symlinked),
|
|
314
|
+
// so doctor may warn about them — that's a separate doctor issue.
|
|
315
|
+
const directorySymlinkNames = ['agents', 'guides', 'output-styles', 'personas', 'scripts', 'workflows'];
|
|
316
|
+
for (const name of directorySymlinkNames) {
|
|
317
|
+
const check = results.find((r) => r.name === `symlink/${name}`);
|
|
318
|
+
assert.ok(check, `Doctor should check symlink/${name}`);
|
|
319
|
+
assert.strictEqual(check.status, 'pass', `Symlink check symlink/${name} should pass, got ${check.status}: ${check.detail}`);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
it('doctor should show settings.local.json as passing', () => {
|
|
323
|
+
runCLI(testDir, ['init', '--force']);
|
|
324
|
+
const doctorResult = runCLI(testDir, ['doctor', '--json']);
|
|
325
|
+
const results = extractDoctorJson(doctorResult.stdout);
|
|
326
|
+
const settingsCheck = results.find((r) => r.name === 'settings.local.json');
|
|
327
|
+
assert.ok(settingsCheck, 'Doctor should check settings.local.json');
|
|
328
|
+
assert.strictEqual(settingsCheck.status, 'pass', 'Settings check should pass');
|
|
329
|
+
});
|
|
330
|
+
it('doctor should show session-start hook as passing', () => {
|
|
331
|
+
runCLI(testDir, ['init', '--force']);
|
|
332
|
+
const doctorResult = runCLI(testDir, ['doctor', '--json']);
|
|
333
|
+
const results = extractDoctorJson(doctorResult.stdout);
|
|
334
|
+
const hookCheck = results.find((r) => r.name === 'settings/session-start-hook');
|
|
335
|
+
assert.ok(hookCheck, 'Doctor should check session-start hook');
|
|
336
|
+
assert.strictEqual(hookCheck.status, 'pass', 'Session-start hook check should pass');
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
// ─── AC6: Cleanup verification ─────────────────────────────────
|
|
340
|
+
describe('AC6: Cleans up the temp repo afterward', () => {
|
|
341
|
+
it('test cleanup in afterEach removes the temp directory', () => {
|
|
342
|
+
// This test verifies that the cleanup function works by
|
|
343
|
+
// checking that a previously-created testDir no longer exists
|
|
344
|
+
// after cleanup. Since afterEach runs after each test, we
|
|
345
|
+
// validate the pattern is in place.
|
|
346
|
+
assert.ok(existsSync(testDir), 'Test dir should exist during test');
|
|
347
|
+
// afterEach will clean up - verified by not leaking temp dirs
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
// ─── Idempotency ───────────────────────────────────────────────
|
|
351
|
+
describe('Idempotency: Running init twice should not break things', () => {
|
|
352
|
+
it('should succeed when run twice on same directory', () => {
|
|
353
|
+
const result1 = runCLI(testDir, ['init', '--force']);
|
|
354
|
+
assert.strictEqual(result1.status, 0, 'First init should succeed');
|
|
355
|
+
const result2 = runCLI(testDir, ['init', '--force']);
|
|
356
|
+
assert.strictEqual(result2.status, 0, 'Second init should succeed');
|
|
357
|
+
// Doctor should still pass after double-init
|
|
358
|
+
const doctorResult = runCLI(testDir, ['doctor', '--json']);
|
|
359
|
+
assert.strictEqual(doctorResult.status, 0, 'Doctor should pass after double init');
|
|
360
|
+
const results = extractDoctorJson(doctorResult.stdout);
|
|
361
|
+
const failures = results.filter((r) => r.status === 'fail');
|
|
362
|
+
assert.strictEqual(failures.length, 0, 'No doctor failures after double init');
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
// ─── Edge cases ────────────────────────────────────────────────
|
|
366
|
+
describe('Edge cases', () => {
|
|
367
|
+
it('should fail gracefully without node_modules', () => {
|
|
368
|
+
// Create a fresh dir without node_modules
|
|
369
|
+
const bareDir = createTestDir();
|
|
370
|
+
initGitRepo(bareDir);
|
|
371
|
+
try {
|
|
372
|
+
const result = runCLI(bareDir, ['init', '--force']);
|
|
373
|
+
assert.notStrictEqual(result.status, 0, 'Init should fail without node_modules');
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
rmSync(bareDir, { recursive: true, force: true });
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
it('should work without .git directory (no hooks installed)', () => {
|
|
380
|
+
// Create dir without git init
|
|
381
|
+
const nonGitDir = createTestDir();
|
|
382
|
+
setupNodeModules(nonGitDir);
|
|
383
|
+
try {
|
|
384
|
+
const result = runCLI(nonGitDir, ['init', '--force']);
|
|
385
|
+
assert.strictEqual(result.status, 0, 'Init should succeed without .git');
|
|
386
|
+
// Verify no hooks dir crash
|
|
387
|
+
assert.ok(existsSync(join(nonGitDir, '.pennyfarthing/manifest.json')), 'Manifest should still be created');
|
|
388
|
+
}
|
|
389
|
+
finally {
|
|
390
|
+
rmSync(nonGitDir, { recursive: true, force: true });
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
//# sourceMappingURL=e2e-fresh-install.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2e-fresh-install.test.js","sourceRoot":"","sources":["../../../src/cli/commands/e2e-fresh-install.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E test for MSSCI-14374: Existing repo upgrade
|
|
3
|
+
*
|
|
4
|
+
* This test sets up an old-style installation with files in legacy .claude/
|
|
5
|
+
* locations, runs `pennyfarthing update` to migrate, and validates that:
|
|
6
|
+
* - Files are migrated to .pennyfarthing/
|
|
7
|
+
* - Symlinks exist for Claude Code compatibility
|
|
8
|
+
* - Doctor passes after migration
|
|
9
|
+
* - Temp directory is cleaned up
|
|
10
|
+
*
|
|
11
|
+
* Acceptance Criteria:
|
|
12
|
+
* AC1: Test creates a temp directory with old-style install layout (.claude/ based)
|
|
13
|
+
* AC2: Test runs `pennyfarthing update` against the old layout
|
|
14
|
+
* AC3: Test validates files migrated to .pennyfarthing/
|
|
15
|
+
* AC4: Test validates symlinks exist for Claude Code compatibility
|
|
16
|
+
* AC5: Test runs doctor and confirms it passes
|
|
17
|
+
* AC6: Test cleans up temp directory afterward
|
|
18
|
+
*
|
|
19
|
+
* Run with: cd packages/core && npm run build && npm test
|
|
20
|
+
*/
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=e2e-upgrade.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2e-upgrade.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/e2e-upgrade.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG"}
|