kimiflare 0.36.0 → 0.36.2

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
@@ -483,6 +483,9 @@ function isRetryable(err, attempt) {
483
483
  return false;
484
484
  }
485
485
  async function* runKimi(opts2) {
486
+ if (opts2.cloudMode && !opts2.cloudToken) {
487
+ throw new KimiApiError("kimiflare: cloud mode requires a cloud token. Run `kimiflare auth cloud` to authenticate.", void 0, 401);
488
+ }
486
489
  const { url, headers: gatewayHeaders } = buildKimiRequestTarget(opts2);
487
490
  const body = {
488
491
  messages: sanitizeMessagesForApi(opts2.messages),
@@ -556,9 +559,11 @@ function validateModelId(model) {
556
559
  function buildKimiRequestTarget(opts2) {
557
560
  validateModelId(opts2.model);
558
561
  if (opts2.cloudMode) {
562
+ const headers2 = opts2.cloudToken ? { Authorization: `Bearer ${opts2.cloudToken}` } : {};
563
+ if (opts2.cloudDeviceId) headers2["X-Device-ID"] = opts2.cloudDeviceId;
559
564
  return {
560
565
  url: "https://api.kimiflare.com/v1/chat",
561
- headers: opts2.cloudToken ? { Authorization: `Bearer ${opts2.cloudToken}` } : {}
566
+ headers: headers2
562
567
  };
563
568
  }
564
569
  if (!opts2.gateway?.id) {
@@ -1757,7 +1762,8 @@ Use console.log() to return results. Only console.log output will be sent back t
1757
1762
  sessionId: opts2.sessionId,
1758
1763
  gateway: opts2.gateway,
1759
1764
  cloudMode: opts2.cloudMode,
1760
- cloudToken: opts2.cloudToken
1765
+ cloudToken: opts2.cloudToken,
1766
+ cloudDeviceId: opts2.cloudDeviceId
1761
1767
  });
1762
1768
  for await (const ev of events) {
1763
1769
  switch (ev.type) {
@@ -4661,24 +4667,30 @@ function generateCode() {
4661
4667
  }
4662
4668
  return out;
4663
4669
  }
4670
+ function generateDeviceId() {
4671
+ const arr = new Uint8Array(16);
4672
+ crypto.getRandomValues(arr);
4673
+ return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
4674
+ }
4664
4675
  function generateDeviceCodes() {
4665
4676
  const deviceCode = `device-${generateCode()}-${Date.now()}`;
4666
4677
  const userCode = `${generateCode()}-${generateCode()}`;
4667
4678
  const authUrl = `${CLOUD_API_URL}/auth/github?code=${encodeURIComponent(userCode)}`;
4668
- return { deviceCode, userCode, authUrl };
4679
+ const deviceId = generateDeviceId();
4680
+ return { deviceCode, userCode, authUrl, deviceId };
4669
4681
  }
4670
4682
  async function registerDevice(codes) {
4671
4683
  const registerRes = await fetch(`${CLOUD_API_URL}/auth/device`, {
4672
4684
  method: "POST",
4673
4685
  headers: { "Content-Type": "application/json" },
4674
- body: JSON.stringify({ device_code: codes.deviceCode, user_code: codes.userCode })
4686
+ body: JSON.stringify({ device_code: codes.deviceCode, user_code: codes.userCode, device_id: codes.deviceId })
4675
4687
  });
4676
4688
  if (!registerRes.ok) {
4677
4689
  const err = await registerRes.json().catch(() => ({}));
4678
4690
  throw new Error(`Failed to register device: ${err.error || registerRes.statusText}`);
4679
4691
  }
4680
4692
  }
4681
- async function pollForToken(deviceCode) {
4693
+ async function pollForToken(deviceCode, deviceId) {
4682
4694
  const pollRes = await fetch(`${CLOUD_API_URL}/auth/poll`, {
4683
4695
  method: "POST",
4684
4696
  headers: { "Content-Type": "application/json" },
@@ -4689,26 +4701,36 @@ async function pollForToken(deviceCode) {
4689
4701
  if (pollData.status === "approved" && pollData.access_token) {
4690
4702
  const creds = {
4691
4703
  accessToken: pollData.access_token,
4692
- expiresAt: Math.floor(Date.now() / 1e3) + 7 * 24 * 60 * 60
4704
+ expiresAt: Math.floor(Date.now() / 1e3) + 7 * 24 * 60 * 60,
4693
4705
  // 7 days
4706
+ deviceId
4694
4707
  };
4695
4708
  await saveCloudCredentials(creds);
4696
4709
  return creds;
4697
4710
  }
4698
4711
  return null;
4699
4712
  }
4700
- async function fetchCloudUsage(token) {
4701
- const res = await fetch(`${CLOUD_API_URL}/v1/usage`, {
4702
- headers: { Authorization: `Bearer ${token}` }
4703
- });
4713
+ async function fetchCloudUsage(token, deviceId) {
4714
+ const headers = { Authorization: `Bearer ${token}` };
4715
+ if (deviceId) headers["X-Device-ID"] = deviceId;
4716
+ const res = await fetch(`${CLOUD_API_URL}/v1/usage`, { headers });
4704
4717
  if (!res.ok) return null;
4705
- return await res.json();
4718
+ const data = await res.json();
4719
+ if (typeof data.remaining !== "number" || typeof data.input_token_limit !== "number" || typeof data.input_tokens_used !== "number" || typeof data.expires_at !== "string") {
4720
+ return null;
4721
+ }
4722
+ return {
4723
+ input_token_limit: data.input_token_limit,
4724
+ input_tokens_used: data.input_tokens_used,
4725
+ remaining: data.remaining,
4726
+ expires_at: data.expires_at
4727
+ };
4706
4728
  }
4707
4729
  async function loadCloudCredentials() {
4708
4730
  try {
4709
4731
  const raw = await readFile11(cloudCredPath(), "utf8");
4710
4732
  const parsed = JSON.parse(raw);
4711
- if (parsed.expiresAt && parsed.expiresAt > Date.now() / 1e3) {
4733
+ if (parsed.expiresAt && parsed.expiresAt > Date.now() / 1e3 && parsed.accessToken) {
4712
4734
  return parsed;
4713
4735
  }
4714
4736
  } catch {
@@ -4734,7 +4756,7 @@ async function authenticateDevice(onStatus) {
4734
4756
  while (Date.now() - startTime < POLL_TIMEOUT_MS) {
4735
4757
  await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
4736
4758
  onStatus({ url: codes.authUrl, userCode: codes.userCode, polling: true });
4737
- const creds = await pollForToken(codes.deviceCode);
4759
+ const creds = await pollForToken(codes.deviceCode, codes.deviceId);
4738
4760
  if (creds) return creds;
4739
4761
  }
4740
4762
  throw new Error("Authentication timed out. Please try again.");
@@ -7966,9 +7988,9 @@ function Onboarding({ onDone, onCancel }) {
7966
7988
  return;
7967
7989
  }
7968
7990
  try {
7969
- const creds = await pollForToken(cloudAuth.codes.deviceCode);
7991
+ const creds = await pollForToken(cloudAuth.codes.deviceCode, cloudAuth.codes.deviceId);
7970
7992
  if (creds && !cancelled) {
7971
- const usage = await fetchCloudUsage(creds.accessToken);
7993
+ const usage = await fetchCloudUsage(creds.accessToken, creds.deviceId);
7972
7994
  if (usage && !cancelled) {
7973
7995
  setCloudAuth({
7974
7996
  phase: "success",
@@ -12971,12 +12993,15 @@ function App({
12971
12993
  initialUpdateResult,
12972
12994
  initialLspScope,
12973
12995
  initialLspProjectPath,
12974
- initialCloudToken
12996
+ initialCloudToken,
12997
+ initialCloudDeviceId
12975
12998
  }) {
12976
12999
  const { exit } = useApp();
12977
13000
  const [cfg, setCfg] = useState10(initialCfg);
12978
13001
  const [lspScope, setLspScope] = useState10(initialLspScope);
12979
13002
  const [lspProjectPath, setLspProjectPath] = useState10(initialLspProjectPath);
13003
+ const [cloudToken, setCloudToken] = useState10(initialCloudToken);
13004
+ const [cloudDeviceId, setCloudDeviceId] = useState10(initialCloudDeviceId);
12980
13005
  const [events, setRawEvents] = useState10([]);
12981
13006
  const setEvents = useCallback2(
12982
13007
  (updater) => {
@@ -13030,7 +13055,7 @@ function App({
13030
13055
  let cancelled = false;
13031
13056
  const fetchBudget = async () => {
13032
13057
  const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
13033
- const usage2 = await fetchCloudUsage2(initialCloudToken);
13058
+ const usage2 = await fetchCloudUsage2(initialCloudToken, cloudDeviceId ?? initialCloudDeviceId);
13034
13059
  if (usage2 && !cancelled) {
13035
13060
  setCloudBudget({ remaining: usage2.remaining, limit: usage2.input_token_limit });
13036
13061
  }
@@ -13953,7 +13978,8 @@ function App({
13953
13978
  memoryManager: memoryManagerRef.current,
13954
13979
  codeMode: effectiveCodeMode,
13955
13980
  cloudMode: cfg.cloudMode,
13956
- cloudToken: initialCloudToken,
13981
+ cloudToken: cloudToken ?? initialCloudToken,
13982
+ cloudDeviceId: cloudDeviceId ?? initialCloudDeviceId,
13957
13983
  onIterationEnd,
13958
13984
  onFileChange: (path, content) => {
13959
13985
  if (content) {
@@ -15163,7 +15189,8 @@ ${lines.join("\n")}` }]);
15163
15189
  keepLastImageTurns: cfg.imageHistoryTurns ?? 2,
15164
15190
  codeMode: effectiveCodeMode,
15165
15191
  cloudMode: cfg.cloudMode,
15166
- cloudToken: initialCloudToken,
15192
+ cloudToken: cloudToken ?? initialCloudToken,
15193
+ cloudDeviceId: cloudDeviceId ?? initialCloudDeviceId,
15167
15194
  onIterationEnd,
15168
15195
  intentClassification: classification,
15169
15196
  onFileChange: (path, content2) => {
@@ -15362,6 +15389,7 @@ ${lines.join("\n")}` }]);
15362
15389
  const { loadCloudCredentials: loadCloudCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15363
15390
  const creds = await loadCloudCredentials2();
15364
15391
  if (creds) {
15392
+ setCloudToken(creds.accessToken);
15365
15393
  setEvents((e) => [
15366
15394
  ...e,
15367
15395
  { kind: "info", key: mkKey(), text: "configuration saved \u2014 welcome to kimiflare! (cloud mode)" }
@@ -15664,7 +15692,7 @@ ${lines.join("\n")}` }]);
15664
15692
  ] })
15665
15693
  ] }) });
15666
15694
  }
15667
- async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null, cloudToken) {
15695
+ async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null, cloudToken, cloudDeviceId) {
15668
15696
  const instance = render(
15669
15697
  /* @__PURE__ */ jsx23(
15670
15698
  App,
@@ -15673,7 +15701,8 @@ async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath
15673
15701
  initialUpdateResult: updateResult,
15674
15702
  initialLspScope: lspScope,
15675
15703
  initialLspProjectPath: lspProjectPath,
15676
- initialCloudToken: cloudToken
15704
+ initialCloudToken: cloudToken,
15705
+ initialCloudDeviceId: cloudDeviceId
15677
15706
  }
15678
15707
  ),
15679
15708
  {
@@ -15886,14 +15915,12 @@ program.command("usage").description("Show Kimiflare Cloud token usage (requires
15886
15915
  console.error("Not authenticated with Kimiflare Cloud. Run: kimiflare auth cloud");
15887
15916
  process.exit(1);
15888
15917
  }
15889
- const res = await fetch("https://api.kimiflare.com/v1/usage", {
15890
- headers: { Authorization: `Bearer ${creds.accessToken}` }
15891
- });
15892
- if (!res.ok) {
15893
- console.error(`Failed to fetch usage: ${res.status} ${res.statusText}`);
15918
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15919
+ const usage = await fetchCloudUsage2(creds.accessToken, creds.deviceId);
15920
+ if (!usage) {
15921
+ console.error("Failed to fetch usage: invalid response from server");
15894
15922
  process.exit(1);
15895
15923
  }
15896
- const usage = await res.json();
15897
15924
  console.log(`Token budget: ${usage.remaining.toLocaleString()} / ${usage.input_token_limit.toLocaleString()} remaining`);
15898
15925
  console.log(`Used: ${usage.input_tokens_used.toLocaleString()}`);
15899
15926
  console.log(`Grant expires: ${usage.expires_at}`);
@@ -15931,11 +15958,9 @@ Kimiflare Cloud Authentication`);
15931
15958
  }
15932
15959
  });
15933
15960
  console.log(`Authenticated! Token expires at ${new Date(creds.expiresAt * 1e3).toISOString()}`);
15934
- const usageRes = await fetch("https://api.kimiflare.com/v1/usage", {
15935
- headers: { Authorization: `Bearer ${creds.accessToken}` }
15936
- });
15937
- if (usageRes.ok) {
15938
- const usage = await usageRes.json();
15961
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15962
+ const usage = await fetchCloudUsage2(creds.accessToken, creds.deviceId);
15963
+ if (usage) {
15939
15964
  console.log(`
15940
15965
  Token budget: ${usage.remaining.toLocaleString()} / ${usage.input_token_limit.toLocaleString()} remaining`);
15941
15966
  console.log(`Grant expires: ${usage.expires_at}`);
@@ -15969,6 +15994,7 @@ async function main() {
15969
15994
  }
15970
15995
  const cloudMode = opts.cloud ?? cfg?.cloudMode ?? false;
15971
15996
  let cloudToken;
15997
+ let cloudDeviceId;
15972
15998
  if (cloudMode) {
15973
15999
  const { loadCloudCredentials: loadCloudCredentials2, authenticateDevice: authenticateDevice2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15974
16000
  let cloudCreds = await loadCloudCredentials2();
@@ -15977,6 +16003,7 @@ async function main() {
15977
16003
  process.exit(2);
15978
16004
  }
15979
16005
  cloudToken = cloudCreds.accessToken;
16006
+ cloudDeviceId = cloudCreds.deviceId;
15980
16007
  cfg = {
15981
16008
  ...cfg ?? { accountId: "", apiToken: "", model: DEFAULT_MODEL },
15982
16009
  cloudMode: true
@@ -15998,6 +16025,7 @@ async function main() {
15998
16025
  showReasoning: !!opts.reasoning,
15999
16026
  codeMode: cfg.codeMode,
16000
16027
  cloudToken,
16028
+ cloudDeviceId,
16001
16029
  continueOnLimit: !!opts.continueOnLimit,
16002
16030
  maxInputTokens: opts.maxInputTokens,
16003
16031
  updateResult
@@ -16013,9 +16041,9 @@ async function main() {
16013
16041
  const { renderApp: renderApp2 } = await Promise.resolve().then(() => (init_app(), app_exports));
16014
16042
  if (cfg) {
16015
16043
  const model = opts.model ?? cfg.model ?? DEFAULT_MODEL;
16016
- await renderApp2({ ...cfg, model }, updateResult, lspScope, lspProjectPath, cloudToken);
16044
+ await renderApp2({ ...cfg, model }, updateResult, lspScope, lspProjectPath, cloudToken, cloudDeviceId);
16017
16045
  } else {
16018
- await renderApp2(null, updateResult, lspScope, lspProjectPath, cloudToken);
16046
+ await renderApp2(null, updateResult, lspScope, lspProjectPath, cloudToken, cloudDeviceId);
16019
16047
  }
16020
16048
  }
16021
16049
  function gatewayFromPrintOpts(opts2) {
@@ -16067,6 +16095,7 @@ async function runPrintMode(opts2) {
16067
16095
  maxInputTokens: opts2.maxInputTokens,
16068
16096
  cloudMode: opts2.cloudMode,
16069
16097
  cloudToken: opts2.cloudToken,
16098
+ cloudDeviceId: opts2.cloudDeviceId,
16070
16099
  coauthor: opts2.coauthor !== false ? { name: opts2.coauthorName || "kimiflare", email: opts2.coauthorEmail || "kimiflare@proton.me" } : void 0,
16071
16100
  callbacks: {
16072
16101
  onReasoningDelta: opts2.showReasoning ? (delta) => {