diff --git a/.claude/skills/tech-lead/SKILL.md b/.claude/skills/tech-lead/SKILL.md index 826ebb45..120c206d 100644 --- a/.claude/skills/tech-lead/SKILL.md +++ b/.claude/skills/tech-lead/SKILL.md @@ -215,36 +215,54 @@ Alternatively, proceed with implementation if user accepts the complexity. Ask u ### Phase 5: Implementation Start -**Step 7: Branch Creation and Implementation** +**Step 7: Branch Protection Check and Implementation** If user agrees to proceed with implementation: -**CRITICAL: Always create feature branch before any code changes** +**CRITICAL: NEVER implement on main/master. Always check branch first.** -1. **Create Feature Branch:** - ```bash - # Check current branch - git branch --show-current +**7a. Check Current Branch (MANDATORY FIRST STEP):** +```bash +git branch --show-current +``` + +**7b. If on `main` or `master` branch — STOP immediately:** + +Do NOT write any code. Display this message: + +```markdown +⚠️ **Branch Protection**: You are currently on the `main` branch. - # Create and switch to feature branch - # For Jira tickets: - git checkout -b EPMCDME-XXXXX +Implementation cannot start on `main`. I will create a feature branch first. - # For non-Jira tasks (use determined branch name): - git checkout -b feature/branch-name - ``` +Creating branch: `[determined-branch-name]`... +``` + +Then create the feature branch immediately before touching any files. -2. **Verify Branch:** - ```bash - # Confirm on new branch - git branch --show-current - ``` +**7c. If already on a feature branch — proceed normally.** -3. **Begin Implementation:** - - Follow patterns identified in analysis phase - - Reference guides for standard approaches - - Implement changes layer by layer (API → Service → Repository) - - Apply security and performance patterns +**7d. Create Feature Branch (if on main/master or no branch exists):** +```bash +# Create and switch to feature branch +# For Jira tickets: +git checkout -b EPMCDME-XXXXX + +# For non-Jira tasks (use determined branch name): +git checkout -b feature/branch-name +``` + +**7e. Verify Branch:** +```bash +# Confirm on correct branch (must NOT be main or master) +git branch --show-current +``` + +**7f. Begin Implementation:** +- Follow patterns identified in analysis phase +- Reference guides for standard approaches +- Implement changes layer by layer (API → Service → Repository) +- Apply security and performance patterns **Branch Naming:** @@ -283,6 +301,7 @@ For non-Jira tasks: ❌ Don't skip guide consultation ❌ Don't ask generic clarifying questions ❌ Don't start coding without branch creation +❌ Don't write ANY code while on `main` or `master` branch ❌ Don't make architectural decisions for complex features without user input ❌ Don't fetch unnecessary Jira fields (when using Jira) ❌ Don't guess at complexity—analyze systematically @@ -382,6 +401,18 @@ Unable to fetch Jira ticket [ID]. Please verify: - You have access to view this ticket ``` +### Currently on Main Branch + +When `git branch --show-current` returns `main` or `master`: + +```markdown +⚠️ **Branch Protection**: You are currently on the `main` branch. + +Implementation cannot start on `main`. Creating feature branch `[branch-name]` now... +``` + +Then immediately run `git checkout -b [branch-name]` before any file edits. + ### Branch Already Exists ```markdown Branch [EPMCDME-XXXXX] already exists. diff --git a/src/agents/core/extension/BaseExtensionInstaller.ts b/src/agents/core/extension/BaseExtensionInstaller.ts index 1b29241d..6ec07ca0 100644 --- a/src/agents/core/extension/BaseExtensionInstaller.ts +++ b/src/agents/core/extension/BaseExtensionInstaller.ts @@ -25,7 +25,7 @@ import { mkdir, cp, access, readFile, writeFile, readdir, stat, rm } from 'fs/pr import { join, dirname, relative } from 'path'; import { constants, existsSync } from 'fs'; import { logger } from '../../../utils/logger.js'; -import { normalizePathSeparators } from '../../../utils/paths.js'; +import { normalizePathSeparators, getCodemiePath } from '../../../utils/paths.js'; /** * Configuration for selective local file copying @@ -460,7 +460,7 @@ export abstract class BaseExtensionInstaller { targetPath: string, version: string | null ): Promise { - const versionFile = join(targetPath, `${this.agentName}.extension.json`); + const versionFile = getCodemiePath(`${this.agentName}.extension.json`); const versionInfo = { version: version || 'unknown', @@ -478,10 +478,8 @@ export abstract class BaseExtensionInstaller { /** * Check if local extension should be updated * - * Performs integrity checks before trusting version file: * 1. Verifies target directory exists - * 2. Verifies directory contains actual files (not just version file) - * 3. Compares versions only if directory is valid + * 2. Compares source version against ~/.codemie/.extension.json * * @param targetPath - Target directory path * @param sourceVersion - Source extension version @@ -491,7 +489,7 @@ export abstract class BaseExtensionInstaller { targetPath: string, sourceVersion: string ): Promise { - const versionFile = join(targetPath, `${this.agentName}.extension.json`); + const versionFile = getCodemiePath(`${this.agentName}.extension.json`); try { // 1. Check if target directory exists @@ -501,21 +499,12 @@ export abstract class BaseExtensionInstaller { return true; } - // 2. Verify directory has actual content (not just version file) - const entries = await readdir(targetPath); - const actualFiles = entries.filter(entry => entry !== `${this.agentName}.extension.json`); - - if (actualFiles.length === 0) { - logger.debug(`[${this.agentName}] Target directory is empty (no files besides version), will install`); - return true; - } - - // 3. Now check version file (directory exists and has files) + // 2. Check version file in ~/.codemie/ const content = await readFile(versionFile, 'utf-8'); const versionInfo = JSON.parse(content); if (versionInfo.version === sourceVersion) { - logger.debug(`[${this.agentName}] Local extension already at v${sourceVersion} with ${actualFiles.length} files`); + logger.debug(`[${this.agentName}] Local extension already at v${sourceVersion}`); return false; } diff --git a/src/agents/core/extension/__tests__/BaseExtensionInstaller-windows.test.ts b/src/agents/core/extension/__tests__/BaseExtensionInstaller-windows.test.ts index 1fbe6f03..4086e600 100644 --- a/src/agents/core/extension/__tests__/BaseExtensionInstaller-windows.test.ts +++ b/src/agents/core/extension/__tests__/BaseExtensionInstaller-windows.test.ts @@ -51,33 +51,33 @@ describe('BaseExtensionInstaller - Windows Path Handling', () => { describe('Glob Pattern Matching', () => { describe('Windows Path Scenarios', () => { it('should match Windows path after normalization', () => { - const windowsPath = 'claude-templates\\README.md'; + const windowsPath = 'sound\\notify.mp3'; const normalized = normalizePathSeparators(windowsPath); - const pattern = 'claude-templates/**'; + const pattern = 'sound/**'; expect(matchesPattern(normalized, pattern)).toBe(true); }); it('should match nested Windows paths after normalization', () => { - const windowsPath = 'claude-templates\\guides\\testing\\patterns.md'; + const windowsPath = 'sound\\themes\\dark\\complete.mp3'; const normalized = normalizePathSeparators(windowsPath); - const pattern = 'claude-templates/**'; + const pattern = 'sound/**'; expect(matchesPattern(normalized, pattern)).toBe(true); }); it('should not match Windows path WITHOUT normalization (bug scenario)', () => { - const windowsPath = 'claude-templates\\README.md'; // Backslashes - const pattern = 'claude-templates/**'; // Forward slashes + const windowsPath = 'sound\\notify.mp3'; // Backslashes + const pattern = 'sound/**'; // Forward slashes // This was the bug: Windows paths don't match forward-slash patterns expect(matchesPattern(windowsPath, pattern)).toBe(false); }); it('should match Windows path WITH normalization (fix scenario)', () => { - const windowsPath = 'claude-templates\\README.md'; + const windowsPath = 'sound\\notify.mp3'; const normalized = normalizePathSeparators(windowsPath); - const pattern = 'claude-templates/**'; + const pattern = 'sound/**'; // After normalization, pattern matching works expect(matchesPattern(normalized, pattern)).toBe(true); @@ -86,15 +86,15 @@ describe('BaseExtensionInstaller - Windows Path Handling', () => { describe('Unix Path Scenarios', () => { it('should match Unix paths (already use forward slashes)', () => { - const unixPath = 'claude-templates/README.md'; - const pattern = 'claude-templates/**'; + const unixPath = 'sound/notify.mp3'; + const pattern = 'sound/**'; expect(matchesPattern(unixPath, pattern)).toBe(true); }); it('should match nested Unix paths', () => { - const unixPath = 'claude-templates/guides/testing/patterns.md'; - const pattern = 'claude-templates/**'; + const unixPath = 'sound/themes/dark/complete.mp3'; + const pattern = 'sound/**'; expect(matchesPattern(unixPath, pattern)).toBe(true); }); @@ -102,22 +102,22 @@ describe('BaseExtensionInstaller - Windows Path Handling', () => { describe('Pattern Variations', () => { it('should match single wildcard', () => { - const path = 'claude-templates/README.md'; - const pattern = 'claude-templates/*.md'; + const path = 'sound/notify.mp3'; + const pattern = 'sound/*.mp3'; expect(matchesPattern(path, pattern)).toBe(true); }); it('should match double wildcard (recursive)', () => { - const path = 'claude-templates/guides/security/patterns.md'; - const pattern = 'claude-templates/**/*.md'; + const path = 'sound/themes/dark/complete.mp3'; + const pattern = 'sound/**/*.mp3'; expect(matchesPattern(path, pattern)).toBe(true); }); it('should match question mark wildcard', () => { - const path = 'claude-templates/test1.md'; - const pattern = 'claude-templates/test?.md'; + const path = 'sound/alert1.mp3'; + const pattern = 'sound/alert?.mp3'; expect(matchesPattern(path, pattern)).toBe(true); }); @@ -125,21 +125,21 @@ describe('BaseExtensionInstaller - Windows Path Handling', () => { describe('Exclusion Patterns', () => { it('should exclude DS_Store files', () => { - const path = 'claude-templates/.DS_Store'; + const path = 'sound/.DS_Store'; const pattern = '**/.DS_Store'; expect(matchesPattern(path, pattern)).toBe(true); }); it('should exclude test files', () => { - const path = 'claude-templates/utils.test.js'; + const path = 'sound/utils.test.js'; const pattern = '**/*.test.js'; expect(matchesPattern(path, pattern)).toBe(true); }); it('should exclude node_modules', () => { - const path = 'claude-templates/node_modules/package.json'; + const path = 'sound/node_modules/package.json'; const pattern = '**/node_modules/**'; expect(matchesPattern(path, pattern)).toBe(true); @@ -148,15 +148,15 @@ describe('BaseExtensionInstaller - Windows Path Handling', () => { }); describe('Real-World Windows Scenarios', () => { - it('should handle typical Claude templates structure on Windows', () => { + it('should handle typical sound assets structure on Windows', () => { const windowsPaths = [ - 'claude-templates\\README.md', - 'claude-templates\\templates\\CLAUDE.md.template', - 'claude-templates\\templates\\guides\\testing\\testing-patterns.md.template', - 'claude-templates\\templates\\guides\\security\\security-practices.md.template', + 'sound\\notify.mp3', + 'sound\\alert.wav', + 'sound\\themes\\dark\\complete.mp3', + 'sound\\themes\\light\\error.wav', ]; - const pattern = 'claude-templates/**'; + const pattern = 'sound/**'; // All paths should match after normalization windowsPaths.forEach(path => { @@ -167,9 +167,9 @@ describe('BaseExtensionInstaller - Windows Path Handling', () => { it('should exclude unwanted files even with Windows paths', () => { const windowsPaths = [ - 'claude-templates\\.DS_Store', - 'claude-templates\\node_modules\\package.json', - 'claude-templates\\utils.test.js', + 'sound\\.DS_Store', + 'sound\\node_modules\\package.json', + 'sound\\utils.test.js', ]; const excludePatterns = ['**/.DS_Store', '**/node_modules/**', '**/*.test.js']; @@ -186,7 +186,7 @@ describe('BaseExtensionInstaller - Windows Path Handling', () => { }); describe('Hybrid Strategy (Include + Exclude)', () => { - const includes = ['claude-templates/**']; + const includes = ['sound/**']; const excludes = ['**/.DS_Store', '**/node_modules/**', '**/*.test.js']; const shouldInclude = (path: string): boolean => { @@ -208,21 +208,21 @@ describe('BaseExtensionInstaller - Windows Path Handling', () => { return !excluded; }; - it('should include valid template files', () => { - expect(shouldInclude('claude-templates\\README.md')).toBe(true); - expect(shouldInclude('claude-templates\\templates\\CLAUDE.md.template')).toBe(true); + it('should include valid sound files', () => { + expect(shouldInclude('sound\\notify.mp3')).toBe(true); + expect(shouldInclude('sound\\themes\\dark\\complete.mp3')).toBe(true); }); it('should exclude DS_Store files', () => { - expect(shouldInclude('claude-templates\\.DS_Store')).toBe(false); + expect(shouldInclude('sound\\.DS_Store')).toBe(false); }); it('should exclude test files', () => { - expect(shouldInclude('claude-templates\\utils.test.js')).toBe(false); + expect(shouldInclude('sound\\utils.test.js')).toBe(false); }); it('should exclude node_modules', () => { - expect(shouldInclude('claude-templates\\node_modules\\package.json')).toBe(false); + expect(shouldInclude('sound\\node_modules\\package.json')).toBe(false); }); }); }); diff --git a/src/agents/plugins/claude/plugin/.claude-plugin/local-install.json b/src/agents/plugins/claude/plugin/.claude-plugin/local-install.json index eb385514..b6c29f39 100644 --- a/src/agents/plugins/claude/plugin/.claude-plugin/local-install.json +++ b/src/agents/plugins/claude/plugin/.claude-plugin/local-install.json @@ -2,8 +2,7 @@ "enabled": true, "strategy": "hybrid", "includes": [ - "sound/**", - "claude-templates/**" + "sound/**" ], "excludes": [ "**/*.test.js", diff --git a/src/agents/plugins/claude/plugin/.claude-plugin/plugin.json b/src/agents/plugins/claude/plugin/.claude-plugin/plugin.json index b85325fd..2454f703 100644 --- a/src/agents/plugins/claude/plugin/.claude-plugin/plugin.json +++ b/src/agents/plugins/claude/plugin/.claude-plugin/plugin.json @@ -5,5 +5,5 @@ "name": "AI/Run CodeMie", "email": "support@codemieai.com" }, - "version": "1.0.15" + "version": "1.0.16" } diff --git a/src/agents/plugins/claude/plugin/commands/codemie-init.md b/src/agents/plugins/claude/plugin/commands/codemie-init.md index 12b65865..faf5274b 100644 --- a/src/agents/plugins/claude/plugin/commands/codemie-init.md +++ b/src/agents/plugins/claude/plugin/commands/codemie-init.md @@ -22,7 +22,7 @@ Analyze any software project and generate AI-optimized documentation for Claude - [ ] Project is cloned and accessible - [ ] Read access to the codebase -- [ ] Templates available at `.codemie/claude-templates/templates/` +- [ ] Templates available at `${CLAUDE_PLUGIN_ROOT}/claude-templates/templates/` --- @@ -256,7 +256,7 @@ mkdir -p .codemie/guides **For each guide in approved list**: **3.2.1: Load Template** -- Read from `.codemie/claude-templates/templates/guides/[category]/[guide].md.template` +- Read from `${CLAUDE_PLUGIN_ROOT}/claude-templates/templates/guides/[category]/[guide].md.template` - If no specific template exists, use category base template **3.2.2: Analyze Codebase for This Guide** @@ -318,7 +318,7 @@ Security: #### Step 4.1: Load Template -- Read `.codemie/claude-templates/templates/CLAUDE.md.template` +- Read `${CLAUDE_PLUGIN_ROOT}/claude-templates/templates/CLAUDE.md.template` --- diff --git a/src/agents/plugins/claude/plugin/commands/codemie-subagents.md b/src/agents/plugins/claude/plugin/commands/codemie-subagents.md index c751776b..154f03bd 100644 --- a/src/agents/plugins/claude/plugin/commands/codemie-subagents.md +++ b/src/agents/plugins/claude/plugin/commands/codemie-subagents.md @@ -21,7 +21,7 @@ Analyze project and generate tailored subagent files: ## Prerequisites - [ ] Project is accessible -- [ ] Templates exist at `.codemie/claude-templates/templates/agents/` +- [ ] Templates exist at `${CLAUDE_PLUGIN_ROOT}/claude-templates/templates/agents/` - [ ] (Optional) Backup existing `.claude/agents/` if updating agents **Safety Note**: If existing agents are found, original content will be preserved during updates. However, creating a backup before running this command is recommended for recovery purposes. @@ -48,7 +48,7 @@ Analyze project and generate tailored subagent files: #### Step 1.1: Find Templates ```bash -ls .codemie/claude-templates/templates/agents/ +ls ${CLAUDE_PLUGIN_ROOT}/claude-templates/templates/agents/ ``` Expected: `code-review-agent-template.md`, `solution-architect-agent.md`, `unit-tester-agent.md`, `refactor-cleaner-agent.md` @@ -137,7 +137,7 @@ For each template, create a todo item and process: **If CREATE (no existing agent)**: ```bash -cat .codemie/claude-templates/templates/agents/[template-file] +cat ${CLAUDE_PLUGIN_ROOT}/claude-templates/templates/agents/[template-file] ``` Identify all `[PLACEHOLDERS]` and `[GENERATION INSTRUCTION]` blocks. @@ -145,7 +145,7 @@ Identify all `[PLACEHOLDERS]` and `[GENERATION INSTRUCTION]` blocks. **If UPDATE (existing agent found)**: ```bash # Read both template and existing agent -cat .codemie/claude-templates/templates/agents/[template-file] +cat ${CLAUDE_PLUGIN_ROOT}/claude-templates/templates/agents/[template-file] cat .claude/agents/[existing-agent-file] ``` diff --git a/src/agents/plugins/claude/plugin/commands/memory-refresh.md b/src/agents/plugins/claude/plugin/commands/memory-refresh.md index fd072f79..d84ffb61 100644 --- a/src/agents/plugins/claude/plugin/commands/memory-refresh.md +++ b/src/agents/plugins/claude/plugin/commands/memory-refresh.md @@ -215,7 +215,7 @@ Read .codemie/guides/[category]/[guide].md **Load template** (for structural reference): ```bash -Read .codemie/claude-templates/templates/guides/[category]/[template].md.template +Read ${CLAUDE_PLUGIN_ROOT}/claude-templates/templates/guides/[category]/[template].md.template ``` **Check**: @@ -373,7 +373,7 @@ Only modify files where changes are actually needed: 5. Ensure info is in most appropriate file **For Codemie Guides** (if updating in traditional mode): -1. Maintain template structure from `.codemie/claude-templates/` +1. Maintain template structure from `${CLAUDE_PLUGIN_ROOT}/claude-templates/` 2. Update specific sections that are outdated 3. Preserve existing valid examples 4. Keep guides within size limits (200-400 lines) diff --git a/tests/integration/sso-claude-plugin.test.ts b/tests/integration/sso-claude-plugin.test.ts index 84942d41..8a9ad5ae 100644 --- a/tests/integration/sso-claude-plugin.test.ts +++ b/tests/integration/sso-claude-plugin.test.ts @@ -280,7 +280,7 @@ describe('SSO Provider - Claude Plugin Auto-Install', () => { expect(result.success).toBe(true); expect(result.action).toBe('copied'); expect(result.sourceVersion).toBeDefined(); - expect(result.sourceVersion).toBe('1.0.15'); + expect(result.sourceVersion).toBe('1.0.16'); expect(result.installedVersion).toBeUndefined(); // First install }); @@ -293,8 +293,8 @@ describe('SSO Provider - Claude Plugin Auto-Install', () => { const result2 = await installer.install(); expect(result2.success).toBe(true); expect(result2.action).toBe('already_exists'); - expect(result2.sourceVersion).toBe('1.0.15'); - expect(result2.installedVersion).toBe('1.0.15'); + expect(result2.sourceVersion).toBe('1.0.16'); + expect(result2.installedVersion).toBe('1.0.16'); }); it('should detect version in installed plugin', async () => { @@ -308,7 +308,7 @@ describe('SSO Provider - Claude Plugin Auto-Install', () => { const json = JSON.parse(content); expect(json.version).toBeDefined(); - expect(json.version).toBe('1.0.15'); + expect(json.version).toBe('1.0.16'); }); }); });