@veolab/discoverylab 0.1.9 → 1.1.0

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/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ program.command("serve").description("Start the DiscoveryLab web UI server").opt
11
11
  console.log(chalk.cyan("\n DiscoveryLab"));
12
12
  console.log(chalk.gray(" AI-powered app testing & evidence generator\n"));
13
13
  try {
14
- const { startServer } = await import("./server-JSCHEBOD.js");
14
+ const { startServer } = await import("./server-G32U7VOQ.js");
15
15
  await startServer(port);
16
16
  console.log(chalk.green(` Server running at http://localhost:${port}`));
17
17
  console.log(chalk.gray(" Press Ctrl+C to stop\n"));
@@ -26,7 +26,7 @@ program.command("serve").description("Start the DiscoveryLab web UI server").opt
26
26
  program.command("setup").description("Check and configure DiscoveryLab dependencies").action(async () => {
27
27
  console.log(chalk.cyan("\n DiscoveryLab Setup\n"));
28
28
  try {
29
- const { setupStatusTool } = await import("./setup-27CQAX6K.js");
29
+ const { setupStatusTool } = await import("./setup-EQTU7FI6.js");
30
30
  const result = await setupStatusTool.handler({});
31
31
  if (result.isError) {
32
32
  console.error(chalk.red(" Setup check failed"));
@@ -111,7 +111,7 @@ program.command("mcp").description("Run as MCP server (for Claude Code integrati
111
111
  const { getDatabase } = await import("./db-IWIL65EX.js");
112
112
  getDatabase();
113
113
  const { mcpServer } = await import("./server-3FBHBA7L.js");
114
- const { uiTools, projectTools, setupTools, captureTools, analyzeTools, canvasTools, exportTools, testingTools, integrationTools } = await import("./tools-NFJEZ2FF.js");
114
+ const { uiTools, projectTools, setupTools, captureTools, analyzeTools, canvasTools, exportTools, testingTools, integrationTools } = await import("./tools-3KYHPDCJ.js");
115
115
  mcpServer.registerTools([
116
116
  ...uiTools,
117
117
  ...projectTools,
package/dist/index.html CHANGED
@@ -6965,7 +6965,7 @@
6965
6965
  <option value="auto">Auto (priority order)</option>
6966
6966
  </select>
6967
6967
  <div style="font-size: 10px; color: var(--text-muted); margin-top: 4px;">
6968
- Auto: Anthropic → OpenAI → Claude CLI → Ollama
6968
+ Auto: Anthropic → OpenAI → Ollama → Claude CLI
6969
6969
  </div>
6970
6970
  </div>
6971
6971
  <div class="setting-item">
@@ -6978,15 +6978,18 @@
6978
6978
  <div class="setting-item">
6979
6979
  <label class="setting-label">Anthropic Model</label>
6980
6980
  <select class="setting-input" id="anthropicModel" style="cursor: pointer;">
6981
- <option value="claude-sonnet-4-20250514">Claude Sonnet 4 ($3/$15 per 1M tokens)</option>
6982
- <option value="claude-opus-4-5-20250514">Claude Opus 4.5 ($5/$25) - Most capable</option>
6983
- <option value="claude-sonnet-4-5-20250514">Claude Sonnet 4.5 ($3/$15)</option>
6984
- <option value="claude-3-5-haiku-20241022">Claude Haiku 3.5 ($1/$5)</option>
6985
- <option value="claude-3-haiku-20240307">Claude Haiku 3 ($0.25/$1.25) - Cheapest</option>
6981
+ <option value="claude-sonnet-4-6">Claude Sonnet 4.6 (recommended default)</option>
6982
+ <option value="claude-opus-4-6">Claude Opus 4.6 (most capable)</option>
6983
+ <option value="claude-haiku-4-5">Claude Haiku 4.5 (fastest/lowest cost)</option>
6984
+ <option value="claude-opus-4-1">Claude Opus 4.1</option>
6985
+ <option value="claude-sonnet-4">Claude Sonnet 4</option>
6986
+ <option value="claude-3-7-sonnet-latest">Claude Sonnet 3.7</option>
6987
+ <option value="claude-3-5-sonnet-latest">Claude Sonnet 3.5</option>
6988
+ <option value="claude-3-5-haiku-latest">Claude Haiku 3.5</option>
6986
6989
  </select>
6987
6990
  </div>
6988
6991
  <div class="setting-item">
6989
- <label class="setting-label">OpenAI API Key (GPT-4)</label>
6992
+ <label class="setting-label">OpenAI API Key</label>
6990
6993
  <input type="password" class="setting-input" id="openaiApiKey" placeholder="sk-..." autocomplete="off">
6991
6994
  <div style="font-size: 10px; color: var(--text-muted); margin-top: 4px;">
6992
6995
  <a href="https://platform.openai.com/api-keys" target="_blank" style="color: var(--accent);">Get API key</a> - Alternative
@@ -6996,29 +6999,44 @@
6996
6999
  <label class="setting-label">OpenAI Model</label>
6997
7000
  <select class="setting-input" id="openaiModel" style="cursor: pointer;">
6998
7001
  <optgroup label="GPT-5 Series (Latest)">
6999
- <option value="gpt-5.2">GPT-5.2 ($1.25/$10) - Best for coding & agents</option>
7000
- <option value="gpt-5-mini">GPT-5 Mini ($0.25/$2) - Fast & efficient</option>
7001
- <option value="gpt-5-nano">GPT-5 Nano ($0.05/$0.40) - Fastest & cheapest</option>
7002
+ <option value="gpt-5.2">GPT-5.2 (best default for coding/agents)</option>
7003
+ <option value="gpt-5">GPT-5</option>
7004
+ <option value="gpt-5-mini">GPT-5 Mini (fast/efficient)</option>
7005
+ <option value="gpt-5-nano">GPT-5 Nano (lowest cost)</option>
7002
7006
  </optgroup>
7003
7007
  <optgroup label="GPT-4.1 Series">
7004
- <option value="gpt-4.1">GPT-4.1 ($3/$12)</option>
7005
- <option value="gpt-4.1-mini">GPT-4.1 Mini ($0.80/$3.20)</option>
7006
- <option value="gpt-4.1-nano">GPT-4.1 Nano ($0.20/$0.80)</option>
7008
+ <option value="gpt-4.1">GPT-4.1</option>
7009
+ <option value="gpt-4.1-mini">GPT-4.1 Mini</option>
7010
+ <option value="gpt-4.1-nano">GPT-4.1 Nano</option>
7007
7011
  </optgroup>
7008
7012
  <optgroup label="GPT-4o Series">
7009
- <option value="gpt-4o">GPT-4o ($2.50/$10)</option>
7010
- <option value="gpt-4o-mini">GPT-4o Mini ($0.15/$0.60)</option>
7013
+ <option value="gpt-4o">GPT-4o</option>
7014
+ <option value="gpt-4o-mini">GPT-4o Mini</option>
7011
7015
  </optgroup>
7012
7016
  <optgroup label="o-Series (Reasoning)">
7013
- <option value="o4-mini">o4-mini ($4/$16) - Latest reasoning</option>
7017
+ <option value="o4-mini">o4-mini (latest fast reasoning)</option>
7018
+ <option value="o3">o3 (strong reasoning)</option>
7014
7019
  <option value="o3-mini">o3-mini</option>
7015
- <option value="o1">o1 ($15/$60)</option>
7016
- <option value="o1-mini">o1-mini ($3/$12)</option>
7017
7020
  </optgroup>
7018
7021
  </select>
7022
+ <div style="font-size: 10px; color: var(--text-muted); margin-top: 4px;">
7023
+ Keep this list focused on general-purpose models that work well in DiscoveryLab.
7024
+ </div>
7025
+ </div>
7026
+ <div class="setting-item">
7027
+ <label class="setting-label">Claude CLI Model (Local)</label>
7028
+ <select class="setting-input" id="claudeCliModel" style="cursor: pointer;">
7029
+ <option value="haiku">Haiku 4.5 · Fastest for quick answers (default)</option>
7030
+ <option value="sonnet">Sonnet · Better reasoning/coding (higher cost)</option>
7031
+ <option value="opus">Opus · Most capable (higher cost)</option>
7032
+ <option value="opus[1m]">Opus 1M · Long context beta (requires access)</option>
7033
+ </select>
7034
+ <div style="font-size: 10px; color: var(--text-muted); margin-top: 4px;">
7035
+ Haiku 4.5 is the best default for DiscoveryLab: fast, lower cost, and works with image/vision flows.
7036
+ </div>
7019
7037
  </div>
7020
7038
  <div class="setting-item">
7021
- <label class="setting-label">Ollama URL (Local - Free)</label>
7039
+ <label class="setting-label">Ollama URL (Local - Free, optional)</label>
7022
7040
  <div style="display: flex; gap: 8px;">
7023
7041
  <input type="text" class="setting-input" id="ollamaUrl" placeholder="http://localhost:11434" autocomplete="off" style="flex: 1;">
7024
7042
  <button type="button" class="btn btn-secondary" onclick="checkOllamaStatus()" title="Check Ollama status" style="padding: 8px 10px; min-width: auto;">
@@ -7029,7 +7047,7 @@
7029
7047
  </button>
7030
7048
  </div>
7031
7049
  <div style="font-size: 10px; color: var(--text-muted); margin-top: 4px;">
7032
- <a href="https://ollama.ai" target="_blank" style="color: var(--accent);">Install Ollama</a> - Run: <code style="background: var(--bg-tertiary); padding: 1px 4px; border-radius: 3px;">ollama run llama3.2</code>
7050
+ <a href="https://ollama.ai" target="_blank" style="color: var(--accent);">Install Ollama</a> - Only used when provider is set to <strong>Ollama</strong>. Install any model (example: <code style="background: var(--bg-tertiary); padding: 1px 4px; border-radius: 3px;">ollama pull llama3.2</code>).
7033
7051
  </div>
7034
7052
  </div>
7035
7053
  <div class="setting-item" id="ollamaModelContainer">
@@ -8046,16 +8064,55 @@
8046
8064
  }
8047
8065
  }
8048
8066
 
8049
- function saveSettingsFromForm() {
8067
+ async function saveSettingsFromForm() {
8050
8068
  persistCaptureSettingsFromForm({ silent: false });
8051
8069
 
8052
8070
  // Also save LLM settings
8053
- saveLLMSettings();
8071
+ const llmSaved = await saveLLMSettings({ silent: true });
8072
+ if (llmSaved === false) return;
8054
8073
  closeAllModals();
8055
8074
  }
8056
8075
 
8057
8076
  // LLM Settings
8058
8077
  let currentOllamaModel = 'llama3.2';
8078
+ const LLM_AUTO_PROVIDER_PRIORITY = ['anthropic', 'openai', 'ollama', 'claude-cli'];
8079
+
8080
+ function normalizeOllamaModelName(value) {
8081
+ return String(value || '').trim().toLowerCase();
8082
+ }
8083
+
8084
+ function ollamaModelNamesMatch(installedName, selectedName) {
8085
+ const installed = normalizeOllamaModelName(installedName);
8086
+ const selected = normalizeOllamaModelName(selectedName);
8087
+ if (!installed || !selected) return false;
8088
+ if (installed === selected) return true;
8089
+ return installed.split(':')[0] === selected.split(':')[0];
8090
+ }
8091
+
8092
+ function resolveLLMProviderStatus(data) {
8093
+ const providers = Array.isArray(data?.providers) ? data.providers : [];
8094
+ const preferredProvider = data?.preferredProvider || 'auto';
8095
+ const byKey = new Map(providers.map(p => [p.key, p]));
8096
+ const isReady = (p) => !!(p && p.available && p.configured);
8097
+
8098
+ const resolveAuto = () => {
8099
+ for (const key of LLM_AUTO_PROVIDER_PRIORITY) {
8100
+ const candidate = byKey.get(key);
8101
+ if (isReady(candidate)) return candidate;
8102
+ }
8103
+ return null;
8104
+ };
8105
+
8106
+ if (preferredProvider && preferredProvider !== 'auto') {
8107
+ const preferred = byKey.get(preferredProvider);
8108
+ if (isReady(preferred)) {
8109
+ return { activeProvider: preferred, fallbackFromPreferred: false };
8110
+ }
8111
+ return { activeProvider: resolveAuto(), fallbackFromPreferred: true, preferredProvider };
8112
+ }
8113
+
8114
+ return { activeProvider: resolveAuto(), fallbackFromPreferred: false };
8115
+ }
8059
8116
 
8060
8117
  async function loadLLMSettings() {
8061
8118
  try {
@@ -8063,20 +8120,21 @@
8063
8120
  const data = await response.json();
8064
8121
 
8065
8122
  document.getElementById('anthropicApiKey').value = data.anthropicApiKey || '';
8066
- document.getElementById('anthropicModel').value = data.anthropicModel || 'claude-sonnet-4-20250514';
8123
+ document.getElementById('anthropicModel').value = data.anthropicModel || 'claude-sonnet-4-6';
8067
8124
  document.getElementById('openaiApiKey').value = data.openaiApiKey || '';
8068
8125
  document.getElementById('openaiModel').value = data.openaiModel || 'gpt-5.2';
8069
8126
  document.getElementById('ollamaUrl').value = data.ollamaUrl || 'http://localhost:11434';
8127
+ document.getElementById('claudeCliModel').value = data.claudeCliModel || 'haiku';
8070
8128
  currentOllamaModel = data.ollamaModel || 'llama3.2';
8071
8129
 
8072
8130
  // Update preferred provider dropdown
8073
- updatePreferredProviderDropdown(data.preferredProvider || 'auto');
8131
+ await updatePreferredProviderDropdown(data.preferredProvider || 'auto');
8074
8132
 
8075
8133
  // Update status
8076
- updateLLMStatus();
8134
+ await updateLLMStatus();
8077
8135
 
8078
8136
  // Check Ollama status and load models
8079
- checkOllamaStatus();
8137
+ await checkOllamaStatus();
8080
8138
  } catch (e) {
8081
8139
  console.log('Failed to load LLM settings:', e);
8082
8140
  }
@@ -8090,19 +8148,18 @@
8090
8148
  const data = await response.json();
8091
8149
  let html = '<option value="auto">Auto (priority order)</option>';
8092
8150
  for (const p of (data.providers || [])) {
8093
- if (p.available && p.configured) {
8094
- const selected = currentValue === p.key ? ' selected' : '';
8095
- html += `<option value="${p.key}"${selected}>${p.name}</option>`;
8096
- }
8151
+ const selected = currentValue === p.key ? ' selected' : '';
8152
+ const ready = !!(p.available && p.configured);
8153
+ const suffix = ready ? '' : (p.available ? ' (setup incomplete)' : ' (unavailable)');
8154
+ html += `<option value="${p.key}"${selected}>${p.name}${suffix}</option>`;
8097
8155
  }
8098
- select.innerHTML = html;
8099
- // Ensure current value is set even if provider is not currently available
8100
8156
  if (currentValue && currentValue !== 'auto') {
8101
- const exists = [...select.options].some(o => o.value === currentValue);
8102
- if (!exists) {
8103
- select.value = 'auto';
8157
+ const known = (data.providers || []).some(p => p.key === currentValue);
8158
+ if (!known) {
8159
+ html += `<option value="${currentValue}" selected>${currentValue} (saved, unknown)</option>`;
8104
8160
  }
8105
8161
  }
8162
+ select.innerHTML = html;
8106
8163
  } catch (e) {
8107
8164
  console.log('Failed to update preferred provider dropdown:', e);
8108
8165
  }
@@ -8112,6 +8169,8 @@
8112
8169
  const container = document.getElementById('ollamaModelSelector');
8113
8170
  const badge = document.getElementById('ollamaStatusBadge');
8114
8171
  const refreshIcon = document.getElementById('ollamaRefreshIcon');
8172
+ const ollamaUrlInput = document.getElementById('ollamaUrl');
8173
+ const typedOllamaUrl = (ollamaUrlInput?.value || '').trim();
8115
8174
 
8116
8175
  // Show loading state
8117
8176
  if (refreshIcon) {
@@ -8135,7 +8194,8 @@
8135
8194
  }
8136
8195
 
8137
8196
  try {
8138
- const response = await fetch('/api/ollama/status');
8197
+ const query = typedOllamaUrl ? `?url=${encodeURIComponent(typedOllamaUrl)}` : '';
8198
+ const response = await fetch(`/api/ollama/status${query}`);
8139
8199
  const data = await response.json();
8140
8200
 
8141
8201
  if (refreshIcon) {
@@ -8143,24 +8203,40 @@
8143
8203
  }
8144
8204
 
8145
8205
  if (data.running && data.models && data.models.length > 0) {
8206
+ const selectedModelAvailable = data.selectedModelAvailable !== false;
8207
+ const selectedModel = data.currentModel || currentOllamaModel || 'llama3.2';
8208
+
8146
8209
  // Ollama is running and has models
8147
8210
  if (badge) {
8148
- badge.textContent = `${data.models.length} model${data.models.length > 1 ? 's' : ''}`;
8149
- badge.style.background = 'rgba(34, 197, 94, 0.15)';
8150
- badge.style.color = 'var(--success)';
8211
+ if (selectedModelAvailable) {
8212
+ badge.textContent = `${data.models.length} model${data.models.length > 1 ? 's' : ''}`;
8213
+ badge.style.background = 'rgba(34, 197, 94, 0.15)';
8214
+ badge.style.color = 'var(--success)';
8215
+ } else {
8216
+ badge.textContent = 'Model missing';
8217
+ badge.style.background = 'rgba(245, 158, 11, 0.15)';
8218
+ badge.style.color = 'var(--warning)';
8219
+ }
8151
8220
  }
8152
8221
  if (container) {
8153
8222
  const modelOptions = data.models.map(m => {
8154
8223
  const sizeMB = Math.round(m.size / 1024 / 1024);
8155
8224
  const sizeStr = sizeMB > 1024 ? `${(sizeMB / 1024).toFixed(1)}GB` : `${sizeMB}MB`;
8156
- const selected = m.name === currentOllamaModel ? 'selected' : '';
8225
+ const selected = ollamaModelNamesMatch(m.name, selectedModel) ? 'selected' : '';
8157
8226
  return `<option value="${m.name}" ${selected}>${m.name} (${sizeStr})</option>`;
8158
8227
  }).join('');
8159
8228
 
8160
8229
  container.innerHTML = `
8161
- <select class="setting-input" id="ollamaModel" style="cursor: pointer;">
8162
- ${modelOptions}
8163
- </select>
8230
+ <div style="display: grid; gap: 8px;">
8231
+ <select class="setting-input" id="ollamaModel" style="cursor: pointer;">
8232
+ ${modelOptions}
8233
+ </select>
8234
+ ${selectedModelAvailable ? '' : `
8235
+ <div style="padding: 8px; background: rgba(245, 158, 11, 0.08); border: 1px solid rgba(245, 158, 11, 0.2); border-radius: 6px; color: var(--warning); font-size: 11px;">
8236
+ Selected model "${selectedModel}" is not installed. Choose an available model and save.
8237
+ </div>
8238
+ `}
8239
+ </div>
8164
8240
  `;
8165
8241
  }
8166
8242
  } else if (data.running) {
@@ -8175,7 +8251,7 @@
8175
8251
  <div style="padding: 10px; background: var(--bg-tertiary); border-radius: 6px; font-size: 12px;">
8176
8252
  <div style="color: var(--warning); margin-bottom: 6px;">No models installed</div>
8177
8253
  <div style="color: var(--text-muted);">
8178
- Run: <code style="background: var(--bg-elevated); padding: 1px 4px; border-radius: 3px;">ollama pull llama3.2</code>
8254
+ Install any model (example): <code style="background: var(--bg-elevated); padding: 1px 4px; border-radius: 3px;">ollama pull llama3.2</code>
8179
8255
  </div>
8180
8256
  </div>
8181
8257
  `;
@@ -8218,7 +8294,8 @@
8218
8294
  }
8219
8295
  }
8220
8296
 
8221
- async function saveLLMSettings() {
8297
+ async function saveLLMSettings(options = {}) {
8298
+ const { silent = false } = options;
8222
8299
  try {
8223
8300
  // Get Ollama model from select or use current value
8224
8301
  const ollamaModelSelect = document.getElementById('ollamaModel');
@@ -8226,26 +8303,43 @@
8226
8303
 
8227
8304
  const settings = {
8228
8305
  anthropicApiKey: document.getElementById('anthropicApiKey')?.value || '',
8229
- anthropicModel: document.getElementById('anthropicModel')?.value || 'claude-sonnet-4-20250514',
8306
+ anthropicModel: document.getElementById('anthropicModel')?.value || 'claude-sonnet-4-6',
8230
8307
  openaiApiKey: document.getElementById('openaiApiKey')?.value || '',
8231
8308
  openaiModel: document.getElementById('openaiModel')?.value || 'gpt-5.2',
8309
+ claudeCliModel: document.getElementById('claudeCliModel')?.value || 'haiku',
8232
8310
  ollamaUrl: document.getElementById('ollamaUrl')?.value || 'http://localhost:11434',
8233
8311
  ollamaModel: ollamaModel,
8234
8312
  preferredProvider: document.getElementById('preferredProvider')?.value || 'auto'
8235
8313
  };
8236
8314
 
8237
- await fetch('/api/settings/llm', {
8315
+ const response = await fetch('/api/settings/llm', {
8238
8316
  method: 'PUT',
8239
8317
  headers: { 'Content-Type': 'application/json' },
8240
8318
  body: JSON.stringify(settings)
8241
8319
  });
8320
+ if (!response.ok) {
8321
+ let message = `HTTP ${response.status}`;
8322
+ try {
8323
+ const errorData = await response.json();
8324
+ if (errorData?.error) message = errorData.error;
8325
+ } catch {}
8326
+ throw new Error(message);
8327
+ }
8242
8328
 
8243
8329
  // Update current model
8244
8330
  currentOllamaModel = ollamaModel;
8245
8331
 
8246
- updateLLMStatus();
8332
+ await checkOllamaStatus();
8333
+ await updatePreferredProviderDropdown(settings.preferredProvider || 'auto');
8334
+ await updateLLMStatus();
8335
+ if (!silent) {
8336
+ showToast('LLM settings saved', 'success', 2000);
8337
+ }
8338
+ return true;
8247
8339
  } catch (e) {
8248
8340
  console.error('Failed to save LLM settings:', e);
8341
+ showToast('Failed to save LLM settings', 'error', 5000);
8342
+ return false;
8249
8343
  }
8250
8344
  }
8251
8345
 
@@ -8257,17 +8351,21 @@
8257
8351
  try {
8258
8352
  const response = await fetch('/api/mobile-chat/providers');
8259
8353
  const data = await response.json();
8260
-
8261
- const activeProvider = data.providers?.find(p => p.available && p.configured);
8354
+ const resolved = resolveLLMProviderStatus(data);
8355
+ const activeProvider = resolved.activeProvider;
8262
8356
  if (activeProvider) {
8263
8357
  statusDot.classList.remove('missing');
8264
8358
  statusDot.classList.add('installed');
8265
- statusText.textContent = `Active: ${activeProvider.name}`;
8359
+ statusText.textContent = resolved.fallbackFromPreferred
8360
+ ? `Preferred unavailable, using ${activeProvider.name}`
8361
+ : `Active: ${activeProvider.name}`;
8266
8362
  statusText.style.color = 'var(--success)';
8267
8363
  } else {
8268
8364
  statusDot.classList.remove('installed');
8269
8365
  statusDot.classList.add('missing');
8270
- statusText.textContent = 'No provider configured';
8366
+ statusText.textContent = resolved.fallbackFromPreferred
8367
+ ? 'Preferred provider unavailable'
8368
+ : 'No provider configured';
8271
8369
  statusText.style.color = 'var(--error)';
8272
8370
  }
8273
8371
  } catch (e) {
@@ -8323,6 +8421,16 @@
8323
8421
  document.getElementById('closeSettings').addEventListener('click', closeAllModals);
8324
8422
  document.getElementById('refreshSetup').addEventListener('click', loadSetupStatus);
8325
8423
  document.getElementById('saveSettings')?.addEventListener('click', saveSettingsFromForm);
8424
+ ['preferredProvider', 'anthropicModel', 'openaiModel', 'claudeCliModel', 'ollamaUrl', 'anthropicApiKey', 'openaiApiKey'].forEach((id) => {
8425
+ document.getElementById(id)?.addEventListener('change', () => {
8426
+ void saveLLMSettings({ silent: true });
8427
+ });
8428
+ });
8429
+ document.getElementById('ollamaModelSelector')?.addEventListener('change', (event) => {
8430
+ if (event.target && event.target.id === 'ollamaModel') {
8431
+ void saveLLMSettings({ silent: true });
8432
+ }
8433
+ });
8326
8434
 
8327
8435
  // Close modal on overlay click
8328
8436
  [shortcutsModal, settingsModal].forEach(modal => {
@@ -13983,7 +14091,16 @@
13983
14091
  return;
13984
14092
  }
13985
14093
 
13986
- updateAnalysisTerminalStep(step, status, detail);
14094
+ const failureDetail = (status === 'failed' && error)
14095
+ ? (detail ? `${detail} (${error})` : error)
14096
+ : detail;
14097
+
14098
+ if (status === 'failed') {
14099
+ const logMessage = failureDetail || detail || error || 'unknown error';
14100
+ console.warn(`[AnalysisProgress] ${step} failed for project ${projectId}: ${logMessage}`);
14101
+ }
14102
+
14103
+ updateAnalysisTerminalStep(step, status, failureDetail);
13987
14104
  }
13988
14105
 
13989
14106
  function updateAnalysisTerminalStep(step, status, detail) {
package/dist/index.js CHANGED
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ startServer,
4
+ stopServer
5
+ } from "./chunk-6H3NXFX3.js";
2
6
  import {
3
7
  analyzeTools,
4
8
  canvasTools,
@@ -9,19 +13,13 @@ import {
9
13
  taskHubTools,
10
14
  testingTools,
11
15
  uiTools
12
- } from "./chunk-7NP64TGJ.js";
16
+ } from "./chunk-RUGHHO4K.js";
17
+ import "./chunk-NBAUZ7X2.js";
13
18
  import "./chunk-W3WJGYR6.js";
19
+ import "./chunk-PTXSB3UV.js";
14
20
  import {
15
21
  setupTools
16
- } from "./chunk-7IDQLLBW.js";
17
- import {
18
- mcpServer
19
- } from "./chunk-QJXXHOV7.js";
20
- import {
21
- startServer,
22
- stopServer
23
- } from "./chunk-Y5VDMSYC.js";
24
- import "./chunk-NBAUZ7X2.js";
22
+ } from "./chunk-IGZ5TICZ.js";
25
23
  import {
26
24
  closeDatabase,
27
25
  exportDestinations,
@@ -32,6 +30,9 @@ import {
32
30
  projects,
33
31
  settings
34
32
  } from "./chunk-VY3BLXBW.js";
33
+ import {
34
+ mcpServer
35
+ } from "./chunk-QJXXHOV7.js";
35
36
  import "./chunk-MLKGABMK.js";
36
37
 
37
38
  // src/core/protocol/types.ts
@@ -0,0 +1,38 @@
1
+ import {
2
+ BrowserDevices,
3
+ PlaywrightActions,
4
+ createFormSubmissionScript,
5
+ createLoginScript,
6
+ createNavigationScript,
7
+ generatePlaywrightScript,
8
+ getBrowserDevice,
9
+ getPlaywrightVersion,
10
+ installPlaywrightBrowsers,
11
+ isPlaywrightInstalled,
12
+ listBrowserDevices,
13
+ runPlaywrightScript,
14
+ runPlaywrightTest,
15
+ savePlaywrightScript,
16
+ showPlaywrightReport,
17
+ startPlaywrightCodegen
18
+ } from "./chunk-PTXSB3UV.js";
19
+ import "./chunk-VY3BLXBW.js";
20
+ import "./chunk-MLKGABMK.js";
21
+ export {
22
+ BrowserDevices,
23
+ PlaywrightActions,
24
+ createFormSubmissionScript,
25
+ createLoginScript,
26
+ createNavigationScript,
27
+ generatePlaywrightScript,
28
+ getBrowserDevice,
29
+ getPlaywrightVersion,
30
+ installPlaywrightBrowsers,
31
+ isPlaywrightInstalled,
32
+ listBrowserDevices,
33
+ runPlaywrightScript,
34
+ runPlaywrightTest,
35
+ savePlaywrightScript,
36
+ showPlaywrightReport,
37
+ startPlaywrightCodegen
38
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ app,
3
+ startServer,
4
+ stopServer
5
+ } from "./chunk-EQOZSXAT.js";
6
+ import "./chunk-NBAUZ7X2.js";
7
+ import "./chunk-VY3BLXBW.js";
8
+ import "./chunk-MLKGABMK.js";
9
+ export {
10
+ app,
11
+ startServer,
12
+ stopServer
13
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ app,
3
+ startServer,
4
+ stopServer
5
+ } from "./chunk-SIOQVM2E.js";
6
+ import "./chunk-NBAUZ7X2.js";
7
+ import "./chunk-VY3BLXBW.js";
8
+ import "./chunk-MLKGABMK.js";
9
+ export {
10
+ app,
11
+ startServer,
12
+ stopServer
13
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ app,
3
+ startServer,
4
+ stopServer
5
+ } from "./chunk-6H3NXFX3.js";
6
+ import "./chunk-NBAUZ7X2.js";
7
+ import "./chunk-VY3BLXBW.js";
8
+ import "./chunk-MLKGABMK.js";
9
+ export {
10
+ app,
11
+ startServer,
12
+ stopServer
13
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ app,
3
+ startServer,
4
+ stopServer
5
+ } from "./chunk-V3CBINLD.js";
6
+ import "./chunk-NBAUZ7X2.js";
7
+ import "./chunk-VY3BLXBW.js";
8
+ import "./chunk-MLKGABMK.js";
9
+ export {
10
+ app,
11
+ startServer,
12
+ stopServer
13
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ app,
3
+ startServer,
4
+ stopServer
5
+ } from "./chunk-VPYSLEGM.js";
6
+ import "./chunk-NBAUZ7X2.js";
7
+ import "./chunk-VY3BLXBW.js";
8
+ import "./chunk-MLKGABMK.js";
9
+ export {
10
+ app,
11
+ startServer,
12
+ stopServer
13
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ app,
3
+ startServer,
4
+ stopServer
5
+ } from "./chunk-FPHD7HSQ.js";
6
+ import "./chunk-NBAUZ7X2.js";
7
+ import "./chunk-VY3BLXBW.js";
8
+ import "./chunk-MLKGABMK.js";
9
+ export {
10
+ app,
11
+ startServer,
12
+ stopServer
13
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ app,
3
+ startServer,
4
+ stopServer
5
+ } from "./chunk-L5IJZV5F.js";
6
+ import "./chunk-NBAUZ7X2.js";
7
+ import "./chunk-VY3BLXBW.js";
8
+ import "./chunk-MLKGABMK.js";
9
+ export {
10
+ app,
11
+ startServer,
12
+ stopServer
13
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ app,
3
+ startServer,
4
+ stopServer
5
+ } from "./chunk-KUFBCBNJ.js";
6
+ import "./chunk-NBAUZ7X2.js";
7
+ import "./chunk-VY3BLXBW.js";
8
+ import "./chunk-MLKGABMK.js";
9
+ export {
10
+ app,
11
+ startServer,
12
+ stopServer
13
+ };
@@ -0,0 +1,17 @@
1
+ import {
2
+ setupCheckTool,
3
+ setupInitTool,
4
+ setupInstallTool,
5
+ setupStatusTool,
6
+ setupTools
7
+ } from "./chunk-IGZ5TICZ.js";
8
+ import "./chunk-VY3BLXBW.js";
9
+ import "./chunk-QJXXHOV7.js";
10
+ import "./chunk-MLKGABMK.js";
11
+ export {
12
+ setupCheckTool,
13
+ setupInitTool,
14
+ setupInstallTool,
15
+ setupStatusTool,
16
+ setupTools
17
+ };