kimiflare 0.84.0 → 0.84.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -13999,6 +13999,301 @@ var init_deploy_commute = __esm({
13999
13999
  }
14000
14000
  });
14001
14001
 
14002
+ // src/util/image.ts
14003
+ import { readFile as readFile15 } from "fs/promises";
14004
+ import { basename as basename3 } from "path";
14005
+ async function encodeImageFile(filePath) {
14006
+ const buf = await readFile15(filePath);
14007
+ if (buf.byteLength > MAX_IMAGE_BYTES) {
14008
+ throw new Error(
14009
+ `image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
14010
+ );
14011
+ }
14012
+ const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
14013
+ const mime = EXT_TO_MIME[ext] ?? "image/jpeg";
14014
+ const b64 = buf.toString("base64");
14015
+ return {
14016
+ filename: basename3(filePath),
14017
+ mime,
14018
+ dataUrl: `data:${mime};base64,${b64}`
14019
+ };
14020
+ }
14021
+ function isImagePath(path) {
14022
+ const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
14023
+ return ext in EXT_TO_MIME;
14024
+ }
14025
+ var MAX_IMAGE_BYTES, EXT_TO_MIME;
14026
+ var init_image = __esm({
14027
+ "src/util/image.ts"() {
14028
+ "use strict";
14029
+ MAX_IMAGE_BYTES = 5 * 1024 * 1024;
14030
+ EXT_TO_MIME = {
14031
+ ".png": "image/png",
14032
+ ".jpg": "image/jpeg",
14033
+ ".jpeg": "image/jpeg",
14034
+ ".gif": "image/gif",
14035
+ ".webp": "image/webp",
14036
+ ".bmp": "image/bmp"
14037
+ };
14038
+ }
14039
+ });
14040
+
14041
+ // src/ui/app-helpers.ts
14042
+ import { execSync as execSync3, spawn as spawn5 } from "child_process";
14043
+ import { existsSync as existsSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
14044
+ import { join as join24 } from "path";
14045
+ import { platform as platform3 } from "os";
14046
+ function buildFilePickerIgnoreList(cwd) {
14047
+ const hardcoded = [
14048
+ // Dependencies
14049
+ "**/node_modules/**",
14050
+ "**/vendor/**",
14051
+ "**/.bundle/**",
14052
+ "**/bower_components/**",
14053
+ // Version control
14054
+ "**/.git/**",
14055
+ "**/.svn/**",
14056
+ "**/.hg/**",
14057
+ // Build / output directories
14058
+ "**/dist/**",
14059
+ "**/build/**",
14060
+ "**/out/**",
14061
+ "**/public/**",
14062
+ "**/.next/**",
14063
+ "**/.nuxt/**",
14064
+ "**/.svelte-kit/**",
14065
+ "**/.vercel/**",
14066
+ "**/.netlify/**",
14067
+ "**/target/**",
14068
+ "**/bin/**",
14069
+ "**/obj/**",
14070
+ "**/Debug/**",
14071
+ "**/Release/**",
14072
+ "**/.gradle/**",
14073
+ // Caches
14074
+ "**/.cache/**",
14075
+ "**/.parcel-cache/**",
14076
+ "**/.turbo/**",
14077
+ "**/.eslintcache",
14078
+ "**/.stylelintcache",
14079
+ "**/.rpt2_cache/**",
14080
+ "**/.rts2_cache/**",
14081
+ // Temporary
14082
+ "**/tmp/**",
14083
+ "**/temp/**",
14084
+ "**/*.tmp",
14085
+ // Coverage
14086
+ "**/coverage/**",
14087
+ "**/.nyc_output/**",
14088
+ // OS files
14089
+ "**/.DS_Store",
14090
+ "**/Thumbs.db",
14091
+ // Logs
14092
+ "**/*.log",
14093
+ "**/logs/**",
14094
+ // Lock files (auto-generated, usually huge)
14095
+ "**/package-lock.json",
14096
+ "**/yarn.lock",
14097
+ "**/pnpm-lock.yaml",
14098
+ "**/bun.lockb",
14099
+ "**/Cargo.lock",
14100
+ "**/Gemfile.lock",
14101
+ "**/composer.lock",
14102
+ "**/Pipfile.lock",
14103
+ "**/poetry.lock",
14104
+ "**/go.sum",
14105
+ // Minified / source maps
14106
+ "**/*.min.js",
14107
+ "**/*.min.css",
14108
+ "**/*.map",
14109
+ // kimiflare internal
14110
+ "**/.kimiflare/**",
14111
+ // IDE (usually not relevant to mention)
14112
+ "**/.idea/**"
14113
+ ];
14114
+ const gitignorePatterns = [];
14115
+ try {
14116
+ const gitignorePath = join24(cwd, ".gitignore");
14117
+ const stats = statSync4(gitignorePath);
14118
+ if (stats.size > MAX_GITIGNORE_SIZE) {
14119
+ return hardcoded;
14120
+ }
14121
+ const content = readFileSync4(gitignorePath, "utf-8");
14122
+ for (const line of content.split(/\r?\n/)) {
14123
+ const trimmed = line.trim();
14124
+ if (!trimmed || trimmed.startsWith("#")) continue;
14125
+ if (trimmed.startsWith("!")) continue;
14126
+ let pattern = trimmed;
14127
+ const isAnchored = pattern.startsWith("/");
14128
+ const isDir = pattern.endsWith("/");
14129
+ if (isAnchored) pattern = pattern.slice(1);
14130
+ if (isDir) pattern = pattern.slice(0, -1);
14131
+ if (!pattern) continue;
14132
+ if (isAnchored) {
14133
+ gitignorePatterns.push(isDir ? pattern + "/**" : pattern);
14134
+ } else {
14135
+ gitignorePatterns.push(isDir ? "**/" + pattern + "/**" : "**/" + pattern);
14136
+ }
14137
+ }
14138
+ } catch {
14139
+ }
14140
+ return [...hardcoded, ...gitignorePatterns];
14141
+ }
14142
+ function gatewayFromConfig(cfg) {
14143
+ if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
14144
+ if (!cfg.aiGatewayId) return void 0;
14145
+ return {
14146
+ id: cfg.aiGatewayId,
14147
+ cacheTtl: cfg.aiGatewayCacheTtl,
14148
+ skipCache: cfg.aiGatewaySkipCache,
14149
+ collectLogPayload: cfg.aiGatewayCollectLogPayload,
14150
+ metadata: cfg.aiGatewayMetadata
14151
+ };
14152
+ }
14153
+ function gatewayUsageLookupFromConfig(cfg, meta) {
14154
+ if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
14155
+ if (!cfg.aiGatewayId || !meta) return void 0;
14156
+ return {
14157
+ accountId: cfg.accountId,
14158
+ apiToken: cfg.apiToken,
14159
+ gatewayId: cfg.aiGatewayId,
14160
+ meta
14161
+ };
14162
+ }
14163
+ function openBrowser(url) {
14164
+ const cmd = platform3() === "darwin" ? "open" : platform3() === "win32" ? "start" : "xdg-open";
14165
+ const child = spawn5(cmd, [url], { detached: true, stdio: "ignore" });
14166
+ child.unref();
14167
+ }
14168
+ function detectGitHubRepo(cachedRepo) {
14169
+ if (cachedRepo) {
14170
+ const parts = cachedRepo.split("/");
14171
+ if (parts.length === 2) return { owner: parts[0], name: parts[1] };
14172
+ }
14173
+ try {
14174
+ const remoteUrl = execSync3("git remote get-url origin", { cwd: process.cwd(), encoding: "utf8" }).trim();
14175
+ const httpsMatch = remoteUrl.match(/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
14176
+ if (httpsMatch) return { owner: httpsMatch[1], name: httpsMatch[2] };
14177
+ const sshMatch = remoteUrl.match(/github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
14178
+ if (sshMatch) return { owner: sshMatch[1], name: sshMatch[2] };
14179
+ } catch {
14180
+ }
14181
+ return null;
14182
+ }
14183
+ function detectGitBranch() {
14184
+ try {
14185
+ return execSync3("git branch --show-current", { cwd: process.cwd(), encoding: "utf8" }).trim() || null;
14186
+ } catch {
14187
+ return null;
14188
+ }
14189
+ }
14190
+ function formatTokens(n) {
14191
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
14192
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
14193
+ return String(n);
14194
+ }
14195
+ function trackRecentFile(ref, path, max = 10) {
14196
+ ref.current.set(path, Date.now());
14197
+ if (ref.current.size > max) {
14198
+ let oldest = null;
14199
+ let oldestTime = Infinity;
14200
+ for (const [p, t] of ref.current) {
14201
+ if (t < oldestTime) {
14202
+ oldestTime = t;
14203
+ oldest = p;
14204
+ }
14205
+ }
14206
+ if (oldest) ref.current.delete(oldest);
14207
+ }
14208
+ }
14209
+ function capEvents(prev) {
14210
+ if (prev.length <= MAX_EVENTS) return prev;
14211
+ return prev.slice(prev.length - MAX_EVENTS);
14212
+ }
14213
+ function compactEventsVisual(prev, keepLastTurns) {
14214
+ let seen = 0;
14215
+ let cutoff = -1;
14216
+ for (let i = prev.length - 1; i >= 0; i--) {
14217
+ if (prev[i].kind === "user") {
14218
+ seen++;
14219
+ if (seen === keepLastTurns + 1) {
14220
+ cutoff = i;
14221
+ break;
14222
+ }
14223
+ }
14224
+ }
14225
+ if (cutoff <= 0) return prev;
14226
+ const kept = prev.slice(cutoff);
14227
+ return [
14228
+ { kind: "info", key: mkKey(), text: `\xB7\xB7\xB7 ${cutoff} earlier messages compacted \xB7\xB7\xB7` },
14229
+ ...kept
14230
+ ];
14231
+ }
14232
+ function makePrefixMessages(cacheStable, model, mode, tools) {
14233
+ if (cacheStable) {
14234
+ return buildSystemMessages({ cwd: process.cwd(), tools, model, mode });
14235
+ }
14236
+ return [
14237
+ {
14238
+ role: "system",
14239
+ content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode })
14240
+ }
14241
+ ];
14242
+ }
14243
+ function rebuildSystemPromptForMode(messages, cacheStable, model, mode, tools) {
14244
+ if (cacheStable) {
14245
+ const rebuilt = buildSystemMessages({ cwd: process.cwd(), tools, model, mode });
14246
+ messages[0] = rebuilt[0];
14247
+ if (rebuilt[1]) {
14248
+ messages[1] = rebuilt[1];
14249
+ }
14250
+ } else {
14251
+ messages[0] = {
14252
+ role: "system",
14253
+ content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode })
14254
+ };
14255
+ }
14256
+ }
14257
+ function findImagePaths(text) {
14258
+ const paths = [];
14259
+ const quotedRegex = /"([^"]+)"|'([^']+)'/g;
14260
+ let match;
14261
+ while ((match = quotedRegex.exec(text)) !== null) {
14262
+ const path = match[1] ?? match[2];
14263
+ if (path && isImagePath(path) && existsSync4(path)) {
14264
+ paths.push(path);
14265
+ }
14266
+ }
14267
+ const remaining = text.replace(/"[^"]+"|'[^']+'/g, "");
14268
+ const ESCAPED_SPACE = "\0";
14269
+ const processed = remaining.replace(/\\ /g, ESCAPED_SPACE);
14270
+ for (const token of processed.split(/\s+/)) {
14271
+ const clean = token.replace(new RegExp(ESCAPED_SPACE, "g"), " ").replace(/^["']|["',;:!?]$/g, "").replace(/[.,;:!?]$/, "");
14272
+ if (clean && isImagePath(clean) && existsSync4(clean) && !paths.includes(clean)) {
14273
+ paths.push(clean);
14274
+ }
14275
+ }
14276
+ return paths;
14277
+ }
14278
+ var MAX_GITIGNORE_SIZE, CONTEXT_LIMIT, AUTO_COMPACT_THRESHOLD, MAX_EVENTS, MAX_IMAGES_PER_MESSAGE, FEEDBACK_WORKER_URL, nextKey, mkKey, nextAssistantId, mkAssistantId;
14279
+ var init_app_helpers = __esm({
14280
+ "src/ui/app-helpers.ts"() {
14281
+ "use strict";
14282
+ init_system_prompt();
14283
+ init_image();
14284
+ MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
14285
+ CONTEXT_LIMIT = 262e3;
14286
+ AUTO_COMPACT_THRESHOLD = 0.8;
14287
+ MAX_EVENTS = 500;
14288
+ MAX_IMAGES_PER_MESSAGE = 10;
14289
+ FEEDBACK_WORKER_URL = "https://hello.kimiflare.com";
14290
+ nextKey = 1;
14291
+ mkKey = () => `evt_${nextKey++}`;
14292
+ nextAssistantId = 1;
14293
+ mkAssistantId = () => nextAssistantId++;
14294
+ }
14295
+ });
14296
+
14002
14297
  // src/commands/builtins.ts
14003
14298
  var BUILTIN_COMMANDS, BUILTIN_COMMAND_NAMES;
14004
14299
  var init_builtins = __esm({
@@ -15021,24 +15316,24 @@ var init_theme = __esm({
15021
15316
  });
15022
15317
 
15023
15318
  // src/util/clipboard.ts
15024
- import { execSync as execSync3 } from "child_process";
15025
- import { platform as platform3 } from "os";
15319
+ import { execSync as execSync4 } from "child_process";
15320
+ import { platform as platform4 } from "os";
15026
15321
  function writeToClipboard(text) {
15027
- const os2 = platform3();
15322
+ const os2 = platform4();
15028
15323
  try {
15029
15324
  if (os2 === "darwin") {
15030
- execSync3("pbcopy", { input: text, timeout: 5e3 });
15325
+ execSync4("pbcopy", { input: text, timeout: 5e3 });
15031
15326
  return { success: true, message: "Copied to clipboard" };
15032
15327
  }
15033
15328
  if (os2 === "win32") {
15034
- execSync3("clip", { input: text, timeout: 5e3 });
15329
+ execSync4("clip", { input: text, timeout: 5e3 });
15035
15330
  return { success: true, message: "Copied to clipboard" };
15036
15331
  }
15037
15332
  try {
15038
- execSync3("xclip -selection clipboard", { input: text, timeout: 5e3 });
15333
+ execSync4("xclip -selection clipboard", { input: text, timeout: 5e3 });
15039
15334
  return { success: true, message: "Copied to clipboard" };
15040
15335
  } catch {
15041
- execSync3("xsel --clipboard --input", { input: text, timeout: 5e3 });
15336
+ execSync4("xsel --clipboard --input", { input: text, timeout: 5e3 });
15042
15337
  return { success: true, message: "Copied to clipboard" };
15043
15338
  }
15044
15339
  } catch {
@@ -15359,8 +15654,8 @@ var init_frontmatter = __esm({
15359
15654
  });
15360
15655
 
15361
15656
  // src/skills/loader.ts
15362
- import { readFile as readFile15, readdir as readdir6, stat as stat6 } from "fs/promises";
15363
- import { join as join24, extname } from "path";
15657
+ import { readFile as readFile16, readdir as readdir6, stat as stat6 } from "fs/promises";
15658
+ import { join as join25, extname } from "path";
15364
15659
  function normalizeManifest(raw, filePath) {
15365
15660
  const name = typeof raw.name === "string" ? raw.name : "";
15366
15661
  const description = typeof raw.description === "string" ? raw.description : "";
@@ -15374,7 +15669,7 @@ function normalizeManifest(raw, filePath) {
15374
15669
  return { name, description, match, scope, priority, enabled };
15375
15670
  }
15376
15671
  async function loadSkillFile(filePath) {
15377
- const raw = await readFile15(filePath, "utf-8");
15672
+ const raw = await readFile16(filePath, "utf-8");
15378
15673
  const parsed = parseFrontmatter(raw);
15379
15674
  const manifest = normalizeManifest(parsed.data, filePath);
15380
15675
  const body = parsed.content.trim();
@@ -15396,7 +15691,7 @@ async function loadSkillsFromDir(dirPath) {
15396
15691
  const entries = await readdir6(dirPath);
15397
15692
  const files = [];
15398
15693
  for (const entry of entries) {
15399
- const full = join24(dirPath, entry);
15694
+ const full = join25(dirPath, entry);
15400
15695
  const s = await stat6(full);
15401
15696
  if (s.isFile() && extname(entry) === ".md") {
15402
15697
  files.push(full);
@@ -15424,12 +15719,12 @@ var init_loader = __esm({
15424
15719
  });
15425
15720
 
15426
15721
  // src/skills/manager.ts
15427
- import { mkdir as mkdir10, writeFile as writeFile11, unlink as unlink2, readFile as readFile16 } from "fs/promises";
15428
- import { join as join25 } from "path";
15722
+ import { mkdir as mkdir10, writeFile as writeFile11, unlink as unlink2, readFile as readFile17 } from "fs/promises";
15723
+ import { join as join26 } from "path";
15429
15724
  function getSkillDirs(cwd) {
15430
15725
  return {
15431
- projectDir: join25(cwd, ".kimiflare", "skills"),
15432
- globalDir: join25(process.env.HOME ?? "", ".config", "kimiflare", "skills")
15726
+ projectDir: join26(cwd, ".kimiflare", "skills"),
15727
+ globalDir: join26(process.env.HOME ?? "", ".config", "kimiflare", "skills")
15433
15728
  };
15434
15729
  }
15435
15730
  async function listAllSkills(cwd) {
@@ -15443,7 +15738,7 @@ async function listAllSkills(cwd) {
15443
15738
  async function createSkill(opts2) {
15444
15739
  const dirs = getSkillDirs(opts2.cwd);
15445
15740
  const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
15446
- const filepath = join25(dir, `${opts2.name}.md`);
15741
+ const filepath = join26(dir, `${opts2.name}.md`);
15447
15742
  const frontmatter = {
15448
15743
  name: opts2.name,
15449
15744
  enabled: true,
@@ -15479,7 +15774,7 @@ async function setSkillEnabled(name, enabled, cwd) {
15479
15774
  const all = await listAllSkills(cwd);
15480
15775
  const skill = all.project.find((s) => s.name === name) ?? all.global.find((s) => s.name === name);
15481
15776
  if (!skill) throw new Error(`skill "${name}" not found`);
15482
- const raw = await readFile16(skill.filePath, "utf-8");
15777
+ const raw = await readFile17(skill.filePath, "utf-8");
15483
15778
  const parsed = parseFrontmatter(raw);
15484
15779
  parsed.data.enabled = enabled;
15485
15780
  const yaml = Object.entries(parsed.data).map(([k, v]) => {
@@ -15564,13 +15859,13 @@ var init_frontmatter2 = __esm({
15564
15859
  // src/commands/loader.ts
15565
15860
  import { open, realpath as realpath2 } from "fs/promises";
15566
15861
  import { homedir as homedir14 } from "os";
15567
- import { join as join26, relative as relative5, sep as sep2 } from "path";
15862
+ import { join as join27, relative as relative5, sep as sep2 } from "path";
15568
15863
  function projectCommandsDir(cwd = process.cwd()) {
15569
- return join26(cwd, ".kimiflare", "commands");
15864
+ return join27(cwd, ".kimiflare", "commands");
15570
15865
  }
15571
15866
  function globalCommandsDir() {
15572
- const xdg = process.env.XDG_CONFIG_HOME || join26(homedir14(), ".config");
15573
- return join26(xdg, "kimiflare", "commands");
15867
+ const xdg = process.env.XDG_CONFIG_HOME || join27(homedir14(), ".config");
15868
+ return join27(xdg, "kimiflare", "commands");
15574
15869
  }
15575
15870
  async function loadCustomCommands(cwd = process.cwd()) {
15576
15871
  const warnings = [];
@@ -15844,13 +16139,13 @@ var init_worker_client = __esm({
15844
16139
  });
15845
16140
 
15846
16141
  // src/init/context-generator.ts
15847
- import { existsSync as existsSync4, statSync as statSync4 } from "fs";
15848
- import { join as join27 } from "path";
16142
+ import { existsSync as existsSync5, statSync as statSync5 } from "fs";
16143
+ import { join as join28 } from "path";
15849
16144
  function detectFlavor(cwd) {
15850
16145
  for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
15851
16146
  if (flavor === "generic") continue;
15852
16147
  for (const sig of signatures) {
15853
- const path = join27(cwd, sig);
16148
+ const path = join28(cwd, sig);
15854
16149
  if (sig.includes("*")) {
15855
16150
  try {
15856
16151
  const parts = sig.split("*");
@@ -15862,7 +16157,7 @@ function detectFlavor(cwd) {
15862
16157
  }
15863
16158
  } catch {
15864
16159
  }
15865
- } else if (existsSync4(path)) {
16160
+ } else if (existsSync5(path)) {
15866
16161
  return flavor;
15867
16162
  }
15868
16163
  }
@@ -15871,16 +16166,16 @@ function detectFlavor(cwd) {
15871
16166
  }
15872
16167
  function findFile(cwd, candidates) {
15873
16168
  for (const c of candidates) {
15874
- if (existsSync4(join27(cwd, c))) return c;
16169
+ if (existsSync5(join28(cwd, c))) return c;
15875
16170
  }
15876
16171
  return null;
15877
16172
  }
15878
16173
  function findSourceRoots(cwd) {
15879
16174
  const roots = [];
15880
16175
  for (const r of SOURCE_ROOT_CANDIDATES) {
15881
- const p = join27(cwd, r);
16176
+ const p = join28(cwd, r);
15882
16177
  try {
15883
- const s = statSync4(p);
16178
+ const s = statSync5(p);
15884
16179
  if (s.isDirectory()) roots.push(r);
15885
16180
  } catch {
15886
16181
  }
@@ -15889,9 +16184,9 @@ function findSourceRoots(cwd) {
15889
16184
  }
15890
16185
  function findCiConfig(cwd) {
15891
16186
  for (const c of CI_PATHS) {
15892
- if (existsSync4(join27(cwd, c))) {
16187
+ if (existsSync5(join28(cwd, c))) {
15893
16188
  try {
15894
- const s = statSync4(join27(cwd, c));
16189
+ const s = statSync5(join28(cwd, c));
15895
16190
  return s.isDirectory() ? c : c;
15896
16191
  } catch {
15897
16192
  }
@@ -16028,7 +16323,7 @@ function analyzeProject(cwd) {
16028
16323
  ciConfig: findCiConfig(cwd),
16029
16324
  readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
16030
16325
  sourceRoots: findSourceRoots(cwd),
16031
- hasGit: existsSync4(join27(cwd, ".git"))
16326
+ hasGit: existsSync5(join28(cwd, ".git"))
16032
16327
  };
16033
16328
  }
16034
16329
  function bashDiscoveryCommands(profile) {
@@ -16193,7 +16488,7 @@ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
16193
16488
  }
16194
16489
  function buildInitPrompt(cwd) {
16195
16490
  const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
16196
- (n) => existsSync4(join27(cwd, n))
16491
+ (n) => existsSync5(join28(cwd, n))
16197
16492
  );
16198
16493
  const isRefresh = existingName !== void 0;
16199
16494
  const targetFilename = existingName ?? "KIMI.md";
@@ -16281,11 +16576,11 @@ __export(ui_mode_exports, {
16281
16576
  runCamouflageOnboarding: () => runCamouflageOnboarding,
16282
16577
  runUiMode: () => runUiMode
16283
16578
  });
16284
- import { execSync as execSync4, spawn as spawn5 } from "child_process";
16579
+ import { execSync as execSync5, spawn as spawn6 } from "child_process";
16285
16580
  import { appendFileSync, openSync } from "fs";
16286
16581
  import { readdir as readdir7, unlink as unlink4 } from "fs/promises";
16287
- import { join as join28, relative as relative6 } from "path";
16288
- import { platform as platform4 } from "os";
16582
+ import { join as join29, relative as relative6 } from "path";
16583
+ import { platform as platform5 } from "os";
16289
16584
  function kimiLog(payload) {
16290
16585
  if (!KIMI_LOG_PATH) return;
16291
16586
  try {
@@ -17067,6 +17362,14 @@ Executor opened PR: ${prUrl}` : plan });
17067
17362
  cam.send("StatusUpdate", {
17068
17363
  segments: { tokens: "in 0", cost: "$0.00", elapsed: "" }
17069
17364
  });
17365
+ rebuildSystemPromptForMode(
17366
+ messages,
17367
+ false,
17368
+ // Camouflage UI always uses single system message
17369
+ opts2.model,
17370
+ currentMode,
17371
+ ALL_TOOLS
17372
+ );
17070
17373
  messages.push({ role: "user", content: selected.plan });
17071
17374
  cam.send("UserMessageCreated", { text: selected.plan });
17072
17375
  cam.send("ShowToast", {
@@ -17129,7 +17432,7 @@ Executor opened PR: ${prUrl}` : plan });
17129
17432
  allow_cancel: true
17130
17433
  });
17131
17434
  if (pick3.cancelled || !pick3.value) return;
17132
- openBrowser(
17435
+ openBrowser2(
17133
17436
  `${URL2}/inbox?u=${encodeURIComponent(handle)}&s=${encodeURIComponent(secret)}&m=${encodeURIComponent(pick3.value)}`
17134
17437
  );
17135
17438
  cam.send("ShowToast", { text: "opened in browser", kind: "success", ttl_ms: 1500 });
@@ -18246,7 +18549,7 @@ Executor opened PR: ${prUrl}` : plan });
18246
18549
  return true;
18247
18550
  }
18248
18551
  case "hello":
18249
- openBrowser("https://hello.kimiflare.com");
18552
+ openBrowser2("https://hello.kimiflare.com");
18250
18553
  cam.send("ShowToast", { text: "opened hello.kimiflare.com \u2014 leave the creator a voice note", kind: "info", ttl_ms: 3500 });
18251
18554
  return true;
18252
18555
  case "inbox":
@@ -18282,6 +18585,14 @@ Executor opened PR: ${prUrl}` : plan });
18282
18585
  cam.send("StatusUpdate", {
18283
18586
  segments: { tokens: "in 0", cost: "$0.00", elapsed: "" }
18284
18587
  });
18588
+ rebuildSystemPromptForMode(
18589
+ messages,
18590
+ false,
18591
+ // Camouflage UI always uses single system message
18592
+ opts2.model,
18593
+ currentMode,
18594
+ ALL_TOOLS
18595
+ );
18285
18596
  messages.push({ role: "user", content: plan });
18286
18597
  cam.send("ShowToast", {
18287
18598
  text: clipResult.success ? "Plan copied to clipboard. Starting fresh session with plan only\u2026" : "Clipboard unavailable. Starting fresh session with plan only\u2026",
@@ -18355,7 +18666,7 @@ async function registerMentions(cam, recents) {
18355
18666
  for (const e of entries) {
18356
18667
  if (collected.length >= 200) return;
18357
18668
  if (e.name.startsWith(".") || SKIP.has(e.name)) continue;
18358
- const full = join28(dir, e.name);
18669
+ const full = join29(dir, e.name);
18359
18670
  if (e.isDirectory()) {
18360
18671
  await walk2(full, depth + 1);
18361
18672
  } else if (e.isFile()) {
@@ -18404,9 +18715,9 @@ function formatShortDate(iso) {
18404
18715
  return iso;
18405
18716
  }
18406
18717
  }
18407
- function openBrowser(url) {
18408
- const cmd = platform4() === "darwin" ? "open" : platform4() === "win32" ? "start" : "xdg-open";
18409
- const child = spawn5(cmd, [url], { detached: true, stdio: "ignore" });
18718
+ function openBrowser2(url) {
18719
+ const cmd = platform5() === "darwin" ? "open" : platform5() === "win32" ? "start" : "xdg-open";
18720
+ const child = spawn6(cmd, [url], { detached: true, stdio: "ignore" });
18410
18721
  child.unref();
18411
18722
  }
18412
18723
  function formatUsd(n) {
@@ -18425,7 +18736,7 @@ function formatElapsed2(secs) {
18425
18736
  }
18426
18737
  function tryGitBranch2() {
18427
18738
  try {
18428
- const out = execSync4("git rev-parse --abbrev-ref HEAD 2>/dev/null", {
18739
+ const out = execSync5("git rev-parse --abbrev-ref HEAD 2>/dev/null", {
18429
18740
  encoding: "utf8",
18430
18741
  timeout: 200
18431
18742
  }).trim();
@@ -18530,6 +18841,7 @@ var init_ui_mode = __esm({
18530
18841
  init_classify();
18531
18842
  init_deploy_commute();
18532
18843
  init_system_prompt();
18844
+ init_app_helpers();
18533
18845
  init_executor();
18534
18846
  init_errors();
18535
18847
  init_builtins();
@@ -21017,7 +21329,7 @@ var init_text_input = __esm({
21017
21329
  // src/ui/permission.tsx
21018
21330
  import { useState as useState4, useCallback } from "react";
21019
21331
  import { Box as Box7, Text as Text8, useInput as useInput2 } from "ink";
21020
- import { platform as platform5 } from "os";
21332
+ import { platform as platform6 } from "os";
21021
21333
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
21022
21334
  function formatSelection(label, shortcut) {
21023
21335
  return `${label} [${MOD_KEY}+${shortcut}]`;
@@ -21181,7 +21493,7 @@ var init_permission = __esm({
21181
21493
  { value: { decision: "deny", scope: "once" }, label: "Something else", key: 3 }
21182
21494
  ];
21183
21495
  DENY = { decision: "deny", scope: "once" };
21184
- MOD_KEY = platform5() === "darwin" ? "\u2325" : "Alt";
21496
+ MOD_KEY = platform6() === "darwin" ? "\u2325" : "Alt";
21185
21497
  }
21186
21498
  });
21187
21499
 
@@ -21619,7 +21931,7 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
21619
21931
  const allDone = done === total;
21620
21932
  const header = active ? active.title : allDone ? `${total} tasks done` : `${done}/${total}`;
21621
21933
  const elapsed = startedAt ? formatElapsed5(now2 - startedAt) : null;
21622
- const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
21934
+ const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens2(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
21623
21935
  const visibleTasks = tasks.slice(0, MAX_VISIBLE);
21624
21936
  const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
21625
21937
  return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
@@ -21671,7 +21983,7 @@ function formatElapsed5(ms) {
21671
21983
  if (m === 0) return `${s}s`;
21672
21984
  return `${m}m ${s}s`;
21673
21985
  }
21674
- function formatTokens(n) {
21986
+ function formatTokens2(n) {
21675
21987
  if (n < 1e3) return String(n);
21676
21988
  return `${(n / 1e3).toFixed(1)}k`;
21677
21989
  }
@@ -23210,54 +23522,15 @@ function Welcome() {
23210
23522
  day: now2.getDay()
23211
23523
  });
23212
23524
  return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginBottom: 1, children: [
23213
- /* @__PURE__ */ jsx20(Box18, { marginBottom: 1, children: /* @__PURE__ */ jsx20(Text19, { bold: true, color: theme.accent, children: headline }) }),
23214
- /* @__PURE__ */ jsx20(Box18, { flexDirection: "column", children: /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: true, children: "Type / for commands" }) })
23215
- ] });
23216
- }
23217
- var init_welcome = __esm({
23218
- "src/ui/welcome.tsx"() {
23219
- "use strict";
23220
- init_theme_context();
23221
- init_greetings();
23222
- }
23223
- });
23224
-
23225
- // src/util/image.ts
23226
- import { readFile as readFile17 } from "fs/promises";
23227
- import { basename as basename4 } from "path";
23228
- async function encodeImageFile(filePath) {
23229
- const buf = await readFile17(filePath);
23230
- if (buf.byteLength > MAX_IMAGE_BYTES) {
23231
- throw new Error(
23232
- `image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
23233
- );
23234
- }
23235
- const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
23236
- const mime = EXT_TO_MIME[ext] ?? "image/jpeg";
23237
- const b64 = buf.toString("base64");
23238
- return {
23239
- filename: basename4(filePath),
23240
- mime,
23241
- dataUrl: `data:${mime};base64,${b64}`
23242
- };
23243
- }
23244
- function isImagePath(path) {
23245
- const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
23246
- return ext in EXT_TO_MIME;
23525
+ /* @__PURE__ */ jsx20(Box18, { marginBottom: 1, children: /* @__PURE__ */ jsx20(Text19, { bold: true, color: theme.accent, children: headline }) }),
23526
+ /* @__PURE__ */ jsx20(Box18, { flexDirection: "column", children: /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: true, children: "Type / for commands" }) })
23527
+ ] });
23247
23528
  }
23248
- var MAX_IMAGE_BYTES, EXT_TO_MIME;
23249
- var init_image = __esm({
23250
- "src/util/image.ts"() {
23529
+ var init_welcome = __esm({
23530
+ "src/ui/welcome.tsx"() {
23251
23531
  "use strict";
23252
- MAX_IMAGE_BYTES = 5 * 1024 * 1024;
23253
- EXT_TO_MIME = {
23254
- ".png": "image/png",
23255
- ".jpg": "image/jpeg",
23256
- ".jpeg": "image/jpeg",
23257
- ".gif": "image/gif",
23258
- ".webp": "image/webp",
23259
- ".bmp": "image/bmp"
23260
- };
23532
+ init_theme_context();
23533
+ init_greetings();
23261
23534
  }
23262
23535
  });
23263
23536
 
@@ -23494,10 +23767,10 @@ var init_wcag = __esm({
23494
23767
 
23495
23768
  // src/ui/theme-loader.ts
23496
23769
  import { readFile as readFile18, readdir as readdir8 } from "fs/promises";
23497
- import { join as join29 } from "path";
23770
+ import { join as join30 } from "path";
23498
23771
  import { homedir as homedir15 } from "os";
23499
23772
  function projectThemesDir(cwd = process.cwd()) {
23500
- return join29(cwd, ".kimiflare", "themes");
23773
+ return join30(cwd, ".kimiflare", "themes");
23501
23774
  }
23502
23775
  function isHexColor(c) {
23503
23776
  return /^#[0-9a-fA-F]{6}$/.test(c);
@@ -23586,7 +23859,7 @@ async function loadThemesFromDir(dir, source) {
23586
23859
  return { themes, errors };
23587
23860
  }
23588
23861
  for (const file of files.filter((f) => f.endsWith(".json"))) {
23589
- const path = join29(dir, file);
23862
+ const path = join30(dir, file);
23590
23863
  let raw;
23591
23864
  try {
23592
23865
  raw = await readFile18(path, "utf-8");
@@ -23735,8 +24008,8 @@ var init_theme_loader = __esm({
23735
24008
  "use strict";
23736
24009
  init_wcag();
23737
24010
  init_theme();
23738
- USER_THEMES_DIR = join29(
23739
- process.env.XDG_CONFIG_HOME || join29(homedir15(), ".config"),
24011
+ USER_THEMES_DIR = join30(
24012
+ process.env.XDG_CONFIG_HOME || join30(homedir15(), ".config"),
23740
24013
  "kimiflare",
23741
24014
  "themes"
23742
24015
  );
@@ -24823,7 +25096,7 @@ var init_command_list = __esm({
24823
25096
  import { useState as useState18 } from "react";
24824
25097
  import { Box as Box25, Text as Text26 } from "ink";
24825
25098
  import SelectInput10 from "ink-select-input";
24826
- import { spawn as spawn6 } from "child_process";
25099
+ import { spawn as spawn7 } from "child_process";
24827
25100
  import { jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
24828
25101
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
24829
25102
  const theme = useTheme();
@@ -24837,7 +25110,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
24837
25110
  const runInstall = (command) => {
24838
25111
  setInstallState({ status: "running", output: "Installing..." });
24839
25112
  const { shell, args } = getShellCommand();
24840
- const child = spawn6(shell, [...args, command], {
25113
+ const child = spawn7(shell, [...args, command], {
24841
25114
  env: process.env
24842
25115
  });
24843
25116
  let stdout = "";
@@ -25863,7 +26136,7 @@ function formatSessionLine(s) {
25863
26136
  const ago = formatAgo(new Date(s.updatedAt));
25864
26137
  const prompt = s.prompt.slice(0, 30) + (s.prompt.length > 30 ? "\u2026" : "");
25865
26138
  const outcome = s.prUrl ? `PR ${s.prUrl.split("/").pop()}` : s.status;
25866
- const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens2(s.tokensUsed)}/${formatTokens2(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens2(s.tokensUsed)})` : "";
26139
+ const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens3(s.tokensUsed)}/${formatTokens3(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens3(s.tokensUsed)})` : "";
25867
26140
  return `${icon} ${prompt} \u2192 ${outcome} ${ago}${cost}`;
25868
26141
  }
25869
26142
  function formatAgo(date) {
@@ -25876,7 +26149,7 @@ function formatAgo(date) {
25876
26149
  if (minutes > 0) return `${minutes}m ago`;
25877
26150
  return "just now";
25878
26151
  }
25879
- function formatTokens2(n) {
26152
+ function formatTokens3(n) {
25880
26153
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
25881
26154
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
25882
26155
  return String(n);
@@ -25937,8 +26210,8 @@ function RemoteSessionDetail({
25937
26210
  ] }),
25938
26211
  session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs33(Text34, { children: [
25939
26212
  "Tokens: ",
25940
- formatTokens2(session.tokensUsed),
25941
- session.tokensBudget ? ` / ${formatTokens2(session.tokensBudget)}` : ""
26213
+ formatTokens3(session.tokensUsed),
26214
+ session.tokensBudget ? ` / ${formatTokens3(session.tokensBudget)}` : ""
25942
26215
  ] }),
25943
26216
  /* @__PURE__ */ jsxs33(Text34, { children: [
25944
26217
  "Created: ",
@@ -25982,7 +26255,7 @@ function InboxModal({ onDone, onOpen }) {
25982
26255
  setError(null);
25983
26256
  try {
25984
26257
  const res = await fetch(
25985
- `${FEEDBACK_WORKER_URL}/inbox/check?u=${encodeURIComponent(u)}&s=${encodeURIComponent(s)}`
26258
+ `${FEEDBACK_WORKER_URL2}/inbox/check?u=${encodeURIComponent(u)}&s=${encodeURIComponent(s)}`
25986
26259
  );
25987
26260
  if (!res.ok) {
25988
26261
  throw new Error(`Server returned ${res.status}`);
@@ -26028,7 +26301,7 @@ function InboxModal({ onDone, onOpen }) {
26028
26301
  if (messages.length === 0) return;
26029
26302
  const msg = messages[selectedIndex];
26030
26303
  if (!msg) return;
26031
- const url = `${FEEDBACK_WORKER_URL}/inbox?u=${encodeURIComponent(twitter)}&s=${encodeURIComponent(secret)}&m=${encodeURIComponent(msg.id)}`;
26304
+ const url = `${FEEDBACK_WORKER_URL2}/inbox?u=${encodeURIComponent(twitter)}&s=${encodeURIComponent(secret)}&m=${encodeURIComponent(msg.id)}`;
26032
26305
  onOpen(url);
26033
26306
  onDone();
26034
26307
  }, [messages, selectedIndex, twitter, secret, onOpen, onDone]);
@@ -26127,255 +26400,13 @@ function InboxModal({ onDone, onOpen }) {
26127
26400
  ] })
26128
26401
  ] });
26129
26402
  }
26130
- var FEEDBACK_WORKER_URL;
26403
+ var FEEDBACK_WORKER_URL2;
26131
26404
  var init_inbox_modal = __esm({
26132
26405
  "src/ui/inbox-modal.tsx"() {
26133
26406
  "use strict";
26134
26407
  init_text_input();
26135
26408
  init_theme_context();
26136
- FEEDBACK_WORKER_URL = "https://hello.kimiflare.com";
26137
- }
26138
- });
26139
-
26140
- // src/ui/app-helpers.ts
26141
- import { execSync as execSync5, spawn as spawn7 } from "child_process";
26142
- import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync5 } from "fs";
26143
- import { join as join30 } from "path";
26144
- import { platform as platform6 } from "os";
26145
- function buildFilePickerIgnoreList(cwd) {
26146
- const hardcoded = [
26147
- // Dependencies
26148
- "**/node_modules/**",
26149
- "**/vendor/**",
26150
- "**/.bundle/**",
26151
- "**/bower_components/**",
26152
- // Version control
26153
- "**/.git/**",
26154
- "**/.svn/**",
26155
- "**/.hg/**",
26156
- // Build / output directories
26157
- "**/dist/**",
26158
- "**/build/**",
26159
- "**/out/**",
26160
- "**/public/**",
26161
- "**/.next/**",
26162
- "**/.nuxt/**",
26163
- "**/.svelte-kit/**",
26164
- "**/.vercel/**",
26165
- "**/.netlify/**",
26166
- "**/target/**",
26167
- "**/bin/**",
26168
- "**/obj/**",
26169
- "**/Debug/**",
26170
- "**/Release/**",
26171
- "**/.gradle/**",
26172
- // Caches
26173
- "**/.cache/**",
26174
- "**/.parcel-cache/**",
26175
- "**/.turbo/**",
26176
- "**/.eslintcache",
26177
- "**/.stylelintcache",
26178
- "**/.rpt2_cache/**",
26179
- "**/.rts2_cache/**",
26180
- // Temporary
26181
- "**/tmp/**",
26182
- "**/temp/**",
26183
- "**/*.tmp",
26184
- // Coverage
26185
- "**/coverage/**",
26186
- "**/.nyc_output/**",
26187
- // OS files
26188
- "**/.DS_Store",
26189
- "**/Thumbs.db",
26190
- // Logs
26191
- "**/*.log",
26192
- "**/logs/**",
26193
- // Lock files (auto-generated, usually huge)
26194
- "**/package-lock.json",
26195
- "**/yarn.lock",
26196
- "**/pnpm-lock.yaml",
26197
- "**/bun.lockb",
26198
- "**/Cargo.lock",
26199
- "**/Gemfile.lock",
26200
- "**/composer.lock",
26201
- "**/Pipfile.lock",
26202
- "**/poetry.lock",
26203
- "**/go.sum",
26204
- // Minified / source maps
26205
- "**/*.min.js",
26206
- "**/*.min.css",
26207
- "**/*.map",
26208
- // kimiflare internal
26209
- "**/.kimiflare/**",
26210
- // IDE (usually not relevant to mention)
26211
- "**/.idea/**"
26212
- ];
26213
- const gitignorePatterns = [];
26214
- try {
26215
- const gitignorePath = join30(cwd, ".gitignore");
26216
- const stats = statSync5(gitignorePath);
26217
- if (stats.size > MAX_GITIGNORE_SIZE) {
26218
- return hardcoded;
26219
- }
26220
- const content = readFileSync4(gitignorePath, "utf-8");
26221
- for (const line of content.split(/\r?\n/)) {
26222
- const trimmed = line.trim();
26223
- if (!trimmed || trimmed.startsWith("#")) continue;
26224
- if (trimmed.startsWith("!")) continue;
26225
- let pattern = trimmed;
26226
- const isAnchored = pattern.startsWith("/");
26227
- const isDir = pattern.endsWith("/");
26228
- if (isAnchored) pattern = pattern.slice(1);
26229
- if (isDir) pattern = pattern.slice(0, -1);
26230
- if (!pattern) continue;
26231
- if (isAnchored) {
26232
- gitignorePatterns.push(isDir ? pattern + "/**" : pattern);
26233
- } else {
26234
- gitignorePatterns.push(isDir ? "**/" + pattern + "/**" : "**/" + pattern);
26235
- }
26236
- }
26237
- } catch {
26238
- }
26239
- return [...hardcoded, ...gitignorePatterns];
26240
- }
26241
- function gatewayFromConfig(cfg) {
26242
- if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
26243
- if (!cfg.aiGatewayId) return void 0;
26244
- return {
26245
- id: cfg.aiGatewayId,
26246
- cacheTtl: cfg.aiGatewayCacheTtl,
26247
- skipCache: cfg.aiGatewaySkipCache,
26248
- collectLogPayload: cfg.aiGatewayCollectLogPayload,
26249
- metadata: cfg.aiGatewayMetadata
26250
- };
26251
- }
26252
- function gatewayUsageLookupFromConfig(cfg, meta) {
26253
- if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
26254
- if (!cfg.aiGatewayId || !meta) return void 0;
26255
- return {
26256
- accountId: cfg.accountId,
26257
- apiToken: cfg.apiToken,
26258
- gatewayId: cfg.aiGatewayId,
26259
- meta
26260
- };
26261
- }
26262
- function openBrowser2(url) {
26263
- const cmd = platform6() === "darwin" ? "open" : platform6() === "win32" ? "start" : "xdg-open";
26264
- const child = spawn7(cmd, [url], { detached: true, stdio: "ignore" });
26265
- child.unref();
26266
- }
26267
- function detectGitHubRepo(cachedRepo) {
26268
- if (cachedRepo) {
26269
- const parts = cachedRepo.split("/");
26270
- if (parts.length === 2) return { owner: parts[0], name: parts[1] };
26271
- }
26272
- try {
26273
- const remoteUrl = execSync5("git remote get-url origin", { cwd: process.cwd(), encoding: "utf8" }).trim();
26274
- const httpsMatch = remoteUrl.match(/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
26275
- if (httpsMatch) return { owner: httpsMatch[1], name: httpsMatch[2] };
26276
- const sshMatch = remoteUrl.match(/github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
26277
- if (sshMatch) return { owner: sshMatch[1], name: sshMatch[2] };
26278
- } catch {
26279
- }
26280
- return null;
26281
- }
26282
- function detectGitBranch() {
26283
- try {
26284
- return execSync5("git branch --show-current", { cwd: process.cwd(), encoding: "utf8" }).trim() || null;
26285
- } catch {
26286
- return null;
26287
- }
26288
- }
26289
- function formatTokens3(n) {
26290
- if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
26291
- if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
26292
- return String(n);
26293
- }
26294
- function trackRecentFile(ref, path, max = 10) {
26295
- ref.current.set(path, Date.now());
26296
- if (ref.current.size > max) {
26297
- let oldest = null;
26298
- let oldestTime = Infinity;
26299
- for (const [p, t] of ref.current) {
26300
- if (t < oldestTime) {
26301
- oldestTime = t;
26302
- oldest = p;
26303
- }
26304
- }
26305
- if (oldest) ref.current.delete(oldest);
26306
- }
26307
- }
26308
- function capEvents(prev) {
26309
- if (prev.length <= MAX_EVENTS) return prev;
26310
- return prev.slice(prev.length - MAX_EVENTS);
26311
- }
26312
- function compactEventsVisual(prev, keepLastTurns) {
26313
- let seen = 0;
26314
- let cutoff = -1;
26315
- for (let i = prev.length - 1; i >= 0; i--) {
26316
- if (prev[i].kind === "user") {
26317
- seen++;
26318
- if (seen === keepLastTurns + 1) {
26319
- cutoff = i;
26320
- break;
26321
- }
26322
- }
26323
- }
26324
- if (cutoff <= 0) return prev;
26325
- const kept = prev.slice(cutoff);
26326
- return [
26327
- { kind: "info", key: mkKey(), text: `\xB7\xB7\xB7 ${cutoff} earlier messages compacted \xB7\xB7\xB7` },
26328
- ...kept
26329
- ];
26330
- }
26331
- function makePrefixMessages(cacheStable, model, mode, tools) {
26332
- if (cacheStable) {
26333
- return buildSystemMessages({ cwd: process.cwd(), tools, model, mode });
26334
- }
26335
- return [
26336
- {
26337
- role: "system",
26338
- content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode })
26339
- }
26340
- ];
26341
- }
26342
- function findImagePaths(text) {
26343
- const paths = [];
26344
- const quotedRegex = /"([^"]+)"|'([^']+)'/g;
26345
- let match;
26346
- while ((match = quotedRegex.exec(text)) !== null) {
26347
- const path = match[1] ?? match[2];
26348
- if (path && isImagePath(path) && existsSync5(path)) {
26349
- paths.push(path);
26350
- }
26351
- }
26352
- const remaining = text.replace(/"[^"]+"|'[^']+'/g, "");
26353
- const ESCAPED_SPACE = "\0";
26354
- const processed = remaining.replace(/\\ /g, ESCAPED_SPACE);
26355
- for (const token of processed.split(/\s+/)) {
26356
- const clean = token.replace(new RegExp(ESCAPED_SPACE, "g"), " ").replace(/^["']|["',;:!?]$/g, "").replace(/[.,;:!?]$/, "");
26357
- if (clean && isImagePath(clean) && existsSync5(clean) && !paths.includes(clean)) {
26358
- paths.push(clean);
26359
- }
26360
- }
26361
- return paths;
26362
- }
26363
- var MAX_GITIGNORE_SIZE, CONTEXT_LIMIT, AUTO_COMPACT_THRESHOLD, MAX_EVENTS, MAX_IMAGES_PER_MESSAGE, FEEDBACK_WORKER_URL2, nextKey, mkKey, nextAssistantId, mkAssistantId;
26364
- var init_app_helpers = __esm({
26365
- "src/ui/app-helpers.ts"() {
26366
- "use strict";
26367
- init_system_prompt();
26368
- init_image();
26369
- MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
26370
- CONTEXT_LIMIT = 262e3;
26371
- AUTO_COMPACT_THRESHOLD = 0.8;
26372
- MAX_EVENTS = 500;
26373
- MAX_IMAGES_PER_MESSAGE = 10;
26374
26409
  FEEDBACK_WORKER_URL2 = "https://hello.kimiflare.com";
26375
- nextKey = 1;
26376
- mkKey = () => `evt_${nextKey++}`;
26377
- nextAssistantId = 1;
26378
- mkAssistantId = () => nextAssistantId++;
26379
26410
  }
26380
26411
  });
26381
26412
 
@@ -26556,7 +26587,7 @@ function MultiAgentModal({ initial, onSave, onDone, remoteWorkerUrl, remoteAuthS
26556
26587
  if (deployFailed) {
26557
26588
  if (input === "o" || input === "O") {
26558
26589
  const url = deployLog.map((l) => l.match(/https:\/\/dash\.cloudflare\.com\/[^\s)]+/)?.[0]).find((u) => !!u) ?? "https://dash.cloudflare.com/profile/api-tokens";
26559
- openBrowser2(url);
26590
+ openBrowser(url);
26560
26591
  return;
26561
26592
  }
26562
26593
  if (input === "r" || input === "R") {
@@ -28465,6 +28496,13 @@ function executeFreshStart(ctx, planText) {
28465
28496
  ctx.compactSuggestedRef.current = false;
28466
28497
  ctx.updateNudgedRef.current = false;
28467
28498
  ctx.sessionPlanRef.current = null;
28499
+ rebuildSystemPromptForMode(
28500
+ ctx.messagesRef.current,
28501
+ ctx.cacheStableRef.current,
28502
+ ctx.cfg?.model ?? "@cf/moonshotai/kimi-k2.6",
28503
+ ctx.mode,
28504
+ [...ALL_TOOLS, ...ctx.mcpToolsRef.current, ...ctx.lspToolsRef.current]
28505
+ );
28468
28506
  ctx.messagesRef.current.push({ role: "user", content: planText });
28469
28507
  const newSessionId = ctx.ensureSessionId();
28470
28508
  if (oldSessionId) {
@@ -28497,6 +28535,7 @@ var init_slash_commands = __esm({
28497
28535
  init_manager4();
28498
28536
  init_sessions();
28499
28537
  init_session_state();
28538
+ init_executor();
28500
28539
  init_recommended();
28501
28540
  init_settings();
28502
28541
  init_types2();
@@ -29555,8 +29594,8 @@ project: ${projectSettingsPath(cwd)}`
29555
29594
  handleHello = (ctx) => {
29556
29595
  const { setEvents, mkKey: mkKey2 } = ctx;
29557
29596
  const session = crypto.randomUUID();
29558
- const url = `${FEEDBACK_WORKER_URL2}/?s=${session}&v=${getAppVersion()}`;
29559
- openBrowser2(url);
29597
+ const url = `${FEEDBACK_WORKER_URL}/?s=${session}&v=${getAppVersion()}`;
29598
+ openBrowser(url);
29560
29599
  void (async () => {
29561
29600
  try {
29562
29601
  const qr = await QRCode.toString(url, { type: "terminal", small: true });
@@ -29709,7 +29748,7 @@ project: ${projectSettingsPath(cwd)}`
29709
29748
  setEvents((e) => [
29710
29749
  ...e,
29711
29750
  { kind: "info", key: mkKey2(), text: `Starting remote session for ${repo.owner}/${repo.name}...` },
29712
- { kind: "info", key: mkKey2(), text: `Budget: ${formatTokens3(budget)} tokens. TTL: ${ttl} min.` }
29751
+ { kind: "info", key: mkKey2(), text: `Budget: ${formatTokens(budget)} tokens. TTL: ${ttl} min.` }
29713
29752
  ]);
29714
29753
  try {
29715
29754
  const data = await startRemoteSession({
@@ -31946,6 +31985,13 @@ ${wcagWarnings.join("\n")}` }
31946
31985
  }
31947
31986
  setMode(picked);
31948
31987
  modeRef.current = picked;
31988
+ rebuildSystemPromptForMode(
31989
+ messagesRef.current,
31990
+ cacheStableRef.current,
31991
+ cfg?.model ?? DEFAULT_MODEL,
31992
+ picked,
31993
+ [...ALL_TOOLS, ...mcpToolsRef.current, ...lspToolsRef.current]
31994
+ );
31949
31995
  submitRef.current(plan);
31950
31996
  },
31951
31997
  [mkKey, setShowPlanCompletePicker, setMode, setEvents, setUsage, setSessionUsage, setGatewayMeta, clearTaskTracking, resetSession, submitRef]
@@ -33018,7 +33064,7 @@ ${conflicts.join("\n")}` }
33018
33064
  selectedRemoteSession,
33019
33065
  onSelectRemoteSession: setSelectedRemoteSession,
33020
33066
  onCancelRemoteSession: handleRemoteCancel2,
33021
- onInboxOpen: openBrowser2,
33067
+ onInboxOpen: openBrowser,
33022
33068
  multiAgentSettings: cfg ? {
33023
33069
  multiAgentEnabled: cfg.multiAgentEnabled,
33024
33070
  workerEndpoint: cfg.workerEndpoint,