fluxflow-cli 1.21.0 → 1.21.1

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.
Files changed (2) hide show
  1. package/dist/fluxflow.js +147 -10
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -1859,6 +1859,8 @@ function SettingsMenu({
1859
1859
  setEditValue(systemSettings.autoDisallowCommands || "");
1860
1860
  } else if (item.value === "apiTier") {
1861
1861
  setActiveView("apiTier");
1862
+ } else if (item.value === "aiProvider") {
1863
+ setActiveView("selectProvider");
1862
1864
  } else if (item.value === "autoDelete") {
1863
1865
  const options = ["1d", "7d", "30d"];
1864
1866
  const currentIndex = options.indexOf(systemSettings.autoDeleteHistory || "30d");
@@ -2283,18 +2285,20 @@ var init_paths = __esm({
2283
2285
  var secrets_exports = {};
2284
2286
  __export(secrets_exports, {
2285
2287
  getAPIKey: () => getAPIKey,
2288
+ getProviderAPIKey: () => getProviderAPIKey,
2286
2289
  getSearchSecrets: () => getSearchSecrets,
2287
2290
  getSecret: () => getSecret,
2288
2291
  removeAPIKey: () => removeAPIKey,
2289
2292
  removeSecret: () => removeSecret,
2290
2293
  saveAPIKey: () => saveAPIKey,
2294
+ saveProviderAPIKey: () => saveProviderAPIKey,
2291
2295
  saveSearchId: () => saveSearchId,
2292
2296
  saveSearchKey: () => saveSearchKey,
2293
2297
  saveSecret: () => saveSecret
2294
2298
  });
2295
2299
  import fs3 from "fs-extra";
2296
2300
  import path3 from "path";
2297
- var SECRET_FILE, getAPIKey, getSecret, saveSecret, getSearchSecrets, saveAPIKey, saveSearchKey, saveSearchId, removeSecret, removeAPIKey;
2301
+ var SECRET_FILE, getAPIKey, getProviderAPIKey, saveProviderAPIKey, getSecret, saveSecret, getSearchSecrets, saveAPIKey, saveSearchKey, saveSearchId, removeSecret, removeAPIKey;
2298
2302
  var init_secrets = __esm({
2299
2303
  "src/utils/secrets.js"() {
2300
2304
  init_crypto();
@@ -2308,6 +2312,26 @@ var init_secrets = __esm({
2308
2312
  }
2309
2313
  return null;
2310
2314
  };
2315
+ getProviderAPIKey = async (provider) => {
2316
+ try {
2317
+ const secrets = readEncryptedJson(SECRET_FILE, {});
2318
+ if (provider === "Google") return secrets.GOOGLE_API_KEY || secrets.API_KEY || null;
2319
+ if (provider === "DeepSeek") return secrets.DEEPSEEK_API_KEY || null;
2320
+ if (provider === "OpenRouter") return secrets.OPENROUTER_API_KEY || null;
2321
+ } catch (e) {
2322
+ }
2323
+ return null;
2324
+ };
2325
+ saveProviderAPIKey = async (provider, key) => {
2326
+ if (provider === "Google") {
2327
+ await saveSecret("GOOGLE_API_KEY", key);
2328
+ await saveSecret("API_KEY", key);
2329
+ } else if (provider === "DeepSeek") {
2330
+ await saveSecret("DEEPSEEK_API_KEY", key);
2331
+ } else if (provider === "OpenRouter") {
2332
+ await saveSecret("OPENROUTER_API_KEY", key);
2333
+ }
2334
+ };
2311
2335
  getSecret = async (key) => {
2312
2336
  try {
2313
2337
  const secrets = readEncryptedJson(SECRET_FILE, {});
@@ -5075,7 +5099,7 @@ var init_ai = __esm({
5075
5099
  } catch (e) {
5076
5100
  }
5077
5101
  }
5078
- if (Date.now() - lastFlushTime >= 350 && hasNewData) {
5102
+ if (Date.now() - lastFlushTime >= 100 && hasNewData) {
5079
5103
  yield {
5080
5104
  candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
5081
5105
  usageMetadata: latestUsageMetadata
@@ -5212,7 +5236,7 @@ var init_ai = __esm({
5212
5236
  } catch (e) {
5213
5237
  }
5214
5238
  }
5215
- if (Date.now() - lastFlushTime >= 350 && hasNewData) {
5239
+ if (Date.now() - lastFlushTime >= 100 && hasNewData) {
5216
5240
  yield {
5217
5241
  candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
5218
5242
  usageMetadata: latestUsageMetadata
@@ -6372,6 +6396,8 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
6372
6396
  yield { type: "status", content: "Working..." };
6373
6397
  dedupeBuffer = "";
6374
6398
  isDedupeActive = accumulatedContext.length > 0;
6399
+ let pendingGoogleText = "";
6400
+ let lastGoogleFlushTime = Date.now();
6375
6401
  for await (const chunk of stream) {
6376
6402
  if (TERMINATION_SIGNAL) {
6377
6403
  yield { type: "status", content: "Termination Signal Received." };
@@ -6424,7 +6450,11 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
6424
6450
  const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])\s*/gi, "") : cleanText.replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])[\s\S]*?(?:<\/(think|thought)>|\[\/(think|thought)\])\s*/gi, "").replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])\s*/gi, "");
6425
6451
  if (dedupeClean) {
6426
6452
  turnText += dedupeClean;
6427
- yield { type: "text", content: dedupeClean };
6453
+ if (aiProvider === "Google") {
6454
+ pendingGoogleText += dedupeClean;
6455
+ } else {
6456
+ yield { type: "text", content: dedupeClean };
6457
+ }
6428
6458
  }
6429
6459
  }
6430
6460
  isDedupeActive = false;
@@ -6433,7 +6463,11 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
6433
6463
  continue;
6434
6464
  } else {
6435
6465
  turnText += chunkText;
6436
- yield { type: "text", content: chunkText };
6466
+ if (aiProvider === "Google") {
6467
+ pendingGoogleText += chunkText;
6468
+ } else {
6469
+ yield { type: "text", content: chunkText };
6470
+ }
6437
6471
  }
6438
6472
  const signalSafeText3 = getSanitizedText(turnText);
6439
6473
  const toolContext = getActiveToolContext(turnText);
@@ -6914,6 +6948,11 @@ ${boxBottom}` };
6914
6948
  if (normToolName === "memory" && result.includes("SUCCESS")) yield { type: "memory_updated" };
6915
6949
  toolCallPointer++;
6916
6950
  }
6951
+ if (aiProvider === "Google" && pendingGoogleText && Date.now() - lastGoogleFlushTime >= 100) {
6952
+ yield { type: "text", content: pendingGoogleText };
6953
+ pendingGoogleText = "";
6954
+ lastGoogleFlushTime = Date.now();
6955
+ }
6917
6956
  }
6918
6957
  if (chunk.usageMetadata) {
6919
6958
  lastUsage = chunk.usageMetadata;
@@ -6928,7 +6967,11 @@ ${boxBottom}` };
6928
6967
  dedupeBuffer += "</think>";
6929
6968
  } else {
6930
6969
  turnText += "</think>";
6931
- yield { type: "text", content: "</think>" };
6970
+ if (aiProvider === "Google") {
6971
+ pendingGoogleText += "</think>";
6972
+ } else {
6973
+ yield { type: "text", content: "</think>" };
6974
+ }
6932
6975
  }
6933
6976
  }
6934
6977
  if (isDedupeActive && dedupeBuffer.length > 0) {
@@ -6946,12 +6989,20 @@ ${boxBottom}` };
6946
6989
  const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])\s*/gi, "") : cleanText.replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])[\s\S]*?(?:<\/(think|thought)>|\[\/(think|thought)\])\s*/gi, "").replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])\s*/gi, "");
6947
6990
  if (dedupeClean) {
6948
6991
  turnText += dedupeClean;
6949
- yield { type: "text", content: dedupeClean };
6992
+ if (aiProvider === "Google") {
6993
+ pendingGoogleText += dedupeClean;
6994
+ } else {
6995
+ yield { type: "text", content: dedupeClean };
6996
+ }
6950
6997
  }
6951
6998
  }
6952
6999
  isDedupeActive = false;
6953
7000
  dedupeBuffer = "";
6954
7001
  }
7002
+ if (aiProvider === "Google" && pendingGoogleText) {
7003
+ yield { type: "text", content: pendingGoogleText };
7004
+ pendingGoogleText = "";
7005
+ }
6955
7006
  if (TERMINATION_SIGNAL) break;
6956
7007
  const signalSafeText2 = (turnText || "").trim();
6957
7008
  const hasFinish2 = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText2.toLowerCase());
@@ -8201,7 +8252,8 @@ function App({ args = [] }) {
8201
8252
  setSystemSettings(freshSettings);
8202
8253
  setProfileData(saved.profileData);
8203
8254
  setImageSettings(saved.imageSettings || { keyType: "Default", quality: "Low-High", apiKey: "" });
8204
- const key = await getAPIKey();
8255
+ const startupProvider = saved.aiProvider || "Google";
8256
+ const key = await getProviderAPIKey(startupProvider);
8205
8257
  if (key) {
8206
8258
  setApiKey(key);
8207
8259
  initAI(key);
@@ -8284,7 +8336,7 @@ function App({ args = [] }) {
8284
8336
  if (aiProvider === "OpenRouter") minLength = 10;
8285
8337
  if (aiProvider === "DeepSeek") minLength = 20;
8286
8338
  if (key.length >= minLength) {
8287
- await saveAPIKey(key);
8339
+ await saveProviderAPIKey(aiProvider, key);
8288
8340
  setApiKey(key);
8289
8341
  initAI(key);
8290
8342
  let defaultModel = "gemma-4-31b-it";
@@ -8390,7 +8442,19 @@ function App({ args = [] }) {
8390
8442
  { cmd: "Fast", desc: "Fastest" },
8391
8443
  { cmd: "Standard", desc: "Standard Reasoning" },
8392
8444
  { cmd: "xHigh", desc: "Extended Reasoning" }
8445
+ ] : aiProvider === "OpenRouter" ? [
8446
+ { cmd: "Fast", desc: "Fastest" },
8447
+ { cmd: "Low", desc: "Quick Reasoning" },
8448
+ { cmd: "Medium", desc: "Balanced Reasoning" },
8449
+ { cmd: "High", desc: "Deep Reasoning" },
8450
+ { cmd: "xHigh", desc: "Extended Reasoning" }
8451
+ ] : activeModel && activeModel.toLowerCase().startsWith("gemini-3") ? [
8452
+ { cmd: "Fast", desc: "Fastest" },
8453
+ { cmd: "Low", desc: "Quick Reasoning" },
8454
+ { cmd: "Medium", desc: "Balanced Reasoning" },
8455
+ { cmd: "High", desc: "Deep Reasoning" }
8393
8456
  ] : [
8457
+ // Google General / Gemma
8394
8458
  { cmd: "Fast", desc: "Fastest" },
8395
8459
  { cmd: "Low", desc: "Quick Reasoning" },
8396
8460
  { cmd: "Medium", desc: "Balanced Reasoning" },
@@ -9656,6 +9720,59 @@ Selection: ${val}`,
9656
9720
  aiProvider
9657
9721
  }
9658
9722
  );
9723
+ case "selectProvider":
9724
+ return /* @__PURE__ */ React13.createElement(
9725
+ CommandMenu,
9726
+ {
9727
+ title: "SELECT AI PROVIDER",
9728
+ items: [
9729
+ { label: "Google (Free/Paid)", value: "Google" },
9730
+ { label: "DeepSeek (Paid)", value: "DeepSeek" },
9731
+ { label: "OpenRouter (Free/Paid) [EXPERIMENTAL]", value: "OpenRouter" },
9732
+ { label: "Back", value: "settings" }
9733
+ ],
9734
+ onSelect: async (item) => {
9735
+ if (item.value === "settings" || item.value === "Back") {
9736
+ setActiveView("settings");
9737
+ return;
9738
+ }
9739
+ const selectedProvider = item.value;
9740
+ const key = await getProviderAPIKey(selectedProvider);
9741
+ if (key) {
9742
+ setAiProvider(selectedProvider);
9743
+ setApiKey(key);
9744
+ initAI(key);
9745
+ let defaultModel = "gemma-4-31b-it";
9746
+ if (selectedProvider === "OpenRouter") {
9747
+ defaultModel = "google/gemma-4-31b-it:free";
9748
+ } else if (selectedProvider === "DeepSeek") {
9749
+ defaultModel = "deepseek-v4-flash";
9750
+ }
9751
+ setActiveModel(defaultModel);
9752
+ saveSettings({ aiProvider: selectedProvider, activeModel: defaultModel, apiTier, quotas });
9753
+ setMessages((prev) => [
9754
+ ...prev,
9755
+ {
9756
+ role: "system",
9757
+ text: `\u2705 Switched to ${selectedProvider}! Key loaded from Vault. Model set to ${defaultModel}.`,
9758
+ isMeta: true
9759
+ }
9760
+ ]);
9761
+ setActiveView("settings");
9762
+ } else {
9763
+ setInputConfig({
9764
+ label: `Enter ${selectedProvider} API Key:`,
9765
+ key: "providerKey",
9766
+ provider: selectedProvider,
9767
+ value: "",
9768
+ returnView: "settings"
9769
+ });
9770
+ setActiveView("input");
9771
+ }
9772
+ },
9773
+ onClose: () => setActiveView("settings")
9774
+ }
9775
+ );
9659
9776
  case "apiTier":
9660
9777
  return /* @__PURE__ */ React13.createElement(
9661
9778
  CommandMenu,
@@ -9695,7 +9812,7 @@ Selection: ${val}`,
9695
9812
  {
9696
9813
  value: inputConfig?.value || "",
9697
9814
  onChange: (val) => setInputConfig((prev) => ({ ...prev, value: val })),
9698
- onSubmit: (val) => {
9815
+ onSubmit: async (val) => {
9699
9816
  const { key, subKey, next } = inputConfig;
9700
9817
  let newQuotas = { ...quotas };
9701
9818
  let newSettings = {};
@@ -9737,6 +9854,26 @@ Selection: ${val}`,
9737
9854
  return [...prev, { id: Date.now(), role: "system", text: `\u274C [IMAGE KEY ERROR] API key must start with sk_. Key strategy reset to Default.`, isMeta: true }];
9738
9855
  });
9739
9856
  }
9857
+ } else if (key === "providerKey") {
9858
+ const keyInput = val.trim();
9859
+ const prov = inputConfig.provider;
9860
+ await saveProviderAPIKey(prov, keyInput);
9861
+ setAiProvider(prov);
9862
+ setApiKey(keyInput);
9863
+ initAI(keyInput);
9864
+ let defaultModel = "gemma-4-31b-it";
9865
+ if (prov === "OpenRouter") {
9866
+ defaultModel = "google/gemma-4-31b-it:free";
9867
+ } else if (prov === "DeepSeek") {
9868
+ defaultModel = "deepseek-v4-flash";
9869
+ }
9870
+ setActiveModel(defaultModel);
9871
+ newSettings.aiProvider = prov;
9872
+ newSettings.activeModel = defaultModel;
9873
+ setMessages((prev) => {
9874
+ setCompletedIndex(prev.length + 1);
9875
+ return [...prev, { id: Date.now(), role: "system", text: `\u2705 ${prov} API Key saved successfully! Model set to ${defaultModel}.`, isMeta: true }];
9876
+ });
9740
9877
  }
9741
9878
  if (next) {
9742
9879
  setInputConfig(next(key === "quotas" ? newQuotas : val));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.21.0",
3
+ "version": "1.21.1",
4
4
  "date": "2026-06-06",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [