claude-code-workflow 6.1.0 → 6.1.3
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/.claude/skills/command-guide/SKILL.md +3 -3
- package/.claude/workflows/tool-strategy.md +79 -90
- package/README.md +274 -285
- package/ccw/src/cli.js +5 -2
- package/ccw/src/commands/tool.js +18 -61
- package/ccw/src/core/server.js +2063 -1948
- package/ccw/src/templates/dashboard-css/01-base.css +130 -0
- package/ccw/src/templates/dashboard-js/components/version-check.js +167 -0
- package/ccw/src/templates/dashboard-js/main.js +1 -0
- package/ccw/src/templates/dashboard-js/views/hook-manager.js +11 -9
- package/package.json +1 -1
|
@@ -159,3 +159,133 @@ body {
|
|
|
159
159
|
display: block;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
|
|
163
|
+
/* ===================================
|
|
164
|
+
Version Update Banner
|
|
165
|
+
=================================== */
|
|
166
|
+
|
|
167
|
+
.version-update-banner {
|
|
168
|
+
position: sticky;
|
|
169
|
+
top: 0;
|
|
170
|
+
z-index: 100;
|
|
171
|
+
background: linear-gradient(135deg, hsl(var(--primary) / 0.1), hsl(var(--accent) / 0.1));
|
|
172
|
+
border-bottom: 1px solid hsl(var(--primary) / 0.3);
|
|
173
|
+
padding: 0.75rem 1rem;
|
|
174
|
+
transform: translateY(-100%);
|
|
175
|
+
opacity: 0;
|
|
176
|
+
transition: transform 0.3s ease, opacity 0.3s ease;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.version-update-banner.show {
|
|
180
|
+
transform: translateY(0);
|
|
181
|
+
opacity: 1;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.version-banner-content {
|
|
185
|
+
display: flex;
|
|
186
|
+
align-items: center;
|
|
187
|
+
gap: 0.75rem;
|
|
188
|
+
max-width: 1400px;
|
|
189
|
+
margin: 0 auto;
|
|
190
|
+
flex-wrap: wrap;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.version-banner-icon {
|
|
194
|
+
font-size: 1.25rem;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.version-banner-text {
|
|
198
|
+
flex: 1;
|
|
199
|
+
font-size: 0.875rem;
|
|
200
|
+
color: hsl(var(--foreground));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.version-banner-text code {
|
|
204
|
+
background: hsl(var(--muted));
|
|
205
|
+
padding: 0.125rem 0.375rem;
|
|
206
|
+
border-radius: 0.25rem;
|
|
207
|
+
font-family: var(--font-mono);
|
|
208
|
+
font-size: 0.8125rem;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.version-banner-btn {
|
|
212
|
+
display: inline-flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
gap: 0.375rem;
|
|
215
|
+
padding: 0.375rem 0.75rem;
|
|
216
|
+
font-size: 0.8125rem;
|
|
217
|
+
font-weight: 500;
|
|
218
|
+
color: hsl(var(--primary-foreground));
|
|
219
|
+
background: hsl(var(--primary));
|
|
220
|
+
border: none;
|
|
221
|
+
border-radius: 0.375rem;
|
|
222
|
+
cursor: pointer;
|
|
223
|
+
transition: background 0.2s, transform 0.1s;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.version-banner-btn:hover {
|
|
227
|
+
background: hsl(var(--primary) / 0.9);
|
|
228
|
+
transform: translateY(-1px);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.version-banner-btn:active {
|
|
232
|
+
transform: translateY(0);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.version-banner-btn.secondary {
|
|
236
|
+
background: hsl(var(--secondary));
|
|
237
|
+
color: hsl(var(--secondary-foreground));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.version-banner-btn.secondary:hover {
|
|
241
|
+
background: hsl(var(--secondary) / 0.8);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.version-banner-close {
|
|
245
|
+
width: 1.5rem;
|
|
246
|
+
height: 1.5rem;
|
|
247
|
+
display: flex;
|
|
248
|
+
align-items: center;
|
|
249
|
+
justify-content: center;
|
|
250
|
+
font-size: 1.25rem;
|
|
251
|
+
color: hsl(var(--muted-foreground));
|
|
252
|
+
background: transparent;
|
|
253
|
+
border: none;
|
|
254
|
+
border-radius: 0.25rem;
|
|
255
|
+
cursor: pointer;
|
|
256
|
+
transition: background 0.2s, color 0.2s;
|
|
257
|
+
margin-left: auto;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.version-banner-close:hover {
|
|
261
|
+
background: hsl(var(--destructive) / 0.1);
|
|
262
|
+
color: hsl(var(--destructive));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* Mobile responsiveness for banner */
|
|
266
|
+
@media (max-width: 640px) {
|
|
267
|
+
.version-banner-content {
|
|
268
|
+
gap: 0.5rem;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.version-banner-text {
|
|
272
|
+
width: 100%;
|
|
273
|
+
order: -1;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.version-banner-btn {
|
|
277
|
+
flex: 1;
|
|
278
|
+
justify-content: center;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.version-banner-close {
|
|
282
|
+
position: absolute;
|
|
283
|
+
top: 0.5rem;
|
|
284
|
+
right: 0.5rem;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.version-update-banner {
|
|
288
|
+
position: relative;
|
|
289
|
+
padding-right: 2.5rem;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// ==========================================
|
|
2
|
+
// VERSION CHECK COMPONENT
|
|
3
|
+
// ==========================================
|
|
4
|
+
// Checks for npm package updates and displays upgrade notification
|
|
5
|
+
|
|
6
|
+
// State
|
|
7
|
+
let versionCheckData = null;
|
|
8
|
+
let versionBannerDismissed = false;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Initialize version check on page load
|
|
12
|
+
*/
|
|
13
|
+
async function initVersionCheck() {
|
|
14
|
+
// Check version after a short delay to not block initial render
|
|
15
|
+
setTimeout(async () => {
|
|
16
|
+
await checkForUpdates();
|
|
17
|
+
}, 2000);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check for package updates
|
|
22
|
+
*/
|
|
23
|
+
async function checkForUpdates() {
|
|
24
|
+
try {
|
|
25
|
+
const res = await fetch('/api/version-check');
|
|
26
|
+
if (!res.ok) return;
|
|
27
|
+
|
|
28
|
+
versionCheckData = await res.json();
|
|
29
|
+
|
|
30
|
+
if (versionCheckData.hasUpdate && !versionBannerDismissed) {
|
|
31
|
+
showUpdateBanner(versionCheckData);
|
|
32
|
+
addGlobalNotification(
|
|
33
|
+
'info',
|
|
34
|
+
'Update Available',
|
|
35
|
+
'Version ' + versionCheckData.latestVersion + ' is now available. Current: ' + versionCheckData.currentVersion,
|
|
36
|
+
'system'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
} catch (err) {
|
|
40
|
+
console.log('Version check skipped:', err.message);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Show update banner at top of page
|
|
46
|
+
*/
|
|
47
|
+
function showUpdateBanner(data) {
|
|
48
|
+
// Remove existing banner if any
|
|
49
|
+
const existing = document.getElementById('versionUpdateBanner');
|
|
50
|
+
if (existing) existing.remove();
|
|
51
|
+
|
|
52
|
+
const banner = document.createElement('div');
|
|
53
|
+
banner.id = 'versionUpdateBanner';
|
|
54
|
+
banner.className = 'version-update-banner';
|
|
55
|
+
banner.innerHTML = '\
|
|
56
|
+
<div class="version-banner-content">\
|
|
57
|
+
<span class="version-banner-icon">🚀</span>\
|
|
58
|
+
<span class="version-banner-text">\
|
|
59
|
+
<strong>Update Available!</strong> \
|
|
60
|
+
Version <code>' + escapeHtml(data.latestVersion) + '</code> is available \
|
|
61
|
+
(you have <code>' + escapeHtml(data.currentVersion) + '</code>)\
|
|
62
|
+
</span>\
|
|
63
|
+
<button class="version-banner-btn" onclick="copyUpdateCommand()">\
|
|
64
|
+
<span>📋</span> Copy Command\
|
|
65
|
+
</button>\
|
|
66
|
+
<button class="version-banner-btn secondary" onclick="showUpdateModal()">\
|
|
67
|
+
<span>ℹ️</span> Details\
|
|
68
|
+
</button>\
|
|
69
|
+
<button class="version-banner-close" onclick="dismissUpdateBanner()" title="Dismiss">\
|
|
70
|
+
×\
|
|
71
|
+
</button>\
|
|
72
|
+
</div>\
|
|
73
|
+
';
|
|
74
|
+
|
|
75
|
+
// Insert at top of main content
|
|
76
|
+
const mainContent = document.querySelector('.main-content');
|
|
77
|
+
if (mainContent) {
|
|
78
|
+
mainContent.insertBefore(banner, mainContent.firstChild);
|
|
79
|
+
} else {
|
|
80
|
+
document.body.insertBefore(banner, document.body.firstChild);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Animate in
|
|
84
|
+
requestAnimationFrame(() => banner.classList.add('show'));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Dismiss update banner
|
|
89
|
+
*/
|
|
90
|
+
function dismissUpdateBanner() {
|
|
91
|
+
versionBannerDismissed = true;
|
|
92
|
+
const banner = document.getElementById('versionUpdateBanner');
|
|
93
|
+
if (banner) {
|
|
94
|
+
banner.classList.remove('show');
|
|
95
|
+
setTimeout(() => banner.remove(), 300);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Copy update command to clipboard
|
|
101
|
+
*/
|
|
102
|
+
async function copyUpdateCommand() {
|
|
103
|
+
if (!versionCheckData) return;
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
await navigator.clipboard.writeText(versionCheckData.updateCommand);
|
|
107
|
+
addGlobalNotification('success', 'Command copied to clipboard', versionCheckData.updateCommand, 'version-check');
|
|
108
|
+
} catch (err) {
|
|
109
|
+
// Fallback for older browsers
|
|
110
|
+
const textArea = document.createElement('textarea');
|
|
111
|
+
textArea.value = versionCheckData.updateCommand;
|
|
112
|
+
document.body.appendChild(textArea);
|
|
113
|
+
textArea.select();
|
|
114
|
+
document.execCommand('copy');
|
|
115
|
+
document.body.removeChild(textArea);
|
|
116
|
+
addGlobalNotification('success', 'Command copied to clipboard', null, 'version-check');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Show update details modal
|
|
122
|
+
*/
|
|
123
|
+
function showUpdateModal() {
|
|
124
|
+
if (!versionCheckData) return;
|
|
125
|
+
|
|
126
|
+
const content = '\
|
|
127
|
+
# Update Available\n\
|
|
128
|
+
\n\
|
|
129
|
+
A new version of Claude Code Workflow is available!\n\
|
|
130
|
+
\n\
|
|
131
|
+
| Property | Value |\n\
|
|
132
|
+
|----------|-------|\n\
|
|
133
|
+
| Current Version | `' + versionCheckData.currentVersion + '` |\n\
|
|
134
|
+
| Latest Version | `' + versionCheckData.latestVersion + '` |\n\
|
|
135
|
+
| Package | `' + versionCheckData.packageName + '` |\n\
|
|
136
|
+
\n\
|
|
137
|
+
## Update Command\n\
|
|
138
|
+
\n\
|
|
139
|
+
```bash\n\
|
|
140
|
+
' + versionCheckData.updateCommand + '\n\
|
|
141
|
+
```\n\
|
|
142
|
+
\n\
|
|
143
|
+
## Alternative Methods\n\
|
|
144
|
+
\n\
|
|
145
|
+
### Using ccw upgrade command\n\
|
|
146
|
+
```bash\n\
|
|
147
|
+
ccw upgrade\n\
|
|
148
|
+
```\n\
|
|
149
|
+
\n\
|
|
150
|
+
### Fresh install\n\
|
|
151
|
+
```bash\n\
|
|
152
|
+
npm install -g ' + versionCheckData.packageName + '@latest\n\
|
|
153
|
+
```\n\
|
|
154
|
+
\n\
|
|
155
|
+
---\n\
|
|
156
|
+
*Checked at: ' + new Date(versionCheckData.checkedAt).toLocaleString() + '*\n\
|
|
157
|
+
';
|
|
158
|
+
|
|
159
|
+
showMarkdownModal(content, 'Update Available - v' + versionCheckData.latestVersion);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Get current version info (for display in UI)
|
|
164
|
+
*/
|
|
165
|
+
function getVersionInfo() {
|
|
166
|
+
return versionCheckData;
|
|
167
|
+
}
|
|
@@ -16,6 +16,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
|
16
16
|
try { initMcpManager(); } catch (e) { console.error('MCP Manager init failed:', e); }
|
|
17
17
|
try { initHookManager(); } catch (e) { console.error('Hook Manager init failed:', e); }
|
|
18
18
|
try { initGlobalNotifications(); } catch (e) { console.error('Global notifications init failed:', e); }
|
|
19
|
+
try { initVersionCheck(); } catch (e) { console.error('Version check init failed:', e); }
|
|
19
20
|
|
|
20
21
|
// Initialize real-time features (WebSocket + auto-refresh)
|
|
21
22
|
try { initWebSocket(); } catch (e) { console.log('WebSocket not available:', e.message); }
|
|
@@ -330,9 +330,10 @@ function attachHookEventListeners() {
|
|
|
330
330
|
// Edit buttons
|
|
331
331
|
document.querySelectorAll('.hook-card button[data-action="edit"]').forEach(btn => {
|
|
332
332
|
btn.addEventListener('click', (e) => {
|
|
333
|
-
const
|
|
334
|
-
const
|
|
335
|
-
const
|
|
333
|
+
const button = e.currentTarget;
|
|
334
|
+
const scope = button.dataset.scope;
|
|
335
|
+
const event = button.dataset.event;
|
|
336
|
+
const index = parseInt(button.dataset.index);
|
|
336
337
|
|
|
337
338
|
const hooks = scope === 'global' ? hookConfig.global.hooks : hookConfig.project.hooks;
|
|
338
339
|
const hookList = Array.isArray(hooks[event]) ? hooks[event] : [hooks[event]];
|
|
@@ -354,9 +355,10 @@ function attachHookEventListeners() {
|
|
|
354
355
|
// Delete buttons
|
|
355
356
|
document.querySelectorAll('.hook-card button[data-action="delete"]').forEach(btn => {
|
|
356
357
|
btn.addEventListener('click', async (e) => {
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
const
|
|
358
|
+
const button = e.currentTarget;
|
|
359
|
+
const scope = button.dataset.scope;
|
|
360
|
+
const event = button.dataset.event;
|
|
361
|
+
const index = parseInt(button.dataset.index);
|
|
360
362
|
|
|
361
363
|
if (confirm(`Remove this ${event} hook?`)) {
|
|
362
364
|
await removeHook(scope, event, index);
|
|
@@ -367,7 +369,7 @@ function attachHookEventListeners() {
|
|
|
367
369
|
// Install project buttons
|
|
368
370
|
document.querySelectorAll('button[data-action="install-project"]').forEach(btn => {
|
|
369
371
|
btn.addEventListener('click', async (e) => {
|
|
370
|
-
const templateId = e.
|
|
372
|
+
const templateId = e.currentTarget.dataset.template;
|
|
371
373
|
await installHookTemplate(templateId, 'project');
|
|
372
374
|
});
|
|
373
375
|
});
|
|
@@ -375,7 +377,7 @@ function attachHookEventListeners() {
|
|
|
375
377
|
// Install global buttons
|
|
376
378
|
document.querySelectorAll('button[data-action="install-global"]').forEach(btn => {
|
|
377
379
|
btn.addEventListener('click', async (e) => {
|
|
378
|
-
const templateId = e.
|
|
380
|
+
const templateId = e.currentTarget.dataset.template;
|
|
379
381
|
await installHookTemplate(templateId, 'global');
|
|
380
382
|
});
|
|
381
383
|
});
|
|
@@ -383,7 +385,7 @@ function attachHookEventListeners() {
|
|
|
383
385
|
// Uninstall buttons
|
|
384
386
|
document.querySelectorAll('button[data-action="uninstall"]').forEach(btn => {
|
|
385
387
|
btn.addEventListener('click', async (e) => {
|
|
386
|
-
const templateId = e.
|
|
388
|
+
const templateId = e.currentTarget.dataset.template;
|
|
387
389
|
await uninstallHookTemplate(templateId);
|
|
388
390
|
});
|
|
389
391
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-workflow",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.3",
|
|
4
4
|
"description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "ccw/src/index.js",
|