myaidev-method 0.2.11 → 0.2.12

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/CHANGELOG.md ADDED
@@ -0,0 +1,164 @@
1
+ # Changelog
2
+
3
+ All notable changes to the MyAIDev Method package will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.12] - 2025-11-10
9
+
10
+ ### Added
11
+ - **Update Command**: `npx myaidev-method@latest update` for intelligent component updates
12
+ - Interactive conflict resolution for modified files
13
+ - Automatic backup creation before updates
14
+ - Dry-run mode to preview changes
15
+ - Force mode for clean updates
16
+ - Version tracking with `.claude/.myaidev-version`
17
+ - Updates all components: commands, agents, scripts, libs, docs, MCP configs
18
+ - Comprehensive update documentation in USER_GUIDE.md
19
+ - Update instructions in README.md
20
+ - CHANGELOG.md for version history tracking
21
+
22
+ ### Changed
23
+ - Init command now saves installation version for update tracking
24
+ - Enhanced documentation with update best practices
25
+
26
+ ## [0.2.11] - 2025-11-10
27
+
28
+ ### Fixed
29
+ - Script installation for non-Node.js projects
30
+ - Scripts now installed to `.myaidev-method/` with self-contained dependencies
31
+ - No longer requires Node.js project structure (package.json in root)
32
+ - Works in any project type (WordPress themes, Hugo sites, plain folders)
33
+ - Agent documentation updated to reference `.myaidev-method/` paths
34
+
35
+ ### Changed
36
+ - Scripts copied to `.myaidev-method/scripts/` directory
37
+ - Libraries copied to `.myaidev-method/lib/` directory
38
+ - Dependencies installed locally in `.myaidev-method/node_modules/`
39
+ - Added `.gitignore` guidance in CLAUDE.md template
40
+
41
+ ## [0.2.10] - 2025-11-06
42
+
43
+ ### Changed
44
+ - ⚠️ **Deprecated approach**: Attempted node_modules path (reverted in v0.2.11)
45
+
46
+ ## [0.2.9] - 2025-11-06
47
+
48
+ ### Added
49
+ - User Pathways section in USER_GUIDE.md
50
+ - Content Creator pathway with complete publishing pipeline
51
+ - Developer pathway with SPARC methodology guidance
52
+ - End-to-end workflow examples
53
+
54
+ ### Changed
55
+ - Enhanced documentation structure
56
+ - Improved onboarding experience
57
+
58
+ ## [0.2.8] - 2025-11-06
59
+
60
+ ### Changed
61
+ - Package documentation distribution updates
62
+ - Fixed package.json files array
63
+
64
+ ## [0.2.7] - 2025-11-06
65
+
66
+ ### Added
67
+ - Comprehensive content creation pipeline examples
68
+ - Multi-platform publishing workflows
69
+
70
+ ## [0.2.6] - 2025-11-05
71
+
72
+ ### Changed
73
+ - Documentation updates and improvements
74
+
75
+ ## [0.2.5] - 2025-11-04
76
+
77
+ ### Added
78
+ - PayloadCMS authentication simplification
79
+ - JWT-based authentication for PayloadCMS
80
+ - Improved publishing workflows
81
+
82
+ ## [0.2.4] - 2025-11-03
83
+
84
+ ### Added
85
+ - Slash command fixes and improvements
86
+ - 14 command updates with proper Task tool invocations
87
+
88
+ ## [0.2.3] - 2025-11-02
89
+
90
+ ### Added
91
+ - Enhanced MCP server integration
92
+ - SPARC orchestrator improvements
93
+
94
+ ## [0.2.2] - 2025-11-01
95
+
96
+ ### Added
97
+ - WordPress admin utilities
98
+ - Security scanning scripts
99
+ - Performance checking tools
100
+
101
+ ## [0.2.1] - 2025-10-31
102
+
103
+ ### Added
104
+ - Coolify deployment integration
105
+ - Multi-platform publishing support
106
+
107
+ ## [0.2.0] - 2025-10-30
108
+
109
+ ### Added
110
+ - SPARC methodology implementation
111
+ - Development workflow agents
112
+ - Git & CI/CD workflows
113
+
114
+ ## [0.1.0] - 2025-10-29
115
+
116
+ ### Added
117
+ - Initial release
118
+ - Content writer agent
119
+ - WordPress publishing integration
120
+ - Basic slash commands
121
+ - MCP server foundation
122
+
123
+ ---
124
+
125
+ ## Release Notes
126
+
127
+ ### Version 0.2.12 Highlights
128
+
129
+ **Major Feature: Update Command**
130
+
131
+ The highlight of this release is the new intelligent update system. Users can now easily keep their MyAIDev Method installation current while preserving customizations:
132
+
133
+ ```bash
134
+ npx myaidev-method@latest update --claude
135
+ ```
136
+
137
+ Key features:
138
+ - Interactive conflict resolution - choose what to update
139
+ - Automatic backups - safe rollback if needed
140
+ - Dry-run mode - preview changes first
141
+ - Version tracking - know what version you're running
142
+
143
+ This solves a major pain point where users had to manually track updates or risk losing customizations by re-running init.
144
+
145
+ ### Migration Guide
146
+
147
+ **From v0.2.10 or earlier to v0.2.12**:
148
+
149
+ 1. Your scripts are now in `.myaidev-method/` instead of `node_modules/`
150
+ 2. If you have any custom scripts referencing the old path, update them
151
+ 3. Add `.myaidev-method/node_modules/` to your `.gitignore`
152
+ 4. Use the new update command going forward instead of re-running init
153
+
154
+ **Checking Your Version**:
155
+ ```bash
156
+ cat .claude/.myaidev-version
157
+ ```
158
+
159
+ **First-Time Update Setup**:
160
+ If you installed before v0.2.12, the version file won't exist. The update command will still work, but it won't know your current version. Consider it an upgrade from "unknown" to v0.2.12.
161
+
162
+ ---
163
+
164
+ For more details on any release, see the [commit history](https://github.com/myaione/myaidev-method/commits/master) or [release notes](https://github.com/myaione/myaidev-method/releases).
package/README.md CHANGED
@@ -29,6 +29,7 @@ The **MyAIDev Method** is a complete development framework for AI CLI tools (Cla
29
29
  - [Features](#features)
30
30
  - [Installation](#installation)
31
31
  - [Quick Start](#quick-start)
32
+ - [Updating](#updating)
32
33
  - [SPARC Development Workflow](#sparc-development-workflow)
33
34
  - [Development Agents](#development-agents)
34
35
  - [Content & Publishing Agents](#content--publishing-agents)
@@ -134,6 +135,30 @@ npx myaidev-method@latest init
134
135
  /myai-wordpress-admin health-check
135
136
  ```
136
137
 
138
+ ## 🔄 Updating
139
+
140
+ Keep your MyAIDev Method installation up to date with the latest features and bug fixes:
141
+
142
+ ```bash
143
+ # Interactive update (recommended) - prompts for conflicts
144
+ npx myaidev-method@latest update --claude
145
+
146
+ # Force update - overwrites all files
147
+ npx myaidev-method@latest update --claude --force
148
+
149
+ # Preview changes without updating
150
+ npx myaidev-method@latest update --claude --dry-run
151
+ ```
152
+
153
+ The update command:
154
+ - ✅ Detects your current version
155
+ - ✅ Updates commands, agents, scripts, and documentation
156
+ - ✅ Preserves your customizations (interactive conflict resolution)
157
+ - ✅ Creates automatic backups before updating
158
+ - ✅ Installs updated dependencies
159
+
160
+ See [USER_GUIDE.md - Updating Section](USER_GUIDE.md#-updating-myaidev-method) for detailed update instructions and best practices.
161
+
137
162
  ## 🏗️ SPARC Development Workflow
138
163
 
139
164
  The **MyAIDev Method** implements the **SPARC methodology** - a systematic 5-phase approach to software development inspired by [GitHub Spec-Kit](https://github.com/github/spec-kit) patterns for agentic software development.
package/USER_GUIDE.md CHANGED
@@ -7,6 +7,7 @@ This guide covers everything you need to know about using, customizing, and exte
7
7
  ## 📋 Table of Contents
8
8
 
9
9
  - [Quick Start](#quick-start)
10
+ - [Updating MyAIDev Method](#-updating-myaidev-method)
10
11
  - [Understanding the Structure](#understanding-the-structure)
11
12
  - [👤 User Pathways](#-user-pathways)
12
13
  - [Content Creator Pathway](#content-creator-pathway)
@@ -98,6 +99,161 @@ You'll have a `.claude` folder in your project:
98
99
  /myai-configure agents --list
99
100
  ```
100
101
 
102
+ ## 🔄 Updating MyAIDev Method
103
+
104
+ The MyAIDev Method package receives regular updates with new features, bug fixes, and improved agents. Keep your installation up to date to access the latest capabilities.
105
+
106
+ ### Checking for Updates
107
+
108
+ Your current installation version is stored in `.claude/.myaidev-version`. When new versions are published to npm, you can update using the dedicated update command.
109
+
110
+ ### Running Updates
111
+
112
+ ```bash
113
+ # Interactive update (recommended) - prompts for conflicts
114
+ npx myaidev-method@latest update --claude
115
+
116
+ # Force update - overwrites all files without prompting
117
+ npx myaidev-method@latest update --claude --force
118
+
119
+ # Preview changes - see what would be updated without making changes
120
+ npx myaidev-method@latest update --claude --dry-run
121
+
122
+ # Verbose output - show detailed progress
123
+ npx myaidev-method@latest update --claude --verbose
124
+ ```
125
+
126
+ ### What Gets Updated
127
+
128
+ The update command updates all MyAIDev Method components:
129
+
130
+ - ✅ **Slash commands** (`.claude/commands/`) - New commands and improvements
131
+ - ✅ **Agent definitions** (`.claude/agents/`) - Enhanced prompts and capabilities
132
+ - ✅ **Executable scripts** (`.myaidev-method/scripts/`) - Bug fixes and new features
133
+ - ✅ **Utility libraries** (`.myaidev-method/lib/`) - Helper functions and utilities
134
+ - ✅ **Documentation files** (`USER_GUIDE.md`, `PUBLISHING_GUIDE.md`, etc.) - Updated guides
135
+ - ✅ **MCP configurations** (`.claude/mcp/`) - Server configurations and integrations
136
+ - ✅ **Dependencies** (`.myaidev-method/package.json`) - npm package updates
137
+
138
+ ### Handling Customizations
139
+
140
+ If you've customized agents or commands, the update process intelligently handles conflicts:
141
+
142
+ 1. **Detection**: The update command detects which files you've modified
143
+ 2. **Diff Display**: Shows you the differences between your version and the new version
144
+ 3. **User Choice**: You decide what to do for each modified file:
145
+ - **Keep current** - Skip this update, preserve your customizations
146
+ - **Use new version** - Overwrite with the latest version
147
+ - **View diff** - See detailed line-by-line differences
148
+ - **Keep + backup** - Update to new version and save your current version as `.bak`
149
+
150
+ Example update session:
151
+
152
+ ```
153
+ $ npx myaidev-method@latest update --claude
154
+
155
+ 🔍 Detecting MyAIDev Method installation...
156
+
157
+ ✓ Found claude installation
158
+ Current version: 0.2.11
159
+ Latest version: 0.2.12
160
+
161
+ ⚠️ This will update your MyAIDev Method installation
162
+ Modified files will require your confirmation
163
+
164
+ ? Continue with update? Yes
165
+
166
+ 💾 Creating backup...
167
+ ✓ Backup created at: .myaidev-method-backup-2025-11-10T20-59-00
168
+
169
+ 📦 Updating components...
170
+
171
+ Commands:
172
+ ➕ myai-new-feature.md (new)
173
+ ✓ myai-git-pr.md (unchanged)
174
+
175
+ Agents:
176
+ 📝 content-writer.md has been modified
177
+ ? What would you like to do?
178
+ ❯ Keep current version (skip update)
179
+ Use new version (overwrite)
180
+ View diff
181
+ Keep current + backup (.bak)
182
+
183
+ ✅ payloadcms-publish.md (updated)
184
+
185
+ Scripts:
186
+ ✅ payloadcms-publish.js (updated)
187
+ ✅ coolify-deploy-app.js (updated)
188
+
189
+ ═══════════════════════════════════════
190
+ Update Summary
191
+ ═══════════════════════════════════════
192
+ ✅ Updated: 5 files
193
+ ➕ Added: 2 new files
194
+ ⏭️ Skipped: 1 files (kept current)
195
+ ═══════════════════════════════════════
196
+
197
+ ✅ Successfully updated to v0.2.12
198
+ Backup available at: .myaidev-method-backup-2025-11-10T20-59-00
199
+ ```
200
+
201
+ ### Safety Features
202
+
203
+ **Automatic Backups**: Before making any changes, the update command creates a complete backup:
204
+ ```
205
+ .myaidev-method-backup-{timestamp}/
206
+ ├── .claude/
207
+ ├── .myaidev-method/
208
+ └── *.md (documentation files)
209
+ ```
210
+
211
+ **Dry Run Mode**: Preview all changes without modifying any files:
212
+ ```bash
213
+ npx myaidev-method@latest update --claude --dry-run
214
+ ```
215
+
216
+ **Version Tracking**: The update command checks your current version and only proceeds if an update is available.
217
+
218
+ ### Best Practices
219
+
220
+ 1. **Review Release Notes**: Check the [CHANGELOG.md](CHANGELOG.md) before updating
221
+ 2. **Use Dry Run**: Preview changes with `--dry-run` before actual update
222
+ 3. **Backup Custom Work**: If you have heavily customized agents, create manual backups
223
+ 4. **Update Regularly**: Stay current with latest features and security fixes
224
+ 5. **Test After Update**: Verify your workflows still function as expected
225
+
226
+ ### Troubleshooting Updates
227
+
228
+ **Update command not found**:
229
+ ```bash
230
+ # Ensure you're using the latest package
231
+ npx myaidev-method@latest --version
232
+ ```
233
+
234
+ **No installation detected**:
235
+ ```bash
236
+ # Verify installation exists
237
+ ls -la .claude
238
+
239
+ # Reinstall if needed
240
+ npx myaidev-method@latest init --claude
241
+ ```
242
+
243
+ **Dependency installation fails**:
244
+ ```bash
245
+ # Manually install dependencies
246
+ cd .myaidev-method
247
+ npm install
248
+ ```
249
+
250
+ **Want to rollback an update**:
251
+ ```bash
252
+ # Restore from backup
253
+ rm -rf .claude .myaidev-method *.md
254
+ cp -r .myaidev-method-backup-{timestamp}/* .
255
+ ```
256
+
101
257
  ## 🏗️ Understanding the Structure
102
258
 
103
259
  ### Commands Directory (`.claude/commands/`)
package/bin/cli.js CHANGED
@@ -327,6 +327,29 @@ To update dependencies, run \`npm install\` inside the \`.myaidev-method/\` dire
327
327
  .myaidev-method/node_modules/
328
328
  \`\`\`
329
329
 
330
+ ## Updating MyAIDev Method
331
+
332
+ To get the latest features, bug fixes, and improved agents:
333
+
334
+ \`\`\`bash
335
+ # Interactive update (recommended) - prompts for conflicts
336
+ npx myaidev-method@latest update --claude
337
+
338
+ # Force update - overwrites all files
339
+ npx myaidev-method@latest update --claude --force
340
+
341
+ # Preview changes without updating
342
+ npx myaidev-method@latest update --claude --dry-run
343
+ \`\`\`
344
+
345
+ The update command:
346
+ - ✅ Preserves your customizations (interactive conflict resolution)
347
+ - ✅ Creates automatic backups before updating
348
+ - ✅ Updates all components (commands, agents, scripts, docs)
349
+ - ✅ Installs updated dependencies
350
+
351
+ See \`USER_GUIDE.md\` for detailed update instructions and best practices.
352
+
330
353
  ## Notes
331
354
 
332
355
  This configuration follows Claude Code's official standards for custom commands and agents.
@@ -424,6 +447,11 @@ This configuration follows Claude Code's official standards for custom commands
424
447
  await fs.copy(sourcePath, path.join(projectDir, docFile));
425
448
  }
426
449
  }
450
+
451
+ // Save installation version for update tracking
452
+ const pkgJson = await fs.readJson(path.join(__dirname, '..', 'package.json'));
453
+ const versionFile = path.join(claudeDir, '.myaidev-version');
454
+ await fs.writeFile(versionFile, pkgJson.version);
427
455
  }
428
456
 
429
457
  async function setupGemini(projectDir) {
@@ -582,6 +610,154 @@ For full documentation, see the USER_GUIDE.md in your project root.
582
610
  await fs.writeFile(path.join(codexDir, 'README.md'), opencodeReadme);
583
611
  }
584
612
 
613
+ program
614
+ .command('update')
615
+ .description('Update MyAIDev Method components to latest version')
616
+ .option('--claude', 'Update Claude Code configuration')
617
+ .option('--gemini', 'Update Gemini CLI configuration')
618
+ .option('--codex', 'Update Codex CLI configuration')
619
+ .option('--force', 'Force update all files without prompting')
620
+ .option('--dry-run', 'Show what would be updated without making changes')
621
+ .option('--verbose', 'Show detailed progress')
622
+ .action(async (options) => {
623
+ const ora = (await import('ora')).default;
624
+ const { fileURLToPath } = await import('url');
625
+ const updateManager = await import('../src/lib/update-manager.js');
626
+
627
+ const __filename = fileURLToPath(import.meta.url);
628
+ const __dirname = path.dirname(__filename);
629
+ const packageRoot = path.join(__dirname, '..');
630
+
631
+ try {
632
+ const cwd = process.cwd();
633
+
634
+ // Detect existing installation
635
+ console.log(chalk.cyan('\n🔍 Detecting MyAIDev Method installation...\n'));
636
+ const installation = await updateManager.detectExistingInstallation(cwd);
637
+
638
+ if (!installation) {
639
+ console.log(chalk.red('❌ No MyAIDev Method installation found'));
640
+ console.log(chalk.gray(' Run: npx myaidev-method@latest init --claude'));
641
+ process.exit(1);
642
+ }
643
+
644
+ console.log(chalk.green(`✓ Found ${installation.type} installation`));
645
+ console.log(chalk.gray(` Current version: ${installation.currentVersion}`));
646
+
647
+ // Get package version
648
+ const packageJson = await fs.readJson(path.join(packageRoot, 'package.json'));
649
+ const newVersion = packageJson.version;
650
+
651
+ console.log(chalk.gray(` Latest version: ${newVersion}`));
652
+
653
+ // Check if already up to date
654
+ if (installation.currentVersion === newVersion && !options.force) {
655
+ console.log(chalk.green('\n✅ Already up to date!'));
656
+ process.exit(0);
657
+ }
658
+
659
+ if (options.dryRun) {
660
+ console.log(chalk.yellow('\n📋 DRY RUN MODE - No changes will be made\n'));
661
+ } else if (!options.force) {
662
+ console.log(chalk.yellow('\n⚠️ This will update your MyAIDev Method installation'));
663
+ console.log(chalk.gray(' Modified files will require your confirmation\n'));
664
+
665
+ const { confirm } = await inquirer.prompt([
666
+ {
667
+ type: 'confirm',
668
+ name: 'confirm',
669
+ message: 'Continue with update?',
670
+ default: true
671
+ }
672
+ ]);
673
+
674
+ if (!confirm) {
675
+ console.log(chalk.gray('Update cancelled'));
676
+ process.exit(0);
677
+ }
678
+ }
679
+
680
+ // Create backup unless dry-run
681
+ let backupDir;
682
+ if (!options.dryRun) {
683
+ console.log(chalk.cyan('\n💾 Creating backup...'));
684
+ backupDir = await updateManager.createBackup(cwd, installation.type);
685
+ console.log(chalk.green(`✓ Backup created at: ${path.basename(backupDir)}`));
686
+ }
687
+
688
+ // Update components
689
+ const allStats = {};
690
+
691
+ console.log(chalk.cyan('\n📦 Updating components...\n'));
692
+
693
+ // Commands
694
+ console.log(chalk.blue('Commands:'));
695
+ allStats.commands = await updateManager.updateComponent(
696
+ 'commands', cwd, installation.type, packageRoot, options
697
+ );
698
+
699
+ // Agents
700
+ console.log(chalk.blue('\nAgents:'));
701
+ allStats.agents = await updateManager.updateComponent(
702
+ 'agents', cwd, installation.type, packageRoot, options
703
+ );
704
+
705
+ // Scripts
706
+ console.log(chalk.blue('\nScripts:'));
707
+ allStats.scripts = await updateManager.updateComponent(
708
+ 'scripts', cwd, installation.type, packageRoot, options
709
+ );
710
+
711
+ // Libraries
712
+ console.log(chalk.blue('\nLibraries:'));
713
+ allStats.lib = await updateManager.updateComponent(
714
+ 'lib', cwd, installation.type, packageRoot, options
715
+ );
716
+
717
+ // MCP configurations
718
+ console.log(chalk.blue('\nMCP Configurations:'));
719
+ allStats.mcp = await updateManager.updateComponent(
720
+ 'mcp', cwd, installation.type, packageRoot, options
721
+ );
722
+
723
+ // Documentation
724
+ console.log(chalk.blue('\nDocumentation:'));
725
+ allStats.docs = await updateManager.updateComponent(
726
+ 'docs', cwd, installation.type, packageRoot, options
727
+ );
728
+
729
+ // Update dependencies
730
+ if (!options.dryRun) {
731
+ await updateManager.updateDependencies(cwd);
732
+ }
733
+
734
+ // Save new version
735
+ if (!options.dryRun) {
736
+ await updateManager.saveVersion(cwd, installation.type, newVersion);
737
+ }
738
+
739
+ // Show report
740
+ updateManager.generateUpdateReport(allStats);
741
+
742
+ if (options.dryRun) {
743
+ console.log(chalk.yellow('This was a dry run. No changes were made.'));
744
+ } else {
745
+ console.log(chalk.green(`✅ Successfully updated to v${newVersion}`));
746
+ if (backupDir) {
747
+ console.log(chalk.gray(` Backup available at: ${path.basename(backupDir)}`));
748
+ }
749
+ }
750
+
751
+ } catch (error) {
752
+ console.error(chalk.red('\n❌ Update failed:'));
753
+ console.error(error.message);
754
+ if (options.verbose) {
755
+ console.error(error);
756
+ }
757
+ process.exit(1);
758
+ }
759
+ });
760
+
585
761
  program
586
762
  .command('claudeweb')
587
763
  .description('Start MyAIDev Method Web UI with Claude Code Viewer')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myaidev-method",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "description": "Comprehensive development framework with SPARC methodology for AI-assisted software development, multi-platform publishing (WordPress, PayloadCMS, Astro, Docusaurus, Mintlify), and Coolify deployment",
5
5
  "mcpName": "io.github.myaione/myaidev-method",
6
6
  "main": "src/index.js",
@@ -142,7 +142,8 @@
142
142
  "PUBLISHING_GUIDE.md",
143
143
  "TECHNICAL_ARCHITECTURE.md",
144
144
  "PACKAGE_FIXES_SUMMARY.md",
145
- "PAYLOADCMS_AUTH_UPDATE.md"
145
+ "PAYLOADCMS_AUTH_UPDATE.md",
146
+ "CHANGELOG.md"
146
147
  ],
147
148
  "engines": {
148
149
  "node": ">=18.0.0"
@@ -0,0 +1,385 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import inquirer from 'inquirer';
5
+ import { createHash } from 'crypto';
6
+
7
+ /**
8
+ * Update Manager for MyAIDev Method
9
+ * Handles intelligent updates with conflict resolution
10
+ */
11
+
12
+ /**
13
+ * Detect existing MyAIDev Method installation
14
+ * @param {string} projectDir - Project directory path
15
+ * @returns {Object} Installation info or null
16
+ */
17
+ export async function detectExistingInstallation(projectDir) {
18
+ const installations = {
19
+ claude: path.join(projectDir, '.claude'),
20
+ gemini: path.join(projectDir, '.gemini'),
21
+ codex: path.join(projectDir, '.codex')
22
+ };
23
+
24
+ for (const [type, dir] of Object.entries(installations)) {
25
+ if (await fs.pathExists(dir)) {
26
+ // Check for version file
27
+ const versionFile = path.join(dir, '.myaidev-version');
28
+ let currentVersion = 'unknown';
29
+
30
+ if (await fs.pathExists(versionFile)) {
31
+ currentVersion = (await fs.readFile(versionFile, 'utf-8')).trim();
32
+ }
33
+
34
+ return {
35
+ type,
36
+ dir,
37
+ currentVersion,
38
+ scriptsDir: path.join(projectDir, '.myaidev-method')
39
+ };
40
+ }
41
+ }
42
+
43
+ return null;
44
+ }
45
+
46
+ /**
47
+ * Get file hash for comparison
48
+ * @param {string} filePath - Path to file
49
+ * @returns {string} File hash
50
+ */
51
+ async function getFileHash(filePath) {
52
+ if (!await fs.pathExists(filePath)) {
53
+ return null;
54
+ }
55
+ const content = await fs.readFile(filePath);
56
+ return createHash('md5').update(content).digest('hex');
57
+ }
58
+
59
+ /**
60
+ * Compare two files
61
+ * @param {string} localFile - Local file path
62
+ * @param {string} newFile - New file path
63
+ * @returns {string} Status: 'identical', 'modified', 'new', 'deleted'
64
+ */
65
+ export async function compareFiles(localFile, newFile) {
66
+ const localExists = await fs.pathExists(localFile);
67
+ const newExists = await fs.pathExists(newFile);
68
+
69
+ if (!localExists && newExists) return 'new';
70
+ if (localExists && !newExists) return 'deleted';
71
+ if (!localExists && !newExists) return 'none';
72
+
73
+ const localHash = await getFileHash(localFile);
74
+ const newHash = await getFileHash(newFile);
75
+
76
+ return localHash === newHash ? 'identical' : 'modified';
77
+ }
78
+
79
+ /**
80
+ * Show diff preview for a file
81
+ * @param {string} localFile - Local file path
82
+ * @param {string} newFile - New file path
83
+ */
84
+ async function showDiff(localFile, newFile) {
85
+ const localContent = await fs.readFile(localFile, 'utf-8');
86
+ const newContent = await fs.readFile(newFile, 'utf-8');
87
+
88
+ const localLines = localContent.split('\n');
89
+ const newLines = newContent.split('\n');
90
+
91
+ console.log(chalk.cyan('\n Local version (first 10 lines):'));
92
+ localLines.slice(0, 10).forEach((line, i) => {
93
+ console.log(chalk.gray(` ${i + 1}: ${line.slice(0, 80)}`));
94
+ });
95
+
96
+ console.log(chalk.green('\n New version (first 10 lines):'));
97
+ newLines.slice(0, 10).forEach((line, i) => {
98
+ console.log(chalk.gray(` ${i + 1}: ${line.slice(0, 80)}`));
99
+ });
100
+
101
+ console.log(chalk.yellow(`\n Local: ${localLines.length} lines, New: ${newLines.length} lines\n`));
102
+ }
103
+
104
+ /**
105
+ * Prompt user for conflict resolution
106
+ * @param {string} file - File path relative to project
107
+ * @param {string} localPath - Local file absolute path
108
+ * @param {string} newPath - New file absolute path
109
+ * @returns {string} User choice: 'keep', 'replace', 'backup'
110
+ */
111
+ export async function promptForConflict(file, localPath, newPath) {
112
+ console.log(chalk.yellow(`\n📝 ${file} has been modified`));
113
+
114
+ const answer = await inquirer.prompt([
115
+ {
116
+ type: 'list',
117
+ name: 'action',
118
+ message: 'What would you like to do?',
119
+ choices: [
120
+ { name: 'Keep current version (skip update)', value: 'keep' },
121
+ { name: 'Use new version (overwrite)', value: 'replace' },
122
+ { name: 'View diff', value: 'diff' },
123
+ { name: 'Keep current + backup (.bak)', value: 'backup' }
124
+ ]
125
+ }
126
+ ]);
127
+
128
+ if (answer.action === 'diff') {
129
+ await showDiff(localPath, newPath);
130
+ // Prompt again after showing diff
131
+ return promptForConflict(file, localPath, newPath);
132
+ }
133
+
134
+ return answer.action;
135
+ }
136
+
137
+ /**
138
+ * Create backup of installation
139
+ * @param {string} projectDir - Project directory
140
+ * @param {string} cliType - CLI type (claude/gemini/codex)
141
+ * @returns {string} Backup directory path
142
+ */
143
+ export async function createBackup(projectDir, cliType) {
144
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
145
+ const backupDir = path.join(projectDir, `.myaidev-method-backup-${timestamp}`);
146
+
147
+ await fs.ensureDir(backupDir);
148
+
149
+ // Backup CLI directory
150
+ const cliDir = path.join(projectDir, `.${cliType}`);
151
+ if (await fs.pathExists(cliDir)) {
152
+ await fs.copy(cliDir, path.join(backupDir, `.${cliType}`));
153
+ }
154
+
155
+ // Backup scripts directory
156
+ const scriptsDir = path.join(projectDir, '.myaidev-method');
157
+ if (await fs.pathExists(scriptsDir)) {
158
+ await fs.copy(scriptsDir, path.join(backupDir, '.myaidev-method'));
159
+ }
160
+
161
+ // Backup documentation
162
+ const docs = [
163
+ 'USER_GUIDE.md',
164
+ 'PUBLISHING_GUIDE.md',
165
+ 'COOLIFY_DEPLOYMENT.md',
166
+ 'DEV_WORKFLOW_GUIDE.md',
167
+ 'MCP_INTEGRATION.md',
168
+ 'WORDPRESS_ADMIN_SCRIPTS.md',
169
+ 'TECHNICAL_ARCHITECTURE.md'
170
+ ];
171
+
172
+ for (const doc of docs) {
173
+ const docPath = path.join(projectDir, doc);
174
+ if (await fs.pathExists(docPath)) {
175
+ await fs.copy(docPath, path.join(backupDir, doc));
176
+ }
177
+ }
178
+
179
+ return backupDir;
180
+ }
181
+
182
+ /**
183
+ * Update a specific component
184
+ * @param {string} componentType - Type of component
185
+ * @param {string} projectDir - Project directory
186
+ * @param {string} cliType - CLI type
187
+ * @param {string} sourceDir - Source directory with new files
188
+ * @param {Object} options - Update options
189
+ * @returns {Object} Update statistics
190
+ */
191
+ export async function updateComponent(componentType, projectDir, cliType, sourceDir, options = {}) {
192
+ const stats = {
193
+ updated: 0,
194
+ skipped: 0,
195
+ added: 0,
196
+ errors: 0
197
+ };
198
+
199
+ let targetDir, sourceSubDir;
200
+
201
+ switch (componentType) {
202
+ case 'commands':
203
+ targetDir = path.join(projectDir, `.${cliType}`, 'commands');
204
+ sourceSubDir = path.join(sourceDir, 'src', 'templates', cliType, 'commands');
205
+ break;
206
+ case 'agents':
207
+ targetDir = path.join(projectDir, `.${cliType}`, 'agents');
208
+ sourceSubDir = path.join(sourceDir, 'src', 'templates', 'claude', 'agents');
209
+ break;
210
+ case 'scripts':
211
+ targetDir = path.join(projectDir, '.myaidev-method', 'scripts');
212
+ sourceSubDir = path.join(sourceDir, 'src', 'scripts');
213
+ break;
214
+ case 'lib':
215
+ targetDir = path.join(projectDir, '.myaidev-method', 'lib');
216
+ sourceSubDir = path.join(sourceDir, 'src', 'lib');
217
+ break;
218
+ case 'mcp':
219
+ targetDir = path.join(projectDir, `.${cliType}`, 'mcp');
220
+ sourceSubDir = path.join(sourceDir, '.claude', 'mcp');
221
+ break;
222
+ case 'docs':
223
+ targetDir = projectDir;
224
+ sourceSubDir = sourceDir;
225
+ break;
226
+ default:
227
+ throw new Error(`Unknown component type: ${componentType}`);
228
+ }
229
+
230
+ if (!await fs.pathExists(sourceSubDir)) {
231
+ console.log(chalk.gray(` Skipping ${componentType} (not found in package)`));
232
+ return stats;
233
+ }
234
+
235
+ const files = componentType === 'docs'
236
+ ? ['USER_GUIDE.md', 'PUBLISHING_GUIDE.md', 'COOLIFY_DEPLOYMENT.md', 'DEV_WORKFLOW_GUIDE.md',
237
+ 'MCP_INTEGRATION.md', 'WORDPRESS_ADMIN_SCRIPTS.md', 'TECHNICAL_ARCHITECTURE.md']
238
+ : await fs.readdir(sourceSubDir);
239
+
240
+ for (const file of files) {
241
+ // Skip init-project.js from scripts
242
+ if (componentType === 'scripts' && file === 'init-project.js') continue;
243
+
244
+ const sourcePath = path.join(sourceSubDir, file);
245
+ const targetPath = path.join(targetDir, file);
246
+
247
+ // Skip if source doesn't exist (for docs)
248
+ if (!await fs.pathExists(sourcePath)) continue;
249
+
250
+ // Skip directories
251
+ const sourceStats = await fs.stat(sourcePath);
252
+ if (sourceStats.isDirectory()) continue;
253
+
254
+ // Skip non-relevant files for component type
255
+ if (componentType === 'commands' && !file.endsWith('.md') && !file.endsWith('.toml')) continue;
256
+ if (componentType === 'agents' && !file.endsWith('.md')) continue;
257
+ if (componentType === 'scripts' && !file.endsWith('.js')) continue;
258
+ if (componentType === 'mcp' && !file.endsWith('.js') && !file.endsWith('.json')) continue;
259
+
260
+ const status = await compareFiles(targetPath, sourcePath);
261
+
262
+ if (status === 'identical') {
263
+ if (options.verbose) {
264
+ console.log(chalk.gray(` ✓ ${file} (unchanged)`));
265
+ }
266
+ continue;
267
+ }
268
+
269
+ if (status === 'new') {
270
+ await fs.copy(sourcePath, targetPath);
271
+ console.log(chalk.green(` ➕ ${file} (new)`));
272
+ stats.added++;
273
+ continue;
274
+ }
275
+
276
+ if (status === 'modified') {
277
+ if (options.force) {
278
+ await fs.copy(sourcePath, targetPath);
279
+ console.log(chalk.blue(` ✅ ${file} (updated)`));
280
+ stats.updated++;
281
+ } else if (options.dryRun) {
282
+ console.log(chalk.yellow(` 📝 ${file} (would update)`));
283
+ } else {
284
+ const action = await promptForConflict(file, targetPath, sourcePath);
285
+
286
+ if (action === 'replace') {
287
+ await fs.copy(sourcePath, targetPath);
288
+ console.log(chalk.blue(` ✅ ${file} (updated)`));
289
+ stats.updated++;
290
+ } else if (action === 'backup') {
291
+ await fs.copy(targetPath, `${targetPath}.bak`);
292
+ await fs.copy(sourcePath, targetPath);
293
+ console.log(chalk.blue(` ✅ ${file} (updated, backup created)`));
294
+ stats.updated++;
295
+ } else {
296
+ console.log(chalk.gray(` ⏭️ ${file} (kept current)`));
297
+ stats.skipped++;
298
+ }
299
+ }
300
+ }
301
+ }
302
+
303
+ return stats;
304
+ }
305
+
306
+ /**
307
+ * Update dependencies in .myaidev-method
308
+ * @param {string} projectDir - Project directory
309
+ * @returns {boolean} Success status
310
+ */
311
+ export async function updateDependencies(projectDir) {
312
+ const myaidevDir = path.join(projectDir, '.myaidev-method');
313
+ const packageJsonPath = path.join(myaidevDir, 'package.json');
314
+
315
+ if (!await fs.pathExists(packageJsonPath)) {
316
+ console.log(chalk.yellow(' ⚠️ No package.json found in .myaidev-method/'));
317
+ return false;
318
+ }
319
+
320
+ console.log(chalk.cyan('\n📦 Updating dependencies...'));
321
+
322
+ const { execSync } = await import('child_process');
323
+ try {
324
+ execSync('npm install', {
325
+ cwd: myaidevDir,
326
+ stdio: 'inherit'
327
+ });
328
+ console.log(chalk.green(' ✓ Dependencies updated successfully'));
329
+ return true;
330
+ } catch (error) {
331
+ console.log(chalk.red(' ✗ Failed to update dependencies'));
332
+ console.log(chalk.gray(' Run: cd .myaidev-method && npm install'));
333
+ return false;
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Save version to installation
339
+ * @param {string} projectDir - Project directory
340
+ * @param {string} cliType - CLI type
341
+ * @param {string} version - Version to save
342
+ */
343
+ export async function saveVersion(projectDir, cliType, version) {
344
+ const versionFile = path.join(projectDir, `.${cliType}`, '.myaidev-version');
345
+ await fs.writeFile(versionFile, version);
346
+ }
347
+
348
+ /**
349
+ * Generate update report
350
+ * @param {Object} allStats - Combined statistics from all components
351
+ */
352
+ export function generateUpdateReport(allStats) {
353
+ const total = {
354
+ updated: 0,
355
+ skipped: 0,
356
+ added: 0,
357
+ errors: 0
358
+ };
359
+
360
+ for (const stats of Object.values(allStats)) {
361
+ total.updated += stats.updated;
362
+ total.skipped += stats.skipped;
363
+ total.added += stats.added;
364
+ total.errors += stats.errors;
365
+ }
366
+
367
+ console.log(chalk.cyan('\n═══════════════════════════════════════'));
368
+ console.log(chalk.cyan(' Update Summary'));
369
+ console.log(chalk.cyan('═══════════════════════════════════════'));
370
+
371
+ if (total.updated > 0) {
372
+ console.log(chalk.green(` ✅ Updated: ${total.updated} files`));
373
+ }
374
+ if (total.added > 0) {
375
+ console.log(chalk.green(` ➕ Added: ${total.added} new files`));
376
+ }
377
+ if (total.skipped > 0) {
378
+ console.log(chalk.gray(` ⏭️ Skipped: ${total.skipped} files (kept current)`));
379
+ }
380
+ if (total.errors > 0) {
381
+ console.log(chalk.red(` ✗ Errors: ${total.errors} files`));
382
+ }
383
+
384
+ console.log(chalk.cyan('═══════════════════════════════════════\n'));
385
+ }