@veolab/discoverylab 1.4.3 → 1.6.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-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +70 -211
- package/dist/{chunk-HB3YPWF3.js → chunk-5AISGCS4.js} +166 -8
- package/dist/{chunk-CUBQRT5L.js → chunk-HFN6BTVO.js} +110 -1
- package/dist/{chunk-D4FTLCKM.js → chunk-IVX2OSOJ.js} +260 -4
- package/dist/cli.js +158 -27
- package/dist/export/infographic-template.html +254 -0
- package/dist/import-W2JEW254.js +180 -0
- package/dist/index.html +420 -9
- package/dist/index.js +4 -4
- package/dist/infographic-GQAHEOAA.js +183 -0
- package/dist/{server-CZPWQYOI.js → server-W3JQ5RG7.js} +1 -1
- package/dist/{setup-6JJYKKBS.js → setup-F7MGEFIM.js} +4 -1
- package/dist/{tools-Q7OZO732.js → tools-VYFNRUS4.js} +5 -3
- 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/doc/esvp-protocol.md +116 -0
- package/package.json +3 -3
- package/skills/knowledge-brain/SKILL.md +44 -43
package/dist/index.html
CHANGED
|
@@ -806,6 +806,10 @@
|
|
|
806
806
|
opacity: 1;
|
|
807
807
|
}
|
|
808
808
|
|
|
809
|
+
.project-card.select-mode .project-claude-action {
|
|
810
|
+
display: none;
|
|
811
|
+
}
|
|
812
|
+
|
|
809
813
|
.project-card.select-mode.checked .checkbox-circle {
|
|
810
814
|
opacity: 0;
|
|
811
815
|
}
|
|
@@ -920,6 +924,37 @@
|
|
|
920
924
|
object-fit: cover;
|
|
921
925
|
}
|
|
922
926
|
|
|
927
|
+
.project-claude-action {
|
|
928
|
+
position: absolute;
|
|
929
|
+
top: 8px;
|
|
930
|
+
left: 8px;
|
|
931
|
+
display: inline-flex;
|
|
932
|
+
align-items: center;
|
|
933
|
+
justify-content: center;
|
|
934
|
+
width: 32px;
|
|
935
|
+
height: 32px;
|
|
936
|
+
border-radius: 999px;
|
|
937
|
+
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
938
|
+
background: rgba(11, 16, 24, 0.78);
|
|
939
|
+
color: #f5f0e6;
|
|
940
|
+
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.22);
|
|
941
|
+
z-index: 2;
|
|
942
|
+
cursor: pointer;
|
|
943
|
+
transition: transform 0.15s ease, border-color 0.15s ease, background 0.15s ease;
|
|
944
|
+
backdrop-filter: blur(10px);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
.project-claude-action:hover {
|
|
948
|
+
transform: translateY(-1px);
|
|
949
|
+
border-color: rgba(245, 240, 230, 0.5);
|
|
950
|
+
background: rgba(17, 24, 32, 0.92);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.project-claude-action svg {
|
|
954
|
+
width: 16px;
|
|
955
|
+
height: 16px;
|
|
956
|
+
}
|
|
957
|
+
|
|
923
958
|
.project-info {
|
|
924
959
|
padding: 12px;
|
|
925
960
|
}
|
|
@@ -987,6 +1022,82 @@
|
|
|
987
1022
|
font-weight: 700;
|
|
988
1023
|
}
|
|
989
1024
|
|
|
1025
|
+
.claude-integration-row {
|
|
1026
|
+
display: flex;
|
|
1027
|
+
align-items: center;
|
|
1028
|
+
justify-content: space-between;
|
|
1029
|
+
gap: 12px;
|
|
1030
|
+
margin-top: 10px;
|
|
1031
|
+
padding-top: 10px;
|
|
1032
|
+
border-top: 1px solid var(--border);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
.claude-integration-meta {
|
|
1036
|
+
min-width: 0;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
.claude-integration-title {
|
|
1040
|
+
font-size: 11px;
|
|
1041
|
+
color: var(--text-muted);
|
|
1042
|
+
font-weight: 600;
|
|
1043
|
+
text-transform: uppercase;
|
|
1044
|
+
letter-spacing: 0.4px;
|
|
1045
|
+
margin-bottom: 4px;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.claude-integration-copy {
|
|
1049
|
+
font-size: 12px;
|
|
1050
|
+
color: var(--text-secondary);
|
|
1051
|
+
line-height: 1.45;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.claude-integration-actions {
|
|
1055
|
+
display: flex;
|
|
1056
|
+
align-items: center;
|
|
1057
|
+
gap: 8px;
|
|
1058
|
+
flex-shrink: 0;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
.claude-action-btn {
|
|
1062
|
+
display: inline-flex;
|
|
1063
|
+
align-items: center;
|
|
1064
|
+
gap: 8px;
|
|
1065
|
+
border: 1px solid rgba(236, 229, 215, 0.18);
|
|
1066
|
+
background: linear-gradient(135deg, rgba(34, 25, 18, 0.96), rgba(17, 12, 9, 0.96));
|
|
1067
|
+
color: #f5f0e6;
|
|
1068
|
+
padding: 9px 12px;
|
|
1069
|
+
border-radius: 10px;
|
|
1070
|
+
cursor: pointer;
|
|
1071
|
+
transition: transform 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
|
|
1072
|
+
font-size: 12px;
|
|
1073
|
+
font-weight: 600;
|
|
1074
|
+
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.18);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
.claude-action-btn:hover {
|
|
1078
|
+
transform: translateY(-1px);
|
|
1079
|
+
border-color: rgba(245, 240, 230, 0.34);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
.claude-action-btn.secondary {
|
|
1083
|
+
background: var(--bg-tertiary);
|
|
1084
|
+
color: var(--text-secondary);
|
|
1085
|
+
box-shadow: none;
|
|
1086
|
+
border-color: var(--border);
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
.claude-action-btn:disabled {
|
|
1090
|
+
opacity: 0.56;
|
|
1091
|
+
cursor: default;
|
|
1092
|
+
transform: none;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
.claude-action-btn svg {
|
|
1096
|
+
width: 14px;
|
|
1097
|
+
height: 14px;
|
|
1098
|
+
flex-shrink: 0;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
990
1101
|
.project-meta {
|
|
991
1102
|
font-size: 11px;
|
|
992
1103
|
color: var(--text-muted);
|
|
@@ -6795,7 +6906,7 @@
|
|
|
6795
6906
|
<span>App Intelligence</span>
|
|
6796
6907
|
</div>
|
|
6797
6908
|
<div class="welcome-footnote">
|
|
6798
|
-
Built with the open
|
|
6909
|
+
Built with the open ESVP protocol by Entropy Lab for reproducible mobile sessions, replay, and network-aware validation.
|
|
6799
6910
|
</div>
|
|
6800
6911
|
</div>
|
|
6801
6912
|
</div>
|
|
@@ -8109,6 +8220,223 @@
|
|
|
8109
8220
|
}
|
|
8110
8221
|
}
|
|
8111
8222
|
|
|
8223
|
+
let claudeDesktopStatus = {
|
|
8224
|
+
ready: false,
|
|
8225
|
+
appDetected: false,
|
|
8226
|
+
launcherSupported: false,
|
|
8227
|
+
mcpConfigured: false,
|
|
8228
|
+
serverName: null,
|
|
8229
|
+
installCommand: 'npx -y @veolab/discoverylab@latest install --target desktop',
|
|
8230
|
+
message: 'Checking Claude Desktop...',
|
|
8231
|
+
checking: false,
|
|
8232
|
+
error: null,
|
|
8233
|
+
lastCheckedAt: null
|
|
8234
|
+
};
|
|
8235
|
+
|
|
8236
|
+
function getClaudeIconSvg() {
|
|
8237
|
+
return `
|
|
8238
|
+
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
8239
|
+
<path d="M12 3.5c-2.1 0-3.8 1-4.9 2.8C4.9 6.5 3.5 8.4 3.5 11c0 3.9 2.9 6.8 7.1 8.7a3 3 0 0 0 2.8 0c4.1-1.9 7.1-4.8 7.1-8.7 0-2.6-1.4-4.5-3.6-4.7C15.8 4.5 14.1 3.5 12 3.5Z" stroke="currentColor" stroke-width="1.5"/>
|
|
8240
|
+
<path d="M8.5 10.5c.9-1 2.1-1.5 3.5-1.5s2.6.5 3.5 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
8241
|
+
<path d="M9.2 13.8c.8.7 1.7 1.1 2.8 1.1 1 0 2-.4 2.8-1.1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
8242
|
+
</svg>
|
|
8243
|
+
`;
|
|
8244
|
+
}
|
|
8245
|
+
|
|
8246
|
+
function isProjectReadyForClaude(project) {
|
|
8247
|
+
if (!project) return false;
|
|
8248
|
+
if (isProjectAnalyzing(project.status || '')) return false;
|
|
8249
|
+
return Boolean(
|
|
8250
|
+
(project.aiSummary && project.aiSummary.trim()) ||
|
|
8251
|
+
(project.ocrText && project.ocrText.trim()) ||
|
|
8252
|
+
(Array.isArray(project.frames) && project.frames.length > 0) ||
|
|
8253
|
+
project.frameCount > 0
|
|
8254
|
+
);
|
|
8255
|
+
}
|
|
8256
|
+
|
|
8257
|
+
function buildClaudeDesktopPrompt(project) {
|
|
8258
|
+
const projectId = project?.id || '';
|
|
8259
|
+
const projectName = project?.name || 'this DiscoveryLab project';
|
|
8260
|
+
return [
|
|
8261
|
+
`Use DiscoveryLab local tools to open project "${projectName}" (projectId: "${projectId}") in an interactive flow canvas.`,
|
|
8262
|
+
`Call dlab.knowledge.open with projectId "${projectId}".`,
|
|
8263
|
+
'After opening the canvas, explain the flow, key screens, and important risks or opportunities.',
|
|
8264
|
+
].join(' ');
|
|
8265
|
+
}
|
|
8266
|
+
|
|
8267
|
+
function renderClaudeProjectQuickAction(project) {
|
|
8268
|
+
if (!claudeDesktopStatus.ready || !isProjectReadyForClaude(project)) {
|
|
8269
|
+
return '';
|
|
8270
|
+
}
|
|
8271
|
+
|
|
8272
|
+
const promptTitle = `Copy prompt and open ${project.name} in Claude Desktop`;
|
|
8273
|
+
return `
|
|
8274
|
+
<button
|
|
8275
|
+
class="project-claude-action"
|
|
8276
|
+
type="button"
|
|
8277
|
+
data-project-id="${escapeAttr(project.id)}"
|
|
8278
|
+
title="${escapeAttr(promptTitle)}"
|
|
8279
|
+
aria-label="${escapeAttr(promptTitle)}"
|
|
8280
|
+
onclick="event.stopPropagation(); openProjectInClaudeById(this.dataset.projectId);"
|
|
8281
|
+
>
|
|
8282
|
+
${getClaudeIconSvg()}
|
|
8283
|
+
</button>
|
|
8284
|
+
`;
|
|
8285
|
+
}
|
|
8286
|
+
|
|
8287
|
+
function renderClaudeProjectLaunchRow(project) {
|
|
8288
|
+
const projectReady = isProjectReadyForClaude(project);
|
|
8289
|
+
const statusCopy = !projectReady
|
|
8290
|
+
? 'Finish analysis or capture enough frames before opening this project in Claude Desktop.'
|
|
8291
|
+
: claudeDesktopStatus.error
|
|
8292
|
+
? claudeDesktopStatus.error
|
|
8293
|
+
: claudeDesktopStatus.message || 'Claude Desktop status unavailable.';
|
|
8294
|
+
const ready = claudeDesktopStatus.ready && projectReady;
|
|
8295
|
+
const setupNeeded = claudeDesktopStatus.appDetected && !claudeDesktopStatus.mcpConfigured;
|
|
8296
|
+
const buttonLabel = ready
|
|
8297
|
+
? 'Open in Claude Desktop'
|
|
8298
|
+
: !projectReady
|
|
8299
|
+
? 'Analyze first'
|
|
8300
|
+
: setupNeeded
|
|
8301
|
+
? 'Copy install command'
|
|
8302
|
+
: 'Reload';
|
|
8303
|
+
const buttonClass = ready ? 'claude-action-btn' : 'claude-action-btn secondary';
|
|
8304
|
+
const action = ready
|
|
8305
|
+
? 'openCurrentProjectInClaude()'
|
|
8306
|
+
: !projectReady
|
|
8307
|
+
? ''
|
|
8308
|
+
: setupNeeded
|
|
8309
|
+
? 'copyClaudeDesktopInstallCommand()'
|
|
8310
|
+
: 'refreshClaudeDesktopStatus()';
|
|
8311
|
+
|
|
8312
|
+
return `
|
|
8313
|
+
<div class="claude-integration-row">
|
|
8314
|
+
<div class="claude-integration-meta">
|
|
8315
|
+
<div class="claude-integration-title">Claude Desktop</div>
|
|
8316
|
+
<div class="claude-integration-copy">${escapeHtml(statusCopy)}</div>
|
|
8317
|
+
</div>
|
|
8318
|
+
<div class="claude-integration-actions">
|
|
8319
|
+
<button class="${buttonClass}" type="button" ${action ? `onclick="${action}"` : 'disabled'}>
|
|
8320
|
+
${getClaudeIconSvg()}
|
|
8321
|
+
<span>${escapeHtml(buttonLabel)}</span>
|
|
8322
|
+
</button>
|
|
8323
|
+
</div>
|
|
8324
|
+
</div>
|
|
8325
|
+
`;
|
|
8326
|
+
}
|
|
8327
|
+
|
|
8328
|
+
function rerenderClaudeDesktopAffordances() {
|
|
8329
|
+
if (currentView === 'projects') {
|
|
8330
|
+
renderProjects();
|
|
8331
|
+
} else if (currentView === 'analysis' && currentProject) {
|
|
8332
|
+
updateAnalysisTab();
|
|
8333
|
+
} else if (currentView === 'export' && currentProject) {
|
|
8334
|
+
updateExportTab();
|
|
8335
|
+
}
|
|
8336
|
+
}
|
|
8337
|
+
|
|
8338
|
+
async function refreshClaudeDesktopStatus(options = {}) {
|
|
8339
|
+
const { silent = false } = options;
|
|
8340
|
+
claudeDesktopStatus.checking = true;
|
|
8341
|
+
|
|
8342
|
+
try {
|
|
8343
|
+
const response = await fetch('/api/integrations/claude-desktop/status');
|
|
8344
|
+
const data = await response.json();
|
|
8345
|
+
if (data?.error) {
|
|
8346
|
+
throw new Error(data.error);
|
|
8347
|
+
}
|
|
8348
|
+
|
|
8349
|
+
claudeDesktopStatus = {
|
|
8350
|
+
...claudeDesktopStatus,
|
|
8351
|
+
ready: !!data.ready,
|
|
8352
|
+
appDetected: !!data.appDetected,
|
|
8353
|
+
launcherSupported: !!data.launcherSupported,
|
|
8354
|
+
mcpConfigured: !!data.mcpConfigured,
|
|
8355
|
+
serverName: data.serverName || null,
|
|
8356
|
+
installCommand: data.installCommand || claudeDesktopStatus.installCommand,
|
|
8357
|
+
message: data.message || 'Claude Desktop status loaded.',
|
|
8358
|
+
checking: false,
|
|
8359
|
+
error: null,
|
|
8360
|
+
lastCheckedAt: new Date().toISOString()
|
|
8361
|
+
};
|
|
8362
|
+
} catch (error) {
|
|
8363
|
+
claudeDesktopStatus = {
|
|
8364
|
+
...claudeDesktopStatus,
|
|
8365
|
+
checking: false,
|
|
8366
|
+
error: error instanceof Error ? error.message : 'Failed to check Claude Desktop status',
|
|
8367
|
+
message: 'Could not check Claude Desktop status.'
|
|
8368
|
+
};
|
|
8369
|
+
if (!silent) {
|
|
8370
|
+
showToast('Failed to check Claude Desktop status', 'error');
|
|
8371
|
+
}
|
|
8372
|
+
}
|
|
8373
|
+
|
|
8374
|
+
rerenderClaudeDesktopAffordances();
|
|
8375
|
+
}
|
|
8376
|
+
|
|
8377
|
+
function copyClaudeDesktopInstallCommand() {
|
|
8378
|
+
void copyToClipboard(
|
|
8379
|
+
claudeDesktopStatus.installCommand || 'npx -y @veolab/discoverylab@latest install --target desktop',
|
|
8380
|
+
{ silent: true }
|
|
8381
|
+
).then((copied) => {
|
|
8382
|
+
showToast(copied ? 'Claude Desktop install command copied' : 'Failed to copy install command', copied ? 'success' : 'error');
|
|
8383
|
+
});
|
|
8384
|
+
}
|
|
8385
|
+
|
|
8386
|
+
async function launchClaudeDesktop() {
|
|
8387
|
+
const response = await fetch('/api/integrations/claude-desktop/launch', { method: 'POST' });
|
|
8388
|
+
const data = await response.json();
|
|
8389
|
+
if (!response.ok || data?.success === false) {
|
|
8390
|
+
throw new Error(data?.error || 'Failed to open Claude Desktop');
|
|
8391
|
+
}
|
|
8392
|
+
}
|
|
8393
|
+
|
|
8394
|
+
async function copyPromptAndLaunchClaude(project) {
|
|
8395
|
+
if (!project) return;
|
|
8396
|
+
|
|
8397
|
+
const copied = await copyToClipboard(buildClaudeDesktopPrompt(project), { silent: true });
|
|
8398
|
+
if (!copied) {
|
|
8399
|
+
showToast('Failed to copy Claude Desktop prompt', 'error');
|
|
8400
|
+
return;
|
|
8401
|
+
}
|
|
8402
|
+
|
|
8403
|
+
try {
|
|
8404
|
+
await launchClaudeDesktop();
|
|
8405
|
+
showToast('Prompt copied and Claude Desktop opened', 'success');
|
|
8406
|
+
} catch (error) {
|
|
8407
|
+
showToast(error instanceof Error ? error.message : 'Prompt copied, but Claude Desktop could not be opened', 'warning');
|
|
8408
|
+
}
|
|
8409
|
+
}
|
|
8410
|
+
|
|
8411
|
+
async function openProjectInClaudeById(projectId) {
|
|
8412
|
+
const project = projects.find((item) => item.id === projectId) || (currentProject?.id === projectId ? currentProject : null);
|
|
8413
|
+
if (!project) {
|
|
8414
|
+
showToast('Project not found', 'error');
|
|
8415
|
+
return;
|
|
8416
|
+
}
|
|
8417
|
+
|
|
8418
|
+
if (!claudeDesktopStatus.ready) {
|
|
8419
|
+
if (claudeDesktopStatus.appDetected && !claudeDesktopStatus.mcpConfigured) {
|
|
8420
|
+
copyClaudeDesktopInstallCommand();
|
|
8421
|
+
return;
|
|
8422
|
+
}
|
|
8423
|
+
|
|
8424
|
+
showToast(claudeDesktopStatus.message || 'Claude Desktop is not ready yet.', 'warning');
|
|
8425
|
+
return;
|
|
8426
|
+
}
|
|
8427
|
+
|
|
8428
|
+
await copyPromptAndLaunchClaude(project);
|
|
8429
|
+
}
|
|
8430
|
+
|
|
8431
|
+
async function openCurrentProjectInClaude() {
|
|
8432
|
+
if (!currentProject?.id) {
|
|
8433
|
+
showToast('Select a project first', 'warning');
|
|
8434
|
+
return;
|
|
8435
|
+
}
|
|
8436
|
+
|
|
8437
|
+
await openProjectInClaudeById(currentProject.id);
|
|
8438
|
+
}
|
|
8439
|
+
|
|
8112
8440
|
let jiraMcpStatus = {
|
|
8113
8441
|
available: false,
|
|
8114
8442
|
configured: false,
|
|
@@ -11288,6 +11616,7 @@
|
|
|
11288
11616
|
<div class="processing-text">${processingText}</div>
|
|
11289
11617
|
</div>
|
|
11290
11618
|
<div class="project-thumb">
|
|
11619
|
+
${renderClaudeProjectQuickAction(p)}
|
|
11291
11620
|
${getProjectThumb(p)}
|
|
11292
11621
|
</div>
|
|
11293
11622
|
<div class="project-info">
|
|
@@ -12418,6 +12747,7 @@
|
|
|
12418
12747
|
<button class="btn btn-primary btn-small" onclick="retryProjectAnalysis()" id="retryProjectAnalysisBtn">Retry Analysis</button>
|
|
12419
12748
|
</div>
|
|
12420
12749
|
` : ''}
|
|
12750
|
+
${renderClaudeProjectLaunchRow(currentProject)}
|
|
12421
12751
|
<div class="project-integration-row">
|
|
12422
12752
|
<div class="project-integration-label">Jira MCP</div>
|
|
12423
12753
|
<div class="project-integration-status">
|
|
@@ -12864,6 +13194,23 @@
|
|
|
12864
13194
|
|
|
12865
13195
|
if (favoriteTemplate && currentTemplateProps?.templatesAllowed !== false) {
|
|
12866
13196
|
switchTemplate(favoriteTemplate);
|
|
13197
|
+
} else if (currentTemplateProps?.templatesAllowed !== false) {
|
|
13198
|
+
// Auto-select cached template if available (no re-render needed)
|
|
13199
|
+
const templates = templateStatus.templates || [];
|
|
13200
|
+
for (const t of templates) {
|
|
13201
|
+
try {
|
|
13202
|
+
const checkRes = await fetch('/api/templates/render', {
|
|
13203
|
+
method: 'POST',
|
|
13204
|
+
headers: { 'Content-Type': 'application/json' },
|
|
13205
|
+
body: JSON.stringify({ projectId: currentProject?.id, templateId: t.id }),
|
|
13206
|
+
});
|
|
13207
|
+
const checkData = await checkRes.json();
|
|
13208
|
+
if (checkData.cached) {
|
|
13209
|
+
switchTemplate(t.id);
|
|
13210
|
+
break;
|
|
13211
|
+
}
|
|
13212
|
+
} catch { /* skip */ }
|
|
13213
|
+
}
|
|
12867
13214
|
}
|
|
12868
13215
|
} catch (e) {
|
|
12869
13216
|
console.log('[Templates] Init error:', e);
|
|
@@ -12983,7 +13330,7 @@
|
|
|
12983
13330
|
}
|
|
12984
13331
|
}
|
|
12985
13332
|
|
|
12986
|
-
async function switchTemplate(templateId) {
|
|
13333
|
+
async function switchTemplate(templateId, force = false) {
|
|
12987
13334
|
// Skip if already on this template
|
|
12988
13335
|
if (templateId === activeTemplate) return;
|
|
12989
13336
|
if (templateId !== 'raw' && currentTemplateProps?.templatesAllowed === false) {
|
|
@@ -13028,7 +13375,7 @@
|
|
|
13028
13375
|
const res = await fetch('/api/templates/render', {
|
|
13029
13376
|
method: 'POST',
|
|
13030
13377
|
headers: { 'Content-Type': 'application/json' },
|
|
13031
|
-
body: JSON.stringify({ projectId: currentProject.id, templateId }),
|
|
13378
|
+
body: JSON.stringify({ projectId: currentProject.id, templateId, force }),
|
|
13032
13379
|
});
|
|
13033
13380
|
const data = await res.json();
|
|
13034
13381
|
|
|
@@ -13038,6 +13385,20 @@
|
|
|
13038
13385
|
return;
|
|
13039
13386
|
}
|
|
13040
13387
|
|
|
13388
|
+
// Cached render - show immediately without polling
|
|
13389
|
+
if (data.cached && data.previewUrl) {
|
|
13390
|
+
const skeleton = document.getElementById('templateSkeleton');
|
|
13391
|
+
const templateContainer = document.getElementById('templatePreviewContainer');
|
|
13392
|
+
const templateVideo = document.getElementById('templateVideo');
|
|
13393
|
+
if (skeleton) skeleton.style.display = 'none';
|
|
13394
|
+
if (templateVideo) {
|
|
13395
|
+
templateVideo.src = data.previewUrl + '&t=' + Date.now();
|
|
13396
|
+
templateVideo.load();
|
|
13397
|
+
}
|
|
13398
|
+
if (templateContainer) templateContainer.style.display = '';
|
|
13399
|
+
return;
|
|
13400
|
+
}
|
|
13401
|
+
|
|
13041
13402
|
if (data.jobId) {
|
|
13042
13403
|
pollRenderJob(data.jobId, templateId);
|
|
13043
13404
|
}
|
|
@@ -13490,11 +13851,11 @@
|
|
|
13490
13851
|
deviceMockup: data.content?.deviceMockup || deviceMockup,
|
|
13491
13852
|
};
|
|
13492
13853
|
|
|
13493
|
-
// Force re-render
|
|
13854
|
+
// Force re-render after content edit
|
|
13494
13855
|
if (activeTemplate !== 'raw') {
|
|
13495
13856
|
const prevTemplate = activeTemplate;
|
|
13496
13857
|
activeTemplate = '__force_rerender__';
|
|
13497
|
-
switchTemplate(prevTemplate);
|
|
13858
|
+
switchTemplate(prevTemplate, true);
|
|
13498
13859
|
}
|
|
13499
13860
|
} catch {
|
|
13500
13861
|
showToast('Failed to save content', 'error');
|
|
@@ -15571,9 +15932,34 @@
|
|
|
15571
15932
|
showToast(`Copied "${command}" - paste in Claude Code`, 'success', 5000);
|
|
15572
15933
|
}
|
|
15573
15934
|
|
|
15574
|
-
function copyToClipboard(text) {
|
|
15575
|
-
|
|
15576
|
-
|
|
15935
|
+
async function copyToClipboard(text, options = {}) {
|
|
15936
|
+
const { silent = false } = options;
|
|
15937
|
+
|
|
15938
|
+
try {
|
|
15939
|
+
if (navigator.clipboard?.writeText) {
|
|
15940
|
+
await navigator.clipboard.writeText(text);
|
|
15941
|
+
} else {
|
|
15942
|
+
const textarea = document.createElement('textarea');
|
|
15943
|
+
textarea.value = text;
|
|
15944
|
+
textarea.setAttribute('readonly', 'true');
|
|
15945
|
+
textarea.style.position = 'absolute';
|
|
15946
|
+
textarea.style.left = '-9999px';
|
|
15947
|
+
document.body.appendChild(textarea);
|
|
15948
|
+
textarea.select();
|
|
15949
|
+
document.execCommand('copy');
|
|
15950
|
+
textarea.remove();
|
|
15951
|
+
}
|
|
15952
|
+
|
|
15953
|
+
if (!silent) {
|
|
15954
|
+
showToast('Copied to clipboard', 'success');
|
|
15955
|
+
}
|
|
15956
|
+
return true;
|
|
15957
|
+
} catch (error) {
|
|
15958
|
+
if (!silent) {
|
|
15959
|
+
showToast('Failed to copy to clipboard', 'error');
|
|
15960
|
+
}
|
|
15961
|
+
return false;
|
|
15962
|
+
}
|
|
15577
15963
|
}
|
|
15578
15964
|
|
|
15579
15965
|
async function openMaestroStudio() {
|
|
@@ -15868,6 +16254,7 @@
|
|
|
15868
16254
|
if (el && data.version) el.textContent = 'v' + data.version;
|
|
15869
16255
|
}).catch(() => {});
|
|
15870
16256
|
void loadProxySafetySettings().catch(() => null);
|
|
16257
|
+
void refreshClaudeDesktopStatus({ silent: true });
|
|
15871
16258
|
|
|
15872
16259
|
// Auto-check dependencies on first load — open Settings if critical deps missing
|
|
15873
16260
|
fetch('/api/setup/status').then(r => r.json()).then(data => {
|
|
@@ -22043,13 +22430,37 @@ appId: ${platform === 'ios' ? 'com.apple.Preferences' : 'com.android.settings'}
|
|
|
22043
22430
|
<div id="exportFormatHelp" style="margin-top: 8px; font-size: 12px; color: var(--text-muted); line-height: 1.5;"></div>
|
|
22044
22431
|
</div>
|
|
22045
22432
|
|
|
22046
|
-
<
|
|
22433
|
+
<div style="display: flex; gap: 8px;">
|
|
22434
|
+
<button class="btn btn-primary" onclick="exportProject()">Export</button>
|
|
22435
|
+
<button class="btn btn-secondary" onclick="exportInfographicHtml()" style="font-size: 11px;">Infographic HTML</button>
|
|
22436
|
+
</div>
|
|
22047
22437
|
</div>
|
|
22048
22438
|
`;
|
|
22049
22439
|
|
|
22050
22440
|
updateExportFormatHelp();
|
|
22051
22441
|
}
|
|
22052
22442
|
|
|
22443
|
+
async function exportInfographicHtml() {
|
|
22444
|
+
if (!currentProject) return;
|
|
22445
|
+
showToast('Generating infographic...', 'info');
|
|
22446
|
+
try {
|
|
22447
|
+
const resp = await fetch('/api/export/infographic', {
|
|
22448
|
+
method: 'POST',
|
|
22449
|
+
headers: { 'Content-Type': 'application/json' },
|
|
22450
|
+
body: JSON.stringify({ projectId: currentProject.id, open: true }),
|
|
22451
|
+
});
|
|
22452
|
+
const data = await resp.json();
|
|
22453
|
+
if (data.success) {
|
|
22454
|
+
const sizeKb = ((data.size || 0) / 1024).toFixed(1);
|
|
22455
|
+
showToast(`Infographic exported (${sizeKb}KB, ${data.frameCount} frames)`, 'success');
|
|
22456
|
+
} else {
|
|
22457
|
+
showToast(data.error || 'Export failed', 'error');
|
|
22458
|
+
}
|
|
22459
|
+
} catch (err) {
|
|
22460
|
+
showToast('Export failed', 'error');
|
|
22461
|
+
}
|
|
22462
|
+
}
|
|
22463
|
+
|
|
22053
22464
|
async function exportProject() {
|
|
22054
22465
|
if (!currentProject) return;
|
|
22055
22466
|
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
startServer,
|
|
4
4
|
stopServer
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-IVX2OSOJ.js";
|
|
6
6
|
import {
|
|
7
7
|
analyzeTools,
|
|
8
8
|
canvasTools,
|
|
@@ -16,15 +16,15 @@ import {
|
|
|
16
16
|
templateTools,
|
|
17
17
|
testingTools,
|
|
18
18
|
uiTools
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-5AISGCS4.js";
|
|
20
|
+
import "./chunk-34GGYFXX.js";
|
|
20
21
|
import "./chunk-PMCXEA7J.js";
|
|
21
22
|
import {
|
|
22
23
|
setupTools
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-HFN6BTVO.js";
|
|
24
25
|
import {
|
|
25
26
|
mcpServer
|
|
26
27
|
} from "./chunk-XKX6NBHF.js";
|
|
27
|
-
import "./chunk-34GGYFXX.js";
|
|
28
28
|
import "./chunk-6GK5K6CS.js";
|
|
29
29
|
import "./chunk-7R5YNOXE.js";
|
|
30
30
|
import "./chunk-3ERJNXYM.js";
|