@veolab/discoverylab 0.1.9 → 1.0.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-Q4FBWQUA.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"));
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">
@@ -7017,6 +7017,18 @@
7017
7017
  </optgroup>
7018
7018
  </select>
7019
7019
  </div>
7020
+ <div class="setting-item">
7021
+ <label class="setting-label">Claude CLI Model (Local)</label>
7022
+ <select class="setting-input" id="claudeCliModel" style="cursor: pointer;">
7023
+ <option value="haiku">Haiku 4.5 · Fastest for quick answers (default)</option>
7024
+ <option value="sonnet">Sonnet · Better reasoning/coding (higher cost)</option>
7025
+ <option value="opus">Opus · Most capable (higher cost)</option>
7026
+ <option value="opus[1m]">Opus 1M · Long context beta (requires access)</option>
7027
+ </select>
7028
+ <div style="font-size: 10px; color: var(--text-muted); margin-top: 4px;">
7029
+ Haiku 4.5 is the best default for DiscoveryLab: fast, lower cost, and works with image/vision flows.
7030
+ </div>
7031
+ </div>
7020
7032
  <div class="setting-item">
7021
7033
  <label class="setting-label">Ollama URL (Local - Free)</label>
7022
7034
  <div style="display: flex; gap: 8px;">
@@ -8056,6 +8068,44 @@
8056
8068
 
8057
8069
  // LLM Settings
8058
8070
  let currentOllamaModel = 'llama3.2';
8071
+ const LLM_AUTO_PROVIDER_PRIORITY = ['anthropic', 'openai', 'ollama', 'claude-cli'];
8072
+
8073
+ function normalizeOllamaModelName(value) {
8074
+ return String(value || '').trim().toLowerCase();
8075
+ }
8076
+
8077
+ function ollamaModelNamesMatch(installedName, selectedName) {
8078
+ const installed = normalizeOllamaModelName(installedName);
8079
+ const selected = normalizeOllamaModelName(selectedName);
8080
+ if (!installed || !selected) return false;
8081
+ if (installed === selected) return true;
8082
+ return installed.split(':')[0] === selected.split(':')[0];
8083
+ }
8084
+
8085
+ function resolveLLMProviderStatus(data) {
8086
+ const providers = Array.isArray(data?.providers) ? data.providers : [];
8087
+ const preferredProvider = data?.preferredProvider || 'auto';
8088
+ const byKey = new Map(providers.map(p => [p.key, p]));
8089
+ const isReady = (p) => !!(p && p.available && p.configured);
8090
+
8091
+ const resolveAuto = () => {
8092
+ for (const key of LLM_AUTO_PROVIDER_PRIORITY) {
8093
+ const candidate = byKey.get(key);
8094
+ if (isReady(candidate)) return candidate;
8095
+ }
8096
+ return null;
8097
+ };
8098
+
8099
+ if (preferredProvider && preferredProvider !== 'auto') {
8100
+ const preferred = byKey.get(preferredProvider);
8101
+ if (isReady(preferred)) {
8102
+ return { activeProvider: preferred, fallbackFromPreferred: false };
8103
+ }
8104
+ return { activeProvider: resolveAuto(), fallbackFromPreferred: true, preferredProvider };
8105
+ }
8106
+
8107
+ return { activeProvider: resolveAuto(), fallbackFromPreferred: false };
8108
+ }
8059
8109
 
8060
8110
  async function loadLLMSettings() {
8061
8111
  try {
@@ -8067,6 +8117,7 @@
8067
8117
  document.getElementById('openaiApiKey').value = data.openaiApiKey || '';
8068
8118
  document.getElementById('openaiModel').value = data.openaiModel || 'gpt-5.2';
8069
8119
  document.getElementById('ollamaUrl').value = data.ollamaUrl || 'http://localhost:11434';
8120
+ document.getElementById('claudeCliModel').value = data.claudeCliModel || 'haiku';
8070
8121
  currentOllamaModel = data.ollamaModel || 'llama3.2';
8071
8122
 
8072
8123
  // Update preferred provider dropdown
@@ -8112,6 +8163,8 @@
8112
8163
  const container = document.getElementById('ollamaModelSelector');
8113
8164
  const badge = document.getElementById('ollamaStatusBadge');
8114
8165
  const refreshIcon = document.getElementById('ollamaRefreshIcon');
8166
+ const ollamaUrlInput = document.getElementById('ollamaUrl');
8167
+ const typedOllamaUrl = (ollamaUrlInput?.value || '').trim();
8115
8168
 
8116
8169
  // Show loading state
8117
8170
  if (refreshIcon) {
@@ -8135,7 +8188,8 @@
8135
8188
  }
8136
8189
 
8137
8190
  try {
8138
- const response = await fetch('/api/ollama/status');
8191
+ const query = typedOllamaUrl ? `?url=${encodeURIComponent(typedOllamaUrl)}` : '';
8192
+ const response = await fetch(`/api/ollama/status${query}`);
8139
8193
  const data = await response.json();
8140
8194
 
8141
8195
  if (refreshIcon) {
@@ -8143,24 +8197,40 @@
8143
8197
  }
8144
8198
 
8145
8199
  if (data.running && data.models && data.models.length > 0) {
8200
+ const selectedModelAvailable = data.selectedModelAvailable !== false;
8201
+ const selectedModel = data.currentModel || currentOllamaModel || 'llama3.2';
8202
+
8146
8203
  // Ollama is running and has models
8147
8204
  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)';
8205
+ if (selectedModelAvailable) {
8206
+ badge.textContent = `${data.models.length} model${data.models.length > 1 ? 's' : ''}`;
8207
+ badge.style.background = 'rgba(34, 197, 94, 0.15)';
8208
+ badge.style.color = 'var(--success)';
8209
+ } else {
8210
+ badge.textContent = 'Model missing';
8211
+ badge.style.background = 'rgba(245, 158, 11, 0.15)';
8212
+ badge.style.color = 'var(--warning)';
8213
+ }
8151
8214
  }
8152
8215
  if (container) {
8153
8216
  const modelOptions = data.models.map(m => {
8154
8217
  const sizeMB = Math.round(m.size / 1024 / 1024);
8155
8218
  const sizeStr = sizeMB > 1024 ? `${(sizeMB / 1024).toFixed(1)}GB` : `${sizeMB}MB`;
8156
- const selected = m.name === currentOllamaModel ? 'selected' : '';
8219
+ const selected = ollamaModelNamesMatch(m.name, selectedModel) ? 'selected' : '';
8157
8220
  return `<option value="${m.name}" ${selected}>${m.name} (${sizeStr})</option>`;
8158
8221
  }).join('');
8159
8222
 
8160
8223
  container.innerHTML = `
8161
- <select class="setting-input" id="ollamaModel" style="cursor: pointer;">
8162
- ${modelOptions}
8163
- </select>
8224
+ <div style="display: grid; gap: 8px;">
8225
+ <select class="setting-input" id="ollamaModel" style="cursor: pointer;">
8226
+ ${modelOptions}
8227
+ </select>
8228
+ ${selectedModelAvailable ? '' : `
8229
+ <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;">
8230
+ Selected model "${selectedModel}" is not installed. Choose an available model and save.
8231
+ </div>
8232
+ `}
8233
+ </div>
8164
8234
  `;
8165
8235
  }
8166
8236
  } else if (data.running) {
@@ -8229,6 +8299,7 @@
8229
8299
  anthropicModel: document.getElementById('anthropicModel')?.value || 'claude-sonnet-4-20250514',
8230
8300
  openaiApiKey: document.getElementById('openaiApiKey')?.value || '',
8231
8301
  openaiModel: document.getElementById('openaiModel')?.value || 'gpt-5.2',
8302
+ claudeCliModel: document.getElementById('claudeCliModel')?.value || 'haiku',
8232
8303
  ollamaUrl: document.getElementById('ollamaUrl')?.value || 'http://localhost:11434',
8233
8304
  ollamaModel: ollamaModel,
8234
8305
  preferredProvider: document.getElementById('preferredProvider')?.value || 'auto'
@@ -8243,7 +8314,9 @@
8243
8314
  // Update current model
8244
8315
  currentOllamaModel = ollamaModel;
8245
8316
 
8246
- updateLLMStatus();
8317
+ await checkOllamaStatus();
8318
+ await updatePreferredProviderDropdown(settings.preferredProvider || 'auto');
8319
+ await updateLLMStatus();
8247
8320
  } catch (e) {
8248
8321
  console.error('Failed to save LLM settings:', e);
8249
8322
  }
@@ -8257,17 +8330,21 @@
8257
8330
  try {
8258
8331
  const response = await fetch('/api/mobile-chat/providers');
8259
8332
  const data = await response.json();
8260
-
8261
- const activeProvider = data.providers?.find(p => p.available && p.configured);
8333
+ const resolved = resolveLLMProviderStatus(data);
8334
+ const activeProvider = resolved.activeProvider;
8262
8335
  if (activeProvider) {
8263
8336
  statusDot.classList.remove('missing');
8264
8337
  statusDot.classList.add('installed');
8265
- statusText.textContent = `Active: ${activeProvider.name}`;
8338
+ statusText.textContent = resolved.fallbackFromPreferred
8339
+ ? `Preferred unavailable, using ${activeProvider.name}`
8340
+ : `Active: ${activeProvider.name}`;
8266
8341
  statusText.style.color = 'var(--success)';
8267
8342
  } else {
8268
8343
  statusDot.classList.remove('installed');
8269
8344
  statusDot.classList.add('missing');
8270
- statusText.textContent = 'No provider configured';
8345
+ statusText.textContent = resolved.fallbackFromPreferred
8346
+ ? 'Preferred provider unavailable'
8347
+ : 'No provider configured';
8271
8348
  statusText.style.color = 'var(--error)';
8272
8349
  }
8273
8350
  } catch (e) {
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  import {
21
21
  startServer,
22
22
  stopServer
23
- } from "./chunk-Y5VDMSYC.js";
23
+ } from "./chunk-L5IJZV5F.js";
24
24
  import "./chunk-NBAUZ7X2.js";
25
25
  import {
26
26
  closeDatabase,
@@ -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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veolab/discoverylab",
3
- "version": "0.1.9",
3
+ "version": "1.0.0",
4
4
  "description": "AI-powered app testing & evidence generator - Claude Code Plugin",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",