From fae6e15cd406153a82f97bc6cef646a49d0e5478 Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Sat, 27 Jun 2026 08:17:21 +0000 Subject: [PATCH 1/3] Avoid config timestamp churn on install --- packages/cli/src/__tests__/lib/Config.test.ts | 22 +++++++++++++++++++ packages/cli/src/lib/Config.ts | 22 +++++++++++++++---- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/__tests__/lib/Config.test.ts b/packages/cli/src/__tests__/lib/Config.test.ts index dbb932a8..b432340a 100644 --- a/packages/cli/src/__tests__/lib/Config.test.ts +++ b/packages/cli/src/__tests__/lib/Config.test.ts @@ -162,6 +162,28 @@ describe('ConfigManager', () => { expect(result.createdAt).toBe(existingConfig.createdAt); }); + it('should not rewrite config or change updatedAt when updates are unchanged', async () => { + const existingConfig: DevKitConfig = { + version: '1.0.0', + environments: ['cursor'], + phases: [], + skills: [{ registry: 'codeaholicguy/ai-devkit', name: 'debug' }], + createdAt: '2024-01-01T00:00:00.000Z', + updatedAt: '2024-01-01T00:00:00.000Z' + }; + + (mockFs.pathExists as any).mockResolvedValue(true); + (mockFs.readJson as any).mockResolvedValue(existingConfig); + + const result = await configManager.update({ + environments: ['cursor'], + skills: [{ registry: 'codeaholicguy/ai-devkit', name: 'debug' }] + }); + + expect(result).toEqual(existingConfig); + expect(mockFs.writeJson).not.toHaveBeenCalled(); + }); + it('should throw error when config file not found', async () => { (mockFs.readJson as any).mockResolvedValue(null); diff --git a/packages/cli/src/lib/Config.ts b/packages/cli/src/lib/Config.ts index 75ec43a2..74078157 100644 --- a/packages/cli/src/lib/Config.ts +++ b/packages/cli/src/lib/Config.ts @@ -7,6 +7,12 @@ import packageJson from '../../package.json' with { type: 'json' }; const CONFIG_FILE_NAME = '.ai-devkit.json'; +function withoutUpdatedAt(config: DevKitConfig): Omit { + const { updatedAt, ...meaningfulConfig } = config; + void updatedAt; + return meaningfulConfig; +} + export class ConfigManager { private configPath: string; @@ -48,9 +54,17 @@ export class ConfigManager { throw new ConfigNotFoundError('Config file not found. Run ai-devkit init first.'); } - const updated = { + const nextConfig = { ...config, - ...updates, + ...updates + }; + + if (JSON.stringify(withoutUpdatedAt(nextConfig)) === JSON.stringify(withoutUpdatedAt(config))) { + return config; + } + + const updated = { + ...nextConfig, updatedAt: new Date().toISOString() }; @@ -64,7 +78,7 @@ export class ConfigManager { throw new ConfigNotFoundError('Config file not found. Run ai-devkit init first.'); } - const phases = Array.isArray(config.phases) ? config.phases : []; + const phases = Array.isArray(config.phases) ? [...config.phases] : []; if (!phases.includes(phase)) { phases.push(phase); return this.update({ phases }); @@ -141,7 +155,7 @@ export class ConfigManager { throw new ConfigNotFoundError('Config file not found. Run ai-devkit init first.'); } - const installed = Array.isArray(config.skills) ? config.skills : []; + const installed = Array.isArray(config.skills) ? [...config.skills] : []; const exists = installed.some( entry => entry.registry === skill.registry && entry.name === skill.name From a9ee0a08df07e91b9e635cadd7a4d03cacbb2e14 Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Sat, 27 Jun 2026 11:57:31 +0000 Subject: [PATCH 2/3] Remove updatedAt from project config --- .ai-devkit.json | 1 - e2e/cli.e2e.ts | 15 ++-- packages/cli/src/__tests__/lib/Config.test.ts | 68 +++++++++---------- packages/cli/src/lib/Config.ts | 23 +++---- packages/cli/src/types.ts | 1 - web/content/docs/11-configuration-file.md | 9 ++- 6 files changed, 51 insertions(+), 66 deletions(-) diff --git a/.ai-devkit.json b/.ai-devkit.json index f10b5a05..51083048 100644 --- a/.ai-devkit.json +++ b/.ai-devkit.json @@ -9,7 +9,6 @@ "antigravity" ], "createdAt": "2025-12-28T13:35:45.251Z", - "updatedAt": "2026-06-14T11:53:00.073Z", "phases": [ "requirements", "design", diff --git a/e2e/cli.e2e.ts b/e2e/cli.e2e.ts index 56cb46e6..d93207fe 100644 --- a/e2e/cli.e2e.ts +++ b/e2e/cli.e2e.ts @@ -207,8 +207,7 @@ describe('memory commands', () => { memory: { path: '.ai-devkit/memory.db' }, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString() + createdAt: new Date().toISOString() }); }); @@ -335,8 +334,7 @@ describe('install command', () => { version: '1.0.0', environments: ['claude'], phases: ['requirements', 'design'], - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString() + createdAt: new Date().toISOString() }); const result = run('install', { cwd: projectDir }); @@ -359,8 +357,7 @@ describe('install command', () => { skills: [ { registry: 'codeaholicguy/ai-devkit', name: 'dev-lifecycle' } ], - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString() + createdAt: new Date().toISOString() }); const result = run('install', { cwd: projectDir }); @@ -398,8 +395,7 @@ describe('skill command', () => { skills: [ { registry: 'codeaholicguy/ai-devkit', name: 'dev-lifecycle' } ], - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString() + createdAt: new Date().toISOString() }); // Create the skill directory so the remove command finds it @@ -427,8 +423,7 @@ describe('skill command', () => { { registry: 'codeaholicguy/ai-devkit', name: 'dev-lifecycle' }, { registry: 'codeaholicguy/ai-devkit', name: 'memory' } ], - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString() + createdAt: new Date().toISOString() }); const skillDir = join(projectDir, '.claude', 'skills', 'dev-lifecycle'); diff --git a/packages/cli/src/__tests__/lib/Config.test.ts b/packages/cli/src/__tests__/lib/Config.test.ts index b432340a..e0f61ddf 100644 --- a/packages/cli/src/__tests__/lib/Config.test.ts +++ b/packages/cli/src/__tests__/lib/Config.test.ts @@ -94,7 +94,6 @@ describe('ConfigManager', () => { environments: ['cursor' as any], phases: ['requirements' as any], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -123,7 +122,6 @@ describe('ConfigManager', () => { environments: [], phases: [], createdAt: expect.any(String), - updatedAt: expect.any(String) }; (mockFs.writeJson as any).mockResolvedValue(undefined); @@ -136,17 +134,17 @@ describe('ConfigManager', () => { expectedConfig, { spaces: 2 } ); + expect(result).not.toHaveProperty('updatedAt'); }); }); describe('update', () => { - it('should update existing config and set updatedAt', async () => { + it('should update existing config without adding updatedAt', async () => { const existingConfig: DevKitConfig = { version: '1.0.0', environments: ['cursor'], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; const updates = { environments: ['cursor' as any, 'claude' as any] }; @@ -158,18 +156,17 @@ describe('ConfigManager', () => { const result = await configManager.update(updates); expect(result.environments).toEqual(['cursor', 'claude']); - expect(result.updatedAt).not.toBe(existingConfig.updatedAt); expect(result.createdAt).toBe(existingConfig.createdAt); + expect(result).not.toHaveProperty('updatedAt'); }); - it('should not rewrite config or change updatedAt when updates are unchanged', async () => { + it('should not rewrite config when updates are unchanged and updatedAt is absent', async () => { const existingConfig: DevKitConfig = { version: '1.0.0', environments: ['cursor'], phases: [], skills: [{ registry: 'codeaholicguy/ai-devkit', name: 'debug' }], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -184,6 +181,34 @@ describe('ConfigManager', () => { expect(mockFs.writeJson).not.toHaveBeenCalled(); }); + it('should remove legacy updatedAt when updating config', async () => { + const existingConfig = { + version: '1.0.0', + environments: ['cursor'], + phases: [], + createdAt: '2024-01-01T00:00:00.000Z', + updatedAt: '2024-01-01T00:00:00.000Z' + }; + + (mockFs.pathExists as any).mockResolvedValue(true); + (mockFs.readJson as any).mockResolvedValue(existingConfig); + (mockFs.writeJson as any).mockResolvedValue(undefined); + + const result = await configManager.update({}); + + expect(result).not.toHaveProperty('updatedAt'); + expect(mockFs.writeJson).toHaveBeenCalledWith( + '/test/dir/.ai-devkit.json', + { + version: '1.0.0', + environments: ['cursor'], + phases: [], + createdAt: '2024-01-01T00:00:00.000Z' + }, + { spaces: 2 } + ); + }); + it('should throw error when config file not found', async () => { (mockFs.readJson as any).mockResolvedValue(null); @@ -200,7 +225,6 @@ describe('ConfigManager', () => { environments: [], phases: ['requirements'], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -218,7 +242,6 @@ describe('ConfigManager', () => { environments: [], phases: ['requirements'], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -235,7 +258,6 @@ describe('ConfigManager', () => { version: '1.0.0', environments: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -255,7 +277,6 @@ describe('ConfigManager', () => { environments: [], phases: ['requirements', 'design'], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -272,7 +293,6 @@ describe('ConfigManager', () => { environments: [], phases: ['requirements'], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -296,7 +316,6 @@ describe('ConfigManager', () => { version: '1.0.0', environments: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -316,7 +335,6 @@ describe('ConfigManager', () => { environments: [], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -333,7 +351,6 @@ describe('ConfigManager', () => { environments: [], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -360,7 +377,6 @@ describe('ConfigManager', () => { environments: [], phases: ['requirements', 'deployment'], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -377,7 +393,6 @@ describe('ConfigManager', () => { environments: [], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -396,7 +411,6 @@ describe('ConfigManager', () => { environments: [], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -417,7 +431,6 @@ describe('ConfigManager', () => { environments: ['cursor', 'claude'], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -442,7 +455,6 @@ describe('ConfigManager', () => { environments: [], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -461,7 +473,6 @@ describe('ConfigManager', () => { environments: ['cursor'], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -482,7 +493,6 @@ describe('ConfigManager', () => { environments: ['cursor', 'claude'], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -499,7 +509,6 @@ describe('ConfigManager', () => { environments: ['cursor'], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -519,7 +528,6 @@ describe('ConfigManager', () => { phases: [], skills: [{ registry: 'codeaholicguy/ai-devkit', name: 'debug' }], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -545,7 +553,6 @@ describe('ConfigManager', () => { phases: [], skills: [{ registry: 'codeaholicguy/ai-devkit', name: 'debug' }], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -566,7 +573,6 @@ describe('ConfigManager', () => { environments: ['cursor'], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -596,7 +602,6 @@ describe('ConfigManager', () => { { registry: 'codeaholicguy/ai-devkit', name: 'memory' } ], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -620,7 +625,6 @@ describe('ConfigManager', () => { { registry: 'codeaholicguy/ai-devkit', name: 'dev-lifecycle' } ], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -642,7 +646,6 @@ describe('ConfigManager', () => { { registry: 'codeaholicguy/ai-devkit', name: 'memory' } ], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }; (mockFs.pathExists as any).mockResolvedValue(true); @@ -677,7 +680,6 @@ describe('ConfigManager', () => { 'invalid/value': false }, createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }); const registries = await configManager.getSkillRegistries(); @@ -695,7 +697,6 @@ describe('ConfigManager', () => { phases: [], skills: [{ registry: 'codeaholicguy/ai-devkit', name: 'debug' }], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }); const registries = await configManager.getSkillRegistries(); @@ -720,7 +721,6 @@ describe('ConfigManager', () => { environments: [], phases: [], createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }); const result = await configManager.getMemoryDbPath(); @@ -736,7 +736,6 @@ describe('ConfigManager', () => { phases: [], memory: { path: ' ' }, createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }); await expect(configManager.getMemoryDbPath()).resolves.toBeUndefined(); @@ -747,7 +746,6 @@ describe('ConfigManager', () => { phases: [], memory: { path: 42 }, createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }); await expect(configManager.getMemoryDbPath()).resolves.toBeUndefined(); @@ -761,7 +759,6 @@ describe('ConfigManager', () => { phases: [], memory: { path: '/custom/memory.db' }, createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }); const result = await configManager.getMemoryDbPath(); @@ -778,7 +775,6 @@ describe('ConfigManager', () => { phases: [], memory: { path: '.ai-devkit/project-memory.db' }, createdAt: '2024-01-01T00:00:00.000Z', - updatedAt: '2024-01-01T00:00:00.000Z' }); const result = await configManager.getMemoryDbPath(); diff --git a/packages/cli/src/lib/Config.ts b/packages/cli/src/lib/Config.ts index 74078157..8d84e7b2 100644 --- a/packages/cli/src/lib/Config.ts +++ b/packages/cli/src/lib/Config.ts @@ -7,10 +7,10 @@ import packageJson from '../../package.json' with { type: 'json' }; const CONFIG_FILE_NAME = '.ai-devkit.json'; -function withoutUpdatedAt(config: DevKitConfig): Omit { - const { updatedAt, ...meaningfulConfig } = config; +function stripLegacyUpdatedAt(config: DevKitConfig): DevKitConfig { + const { updatedAt, ...configWithoutUpdatedAt } = config as DevKitConfig & { updatedAt?: string }; void updatedAt; - return meaningfulConfig; + return configWithoutUpdatedAt; } export class ConfigManager { @@ -40,8 +40,7 @@ export class ConfigManager { version: packageJson.version, environments: [], phases: [], - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString() + createdAt: new Date().toISOString() }; await fs.writeJson(this.configPath, config, { spaces: 2 }); @@ -54,19 +53,17 @@ export class ConfigManager { throw new ConfigNotFoundError('Config file not found. Run ai-devkit init first.'); } + const currentConfig = stripLegacyUpdatedAt(config); const nextConfig = { - ...config, + ...currentConfig, ...updates }; - if (JSON.stringify(withoutUpdatedAt(nextConfig)) === JSON.stringify(withoutUpdatedAt(config))) { - return config; - } + const updated = stripLegacyUpdatedAt(nextConfig); - const updated = { - ...nextConfig, - updatedAt: new Date().toISOString() - }; + if (JSON.stringify(updated) === JSON.stringify(config)) { + return currentConfig; + } await fs.writeJson(this.configPath, updated, { spaces: 2 }); return updated; diff --git a/packages/cli/src/types.ts b/packages/cli/src/types.ts index 915e26af..05ab7482 100644 --- a/packages/cli/src/types.ts +++ b/packages/cli/src/types.ts @@ -34,7 +34,6 @@ export interface DevKitConfig { skills?: ConfigSkill[]; mcpServers?: Record; createdAt: string; - updatedAt: string; } export interface ConfigSkill { diff --git a/web/content/docs/11-configuration-file.md b/web/content/docs/11-configuration-file.md index 3a506fbb..46ffbc14 100644 --- a/web/content/docs/11-configuration-file.md +++ b/web/content/docs/11-configuration-file.md @@ -46,8 +46,7 @@ Use this page as a reference for fields inside `.ai-devkit.json`. In most cases, "args": ["-y", "@ai-devkit/memory"] } }, - "createdAt": "2025-12-28T13:35:45.251Z", - "updatedAt": "2026-04-18T10:00:00.000Z" + "createdAt": "2025-12-28T13:35:45.251Z" } ``` @@ -230,11 +229,11 @@ Every server definition requires a `transport` field set to `stdio`, `http`, or **Set by:** `ai-devkit init --template` or by editing `.ai-devkit.json` directly **Read by:** `ai-devkit install` -#### `createdAt` / `updatedAt` +#### `createdAt` - **Type:** `string` (ISO 8601 timestamp) -- **Set automatically** when the config is created or modified. -- You normally should not edit these fields manually. +- **Set automatically** when the config is created. +- You normally should not edit this field manually. ## Global Config (`~/.ai-devkit/.ai-devkit.json`) From 10b5eafb244ab3049173828e642fe74fc2d83e8d Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Sat, 27 Jun 2026 14:29:46 +0000 Subject: [PATCH 3/3] Preserve legacy updatedAt on no-op config updates --- packages/cli/src/__tests__/lib/Config.test.ts | 16 +++------------- packages/cli/src/lib/Config.ts | 15 +++------------ 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/packages/cli/src/__tests__/lib/Config.test.ts b/packages/cli/src/__tests__/lib/Config.test.ts index e0f61ddf..9abb6d46 100644 --- a/packages/cli/src/__tests__/lib/Config.test.ts +++ b/packages/cli/src/__tests__/lib/Config.test.ts @@ -181,7 +181,7 @@ describe('ConfigManager', () => { expect(mockFs.writeJson).not.toHaveBeenCalled(); }); - it('should remove legacy updatedAt when updating config', async () => { + it('should not rewrite config when only legacy updatedAt is present and updates are unchanged', async () => { const existingConfig = { version: '1.0.0', environments: ['cursor'], @@ -192,21 +192,11 @@ describe('ConfigManager', () => { (mockFs.pathExists as any).mockResolvedValue(true); (mockFs.readJson as any).mockResolvedValue(existingConfig); - (mockFs.writeJson as any).mockResolvedValue(undefined); const result = await configManager.update({}); - expect(result).not.toHaveProperty('updatedAt'); - expect(mockFs.writeJson).toHaveBeenCalledWith( - '/test/dir/.ai-devkit.json', - { - version: '1.0.0', - environments: ['cursor'], - phases: [], - createdAt: '2024-01-01T00:00:00.000Z' - }, - { spaces: 2 } - ); + expect(result).toEqual(existingConfig); + expect(mockFs.writeJson).not.toHaveBeenCalled(); }); it('should throw error when config file not found', async () => { diff --git a/packages/cli/src/lib/Config.ts b/packages/cli/src/lib/Config.ts index 8d84e7b2..9e41b093 100644 --- a/packages/cli/src/lib/Config.ts +++ b/packages/cli/src/lib/Config.ts @@ -7,12 +7,6 @@ import packageJson from '../../package.json' with { type: 'json' }; const CONFIG_FILE_NAME = '.ai-devkit.json'; -function stripLegacyUpdatedAt(config: DevKitConfig): DevKitConfig { - const { updatedAt, ...configWithoutUpdatedAt } = config as DevKitConfig & { updatedAt?: string }; - void updatedAt; - return configWithoutUpdatedAt; -} - export class ConfigManager { private configPath: string; @@ -53,16 +47,13 @@ export class ConfigManager { throw new ConfigNotFoundError('Config file not found. Run ai-devkit init first.'); } - const currentConfig = stripLegacyUpdatedAt(config); - const nextConfig = { - ...currentConfig, + const updated = { + ...config, ...updates }; - const updated = stripLegacyUpdatedAt(nextConfig); - if (JSON.stringify(updated) === JSON.stringify(config)) { - return currentConfig; + return config; } await fs.writeJson(this.configPath, updated, { spaces: 2 });