kimiflare 0.94.0 → 0.95.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
@@ -17616,7 +17616,7 @@ function StatusBar({ usage, sessionUsage, thinking, turnStartedAt, mode, context
17616
17616
  const elapsed = turnStartedAt !== null ? formatElapsed3(Math.max(0, now2 - turnStartedAt)) : null;
17617
17617
  const idleParts = [];
17618
17618
  if (gitBranch) idleParts.push(gitBranch);
17619
- if (model) idleParts.push(shortenModelId(model));
17619
+ if (model && !cloudMode) idleParts.push(shortenModelId(model));
17620
17620
  if (cloudMode) idleParts.push("CLOUD");
17621
17621
  if (codeMode) idleParts.push("CODE");
17622
17622
  const metaParts = [];
@@ -20405,6 +20405,287 @@ var init_key_entry_modal = __esm({
20405
20405
  }
20406
20406
  });
20407
20407
 
20408
+ // src/ui/app-helpers.ts
20409
+ var app_helpers_exports = {};
20410
+ __export(app_helpers_exports, {
20411
+ AUTO_COMPACT_THRESHOLD: () => AUTO_COMPACT_THRESHOLD,
20412
+ CONTEXT_LIMIT: () => CONTEXT_LIMIT,
20413
+ DEFAULT_AUTO_FRESH_SUGGESTION_TURNS: () => DEFAULT_AUTO_FRESH_SUGGESTION_TURNS,
20414
+ FEEDBACK_WORKER_URL: () => FEEDBACK_WORKER_URL,
20415
+ MAX_EVENTS: () => MAX_EVENTS,
20416
+ MAX_IMAGES_PER_MESSAGE: () => MAX_IMAGES_PER_MESSAGE,
20417
+ buildFilePickerIgnoreList: () => buildFilePickerIgnoreList,
20418
+ capEvents: () => capEvents,
20419
+ compactEventsVisual: () => compactEventsVisual,
20420
+ detectGitBranch: () => detectGitBranch,
20421
+ detectGitHubRepo: () => detectGitHubRepo,
20422
+ findImagePaths: () => findImagePaths,
20423
+ formatTokens: () => formatTokens4,
20424
+ gatewayFromConfig: () => gatewayFromConfig,
20425
+ gatewayUsageLookupFromConfig: () => gatewayUsageLookupFromConfig,
20426
+ makePrefixMessages: () => makePrefixMessages,
20427
+ mkAssistantId: () => mkAssistantId,
20428
+ mkKey: () => mkKey,
20429
+ openBrowser: () => openBrowser,
20430
+ rebuildSystemPromptForMode: () => rebuildSystemPromptForMode,
20431
+ trackRecentFile: () => trackRecentFile
20432
+ });
20433
+ import { execSync as execSync3, spawn as spawn4 } from "child_process";
20434
+ import { existsSync as existsSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
20435
+ import { join as join26 } from "path";
20436
+ import { platform as platform4 } from "os";
20437
+ function buildFilePickerIgnoreList(cwd) {
20438
+ const hardcoded = [
20439
+ // Dependencies
20440
+ "**/node_modules/**",
20441
+ "**/vendor/**",
20442
+ "**/.bundle/**",
20443
+ "**/bower_components/**",
20444
+ // Version control
20445
+ "**/.git/**",
20446
+ "**/.svn/**",
20447
+ "**/.hg/**",
20448
+ // Build / output directories
20449
+ "**/dist/**",
20450
+ "**/build/**",
20451
+ "**/out/**",
20452
+ "**/public/**",
20453
+ "**/.next/**",
20454
+ "**/.nuxt/**",
20455
+ "**/.svelte-kit/**",
20456
+ "**/.vercel/**",
20457
+ "**/.netlify/**",
20458
+ "**/target/**",
20459
+ "**/bin/**",
20460
+ "**/obj/**",
20461
+ "**/Debug/**",
20462
+ "**/Release/**",
20463
+ "**/.gradle/**",
20464
+ // Caches
20465
+ "**/.cache/**",
20466
+ "**/.parcel-cache/**",
20467
+ "**/.turbo/**",
20468
+ "**/.eslintcache",
20469
+ "**/.stylelintcache",
20470
+ "**/.rpt2_cache/**",
20471
+ "**/.rts2_cache/**",
20472
+ // Temporary
20473
+ "**/tmp/**",
20474
+ "**/temp/**",
20475
+ "**/*.tmp",
20476
+ // Coverage
20477
+ "**/coverage/**",
20478
+ "**/.nyc_output/**",
20479
+ // OS files
20480
+ "**/.DS_Store",
20481
+ "**/Thumbs.db",
20482
+ // Logs
20483
+ "**/*.log",
20484
+ "**/logs/**",
20485
+ // Lock files (auto-generated, usually huge)
20486
+ "**/package-lock.json",
20487
+ "**/yarn.lock",
20488
+ "**/pnpm-lock.yaml",
20489
+ "**/bun.lockb",
20490
+ "**/Cargo.lock",
20491
+ "**/Gemfile.lock",
20492
+ "**/composer.lock",
20493
+ "**/Pipfile.lock",
20494
+ "**/poetry.lock",
20495
+ "**/go.sum",
20496
+ // Minified / source maps
20497
+ "**/*.min.js",
20498
+ "**/*.min.css",
20499
+ "**/*.map",
20500
+ // kimiflare internal
20501
+ "**/.kimiflare/**",
20502
+ // IDE (usually not relevant to mention)
20503
+ "**/.idea/**"
20504
+ ];
20505
+ const gitignorePatterns = [];
20506
+ try {
20507
+ const gitignorePath = join26(cwd, ".gitignore");
20508
+ const stats = statSync4(gitignorePath);
20509
+ if (stats.size > MAX_GITIGNORE_SIZE) {
20510
+ return hardcoded;
20511
+ }
20512
+ const content = readFileSync4(gitignorePath, "utf-8");
20513
+ for (const line of content.split(/\r?\n/)) {
20514
+ const trimmed = line.trim();
20515
+ if (!trimmed || trimmed.startsWith("#")) continue;
20516
+ if (trimmed.startsWith("!")) continue;
20517
+ let pattern = trimmed;
20518
+ const isAnchored = pattern.startsWith("/");
20519
+ const isDir = pattern.endsWith("/");
20520
+ if (isAnchored) pattern = pattern.slice(1);
20521
+ if (isDir) pattern = pattern.slice(0, -1);
20522
+ if (!pattern) continue;
20523
+ if (isAnchored) {
20524
+ gitignorePatterns.push(isDir ? pattern + "/**" : pattern);
20525
+ } else {
20526
+ gitignorePatterns.push(isDir ? "**/" + pattern + "/**" : "**/" + pattern);
20527
+ }
20528
+ }
20529
+ } catch {
20530
+ }
20531
+ return [...hardcoded, ...gitignorePatterns];
20532
+ }
20533
+ function gatewayFromConfig(cfg) {
20534
+ if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
20535
+ if (!cfg.aiGatewayId) return void 0;
20536
+ return {
20537
+ id: cfg.aiGatewayId,
20538
+ cacheTtl: cfg.aiGatewayCacheTtl,
20539
+ skipCache: cfg.aiGatewaySkipCache,
20540
+ collectLogPayload: cfg.aiGatewayCollectLogPayload,
20541
+ metadata: cfg.aiGatewayMetadata
20542
+ };
20543
+ }
20544
+ function gatewayUsageLookupFromConfig(cfg, meta) {
20545
+ if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
20546
+ if (!cfg.aiGatewayId || !meta) return void 0;
20547
+ return {
20548
+ accountId: cfg.accountId,
20549
+ apiToken: cfg.apiToken,
20550
+ gatewayId: cfg.aiGatewayId,
20551
+ meta
20552
+ };
20553
+ }
20554
+ function openBrowser(url) {
20555
+ const cmd = platform4() === "darwin" ? "open" : platform4() === "win32" ? "start" : "xdg-open";
20556
+ const child = spawn4(cmd, [url], { detached: true, stdio: "ignore" });
20557
+ child.unref();
20558
+ }
20559
+ function detectGitHubRepo(cachedRepo) {
20560
+ if (cachedRepo) {
20561
+ const parts = cachedRepo.split("/");
20562
+ if (parts.length === 2) return { owner: parts[0], name: parts[1] };
20563
+ }
20564
+ try {
20565
+ const remoteUrl = execSync3("git remote get-url origin", { cwd: process.cwd(), encoding: "utf8" }).trim().replace(/\/+$/, "");
20566
+ const httpsMatch = remoteUrl.match(/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
20567
+ if (httpsMatch) return { owner: httpsMatch[1], name: httpsMatch[2] };
20568
+ const sshMatch = remoteUrl.match(/github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
20569
+ if (sshMatch) return { owner: sshMatch[1], name: sshMatch[2] };
20570
+ } catch {
20571
+ }
20572
+ return null;
20573
+ }
20574
+ function detectGitBranch() {
20575
+ try {
20576
+ return execSync3("git branch --show-current", { cwd: process.cwd(), encoding: "utf8" }).trim() || null;
20577
+ } catch {
20578
+ return null;
20579
+ }
20580
+ }
20581
+ function formatTokens4(n) {
20582
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
20583
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
20584
+ return String(n);
20585
+ }
20586
+ function trackRecentFile(ref, path, max = 10) {
20587
+ ref.current.set(path, Date.now());
20588
+ if (ref.current.size > max) {
20589
+ let oldest = null;
20590
+ let oldestTime = Infinity;
20591
+ for (const [p, t] of ref.current) {
20592
+ if (t < oldestTime) {
20593
+ oldestTime = t;
20594
+ oldest = p;
20595
+ }
20596
+ }
20597
+ if (oldest) ref.current.delete(oldest);
20598
+ }
20599
+ }
20600
+ function capEvents(prev) {
20601
+ if (prev.length <= MAX_EVENTS) return prev;
20602
+ return prev.slice(prev.length - MAX_EVENTS);
20603
+ }
20604
+ function compactEventsVisual(prev, keepLastTurns) {
20605
+ let seen = 0;
20606
+ let cutoff = -1;
20607
+ for (let i = prev.length - 1; i >= 0; i--) {
20608
+ if (prev[i].kind === "user") {
20609
+ seen++;
20610
+ if (seen === keepLastTurns + 1) {
20611
+ cutoff = i;
20612
+ break;
20613
+ }
20614
+ }
20615
+ }
20616
+ if (cutoff <= 0) return prev;
20617
+ const kept = prev.slice(cutoff);
20618
+ return [
20619
+ { kind: "info", key: mkKey(), text: `\xB7\xB7\xB7 ${cutoff} earlier messages compacted \xB7\xB7\xB7` },
20620
+ ...kept
20621
+ ];
20622
+ }
20623
+ function makePrefixMessages(cacheStable, model, mode, tools, preferPullRequests) {
20624
+ if (cacheStable) {
20625
+ return buildSystemMessages({ cwd: process.cwd(), tools, model, mode, preferPullRequests });
20626
+ }
20627
+ return [
20628
+ {
20629
+ role: "system",
20630
+ content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode, preferPullRequests })
20631
+ }
20632
+ ];
20633
+ }
20634
+ function rebuildSystemPromptForMode(messages, cacheStable, model, mode, tools, preferPullRequests) {
20635
+ if (cacheStable) {
20636
+ const rebuilt = buildSystemMessages({ cwd: process.cwd(), tools, model, mode, preferPullRequests });
20637
+ messages[0] = rebuilt[0];
20638
+ if (rebuilt[1]) {
20639
+ messages[1] = rebuilt[1];
20640
+ }
20641
+ } else {
20642
+ messages[0] = {
20643
+ role: "system",
20644
+ content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode, preferPullRequests })
20645
+ };
20646
+ }
20647
+ }
20648
+ function findImagePaths(text) {
20649
+ const paths = [];
20650
+ const quotedRegex = /"([^"]+)"|'([^']+)'/g;
20651
+ let match;
20652
+ while ((match = quotedRegex.exec(text)) !== null) {
20653
+ const path = match[1] ?? match[2];
20654
+ if (path && isImagePath(path) && existsSync4(path)) {
20655
+ paths.push(path);
20656
+ }
20657
+ }
20658
+ const remaining = text.replace(/"[^"]+"|'[^']+'/g, "");
20659
+ const ESCAPED_SPACE = "\0";
20660
+ const processed = remaining.replace(/\\ /g, ESCAPED_SPACE);
20661
+ for (const token of processed.split(/\s+/)) {
20662
+ const clean = token.replace(new RegExp(ESCAPED_SPACE, "g"), " ").replace(/^["']|["',;:!?]$/g, "").replace(/[.,;:!?]$/, "");
20663
+ if (clean && isImagePath(clean) && existsSync4(clean) && !paths.includes(clean)) {
20664
+ paths.push(clean);
20665
+ }
20666
+ }
20667
+ return paths;
20668
+ }
20669
+ 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;
20670
+ var init_app_helpers = __esm({
20671
+ "src/ui/app-helpers.ts"() {
20672
+ "use strict";
20673
+ init_system_prompt();
20674
+ init_image();
20675
+ MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
20676
+ CONTEXT_LIMIT = 262e3;
20677
+ AUTO_COMPACT_THRESHOLD = 0.8;
20678
+ MAX_EVENTS = 500;
20679
+ DEFAULT_AUTO_FRESH_SUGGESTION_TURNS = 30;
20680
+ MAX_IMAGES_PER_MESSAGE = 10;
20681
+ FEEDBACK_WORKER_URL = "https://hello.kimiflare.com";
20682
+ nextKey = 1;
20683
+ mkKey = () => `evt_${nextKey++}`;
20684
+ nextAssistantId = 1;
20685
+ mkAssistantId = () => nextAssistantId++;
20686
+ }
20687
+ });
20688
+
20408
20689
  // src/ui/onboarding.tsx
20409
20690
  import { useState as useState14, useCallback as useCallback3, useEffect as useEffect8 } from "react";
20410
20691
  import { Box as Box20, Text as Text20, useInput as useInput10 } from "ink";
@@ -20444,6 +20725,14 @@ function Onboarding({ onDone, onCancel }) {
20444
20725
  [onCancel]
20445
20726
  )
20446
20727
  );
20728
+ useInput10(
20729
+ (_input, key) => {
20730
+ if (step !== "cloudAuth") return;
20731
+ if (key.return && cloudAuthStatus?.url) {
20732
+ openBrowser(cloudAuthStatus.url);
20733
+ }
20734
+ }
20735
+ );
20447
20736
  useInput10(
20448
20737
  (_input, key) => {
20449
20738
  if (step !== "mode") return;
@@ -20846,7 +21135,11 @@ function Onboarding({ onDone, onCancel }) {
20846
21135
  step === "cloudAuth" && /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", marginTop: 1, children: [
20847
21136
  /* @__PURE__ */ jsx21(Text20, { bold: true, color: theme.accent, children: "Kimiflare Cloud Authentication" }),
20848
21137
  cloudAuthStatus ? /* @__PURE__ */ jsxs19(Fragment, { children: [
20849
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "1. Open this URL in your browser:" }),
21138
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
21139
+ "1. Press ",
21140
+ /* @__PURE__ */ jsx21(Text20, { bold: true, color: theme.accent, children: "Enter" }),
21141
+ " to open this URL in your browser:"
21142
+ ] }),
20850
21143
  /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: cloudAuthStatus.url }),
20851
21144
  /* @__PURE__ */ jsx21(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "2. Sign in with GitHub or Email" }) }),
20852
21145
  /* @__PURE__ */ jsx21(Box20, { marginTop: 1, children: /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
@@ -20900,7 +21193,7 @@ function Onboarding({ onDone, onCancel }) {
20900
21193
  "\u2022".repeat(apiToken.length)
20901
21194
  ] })
20902
21195
  ] }),
20903
- /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
21196
+ !cloudMode && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
20904
21197
  "Model: ",
20905
21198
  model
20906
21199
  ] }),
@@ -20959,6 +21252,7 @@ var init_onboarding = __esm({
20959
21252
  init_key_entry_modal();
20960
21253
  init_registry();
20961
21254
  init_config();
21255
+ init_app_helpers();
20962
21256
  init_theme_context();
20963
21257
  init_ai_gateway_api();
20964
21258
  }
@@ -21082,13 +21376,13 @@ var init_frontmatter = __esm({
21082
21376
  // src/commands/loader.ts
21083
21377
  import { open, realpath as realpath2 } from "fs/promises";
21084
21378
  import { homedir as homedir17 } from "os";
21085
- import { join as join26, relative as relative6, sep as sep2 } from "path";
21379
+ import { join as join27, relative as relative6, sep as sep2 } from "path";
21086
21380
  function projectCommandsDir(cwd = process.cwd()) {
21087
- return join26(cwd, ".kimiflare", "commands");
21381
+ return join27(cwd, ".kimiflare", "commands");
21088
21382
  }
21089
21383
  function globalCommandsDir() {
21090
- const xdg = process.env.XDG_CONFIG_HOME || join26(homedir17(), ".config");
21091
- return join26(xdg, "kimiflare", "commands");
21384
+ const xdg = process.env.XDG_CONFIG_HOME || join27(homedir17(), ".config");
21385
+ return join27(xdg, "kimiflare", "commands");
21092
21386
  }
21093
21387
  async function loadCustomCommands(cwd = process.cwd()) {
21094
21388
  const warnings = [];
@@ -22340,10 +22634,10 @@ var init_wcag = __esm({
22340
22634
 
22341
22635
  // src/ui/theme-loader.ts
22342
22636
  import { readFile as readFile19, readdir as readdir6 } from "fs/promises";
22343
- import { join as join27 } from "path";
22637
+ import { join as join28 } from "path";
22344
22638
  import { homedir as homedir18 } from "os";
22345
22639
  function projectThemesDir(cwd = process.cwd()) {
22346
- return join27(cwd, ".kimiflare", "themes");
22640
+ return join28(cwd, ".kimiflare", "themes");
22347
22641
  }
22348
22642
  function isHexColor(c) {
22349
22643
  return /^#[0-9a-fA-F]{6}$/.test(c);
@@ -22432,7 +22726,7 @@ async function loadThemesFromDir(dir, source) {
22432
22726
  return { themes, errors };
22433
22727
  }
22434
22728
  for (const file of files.filter((f) => f.endsWith(".json"))) {
22435
- const path = join27(dir, file);
22729
+ const path = join28(dir, file);
22436
22730
  let raw;
22437
22731
  try {
22438
22732
  raw = await readFile19(path, "utf-8");
@@ -22581,8 +22875,8 @@ var init_theme_loader = __esm({
22581
22875
  "use strict";
22582
22876
  init_wcag();
22583
22877
  init_theme();
22584
- USER_THEMES_DIR = join27(
22585
- process.env.XDG_CONFIG_HOME || join27(homedir18(), ".config"),
22878
+ USER_THEMES_DIR = join28(
22879
+ process.env.XDG_CONFIG_HOME || join28(homedir18(), ".config"),
22586
22880
  "kimiflare",
22587
22881
  "themes"
22588
22882
  );
@@ -23673,7 +23967,7 @@ var init_command_list = __esm({
23673
23967
  import { useState as useState18 } from "react";
23674
23968
  import { Box as Box28, Text as Text28 } from "ink";
23675
23969
  import SelectInput10 from "ink-select-input";
23676
- import { spawn as spawn4 } from "child_process";
23970
+ import { spawn as spawn5 } from "child_process";
23677
23971
  import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
23678
23972
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
23679
23973
  const theme = useTheme();
@@ -23687,7 +23981,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
23687
23981
  const runInstall = (command) => {
23688
23982
  setInstallState({ status: "running", output: "Installing..." });
23689
23983
  const { shell, args } = getShellCommand();
23690
- const child = spawn4(shell, [...args, command], {
23984
+ const child = spawn5(shell, [...args, command], {
23691
23985
  env: process.env
23692
23986
  });
23693
23987
  let stdout = "";
@@ -24803,7 +25097,7 @@ function formatSessionLine(s) {
24803
25097
  const ago = formatAgo(new Date(s.updatedAt));
24804
25098
  const prompt = s.prompt.slice(0, 30) + (s.prompt.length > 30 ? "\u2026" : "");
24805
25099
  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)})` : "";
25100
+ const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens5(s.tokensUsed)}/${formatTokens5(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens5(s.tokensUsed)})` : "";
24807
25101
  return `${icon} ${prompt} \u2192 ${outcome} ${ago}${cost}`;
24808
25102
  }
24809
25103
  function formatAgo(date) {
@@ -24816,7 +25110,7 @@ function formatAgo(date) {
24816
25110
  if (minutes > 0) return `${minutes}m ago`;
24817
25111
  return "just now";
24818
25112
  }
24819
- function formatTokens4(n) {
25113
+ function formatTokens5(n) {
24820
25114
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
24821
25115
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
24822
25116
  return String(n);
@@ -24877,8 +25171,8 @@ function RemoteSessionDetail({
24877
25171
  ] }),
24878
25172
  session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs35(Text36, { children: [
24879
25173
  "Tokens: ",
24880
- formatTokens4(session.tokensUsed),
24881
- session.tokensBudget ? ` / ${formatTokens4(session.tokensBudget)}` : ""
25174
+ formatTokens5(session.tokensUsed),
25175
+ session.tokensBudget ? ` / ${formatTokens5(session.tokensBudget)}` : ""
24882
25176
  ] }),
24883
25177
  /* @__PURE__ */ jsxs35(Text36, { children: [
24884
25178
  "Created: ",
@@ -24922,7 +25216,7 @@ function InboxModal({ onDone, onOpen }) {
24922
25216
  setError(null);
24923
25217
  try {
24924
25218
  const res = await fetch(
24925
- `${FEEDBACK_WORKER_URL}/inbox/check?u=${encodeURIComponent(u)}&s=${encodeURIComponent(s)}`
25219
+ `${FEEDBACK_WORKER_URL2}/inbox/check?u=${encodeURIComponent(u)}&s=${encodeURIComponent(s)}`
24926
25220
  );
24927
25221
  if (!res.ok) {
24928
25222
  throw new Error(`Server returned ${res.status}`);
@@ -24968,7 +25262,7 @@ function InboxModal({ onDone, onOpen }) {
24968
25262
  if (messages.length === 0) return;
24969
25263
  const msg = messages[selectedIndex];
24970
25264
  if (!msg) return;
24971
- const url = `${FEEDBACK_WORKER_URL}/inbox?u=${encodeURIComponent(twitter)}&s=${encodeURIComponent(secret)}&m=${encodeURIComponent(msg.id)}`;
25265
+ const url = `${FEEDBACK_WORKER_URL2}/inbox?u=${encodeURIComponent(twitter)}&s=${encodeURIComponent(secret)}&m=${encodeURIComponent(msg.id)}`;
24972
25266
  onOpen(url);
24973
25267
  onDone();
24974
25268
  }, [messages, selectedIndex, twitter, secret, onOpen, onDone]);
@@ -25067,21 +25361,21 @@ function InboxModal({ onDone, onOpen }) {
25067
25361
  ] })
25068
25362
  ] });
25069
25363
  }
25070
- var FEEDBACK_WORKER_URL;
25364
+ var FEEDBACK_WORKER_URL2;
25071
25365
  var init_inbox_modal = __esm({
25072
25366
  "src/ui/inbox-modal.tsx"() {
25073
25367
  "use strict";
25074
25368
  init_text_input();
25075
25369
  init_theme_context();
25076
- FEEDBACK_WORKER_URL = "https://hello.kimiflare.com";
25370
+ FEEDBACK_WORKER_URL2 = "https://hello.kimiflare.com";
25077
25371
  }
25078
25372
  });
25079
25373
 
25080
25374
  // src/remote/deploy-commute.ts
25081
- import { spawn as spawn5 } from "child_process";
25375
+ import { spawn as spawn6 } from "child_process";
25082
25376
  import { mkdtemp, readFile as readFile20, writeFile as writeFile12, rm } from "fs/promises";
25083
25377
  import { tmpdir as tmpdir3 } from "os";
25084
- import { join as join28 } from "path";
25378
+ import { join as join29 } from "path";
25085
25379
  import { randomBytes as randomBytes2 } from "crypto";
25086
25380
  async function cfApiFetch(accountId, apiToken, path, init) {
25087
25381
  const url = `${CF_API2}/accounts/${encodeURIComponent(accountId)}${path}`;
@@ -25152,7 +25446,7 @@ function generateSecret2() {
25152
25446
  }
25153
25447
  function runCmd(cmd, args, opts2 = {}) {
25154
25448
  return new Promise((resolve8) => {
25155
- const child = spawn5(cmd, args, {
25449
+ const child = spawn6(cmd, args, {
25156
25450
  cwd: opts2.cwd,
25157
25451
  env: { ...process.env, ...opts2.env ?? {} },
25158
25452
  stdio: [opts2.input ? "pipe" : "ignore", "pipe", "pipe"]
@@ -25312,8 +25606,8 @@ ${wranglerInstall.stderr.slice(-600)}`,
25312
25606
  ok: true
25313
25607
  };
25314
25608
  yield { message: "Prerequisites ready", ok: true };
25315
- const tmpRoot = await mkdtemp(join28(tmpdir3(), "kimiflare-commute-"));
25316
- const repoDir = join28(tmpRoot, "kimiflare-commute");
25609
+ const tmpRoot = await mkdtemp(join29(tmpdir3(), "kimiflare-commute-"));
25610
+ const repoDir = join29(tmpRoot, "kimiflare-commute");
25317
25611
  yield { message: `Fetching worker source from GitHub (${COMMUTE_REPO})\u2026` };
25318
25612
  const clone = await runCmd("git", ["clone", "--depth", "1", "--branch", COMMUTE_BRANCH, COMMUTE_REPO, repoDir], { timeoutMs: 6e4 });
25319
25613
  if (clone.code !== 0) {
@@ -25322,8 +25616,8 @@ ${(clone.stderr || clone.stdout).slice(0, 400)}`, error: true };
25322
25616
  throw new Error("clone failed");
25323
25617
  }
25324
25618
  yield { message: "Source fetched from GitHub", ok: true };
25325
- const workerDir = join28(repoDir, "remote", "worker");
25326
- const wranglerToml = join28(workerDir, "wrangler.toml");
25619
+ const workerDir = join29(repoDir, "remote", "worker");
25620
+ const wranglerToml = join29(workerDir, "wrangler.toml");
25327
25621
  yield { message: "Installing Worker dependencies (npm install)\u2026" };
25328
25622
  const install = await runCmd("npm", ["install", "--no-audit", "--no-fund", "--loglevel=error"], {
25329
25623
  cwd: workerDir,
@@ -25434,488 +25728,207 @@ new_sqlite_classes = ["SessionDO", "WorkerDO", "Sandbox"]`
25434
25728
  [[migrations]]
25435
25729
  tag = "v1"
25436
25730
  new_sqlite_classes = ["SessionDO", "WorkerDO", "Sandbox"]
25437
- `;
25438
- }
25439
- }
25440
- if (!/\[observability\.logs\]/.test(toml)) {
25441
- toml += `
25442
- # Auto-added by kimiflare /multi-agent \u2192 Set up
25443
- [observability.logs]
25444
- enabled = false
25445
- invocation_logs = true
25446
- `;
25447
- }
25448
- await writeFile12(wranglerToml, toml, "utf8");
25449
- yield {
25450
- message: workerExists ? "wrangler.toml patched (name, KV id, [[artifacts]] stripped)" : "wrangler.toml patched (name, KV id, [[artifacts]] stripped, DO migrations added)",
25451
- ok: true
25452
- };
25453
- const workerApiKey = generateSecret2();
25454
- yield { message: "Setting WORKER_API_KEY secret\u2026" };
25455
- const secret = await runCmd("wrangler", ["secret", "put", "WORKER_API_KEY"], {
25456
- cwd: workerDir,
25457
- env: cfEnv,
25458
- input: workerApiKey + "\n",
25459
- timeoutMs: 3e4
25460
- });
25461
- if (secret.code !== 0) {
25462
- yield {
25463
- message: explainWranglerFailure("wrangler secret put WORKER_API_KEY", secret.stdout, secret.stderr),
25464
- error: true
25465
- };
25466
- throw new Error("secret put failed");
25467
- }
25468
- await runCmd("wrangler", ["secret", "put", "ACCOUNT_ID"], { cwd: workerDir, env: cfEnv, input: cfg.accountId + "\n", timeoutMs: 3e4 });
25469
- await runCmd("wrangler", ["secret", "put", "CF_API_TOKEN"], { cwd: workerDir, env: cfEnv, input: cfg.apiToken + "\n", timeoutMs: 3e4 });
25470
- yield { message: "Worker secrets uploaded (WORKER_API_KEY, ACCOUNT_ID, CF_API_TOKEN)", ok: true };
25471
- yield { message: "Deploying Worker (this can take ~30s)\u2026" };
25472
- const deploy = await runCmd("wrangler", ["deploy"], {
25473
- cwd: workerDir,
25474
- env: cfEnv,
25475
- timeoutMs: 18e4
25476
- });
25477
- if (deploy.code !== 0) {
25478
- yield {
25479
- message: explainWranglerFailure("wrangler deploy", deploy.stdout, deploy.stderr),
25480
- error: true
25481
- };
25482
- throw new Error("deploy failed");
25483
- }
25484
- const workerUrl = extractWorkerUrl(deploy.stdout + "\n" + deploy.stderr);
25485
- if (!workerUrl) {
25486
- yield { message: "Deploy succeeded but couldn't parse the Worker URL \u2014 set it manually via /multi-agent.", error: true };
25487
- throw new Error("url parse failed");
25488
- }
25489
- yield { message: `Worker deployed at ${workerUrl}`, ok: true };
25490
- const next = {
25491
- ...cfg,
25492
- workerEndpoint: workerUrl,
25493
- workerApiKey,
25494
- workerName,
25495
- multiAgentEnabled: true
25496
- };
25497
- await saveConfig(next);
25498
- yield { message: "Saved to ~/.config/kimiflare/config.json", ok: true };
25499
- await rm(tmpRoot, { recursive: true, force: true }).catch(() => {
25500
- });
25501
- yield { message: "Setup complete \u2014 multi-agent is ready to use.", done: true };
25502
- return { workerEndpoint: workerUrl, workerApiKey };
25503
- }
25504
- async function* teardownCommute(opts2 = {}) {
25505
- const cfg = await loadConfig();
25506
- if (!cfg?.accountId || !cfg?.apiToken) {
25507
- yield { message: "Cloudflare credentials missing \u2014 nothing to tear down.", error: true };
25508
- throw new Error("missing CF creds");
25509
- }
25510
- const workerName = opts2.workerName ?? cfg.workerName ?? WORKER_NAME;
25511
- const cfEnv = {
25512
- CLOUDFLARE_ACCOUNT_ID: cfg.accountId,
25513
- CLOUDFLARE_API_TOKEN: cfg.apiToken
25514
- };
25515
- if (!await hasBinary("wrangler")) {
25516
- yield { message: "wrangler not found. Install: npm install -g wrangler", error: true };
25517
- throw new Error("wrangler missing");
25518
- }
25519
- yield { message: `Deleting Worker "${workerName}"\u2026` };
25520
- const del = await runCmd("wrangler", ["delete", "--name", workerName], {
25521
- env: cfEnv,
25522
- input: "y\n",
25523
- timeoutMs: 6e4
25524
- });
25525
- if (del.code === 0) {
25526
- yield { message: `Worker "${workerName}" deleted`, ok: true };
25527
- } else {
25528
- const combined = (del.stdout + del.stderr).toLowerCase();
25529
- if (combined.includes("not found") || combined.includes("does not exist") || combined.includes("10007")) {
25530
- yield { message: "Worker not found (already deleted or never created)", ok: true };
25531
- } else {
25532
- yield {
25533
- message: explainWranglerFailure(`wrangler delete --name ${workerName}`, del.stdout, del.stderr),
25534
- error: true
25535
- };
25536
- }
25537
- }
25538
- yield { message: `Looking up Durable Object namespaces for "${workerName}"\u2026` };
25539
- try {
25540
- const namespaces = await listDurableObjectNamespaces(cfg.accountId, cfg.apiToken);
25541
- const targets = namespaces.filter(
25542
- (ns) => ns.script === workerName || ns.name.startsWith(`${workerName}_`)
25543
- );
25544
- if (targets.length === 0) {
25545
- yield { message: "No Durable Object namespaces found (nothing to delete)", ok: true };
25546
- } else {
25547
- for (const ns of targets) {
25548
- try {
25549
- await deleteDurableObjectNamespace(cfg.accountId, cfg.apiToken, ns.id);
25550
- yield { message: `DO namespace ${ns.name} deleted (${ns.id.slice(0, 8)}\u2026)`, ok: true };
25551
- } catch (err) {
25552
- yield {
25553
- message: `DO namespace ${ns.name} delete warning: ${err instanceof Error ? err.message : String(err)}`
25554
- };
25555
- }
25556
- }
25731
+ `;
25557
25732
  }
25558
- } catch (err) {
25733
+ }
25734
+ if (!/\[observability\.logs\]/.test(toml)) {
25735
+ toml += `
25736
+ # Auto-added by kimiflare /multi-agent \u2192 Set up
25737
+ [observability.logs]
25738
+ enabled = false
25739
+ invocation_logs = true
25740
+ `;
25741
+ }
25742
+ await writeFile12(wranglerToml, toml, "utf8");
25743
+ yield {
25744
+ message: workerExists ? "wrangler.toml patched (name, KV id, [[artifacts]] stripped)" : "wrangler.toml patched (name, KV id, [[artifacts]] stripped, DO migrations added)",
25745
+ ok: true
25746
+ };
25747
+ const workerApiKey = generateSecret2();
25748
+ yield { message: "Setting WORKER_API_KEY secret\u2026" };
25749
+ const secret = await runCmd("wrangler", ["secret", "put", "WORKER_API_KEY"], {
25750
+ cwd: workerDir,
25751
+ env: cfEnv,
25752
+ input: workerApiKey + "\n",
25753
+ timeoutMs: 3e4
25754
+ });
25755
+ if (secret.code !== 0) {
25559
25756
  yield {
25560
- message: `DO namespace lookup warning: ${err instanceof Error ? err.message : String(err)}`
25757
+ message: explainWranglerFailure("wrangler secret put WORKER_API_KEY", secret.stdout, secret.stderr),
25758
+ error: true
25561
25759
  };
25760
+ throw new Error("secret put failed");
25562
25761
  }
25563
- yield { message: `Looking up container applications for "${workerName}"\u2026` };
25564
- try {
25565
- const apps = await listContainerApplications(cfg.accountId, cfg.apiToken);
25566
- const appPrefix = `${workerName}-`.toLowerCase();
25567
- const targets = apps.filter((app) => app.name.toLowerCase().startsWith(appPrefix));
25568
- if (targets.length === 0) {
25569
- yield { message: "No container applications found (nothing to delete)", ok: true };
25570
- } else {
25571
- for (const app of targets) {
25572
- try {
25573
- await deleteContainerApplication(cfg.accountId, cfg.apiToken, app.id);
25574
- yield { message: `Container application ${app.name} deleted (${app.id.slice(0, 8)}\u2026)`, ok: true };
25575
- } catch (err) {
25576
- yield {
25577
- message: `Container application ${app.name} delete warning: ${err instanceof Error ? err.message : String(err)}`
25578
- };
25579
- }
25580
- }
25581
- }
25582
- } catch {
25583
- yield { message: "(could not list container applications \u2014 skipping container cleanup)" };
25762
+ await runCmd("wrangler", ["secret", "put", "ACCOUNT_ID"], { cwd: workerDir, env: cfEnv, input: cfg.accountId + "\n", timeoutMs: 3e4 });
25763
+ await runCmd("wrangler", ["secret", "put", "CF_API_TOKEN"], { cwd: workerDir, env: cfEnv, input: cfg.apiToken + "\n", timeoutMs: 3e4 });
25764
+ yield { message: "Worker secrets uploaded (WORKER_API_KEY, ACCOUNT_ID, CF_API_TOKEN)", ok: true };
25765
+ yield { message: "Deploying Worker (this can take ~30s)\u2026" };
25766
+ const deploy = await runCmd("wrangler", ["deploy"], {
25767
+ cwd: workerDir,
25768
+ env: cfEnv,
25769
+ timeoutMs: 18e4
25770
+ });
25771
+ if (deploy.code !== 0) {
25772
+ yield {
25773
+ message: explainWranglerFailure("wrangler deploy", deploy.stdout, deploy.stderr),
25774
+ error: true
25775
+ };
25776
+ throw new Error("deploy failed");
25584
25777
  }
25585
- yield { message: "Listing KV namespaces to find OAUTH_KV\u2026" };
25586
- const kvList = await runCmd("wrangler", ["kv", "namespace", "list"], { env: cfEnv, timeoutMs: 3e4 });
25587
- if (kvList.code === 0) {
25588
- try {
25589
- const items = JSON.parse(kvList.stdout);
25590
- const targets = items.filter((it) => typeof it.title === "string" && /OAUTH_KV$/i.test(it.title));
25591
- if (targets.length === 0) {
25592
- yield { message: "No OAUTH_KV namespaces found (nothing to delete)", ok: true };
25593
- } else {
25594
- for (const t of targets) {
25595
- if (!t.id) continue;
25596
- const r = await runCmd("wrangler", ["kv", "namespace", "delete", "--namespace-id", t.id], {
25597
- env: cfEnv,
25598
- input: "y\n",
25599
- timeoutMs: 3e4
25600
- });
25601
- if (r.code === 0) {
25602
- yield { message: `KV namespace ${t.title} deleted (${t.id.slice(0, 8)}\u2026)`, ok: true };
25603
- } else {
25604
- yield { message: `KV namespace ${t.title} delete warning: ${(r.stderr || r.stdout).slice(0, 200)}` };
25605
- }
25606
- }
25607
- }
25608
- } catch {
25609
- yield { message: "(could not parse KV list \u2014 skipping KV cleanup)" };
25610
- }
25611
- } else {
25612
- yield { message: "(could not list KV namespaces \u2014 skipping KV cleanup)" };
25778
+ const workerUrl = extractWorkerUrl(deploy.stdout + "\n" + deploy.stderr);
25779
+ if (!workerUrl) {
25780
+ yield { message: "Deploy succeeded but couldn't parse the Worker URL \u2014 set it manually via /multi-agent.", error: true };
25781
+ throw new Error("url parse failed");
25613
25782
  }
25783
+ yield { message: `Worker deployed at ${workerUrl}`, ok: true };
25614
25784
  const next = {
25615
25785
  ...cfg,
25616
- workerEndpoint: void 0,
25617
- workerApiKey: void 0,
25618
- workerName: void 0,
25619
- multiAgentEnabled: false,
25620
- autoExecute: false
25621
- };
25622
- await saveConfig(next);
25623
- yield { message: "Local multi-agent config cleared", ok: true };
25624
- yield { message: "Tear-down complete \u2014 multi-agent is fully removed.", done: true };
25625
- }
25626
- var COMMUTE_REPO, COMMUTE_BRANCH, WORKER_NAME, KV_TITLE, CF_API2, TOKEN_TEMPLATE_URL;
25627
- var init_deploy_commute = __esm({
25628
- "src/remote/deploy-commute.ts"() {
25629
- "use strict";
25630
- init_config();
25631
- init_version();
25632
- COMMUTE_REPO = "https://github.com/sinameraji/kimiflare-commute.git";
25633
- COMMUTE_BRANCH = "main";
25634
- WORKER_NAME = "kimiflare-multi-agent";
25635
- KV_TITLE = "kimiflare-multi-agent-OAUTH_KV";
25636
- CF_API2 = "https://api.cloudflare.com/client/v4";
25637
- TOKEN_TEMPLATE_URL = "https://dash.cloudflare.com/profile/api-tokens";
25638
- }
25639
- });
25640
-
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
25786
+ workerEndpoint: workerUrl,
25787
+ workerApiKey,
25788
+ workerName,
25789
+ multiAgentEnabled: true
25775
25790
  };
25791
+ await saveConfig(next);
25792
+ yield { message: "Saved to ~/.config/kimiflare/config.json", ok: true };
25793
+ await rm(tmpRoot, { recursive: true, force: true }).catch(() => {
25794
+ });
25795
+ yield { message: "Setup complete \u2014 multi-agent is ready to use.", done: true };
25796
+ return { workerEndpoint: workerUrl, workerApiKey };
25776
25797
  }
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
25798
+ async function* teardownCommute(opts2 = {}) {
25799
+ const cfg = await loadConfig();
25800
+ if (!cfg?.accountId || !cfg?.apiToken) {
25801
+ yield { message: "Cloudflare credentials missing \u2014 nothing to tear down.", error: true };
25802
+ throw new Error("missing CF creds");
25803
+ }
25804
+ const workerName = opts2.workerName ?? cfg.workerName ?? WORKER_NAME;
25805
+ const cfEnv = {
25806
+ CLOUDFLARE_ACCOUNT_ID: cfg.accountId,
25807
+ CLOUDFLARE_API_TOKEN: cfg.apiToken
25785
25808
  };
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] };
25809
+ if (!await hasBinary("wrangler")) {
25810
+ yield { message: "wrangler not found. Install: npm install -g wrangler", error: true };
25811
+ throw new Error("wrangler missing");
25796
25812
  }
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 {
25813
+ yield { message: `Deleting Worker "${workerName}"\u2026` };
25814
+ const del = await runCmd("wrangler", ["delete", "--name", workerName], {
25815
+ env: cfEnv,
25816
+ input: "y\n",
25817
+ timeoutMs: 6e4
25818
+ });
25819
+ if (del.code === 0) {
25820
+ yield { message: `Worker "${workerName}" deleted`, ok: true };
25821
+ } else {
25822
+ const combined = (del.stdout + del.stderr).toLowerCase();
25823
+ if (combined.includes("not found") || combined.includes("does not exist") || combined.includes("10007")) {
25824
+ yield { message: "Worker not found (already deleted or never created)", ok: true };
25825
+ } else {
25826
+ yield {
25827
+ message: explainWranglerFailure(`wrangler delete --name ${workerName}`, del.stdout, del.stderr),
25828
+ error: true
25829
+ };
25830
+ }
25804
25831
  }
25805
- return null;
25806
- }
25807
- function detectGitBranch() {
25832
+ yield { message: `Looking up Durable Object namespaces for "${workerName}"\u2026` };
25808
25833
  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;
25834
+ const namespaces = await listDurableObjectNamespaces(cfg.accountId, cfg.apiToken);
25835
+ const targets = namespaces.filter(
25836
+ (ns) => ns.script === workerName || ns.name.startsWith(`${workerName}_`)
25837
+ );
25838
+ if (targets.length === 0) {
25839
+ yield { message: "No Durable Object namespaces found (nothing to delete)", ok: true };
25840
+ } else {
25841
+ for (const ns of targets) {
25842
+ try {
25843
+ await deleteDurableObjectNamespace(cfg.accountId, cfg.apiToken, ns.id);
25844
+ yield { message: `DO namespace ${ns.name} deleted (${ns.id.slice(0, 8)}\u2026)`, ok: true };
25845
+ } catch (err) {
25846
+ yield {
25847
+ message: `DO namespace ${ns.name} delete warning: ${err instanceof Error ? err.message : String(err)}`
25848
+ };
25849
+ }
25828
25850
  }
25829
25851
  }
25830
- if (oldest) ref.current.delete(oldest);
25852
+ } catch (err) {
25853
+ yield {
25854
+ message: `DO namespace lookup warning: ${err instanceof Error ? err.message : String(err)}`
25855
+ };
25831
25856
  }
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;
25857
+ yield { message: `Looking up container applications for "${workerName}"\u2026` };
25858
+ try {
25859
+ const apps = await listContainerApplications(cfg.accountId, cfg.apiToken);
25860
+ const appPrefix = `${workerName}-`.toLowerCase();
25861
+ const targets = apps.filter((app) => app.name.toLowerCase().startsWith(appPrefix));
25862
+ if (targets.length === 0) {
25863
+ yield { message: "No container applications found (nothing to delete)", ok: true };
25864
+ } else {
25865
+ for (const app of targets) {
25866
+ try {
25867
+ await deleteContainerApplication(cfg.accountId, cfg.apiToken, app.id);
25868
+ yield { message: `Container application ${app.name} deleted (${app.id.slice(0, 8)}\u2026)`, ok: true };
25869
+ } catch (err) {
25870
+ yield {
25871
+ message: `Container application ${app.name} delete warning: ${err instanceof Error ? err.message : String(err)}`
25872
+ };
25873
+ }
25846
25874
  }
25847
25875
  }
25876
+ } catch {
25877
+ yield { message: "(could not list container applications \u2014 skipping container cleanup)" };
25848
25878
  }
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];
25879
+ yield { message: "Listing KV namespaces to find OAUTH_KV\u2026" };
25880
+ const kvList = await runCmd("wrangler", ["kv", "namespace", "list"], { env: cfEnv, timeoutMs: 3e4 });
25881
+ if (kvList.code === 0) {
25882
+ try {
25883
+ const items = JSON.parse(kvList.stdout);
25884
+ const targets = items.filter((it) => typeof it.title === "string" && /OAUTH_KV$/i.test(it.title));
25885
+ if (targets.length === 0) {
25886
+ yield { message: "No OAUTH_KV namespaces found (nothing to delete)", ok: true };
25887
+ } else {
25888
+ for (const t of targets) {
25889
+ if (!t.id) continue;
25890
+ const r = await runCmd("wrangler", ["kv", "namespace", "delete", "--namespace-id", t.id], {
25891
+ env: cfEnv,
25892
+ input: "y\n",
25893
+ timeoutMs: 3e4
25894
+ });
25895
+ if (r.code === 0) {
25896
+ yield { message: `KV namespace ${t.title} deleted (${t.id.slice(0, 8)}\u2026)`, ok: true };
25897
+ } else {
25898
+ yield { message: `KV namespace ${t.title} delete warning: ${(r.stderr || r.stdout).slice(0, 200)}` };
25899
+ }
25900
+ }
25901
+ }
25902
+ } catch {
25903
+ yield { message: "(could not parse KV list \u2014 skipping KV cleanup)" };
25873
25904
  }
25874
25905
  } 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
- }
25906
+ yield { message: "(could not list KV namespaces \u2014 skipping KV cleanup)" };
25899
25907
  }
25900
- return paths;
25908
+ const next = {
25909
+ ...cfg,
25910
+ workerEndpoint: void 0,
25911
+ workerApiKey: void 0,
25912
+ workerName: void 0,
25913
+ multiAgentEnabled: false,
25914
+ autoExecute: false
25915
+ };
25916
+ await saveConfig(next);
25917
+ yield { message: "Local multi-agent config cleared", ok: true };
25918
+ yield { message: "Tear-down complete \u2014 multi-agent is fully removed.", done: true };
25901
25919
  }
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"() {
25920
+ var COMMUTE_REPO, COMMUTE_BRANCH, WORKER_NAME, KV_TITLE, CF_API2, TOKEN_TEMPLATE_URL;
25921
+ var init_deploy_commute = __esm({
25922
+ "src/remote/deploy-commute.ts"() {
25905
25923
  "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++;
25924
+ init_config();
25925
+ init_version();
25926
+ COMMUTE_REPO = "https://github.com/sinameraji/kimiflare-commute.git";
25927
+ COMMUTE_BRANCH = "main";
25928
+ WORKER_NAME = "kimiflare-multi-agent";
25929
+ KV_TITLE = "kimiflare-multi-agent-OAUTH_KV";
25930
+ CF_API2 = "https://api.cloudflare.com/client/v4";
25931
+ TOKEN_TEMPLATE_URL = "https://dash.cloudflare.com/profile/api-tokens";
25919
25932
  }
25920
25933
  });
25921
25934
 
@@ -29115,6 +29128,13 @@ var init_slash_commands = __esm({
29115
29128
  };
29116
29129
  handleModel = (ctx, rest, arg) => {
29117
29130
  const { cfg, setCfg, setEvents, mkKey: mkKey2 } = ctx;
29131
+ if (cfg?.cloudMode) {
29132
+ setEvents((e) => [
29133
+ ...e,
29134
+ { kind: "info", key: mkKey2(), text: "Model selection isn't available on KimiFlare Cloud \u2014 the model is managed for you." }
29135
+ ]);
29136
+ return true;
29137
+ }
29118
29138
  const sub = rest[0]?.toLowerCase() ?? "";
29119
29139
  if (!arg) {
29120
29140
  ctx.setShowModelPicker(true);
@@ -29978,7 +29998,7 @@ project: ${projectSettingsPath(cwd)}`
29978
29998
  handleHello = (ctx) => {
29979
29999
  const { setEvents, mkKey: mkKey2 } = ctx;
29980
30000
  const session = crypto.randomUUID();
29981
- const url = `${FEEDBACK_WORKER_URL2}/?s=${session}&v=${getAppVersion()}`;
30001
+ const url = `${FEEDBACK_WORKER_URL}/?s=${session}&v=${getAppVersion()}`;
29982
30002
  openBrowser(url);
29983
30003
  void (async () => {
29984
30004
  try {
@@ -30185,7 +30205,7 @@ project: ${projectSettingsPath(cwd)}`
30185
30205
  setEvents((e) => [
30186
30206
  ...e,
30187
30207
  { 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.` }
30208
+ { kind: "info", key: mkKey2(), text: `Budget: ${formatTokens4(budget)} tokens. TTL: ${ttl} min.` }
30189
30209
  ]);
30190
30210
  try {
30191
30211
  const data = await startRemoteSession({
@@ -32455,7 +32475,8 @@ ${wcagWarnings.join("\n")}` }
32455
32475
  { name: "topup", description: "Buy a one-time token top-up (+50M)", source: "builtin" },
32456
32476
  { name: "manage", description: "Manage membership, billing & invoices", source: "builtin" }
32457
32477
  ] : [];
32458
- return [...BUILTIN_COMMANDS, ...cloudCommands, ...customs];
32478
+ const builtins = cfg?.cloudMode ? BUILTIN_COMMANDS.filter((c) => c.name !== "model") : BUILTIN_COMMANDS;
32479
+ return [...builtins, ...cloudCommands, ...customs];
32459
32480
  }, [customCommandsVersion, cfg?.cloudMode]);
32460
32481
  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
32482
  const loadFilePickerItems = useCallback10(async () => {