kimiflare 0.84.0 → 0.85.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 +1803 -829
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.d.ts +12 -0
- package/dist/sdk/index.js +448 -40
- package/dist/sdk/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -4277,7 +4277,11 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
4277
4277
|
sessionId: opts2.sessionId,
|
|
4278
4278
|
githubToken: opts2.githubToken,
|
|
4279
4279
|
shell: opts2.shell,
|
|
4280
|
-
intentTier: opts2.intentClassification?.tier
|
|
4280
|
+
intentTier: opts2.intentClassification?.tier,
|
|
4281
|
+
accountId: opts2.accountId,
|
|
4282
|
+
apiToken: opts2.apiToken,
|
|
4283
|
+
model: opts2.model,
|
|
4284
|
+
gateway: opts2.gateway
|
|
4281
4285
|
},
|
|
4282
4286
|
opts2.onFileChange
|
|
4283
4287
|
);
|
|
@@ -5640,13 +5644,81 @@ function makeOutput(content) {
|
|
|
5640
5644
|
function getToken(ctx) {
|
|
5641
5645
|
return ctx.githubToken || process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
|
|
5642
5646
|
}
|
|
5643
|
-
var GITHUB_API_BASE, TIMEOUT_MS3, githubReadPrTool, githubReadIssueTool, githubReadCodeTool;
|
|
5647
|
+
var GITHUB_API_BASE, TIMEOUT_MS3, githubListMergedPrsTool, githubListReleasesTool, githubReadPrTool, githubReadIssueTool, githubReadCodeTool;
|
|
5644
5648
|
var init_github = __esm({
|
|
5645
5649
|
"src/tools/github.ts"() {
|
|
5646
5650
|
"use strict";
|
|
5647
5651
|
init_version();
|
|
5648
5652
|
GITHUB_API_BASE = "https://api.github.com";
|
|
5649
5653
|
TIMEOUT_MS3 = 2e4;
|
|
5654
|
+
githubListMergedPrsTool = {
|
|
5655
|
+
name: "github_list_merged_prs",
|
|
5656
|
+
description: "List merged pull requests for a repository within the last N days. Returns PR number, title, author, merge date, and URL for each merged PR.",
|
|
5657
|
+
parameters: {
|
|
5658
|
+
type: "object",
|
|
5659
|
+
properties: {
|
|
5660
|
+
owner: { type: "string", description: "Repository owner (user or organization)." },
|
|
5661
|
+
repo: { type: "string", description: "Repository name." },
|
|
5662
|
+
days: { type: "integer", description: "Number of days to look back. Default: 7.", minimum: 1, maximum: 90 }
|
|
5663
|
+
},
|
|
5664
|
+
required: ["owner", "repo"],
|
|
5665
|
+
additionalProperties: false
|
|
5666
|
+
},
|
|
5667
|
+
needsPermission: false,
|
|
5668
|
+
render: (args) => ({ title: `GitHub merged PRs ${args.owner ?? ""}/${args.repo ?? ""}` }),
|
|
5669
|
+
async run(args, ctx) {
|
|
5670
|
+
const token = getToken(ctx);
|
|
5671
|
+
const days = args.days ?? 7;
|
|
5672
|
+
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
5673
|
+
const prs = await githubFetch(
|
|
5674
|
+
`/repos/${args.owner}/${args.repo}/pulls?state=closed&sort=updated&direction=desc&per_page=100`,
|
|
5675
|
+
token
|
|
5676
|
+
);
|
|
5677
|
+
const merged = prs.filter((p) => p.merged_at && p.merged_at >= since).sort((a, b) => (b.merged_at ?? "").localeCompare(a.merged_at ?? ""));
|
|
5678
|
+
if (merged.length === 0) {
|
|
5679
|
+
return makeOutput(`No merged PRs in ${args.owner}/${args.repo} within the last ${days} day(s).`);
|
|
5680
|
+
}
|
|
5681
|
+
const lines = merged.map(
|
|
5682
|
+
(p) => `#${p.number} ${p.title} \u2014 @${p.user.login} \u2014 merged ${p.merged_at.slice(0, 10)} \u2014 ${p.html_url}`
|
|
5683
|
+
);
|
|
5684
|
+
return makeOutput(
|
|
5685
|
+
[`Merged PRs in ${args.owner}/${args.repo} (last ${days} days):`, "", ...lines].join("\n")
|
|
5686
|
+
);
|
|
5687
|
+
}
|
|
5688
|
+
};
|
|
5689
|
+
githubListReleasesTool = {
|
|
5690
|
+
name: "github_list_releases",
|
|
5691
|
+
description: "List recent GitHub releases for a repository. Returns tag name, name, published date, and URL for each release.",
|
|
5692
|
+
parameters: {
|
|
5693
|
+
type: "object",
|
|
5694
|
+
properties: {
|
|
5695
|
+
owner: { type: "string", description: "Repository owner (user or organization)." },
|
|
5696
|
+
repo: { type: "string", description: "Repository name." },
|
|
5697
|
+
limit: { type: "integer", description: "Max releases to return. Default: 5.", minimum: 1, maximum: 20 }
|
|
5698
|
+
},
|
|
5699
|
+
required: ["owner", "repo"],
|
|
5700
|
+
additionalProperties: false
|
|
5701
|
+
},
|
|
5702
|
+
needsPermission: false,
|
|
5703
|
+
render: (args) => ({ title: `GitHub releases ${args.owner ?? ""}/${args.repo ?? ""}` }),
|
|
5704
|
+
async run(args, ctx) {
|
|
5705
|
+
const token = getToken(ctx);
|
|
5706
|
+
const limit = args.limit ?? 5;
|
|
5707
|
+
const releases = await githubFetch(
|
|
5708
|
+
`/repos/${args.owner}/${args.repo}/releases?per_page=${limit}`,
|
|
5709
|
+
token
|
|
5710
|
+
);
|
|
5711
|
+
if (releases.length === 0) {
|
|
5712
|
+
return makeOutput(`No releases found for ${args.owner}/${args.repo}.`);
|
|
5713
|
+
}
|
|
5714
|
+
const lines = releases.map(
|
|
5715
|
+
(r) => `${r.tag_name} \u2014 ${r.name} \u2014 published ${r.published_at.slice(0, 10)} \u2014 ${r.html_url}`
|
|
5716
|
+
);
|
|
5717
|
+
return makeOutput(
|
|
5718
|
+
[`Releases for ${args.owner}/${args.repo}:`, "", ...lines].join("\n")
|
|
5719
|
+
);
|
|
5720
|
+
}
|
|
5721
|
+
};
|
|
5650
5722
|
githubReadPrTool = {
|
|
5651
5723
|
name: "github_read_pr",
|
|
5652
5724
|
description: "Read a GitHub pull request by owner, repo, and PR number. Returns title, body, state, author, created/updated dates, and a summary of changed files. Use this in plan mode or when you need structured PR data without write permissions.",
|
|
@@ -5772,10 +5844,354 @@ var init_github = __esm({
|
|
|
5772
5844
|
}
|
|
5773
5845
|
});
|
|
5774
5846
|
|
|
5847
|
+
// src/tools/changelog-image.ts
|
|
5848
|
+
var changelog_image_exports = {};
|
|
5849
|
+
__export(changelog_image_exports, {
|
|
5850
|
+
changelogImageTool: () => changelogImageTool
|
|
5851
|
+
});
|
|
5852
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
5853
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
5854
|
+
import { join as join11 } from "path";
|
|
5855
|
+
import { Resvg } from "@resvg/resvg-js";
|
|
5856
|
+
async function githubFetch2(path, token) {
|
|
5857
|
+
const controller = new AbortController();
|
|
5858
|
+
const timer2 = setTimeout(() => controller.abort(), TIMEOUT_MS4);
|
|
5859
|
+
try {
|
|
5860
|
+
const headers = {
|
|
5861
|
+
Accept: "application/vnd.github+json",
|
|
5862
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
5863
|
+
};
|
|
5864
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
5865
|
+
const res = await fetch(`${GITHUB_API_BASE2}${path}`, {
|
|
5866
|
+
signal: controller.signal,
|
|
5867
|
+
headers
|
|
5868
|
+
});
|
|
5869
|
+
if (!res.ok) {
|
|
5870
|
+
const body = await res.text().catch(() => "");
|
|
5871
|
+
throw new Error(`GitHub API ${res.status}: ${res.statusText}${body ? ` \u2014 ${body.slice(0, 200)}` : ""}`);
|
|
5872
|
+
}
|
|
5873
|
+
return await res.json();
|
|
5874
|
+
} finally {
|
|
5875
|
+
clearTimeout(timer2);
|
|
5876
|
+
}
|
|
5877
|
+
}
|
|
5878
|
+
function getToken2(ctx) {
|
|
5879
|
+
return ctx.githubToken;
|
|
5880
|
+
}
|
|
5881
|
+
function escapeXml(str) {
|
|
5882
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
5883
|
+
}
|
|
5884
|
+
async function loadLogoBase64() {
|
|
5885
|
+
try {
|
|
5886
|
+
const buf = await readFile7(join11(process.cwd(), "docs", "logo.png"));
|
|
5887
|
+
return `data:image/png;base64,${buf.toString("base64")}`;
|
|
5888
|
+
} catch {
|
|
5889
|
+
return null;
|
|
5890
|
+
}
|
|
5891
|
+
}
|
|
5892
|
+
function wrapText(text, maxWidth, fontSize) {
|
|
5893
|
+
const avgCharWidth = fontSize * 0.55;
|
|
5894
|
+
const maxChars = Math.floor(maxWidth / avgCharWidth);
|
|
5895
|
+
const lines = [];
|
|
5896
|
+
const rawLines = text.split("\n");
|
|
5897
|
+
for (const raw of rawLines) {
|
|
5898
|
+
const trimmed = raw.trim();
|
|
5899
|
+
if (!trimmed) {
|
|
5900
|
+
lines.push("");
|
|
5901
|
+
continue;
|
|
5902
|
+
}
|
|
5903
|
+
let remaining = trimmed;
|
|
5904
|
+
while (remaining.length > maxChars) {
|
|
5905
|
+
let cut = maxChars;
|
|
5906
|
+
while (cut > 0 && remaining[cut] !== " ") cut--;
|
|
5907
|
+
if (cut === 0) cut = maxChars;
|
|
5908
|
+
lines.push(remaining.slice(0, cut).trimEnd());
|
|
5909
|
+
remaining = remaining.slice(cut).trimStart();
|
|
5910
|
+
}
|
|
5911
|
+
if (remaining) lines.push(remaining);
|
|
5912
|
+
}
|
|
5913
|
+
return lines;
|
|
5914
|
+
}
|
|
5915
|
+
async function summarizeWithLlm(prs, ctx) {
|
|
5916
|
+
if (!ctx.accountId || !ctx.apiToken || !ctx.model) {
|
|
5917
|
+
return prs.map((p) => `\u2022 ${p.title} [PR #${p.number}]`).join("\n");
|
|
5918
|
+
}
|
|
5919
|
+
const prDescriptions = prs.map((p) => {
|
|
5920
|
+
const bodySnippet = p.body ? `
|
|
5921
|
+
${p.body.slice(0, 300).replace(/\n/g, " ")}` : "";
|
|
5922
|
+
return `PR #${p.number}: ${p.title} (merged ${p.merged_at.slice(0, 10)} by @${p.user.login})${bodySnippet}`;
|
|
5923
|
+
}).join("\n\n");
|
|
5924
|
+
let summary = "";
|
|
5925
|
+
const events = runKimi({
|
|
5926
|
+
accountId: ctx.accountId,
|
|
5927
|
+
apiToken: ctx.apiToken,
|
|
5928
|
+
model: ctx.model,
|
|
5929
|
+
messages: [
|
|
5930
|
+
{ role: "system", content: CHANGELOG_SYSTEM_PROMPT },
|
|
5931
|
+
{
|
|
5932
|
+
role: "user",
|
|
5933
|
+
content: `Write a changelog summary for the following merged pull requests:
|
|
5934
|
+
|
|
5935
|
+
${prDescriptions}`
|
|
5936
|
+
}
|
|
5937
|
+
],
|
|
5938
|
+
signal: ctx.signal,
|
|
5939
|
+
temperature: 0.4,
|
|
5940
|
+
reasoningEffort: "low",
|
|
5941
|
+
gateway: ctx.gateway,
|
|
5942
|
+
idleTimeoutMs: 6e4
|
|
5943
|
+
});
|
|
5944
|
+
for await (const ev of events) {
|
|
5945
|
+
if (ev.type === "text") summary += ev.delta;
|
|
5946
|
+
}
|
|
5947
|
+
return summary.trim() || prs.map((p) => `\u2022 ${p.title} [PR #${p.number}]`).join("\n");
|
|
5948
|
+
}
|
|
5949
|
+
function buildChangelogSvg(opts2) {
|
|
5950
|
+
const { owner, repo, version, writeUp, logoBase64 } = opts2;
|
|
5951
|
+
const width = 900;
|
|
5952
|
+
const padX = 72;
|
|
5953
|
+
const padTop = 64;
|
|
5954
|
+
const padBottom = 56;
|
|
5955
|
+
const contentW = width - padX * 2;
|
|
5956
|
+
const repoFontSize = 22;
|
|
5957
|
+
const labelFontSize = 12;
|
|
5958
|
+
const bodyFontSize = 16;
|
|
5959
|
+
const bodyLineHeight = 24;
|
|
5960
|
+
const bulletIndent = 20;
|
|
5961
|
+
const bulletGap = 32;
|
|
5962
|
+
const paraGap = 8;
|
|
5963
|
+
const logoW = 28;
|
|
5964
|
+
const logoH = 28;
|
|
5965
|
+
const logoY = padTop + 4;
|
|
5966
|
+
const repoTextX = padX + (logoBase64 ? logoW + 14 : 0);
|
|
5967
|
+
const repoTextY = padTop + 24;
|
|
5968
|
+
const labelY = repoTextY + 32;
|
|
5969
|
+
const headerBottom = labelY + 32;
|
|
5970
|
+
const rawLines = writeUp.split("\n").map((l) => l.trim());
|
|
5971
|
+
const blocks = [];
|
|
5972
|
+
let currentBlock = null;
|
|
5973
|
+
for (const raw of rawLines) {
|
|
5974
|
+
if (!raw) {
|
|
5975
|
+
if (currentBlock) {
|
|
5976
|
+
blocks.push(currentBlock);
|
|
5977
|
+
currentBlock = null;
|
|
5978
|
+
}
|
|
5979
|
+
continue;
|
|
5980
|
+
}
|
|
5981
|
+
const isBullet = raw.startsWith("\u2022");
|
|
5982
|
+
const text = isBullet ? raw.slice(1).trim() : raw;
|
|
5983
|
+
if (!currentBlock || currentBlock.type !== (isBullet ? "bullet" : "paragraph")) {
|
|
5984
|
+
if (currentBlock) blocks.push(currentBlock);
|
|
5985
|
+
currentBlock = { type: isBullet ? "bullet" : "paragraph", lines: [] };
|
|
5986
|
+
}
|
|
5987
|
+
const wrapW = isBullet ? contentW - bulletIndent : contentW;
|
|
5988
|
+
const wrapped = wrapText(text, wrapW, bodyFontSize);
|
|
5989
|
+
currentBlock.lines.push(...wrapped);
|
|
5990
|
+
}
|
|
5991
|
+
if (currentBlock) blocks.push(currentBlock);
|
|
5992
|
+
let bodyHeight = 0;
|
|
5993
|
+
const lineMeta = [];
|
|
5994
|
+
let y = headerBottom;
|
|
5995
|
+
for (let b = 0; b < blocks.length; b++) {
|
|
5996
|
+
const block = blocks[b];
|
|
5997
|
+
for (let i = 0; i < block.lines.length; i++) {
|
|
5998
|
+
const line = block.lines[i];
|
|
5999
|
+
lineMeta.push({
|
|
6000
|
+
text: line,
|
|
6001
|
+
y,
|
|
6002
|
+
isBullet: block.type === "bullet",
|
|
6003
|
+
isFirst: i === 0
|
|
6004
|
+
});
|
|
6005
|
+
y += bodyLineHeight;
|
|
6006
|
+
if (block.type === "bullet" && i < block.lines.length - 1) {
|
|
6007
|
+
y += paraGap;
|
|
6008
|
+
}
|
|
6009
|
+
}
|
|
6010
|
+
if (b < blocks.length - 1) {
|
|
6011
|
+
y += bulletGap;
|
|
6012
|
+
}
|
|
6013
|
+
}
|
|
6014
|
+
bodyHeight = y - headerBottom;
|
|
6015
|
+
const height = headerBottom + bodyHeight + padBottom;
|
|
6016
|
+
const logoEl = logoBase64 ? `<image x="${padX}" y="${logoY}" width="${logoW}" height="${logoH}" href="${logoBase64}"/>` : "";
|
|
6017
|
+
const bodySpans = lineMeta.map(({ text, y: ly, isBullet, isFirst }) => {
|
|
6018
|
+
const x = isBullet ? padX + bulletIndent : padX;
|
|
6019
|
+
const weight = isBullet ? 'font-weight="500"' : "";
|
|
6020
|
+
const fill = isBullet ? "#1f2937" : "#4b5563";
|
|
6021
|
+
return `<tspan x="${x}" y="${ly}" fill="${fill}" ${weight}>${escapeXml(text)}</tspan>`;
|
|
6022
|
+
}).join("");
|
|
6023
|
+
const bulletDots = lineMeta.filter((m) => m.isBullet && m.isFirst).map(({ y: ly }) => {
|
|
6024
|
+
const cy = ly - bodyFontSize * 0.35;
|
|
6025
|
+
return `<circle cx="${padX + 6}" cy="${cy}" r="3" fill="#f97316"/>`;
|
|
6026
|
+
}).join("");
|
|
6027
|
+
const today4 = escapeXml((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
6028
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
6029
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
|
6030
|
+
<defs>
|
|
6031
|
+
<style>
|
|
6032
|
+
.font { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; }
|
|
6033
|
+
</style>
|
|
6034
|
+
</defs>
|
|
6035
|
+
|
|
6036
|
+
<!-- Background -->
|
|
6037
|
+
<rect width="${width}" height="${height}" fill="#ffffff"/>
|
|
6038
|
+
|
|
6039
|
+
<!-- Top accent bar -->
|
|
6040
|
+
<rect x="${padX}" y="${padTop}" width="36" height="3" fill="#f97316" rx="1.5"/>
|
|
6041
|
+
|
|
6042
|
+
<!-- Header -->
|
|
6043
|
+
<g class="font">
|
|
6044
|
+
${logoEl}
|
|
6045
|
+
<text x="${repoTextX}" y="${repoTextY}" fill="#111827" font-size="${repoFontSize}" font-weight="600">${escapeXml(owner)}/${escapeXml(repo)}</text>
|
|
6046
|
+
|
|
6047
|
+
<text x="${padX}" y="${labelY}" fill="#9ca3af" font-size="${labelFontSize}" font-weight="500" letter-spacing="0.08em">CHANGELOG</text>
|
|
6048
|
+
|
|
6049
|
+
<!-- Version pill -->
|
|
6050
|
+
<rect x="${padX + 88}" y="${labelY - 14}" width="${Math.max(40, version.length * 7 + 16)}" height="22" fill="#fff7ed" rx="11"/>
|
|
6051
|
+
<text x="${padX + 88 + 10}" y="${labelY}" fill="#f97316" font-size="${labelFontSize}" font-weight="500">${escapeXml(version)}</text>
|
|
6052
|
+
</g>
|
|
6053
|
+
|
|
6054
|
+
<!-- Separator -->
|
|
6055
|
+
<line x1="${padX}" y1="${headerBottom - 10}" x2="${width - padX}" y2="${headerBottom - 10}" stroke="#f3f4f6" stroke-width="1"/>
|
|
6056
|
+
|
|
6057
|
+
<!-- Body -->
|
|
6058
|
+
<g class="font">
|
|
6059
|
+
${bulletDots}
|
|
6060
|
+
<text font-size="${bodyFontSize}" line-height="${bodyLineHeight}">
|
|
6061
|
+
${bodySpans}
|
|
6062
|
+
</text>
|
|
6063
|
+
</g>
|
|
6064
|
+
|
|
6065
|
+
<!-- Footer -->
|
|
6066
|
+
<g class="font" transform="translate(0, ${height - padBottom + 20})">
|
|
6067
|
+
<text x="${padX}" y="0" fill="#d1d5db" font-size="11">Generated with KimiFlare \xB7 ${today4}</text>
|
|
6068
|
+
</g>
|
|
6069
|
+
</svg>`;
|
|
6070
|
+
}
|
|
6071
|
+
var GITHUB_API_BASE2, TIMEOUT_MS4, CHANGELOG_SYSTEM_PROMPT, changelogImageTool;
|
|
6072
|
+
var init_changelog_image = __esm({
|
|
6073
|
+
"src/tools/changelog-image.ts"() {
|
|
6074
|
+
"use strict";
|
|
6075
|
+
init_client();
|
|
6076
|
+
GITHUB_API_BASE2 = "https://api.github.com";
|
|
6077
|
+
TIMEOUT_MS4 = 2e4;
|
|
6078
|
+
CHANGELOG_SYSTEM_PROMPT = `You are a senior technical product writer. Your job is to write release notes that make users excited about new features while being completely accurate and grounded only in the provided pull requests.
|
|
6079
|
+
|
|
6080
|
+
Rules:
|
|
6081
|
+
- Write 3\u20136 bullet points maximum. Highlight only the most significant, user-facing changes.
|
|
6082
|
+
- Focus on USER VALUE and IMPACT, not implementation details or internal refactors.
|
|
6083
|
+
- Use confident, clear, engaging language \u2014 like Apple product release notes.
|
|
6084
|
+
- Group related changes under themes when it makes sense.
|
|
6085
|
+
- Each bullet should be 1\u20132 sentences.
|
|
6086
|
+
- Include the PR number in square brackets at the end of each bullet, e.g. [PR #123]
|
|
6087
|
+
- Do NOT include changes that are purely internal (chores, refactors, dependency updates, version bumps) unless they have clear user-facing impact.
|
|
6088
|
+
- Do NOT hallucinate features not present in the PRs.
|
|
6089
|
+
- If there are no meaningful user-facing changes, say so briefly.
|
|
6090
|
+
|
|
6091
|
+
Format your response as plain text bullet points, one per line, starting with "\u2022 ". Do not use markdown headers or bold/italic.`;
|
|
6092
|
+
changelogImageTool = {
|
|
6093
|
+
name: "changelog_image",
|
|
6094
|
+
description: "Generate a beautiful changelog image for a GitHub repository. Fetches merged PRs from the last N days, uses an LLM to write a creative summary, then renders a shareable PNG with the project logo, version, and highlights.",
|
|
6095
|
+
parameters: {
|
|
6096
|
+
type: "object",
|
|
6097
|
+
properties: {
|
|
6098
|
+
owner: { type: "string", description: "Repository owner (user or organization)." },
|
|
6099
|
+
repo: { type: "string", description: "Repository name." },
|
|
6100
|
+
days: { type: "integer", description: "Number of days to look back for merged PRs. Default: 7.", minimum: 1, maximum: 90 },
|
|
6101
|
+
output: { type: "string", description: "Output file path for the PNG. Default: ./changelog-<repo>-<version>.png" }
|
|
6102
|
+
},
|
|
6103
|
+
required: ["owner", "repo"],
|
|
6104
|
+
additionalProperties: false
|
|
6105
|
+
},
|
|
6106
|
+
needsPermission: false,
|
|
6107
|
+
render: (args) => ({ title: `Changelog image for ${args.owner ?? ""}/${args.repo ?? ""}` }),
|
|
6108
|
+
async run(args, ctx) {
|
|
6109
|
+
const token = getToken2(ctx);
|
|
6110
|
+
const days = args.days ?? 7;
|
|
6111
|
+
const tasks = [
|
|
6112
|
+
{ id: "1", title: "Fetch merged PRs from GitHub", status: "pending" },
|
|
6113
|
+
{ id: "2", title: "Determine latest version", status: "pending" },
|
|
6114
|
+
{ id: "3", title: "Summarize changes with LLM", status: "pending" },
|
|
6115
|
+
{ id: "4", title: "Render changelog image", status: "pending" },
|
|
6116
|
+
{ id: "5", title: "Save PNG to file", status: "pending" }
|
|
6117
|
+
];
|
|
6118
|
+
const setTask = (id, status) => {
|
|
6119
|
+
const t = tasks.find((x) => x.id === id);
|
|
6120
|
+
if (t) t.status = status;
|
|
6121
|
+
ctx.onTasks?.(tasks.map((x) => ({ ...x })));
|
|
6122
|
+
};
|
|
6123
|
+
setTask("1", "in_progress");
|
|
6124
|
+
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
6125
|
+
const prs = await githubFetch2(
|
|
6126
|
+
`/repos/${args.owner}/${args.repo}/pulls?state=closed&sort=updated&direction=desc&per_page=100`,
|
|
6127
|
+
token
|
|
6128
|
+
);
|
|
6129
|
+
const merged = prs.filter((p) => p.merged_at && p.merged_at >= since).sort((a, b) => (b.merged_at ?? "").localeCompare(a.merged_at ?? ""));
|
|
6130
|
+
if (merged.length === 0) {
|
|
6131
|
+
setTask("1", "completed");
|
|
6132
|
+
return {
|
|
6133
|
+
content: `No merged PRs in ${args.owner}/${args.repo} within the last ${days} day(s).`,
|
|
6134
|
+
rawBytes: 0,
|
|
6135
|
+
reducedBytes: 0
|
|
6136
|
+
};
|
|
6137
|
+
}
|
|
6138
|
+
setTask("1", "completed");
|
|
6139
|
+
setTask("2", "in_progress");
|
|
6140
|
+
let version = "latest";
|
|
6141
|
+
try {
|
|
6142
|
+
const releases = await githubFetch2(
|
|
6143
|
+
`/repos/${args.owner}/${args.repo}/releases?per_page=1`,
|
|
6144
|
+
token
|
|
6145
|
+
);
|
|
6146
|
+
if (releases.length > 0) {
|
|
6147
|
+
version = releases[0].tag_name;
|
|
6148
|
+
}
|
|
6149
|
+
} catch {
|
|
6150
|
+
try {
|
|
6151
|
+
const tags = await githubFetch2(
|
|
6152
|
+
`/repos/${args.owner}/${args.repo}/tags?per_page=1`,
|
|
6153
|
+
token
|
|
6154
|
+
);
|
|
6155
|
+
if (tags.length > 0) {
|
|
6156
|
+
version = tags[0].name;
|
|
6157
|
+
}
|
|
6158
|
+
} catch {
|
|
6159
|
+
}
|
|
6160
|
+
}
|
|
6161
|
+
setTask("2", "completed");
|
|
6162
|
+
setTask("3", "in_progress");
|
|
6163
|
+
const writeUp = await summarizeWithLlm(merged, ctx);
|
|
6164
|
+
setTask("3", "completed");
|
|
6165
|
+
setTask("4", "in_progress");
|
|
6166
|
+
const logoBase64 = await loadLogoBase64();
|
|
6167
|
+
const svg = buildChangelogSvg({ owner: args.owner, repo: args.repo, version, writeUp, logoBase64 });
|
|
6168
|
+
const resvg = new Resvg(svg, {
|
|
6169
|
+
fitTo: { mode: "zoom", value: 2 },
|
|
6170
|
+
font: {
|
|
6171
|
+
defaultFontFamily: "system-ui"
|
|
6172
|
+
}
|
|
6173
|
+
});
|
|
6174
|
+
const pngData = resvg.render();
|
|
6175
|
+
const pngBuffer = pngData.asPng();
|
|
6176
|
+
setTask("4", "completed");
|
|
6177
|
+
setTask("5", "in_progress");
|
|
6178
|
+
const outputPath = args.output ?? `./changelog-${args.repo}-${version.replace(/[^a-zA-Z0-9._-]/g, "_")}.png`;
|
|
6179
|
+
await writeFile5(outputPath, pngBuffer);
|
|
6180
|
+
setTask("5", "completed");
|
|
6181
|
+
const periodLabel = days === 1 ? "past day" : `past ${days} days`;
|
|
6182
|
+
const content = `\u2713 Changelog image saved to ${outputPath}
|
|
6183
|
+
${merged.length} PR${merged.length === 1 ? "" : "s"} from the ${periodLabel} \xB7 ${version} \xB7 ${resvg.width}\xD7${resvg.height}`;
|
|
6184
|
+
const bytes = Buffer.byteLength(content, "utf8");
|
|
6185
|
+
return { content, rawBytes: bytes, reducedBytes: bytes };
|
|
6186
|
+
}
|
|
6187
|
+
};
|
|
6188
|
+
}
|
|
6189
|
+
});
|
|
6190
|
+
|
|
5775
6191
|
// src/tools/browser.ts
|
|
5776
6192
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
5777
6193
|
import { tmpdir as tmpdir2 } from "os";
|
|
5778
|
-
import { join as
|
|
6194
|
+
import { join as join12, dirname as dirname5 } from "path";
|
|
5779
6195
|
async function autoScroll(page) {
|
|
5780
6196
|
await page.evaluate(async () => {
|
|
5781
6197
|
await new Promise((resolve5) => {
|
|
@@ -5797,11 +6213,11 @@ async function autoScroll(page) {
|
|
|
5797
6213
|
});
|
|
5798
6214
|
});
|
|
5799
6215
|
}
|
|
5800
|
-
var
|
|
6216
|
+
var TIMEOUT_MS5, NAV_TIMEOUT_MS, browserFetchTool;
|
|
5801
6217
|
var init_browser = __esm({
|
|
5802
6218
|
"src/tools/browser.ts"() {
|
|
5803
6219
|
"use strict";
|
|
5804
|
-
|
|
6220
|
+
TIMEOUT_MS5 = 3e4;
|
|
5805
6221
|
NAV_TIMEOUT_MS = 2e4;
|
|
5806
6222
|
browserFetchTool = {
|
|
5807
6223
|
name: "browser_fetch",
|
|
@@ -5844,14 +6260,14 @@ var init_browser = __esm({
|
|
|
5844
6260
|
const page = await browser.newPage();
|
|
5845
6261
|
await page.goto(args.url, { waitUntil: "networkidle", timeout: NAV_TIMEOUT_MS });
|
|
5846
6262
|
if (args.wait_for) {
|
|
5847
|
-
await page.waitForSelector(args.wait_for, { timeout:
|
|
6263
|
+
await page.waitForSelector(args.wait_for, { timeout: TIMEOUT_MS5 });
|
|
5848
6264
|
}
|
|
5849
6265
|
if (args.scroll) {
|
|
5850
6266
|
await autoScroll(page);
|
|
5851
6267
|
}
|
|
5852
6268
|
let screenshotPath;
|
|
5853
6269
|
if (args.screenshot) {
|
|
5854
|
-
screenshotPath =
|
|
6270
|
+
screenshotPath = join12(tmpdir2(), `kimiflare-browser-${Date.now()}.png`);
|
|
5855
6271
|
await mkdir5(dirname5(screenshotPath), { recursive: true });
|
|
5856
6272
|
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
5857
6273
|
}
|
|
@@ -6976,6 +7392,7 @@ var init_executor = __esm({
|
|
|
6976
7392
|
init_web_fetch();
|
|
6977
7393
|
init_web_search();
|
|
6978
7394
|
init_github();
|
|
7395
|
+
init_changelog_image();
|
|
6979
7396
|
init_browser();
|
|
6980
7397
|
init_tasks();
|
|
6981
7398
|
init_memory();
|
|
@@ -6996,6 +7413,9 @@ var init_executor = __esm({
|
|
|
6996
7413
|
githubReadPrTool,
|
|
6997
7414
|
githubReadIssueTool,
|
|
6998
7415
|
githubReadCodeTool,
|
|
7416
|
+
githubListMergedPrsTool,
|
|
7417
|
+
githubListReleasesTool,
|
|
7418
|
+
changelogImageTool,
|
|
6999
7419
|
browserFetchTool,
|
|
7000
7420
|
tasksSetTool,
|
|
7001
7421
|
memoryRememberTool,
|
|
@@ -7215,20 +7635,20 @@ var init_executor = __esm({
|
|
|
7215
7635
|
});
|
|
7216
7636
|
|
|
7217
7637
|
// src/util/update-check.ts
|
|
7218
|
-
import { readFile as
|
|
7638
|
+
import { readFile as readFile8, writeFile as writeFile7, mkdir as mkdir6 } from "fs/promises";
|
|
7219
7639
|
import { homedir as homedir6 } from "os";
|
|
7220
|
-
import { join as
|
|
7640
|
+
import { join as join13, dirname as dirname6 } from "path";
|
|
7221
7641
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7222
7642
|
function cachePath() {
|
|
7223
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
7224
|
-
return
|
|
7643
|
+
const xdg = process.env.XDG_CONFIG_HOME || join13(homedir6(), ".config");
|
|
7644
|
+
return join13(xdg, "kimiflare", "update-check.json");
|
|
7225
7645
|
}
|
|
7226
7646
|
async function findPackageJson(startDir) {
|
|
7227
7647
|
let dir = startDir;
|
|
7228
7648
|
while (true) {
|
|
7229
|
-
const candidate =
|
|
7649
|
+
const candidate = join13(dir, "package.json");
|
|
7230
7650
|
try {
|
|
7231
|
-
const raw = await
|
|
7651
|
+
const raw = await readFile8(candidate, "utf8");
|
|
7232
7652
|
const parsed = JSON.parse(raw);
|
|
7233
7653
|
if (parsed.name === "kimiflare" && parsed.version) {
|
|
7234
7654
|
return { path: candidate, version: parsed.version };
|
|
@@ -7248,7 +7668,7 @@ async function readLocalVersion() {
|
|
|
7248
7668
|
}
|
|
7249
7669
|
async function readCache() {
|
|
7250
7670
|
try {
|
|
7251
|
-
const raw = await
|
|
7671
|
+
const raw = await readFile8(cachePath(), "utf8");
|
|
7252
7672
|
const parsed = JSON.parse(raw);
|
|
7253
7673
|
if (Date.now() - parsed.checkedAt < CACHE_TTL_MS) {
|
|
7254
7674
|
return parsed;
|
|
@@ -7260,7 +7680,7 @@ async function readCache() {
|
|
|
7260
7680
|
async function writeCache(entry) {
|
|
7261
7681
|
const p = cachePath();
|
|
7262
7682
|
await mkdir6(dirname6(p), { recursive: true });
|
|
7263
|
-
await
|
|
7683
|
+
await writeFile7(p, JSON.stringify(entry), "utf8");
|
|
7264
7684
|
}
|
|
7265
7685
|
async function fetchLatestVersion() {
|
|
7266
7686
|
try {
|
|
@@ -7291,8 +7711,8 @@ function isNewer(local, remote) {
|
|
|
7291
7711
|
async function readOptionalDepVersion(name) {
|
|
7292
7712
|
try {
|
|
7293
7713
|
const here = dirname6(fileURLToPath2(import.meta.url));
|
|
7294
|
-
const candidate =
|
|
7295
|
-
const raw = await
|
|
7714
|
+
const candidate = join13(here, "..", "..", "node_modules", name, "package.json");
|
|
7715
|
+
const raw = await readFile8(candidate, "utf8");
|
|
7296
7716
|
const parsed = JSON.parse(raw);
|
|
7297
7717
|
return parsed.version ?? null;
|
|
7298
7718
|
} catch {
|
|
@@ -7352,23 +7772,23 @@ var init_update_check = __esm({
|
|
|
7352
7772
|
});
|
|
7353
7773
|
|
|
7354
7774
|
// src/remote/session-store.ts
|
|
7355
|
-
import { readFile as
|
|
7775
|
+
import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir7, readdir as readdir3 } from "fs/promises";
|
|
7356
7776
|
import { homedir as homedir7 } from "os";
|
|
7357
|
-
import { join as
|
|
7777
|
+
import { join as join14 } from "path";
|
|
7358
7778
|
function remoteDir() {
|
|
7359
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
7360
|
-
return
|
|
7779
|
+
const xdg = process.env.XDG_DATA_HOME || join14(homedir7(), ".config");
|
|
7780
|
+
return join14(xdg, "kimiflare", "remote");
|
|
7361
7781
|
}
|
|
7362
7782
|
async function saveRemoteSession(session) {
|
|
7363
7783
|
const dir = remoteDir();
|
|
7364
7784
|
await mkdir7(dir, { recursive: true });
|
|
7365
|
-
const path =
|
|
7366
|
-
await
|
|
7785
|
+
const path = join14(dir, `${session.sessionId}.json`);
|
|
7786
|
+
await writeFile8(path, JSON.stringify(session, null, 2) + "\n", "utf8");
|
|
7367
7787
|
}
|
|
7368
7788
|
async function loadRemoteSession(sessionId) {
|
|
7369
7789
|
try {
|
|
7370
|
-
const path =
|
|
7371
|
-
const raw = await
|
|
7790
|
+
const path = join14(remoteDir(), `${sessionId}.json`);
|
|
7791
|
+
const raw = await readFile9(path, "utf8");
|
|
7372
7792
|
return JSON.parse(raw);
|
|
7373
7793
|
} catch {
|
|
7374
7794
|
return null;
|
|
@@ -7382,7 +7802,7 @@ async function listRemoteSessions() {
|
|
|
7382
7802
|
for (const file of files) {
|
|
7383
7803
|
if (!file.endsWith(".json")) continue;
|
|
7384
7804
|
try {
|
|
7385
|
-
const raw = await
|
|
7805
|
+
const raw = await readFile9(join14(dir, file), "utf8");
|
|
7386
7806
|
sessions.push(JSON.parse(raw));
|
|
7387
7807
|
} catch {
|
|
7388
7808
|
}
|
|
@@ -7404,7 +7824,7 @@ var init_session_store = __esm({
|
|
|
7404
7824
|
|
|
7405
7825
|
// src/remote/deploy.ts
|
|
7406
7826
|
import { execSync } from "child_process";
|
|
7407
|
-
import { join as
|
|
7827
|
+
import { join as join15, dirname as dirname7 } from "path";
|
|
7408
7828
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7409
7829
|
import { randomBytes } from "crypto";
|
|
7410
7830
|
function generateSecret() {
|
|
@@ -7439,7 +7859,7 @@ async function* deployForTui() {
|
|
|
7439
7859
|
yield { message: "Docker OK" };
|
|
7440
7860
|
yield { message: "Building remote agent bundle..." };
|
|
7441
7861
|
try {
|
|
7442
|
-
runCapture("npm run build:remote-agent",
|
|
7862
|
+
runCapture("npm run build:remote-agent", join15(REMOTE_DIR, ".."));
|
|
7443
7863
|
yield { message: "Agent bundle built" };
|
|
7444
7864
|
} catch (err) {
|
|
7445
7865
|
yield { message: `Build failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
|
|
@@ -7569,8 +7989,8 @@ var init_deploy = __esm({
|
|
|
7569
7989
|
"use strict";
|
|
7570
7990
|
init_config();
|
|
7571
7991
|
__dirname2 = dirname7(fileURLToPath3(import.meta.url));
|
|
7572
|
-
REMOTE_DIR =
|
|
7573
|
-
WORKER_DIR =
|
|
7992
|
+
REMOTE_DIR = join15(__dirname2, "..", "..", "..", "remote");
|
|
7993
|
+
WORKER_DIR = join15(REMOTE_DIR, "worker");
|
|
7574
7994
|
}
|
|
7575
7995
|
});
|
|
7576
7996
|
|
|
@@ -8084,12 +8504,12 @@ var init_heuristic = __esm({
|
|
|
8084
8504
|
});
|
|
8085
8505
|
|
|
8086
8506
|
// src/cost-attribution/classify-from-session.ts
|
|
8087
|
-
import { readFile as
|
|
8088
|
-
import { join as
|
|
8507
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
8508
|
+
import { join as join16 } from "path";
|
|
8089
8509
|
import { homedir as homedir8 } from "os";
|
|
8090
8510
|
function sessionsDir() {
|
|
8091
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
8092
|
-
return
|
|
8511
|
+
const xdg = process.env.XDG_DATA_HOME || join16(homedir8(), ".local", "share");
|
|
8512
|
+
return join16(xdg, "kimiflare", "sessions");
|
|
8093
8513
|
}
|
|
8094
8514
|
function parseToolCalls(calls) {
|
|
8095
8515
|
return calls.map((c) => {
|
|
@@ -8103,7 +8523,7 @@ function parseToolCalls(calls) {
|
|
|
8103
8523
|
}
|
|
8104
8524
|
async function classifyFromSessionFile(sessionId) {
|
|
8105
8525
|
try {
|
|
8106
|
-
const raw = await
|
|
8526
|
+
const raw = await readFile10(join16(sessionsDir(), `${sessionId}.json`), "utf8");
|
|
8107
8527
|
const session = JSON.parse(raw);
|
|
8108
8528
|
const messages = session.messages ?? [];
|
|
8109
8529
|
const turns = [];
|
|
@@ -8136,15 +8556,15 @@ var cli_exports = {};
|
|
|
8136
8556
|
__export(cli_exports, {
|
|
8137
8557
|
runCostCommand: () => runCostCommand
|
|
8138
8558
|
});
|
|
8139
|
-
import { readFile as
|
|
8140
|
-
import { join as
|
|
8559
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
8560
|
+
import { join as join17 } from "path";
|
|
8141
8561
|
import { homedir as homedir9 } from "os";
|
|
8142
8562
|
function usageDir() {
|
|
8143
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
8144
|
-
return
|
|
8563
|
+
const xdg = process.env.XDG_DATA_HOME || join17(homedir9(), ".local", "share");
|
|
8564
|
+
return join17(xdg, "kimiflare");
|
|
8145
8565
|
}
|
|
8146
8566
|
function usagePath() {
|
|
8147
|
-
return
|
|
8567
|
+
return join17(usageDir(), "usage.json");
|
|
8148
8568
|
}
|
|
8149
8569
|
function today() {
|
|
8150
8570
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -8156,7 +8576,7 @@ function daysAgo(n) {
|
|
|
8156
8576
|
}
|
|
8157
8577
|
async function loadLog() {
|
|
8158
8578
|
try {
|
|
8159
|
-
const raw = await
|
|
8579
|
+
const raw = await readFile11(usagePath(), "utf8");
|
|
8160
8580
|
return JSON.parse(raw);
|
|
8161
8581
|
} catch {
|
|
8162
8582
|
return { version: 1, days: [], sessions: [] };
|
|
@@ -8255,12 +8675,12 @@ __export(sessions_exports, {
|
|
|
8255
8675
|
saveSession: () => saveSession,
|
|
8256
8676
|
sessionsDir: () => sessionsDir2
|
|
8257
8677
|
});
|
|
8258
|
-
import { readFile as
|
|
8678
|
+
import { readFile as readFile12, writeFile as writeFile9, mkdir as mkdir8, readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
8259
8679
|
import { homedir as homedir10 } from "os";
|
|
8260
|
-
import { join as
|
|
8680
|
+
import { join as join18 } from "path";
|
|
8261
8681
|
function sessionsDir2() {
|
|
8262
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
8263
|
-
return
|
|
8682
|
+
const xdg = process.env.XDG_DATA_HOME || join18(homedir10(), ".local", "share");
|
|
8683
|
+
return join18(xdg, "kimiflare", "sessions");
|
|
8264
8684
|
}
|
|
8265
8685
|
function sanitize(text) {
|
|
8266
8686
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -8280,8 +8700,8 @@ function makeSessionId(firstPrompt) {
|
|
|
8280
8700
|
async function saveSession(file) {
|
|
8281
8701
|
const dir = sessionsDir2();
|
|
8282
8702
|
await mkdir8(dir, { recursive: true });
|
|
8283
|
-
const path =
|
|
8284
|
-
await
|
|
8703
|
+
const path = join18(dir, `${file.id}.json`);
|
|
8704
|
+
await writeFile9(path, JSON.stringify(file, null, 2), "utf8");
|
|
8285
8705
|
return path;
|
|
8286
8706
|
}
|
|
8287
8707
|
async function pruneSessions() {
|
|
@@ -8300,9 +8720,9 @@ async function listSessions(limit = 30, cwd) {
|
|
|
8300
8720
|
const summaries = [];
|
|
8301
8721
|
for (const name of entries) {
|
|
8302
8722
|
if (!name.endsWith(".json")) continue;
|
|
8303
|
-
const path =
|
|
8723
|
+
const path = join18(dir, name);
|
|
8304
8724
|
try {
|
|
8305
|
-
const [s, raw] = await Promise.all([stat4(path),
|
|
8725
|
+
const [s, raw] = await Promise.all([stat4(path), readFile12(path, "utf8")]);
|
|
8306
8726
|
const parsed = JSON.parse(raw);
|
|
8307
8727
|
if (cwd && parsed.cwd !== cwd) continue;
|
|
8308
8728
|
const firstUser = parsed.messages.find((m) => m.role === "user");
|
|
@@ -8324,7 +8744,7 @@ async function listSessions(limit = 30, cwd) {
|
|
|
8324
8744
|
return summaries.slice(0, limit);
|
|
8325
8745
|
}
|
|
8326
8746
|
async function loadSession(filePath) {
|
|
8327
|
-
const raw = await
|
|
8747
|
+
const raw = await readFile12(filePath, "utf8");
|
|
8328
8748
|
return JSON.parse(raw);
|
|
8329
8749
|
}
|
|
8330
8750
|
async function addCheckpoint(filePath, checkpoint) {
|
|
@@ -10599,20 +11019,20 @@ var init_pricing = __esm({
|
|
|
10599
11019
|
});
|
|
10600
11020
|
|
|
10601
11021
|
// src/usage-tracker.ts
|
|
10602
|
-
import { readFile as
|
|
11022
|
+
import { readFile as readFile13, writeFile as writeFile10, mkdir as mkdir9 } from "fs/promises";
|
|
10603
11023
|
import { homedir as homedir11 } from "os";
|
|
10604
|
-
import { join as
|
|
11024
|
+
import { join as join20 } from "path";
|
|
10605
11025
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
10606
11026
|
import { randomUUID } from "crypto";
|
|
10607
11027
|
function usageDir2() {
|
|
10608
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
10609
|
-
return
|
|
11028
|
+
const xdg = process.env.XDG_DATA_HOME || join20(homedir11(), ".local", "share");
|
|
11029
|
+
return join20(xdg, "kimiflare");
|
|
10610
11030
|
}
|
|
10611
11031
|
function usagePath2() {
|
|
10612
|
-
return
|
|
11032
|
+
return join20(usageDir2(), "usage.json");
|
|
10613
11033
|
}
|
|
10614
11034
|
function historyPath() {
|
|
10615
|
-
return
|
|
11035
|
+
return join20(usageDir2(), "history.jsonl");
|
|
10616
11036
|
}
|
|
10617
11037
|
function today2() {
|
|
10618
11038
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -10623,7 +11043,7 @@ function cutoffDate(daysBack) {
|
|
|
10623
11043
|
}
|
|
10624
11044
|
async function loadLog2() {
|
|
10625
11045
|
try {
|
|
10626
|
-
const raw = await
|
|
11046
|
+
const raw = await readFile13(usagePath2(), "utf8");
|
|
10627
11047
|
const parsed = JSON.parse(raw);
|
|
10628
11048
|
if (parsed.version === LOG_VERSION2) return parsed;
|
|
10629
11049
|
} catch {
|
|
@@ -10632,7 +11052,7 @@ async function loadLog2() {
|
|
|
10632
11052
|
}
|
|
10633
11053
|
async function saveLog(log2) {
|
|
10634
11054
|
await mkdir9(usageDir2(), { recursive: true });
|
|
10635
|
-
await
|
|
11055
|
+
await writeFile10(usagePath2(), JSON.stringify(log2, null, 2), "utf8");
|
|
10636
11056
|
}
|
|
10637
11057
|
function withLock(fn) {
|
|
10638
11058
|
const next = writeChain.then(fn, fn);
|
|
@@ -10641,7 +11061,7 @@ function withLock(fn) {
|
|
|
10641
11061
|
}
|
|
10642
11062
|
async function loadHistory() {
|
|
10643
11063
|
try {
|
|
10644
|
-
const raw = await
|
|
11064
|
+
const raw = await readFile13(historyPath(), "utf8");
|
|
10645
11065
|
const lines = raw.split("\n").filter((l) => l.trim());
|
|
10646
11066
|
const entries = [];
|
|
10647
11067
|
for (const line of lines) {
|
|
@@ -10666,7 +11086,7 @@ async function upsertHistoryDay(day) {
|
|
|
10666
11086
|
}
|
|
10667
11087
|
const lines = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
10668
11088
|
await mkdir9(usageDir2(), { recursive: true });
|
|
10669
|
-
await
|
|
11089
|
+
await writeFile10(historyPath(), lines, "utf8");
|
|
10670
11090
|
}
|
|
10671
11091
|
function getOrCreateDay(log2, date) {
|
|
10672
11092
|
let day = log2.days.find((d) => d.date === date);
|
|
@@ -11075,14 +11495,14 @@ var init_types2 = __esm({
|
|
|
11075
11495
|
// src/hooks/settings.ts
|
|
11076
11496
|
import { existsSync as existsSync2, readFileSync as readFileSync3, mkdirSync as mkdirSync3, writeFileSync } from "fs";
|
|
11077
11497
|
import { homedir as homedir12 } from "os";
|
|
11078
|
-
import { join as
|
|
11498
|
+
import { join as join21, dirname as dirname9 } from "path";
|
|
11079
11499
|
import { createHash } from "crypto";
|
|
11080
11500
|
function globalSettingsPath() {
|
|
11081
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
11082
|
-
return
|
|
11501
|
+
const xdg = process.env.XDG_CONFIG_HOME || join21(homedir12(), ".config");
|
|
11502
|
+
return join21(xdg, "kimiflare", "settings.json");
|
|
11083
11503
|
}
|
|
11084
11504
|
function projectSettingsPath(cwd) {
|
|
11085
|
-
return
|
|
11505
|
+
return join21(cwd, ".kimiflare", "settings.json");
|
|
11086
11506
|
}
|
|
11087
11507
|
function readSettingsFile(path) {
|
|
11088
11508
|
if (!existsSync2(path)) return null;
|
|
@@ -11407,7 +11827,7 @@ var init_manager3 = __esm({
|
|
|
11407
11827
|
// src/sdk/session.ts
|
|
11408
11828
|
import { resolve as resolve3 } from "path";
|
|
11409
11829
|
import { homedir as homedir13 } from "os";
|
|
11410
|
-
import { join as
|
|
11830
|
+
import { join as join22 } from "path";
|
|
11411
11831
|
import { existsSync as existsSync3 } from "fs";
|
|
11412
11832
|
async function createAgentSession(opts2) {
|
|
11413
11833
|
const config2 = await resolveSdkConfig(opts2);
|
|
@@ -11422,7 +11842,7 @@ async function createAgentSession(opts2) {
|
|
|
11422
11842
|
let memoryManager = null;
|
|
11423
11843
|
const memoryEnabled = opts2.memoryEnabled ?? config2.memoryEnabled ?? false;
|
|
11424
11844
|
if (memoryEnabled) {
|
|
11425
|
-
const dbPath = config2.memoryDbPath ??
|
|
11845
|
+
const dbPath = config2.memoryDbPath ?? join22(homedir13(), ".local", "share", "kimiflare", "memory.db");
|
|
11426
11846
|
memoryManager = new MemoryManager({
|
|
11427
11847
|
dbPath,
|
|
11428
11848
|
accountId: config2.accountId,
|
|
@@ -11453,7 +11873,7 @@ async function createAgentSession(opts2) {
|
|
|
11453
11873
|
}
|
|
11454
11874
|
let sessionFile;
|
|
11455
11875
|
if (opts2.sessionId) {
|
|
11456
|
-
const filePath =
|
|
11876
|
+
const filePath = join22(sessionsDir2(), `${opts2.sessionId}.json`);
|
|
11457
11877
|
try {
|
|
11458
11878
|
sessionFile = await loadSession(filePath);
|
|
11459
11879
|
} catch {
|
|
@@ -11612,8 +12032,8 @@ var init_session = __esm({
|
|
|
11612
12032
|
const parts = [{ type: "text", text }];
|
|
11613
12033
|
for (const img of options.images) {
|
|
11614
12034
|
if ("path" in img) {
|
|
11615
|
-
const { readFile:
|
|
11616
|
-
const data = await
|
|
12035
|
+
const { readFile: readFile23 } = await import("fs/promises");
|
|
12036
|
+
const data = await readFile23(img.path, "base64");
|
|
11617
12037
|
const mimeType = img.path.endsWith(".png") ? "image/png" : img.path.endsWith(".jpg") || img.path.endsWith(".jpeg") ? "image/jpeg" : "image/webp";
|
|
11618
12038
|
parts.push({ type: "image_url", image_url: { url: `data:${mimeType};base64,${data}` } });
|
|
11619
12039
|
} else {
|
|
@@ -11859,14 +12279,14 @@ var init_session = __esm({
|
|
|
11859
12279
|
this.lspManager?.notifyChange(path, content);
|
|
11860
12280
|
} else {
|
|
11861
12281
|
void import("fs/promises").then(
|
|
11862
|
-
({ readFile:
|
|
12282
|
+
({ readFile: readFile23 }) => readFile23(path, "utf8").then((c) => this.lspManager?.notifyChange(path, c)).catch(() => {
|
|
11863
12283
|
})
|
|
11864
12284
|
).catch(() => {
|
|
11865
12285
|
});
|
|
11866
12286
|
}
|
|
11867
12287
|
}
|
|
11868
12288
|
});
|
|
11869
|
-
if (existsSync3(
|
|
12289
|
+
if (existsSync3(join22(this.cwd, "KIMI.md"))) {
|
|
11870
12290
|
this.messages[0] = {
|
|
11871
12291
|
role: "system",
|
|
11872
12292
|
content: buildSystemPrompt({
|
|
@@ -12141,9 +12561,9 @@ var init_repo_info = __esm({
|
|
|
12141
12561
|
});
|
|
12142
12562
|
|
|
12143
12563
|
// src/agent/supervisor.ts
|
|
12144
|
-
import { readdir as readdir5, readFile as
|
|
12564
|
+
import { readdir as readdir5, readFile as readFile14, stat as stat5 } from "fs/promises";
|
|
12145
12565
|
import { createHash as createHash2 } from "crypto";
|
|
12146
|
-
import { resolve as resolve4, join as
|
|
12566
|
+
import { resolve as resolve4, join as join23 } from "path";
|
|
12147
12567
|
async function preReadFilesForWorkers(files, repoRoot, maxChars = DEFAULT_PRE_READ_MAX_CHARS) {
|
|
12148
12568
|
const results = [];
|
|
12149
12569
|
const filesRead = [];
|
|
@@ -12154,7 +12574,7 @@ async function preReadFilesForWorkers(files, repoRoot, maxChars = DEFAULT_PRE_RE
|
|
|
12154
12574
|
try {
|
|
12155
12575
|
const s = await stat5(path);
|
|
12156
12576
|
if (!s.isFile()) continue;
|
|
12157
|
-
const raw = await
|
|
12577
|
+
const raw = await readFile14(path, "utf8");
|
|
12158
12578
|
const remaining = maxChars - chars;
|
|
12159
12579
|
const content = raw.length > remaining ? raw.slice(0, remaining) + "\n\u2026 (truncated)" : raw;
|
|
12160
12580
|
results.push(`--- ${file} ---
|
|
@@ -12178,7 +12598,7 @@ ${results.join("\n\n")}`,
|
|
|
12178
12598
|
}
|
|
12179
12599
|
function getPreReadFilesFromMemory(cfg, repoRoot, limit = 10) {
|
|
12180
12600
|
if (!cfg.memoryEnabled) return [];
|
|
12181
|
-
const dbPath = cfg.memoryDbPath ??
|
|
12601
|
+
const dbPath = cfg.memoryDbPath ?? join23(repoRoot, ".kimiflare", "memory.db");
|
|
12182
12602
|
try {
|
|
12183
12603
|
const db = openMemoryDb(dbPath);
|
|
12184
12604
|
const files = getTopRelatedFiles(db, repoRoot, limit);
|
|
@@ -13440,9 +13860,9 @@ var init_emit_mode = __esm({
|
|
|
13440
13860
|
|
|
13441
13861
|
// src/remote/deploy-commute.ts
|
|
13442
13862
|
import { spawn as spawn4 } from "child_process";
|
|
13443
|
-
import { mkdtemp, readFile as
|
|
13863
|
+
import { mkdtemp, readFile as readFile15, writeFile as writeFile11, rm } from "fs/promises";
|
|
13444
13864
|
import { tmpdir as tmpdir3 } from "os";
|
|
13445
|
-
import { join as
|
|
13865
|
+
import { join as join24 } from "path";
|
|
13446
13866
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
13447
13867
|
async function cfApiFetch(accountId, apiToken, path, init) {
|
|
13448
13868
|
const url = `${CF_API}/accounts/${encodeURIComponent(accountId)}${path}`;
|
|
@@ -13673,8 +14093,8 @@ ${wranglerInstall.stderr.slice(-600)}`,
|
|
|
13673
14093
|
ok: true
|
|
13674
14094
|
};
|
|
13675
14095
|
yield { message: "Prerequisites ready", ok: true };
|
|
13676
|
-
const tmpRoot = await mkdtemp(
|
|
13677
|
-
const repoDir =
|
|
14096
|
+
const tmpRoot = await mkdtemp(join24(tmpdir3(), "kimiflare-commute-"));
|
|
14097
|
+
const repoDir = join24(tmpRoot, "kimiflare-commute");
|
|
13678
14098
|
yield { message: `Fetching worker source from GitHub (${COMMUTE_REPO})\u2026` };
|
|
13679
14099
|
const clone = await runCmd("git", ["clone", "--depth", "1", "--branch", COMMUTE_BRANCH, COMMUTE_REPO, repoDir], { timeoutMs: 6e4 });
|
|
13680
14100
|
if (clone.code !== 0) {
|
|
@@ -13683,8 +14103,8 @@ ${(clone.stderr || clone.stdout).slice(0, 400)}`, error: true };
|
|
|
13683
14103
|
throw new Error("clone failed");
|
|
13684
14104
|
}
|
|
13685
14105
|
yield { message: "Source fetched from GitHub", ok: true };
|
|
13686
|
-
const workerDir =
|
|
13687
|
-
const wranglerToml =
|
|
14106
|
+
const workerDir = join24(repoDir, "remote", "worker");
|
|
14107
|
+
const wranglerToml = join24(workerDir, "wrangler.toml");
|
|
13688
14108
|
yield { message: "Installing Worker dependencies (npm install)\u2026" };
|
|
13689
14109
|
const install = await runCmd("npm", ["install", "--no-audit", "--no-fund", "--loglevel=error"], {
|
|
13690
14110
|
cwd: workerDir,
|
|
@@ -13773,7 +14193,7 @@ ${(install.stderr || install.stdout).slice(-1200).trim()}`,
|
|
|
13773
14193
|
ok: true
|
|
13774
14194
|
};
|
|
13775
14195
|
yield { message: "Patching wrangler.toml\u2026" };
|
|
13776
|
-
let toml = await
|
|
14196
|
+
let toml = await readFile15(wranglerToml, "utf8");
|
|
13777
14197
|
toml = toml.replace(/^name\s*=\s*"[^"]+"/m, `name = "${workerName}"`);
|
|
13778
14198
|
toml = toml.replace(
|
|
13779
14199
|
/(\[\[kv_namespaces\]\][\s\S]*?binding\s*=\s*"OAUTH_KV"[\s\S]*?id\s*=\s*")[^"]+(")/,
|
|
@@ -13806,7 +14226,7 @@ enabled = false
|
|
|
13806
14226
|
invocation_logs = true
|
|
13807
14227
|
`;
|
|
13808
14228
|
}
|
|
13809
|
-
await
|
|
14229
|
+
await writeFile11(wranglerToml, toml, "utf8");
|
|
13810
14230
|
yield {
|
|
13811
14231
|
message: workerExists ? "wrangler.toml patched (name, KV id, [[artifacts]] stripped)" : "wrangler.toml patched (name, KV id, [[artifacts]] stripped, DO migrations added)",
|
|
13812
14232
|
ok: true
|
|
@@ -13999,128 +14419,449 @@ var init_deploy_commute = __esm({
|
|
|
13999
14419
|
}
|
|
14000
14420
|
});
|
|
14001
14421
|
|
|
14002
|
-
// src/
|
|
14003
|
-
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
|
|
14007
|
-
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
{ name: "mode", argHint: "edit|plan|auto|multi-agent-experimental", description: "Switch agent mode", source: "builtin" },
|
|
14011
|
-
{ name: "multi-agent", argHint: "[enable|disable|status|setup]", description: "Configure multi-agent (endpoint, auto-implement, set up)", source: "builtin" },
|
|
14012
|
-
{ name: "theme", argHint: "[<name>]", description: "Switch color theme", source: "builtin" },
|
|
14013
|
-
{ name: "ui", argHint: "ink|camouflage", description: "Switch UI engine (takes effect on next launch)", source: "builtin" },
|
|
14014
|
-
{ name: "plan", description: "Switch to plan mode", source: "builtin" },
|
|
14015
|
-
{ name: "auto", description: "Switch to auto mode", source: "builtin" },
|
|
14016
|
-
{ name: "edit", description: "Switch to edit mode", source: "builtin" },
|
|
14017
|
-
{ name: "reasoning", description: "Toggle reasoning visibility", source: "builtin" },
|
|
14018
|
-
{ name: "memory", argHint: "[on|off|clear|search ...]", description: "Manage memory", source: "builtin" },
|
|
14019
|
-
{ name: "cost", argHint: "[on|off]", description: "Show cost report or toggle attribution", source: "builtin" },
|
|
14020
|
-
{ name: "gateway", argHint: "[status|off|<id>|cache-ttl|skip-cache|...]", description: "Manage AI Gateway", source: "builtin" },
|
|
14021
|
-
{ name: "mcp", argHint: "[list|reload]", description: "Manage MCP servers", source: "builtin" },
|
|
14022
|
-
{ name: "lsp", argHint: "[config|list|reload|scope]", description: "Manage language servers", source: "builtin" },
|
|
14023
|
-
{ name: "hooks", argHint: "[list|recommended|enable <id>|disable <id>|path|reload]", description: "Manage lifecycle hooks", source: "builtin" },
|
|
14024
|
-
{ name: "skills", argHint: "[list|add|edit|delete|enable|disable]", description: "Manage skills", source: "builtin" },
|
|
14025
|
-
{ name: "command", argHint: "[create|edit|delete|list]", description: "Manage custom slash commands", source: "builtin" },
|
|
14026
|
-
{ name: "resume", description: "Pick a past conversation to resume", source: "builtin" },
|
|
14027
|
-
{ name: "checkpoint", argHint: "[label]", description: "Save current point in session", source: "builtin" },
|
|
14028
|
-
{ name: "checkpoints", description: "List checkpoints in current session", source: "builtin" },
|
|
14029
|
-
{ name: "compact", description: "Summarize old turns to free context", source: "builtin" },
|
|
14030
|
-
{ name: "clear", description: "Clear current conversation", source: "builtin" },
|
|
14031
|
-
{ name: "fresh", description: "Reset session and start fresh with the last plan", source: "builtin" },
|
|
14032
|
-
{ name: "init", description: "Scan repo and write KIMI.md", source: "builtin" },
|
|
14033
|
-
{ name: "remote", argHint: "<prompt>", description: "Run a remote session on Cloudflare", source: "builtin" },
|
|
14034
|
-
{ name: "update", description: "Check for updates", source: "builtin" },
|
|
14035
|
-
{ name: "hello", description: "Send a voice note to the creator", source: "builtin" },
|
|
14036
|
-
{ name: "report", argHint: "[send] [note]", description: "Report the last API error with diagnostic logs", source: "builtin" },
|
|
14037
|
-
{ name: "shell", argHint: "[auto|bash|cmd|powershell|<path>]", description: "Show or set shell for bash tool", source: "builtin" },
|
|
14038
|
-
{ name: "logout", description: "Clear stored credentials", source: "builtin" },
|
|
14039
|
-
{ name: "exit", description: "Exit kimiflare", source: "builtin" }
|
|
14040
|
-
];
|
|
14041
|
-
BUILTIN_COMMAND_NAMES = new Set(
|
|
14042
|
-
BUILTIN_COMMANDS.map((c) => c.name.toLowerCase())
|
|
14422
|
+
// src/util/image.ts
|
|
14423
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
14424
|
+
import { basename as basename3 } from "path";
|
|
14425
|
+
async function encodeImageFile(filePath) {
|
|
14426
|
+
const buf = await readFile16(filePath);
|
|
14427
|
+
if (buf.byteLength > MAX_IMAGE_BYTES) {
|
|
14428
|
+
throw new Error(
|
|
14429
|
+
`image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
|
|
14043
14430
|
);
|
|
14044
14431
|
}
|
|
14045
|
-
|
|
14046
|
-
|
|
14047
|
-
|
|
14048
|
-
function indexOfNthUserFromEnd(messages, n) {
|
|
14049
|
-
let seen = 0;
|
|
14050
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
14051
|
-
if (messages[i].role === "user") {
|
|
14052
|
-
seen++;
|
|
14053
|
-
if (seen === n) return i;
|
|
14054
|
-
}
|
|
14055
|
-
}
|
|
14056
|
-
return -1;
|
|
14057
|
-
}
|
|
14058
|
-
async function summarizeMessagesViaLlm(opts2) {
|
|
14059
|
-
const keep = opts2.keepLastTurns ?? 4;
|
|
14060
|
-
const messages = opts2.messages;
|
|
14061
|
-
let prefixEnd = 0;
|
|
14062
|
-
while (prefixEnd < messages.length && messages[prefixEnd].role === "system") {
|
|
14063
|
-
prefixEnd++;
|
|
14064
|
-
}
|
|
14065
|
-
const prefix = messages.slice(0, prefixEnd);
|
|
14066
|
-
if (prefix.length === 0) {
|
|
14067
|
-
return { summary: "", newMessages: messages, replacedCount: 0 };
|
|
14068
|
-
}
|
|
14069
|
-
const cutoffUserIdx = indexOfNthUserFromEnd(messages, keep);
|
|
14070
|
-
const firstKeepIdx = cutoffUserIdx >= 0 ? cutoffUserIdx : messages.length;
|
|
14071
|
-
const toSummarize = messages.slice(prefixEnd, firstKeepIdx);
|
|
14072
|
-
const toKeep = messages.slice(firstKeepIdx);
|
|
14073
|
-
if (toSummarize.length === 0) {
|
|
14074
|
-
return { summary: "", newMessages: messages, replacedCount: 0 };
|
|
14075
|
-
}
|
|
14076
|
-
const transcript = toSummarize.map((m) => {
|
|
14077
|
-
const contentStr = typeof m.content === "string" ? m.content : m.content?.map((p) => p.type === "text" ? p.text : "[image]").join(" ") ?? "";
|
|
14078
|
-
if (m.role === "tool") {
|
|
14079
|
-
const snippet = contentStr.slice(0, 500);
|
|
14080
|
-
return `[tool ${m.name ?? ""}] ${snippet}`;
|
|
14081
|
-
}
|
|
14082
|
-
if (m.role === "assistant") {
|
|
14083
|
-
const calls = m.tool_calls ? ` (tool_calls: ${m.tool_calls.map((c) => c.function.name).join(", ")})` : "";
|
|
14084
|
-
return `[assistant]${calls} ${contentStr}`;
|
|
14085
|
-
}
|
|
14086
|
-
return `[${m.role}] ${contentStr}`;
|
|
14087
|
-
}).join("\n");
|
|
14088
|
-
let summary = "";
|
|
14089
|
-
const events = runKimi({
|
|
14090
|
-
accountId: opts2.accountId,
|
|
14091
|
-
apiToken: opts2.apiToken,
|
|
14092
|
-
model: opts2.model,
|
|
14093
|
-
messages: [
|
|
14094
|
-
{ role: "system", content: SUMMARY_SYSTEM },
|
|
14095
|
-
{ role: "user", content: `Summarize this session so it can be replaced by your summary:
|
|
14096
|
-
|
|
14097
|
-
${transcript}` }
|
|
14098
|
-
],
|
|
14099
|
-
signal: opts2.signal,
|
|
14100
|
-
temperature: 0.1,
|
|
14101
|
-
reasoningEffort: "low",
|
|
14102
|
-
gateway: opts2.gateway,
|
|
14103
|
-
idleTimeoutMs: 6e4
|
|
14104
|
-
});
|
|
14105
|
-
for await (const ev of events) {
|
|
14106
|
-
if (ev.type === "text") summary += ev.delta;
|
|
14107
|
-
}
|
|
14108
|
-
const summaryMsg = {
|
|
14109
|
-
role: "user",
|
|
14110
|
-
content: `[compacted summary of earlier turns]
|
|
14111
|
-
${summary.trim()}`
|
|
14112
|
-
};
|
|
14432
|
+
const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
|
|
14433
|
+
const mime = EXT_TO_MIME[ext] ?? "image/jpeg";
|
|
14434
|
+
const b64 = buf.toString("base64");
|
|
14113
14435
|
return {
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14436
|
+
filename: basename3(filePath),
|
|
14437
|
+
mime,
|
|
14438
|
+
dataUrl: `data:${mime};base64,${b64}`
|
|
14117
14439
|
};
|
|
14118
14440
|
}
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
|
|
14123
|
-
|
|
14441
|
+
function isImagePath(path) {
|
|
14442
|
+
const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
|
|
14443
|
+
return ext in EXT_TO_MIME;
|
|
14444
|
+
}
|
|
14445
|
+
var MAX_IMAGE_BYTES, EXT_TO_MIME;
|
|
14446
|
+
var init_image = __esm({
|
|
14447
|
+
"src/util/image.ts"() {
|
|
14448
|
+
"use strict";
|
|
14449
|
+
MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
14450
|
+
EXT_TO_MIME = {
|
|
14451
|
+
".png": "image/png",
|
|
14452
|
+
".jpg": "image/jpeg",
|
|
14453
|
+
".jpeg": "image/jpeg",
|
|
14454
|
+
".gif": "image/gif",
|
|
14455
|
+
".webp": "image/webp",
|
|
14456
|
+
".bmp": "image/bmp"
|
|
14457
|
+
};
|
|
14458
|
+
}
|
|
14459
|
+
});
|
|
14460
|
+
|
|
14461
|
+
// src/ui/app-helpers.ts
|
|
14462
|
+
var app_helpers_exports = {};
|
|
14463
|
+
__export(app_helpers_exports, {
|
|
14464
|
+
AUTO_COMPACT_THRESHOLD: () => AUTO_COMPACT_THRESHOLD,
|
|
14465
|
+
CONTEXT_LIMIT: () => CONTEXT_LIMIT,
|
|
14466
|
+
DEFAULT_AUTO_FRESH_SUGGESTION_TURNS: () => DEFAULT_AUTO_FRESH_SUGGESTION_TURNS,
|
|
14467
|
+
FEEDBACK_WORKER_URL: () => FEEDBACK_WORKER_URL,
|
|
14468
|
+
MAX_EVENTS: () => MAX_EVENTS,
|
|
14469
|
+
MAX_IMAGES_PER_MESSAGE: () => MAX_IMAGES_PER_MESSAGE,
|
|
14470
|
+
buildFilePickerIgnoreList: () => buildFilePickerIgnoreList,
|
|
14471
|
+
capEvents: () => capEvents,
|
|
14472
|
+
compactEventsVisual: () => compactEventsVisual,
|
|
14473
|
+
detectGitBranch: () => detectGitBranch,
|
|
14474
|
+
detectGitHubRepo: () => detectGitHubRepo,
|
|
14475
|
+
findImagePaths: () => findImagePaths,
|
|
14476
|
+
formatTokens: () => formatTokens,
|
|
14477
|
+
gatewayFromConfig: () => gatewayFromConfig,
|
|
14478
|
+
gatewayUsageLookupFromConfig: () => gatewayUsageLookupFromConfig,
|
|
14479
|
+
makePrefixMessages: () => makePrefixMessages,
|
|
14480
|
+
mkAssistantId: () => mkAssistantId,
|
|
14481
|
+
mkKey: () => mkKey,
|
|
14482
|
+
openBrowser: () => openBrowser,
|
|
14483
|
+
rebuildSystemPromptForMode: () => rebuildSystemPromptForMode,
|
|
14484
|
+
trackRecentFile: () => trackRecentFile
|
|
14485
|
+
});
|
|
14486
|
+
import { execSync as execSync3, spawn as spawn5 } from "child_process";
|
|
14487
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
14488
|
+
import { join as join25 } from "path";
|
|
14489
|
+
import { platform as platform3 } from "os";
|
|
14490
|
+
function buildFilePickerIgnoreList(cwd) {
|
|
14491
|
+
const hardcoded = [
|
|
14492
|
+
// Dependencies
|
|
14493
|
+
"**/node_modules/**",
|
|
14494
|
+
"**/vendor/**",
|
|
14495
|
+
"**/.bundle/**",
|
|
14496
|
+
"**/bower_components/**",
|
|
14497
|
+
// Version control
|
|
14498
|
+
"**/.git/**",
|
|
14499
|
+
"**/.svn/**",
|
|
14500
|
+
"**/.hg/**",
|
|
14501
|
+
// Build / output directories
|
|
14502
|
+
"**/dist/**",
|
|
14503
|
+
"**/build/**",
|
|
14504
|
+
"**/out/**",
|
|
14505
|
+
"**/public/**",
|
|
14506
|
+
"**/.next/**",
|
|
14507
|
+
"**/.nuxt/**",
|
|
14508
|
+
"**/.svelte-kit/**",
|
|
14509
|
+
"**/.vercel/**",
|
|
14510
|
+
"**/.netlify/**",
|
|
14511
|
+
"**/target/**",
|
|
14512
|
+
"**/bin/**",
|
|
14513
|
+
"**/obj/**",
|
|
14514
|
+
"**/Debug/**",
|
|
14515
|
+
"**/Release/**",
|
|
14516
|
+
"**/.gradle/**",
|
|
14517
|
+
// Caches
|
|
14518
|
+
"**/.cache/**",
|
|
14519
|
+
"**/.parcel-cache/**",
|
|
14520
|
+
"**/.turbo/**",
|
|
14521
|
+
"**/.eslintcache",
|
|
14522
|
+
"**/.stylelintcache",
|
|
14523
|
+
"**/.rpt2_cache/**",
|
|
14524
|
+
"**/.rts2_cache/**",
|
|
14525
|
+
// Temporary
|
|
14526
|
+
"**/tmp/**",
|
|
14527
|
+
"**/temp/**",
|
|
14528
|
+
"**/*.tmp",
|
|
14529
|
+
// Coverage
|
|
14530
|
+
"**/coverage/**",
|
|
14531
|
+
"**/.nyc_output/**",
|
|
14532
|
+
// OS files
|
|
14533
|
+
"**/.DS_Store",
|
|
14534
|
+
"**/Thumbs.db",
|
|
14535
|
+
// Logs
|
|
14536
|
+
"**/*.log",
|
|
14537
|
+
"**/logs/**",
|
|
14538
|
+
// Lock files (auto-generated, usually huge)
|
|
14539
|
+
"**/package-lock.json",
|
|
14540
|
+
"**/yarn.lock",
|
|
14541
|
+
"**/pnpm-lock.yaml",
|
|
14542
|
+
"**/bun.lockb",
|
|
14543
|
+
"**/Cargo.lock",
|
|
14544
|
+
"**/Gemfile.lock",
|
|
14545
|
+
"**/composer.lock",
|
|
14546
|
+
"**/Pipfile.lock",
|
|
14547
|
+
"**/poetry.lock",
|
|
14548
|
+
"**/go.sum",
|
|
14549
|
+
// Minified / source maps
|
|
14550
|
+
"**/*.min.js",
|
|
14551
|
+
"**/*.min.css",
|
|
14552
|
+
"**/*.map",
|
|
14553
|
+
// kimiflare internal
|
|
14554
|
+
"**/.kimiflare/**",
|
|
14555
|
+
// IDE (usually not relevant to mention)
|
|
14556
|
+
"**/.idea/**"
|
|
14557
|
+
];
|
|
14558
|
+
const gitignorePatterns = [];
|
|
14559
|
+
try {
|
|
14560
|
+
const gitignorePath = join25(cwd, ".gitignore");
|
|
14561
|
+
const stats = statSync4(gitignorePath);
|
|
14562
|
+
if (stats.size > MAX_GITIGNORE_SIZE) {
|
|
14563
|
+
return hardcoded;
|
|
14564
|
+
}
|
|
14565
|
+
const content = readFileSync4(gitignorePath, "utf-8");
|
|
14566
|
+
for (const line of content.split(/\r?\n/)) {
|
|
14567
|
+
const trimmed = line.trim();
|
|
14568
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
14569
|
+
if (trimmed.startsWith("!")) continue;
|
|
14570
|
+
let pattern = trimmed;
|
|
14571
|
+
const isAnchored = pattern.startsWith("/");
|
|
14572
|
+
const isDir = pattern.endsWith("/");
|
|
14573
|
+
if (isAnchored) pattern = pattern.slice(1);
|
|
14574
|
+
if (isDir) pattern = pattern.slice(0, -1);
|
|
14575
|
+
if (!pattern) continue;
|
|
14576
|
+
if (isAnchored) {
|
|
14577
|
+
gitignorePatterns.push(isDir ? pattern + "/**" : pattern);
|
|
14578
|
+
} else {
|
|
14579
|
+
gitignorePatterns.push(isDir ? "**/" + pattern + "/**" : "**/" + pattern);
|
|
14580
|
+
}
|
|
14581
|
+
}
|
|
14582
|
+
} catch {
|
|
14583
|
+
}
|
|
14584
|
+
return [...hardcoded, ...gitignorePatterns];
|
|
14585
|
+
}
|
|
14586
|
+
function gatewayFromConfig(cfg) {
|
|
14587
|
+
if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
|
|
14588
|
+
if (!cfg.aiGatewayId) return void 0;
|
|
14589
|
+
return {
|
|
14590
|
+
id: cfg.aiGatewayId,
|
|
14591
|
+
cacheTtl: cfg.aiGatewayCacheTtl,
|
|
14592
|
+
skipCache: cfg.aiGatewaySkipCache,
|
|
14593
|
+
collectLogPayload: cfg.aiGatewayCollectLogPayload,
|
|
14594
|
+
metadata: cfg.aiGatewayMetadata
|
|
14595
|
+
};
|
|
14596
|
+
}
|
|
14597
|
+
function gatewayUsageLookupFromConfig(cfg, meta) {
|
|
14598
|
+
if (process.env.KIMIFLARE_DISABLE_AI_GATEWAY === "1") return void 0;
|
|
14599
|
+
if (!cfg.aiGatewayId || !meta) return void 0;
|
|
14600
|
+
return {
|
|
14601
|
+
accountId: cfg.accountId,
|
|
14602
|
+
apiToken: cfg.apiToken,
|
|
14603
|
+
gatewayId: cfg.aiGatewayId,
|
|
14604
|
+
meta
|
|
14605
|
+
};
|
|
14606
|
+
}
|
|
14607
|
+
function openBrowser(url) {
|
|
14608
|
+
const cmd = platform3() === "darwin" ? "open" : platform3() === "win32" ? "start" : "xdg-open";
|
|
14609
|
+
const child = spawn5(cmd, [url], { detached: true, stdio: "ignore" });
|
|
14610
|
+
child.unref();
|
|
14611
|
+
}
|
|
14612
|
+
function detectGitHubRepo(cachedRepo) {
|
|
14613
|
+
if (cachedRepo) {
|
|
14614
|
+
const parts = cachedRepo.split("/");
|
|
14615
|
+
if (parts.length === 2) return { owner: parts[0], name: parts[1] };
|
|
14616
|
+
}
|
|
14617
|
+
try {
|
|
14618
|
+
const remoteUrl = execSync3("git remote get-url origin", { cwd: process.cwd(), encoding: "utf8" }).trim().replace(/\/+$/, "");
|
|
14619
|
+
const httpsMatch = remoteUrl.match(/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
|
|
14620
|
+
if (httpsMatch) return { owner: httpsMatch[1], name: httpsMatch[2] };
|
|
14621
|
+
const sshMatch = remoteUrl.match(/github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
|
|
14622
|
+
if (sshMatch) return { owner: sshMatch[1], name: sshMatch[2] };
|
|
14623
|
+
} catch {
|
|
14624
|
+
}
|
|
14625
|
+
return null;
|
|
14626
|
+
}
|
|
14627
|
+
function detectGitBranch() {
|
|
14628
|
+
try {
|
|
14629
|
+
return execSync3("git branch --show-current", { cwd: process.cwd(), encoding: "utf8" }).trim() || null;
|
|
14630
|
+
} catch {
|
|
14631
|
+
return null;
|
|
14632
|
+
}
|
|
14633
|
+
}
|
|
14634
|
+
function formatTokens(n) {
|
|
14635
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
14636
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
14637
|
+
return String(n);
|
|
14638
|
+
}
|
|
14639
|
+
function trackRecentFile(ref, path, max = 10) {
|
|
14640
|
+
ref.current.set(path, Date.now());
|
|
14641
|
+
if (ref.current.size > max) {
|
|
14642
|
+
let oldest = null;
|
|
14643
|
+
let oldestTime = Infinity;
|
|
14644
|
+
for (const [p, t] of ref.current) {
|
|
14645
|
+
if (t < oldestTime) {
|
|
14646
|
+
oldestTime = t;
|
|
14647
|
+
oldest = p;
|
|
14648
|
+
}
|
|
14649
|
+
}
|
|
14650
|
+
if (oldest) ref.current.delete(oldest);
|
|
14651
|
+
}
|
|
14652
|
+
}
|
|
14653
|
+
function capEvents(prev) {
|
|
14654
|
+
if (prev.length <= MAX_EVENTS) return prev;
|
|
14655
|
+
return prev.slice(prev.length - MAX_EVENTS);
|
|
14656
|
+
}
|
|
14657
|
+
function compactEventsVisual(prev, keepLastTurns) {
|
|
14658
|
+
let seen = 0;
|
|
14659
|
+
let cutoff = -1;
|
|
14660
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
14661
|
+
if (prev[i].kind === "user") {
|
|
14662
|
+
seen++;
|
|
14663
|
+
if (seen === keepLastTurns + 1) {
|
|
14664
|
+
cutoff = i;
|
|
14665
|
+
break;
|
|
14666
|
+
}
|
|
14667
|
+
}
|
|
14668
|
+
}
|
|
14669
|
+
if (cutoff <= 0) return prev;
|
|
14670
|
+
const kept = prev.slice(cutoff);
|
|
14671
|
+
return [
|
|
14672
|
+
{ kind: "info", key: mkKey(), text: `\xB7\xB7\xB7 ${cutoff} earlier messages compacted \xB7\xB7\xB7` },
|
|
14673
|
+
...kept
|
|
14674
|
+
];
|
|
14675
|
+
}
|
|
14676
|
+
function makePrefixMessages(cacheStable, model, mode, tools) {
|
|
14677
|
+
if (cacheStable) {
|
|
14678
|
+
return buildSystemMessages({ cwd: process.cwd(), tools, model, mode });
|
|
14679
|
+
}
|
|
14680
|
+
return [
|
|
14681
|
+
{
|
|
14682
|
+
role: "system",
|
|
14683
|
+
content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode })
|
|
14684
|
+
}
|
|
14685
|
+
];
|
|
14686
|
+
}
|
|
14687
|
+
function rebuildSystemPromptForMode(messages, cacheStable, model, mode, tools) {
|
|
14688
|
+
if (cacheStable) {
|
|
14689
|
+
const rebuilt = buildSystemMessages({ cwd: process.cwd(), tools, model, mode });
|
|
14690
|
+
messages[0] = rebuilt[0];
|
|
14691
|
+
if (rebuilt[1]) {
|
|
14692
|
+
messages[1] = rebuilt[1];
|
|
14693
|
+
}
|
|
14694
|
+
} else {
|
|
14695
|
+
messages[0] = {
|
|
14696
|
+
role: "system",
|
|
14697
|
+
content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode })
|
|
14698
|
+
};
|
|
14699
|
+
}
|
|
14700
|
+
}
|
|
14701
|
+
function findImagePaths(text) {
|
|
14702
|
+
const paths = [];
|
|
14703
|
+
const quotedRegex = /"([^"]+)"|'([^']+)'/g;
|
|
14704
|
+
let match;
|
|
14705
|
+
while ((match = quotedRegex.exec(text)) !== null) {
|
|
14706
|
+
const path = match[1] ?? match[2];
|
|
14707
|
+
if (path && isImagePath(path) && existsSync4(path)) {
|
|
14708
|
+
paths.push(path);
|
|
14709
|
+
}
|
|
14710
|
+
}
|
|
14711
|
+
const remaining = text.replace(/"[^"]+"|'[^']+'/g, "");
|
|
14712
|
+
const ESCAPED_SPACE = "\0";
|
|
14713
|
+
const processed = remaining.replace(/\\ /g, ESCAPED_SPACE);
|
|
14714
|
+
for (const token of processed.split(/\s+/)) {
|
|
14715
|
+
const clean = token.replace(new RegExp(ESCAPED_SPACE, "g"), " ").replace(/^["']|["',;:!?]$/g, "").replace(/[.,;:!?]$/, "");
|
|
14716
|
+
if (clean && isImagePath(clean) && existsSync4(clean) && !paths.includes(clean)) {
|
|
14717
|
+
paths.push(clean);
|
|
14718
|
+
}
|
|
14719
|
+
}
|
|
14720
|
+
return paths;
|
|
14721
|
+
}
|
|
14722
|
+
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;
|
|
14723
|
+
var init_app_helpers = __esm({
|
|
14724
|
+
"src/ui/app-helpers.ts"() {
|
|
14725
|
+
"use strict";
|
|
14726
|
+
init_system_prompt();
|
|
14727
|
+
init_image();
|
|
14728
|
+
MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
|
|
14729
|
+
CONTEXT_LIMIT = 262e3;
|
|
14730
|
+
AUTO_COMPACT_THRESHOLD = 0.8;
|
|
14731
|
+
MAX_EVENTS = 500;
|
|
14732
|
+
DEFAULT_AUTO_FRESH_SUGGESTION_TURNS = 30;
|
|
14733
|
+
MAX_IMAGES_PER_MESSAGE = 10;
|
|
14734
|
+
FEEDBACK_WORKER_URL = "https://hello.kimiflare.com";
|
|
14735
|
+
nextKey = 1;
|
|
14736
|
+
mkKey = () => `evt_${nextKey++}`;
|
|
14737
|
+
nextAssistantId = 1;
|
|
14738
|
+
mkAssistantId = () => nextAssistantId++;
|
|
14739
|
+
}
|
|
14740
|
+
});
|
|
14741
|
+
|
|
14742
|
+
// src/commands/builtins.ts
|
|
14743
|
+
var BUILTIN_COMMANDS, BUILTIN_COMMAND_NAMES;
|
|
14744
|
+
var init_builtins = __esm({
|
|
14745
|
+
"src/commands/builtins.ts"() {
|
|
14746
|
+
"use strict";
|
|
14747
|
+
BUILTIN_COMMANDS = [
|
|
14748
|
+
{ name: "help", description: "Show keybindings and command list", source: "builtin" },
|
|
14749
|
+
{ name: "model", argHint: "[list|<id>]", description: "Pick model (no args opens picker)", source: "builtin" },
|
|
14750
|
+
{ name: "mode", argHint: "edit|plan|auto|multi-agent-experimental", description: "Switch agent mode", source: "builtin" },
|
|
14751
|
+
{ name: "multi-agent", argHint: "[enable|disable|status|setup]", description: "Configure multi-agent (endpoint, auto-implement, set up)", source: "builtin" },
|
|
14752
|
+
{ name: "theme", argHint: "[<name>]", description: "Switch color theme", source: "builtin" },
|
|
14753
|
+
{ name: "ui", argHint: "ink|camouflage", description: "Switch UI engine (takes effect on next launch)", source: "builtin" },
|
|
14754
|
+
{ name: "plan", description: "Switch to plan mode", source: "builtin" },
|
|
14755
|
+
{ name: "auto", description: "Switch to auto mode", source: "builtin" },
|
|
14756
|
+
{ name: "edit", description: "Switch to edit mode", source: "builtin" },
|
|
14757
|
+
{ name: "reasoning", description: "Toggle reasoning visibility", source: "builtin" },
|
|
14758
|
+
{ name: "memory", argHint: "[on|off|clear|search ...]", description: "Manage memory", source: "builtin" },
|
|
14759
|
+
{ name: "cost", argHint: "[on|off]", description: "Show cost report or toggle attribution", source: "builtin" },
|
|
14760
|
+
{ name: "gateway", argHint: "[status|off|<id>|cache-ttl|skip-cache|...]", description: "Manage AI Gateway", source: "builtin" },
|
|
14761
|
+
{ name: "mcp", argHint: "[list|reload]", description: "Manage MCP servers", source: "builtin" },
|
|
14762
|
+
{ name: "lsp", argHint: "[config|list|reload|scope]", description: "Manage language servers", source: "builtin" },
|
|
14763
|
+
{ name: "hooks", argHint: "[list|recommended|enable <id>|disable <id>|path|reload]", description: "Manage lifecycle hooks", source: "builtin" },
|
|
14764
|
+
{ name: "skills", argHint: "[list|add|edit|delete|enable|disable]", description: "Manage skills", source: "builtin" },
|
|
14765
|
+
{ name: "command", argHint: "[create|edit|delete|list]", description: "Manage custom slash commands", source: "builtin" },
|
|
14766
|
+
{ name: "resume", description: "Pick a past conversation to resume", source: "builtin" },
|
|
14767
|
+
{ name: "checkpoint", argHint: "[label]", description: "Save current point in session", source: "builtin" },
|
|
14768
|
+
{ name: "checkpoints", description: "List checkpoints in current session", source: "builtin" },
|
|
14769
|
+
{ name: "compact", description: "Summarize old turns to free context", source: "builtin" },
|
|
14770
|
+
{ name: "clear", description: "Clear current conversation", source: "builtin" },
|
|
14771
|
+
{ name: "fresh", description: "Start a fresh session with a summarized plan or continuation context", source: "builtin" },
|
|
14772
|
+
{ name: "init", description: "Scan repo and write KIMI.md", source: "builtin" },
|
|
14773
|
+
{ name: "remote", argHint: "<prompt>", description: "Run a remote session on Cloudflare", source: "builtin" },
|
|
14774
|
+
{ name: "update", description: "Check for updates", source: "builtin" },
|
|
14775
|
+
{ name: "hello", description: "Send a voice note to the creator", source: "builtin" },
|
|
14776
|
+
{ name: "report", argHint: "[send] [note]", description: "Report the last API error with diagnostic logs", source: "builtin" },
|
|
14777
|
+
{ name: "shell", argHint: "[auto|bash|cmd|powershell|<path>]", description: "Show or set shell for bash tool", source: "builtin" },
|
|
14778
|
+
{ name: "changelog-image", argHint: "[owner/repo] [days]", description: "Generate a changelog image from merged PRs", source: "builtin" },
|
|
14779
|
+
{ name: "logout", description: "Clear stored credentials", source: "builtin" },
|
|
14780
|
+
{ name: "exit", description: "Exit kimiflare", source: "builtin" }
|
|
14781
|
+
];
|
|
14782
|
+
BUILTIN_COMMAND_NAMES = new Set(
|
|
14783
|
+
BUILTIN_COMMANDS.map((c) => c.name.toLowerCase())
|
|
14784
|
+
);
|
|
14785
|
+
}
|
|
14786
|
+
});
|
|
14787
|
+
|
|
14788
|
+
// src/agent/llm-summarize.ts
|
|
14789
|
+
function indexOfNthUserFromEnd(messages, n) {
|
|
14790
|
+
let seen = 0;
|
|
14791
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
14792
|
+
if (messages[i].role === "user") {
|
|
14793
|
+
seen++;
|
|
14794
|
+
if (seen === n) return i;
|
|
14795
|
+
}
|
|
14796
|
+
}
|
|
14797
|
+
return -1;
|
|
14798
|
+
}
|
|
14799
|
+
async function summarizeMessagesViaLlm(opts2) {
|
|
14800
|
+
const keep = opts2.keepLastTurns ?? 4;
|
|
14801
|
+
const messages = opts2.messages;
|
|
14802
|
+
let prefixEnd = 0;
|
|
14803
|
+
while (prefixEnd < messages.length && messages[prefixEnd].role === "system") {
|
|
14804
|
+
prefixEnd++;
|
|
14805
|
+
}
|
|
14806
|
+
const prefix = messages.slice(0, prefixEnd);
|
|
14807
|
+
if (prefix.length === 0) {
|
|
14808
|
+
return { summary: "", newMessages: messages, replacedCount: 0 };
|
|
14809
|
+
}
|
|
14810
|
+
const cutoffUserIdx = indexOfNthUserFromEnd(messages, keep);
|
|
14811
|
+
const firstKeepIdx = cutoffUserIdx >= 0 ? cutoffUserIdx : messages.length;
|
|
14812
|
+
const toSummarize = messages.slice(prefixEnd, firstKeepIdx);
|
|
14813
|
+
const toKeep = messages.slice(firstKeepIdx);
|
|
14814
|
+
if (toSummarize.length === 0) {
|
|
14815
|
+
return { summary: "", newMessages: messages, replacedCount: 0 };
|
|
14816
|
+
}
|
|
14817
|
+
const transcript = toSummarize.map((m) => {
|
|
14818
|
+
const contentStr = typeof m.content === "string" ? m.content : m.content?.map((p) => p.type === "text" ? p.text : "[image]").join(" ") ?? "";
|
|
14819
|
+
if (m.role === "tool") {
|
|
14820
|
+
const snippet = contentStr.slice(0, 500);
|
|
14821
|
+
return `[tool ${m.name ?? ""}] ${snippet}`;
|
|
14822
|
+
}
|
|
14823
|
+
if (m.role === "assistant") {
|
|
14824
|
+
const calls = m.tool_calls ? ` (tool_calls: ${m.tool_calls.map((c) => c.function.name).join(", ")})` : "";
|
|
14825
|
+
return `[assistant]${calls} ${contentStr}`;
|
|
14826
|
+
}
|
|
14827
|
+
return `[${m.role}] ${contentStr}`;
|
|
14828
|
+
}).join("\n");
|
|
14829
|
+
let summary = "";
|
|
14830
|
+
const events = runKimi({
|
|
14831
|
+
accountId: opts2.accountId,
|
|
14832
|
+
apiToken: opts2.apiToken,
|
|
14833
|
+
model: opts2.model,
|
|
14834
|
+
messages: [
|
|
14835
|
+
{ role: "system", content: SUMMARY_SYSTEM },
|
|
14836
|
+
{ role: "user", content: `Summarize this session so it can be replaced by your summary:
|
|
14837
|
+
|
|
14838
|
+
${transcript}` }
|
|
14839
|
+
],
|
|
14840
|
+
signal: opts2.signal,
|
|
14841
|
+
temperature: 0.1,
|
|
14842
|
+
reasoningEffort: "low",
|
|
14843
|
+
gateway: opts2.gateway,
|
|
14844
|
+
idleTimeoutMs: 6e4
|
|
14845
|
+
});
|
|
14846
|
+
for await (const ev of events) {
|
|
14847
|
+
if (ev.type === "text") summary += ev.delta;
|
|
14848
|
+
}
|
|
14849
|
+
const summaryMsg = {
|
|
14850
|
+
role: "user",
|
|
14851
|
+
content: `[compacted summary of earlier turns]
|
|
14852
|
+
${summary.trim()}`
|
|
14853
|
+
};
|
|
14854
|
+
return {
|
|
14855
|
+
summary: summary.trim(),
|
|
14856
|
+
newMessages: [...prefix, summaryMsg, ...toKeep],
|
|
14857
|
+
replacedCount: toSummarize.length
|
|
14858
|
+
};
|
|
14859
|
+
}
|
|
14860
|
+
var SUMMARY_SYSTEM;
|
|
14861
|
+
var init_llm_summarize = __esm({
|
|
14862
|
+
"src/agent/llm-summarize.ts"() {
|
|
14863
|
+
"use strict";
|
|
14864
|
+
init_client();
|
|
14124
14865
|
SUMMARY_SYSTEM = `You are summarizing a terminal coding session so it can fit back into a short context window. Produce a dense summary that captures:
|
|
14125
14866
|
- The user's goal(s) and what they've asked for.
|
|
14126
14867
|
- Files read or modified, with paths.
|
|
@@ -14156,6 +14897,155 @@ var init_distill = __esm({
|
|
|
14156
14897
|
}
|
|
14157
14898
|
});
|
|
14158
14899
|
|
|
14900
|
+
// src/agent/continuation-summary.ts
|
|
14901
|
+
import { execSync as execSync4 } from "child_process";
|
|
14902
|
+
function extractFirstUserGoal(messages) {
|
|
14903
|
+
const texts = [];
|
|
14904
|
+
for (const m of messages) {
|
|
14905
|
+
if (m.role !== "user") continue;
|
|
14906
|
+
let text = "";
|
|
14907
|
+
if (typeof m.content === "string") {
|
|
14908
|
+
text = m.content;
|
|
14909
|
+
} else if (Array.isArray(m.content)) {
|
|
14910
|
+
text = m.content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
14911
|
+
}
|
|
14912
|
+
text = text.trim();
|
|
14913
|
+
if (text.length > 5) {
|
|
14914
|
+
texts.push(text);
|
|
14915
|
+
if (texts.length >= 3) break;
|
|
14916
|
+
}
|
|
14917
|
+
}
|
|
14918
|
+
return texts.join("\n---\n");
|
|
14919
|
+
}
|
|
14920
|
+
function extractRecentAssistantMessages(messages, count = 3) {
|
|
14921
|
+
const texts = [];
|
|
14922
|
+
for (let i = messages.length - 1; i >= 0 && texts.length < count; i--) {
|
|
14923
|
+
const m = messages[i];
|
|
14924
|
+
if (m?.role !== "assistant") continue;
|
|
14925
|
+
let text = "";
|
|
14926
|
+
if (typeof m.content === "string") {
|
|
14927
|
+
text = m.content;
|
|
14928
|
+
} else if (Array.isArray(m.content)) {
|
|
14929
|
+
text = m.content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
14930
|
+
}
|
|
14931
|
+
text = text.trim();
|
|
14932
|
+
if (text.length > 10) {
|
|
14933
|
+
texts.unshift(text);
|
|
14934
|
+
}
|
|
14935
|
+
}
|
|
14936
|
+
return texts.join("\n---\n");
|
|
14937
|
+
}
|
|
14938
|
+
function gatherGitEvidence() {
|
|
14939
|
+
const pieces = [];
|
|
14940
|
+
try {
|
|
14941
|
+
const branch = execSync4("git branch --show-current", { cwd: process.cwd(), encoding: "utf8" }).trim();
|
|
14942
|
+
if (branch) pieces.push(`Branch: ${branch}`);
|
|
14943
|
+
} catch {
|
|
14944
|
+
}
|
|
14945
|
+
try {
|
|
14946
|
+
const log2 = execSync4("git log --oneline -5", { cwd: process.cwd(), encoding: "utf8" }).trim();
|
|
14947
|
+
if (log2) pieces.push(`Recent commits:
|
|
14948
|
+
${log2}`);
|
|
14949
|
+
} catch {
|
|
14950
|
+
}
|
|
14951
|
+
try {
|
|
14952
|
+
const status = execSync4("git status --short", { cwd: process.cwd(), encoding: "utf8" }).trim();
|
|
14953
|
+
if (status) pieces.push(`Working tree changes:
|
|
14954
|
+
${status}`);
|
|
14955
|
+
} catch {
|
|
14956
|
+
}
|
|
14957
|
+
return pieces.join("\n\n");
|
|
14958
|
+
}
|
|
14959
|
+
async function gatherMemoryEvidence(manager, enabled, signal) {
|
|
14960
|
+
if (!enabled) return "";
|
|
14961
|
+
try {
|
|
14962
|
+
const cwd = process.cwd();
|
|
14963
|
+
const results = await manager.recall({ text: cwd, repoPath: cwd, limit: 10 });
|
|
14964
|
+
const highSignal = results.filter(
|
|
14965
|
+
(r) => ["edit_event", "task", "instruction"].includes(r.memory.category)
|
|
14966
|
+
);
|
|
14967
|
+
if (highSignal.length === 0) return "";
|
|
14968
|
+
const synthesized = await manager.synthesizeRecalled(highSignal, signal);
|
|
14969
|
+
return synthesized ? `Recorded work log:
|
|
14970
|
+
${synthesized}` : "";
|
|
14971
|
+
} catch {
|
|
14972
|
+
return "";
|
|
14973
|
+
}
|
|
14974
|
+
}
|
|
14975
|
+
async function runKimiText2(opts2) {
|
|
14976
|
+
const events = runKimi({
|
|
14977
|
+
accountId: opts2.accountId,
|
|
14978
|
+
apiToken: opts2.apiToken,
|
|
14979
|
+
model: opts2.model,
|
|
14980
|
+
messages: opts2.messages,
|
|
14981
|
+
temperature: 0.1,
|
|
14982
|
+
reasoningEffort: "low",
|
|
14983
|
+
gateway: opts2.gateway,
|
|
14984
|
+
signal: opts2.signal
|
|
14985
|
+
});
|
|
14986
|
+
let text = "";
|
|
14987
|
+
for await (const ev of events) {
|
|
14988
|
+
if (ev.type === "text") text += ev.delta;
|
|
14989
|
+
}
|
|
14990
|
+
return text.trim();
|
|
14991
|
+
}
|
|
14992
|
+
async function generateContinuationSummary(opts2) {
|
|
14993
|
+
const { messages, mode } = opts2;
|
|
14994
|
+
if (mode === "plan") {
|
|
14995
|
+
return distillSessionPlan(messages);
|
|
14996
|
+
}
|
|
14997
|
+
const goal = extractFirstUserGoal(messages);
|
|
14998
|
+
const recentAssistant = extractRecentAssistantMessages(messages);
|
|
14999
|
+
const gitEvidence = gatherGitEvidence();
|
|
15000
|
+
const memoryEvidence = opts2.memoryManager ? await gatherMemoryEvidence(opts2.memoryManager, opts2.memoryEnabled ?? false, opts2.signal) : "";
|
|
15001
|
+
const evidenceParts = [];
|
|
15002
|
+
if (goal) evidenceParts.push(`## Original goal(s)
|
|
15003
|
+
${goal}`);
|
|
15004
|
+
if (recentAssistant) evidenceParts.push(`## Recent assistant messages
|
|
15005
|
+
${recentAssistant}`);
|
|
15006
|
+
if (gitEvidence) evidenceParts.push(`## Git state
|
|
15007
|
+
${gitEvidence}`);
|
|
15008
|
+
if (memoryEvidence) evidenceParts.push(`## ${memoryEvidence}`);
|
|
15009
|
+
if (evidenceParts.length === 0) {
|
|
15010
|
+
return null;
|
|
15011
|
+
}
|
|
15012
|
+
const userPrompt = evidenceParts.join("\n\n");
|
|
15013
|
+
const summary = await runKimiText2({
|
|
15014
|
+
accountId: opts2.accountId,
|
|
15015
|
+
apiToken: opts2.apiToken,
|
|
15016
|
+
model: opts2.model,
|
|
15017
|
+
gateway: opts2.gateway,
|
|
15018
|
+
signal: opts2.signal,
|
|
15019
|
+
messages: [
|
|
15020
|
+
{ role: "system", content: HANDOFF_SYSTEM },
|
|
15021
|
+
{ role: "user", content: userPrompt }
|
|
15022
|
+
]
|
|
15023
|
+
});
|
|
15024
|
+
return summary || null;
|
|
15025
|
+
}
|
|
15026
|
+
var HANDOFF_SYSTEM;
|
|
15027
|
+
var init_continuation_summary = __esm({
|
|
15028
|
+
"src/agent/continuation-summary.ts"() {
|
|
15029
|
+
"use strict";
|
|
15030
|
+
init_client();
|
|
15031
|
+
init_distill();
|
|
15032
|
+
HANDOFF_SYSTEM = `You are a session-continuation engine. Given evidence from a coding session, produce a dense handoff document so a new agent can pick up exactly where this one left off.
|
|
15033
|
+
|
|
15034
|
+
Output format (use these exact headings):
|
|
15035
|
+
Goal: what the user originally asked for.
|
|
15036
|
+
Completed: files modified, tests added, key decisions, commits made.
|
|
15037
|
+
Remaining: what still needs to be done.
|
|
15038
|
+
Current state: any open errors, incomplete refactors, or pending work.
|
|
15039
|
+
Context: relevant file paths or architectural notes.
|
|
15040
|
+
|
|
15041
|
+
Rules:
|
|
15042
|
+
- Be terse but complete. A new agent with zero prior context must be able to continue.
|
|
15043
|
+
- Do not include chat-style pleasantries.
|
|
15044
|
+
- Do not speculate beyond the evidence provided.
|
|
15045
|
+
- Aim for ~300-600 tokens.`;
|
|
15046
|
+
}
|
|
15047
|
+
});
|
|
15048
|
+
|
|
14159
15049
|
// src/ui/greetings.ts
|
|
14160
15050
|
function pick(arr) {
|
|
14161
15051
|
if (arr.length === 0) throw new Error("pick() called with empty array");
|
|
@@ -15021,24 +15911,24 @@ var init_theme = __esm({
|
|
|
15021
15911
|
});
|
|
15022
15912
|
|
|
15023
15913
|
// src/util/clipboard.ts
|
|
15024
|
-
import { execSync as
|
|
15025
|
-
import { platform as
|
|
15914
|
+
import { execSync as execSync5 } from "child_process";
|
|
15915
|
+
import { platform as platform4 } from "os";
|
|
15026
15916
|
function writeToClipboard(text) {
|
|
15027
|
-
const os2 =
|
|
15917
|
+
const os2 = platform4();
|
|
15028
15918
|
try {
|
|
15029
15919
|
if (os2 === "darwin") {
|
|
15030
|
-
|
|
15920
|
+
execSync5("pbcopy", { input: text, timeout: 5e3 });
|
|
15031
15921
|
return { success: true, message: "Copied to clipboard" };
|
|
15032
15922
|
}
|
|
15033
15923
|
if (os2 === "win32") {
|
|
15034
|
-
|
|
15924
|
+
execSync5("clip", { input: text, timeout: 5e3 });
|
|
15035
15925
|
return { success: true, message: "Copied to clipboard" };
|
|
15036
15926
|
}
|
|
15037
15927
|
try {
|
|
15038
|
-
|
|
15928
|
+
execSync5("xclip -selection clipboard", { input: text, timeout: 5e3 });
|
|
15039
15929
|
return { success: true, message: "Copied to clipboard" };
|
|
15040
15930
|
} catch {
|
|
15041
|
-
|
|
15931
|
+
execSync5("xsel --clipboard --input", { input: text, timeout: 5e3 });
|
|
15042
15932
|
return { success: true, message: "Copied to clipboard" };
|
|
15043
15933
|
}
|
|
15044
15934
|
} catch {
|
|
@@ -15359,8 +16249,8 @@ var init_frontmatter = __esm({
|
|
|
15359
16249
|
});
|
|
15360
16250
|
|
|
15361
16251
|
// src/skills/loader.ts
|
|
15362
|
-
import { readFile as
|
|
15363
|
-
import { join as
|
|
16252
|
+
import { readFile as readFile17, readdir as readdir6, stat as stat6 } from "fs/promises";
|
|
16253
|
+
import { join as join26, extname } from "path";
|
|
15364
16254
|
function normalizeManifest(raw, filePath) {
|
|
15365
16255
|
const name = typeof raw.name === "string" ? raw.name : "";
|
|
15366
16256
|
const description = typeof raw.description === "string" ? raw.description : "";
|
|
@@ -15374,7 +16264,7 @@ function normalizeManifest(raw, filePath) {
|
|
|
15374
16264
|
return { name, description, match, scope, priority, enabled };
|
|
15375
16265
|
}
|
|
15376
16266
|
async function loadSkillFile(filePath) {
|
|
15377
|
-
const raw = await
|
|
16267
|
+
const raw = await readFile17(filePath, "utf-8");
|
|
15378
16268
|
const parsed = parseFrontmatter(raw);
|
|
15379
16269
|
const manifest = normalizeManifest(parsed.data, filePath);
|
|
15380
16270
|
const body = parsed.content.trim();
|
|
@@ -15396,7 +16286,7 @@ async function loadSkillsFromDir(dirPath) {
|
|
|
15396
16286
|
const entries = await readdir6(dirPath);
|
|
15397
16287
|
const files = [];
|
|
15398
16288
|
for (const entry of entries) {
|
|
15399
|
-
const full =
|
|
16289
|
+
const full = join26(dirPath, entry);
|
|
15400
16290
|
const s = await stat6(full);
|
|
15401
16291
|
if (s.isFile() && extname(entry) === ".md") {
|
|
15402
16292
|
files.push(full);
|
|
@@ -15424,12 +16314,12 @@ var init_loader = __esm({
|
|
|
15424
16314
|
});
|
|
15425
16315
|
|
|
15426
16316
|
// src/skills/manager.ts
|
|
15427
|
-
import { mkdir as mkdir10, writeFile as
|
|
15428
|
-
import { join as
|
|
16317
|
+
import { mkdir as mkdir10, writeFile as writeFile12, unlink as unlink2, readFile as readFile18 } from "fs/promises";
|
|
16318
|
+
import { join as join27 } from "path";
|
|
15429
16319
|
function getSkillDirs(cwd) {
|
|
15430
16320
|
return {
|
|
15431
|
-
projectDir:
|
|
15432
|
-
globalDir:
|
|
16321
|
+
projectDir: join27(cwd, ".kimiflare", "skills"),
|
|
16322
|
+
globalDir: join27(process.env.HOME ?? "", ".config", "kimiflare", "skills")
|
|
15433
16323
|
};
|
|
15434
16324
|
}
|
|
15435
16325
|
async function listAllSkills(cwd) {
|
|
@@ -15443,7 +16333,7 @@ async function listAllSkills(cwd) {
|
|
|
15443
16333
|
async function createSkill(opts2) {
|
|
15444
16334
|
const dirs = getSkillDirs(opts2.cwd);
|
|
15445
16335
|
const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
|
|
15446
|
-
const filepath =
|
|
16336
|
+
const filepath = join27(dir, `${opts2.name}.md`);
|
|
15447
16337
|
const frontmatter = {
|
|
15448
16338
|
name: opts2.name,
|
|
15449
16339
|
enabled: true,
|
|
@@ -15465,7 +16355,7 @@ ${yaml}
|
|
|
15465
16355
|
Add your instructions here.
|
|
15466
16356
|
`;
|
|
15467
16357
|
await mkdir10(dir, { recursive: true });
|
|
15468
|
-
await
|
|
16358
|
+
await writeFile12(filepath, content, "utf8");
|
|
15469
16359
|
return { filepath };
|
|
15470
16360
|
}
|
|
15471
16361
|
async function deleteSkill(name, cwd) {
|
|
@@ -15479,7 +16369,7 @@ async function setSkillEnabled(name, enabled, cwd) {
|
|
|
15479
16369
|
const all = await listAllSkills(cwd);
|
|
15480
16370
|
const skill = all.project.find((s) => s.name === name) ?? all.global.find((s) => s.name === name);
|
|
15481
16371
|
if (!skill) throw new Error(`skill "${name}" not found`);
|
|
15482
|
-
const raw = await
|
|
16372
|
+
const raw = await readFile18(skill.filePath, "utf-8");
|
|
15483
16373
|
const parsed = parseFrontmatter(raw);
|
|
15484
16374
|
parsed.data.enabled = enabled;
|
|
15485
16375
|
const yaml = Object.entries(parsed.data).map(([k, v]) => {
|
|
@@ -15491,7 +16381,7 @@ ${v.map((item) => ` - ${item}`).join("\n")}`;
|
|
|
15491
16381
|
${yaml}
|
|
15492
16382
|
---
|
|
15493
16383
|
${parsed.content}`;
|
|
15494
|
-
await
|
|
16384
|
+
await writeFile12(skill.filePath, content, "utf8");
|
|
15495
16385
|
return { filepath: skill.filePath };
|
|
15496
16386
|
}
|
|
15497
16387
|
async function findSkillFile(name, cwd) {
|
|
@@ -15564,13 +16454,13 @@ var init_frontmatter2 = __esm({
|
|
|
15564
16454
|
// src/commands/loader.ts
|
|
15565
16455
|
import { open, realpath as realpath2 } from "fs/promises";
|
|
15566
16456
|
import { homedir as homedir14 } from "os";
|
|
15567
|
-
import { join as
|
|
16457
|
+
import { join as join28, relative as relative5, sep as sep2 } from "path";
|
|
15568
16458
|
function projectCommandsDir(cwd = process.cwd()) {
|
|
15569
|
-
return
|
|
16459
|
+
return join28(cwd, ".kimiflare", "commands");
|
|
15570
16460
|
}
|
|
15571
16461
|
function globalCommandsDir() {
|
|
15572
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
15573
|
-
return
|
|
16462
|
+
const xdg = process.env.XDG_CONFIG_HOME || join28(homedir14(), ".config");
|
|
16463
|
+
return join28(xdg, "kimiflare", "commands");
|
|
15574
16464
|
}
|
|
15575
16465
|
async function loadCustomCommands(cwd = process.cwd()) {
|
|
15576
16466
|
const warnings = [];
|
|
@@ -15721,7 +16611,7 @@ var init_loader2 = __esm({
|
|
|
15721
16611
|
});
|
|
15722
16612
|
|
|
15723
16613
|
// src/commands/save.ts
|
|
15724
|
-
import { mkdir as mkdir11, writeFile as
|
|
16614
|
+
import { mkdir as mkdir11, writeFile as writeFile13, unlink as unlink3 } from "fs/promises";
|
|
15725
16615
|
import { dirname as dirname11 } from "path";
|
|
15726
16616
|
async function saveCustomCommand(opts2) {
|
|
15727
16617
|
const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
|
|
@@ -15734,7 +16624,7 @@ async function saveCustomCommand(opts2) {
|
|
|
15734
16624
|
const frontmatter = serializeFrontmatter(data);
|
|
15735
16625
|
const content = frontmatter + opts2.template;
|
|
15736
16626
|
await mkdir11(dirname11(filepath), { recursive: true });
|
|
15737
|
-
await
|
|
16627
|
+
await writeFile13(filepath, content, "utf8");
|
|
15738
16628
|
return { filepath };
|
|
15739
16629
|
}
|
|
15740
16630
|
async function deleteCustomCommand(cmd) {
|
|
@@ -15844,13 +16734,13 @@ var init_worker_client = __esm({
|
|
|
15844
16734
|
});
|
|
15845
16735
|
|
|
15846
16736
|
// src/init/context-generator.ts
|
|
15847
|
-
import { existsSync as
|
|
15848
|
-
import { join as
|
|
16737
|
+
import { existsSync as existsSync5, statSync as statSync5 } from "fs";
|
|
16738
|
+
import { join as join29 } from "path";
|
|
15849
16739
|
function detectFlavor(cwd) {
|
|
15850
16740
|
for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
|
|
15851
16741
|
if (flavor === "generic") continue;
|
|
15852
16742
|
for (const sig of signatures) {
|
|
15853
|
-
const path =
|
|
16743
|
+
const path = join29(cwd, sig);
|
|
15854
16744
|
if (sig.includes("*")) {
|
|
15855
16745
|
try {
|
|
15856
16746
|
const parts = sig.split("*");
|
|
@@ -15862,7 +16752,7 @@ function detectFlavor(cwd) {
|
|
|
15862
16752
|
}
|
|
15863
16753
|
} catch {
|
|
15864
16754
|
}
|
|
15865
|
-
} else if (
|
|
16755
|
+
} else if (existsSync5(path)) {
|
|
15866
16756
|
return flavor;
|
|
15867
16757
|
}
|
|
15868
16758
|
}
|
|
@@ -15871,16 +16761,16 @@ function detectFlavor(cwd) {
|
|
|
15871
16761
|
}
|
|
15872
16762
|
function findFile(cwd, candidates) {
|
|
15873
16763
|
for (const c of candidates) {
|
|
15874
|
-
if (
|
|
16764
|
+
if (existsSync5(join29(cwd, c))) return c;
|
|
15875
16765
|
}
|
|
15876
16766
|
return null;
|
|
15877
16767
|
}
|
|
15878
16768
|
function findSourceRoots(cwd) {
|
|
15879
16769
|
const roots = [];
|
|
15880
16770
|
for (const r of SOURCE_ROOT_CANDIDATES) {
|
|
15881
|
-
const p =
|
|
16771
|
+
const p = join29(cwd, r);
|
|
15882
16772
|
try {
|
|
15883
|
-
const s =
|
|
16773
|
+
const s = statSync5(p);
|
|
15884
16774
|
if (s.isDirectory()) roots.push(r);
|
|
15885
16775
|
} catch {
|
|
15886
16776
|
}
|
|
@@ -15889,9 +16779,9 @@ function findSourceRoots(cwd) {
|
|
|
15889
16779
|
}
|
|
15890
16780
|
function findCiConfig(cwd) {
|
|
15891
16781
|
for (const c of CI_PATHS) {
|
|
15892
|
-
if (
|
|
16782
|
+
if (existsSync5(join29(cwd, c))) {
|
|
15893
16783
|
try {
|
|
15894
|
-
const s =
|
|
16784
|
+
const s = statSync5(join29(cwd, c));
|
|
15895
16785
|
return s.isDirectory() ? c : c;
|
|
15896
16786
|
} catch {
|
|
15897
16787
|
}
|
|
@@ -16028,7 +16918,7 @@ function analyzeProject(cwd) {
|
|
|
16028
16918
|
ciConfig: findCiConfig(cwd),
|
|
16029
16919
|
readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
|
|
16030
16920
|
sourceRoots: findSourceRoots(cwd),
|
|
16031
|
-
hasGit:
|
|
16921
|
+
hasGit: existsSync5(join29(cwd, ".git"))
|
|
16032
16922
|
};
|
|
16033
16923
|
}
|
|
16034
16924
|
function bashDiscoveryCommands(profile) {
|
|
@@ -16193,7 +17083,7 @@ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
|
|
|
16193
17083
|
}
|
|
16194
17084
|
function buildInitPrompt(cwd) {
|
|
16195
17085
|
const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
|
|
16196
|
-
(n) =>
|
|
17086
|
+
(n) => existsSync5(join29(cwd, n))
|
|
16197
17087
|
);
|
|
16198
17088
|
const isRefresh = existingName !== void 0;
|
|
16199
17089
|
const targetFilename = existingName ?? "KIMI.md";
|
|
@@ -16281,11 +17171,11 @@ __export(ui_mode_exports, {
|
|
|
16281
17171
|
runCamouflageOnboarding: () => runCamouflageOnboarding,
|
|
16282
17172
|
runUiMode: () => runUiMode
|
|
16283
17173
|
});
|
|
16284
|
-
import { execSync as
|
|
17174
|
+
import { execSync as execSync6, spawn as spawn6 } from "child_process";
|
|
16285
17175
|
import { appendFileSync, openSync } from "fs";
|
|
16286
17176
|
import { readdir as readdir7, unlink as unlink4 } from "fs/promises";
|
|
16287
|
-
import { join as
|
|
16288
|
-
import { platform as
|
|
17177
|
+
import { join as join30, relative as relative6 } from "path";
|
|
17178
|
+
import { platform as platform5 } from "os";
|
|
16289
17179
|
function kimiLog(payload) {
|
|
16290
17180
|
if (!KIMI_LOG_PATH) return;
|
|
16291
17181
|
try {
|
|
@@ -17067,6 +17957,14 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
17067
17957
|
cam.send("StatusUpdate", {
|
|
17068
17958
|
segments: { tokens: "in 0", cost: "$0.00", elapsed: "" }
|
|
17069
17959
|
});
|
|
17960
|
+
rebuildSystemPromptForMode(
|
|
17961
|
+
messages,
|
|
17962
|
+
false,
|
|
17963
|
+
// Camouflage UI always uses single system message
|
|
17964
|
+
opts2.model,
|
|
17965
|
+
currentMode,
|
|
17966
|
+
ALL_TOOLS
|
|
17967
|
+
);
|
|
17070
17968
|
messages.push({ role: "user", content: selected.plan });
|
|
17071
17969
|
cam.send("UserMessageCreated", { text: selected.plan });
|
|
17072
17970
|
cam.send("ShowToast", {
|
|
@@ -17129,7 +18027,7 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
17129
18027
|
allow_cancel: true
|
|
17130
18028
|
});
|
|
17131
18029
|
if (pick3.cancelled || !pick3.value) return;
|
|
17132
|
-
|
|
18030
|
+
openBrowser2(
|
|
17133
18031
|
`${URL2}/inbox?u=${encodeURIComponent(handle)}&s=${encodeURIComponent(secret)}&m=${encodeURIComponent(pick3.value)}`
|
|
17134
18032
|
);
|
|
17135
18033
|
cam.send("ShowToast", { text: "opened in browser", kind: "success", ttl_ms: 1500 });
|
|
@@ -18246,7 +19144,7 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
18246
19144
|
return true;
|
|
18247
19145
|
}
|
|
18248
19146
|
case "hello":
|
|
18249
|
-
|
|
19147
|
+
openBrowser2("https://hello.kimiflare.com");
|
|
18250
19148
|
cam.send("ShowToast", { text: "opened hello.kimiflare.com \u2014 leave the creator a voice note", kind: "info", ttl_ms: 3500 });
|
|
18251
19149
|
return true;
|
|
18252
19150
|
case "inbox":
|
|
@@ -18264,33 +19162,50 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
18264
19162
|
cam.send("ShowToast", { text: "can't /fresh while model is running \u2014 press Esc to interrupt first", kind: "warn", ttl_ms: 2500 });
|
|
18265
19163
|
return true;
|
|
18266
19164
|
}
|
|
18267
|
-
|
|
18268
|
-
|
|
18269
|
-
|
|
18270
|
-
|
|
18271
|
-
|
|
18272
|
-
|
|
18273
|
-
|
|
18274
|
-
|
|
18275
|
-
|
|
18276
|
-
|
|
18277
|
-
|
|
18278
|
-
|
|
18279
|
-
|
|
18280
|
-
|
|
18281
|
-
|
|
18282
|
-
|
|
18283
|
-
|
|
18284
|
-
|
|
18285
|
-
|
|
18286
|
-
|
|
18287
|
-
|
|
18288
|
-
|
|
18289
|
-
|
|
18290
|
-
|
|
18291
|
-
|
|
18292
|
-
|
|
18293
|
-
|
|
19165
|
+
void (async () => {
|
|
19166
|
+
const summary = await generateContinuationSummary({
|
|
19167
|
+
messages,
|
|
19168
|
+
mode: currentMode,
|
|
19169
|
+
accountId: opts2.accountId,
|
|
19170
|
+
apiToken: opts2.apiToken,
|
|
19171
|
+
model: opts2.plumbingModel ?? "@cf/moonshotai/kimi-k2.5",
|
|
19172
|
+
gateway: gatewayFromOpts2(opts2)
|
|
19173
|
+
});
|
|
19174
|
+
if (!summary) {
|
|
19175
|
+
cam.send("ShowToast", { text: "No plan or summary found to start fresh with.", kind: "error", ttl_ms: 2500 });
|
|
19176
|
+
return;
|
|
19177
|
+
}
|
|
19178
|
+
const clipResult = writeToClipboard(summary);
|
|
19179
|
+
const systemMessages = messages.filter((m) => m.role === "system");
|
|
19180
|
+
messages.length = 0;
|
|
19181
|
+
messages.push(...systemMessages);
|
|
19182
|
+
sessionCostUsd = 0;
|
|
19183
|
+
promptTokens = 0;
|
|
19184
|
+
cachedTokens = 0;
|
|
19185
|
+
completionTokens = 0;
|
|
19186
|
+
sessionPlan = null;
|
|
19187
|
+
cam.send("TranscriptCleared", {});
|
|
19188
|
+
cam.send("StatusUpdate", {
|
|
19189
|
+
segments: { tokens: "in 0", cost: "$0.00", elapsed: "" }
|
|
19190
|
+
});
|
|
19191
|
+
rebuildSystemPromptForMode(
|
|
19192
|
+
messages,
|
|
19193
|
+
false,
|
|
19194
|
+
// Camouflage UI always uses single system message
|
|
19195
|
+
opts2.model,
|
|
19196
|
+
currentMode,
|
|
19197
|
+
ALL_TOOLS
|
|
19198
|
+
);
|
|
19199
|
+
messages.push({ role: "user", content: summary });
|
|
19200
|
+
cam.send("ShowToast", {
|
|
19201
|
+
text: clipResult.success ? "Summary copied to clipboard. Starting fresh session with continuation context\u2026" : "Clipboard unavailable. Starting fresh session with continuation context\u2026",
|
|
19202
|
+
kind: "info",
|
|
19203
|
+
ttl_ms: 3e3
|
|
19204
|
+
});
|
|
19205
|
+
if (!clipResult.success) {
|
|
19206
|
+
cam.send("UserMessageCreated", { text: "--- Continuation Context ---\n" + summary });
|
|
19207
|
+
}
|
|
19208
|
+
})();
|
|
18294
19209
|
return true;
|
|
18295
19210
|
}
|
|
18296
19211
|
case "logout": {
|
|
@@ -18355,7 +19270,7 @@ async function registerMentions(cam, recents) {
|
|
|
18355
19270
|
for (const e of entries) {
|
|
18356
19271
|
if (collected.length >= 200) return;
|
|
18357
19272
|
if (e.name.startsWith(".") || SKIP.has(e.name)) continue;
|
|
18358
|
-
const full =
|
|
19273
|
+
const full = join30(dir, e.name);
|
|
18359
19274
|
if (e.isDirectory()) {
|
|
18360
19275
|
await walk2(full, depth + 1);
|
|
18361
19276
|
} else if (e.isFile()) {
|
|
@@ -18404,9 +19319,9 @@ function formatShortDate(iso) {
|
|
|
18404
19319
|
return iso;
|
|
18405
19320
|
}
|
|
18406
19321
|
}
|
|
18407
|
-
function
|
|
18408
|
-
const cmd =
|
|
18409
|
-
const child =
|
|
19322
|
+
function openBrowser2(url) {
|
|
19323
|
+
const cmd = platform5() === "darwin" ? "open" : platform5() === "win32" ? "start" : "xdg-open";
|
|
19324
|
+
const child = spawn6(cmd, [url], { detached: true, stdio: "ignore" });
|
|
18410
19325
|
child.unref();
|
|
18411
19326
|
}
|
|
18412
19327
|
function formatUsd(n) {
|
|
@@ -18425,7 +19340,7 @@ function formatElapsed2(secs) {
|
|
|
18425
19340
|
}
|
|
18426
19341
|
function tryGitBranch2() {
|
|
18427
19342
|
try {
|
|
18428
|
-
const out =
|
|
19343
|
+
const out = execSync6("git rev-parse --abbrev-ref HEAD 2>/dev/null", {
|
|
18429
19344
|
encoding: "utf8",
|
|
18430
19345
|
timeout: 200
|
|
18431
19346
|
}).trim();
|
|
@@ -18530,12 +19445,14 @@ var init_ui_mode = __esm({
|
|
|
18530
19445
|
init_classify();
|
|
18531
19446
|
init_deploy_commute();
|
|
18532
19447
|
init_system_prompt();
|
|
19448
|
+
init_app_helpers();
|
|
18533
19449
|
init_executor();
|
|
18534
19450
|
init_errors();
|
|
18535
19451
|
init_builtins();
|
|
18536
19452
|
init_sessions();
|
|
18537
19453
|
init_llm_summarize();
|
|
18538
19454
|
init_distill();
|
|
19455
|
+
init_continuation_summary();
|
|
18539
19456
|
init_greetings();
|
|
18540
19457
|
init_theme();
|
|
18541
19458
|
init_update_check();
|
|
@@ -21017,7 +21934,7 @@ var init_text_input = __esm({
|
|
|
21017
21934
|
// src/ui/permission.tsx
|
|
21018
21935
|
import { useState as useState4, useCallback } from "react";
|
|
21019
21936
|
import { Box as Box7, Text as Text8, useInput as useInput2 } from "ink";
|
|
21020
|
-
import { platform as
|
|
21937
|
+
import { platform as platform6 } from "os";
|
|
21021
21938
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
21022
21939
|
function formatSelection(label, shortcut) {
|
|
21023
21940
|
return `${label} [${MOD_KEY}+${shortcut}]`;
|
|
@@ -21181,7 +22098,7 @@ var init_permission = __esm({
|
|
|
21181
22098
|
{ value: { decision: "deny", scope: "once" }, label: "Something else", key: 3 }
|
|
21182
22099
|
];
|
|
21183
22100
|
DENY = { decision: "deny", scope: "once" };
|
|
21184
|
-
MOD_KEY =
|
|
22101
|
+
MOD_KEY = platform6() === "darwin" ? "\u2325" : "Alt";
|
|
21185
22102
|
}
|
|
21186
22103
|
});
|
|
21187
22104
|
|
|
@@ -21619,7 +22536,7 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
|
|
|
21619
22536
|
const allDone = done === total;
|
|
21620
22537
|
const header = active ? active.title : allDone ? `${total} tasks done` : `${done}/${total}`;
|
|
21621
22538
|
const elapsed = startedAt ? formatElapsed5(now2 - startedAt) : null;
|
|
21622
|
-
const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${
|
|
22539
|
+
const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens2(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
|
|
21623
22540
|
const visibleTasks = tasks.slice(0, MAX_VISIBLE);
|
|
21624
22541
|
const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
|
|
21625
22542
|
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
|
|
@@ -21671,7 +22588,7 @@ function formatElapsed5(ms) {
|
|
|
21671
22588
|
if (m === 0) return `${s}s`;
|
|
21672
22589
|
return `${m}m ${s}s`;
|
|
21673
22590
|
}
|
|
21674
|
-
function
|
|
22591
|
+
function formatTokens2(n) {
|
|
21675
22592
|
if (n < 1e3) return String(n);
|
|
21676
22593
|
return `${(n / 1e3).toFixed(1)}k`;
|
|
21677
22594
|
}
|
|
@@ -23212,52 +24129,13 @@ function Welcome() {
|
|
|
23212
24129
|
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginBottom: 1, children: [
|
|
23213
24130
|
/* @__PURE__ */ jsx20(Box18, { marginBottom: 1, children: /* @__PURE__ */ jsx20(Text19, { bold: true, color: theme.accent, children: headline }) }),
|
|
23214
24131
|
/* @__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;
|
|
23247
|
-
}
|
|
23248
|
-
var MAX_IMAGE_BYTES, EXT_TO_MIME;
|
|
23249
|
-
var init_image = __esm({
|
|
23250
|
-
"src/util/image.ts"() {
|
|
23251
|
-
"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
|
-
};
|
|
24132
|
+
] });
|
|
24133
|
+
}
|
|
24134
|
+
var init_welcome = __esm({
|
|
24135
|
+
"src/ui/welcome.tsx"() {
|
|
24136
|
+
"use strict";
|
|
24137
|
+
init_theme_context();
|
|
24138
|
+
init_greetings();
|
|
23261
24139
|
}
|
|
23262
24140
|
});
|
|
23263
24141
|
|
|
@@ -23493,11 +24371,11 @@ var init_wcag = __esm({
|
|
|
23493
24371
|
});
|
|
23494
24372
|
|
|
23495
24373
|
// src/ui/theme-loader.ts
|
|
23496
|
-
import { readFile as
|
|
23497
|
-
import { join as
|
|
24374
|
+
import { readFile as readFile19, readdir as readdir8 } from "fs/promises";
|
|
24375
|
+
import { join as join31 } from "path";
|
|
23498
24376
|
import { homedir as homedir15 } from "os";
|
|
23499
24377
|
function projectThemesDir(cwd = process.cwd()) {
|
|
23500
|
-
return
|
|
24378
|
+
return join31(cwd, ".kimiflare", "themes");
|
|
23501
24379
|
}
|
|
23502
24380
|
function isHexColor(c) {
|
|
23503
24381
|
return /^#[0-9a-fA-F]{6}$/.test(c);
|
|
@@ -23586,10 +24464,10 @@ async function loadThemesFromDir(dir, source) {
|
|
|
23586
24464
|
return { themes, errors };
|
|
23587
24465
|
}
|
|
23588
24466
|
for (const file of files.filter((f) => f.endsWith(".json"))) {
|
|
23589
|
-
const path =
|
|
24467
|
+
const path = join31(dir, file);
|
|
23590
24468
|
let raw;
|
|
23591
24469
|
try {
|
|
23592
|
-
raw = await
|
|
24470
|
+
raw = await readFile19(path, "utf-8");
|
|
23593
24471
|
} catch (e) {
|
|
23594
24472
|
errors.push(`${path}: ${e instanceof Error ? e.message : String(e)}`);
|
|
23595
24473
|
continue;
|
|
@@ -23735,8 +24613,8 @@ var init_theme_loader = __esm({
|
|
|
23735
24613
|
"use strict";
|
|
23736
24614
|
init_wcag();
|
|
23737
24615
|
init_theme();
|
|
23738
|
-
USER_THEMES_DIR =
|
|
23739
|
-
process.env.XDG_CONFIG_HOME ||
|
|
24616
|
+
USER_THEMES_DIR = join31(
|
|
24617
|
+
process.env.XDG_CONFIG_HOME || join31(homedir15(), ".config"),
|
|
23740
24618
|
"kimiflare",
|
|
23741
24619
|
"themes"
|
|
23742
24620
|
);
|
|
@@ -24173,8 +25051,9 @@ function useModalHost() {
|
|
|
24173
25051
|
const [showSkillsPicker, setShowSkillsPicker] = useState16(false);
|
|
24174
25052
|
const [showShellPicker, setShowShellPicker] = useState16(false);
|
|
24175
25053
|
const [showPlanCompletePicker, setShowPlanCompletePicker] = useState16(false);
|
|
25054
|
+
const [showChangelogImagePicker, setShowChangelogImagePicker] = useState16(false);
|
|
24176
25055
|
const flags = useMemo4(() => {
|
|
24177
|
-
const hasFullscreenModal = commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || showThemePicker || showUiPicker || showModelPicker || showModePicker || keyEntryFor !== null || billingChooserFor !== null || unifiedProbeFor !== null || showRemoteDashboard || showInboxModal || showMultiAgentModal || showHooksDashboard || showHelpMenu || showMemoryPicker || showGatewayPicker || showSkillsPicker || showShellPicker;
|
|
25056
|
+
const hasFullscreenModal = commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || showThemePicker || showUiPicker || showModelPicker || showModePicker || keyEntryFor !== null || billingChooserFor !== null || unifiedProbeFor !== null || showRemoteDashboard || showInboxModal || showMultiAgentModal || showHooksDashboard || showHelpMenu || showMemoryPicker || showGatewayPicker || showSkillsPicker || showShellPicker || showChangelogImagePicker;
|
|
24178
25057
|
const hasOverlayModal = limitModal !== null || loopModal !== null || showPlanCompletePicker;
|
|
24179
25058
|
return {
|
|
24180
25059
|
hasFullscreenModal,
|
|
@@ -24204,6 +25083,7 @@ function useModalHost() {
|
|
|
24204
25083
|
showSkillsPicker,
|
|
24205
25084
|
showShellPicker,
|
|
24206
25085
|
showPlanCompletePicker,
|
|
25086
|
+
showChangelogImagePicker,
|
|
24207
25087
|
limitModal,
|
|
24208
25088
|
loopModal
|
|
24209
25089
|
]);
|
|
@@ -24256,6 +25136,8 @@ function useModalHost() {
|
|
|
24256
25136
|
setShowShellPicker,
|
|
24257
25137
|
showPlanCompletePicker,
|
|
24258
25138
|
setShowPlanCompletePicker,
|
|
25139
|
+
showChangelogImagePicker,
|
|
25140
|
+
setShowChangelogImagePicker,
|
|
24259
25141
|
...flags
|
|
24260
25142
|
};
|
|
24261
25143
|
}
|
|
@@ -24823,7 +25705,7 @@ var init_command_list = __esm({
|
|
|
24823
25705
|
import { useState as useState18 } from "react";
|
|
24824
25706
|
import { Box as Box25, Text as Text26 } from "ink";
|
|
24825
25707
|
import SelectInput10 from "ink-select-input";
|
|
24826
|
-
import { spawn as
|
|
25708
|
+
import { spawn as spawn7 } from "child_process";
|
|
24827
25709
|
import { jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
24828
25710
|
function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
|
|
24829
25711
|
const theme = useTheme();
|
|
@@ -24837,7 +25719,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
|
|
|
24837
25719
|
const runInstall = (command) => {
|
|
24838
25720
|
setInstallState({ status: "running", output: "Installing..." });
|
|
24839
25721
|
const { shell, args } = getShellCommand();
|
|
24840
|
-
const child =
|
|
25722
|
+
const child = spawn7(shell, [...args, command], {
|
|
24841
25723
|
env: process.env
|
|
24842
25724
|
});
|
|
24843
25725
|
let stdout = "";
|
|
@@ -25863,7 +26745,7 @@ function formatSessionLine(s) {
|
|
|
25863
26745
|
const ago = formatAgo(new Date(s.updatedAt));
|
|
25864
26746
|
const prompt = s.prompt.slice(0, 30) + (s.prompt.length > 30 ? "\u2026" : "");
|
|
25865
26747
|
const outcome = s.prUrl ? `PR ${s.prUrl.split("/").pop()}` : s.status;
|
|
25866
|
-
const cost = s.tokensUsed && s.tokensBudget ? ` (${
|
|
26748
|
+
const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens3(s.tokensUsed)}/${formatTokens3(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens3(s.tokensUsed)})` : "";
|
|
25867
26749
|
return `${icon} ${prompt} \u2192 ${outcome} ${ago}${cost}`;
|
|
25868
26750
|
}
|
|
25869
26751
|
function formatAgo(date) {
|
|
@@ -25876,7 +26758,7 @@ function formatAgo(date) {
|
|
|
25876
26758
|
if (minutes > 0) return `${minutes}m ago`;
|
|
25877
26759
|
return "just now";
|
|
25878
26760
|
}
|
|
25879
|
-
function
|
|
26761
|
+
function formatTokens3(n) {
|
|
25880
26762
|
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
25881
26763
|
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
25882
26764
|
return String(n);
|
|
@@ -25937,8 +26819,8 @@ function RemoteSessionDetail({
|
|
|
25937
26819
|
] }),
|
|
25938
26820
|
session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs33(Text34, { children: [
|
|
25939
26821
|
"Tokens: ",
|
|
25940
|
-
|
|
25941
|
-
session.tokensBudget ? ` / ${
|
|
26822
|
+
formatTokens3(session.tokensUsed),
|
|
26823
|
+
session.tokensBudget ? ` / ${formatTokens3(session.tokensBudget)}` : ""
|
|
25942
26824
|
] }),
|
|
25943
26825
|
/* @__PURE__ */ jsxs33(Text34, { children: [
|
|
25944
26826
|
"Created: ",
|
|
@@ -25982,7 +26864,7 @@ function InboxModal({ onDone, onOpen }) {
|
|
|
25982
26864
|
setError(null);
|
|
25983
26865
|
try {
|
|
25984
26866
|
const res = await fetch(
|
|
25985
|
-
`${
|
|
26867
|
+
`${FEEDBACK_WORKER_URL2}/inbox/check?u=${encodeURIComponent(u)}&s=${encodeURIComponent(s)}`
|
|
25986
26868
|
);
|
|
25987
26869
|
if (!res.ok) {
|
|
25988
26870
|
throw new Error(`Server returned ${res.status}`);
|
|
@@ -26028,7 +26910,7 @@ function InboxModal({ onDone, onOpen }) {
|
|
|
26028
26910
|
if (messages.length === 0) return;
|
|
26029
26911
|
const msg = messages[selectedIndex];
|
|
26030
26912
|
if (!msg) return;
|
|
26031
|
-
const url = `${
|
|
26913
|
+
const url = `${FEEDBACK_WORKER_URL2}/inbox?u=${encodeURIComponent(twitter)}&s=${encodeURIComponent(secret)}&m=${encodeURIComponent(msg.id)}`;
|
|
26032
26914
|
onOpen(url);
|
|
26033
26915
|
onDone();
|
|
26034
26916
|
}, [messages, selectedIndex, twitter, secret, onOpen, onDone]);
|
|
@@ -26102,280 +26984,38 @@ function InboxModal({ onDone, onOpen }) {
|
|
|
26102
26984
|
return /* @__PURE__ */ jsxs34(
|
|
26103
26985
|
Text35,
|
|
26104
26986
|
{
|
|
26105
|
-
color: isSelected ? theme.accent : theme.palette.foreground,
|
|
26106
|
-
bold: isSelected,
|
|
26107
|
-
dimColor: !isSelected && msg.seen,
|
|
26108
|
-
children: [
|
|
26109
|
-
isSelected ? "> " : " ",
|
|
26110
|
-
marker,
|
|
26111
|
-
dateStr,
|
|
26112
|
-
msg.seen ? " (played)" : " (new)"
|
|
26113
|
-
]
|
|
26114
|
-
},
|
|
26115
|
-
msg.id
|
|
26116
|
-
);
|
|
26117
|
-
}) }),
|
|
26118
|
-
/* @__PURE__ */ jsx36(Box34, { marginTop: 1, children: /* @__PURE__ */ jsx36(Text35, { color: theme.info.color, children: "\u2191\u2193 to select \xB7 Enter to open in browser" }) })
|
|
26119
|
-
] }) : /* @__PURE__ */ jsxs34(Text35, { color: theme.muted?.color ?? theme.palette.secondary, children: [
|
|
26120
|
-
"No messages yet for @",
|
|
26121
|
-
twitter,
|
|
26122
|
-
" / ",
|
|
26123
|
-
secret.replace(/./g, "*"),
|
|
26124
|
-
"."
|
|
26125
|
-
] }),
|
|
26126
|
-
/* @__PURE__ */ jsx36(Text35, { dimColor: true, children: "Press Esc to close." })
|
|
26127
|
-
] })
|
|
26128
|
-
] });
|
|
26129
|
-
}
|
|
26130
|
-
var FEEDBACK_WORKER_URL;
|
|
26131
|
-
var init_inbox_modal = __esm({
|
|
26132
|
-
"src/ui/inbox-modal.tsx"() {
|
|
26133
|
-
"use strict";
|
|
26134
|
-
init_text_input();
|
|
26135
|
-
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;
|
|
26987
|
+
color: isSelected ? theme.accent : theme.palette.foreground,
|
|
26988
|
+
bold: isSelected,
|
|
26989
|
+
dimColor: !isSelected && msg.seen,
|
|
26990
|
+
children: [
|
|
26991
|
+
isSelected ? "> " : " ",
|
|
26992
|
+
marker,
|
|
26993
|
+
dateStr,
|
|
26994
|
+
msg.seen ? " (played)" : " (new)"
|
|
26995
|
+
]
|
|
26996
|
+
},
|
|
26997
|
+
msg.id
|
|
26998
|
+
);
|
|
26999
|
+
}) }),
|
|
27000
|
+
/* @__PURE__ */ jsx36(Box34, { marginTop: 1, children: /* @__PURE__ */ jsx36(Text35, { color: theme.info.color, children: "\u2191\u2193 to select \xB7 Enter to open in browser" }) })
|
|
27001
|
+
] }) : /* @__PURE__ */ jsxs34(Text35, { color: theme.muted?.color ?? theme.palette.secondary, children: [
|
|
27002
|
+
"No messages yet for @",
|
|
27003
|
+
twitter,
|
|
27004
|
+
" / ",
|
|
27005
|
+
secret.replace(/./g, "*"),
|
|
27006
|
+
"."
|
|
27007
|
+
] }),
|
|
27008
|
+
/* @__PURE__ */ jsx36(Text35, { dimColor: true, children: "Press Esc to close." })
|
|
27009
|
+
] })
|
|
27010
|
+
] });
|
|
26362
27011
|
}
|
|
26363
|
-
var
|
|
26364
|
-
var
|
|
26365
|
-
"src/ui/
|
|
27012
|
+
var FEEDBACK_WORKER_URL2;
|
|
27013
|
+
var init_inbox_modal = __esm({
|
|
27014
|
+
"src/ui/inbox-modal.tsx"() {
|
|
26366
27015
|
"use strict";
|
|
26367
|
-
|
|
26368
|
-
|
|
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;
|
|
27016
|
+
init_text_input();
|
|
27017
|
+
init_theme_context();
|
|
26374
27018
|
FEEDBACK_WORKER_URL2 = "https://hello.kimiflare.com";
|
|
26375
|
-
nextKey = 1;
|
|
26376
|
-
mkKey = () => `evt_${nextKey++}`;
|
|
26377
|
-
nextAssistantId = 1;
|
|
26378
|
-
mkAssistantId = () => nextAssistantId++;
|
|
26379
27019
|
}
|
|
26380
27020
|
});
|
|
26381
27021
|
|
|
@@ -26556,7 +27196,7 @@ function MultiAgentModal({ initial, onSave, onDone, remoteWorkerUrl, remoteAuthS
|
|
|
26556
27196
|
if (deployFailed) {
|
|
26557
27197
|
if (input === "o" || input === "O") {
|
|
26558
27198
|
const url = deployLog.map((l) => l.match(/https:\/\/dash\.cloudflare\.com\/[^\s)]+/)?.[0]).find((u) => !!u) ?? "https://dash.cloudflare.com/profile/api-tokens";
|
|
26559
|
-
|
|
27199
|
+
openBrowser(url);
|
|
26560
27200
|
return;
|
|
26561
27201
|
}
|
|
26562
27202
|
if (input === "r" || input === "R") {
|
|
@@ -27661,10 +28301,71 @@ var init_help_menu = __esm({
|
|
|
27661
28301
|
}
|
|
27662
28302
|
});
|
|
27663
28303
|
|
|
28304
|
+
// src/ui/changelog-image-picker.tsx
|
|
28305
|
+
import { useState as useState26 } from "react";
|
|
28306
|
+
import { Box as Box39, Text as Text40, useInput as useInput20 } from "ink";
|
|
28307
|
+
import { jsx as jsx41, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
28308
|
+
function ChangelogImagePicker({ owner, repo, onGenerate, onCancel }) {
|
|
28309
|
+
const theme = useTheme();
|
|
28310
|
+
const [selectedIndex, setSelectedIndex] = useState26(0);
|
|
28311
|
+
useInput20((_input, key) => {
|
|
28312
|
+
if (key.escape) {
|
|
28313
|
+
onCancel();
|
|
28314
|
+
return;
|
|
28315
|
+
}
|
|
28316
|
+
if (key.return) {
|
|
28317
|
+
const option = PERIODS[selectedIndex];
|
|
28318
|
+
if (option) {
|
|
28319
|
+
onGenerate(owner, repo, option.days);
|
|
28320
|
+
}
|
|
28321
|
+
return;
|
|
28322
|
+
}
|
|
28323
|
+
if (key.upArrow) {
|
|
28324
|
+
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
28325
|
+
return;
|
|
28326
|
+
}
|
|
28327
|
+
if (key.downArrow) {
|
|
28328
|
+
setSelectedIndex((i) => Math.min(PERIODS.length - 1, i + 1));
|
|
28329
|
+
return;
|
|
28330
|
+
}
|
|
28331
|
+
});
|
|
28332
|
+
return /* @__PURE__ */ jsxs39(Box39, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
28333
|
+
/* @__PURE__ */ jsxs39(Text40, { color: theme.accent, bold: true, children: [
|
|
28334
|
+
"Changelog Image: ",
|
|
28335
|
+
owner,
|
|
28336
|
+
"/",
|
|
28337
|
+
repo
|
|
28338
|
+
] }),
|
|
28339
|
+
/* @__PURE__ */ jsx41(Text40, { color: theme.info.color, dimColor: true, children: "Select a time period to summarize" }),
|
|
28340
|
+
/* @__PURE__ */ jsx41(Box39, { marginTop: 1, flexDirection: "column", children: PERIODS.map((period, i) => {
|
|
28341
|
+
const isSelected = i === selectedIndex;
|
|
28342
|
+
const marker = isSelected ? "\u25B8" : " ";
|
|
28343
|
+
return /* @__PURE__ */ jsx41(Box39, { children: /* @__PURE__ */ jsxs39(Text40, { color: isSelected ? theme.accent : theme.info.color, bold: isSelected, children: [
|
|
28344
|
+
marker,
|
|
28345
|
+
" ",
|
|
28346
|
+
period.label
|
|
28347
|
+
] }) }, period.label);
|
|
28348
|
+
}) }),
|
|
28349
|
+
/* @__PURE__ */ jsx41(Box39, { marginTop: 1, children: /* @__PURE__ */ jsx41(Text40, { color: theme.info.color, dimColor: theme.info.dim, children: "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc cancel" }) })
|
|
28350
|
+
] });
|
|
28351
|
+
}
|
|
28352
|
+
var PERIODS;
|
|
28353
|
+
var init_changelog_image_picker = __esm({
|
|
28354
|
+
"src/ui/changelog-image-picker.tsx"() {
|
|
28355
|
+
"use strict";
|
|
28356
|
+
init_theme_context();
|
|
28357
|
+
PERIODS = [
|
|
28358
|
+
{ label: "Past 24 hours", days: 1 },
|
|
28359
|
+
{ label: "Past 7 days", days: 7 },
|
|
28360
|
+
{ label: "Past 30 days", days: 30 }
|
|
28361
|
+
];
|
|
28362
|
+
}
|
|
28363
|
+
});
|
|
28364
|
+
|
|
27664
28365
|
// src/ui/modal-host.tsx
|
|
27665
|
-
import { Box as
|
|
28366
|
+
import { Box as Box40, Text as Text41 } from "ink";
|
|
27666
28367
|
import SelectInput22 from "ink-select-input";
|
|
27667
|
-
import { jsx as
|
|
28368
|
+
import { jsx as jsx42, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
27668
28369
|
function ModalHost(props) {
|
|
27669
28370
|
const {
|
|
27670
28371
|
modals,
|
|
@@ -27697,7 +28398,7 @@ function ModalHost(props) {
|
|
|
27697
28398
|
onInboxOpen
|
|
27698
28399
|
} = props;
|
|
27699
28400
|
if (modals.showRemoteDashboard) {
|
|
27700
|
-
return /* @__PURE__ */
|
|
28401
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx42(
|
|
27701
28402
|
RemoteSessionDetail,
|
|
27702
28403
|
{
|
|
27703
28404
|
session: selectedRemoteSession,
|
|
@@ -27706,7 +28407,7 @@ function ModalHost(props) {
|
|
|
27706
28407
|
void onCancelRemoteSession(session);
|
|
27707
28408
|
}
|
|
27708
28409
|
}
|
|
27709
|
-
) : /* @__PURE__ */
|
|
28410
|
+
) : /* @__PURE__ */ jsx42(
|
|
27710
28411
|
RemoteDashboard,
|
|
27711
28412
|
{
|
|
27712
28413
|
onSelect: (session) => onSelectRemoteSession(session),
|
|
@@ -27715,7 +28416,7 @@ function ModalHost(props) {
|
|
|
27715
28416
|
) }) });
|
|
27716
28417
|
}
|
|
27717
28418
|
if (modals.showInboxModal) {
|
|
27718
|
-
return /* @__PURE__ */
|
|
28419
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27719
28420
|
InboxModal,
|
|
27720
28421
|
{
|
|
27721
28422
|
onDone: () => modals.setShowInboxModal(false),
|
|
@@ -27724,7 +28425,7 @@ function ModalHost(props) {
|
|
|
27724
28425
|
) }) });
|
|
27725
28426
|
}
|
|
27726
28427
|
if (modals.showMultiAgentModal) {
|
|
27727
|
-
return /* @__PURE__ */
|
|
28428
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27728
28429
|
MultiAgentModal,
|
|
27729
28430
|
{
|
|
27730
28431
|
initial: props.multiAgentSettings ?? {},
|
|
@@ -27737,7 +28438,7 @@ function ModalHost(props) {
|
|
|
27737
28438
|
) }) });
|
|
27738
28439
|
}
|
|
27739
28440
|
if (modals.showHooksDashboard) {
|
|
27740
|
-
return /* @__PURE__ */
|
|
28441
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27741
28442
|
HooksDashboard,
|
|
27742
28443
|
{
|
|
27743
28444
|
getConfigured: props.getConfiguredHooks,
|
|
@@ -27748,7 +28449,7 @@ function ModalHost(props) {
|
|
|
27748
28449
|
) }) });
|
|
27749
28450
|
}
|
|
27750
28451
|
if (modals.showHelpMenu) {
|
|
27751
|
-
return /* @__PURE__ */
|
|
28452
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27752
28453
|
HelpMenu,
|
|
27753
28454
|
{
|
|
27754
28455
|
customCommands: customCommands.map((c) => ({ name: c.name, description: c.description })),
|
|
@@ -27762,10 +28463,10 @@ function ModalHost(props) {
|
|
|
27762
28463
|
) }) });
|
|
27763
28464
|
}
|
|
27764
28465
|
if (modals.showShellPicker) {
|
|
27765
|
-
return /* @__PURE__ */
|
|
28466
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(ShellPicker, { current: props.currentShell, onPick: props.onPickShell }) }) });
|
|
27766
28467
|
}
|
|
27767
28468
|
if (modals.showMemoryPicker) {
|
|
27768
|
-
return /* @__PURE__ */
|
|
28469
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27769
28470
|
MemoryPicker,
|
|
27770
28471
|
{
|
|
27771
28472
|
enabled: props.memoryEnabled,
|
|
@@ -27776,7 +28477,7 @@ function ModalHost(props) {
|
|
|
27776
28477
|
) }) });
|
|
27777
28478
|
}
|
|
27778
28479
|
if (modals.showGatewayPicker) {
|
|
27779
|
-
return /* @__PURE__ */
|
|
28480
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27780
28481
|
GatewayPicker,
|
|
27781
28482
|
{
|
|
27782
28483
|
gatewayId: props.gatewayId,
|
|
@@ -27789,10 +28490,10 @@ function ModalHost(props) {
|
|
|
27789
28490
|
) }) });
|
|
27790
28491
|
}
|
|
27791
28492
|
if (modals.showSkillsPicker) {
|
|
27792
|
-
return /* @__PURE__ */
|
|
28493
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(SkillsPicker, { onAction: props.onSkillsAction, onDone: props.onSkillsDone }) }) });
|
|
27793
28494
|
}
|
|
27794
28495
|
if (modals.showLspWizard) {
|
|
27795
|
-
return /* @__PURE__ */
|
|
28496
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27796
28497
|
LspWizard,
|
|
27797
28498
|
{
|
|
27798
28499
|
servers: lspServers,
|
|
@@ -27804,7 +28505,7 @@ function ModalHost(props) {
|
|
|
27804
28505
|
) }) });
|
|
27805
28506
|
}
|
|
27806
28507
|
if (modals.commandWizard) {
|
|
27807
|
-
return /* @__PURE__ */
|
|
28508
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27808
28509
|
CommandWizard,
|
|
27809
28510
|
{
|
|
27810
28511
|
mode: modals.commandWizard.mode,
|
|
@@ -27818,7 +28519,7 @@ function ModalHost(props) {
|
|
|
27818
28519
|
}
|
|
27819
28520
|
if (modals.commandPicker) {
|
|
27820
28521
|
const pickerMode = modals.commandPicker.mode;
|
|
27821
|
-
return /* @__PURE__ */
|
|
28522
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27822
28523
|
CommandPicker,
|
|
27823
28524
|
{
|
|
27824
28525
|
commands: customCommands,
|
|
@@ -27837,14 +28538,14 @@ function ModalHost(props) {
|
|
|
27837
28538
|
}
|
|
27838
28539
|
if (modals.commandToDelete) {
|
|
27839
28540
|
const cmd = modals.commandToDelete;
|
|
27840
|
-
return /* @__PURE__ */
|
|
27841
|
-
/* @__PURE__ */
|
|
28541
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs40(Box40, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
28542
|
+
/* @__PURE__ */ jsxs40(Text41, { color: theme.accent, bold: true, children: [
|
|
27842
28543
|
"Delete /",
|
|
27843
28544
|
cmd.name,
|
|
27844
28545
|
"?"
|
|
27845
28546
|
] }),
|
|
27846
|
-
/* @__PURE__ */
|
|
27847
|
-
/* @__PURE__ */
|
|
28547
|
+
/* @__PURE__ */ jsx42(Text41, { color: theme.info.color, children: cmd.filepath }),
|
|
28548
|
+
/* @__PURE__ */ jsx42(Box40, { marginTop: 1, children: /* @__PURE__ */ jsx42(
|
|
27848
28549
|
SelectInput22,
|
|
27849
28550
|
{
|
|
27850
28551
|
items: [
|
|
@@ -27863,7 +28564,7 @@ function ModalHost(props) {
|
|
|
27863
28564
|
] }) });
|
|
27864
28565
|
}
|
|
27865
28566
|
if (modals.showCommandList) {
|
|
27866
|
-
return /* @__PURE__ */
|
|
28567
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27867
28568
|
CommandList,
|
|
27868
28569
|
{
|
|
27869
28570
|
commands: customCommands,
|
|
@@ -27872,24 +28573,24 @@ function ModalHost(props) {
|
|
|
27872
28573
|
) }) });
|
|
27873
28574
|
}
|
|
27874
28575
|
if (modals.showThemePicker) {
|
|
27875
|
-
return /* @__PURE__ */
|
|
28576
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(ThemePicker, { themes, onPick: onPickTheme }) }) });
|
|
27876
28577
|
}
|
|
27877
28578
|
if (modals.showUiPicker) {
|
|
27878
|
-
return /* @__PURE__ */
|
|
28579
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(UiPicker, { current: currentUiEngine, onPick: onPickUi }) }) });
|
|
27879
28580
|
}
|
|
27880
28581
|
if (modals.showModelPicker) {
|
|
27881
|
-
return /* @__PURE__ */
|
|
28582
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(ModelPicker, { current: currentModel, onPick: onPickModel }) }) });
|
|
27882
28583
|
}
|
|
27883
28584
|
if (modals.showModePicker) {
|
|
27884
|
-
return /* @__PURE__ */
|
|
28585
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(ModePicker, { current: props.currentMode, onPick: props.onPickMode, multiAgentEnabled: props.multiAgentEnabled }) }) });
|
|
27885
28586
|
}
|
|
27886
28587
|
if (modals.billingChooserFor) {
|
|
27887
28588
|
const model = modals.billingChooserFor;
|
|
27888
|
-
return /* @__PURE__ */
|
|
28589
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(BillingChooser, { model, onPick: (choice) => onPickBilling(model, choice) }) }) });
|
|
27889
28590
|
}
|
|
27890
28591
|
if (modals.unifiedProbeFor) {
|
|
27891
28592
|
const model = modals.unifiedProbeFor;
|
|
27892
|
-
return /* @__PURE__ */
|
|
28593
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27893
28594
|
UnifiedBillingStatus,
|
|
27894
28595
|
{
|
|
27895
28596
|
model,
|
|
@@ -27902,7 +28603,7 @@ function ModalHost(props) {
|
|
|
27902
28603
|
}
|
|
27903
28604
|
if (modals.keyEntryFor) {
|
|
27904
28605
|
const model = modals.keyEntryFor;
|
|
27905
|
-
return /* @__PURE__ */
|
|
28606
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
27906
28607
|
KeyEntryModal,
|
|
27907
28608
|
{
|
|
27908
28609
|
model,
|
|
@@ -27914,6 +28615,17 @@ function ModalHost(props) {
|
|
|
27914
28615
|
}
|
|
27915
28616
|
) }) });
|
|
27916
28617
|
}
|
|
28618
|
+
if (modals.showChangelogImagePicker && props.changelogImageRepo) {
|
|
28619
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
28620
|
+
ChangelogImagePicker,
|
|
28621
|
+
{
|
|
28622
|
+
owner: props.changelogImageRepo.owner,
|
|
28623
|
+
repo: props.changelogImageRepo.name,
|
|
28624
|
+
onGenerate: props.onChangelogImageGenerate,
|
|
28625
|
+
onCancel: props.onChangelogImageCancel
|
|
28626
|
+
}
|
|
28627
|
+
) }) });
|
|
28628
|
+
}
|
|
27917
28629
|
return null;
|
|
27918
28630
|
}
|
|
27919
28631
|
function ModalOverlay({
|
|
@@ -27923,7 +28635,7 @@ function ModalOverlay({
|
|
|
27923
28635
|
}) {
|
|
27924
28636
|
if (modals.limitModal) {
|
|
27925
28637
|
const m = modals.limitModal;
|
|
27926
|
-
return /* @__PURE__ */
|
|
28638
|
+
return /* @__PURE__ */ jsx42(
|
|
27927
28639
|
LimitModal,
|
|
27928
28640
|
{
|
|
27929
28641
|
limit: m.limit,
|
|
@@ -27937,7 +28649,7 @@ function ModalOverlay({
|
|
|
27937
28649
|
}
|
|
27938
28650
|
if (modals.loopModal) {
|
|
27939
28651
|
const m = modals.loopModal;
|
|
27940
|
-
return /* @__PURE__ */
|
|
28652
|
+
return /* @__PURE__ */ jsx42(
|
|
27941
28653
|
LimitModal,
|
|
27942
28654
|
{
|
|
27943
28655
|
limit: 50,
|
|
@@ -27982,13 +28694,14 @@ var init_modal_host = __esm({
|
|
|
27982
28694
|
init_multi_agent_modal();
|
|
27983
28695
|
init_hooks_dashboard();
|
|
27984
28696
|
init_help_menu();
|
|
28697
|
+
init_changelog_image_picker();
|
|
27985
28698
|
}
|
|
27986
28699
|
});
|
|
27987
28700
|
|
|
27988
28701
|
// src/ui/plan-complete-picker.tsx
|
|
27989
|
-
import { Box as
|
|
28702
|
+
import { Box as Box41, Text as Text42 } from "ink";
|
|
27990
28703
|
import SelectInput23 from "ink-select-input";
|
|
27991
|
-
import { jsx as
|
|
28704
|
+
import { jsx as jsx43, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
27992
28705
|
function PlanCompletePicker({ onPick }) {
|
|
27993
28706
|
const theme = useTheme();
|
|
27994
28707
|
const items = [
|
|
@@ -27996,10 +28709,10 @@ function PlanCompletePicker({ onPick }) {
|
|
|
27996
28709
|
{ label: "\u25B8 Start building and ask for permission (edit mode)", value: "edit", key: "edit" },
|
|
27997
28710
|
{ label: "\u25B8 Continue planning / ask a question", value: "continue", key: "continue" }
|
|
27998
28711
|
];
|
|
27999
|
-
return /* @__PURE__ */
|
|
28000
|
-
/* @__PURE__ */
|
|
28001
|
-
/* @__PURE__ */
|
|
28002
|
-
/* @__PURE__ */
|
|
28712
|
+
return /* @__PURE__ */ jsxs41(Box41, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
28713
|
+
/* @__PURE__ */ jsx43(Text42, { color: theme.accent, bold: true, children: "Plan complete \u2014 what next?" }),
|
|
28714
|
+
/* @__PURE__ */ jsx43(Text42, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
|
|
28715
|
+
/* @__PURE__ */ jsx43(Box41, { marginTop: 1, children: /* @__PURE__ */ jsx43(
|
|
28003
28716
|
SelectInput23,
|
|
28004
28717
|
{
|
|
28005
28718
|
items,
|
|
@@ -28018,7 +28731,7 @@ var init_plan_complete_picker = __esm({
|
|
|
28018
28731
|
});
|
|
28019
28732
|
|
|
28020
28733
|
// src/ui/use-session-manager.ts
|
|
28021
|
-
import { useCallback as useCallback8, useRef as useRef5, useState as
|
|
28734
|
+
import { useCallback as useCallback8, useRef as useRef5, useState as useState27 } from "react";
|
|
28022
28735
|
function extractFirstUserText(messages) {
|
|
28023
28736
|
const firstUser = messages.find((m) => m.role === "user");
|
|
28024
28737
|
if (!firstUser) return "session";
|
|
@@ -28035,9 +28748,9 @@ function useSessionManager(deps) {
|
|
|
28035
28748
|
const sessionIdRef = useRef5(null);
|
|
28036
28749
|
const sessionCreatedAtRef = useRef5(null);
|
|
28037
28750
|
const sessionTitleRef = useRef5(null);
|
|
28038
|
-
const [resumeSessions, setResumeSessions] =
|
|
28039
|
-
const [checkpointSession, setCheckpointSession] =
|
|
28040
|
-
const [checkpointList, setCheckpointList] =
|
|
28751
|
+
const [resumeSessions, setResumeSessions] = useState27(null);
|
|
28752
|
+
const [checkpointSession, setCheckpointSession] = useState27(null);
|
|
28753
|
+
const [checkpointList, setCheckpointList] = useState27([]);
|
|
28041
28754
|
const depsRef = useRef5(deps);
|
|
28042
28755
|
depsRef.current = deps;
|
|
28043
28756
|
const ensureSessionId = useCallback8(() => {
|
|
@@ -28109,8 +28822,22 @@ function useSessionManager(deps) {
|
|
|
28109
28822
|
} catch {
|
|
28110
28823
|
}
|
|
28111
28824
|
}
|
|
28112
|
-
const
|
|
28825
|
+
const nonSystemCount = file.messages.filter((m) => m.role !== "system").length;
|
|
28826
|
+
const msg = checkpointId ? `resumed session ${file.id} from checkpoint` : `resumed session ${file.id} (${nonSystemCount} msgs)`;
|
|
28113
28827
|
d.setEvents([{ kind: "info", key: d.mkKey(), text: msg }]);
|
|
28828
|
+
if (!checkpointId) {
|
|
28829
|
+
const threshold = d.cfg?.autoFreshSuggestionTurns ?? DEFAULT_AUTO_FRESH_SUGGESTION_TURNS;
|
|
28830
|
+
if (threshold > 0 && nonSystemCount >= threshold && (d.mode === "auto" || d.mode === "edit" || d.mode === "multi-agent-experimental")) {
|
|
28831
|
+
d.setEvents((es) => [
|
|
28832
|
+
...es,
|
|
28833
|
+
{
|
|
28834
|
+
kind: "info",
|
|
28835
|
+
key: d.mkKey(),
|
|
28836
|
+
text: `This session has ${nonSystemCount} turns. The model may slow down with accumulated context. Run /fresh to continue with a summarized state, or /compact to compress history.`
|
|
28837
|
+
}
|
|
28838
|
+
]);
|
|
28839
|
+
}
|
|
28840
|
+
}
|
|
28114
28841
|
const userMsgs = file.messages.filter((m) => m.role === "user" && m.content).map((m) => {
|
|
28115
28842
|
if (!m.content) return "";
|
|
28116
28843
|
if (typeof m.content === "string") return m.content;
|
|
@@ -28209,30 +28936,31 @@ var init_use_session_manager = __esm({
|
|
|
28209
28936
|
init_session_state();
|
|
28210
28937
|
init_usage_tracker();
|
|
28211
28938
|
init_log_sink();
|
|
28939
|
+
init_app_helpers();
|
|
28212
28940
|
}
|
|
28213
28941
|
});
|
|
28214
28942
|
|
|
28215
28943
|
// src/ui/use-turn-controller.ts
|
|
28216
|
-
import { useCallback as useCallback9, useRef as useRef6, useState as
|
|
28944
|
+
import { useCallback as useCallback9, useRef as useRef6, useState as useState28 } from "react";
|
|
28217
28945
|
function useTurnController() {
|
|
28218
|
-
const [busy, setBusy] =
|
|
28946
|
+
const [busy, setBusy] = useState28(false);
|
|
28219
28947
|
const busyRef = useRef6(false);
|
|
28220
28948
|
const isAbortingRef = useRef6(false);
|
|
28221
28949
|
const lastEscapeAtRef = useRef6(0);
|
|
28222
28950
|
const supervisorRef = useRef6(new TurnSupervisor());
|
|
28223
|
-
const [turnPhase, setTurnPhase] =
|
|
28224
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
28225
|
-
const [currentToolName, setCurrentToolName] =
|
|
28226
|
-
const [lastActivityAt, setLastActivityAt] =
|
|
28951
|
+
const [turnPhase, setTurnPhase] = useState28("waiting");
|
|
28952
|
+
const [turnStartedAt, setTurnStartedAt] = useState28(null);
|
|
28953
|
+
const [currentToolName, setCurrentToolName] = useState28(null);
|
|
28954
|
+
const [lastActivityAt, setLastActivityAt] = useState28(null);
|
|
28227
28955
|
const turnCounterRef = useRef6(0);
|
|
28228
|
-
const [showReasoning, setShowReasoning] =
|
|
28956
|
+
const [showReasoning, setShowReasoning] = useState28(false);
|
|
28229
28957
|
const toggleReasoning = useCallback9(() => {
|
|
28230
28958
|
setShowReasoning((s) => !s);
|
|
28231
28959
|
}, []);
|
|
28232
|
-
const [tasks, setTasks] =
|
|
28960
|
+
const [tasks, setTasks] = useState28([]);
|
|
28233
28961
|
const tasksRef = useRef6([]);
|
|
28234
|
-
const [tasksStartedAt, setTasksStartedAt] =
|
|
28235
|
-
const [tasksStartTokens, setTasksStartTokens] =
|
|
28962
|
+
const [tasksStartedAt, setTasksStartedAt] = useState28(null);
|
|
28963
|
+
const [tasksStartTokens, setTasksStartTokens] = useState28(0);
|
|
28236
28964
|
const beginTurn = useCallback9(() => {
|
|
28237
28965
|
setBusy(true);
|
|
28238
28966
|
busyRef.current = true;
|
|
@@ -28358,15 +29086,15 @@ var tui_report_exports = {};
|
|
|
28358
29086
|
__export(tui_report_exports, {
|
|
28359
29087
|
getCategoryReportText: () => getCategoryReportText
|
|
28360
29088
|
});
|
|
28361
|
-
import { readFile as
|
|
28362
|
-
import { join as
|
|
29089
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
29090
|
+
import { join as join32 } from "path";
|
|
28363
29091
|
import { homedir as homedir16 } from "os";
|
|
28364
29092
|
function usageDir3() {
|
|
28365
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
28366
|
-
return
|
|
29093
|
+
const xdg = process.env.XDG_DATA_HOME || join32(homedir16(), ".local", "share");
|
|
29094
|
+
return join32(xdg, "kimiflare");
|
|
28367
29095
|
}
|
|
28368
29096
|
function usagePath3() {
|
|
28369
|
-
return
|
|
29097
|
+
return join32(usageDir3(), "usage.json");
|
|
28370
29098
|
}
|
|
28371
29099
|
function today3() {
|
|
28372
29100
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -28378,7 +29106,7 @@ function daysAgo2(n) {
|
|
|
28378
29106
|
}
|
|
28379
29107
|
async function loadLog3() {
|
|
28380
29108
|
try {
|
|
28381
|
-
const raw = await
|
|
29109
|
+
const raw = await readFile20(usagePath3(), "utf8");
|
|
28382
29110
|
return JSON.parse(raw);
|
|
28383
29111
|
} catch {
|
|
28384
29112
|
return { version: 1, days: [], sessions: [] };
|
|
@@ -28435,10 +29163,10 @@ var init_tui_report = __esm({
|
|
|
28435
29163
|
});
|
|
28436
29164
|
|
|
28437
29165
|
// src/ui/slash-commands.ts
|
|
28438
|
-
import { join as
|
|
29166
|
+
import { join as join33 } from "path";
|
|
28439
29167
|
import { unlink as unlink5 } from "fs/promises";
|
|
28440
29168
|
import QRCode from "qrcode";
|
|
28441
|
-
function executeFreshStart(ctx, planText) {
|
|
29169
|
+
function executeFreshStart(ctx, planText, overrideMode) {
|
|
28442
29170
|
const oldSessionId = ctx.sessionIdRef.current;
|
|
28443
29171
|
if (ctx.cacheStableRef.current && ctx.messagesRef.current.length >= 2) {
|
|
28444
29172
|
ctx.messagesRef.current = [ctx.messagesRef.current[0], ctx.messagesRef.current[1]];
|
|
@@ -28464,7 +29192,15 @@ function executeFreshStart(ctx, planText) {
|
|
|
28464
29192
|
ctx.clearTaskTracking();
|
|
28465
29193
|
ctx.compactSuggestedRef.current = false;
|
|
28466
29194
|
ctx.updateNudgedRef.current = false;
|
|
29195
|
+
ctx.freshSuggestedRef.current = false;
|
|
28467
29196
|
ctx.sessionPlanRef.current = null;
|
|
29197
|
+
rebuildSystemPromptForMode(
|
|
29198
|
+
ctx.messagesRef.current,
|
|
29199
|
+
ctx.cacheStableRef.current,
|
|
29200
|
+
ctx.cfg?.model ?? "@cf/moonshotai/kimi-k2.6",
|
|
29201
|
+
overrideMode ?? ctx.mode,
|
|
29202
|
+
[...ALL_TOOLS, ...ctx.mcpToolsRef.current, ...ctx.lspToolsRef.current]
|
|
29203
|
+
);
|
|
28468
29204
|
ctx.messagesRef.current.push({ role: "user", content: planText });
|
|
28469
29205
|
const newSessionId = ctx.ensureSessionId();
|
|
28470
29206
|
if (oldSessionId) {
|
|
@@ -28483,7 +29219,7 @@ function dispatchSlashCommand(ctx, cmd) {
|
|
|
28483
29219
|
if (!handler) return false;
|
|
28484
29220
|
return handler(ctx, rest, arg);
|
|
28485
29221
|
}
|
|
28486
|
-
var handleExit, handleClear, handleFresh, handleReasoning, handleCost, handleShell, handleModel, handleGateway, handleMode, handleMultiAgent, handleTheme, handleUi, handlePlan, handleAuto, handleEdit, handleSkills, handleMemory, handleResume, handleCheckpoint, handleCompact, handleInit, handleUpdate, handleMcp, handleLsp, handleHooks, handleHello, handleInbox, handleLogout, handleCommand, handleRemote, handleHelp, handlers;
|
|
29222
|
+
var handleExit, handleClear, handleFresh, handleReasoning, handleCost, handleShell, handleModel, handleGateway, handleMode, handleMultiAgent, handleTheme, handleUi, handlePlan, handleAuto, handleEdit, handleSkills, handleMemory, handleResume, handleCheckpoint, handleCompact, handleInit, handleUpdate, handleMcp, handleLsp, handleHooks, handleHello, handleInbox, handleLogout, handleCommand, handleRemote, handleHelp, handleChangelogImage, handlers;
|
|
28487
29223
|
var init_slash_commands = __esm({
|
|
28488
29224
|
"src/ui/slash-commands.ts"() {
|
|
28489
29225
|
"use strict";
|
|
@@ -28497,6 +29233,7 @@ var init_slash_commands = __esm({
|
|
|
28497
29233
|
init_manager4();
|
|
28498
29234
|
init_sessions();
|
|
28499
29235
|
init_session_state();
|
|
29236
|
+
init_executor();
|
|
28500
29237
|
init_recommended();
|
|
28501
29238
|
init_settings();
|
|
28502
29239
|
init_types2();
|
|
@@ -28507,7 +29244,7 @@ var init_slash_commands = __esm({
|
|
|
28507
29244
|
init_session_store();
|
|
28508
29245
|
init_deploy();
|
|
28509
29246
|
init_tui_auth();
|
|
28510
|
-
|
|
29247
|
+
init_continuation_summary();
|
|
28511
29248
|
init_clipboard();
|
|
28512
29249
|
handleExit = (ctx) => {
|
|
28513
29250
|
void ctx.lspManagerRef.current.stopAll().finally(() => ctx.exit());
|
|
@@ -28546,11 +29283,12 @@ var init_slash_commands = __esm({
|
|
|
28546
29283
|
ctx.clearTaskTracking();
|
|
28547
29284
|
ctx.compactSuggestedRef.current = false;
|
|
28548
29285
|
ctx.updateNudgedRef.current = false;
|
|
29286
|
+
ctx.freshSuggestedRef.current = false;
|
|
28549
29287
|
ctx.sessionPlanRef.current = null;
|
|
28550
29288
|
return true;
|
|
28551
29289
|
};
|
|
28552
|
-
handleFresh = (ctx) => {
|
|
28553
|
-
const { busy, mkKey: mkKey2, setEvents } = ctx;
|
|
29290
|
+
handleFresh = async (ctx) => {
|
|
29291
|
+
const { busy, mkKey: mkKey2, setEvents, cfg } = ctx;
|
|
28554
29292
|
if (busy) {
|
|
28555
29293
|
setEvents((e) => [
|
|
28556
29294
|
...e,
|
|
@@ -28558,27 +29296,42 @@ var init_slash_commands = __esm({
|
|
|
28558
29296
|
]);
|
|
28559
29297
|
return true;
|
|
28560
29298
|
}
|
|
28561
|
-
const
|
|
28562
|
-
|
|
29299
|
+
const summary = await generateContinuationSummary({
|
|
29300
|
+
messages: ctx.messagesRef.current,
|
|
29301
|
+
mode: ctx.mode,
|
|
29302
|
+
accountId: cfg?.accountId ?? "",
|
|
29303
|
+
apiToken: cfg?.apiToken ?? "",
|
|
29304
|
+
model: cfg?.plumbingModel ?? "@cf/moonshotai/kimi-k2.5",
|
|
29305
|
+
gateway: cfg?.aiGatewayId ? {
|
|
29306
|
+
id: cfg.aiGatewayId,
|
|
29307
|
+
cacheTtl: cfg.aiGatewayCacheTtl,
|
|
29308
|
+
skipCache: cfg.aiGatewaySkipCache,
|
|
29309
|
+
collectLogPayload: cfg.aiGatewayCollectLogPayload,
|
|
29310
|
+
metadata: cfg.aiGatewayMetadata
|
|
29311
|
+
} : void 0,
|
|
29312
|
+
memoryManager: ctx.memoryManagerRef.current,
|
|
29313
|
+
memoryEnabled: cfg?.memoryEnabled
|
|
29314
|
+
});
|
|
29315
|
+
if (!summary) {
|
|
28563
29316
|
setEvents((e) => [
|
|
28564
29317
|
...e,
|
|
28565
|
-
{ kind: "error", key: mkKey2(), text: "No plan found to start fresh with." }
|
|
29318
|
+
{ kind: "error", key: mkKey2(), text: "No plan or summary found to start fresh with." }
|
|
28566
29319
|
]);
|
|
28567
29320
|
return true;
|
|
28568
29321
|
}
|
|
28569
|
-
const clipResult = executeFreshStart(ctx,
|
|
29322
|
+
const clipResult = executeFreshStart(ctx, summary);
|
|
28570
29323
|
setEvents((e) => [
|
|
28571
29324
|
...e,
|
|
28572
29325
|
{
|
|
28573
29326
|
kind: "info",
|
|
28574
29327
|
key: mkKey2(),
|
|
28575
|
-
text: clipResult.success ? "
|
|
29328
|
+
text: clipResult.success ? "Summary copied to clipboard. Starting fresh session with continuation context\u2026" : "Clipboard unavailable. Starting fresh session with continuation context\u2026"
|
|
28576
29329
|
}
|
|
28577
29330
|
]);
|
|
28578
29331
|
if (!clipResult.success) {
|
|
28579
29332
|
setEvents((e) => [
|
|
28580
29333
|
...e,
|
|
28581
|
-
{ kind: "info", key: mkKey2(), text: "---
|
|
29334
|
+
{ kind: "info", key: mkKey2(), text: "--- Continuation Context ---\n" + summary }
|
|
28582
29335
|
]);
|
|
28583
29336
|
}
|
|
28584
29337
|
return true;
|
|
@@ -29249,7 +30002,7 @@ ${lines.join("\n")}` }]);
|
|
|
29249
30002
|
void (async () => {
|
|
29250
30003
|
try {
|
|
29251
30004
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
29252
|
-
const file = await loadSession(
|
|
30005
|
+
const file = await loadSession(join33(sessionsDir3(), `${currentId}.json`));
|
|
29253
30006
|
const cps = file.checkpoints ?? [];
|
|
29254
30007
|
if (cps.length === 0) {
|
|
29255
30008
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "no checkpoints in this session" }]);
|
|
@@ -29294,7 +30047,7 @@ ${lines.join("\n")}` }]);
|
|
|
29294
30047
|
try {
|
|
29295
30048
|
ctx.ensureSessionId();
|
|
29296
30049
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
29297
|
-
const filePath =
|
|
30050
|
+
const filePath = join33(sessionsDir3(), `${ctx.sessionIdRef.current}.json`);
|
|
29298
30051
|
await addCheckpoint(filePath, cp);
|
|
29299
30052
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: `checkpoint saved: "${label}"` }]);
|
|
29300
30053
|
} catch (e) {
|
|
@@ -29555,8 +30308,8 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
29555
30308
|
handleHello = (ctx) => {
|
|
29556
30309
|
const { setEvents, mkKey: mkKey2 } = ctx;
|
|
29557
30310
|
const session = crypto.randomUUID();
|
|
29558
|
-
const url = `${
|
|
29559
|
-
|
|
30311
|
+
const url = `${FEEDBACK_WORKER_URL}/?s=${session}&v=${getAppVersion()}`;
|
|
30312
|
+
openBrowser(url);
|
|
29560
30313
|
void (async () => {
|
|
29561
30314
|
try {
|
|
29562
30315
|
const qr = await QRCode.toString(url, { type: "terminal", small: true });
|
|
@@ -29709,7 +30462,7 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
29709
30462
|
setEvents((e) => [
|
|
29710
30463
|
...e,
|
|
29711
30464
|
{ kind: "info", key: mkKey2(), text: `Starting remote session for ${repo.owner}/${repo.name}...` },
|
|
29712
|
-
{ kind: "info", key: mkKey2(), text: `Budget: ${
|
|
30465
|
+
{ kind: "info", key: mkKey2(), text: `Budget: ${formatTokens(budget)} tokens. TTL: ${ttl} min.` }
|
|
29713
30466
|
]);
|
|
29714
30467
|
try {
|
|
29715
30468
|
const data = await startRemoteSession({
|
|
@@ -29781,6 +30534,115 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
29781
30534
|
ctx.setShowHelpMenu(true);
|
|
29782
30535
|
return true;
|
|
29783
30536
|
};
|
|
30537
|
+
handleChangelogImage = (ctx, rest) => {
|
|
30538
|
+
const { cfg, setEvents, mkKey: mkKey2, setShowChangelogImagePicker, setChangelogImageRepo, setTasks, setTasksStartedAt } = ctx;
|
|
30539
|
+
if (!cfg) {
|
|
30540
|
+
setEvents((e) => [...e, { kind: "error", key: mkKey2(), text: "Not configured yet." }]);
|
|
30541
|
+
return true;
|
|
30542
|
+
}
|
|
30543
|
+
let owner = cfg.githubRepo?.split("/")[0];
|
|
30544
|
+
let repo = cfg.githubRepo?.split("/")[1];
|
|
30545
|
+
let days = 7;
|
|
30546
|
+
if (rest.length > 0 && rest[0].includes("/")) {
|
|
30547
|
+
const parts = rest[0].split("/");
|
|
30548
|
+
owner = parts[0];
|
|
30549
|
+
repo = parts[1];
|
|
30550
|
+
}
|
|
30551
|
+
if (rest.length > 1) {
|
|
30552
|
+
const d = parseInt(rest[1], 10);
|
|
30553
|
+
if (!Number.isNaN(d)) days = d;
|
|
30554
|
+
}
|
|
30555
|
+
const runGeneration = (o, r, d) => {
|
|
30556
|
+
const asstId = mkAssistantId();
|
|
30557
|
+
setEvents((e) => [
|
|
30558
|
+
...e,
|
|
30559
|
+
{
|
|
30560
|
+
kind: "assistant",
|
|
30561
|
+
key: `asst_${asstId}`,
|
|
30562
|
+
id: asstId,
|
|
30563
|
+
text: `Generating changelog image for ${o}/${r} (last ${d} day${d === 1 ? "" : "s"})\u2026`,
|
|
30564
|
+
reasoning: "",
|
|
30565
|
+
streaming: true
|
|
30566
|
+
}
|
|
30567
|
+
]);
|
|
30568
|
+
const taskList = [
|
|
30569
|
+
{ id: "fetch-prs", title: "Fetch merged PRs", status: "pending" },
|
|
30570
|
+
{ id: "fetch-release", title: "Fetch latest release", status: "pending" },
|
|
30571
|
+
{ id: "summarize", title: "Summarize with LLM", status: "pending" },
|
|
30572
|
+
{ id: "render", title: "Render changelog image", status: "pending" },
|
|
30573
|
+
{ id: "save", title: "Save PNG file", status: "pending" }
|
|
30574
|
+
];
|
|
30575
|
+
setTasks(taskList);
|
|
30576
|
+
setTasksStartedAt(Date.now());
|
|
30577
|
+
const updateTask = (id, status) => {
|
|
30578
|
+
setTasks((prev) => prev.map((t) => t.id === id ? { ...t, status } : t));
|
|
30579
|
+
};
|
|
30580
|
+
void (async () => {
|
|
30581
|
+
try {
|
|
30582
|
+
const { changelogImageTool: changelogImageTool2 } = await Promise.resolve().then(() => (init_changelog_image(), changelog_image_exports));
|
|
30583
|
+
const { gatewayFromConfig: gatewayFromConfig2 } = await Promise.resolve().then(() => (init_app_helpers(), app_helpers_exports));
|
|
30584
|
+
updateTask("fetch-prs", "in_progress");
|
|
30585
|
+
updateTask("fetch-release", "in_progress");
|
|
30586
|
+
const result = await changelogImageTool2.run({ owner: o, repo: r, days: d }, {
|
|
30587
|
+
cwd: process.cwd(),
|
|
30588
|
+
githubToken: cfg.githubOAuthToken,
|
|
30589
|
+
accountId: cfg.accountId,
|
|
30590
|
+
apiToken: cfg.apiToken,
|
|
30591
|
+
model: cfg.model,
|
|
30592
|
+
gateway: gatewayFromConfig2(cfg)
|
|
30593
|
+
});
|
|
30594
|
+
updateTask("fetch-prs", "completed");
|
|
30595
|
+
updateTask("fetch-release", "completed");
|
|
30596
|
+
updateTask("summarize", "completed");
|
|
30597
|
+
updateTask("render", "completed");
|
|
30598
|
+
updateTask("save", "completed");
|
|
30599
|
+
const text = typeof result === "string" ? result : result.content;
|
|
30600
|
+
setEvents(
|
|
30601
|
+
(e) => e.map(
|
|
30602
|
+
(ev) => ev.kind === "assistant" && ev.id === asstId ? { ...ev, text, streaming: false } : ev
|
|
30603
|
+
)
|
|
30604
|
+
);
|
|
30605
|
+
} catch (err) {
|
|
30606
|
+
const msg = `changelog-image failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
30607
|
+
setEvents(
|
|
30608
|
+
(e) => e.map(
|
|
30609
|
+
(ev) => ev.kind === "assistant" && ev.id === asstId ? { ...ev, text: msg, streaming: false } : ev
|
|
30610
|
+
)
|
|
30611
|
+
);
|
|
30612
|
+
} finally {
|
|
30613
|
+
setTasksStartedAt(null);
|
|
30614
|
+
}
|
|
30615
|
+
})();
|
|
30616
|
+
};
|
|
30617
|
+
const tryOpenPicker = (o, r) => {
|
|
30618
|
+
if (o && r) {
|
|
30619
|
+
if (rest.length === 0) {
|
|
30620
|
+
setChangelogImageRepo({ owner: o, name: r });
|
|
30621
|
+
setShowChangelogImagePicker(true);
|
|
30622
|
+
return;
|
|
30623
|
+
}
|
|
30624
|
+
runGeneration(o, r, days);
|
|
30625
|
+
return;
|
|
30626
|
+
}
|
|
30627
|
+
setEvents((e) => [
|
|
30628
|
+
...e,
|
|
30629
|
+
{
|
|
30630
|
+
kind: "error",
|
|
30631
|
+
key: mkKey2(),
|
|
30632
|
+
text: "Usage: /changelog-image [owner/repo] [days]\nSet githubRepo in config or pass owner/repo explicitly."
|
|
30633
|
+
}
|
|
30634
|
+
]);
|
|
30635
|
+
};
|
|
30636
|
+
if (owner && repo) {
|
|
30637
|
+
tryOpenPicker(owner, repo);
|
|
30638
|
+
return true;
|
|
30639
|
+
}
|
|
30640
|
+
void Promise.resolve().then(() => (init_app_helpers(), app_helpers_exports)).then(({ detectGitHubRepo: detectGitHubRepo3 }) => {
|
|
30641
|
+
const detected = detectGitHubRepo3();
|
|
30642
|
+
tryOpenPicker(detected?.owner, detected?.name);
|
|
30643
|
+
});
|
|
30644
|
+
return true;
|
|
30645
|
+
};
|
|
29784
30646
|
handlers = {
|
|
29785
30647
|
"/exit": handleExit,
|
|
29786
30648
|
"/clear": handleClear,
|
|
@@ -29812,6 +30674,7 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
29812
30674
|
"/logout": handleLogout,
|
|
29813
30675
|
"/command": handleCommand,
|
|
29814
30676
|
"/remote": handleRemote,
|
|
30677
|
+
"/changelog-image": handleChangelogImage,
|
|
29815
30678
|
"/help": handleHelp
|
|
29816
30679
|
};
|
|
29817
30680
|
}
|
|
@@ -29819,7 +30682,7 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
29819
30682
|
|
|
29820
30683
|
// src/init/run-init.ts
|
|
29821
30684
|
import { existsSync as existsSync6 } from "fs";
|
|
29822
|
-
import { join as
|
|
30685
|
+
import { join as join34 } from "path";
|
|
29823
30686
|
async function runInit(deps) {
|
|
29824
30687
|
const {
|
|
29825
30688
|
cfg,
|
|
@@ -29916,7 +30779,7 @@ async function runInit(deps) {
|
|
|
29916
30779
|
lspManagerRef.current.notifyChange(path, content);
|
|
29917
30780
|
} else {
|
|
29918
30781
|
void import("fs/promises").then(
|
|
29919
|
-
({ readFile:
|
|
30782
|
+
({ readFile: readFile23 }) => readFile23(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
|
|
29920
30783
|
})
|
|
29921
30784
|
);
|
|
29922
30785
|
}
|
|
@@ -30022,7 +30885,7 @@ async function runInit(deps) {
|
|
|
30022
30885
|
}
|
|
30023
30886
|
}
|
|
30024
30887
|
});
|
|
30025
|
-
if (existsSync6(
|
|
30888
|
+
if (existsSync6(join34(cwd, "KIMI.md"))) {
|
|
30026
30889
|
if (cacheStableRef.current) {
|
|
30027
30890
|
messagesRef.current[1] = {
|
|
30028
30891
|
role: "system",
|
|
@@ -30116,8 +30979,8 @@ var init_run_init = __esm({
|
|
|
30116
30979
|
});
|
|
30117
30980
|
|
|
30118
30981
|
// src/skills/discovery.ts
|
|
30119
|
-
import { readdir as readdir9, stat as stat7, readFile as
|
|
30120
|
-
import { join as
|
|
30982
|
+
import { readdir as readdir9, stat as stat7, readFile as readFile21 } from "fs/promises";
|
|
30983
|
+
import { join as join35, extname as extname2 } from "path";
|
|
30121
30984
|
async function dirExists(path) {
|
|
30122
30985
|
try {
|
|
30123
30986
|
const s = await stat7(path);
|
|
@@ -30141,20 +31004,20 @@ async function scanSkillDir(dirPath, source) {
|
|
|
30141
31004
|
for (const entry of entries) {
|
|
30142
31005
|
if (!entry.isFile()) continue;
|
|
30143
31006
|
if (!SKILL_EXTENSIONS.has(extname2(entry.name))) continue;
|
|
30144
|
-
files.push({ filePath:
|
|
31007
|
+
files.push({ filePath: join35(dirPath, entry.name), source });
|
|
30145
31008
|
}
|
|
30146
31009
|
return files;
|
|
30147
31010
|
}
|
|
30148
31011
|
async function discoverSkills(cwd) {
|
|
30149
|
-
const agentsSkills = await scanSkillDir(
|
|
30150
|
-
const agentsMd = await fileExists(
|
|
30151
|
-
const githubSkills = await scanSkillDir(
|
|
30152
|
-
const kimiflareSkills = await scanSkillDir(
|
|
31012
|
+
const agentsSkills = await scanSkillDir(join35(cwd, ".agents", "skills"), "agents");
|
|
31013
|
+
const agentsMd = await fileExists(join35(cwd, "AGENTS.md")) ? [{ filePath: join35(cwd, "AGENTS.md"), source: "agents-md" }] : [];
|
|
31014
|
+
const githubSkills = await scanSkillDir(join35(cwd, ".github", "skills"), "github");
|
|
31015
|
+
const kimiflareSkills = await scanSkillDir(join35(cwd, ".kimiflare", "skills"), "kimiflare");
|
|
30153
31016
|
const ordered = [...agentsSkills, ...agentsMd, ...githubSkills, ...kimiflareSkills];
|
|
30154
31017
|
return ordered;
|
|
30155
31018
|
}
|
|
30156
31019
|
async function readSkillFile(filePath) {
|
|
30157
|
-
const bytes = await
|
|
31020
|
+
const bytes = await readFile21(filePath);
|
|
30158
31021
|
return { bytes, text: bytes.toString("utf-8") };
|
|
30159
31022
|
}
|
|
30160
31023
|
var SKILL_EXTENSIONS;
|
|
@@ -30359,16 +31222,16 @@ var init_skills = __esm({
|
|
|
30359
31222
|
});
|
|
30360
31223
|
|
|
30361
31224
|
// src/util/state.ts
|
|
30362
|
-
import { readFile as
|
|
31225
|
+
import { readFile as readFile22, writeFile as writeFile14, mkdir as mkdir12 } from "fs/promises";
|
|
30363
31226
|
import { homedir as homedir17 } from "os";
|
|
30364
|
-
import { join as
|
|
31227
|
+
import { join as join36 } from "path";
|
|
30365
31228
|
function statePath() {
|
|
30366
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
30367
|
-
return
|
|
31229
|
+
const xdg = process.env.XDG_CONFIG_HOME || join36(homedir17(), ".config");
|
|
31230
|
+
return join36(xdg, "kimiflare", "state.json");
|
|
30368
31231
|
}
|
|
30369
31232
|
async function readState() {
|
|
30370
31233
|
try {
|
|
30371
|
-
const raw = await
|
|
31234
|
+
const raw = await readFile22(statePath(), "utf8");
|
|
30372
31235
|
return JSON.parse(raw);
|
|
30373
31236
|
} catch {
|
|
30374
31237
|
return {};
|
|
@@ -30376,8 +31239,8 @@ async function readState() {
|
|
|
30376
31239
|
}
|
|
30377
31240
|
async function writeState(state) {
|
|
30378
31241
|
const path = statePath();
|
|
30379
|
-
await mkdir12(
|
|
30380
|
-
await
|
|
31242
|
+
await mkdir12(join36(path, ".."), { recursive: true });
|
|
31243
|
+
await writeFile14(path, JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
30381
31244
|
}
|
|
30382
31245
|
async function markCreatorMessageSeen(version) {
|
|
30383
31246
|
const state = await readState();
|
|
@@ -30396,7 +31259,7 @@ var init_state = __esm({
|
|
|
30396
31259
|
|
|
30397
31260
|
// src/ui/run-startup-tasks.ts
|
|
30398
31261
|
import { existsSync as existsSync7 } from "fs";
|
|
30399
|
-
import { join as
|
|
31262
|
+
import { join as join37 } from "path";
|
|
30400
31263
|
function runStartupTasks(deps) {
|
|
30401
31264
|
const {
|
|
30402
31265
|
cfg,
|
|
@@ -30447,7 +31310,7 @@ function runStartupTasks(deps) {
|
|
|
30447
31310
|
}
|
|
30448
31311
|
});
|
|
30449
31312
|
if (cfg.memoryEnabled) {
|
|
30450
|
-
const dbPath = cfg.memoryDbPath ??
|
|
31313
|
+
const dbPath = cfg.memoryDbPath ?? join37(process.cwd(), ".kimiflare", "memory.db");
|
|
30451
31314
|
const manager = new MemoryManager({
|
|
30452
31315
|
dbPath,
|
|
30453
31316
|
accountId: cfg.accountId,
|
|
@@ -30481,7 +31344,7 @@ function runStartupTasks(deps) {
|
|
|
30481
31344
|
});
|
|
30482
31345
|
const cwd = process.cwd();
|
|
30483
31346
|
sessionStartRecallRef.current = manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
|
|
30484
|
-
if (existsSync7(
|
|
31347
|
+
if (existsSync7(join37(cwd, "KIMI.md"))) {
|
|
30485
31348
|
const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
|
|
30486
31349
|
const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
|
|
30487
31350
|
if (driftCount >= 5) {
|
|
@@ -30492,7 +31355,7 @@ function runStartupTasks(deps) {
|
|
|
30492
31355
|
memoryManagerRef.current?.close();
|
|
30493
31356
|
memoryManagerRef.current = null;
|
|
30494
31357
|
}
|
|
30495
|
-
const skillDbPath = cfg.memoryDbPath ??
|
|
31358
|
+
const skillDbPath = cfg.memoryDbPath ?? join37(process.cwd(), ".kimiflare", "memory.db");
|
|
30496
31359
|
const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
|
|
30497
31360
|
initSkillsSchema(skillDb);
|
|
30498
31361
|
void indexSkills({
|
|
@@ -30958,11 +31821,11 @@ var app_exports = {};
|
|
|
30958
31821
|
__export(app_exports, {
|
|
30959
31822
|
renderApp: () => renderApp
|
|
30960
31823
|
});
|
|
30961
|
-
import
|
|
30962
|
-
import { Box as
|
|
31824
|
+
import React25, { useState as useState29, useRef as useRef7, useEffect as useEffect11, useCallback as useCallback10, useMemo as useMemo6 } from "react";
|
|
31825
|
+
import { Box as Box42, Text as Text43, useApp, useInput as useInput21, render } from "ink";
|
|
30963
31826
|
import { existsSync as existsSync8 } from "fs";
|
|
30964
|
-
import { join as
|
|
30965
|
-
import { jsx as
|
|
31827
|
+
import { join as join38 } from "path";
|
|
31828
|
+
import { jsx as jsx44, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
30966
31829
|
function App({
|
|
30967
31830
|
initialCfg,
|
|
30968
31831
|
initialUpdateResult,
|
|
@@ -30970,14 +31833,14 @@ function App({
|
|
|
30970
31833
|
initialLspProjectPath
|
|
30971
31834
|
}) {
|
|
30972
31835
|
const { exit } = useApp();
|
|
30973
|
-
const [cfg, setCfg] =
|
|
31836
|
+
const [cfg, setCfg] = useState29(initialCfg);
|
|
30974
31837
|
const modelContextLimit = useMemo6(
|
|
30975
31838
|
() => cfg ? getModelOrInfer(cfg.model).contextWindow : CONTEXT_LIMIT,
|
|
30976
31839
|
[cfg?.model]
|
|
30977
31840
|
);
|
|
30978
|
-
const [lspScope, setLspScope] =
|
|
30979
|
-
const [lspProjectPath, setLspProjectPath] =
|
|
30980
|
-
const [events, setRawEvents] =
|
|
31841
|
+
const [lspScope, setLspScope] = useState29(initialLspScope);
|
|
31842
|
+
const [lspProjectPath, setLspProjectPath] = useState29(initialLspProjectPath);
|
|
31843
|
+
const [events, setRawEvents] = useState29([]);
|
|
30981
31844
|
const setEvents = useCallback10(
|
|
30982
31845
|
(updater) => {
|
|
30983
31846
|
setRawEvents((prev) => {
|
|
@@ -30987,9 +31850,9 @@ function App({
|
|
|
30987
31850
|
},
|
|
30988
31851
|
[]
|
|
30989
31852
|
);
|
|
30990
|
-
const [input, setInput] =
|
|
30991
|
-
const [usage, setUsage] =
|
|
30992
|
-
const [sessionUsage, setSessionUsage] =
|
|
31853
|
+
const [input, setInput] = useState29("");
|
|
31854
|
+
const [usage, setUsage] = useState29(null);
|
|
31855
|
+
const [sessionUsage, setSessionUsage] = useState29(null);
|
|
30993
31856
|
useEffect11(() => {
|
|
30994
31857
|
const handler = (sid) => {
|
|
30995
31858
|
if (sessionIdRef.current && sid === sessionIdRef.current) {
|
|
@@ -31001,7 +31864,7 @@ function App({
|
|
|
31001
31864
|
usageEvents.off("update", handler);
|
|
31002
31865
|
};
|
|
31003
31866
|
}, []);
|
|
31004
|
-
const [gatewayMeta, setGatewayMeta] =
|
|
31867
|
+
const [gatewayMeta, setGatewayMeta] = useState29(null);
|
|
31005
31868
|
const turn = useTurnController();
|
|
31006
31869
|
const {
|
|
31007
31870
|
busy,
|
|
@@ -31029,7 +31892,7 @@ function App({
|
|
|
31029
31892
|
endTurn,
|
|
31030
31893
|
clearTaskTracking
|
|
31031
31894
|
} = turn;
|
|
31032
|
-
const [planOptions, setPlanOptions] =
|
|
31895
|
+
const [planOptions, setPlanOptions] = useState29(null);
|
|
31033
31896
|
const planOptionsRef = useRef7(null);
|
|
31034
31897
|
const {
|
|
31035
31898
|
pending: perm,
|
|
@@ -31096,39 +31959,42 @@ function App({
|
|
|
31096
31959
|
setShowShellPicker,
|
|
31097
31960
|
showPlanCompletePicker,
|
|
31098
31961
|
setShowPlanCompletePicker,
|
|
31962
|
+
showChangelogImagePicker,
|
|
31963
|
+
setShowChangelogImagePicker,
|
|
31099
31964
|
hasFullscreenModal,
|
|
31100
31965
|
hasAnyModal
|
|
31101
31966
|
} = modals;
|
|
31102
|
-
const [queue2, setQueue] =
|
|
31103
|
-
const [history, setHistory] =
|
|
31104
|
-
const [historyIndex, setHistoryIndex] =
|
|
31105
|
-
const [draftInput, setDraftInput] =
|
|
31106
|
-
const [mode, setMode] =
|
|
31967
|
+
const [queue2, setQueue] = useState29([]);
|
|
31968
|
+
const [history, setHistory] = useState29([]);
|
|
31969
|
+
const [historyIndex, setHistoryIndex] = useState29(-1);
|
|
31970
|
+
const [draftInput, setDraftInput] = useState29("");
|
|
31971
|
+
const [mode, setMode] = useState29("edit");
|
|
31107
31972
|
useEffect11(() => {
|
|
31108
31973
|
if (mode === "multi-agent-experimental" && cfg && !cfg.workerEndpoint && !cfg.remoteWorkerUrl && !showMultiAgentModal) {
|
|
31109
31974
|
setShowMultiAgentModal(true);
|
|
31110
31975
|
}
|
|
31111
31976
|
}, [mode, cfg?.workerEndpoint, cfg?.remoteWorkerUrl]);
|
|
31112
|
-
const [codeMode, setCodeMode] =
|
|
31977
|
+
const [codeMode, setCodeMode] = useState29(false);
|
|
31113
31978
|
const filePickerEnabled = initialCfg?.filePicker ?? true;
|
|
31114
|
-
const [effort, setEffort] =
|
|
31979
|
+
const [effort, setEffort] = useState29(
|
|
31115
31980
|
initialCfg?.reasoningEffort ?? DEFAULT_REASONING_EFFORT
|
|
31116
31981
|
);
|
|
31117
|
-
const [selectedRemoteSession, setSelectedRemoteSession] =
|
|
31118
|
-
const [verbose, setVerbose] =
|
|
31119
|
-
const [hasUpdate, setHasUpdate] =
|
|
31120
|
-
const [latestVersion, setLatestVersion] =
|
|
31121
|
-
const [theme, setTheme] =
|
|
31122
|
-
const [originalTheme, setOriginalTheme] =
|
|
31123
|
-
const [skillsActive, setSkillsActive] =
|
|
31124
|
-
const [memoryRecalled, setMemoryRecalled] =
|
|
31125
|
-
const [intentTier, setIntentTier] =
|
|
31126
|
-
const [kimiMdStale, setKimiMdStale] =
|
|
31127
|
-
const [gitBranch, setGitBranch] =
|
|
31128
|
-
const [lastSessionTopic, setLastSessionTopic] =
|
|
31129
|
-
const [activeWorkers, setActiveWorkers] =
|
|
31130
|
-
const [isSynthesizing, setIsSynthesizing] =
|
|
31131
|
-
const [coordinatorNarration, setCoordinatorNarration] =
|
|
31982
|
+
const [selectedRemoteSession, setSelectedRemoteSession] = useState29(null);
|
|
31983
|
+
const [verbose, setVerbose] = useState29(false);
|
|
31984
|
+
const [hasUpdate, setHasUpdate] = useState29(initialUpdateResult?.hasUpdate ?? false);
|
|
31985
|
+
const [latestVersion, setLatestVersion] = useState29(initialUpdateResult?.latestVersion ?? null);
|
|
31986
|
+
const [theme, setTheme] = useState29(resolveTheme(initialCfg?.theme));
|
|
31987
|
+
const [originalTheme, setOriginalTheme] = useState29(null);
|
|
31988
|
+
const [skillsActive, setSkillsActive] = useState29(0);
|
|
31989
|
+
const [memoryRecalled, setMemoryRecalled] = useState29(false);
|
|
31990
|
+
const [intentTier, setIntentTier] = useState29(null);
|
|
31991
|
+
const [kimiMdStale, setKimiMdStale] = useState29(false);
|
|
31992
|
+
const [gitBranch, setGitBranch] = useState29(null);
|
|
31993
|
+
const [lastSessionTopic, setLastSessionTopic] = useState29(null);
|
|
31994
|
+
const [activeWorkers, setActiveWorkers] = useState29([]);
|
|
31995
|
+
const [isSynthesizing, setIsSynthesizing] = useState29(false);
|
|
31996
|
+
const [coordinatorNarration, setCoordinatorNarration] = useState29("");
|
|
31997
|
+
const [changelogImageRepo, setChangelogImageRepo] = useState29(null);
|
|
31132
31998
|
useEffect11(() => {
|
|
31133
31999
|
setGitBranch(detectGitBranch());
|
|
31134
32000
|
}, []);
|
|
@@ -31178,8 +32044,8 @@ ${wcagWarnings.join("\n")}` }
|
|
|
31178
32044
|
cancelled = true;
|
|
31179
32045
|
};
|
|
31180
32046
|
}, []);
|
|
31181
|
-
const [cursorOffset, setCursorOffset] =
|
|
31182
|
-
const [customCommandsVersion, setCustomCommandsVersion] =
|
|
32047
|
+
const [cursorOffset, setCursorOffset] = useState29(0);
|
|
32048
|
+
const [customCommandsVersion, setCustomCommandsVersion] = useState29(0);
|
|
31183
32049
|
const cacheStableRef = useRef7(initialCfg?.cacheStablePrompts !== false);
|
|
31184
32050
|
const messagesRef = useRef7(
|
|
31185
32051
|
makePrefixMessages(cacheStableRef.current, cfg?.model ?? DEFAULT_MODEL, "edit", ALL_TOOLS)
|
|
@@ -31203,6 +32069,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
31203
32069
|
const compiledContextRef = useRef7(initialCfg?.compiledContext === true);
|
|
31204
32070
|
const updateNudgedRef = useRef7(false);
|
|
31205
32071
|
const compactSuggestedRef = useRef7(false);
|
|
32072
|
+
const freshSuggestedRef = useRef7(false);
|
|
31206
32073
|
const mcpManagerRef = useRef7(new McpManager());
|
|
31207
32074
|
const mcpToolsRef = useRef7([]);
|
|
31208
32075
|
const mcpInitRef = useRef7(false);
|
|
@@ -31223,6 +32090,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
31223
32090
|
const sessionPlanRef = useRef7(null);
|
|
31224
32091
|
const sessionMgr = useSessionManager({
|
|
31225
32092
|
cfg,
|
|
32093
|
+
mode,
|
|
31226
32094
|
messagesRef,
|
|
31227
32095
|
sessionStateRef,
|
|
31228
32096
|
artifactStoreRef,
|
|
@@ -31258,7 +32126,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
31258
32126
|
const customCommandsRef = useRef7([]);
|
|
31259
32127
|
const recentFilesRef = useRef7(/* @__PURE__ */ new Map());
|
|
31260
32128
|
const MAX_RECENT_FILES = 10;
|
|
31261
|
-
const allSlashCommands =
|
|
32129
|
+
const allSlashCommands = React25.useMemo(() => {
|
|
31262
32130
|
const customs = customCommandsRef.current.filter((c) => !BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase())).map((c) => ({
|
|
31263
32131
|
name: c.name,
|
|
31264
32132
|
description: c.description ?? "",
|
|
@@ -31624,7 +32492,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
31624
32492
|
[cfg]
|
|
31625
32493
|
);
|
|
31626
32494
|
const interruptDepsRef = useRef7(null);
|
|
31627
|
-
|
|
32495
|
+
useInput21((inputChar, key) => {
|
|
31628
32496
|
if (key.ctrl && inputChar === "c") {
|
|
31629
32497
|
logger.info("input:ctrl+c", {
|
|
31630
32498
|
busy: busyRef.current,
|
|
@@ -31894,62 +32762,6 @@ ${wcagWarnings.join("\n")}` }
|
|
|
31894
32762
|
},
|
|
31895
32763
|
[mkKey, setShowUiPicker]
|
|
31896
32764
|
);
|
|
31897
|
-
const handlePlanCompletePick = useCallback10(
|
|
31898
|
-
(picked) => {
|
|
31899
|
-
setShowPlanCompletePicker(false);
|
|
31900
|
-
if (!picked || picked === "continue") return;
|
|
31901
|
-
const plan = sessionPlanRef.current ?? distillSessionPlan(messagesRef.current);
|
|
31902
|
-
if (!plan) {
|
|
31903
|
-
setEvents((e) => [
|
|
31904
|
-
...e,
|
|
31905
|
-
{ kind: "error", key: mkKey(), text: "No plan found to start fresh with." }
|
|
31906
|
-
]);
|
|
31907
|
-
setMode(picked);
|
|
31908
|
-
return;
|
|
31909
|
-
}
|
|
31910
|
-
const clipResult = writeToClipboard(plan);
|
|
31911
|
-
if (cacheStableRef.current && messagesRef.current.length >= 2) {
|
|
31912
|
-
messagesRef.current = [messagesRef.current[0], messagesRef.current[1]];
|
|
31913
|
-
} else {
|
|
31914
|
-
messagesRef.current = [messagesRef.current[0]];
|
|
31915
|
-
}
|
|
31916
|
-
resetSession();
|
|
31917
|
-
executorRef.current.clearArtifacts();
|
|
31918
|
-
if (flushTimeoutRef.current) {
|
|
31919
|
-
clearTimeout(flushTimeoutRef.current);
|
|
31920
|
-
flushTimeoutRef.current = null;
|
|
31921
|
-
}
|
|
31922
|
-
pendingTextRef.current.clear();
|
|
31923
|
-
activeAsstIdRef.current = null;
|
|
31924
|
-
pendingToolCallsRef.current.clear();
|
|
31925
|
-
usageRef.current = null;
|
|
31926
|
-
turnCounterRef.current = 0;
|
|
31927
|
-
setEvents([]);
|
|
31928
|
-
setUsage(null);
|
|
31929
|
-
setSessionUsage(null);
|
|
31930
|
-
gatewayMetaRef.current = null;
|
|
31931
|
-
setGatewayMeta(null);
|
|
31932
|
-
clearTaskTracking();
|
|
31933
|
-
compactSuggestedRef.current = false;
|
|
31934
|
-
updateNudgedRef.current = false;
|
|
31935
|
-
sessionPlanRef.current = null;
|
|
31936
|
-
setEvents((e) => [
|
|
31937
|
-
...e,
|
|
31938
|
-
{
|
|
31939
|
-
kind: "info",
|
|
31940
|
-
key: mkKey(),
|
|
31941
|
-
text: clipResult.success ? `Plan copied to clipboard. Starting fresh session in ${picked} mode with plan only\u2026` : `Clipboard unavailable. Starting fresh session in ${picked} mode with plan only\u2026`
|
|
31942
|
-
}
|
|
31943
|
-
]);
|
|
31944
|
-
if (!clipResult.success) {
|
|
31945
|
-
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "--- Plan ---\n" + plan }]);
|
|
31946
|
-
}
|
|
31947
|
-
setMode(picked);
|
|
31948
|
-
modeRef.current = picked;
|
|
31949
|
-
submitRef.current(plan);
|
|
31950
|
-
},
|
|
31951
|
-
[mkKey, setShowPlanCompletePicker, setMode, setEvents, setUsage, setSessionUsage, setGatewayMeta, clearTaskTracking, resetSession, submitRef]
|
|
31952
|
-
);
|
|
31953
32765
|
const handleModelPick = useCallback10(
|
|
31954
32766
|
(picked) => {
|
|
31955
32767
|
setShowModelPicker(false);
|
|
@@ -32124,6 +32936,10 @@ ${wcagWarnings.join("\n")}` }
|
|
|
32124
32936
|
setShowGatewayPicker,
|
|
32125
32937
|
setShowSkillsPicker,
|
|
32126
32938
|
setShowShellPicker,
|
|
32939
|
+
setShowChangelogImagePicker,
|
|
32940
|
+
setChangelogImageRepo,
|
|
32941
|
+
setTasks: turn.setTasks,
|
|
32942
|
+
setTasksStartedAt: turn.setTasksStartedAt,
|
|
32127
32943
|
lspScope,
|
|
32128
32944
|
lspProjectPath,
|
|
32129
32945
|
resetSession,
|
|
@@ -32154,6 +32970,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
32154
32970
|
sessionIdRef,
|
|
32155
32971
|
compactSuggestedRef,
|
|
32156
32972
|
updateNudgedRef,
|
|
32973
|
+
freshSuggestedRef,
|
|
32157
32974
|
memoryManagerRef,
|
|
32158
32975
|
artifactStoreRef,
|
|
32159
32976
|
sessionStateRef,
|
|
@@ -32188,12 +33005,16 @@ ${wcagWarnings.join("\n")}` }
|
|
|
32188
33005
|
setShowGatewayPicker,
|
|
32189
33006
|
setShowSkillsPicker,
|
|
32190
33007
|
setShowShellPicker,
|
|
33008
|
+
setShowChangelogImagePicker,
|
|
33009
|
+
setChangelogImageRepo,
|
|
32191
33010
|
setShowLspWizard,
|
|
32192
33011
|
setShowRemoteDashboard,
|
|
32193
33012
|
setShowCommandList,
|
|
32194
33013
|
setCommandWizard,
|
|
32195
33014
|
setCommandPicker,
|
|
32196
33015
|
turn.setShowReasoning,
|
|
33016
|
+
turn.setTasks,
|
|
33017
|
+
turn.setTasksStartedAt,
|
|
32197
33018
|
resetSession,
|
|
32198
33019
|
clearTaskTracking,
|
|
32199
33020
|
openResumePicker,
|
|
@@ -32203,8 +33024,39 @@ ${wcagWarnings.join("\n")}` }
|
|
|
32203
33024
|
initLsp2,
|
|
32204
33025
|
ensureSessionId
|
|
32205
33026
|
]);
|
|
33027
|
+
const handlePlanCompletePick = useCallback10(
|
|
33028
|
+
(picked) => {
|
|
33029
|
+
setShowPlanCompletePicker(false);
|
|
33030
|
+
if (!picked || picked === "continue") return;
|
|
33031
|
+
const plan = sessionPlanRef.current ?? distillSessionPlan(messagesRef.current);
|
|
33032
|
+
if (!plan) {
|
|
33033
|
+
setEvents((e) => [
|
|
33034
|
+
...e,
|
|
33035
|
+
{ kind: "error", key: mkKey(), text: "No plan found to start fresh with." }
|
|
33036
|
+
]);
|
|
33037
|
+
setMode(picked);
|
|
33038
|
+
return;
|
|
33039
|
+
}
|
|
33040
|
+
const clipResult = executeFreshStart(buildSlashContext(), plan, picked);
|
|
33041
|
+
setEvents((e) => [
|
|
33042
|
+
...e,
|
|
33043
|
+
{
|
|
33044
|
+
kind: "info",
|
|
33045
|
+
key: mkKey(),
|
|
33046
|
+
text: clipResult.success ? `Plan copied to clipboard. Starting fresh session in ${picked} mode with plan only\u2026` : `Clipboard unavailable. Starting fresh session in ${picked} mode with plan only\u2026`
|
|
33047
|
+
}
|
|
33048
|
+
]);
|
|
33049
|
+
if (!clipResult.success) {
|
|
33050
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "--- Plan ---\n" + plan }]);
|
|
33051
|
+
}
|
|
33052
|
+
setMode(picked);
|
|
33053
|
+
modeRef.current = picked;
|
|
33054
|
+
submitRef.current(plan);
|
|
33055
|
+
},
|
|
33056
|
+
[mkKey, setShowPlanCompletePicker, setMode, setEvents, submitRef, buildSlashContext]
|
|
33057
|
+
);
|
|
32206
33058
|
const handleSlash = useCallback10(
|
|
32207
|
-
(cmd) => dispatchSlashCommand(buildSlashContext(), cmd),
|
|
33059
|
+
async (cmd) => dispatchSlashCommand(buildSlashContext(), cmd),
|
|
32208
33060
|
[buildSlashContext]
|
|
32209
33061
|
);
|
|
32210
33062
|
const handleCommandSave2 = useCallback10(
|
|
@@ -32257,7 +33109,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
32257
33109
|
if (trimmed.startsWith("/")) {
|
|
32258
33110
|
const head = trimmed.split(/\s+/)[0].toLowerCase();
|
|
32259
33111
|
const selfManaged = ["/compact", "/init"].includes(head);
|
|
32260
|
-
if (handleSlash(trimmed)) {
|
|
33112
|
+
if (await handleSlash(trimmed)) {
|
|
32261
33113
|
if (!selfManaged) {
|
|
32262
33114
|
endTurn();
|
|
32263
33115
|
}
|
|
@@ -32376,12 +33228,68 @@ ${wcagWarnings.join("\n")}` }
|
|
|
32376
33228
|
}
|
|
32377
33229
|
}
|
|
32378
33230
|
turnCounterRef.current += 1;
|
|
32379
|
-
if (turnCounterRef.current % 15 === 0 && existsSync8(
|
|
33231
|
+
if (turnCounterRef.current % 15 === 0 && existsSync8(join38(process.cwd(), "KIMI.md")) && !kimiMdStale) {
|
|
32380
33232
|
setEvents((e) => [
|
|
32381
33233
|
...e,
|
|
32382
33234
|
{ kind: "info", key: mkKey(), text: "Tip: Rerunning /init occasionally helps KimiFlare stay accurate as your project evolves." }
|
|
32383
33235
|
]);
|
|
32384
33236
|
}
|
|
33237
|
+
const autoFreshThreshold = cfg?.autoFreshSuggestionTurns ?? DEFAULT_AUTO_FRESH_SUGGESTION_TURNS;
|
|
33238
|
+
if (autoFreshThreshold > 0 && turnCounterRef.current >= autoFreshThreshold && (modeRef.current === "auto" || modeRef.current === "edit" || modeRef.current === "multi-agent-experimental") && !freshSuggestedRef.current) {
|
|
33239
|
+
freshSuggestedRef.current = true;
|
|
33240
|
+
if (cfg?.autoFreshEnabled) {
|
|
33241
|
+
void (async () => {
|
|
33242
|
+
try {
|
|
33243
|
+
const turnIndex = messagesRef.current.length;
|
|
33244
|
+
if (turnIndex > 0) {
|
|
33245
|
+
const cp = {
|
|
33246
|
+
id: `cp_prefresh_${Date.now()}`,
|
|
33247
|
+
label: "pre-fresh auto-save",
|
|
33248
|
+
turnIndex,
|
|
33249
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
33250
|
+
sessionState: compiledContextRef.current ? sessionStateRef.current : void 0,
|
|
33251
|
+
artifactStore: serializeArtifactStore(artifactStoreRef.current)
|
|
33252
|
+
};
|
|
33253
|
+
ensureSessionId();
|
|
33254
|
+
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
33255
|
+
const filePath = join38(sessionsDir3(), `${sessionIdRef.current}.json`);
|
|
33256
|
+
await addCheckpoint(filePath, cp);
|
|
33257
|
+
}
|
|
33258
|
+
const summary = await generateContinuationSummary({
|
|
33259
|
+
messages: messagesRef.current,
|
|
33260
|
+
mode: modeRef.current,
|
|
33261
|
+
accountId: cfg.accountId,
|
|
33262
|
+
apiToken: cfg.apiToken,
|
|
33263
|
+
model: cfg.plumbingModel ?? "@cf/moonshotai/kimi-k2.5",
|
|
33264
|
+
gateway: gatewayFromConfig(cfg),
|
|
33265
|
+
memoryManager: memoryManagerRef.current,
|
|
33266
|
+
memoryEnabled: cfg.memoryEnabled
|
|
33267
|
+
});
|
|
33268
|
+
if (summary) {
|
|
33269
|
+
executeFreshStart(buildSlashContext(), summary);
|
|
33270
|
+
setEvents((e) => [
|
|
33271
|
+
...e,
|
|
33272
|
+
{ kind: "info", key: mkKey(), text: "Auto-fresh triggered: starting new session with continuation context\u2026" }
|
|
33273
|
+
]);
|
|
33274
|
+
}
|
|
33275
|
+
} catch (e) {
|
|
33276
|
+
setEvents((es) => [
|
|
33277
|
+
...es,
|
|
33278
|
+
{ kind: "error", key: mkKey(), text: `Auto-fresh failed: ${e.message}` }
|
|
33279
|
+
]);
|
|
33280
|
+
}
|
|
33281
|
+
})();
|
|
33282
|
+
} else {
|
|
33283
|
+
setEvents((e) => [
|
|
33284
|
+
...e,
|
|
33285
|
+
{
|
|
33286
|
+
kind: "info",
|
|
33287
|
+
key: mkKey(),
|
|
33288
|
+
text: `Session has run for ${turnCounterRef.current} turns. The model may slow down with accumulated context. Run /fresh to continue with a summarized state, or /compact to compress history.`
|
|
33289
|
+
}
|
|
33290
|
+
]);
|
|
33291
|
+
}
|
|
33292
|
+
}
|
|
32385
33293
|
gatewayMetaRef.current = null;
|
|
32386
33294
|
setGatewayMeta(null);
|
|
32387
33295
|
setIntentTier(classification.tier);
|
|
@@ -32703,7 +33611,7 @@ ${conflicts.join("\n")}` }
|
|
|
32703
33611
|
lspManagerRef.current.notifyChange(path, content2);
|
|
32704
33612
|
} else {
|
|
32705
33613
|
void import("fs/promises").then(
|
|
32706
|
-
({ readFile:
|
|
33614
|
+
({ readFile: readFile23 }) => readFile23(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
|
|
32707
33615
|
})
|
|
32708
33616
|
);
|
|
32709
33617
|
}
|
|
@@ -32921,7 +33829,7 @@ ${conflicts.join("\n")}` }
|
|
|
32921
33829
|
});
|
|
32922
33830
|
}, [usage, modelContextLimit, busy, runCompact2]);
|
|
32923
33831
|
if (!cfg) {
|
|
32924
|
-
return /* @__PURE__ */
|
|
33832
|
+
return /* @__PURE__ */ jsx44(ThemeProvider, { theme, children: /* @__PURE__ */ jsx44(
|
|
32925
33833
|
Onboarding,
|
|
32926
33834
|
{
|
|
32927
33835
|
onCancel: () => exit(),
|
|
@@ -32936,7 +33844,7 @@ ${conflicts.join("\n")}` }
|
|
|
32936
33844
|
) });
|
|
32937
33845
|
}
|
|
32938
33846
|
if (planOptions !== null) {
|
|
32939
|
-
return /* @__PURE__ */
|
|
33847
|
+
return /* @__PURE__ */ jsx44(ThemeProvider, { theme, children: /* @__PURE__ */ jsx44(Box42, { flexDirection: "column", children: /* @__PURE__ */ jsx44(
|
|
32940
33848
|
PlanOptionsPicker,
|
|
32941
33849
|
{
|
|
32942
33850
|
options: planOptions,
|
|
@@ -32966,7 +33874,7 @@ ${conflicts.join("\n")}` }
|
|
|
32966
33874
|
) }) });
|
|
32967
33875
|
}
|
|
32968
33876
|
if (checkpointSession !== null) {
|
|
32969
|
-
return /* @__PURE__ */
|
|
33877
|
+
return /* @__PURE__ */ jsx44(ThemeProvider, { theme, children: /* @__PURE__ */ jsx44(Box42, { flexDirection: "column", children: /* @__PURE__ */ jsx44(
|
|
32970
33878
|
CheckpointPicker,
|
|
32971
33879
|
{
|
|
32972
33880
|
session: checkpointSession,
|
|
@@ -32976,10 +33884,10 @@ ${conflicts.join("\n")}` }
|
|
|
32976
33884
|
) }) });
|
|
32977
33885
|
}
|
|
32978
33886
|
if (resumeSessions !== null) {
|
|
32979
|
-
return /* @__PURE__ */
|
|
33887
|
+
return /* @__PURE__ */ jsx44(ThemeProvider, { theme, children: /* @__PURE__ */ jsx44(Box42, { flexDirection: "column", children: /* @__PURE__ */ jsx44(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
|
|
32980
33888
|
}
|
|
32981
33889
|
if (hasFullscreenModal) {
|
|
32982
|
-
return /* @__PURE__ */
|
|
33890
|
+
return /* @__PURE__ */ jsx44(
|
|
32983
33891
|
ModalHost,
|
|
32984
33892
|
{
|
|
32985
33893
|
modals,
|
|
@@ -32990,7 +33898,7 @@ ${conflicts.join("\n")}` }
|
|
|
32990
33898
|
onCommandDelete: handleCommandDelete2,
|
|
32991
33899
|
lspServers: cfg?.lspServers ?? {},
|
|
32992
33900
|
lspScope,
|
|
32993
|
-
hasProjectDir: existsSync8(
|
|
33901
|
+
hasProjectDir: existsSync8(join38(process.cwd(), ".kimiflare")),
|
|
32994
33902
|
onLspSave: handleLspSave2,
|
|
32995
33903
|
themes: themeList(),
|
|
32996
33904
|
onPickTheme: handleThemePick,
|
|
@@ -33018,7 +33926,7 @@ ${conflicts.join("\n")}` }
|
|
|
33018
33926
|
selectedRemoteSession,
|
|
33019
33927
|
onSelectRemoteSession: setSelectedRemoteSession,
|
|
33020
33928
|
onCancelRemoteSession: handleRemoteCancel2,
|
|
33021
|
-
onInboxOpen:
|
|
33929
|
+
onInboxOpen: openBrowser,
|
|
33022
33930
|
multiAgentSettings: cfg ? {
|
|
33023
33931
|
multiAgentEnabled: cfg.multiAgentEnabled,
|
|
33024
33932
|
workerEndpoint: cfg.workerEndpoint,
|
|
@@ -33118,14 +34026,80 @@ ${conflicts.join("\n")}` }
|
|
|
33118
34026
|
}
|
|
33119
34027
|
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: `Type /skills ${action} <name> to ${action} a skill.` }]);
|
|
33120
34028
|
},
|
|
33121
|
-
onSkillsDone: () => setShowSkillsPicker(false)
|
|
34029
|
+
onSkillsDone: () => setShowSkillsPicker(false),
|
|
34030
|
+
changelogImageRepo,
|
|
34031
|
+
onChangelogImageGenerate: (owner, repo, days) => {
|
|
34032
|
+
setShowChangelogImagePicker(false);
|
|
34033
|
+
const asstId = mkAssistantId();
|
|
34034
|
+
setEvents((e) => [
|
|
34035
|
+
...e,
|
|
34036
|
+
{
|
|
34037
|
+
kind: "assistant",
|
|
34038
|
+
key: `asst_${asstId}`,
|
|
34039
|
+
id: asstId,
|
|
34040
|
+
text: `Generating changelog image for ${owner}/${repo} (last ${days} day${days === 1 ? "" : "s"})\u2026`,
|
|
34041
|
+
reasoning: "",
|
|
34042
|
+
streaming: true
|
|
34043
|
+
}
|
|
34044
|
+
]);
|
|
34045
|
+
const taskList = [
|
|
34046
|
+
{ id: "fetch-prs", title: "Fetch merged PRs", status: "pending" },
|
|
34047
|
+
{ id: "fetch-release", title: "Fetch latest release", status: "pending" },
|
|
34048
|
+
{ id: "summarize", title: "Summarize with LLM", status: "pending" },
|
|
34049
|
+
{ id: "render", title: "Render changelog image", status: "pending" },
|
|
34050
|
+
{ id: "save", title: "Save PNG file", status: "pending" }
|
|
34051
|
+
];
|
|
34052
|
+
turn.setTasks(taskList);
|
|
34053
|
+
turn.setTasksStartedAt(Date.now());
|
|
34054
|
+
const updateTask = (id, status) => {
|
|
34055
|
+
turn.setTasks((prev) => prev.map((t) => t.id === id ? { ...t, status } : t));
|
|
34056
|
+
};
|
|
34057
|
+
setTimeout(() => {
|
|
34058
|
+
void (async () => {
|
|
34059
|
+
try {
|
|
34060
|
+
updateTask("fetch-prs", "in_progress");
|
|
34061
|
+
updateTask("fetch-release", "in_progress");
|
|
34062
|
+
const { changelogImageTool: changelogImageTool2 } = await Promise.resolve().then(() => (init_changelog_image(), changelog_image_exports));
|
|
34063
|
+
const result = await changelogImageTool2.run({ owner, repo, days }, {
|
|
34064
|
+
cwd: process.cwd(),
|
|
34065
|
+
githubToken: cfg?.githubOAuthToken,
|
|
34066
|
+
accountId: cfg?.accountId,
|
|
34067
|
+
apiToken: cfg?.apiToken,
|
|
34068
|
+
model: cfg?.model,
|
|
34069
|
+
gateway: gatewayFromConfig(cfg)
|
|
34070
|
+
});
|
|
34071
|
+
updateTask("fetch-prs", "completed");
|
|
34072
|
+
updateTask("fetch-release", "completed");
|
|
34073
|
+
updateTask("summarize", "completed");
|
|
34074
|
+
updateTask("render", "completed");
|
|
34075
|
+
updateTask("save", "completed");
|
|
34076
|
+
const text = typeof result === "string" ? result : result.content;
|
|
34077
|
+
setEvents(
|
|
34078
|
+
(e) => e.map(
|
|
34079
|
+
(ev) => ev.kind === "assistant" && ev.id === asstId ? { ...ev, text, streaming: false } : ev
|
|
34080
|
+
)
|
|
34081
|
+
);
|
|
34082
|
+
} catch (err) {
|
|
34083
|
+
const msg = `changelog-image failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
34084
|
+
setEvents(
|
|
34085
|
+
(e) => e.map(
|
|
34086
|
+
(ev) => ev.kind === "assistant" && ev.id === asstId ? { ...ev, text: msg, streaming: false } : ev
|
|
34087
|
+
)
|
|
34088
|
+
);
|
|
34089
|
+
} finally {
|
|
34090
|
+
turn.setTasksStartedAt(null);
|
|
34091
|
+
}
|
|
34092
|
+
})();
|
|
34093
|
+
}, 0);
|
|
34094
|
+
},
|
|
34095
|
+
onChangelogImageCancel: () => setShowChangelogImagePicker(false)
|
|
33122
34096
|
}
|
|
33123
34097
|
);
|
|
33124
34098
|
}
|
|
33125
34099
|
const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
|
|
33126
|
-
return /* @__PURE__ */
|
|
33127
|
-
!hasConversation && events.length === 0 ? /* @__PURE__ */
|
|
33128
|
-
perm ? /* @__PURE__ */
|
|
34100
|
+
return /* @__PURE__ */ jsx44(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs42(Box42, { flexDirection: "column", children: [
|
|
34101
|
+
!hasConversation && events.length === 0 ? /* @__PURE__ */ jsx44(Welcome, {}) : /* @__PURE__ */ jsx44(ChatView, { events, showReasoning, verbose, intentTier: intentTier ?? void 0 }),
|
|
34102
|
+
perm ? /* @__PURE__ */ jsx44(
|
|
33129
34103
|
PermissionModal,
|
|
33130
34104
|
{
|
|
33131
34105
|
tool: perm.tool,
|
|
@@ -33135,7 +34109,7 @@ ${conflicts.join("\n")}` }
|
|
|
33135
34109
|
submitRef.current(text);
|
|
33136
34110
|
}
|
|
33137
34111
|
}
|
|
33138
|
-
) : limitModal || loopModal ? /* @__PURE__ */
|
|
34112
|
+
) : limitModal || loopModal ? /* @__PURE__ */ jsx44(
|
|
33139
34113
|
ModalOverlay,
|
|
33140
34114
|
{
|
|
33141
34115
|
modals,
|
|
@@ -33146,9 +34120,9 @@ ${conflicts.join("\n")}` }
|
|
|
33146
34120
|
loopResolveRef.current = null;
|
|
33147
34121
|
}
|
|
33148
34122
|
}
|
|
33149
|
-
) : showPlanCompletePicker ? /* @__PURE__ */
|
|
33150
|
-
(activeWorkers.length > 0 || coordinatorNarration) && /* @__PURE__ */
|
|
33151
|
-
tasks.length > 0 && /* @__PURE__ */
|
|
34123
|
+
) : showPlanCompletePicker ? /* @__PURE__ */ jsx44(PlanCompletePicker, { onPick: handlePlanCompletePick }) : /* @__PURE__ */ jsxs42(Box42, { flexDirection: "column", marginTop: 1, children: [
|
|
34124
|
+
(activeWorkers.length > 0 || coordinatorNarration) && /* @__PURE__ */ jsx44(WorkerList, { workers: activeWorkers, isSynthesizing, narration: coordinatorNarration }),
|
|
34125
|
+
tasks.length > 0 && /* @__PURE__ */ jsx44(
|
|
33152
34126
|
TaskList,
|
|
33153
34127
|
{
|
|
33154
34128
|
tasks,
|
|
@@ -33156,11 +34130,11 @@ ${conflicts.join("\n")}` }
|
|
|
33156
34130
|
tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
|
|
33157
34131
|
}
|
|
33158
34132
|
),
|
|
33159
|
-
queue2.length > 0 && /* @__PURE__ */
|
|
34133
|
+
queue2.length > 0 && /* @__PURE__ */ jsx44(Box42, { flexDirection: "column", marginBottom: 1, children: queue2.map((q, i) => /* @__PURE__ */ jsxs42(Text43, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
33160
34134
|
"\u23F3 ",
|
|
33161
34135
|
q.display
|
|
33162
34136
|
] }, `queue_${i}`)) }),
|
|
33163
|
-
/* @__PURE__ */
|
|
34137
|
+
/* @__PURE__ */ jsx44(
|
|
33164
34138
|
StatusBar,
|
|
33165
34139
|
{
|
|
33166
34140
|
usage,
|
|
@@ -33182,7 +34156,7 @@ ${conflicts.join("\n")}` }
|
|
|
33182
34156
|
intentTier: intentTier ?? void 0
|
|
33183
34157
|
}
|
|
33184
34158
|
),
|
|
33185
|
-
picker.active?.kind === "file" && /* @__PURE__ */
|
|
34159
|
+
picker.active?.kind === "file" && /* @__PURE__ */ jsx44(
|
|
33186
34160
|
FilePicker,
|
|
33187
34161
|
{
|
|
33188
34162
|
items: picker.fileItems,
|
|
@@ -33191,7 +34165,7 @@ ${conflicts.join("\n")}` }
|
|
|
33191
34165
|
recentFiles: new Set(recentFilesRef.current.keys())
|
|
33192
34166
|
}
|
|
33193
34167
|
),
|
|
33194
|
-
picker.active?.kind === "slash" && /* @__PURE__ */
|
|
34168
|
+
picker.active?.kind === "slash" && /* @__PURE__ */ jsx44(
|
|
33195
34169
|
SlashPicker,
|
|
33196
34170
|
{
|
|
33197
34171
|
items: picker.slashItems,
|
|
@@ -33199,9 +34173,9 @@ ${conflicts.join("\n")}` }
|
|
|
33199
34173
|
query: picker.query
|
|
33200
34174
|
}
|
|
33201
34175
|
),
|
|
33202
|
-
/* @__PURE__ */
|
|
33203
|
-
/* @__PURE__ */
|
|
33204
|
-
/* @__PURE__ */
|
|
34176
|
+
/* @__PURE__ */ jsxs42(Box42, { marginTop: 1, children: [
|
|
34177
|
+
/* @__PURE__ */ jsx44(Text43, { color: theme.prompt ?? theme.accent, children: "\u203A " }),
|
|
34178
|
+
/* @__PURE__ */ jsx44(
|
|
33205
34179
|
CustomTextInput,
|
|
33206
34180
|
{
|
|
33207
34181
|
value: input,
|
|
@@ -33258,7 +34232,7 @@ ${conflicts.join("\n")}` }
|
|
|
33258
34232
|
}
|
|
33259
34233
|
async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null) {
|
|
33260
34234
|
const instance = render(
|
|
33261
|
-
/* @__PURE__ */
|
|
34235
|
+
/* @__PURE__ */ jsx44(
|
|
33262
34236
|
App,
|
|
33263
34237
|
{
|
|
33264
34238
|
initialCfg: cfg,
|
|
@@ -33337,12 +34311,12 @@ var init_app = __esm({
|
|
|
33337
34311
|
init_use_turn_controller();
|
|
33338
34312
|
init_input_handlers();
|
|
33339
34313
|
init_slash_commands();
|
|
34314
|
+
init_continuation_summary();
|
|
33340
34315
|
init_run_init();
|
|
33341
34316
|
init_run_startup_tasks();
|
|
33342
34317
|
init_manager_init();
|
|
33343
34318
|
init_run_compact();
|
|
33344
34319
|
init_distill();
|
|
33345
|
-
init_clipboard();
|
|
33346
34320
|
init_command_handlers();
|
|
33347
34321
|
init_app_helpers();
|
|
33348
34322
|
}
|