kimiflare 0.94.0 → 0.96.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/index.js CHANGED
@@ -40,6 +40,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
40
40
  // src/config.ts
41
41
  var config_exports = {};
42
42
  __export(config_exports, {
43
+ DEFAULT_CLOUD_MODEL: () => DEFAULT_CLOUD_MODEL,
43
44
  DEFAULT_MODEL: () => DEFAULT_MODEL,
44
45
  DEFAULT_REASONING_EFFORT: () => DEFAULT_REASONING_EFFORT,
45
46
  EFFORTS: () => EFFORTS,
@@ -388,12 +389,13 @@ async function saveConfig(cfg) {
388
389
  await chmod(p, 384);
389
390
  return p;
390
391
  }
391
- var EFFORTS, DEFAULT_MODEL, DEFAULT_REASONING_EFFORT;
392
+ var EFFORTS, DEFAULT_MODEL, DEFAULT_CLOUD_MODEL, DEFAULT_REASONING_EFFORT;
392
393
  var init_config = __esm({
393
394
  "src/config.ts"() {
394
395
  "use strict";
395
396
  EFFORTS = ["low", "medium", "high"];
396
397
  DEFAULT_MODEL = "@cf/moonshotai/kimi-k2.6";
398
+ DEFAULT_CLOUD_MODEL = "@cf/moonshotai/kimi-k2.7-code";
397
399
  DEFAULT_REASONING_EFFORT = "medium";
398
400
  }
399
401
  });
@@ -2240,7 +2242,7 @@ async function* runKimi(opts2) {
2240
2242
  `Your stored ${modelProvider} key is likely invalid or expired. Fix:`,
2241
2243
  ` /keys set ${modelProvider} <new-key> replace the stored key`,
2242
2244
  ` /keys clear ${modelProvider} remove it and reopen the picker to paste fresh`,
2243
- ` /model @cf/moonshotai/kimi-k2.6 switch back to Workers AI (no key needed)`
2245
+ ` /model ${opts2.cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL} switch back to Workers AI (no key needed)`
2244
2246
  ].join("\n") : msg;
2245
2247
  const apiErr = new KimiApiError(`kimiflare: ${wrappedMsg}`, err?.code, res.status);
2246
2248
  if (isRetryable(apiErr, attempt)) {
@@ -2320,7 +2322,7 @@ function validateModelId(model) {
2320
2322
  if (/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9._-]+$/.test(model)) return;
2321
2323
  throw new KimiApiError(`Invalid model ID: ${model}`, 400);
2322
2324
  }
2323
- function missingKeyMessage(model, provider, unifiedAvailable) {
2325
+ function missingKeyMessage(model, provider, unifiedAvailable, cloudMode) {
2324
2326
  const doc = PROVIDER_DOC[provider] ?? { name: "your provider", where: "your provider's dashboard" };
2325
2327
  const lines = [
2326
2328
  `kimiflare: ${model} needs a ${doc.name} API key.`,
@@ -2331,7 +2333,8 @@ function missingKeyMessage(model, provider, unifiedAvailable) {
2331
2333
  if (unifiedAvailable) {
2332
2334
  lines.push(` 2. Enable Cloudflare Unified Billing for this gateway in the CF dashboard, then run: /keys unified on`);
2333
2335
  }
2334
- lines.push(` ${unifiedAvailable ? "3" : "2"}. Switch back to a Workers AI model: /model @cf/moonshotai/kimi-k2.6`);
2336
+ const fallbackModel = cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL;
2337
+ lines.push(` ${unifiedAvailable ? "3" : "2"}. Switch back to a Workers AI model: /model ${fallbackModel}`);
2335
2338
  return lines.join("\n");
2336
2339
  }
2337
2340
  function gatewayHeadersFor(opts2) {
@@ -2394,7 +2397,7 @@ function buildKimiRequestTarget(opts2) {
2394
2397
  headers["cf-aig-authorization"] = `Bearer ${providerKey}`;
2395
2398
  } else {
2396
2399
  throw new KimiApiError(
2397
- missingKeyMessage(opts2.model, entry.provider, entry.billingMode === "unified"),
2400
+ missingKeyMessage(opts2.model, entry.provider, entry.billingMode === "unified", opts2.cloudMode),
2398
2401
  void 0,
2399
2402
  401
2400
2403
  );
@@ -2573,6 +2576,7 @@ var init_client = __esm({
2573
2576
  init_log_sink();
2574
2577
  init_llm_dump();
2575
2578
  init_registry();
2579
+ init_config();
2576
2580
  RETRYABLE_CODES = /* @__PURE__ */ new Set([3040]);
2577
2581
  MAX_ATTEMPTS = 5;
2578
2582
  PROVIDER_DOC = {
@@ -7844,7 +7848,7 @@ var init_spawn_worker = __esm({
7844
7848
  },
7845
7849
  model: {
7846
7850
  type: "string",
7847
- description: "Model to use for the worker. Defaults to @cf/moonshotai/kimi-k2.6."
7851
+ description: `Model to use for the worker. Defaults to ${DEFAULT_MODEL} (or ${DEFAULT_CLOUD_MODEL} in cloud mode).`
7848
7852
  },
7849
7853
  branchName: {
7850
7854
  type: "string",
@@ -7882,6 +7886,7 @@ var init_spawn_worker = __esm({
7882
7886
  const timeoutMs = readNumberEnv2("KIMIFLARE_WORKER_TIMEOUT_MS") ?? DEFAULT_WORKER_TIMEOUT_MS;
7883
7887
  const cfg = await loadConfig().catch(() => null);
7884
7888
  const budgetUsd = resolveWorkerBudgetUsd(cfg);
7889
+ const defaultModel = cfg?.cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL;
7885
7890
  const payload = {
7886
7891
  mode: args.mode,
7887
7892
  task: args.task,
@@ -7889,7 +7894,7 @@ var init_spawn_worker = __esm({
7889
7894
  budget: { maxCostUsd: budgetUsd },
7890
7895
  outputFormat: args.outputFormat ?? "structured",
7891
7896
  tools: args.tools ?? (args.mode === "plan" ? "read-only" : "all"),
7892
- model: args.model ?? "@cf/moonshotai/kimi-k2.6",
7897
+ model: args.model ?? defaultModel,
7893
7898
  ...args.mode === "execute" ? {
7894
7899
  branchName: args.branchName,
7895
7900
  baseBranch: args.baseBranch ?? "main",
@@ -10868,7 +10873,7 @@ function setupRoutes(config2) {
10868
10873
  if (pathname === "/prompt" && method === "POST") {
10869
10874
  const body = await readBody(req);
10870
10875
  const prompt = typeof body.prompt === "string" ? body.prompt : "";
10871
- const model = typeof body.model === "string" ? body.model : config2.model ?? "@cf/moonshotai/kimi-k2.6";
10876
+ const model = typeof body.model === "string" ? body.model : config2.model ?? (config2.cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL);
10872
10877
  const cwd = typeof body.cwd === "string" ? body.cwd : process.cwd();
10873
10878
  const title = typeof body.title === "string" ? body.title : void 0;
10874
10879
  const files = Array.isArray(body.files) ? body.files.filter((f) => typeof f === "string") : [];
@@ -11043,6 +11048,7 @@ var activeSessions;
11043
11048
  var init_routes = __esm({
11044
11049
  "src/server/routes.ts"() {
11045
11050
  "use strict";
11051
+ init_config();
11046
11052
  init_loop();
11047
11053
  init_system_prompt();
11048
11054
  init_executor();
@@ -11827,6 +11833,7 @@ var init_manager2 = __esm({
11827
11833
  init_schema();
11828
11834
  init_db2();
11829
11835
  init_embeddings();
11836
+ init_config();
11830
11837
  init_retrieval();
11831
11838
  init_cleanup();
11832
11839
  SECRET_PATTERNS = [
@@ -11877,7 +11884,7 @@ Return a JSON array of strings. Example:
11877
11884
  return {
11878
11885
  accountId: this.opts.accountId,
11879
11886
  apiToken: this.opts.apiToken,
11880
- model: this.opts.model ?? "@cf/moonshotai/kimi-k2.6",
11887
+ model: this.opts.model ?? (this.opts.cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL),
11881
11888
  gateway: this.opts.gateway
11882
11889
  };
11883
11890
  }
@@ -13717,7 +13724,8 @@ async function createAgentSession(opts2) {
13717
13724
  extractionModel: config2.memoryExtractionModel,
13718
13725
  embeddingModel: config2.memoryEmbeddingModel,
13719
13726
  maxAgeDays: config2.memoryMaxAgeDays,
13720
- maxEntries: config2.memoryMaxEntries
13727
+ maxEntries: config2.memoryMaxEntries,
13728
+ cloudMode: config2.cloudMode
13721
13729
  });
13722
13730
  memoryManager.open();
13723
13731
  }
@@ -14849,6 +14857,7 @@ var init_supervisor = __esm({
14849
14857
  logger.warn("supervisor:mcp_export_failed", { error: err.message });
14850
14858
  }
14851
14859
  }
14860
+ const defaultWorkerModel = cfg?.cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL;
14852
14861
  const payload = {
14853
14862
  mode: w.mode,
14854
14863
  task: w.task,
@@ -14858,7 +14867,7 @@ ${w.context ?? ""}` : w.context ?? "",
14858
14867
  budget: { maxCostUsd },
14859
14868
  outputFormat: "structured",
14860
14869
  tools: w.mode === "plan" ? "read-only" : "all",
14861
- model: w.model ?? "@cf/moonshotai/kimi-k2.6",
14870
+ model: w.model ?? defaultWorkerModel,
14862
14871
  // Sandbox-driven worker needs the repo to clone:
14863
14872
  githubToken: repo.token,
14864
14873
  owner: repo.owner,
@@ -17616,7 +17625,7 @@ function StatusBar({ usage, sessionUsage, thinking, turnStartedAt, mode, context
17616
17625
  const elapsed = turnStartedAt !== null ? formatElapsed3(Math.max(0, now2 - turnStartedAt)) : null;
17617
17626
  const idleParts = [];
17618
17627
  if (gitBranch) idleParts.push(gitBranch);
17619
- if (model) idleParts.push(shortenModelId(model));
17628
+ if (model && !cloudMode) idleParts.push(shortenModelId(model));
17620
17629
  if (cloudMode) idleParts.push("CLOUD");
17621
17630
  if (codeMode) idleParts.push("CODE");
17622
17631
  const metaParts = [];
@@ -20405,6 +20414,287 @@ var init_key_entry_modal = __esm({
20405
20414
  }
20406
20415
  });
20407
20416
 
20417
+ // src/ui/app-helpers.ts
20418
+ var app_helpers_exports = {};
20419
+ __export(app_helpers_exports, {
20420
+ AUTO_COMPACT_THRESHOLD: () => AUTO_COMPACT_THRESHOLD,
20421
+ CONTEXT_LIMIT: () => CONTEXT_LIMIT,
20422
+ DEFAULT_AUTO_FRESH_SUGGESTION_TURNS: () => DEFAULT_AUTO_FRESH_SUGGESTION_TURNS,
20423
+ FEEDBACK_WORKER_URL: () => FEEDBACK_WORKER_URL,
20424
+ MAX_EVENTS: () => MAX_EVENTS,
20425
+ MAX_IMAGES_PER_MESSAGE: () => MAX_IMAGES_PER_MESSAGE,
20426
+ buildFilePickerIgnoreList: () => buildFilePickerIgnoreList,
20427
+ capEvents: () => capEvents,
20428
+ compactEventsVisual: () => compactEventsVisual,
20429
+ detectGitBranch: () => detectGitBranch,
20430
+ detectGitHubRepo: () => detectGitHubRepo,
20431
+ findImagePaths: () => findImagePaths,
20432
+ formatTokens: () => formatTokens4,
20433
+ gatewayFromConfig: () => gatewayFromConfig,
20434
+ gatewayUsageLookupFromConfig: () => gatewayUsageLookupFromConfig,
20435
+ makePrefixMessages: () => makePrefixMessages,
20436
+ mkAssistantId: () => mkAssistantId,
20437
+ mkKey: () => mkKey,
20438
+ openBrowser: () => openBrowser,
20439
+ rebuildSystemPromptForMode: () => rebuildSystemPromptForMode,
20440
+ trackRecentFile: () => trackRecentFile
20441
+ });
20442
+ import { execSync as execSync3, spawn as spawn4 } from "child_process";
20443
+ import { existsSync as existsSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
20444
+ import { join as join26 } from "path";
20445
+ import { platform as platform4 } from "os";
20446
+ function buildFilePickerIgnoreList(cwd) {
20447
+ const hardcoded = [
20448
+ // Dependencies
20449
+ "**/node_modules/**",
20450
+ "**/vendor/**",
20451
+ "**/.bundle/**",
20452
+ "**/bower_components/**",
20453
+ // Version control
20454
+ "**/.git/**",
20455
+ "**/.svn/**",
20456
+ "**/.hg/**",
20457
+ // Build / output directories
20458
+ "**/dist/**",
20459
+ "**/build/**",
20460
+ "**/out/**",
20461
+ "**/public/**",
20462
+ "**/.next/**",
20463
+ "**/.nuxt/**",
20464
+ "**/.svelte-kit/**",
20465
+ "**/.vercel/**",
20466
+ "**/.netlify/**",
20467
+ "**/target/**",
20468
+ "**/bin/**",
20469
+ "**/obj/**",
20470
+ "**/Debug/**",
20471
+ "**/Release/**",
20472
+ "**/.gradle/**",
20473
+ // Caches
20474
+ "**/.cache/**",
20475
+ "**/.parcel-cache/**",
20476
+ "**/.turbo/**",
20477
+ "**/.eslintcache",
20478
+ "**/.stylelintcache",
20479
+ "**/.rpt2_cache/**",
20480
+ "**/.rts2_cache/**",
20481
+ // Temporary
20482
+ "**/tmp/**",
20483
+ "**/temp/**",
20484
+ "**/*.tmp",
20485
+ // Coverage
20486
+ "**/coverage/**",
20487
+ "**/.nyc_output/**",
20488
+ // OS files
20489
+ "**/.DS_Store",
20490
+ "**/Thumbs.db",
20491
+ // Logs
20492
+ "**/*.log",
20493
+ "**/logs/**",
20494
+ // Lock files (auto-generated, usually huge)
20495
+ "**/package-lock.json",
20496
+ "**/yarn.lock",
20497
+ "**/pnpm-lock.yaml",
20498
+ "**/bun.lockb",
20499
+ "**/Cargo.lock",
20500
+ "**/Gemfile.lock",
20501
+ "**/composer.lock",
20502
+ "**/Pipfile.lock",
20503
+ "**/poetry.lock",
20504
+ "**/go.sum",
20505
+ // Minified / source maps
20506
+ "**/*.min.js",
20507
+ "**/*.min.css",
20508
+ "**/*.map",
20509
+ // kimiflare internal
20510
+ "**/.kimiflare/**",
20511
+ // IDE (usually not relevant to mention)
20512
+ "**/.idea/**"
20513
+ ];
20514
+ const gitignorePatterns = [];
20515
+ try {
20516
+ const gitignorePath = join26(cwd, ".gitignore");
20517
+ const stats = statSync4(gitignorePath);
20518
+ if (stats.size > MAX_GITIGNORE_SIZE) {
20519
+ return hardcoded;
20520
+ }
20521
+ const content = readFileSync4(gitignorePath, "utf-8");
20522
+ for (const line of content.split(/\r?\n/)) {
20523
+ const trimmed = line.trim();
20524
+ if (!trimmed || trimmed.startsWith("#")) continue;
20525
+ if (trimmed.startsWith("!")) continue;
20526
+ let pattern = trimmed;
20527
+ const isAnchored = pattern.startsWith("/");
20528
+ const isDir = pattern.endsWith("/");
20529
+ if (isAnchored) pattern = pattern.slice(1);
20530
+ if (isDir) pattern = pattern.slice(0, -1);
20531
+ if (!pattern) continue;
20532
+ if (isAnchored) {
20533
+ gitignorePatterns.push(isDir ? pattern + "/**" : pattern);
20534
+ } else {
20535
+ gitignorePatterns.push(isDir ? "**/" + pattern + "/**" : "**/" + pattern);
20536
+ }
20537
+ }
20538
+ } catch {
20539
+ }
20540
+ return [...hardcoded, ...gitignorePatterns];
20541
+ }
20542
+ function gatewayFromConfig(cfg) {
20543
+ if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
20544
+ if (!cfg.aiGatewayId) return void 0;
20545
+ return {
20546
+ id: cfg.aiGatewayId,
20547
+ cacheTtl: cfg.aiGatewayCacheTtl,
20548
+ skipCache: cfg.aiGatewaySkipCache,
20549
+ collectLogPayload: cfg.aiGatewayCollectLogPayload,
20550
+ metadata: cfg.aiGatewayMetadata
20551
+ };
20552
+ }
20553
+ function gatewayUsageLookupFromConfig(cfg, meta) {
20554
+ if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
20555
+ if (!cfg.aiGatewayId || !meta) return void 0;
20556
+ return {
20557
+ accountId: cfg.accountId,
20558
+ apiToken: cfg.apiToken,
20559
+ gatewayId: cfg.aiGatewayId,
20560
+ meta
20561
+ };
20562
+ }
20563
+ function openBrowser(url) {
20564
+ const cmd = platform4() === "darwin" ? "open" : platform4() === "win32" ? "start" : "xdg-open";
20565
+ const child = spawn4(cmd, [url], { detached: true, stdio: "ignore" });
20566
+ child.unref();
20567
+ }
20568
+ function detectGitHubRepo(cachedRepo) {
20569
+ if (cachedRepo) {
20570
+ const parts = cachedRepo.split("/");
20571
+ if (parts.length === 2) return { owner: parts[0], name: parts[1] };
20572
+ }
20573
+ try {
20574
+ const remoteUrl = execSync3("git remote get-url origin", { cwd: process.cwd(), encoding: "utf8" }).trim().replace(/\/+$/, "");
20575
+ const httpsMatch = remoteUrl.match(/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
20576
+ if (httpsMatch) return { owner: httpsMatch[1], name: httpsMatch[2] };
20577
+ const sshMatch = remoteUrl.match(/github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
20578
+ if (sshMatch) return { owner: sshMatch[1], name: sshMatch[2] };
20579
+ } catch {
20580
+ }
20581
+ return null;
20582
+ }
20583
+ function detectGitBranch() {
20584
+ try {
20585
+ return execSync3("git branch --show-current", { cwd: process.cwd(), encoding: "utf8" }).trim() || null;
20586
+ } catch {
20587
+ return null;
20588
+ }
20589
+ }
20590
+ function formatTokens4(n) {
20591
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
20592
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
20593
+ return String(n);
20594
+ }
20595
+ function trackRecentFile(ref, path, max = 10) {
20596
+ ref.current.set(path, Date.now());
20597
+ if (ref.current.size > max) {
20598
+ let oldest = null;
20599
+ let oldestTime = Infinity;
20600
+ for (const [p, t] of ref.current) {
20601
+ if (t < oldestTime) {
20602
+ oldestTime = t;
20603
+ oldest = p;
20604
+ }
20605
+ }
20606
+ if (oldest) ref.current.delete(oldest);
20607
+ }
20608
+ }
20609
+ function capEvents(prev) {
20610
+ if (prev.length <= MAX_EVENTS) return prev;
20611
+ return prev.slice(prev.length - MAX_EVENTS);
20612
+ }
20613
+ function compactEventsVisual(prev, keepLastTurns) {
20614
+ let seen = 0;
20615
+ let cutoff = -1;
20616
+ for (let i = prev.length - 1; i >= 0; i--) {
20617
+ if (prev[i].kind === "user") {
20618
+ seen++;
20619
+ if (seen === keepLastTurns + 1) {
20620
+ cutoff = i;
20621
+ break;
20622
+ }
20623
+ }
20624
+ }
20625
+ if (cutoff <= 0) return prev;
20626
+ const kept = prev.slice(cutoff);
20627
+ return [
20628
+ { kind: "info", key: mkKey(), text: `\xB7\xB7\xB7 ${cutoff} earlier messages compacted \xB7\xB7\xB7` },
20629
+ ...kept
20630
+ ];
20631
+ }
20632
+ function makePrefixMessages(cacheStable, model, mode, tools, preferPullRequests) {
20633
+ if (cacheStable) {
20634
+ return buildSystemMessages({ cwd: process.cwd(), tools, model, mode, preferPullRequests });
20635
+ }
20636
+ return [
20637
+ {
20638
+ role: "system",
20639
+ content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode, preferPullRequests })
20640
+ }
20641
+ ];
20642
+ }
20643
+ function rebuildSystemPromptForMode(messages, cacheStable, model, mode, tools, preferPullRequests) {
20644
+ if (cacheStable) {
20645
+ const rebuilt = buildSystemMessages({ cwd: process.cwd(), tools, model, mode, preferPullRequests });
20646
+ messages[0] = rebuilt[0];
20647
+ if (rebuilt[1]) {
20648
+ messages[1] = rebuilt[1];
20649
+ }
20650
+ } else {
20651
+ messages[0] = {
20652
+ role: "system",
20653
+ content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode, preferPullRequests })
20654
+ };
20655
+ }
20656
+ }
20657
+ function findImagePaths(text) {
20658
+ const paths = [];
20659
+ const quotedRegex = /"([^"]+)"|'([^']+)'/g;
20660
+ let match;
20661
+ while ((match = quotedRegex.exec(text)) !== null) {
20662
+ const path = match[1] ?? match[2];
20663
+ if (path && isImagePath(path) && existsSync4(path)) {
20664
+ paths.push(path);
20665
+ }
20666
+ }
20667
+ const remaining = text.replace(/"[^"]+"|'[^']+'/g, "");
20668
+ const ESCAPED_SPACE = "\0";
20669
+ const processed = remaining.replace(/\\ /g, ESCAPED_SPACE);
20670
+ for (const token of processed.split(/\s+/)) {
20671
+ const clean = token.replace(new RegExp(ESCAPED_SPACE, "g"), " ").replace(/^["']|["',;:!?]$/g, "").replace(/[.,;:!?]$/, "");
20672
+ if (clean && isImagePath(clean) && existsSync4(clean) && !paths.includes(clean)) {
20673
+ paths.push(clean);
20674
+ }
20675
+ }
20676
+ return paths;
20677
+ }
20678
+ var MAX_GITIGNORE_SIZE, CONTEXT_LIMIT, AUTO_COMPACT_THRESHOLD, MAX_EVENTS, DEFAULT_AUTO_FRESH_SUGGESTION_TURNS, MAX_IMAGES_PER_MESSAGE, FEEDBACK_WORKER_URL, nextKey, mkKey, nextAssistantId, mkAssistantId;
20679
+ var init_app_helpers = __esm({
20680
+ "src/ui/app-helpers.ts"() {
20681
+ "use strict";
20682
+ init_system_prompt();
20683
+ init_image();
20684
+ MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
20685
+ CONTEXT_LIMIT = 262e3;
20686
+ AUTO_COMPACT_THRESHOLD = 0.8;
20687
+ MAX_EVENTS = 500;
20688
+ DEFAULT_AUTO_FRESH_SUGGESTION_TURNS = 30;
20689
+ MAX_IMAGES_PER_MESSAGE = 10;
20690
+ FEEDBACK_WORKER_URL = "https://hello.kimiflare.com";
20691
+ nextKey = 1;
20692
+ mkKey = () => `evt_${nextKey++}`;
20693
+ nextAssistantId = 1;
20694
+ mkAssistantId = () => nextAssistantId++;
20695
+ }
20696
+ });
20697
+
20408
20698
  // src/ui/onboarding.tsx
20409
20699
  import { useState as useState14, useCallback as useCallback3, useEffect as useEffect8 } from "react";
20410
20700
  import { Box as Box20, Text as Text20, useInput as useInput10 } from "ink";
@@ -20444,6 +20734,14 @@ function Onboarding({ onDone, onCancel }) {
20444
20734
  [onCancel]
20445
20735
  )
20446
20736
  );
20737
+ useInput10(
20738
+ (_input, key) => {
20739
+ if (step !== "cloudAuth") return;
20740
+ if (key.return && cloudAuthStatus?.url) {
20741
+ openBrowser(cloudAuthStatus.url);
20742
+ }
20743
+ }
20744
+ );
20447
20745
  useInput10(
20448
20746
  (_input, key) => {
20449
20747
  if (step !== "mode") return;
@@ -20846,7 +21144,11 @@ function Onboarding({ onDone, onCancel }) {
20846
21144
  step === "cloudAuth" && /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", marginTop: 1, children: [
20847
21145
  /* @__PURE__ */ jsx21(Text20, { bold: true, color: theme.accent, children: "Kimiflare Cloud Authentication" }),
20848
21146
  cloudAuthStatus ? /* @__PURE__ */ jsxs19(Fragment, { children: [
20849
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "1. Open this URL in your browser:" }),
21147
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
21148
+ "1. Press ",
21149
+ /* @__PURE__ */ jsx21(Text20, { bold: true, color: theme.accent, children: "Enter" }),
21150
+ " to open this URL in your browser:"
21151
+ ] }),
20850
21152
  /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: cloudAuthStatus.url }),
20851
21153
  /* @__PURE__ */ jsx21(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "2. Sign in with GitHub or Email" }) }),
20852
21154
  /* @__PURE__ */ jsx21(Box20, { marginTop: 1, children: /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
@@ -20900,7 +21202,7 @@ function Onboarding({ onDone, onCancel }) {
20900
21202
  "\u2022".repeat(apiToken.length)
20901
21203
  ] })
20902
21204
  ] }),
20903
- /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
21205
+ !cloudMode && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
20904
21206
  "Model: ",
20905
21207
  model
20906
21208
  ] }),
@@ -20959,6 +21261,7 @@ var init_onboarding = __esm({
20959
21261
  init_key_entry_modal();
20960
21262
  init_registry();
20961
21263
  init_config();
21264
+ init_app_helpers();
20962
21265
  init_theme_context();
20963
21266
  init_ai_gateway_api();
20964
21267
  }
@@ -21082,13 +21385,13 @@ var init_frontmatter = __esm({
21082
21385
  // src/commands/loader.ts
21083
21386
  import { open, realpath as realpath2 } from "fs/promises";
21084
21387
  import { homedir as homedir17 } from "os";
21085
- import { join as join26, relative as relative6, sep as sep2 } from "path";
21388
+ import { join as join27, relative as relative6, sep as sep2 } from "path";
21086
21389
  function projectCommandsDir(cwd = process.cwd()) {
21087
- return join26(cwd, ".kimiflare", "commands");
21390
+ return join27(cwd, ".kimiflare", "commands");
21088
21391
  }
21089
21392
  function globalCommandsDir() {
21090
- const xdg = process.env.XDG_CONFIG_HOME || join26(homedir17(), ".config");
21091
- return join26(xdg, "kimiflare", "commands");
21393
+ const xdg = process.env.XDG_CONFIG_HOME || join27(homedir17(), ".config");
21394
+ return join27(xdg, "kimiflare", "commands");
21092
21395
  }
21093
21396
  async function loadCustomCommands(cwd = process.cwd()) {
21094
21397
  const warnings = [];
@@ -22340,10 +22643,10 @@ var init_wcag = __esm({
22340
22643
 
22341
22644
  // src/ui/theme-loader.ts
22342
22645
  import { readFile as readFile19, readdir as readdir6 } from "fs/promises";
22343
- import { join as join27 } from "path";
22646
+ import { join as join28 } from "path";
22344
22647
  import { homedir as homedir18 } from "os";
22345
22648
  function projectThemesDir(cwd = process.cwd()) {
22346
- return join27(cwd, ".kimiflare", "themes");
22649
+ return join28(cwd, ".kimiflare", "themes");
22347
22650
  }
22348
22651
  function isHexColor(c) {
22349
22652
  return /^#[0-9a-fA-F]{6}$/.test(c);
@@ -22432,7 +22735,7 @@ async function loadThemesFromDir(dir, source) {
22432
22735
  return { themes, errors };
22433
22736
  }
22434
22737
  for (const file of files.filter((f) => f.endsWith(".json"))) {
22435
- const path = join27(dir, file);
22738
+ const path = join28(dir, file);
22436
22739
  let raw;
22437
22740
  try {
22438
22741
  raw = await readFile19(path, "utf-8");
@@ -22581,8 +22884,8 @@ var init_theme_loader = __esm({
22581
22884
  "use strict";
22582
22885
  init_wcag();
22583
22886
  init_theme();
22584
- USER_THEMES_DIR = join27(
22585
- process.env.XDG_CONFIG_HOME || join27(homedir18(), ".config"),
22887
+ USER_THEMES_DIR = join28(
22888
+ process.env.XDG_CONFIG_HOME || join28(homedir18(), ".config"),
22586
22889
  "kimiflare",
22587
22890
  "themes"
22588
22891
  );
@@ -23673,7 +23976,7 @@ var init_command_list = __esm({
23673
23976
  import { useState as useState18 } from "react";
23674
23977
  import { Box as Box28, Text as Text28 } from "ink";
23675
23978
  import SelectInput10 from "ink-select-input";
23676
- import { spawn as spawn4 } from "child_process";
23979
+ import { spawn as spawn5 } from "child_process";
23677
23980
  import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
23678
23981
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
23679
23982
  const theme = useTheme();
@@ -23687,7 +23990,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
23687
23990
  const runInstall = (command) => {
23688
23991
  setInstallState({ status: "running", output: "Installing..." });
23689
23992
  const { shell, args } = getShellCommand();
23690
- const child = spawn4(shell, [...args, command], {
23993
+ const child = spawn5(shell, [...args, command], {
23691
23994
  env: process.env
23692
23995
  });
23693
23996
  let stdout = "";
@@ -24803,7 +25106,7 @@ function formatSessionLine(s) {
24803
25106
  const ago = formatAgo(new Date(s.updatedAt));
24804
25107
  const prompt = s.prompt.slice(0, 30) + (s.prompt.length > 30 ? "\u2026" : "");
24805
25108
  const outcome = s.prUrl ? `PR ${s.prUrl.split("/").pop()}` : s.status;
24806
- const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens4(s.tokensUsed)}/${formatTokens4(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens4(s.tokensUsed)})` : "";
25109
+ const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens5(s.tokensUsed)}/${formatTokens5(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens5(s.tokensUsed)})` : "";
24807
25110
  return `${icon} ${prompt} \u2192 ${outcome} ${ago}${cost}`;
24808
25111
  }
24809
25112
  function formatAgo(date) {
@@ -24816,7 +25119,7 @@ function formatAgo(date) {
24816
25119
  if (minutes > 0) return `${minutes}m ago`;
24817
25120
  return "just now";
24818
25121
  }
24819
- function formatTokens4(n) {
25122
+ function formatTokens5(n) {
24820
25123
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
24821
25124
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
24822
25125
  return String(n);
@@ -24877,8 +25180,8 @@ function RemoteSessionDetail({
24877
25180
  ] }),
24878
25181
  session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs35(Text36, { children: [
24879
25182
  "Tokens: ",
24880
- formatTokens4(session.tokensUsed),
24881
- session.tokensBudget ? ` / ${formatTokens4(session.tokensBudget)}` : ""
25183
+ formatTokens5(session.tokensUsed),
25184
+ session.tokensBudget ? ` / ${formatTokens5(session.tokensBudget)}` : ""
24882
25185
  ] }),
24883
25186
  /* @__PURE__ */ jsxs35(Text36, { children: [
24884
25187
  "Created: ",
@@ -24922,7 +25225,7 @@ function InboxModal({ onDone, onOpen }) {
24922
25225
  setError(null);
24923
25226
  try {
24924
25227
  const res = await fetch(
24925
- `${FEEDBACK_WORKER_URL}/inbox/check?u=${encodeURIComponent(u)}&s=${encodeURIComponent(s)}`
25228
+ `${FEEDBACK_WORKER_URL2}/inbox/check?u=${encodeURIComponent(u)}&s=${encodeURIComponent(s)}`
24926
25229
  );
24927
25230
  if (!res.ok) {
24928
25231
  throw new Error(`Server returned ${res.status}`);
@@ -24968,7 +25271,7 @@ function InboxModal({ onDone, onOpen }) {
24968
25271
  if (messages.length === 0) return;
24969
25272
  const msg = messages[selectedIndex];
24970
25273
  if (!msg) return;
24971
- const url = `${FEEDBACK_WORKER_URL}/inbox?u=${encodeURIComponent(twitter)}&s=${encodeURIComponent(secret)}&m=${encodeURIComponent(msg.id)}`;
25274
+ const url = `${FEEDBACK_WORKER_URL2}/inbox?u=${encodeURIComponent(twitter)}&s=${encodeURIComponent(secret)}&m=${encodeURIComponent(msg.id)}`;
24972
25275
  onOpen(url);
24973
25276
  onDone();
24974
25277
  }, [messages, selectedIndex, twitter, secret, onOpen, onDone]);
@@ -25067,21 +25370,21 @@ function InboxModal({ onDone, onOpen }) {
25067
25370
  ] })
25068
25371
  ] });
25069
25372
  }
25070
- var FEEDBACK_WORKER_URL;
25373
+ var FEEDBACK_WORKER_URL2;
25071
25374
  var init_inbox_modal = __esm({
25072
25375
  "src/ui/inbox-modal.tsx"() {
25073
25376
  "use strict";
25074
25377
  init_text_input();
25075
25378
  init_theme_context();
25076
- FEEDBACK_WORKER_URL = "https://hello.kimiflare.com";
25379
+ FEEDBACK_WORKER_URL2 = "https://hello.kimiflare.com";
25077
25380
  }
25078
25381
  });
25079
25382
 
25080
25383
  // src/remote/deploy-commute.ts
25081
- import { spawn as spawn5 } from "child_process";
25384
+ import { spawn as spawn6 } from "child_process";
25082
25385
  import { mkdtemp, readFile as readFile20, writeFile as writeFile12, rm } from "fs/promises";
25083
25386
  import { tmpdir as tmpdir3 } from "os";
25084
- import { join as join28 } from "path";
25387
+ import { join as join29 } from "path";
25085
25388
  import { randomBytes as randomBytes2 } from "crypto";
25086
25389
  async function cfApiFetch(accountId, apiToken, path, init) {
25087
25390
  const url = `${CF_API2}/accounts/${encodeURIComponent(accountId)}${path}`;
@@ -25152,7 +25455,7 @@ function generateSecret2() {
25152
25455
  }
25153
25456
  function runCmd(cmd, args, opts2 = {}) {
25154
25457
  return new Promise((resolve8) => {
25155
- const child = spawn5(cmd, args, {
25458
+ const child = spawn6(cmd, args, {
25156
25459
  cwd: opts2.cwd,
25157
25460
  env: { ...process.env, ...opts2.env ?? {} },
25158
25461
  stdio: [opts2.input ? "pipe" : "ignore", "pipe", "pipe"]
@@ -25312,8 +25615,8 @@ ${wranglerInstall.stderr.slice(-600)}`,
25312
25615
  ok: true
25313
25616
  };
25314
25617
  yield { message: "Prerequisites ready", ok: true };
25315
- const tmpRoot = await mkdtemp(join28(tmpdir3(), "kimiflare-commute-"));
25316
- const repoDir = join28(tmpRoot, "kimiflare-commute");
25618
+ const tmpRoot = await mkdtemp(join29(tmpdir3(), "kimiflare-commute-"));
25619
+ const repoDir = join29(tmpRoot, "kimiflare-commute");
25317
25620
  yield { message: `Fetching worker source from GitHub (${COMMUTE_REPO})\u2026` };
25318
25621
  const clone = await runCmd("git", ["clone", "--depth", "1", "--branch", COMMUTE_BRANCH, COMMUTE_REPO, repoDir], { timeoutMs: 6e4 });
25319
25622
  if (clone.code !== 0) {
@@ -25322,8 +25625,8 @@ ${(clone.stderr || clone.stdout).slice(0, 400)}`, error: true };
25322
25625
  throw new Error("clone failed");
25323
25626
  }
25324
25627
  yield { message: "Source fetched from GitHub", ok: true };
25325
- const workerDir = join28(repoDir, "remote", "worker");
25326
- const wranglerToml = join28(workerDir, "wrangler.toml");
25628
+ const workerDir = join29(repoDir, "remote", "worker");
25629
+ const wranglerToml = join29(workerDir, "wrangler.toml");
25327
25630
  yield { message: "Installing Worker dependencies (npm install)\u2026" };
25328
25631
  const install = await runCmd("npm", ["install", "--no-audit", "--no-fund", "--loglevel=error"], {
25329
25632
  cwd: workerDir,
@@ -25638,287 +25941,6 @@ var init_deploy_commute = __esm({
25638
25941
  }
25639
25942
  });
25640
25943
 
25641
- // src/ui/app-helpers.ts
25642
- var app_helpers_exports = {};
25643
- __export(app_helpers_exports, {
25644
- AUTO_COMPACT_THRESHOLD: () => AUTO_COMPACT_THRESHOLD,
25645
- CONTEXT_LIMIT: () => CONTEXT_LIMIT,
25646
- DEFAULT_AUTO_FRESH_SUGGESTION_TURNS: () => DEFAULT_AUTO_FRESH_SUGGESTION_TURNS,
25647
- FEEDBACK_WORKER_URL: () => FEEDBACK_WORKER_URL2,
25648
- MAX_EVENTS: () => MAX_EVENTS,
25649
- MAX_IMAGES_PER_MESSAGE: () => MAX_IMAGES_PER_MESSAGE,
25650
- buildFilePickerIgnoreList: () => buildFilePickerIgnoreList,
25651
- capEvents: () => capEvents,
25652
- compactEventsVisual: () => compactEventsVisual,
25653
- detectGitBranch: () => detectGitBranch,
25654
- detectGitHubRepo: () => detectGitHubRepo,
25655
- findImagePaths: () => findImagePaths,
25656
- formatTokens: () => formatTokens5,
25657
- gatewayFromConfig: () => gatewayFromConfig,
25658
- gatewayUsageLookupFromConfig: () => gatewayUsageLookupFromConfig,
25659
- makePrefixMessages: () => makePrefixMessages,
25660
- mkAssistantId: () => mkAssistantId,
25661
- mkKey: () => mkKey,
25662
- openBrowser: () => openBrowser,
25663
- rebuildSystemPromptForMode: () => rebuildSystemPromptForMode,
25664
- trackRecentFile: () => trackRecentFile
25665
- });
25666
- import { execSync as execSync3, spawn as spawn6 } from "child_process";
25667
- import { existsSync as existsSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
25668
- import { join as join29 } from "path";
25669
- import { platform as platform4 } from "os";
25670
- function buildFilePickerIgnoreList(cwd) {
25671
- const hardcoded = [
25672
- // Dependencies
25673
- "**/node_modules/**",
25674
- "**/vendor/**",
25675
- "**/.bundle/**",
25676
- "**/bower_components/**",
25677
- // Version control
25678
- "**/.git/**",
25679
- "**/.svn/**",
25680
- "**/.hg/**",
25681
- // Build / output directories
25682
- "**/dist/**",
25683
- "**/build/**",
25684
- "**/out/**",
25685
- "**/public/**",
25686
- "**/.next/**",
25687
- "**/.nuxt/**",
25688
- "**/.svelte-kit/**",
25689
- "**/.vercel/**",
25690
- "**/.netlify/**",
25691
- "**/target/**",
25692
- "**/bin/**",
25693
- "**/obj/**",
25694
- "**/Debug/**",
25695
- "**/Release/**",
25696
- "**/.gradle/**",
25697
- // Caches
25698
- "**/.cache/**",
25699
- "**/.parcel-cache/**",
25700
- "**/.turbo/**",
25701
- "**/.eslintcache",
25702
- "**/.stylelintcache",
25703
- "**/.rpt2_cache/**",
25704
- "**/.rts2_cache/**",
25705
- // Temporary
25706
- "**/tmp/**",
25707
- "**/temp/**",
25708
- "**/*.tmp",
25709
- // Coverage
25710
- "**/coverage/**",
25711
- "**/.nyc_output/**",
25712
- // OS files
25713
- "**/.DS_Store",
25714
- "**/Thumbs.db",
25715
- // Logs
25716
- "**/*.log",
25717
- "**/logs/**",
25718
- // Lock files (auto-generated, usually huge)
25719
- "**/package-lock.json",
25720
- "**/yarn.lock",
25721
- "**/pnpm-lock.yaml",
25722
- "**/bun.lockb",
25723
- "**/Cargo.lock",
25724
- "**/Gemfile.lock",
25725
- "**/composer.lock",
25726
- "**/Pipfile.lock",
25727
- "**/poetry.lock",
25728
- "**/go.sum",
25729
- // Minified / source maps
25730
- "**/*.min.js",
25731
- "**/*.min.css",
25732
- "**/*.map",
25733
- // kimiflare internal
25734
- "**/.kimiflare/**",
25735
- // IDE (usually not relevant to mention)
25736
- "**/.idea/**"
25737
- ];
25738
- const gitignorePatterns = [];
25739
- try {
25740
- const gitignorePath = join29(cwd, ".gitignore");
25741
- const stats = statSync4(gitignorePath);
25742
- if (stats.size > MAX_GITIGNORE_SIZE) {
25743
- return hardcoded;
25744
- }
25745
- const content = readFileSync4(gitignorePath, "utf-8");
25746
- for (const line of content.split(/\r?\n/)) {
25747
- const trimmed = line.trim();
25748
- if (!trimmed || trimmed.startsWith("#")) continue;
25749
- if (trimmed.startsWith("!")) continue;
25750
- let pattern = trimmed;
25751
- const isAnchored = pattern.startsWith("/");
25752
- const isDir = pattern.endsWith("/");
25753
- if (isAnchored) pattern = pattern.slice(1);
25754
- if (isDir) pattern = pattern.slice(0, -1);
25755
- if (!pattern) continue;
25756
- if (isAnchored) {
25757
- gitignorePatterns.push(isDir ? pattern + "/**" : pattern);
25758
- } else {
25759
- gitignorePatterns.push(isDir ? "**/" + pattern + "/**" : "**/" + pattern);
25760
- }
25761
- }
25762
- } catch {
25763
- }
25764
- return [...hardcoded, ...gitignorePatterns];
25765
- }
25766
- function gatewayFromConfig(cfg) {
25767
- if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
25768
- if (!cfg.aiGatewayId) return void 0;
25769
- return {
25770
- id: cfg.aiGatewayId,
25771
- cacheTtl: cfg.aiGatewayCacheTtl,
25772
- skipCache: cfg.aiGatewaySkipCache,
25773
- collectLogPayload: cfg.aiGatewayCollectLogPayload,
25774
- metadata: cfg.aiGatewayMetadata
25775
- };
25776
- }
25777
- function gatewayUsageLookupFromConfig(cfg, meta) {
25778
- if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
25779
- if (!cfg.aiGatewayId || !meta) return void 0;
25780
- return {
25781
- accountId: cfg.accountId,
25782
- apiToken: cfg.apiToken,
25783
- gatewayId: cfg.aiGatewayId,
25784
- meta
25785
- };
25786
- }
25787
- function openBrowser(url) {
25788
- const cmd = platform4() === "darwin" ? "open" : platform4() === "win32" ? "start" : "xdg-open";
25789
- const child = spawn6(cmd, [url], { detached: true, stdio: "ignore" });
25790
- child.unref();
25791
- }
25792
- function detectGitHubRepo(cachedRepo) {
25793
- if (cachedRepo) {
25794
- const parts = cachedRepo.split("/");
25795
- if (parts.length === 2) return { owner: parts[0], name: parts[1] };
25796
- }
25797
- try {
25798
- const remoteUrl = execSync3("git remote get-url origin", { cwd: process.cwd(), encoding: "utf8" }).trim().replace(/\/+$/, "");
25799
- const httpsMatch = remoteUrl.match(/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
25800
- if (httpsMatch) return { owner: httpsMatch[1], name: httpsMatch[2] };
25801
- const sshMatch = remoteUrl.match(/github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
25802
- if (sshMatch) return { owner: sshMatch[1], name: sshMatch[2] };
25803
- } catch {
25804
- }
25805
- return null;
25806
- }
25807
- function detectGitBranch() {
25808
- try {
25809
- return execSync3("git branch --show-current", { cwd: process.cwd(), encoding: "utf8" }).trim() || null;
25810
- } catch {
25811
- return null;
25812
- }
25813
- }
25814
- function formatTokens5(n) {
25815
- if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
25816
- if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
25817
- return String(n);
25818
- }
25819
- function trackRecentFile(ref, path, max = 10) {
25820
- ref.current.set(path, Date.now());
25821
- if (ref.current.size > max) {
25822
- let oldest = null;
25823
- let oldestTime = Infinity;
25824
- for (const [p, t] of ref.current) {
25825
- if (t < oldestTime) {
25826
- oldestTime = t;
25827
- oldest = p;
25828
- }
25829
- }
25830
- if (oldest) ref.current.delete(oldest);
25831
- }
25832
- }
25833
- function capEvents(prev) {
25834
- if (prev.length <= MAX_EVENTS) return prev;
25835
- return prev.slice(prev.length - MAX_EVENTS);
25836
- }
25837
- function compactEventsVisual(prev, keepLastTurns) {
25838
- let seen = 0;
25839
- let cutoff = -1;
25840
- for (let i = prev.length - 1; i >= 0; i--) {
25841
- if (prev[i].kind === "user") {
25842
- seen++;
25843
- if (seen === keepLastTurns + 1) {
25844
- cutoff = i;
25845
- break;
25846
- }
25847
- }
25848
- }
25849
- if (cutoff <= 0) return prev;
25850
- const kept = prev.slice(cutoff);
25851
- return [
25852
- { kind: "info", key: mkKey(), text: `\xB7\xB7\xB7 ${cutoff} earlier messages compacted \xB7\xB7\xB7` },
25853
- ...kept
25854
- ];
25855
- }
25856
- function makePrefixMessages(cacheStable, model, mode, tools, preferPullRequests) {
25857
- if (cacheStable) {
25858
- return buildSystemMessages({ cwd: process.cwd(), tools, model, mode, preferPullRequests });
25859
- }
25860
- return [
25861
- {
25862
- role: "system",
25863
- content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode, preferPullRequests })
25864
- }
25865
- ];
25866
- }
25867
- function rebuildSystemPromptForMode(messages, cacheStable, model, mode, tools, preferPullRequests) {
25868
- if (cacheStable) {
25869
- const rebuilt = buildSystemMessages({ cwd: process.cwd(), tools, model, mode, preferPullRequests });
25870
- messages[0] = rebuilt[0];
25871
- if (rebuilt[1]) {
25872
- messages[1] = rebuilt[1];
25873
- }
25874
- } else {
25875
- messages[0] = {
25876
- role: "system",
25877
- content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode, preferPullRequests })
25878
- };
25879
- }
25880
- }
25881
- function findImagePaths(text) {
25882
- const paths = [];
25883
- const quotedRegex = /"([^"]+)"|'([^']+)'/g;
25884
- let match;
25885
- while ((match = quotedRegex.exec(text)) !== null) {
25886
- const path = match[1] ?? match[2];
25887
- if (path && isImagePath(path) && existsSync4(path)) {
25888
- paths.push(path);
25889
- }
25890
- }
25891
- const remaining = text.replace(/"[^"]+"|'[^']+'/g, "");
25892
- const ESCAPED_SPACE = "\0";
25893
- const processed = remaining.replace(/\\ /g, ESCAPED_SPACE);
25894
- for (const token of processed.split(/\s+/)) {
25895
- const clean = token.replace(new RegExp(ESCAPED_SPACE, "g"), " ").replace(/^["']|["',;:!?]$/g, "").replace(/[.,;:!?]$/, "");
25896
- if (clean && isImagePath(clean) && existsSync4(clean) && !paths.includes(clean)) {
25897
- paths.push(clean);
25898
- }
25899
- }
25900
- return paths;
25901
- }
25902
- var MAX_GITIGNORE_SIZE, CONTEXT_LIMIT, AUTO_COMPACT_THRESHOLD, MAX_EVENTS, DEFAULT_AUTO_FRESH_SUGGESTION_TURNS, MAX_IMAGES_PER_MESSAGE, FEEDBACK_WORKER_URL2, nextKey, mkKey, nextAssistantId, mkAssistantId;
25903
- var init_app_helpers = __esm({
25904
- "src/ui/app-helpers.ts"() {
25905
- "use strict";
25906
- init_system_prompt();
25907
- init_image();
25908
- MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
25909
- CONTEXT_LIMIT = 262e3;
25910
- AUTO_COMPACT_THRESHOLD = 0.8;
25911
- MAX_EVENTS = 500;
25912
- DEFAULT_AUTO_FRESH_SUGGESTION_TURNS = 30;
25913
- MAX_IMAGES_PER_MESSAGE = 10;
25914
- FEEDBACK_WORKER_URL2 = "https://hello.kimiflare.com";
25915
- nextKey = 1;
25916
- mkKey = () => `evt_${nextKey++}`;
25917
- nextAssistantId = 1;
25918
- mkAssistantId = () => nextAssistantId++;
25919
- }
25920
- });
25921
-
25922
25944
  // src/ui/multi-agent-modal.tsx
25923
25945
  import { useState as useState22, useCallback as useCallback7 } from "react";
25924
25946
  import { Box as Box38, Text as Text38, useInput as useInput16 } from "ink";
@@ -28858,7 +28880,7 @@ function executeFreshStart(ctx, planText, overrideMode, opts2 = {}) {
28858
28880
  rebuildSystemPromptForMode(
28859
28881
  ctx.messagesRef.current,
28860
28882
  ctx.cacheStableRef.current,
28861
- ctx.cfg?.model ?? "@cf/moonshotai/kimi-k2.6",
28883
+ ctx.cfg?.model ?? (ctx.cfg?.cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL),
28862
28884
  overrideMode ?? ctx.mode,
28863
28885
  [...ALL_TOOLS, ...ctx.mcpToolsRef.current, ...ctx.lspToolsRef.current],
28864
28886
  ctx.cfg?.preferPullRequests
@@ -29115,6 +29137,13 @@ var init_slash_commands = __esm({
29115
29137
  };
29116
29138
  handleModel = (ctx, rest, arg) => {
29117
29139
  const { cfg, setCfg, setEvents, mkKey: mkKey2 } = ctx;
29140
+ if (cfg?.cloudMode) {
29141
+ setEvents((e) => [
29142
+ ...e,
29143
+ { kind: "info", key: mkKey2(), text: "Model selection isn't available on KimiFlare Cloud \u2014 the model is managed for you." }
29144
+ ]);
29145
+ return true;
29146
+ }
29118
29147
  const sub = rest[0]?.toLowerCase() ?? "";
29119
29148
  if (!arg) {
29120
29149
  ctx.setShowModelPicker(true);
@@ -29978,7 +30007,7 @@ project: ${projectSettingsPath(cwd)}`
29978
30007
  handleHello = (ctx) => {
29979
30008
  const { setEvents, mkKey: mkKey2 } = ctx;
29980
30009
  const session = crypto.randomUUID();
29981
- const url = `${FEEDBACK_WORKER_URL2}/?s=${session}&v=${getAppVersion()}`;
30010
+ const url = `${FEEDBACK_WORKER_URL}/?s=${session}&v=${getAppVersion()}`;
29982
30011
  openBrowser(url);
29983
30012
  void (async () => {
29984
30013
  try {
@@ -30185,7 +30214,7 @@ project: ${projectSettingsPath(cwd)}`
30185
30214
  setEvents((e) => [
30186
30215
  ...e,
30187
30216
  { kind: "info", key: mkKey2(), text: `Starting remote session for ${repo.owner}/${repo.name}...` },
30188
- { kind: "info", key: mkKey2(), text: `Budget: ${formatTokens5(budget)} tokens. TTL: ${ttl} min.` }
30217
+ { kind: "info", key: mkKey2(), text: `Budget: ${formatTokens4(budget)} tokens. TTL: ${ttl} min.` }
30189
30218
  ]);
30190
30219
  try {
30191
30220
  const data = await startRemoteSession({
@@ -31489,7 +31518,8 @@ function runStartupTasks(deps) {
31489
31518
  embeddingModel: cfg.memoryEmbeddingModel,
31490
31519
  gateway: gatewayFromConfig(cfg),
31491
31520
  maxAgeDays: cfg.memoryMaxAgeDays ?? RETENTION.memoryMaxAgeDays,
31492
- maxEntries: cfg.memoryMaxEntries ?? RETENTION.memoryMaxEntries
31521
+ maxEntries: cfg.memoryMaxEntries ?? RETENTION.memoryMaxEntries,
31522
+ cloudMode: cfg.cloudMode
31493
31523
  });
31494
31524
  manager.open();
31495
31525
  memoryManagerRef.current = manager;
@@ -32455,7 +32485,8 @@ ${wcagWarnings.join("\n")}` }
32455
32485
  { name: "topup", description: "Buy a one-time token top-up (+50M)", source: "builtin" },
32456
32486
  { name: "manage", description: "Manage membership, billing & invoices", source: "builtin" }
32457
32487
  ] : [];
32458
- return [...BUILTIN_COMMANDS, ...cloudCommands, ...customs];
32488
+ const builtins = cfg?.cloudMode ? BUILTIN_COMMANDS.filter((c) => c.name !== "model") : BUILTIN_COMMANDS;
32489
+ return [...builtins, ...cloudCommands, ...customs];
32459
32490
  }, [customCommandsVersion, cfg?.cloudMode]);
32460
32491
  const modalActive = commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || resumeSessions !== null || checkpointSession !== null || resuming || perm !== null || limitModal !== null || loopModal !== null || showInboxModal || showHelpMenu || showModePicker || showMemoryPicker || showGatewayPicker || showSkillsPicker || showShellPicker;
32461
32492
  const loadFilePickerItems = useCallback10(async () => {
@@ -34964,6 +34995,7 @@ init_errors();
34964
34995
  init_lsp_config();
34965
34996
  init_update_check();
34966
34997
  init_version();
34998
+ import { readFileSync as readFileSync5 } from "fs";
34967
34999
  import { Command as Command2 } from "commander";
34968
35000
 
34969
35001
  // src/remote/cli.ts
@@ -35090,11 +35122,12 @@ var LOGO_ART = `\x1B[49m \x1B[m
35090
35122
  \x1B[49m \x1B[m
35091
35123
  `;
35092
35124
  var LOGO_WIDTH = 48;
35093
- function buildTextLines(version) {
35125
+ function buildTextLines(version, cloudMode) {
35094
35126
  const accent = "\x1B[38;2;255;153;0m";
35095
35127
  const dim = "\x1B[2m";
35096
35128
  const reset = "\x1B[0m";
35097
35129
  const bold = "\x1B[1m";
35130
+ const modelLabel = cloudMode ? "Kimi-K2.7" : "Kimi-K2.6";
35098
35131
  return [
35099
35132
  "",
35100
35133
  "",
@@ -35105,7 +35138,7 @@ function buildTextLines(version) {
35105
35138
  ` ${bold}${accent}Kimiflare${reset}`,
35106
35139
  "",
35107
35140
  ` ${dim}Terminal coding agent${reset}`,
35108
- ` ${dim}powered by Kimi-K2.6${reset}`,
35141
+ ` ${dim}powered by ${modelLabel}${reset}`,
35109
35142
  "",
35110
35143
  ` ${dim}v${version}${reset}`,
35111
35144
  "",
@@ -35129,9 +35162,9 @@ function padVisual(str, width) {
35129
35162
  const visualLen = stripAnsi(str).length;
35130
35163
  return str + " ".repeat(Math.max(0, width - visualLen));
35131
35164
  }
35132
- function renderLogo(version) {
35165
+ function renderLogo(version, cloudMode) {
35133
35166
  const logoLines = LOGO_ART.split("\n");
35134
- const textLines = buildTextLines(version);
35167
+ const textLines = buildTextLines(version, cloudMode);
35135
35168
  const out = [];
35136
35169
  for (let i = 0; i < logoLines.length; i++) {
35137
35170
  const logoLine = padVisual(logoLines[i], LOGO_WIDTH);
@@ -35488,8 +35521,20 @@ async function runPrintMode(opts2) {
35488
35521
  }
35489
35522
 
35490
35523
  // src/index.tsx
35524
+ function isCloudModeConfigured() {
35525
+ if (process.env.KIMIFLARE_CLOUD === "1" || process.env.KIMIFLARE_CLOUD === "true") return true;
35526
+ try {
35527
+ const raw = readFileSync5(configPath(), "utf8");
35528
+ const parsed = JSON.parse(raw);
35529
+ return parsed.cloudMode === true;
35530
+ } catch {
35531
+ return false;
35532
+ }
35533
+ }
35534
+ var helpDefaultModel = isCloudModeConfigured() ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL;
35535
+ var helpModelName = helpDefaultModel === DEFAULT_CLOUD_MODEL ? "Kimi-K2.7" : "Kimi-K2.6";
35491
35536
  var program = new Command2();
35492
- program.name("kimiflare").description("Terminal coding agent powered by Kimi-K2.6 on Cloudflare Workers AI.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", "model id (defaults to @cf/moonshotai/kimi-k2.6)").option("--cloud", "use Kimiflare Cloud (api.kimiflare.com) instead of direct Workers AI").option("--dangerously-allow-all", "auto-approve every permission prompt (print mode only)").option("--reasoning", "include reasoning in stdout (print mode only)").option("--thinking", "alias for --reasoning").option("--continue-on-limit", "reset tool-call counter and continue when the 200-call limit is hit (print mode only)").option("--max-input-tokens <n>", "cumulative prompt token budget; exits 42 when exhausted (print mode only)", (v) => parseInt(v, 10)).option("--emit-events", "emit Camouflage NDJSON events to stdout; requires -p (for initial prompt)").option("--multi-turn", "with --emit-events: keep reading stdin for UserInputSubmitted follow-ups after the initial turn").option("--ui <name>", "render UI with React Ink (the only supported engine). This flag and KIMIFLARE_UI are currently ignored.").option("--mode <mode>", "run mode: interactive (default), print, rpc").option("-c, --continue", "continue the most recent session in the current working directory (print mode only)").option("-S, --session <id>", "resume a specific session by id (print mode only)").option("-f, --file <path>", "attach file(s) to the prompt; repeatable, supports globs (print mode only)", (v, prev) => (prev ?? []).concat(v)).option("--format <mode>", "output format for print mode: text (default), json, stream-json").option("--dir <path>", "run in the specified directory instead of the current one (print mode only)").option("--title <title>", "override the auto-generated session title (print mode only)").option("--attach <url>", "attach to a running kimiflare serve instance (print mode only)");
35537
+ program.name("kimiflare").description(`Terminal coding agent powered by ${helpModelName} on Cloudflare Workers AI.`).version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", `model id (defaults to ${helpDefaultModel})`).option("--cloud", "use Kimiflare Cloud (api.kimiflare.com) instead of direct Workers AI").option("--dangerously-allow-all", "auto-approve every permission prompt (print mode only)").option("--reasoning", "include reasoning in stdout (print mode only)").option("--thinking", "alias for --reasoning").option("--continue-on-limit", "reset tool-call counter and continue when the 200-call limit is hit (print mode only)").option("--max-input-tokens <n>", "cumulative prompt token budget; exits 42 when exhausted (print mode only)", (v) => parseInt(v, 10)).option("--emit-events", "emit Camouflage NDJSON events to stdout; requires -p (for initial prompt)").option("--multi-turn", "with --emit-events: keep reading stdin for UserInputSubmitted follow-ups after the initial turn").option("--ui <name>", "render UI with React Ink (the only supported engine). This flag and KIMIFLARE_UI are currently ignored.").option("--mode <mode>", "run mode: interactive (default), print, rpc").option("-c, --continue", "continue the most recent session in the current working directory (print mode only)").option("-S, --session <id>", "resume a specific session by id (print mode only)").option("-f, --file <path>", "attach file(s) to the prompt; repeatable, supports globs (print mode only)", (v, prev) => (prev ?? []).concat(v)).option("--format <mode>", "output format for print mode: text (default), json, stream-json").option("--dir <path>", "run in the specified directory instead of the current one (print mode only)").option("--title <title>", "override the auto-generated session title (print mode only)").option("--attach <url>", "attach to a running kimiflare serve instance (print mode only)");
35493
35538
  program.command("cost").description("Show cost attribution by task type (requires costAttribution enabled)").option("-w, --week", "last 7 days (default)").option("-m, --month", "last 30 days").option("-d, --day", "today only").option("-s, --session <id>", "single session detail").option("-c, --category <name>", "filter by category").option("--json", "machine-readable output").option("--reclassify", "re-run classification on all sessions").option("--local-only", "skip Cloudflare reconciliation").action(async (cmdOpts) => {
35494
35539
  const cfg = await loadConfig();
35495
35540
  const enabled = cfg?.costAttribution ?? false;
@@ -35661,7 +35706,7 @@ async function main() {
35661
35706
  }
35662
35707
  }
35663
35708
  cfg = {
35664
- ...cfg ?? { accountId: "", apiToken: "", model: DEFAULT_MODEL, memoryEnabled: false },
35709
+ ...cfg ?? { accountId: "", apiToken: "", model: DEFAULT_CLOUD_MODEL, memoryEnabled: false },
35665
35710
  cloudMode: true
35666
35711
  };
35667
35712
  }
@@ -35681,7 +35726,7 @@ async function main() {
35681
35726
  console.error("kimiflare: --emit-events requires credentials.");
35682
35727
  process.exit(2);
35683
35728
  }
35684
- const model = opts.model ?? cfg.model ?? DEFAULT_MODEL;
35729
+ const model = opts.model ?? cfg.model ?? (cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL);
35685
35730
  const { runEmitMode: runEmitMode2 } = await Promise.resolve().then(() => (init_emit_mode(), emit_mode_exports));
35686
35731
  await runEmitMode2({
35687
35732
  accountId: cfg.accountId,
@@ -35700,13 +35745,18 @@ async function main() {
35700
35745
  return;
35701
35746
  }
35702
35747
  if (opts.print !== void 0) {
35748
+ const exampleModel = cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL;
35703
35749
  if (!cfg) {
35704
35750
  console.error(
35705
- 'kimiflare: missing credentials.\nSet CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, or write them to\n ~/.config/kimiflare/config.json (chmod 600)\n { "accountId": "...", "apiToken": "...", "model": "@cf/moonshotai/kimi-k2.6" }\nOr use cloud mode: kimiflare --cloud -p "..."'
35751
+ `kimiflare: missing credentials.
35752
+ Set CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, or write them to
35753
+ ~/.config/kimiflare/config.json (chmod 600)
35754
+ { "accountId": "...", "apiToken": "...", "model": "${exampleModel}" }
35755
+ Or use cloud mode: kimiflare --cloud -p "..."`
35706
35756
  );
35707
35757
  process.exit(2);
35708
35758
  }
35709
- const model = opts.model ?? cfg.model ?? DEFAULT_MODEL;
35759
+ const model = opts.model ?? cfg.model ?? (cloudMode ? DEFAULT_CLOUD_MODEL : DEFAULT_MODEL);
35710
35760
  const format = opts.format ?? "text";
35711
35761
  if (format !== "text" && format !== "json" && format !== "stream-json") {
35712
35762
  console.error(`kimiflare: invalid --format "${format}". Use: text, json, stream-json`);
@@ -35754,7 +35804,7 @@ async function main() {
35754
35804
  );
35755
35805
  process.exit(2);
35756
35806
  }
35757
- const logoText = renderLogo(getAppVersion());
35807
+ const logoText = renderLogo(getAppVersion(), cloudMode);
35758
35808
  const uiEngine = "ink";
35759
35809
  console.log(logoText);
35760
35810
  const { renderApp: renderApp2 } = await Promise.resolve().then(() => (init_app(), app_exports));