@jacobbd/relay-ai 0.4.7 → 0.4.8

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
@@ -171,7 +171,7 @@ import {
171
171
  validateCustomEndpointUrl,
172
172
  writeSecureLogLine,
173
173
  zenRegistryStub
174
- } from "./chunk-XQCHSU6L.js";
174
+ } from "./chunk-I3SSHXSP.js";
175
175
  import {
176
176
  filterTemplates,
177
177
  init_provider_templates,
@@ -13461,7 +13461,7 @@ Error: ${parsed.error}
13461
13461
  console.log("Usage: relay-ai ui [--trace]\n\nOpen the settings UI in your browser.");
13462
13462
  return 0;
13463
13463
  }
13464
- const { runUiCommand } = await import("./ui-command-W2W6P6VJ.js");
13464
+ const { runUiCommand } = await import("./ui-command-P27KHEJG.js");
13465
13465
  return runUiCommand({ trace: parsed.trace });
13466
13466
  }
13467
13467
  if (parsed.command === "models") {
@@ -2332,10 +2332,14 @@ function renderServerProviderPicker() {
2332
2332
  const label = p ? p.name : id;
2333
2333
  return `<span class="server-provider-chip">${escapeHtml(label)}<button type="button" onclick="toggleServerProvider('${id}')" aria-label="Remove ${escapeHtml(label)}">&times;</button></span>`;
2334
2334
  }).join('');
2335
+ const allFreeNote = s.form.freeModelsOnly && s.form.exposedProviders.length === 0
2336
+ ? '<div class="server-field-hint">No providers selected — exposing free models from every available provider.</div>'
2337
+ : '';
2335
2338
 
2336
2339
  return `
2337
2340
  <div class="server-providers-picker">
2338
2341
  ${chips ? `<div class="server-provider-chips">${chips}</div>` : ''}
2342
+ ${allFreeNote}
2339
2343
  <div class="search-field">
2340
2344
  <svg class="search-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
2341
2345
  <input type="search" class="search-input" placeholder="Search providers to expose…" value="${escapeHtml(s.form.providerSearch)}" oninput="setServerProviderSearch(this.value)">
@@ -2377,13 +2381,27 @@ function renderServerNetworkOptions() {
2377
2381
  function renderServerSetup(s) {
2378
2382
  const f = s.form;
2379
2383
  const specific = f.expose === 'specific';
2380
- const providersOk = f.expose === 'favorites' || (specific && f.exposedProviders.length > 0);
2384
+ const hasProviders = f.exposedProviders.length > 0;
2385
+ // Free-only with no providers selected = expose free models from every provider
2386
+ // (backend: exposedProviders null + freeModelsOnly). Otherwise require a selection.
2387
+ const providersOk = f.expose === 'favorites'
2388
+ || (specific && hasProviders)
2389
+ || (specific && f.freeModelsOnly);
2381
2390
  const passwordOk = f.listenMode !== 'network' || f.passwordMode === 'saved' || f.password.trim().length > 0;
2382
2391
  const canStart = providersOk && passwordOk && !s.starting;
2383
2392
 
2384
2393
  let hint = '';
2385
- if (!providersOk) hint = 'Select at least one provider to expose.';
2386
- else if (!passwordOk) hint = 'Enter a server password for network mode.';
2394
+ if (!providersOk) {
2395
+ hint = f.freeModelsOnly
2396
+ ? 'Select at least one provider, or leave none selected to expose free models from all providers.'
2397
+ : 'Select at least one provider to expose.';
2398
+ } else if (!passwordOk) {
2399
+ hint = 'Enter a server password for network mode.';
2400
+ }
2401
+
2402
+ const freeModelsHint = specific
2403
+ ? 'With providers selected, only their free models are exposed. With none selected, free models from every available provider are exposed.'
2404
+ : 'Includes verified $0 models and free developer access.';
2387
2405
 
2388
2406
  return `
2389
2407
  <div class="server-setup">
@@ -2405,6 +2423,7 @@ function renderServerSetup(s) {
2405
2423
  <input type="checkbox" ${f.freeModelsOnly ? 'checked' : ''} onchange="setServerFreeModelsOnly(this.checked)">
2406
2424
  <span>Free models only <span class="server-field-hint">(includes verified $0 models and free developer access)</span></span>
2407
2425
  </label>
2426
+ <div class="server-field-hint">${escapeHtml(freeModelsHint)}</div>
2408
2427
  </div>
2409
2428
 
2410
2429
  <div class="server-field">
@@ -2475,8 +2494,8 @@ function renderServerRunning(status) {
2475
2494
  <tr>
2476
2495
  <td>${escapeHtml(m.providerLabel)}</td>
2477
2496
  <td>${escapeHtml(m.name)}</td>
2478
- <td><code>${escapeHtml(m.anthropicId)}</code></td>
2479
- <td><code>${escapeHtml(m.openaiId)}</code></td>
2497
+ <td>${serverIdCell(m.anthropicId)}</td>
2498
+ <td>${serverIdCell(m.openaiId)}</td>
2480
2499
  </tr>
2481
2500
  `).join('');
2482
2501
 
@@ -2531,6 +2550,8 @@ function setServerMask(checked) {
2531
2550
 
2532
2551
  function setServerFreeModelsOnly(checked) {
2533
2552
  state.server.form.freeModelsOnly = checked;
2553
+ state.server.error = null;
2554
+ renderServerPanel();
2534
2555
  }
2535
2556
 
2536
2557
  function setServerListenMode(mode) {
@@ -2561,7 +2582,10 @@ async function submitServerStart() {
2561
2582
  const body = {
2562
2583
  favoritesOnly: f.expose === 'favorites',
2563
2584
  freeModelsOnly: f.freeModelsOnly,
2564
- exposedProviders: f.expose === 'specific' ? f.exposedProviders : null,
2585
+ // Empty specific selection + free-only null (all providers, free filter applied server-side).
2586
+ exposedProviders: f.expose === 'specific' && f.exposedProviders.length > 0
2587
+ ? f.exposedProviders
2588
+ : null,
2565
2589
  maskGatewayIds: f.maskGatewayIds,
2566
2590
  listenMode: f.listenMode,
2567
2591
  passwordMode: f.passwordMode,
@@ -2599,10 +2623,18 @@ async function stopServerGateway() {
2599
2623
  }
2600
2624
  }
2601
2625
 
2602
- async function copyServerValue(id) {
2603
- const el = document.getElementById(id);
2604
- if (!el) return;
2605
- const text = el.dataset.value ?? el.textContent;
2626
+ function serverIdCell(id) {
2627
+ const value = String(id ?? '');
2628
+ if (!value) return '<span class="server-id-empty">—</span>';
2629
+ return `
2630
+ <div class="server-id-cell">
2631
+ <code title="${escapeHtml(value)}">${escapeHtml(value)}</code>
2632
+ <button type="button" class="btn btn-ghost btn-sm server-id-copy" onclick='copyPlainText(${JSON.stringify(value)})'>Copy</button>
2633
+ </div>
2634
+ `;
2635
+ }
2636
+
2637
+ async function copyPlainText(text) {
2606
2638
  try {
2607
2639
  await navigator.clipboard.writeText(text);
2608
2640
  showToast('Copied to clipboard');
@@ -2611,6 +2643,12 @@ async function copyServerValue(id) {
2611
2643
  }
2612
2644
  }
2613
2645
 
2646
+ async function copyServerValue(id) {
2647
+ const el = document.getElementById(id);
2648
+ if (!el) return;
2649
+ await copyPlainText(el.dataset.value ?? el.textContent);
2650
+ }
2651
+
2614
2652
  function toggleServerApiKeyVisibility() {
2615
2653
  const el = document.getElementById('server-api-key-value');
2616
2654
  if (!el) return;
@@ -2630,4 +2668,5 @@ window.setServerSavePassword = setServerSavePassword;
2630
2668
  window.submitServerStart = submitServerStart;
2631
2669
  window.stopServerGateway = stopServerGateway;
2632
2670
  window.copyServerValue = copyServerValue;
2671
+ window.copyPlainText = copyPlainText;
2633
2672
  window.toggleServerApiKeyVisibility = toggleServerApiKeyVisibility;
@@ -401,6 +401,10 @@ input { font-family: inherit; }
401
401
  max-width: 680px;
402
402
  }
403
403
 
404
+ #server.section {
405
+ max-width: 920px;
406
+ }
407
+
404
408
  .section + .section {
405
409
  padding-top: 64px;
406
410
  margin-top: 12px;
@@ -1883,6 +1887,7 @@ input { font-family: inherit; }
1883
1887
 
1884
1888
  .server-model-table {
1885
1889
  width: 100%;
1890
+ table-layout: fixed;
1886
1891
  border-collapse: collapse;
1887
1892
  font-size: 14px;
1888
1893
  }
@@ -1899,16 +1904,45 @@ input { font-family: inherit; }
1899
1904
  border-bottom: 1px solid var(--border);
1900
1905
  }
1901
1906
 
1907
+ .server-model-table th:nth-child(1) { width: 18%; }
1908
+ .server-model-table th:nth-child(2) { width: 22%; }
1909
+ .server-model-table th:nth-child(3),
1910
+ .server-model-table th:nth-child(4) { width: 30%; }
1911
+
1902
1912
  .server-model-table td {
1903
1913
  padding: 9px 14px;
1904
1914
  border-bottom: 1px solid var(--border);
1905
1915
  color: var(--text-1);
1916
+ vertical-align: middle;
1917
+ overflow: hidden;
1906
1918
  }
1907
1919
 
1908
1920
  .server-model-table tr:last-child td { border-bottom: none; }
1909
1921
 
1910
- .server-model-table code {
1922
+ .server-id-cell {
1923
+ display: flex;
1924
+ align-items: center;
1925
+ gap: 8px;
1926
+ min-width: 0;
1927
+ }
1928
+
1929
+ .server-id-cell code {
1930
+ flex: 1;
1931
+ min-width: 0;
1932
+ overflow: hidden;
1933
+ text-overflow: ellipsis;
1934
+ white-space: nowrap;
1911
1935
  font-family: 'SF Mono', 'Fira Code', ui-monospace, monospace;
1912
1936
  font-size: 12px;
1913
1937
  color: var(--text-2);
1914
1938
  }
1939
+
1940
+ .server-id-copy {
1941
+ flex-shrink: 0;
1942
+ padding: 3px 8px;
1943
+ font-size: 12px;
1944
+ }
1945
+
1946
+ .server-id-empty {
1947
+ color: var(--text-3);
1948
+ }
@@ -66,7 +66,7 @@ import {
66
66
  supportsClaudeTransparentMode,
67
67
  validateCustomEndpointUrl,
68
68
  writeSecureLogLine
69
- } from "./chunk-XQCHSU6L.js";
69
+ } from "./chunk-I3SSHXSP.js";
70
70
  import {
71
71
  __toCommonJS,
72
72
  init_provider_templates,
@@ -478,7 +478,9 @@ async function doStartGatewayServer(req) {
478
478
  }
479
479
  setServerFavoritesOnly(req.favoritesOnly);
480
480
  setServerFreeModelsOnly(req.freeModelsOnly);
481
- if (req.exposedProviders) setServerExposedProviders(req.exposedProviders);
481
+ if (!req.favoritesOnly) {
482
+ setServerExposedProviders(req.exposedProviders ?? []);
483
+ }
482
484
  setServerMaskGatewayIds(req.maskGatewayIds);
483
485
  setServerListenMode(req.listenMode);
484
486
  const host = req.listenMode === "network" ? "0.0.0.0" : "127.0.0.1";
@@ -1487,4 +1489,4 @@ export {
1487
1489
  resolveUiShutdownDecision,
1488
1490
  runUiCommand
1489
1491
  };
1490
- //# sourceMappingURL=ui-command-W2W6P6VJ.js.map
1492
+ //# sourceMappingURL=ui-command-P27KHEJG.js.map