@trops/dash-core 0.1.611 → 0.1.612

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/index.js CHANGED
@@ -52196,18 +52196,35 @@ var McpServerSection = function McpServerSection() {
52196
52196
  });
52197
52197
  };
52198
52198
 
52199
+ /**
52200
+ * modelMigration.js (renderer mirror)
52201
+ *
52202
+ * Mirrors the retired-model map + default from the main-process provider
52203
+ * registry (electron/llm/modelProviders.js) so the Settings UI can detect a
52204
+ * stale saved selection, auto-migrate it, and show a notice — without an IPC
52205
+ * round-trip. KEEP IN SYNC with modelProviders.js (anthropic provider).
52206
+ */
52207
+ var DEFAULT_MODEL = "claude-opus-4-8";
52208
+ var RETIRED_MODEL_MAP = {
52209
+ "claude-sonnet-4-20250514": "claude-sonnet-4-6",
52210
+ "claude-opus-4-20250514": "claude-opus-4-8",
52211
+ "claude-opus-4-1-20250805": "claude-opus-4-8",
52212
+ "claude-3-7-sonnet-20250219": "claude-sonnet-4-6",
52213
+ "claude-3-5-sonnet-20241022": "claude-sonnet-4-6",
52214
+ "claude-3-5-sonnet-20240620": "claude-sonnet-4-6",
52215
+ "claude-3-5-haiku-20241022": "claude-haiku-4-5",
52216
+ "claude-3-opus-20240229": "claude-opus-4-8"
52217
+ };
52218
+ function isRetiredModel(id) {
52219
+ return !!RETIRED_MODEL_MAP[id];
52220
+ }
52221
+ function migrateModelId(id) {
52222
+ if (!id) return DEFAULT_MODEL;
52223
+ return RETIRED_MODEL_MAP[id] || id;
52224
+ }
52225
+
52199
52226
  function ownKeys$m(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
52200
52227
  function _objectSpread$m(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$m(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$m(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
52201
- var MODELS = [{
52202
- value: "claude-sonnet-4-20250514",
52203
- label: "Claude Sonnet 4"
52204
- }, {
52205
- value: "claude-opus-4-20250514",
52206
- label: "Claude Opus 4"
52207
- }, {
52208
- value: "claude-haiku-4-5-20251001",
52209
- label: "Claude Haiku 4.5"
52210
- }];
52211
52228
  var BACKENDS = [{
52212
52229
  value: "claude-code",
52213
52230
  label: "Claude Code CLI"
@@ -52216,6 +52233,7 @@ var BACKENDS = [{
52216
52233
  label: "Anthropic API"
52217
52234
  }];
52218
52235
  var AiAssistantSection = function AiAssistantSection() {
52236
+ var _anthropicProvider$;
52219
52237
  var appContext = React.useContext(AppContext);
52220
52238
  var settings = (appContext === null || appContext === void 0 ? void 0 : appContext.settings) || {};
52221
52239
  var providers = (appContext === null || appContext === void 0 ? void 0 : appContext.providers) || {};
@@ -52233,7 +52251,7 @@ var AiAssistantSection = function AiAssistantSection() {
52233
52251
  _useState4 = _slicedToArray(_useState3, 2),
52234
52252
  preferredBackend = _useState4[0],
52235
52253
  setPreferredBackend = _useState4[1];
52236
- var _useState5 = React.useState(aiSettings.model || "claude-sonnet-4-20250514"),
52254
+ var _useState5 = React.useState(aiSettings.model || DEFAULT_MODEL),
52237
52255
  _useState6 = _slicedToArray(_useState5, 2),
52238
52256
  selectedModel = _useState6[0],
52239
52257
  setSelectedModel = _useState6[1];
@@ -52250,6 +52268,21 @@ var AiAssistantSection = function AiAssistantSection() {
52250
52268
  saveKeyStatus = _useState10[0],
52251
52269
  setSaveKeyStatus = _useState10[1];
52252
52270
 
52271
+ // Provider-pluggable model discovery (live fetch + curated fallback)
52272
+ var _useState11 = React.useState([]),
52273
+ _useState12 = _slicedToArray(_useState11, 2),
52274
+ availableModels = _useState12[0],
52275
+ setAvailableModels = _useState12[1];
52276
+ var _useState13 = React.useState(false),
52277
+ _useState14 = _slicedToArray(_useState13, 2),
52278
+ modelsLoading = _useState14[0],
52279
+ setModelsLoading = _useState14[1];
52280
+ // One-time notice when a retired saved model was auto-migrated
52281
+ var _useState15 = React.useState(null),
52282
+ _useState16 = _slicedToArray(_useState15, 2),
52283
+ migrationNotice = _useState16[0],
52284
+ setMigrationNotice = _useState16[1];
52285
+
52253
52286
  // Find existing Anthropic provider
52254
52287
  var anthropicProvider = Object.entries(providers).find(function (_ref) {
52255
52288
  var _ref2 = _slicedToArray(_ref, 2),
@@ -52258,6 +52291,9 @@ var AiAssistantSection = function AiAssistantSection() {
52258
52291
  });
52259
52292
  var hasAnthropicProvider = !!anthropicProvider;
52260
52293
  var anthropicProviderName = anthropicProvider === null || anthropicProvider === void 0 ? void 0 : anthropicProvider[0];
52294
+ // Decrypted key (when AppContext exposes it) enables the live Models API
52295
+ // fetch; without it, listModels returns the curated fallback list.
52296
+ var anthropicApiKey = (anthropicProvider === null || anthropicProvider === void 0 || (_anthropicProvider$ = anthropicProvider[1]) === null || _anthropicProvider$ === void 0 || (_anthropicProvider$ = _anthropicProvider$.credentials) === null || _anthropicProvider$ === void 0 ? void 0 : _anthropicProvider$.apiKey) || null;
52261
52297
 
52262
52298
  // Check CLI availability on mount
52263
52299
  React.useEffect(function () {
@@ -52279,6 +52315,28 @@ var AiAssistantSection = function AiAssistantSection() {
52279
52315
  }
52280
52316
  }, []);
52281
52317
 
52318
+ // Fetch selectable models for the current provider. With an API key the
52319
+ // main process does a live Anthropic Models API fetch; otherwise it returns
52320
+ // the curated fallback. Provider is "anthropic" for both current backends.
52321
+ var fetchModels = React.useCallback(function () {
52322
+ var _window$mainApi2;
52323
+ if (!((_window$mainApi2 = window.mainApi) !== null && _window$mainApi2 !== void 0 && (_window$mainApi2 = _window$mainApi2.llm) !== null && _window$mainApi2 !== void 0 && _window$mainApi2.listModels)) return;
52324
+ setModelsLoading(true);
52325
+ window.mainApi.llm.listModels("anthropic", anthropicApiKey).then(function (res) {
52326
+ return setAvailableModels(res && res.models || []);
52327
+ })["catch"](function () {
52328
+ return setAvailableModels([]);
52329
+ })["finally"](function () {
52330
+ return setModelsLoading(false);
52331
+ });
52332
+ }, [anthropicApiKey]);
52333
+
52334
+ // Load models on mount and whenever the available API key changes (so the
52335
+ // list upgrades from curated → live once a key is configured).
52336
+ React.useEffect(function () {
52337
+ fetchModels();
52338
+ }, [fetchModels]);
52339
+
52282
52340
  // Save AI settings to app settings
52283
52341
  var saveAiSettings = React.useCallback(function (updates) {
52284
52342
  if (appContext !== null && appContext !== void 0 && appContext.changeSettings) {
@@ -52289,6 +52347,24 @@ var AiAssistantSection = function AiAssistantSection() {
52289
52347
  }));
52290
52348
  }
52291
52349
  }, [appContext]);
52350
+
52351
+ // Auto-migrate a retired saved model to its current replacement (one-time,
52352
+ // on mount) so an old selection can't 404 the assistant. Shows a notice.
52353
+ React.useEffect(function () {
52354
+ var saved = aiSettings.model;
52355
+ if (saved && isRetiredModel(saved)) {
52356
+ var replacement = migrateModelId(saved);
52357
+ setSelectedModel(replacement);
52358
+ saveAiSettings({
52359
+ model: replacement
52360
+ });
52361
+ setMigrationNotice({
52362
+ from: saved,
52363
+ to: replacement
52364
+ });
52365
+ }
52366
+ // eslint-disable-next-line react-hooks/exhaustive-deps
52367
+ }, []);
52292
52368
  function handleBackendChange(e) {
52293
52369
  var value = e.target.value;
52294
52370
  setPreferredBackend(value);
@@ -52332,6 +52408,15 @@ var AiAssistantSection = function AiAssistantSection() {
52332
52408
  });
52333
52409
  }
52334
52410
 
52411
+ // Model dropdown options — keep the current selection selectable even if it
52412
+ // isn't in the fetched list (e.g. a pinned/custom id).
52413
+ var modelOptions = selectedModel && !availableModels.some(function (m) {
52414
+ return m.value === selectedModel;
52415
+ }) ? [{
52416
+ value: selectedModel,
52417
+ label: selectedModel
52418
+ }].concat(_toConsumableArray(availableModels)) : availableModels;
52419
+
52335
52420
  // Determine effective backend (what will actually be used)
52336
52421
  var effectiveBackend = preferredBackend === "claude-code" && cliStatus !== null && cliStatus !== void 0 && cliStatus.available ? "claude-code" : preferredBackend === "anthropic" && hasAnthropicProvider ? "anthropic" : cliStatus !== null && cliStatus !== void 0 && cliStatus.available ? "claude-code" : hasAnthropicProvider ? "anthropic" : null;
52337
52422
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -52428,6 +52513,18 @@ var AiAssistantSection = function AiAssistantSection() {
52428
52513
  }, b.value);
52429
52514
  })
52430
52515
  })]
52516
+ }), migrationNotice && /*#__PURE__*/jsxRuntime.jsxs("div", {
52517
+ className: "flex items-start gap-2 rounded-lg bg-yellow-900/30 border border-yellow-700 px-3 py-2 text-xs text-yellow-300",
52518
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
52519
+ icon: "exclamation-triangle",
52520
+ className: "h-3.5 w-3.5 mt-0.5"
52521
+ }), /*#__PURE__*/jsxRuntime.jsxs("span", {
52522
+ children: ["Your previously selected model (", /*#__PURE__*/jsxRuntime.jsx("code", {
52523
+ children: migrationNotice.from
52524
+ }), ") is no longer available. Switched to ", /*#__PURE__*/jsxRuntime.jsx("code", {
52525
+ children: migrationNotice.to
52526
+ }), "."]
52527
+ })]
52431
52528
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
52432
52529
  className: "flex flex-row items-center justify-between py-1",
52433
52530
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -52437,18 +52534,31 @@ var AiAssistantSection = function AiAssistantSection() {
52437
52534
  children: "Model"
52438
52535
  }), /*#__PURE__*/jsxRuntime.jsx("span", {
52439
52536
  className: "text-xs opacity-50",
52440
- children: "Claude model for AI Assistant conversations"
52537
+ children: "Model for AI Assistant conversations"
52538
+ })]
52539
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
52540
+ className: "flex items-center gap-2",
52541
+ children: [/*#__PURE__*/jsxRuntime.jsx("select", {
52542
+ value: selectedModel,
52543
+ onChange: handleModelChange,
52544
+ className: "bg-white/10 border border-white/10 rounded-md px-3 py-1.5 text-sm text-gray-200 focus:outline-none focus:ring-1 focus:ring-blue-500",
52545
+ children: modelOptions.map(function (m) {
52546
+ return /*#__PURE__*/jsxRuntime.jsx("option", {
52547
+ value: m.value,
52548
+ children: m.label
52549
+ }, m.value);
52550
+ })
52551
+ }), /*#__PURE__*/jsxRuntime.jsx("button", {
52552
+ type: "button",
52553
+ onClick: fetchModels,
52554
+ disabled: modelsLoading,
52555
+ title: "Refresh available models",
52556
+ className: "text-gray-400 hover:text-gray-200 disabled:opacity-40 transition-colors p-1.5",
52557
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
52558
+ icon: "rotate",
52559
+ className: "h-3.5 w-3.5 ".concat(modelsLoading ? "animate-spin" : "")
52560
+ })
52441
52561
  })]
52442
- }), /*#__PURE__*/jsxRuntime.jsx("select", {
52443
- value: selectedModel,
52444
- onChange: handleModelChange,
52445
- className: "bg-white/10 border border-white/10 rounded-md px-3 py-1.5 text-sm text-gray-200 focus:outline-none focus:ring-1 focus:ring-blue-500",
52446
- children: MODELS.map(function (m) {
52447
- return /*#__PURE__*/jsxRuntime.jsx("option", {
52448
- value: m.value,
52449
- children: m.label
52450
- }, m.value);
52451
- })
52452
52562
  })]
52453
52563
  })]
52454
52564
  }), !hasAnthropicProvider && /*#__PURE__*/jsxRuntime.jsxs("div", {