claude-code-workflow 6.0.5 → 6.1.1
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/agents/action-planning-agent.md +1 -1
- package/.claude/agents/cli-execution-agent.md +269 -269
- package/.claude/agents/cli-explore-agent.md +182 -182
- package/.claude/agents/context-search-agent.md +582 -582
- package/.claude/agents/memory-bridge.md +93 -93
- package/.claude/commands/cli/cli-init.md +1 -1
- package/.claude/commands/memory/docs-full-cli.md +471 -471
- package/.claude/commands/memory/docs-related-cli.md +386 -386
- package/.claude/commands/memory/docs.md +615 -615
- package/.claude/commands/memory/load.md +1 -1
- package/.claude/commands/memory/update-full.md +332 -332
- package/.claude/commands/memory/update-related.md +5 -5
- package/.claude/commands/workflow/init.md +1 -1
- package/.claude/commands/workflow/lite-fix.md +621 -621
- package/.claude/commands/workflow/lite-plan.md +592 -592
- package/.claude/commands/workflow/tools/context-gather.md +434 -434
- package/.claude/commands/workflow/ui-design/generate.md +504 -504
- package/.claude/commands/workflow/ui-design/import-from-code.md +537 -537
- package/.claude/scripts/classify-folders.sh +4 -0
- package/.claude/scripts/convert_tokens_to_css.sh +4 -0
- package/.claude/scripts/detect_changed_modules.sh +5 -1
- package/.claude/scripts/discover-design-files.sh +87 -83
- package/.claude/scripts/generate_module_docs.sh +717 -713
- package/.claude/scripts/get_modules_by_depth.sh +5 -1
- package/.claude/scripts/ui-generate-preview.sh +4 -0
- package/.claude/scripts/ui-instantiate-prototypes.sh +4 -0
- package/.claude/scripts/update_module_claude.sh +4 -0
- package/.claude/skills/command-guide/index/all-commands.json +1 -12
- package/.claude/skills/command-guide/index/by-category.json +1 -12
- package/.claude/skills/command-guide/index/by-use-case.json +1 -12
- package/.claude/skills/command-guide/index/essential-commands.json +1 -12
- package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +127 -71
- package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +269 -269
- package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +182 -182
- package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +18 -38
- package/.claude/skills/command-guide/reference/agents/context-search-agent.md +582 -577
- package/.claude/skills/command-guide/reference/agents/memory-bridge.md +93 -93
- package/.claude/skills/command-guide/reference/commands/cli/cli-init.md +1 -1
- package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +471 -471
- package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +386 -386
- package/.claude/skills/command-guide/reference/commands/memory/docs.md +615 -610
- package/.claude/skills/command-guide/reference/commands/memory/load.md +1 -1
- package/.claude/skills/command-guide/reference/commands/memory/update-full.md +332 -332
- package/.claude/skills/command-guide/reference/commands/memory/update-related.md +5 -5
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/artifacts.md +299 -451
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +14 -37
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/synthesis.md +252 -350
- package/.claude/skills/command-guide/reference/commands/workflow/init.md +2 -2
- package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +52 -0
- package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +621 -602
- package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +46 -36
- package/.claude/skills/command-guide/reference/commands/workflow/review-fix.md +18 -58
- package/.claude/skills/command-guide/reference/commands/workflow/review-module-cycle.md +22 -52
- package/.claude/skills/command-guide/reference/commands/workflow/review-session-cycle.md +19 -48
- package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +25 -5
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +7 -7
- package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +434 -434
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +151 -11
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +4 -4
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-task-generate.md +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/generate.md +504 -504
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +537 -537
- package/.claude/workflows/context-search-strategy.md +77 -77
- package/.claude/workflows/tool-strategy.md +90 -71
- package/.claude/workflows/workflow-architecture.md +1 -1
- package/README.md +285 -285
- package/ccw/src/cli.js +7 -0
- package/ccw/src/commands/tool.js +217 -0
- package/ccw/src/core/dashboard-generator.js +18 -3
- package/ccw/src/core/lite-scanner.js +35 -11
- package/ccw/src/core/server.js +531 -46
- package/ccw/src/templates/dashboard-css/01-base.css +161 -0
- package/ccw/src/templates/dashboard-css/02-session.css +726 -0
- package/ccw/src/templates/dashboard-css/03-tasks.css +512 -0
- package/ccw/src/templates/dashboard-css/04-lite-tasks.css +843 -0
- package/ccw/src/templates/dashboard-css/05-context.css +2206 -0
- package/ccw/src/templates/dashboard-css/06-cards.css +1570 -0
- package/ccw/src/templates/dashboard-css/07-managers.css +936 -0
- package/ccw/src/templates/dashboard-css/08-review.css +1266 -0
- package/ccw/src/templates/dashboard-css/09-explorer.css +1397 -0
- package/ccw/src/templates/dashboard-js/components/global-notifications.js +219 -0
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +10 -0
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +11 -1
- package/ccw/src/templates/dashboard-js/components/navigation.js +11 -5
- package/ccw/src/templates/dashboard-js/components/tabs-context.js +20 -20
- package/ccw/src/templates/dashboard-js/components/tabs-other.js +11 -11
- package/ccw/src/templates/dashboard-js/components/theme.js +29 -1
- package/ccw/src/templates/dashboard-js/main.js +4 -0
- package/ccw/src/templates/dashboard-js/state.js +5 -0
- package/ccw/src/templates/dashboard-js/views/explorer.js +852 -0
- package/ccw/src/templates/dashboard-js/views/home.js +13 -9
- package/ccw/src/templates/dashboard-js/views/hook-manager.js +8 -5
- package/ccw/src/templates/dashboard-js/views/lite-tasks.js +21 -16
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js +90 -19
- package/ccw/src/templates/dashboard-js/views/project-overview.js +15 -11
- package/ccw/src/templates/dashboard-js/views/review-session.js +3 -3
- package/ccw/src/templates/dashboard-js/views/session-detail.js +38 -28
- package/ccw/src/templates/dashboard.html +129 -28
- package/ccw/src/tools/classify-folders.js +204 -0
- package/ccw/src/tools/convert-tokens-to-css.js +250 -0
- package/ccw/src/tools/detect-changed-modules.js +288 -0
- package/ccw/src/tools/discover-design-files.js +134 -0
- package/ccw/src/tools/edit-file.js +266 -0
- package/ccw/src/tools/generate-module-docs.js +416 -0
- package/ccw/src/tools/get-modules-by-depth.js +308 -0
- package/ccw/src/tools/index.js +176 -0
- package/ccw/src/tools/ui-generate-preview.js +327 -0
- package/ccw/src/tools/ui-instantiate-prototypes.js +301 -0
- package/ccw/src/tools/update-module-claude.js +380 -0
- package/package.json +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/status.md +0 -352
- package/ccw/src/core/server.js.bak +0 -385
- package/ccw/src/core/server_original.bak +0 -385
- package/ccw/src/templates/dashboard.css +0 -8187
- package/ccw/src/templates/dashboard_tailwind.html +0 -42
- package/ccw/src/templates/dashboard_test.html +0 -37
- package/ccw/src/templates/tailwind-base.css +0 -212
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Generate Preview Tool
|
|
3
|
+
* Generate compare.html and index.html for UI prototypes
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readdirSync, existsSync, readFileSync, writeFileSync } from 'fs';
|
|
7
|
+
import { resolve, basename } from 'path';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Auto-detect matrix dimensions from file patterns
|
|
11
|
+
* Pattern: {target}-style-{s}-layout-{l}.html
|
|
12
|
+
*/
|
|
13
|
+
function detectMatrixDimensions(prototypesDir) {
|
|
14
|
+
const files = readdirSync(prototypesDir).filter(f => f.match(/.*-style-\d+-layout-\d+\.html$/));
|
|
15
|
+
|
|
16
|
+
const styles = new Set();
|
|
17
|
+
const layouts = new Set();
|
|
18
|
+
const targets = new Set();
|
|
19
|
+
|
|
20
|
+
files.forEach(file => {
|
|
21
|
+
const styleMatch = file.match(/-style-(\d+)-/);
|
|
22
|
+
const layoutMatch = file.match(/-layout-(\d+)\.html/);
|
|
23
|
+
const targetMatch = file.match(/^(.+)-style-/);
|
|
24
|
+
|
|
25
|
+
if (styleMatch) styles.add(parseInt(styleMatch[1]));
|
|
26
|
+
if (layoutMatch) layouts.add(parseInt(layoutMatch[1]));
|
|
27
|
+
if (targetMatch) targets.add(targetMatch[1]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
styles: Math.max(...Array.from(styles)),
|
|
32
|
+
layouts: Math.max(...Array.from(layouts)),
|
|
33
|
+
targets: Array.from(targets).sort()
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Load template from file
|
|
39
|
+
*/
|
|
40
|
+
function loadTemplate(templatePath) {
|
|
41
|
+
const defaultPath = resolve(
|
|
42
|
+
process.env.HOME || process.env.USERPROFILE,
|
|
43
|
+
'.claude/workflows/_template-compare-matrix.html'
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const path = templatePath || defaultPath;
|
|
47
|
+
|
|
48
|
+
if (!existsSync(path)) {
|
|
49
|
+
// Return minimal fallback template
|
|
50
|
+
return `<!DOCTYPE html>
|
|
51
|
+
<html>
|
|
52
|
+
<head><title>UI Prototypes Comparison</title></head>
|
|
53
|
+
<body>
|
|
54
|
+
<h1>UI Prototypes Matrix</h1>
|
|
55
|
+
<p>Styles: {{style_variants}} | Layouts: {{layout_variants}}</p>
|
|
56
|
+
<p>Pages: {{pages_json}}</p>
|
|
57
|
+
<p>Generated: {{timestamp}}</p>
|
|
58
|
+
</body>
|
|
59
|
+
</html>`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return readFileSync(path, 'utf8');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Generate compare.html from template
|
|
67
|
+
*/
|
|
68
|
+
function generateCompareHtml(template, metadata) {
|
|
69
|
+
const { runId, sessionId, timestamp, styles, layouts, targets } = metadata;
|
|
70
|
+
|
|
71
|
+
const pagesJson = JSON.stringify(targets);
|
|
72
|
+
|
|
73
|
+
return template
|
|
74
|
+
.replace(/\{\{run_id\}\}/g, runId)
|
|
75
|
+
.replace(/\{\{session_id\}\}/g, sessionId)
|
|
76
|
+
.replace(/\{\{timestamp\}\}/g, timestamp)
|
|
77
|
+
.replace(/\{\{style_variants\}\}/g, styles.toString())
|
|
78
|
+
.replace(/\{\{layout_variants\}\}/g, layouts.toString())
|
|
79
|
+
.replace(/\{\{pages_json\}\}/g, pagesJson);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Generate index.html
|
|
84
|
+
*/
|
|
85
|
+
function generateIndexHtml(metadata) {
|
|
86
|
+
const { styles, layouts, targets } = metadata;
|
|
87
|
+
const total = styles * layouts * targets.length;
|
|
88
|
+
|
|
89
|
+
return `<!DOCTYPE html>
|
|
90
|
+
<html lang="en">
|
|
91
|
+
<head>
|
|
92
|
+
<meta charset="UTF-8">
|
|
93
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
94
|
+
<title>UI Prototypes Index</title>
|
|
95
|
+
<style>
|
|
96
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
97
|
+
body {
|
|
98
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
99
|
+
max-width: 1200px;
|
|
100
|
+
margin: 0 auto;
|
|
101
|
+
padding: 40px 20px;
|
|
102
|
+
background: #f5f5f5;
|
|
103
|
+
}
|
|
104
|
+
h1 { margin-bottom: 10px; color: #333; }
|
|
105
|
+
.subtitle { color: #666; margin-bottom: 30px; }
|
|
106
|
+
.cta {
|
|
107
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
108
|
+
color: white;
|
|
109
|
+
padding: 20px;
|
|
110
|
+
border-radius: 8px;
|
|
111
|
+
margin-bottom: 30px;
|
|
112
|
+
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
|
113
|
+
}
|
|
114
|
+
.cta h2 { margin-bottom: 10px; }
|
|
115
|
+
.cta a {
|
|
116
|
+
display: inline-block;
|
|
117
|
+
background: white;
|
|
118
|
+
color: #667eea;
|
|
119
|
+
padding: 10px 20px;
|
|
120
|
+
border-radius: 6px;
|
|
121
|
+
text-decoration: none;
|
|
122
|
+
font-weight: 600;
|
|
123
|
+
margin-top: 10px;
|
|
124
|
+
}
|
|
125
|
+
.stats {
|
|
126
|
+
display: grid;
|
|
127
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
128
|
+
gap: 15px;
|
|
129
|
+
margin-bottom: 30px;
|
|
130
|
+
}
|
|
131
|
+
.stat {
|
|
132
|
+
background: white;
|
|
133
|
+
padding: 15px;
|
|
134
|
+
border-radius: 8px;
|
|
135
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
136
|
+
}
|
|
137
|
+
.stat-label { font-size: 0.85em; color: #666; margin-bottom: 5px; }
|
|
138
|
+
.stat-value { font-size: 1.5em; font-weight: bold; color: #333; }
|
|
139
|
+
.files {
|
|
140
|
+
background: white;
|
|
141
|
+
padding: 20px;
|
|
142
|
+
border-radius: 8px;
|
|
143
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
144
|
+
}
|
|
145
|
+
.files h2 { margin-bottom: 15px; color: #333; }
|
|
146
|
+
.file-list { list-style: none; }
|
|
147
|
+
.file-list li {
|
|
148
|
+
padding: 8px 0;
|
|
149
|
+
border-bottom: 1px solid #eee;
|
|
150
|
+
}
|
|
151
|
+
.file-list li:last-child { border-bottom: none; }
|
|
152
|
+
.file-list a {
|
|
153
|
+
color: #667eea;
|
|
154
|
+
text-decoration: none;
|
|
155
|
+
}
|
|
156
|
+
.file-list a:hover { text-decoration: underline; }
|
|
157
|
+
</style>
|
|
158
|
+
</head>
|
|
159
|
+
<body>
|
|
160
|
+
<h1>UI Prototypes</h1>
|
|
161
|
+
<p class="subtitle">Interactive design exploration matrix</p>
|
|
162
|
+
|
|
163
|
+
<div class="cta">
|
|
164
|
+
<h2>📊 Interactive Comparison</h2>
|
|
165
|
+
<p>View all prototypes side-by-side with synchronized scrolling</p>
|
|
166
|
+
<a href="compare.html">Open Comparison Matrix →</a>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div class="stats">
|
|
170
|
+
<div class="stat">
|
|
171
|
+
<div class="stat-label">Style Variants</div>
|
|
172
|
+
<div class="stat-value">${styles}</div>
|
|
173
|
+
</div>
|
|
174
|
+
<div class="stat">
|
|
175
|
+
<div class="stat-label">Layout Variants</div>
|
|
176
|
+
<div class="stat-value">${layouts}</div>
|
|
177
|
+
</div>
|
|
178
|
+
<div class="stat">
|
|
179
|
+
<div class="stat-label">Pages/Components</div>
|
|
180
|
+
<div class="stat-value">${targets.length}</div>
|
|
181
|
+
</div>
|
|
182
|
+
<div class="stat">
|
|
183
|
+
<div class="stat-label">Total Prototypes</div>
|
|
184
|
+
<div class="stat-value">${total}</div>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
<div class="files">
|
|
189
|
+
<h2>Individual Prototypes</h2>
|
|
190
|
+
<ul class="file-list">
|
|
191
|
+
${targets.map(target => {
|
|
192
|
+
const items = [];
|
|
193
|
+
for (let s = 1; s <= styles; s++) {
|
|
194
|
+
for (let l = 1; l <= layouts; l++) {
|
|
195
|
+
const filename = `${target}-style-${s}-layout-${l}.html`;
|
|
196
|
+
items.push(` <li><a href="${filename}">${filename}</a></li>`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return items.join('\n');
|
|
200
|
+
}).join('\n')}
|
|
201
|
+
</ul>
|
|
202
|
+
</div>
|
|
203
|
+
</body>
|
|
204
|
+
</html>`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Generate PREVIEW.md
|
|
209
|
+
*/
|
|
210
|
+
function generatePreviewMd(metadata) {
|
|
211
|
+
const { styles, layouts, targets } = metadata;
|
|
212
|
+
|
|
213
|
+
return `# UI Prototypes Preview
|
|
214
|
+
|
|
215
|
+
## Matrix Dimensions
|
|
216
|
+
|
|
217
|
+
- **Style Variants**: ${styles}
|
|
218
|
+
- **Layout Variants**: ${layouts}
|
|
219
|
+
- **Pages/Components**: ${targets.join(', ')}
|
|
220
|
+
- **Total Prototypes**: ${styles * layouts * targets.length}
|
|
221
|
+
|
|
222
|
+
## Quick Start
|
|
223
|
+
|
|
224
|
+
1. **Interactive Comparison**: Open \`compare.html\` for side-by-side view with synchronized scrolling
|
|
225
|
+
2. **Browse Index**: Open \`index.html\` for a navigable list of all prototypes
|
|
226
|
+
3. **Individual Files**: Access specific prototypes directly (e.g., \`${targets[0]}-style-1-layout-1.html\`)
|
|
227
|
+
|
|
228
|
+
## File Naming Convention
|
|
229
|
+
|
|
230
|
+
\`\`\`
|
|
231
|
+
{page}-style-{s}-layout-{l}.html
|
|
232
|
+
\`\`\`
|
|
233
|
+
|
|
234
|
+
- **page**: Component/page name (${targets.join(', ')})
|
|
235
|
+
- **s**: Style variant number (1-${styles})
|
|
236
|
+
- **l**: Layout variant number (1-${layouts})
|
|
237
|
+
|
|
238
|
+
## Tips
|
|
239
|
+
|
|
240
|
+
- Use compare.html for quick visual comparison across all variants
|
|
241
|
+
- Synchronized scrolling helps identify consistency issues
|
|
242
|
+
- Check responsive behavior across different layout variants
|
|
243
|
+
`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Main execute function
|
|
248
|
+
*/
|
|
249
|
+
async function execute(params) {
|
|
250
|
+
const { prototypesDir = '.', template: templatePath } = params;
|
|
251
|
+
|
|
252
|
+
const targetPath = resolve(process.cwd(), prototypesDir);
|
|
253
|
+
|
|
254
|
+
if (!existsSync(targetPath)) {
|
|
255
|
+
throw new Error(`Directory not found: ${targetPath}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Auto-detect matrix dimensions
|
|
259
|
+
const { styles, layouts, targets } = detectMatrixDimensions(targetPath);
|
|
260
|
+
|
|
261
|
+
if (styles === 0 || layouts === 0 || targets.length === 0) {
|
|
262
|
+
throw new Error('No prototype files found matching pattern {target}-style-{s}-layout-{l}.html');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Generate metadata
|
|
266
|
+
const metadata = {
|
|
267
|
+
runId: `run-${new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5)}`,
|
|
268
|
+
sessionId: 'standalone',
|
|
269
|
+
timestamp: new Date().toISOString(),
|
|
270
|
+
styles,
|
|
271
|
+
layouts,
|
|
272
|
+
targets
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// Load template
|
|
276
|
+
const template = loadTemplate(templatePath);
|
|
277
|
+
|
|
278
|
+
// Generate files
|
|
279
|
+
const compareHtml = generateCompareHtml(template, metadata);
|
|
280
|
+
const indexHtml = generateIndexHtml(metadata);
|
|
281
|
+
const previewMd = generatePreviewMd(metadata);
|
|
282
|
+
|
|
283
|
+
// Write files
|
|
284
|
+
writeFileSync(resolve(targetPath, 'compare.html'), compareHtml, 'utf8');
|
|
285
|
+
writeFileSync(resolve(targetPath, 'index.html'), indexHtml, 'utf8');
|
|
286
|
+
writeFileSync(resolve(targetPath, 'PREVIEW.md'), previewMd, 'utf8');
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
success: true,
|
|
290
|
+
prototypes_dir: prototypesDir,
|
|
291
|
+
styles,
|
|
292
|
+
layouts,
|
|
293
|
+
targets,
|
|
294
|
+
total_prototypes: styles * layouts * targets.length,
|
|
295
|
+
files_generated: ['compare.html', 'index.html', 'PREVIEW.md']
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Tool Definition
|
|
301
|
+
*/
|
|
302
|
+
export const uiGeneratePreviewTool = {
|
|
303
|
+
name: 'ui_generate_preview',
|
|
304
|
+
description: `Generate interactive preview files for UI prototypes.
|
|
305
|
+
Generates:
|
|
306
|
+
- compare.html: Interactive matrix view with synchronized scrolling
|
|
307
|
+
- index.html: Navigation and statistics
|
|
308
|
+
- PREVIEW.md: Usage guide
|
|
309
|
+
|
|
310
|
+
Auto-detects matrix dimensions from file pattern: {target}-style-{s}-layout-{l}.html`,
|
|
311
|
+
parameters: {
|
|
312
|
+
type: 'object',
|
|
313
|
+
properties: {
|
|
314
|
+
prototypesDir: {
|
|
315
|
+
type: 'string',
|
|
316
|
+
description: 'Prototypes directory path (default: current directory)',
|
|
317
|
+
default: '.'
|
|
318
|
+
},
|
|
319
|
+
template: {
|
|
320
|
+
type: 'string',
|
|
321
|
+
description: 'Optional path to compare.html template'
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
required: []
|
|
325
|
+
},
|
|
326
|
+
execute
|
|
327
|
+
};
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Instantiate Prototypes Tool
|
|
3
|
+
* Create final UI prototypes from templates (Style × Layout × Page matrix)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readdirSync, existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'fs';
|
|
7
|
+
import { resolve, join, basename } from 'path';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Auto-detect pages from templates directory
|
|
11
|
+
*/
|
|
12
|
+
function autoDetectPages(templatesDir) {
|
|
13
|
+
if (!existsSync(templatesDir)) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const files = readdirSync(templatesDir).filter(f => f.match(/.*-layout-\d+\.html$/));
|
|
18
|
+
const pages = new Set();
|
|
19
|
+
|
|
20
|
+
files.forEach(file => {
|
|
21
|
+
const match = file.match(/^(.+)-layout-\d+\.html$/);
|
|
22
|
+
if (match) pages.add(match[1]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return Array.from(pages).sort();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Auto-detect style variants count
|
|
30
|
+
*/
|
|
31
|
+
function autoDetectStyleVariants(basePath) {
|
|
32
|
+
const styleDir = resolve(basePath, '..', 'style-extraction');
|
|
33
|
+
|
|
34
|
+
if (!existsSync(styleDir)) {
|
|
35
|
+
return 3; // Default
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const dirs = readdirSync(styleDir, { withFileTypes: true })
|
|
39
|
+
.filter(d => d.isDirectory() && d.name.startsWith('style-'));
|
|
40
|
+
|
|
41
|
+
return dirs.length > 0 ? dirs.length : 3;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Auto-detect layout variants count
|
|
46
|
+
*/
|
|
47
|
+
function autoDetectLayoutVariants(templatesDir) {
|
|
48
|
+
if (!existsSync(templatesDir)) {
|
|
49
|
+
return 3; // Default
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const files = readdirSync(templatesDir);
|
|
53
|
+
const firstPage = files.find(f => f.endsWith('-layout-1.html'));
|
|
54
|
+
|
|
55
|
+
if (!firstPage) return 3;
|
|
56
|
+
|
|
57
|
+
const pageName = firstPage.replace(/-layout-1\.html$/, '');
|
|
58
|
+
const layoutFiles = files.filter(f => f.match(new RegExp(`^${pageName}-layout-\\d+\\.html$`)));
|
|
59
|
+
|
|
60
|
+
return layoutFiles.length > 0 ? layoutFiles.length : 3;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Load CSS tokens file
|
|
65
|
+
*/
|
|
66
|
+
function loadTokensCss(styleDir, styleNum) {
|
|
67
|
+
const tokenPath = join(styleDir, `style-${styleNum}`, 'tokens.css');
|
|
68
|
+
|
|
69
|
+
if (existsSync(tokenPath)) {
|
|
70
|
+
return readFileSync(tokenPath, 'utf8');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return '/* No tokens.css found */';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Replace CSS placeholder in template
|
|
78
|
+
*/
|
|
79
|
+
function replaceCssPlaceholder(html, tokensCss) {
|
|
80
|
+
// Replace {{tokens.css}} placeholder
|
|
81
|
+
return html.replace(/\{\{tokens\.css\}\}/g, tokensCss);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Generate prototype from template
|
|
86
|
+
*/
|
|
87
|
+
function generatePrototype(templatePath, styleDir, styleNum, outputPath) {
|
|
88
|
+
const templateHtml = readFileSync(templatePath, 'utf8');
|
|
89
|
+
const tokensCss = loadTokensCss(styleDir, styleNum);
|
|
90
|
+
const finalHtml = replaceCssPlaceholder(templateHtml, tokensCss);
|
|
91
|
+
|
|
92
|
+
writeFileSync(outputPath, finalHtml, 'utf8');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Generate implementation notes
|
|
97
|
+
*/
|
|
98
|
+
function generateImplementationNotes(page, styleNum, layoutNum) {
|
|
99
|
+
return `# Implementation Notes: ${page}-style-${styleNum}-layout-${layoutNum}
|
|
100
|
+
|
|
101
|
+
## Overview
|
|
102
|
+
Prototype combining:
|
|
103
|
+
- **Page/Component**: ${page}
|
|
104
|
+
- **Style Variant**: ${styleNum}
|
|
105
|
+
- **Layout Variant**: ${layoutNum}
|
|
106
|
+
|
|
107
|
+
## Implementation Checklist
|
|
108
|
+
|
|
109
|
+
### 1. Style Integration
|
|
110
|
+
- [ ] Verify all CSS custom properties are applied correctly
|
|
111
|
+
- [ ] Check color palette consistency
|
|
112
|
+
- [ ] Validate typography settings
|
|
113
|
+
- [ ] Test spacing and border radius values
|
|
114
|
+
|
|
115
|
+
### 2. Layout Verification
|
|
116
|
+
- [ ] Confirm component structure matches layout variant
|
|
117
|
+
- [ ] Test responsive behavior
|
|
118
|
+
- [ ] Verify flex/grid layouts
|
|
119
|
+
- [ ] Check alignment and spacing
|
|
120
|
+
|
|
121
|
+
### 3. Accessibility
|
|
122
|
+
- [ ] Color contrast ratios (WCAG AA minimum)
|
|
123
|
+
- [ ] Keyboard navigation
|
|
124
|
+
- [ ] Screen reader compatibility
|
|
125
|
+
- [ ] Focus indicators
|
|
126
|
+
|
|
127
|
+
### 4. Browser Testing
|
|
128
|
+
- [ ] Chrome/Edge
|
|
129
|
+
- [ ] Firefox
|
|
130
|
+
- [ ] Safari
|
|
131
|
+
- [ ] Mobile browsers
|
|
132
|
+
|
|
133
|
+
## Next Steps
|
|
134
|
+
1. Review prototype in browser
|
|
135
|
+
2. Compare with design specifications
|
|
136
|
+
3. Implement in production codebase
|
|
137
|
+
4. Add interactive functionality
|
|
138
|
+
5. Write tests
|
|
139
|
+
`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Main execute function
|
|
144
|
+
*/
|
|
145
|
+
async function execute(params) {
|
|
146
|
+
const {
|
|
147
|
+
prototypesDir,
|
|
148
|
+
pages: pagesParam,
|
|
149
|
+
styleVariants: styleVariantsParam,
|
|
150
|
+
layoutVariants: layoutVariantsParam,
|
|
151
|
+
runId: runIdParam,
|
|
152
|
+
sessionId = 'standalone',
|
|
153
|
+
generatePreview = true
|
|
154
|
+
} = params;
|
|
155
|
+
|
|
156
|
+
if (!prototypesDir) {
|
|
157
|
+
throw new Error('Parameter "prototypesDir" is required');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const basePath = resolve(process.cwd(), prototypesDir);
|
|
161
|
+
|
|
162
|
+
if (!existsSync(basePath)) {
|
|
163
|
+
throw new Error(`Directory not found: ${basePath}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const templatesDir = join(basePath, '_templates');
|
|
167
|
+
const styleDir = resolve(basePath, '..', 'style-extraction');
|
|
168
|
+
|
|
169
|
+
// Auto-detect or use provided parameters
|
|
170
|
+
let pages, styleVariants, layoutVariants;
|
|
171
|
+
|
|
172
|
+
if (pagesParam && styleVariantsParam && layoutVariantsParam) {
|
|
173
|
+
// Manual mode
|
|
174
|
+
pages = Array.isArray(pagesParam) ? pagesParam : pagesParam.split(',').map(p => p.trim());
|
|
175
|
+
styleVariants = parseInt(styleVariantsParam);
|
|
176
|
+
layoutVariants = parseInt(layoutVariantsParam);
|
|
177
|
+
} else {
|
|
178
|
+
// Auto-detect mode
|
|
179
|
+
pages = autoDetectPages(templatesDir);
|
|
180
|
+
styleVariants = autoDetectStyleVariants(basePath);
|
|
181
|
+
layoutVariants = autoDetectLayoutVariants(templatesDir);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (pages.length === 0) {
|
|
185
|
+
throw new Error('No pages detected. Ensure _templates directory contains layout files.');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Generate run ID
|
|
189
|
+
const runId = runIdParam || `run-${new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5)}`;
|
|
190
|
+
|
|
191
|
+
// Phase 1: Copy templates and replace CSS placeholders
|
|
192
|
+
const generatedFiles = [];
|
|
193
|
+
|
|
194
|
+
for (const page of pages) {
|
|
195
|
+
for (let s = 1; s <= styleVariants; s++) {
|
|
196
|
+
for (let l = 1; l <= layoutVariants; l++) {
|
|
197
|
+
const templateFile = `${page}-layout-${l}.html`;
|
|
198
|
+
const templatePath = join(templatesDir, templateFile);
|
|
199
|
+
|
|
200
|
+
if (!existsSync(templatePath)) {
|
|
201
|
+
console.warn(`Template not found: ${templateFile}, skipping...`);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const outputFile = `${page}-style-${s}-layout-${l}.html`;
|
|
206
|
+
const outputPath = join(basePath, outputFile);
|
|
207
|
+
|
|
208
|
+
// Generate prototype
|
|
209
|
+
generatePrototype(templatePath, styleDir, s, outputPath);
|
|
210
|
+
|
|
211
|
+
// Generate implementation notes
|
|
212
|
+
const notesFile = `${page}-style-${s}-layout-${l}-notes.md`;
|
|
213
|
+
const notesPath = join(basePath, notesFile);
|
|
214
|
+
const notes = generateImplementationNotes(page, s, l);
|
|
215
|
+
writeFileSync(notesPath, notes, 'utf8');
|
|
216
|
+
|
|
217
|
+
generatedFiles.push(outputFile);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Phase 2: Generate preview files (optional)
|
|
223
|
+
const previewFiles = [];
|
|
224
|
+
if (generatePreview) {
|
|
225
|
+
// Import and execute ui_generate_preview tool
|
|
226
|
+
const { uiGeneratePreviewTool } = await import('./ui-generate-preview.js');
|
|
227
|
+
const previewResult = await uiGeneratePreviewTool.execute({ prototypesDir: basePath });
|
|
228
|
+
|
|
229
|
+
if (previewResult.success) {
|
|
230
|
+
previewFiles.push(...previewResult.files_generated);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
success: true,
|
|
236
|
+
run_id: runId,
|
|
237
|
+
session_id: sessionId,
|
|
238
|
+
prototypes_dir: basePath,
|
|
239
|
+
pages,
|
|
240
|
+
style_variants: styleVariants,
|
|
241
|
+
layout_variants: layoutVariants,
|
|
242
|
+
total_prototypes: generatedFiles.length,
|
|
243
|
+
files_generated: generatedFiles,
|
|
244
|
+
preview_files: previewFiles,
|
|
245
|
+
message: `Generated ${generatedFiles.length} prototypes (${styleVariants} styles × ${layoutVariants} layouts × ${pages.length} pages)`
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Tool Definition
|
|
251
|
+
*/
|
|
252
|
+
export const uiInstantiatePrototypesTool = {
|
|
253
|
+
name: 'ui_instantiate_prototypes',
|
|
254
|
+
description: `Create final UI prototypes from templates (Style × Layout × Page matrix).
|
|
255
|
+
|
|
256
|
+
Two Modes:
|
|
257
|
+
1. Auto-detect (recommended): Only specify prototypesDir
|
|
258
|
+
2. Manual: Specify prototypesDir, pages, styleVariants, layoutVariants
|
|
259
|
+
|
|
260
|
+
Features:
|
|
261
|
+
- Copies templates and replaces CSS placeholders with tokens.css
|
|
262
|
+
- Generates implementation notes for each prototype
|
|
263
|
+
- Optionally generates preview files (compare.html, index.html, PREVIEW.md)`,
|
|
264
|
+
parameters: {
|
|
265
|
+
type: 'object',
|
|
266
|
+
properties: {
|
|
267
|
+
prototypesDir: {
|
|
268
|
+
type: 'string',
|
|
269
|
+
description: 'Prototypes directory path'
|
|
270
|
+
},
|
|
271
|
+
pages: {
|
|
272
|
+
type: 'string',
|
|
273
|
+
description: 'Comma-separated list of pages (auto-detected if not provided)'
|
|
274
|
+
},
|
|
275
|
+
styleVariants: {
|
|
276
|
+
type: 'number',
|
|
277
|
+
description: 'Number of style variants (auto-detected if not provided)'
|
|
278
|
+
},
|
|
279
|
+
layoutVariants: {
|
|
280
|
+
type: 'number',
|
|
281
|
+
description: 'Number of layout variants (auto-detected if not provided)'
|
|
282
|
+
},
|
|
283
|
+
runId: {
|
|
284
|
+
type: 'string',
|
|
285
|
+
description: 'Run ID (auto-generated if not provided)'
|
|
286
|
+
},
|
|
287
|
+
sessionId: {
|
|
288
|
+
type: 'string',
|
|
289
|
+
description: 'Session ID (default: standalone)',
|
|
290
|
+
default: 'standalone'
|
|
291
|
+
},
|
|
292
|
+
generatePreview: {
|
|
293
|
+
type: 'boolean',
|
|
294
|
+
description: 'Generate preview files (default: true)',
|
|
295
|
+
default: true
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
required: ['prototypesDir']
|
|
299
|
+
},
|
|
300
|
+
execute
|
|
301
|
+
};
|