@veolab/discoverylab 1.4.3 → 1.4.4
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-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/dist/{chunk-D4FTLCKM.js → chunk-2UUMLAVR.js} +9 -3
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{server-CZPWQYOI.js → server-QFNKZCOJ.js} +1 -1
- package/dist/visualizations/app-flow-map.html +177 -0
- package/dist/visualizations/device-showcase.html +150 -0
- package/dist/visualizations/flow-diagram.html +181 -0
- package/dist/visualizations/metrics-dashboard.html +263 -0
- package/package.json +3 -3
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"name": "discoverylab",
|
|
13
13
|
"source": ".",
|
|
14
14
|
"description": "AI-powered app testing & marketing asset generator. Record mobile/web apps, run automated tests with Maestro & Playwright, and generate professional screenshots, GIFs, and test reports.",
|
|
15
|
-
"version": "1.4.
|
|
15
|
+
"version": "1.4.4",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Anderson Melo"
|
|
18
18
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discoverylab",
|
|
3
3
|
"description": "AI-powered app testing & marketing asset generator. Record mobile/web apps, run automated tests with Maestro & Playwright, and generate professional screenshots, GIFs, and test reports.",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.4",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Anderson Melo",
|
|
7
7
|
"email": "anderson.90@gmail.com"
|
|
@@ -5804,11 +5804,17 @@ Rules:
|
|
|
5804
5804
|
default:
|
|
5805
5805
|
return c.json({ error: `Unknown template: ${templateId}` }, 400);
|
|
5806
5806
|
}
|
|
5807
|
-
const templatePath = join6(__dirname, "..", "core", "visualizations", "templates", `${templateId}.html`);
|
|
5808
5807
|
const possiblePaths = [
|
|
5809
|
-
|
|
5810
|
-
|
|
5808
|
+
join6(__dirname, "..", "visualizations", `${templateId}.html`),
|
|
5809
|
+
// dist/visualizations/
|
|
5810
|
+
join6(__dirname, "visualizations", `${templateId}.html`),
|
|
5811
|
+
// dist/visualizations/ (alt)
|
|
5812
|
+
join6(__dirname, "..", "core", "visualizations", "templates", `${templateId}.html`),
|
|
5813
|
+
// dist/core/...
|
|
5814
|
+
join6(process.cwd(), "dist", "visualizations", `${templateId}.html`),
|
|
5815
|
+
// cwd/dist/visualizations/
|
|
5811
5816
|
join6(process.cwd(), "src", "core", "visualizations", "templates", `${templateId}.html`)
|
|
5817
|
+
// dev: src/
|
|
5812
5818
|
];
|
|
5813
5819
|
let htmlContent = "";
|
|
5814
5820
|
for (const p of possiblePaths) {
|
package/dist/cli.js
CHANGED
|
@@ -389,7 +389,7 @@ program.command("serve").alias("server").description("Start the DiscoveryLab web
|
|
|
389
389
|
console.log(chalk.cyan("\n DiscoveryLab"));
|
|
390
390
|
console.log(chalk.gray(" AI-powered app testing & evidence generator\n"));
|
|
391
391
|
try {
|
|
392
|
-
const { startServer } = await import("./server-
|
|
392
|
+
const { startServer } = await import("./server-QFNKZCOJ.js");
|
|
393
393
|
await startServer(port);
|
|
394
394
|
console.log(chalk.green(` Server running at http://localhost:${port}`));
|
|
395
395
|
console.log(chalk.gray(" Press Ctrl+C to stop\n"));
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>App Flow Map</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
background: #1a1a2e;
|
|
11
|
+
color: #e0e0e0;
|
|
12
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
padding: 32px;
|
|
15
|
+
overflow-x: hidden;
|
|
16
|
+
}
|
|
17
|
+
.map { max-width: 900px; margin: 0 auto; }
|
|
18
|
+
.map-header {
|
|
19
|
+
text-align: center; margin-bottom: 36px;
|
|
20
|
+
opacity: 0; animation: fadeIn 0.6s 0.1s forwards;
|
|
21
|
+
}
|
|
22
|
+
.map-header h1 { font-size: 24px; font-weight: 700; color: #fff; }
|
|
23
|
+
.map-header p { font-size: 13px; color: rgba(255,255,255,0.45); margin-top: 6px; }
|
|
24
|
+
@keyframes fadeIn { to { opacity: 1; } }
|
|
25
|
+
@keyframes slideUp { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
|
|
26
|
+
|
|
27
|
+
/* Phase blocks */
|
|
28
|
+
.phase {
|
|
29
|
+
border-radius: 16px;
|
|
30
|
+
padding: 20px;
|
|
31
|
+
margin-bottom: 0;
|
|
32
|
+
opacity: 0;
|
|
33
|
+
animation: slideUp 0.5s forwards;
|
|
34
|
+
position: relative;
|
|
35
|
+
}
|
|
36
|
+
.phase-title { font-size: 16px; font-weight: 700; color: #fff; margin-bottom: 4px; }
|
|
37
|
+
.phase-desc { font-size: 12px; opacity: 0.6; margin-bottom: 14px; }
|
|
38
|
+
|
|
39
|
+
/* Phase color themes */
|
|
40
|
+
.phase-0 { background: rgba(34, 197, 94, 0.12); border: 1px solid rgba(34, 197, 94, 0.25); }
|
|
41
|
+
.phase-0 .phase-title { color: #86efac; }
|
|
42
|
+
.phase-1 { background: rgba(99, 102, 241, 0.12); border: 1px solid rgba(99, 102, 241, 0.25); }
|
|
43
|
+
.phase-1 .phase-title { color: #a5b4fc; }
|
|
44
|
+
.phase-2 { background: rgba(234, 179, 8, 0.12); border: 1px solid rgba(234, 179, 8, 0.25); }
|
|
45
|
+
.phase-2 .phase-title { color: #fde047; }
|
|
46
|
+
.phase-3 { background: rgba(236, 72, 153, 0.12); border: 1px solid rgba(236, 72, 153, 0.25); }
|
|
47
|
+
.phase-3 .phase-title { color: #f9a8d4; }
|
|
48
|
+
.phase-4 { background: rgba(14, 165, 233, 0.12); border: 1px solid rgba(14, 165, 233, 0.25); }
|
|
49
|
+
.phase-4 .phase-title { color: #7dd3fc; }
|
|
50
|
+
|
|
51
|
+
/* Screen cards inside phases */
|
|
52
|
+
.phase-screens {
|
|
53
|
+
display: flex; gap: 10px; overflow-x: auto; padding: 4px 0;
|
|
54
|
+
}
|
|
55
|
+
.screen-card {
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
background: rgba(255,255,255,0.06);
|
|
58
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
59
|
+
border-radius: 10px;
|
|
60
|
+
padding: 8px;
|
|
61
|
+
min-width: 130px;
|
|
62
|
+
max-width: 160px;
|
|
63
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
64
|
+
}
|
|
65
|
+
.screen-card:hover {
|
|
66
|
+
transform: translateY(-2px);
|
|
67
|
+
box-shadow: 0 8px 24px rgba(0,0,0,0.3);
|
|
68
|
+
}
|
|
69
|
+
.screen-card-img {
|
|
70
|
+
width: 100%; height: 180px;
|
|
71
|
+
border-radius: 6px; overflow: hidden;
|
|
72
|
+
background: #000; margin-bottom: 6px;
|
|
73
|
+
}
|
|
74
|
+
.screen-card-img img { width: 100%; height: 100%; object-fit: contain; }
|
|
75
|
+
.screen-card-label { font-size: 11px; font-weight: 600; color: rgba(255,255,255,0.85); }
|
|
76
|
+
.screen-card-detail { font-size: 10px; color: rgba(255,255,255,0.4); margin-top: 2px; }
|
|
77
|
+
|
|
78
|
+
/* Arrow connector between phases */
|
|
79
|
+
.arrow-connector {
|
|
80
|
+
display: flex; align-items: center; justify-content: center;
|
|
81
|
+
height: 40px;
|
|
82
|
+
opacity: 0; animation: fadeIn 0.3s forwards;
|
|
83
|
+
}
|
|
84
|
+
.arrow-connector svg {
|
|
85
|
+
stroke: rgba(255,255,255,0.2); fill: none; stroke-width: 2;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Insight callout */
|
|
89
|
+
.insight {
|
|
90
|
+
margin-top: 6px; padding: 8px 12px;
|
|
91
|
+
background: rgba(255,255,255,0.04);
|
|
92
|
+
border-left: 3px solid rgba(255,255,255,0.15);
|
|
93
|
+
border-radius: 0 8px 8px 0;
|
|
94
|
+
font-size: 11px; color: rgba(255,255,255,0.55);
|
|
95
|
+
line-height: 1.5;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.footer {
|
|
99
|
+
text-align: center; margin-top: 32px;
|
|
100
|
+
font-size: 10px; color: rgba(255,255,255,0.2);
|
|
101
|
+
}
|
|
102
|
+
.model-label {
|
|
103
|
+
position: fixed; bottom: 10px; right: 14px;
|
|
104
|
+
font-size: 9px; color: rgba(255,255,255,0.2);
|
|
105
|
+
background: rgba(0,0,0,0.3);
|
|
106
|
+
padding: 2px 8px; border-radius: 4px;
|
|
107
|
+
}
|
|
108
|
+
</style>
|
|
109
|
+
</head>
|
|
110
|
+
<body>
|
|
111
|
+
<div class="map">
|
|
112
|
+
<div class="map-header">
|
|
113
|
+
<h1 id="mapTitle">App Flow Map</h1>
|
|
114
|
+
<p id="mapSubtitle"></p>
|
|
115
|
+
</div>
|
|
116
|
+
<div id="mapContent"></div>
|
|
117
|
+
<div class="footer" id="mapFooter">Generated by DiscoveryLab</div>
|
|
118
|
+
<div class="model-label" id="modelLabel"></div>
|
|
119
|
+
</div>
|
|
120
|
+
<script>
|
|
121
|
+
const DATA = window.__VISUALIZATION_DATA__ || {};
|
|
122
|
+
const phases = DATA.phases || [];
|
|
123
|
+
|
|
124
|
+
if (DATA.title) document.getElementById('mapTitle').textContent = DATA.title;
|
|
125
|
+
if (DATA.subtitle) document.getElementById('mapSubtitle').textContent = DATA.subtitle;
|
|
126
|
+
if (DATA.providerName) document.getElementById('modelLabel').textContent = DATA.providerName;
|
|
127
|
+
|
|
128
|
+
const container = document.getElementById('mapContent');
|
|
129
|
+
let animDelay = 0.3;
|
|
130
|
+
|
|
131
|
+
phases.forEach((phase, phaseIdx) => {
|
|
132
|
+
// Arrow between phases
|
|
133
|
+
if (phaseIdx > 0) {
|
|
134
|
+
const arrow = document.createElement('div');
|
|
135
|
+
arrow.className = 'arrow-connector';
|
|
136
|
+
arrow.style.animationDelay = animDelay + 's';
|
|
137
|
+
arrow.innerHTML = '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M12 5v14M5 12l7 7 7-7" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
138
|
+
container.appendChild(arrow);
|
|
139
|
+
animDelay += 0.15;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const phaseEl = document.createElement('div');
|
|
143
|
+
phaseEl.className = `phase phase-${phaseIdx % 5}`;
|
|
144
|
+
phaseEl.style.animationDelay = animDelay + 's';
|
|
145
|
+
|
|
146
|
+
let html = `
|
|
147
|
+
<div class="phase-title">${phase.title || 'Phase ' + (phaseIdx + 1)}</div>
|
|
148
|
+
<div class="phase-desc">${phase.description || ''}</div>
|
|
149
|
+
`;
|
|
150
|
+
|
|
151
|
+
// Screen cards
|
|
152
|
+
if (phase.screens && phase.screens.length > 0) {
|
|
153
|
+
html += '<div class="phase-screens">';
|
|
154
|
+
phase.screens.forEach(screen => {
|
|
155
|
+
html += `
|
|
156
|
+
<div class="screen-card">
|
|
157
|
+
${screen.imageUrl ? `<div class="screen-card-img"><img src="${screen.imageUrl}" alt="" loading="lazy"></div>` : ''}
|
|
158
|
+
<div class="screen-card-label">${screen.label || ''}</div>
|
|
159
|
+
${screen.detail ? `<div class="screen-card-detail">${screen.detail}</div>` : ''}
|
|
160
|
+
</div>
|
|
161
|
+
`;
|
|
162
|
+
});
|
|
163
|
+
html += '</div>';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Insight
|
|
167
|
+
if (phase.insight) {
|
|
168
|
+
html += `<div class="insight">${phase.insight}</div>`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
phaseEl.innerHTML = html;
|
|
172
|
+
container.appendChild(phaseEl);
|
|
173
|
+
animDelay += 0.3;
|
|
174
|
+
});
|
|
175
|
+
</script>
|
|
176
|
+
</body>
|
|
177
|
+
</html>
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Device Showcase</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
background: linear-gradient(135deg, #0c0c1d, #1e1e3f, #0c0c1d);
|
|
11
|
+
color: #fff;
|
|
12
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
}
|
|
20
|
+
.header { text-align: center; margin-bottom: 32px; z-index: 10; }
|
|
21
|
+
.header h1 { font-size: 28px; font-weight: 700; }
|
|
22
|
+
.header p { font-size: 13px; color: rgba(255,255,255,0.5); margin-top: 4px; }
|
|
23
|
+
.carousel-wrapper {
|
|
24
|
+
perspective: 1200px;
|
|
25
|
+
width: 100%;
|
|
26
|
+
max-width: 800px;
|
|
27
|
+
height: 500px;
|
|
28
|
+
position: relative;
|
|
29
|
+
}
|
|
30
|
+
.carousel {
|
|
31
|
+
width: 100%;
|
|
32
|
+
height: 100%;
|
|
33
|
+
position: relative;
|
|
34
|
+
transform-style: preserve-3d;
|
|
35
|
+
animation: spin 20s linear infinite;
|
|
36
|
+
animation-play-state: running;
|
|
37
|
+
}
|
|
38
|
+
.carousel:hover { animation-play-state: paused; }
|
|
39
|
+
@keyframes spin { to { transform: rotateY(360deg); } }
|
|
40
|
+
.device {
|
|
41
|
+
position: absolute;
|
|
42
|
+
width: 200px;
|
|
43
|
+
left: 50%;
|
|
44
|
+
top: 50%;
|
|
45
|
+
margin-left: -100px;
|
|
46
|
+
margin-top: -200px;
|
|
47
|
+
transform-style: preserve-3d;
|
|
48
|
+
transition: transform 0.5s, box-shadow 0.5s;
|
|
49
|
+
}
|
|
50
|
+
.device-frame {
|
|
51
|
+
background: #111;
|
|
52
|
+
border-radius: 24px;
|
|
53
|
+
padding: 8px;
|
|
54
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.1);
|
|
55
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
56
|
+
}
|
|
57
|
+
.device-screen {
|
|
58
|
+
border-radius: 16px;
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
background: #000;
|
|
61
|
+
}
|
|
62
|
+
.device-screen img {
|
|
63
|
+
width: 100%;
|
|
64
|
+
height: auto;
|
|
65
|
+
display: block;
|
|
66
|
+
}
|
|
67
|
+
.device-label {
|
|
68
|
+
text-align: center;
|
|
69
|
+
font-size: 11px;
|
|
70
|
+
color: rgba(255,255,255,0.5);
|
|
71
|
+
margin-top: 12px;
|
|
72
|
+
}
|
|
73
|
+
.glow {
|
|
74
|
+
position: absolute;
|
|
75
|
+
width: 300px; height: 300px;
|
|
76
|
+
background: radial-gradient(circle, rgba(99,102,241,0.15) 0%, transparent 70%);
|
|
77
|
+
top: 50%; left: 50%;
|
|
78
|
+
transform: translate(-50%, -50%);
|
|
79
|
+
pointer-events: none;
|
|
80
|
+
}
|
|
81
|
+
.footer {
|
|
82
|
+
position: fixed; bottom: 16px;
|
|
83
|
+
font-size: 11px; color: rgba(255,255,255,0.25);
|
|
84
|
+
}
|
|
85
|
+
.nav-dots {
|
|
86
|
+
display: flex; gap: 8px; margin-top: 24px; z-index: 10;
|
|
87
|
+
}
|
|
88
|
+
.nav-dot {
|
|
89
|
+
width: 8px; height: 8px; border-radius: 50%;
|
|
90
|
+
background: rgba(255,255,255,0.2);
|
|
91
|
+
cursor: pointer;
|
|
92
|
+
transition: background 0.3s;
|
|
93
|
+
}
|
|
94
|
+
.nav-dot.active { background: #6366f1; }
|
|
95
|
+
</style>
|
|
96
|
+
</head>
|
|
97
|
+
<body>
|
|
98
|
+
<div class="header">
|
|
99
|
+
<h1 id="vizTitle">Device Showcase</h1>
|
|
100
|
+
<p id="vizSubtitle"></p>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="carousel-wrapper">
|
|
103
|
+
<div class="glow"></div>
|
|
104
|
+
<div class="carousel" id="carousel"></div>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="nav-dots" id="navDots"></div>
|
|
107
|
+
<div class="footer" id="vizFooter">Generated by DiscoveryLab</div>
|
|
108
|
+
<script>
|
|
109
|
+
const DATA = window.__VISUALIZATION_DATA__ || {};
|
|
110
|
+
const screens = DATA.screens || [];
|
|
111
|
+
|
|
112
|
+
if (DATA.title) document.getElementById('vizTitle').textContent = DATA.title;
|
|
113
|
+
if (DATA.subtitle) document.getElementById('vizSubtitle').textContent = DATA.subtitle;
|
|
114
|
+
|
|
115
|
+
const carousel = document.getElementById('carousel');
|
|
116
|
+
const dotsContainer = document.getElementById('navDots');
|
|
117
|
+
const n = screens.length || 1;
|
|
118
|
+
const angleStep = 360 / n;
|
|
119
|
+
const radius = Math.max(250, n * 60);
|
|
120
|
+
|
|
121
|
+
screens.forEach((screen, i) => {
|
|
122
|
+
const angle = angleStep * i;
|
|
123
|
+
const device = document.createElement('div');
|
|
124
|
+
device.className = 'device';
|
|
125
|
+
device.style.transform = `rotateY(${angle}deg) translateZ(${radius}px)`;
|
|
126
|
+
device.innerHTML = `
|
|
127
|
+
<div class="device-frame">
|
|
128
|
+
<div class="device-screen">
|
|
129
|
+
<img src="${screen.imageUrl}" alt="Screen ${i + 1}" loading="lazy">
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="device-label">${screen.label || `Screen ${i + 1}`}</div>
|
|
133
|
+
`;
|
|
134
|
+
carousel.appendChild(device);
|
|
135
|
+
|
|
136
|
+
const dot = document.createElement('div');
|
|
137
|
+
dot.className = `nav-dot ${i === 0 ? 'active' : ''}`;
|
|
138
|
+
dot.addEventListener('click', () => {
|
|
139
|
+
carousel.style.animation = 'none';
|
|
140
|
+
carousel.offsetHeight; // reflow
|
|
141
|
+
carousel.style.transform = `rotateY(${-angle}deg)`;
|
|
142
|
+
carousel.style.transition = 'transform 0.8s ease';
|
|
143
|
+
dotsContainer.querySelectorAll('.nav-dot').forEach(d => d.classList.remove('active'));
|
|
144
|
+
dot.classList.add('active');
|
|
145
|
+
});
|
|
146
|
+
dotsContainer.appendChild(dot);
|
|
147
|
+
});
|
|
148
|
+
</script>
|
|
149
|
+
</body>
|
|
150
|
+
</html>
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Flow Diagram</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
background: linear-gradient(160deg, #0f0f23, #1a1a3e);
|
|
11
|
+
color: #fff;
|
|
12
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
}
|
|
17
|
+
.container {
|
|
18
|
+
flex: 1;
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
padding: 24px;
|
|
22
|
+
max-width: 100%;
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
}
|
|
25
|
+
.header { text-align: center; margin-bottom: 20px; flex-shrink: 0; }
|
|
26
|
+
.header h1 { font-size: 22px; font-weight: 700; margin-bottom: 4px; }
|
|
27
|
+
.header p { font-size: 13px; color: rgba(255,255,255,0.5); }
|
|
28
|
+
.flow {
|
|
29
|
+
flex: 1;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: row;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
gap: 0;
|
|
35
|
+
padding: 10px 0;
|
|
36
|
+
min-height: 0;
|
|
37
|
+
}
|
|
38
|
+
.flow.vertical {
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
overflow-y: auto;
|
|
41
|
+
overflow-x: hidden;
|
|
42
|
+
}
|
|
43
|
+
.step {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
align-items: center;
|
|
47
|
+
flex-shrink: 1;
|
|
48
|
+
min-width: 0;
|
|
49
|
+
max-width: 220px;
|
|
50
|
+
opacity: 0;
|
|
51
|
+
transform: translateY(20px);
|
|
52
|
+
animation: fadeInUp 0.5s forwards;
|
|
53
|
+
/* delay set dynamically via JS for correct sequential order */
|
|
54
|
+
}
|
|
55
|
+
@keyframes fadeInUp {
|
|
56
|
+
to { opacity: 1; transform: translateY(0); }
|
|
57
|
+
}
|
|
58
|
+
.step-badge {
|
|
59
|
+
width: 28px; height: 28px; border-radius: 50%;
|
|
60
|
+
background: #6366f1; color: #fff;
|
|
61
|
+
display: flex; align-items: center; justify-content: center;
|
|
62
|
+
font-size: 12px; font-weight: 700;
|
|
63
|
+
margin-bottom: 8px;
|
|
64
|
+
box-shadow: 0 3px 10px rgba(99,102,241,0.4);
|
|
65
|
+
flex-shrink: 0;
|
|
66
|
+
}
|
|
67
|
+
.step-screenshot {
|
|
68
|
+
width: 100%;
|
|
69
|
+
max-height: 55vh;
|
|
70
|
+
border-radius: 10px;
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
box-shadow: 0 6px 20px rgba(0,0,0,0.3);
|
|
73
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
74
|
+
transition: transform 0.3s, box-shadow 0.3s;
|
|
75
|
+
flex-shrink: 1;
|
|
76
|
+
}
|
|
77
|
+
.step-screenshot:hover {
|
|
78
|
+
transform: scale(1.03);
|
|
79
|
+
box-shadow: 0 10px 30px rgba(99,102,241,0.25);
|
|
80
|
+
}
|
|
81
|
+
.step-screenshot img {
|
|
82
|
+
width: 100%;
|
|
83
|
+
height: auto;
|
|
84
|
+
display: block;
|
|
85
|
+
max-height: 55vh;
|
|
86
|
+
object-fit: contain;
|
|
87
|
+
}
|
|
88
|
+
.step-label {
|
|
89
|
+
font-size: 11px;
|
|
90
|
+
color: rgba(255,255,255,0.7);
|
|
91
|
+
margin-top: 8px;
|
|
92
|
+
text-align: center;
|
|
93
|
+
max-width: 100%;
|
|
94
|
+
overflow: hidden;
|
|
95
|
+
text-overflow: ellipsis;
|
|
96
|
+
white-space: nowrap;
|
|
97
|
+
flex-shrink: 0;
|
|
98
|
+
}
|
|
99
|
+
.arrow {
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
justify-content: center;
|
|
103
|
+
flex-shrink: 0;
|
|
104
|
+
padding: 0 4px;
|
|
105
|
+
opacity: 0;
|
|
106
|
+
animation: fadeInArrow 0.3s forwards;
|
|
107
|
+
/* delay set dynamically via JS */
|
|
108
|
+
}
|
|
109
|
+
@keyframes fadeInArrow { to { opacity: 1; } }
|
|
110
|
+
.arrow svg {
|
|
111
|
+
width: 20px; height: 20px;
|
|
112
|
+
stroke: rgba(255,255,255,0.35);
|
|
113
|
+
fill: none;
|
|
114
|
+
stroke-width: 2;
|
|
115
|
+
}
|
|
116
|
+
.flow.vertical .arrow { transform: rotate(90deg); }
|
|
117
|
+
.footer {
|
|
118
|
+
text-align: center;
|
|
119
|
+
padding: 12px;
|
|
120
|
+
font-size: 10px;
|
|
121
|
+
color: rgba(255,255,255,0.25);
|
|
122
|
+
flex-shrink: 0;
|
|
123
|
+
}
|
|
124
|
+
</style>
|
|
125
|
+
</head>
|
|
126
|
+
<body>
|
|
127
|
+
<div class="container">
|
|
128
|
+
<div class="header">
|
|
129
|
+
<h1 id="vizTitle">App Flow</h1>
|
|
130
|
+
<p id="vizSubtitle"></p>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="flow" id="flowContainer"></div>
|
|
133
|
+
<div class="footer" id="vizFooter">Generated by DiscoveryLab</div>
|
|
134
|
+
</div>
|
|
135
|
+
<script>
|
|
136
|
+
const DATA = window.__VISUALIZATION_DATA__ || {};
|
|
137
|
+
const steps = DATA.steps || [];
|
|
138
|
+
const direction = DATA.direction || 'horizontal';
|
|
139
|
+
const count = steps.length;
|
|
140
|
+
|
|
141
|
+
if (DATA.title) document.getElementById('vizTitle').textContent = DATA.title;
|
|
142
|
+
if (DATA.subtitle) document.getElementById('vizSubtitle').textContent = DATA.subtitle;
|
|
143
|
+
|
|
144
|
+
const container = document.getElementById('flowContainer');
|
|
145
|
+
if (direction === 'vertical') container.classList.add('vertical');
|
|
146
|
+
|
|
147
|
+
// Auto-size steps based on count and viewport
|
|
148
|
+
const maxStepWidth = Math.min(220, Math.floor((window.innerWidth - 80 - (count - 1) * 28) / count));
|
|
149
|
+
|
|
150
|
+
// Sequential animation: step1 → arrow1 → step2 → arrow2 → step3 ...
|
|
151
|
+
const baseDelay = 0.2; // seconds
|
|
152
|
+
const stepDuration = 0.3; // time between each element appearing
|
|
153
|
+
|
|
154
|
+
steps.forEach((step, i) => {
|
|
155
|
+
const elementIndex = i * 2; // step0=0, arrow0=1, step1=2, arrow1=3, step2=4...
|
|
156
|
+
|
|
157
|
+
if (i > 0) {
|
|
158
|
+
const arrowIndex = (i * 2) - 1;
|
|
159
|
+
const arrow = document.createElement('div');
|
|
160
|
+
arrow.className = 'arrow';
|
|
161
|
+
arrow.style.animationDelay = (baseDelay + arrowIndex * stepDuration) + 's';
|
|
162
|
+
arrow.innerHTML = '<svg viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
163
|
+
container.appendChild(arrow);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const el = document.createElement('div');
|
|
167
|
+
el.className = 'step';
|
|
168
|
+
el.style.maxWidth = maxStepWidth + 'px';
|
|
169
|
+
el.style.animationDelay = (baseDelay + elementIndex * stepDuration) + 's';
|
|
170
|
+
el.innerHTML = `
|
|
171
|
+
<div class="step-badge">${step.number || i + 1}</div>
|
|
172
|
+
<div class="step-screenshot">
|
|
173
|
+
<img src="${step.imageUrl}" alt="Step ${i + 1}">
|
|
174
|
+
</div>
|
|
175
|
+
<div class="step-label">${step.label || ''}</div>
|
|
176
|
+
`;
|
|
177
|
+
container.appendChild(el);
|
|
178
|
+
});
|
|
179
|
+
</script>
|
|
180
|
+
</body>
|
|
181
|
+
</html>
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Metrics Dashboard</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
background: #0f0f1a;
|
|
11
|
+
color: #fff;
|
|
12
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
padding: 24px;
|
|
15
|
+
}
|
|
16
|
+
.dashboard { max-width: 960px; margin: 0 auto; }
|
|
17
|
+
.header { margin-bottom: 24px; }
|
|
18
|
+
.header h1 { font-size: 22px; font-weight: 700; }
|
|
19
|
+
.header p { font-size: 13px; color: rgba(255,255,255,0.4); margin-top: 4px; }
|
|
20
|
+
|
|
21
|
+
/* Metrics cards */
|
|
22
|
+
.metrics-grid {
|
|
23
|
+
display: grid;
|
|
24
|
+
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
|
25
|
+
gap: 12px;
|
|
26
|
+
margin-bottom: 24px;
|
|
27
|
+
}
|
|
28
|
+
.metric-card {
|
|
29
|
+
background: rgba(255,255,255,0.04);
|
|
30
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
31
|
+
border-radius: 12px;
|
|
32
|
+
padding: 16px;
|
|
33
|
+
opacity: 0;
|
|
34
|
+
transform: scale(0.95);
|
|
35
|
+
animation: popIn 0.4s forwards;
|
|
36
|
+
}
|
|
37
|
+
.metric-card:nth-child(1) { animation-delay: 0.1s; }
|
|
38
|
+
.metric-card:nth-child(2) { animation-delay: 0.2s; }
|
|
39
|
+
.metric-card:nth-child(3) { animation-delay: 0.3s; }
|
|
40
|
+
.metric-card:nth-child(4) { animation-delay: 0.4s; }
|
|
41
|
+
@keyframes popIn { to { opacity: 1; transform: scale(1); } }
|
|
42
|
+
.metric-value {
|
|
43
|
+
font-size: 32px; font-weight: 800;
|
|
44
|
+
background: linear-gradient(135deg, #6366f1, #a78bfa);
|
|
45
|
+
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
|
46
|
+
background-clip: text;
|
|
47
|
+
}
|
|
48
|
+
.metric-label { font-size: 11px; color: rgba(255,255,255,0.5); margin-top: 2px; }
|
|
49
|
+
|
|
50
|
+
/* Two-column layout for charts + screens */
|
|
51
|
+
.content-grid {
|
|
52
|
+
display: grid;
|
|
53
|
+
grid-template-columns: 1fr 1fr;
|
|
54
|
+
gap: 16px;
|
|
55
|
+
margin-bottom: 24px;
|
|
56
|
+
}
|
|
57
|
+
@media (max-width: 700px) { .content-grid { grid-template-columns: 1fr; } }
|
|
58
|
+
|
|
59
|
+
.section-card {
|
|
60
|
+
background: rgba(255,255,255,0.03);
|
|
61
|
+
border: 1px solid rgba(255,255,255,0.06);
|
|
62
|
+
border-radius: 12px;
|
|
63
|
+
padding: 16px;
|
|
64
|
+
}
|
|
65
|
+
.section-title { font-size: 13px; font-weight: 600; margin-bottom: 12px; color: rgba(255,255,255,0.8); }
|
|
66
|
+
|
|
67
|
+
/* Bar chart */
|
|
68
|
+
.bar-chart { display: flex; flex-direction: column; gap: 6px; }
|
|
69
|
+
.bar-row {
|
|
70
|
+
display: grid; grid-template-columns: 90px 1fr 32px;
|
|
71
|
+
gap: 8px; align-items: center;
|
|
72
|
+
opacity: 0; animation: slideIn 0.5s forwards;
|
|
73
|
+
}
|
|
74
|
+
.bar-row:nth-child(1) { animation-delay: 0.5s; }
|
|
75
|
+
.bar-row:nth-child(2) { animation-delay: 0.6s; }
|
|
76
|
+
.bar-row:nth-child(3) { animation-delay: 0.7s; }
|
|
77
|
+
.bar-row:nth-child(4) { animation-delay: 0.8s; }
|
|
78
|
+
@keyframes slideIn { from { opacity: 0; transform: translateX(-16px); } to { opacity: 1; transform: translateX(0); } }
|
|
79
|
+
.bar-label { font-size: 10px; color: rgba(255,255,255,0.6); text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
80
|
+
.bar-track { height: 20px; background: rgba(255,255,255,0.06); border-radius: 5px; overflow: hidden; }
|
|
81
|
+
.bar-fill { height: 100%; border-radius: 5px; background: linear-gradient(90deg, #6366f1, #818cf8); transition: width 1s ease; width: 0; }
|
|
82
|
+
.bar-value { font-size: 11px; color: rgba(255,255,255,0.7); font-weight: 600; }
|
|
83
|
+
|
|
84
|
+
/* Screen thumbnails strip */
|
|
85
|
+
.screens-strip {
|
|
86
|
+
display: flex;
|
|
87
|
+
gap: 8px;
|
|
88
|
+
overflow-x: auto;
|
|
89
|
+
padding: 4px 0;
|
|
90
|
+
}
|
|
91
|
+
.screen-thumb {
|
|
92
|
+
flex-shrink: 0;
|
|
93
|
+
width: 80px;
|
|
94
|
+
border-radius: 8px;
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
97
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
|
98
|
+
opacity: 0;
|
|
99
|
+
animation: thumbIn 0.4s forwards;
|
|
100
|
+
position: relative;
|
|
101
|
+
transition: transform 0.2s;
|
|
102
|
+
}
|
|
103
|
+
.screen-thumb:hover { transform: scale(1.08); }
|
|
104
|
+
.screen-thumb img { width: 100%; height: auto; display: block; }
|
|
105
|
+
.screen-thumb-label {
|
|
106
|
+
position: absolute; bottom: 0; left: 0; right: 0;
|
|
107
|
+
background: linear-gradient(transparent, rgba(0,0,0,0.8));
|
|
108
|
+
padding: 12px 4px 4px;
|
|
109
|
+
font-size: 8px; color: rgba(255,255,255,0.8);
|
|
110
|
+
text-align: center;
|
|
111
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
112
|
+
}
|
|
113
|
+
.screen-thumb:nth-child(1) { animation-delay: 0.3s; }
|
|
114
|
+
.screen-thumb:nth-child(2) { animation-delay: 0.4s; }
|
|
115
|
+
.screen-thumb:nth-child(3) { animation-delay: 0.5s; }
|
|
116
|
+
.screen-thumb:nth-child(4) { animation-delay: 0.6s; }
|
|
117
|
+
.screen-thumb:nth-child(5) { animation-delay: 0.7s; }
|
|
118
|
+
.screen-thumb:nth-child(6) { animation-delay: 0.8s; }
|
|
119
|
+
@keyframes thumbIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
|
|
120
|
+
|
|
121
|
+
/* Flow steps with thumbnails */
|
|
122
|
+
.flow-steps { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
|
|
123
|
+
.flow-step {
|
|
124
|
+
display: flex; align-items: center; gap: 10px;
|
|
125
|
+
padding: 8px 10px;
|
|
126
|
+
background: rgba(99,102,241,0.06);
|
|
127
|
+
border: 1px solid rgba(99,102,241,0.12);
|
|
128
|
+
border-radius: 10px;
|
|
129
|
+
opacity: 0;
|
|
130
|
+
animation: fadeIn 0.3s forwards;
|
|
131
|
+
}
|
|
132
|
+
@keyframes fadeIn { to { opacity: 1; } }
|
|
133
|
+
.flow-step-num {
|
|
134
|
+
width: 22px; height: 22px; border-radius: 50%;
|
|
135
|
+
background: #6366f1; color: #fff;
|
|
136
|
+
display: flex; align-items: center; justify-content: center;
|
|
137
|
+
font-size: 10px; font-weight: 700; flex-shrink: 0;
|
|
138
|
+
}
|
|
139
|
+
.flow-step-thumb {
|
|
140
|
+
width: 36px; height: 64px; border-radius: 4px;
|
|
141
|
+
overflow: hidden; flex-shrink: 0;
|
|
142
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
143
|
+
}
|
|
144
|
+
.flow-step-thumb img { width: 100%; height: 100%; object-fit: cover; }
|
|
145
|
+
.flow-step-label { font-size: 11px; color: rgba(255,255,255,0.7); flex: 1; }
|
|
146
|
+
|
|
147
|
+
.footer {
|
|
148
|
+
text-align: center; margin-top: 24px;
|
|
149
|
+
font-size: 10px; color: rgba(255,255,255,0.2);
|
|
150
|
+
}
|
|
151
|
+
</style>
|
|
152
|
+
</head>
|
|
153
|
+
<body>
|
|
154
|
+
<div class="dashboard">
|
|
155
|
+
<div class="header">
|
|
156
|
+
<h1 id="vizTitle">Analysis Dashboard</h1>
|
|
157
|
+
<p id="vizSubtitle"></p>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div class="metrics-grid" id="metricsGrid"></div>
|
|
161
|
+
|
|
162
|
+
<!-- Screen thumbnails strip -->
|
|
163
|
+
<div class="section-card" style="margin-bottom: 16px;" id="screensSection">
|
|
164
|
+
<div class="section-title">Screens Captured</div>
|
|
165
|
+
<div class="screens-strip" id="screensStrip"></div>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<div class="content-grid">
|
|
169
|
+
<!-- Left: Bar chart -->
|
|
170
|
+
<div class="section-card">
|
|
171
|
+
<div class="section-title">UI Elements Distribution</div>
|
|
172
|
+
<div class="bar-chart" id="barChart"></div>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
<!-- Right: Flow steps with thumbnails -->
|
|
176
|
+
<div class="section-card">
|
|
177
|
+
<div class="section-title">User Flow</div>
|
|
178
|
+
<div class="flow-steps" id="flowSteps"></div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
|
|
182
|
+
<div class="footer" id="vizFooter">Generated by DiscoveryLab</div>
|
|
183
|
+
</div>
|
|
184
|
+
<script>
|
|
185
|
+
const DATA = window.__VISUALIZATION_DATA__ || {};
|
|
186
|
+
const screens = DATA.screens || [];
|
|
187
|
+
|
|
188
|
+
if (DATA.title) document.getElementById('vizTitle').textContent = DATA.title;
|
|
189
|
+
if (DATA.subtitle) document.getElementById('vizSubtitle').textContent = DATA.subtitle;
|
|
190
|
+
|
|
191
|
+
// Metrics cards
|
|
192
|
+
const metrics = DATA.metrics || [
|
|
193
|
+
{ value: DATA.screenCount || 0, label: 'Screens Analyzed' },
|
|
194
|
+
{ value: DATA.flowSteps || 0, label: 'Flow Steps' },
|
|
195
|
+
{ value: DATA.uiElements || 0, label: 'UI Elements' },
|
|
196
|
+
{ value: DATA.platform || 'N/A', label: 'Platform' },
|
|
197
|
+
];
|
|
198
|
+
const metricsGrid = document.getElementById('metricsGrid');
|
|
199
|
+
metrics.forEach(m => {
|
|
200
|
+
const card = document.createElement('div');
|
|
201
|
+
card.className = 'metric-card';
|
|
202
|
+
card.innerHTML = `
|
|
203
|
+
<div class="metric-value">${m.value}</div>
|
|
204
|
+
<div class="metric-label">${m.label}</div>
|
|
205
|
+
`;
|
|
206
|
+
metricsGrid.appendChild(card);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Screen thumbnails strip
|
|
210
|
+
const screensStrip = document.getElementById('screensStrip');
|
|
211
|
+
const screensSection = document.getElementById('screensSection');
|
|
212
|
+
if (screens.length > 0) {
|
|
213
|
+
screens.forEach((screen, i) => {
|
|
214
|
+
const el = document.createElement('div');
|
|
215
|
+
el.className = 'screen-thumb';
|
|
216
|
+
el.style.animationDelay = (0.3 + i * 0.1) + 's';
|
|
217
|
+
el.innerHTML = `
|
|
218
|
+
<img src="${screen.imageUrl}" alt="Screen ${i + 1}">
|
|
219
|
+
<div class="screen-thumb-label">${screen.label || 'Screen ' + (i + 1)}</div>
|
|
220
|
+
`;
|
|
221
|
+
screensStrip.appendChild(el);
|
|
222
|
+
});
|
|
223
|
+
} else {
|
|
224
|
+
screensSection.style.display = 'none';
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Bar chart
|
|
228
|
+
const categories = DATA.categories || [];
|
|
229
|
+
const barChart = document.getElementById('barChart');
|
|
230
|
+
const maxVal = Math.max(...categories.map(c => c.count), 1);
|
|
231
|
+
categories.forEach(cat => {
|
|
232
|
+
const pct = Math.round((cat.count / maxVal) * 100);
|
|
233
|
+
const row = document.createElement('div');
|
|
234
|
+
row.className = 'bar-row';
|
|
235
|
+
row.innerHTML = `
|
|
236
|
+
<div class="bar-label" title="${cat.name}">${cat.name}</div>
|
|
237
|
+
<div class="bar-track"><div class="bar-fill" style="width: 0%"></div></div>
|
|
238
|
+
<div class="bar-value">${cat.count}</div>
|
|
239
|
+
`;
|
|
240
|
+
barChart.appendChild(row);
|
|
241
|
+
requestAnimationFrame(() => {
|
|
242
|
+
setTimeout(() => { row.querySelector('.bar-fill').style.width = pct + '%'; }, 800);
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Flow steps with thumbnails
|
|
247
|
+
const steps = DATA.steps || [];
|
|
248
|
+
const flowSteps = document.getElementById('flowSteps');
|
|
249
|
+
steps.forEach((step, i) => {
|
|
250
|
+
const screen = screens[i];
|
|
251
|
+
const el = document.createElement('div');
|
|
252
|
+
el.className = 'flow-step';
|
|
253
|
+
el.style.animationDelay = (0.8 + i * 0.1) + 's';
|
|
254
|
+
el.innerHTML = `
|
|
255
|
+
<div class="flow-step-num">${i + 1}</div>
|
|
256
|
+
${screen ? `<div class="flow-step-thumb"><img src="${screen.imageUrl}" alt=""></div>` : ''}
|
|
257
|
+
<div class="flow-step-label">${step.label || step}</div>
|
|
258
|
+
`;
|
|
259
|
+
flowSteps.appendChild(el);
|
|
260
|
+
});
|
|
261
|
+
</script>
|
|
262
|
+
</body>
|
|
263
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veolab/discoverylab",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.4",
|
|
4
4
|
"description": "AI-powered app testing & evidence generator - Claude Code Plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"dev": "tsx watch src/cli.ts serve",
|
|
13
|
-
"build": "tsup src/index.ts src/cli.ts --format esm --dts --clean && cp src/web/index.html dist/index.html && node scripts/build-host-runtime.mjs --best-effort",
|
|
13
|
+
"build": "tsup src/index.ts src/cli.ts --format esm --dts --clean && cp src/web/index.html dist/index.html && mkdir -p dist/visualizations && cp src/core/visualizations/templates/*.html dist/visualizations/ && node scripts/build-host-runtime.mjs --best-effort",
|
|
14
14
|
"build:host-runtime": "node scripts/build-host-runtime.mjs",
|
|
15
15
|
"pack:local": "npm run build && npm run build:host-runtime && node scripts/verify-host-runtime-bundle.mjs && npm pack",
|
|
16
16
|
"prepack": "npm run build && npm run build:host-runtime && node scripts/verify-host-runtime-bundle.mjs",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"claude-plugin": {
|
|
69
69
|
"name": "DiscoveryLab",
|
|
70
70
|
"description": "AI-powered app testing & evidence generator",
|
|
71
|
-
"version": "1.4.
|
|
71
|
+
"version": "1.4.4",
|
|
72
72
|
"tools": [
|
|
73
73
|
"dlab.capture.screen",
|
|
74
74
|
"dlab.capture.emulator",
|