@pennyfarthing/core 9.3.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.
Files changed (72) hide show
  1. package/dist/cli/commands/cyclist.d.ts +1 -1
  2. package/dist/cli/commands/cyclist.d.ts.map +1 -1
  3. package/dist/cli/commands/cyclist.js +15 -25
  4. package/dist/cli/commands/cyclist.js.map +1 -1
  5. package/dist/cli/commands/cyclist.test.js +12 -8
  6. package/dist/cli/commands/cyclist.test.js.map +1 -1
  7. package/dist/cli/commands/doctor.d.ts.map +1 -1
  8. package/dist/cli/commands/doctor.js +149 -15
  9. package/dist/cli/commands/doctor.js.map +1 -1
  10. package/dist/cli/commands/e2e-fresh-install.test.d.ts +19 -0
  11. package/dist/cli/commands/e2e-fresh-install.test.d.ts.map +1 -0
  12. package/dist/cli/commands/e2e-fresh-install.test.js +395 -0
  13. package/dist/cli/commands/e2e-fresh-install.test.js.map +1 -0
  14. package/dist/cli/commands/e2e-upgrade.test.d.ts +22 -0
  15. package/dist/cli/commands/e2e-upgrade.test.d.ts.map +1 -0
  16. package/dist/cli/commands/e2e-upgrade.test.js +562 -0
  17. package/dist/cli/commands/e2e-upgrade.test.js.map +1 -0
  18. package/dist/cli/commands/init-consolidation.test.d.ts +17 -0
  19. package/dist/cli/commands/init-consolidation.test.d.ts.map +1 -0
  20. package/dist/cli/commands/init-consolidation.test.js +217 -0
  21. package/dist/cli/commands/init-consolidation.test.js.map +1 -0
  22. package/dist/cli/commands/init.js +18 -15
  23. package/dist/cli/commands/init.js.map +1 -1
  24. package/dist/cli/commands/persona-config-consolidation.test.d.ts +18 -0
  25. package/dist/cli/commands/persona-config-consolidation.test.d.ts.map +1 -0
  26. package/dist/cli/commands/persona-config-consolidation.test.js +230 -0
  27. package/dist/cli/commands/persona-config-consolidation.test.js.map +1 -0
  28. package/dist/cli/commands/theme.js +2 -2
  29. package/dist/cli/commands/theme.js.map +1 -1
  30. package/dist/cli/commands/uninstall.d.ts.map +1 -1
  31. package/dist/cli/commands/uninstall.js +2 -1
  32. package/dist/cli/commands/uninstall.js.map +1 -1
  33. package/dist/cli/commands/update-consolidation.test.d.ts +19 -0
  34. package/dist/cli/commands/update-consolidation.test.d.ts.map +1 -0
  35. package/dist/cli/commands/update-consolidation.test.js +572 -0
  36. package/dist/cli/commands/update-consolidation.test.js.map +1 -0
  37. package/dist/cli/commands/update.d.ts +25 -0
  38. package/dist/cli/commands/update.d.ts.map +1 -1
  39. package/dist/cli/commands/update.js +128 -11
  40. package/dist/cli/commands/update.js.map +1 -1
  41. package/dist/cli/utils/manifest.d.ts +3 -3
  42. package/dist/cli/utils/manifest.d.ts.map +1 -1
  43. package/dist/cli/utils/manifest.js +21 -12
  44. package/dist/cli/utils/manifest.js.map +1 -1
  45. package/dist/cli/utils/settings-consolidation.test.d.ts +13 -0
  46. package/dist/cli/utils/settings-consolidation.test.d.ts.map +1 -0
  47. package/dist/cli/utils/settings-consolidation.test.js +227 -0
  48. package/dist/cli/utils/settings-consolidation.test.js.map +1 -0
  49. package/dist/cli/utils/settings.d.ts +11 -0
  50. package/dist/cli/utils/settings.d.ts.map +1 -1
  51. package/dist/cli/utils/settings.js +59 -6
  52. package/dist/cli/utils/settings.js.map +1 -1
  53. package/dist/cli/utils/themes.d.ts +3 -3
  54. package/dist/cli/utils/themes.d.ts.map +1 -1
  55. package/dist/cli/utils/themes.js +14 -12
  56. package/dist/cli/utils/themes.js.map +1 -1
  57. package/dist/cli/utils/themes.test.d.ts +2 -2
  58. package/dist/cli/utils/themes.test.js +29 -13
  59. package/dist/cli/utils/themes.test.js.map +1 -1
  60. package/dist/workflow/complete-step-integration.test.d.ts +13 -0
  61. package/dist/workflow/complete-step-integration.test.d.ts.map +1 -0
  62. package/dist/workflow/complete-step-integration.test.js +163 -0
  63. package/dist/workflow/complete-step-integration.test.js.map +1 -0
  64. package/dist/workflow/handoff.test.js +2 -2
  65. package/dist/workflow/handoff.test.js.map +1 -1
  66. package/dist/workflow/index.d.ts +2 -0
  67. package/dist/workflow/index.d.ts.map +1 -1
  68. package/dist/workflow/index.js +6 -0
  69. package/dist/workflow/index.js.map +1 -1
  70. package/dist/workflow/workflow-stepped-schema.test.js +1 -1
  71. package/dist/workflow/workflow-stepped-schema.test.js.map +1 -1
  72. package/package.json +1 -1
@@ -0,0 +1,562 @@
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
+ import { describe, it, beforeEach, afterEach } from 'node:test';
22
+ import assert from 'node:assert';
23
+ import { existsSync, mkdirSync, rmSync, readFileSync, lstatSync, readdirSync, symlinkSync, writeFileSync, chmodSync, } from 'fs';
24
+ import { join, resolve, dirname } from 'path';
25
+ import { tmpdir } from 'os';
26
+ import { execSync, spawnSync } from 'child_process';
27
+ import { fileURLToPath } from 'url';
28
+ const __filename = fileURLToPath(import.meta.url);
29
+ const __dirname = dirname(__filename);
30
+ // Path to the CLI binary (compiled JS)
31
+ const CLI_BIN = resolve(__dirname, '../../../bin/pennyfarthing.js');
32
+ // Path to the real pennyfarthing-dist (for creating fake node_modules)
33
+ // From dist/cli/commands/ β†’ packages/core/dist/cli/commands/ β†’ 5 levels up to repo root
34
+ const REAL_PENNYFARTHING_DIST = resolve(__dirname, '../../../../../pennyfarthing-dist');
35
+ // ─── Helpers ───────────────────────────────────────────────────────
36
+ function createTestDir() {
37
+ const dir = join(tmpdir(), `pf-e2e-upgrade-${Date.now()}-${Math.random().toString(36).slice(2)}`);
38
+ mkdirSync(dir, { recursive: true });
39
+ return dir;
40
+ }
41
+ /**
42
+ * Create a fake node_modules tree that symlinks to the real pennyfarthing-dist.
43
+ * This simulates what `npm install pennyfarthing` would produce.
44
+ */
45
+ function setupNodeModules(testDir) {
46
+ const targetDir = join(testDir, 'node_modules/@pennyfarthing/core');
47
+ mkdirSync(targetDir, { recursive: true });
48
+ // Symlink to the real pennyfarthing-dist so update can find templates, commands, etc.
49
+ symlinkSync(REAL_PENNYFARTHING_DIST, join(targetDir, 'pennyfarthing-dist'));
50
+ }
51
+ /**
52
+ * Initialize a git repo in the test directory so hooks can be installed.
53
+ */
54
+ function initGitRepo(testDir) {
55
+ execSync('git init', { cwd: testDir, stdio: 'pipe' });
56
+ writeFileSync(join(testDir, '.gitkeep'), '');
57
+ execSync('git add .gitkeep && git commit -m "init"', {
58
+ cwd: testDir,
59
+ stdio: 'pipe',
60
+ env: {
61
+ ...process.env,
62
+ GIT_AUTHOR_NAME: 'Test',
63
+ GIT_AUTHOR_EMAIL: 'test@test.com',
64
+ GIT_COMMITTER_NAME: 'Test',
65
+ GIT_COMMITTER_EMAIL: 'test@test.com',
66
+ },
67
+ });
68
+ }
69
+ /**
70
+ * Run the pennyfarthing CLI in the test directory.
71
+ */
72
+ function runCLI(testDir, args) {
73
+ const result = spawnSync('node', [CLI_BIN, ...args], {
74
+ cwd: testDir,
75
+ stdio: 'pipe',
76
+ timeout: 30000,
77
+ env: {
78
+ ...process.env,
79
+ NODE_PATH: '',
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 before the JSON array.
93
+ */
94
+ function extractDoctorJson(stdout) {
95
+ const jsonStart = stdout.indexOf('[');
96
+ if (jsonStart === -1) {
97
+ throw new Error(`No JSON array found in doctor output: ${stdout.slice(0, 200)}`);
98
+ }
99
+ return JSON.parse(stdout.slice(jsonStart));
100
+ }
101
+ // ─── Constants for verification ───────────────────────────────────
102
+ const CORE_AGENTS = [
103
+ 'dev', 'tea', 'sm', 'reviewer', 'architect',
104
+ 'pm', 'tech-writer', 'ux-designer', 'devops', 'orchestrator'
105
+ ];
106
+ const DIRECTORY_SYMLINKS = [
107
+ { name: 'agents', link: '.pennyfarthing/agents' },
108
+ { name: 'guides', link: '.pennyfarthing/guides' },
109
+ { name: 'output-styles', link: '.pennyfarthing/output-styles' },
110
+ { name: 'personas', link: '.pennyfarthing/personas' },
111
+ { name: 'scripts', link: '.pennyfarthing/scripts' },
112
+ { name: 'workflows', link: '.pennyfarthing/workflows' },
113
+ ];
114
+ // Legacy template files that should migrate from .claude/ to .pennyfarthing/
115
+ const LEGACY_TEMPLATE_MIGRATIONS = [
116
+ { oldPath: '.claude/project/docs/agent-scopes.yaml', newPath: '.pennyfarthing/project/docs/agent-scopes.yaml' },
117
+ { oldPath: '.claude/project/hooks/setup-env.sh', newPath: '.pennyfarthing/project/hooks/setup-env.sh' },
118
+ { oldPath: '.claude/project/pennyfarthing-settings.yaml', newPath: '.pennyfarthing/project/pennyfarthing-settings.yaml' },
119
+ { oldPath: '.claude/preferences.yaml', newPath: '.pennyfarthing/preferences.yaml' },
120
+ { oldPath: '.claude/persona-config.yaml', newPath: '.pennyfarthing/persona-config.yaml' },
121
+ ];
122
+ // ─── Legacy Layout Setup ──────────────────────────────────────────
123
+ /**
124
+ * Create an old-style Pennyfarthing installation layout.
125
+ * This simulates what a pre-consolidation install looked like:
126
+ * - Manifest at .claude/manifest.json (legacy location)
127
+ * - Symlinks at .claude/{agents,guides,personas,scripts} (legacy)
128
+ * - Template files at .claude/ locations (legacy)
129
+ * - Sidecars at sprint/sidecars/ (legacy)
130
+ * - settings.local.json as a real file in .claude/ (not symlinked)
131
+ */
132
+ function createLegacyLayout(testDir) {
133
+ const distPath = join(testDir, 'node_modules/@pennyfarthing/core/pennyfarthing-dist');
134
+ // Create required directories
135
+ mkdirSync(join(testDir, '.claude/project/docs'), { recursive: true });
136
+ mkdirSync(join(testDir, '.claude/project/hooks'), { recursive: true });
137
+ mkdirSync(join(testDir, '.claude/project/commands'), { recursive: true });
138
+ mkdirSync(join(testDir, '.claude/project/skills'), { recursive: true });
139
+ mkdirSync(join(testDir, '.pennyfarthing'), { recursive: true });
140
+ mkdirSync(join(testDir, 'sprint'), { recursive: true });
141
+ mkdirSync(join(testDir, '.session'), { recursive: true });
142
+ // 1. Legacy manifest at .claude/manifest.json
143
+ const manifest = {
144
+ version: '9.0.0', // Old version to trigger update
145
+ installedAt: '2025-12-01T00:00:00.000Z',
146
+ updatedAt: '2025-12-01T00:00:00.000Z',
147
+ projectName: 'test-upgrade',
148
+ installationType: 'symlink',
149
+ nodeModulesPath: 'node_modules/@pennyfarthing/core/pennyfarthing-dist',
150
+ managedPaths: [
151
+ '.claude/commands',
152
+ '.claude/skills',
153
+ '.claude/agents', // Old-style paths
154
+ '.claude/guides',
155
+ '.claude/personas',
156
+ '.claude/scripts',
157
+ ],
158
+ fileHashes: {},
159
+ };
160
+ writeFileSync(join(testDir, '.claude/manifest.json'), JSON.stringify(manifest, null, 2));
161
+ // 2. Legacy symlinks at .claude/{agents,guides,personas,scripts}
162
+ // These pointed to node_modules in the old layout
163
+ const legacySymlinkDirs = ['agents', 'guides', 'personas', 'scripts'];
164
+ for (const name of legacySymlinkDirs) {
165
+ const sourcePath = join(distPath, name);
166
+ const linkPath = join(testDir, '.claude', name);
167
+ if (existsSync(sourcePath)) {
168
+ symlinkSync(sourcePath, linkPath);
169
+ }
170
+ }
171
+ // 3. Legacy template files at .claude/ locations
172
+ writeFileSync(join(testDir, '.claude/preferences.yaml'), '# User preferences\ntheme: blade-runner\n');
173
+ writeFileSync(join(testDir, '.claude/persona-config.yaml'), '# Persona config\nactive_theme: blade-runner\n');
174
+ writeFileSync(join(testDir, '.claude/project/docs/agent-scopes.yaml'), '# Agent scopes\nscopes: {}\n');
175
+ writeFileSync(join(testDir, '.claude/project/pennyfarthing-settings.yaml'), '# Settings\nrepos: []\n');
176
+ const setupEnvPath = join(testDir, '.claude/project/hooks/setup-env.sh');
177
+ writeFileSync(setupEnvPath, '#!/bin/bash\n# Setup env\n');
178
+ chmodSync(setupEnvPath, 0o755);
179
+ // 4. shared-context.md (user-owned, should stay at .claude/)
180
+ writeFileSync(join(testDir, '.claude/project/docs/shared-context.md'), '# My Project\nUser-written project description\n');
181
+ // 5. Legacy sidecars at sprint/sidecars/
182
+ for (const agent of CORE_AGENTS) {
183
+ const sidecarDir = join(testDir, `sprint/sidecars/${agent}`);
184
+ mkdirSync(sidecarDir, { recursive: true });
185
+ writeFileSync(join(sidecarDir, 'patterns.md'), `# ${agent} patterns\nLegacy content\n`);
186
+ writeFileSync(join(sidecarDir, 'gotchas.md'), `# ${agent} gotchas\nLegacy content\n`);
187
+ writeFileSync(join(sidecarDir, 'decisions.md'), `# ${agent} decisions\nLegacy content\n`);
188
+ }
189
+ // 6. settings.local.json as a real file (not symlinked) in .claude/
190
+ const settings = {
191
+ permissions: {
192
+ allow: ['Read', 'Grep', 'Glob'],
193
+ },
194
+ hooks: {
195
+ SessionStart: [
196
+ { hooks: [{ type: 'command', command: '$CLAUDE_PROJECT_DIR/.pennyfarthing/scripts/hooks/session-start.sh' }] }
197
+ ],
198
+ },
199
+ };
200
+ writeFileSync(join(testDir, '.claude/settings.local.json'), JSON.stringify(settings, null, 2));
201
+ // 7. Copy commands and skills as real directories (like init did)
202
+ // We use the real pennyfarthing-dist as source
203
+ const commandsSrc = join(distPath, 'commands');
204
+ const skillsSrc = join(distPath, 'skills');
205
+ const commandsDest = join(testDir, '.claude/commands');
206
+ const skillsDest = join(testDir, '.claude/skills');
207
+ mkdirSync(commandsDest, { recursive: true });
208
+ mkdirSync(skillsDest, { recursive: true });
209
+ // Copy a few command files
210
+ if (existsSync(commandsSrc)) {
211
+ for (const file of readdirSync(commandsSrc)) {
212
+ const src = join(commandsSrc, file);
213
+ const dest = join(commandsDest, file);
214
+ writeFileSync(dest, readFileSync(src));
215
+ }
216
+ }
217
+ // Copy skill directories
218
+ if (existsSync(skillsSrc)) {
219
+ for (const entry of readdirSync(skillsSrc)) {
220
+ const srcDir = join(skillsSrc, entry);
221
+ const destDir = join(skillsDest, entry);
222
+ if (lstatSync(srcDir).isDirectory()) {
223
+ mkdirSync(destDir, { recursive: true });
224
+ for (const file of readdirSync(srcDir)) {
225
+ const fileSrc = join(srcDir, file);
226
+ if (!lstatSync(fileSrc).isDirectory()) {
227
+ writeFileSync(join(destDir, file), readFileSync(fileSrc));
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
233
+ // 8. Git hooks (these were in .git/hooks/ in old layout too)
234
+ const hooksDir = join(testDir, '.git/hooks');
235
+ mkdirSync(hooksDir, { recursive: true });
236
+ for (const hook of ['pre-commit', 'pre-push', 'post-merge']) {
237
+ const hookPath = join(hooksDir, hook);
238
+ writeFileSync(hookPath, '#!/bin/bash\n# pennyfarthing hook\nexit 0\n');
239
+ chmodSync(hookPath, 0o755);
240
+ }
241
+ }
242
+ // ─── Test Suites ──────────────────────────────────────────────────
243
+ describe('MSSCI-14374: E2E existing repo upgrade', () => {
244
+ let testDir;
245
+ beforeEach(() => {
246
+ testDir = createTestDir();
247
+ setupNodeModules(testDir);
248
+ initGitRepo(testDir);
249
+ createLegacyLayout(testDir);
250
+ });
251
+ afterEach(() => {
252
+ // AC6: Cleans up the temp repo afterward
253
+ if (existsSync(testDir)) {
254
+ rmSync(testDir, { recursive: true, force: true });
255
+ }
256
+ });
257
+ // ─── AC1: Create old-style install layout ─────────────────────
258
+ describe('AC1: Test creates a temp directory with old-style install layout', () => {
259
+ it('should have a valid git repo with node_modules', () => {
260
+ assert.ok(existsSync(join(testDir, '.git')), 'Test dir should be a git repo');
261
+ const distPath = join(testDir, 'node_modules/@pennyfarthing/core/pennyfarthing-dist');
262
+ assert.ok(existsSync(distPath), 'node_modules should contain pennyfarthing-dist');
263
+ });
264
+ it('should have legacy manifest at .claude/manifest.json', () => {
265
+ const manifestPath = join(testDir, '.claude/manifest.json');
266
+ assert.ok(existsSync(manifestPath), 'Legacy manifest should exist at .claude/');
267
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
268
+ assert.strictEqual(manifest.installationType, 'symlink', 'Should be symlink type');
269
+ assert.strictEqual(manifest.version, '9.0.0', 'Should have old version');
270
+ });
271
+ it('should have legacy symlinks at .claude/{agents,guides,personas,scripts}', () => {
272
+ const legacyDirs = ['agents', 'guides', 'personas', 'scripts'];
273
+ for (const name of legacyDirs) {
274
+ const legacyPath = join(testDir, '.claude', name);
275
+ assert.ok(existsSync(legacyPath), `Legacy .claude/${name} should exist`);
276
+ assert.ok(lstatSync(legacyPath).isSymbolicLink(), `.claude/${name} should be a symlink in the legacy layout`);
277
+ }
278
+ });
279
+ it('should have legacy template files at .claude/ locations', () => {
280
+ for (const { oldPath } of LEGACY_TEMPLATE_MIGRATIONS) {
281
+ assert.ok(existsSync(join(testDir, oldPath)), `Legacy template ${oldPath} should exist`);
282
+ }
283
+ });
284
+ it('should have legacy sidecars at sprint/sidecars/', () => {
285
+ for (const agent of CORE_AGENTS) {
286
+ const sidecarDir = join(testDir, `sprint/sidecars/${agent}`);
287
+ assert.ok(existsSync(sidecarDir), `Legacy sidecar for ${agent} should exist`);
288
+ assert.ok(existsSync(join(sidecarDir, 'patterns.md')), `Legacy patterns.md for ${agent} should exist`);
289
+ }
290
+ });
291
+ it('should have settings.local.json as a real file (not symlink)', () => {
292
+ const settingsPath = join(testDir, '.claude/settings.local.json');
293
+ assert.ok(existsSync(settingsPath), 'settings.local.json should exist');
294
+ assert.ok(!lstatSync(settingsPath).isSymbolicLink(), 'settings.local.json should be a real file in legacy layout');
295
+ });
296
+ });
297
+ // ─── AC2: Run pennyfarthing update ────────────────────────────
298
+ describe('AC2: Test runs pennyfarthing update against the old layout', () => {
299
+ it('should complete update without error', () => {
300
+ const result = runCLI(testDir, ['update']);
301
+ assert.strictEqual(result.status, 0, `Update should exit 0, got ${result.status}.\nStdout: ${result.stdout}\nStderr: ${result.stderr}`);
302
+ });
303
+ it('should report migration activity in output', () => {
304
+ const result = runCLI(testDir, ['update']);
305
+ assert.strictEqual(result.status, 0, 'Update should succeed');
306
+ // Update should mention migration activity
307
+ const output = result.stdout + result.stderr;
308
+ assert.ok(output.includes('Migrated') || output.includes('Updated') || output.includes('Update'), 'Output should indicate migration/update activity');
309
+ });
310
+ });
311
+ // ─── AC3: Validate files migrated to .pennyfarthing/ ──────────
312
+ describe('AC3: Test validates files migrated to .pennyfarthing/', () => {
313
+ it('should migrate manifest from .claude/ to .pennyfarthing/', () => {
314
+ runCLI(testDir, ['update']);
315
+ // Manifest should now be at .pennyfarthing/
316
+ const newManifestPath = join(testDir, '.pennyfarthing/manifest.json');
317
+ assert.ok(existsSync(newManifestPath), 'Manifest should exist at .pennyfarthing/');
318
+ const manifest = JSON.parse(readFileSync(newManifestPath, 'utf8'));
319
+ assert.strictEqual(manifest.installationType, 'symlink', 'Manifest should remain symlink type');
320
+ assert.ok(manifest.version, 'Manifest should have a version');
321
+ });
322
+ it('should remove legacy manifest from .claude/', () => {
323
+ runCLI(testDir, ['update']);
324
+ assert.ok(!existsSync(join(testDir, '.claude/manifest.json')), 'Legacy manifest should be removed from .claude/');
325
+ });
326
+ it('should migrate template files to .pennyfarthing/', () => {
327
+ runCLI(testDir, ['update']);
328
+ for (const { oldPath, newPath } of LEGACY_TEMPLATE_MIGRATIONS) {
329
+ assert.ok(existsSync(join(testDir, newPath)), `Template should be migrated to ${newPath}`);
330
+ assert.ok(!existsSync(join(testDir, oldPath)), `Legacy template ${oldPath} should be removed after migration`);
331
+ }
332
+ });
333
+ it('should preserve user content in migrated template files', () => {
334
+ runCLI(testDir, ['update']);
335
+ // preferences.yaml should retain user content
336
+ const prefsPath = join(testDir, '.pennyfarthing/preferences.yaml');
337
+ const content = readFileSync(prefsPath, 'utf8');
338
+ assert.ok(content.includes('theme: blade-runner'), 'Migrated preferences should preserve user content');
339
+ });
340
+ it('should migrate sidecars from sprint/sidecars/ to .pennyfarthing/sidecars/', () => {
341
+ runCLI(testDir, ['update']);
342
+ for (const agent of CORE_AGENTS) {
343
+ const newSidecarDir = join(testDir, `.pennyfarthing/sidecars/${agent}`);
344
+ assert.ok(existsSync(newSidecarDir), `Sidecar for ${agent} should exist at .pennyfarthing/sidecars/`);
345
+ // Verify files were migrated
346
+ for (const file of ['patterns.md', 'gotchas.md', 'decisions.md']) {
347
+ assert.ok(existsSync(join(newSidecarDir, file)), `${file} for ${agent} should exist at new location`);
348
+ }
349
+ // Verify content was preserved
350
+ const content = readFileSync(join(newSidecarDir, 'patterns.md'), 'utf8');
351
+ assert.ok(content.includes('Legacy content'), `Sidecar content for ${agent} should be preserved`);
352
+ }
353
+ });
354
+ it('should remove legacy sprint/sidecars/ directory after migration', () => {
355
+ runCLI(testDir, ['update']);
356
+ assert.ok(!existsSync(join(testDir, 'sprint/sidecars')), 'Legacy sprint/sidecars/ should be removed after migration');
357
+ });
358
+ it('should remove legacy .claude/{agents,guides,personas,scripts} symlinks', () => {
359
+ runCLI(testDir, ['update']);
360
+ const legacyDirs = ['agents', 'guides', 'personas', 'scripts'];
361
+ for (const name of legacyDirs) {
362
+ assert.ok(!existsSync(join(testDir, '.claude', name)), `Legacy .claude/${name} should be removed after update`);
363
+ }
364
+ });
365
+ it('should NOT move shared-context.md (user-owned, stays in .claude/)', () => {
366
+ runCLI(testDir, ['update']);
367
+ assert.ok(existsSync(join(testDir, '.claude/project/docs/shared-context.md')), 'shared-context.md should remain at .claude/project/docs/');
368
+ const content = readFileSync(join(testDir, '.claude/project/docs/shared-context.md'), 'utf8');
369
+ assert.ok(content.includes('User-written project description'), 'shared-context.md content should be preserved');
370
+ });
371
+ it('should migrate settings.local.json to .pennyfarthing/', () => {
372
+ runCLI(testDir, ['update']);
373
+ const pennyfarthingSettings = join(testDir, '.pennyfarthing/settings.local.json');
374
+ assert.ok(existsSync(pennyfarthingSettings), 'settings.local.json should exist at .pennyfarthing/');
375
+ // Verify settings have been merged (should include required hooks)
376
+ const settings = JSON.parse(readFileSync(pennyfarthingSettings, 'utf8'));
377
+ assert.ok(settings.hooks, 'Migrated settings should have hooks');
378
+ assert.ok(settings.hooks.SessionStart, 'Should have SessionStart hooks');
379
+ });
380
+ it('should update managedPaths to use .pennyfarthing/ paths', () => {
381
+ runCLI(testDir, ['update']);
382
+ const manifestPath = join(testDir, '.pennyfarthing/manifest.json');
383
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
384
+ // Should have new .pennyfarthing/ paths
385
+ assert.ok(manifest.managedPaths.some((p) => p.startsWith('.pennyfarthing/')), 'managedPaths should include .pennyfarthing/ paths');
386
+ // Should still include .claude/commands and .claude/skills
387
+ assert.ok(manifest.managedPaths.includes('.claude/commands'), 'managedPaths should still include .claude/commands');
388
+ assert.ok(manifest.managedPaths.includes('.claude/skills'), 'managedPaths should still include .claude/skills');
389
+ // Should NOT include old .claude/agents etc.
390
+ assert.ok(!manifest.managedPaths.includes('.claude/agents'), 'managedPaths should NOT include legacy .claude/agents');
391
+ });
392
+ });
393
+ // ─── AC4: Validate symlinks for Claude Code compatibility ─────
394
+ describe('AC4: Test validates symlinks exist for Claude Code compatibility', () => {
395
+ it('should create .pennyfarthing/ symlinks to node_modules', () => {
396
+ runCLI(testDir, ['update']);
397
+ for (const { name, link } of DIRECTORY_SYMLINKS) {
398
+ const linkPath = join(testDir, link);
399
+ assert.ok(existsSync(linkPath), `Symlink ${link} should exist after update`);
400
+ assert.ok(lstatSync(linkPath).isSymbolicLink(), `${link} should be a symlink (not a copy)`);
401
+ }
402
+ });
403
+ it('should maintain .claude/commands as real directory', () => {
404
+ runCLI(testDir, ['update']);
405
+ const commandsDir = join(testDir, '.claude/commands');
406
+ assert.ok(existsSync(commandsDir), '.claude/commands should exist');
407
+ assert.ok(!lstatSync(commandsDir).isSymbolicLink(), '.claude/commands should be a real directory (for Claude Code discovery)');
408
+ const files = readdirSync(commandsDir);
409
+ assert.ok(files.length > 0, '.claude/commands should contain files');
410
+ assert.ok(files.some(f => f.endsWith('.md')), '.claude/commands should contain .md command files');
411
+ });
412
+ it('should maintain .claude/skills as real directory', () => {
413
+ runCLI(testDir, ['update']);
414
+ const skillsDir = join(testDir, '.claude/skills');
415
+ assert.ok(existsSync(skillsDir), '.claude/skills should exist');
416
+ assert.ok(!lstatSync(skillsDir).isSymbolicLink(), '.claude/skills should be a real directory (for Claude Code discovery)');
417
+ const entries = readdirSync(skillsDir);
418
+ assert.ok(entries.length > 0, '.claude/skills should contain skill directories');
419
+ });
420
+ it('should create settings.local.json symlink at .claude/', () => {
421
+ runCLI(testDir, ['update']);
422
+ const claudeSettings = join(testDir, '.claude/settings.local.json');
423
+ assert.ok(existsSync(claudeSettings), '.claude/settings.local.json should exist');
424
+ assert.ok(lstatSync(claudeSettings).isSymbolicLink(), '.claude/settings.local.json should be a symlink (pointing to .pennyfarthing/)');
425
+ // Verify the symlink target resolves correctly
426
+ const settings = JSON.parse(readFileSync(claudeSettings, 'utf8'));
427
+ assert.ok(settings.hooks, 'settings.local.json via symlink should have hooks');
428
+ });
429
+ it('should keep .claude/ directory structure intact for Claude Code', () => {
430
+ runCLI(testDir, ['update']);
431
+ // These paths must exist for Claude Code to discover commands/skills
432
+ assert.ok(existsSync(join(testDir, '.claude')), '.claude/ should exist');
433
+ assert.ok(existsSync(join(testDir, '.claude/commands')), '.claude/commands/ should exist');
434
+ assert.ok(existsSync(join(testDir, '.claude/skills')), '.claude/skills/ should exist');
435
+ assert.ok(existsSync(join(testDir, '.claude/settings.local.json')), '.claude/settings.local.json should exist');
436
+ });
437
+ });
438
+ // ─── AC5: Run doctor and confirm it passes ────────────────────
439
+ describe('AC5: Test runs doctor and confirms it passes', () => {
440
+ it('should pass doctor check with no failures after update', () => {
441
+ const updateResult = runCLI(testDir, ['update']);
442
+ assert.strictEqual(updateResult.status, 0, 'Update should succeed first');
443
+ const doctorResult = runCLI(testDir, ['doctor', '--json']);
444
+ assert.strictEqual(doctorResult.status, 0, `Doctor should exit 0.\nStdout: ${doctorResult.stdout}\nStderr: ${doctorResult.stderr}`);
445
+ const results = extractDoctorJson(doctorResult.stdout);
446
+ const failures = results.filter((r) => r.status === 'fail');
447
+ assert.strictEqual(failures.length, 0, `Doctor should have 0 failures after upgrade, got ${failures.length}: ${JSON.stringify(failures, null, 2)}`);
448
+ });
449
+ it('doctor should show manifest as passing', () => {
450
+ runCLI(testDir, ['update']);
451
+ const doctorResult = runCLI(testDir, ['doctor', '--json']);
452
+ const results = extractDoctorJson(doctorResult.stdout);
453
+ const manifestCheck = results.find((r) => r.name === 'manifest/exists');
454
+ assert.ok(manifestCheck, 'Doctor should check manifest');
455
+ assert.strictEqual(manifestCheck.status, 'pass', 'Manifest check should pass after upgrade');
456
+ });
457
+ it('doctor should show all directory symlinks as passing', () => {
458
+ runCLI(testDir, ['update']);
459
+ const doctorResult = runCLI(testDir, ['doctor', '--json']);
460
+ const results = extractDoctorJson(doctorResult.stdout);
461
+ const directorySymlinkNames = ['agents', 'guides', 'output-styles', 'personas', 'scripts', 'workflows'];
462
+ for (const name of directorySymlinkNames) {
463
+ const check = results.find((r) => r.name === `symlink/${name}`);
464
+ assert.ok(check, `Doctor should check symlink/${name}`);
465
+ assert.strictEqual(check.status, 'pass', `symlink/${name} should pass after upgrade, got ${check.status}: ${check.detail}`);
466
+ }
467
+ });
468
+ it('doctor should show settings.local.json as passing', () => {
469
+ runCLI(testDir, ['update']);
470
+ const doctorResult = runCLI(testDir, ['doctor', '--json']);
471
+ const results = extractDoctorJson(doctorResult.stdout);
472
+ const settingsCheck = results.find((r) => r.name === 'settings.local.json');
473
+ assert.ok(settingsCheck, 'Doctor should check settings.local.json');
474
+ assert.strictEqual(settingsCheck.status, 'pass', 'Settings check should pass after upgrade');
475
+ });
476
+ it('doctor should show session-start hook as passing', () => {
477
+ runCLI(testDir, ['update']);
478
+ const doctorResult = runCLI(testDir, ['doctor', '--json']);
479
+ const results = extractDoctorJson(doctorResult.stdout);
480
+ const hookCheck = results.find((r) => r.name === 'settings/session-start-hook');
481
+ assert.ok(hookCheck, 'Doctor should check session-start hook');
482
+ assert.strictEqual(hookCheck.status, 'pass', 'Session-start hook should pass after upgrade');
483
+ });
484
+ it('doctor should detect no legacy files after migration', () => {
485
+ runCLI(testDir, ['update']);
486
+ const doctorResult = runCLI(testDir, ['doctor', '--json']);
487
+ const results = extractDoctorJson(doctorResult.stdout);
488
+ // If doctor has a legacy file check, it should pass
489
+ const legacyChecks = results.filter((r) => r.name.startsWith('legacy/'));
490
+ for (const check of legacyChecks) {
491
+ assert.notStrictEqual(check.status, 'fail', `Legacy check ${check.name} should not fail after migration`);
492
+ }
493
+ });
494
+ });
495
+ // ─── AC6: Cleanup verification ────────────────────────────────
496
+ describe('AC6: Cleans up the temp repo afterward', () => {
497
+ it('test cleanup in afterEach removes the temp directory', () => {
498
+ assert.ok(existsSync(testDir), 'Test dir should exist during test');
499
+ // afterEach will clean up
500
+ });
501
+ });
502
+ // ─── Idempotency ─────────────────────────────────────────────
503
+ describe('Idempotency: Running update twice should not break things', () => {
504
+ it('should succeed when update is run twice', () => {
505
+ const result1 = runCLI(testDir, ['update']);
506
+ assert.strictEqual(result1.status, 0, 'First update should succeed');
507
+ const result2 = runCLI(testDir, ['update']);
508
+ assert.strictEqual(result2.status, 0, 'Second update should succeed');
509
+ // Doctor should still pass after double-update
510
+ const doctorResult = runCLI(testDir, ['doctor', '--json']);
511
+ assert.strictEqual(doctorResult.status, 0, 'Doctor should pass after double update');
512
+ const results = extractDoctorJson(doctorResult.stdout);
513
+ const failures = results.filter((r) => r.status === 'fail');
514
+ assert.strictEqual(failures.length, 0, 'No doctor failures after double update');
515
+ });
516
+ });
517
+ // ─── Edge cases ───────────────────────────────────────────────
518
+ describe('Edge cases', () => {
519
+ it('should handle missing legacy files gracefully', () => {
520
+ // Remove some legacy files to test partial migration
521
+ rmSync(join(testDir, '.claude/preferences.yaml'), { force: true });
522
+ rmSync(join(testDir, '.claude/persona-config.yaml'), { force: true });
523
+ const result = runCLI(testDir, ['update']);
524
+ assert.strictEqual(result.status, 0, `Update should succeed even with missing legacy files.\nStdout: ${result.stdout}\nStderr: ${result.stderr}`);
525
+ });
526
+ it('should handle already-migrated sidecars (no duplicate)', () => {
527
+ // Pre-create a sidecar at the new location with different content
528
+ const newSidecarDir = join(testDir, '.pennyfarthing/sidecars/dev');
529
+ mkdirSync(newSidecarDir, { recursive: true });
530
+ writeFileSync(join(newSidecarDir, 'patterns.md'), '# Already at new location\n');
531
+ const result = runCLI(testDir, ['update']);
532
+ assert.strictEqual(result.status, 0, 'Update should succeed');
533
+ // Existing new-location content should NOT be overwritten
534
+ const content = readFileSync(join(newSidecarDir, 'patterns.md'), 'utf8');
535
+ assert.ok(content.includes('Already at new location'), 'Pre-existing sidecar content should not be overwritten');
536
+ });
537
+ it('should fail without node_modules', () => {
538
+ // Create a legacy layout without node_modules
539
+ const bareDir = createTestDir();
540
+ initGitRepo(bareDir);
541
+ mkdirSync(join(bareDir, '.claude'), { recursive: true });
542
+ mkdirSync(join(bareDir, '.pennyfarthing'), { recursive: true });
543
+ writeFileSync(join(bareDir, '.pennyfarthing/manifest.json'), JSON.stringify({
544
+ version: '9.0.0',
545
+ installationType: 'symlink',
546
+ projectName: 'test',
547
+ installedAt: new Date().toISOString(),
548
+ updatedAt: new Date().toISOString(),
549
+ managedPaths: [],
550
+ fileHashes: {},
551
+ }));
552
+ try {
553
+ const result = runCLI(bareDir, ['update']);
554
+ assert.notStrictEqual(result.status, 0, 'Update should fail without node_modules');
555
+ }
556
+ finally {
557
+ rmSync(bareDir, { recursive: true, force: true });
558
+ }
559
+ });
560
+ });
561
+ });
562
+ //# sourceMappingURL=e2e-upgrade.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e-upgrade.test.js","sourceRoot":"","sources":["../../../src/cli/commands/e2e-upgrade.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EACL,UAAU,EACV,SAAS,EACT,MAAM,EACN,YAAY,EACZ,SAAS,EACT,WAAW,EACX,WAAW,EACX,aAAa,EACb,SAAS,GACV,MAAM,IAAI,CAAC;AACZ,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,uCAAuC;AACvC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,+BAA+B,CAAC,CAAC;AAEpE,uEAAuE;AACvE,wFAAwF;AACxF,MAAM,uBAAuB,GAAG,OAAO,CAAC,SAAS,EAAE,mCAAmC,CAAC,CAAC;AAExF,sEAAsE;AAEtE,SAAS,aAAa;IACpB,MAAM,GAAG,GAAG,IAAI,CACd,MAAM,EAAE,EACR,kBAAkB,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CACtE,CAAC;IACF,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,kCAAkC,CAAC,CAAC;IACpE,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,sFAAsF;IACtF,WAAW,CAAC,uBAAuB,EAAE,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,OAAe;IAClC,QAAQ,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7C,QAAQ,CAAC,0CAA0C,EAAE;QACnD,GAAG,EAAE,OAAO;QACZ,KAAK,EAAE,MAAM;QACb,GAAG,EAAE;YACH,GAAG,OAAO,CAAC,GAAG;YACd,eAAe,EAAE,MAAM;YACvB,gBAAgB,EAAE,eAAe;YACjC,kBAAkB,EAAE,MAAM;YAC1B,mBAAmB,EAAE,eAAe;SACrC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,MAAM,CAAC,OAAe,EAAE,IAAc;IAC7C,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE;QACnD,GAAG,EAAE,OAAO;QACZ,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,KAAK;QACd,GAAG,EAAE;YACH,GAAG,OAAO,CAAC,GAAG;YACd,SAAS,EAAE,EAAE;YACb,WAAW,EAAE,GAAG;YAChB,QAAQ,EAAE,GAAG;SACd;KACF,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,MAAc;IACvC,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,yCAAyC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,qEAAqE;AAErE,MAAM,WAAW,GAAG;IAClB,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW;IAC3C,IAAI,EAAE,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc;CAC7D,CAAC;AAEF,MAAM,kBAAkB,GAAG;IACzB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,uBAAuB,EAAE;IACjD,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,uBAAuB,EAAE;IACjD,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,8BAA8B,EAAE;IAC/D,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,yBAAyB,EAAE;IACrD,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,wBAAwB,EAAE;IACnD,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,0BAA0B,EAAE;CACxD,CAAC;AAEF,6EAA6E;AAC7E,MAAM,0BAA0B,GAAG;IACjC,EAAE,OAAO,EAAE,wCAAwC,EAAE,OAAO,EAAE,+CAA+C,EAAE;IAC/G,EAAE,OAAO,EAAE,oCAAoC,EAAE,OAAO,EAAE,2CAA2C,EAAE;IACvG,EAAE,OAAO,EAAE,6CAA6C,EAAE,OAAO,EAAE,oDAAoD,EAAE;IACzH,EAAE,OAAO,EAAE,0BAA0B,EAAE,OAAO,EAAE,iCAAiC,EAAE;IACnF,EAAE,OAAO,EAAE,6BAA6B,EAAE,OAAO,EAAE,oCAAoC,EAAE;CAC1F,CAAC;AAEF,qEAAqE;AAErE;;;;;;;;GAQG;AACH,SAAS,kBAAkB,CAAC,OAAe;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,qDAAqD,CAAC,CAAC;IAEtF,8BAA8B;IAC9B,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,sBAAsB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,uBAAuB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,0BAA0B,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1E,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,wBAAwB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,8CAA8C;IAC9C,MAAM,QAAQ,GAAG;QACf,OAAO,EAAE,OAAO,EAAG,gCAAgC;QACnD,WAAW,EAAE,0BAA0B;QACvC,SAAS,EAAE,0BAA0B;QACrC,WAAW,EAAE,cAAc;QAC3B,gBAAgB,EAAE,SAAS;QAC3B,eAAe,EAAE,qDAAqD;QACtE,YAAY,EAAE;YACZ,kBAAkB;YAClB,gBAAgB;YAChB,gBAAgB,EAAO,kBAAkB;YACzC,gBAAgB;YAChB,kBAAkB;YAClB,iBAAiB;SAClB;QACD,UAAU,EAAE,EAAE;KACf,CAAC;IACF,aAAa,CACX,IAAI,CAAC,OAAO,EAAE,uBAAuB,CAAC,EACtC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAClC,CAAC;IAEF,iEAAiE;IACjE,qDAAqD;IACrD,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IACtE,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAChD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,aAAa,CACX,IAAI,CAAC,OAAO,EAAE,0BAA0B,CAAC,EACzC,2CAA2C,CAC5C,CAAC;IACF,aAAa,CACX,IAAI,CAAC,OAAO,EAAE,6BAA6B,CAAC,EAC5C,gDAAgD,CACjD,CAAC;IACF,aAAa,CACX,IAAI,CAAC,OAAO,EAAE,wCAAwC,CAAC,EACvD,8BAA8B,CAC/B,CAAC;IACF,aAAa,CACX,IAAI,CAAC,OAAO,EAAE,6CAA6C,CAAC,EAC5D,yBAAyB,CAC1B,CAAC;IAEF,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,oCAAoC,CAAC,CAAC;IACzE,aAAa,CAAC,YAAY,EAAE,4BAA4B,CAAC,CAAC;IAC1D,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAE/B,6DAA6D;IAC7D,aAAa,CACX,IAAI,CAAC,OAAO,EAAE,wCAAwC,CAAC,EACvD,kDAAkD,CACnD,CAAC;IAEF,yCAAyC;IACzC,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,mBAAmB,KAAK,EAAE,CAAC,CAAC;QAC7D,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,EAAE,KAAK,KAAK,6BAA6B,CAAC,CAAC;QACxF,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,KAAK,KAAK,4BAA4B,CAAC,CAAC;QACtF,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EAAE,KAAK,KAAK,8BAA8B,CAAC,CAAC;IAC5F,CAAC;IAED,oEAAoE;IACpE,MAAM,QAAQ,GAAG;QACf,WAAW,EAAE;YACX,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC;QACD,KAAK,EAAE;YACL,YAAY,EAAE;gBACZ,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,mEAAmE,EAAE,CAAC,EAAE;aAC/G;SACF;KACF,CAAC;IACF,aAAa,CACX,IAAI,CAAC,OAAO,EAAE,6BAA6B,CAAC,EAC5C,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAClC,CAAC;IAEF,kEAAkE;IAClE,kDAAkD;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAEnD,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,2BAA2B;IAC3B,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;YACtC,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACtC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YACxC,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;gBACpC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACxC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;oBACvC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;oBACnC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;wBACtC,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;oBAC5D,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC7C,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,CAAC,YAAY,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACtC,aAAa,CAAC,QAAQ,EAAE,6CAA6C,CAAC,CAAC;QACvE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,qEAAqE;AAErE,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,IAAI,OAAe,CAAC;IAEpB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,aAAa,EAAE,CAAC;QAC1B,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC1B,WAAW,CAAC,OAAO,CAAC,CAAC;QACrB,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,yCAAyC;QACzC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,iEAAiE;IAEjE,QAAQ,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAChF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,EAAE,+BAA+B,CAAC,CAAC;YAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,qDAAqD,CAAC,CAAC;YACtF,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,gDAAgD,CAAC,CAAC;QACpF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;YAC5D,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,0CAA0C,CAAC,CAAC;YAEhF,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;YAChE,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,EAAE,wBAAwB,CAAC,CAAC;YACnF,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,yBAAyB,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;YACjF,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;YAC/D,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;gBAClD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,kBAAkB,IAAI,eAAe,CAAC,CAAC;gBACzE,MAAM,CAAC,EAAE,CACP,SAAS,CAAC,UAAU,CAAC,CAAC,cAAc,EAAE,EACtC,WAAW,IAAI,2CAA2C,CAC3D,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACjE,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,0BAA0B,EAAE,CAAC;gBACrD,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAClC,mBAAmB,OAAO,eAAe,CAC1C,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;YACzD,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;gBAChC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,mBAAmB,KAAK,EAAE,CAAC,CAAC;gBAC7D,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,sBAAsB,KAAK,eAAe,CAAC,CAAC;gBAC9E,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,EAC3C,0BAA0B,KAAK,eAAe,CAC/C,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;YACtE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC;YAClE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,kCAAkC,CAAC,CAAC;YACxE,MAAM,CAAC,EAAE,CACP,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,cAAc,EAAE,EACzC,4DAA4D,CAC7D,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,iEAAiE;IAEjE,QAAQ,CAAC,4DAA4D,EAAE,GAAG,EAAE;QAC1E,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,MAAM,EACb,CAAC,EACD,6BAA6B,MAAM,CAAC,MAAM,cAAc,MAAM,CAAC,MAAM,aAAa,MAAM,CAAC,MAAM,EAAE,CAClG,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,uBAAuB,CAAC,CAAC;YAE9D,2CAA2C;YAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAC7C,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EACtF,kDAAkD,CACnD,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,iEAAiE;IAEjE,QAAQ,CAAC,uDAAuD,EAAE,GAAG,EAAE;QACrE,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,4CAA4C;YAC5C,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,8BAA8B,CAAC,CAAC;YACtE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,0CAA0C,CAAC,CAAC;YAEnF,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;YACnE,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,EAAE,qCAAqC,CAAC,CAAC;YAChG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,gCAAgC,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,MAAM,CAAC,EAAE,CACP,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC,EACnD,iDAAiD,CAClD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,KAAK,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,0BAA0B,EAAE,CAAC;gBAC9D,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAClC,kCAAkC,OAAO,EAAE,CAC5C,CAAC;gBACF,MAAM,CAAC,EAAE,CACP,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EACnC,mBAAmB,OAAO,oCAAoC,CAC/D,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACjE,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,8CAA8C;YAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,iCAAiC,CAAC,CAAC;YACnE,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAChD,MAAM,CAAC,EAAE,CACP,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EACvC,mDAAmD,CACpD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;YACnF,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;gBAChC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,2BAA2B,KAAK,EAAE,CAAC,CAAC;gBACxE,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,aAAa,CAAC,EACzB,eAAe,KAAK,2CAA2C,CAChE,CAAC;gBAEF,6BAA6B;gBAC7B,KAAK,MAAM,IAAI,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,CAAC;oBACjE,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,EACrC,GAAG,IAAI,QAAQ,KAAK,+BAA+B,CACpD,CAAC;gBACJ,CAAC;gBAED,+BAA+B;gBAC/B,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;gBACzE,MAAM,CAAC,EAAE,CACP,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAClC,uBAAuB,KAAK,sBAAsB,CACnD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACzE,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,MAAM,CAAC,EAAE,CACP,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,EAC7C,2DAA2D,CAC5D,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;YAChF,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;YAC/D,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC9B,MAAM,CAAC,EAAE,CACP,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,EAC3C,kBAAkB,IAAI,iCAAiC,CACxD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;YAC3E,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,wCAAwC,CAAC,CAAC,EACnE,0DAA0D,CAC3D,CAAC;YAEF,MAAM,OAAO,GAAG,YAAY,CAC1B,IAAI,CAAC,OAAO,EAAE,wCAAwC,CAAC,EACvD,MAAM,CACP,CAAC;YACF,MAAM,CAAC,EAAE,CACP,OAAO,CAAC,QAAQ,CAAC,kCAAkC,CAAC,EACpD,+CAA+C,CAChD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,MAAM,qBAAqB,GAAG,IAAI,CAAC,OAAO,EAAE,oCAAoC,CAAC,CAAC;YAClF,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,qBAAqB,CAAC,EACjC,qDAAqD,CACtD,CAAC;YAEF,mEAAmE;YACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC;YACzE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,qCAAqC,CAAC,CAAC;YACjE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,gCAAgC,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACjE,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,8BAA8B,CAAC,CAAC;YACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;YAEhE,wCAAwC;YACxC,MAAM,CAAC,EAAE,CACP,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,EAC1E,mDAAmD,CACpD,CAAC;YAEF,2DAA2D;YAC3D,MAAM,CAAC,EAAE,CACP,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAClD,oDAAoD,CACrD,CAAC;YACF,MAAM,CAAC,EAAE,CACP,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAChD,kDAAkD,CACnD,CAAC;YAEF,6CAA6C;YAC7C,MAAM,CAAC,EAAE,CACP,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EACjD,uDAAuD,CACxD,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,iEAAiE;IAEjE,QAAQ,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAChF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,kBAAkB,EAAE,CAAC;gBAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBACrC,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,QAAQ,CAAC,EACpB,WAAW,IAAI,4BAA4B,CAC5C,CAAC;gBACF,MAAM,CAAC,EAAE,CACP,SAAS,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,EACpC,GAAG,IAAI,mCAAmC,CAC3C,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACtD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,+BAA+B,CAAC,CAAC;YACpE,MAAM,CAAC,EAAE,CACP,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,cAAc,EAAE,EACxC,yEAAyE,CAC1E,CAAC;YAEF,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,uCAAuC,CAAC,CAAC;YACrE,MAAM,CAAC,EAAE,CACP,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAClC,mDAAmD,CACpD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;YAClD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,6BAA6B,CAAC,CAAC;YAChE,MAAM,CAAC,EAAE,CACP,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,EACtC,uEAAuE,CACxE,CAAC;YAEF,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,iDAAiD,CAAC,CAAC;QACnF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC;YACpE,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,cAAc,CAAC,EAC1B,0CAA0C,CAC3C,CAAC;YACF,MAAM,CAAC,EAAE,CACP,SAAS,CAAC,cAAc,CAAC,CAAC,cAAc,EAAE,EAC1C,+EAA+E,CAChF,CAAC;YAEF,+CAA+C;YAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;YAClE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,mDAAmD,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACzE,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5B,qEAAqE;YACrE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAC;YACzE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,gCAAgC,CAAC,CAAC;YAC3F,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,8BAA8B,CAAC,CAAC;YACvF,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC,EAAE,0CAA0C,CAAC,CAAC;QAClH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,iEAAiE;IAEjE,QAAQ,CAAC,8CAA8C,EAAE,GAAG,EAAE;QAC5D,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,6BAA6B,CAAC,CAAC;YAE1E,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC3D,MAAM,CAAC,WAAW,CAChB,YAAY,CAAC,MAAM,EACnB,CAAC,EACD,kCAAkC,YAAY,CAAC,MAAM,aAAa,YAAY,CAAC,MAAM,EAAE,CACxF,CAAC;YAEF,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YACvD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;YAEhF,MAAM,CAAC,WAAW,CAChB,QAAQ,CAAC,MAAM,EACf,CAAC,EACD,oDAAoD,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAC5G,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5B,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC3D,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAEvD,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC;YAC1F,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,8BAA8B,CAAC,CAAC;YACzD,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,0CAA0C,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5B,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC3D,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAEvD,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;YAExG,KAAK,MAAM,IAAI,IAAI,qBAAqB,EAAE,CAAC;gBACzC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,EAAE,CAAC,CAAC;gBAClF,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,+BAA+B,IAAI,EAAE,CAAC,CAAC;gBACxD,MAAM,CAAC,WAAW,CAChB,KAAM,CAAC,MAAM,EACb,MAAM,EACN,WAAW,IAAI,mCAAmC,KAAM,CAAC,MAAM,KAAK,KAAM,CAAC,MAAM,EAAE,CACpF,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5B,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC3D,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAEvD,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAChC,CAAC,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,qBAAqB,CAC1D,CAAC;YACF,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,yCAAyC,CAAC,CAAC;YACpE,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,0CAA0C,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5B,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC3D,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAEvD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAC5B,CAAC,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,6BAA6B,CAClE,CAAC;YACF,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,wCAAwC,CAAC,CAAC;YAC/D,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,8CAA8C,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5B,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC3D,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAEvD,oDAAoD;YACpD,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CACjC,CAAC,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CACtD,CAAC;YACF,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;gBACjC,MAAM,CAAC,cAAc,CACnB,KAAK,CAAC,MAAM,EACZ,MAAM,EACN,gBAAgB,KAAK,CAAC,IAAI,kCAAkC,CAC7D,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,iEAAiE;IAEjE,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;QACtD,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,mCAAmC,CAAC,CAAC;YACpE,0BAA0B;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,gEAAgE;IAEhE,QAAQ,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACzE,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,6BAA6B,CAAC,CAAC;YAErE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,8BAA8B,CAAC,CAAC;YAEtE,+CAA+C;YAC/C,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC3D,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,wCAAwC,CAAC,CAAC;YAErF,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YACvD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;YAChF,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,wCAAwC,CAAC,CAAC;QACnF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,iEAAiE;IAEjE,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,qDAAqD;YACrD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,0BAA0B,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,6BAA6B,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAEtE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,MAAM,EACb,CAAC,EACD,kEAAkE,MAAM,CAAC,MAAM,aAAa,MAAM,CAAC,MAAM,EAAE,CAC5G,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,kEAAkE;YAClE,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC;YACnE,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,EAAE,6BAA6B,CAAC,CAAC;YAEjF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,uBAAuB,CAAC,CAAC;YAE9D,0DAA0D;YAC1D,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;YACzE,MAAM,CAAC,EAAE,CACP,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAC3C,wDAAwD,CACzD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,8CAA8C;YAC9C,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;YAChC,WAAW,CAAC,OAAO,CAAC,CAAC;YACrB,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzD,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAChE,aAAa,CACX,IAAI,CAAC,OAAO,EAAE,8BAA8B,CAAC,EAC7C,IAAI,CAAC,SAAS,CAAC;gBACb,OAAO,EAAE,OAAO;gBAChB,gBAAgB,EAAE,SAAS;gBAC3B,WAAW,EAAE,MAAM;gBACnB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACrC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,YAAY,EAAE,EAAE;gBAChB,UAAU,EAAE,EAAE;aACf,CAAC,CACH,CAAC;YAEF,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC3C,MAAM,CAAC,cAAc,CACnB,MAAM,CAAC,MAAM,EACb,CAAC,EACD,yCAAyC,CAC1C,CAAC;YACJ,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Tests for MSSCI-14370: Update init command for bootstrapping install
3
+ *
4
+ * These tests verify that the init command creates the consolidated .pennyfarthing/
5
+ * layout established by epic-85 stories 1.2-1.5.
6
+ *
7
+ * Key changes tested:
8
+ * - Manifest at .pennyfarthing/manifest.json (not .claude/)
9
+ * - Template files placed under .pennyfarthing/ (not .claude/)
10
+ * - managedPaths in manifest reflect new layout
11
+ * - Backward compatibility with legacy .claude/ manifest
12
+ * - Directory structure includes .pennyfarthing/project/* dirs
13
+ *
14
+ * Run with: cd packages/core && npm run build && npm test
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=init-consolidation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-consolidation.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init-consolidation.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}