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.
@@ -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 scope = e.target.dataset.scope;
334
- const event = e.target.dataset.event;
335
- const index = parseInt(e.target.dataset.index);
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 scope = e.target.dataset.scope;
358
- const event = e.target.dataset.event;
359
- const index = parseInt(e.target.dataset.index);
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.target.dataset.template;
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.target.dataset.template;
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.target.dataset.template;
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.0",
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",