Compare commits

..

9 Commits

Author SHA1 Message Date
catlog22
faa86eded0 docs: add changelog entries for 6.1.2 and 6.1.3
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 15:53:15 +08:00
catlog22
44fa6e0a42 chore: bump version to 6.1.3
- Update README version badge and release notes
- Published to npm with simplified edit_file CLI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 15:52:43 +08:00
catlog22
be9a1c76d4 refactor(tool): simplify edit_file to parameter-based input only
- Remove JSON input support, use CLI parameters only
- Remove line mode, keep text replacement only
- Add sed as line operation alternative in tool-strategy.md
- Update documentation to English

Usage: ccw tool exec edit_file --path file.txt --old "old" --new "new"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 15:50:35 +08:00
catlog22
fcc811d6a1 docs(readme): update to v6.1.2 and simplify installation
- Update version badge and release notes to v6.1.2
- Remove one-click script install section (npm only)
- Update changelog highlights for latest release

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 15:41:39 +08:00
catlog22
906404f075 feat(server): add API endpoint for version check 2025-12-09 14:39:07 +08:00
catlog22
1267c8d0f4 feat(dashboard): add npm version update notification
- Add /api/version-check endpoint to check npm registry for updates
- Create version-check.js component with update banner UI
- Add CSS styles for version update banner
- Fix hook manager button event handling (use e.currentTarget)
- Bump version to 6.1.2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 14:38:55 +08:00
catlog22
eb1093128e docs(skill): fix project name from "Claude DMS3" to "Claude Code Workflow"
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 14:38:55 +08:00
catlog22
4ddeb6551e Merge pull request #36 from gurdasnijor/smithery/add-badge
Add "Run in Smithery" badge
2025-12-09 10:30:05 +08:00
Gurdas Nijor
7252c2ff3d Add Smithery badge 2025-12-08 16:10:45 -08:00
13 changed files with 538 additions and 194 deletions

View File

@@ -1,13 +1,13 @@
---
name: command-guide
description: Workflow command guide for Claude DMS3 (78 commands). Search/browse commands, get next-step recommendations, view documentation, report issues. Triggers "CCW-help", "CCW-issue", "ccw-help", "ccw-issue", "ccw"
description: Workflow command guide for Claude Code Workflow (78 commands). Search/browse commands, get next-step recommendations, view documentation, report issues. Triggers "CCW-help", "CCW-issue", "ccw-help", "ccw-issue", "ccw"
allowed-tools: Read, Grep, Glob, AskUserQuestion
version: 5.8.0
---
# Command Guide Skill
Comprehensive command guide for Claude DMS3 workflow system covering 78 commands across 5 categories (workflow, cli, memory, task, general).
Comprehensive command guide for Claude Code Workflow (CCW) system covering 78 commands across 5 categories (workflow, cli, memory, task, general).
## 🆕 What's New in v5.8.0
@@ -385,4 +385,4 @@ This SKILL documentation is kept in sync with command implementations through a
- 4 issue templates for standardized problem reporting
- CLI-assisted complex query analysis with gemini/qwen integration
**Maintainer**: Claude DMS3 Team
**Maintainer**: CCW Team

View File

@@ -12,79 +12,68 @@
## ⚡ CCW edit_file Tool (AI-Powered Editing)
**When to Use**: Edit tool fails 2+ times on same file
**When to Use**: Edit tool fails 1+ times on same file
### update Mode (Default)
### Usage
**Best for**: Code block replacements, function rewrites, multi-line changes
```bash
ccw tool exec edit_file '{
"path": "file.py",
"oldText": "def old():\n pass",
"newText": "def new():\n return True"
}'
ccw tool exec edit_file --path "file.py" --old "def old():
pass" --new "def new():
return True"
```
**Parameters**:
- `--path`: File path to edit
- `--old`: Text to find and replace
- `--new`: New text to insert
**Features**:
- ✅ Exact text matching (precise and predictable)
- ✅ Auto line ending adaptation (CRLF/LF)
-Simple `oldText``newText` replacement
-No special markers needed
### line Mode (Precise Line Operations)
**Best for**: Config files, line insertions/deletions, precise line number control
```bash
# Insert after specific line
ccw tool exec edit_file '{
"path": "config.txt",
"mode": "line",
"operation": "insert_after",
"line": 10,
"text": "new config line"
}'
# Delete line range
ccw tool exec edit_file '{
"path": "log.txt",
"mode": "line",
"operation": "delete",
"line": 5,
"end_line": 8
}'
# Replace specific line
ccw tool exec edit_file '{
"path": "script.sh",
"mode": "line",
"operation": "replace",
"line": 3,
"text": "#!/bin/bash"
}'
```
**Operations**:
- `insert_before`: Insert text before specified line
- `insert_after`: Insert text after specified line
- `replace`: Replace line or line range
- `delete`: Delete line or line range
### Mode Selection Guide
| Scenario | Mode | Reason |
|----------|------|--------|
| Code refactoring | update | Content-driven replacement |
| Function rewrite | update | Simple oldText/newText |
| Config line change | line | Precise line number control |
| Insert at specific position | line | Exact line number needed |
| Delete line range | line | Line-based operation |
-No JSON escaping issues
-Multi-line text supported with quotes
### Fallback Strategy
1. **Edit fails 1+ times** → Use `ccw tool exec edit_file` (update mode)
2. **update mode fails**Try line mode with precise line numbers
3. **All fails** → Use Write to recreate file
1. **Edit fails 1+ times** → Use `ccw tool exec edit_file`
2. **Still fails**Use Write to recreate file
**Default mode**: update (exact matching with line ending adaptation)
## ⚡ sed Line Operations (Line Mode Alternative)
**When to Use**: Precise line number control (insert, delete, replace specific lines)
### Common Operations
```bash
# Insert after line 10
sed -i '10a\new line content' file.txt
# Insert before line 5
sed -i '5i\new line content' file.txt
# Delete line 3
sed -i '3d' file.txt
# Delete lines 5-8
sed -i '5,8d' file.txt
# Replace line 3 content
sed -i '3c\replacement line' file.txt
# Replace lines 3-5 content
sed -i '3,5c\single replacement line' file.txt
```
### Operation Reference
| Operation | Command | Example |
|-----------|---------|---------|
| Insert after | `Na\text` | `sed -i '10a\new' file` |
| Insert before | `Ni\text` | `sed -i '5i\new' file` |
| Delete line | `Nd` | `sed -i '3d' file` |
| Delete range | `N,Md` | `sed -i '5,8d' file` |
| Replace line | `Nc\text` | `sed -i '3c\new' file` |
**Note**: Use `sed -i` for in-place file modification (works in Git Bash on Windows)

View File

@@ -5,6 +5,33 @@ All notable changes to Claude Code Workflow (CCW) will be documented in this fil
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [6.1.3] - 2025-12-09
### 🔧 CLI Tool Simplification
This release simplifies the `ccw tool exec edit_file` command for better usability.
#### 🔄 Changed
- **Simplified edit_file**: Removed JSON input support, now uses parameter-based input only (`--path`, `--old`, `--new`)
- **Removed line mode**: Line operations now recommended via `sed` command
- **Updated tool-strategy.md**: Added sed as line operation alternative with usage examples
#### Usage
```bash
ccw tool exec edit_file --path "file.txt" --old "old text" --new "new text"
```
## [6.1.2] - 2025-12-09
### 🔔 Dashboard Update Notification & Bug Fixes
#### ✨ Added
- **Version Update Notification**: Dashboard now checks npm registry for updates and displays upgrade banner
- **Version Check API**: New `/api/version-check` endpoint with 1-hour cache
#### 🐛 Fixed
- **Hook Manager**: Fixed button click event handling for edit/delete operations (changed `e.target` to `e.currentTarget`)
## [5.9.6] - 2025-11-28
### 🚀 Review Cycle & Dashboard Enhancement

View File

@@ -1,8 +1,11 @@
# 🚀 Claude Code Workflow (CCW)
[![Run in Smithery](https://smithery.ai/badge/skills/catlog22)](https://smithery.ai/skills?ns=catlog22&utm_source=github&utm_medium=badge)
<div align="center">
[![Version](https://img.shields.io/badge/version-v6.1.0-blue.svg)](https://github.com/catlog22/Claude-Code-Workflow/releases)
[![Version](https://img.shields.io/badge/version-v6.1.3-blue.svg)](https://github.com/catlog22/Claude-Code-Workflow/releases)
[![npm](https://img.shields.io/npm/v/claude-code-workflow.svg)](https://www.npmjs.com/package/claude-code-workflow)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)]()
@@ -15,13 +18,11 @@
**Claude Code Workflow (CCW)** is a JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution. It transforms AI development from simple prompt chaining into a powerful orchestration system.
> **🎉 Version 6.1.0: Dashboard Icon Unification & CCW Tool System**
> **🎉 Version 6.1.3: CLI Tool Simplification**
>
> **Core Improvements**:
> - 🎨 **Dashboard Icon Unification**: Complete migration to Lucide Icons library across all views
> - 🛠️ **CCW Tool Exec System**: New `ccw tool exec` command for executing tools with JSON parameters
> - 🚀 **Explorer Enhancements**: Async task execution, CLI selector improvements, WebSocket frame handling
> - ✨ **Smart Server Recognition**: Intelligent workspace switching and MCP multi-source configuration
> - 🔧 **Simplified edit_file**: Parameter-based input only (`--path`, `--old`, `--new`)
> - 📝 **Updated tool-strategy.md**: Added sed as line operation alternative
>
> See [CHANGELOG.md](CHANGELOG.md) for complete details.
@@ -63,18 +64,6 @@ ccw install -m Global
ccw install -m Path -p /path/to/project
```
### **🚀 Alternative: One-Click Script Install**
**Windows (PowerShell):**
```powershell
Invoke-Expression (Invoke-WebRequest -Uri "https://raw.githubusercontent.com/catlog22/Claude-Code-Workflow/main/install-remote.ps1" -UseBasicParsing).Content
```
**Linux/macOS (Bash/Zsh):**
```bash
bash <(curl -fsSL https://raw.githubusercontent.com/catlog22/Claude-Code-Workflow/main/install-remote.sh)
```
### **✅ Verify Installation**
After installation, open **Claude Code** and verify that workflow commands are available by running:
```bash

View File

@@ -108,9 +108,12 @@ export function run(argv) {
// Tool command
program
.command('tool [subcommand] [args] [json]')
.command('tool [subcommand] [args]')
.description('Execute CCW tools')
.action((subcommand, args, json) => toolCommand(subcommand, args, { json }));
.option('--path <path>', 'File path (for edit_file)')
.option('--old <text>', 'Old text to replace (for edit_file)')
.option('--new <text>', 'New text (for edit_file)')
.action((subcommand, args, options) => toolCommand(subcommand, args, options));
program.parse(argv);
}

View File

@@ -66,80 +66,13 @@ async function schemaAction(options) {
}
}
/**
* Read from stdin if available
*/
async function readStdin() {
// Check if stdin is a TTY (interactive terminal)
if (process.stdin.isTTY) {
return null;
}
return new Promise((resolve, reject) => {
let data = '';
process.stdin.setEncoding('utf8');
process.stdin.on('readable', () => {
let chunk;
while ((chunk = process.stdin.read()) !== null) {
data += chunk;
}
});
process.stdin.on('end', () => {
resolve(data.trim() || null);
});
process.stdin.on('error', (err) => {
reject(err);
});
});
}
/**
* Smart JSON parser with Windows path handling
*/
function parseJsonWithPathFix(jsonString) {
try {
// Try normal parse first
return JSON.parse(jsonString);
} catch (firstError) {
// If parsing fails, try to fix Windows paths
try {
// Pattern: "path": "X:\..." or "path":"X:\..."
const fixedJson = jsonString.replace(
/("(?:path|file|target|source|dest|destination)":\s*")([A-Za-z]:[^"]+)"/g,
(match, prefix, path) => {
// Convert backslashes to forward slashes (universal)
const fixedPath = path.replace(/\\/g, '/');
return `${prefix}${fixedPath}"`;
}
);
return JSON.parse(fixedJson);
} catch (secondError) {
// If still fails, throw original error with helpful message
const errorMsg = firstError.message;
const hint = errorMsg.includes('escaped character') || errorMsg.includes('position')
? '\n\n' + chalk.yellow('Hint: Windows paths in JSON need forward slashes or double backslashes:') +
'\n ' + chalk.green('✓ "D:/Claude_dms3/file.md"') +
'\n ' + chalk.green('✓ "D:\\\\Claude_dms3\\\\file.md"') +
'\n ' + chalk.red('✗ "D:\\Claude_dms3\\file.md"')
: '';
throw new Error(errorMsg + hint);
}
}
}
/**
* Execute a tool with given parameters
*/
async function execAction(toolName, jsonInput, options) {
async function execAction(toolName, options) {
if (!toolName) {
console.error(chalk.red('Tool name is required'));
console.error(chalk.gray('Usage: ccw tool exec <tool-name> \'{"param": "value"}\''));
console.error(chalk.gray('Usage: ccw tool exec edit_file --path file.txt --old "old" --new "new"'));
process.exit(1);
}
@@ -150,34 +83,22 @@ async function execAction(toolName, jsonInput, options) {
process.exit(1);
}
// Parse JSON input (default format)
let params = {};
// Build params from CLI options
const params = {};
if (jsonInput) {
try {
params = parseJsonWithPathFix(jsonInput);
} catch (error) {
console.error(chalk.red(`Invalid JSON: ${error.message}`));
if (toolName === 'edit_file') {
if (!options.path || !options.old || !options.new) {
console.error(chalk.red('edit_file requires --path, --old, and --new parameters'));
console.error(chalk.gray('Usage: ccw tool exec edit_file --path file.txt --old "old text" --new "new text"'));
process.exit(1);
}
}
// Check for stdin input (for piped commands)
const stdinData = await readStdin();
if (stdinData) {
// If tool has an 'input' parameter, use it
// Otherwise, try to parse stdin as JSON and merge with params
if (tool.parameters?.properties?.input) {
params.input = stdinData;
} else {
try {
const stdinJson = JSON.parse(stdinData);
params = { ...stdinJson, ...params };
} catch {
// If not JSON, store as 'input' anyway
params.input = stdinData;
}
}
params.path = options.path;
params.oldText = options.old;
params.newText = options.new;
} else {
console.error(chalk.red(`Tool "${toolName}" is not supported via CLI parameters`));
console.error(chalk.gray('Currently only edit_file is supported'));
process.exit(1);
}
// Execute tool
@@ -200,7 +121,7 @@ export async function toolCommand(subcommand, args, options) {
await schemaAction({ name: args });
break;
case 'exec':
await execAction(args, options.json, options);
await execAction(args, options);
break;
default:
console.log(chalk.bold.cyan('\nCCW Tool System\n'));
@@ -209,9 +130,9 @@ export async function toolCommand(subcommand, args, options) {
console.log(chalk.gray(' schema [name] Show tool schema (JSON)'));
console.log(chalk.gray(' exec <name> Execute a tool'));
console.log();
console.log('Examples:');
console.log('Usage:');
console.log(chalk.gray(' ccw tool list'));
console.log(chalk.gray(' ccw tool schema edit_file'));
console.log(chalk.gray(' ccw tool exec edit_file \'{"path":"file.txt","oldText":"old","newText":"new"}\''));
console.log(chalk.gray(' ccw tool exec edit_file --path file.txt --old "old text" --new "new text"'));
}
}

View File

@@ -86,6 +86,7 @@ const MODULE_FILES = [
'components/carousel.js',
'components/notifications.js',
'components/global-notifications.js',
'components/version-check.js',
'components/mcp-manager.js',
'components/hook-manager.js',
'components/_exp_helpers.js',
@@ -191,6 +192,15 @@ export async function startServer(options = {}) {
return;
}
// API: Version check (check for npm updates)
if (pathname === '/api/version-check') {
const versionData = await checkNpmVersion();
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(versionData));
return;
}
// API: Shutdown server (for ccw stop command)
if (pathname === '/api/shutdown' && req.method === 'POST') {
res.writeHead(200, { 'Content-Type': 'application/json' });
@@ -1946,3 +1956,108 @@ async function triggerUpdateClaudeMd(targetPath, tool, strategy) {
}, 300000);
});
}
// ========================================
// Version Check Functions
// ========================================
// Package name on npm registry
const NPM_PACKAGE_NAME = 'claude-code-workflow';
// Cache for version check (avoid too frequent requests)
let versionCheckCache = null;
let versionCheckTime = 0;
const VERSION_CHECK_CACHE_TTL = 3600000; // 1 hour
/**
* Get current package version from package.json
* @returns {string}
*/
function getCurrentVersion() {
try {
const packageJsonPath = join(import.meta.dirname, '../../../package.json');
if (existsSync(packageJsonPath)) {
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
return pkg.version || '0.0.0';
}
} catch (e) {
console.error('Error reading package.json:', e);
}
return '0.0.0';
}
/**
* Check npm registry for latest version
* @returns {Promise<Object>}
*/
async function checkNpmVersion() {
// Return cached result if still valid
const now = Date.now();
if (versionCheckCache && (now - versionCheckTime) < VERSION_CHECK_CACHE_TTL) {
return versionCheckCache;
}
const currentVersion = getCurrentVersion();
try {
// Fetch latest version from npm registry
const npmUrl = 'https://registry.npmjs.org/' + encodeURIComponent(NPM_PACKAGE_NAME) + '/latest';
const response = await fetch(npmUrl, {
headers: { 'Accept': 'application/json' }
});
if (!response.ok) {
throw new Error('HTTP ' + response.status);
}
const data = await response.json();
const latestVersion = data.version;
// Compare versions
const hasUpdate = compareVersions(latestVersion, currentVersion) > 0;
const result = {
currentVersion,
latestVersion,
hasUpdate,
packageName: NPM_PACKAGE_NAME,
updateCommand: 'npm update -g ' + NPM_PACKAGE_NAME,
checkedAt: new Date().toISOString()
};
// Cache the result
versionCheckCache = result;
versionCheckTime = now;
return result;
} catch (error) {
console.error('Version check failed:', error.message);
return {
currentVersion,
latestVersion: null,
hasUpdate: false,
error: error.message,
checkedAt: new Date().toISOString()
};
}
}
/**
* Compare two semver versions
* @param {string} v1
* @param {string} v2
* @returns {number} 1 if v1 > v2, -1 if v1 < v2, 0 if equal
*/
function compareVersions(v1, v2) {
const parts1 = v1.split('.').map(Number);
const parts2 = v2.split('.').map(Number);
for (let i = 0; i < 3; i++) {
const p1 = parts1[i] || 0;
const p2 = parts2[i] || 0;
if (p1 > p2) return 1;
if (p1 < p2) return -1;
}
return 0;
}

View File

@@ -159,3 +159,133 @@ body {
display: block;
}
/* ===================================
Version Update Banner
=================================== */
.version-update-banner {
position: sticky;
top: 0;
z-index: 100;
background: linear-gradient(135deg, hsl(var(--primary) / 0.1), hsl(var(--accent) / 0.1));
border-bottom: 1px solid hsl(var(--primary) / 0.3);
padding: 0.75rem 1rem;
transform: translateY(-100%);
opacity: 0;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.version-update-banner.show {
transform: translateY(0);
opacity: 1;
}
.version-banner-content {
display: flex;
align-items: center;
gap: 0.75rem;
max-width: 1400px;
margin: 0 auto;
flex-wrap: wrap;
}
.version-banner-icon {
font-size: 1.25rem;
}
.version-banner-text {
flex: 1;
font-size: 0.875rem;
color: hsl(var(--foreground));
}
.version-banner-text code {
background: hsl(var(--muted));
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-family: var(--font-mono);
font-size: 0.8125rem;
}
.version-banner-btn {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.375rem 0.75rem;
font-size: 0.8125rem;
font-weight: 500;
color: hsl(var(--primary-foreground));
background: hsl(var(--primary));
border: none;
border-radius: 0.375rem;
cursor: pointer;
transition: background 0.2s, transform 0.1s;
}
.version-banner-btn:hover {
background: hsl(var(--primary) / 0.9);
transform: translateY(-1px);
}
.version-banner-btn:active {
transform: translateY(0);
}
.version-banner-btn.secondary {
background: hsl(var(--secondary));
color: hsl(var(--secondary-foreground));
}
.version-banner-btn.secondary:hover {
background: hsl(var(--secondary) / 0.8);
}
.version-banner-close {
width: 1.5rem;
height: 1.5rem;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
color: hsl(var(--muted-foreground));
background: transparent;
border: none;
border-radius: 0.25rem;
cursor: pointer;
transition: background 0.2s, color 0.2s;
margin-left: auto;
}
.version-banner-close:hover {
background: hsl(var(--destructive) / 0.1);
color: hsl(var(--destructive));
}
/* Mobile responsiveness for banner */
@media (max-width: 640px) {
.version-banner-content {
gap: 0.5rem;
}
.version-banner-text {
width: 100%;
order: -1;
}
.version-banner-btn {
flex: 1;
justify-content: center;
}
.version-banner-close {
position: absolute;
top: 0.5rem;
right: 0.5rem;
}
.version-update-banner {
position: relative;
padding-right: 2.5rem;
}
}

View File

@@ -0,0 +1,167 @@
// ==========================================
// VERSION CHECK COMPONENT
// ==========================================
// Checks for npm package updates and displays upgrade notification
// State
let versionCheckData = null;
let versionBannerDismissed = false;
/**
* Initialize version check on page load
*/
async function initVersionCheck() {
// Check version after a short delay to not block initial render
setTimeout(async () => {
await checkForUpdates();
}, 2000);
}
/**
* Check for package updates
*/
async function checkForUpdates() {
try {
const res = await fetch('/api/version-check');
if (!res.ok) return;
versionCheckData = await res.json();
if (versionCheckData.hasUpdate && !versionBannerDismissed) {
showUpdateBanner(versionCheckData);
addGlobalNotification(
'info',
'Update Available',
'Version ' + versionCheckData.latestVersion + ' is now available. Current: ' + versionCheckData.currentVersion,
'system'
);
}
} catch (err) {
console.log('Version check skipped:', err.message);
}
}
/**
* Show update banner at top of page
*/
function showUpdateBanner(data) {
// Remove existing banner if any
const existing = document.getElementById('versionUpdateBanner');
if (existing) existing.remove();
const banner = document.createElement('div');
banner.id = 'versionUpdateBanner';
banner.className = 'version-update-banner';
banner.innerHTML = '\
<div class="version-banner-content">\
<span class="version-banner-icon">🚀</span>\
<span class="version-banner-text">\
<strong>Update Available!</strong> \
Version <code>' + escapeHtml(data.latestVersion) + '</code> is available \
(you have <code>' + escapeHtml(data.currentVersion) + '</code>)\
</span>\
<button class="version-banner-btn" onclick="copyUpdateCommand()">\
<span>📋</span> Copy Command\
</button>\
<button class="version-banner-btn secondary" onclick="showUpdateModal()">\
<span></span> Details\
</button>\
<button class="version-banner-close" onclick="dismissUpdateBanner()" title="Dismiss">\
×\
</button>\
</div>\
';
// Insert at top of main content
const mainContent = document.querySelector('.main-content');
if (mainContent) {
mainContent.insertBefore(banner, mainContent.firstChild);
} else {
document.body.insertBefore(banner, document.body.firstChild);
}
// Animate in
requestAnimationFrame(() => banner.classList.add('show'));
}
/**
* Dismiss update banner
*/
function dismissUpdateBanner() {
versionBannerDismissed = true;
const banner = document.getElementById('versionUpdateBanner');
if (banner) {
banner.classList.remove('show');
setTimeout(() => banner.remove(), 300);
}
}
/**
* Copy update command to clipboard
*/
async function copyUpdateCommand() {
if (!versionCheckData) return;
try {
await navigator.clipboard.writeText(versionCheckData.updateCommand);
addGlobalNotification('success', 'Command copied to clipboard', versionCheckData.updateCommand, 'version-check');
} catch (err) {
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = versionCheckData.updateCommand;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
addGlobalNotification('success', 'Command copied to clipboard', null, 'version-check');
}
}
/**
* Show update details modal
*/
function showUpdateModal() {
if (!versionCheckData) return;
const content = '\
# Update Available\n\
\n\
A new version of Claude Code Workflow is available!\n\
\n\
| Property | Value |\n\
|----------|-------|\n\
| Current Version | `' + versionCheckData.currentVersion + '` |\n\
| Latest Version | `' + versionCheckData.latestVersion + '` |\n\
| Package | `' + versionCheckData.packageName + '` |\n\
\n\
## Update Command\n\
\n\
```bash\n\
' + versionCheckData.updateCommand + '\n\
```\n\
\n\
## Alternative Methods\n\
\n\
### Using ccw upgrade command\n\
```bash\n\
ccw upgrade\n\
```\n\
\n\
### Fresh install\n\
```bash\n\
npm install -g ' + versionCheckData.packageName + '@latest\n\
```\n\
\n\
---\n\
*Checked at: ' + new Date(versionCheckData.checkedAt).toLocaleString() + '*\n\
';
showMarkdownModal(content, 'Update Available - v' + versionCheckData.latestVersion);
}
/**
* Get current version info (for display in UI)
*/
function getVersionInfo() {
return versionCheckData;
}

View File

@@ -16,6 +16,7 @@ document.addEventListener('DOMContentLoaded', async () => {
try { initMcpManager(); } catch (e) { console.error('MCP Manager init failed:', e); }
try { initHookManager(); } catch (e) { console.error('Hook Manager init failed:', e); }
try { initGlobalNotifications(); } catch (e) { console.error('Global notifications init failed:', e); }
try { initVersionCheck(); } catch (e) { console.error('Version check init failed:', e); }
// Initialize real-time features (WebSocket + auto-refresh)
try { initWebSocket(); } catch (e) { console.log('WebSocket not available:', e.message); }

View File

@@ -330,9 +330,10 @@ function attachHookEventListeners() {
// Edit buttons
document.querySelectorAll('.hook-card button[data-action="edit"]').forEach(btn => {
btn.addEventListener('click', (e) => {
const scope = e.target.dataset.scope;
const event = e.target.dataset.event;
const index = parseInt(e.target.dataset.index);
const button = e.currentTarget;
const scope = button.dataset.scope;
const event = button.dataset.event;
const index = parseInt(button.dataset.index);
const hooks = scope === 'global' ? hookConfig.global.hooks : hookConfig.project.hooks;
const hookList = Array.isArray(hooks[event]) ? hooks[event] : [hooks[event]];
@@ -354,9 +355,10 @@ function attachHookEventListeners() {
// Delete buttons
document.querySelectorAll('.hook-card button[data-action="delete"]').forEach(btn => {
btn.addEventListener('click', async (e) => {
const scope = e.target.dataset.scope;
const event = e.target.dataset.event;
const index = parseInt(e.target.dataset.index);
const button = e.currentTarget;
const scope = button.dataset.scope;
const event = button.dataset.event;
const index = parseInt(button.dataset.index);
if (confirm(`Remove this ${event} hook?`)) {
await removeHook(scope, event, index);
@@ -367,7 +369,7 @@ function attachHookEventListeners() {
// Install project buttons
document.querySelectorAll('button[data-action="install-project"]').forEach(btn => {
btn.addEventListener('click', async (e) => {
const templateId = e.target.dataset.template;
const templateId = e.currentTarget.dataset.template;
await installHookTemplate(templateId, 'project');
});
});
@@ -375,7 +377,7 @@ function attachHookEventListeners() {
// Install global buttons
document.querySelectorAll('button[data-action="install-global"]').forEach(btn => {
btn.addEventListener('click', async (e) => {
const templateId = e.target.dataset.template;
const templateId = e.currentTarget.dataset.template;
await installHookTemplate(templateId, 'global');
});
});
@@ -383,7 +385,7 @@ function attachHookEventListeners() {
// Uninstall buttons
document.querySelectorAll('button[data-action="uninstall"]').forEach(btn => {
btn.addEventListener('click', async (e) => {
const templateId = e.target.dataset.template;
const templateId = e.currentTarget.dataset.template;
await uninstallHookTemplate(templateId);
});
});

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "claude-code-workflow",
"version": "6.0.5",
"version": "6.1.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "claude-code-workflow",
"version": "6.0.5",
"version": "6.1.3",
"license": "MIT",
"dependencies": {
"boxen": "^7.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "claude-code-workflow",
"version": "6.1.1",
"version": "6.1.3",
"description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
"type": "module",
"main": "ccw/src/index.js",