kimiflare 0.23.0 → 0.25.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 +1032 -180
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -18,8 +18,7 @@ function configPath() {
|
|
|
18
18
|
}
|
|
19
19
|
function readReasoningEffortEnv() {
|
|
20
20
|
const raw = process.env.KIMI_REASONING_EFFORT?.toLowerCase();
|
|
21
|
-
|
|
22
|
-
return void 0;
|
|
21
|
+
return EFFORTS.includes(raw ?? "") ? raw : void 0;
|
|
23
22
|
}
|
|
24
23
|
function readCoauthorEnv() {
|
|
25
24
|
const enabled = process.env.KIMIFLARE_COAUTHOR;
|
|
@@ -152,10 +151,11 @@ async function saveConfig(cfg) {
|
|
|
152
151
|
await chmod(p, 384);
|
|
153
152
|
return p;
|
|
154
153
|
}
|
|
155
|
-
var DEFAULT_MODEL, DEFAULT_REASONING_EFFORT;
|
|
154
|
+
var EFFORTS, DEFAULT_MODEL, DEFAULT_REASONING_EFFORT;
|
|
156
155
|
var init_config = __esm({
|
|
157
156
|
"src/config.ts"() {
|
|
158
157
|
"use strict";
|
|
158
|
+
EFFORTS = ["low", "medium", "high"];
|
|
159
159
|
DEFAULT_MODEL = "@cf/moonshotai/kimi-k2.6";
|
|
160
160
|
DEFAULT_REASONING_EFFORT = "medium";
|
|
161
161
|
}
|
|
@@ -173,10 +173,10 @@ async function* readSSE(stream, signal) {
|
|
|
173
173
|
if (done) break;
|
|
174
174
|
buffer += decoder.decode(value, { stream: true });
|
|
175
175
|
buffer = buffer.replace(/\r\n/g, "\n");
|
|
176
|
-
let
|
|
177
|
-
while ((
|
|
178
|
-
const event = buffer.slice(0,
|
|
179
|
-
buffer = buffer.slice(
|
|
176
|
+
let sep3;
|
|
177
|
+
while ((sep3 = buffer.indexOf("\n\n")) !== -1) {
|
|
178
|
+
const event = buffer.slice(0, sep3);
|
|
179
|
+
buffer = buffer.slice(sep3 + 2);
|
|
180
180
|
const data = extractData(event);
|
|
181
181
|
if (data !== null) yield data;
|
|
182
182
|
}
|
|
@@ -209,8 +209,8 @@ var init_errors = __esm({
|
|
|
209
209
|
"src/util/errors.ts"() {
|
|
210
210
|
"use strict";
|
|
211
211
|
KimiApiError = class extends Error {
|
|
212
|
-
constructor(
|
|
213
|
-
super(
|
|
212
|
+
constructor(message2, code, httpStatus) {
|
|
213
|
+
super(message2);
|
|
214
214
|
this.code = code;
|
|
215
215
|
this.httpStatus = httpStatus;
|
|
216
216
|
this.name = "KimiApiError";
|
|
@@ -1027,8 +1027,8 @@ ${jsCode}
|
|
|
1027
1027
|
await script.run(context, { timeout, release: true });
|
|
1028
1028
|
await new Promise((r) => setTimeout(r, 10));
|
|
1029
1029
|
} catch (err) {
|
|
1030
|
-
const
|
|
1031
|
-
return { output: "", logs, error:
|
|
1030
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
1031
|
+
return { output: "", logs, error: message2, toolCalls };
|
|
1032
1032
|
} finally {
|
|
1033
1033
|
isolate.dispose();
|
|
1034
1034
|
}
|
|
@@ -1110,8 +1110,8 @@ ${jsCode}
|
|
|
1110
1110
|
await runInNewContext(wrapped, sandbox, { timeout, displayErrors: true });
|
|
1111
1111
|
await new Promise((r) => setTimeout(r, 10));
|
|
1112
1112
|
} catch (err) {
|
|
1113
|
-
const
|
|
1114
|
-
return { output: "", logs, error:
|
|
1113
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
1114
|
+
return { output: "", logs, error: message2, toolCalls };
|
|
1115
1115
|
}
|
|
1116
1116
|
return { output: logs.join("\n"), logs, toolCalls };
|
|
1117
1117
|
}
|
|
@@ -1119,8 +1119,8 @@ async function runInSandbox(opts2) {
|
|
|
1119
1119
|
try {
|
|
1120
1120
|
return await runWithIsolatedVm(opts2);
|
|
1121
1121
|
} catch (err) {
|
|
1122
|
-
const
|
|
1123
|
-
if (
|
|
1122
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
1123
|
+
if (message2.includes("isolated-vm") || message2.includes("Cannot find module") || message2.includes("bindings")) {
|
|
1124
1124
|
return runWithNodeVm(opts2);
|
|
1125
1125
|
}
|
|
1126
1126
|
return runWithNodeVm(opts2);
|
|
@@ -1528,7 +1528,7 @@ var init_mode = __esm({
|
|
|
1528
1528
|
"use strict";
|
|
1529
1529
|
MODES = ["edit", "plan", "auto"];
|
|
1530
1530
|
MUTATING_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "bash"]);
|
|
1531
|
-
DANGEROUS_PATTERNS = /[
|
|
1531
|
+
DANGEROUS_PATTERNS = /[<>;`$]|\$\(|\$\{|\|\||\b&\s*$/;
|
|
1532
1532
|
GIT_READONLY_SUBCOMMANDS = {
|
|
1533
1533
|
log: true,
|
|
1534
1534
|
diff: true,
|
|
@@ -1711,6 +1711,9 @@ function resolvePath(cwd, input) {
|
|
|
1711
1711
|
}
|
|
1712
1712
|
return isAbsolute(input) ? input : resolve(cwd, input);
|
|
1713
1713
|
}
|
|
1714
|
+
function isPathOutside(relPath) {
|
|
1715
|
+
return relPath === ".." || relPath.startsWith(`..${sep}`) || isAbsolute(relPath);
|
|
1716
|
+
}
|
|
1714
1717
|
function collapsePath(input, cwd, maxLen = 40) {
|
|
1715
1718
|
if (!input) return input;
|
|
1716
1719
|
let abs;
|
|
@@ -1888,8 +1891,10 @@ function injectCoauthor(command, coauthor) {
|
|
|
1888
1891
|
if (command.includes(trailer)) return command;
|
|
1889
1892
|
const createsCommit = /\bgit\s+(commit|merge|revert|cherry-pick)\b/.test(trimmed);
|
|
1890
1893
|
const isRebaseContinue = /\bgit\s+rebase\b/.test(trimmed) && !/\b--abort\b|\b--skip\b/.test(trimmed);
|
|
1894
|
+
const movesHeadOnly = /\bgit\s+(reset|checkout|switch)\b/.test(trimmed);
|
|
1891
1895
|
const mentionsGit = /\bgit\b/.test(trimmed);
|
|
1892
1896
|
if (!createsCommit && !isRebaseContinue && !mentionsGit) return command;
|
|
1897
|
+
if (movesHeadOnly) return command;
|
|
1893
1898
|
const tmpFile = join5(tmpdir(), `kf-coauthor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
1894
1899
|
const amendBlock = `
|
|
1895
1900
|
if ! git log -1 --pretty=%B 2>/dev/null | grep -qF "${trailer}"; then
|
|
@@ -1902,7 +1907,7 @@ function injectCoauthor(command, coauthor) {
|
|
|
1902
1907
|
const beforeHead = `git rev-parse HEAD 2>/dev/null || echo "NO_HEAD"`;
|
|
1903
1908
|
const afterCheck = `
|
|
1904
1909
|
_KF_AFTER_HEAD=$(git rev-parse HEAD 2>/dev/null || echo "NO_HEAD")
|
|
1905
|
-
if [ "$_KF_BEFORE_HEAD" != "$_KF_AFTER_HEAD" ] && [ "$_KF_AFTER_HEAD" != "NO_HEAD" ]; then
|
|
1910
|
+
if [ "$_KF_BEFORE_HEAD" != "$_KF_AFTER_HEAD" ] && [ "$_KF_AFTER_HEAD" != "NO_HEAD" ] && git merge-base --is-ancestor "$_KF_BEFORE_HEAD" "$_KF_AFTER_HEAD" 2>/dev/null; then
|
|
1906
1911
|
${amendBlock}
|
|
1907
1912
|
fi
|
|
1908
1913
|
`.trim();
|
|
@@ -2837,6 +2842,16 @@ var init_expand_artifact = __esm({
|
|
|
2837
2842
|
});
|
|
2838
2843
|
|
|
2839
2844
|
// src/tools/executor.ts
|
|
2845
|
+
function isDiffCommand(cmd) {
|
|
2846
|
+
const trimmed = cmd.trim();
|
|
2847
|
+
if (/^git\s+show(?:\s|$)/.test(trimmed)) return true;
|
|
2848
|
+
if (/^git\s+diff(?:\s|$)/.test(trimmed)) return true;
|
|
2849
|
+
if (/^git\s+format-patch(?:\s|$)/.test(trimmed)) return true;
|
|
2850
|
+
const hasPatchFlag = /(?:^|\s)(?:-p|--patch)(?:\s|$)/.test(trimmed);
|
|
2851
|
+
if (/^git\s+log(?:\s|$)/.test(trimmed) && hasPatchFlag) return true;
|
|
2852
|
+
if (/^git\s+stash\s+show(?:\s|$)/.test(trimmed) && hasPatchFlag) return true;
|
|
2853
|
+
return false;
|
|
2854
|
+
}
|
|
2840
2855
|
function normalizeToolOutput(result) {
|
|
2841
2856
|
if (typeof result === "string") {
|
|
2842
2857
|
const bytes = Buffer.byteLength(result, "utf8");
|
|
@@ -2939,6 +2954,20 @@ var init_executor = __esm({
|
|
|
2939
2954
|
try {
|
|
2940
2955
|
const result = await tool.run(args, ctx);
|
|
2941
2956
|
const normalized = normalizeToolOutput(result);
|
|
2957
|
+
const cmd = call.name === "bash" && typeof args.command === "string" ? args.command : "";
|
|
2958
|
+
if (isDiffCommand(cmd)) {
|
|
2959
|
+
const artifactId = this.artifactStore.store(normalized.content);
|
|
2960
|
+
const bytes = Buffer.byteLength(normalized.content, "utf8");
|
|
2961
|
+
return {
|
|
2962
|
+
tool_call_id: call.id,
|
|
2963
|
+
name: call.name,
|
|
2964
|
+
content: normalized.content,
|
|
2965
|
+
ok: true,
|
|
2966
|
+
rawBytes: bytes,
|
|
2967
|
+
reducedBytes: bytes,
|
|
2968
|
+
artifactId
|
|
2969
|
+
};
|
|
2970
|
+
}
|
|
2942
2971
|
const reduced = reduceToolOutput(
|
|
2943
2972
|
call.name,
|
|
2944
2973
|
normalized.content,
|
|
@@ -3079,6 +3108,33 @@ var init_update_check = __esm({
|
|
|
3079
3108
|
}
|
|
3080
3109
|
});
|
|
3081
3110
|
|
|
3111
|
+
// src/util/version.ts
|
|
3112
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
3113
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3114
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
3115
|
+
function getAppVersion() {
|
|
3116
|
+
if (cachedVersion !== null) return cachedVersion;
|
|
3117
|
+
const here = dirname3(fileURLToPath2(import.meta.url));
|
|
3118
|
+
const candidates = [join7(here, "..", "..", "package.json"), join7(here, "..", "package.json")];
|
|
3119
|
+
for (const path of candidates) {
|
|
3120
|
+
try {
|
|
3121
|
+
const pkg = JSON.parse(readFileSync2(path, "utf8"));
|
|
3122
|
+
cachedVersion = pkg.version ?? "0.0.0";
|
|
3123
|
+
return cachedVersion;
|
|
3124
|
+
} catch {
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
cachedVersion = "0.0.0";
|
|
3128
|
+
return cachedVersion;
|
|
3129
|
+
}
|
|
3130
|
+
var cachedVersion;
|
|
3131
|
+
var init_version = __esm({
|
|
3132
|
+
"src/util/version.ts"() {
|
|
3133
|
+
"use strict";
|
|
3134
|
+
cachedVersion = null;
|
|
3135
|
+
}
|
|
3136
|
+
});
|
|
3137
|
+
|
|
3082
3138
|
// src/agent/compact.ts
|
|
3083
3139
|
function indexOfNthUserFromEnd(messages, n) {
|
|
3084
3140
|
let seen = 0;
|
|
@@ -3552,11 +3608,12 @@ function recallArtifacts(messages, store, state) {
|
|
|
3552
3608
|
}
|
|
3553
3609
|
for (const failure of state.recent_failures) {
|
|
3554
3610
|
const keyword = failure.split(":")[0];
|
|
3555
|
-
if (keyword
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3611
|
+
if (!keyword) continue;
|
|
3612
|
+
const lowerKeyword = keyword.toLowerCase();
|
|
3613
|
+
if (!text.toLowerCase().includes(lowerKeyword)) continue;
|
|
3614
|
+
for (const [id, meta] of Object.entries(state.artifact_index)) {
|
|
3615
|
+
if (meta.source === "bash" && !ids.includes(id) && meta.summary.toLowerCase().includes(lowerKeyword)) {
|
|
3616
|
+
ids.push(id);
|
|
3560
3617
|
}
|
|
3561
3618
|
}
|
|
3562
3619
|
}
|
|
@@ -3968,13 +4025,12 @@ import React3 from "react";
|
|
|
3968
4025
|
import { Box as Box4, Text as Text4, Static } from "ink";
|
|
3969
4026
|
import Spinner2 from "ink-spinner";
|
|
3970
4027
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
3971
|
-
var
|
|
4028
|
+
var ChatView, EventView;
|
|
3972
4029
|
var init_chat = __esm({
|
|
3973
4030
|
"src/ui/chat.tsx"() {
|
|
3974
4031
|
"use strict";
|
|
3975
4032
|
init_tool_view();
|
|
3976
4033
|
init_markdown();
|
|
3977
|
-
MAX_FINALIZED_EVENTS = 100;
|
|
3978
4034
|
ChatView = React3.memo(function ChatView2({ events, showReasoning, theme, verbose }) {
|
|
3979
4035
|
const finalized = [];
|
|
3980
4036
|
const active = [];
|
|
@@ -3989,15 +4045,13 @@ var init_chat = __esm({
|
|
|
3989
4045
|
finalized.push({ id: e.key, evt: e, showSeparator });
|
|
3990
4046
|
}
|
|
3991
4047
|
}
|
|
3992
|
-
const droppedCount = Math.max(0, finalized.length - MAX_FINALIZED_EVENTS);
|
|
3993
|
-
const visibleFinalized = droppedCount > 0 ? finalized.slice(droppedCount) : finalized;
|
|
3994
4048
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
3995
|
-
/* @__PURE__ */ jsx4(Static, { items:
|
|
4049
|
+
/* @__PURE__ */ jsx4(Static, { items: finalized, children: (item) => /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
3996
4050
|
item.showSeparator && /* @__PURE__ */ jsx4(Box4, { marginY: 1, children: /* @__PURE__ */ jsx4(Text4, { color: theme.info.color, dimColor: theme.info.dim, children: "\u2500".repeat(40) }) }),
|
|
3997
4051
|
/* @__PURE__ */ jsx4(EventView, { evt: item.evt, showReasoning, theme, verbose })
|
|
3998
|
-
] }) }),
|
|
4052
|
+
] }, item.id) }),
|
|
3999
4053
|
active.map((e, i) => {
|
|
4000
|
-
const prevEvt = i > 0 ? active[i - 1] :
|
|
4054
|
+
const prevEvt = i > 0 ? active[i - 1] : finalized[finalized.length - 1]?.evt;
|
|
4001
4055
|
const showSeparator = e.kind === "user" && prevEvt && (prevEvt.kind === "assistant" || prevEvt.kind === "tool");
|
|
4002
4056
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
4003
4057
|
showSeparator && /* @__PURE__ */ jsx4(Box4, { marginY: 1, children: /* @__PURE__ */ jsx4(Text4, { color: theme.info.color, dimColor: theme.info.dim, children: "\u2500".repeat(40) }) }),
|
|
@@ -4131,14 +4185,14 @@ function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta) {
|
|
|
4131
4185
|
parts.push(`in ${sessionUsage.promptTokens}${cached ? ` (${cached} cached)` : ""}`);
|
|
4132
4186
|
parts.push(`out ${sessionUsage.completionTokens}`);
|
|
4133
4187
|
parts.push(`ctx ${pct}%`);
|
|
4134
|
-
parts.push(
|
|
4188
|
+
parts.push(`$${sessionUsage.cost.toFixed(5)}`);
|
|
4135
4189
|
} else {
|
|
4136
4190
|
const cached = usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
4137
4191
|
const cost = calculateCost(usage.prompt_tokens, usage.completion_tokens, cached);
|
|
4138
4192
|
parts.push(`in ${usage.prompt_tokens}${cached ? ` (${cached} cached)` : ""}`);
|
|
4139
4193
|
parts.push(`out ${usage.completion_tokens}`);
|
|
4140
4194
|
parts.push(`ctx ${pct}%`);
|
|
4141
|
-
parts.push(
|
|
4195
|
+
parts.push(`$${cost.total.toFixed(5)}`);
|
|
4142
4196
|
}
|
|
4143
4197
|
const gatewayCache = formatGatewayCacheStatus(gatewayMeta);
|
|
4144
4198
|
if (gatewayCache) parts.push(gatewayCache);
|
|
@@ -4888,18 +4942,18 @@ var init_source = __esm({
|
|
|
4888
4942
|
}
|
|
4889
4943
|
}
|
|
4890
4944
|
});
|
|
4891
|
-
createStyler = (
|
|
4945
|
+
createStyler = (open3, close, parent) => {
|
|
4892
4946
|
let openAll;
|
|
4893
4947
|
let closeAll;
|
|
4894
4948
|
if (parent === void 0) {
|
|
4895
|
-
openAll =
|
|
4949
|
+
openAll = open3;
|
|
4896
4950
|
closeAll = close;
|
|
4897
4951
|
} else {
|
|
4898
|
-
openAll = parent.openAll +
|
|
4952
|
+
openAll = parent.openAll + open3;
|
|
4899
4953
|
closeAll = close + parent.closeAll;
|
|
4900
4954
|
}
|
|
4901
4955
|
return {
|
|
4902
|
-
open,
|
|
4956
|
+
open: open3,
|
|
4903
4957
|
close,
|
|
4904
4958
|
openAll,
|
|
4905
4959
|
closeAll,
|
|
@@ -5328,7 +5382,9 @@ function Welcome({ theme, accountId }) {
|
|
|
5328
5382
|
] }),
|
|
5329
5383
|
/* @__PURE__ */ jsx12(Text12, { color: theme.user, children: s })
|
|
5330
5384
|
] }, i)) }),
|
|
5331
|
-
/* @__PURE__ */ jsx12(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text12, { color: theme.info.color, dimColor: theme.info.dim, children: "Type a message or /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }) })
|
|
5385
|
+
/* @__PURE__ */ jsx12(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text12, { color: theme.info.color, dimColor: theme.info.dim, children: "Type a message or /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }) }),
|
|
5386
|
+
/* @__PURE__ */ jsx12(Box11, { children: /* @__PURE__ */ jsx12(Text12, { color: theme.info.color, dimColor: theme.info.dim, children: "Tip: type /hello to send feedback to the creator" }) }),
|
|
5387
|
+
/* @__PURE__ */ jsx12(Box11, { children: /* @__PURE__ */ jsx12(Text12, { color: theme.info.color, dimColor: theme.info.dim, children: "Join our community: https://discord.gg/aEuAUHNTK5 (type /community to open)" }) })
|
|
5332
5388
|
] });
|
|
5333
5389
|
}
|
|
5334
5390
|
var SUGGESTIONS;
|
|
@@ -5343,6 +5399,235 @@ var init_welcome = __esm({
|
|
|
5343
5399
|
}
|
|
5344
5400
|
});
|
|
5345
5401
|
|
|
5402
|
+
// src/ui/help-menu.tsx
|
|
5403
|
+
import { useState as useState6 } from "react";
|
|
5404
|
+
import { Box as Box12, Text as Text13, useInput as useInput2 } from "ink";
|
|
5405
|
+
import SelectInput4 from "ink-select-input";
|
|
5406
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
5407
|
+
function HelpMenu({ theme, themes, currentThemeName, customCommands, onDone, onCommand }) {
|
|
5408
|
+
const [page, setPage] = useState6("main");
|
|
5409
|
+
const customs = customCommands ?? [];
|
|
5410
|
+
useInput2((_input, key) => {
|
|
5411
|
+
if (key.escape) {
|
|
5412
|
+
if (page !== "main") {
|
|
5413
|
+
setPage("main");
|
|
5414
|
+
} else {
|
|
5415
|
+
onDone();
|
|
5416
|
+
}
|
|
5417
|
+
}
|
|
5418
|
+
});
|
|
5419
|
+
const handleSelect = (command) => {
|
|
5420
|
+
onCommand(command);
|
|
5421
|
+
onDone();
|
|
5422
|
+
};
|
|
5423
|
+
if (page === "main") {
|
|
5424
|
+
const items2 = CATEGORIES.map((cat) => ({
|
|
5425
|
+
label: cat.label,
|
|
5426
|
+
value: cat.key,
|
|
5427
|
+
key: cat.key
|
|
5428
|
+
}));
|
|
5429
|
+
if (customs.length > 0) {
|
|
5430
|
+
items2.push({ label: "Custom commands", value: "custom", key: "custom" });
|
|
5431
|
+
}
|
|
5432
|
+
items2.push({ label: "(close)", value: "__close__", key: "__close__" });
|
|
5433
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
5434
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.accent, bold: true, children: "Help" }),
|
|
5435
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to close." }),
|
|
5436
|
+
/* @__PURE__ */ jsx13(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx13(
|
|
5437
|
+
SelectInput4,
|
|
5438
|
+
{
|
|
5439
|
+
items: items2,
|
|
5440
|
+
onSelect: (item) => {
|
|
5441
|
+
if (item.value === "__close__") {
|
|
5442
|
+
onDone();
|
|
5443
|
+
} else {
|
|
5444
|
+
setPage(item.value);
|
|
5445
|
+
}
|
|
5446
|
+
}
|
|
5447
|
+
}
|
|
5448
|
+
) }),
|
|
5449
|
+
/* @__PURE__ */ jsx13(Box12, { marginTop: 1, flexDirection: "column", children: SINGLE_COMMANDS.map((cmd) => /* @__PURE__ */ jsx13(Text13, { color: theme.info.color, dimColor: false, children: ` ${cmd.command.padEnd(20)} ${cmd.description}` }, cmd.command)) }),
|
|
5450
|
+
/* @__PURE__ */ jsx13(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text13, { color: theme.info.color, dimColor: false, children: "keys: ctrl-c interrupt/exit \xB7 ctrl-r toggle reasoning \xB7 ctrl-o verbose \xB7 ctrl+t theme \xB7 shift+tab cycle mode \xB7 \u2191/\u2193 history" }) })
|
|
5451
|
+
] });
|
|
5452
|
+
}
|
|
5453
|
+
if (page === "theme") {
|
|
5454
|
+
const items2 = themes.map((t) => ({
|
|
5455
|
+
label: t.name === currentThemeName ? `${t.label} \xB7 current` : t.label,
|
|
5456
|
+
value: t.name,
|
|
5457
|
+
key: t.name
|
|
5458
|
+
}));
|
|
5459
|
+
items2.push({ label: "\u2190 Back", value: "__back__", key: "__back__" });
|
|
5460
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
5461
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.accent, bold: true, children: "Theme" }),
|
|
5462
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to apply, Esc to go back." }),
|
|
5463
|
+
/* @__PURE__ */ jsx13(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx13(
|
|
5464
|
+
SelectInput4,
|
|
5465
|
+
{
|
|
5466
|
+
items: items2,
|
|
5467
|
+
onSelect: (item) => {
|
|
5468
|
+
if (item.value === "__back__") {
|
|
5469
|
+
setPage("main");
|
|
5470
|
+
} else {
|
|
5471
|
+
handleSelect(`/theme ${item.value}`);
|
|
5472
|
+
}
|
|
5473
|
+
}
|
|
5474
|
+
}
|
|
5475
|
+
) })
|
|
5476
|
+
] });
|
|
5477
|
+
}
|
|
5478
|
+
if (page === "custom") {
|
|
5479
|
+
const items2 = customs.map((c) => ({
|
|
5480
|
+
label: `${`/${c.name}`.padEnd(28)} ${c.description ?? ""}`.trimEnd(),
|
|
5481
|
+
value: `/${c.name}`,
|
|
5482
|
+
key: c.name
|
|
5483
|
+
}));
|
|
5484
|
+
items2.push({ label: "\u2190 Back", value: "__back__", key: "__back__" });
|
|
5485
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
5486
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.accent, bold: true, children: "Custom commands" }),
|
|
5487
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.info.color, dimColor: false, children: customs.length === 0 ? "no custom commands found in .kimiflare/commands/" : "Arrow keys to navigate, Enter to run, Esc to go back." }),
|
|
5488
|
+
/* @__PURE__ */ jsx13(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx13(
|
|
5489
|
+
SelectInput4,
|
|
5490
|
+
{
|
|
5491
|
+
items: items2,
|
|
5492
|
+
onSelect: (item) => {
|
|
5493
|
+
if (item.value === "__back__") {
|
|
5494
|
+
setPage("main");
|
|
5495
|
+
} else {
|
|
5496
|
+
handleSelect(item.value);
|
|
5497
|
+
}
|
|
5498
|
+
}
|
|
5499
|
+
}
|
|
5500
|
+
) })
|
|
5501
|
+
] });
|
|
5502
|
+
}
|
|
5503
|
+
const category = CATEGORIES.find((c) => c.key === page);
|
|
5504
|
+
const selectable = category.commands.filter((cmd) => cmd.selectable !== false);
|
|
5505
|
+
const staticCmds = category.commands.filter((cmd) => cmd.selectable === false);
|
|
5506
|
+
const items = selectable.map((cmd) => ({
|
|
5507
|
+
label: `${cmd.command.padEnd(28)} ${cmd.description}`,
|
|
5508
|
+
value: cmd.command,
|
|
5509
|
+
key: cmd.command
|
|
5510
|
+
}));
|
|
5511
|
+
items.push({ label: "\u2190 Back", value: "__back__", key: "__back__" });
|
|
5512
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
5513
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.accent, bold: true, children: category.label }),
|
|
5514
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to execute, Esc to go back." }),
|
|
5515
|
+
/* @__PURE__ */ jsx13(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx13(
|
|
5516
|
+
SelectInput4,
|
|
5517
|
+
{
|
|
5518
|
+
items,
|
|
5519
|
+
onSelect: (item) => {
|
|
5520
|
+
if (item.value === "__back__") {
|
|
5521
|
+
setPage("main");
|
|
5522
|
+
} else {
|
|
5523
|
+
handleSelect(item.value);
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5527
|
+
) }),
|
|
5528
|
+
staticCmds.length > 0 && /* @__PURE__ */ jsx13(Box12, { marginTop: 1, flexDirection: "column", children: staticCmds.map((cmd) => /* @__PURE__ */ jsx13(Text13, { color: theme.info.color, dimColor: true, children: ` ${cmd.command.padEnd(28)} ${cmd.description}` }, cmd.command)) })
|
|
5529
|
+
] });
|
|
5530
|
+
}
|
|
5531
|
+
var CATEGORIES, SINGLE_COMMANDS;
|
|
5532
|
+
var init_help_menu = __esm({
|
|
5533
|
+
"src/ui/help-menu.tsx"() {
|
|
5534
|
+
"use strict";
|
|
5535
|
+
CATEGORIES = [
|
|
5536
|
+
{
|
|
5537
|
+
key: "mode",
|
|
5538
|
+
label: "Mode",
|
|
5539
|
+
commands: [
|
|
5540
|
+
{ command: "/mode edit", description: "switch to edit mode" },
|
|
5541
|
+
{ command: "/mode plan", description: "switch to plan mode" },
|
|
5542
|
+
{ command: "/mode auto", description: "switch to auto mode" }
|
|
5543
|
+
]
|
|
5544
|
+
},
|
|
5545
|
+
{
|
|
5546
|
+
key: "thinking",
|
|
5547
|
+
label: "Thinking",
|
|
5548
|
+
commands: [
|
|
5549
|
+
{ command: "/thinking low", description: "fast, lower quality" },
|
|
5550
|
+
{ command: "/thinking medium", description: "balanced" },
|
|
5551
|
+
{ command: "/thinking high", description: "slow, higher quality" }
|
|
5552
|
+
]
|
|
5553
|
+
},
|
|
5554
|
+
{
|
|
5555
|
+
key: "theme",
|
|
5556
|
+
label: "Theme",
|
|
5557
|
+
commands: []
|
|
5558
|
+
},
|
|
5559
|
+
{
|
|
5560
|
+
key: "session",
|
|
5561
|
+
label: "Session",
|
|
5562
|
+
commands: [
|
|
5563
|
+
{ command: "/resume", description: "pick a past conversation" },
|
|
5564
|
+
{ command: "/compact", description: "summarize old turns to free context" },
|
|
5565
|
+
{ command: "/clear", description: "clear current conversation" }
|
|
5566
|
+
]
|
|
5567
|
+
},
|
|
5568
|
+
{
|
|
5569
|
+
key: "memory",
|
|
5570
|
+
label: "Memory",
|
|
5571
|
+
commands: [
|
|
5572
|
+
{ command: "/memory", description: "show memory stats" },
|
|
5573
|
+
{ command: "/memory on", description: "enable memory" },
|
|
5574
|
+
{ command: "/memory off", description: "disable memory" },
|
|
5575
|
+
{ command: "/memory clear", description: "wipe memories for this repo" },
|
|
5576
|
+
{ command: "/memory search <query>", description: "search stored memories", selectable: false }
|
|
5577
|
+
]
|
|
5578
|
+
},
|
|
5579
|
+
{
|
|
5580
|
+
key: "mcp",
|
|
5581
|
+
label: "MCP",
|
|
5582
|
+
commands: [
|
|
5583
|
+
{ command: "/mcp list", description: "list connected MCP servers and tools" },
|
|
5584
|
+
{ command: "/mcp reload", description: "reconnect all configured MCP servers" }
|
|
5585
|
+
]
|
|
5586
|
+
},
|
|
5587
|
+
{
|
|
5588
|
+
key: "gateway",
|
|
5589
|
+
label: "Gateway",
|
|
5590
|
+
commands: [
|
|
5591
|
+
{ command: "/gateway", description: "show gateway status" },
|
|
5592
|
+
{ command: "/gateway off", description: "disable AI Gateway (direct Workers AI)" },
|
|
5593
|
+
{ command: "/gateway skip-cache true", description: "enable skip-cache" },
|
|
5594
|
+
{ command: "/gateway skip-cache false", description: "disable skip-cache" },
|
|
5595
|
+
{ command: "/gateway collect-logs true", description: "enable log collection" },
|
|
5596
|
+
{ command: "/gateway collect-logs false", description: "disable log collection" },
|
|
5597
|
+
{ command: "/gateway metadata clear", description: "remove all metadata" },
|
|
5598
|
+
{ command: "/gateway <id>", description: "enable AI Gateway", selectable: false },
|
|
5599
|
+
{ command: "/gateway cache-ttl <seconds>", description: "set cache TTL", selectable: false },
|
|
5600
|
+
{ command: "/gateway metadata <key>=<value>", description: "add metadata", selectable: false }
|
|
5601
|
+
]
|
|
5602
|
+
},
|
|
5603
|
+
{
|
|
5604
|
+
key: "info",
|
|
5605
|
+
label: "Info",
|
|
5606
|
+
commands: [
|
|
5607
|
+
{ command: "/cost", description: "show cost report" },
|
|
5608
|
+
{ command: "/model", description: "show current model" },
|
|
5609
|
+
{ command: "/update", description: "check for updates" },
|
|
5610
|
+
{ command: "/hello", description: "send a voice note to the creator" },
|
|
5611
|
+
{ command: "/community", description: "join our Discord server" }
|
|
5612
|
+
]
|
|
5613
|
+
},
|
|
5614
|
+
{
|
|
5615
|
+
key: "config",
|
|
5616
|
+
label: "Config",
|
|
5617
|
+
commands: [
|
|
5618
|
+
{ command: "/init", description: "scan this repo and write a KIMI.md" },
|
|
5619
|
+
{ command: "/logout", description: "clear credentials" }
|
|
5620
|
+
]
|
|
5621
|
+
}
|
|
5622
|
+
];
|
|
5623
|
+
SINGLE_COMMANDS = [
|
|
5624
|
+
{ command: "/reasoning", description: "toggle show/hide model reasoning" },
|
|
5625
|
+
{ command: "/help", description: "show this menu" },
|
|
5626
|
+
{ command: "/exit", description: "exit kimiflare" }
|
|
5627
|
+
];
|
|
5628
|
+
}
|
|
5629
|
+
});
|
|
5630
|
+
|
|
5346
5631
|
// src/ui/theme.ts
|
|
5347
5632
|
function resolveTheme(name) {
|
|
5348
5633
|
if (!name) return THEMES[DEFAULT_THEME_NAME];
|
|
@@ -5579,10 +5864,10 @@ __export(sessions_exports, {
|
|
|
5579
5864
|
});
|
|
5580
5865
|
import { readFile as readFile7, writeFile as writeFile5, mkdir as mkdir5, readdir as readdir2, stat as stat3 } from "fs/promises";
|
|
5581
5866
|
import { homedir as homedir6 } from "os";
|
|
5582
|
-
import { join as
|
|
5867
|
+
import { join as join8 } from "path";
|
|
5583
5868
|
function sessionsDir() {
|
|
5584
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
5585
|
-
return
|
|
5869
|
+
const xdg = process.env.XDG_DATA_HOME || join8(homedir6(), ".local", "share");
|
|
5870
|
+
return join8(xdg, "kimiflare", "sessions");
|
|
5586
5871
|
}
|
|
5587
5872
|
function sanitize(text) {
|
|
5588
5873
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -5595,7 +5880,7 @@ function makeSessionId(firstPrompt) {
|
|
|
5595
5880
|
async function saveSession(file) {
|
|
5596
5881
|
const dir = sessionsDir();
|
|
5597
5882
|
await mkdir5(dir, { recursive: true });
|
|
5598
|
-
const path =
|
|
5883
|
+
const path = join8(dir, `${file.id}.json`);
|
|
5599
5884
|
await writeFile5(path, JSON.stringify(file, null, 2), "utf8");
|
|
5600
5885
|
return path;
|
|
5601
5886
|
}
|
|
@@ -5615,7 +5900,7 @@ async function listSessions(limit = 30) {
|
|
|
5615
5900
|
const summaries = [];
|
|
5616
5901
|
for (const name of entries) {
|
|
5617
5902
|
if (!name.endsWith(".json")) continue;
|
|
5618
|
-
const path =
|
|
5903
|
+
const path = join8(dir, name);
|
|
5619
5904
|
try {
|
|
5620
5905
|
const [s, raw] = await Promise.all([stat3(path), readFile7(path, "utf8")]);
|
|
5621
5906
|
const parsed = JSON.parse(raw);
|
|
@@ -5688,13 +5973,13 @@ var init_image = __esm({
|
|
|
5688
5973
|
// src/usage-tracker.ts
|
|
5689
5974
|
import { readFile as readFile9, writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
|
|
5690
5975
|
import { homedir as homedir7 } from "os";
|
|
5691
|
-
import { join as
|
|
5976
|
+
import { join as join9 } from "path";
|
|
5692
5977
|
function usageDir() {
|
|
5693
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
5694
|
-
return
|
|
5978
|
+
const xdg = process.env.XDG_DATA_HOME || join9(homedir7(), ".local", "share");
|
|
5979
|
+
return join9(xdg, "kimiflare");
|
|
5695
5980
|
}
|
|
5696
5981
|
function usagePath() {
|
|
5697
|
-
return
|
|
5982
|
+
return join9(usageDir(), "usage.json");
|
|
5698
5983
|
}
|
|
5699
5984
|
function today() {
|
|
5700
5985
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -5820,7 +6105,7 @@ async function getCostReport(sessionId) {
|
|
|
5820
6105
|
const log = pruneUsageLog(await loadLog());
|
|
5821
6106
|
const date = today();
|
|
5822
6107
|
const currentMonth = date.slice(0, 7);
|
|
5823
|
-
const session = log.sessions.find((s) => s.id === sessionId) ?? { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
|
|
6108
|
+
const session = sessionId ? log.sessions.find((s) => s.id === sessionId) ?? { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 } : { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
|
|
5824
6109
|
const todayUsage = log.days.find((d) => d.date === date) ?? { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
|
|
5825
6110
|
const monthUsage = {
|
|
5826
6111
|
date: currentMonth,
|
|
@@ -5919,7 +6204,7 @@ __export(db_exports, {
|
|
|
5919
6204
|
updateMemoryEmbedding: () => updateMemoryEmbedding
|
|
5920
6205
|
});
|
|
5921
6206
|
import Database from "better-sqlite3";
|
|
5922
|
-
import { dirname as
|
|
6207
|
+
import { dirname as dirname4 } from "path";
|
|
5923
6208
|
import { mkdirSync, statSync as statSync2 } from "fs";
|
|
5924
6209
|
function initSchema(db) {
|
|
5925
6210
|
db.exec(`
|
|
@@ -6000,7 +6285,7 @@ function openMemoryDb(dbPath) {
|
|
|
6000
6285
|
if (dbInstance) {
|
|
6001
6286
|
dbInstance.close();
|
|
6002
6287
|
}
|
|
6003
|
-
mkdirSync(
|
|
6288
|
+
mkdirSync(dirname4(dbPath), { recursive: true });
|
|
6004
6289
|
dbInstance = new Database(dbPath);
|
|
6005
6290
|
dbInstance.pragma("journal_mode = WAL");
|
|
6006
6291
|
dbInstance.pragma("foreign_keys = ON");
|
|
@@ -6872,17 +7157,394 @@ Return only the topic key string.`
|
|
|
6872
7157
|
}
|
|
6873
7158
|
});
|
|
6874
7159
|
|
|
7160
|
+
// src/util/state.ts
|
|
7161
|
+
import { readFile as readFile10, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
|
|
7162
|
+
import { homedir as homedir8 } from "os";
|
|
7163
|
+
import { join as join11 } from "path";
|
|
7164
|
+
function statePath() {
|
|
7165
|
+
const xdg = process.env.XDG_CONFIG_HOME || join11(homedir8(), ".config");
|
|
7166
|
+
return join11(xdg, "kimiflare", "state.json");
|
|
7167
|
+
}
|
|
7168
|
+
async function readState() {
|
|
7169
|
+
try {
|
|
7170
|
+
const raw = await readFile10(statePath(), "utf8");
|
|
7171
|
+
return JSON.parse(raw);
|
|
7172
|
+
} catch {
|
|
7173
|
+
return {};
|
|
7174
|
+
}
|
|
7175
|
+
}
|
|
7176
|
+
async function writeState(state) {
|
|
7177
|
+
const path = statePath();
|
|
7178
|
+
await mkdir7(join11(path, ".."), { recursive: true });
|
|
7179
|
+
await writeFile7(path, JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
7180
|
+
}
|
|
7181
|
+
async function markCreatorMessageSeen(version) {
|
|
7182
|
+
const state = await readState();
|
|
7183
|
+
state.creatorMessageSeenVersion = version;
|
|
7184
|
+
await writeState(state);
|
|
7185
|
+
}
|
|
7186
|
+
async function shouldShowCreatorMessage(version) {
|
|
7187
|
+
const state = await readState();
|
|
7188
|
+
return state.creatorMessageSeenVersion !== version;
|
|
7189
|
+
}
|
|
7190
|
+
var init_state = __esm({
|
|
7191
|
+
"src/util/state.ts"() {
|
|
7192
|
+
"use strict";
|
|
7193
|
+
}
|
|
7194
|
+
});
|
|
7195
|
+
|
|
7196
|
+
// src/commands/frontmatter.ts
|
|
7197
|
+
function parseFrontmatter(input) {
|
|
7198
|
+
const errors = [];
|
|
7199
|
+
if (!FENCE.test(input)) {
|
|
7200
|
+
return { data: {}, body: input, errors };
|
|
7201
|
+
}
|
|
7202
|
+
const afterOpen = input.replace(FENCE, "");
|
|
7203
|
+
const closeIdx = afterOpen.search(/\r?\n---\s*(\r?\n|$)/);
|
|
7204
|
+
if (closeIdx === -1) {
|
|
7205
|
+
errors.push("frontmatter not closed with ---");
|
|
7206
|
+
return { data: {}, body: input, errors };
|
|
7207
|
+
}
|
|
7208
|
+
const yaml = afterOpen.slice(0, closeIdx);
|
|
7209
|
+
const closeMatch = afterOpen.slice(closeIdx).match(/\r?\n---\s*(\r?\n|$)/);
|
|
7210
|
+
const body = closeMatch ? afterOpen.slice(closeIdx + closeMatch[0].length) : "";
|
|
7211
|
+
const data = {};
|
|
7212
|
+
const lines = yaml.split(/\r?\n/);
|
|
7213
|
+
for (const line of lines) {
|
|
7214
|
+
if (line.trim() === "" || line.trim().startsWith("#")) continue;
|
|
7215
|
+
const m = line.match(KV);
|
|
7216
|
+
if (!m) {
|
|
7217
|
+
errors.push(`unparseable line: ${line.trim()}`);
|
|
7218
|
+
continue;
|
|
7219
|
+
}
|
|
7220
|
+
const key = m[1];
|
|
7221
|
+
let value = m[2] ?? "";
|
|
7222
|
+
if (value.startsWith('"') && value.endsWith('"') && value.length >= 2 || value.startsWith("'") && value.endsWith("'") && value.length >= 2) {
|
|
7223
|
+
value = value.slice(1, -1);
|
|
7224
|
+
}
|
|
7225
|
+
data[key] = value;
|
|
7226
|
+
}
|
|
7227
|
+
return { data, body, errors };
|
|
7228
|
+
}
|
|
7229
|
+
var FENCE, KV;
|
|
7230
|
+
var init_frontmatter = __esm({
|
|
7231
|
+
"src/commands/frontmatter.ts"() {
|
|
7232
|
+
"use strict";
|
|
7233
|
+
FENCE = /^---\s*\r?\n/;
|
|
7234
|
+
KV = /^([A-Za-z][\w-]*)\s*:\s*(.*?)\s*$/;
|
|
7235
|
+
}
|
|
7236
|
+
});
|
|
7237
|
+
|
|
7238
|
+
// src/commands/loader.ts
|
|
7239
|
+
import { open, realpath } from "fs/promises";
|
|
7240
|
+
import { homedir as homedir9 } from "os";
|
|
7241
|
+
import { join as join12, relative as relative2, sep as sep2 } from "path";
|
|
7242
|
+
import fg3 from "fast-glob";
|
|
7243
|
+
function projectCommandsDir(cwd = process.cwd()) {
|
|
7244
|
+
return join12(cwd, ".kimiflare", "commands");
|
|
7245
|
+
}
|
|
7246
|
+
function globalCommandsDir() {
|
|
7247
|
+
const xdg = process.env.XDG_CONFIG_HOME || join12(homedir9(), ".config");
|
|
7248
|
+
return join12(xdg, "kimiflare", "commands");
|
|
7249
|
+
}
|
|
7250
|
+
async function loadCustomCommands(cwd = process.cwd()) {
|
|
7251
|
+
const warnings = [];
|
|
7252
|
+
const byName = /* @__PURE__ */ new Map();
|
|
7253
|
+
const sources = [
|
|
7254
|
+
{ dir: globalCommandsDir(), source: "global" },
|
|
7255
|
+
{ dir: projectCommandsDir(cwd), source: "project" }
|
|
7256
|
+
];
|
|
7257
|
+
const perSource = await Promise.all(
|
|
7258
|
+
sources.map(async ({ dir, source }) => {
|
|
7259
|
+
const safeDir = await resolveSafeDir(dir, source, cwd, warnings);
|
|
7260
|
+
if (safeDir === null) return [];
|
|
7261
|
+
const files = await fg3("**/*.md", {
|
|
7262
|
+
cwd: safeDir,
|
|
7263
|
+
absolute: true,
|
|
7264
|
+
onlyFiles: true,
|
|
7265
|
+
followSymbolicLinks: false,
|
|
7266
|
+
suppressErrors: true
|
|
7267
|
+
});
|
|
7268
|
+
return Promise.all(files.map((file) => loadOne(file, safeDir, source, warnings)));
|
|
7269
|
+
})
|
|
7270
|
+
);
|
|
7271
|
+
for (const loaded of perSource) {
|
|
7272
|
+
for (const cmd of loaded) {
|
|
7273
|
+
if (cmd) byName.set(cmd.name, cmd);
|
|
7274
|
+
}
|
|
7275
|
+
}
|
|
7276
|
+
return {
|
|
7277
|
+
commands: [...byName.values()].sort((a, b) => a.name.localeCompare(b.name)),
|
|
7278
|
+
warnings
|
|
7279
|
+
};
|
|
7280
|
+
}
|
|
7281
|
+
async function resolveSafeDir(dir, source, cwd, warnings) {
|
|
7282
|
+
let realDir;
|
|
7283
|
+
try {
|
|
7284
|
+
realDir = await realpath(dir);
|
|
7285
|
+
} catch (err) {
|
|
7286
|
+
const code = err.code;
|
|
7287
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
7288
|
+
warnings.push(`commands dir ${dir} unreadable: ${err.message}`);
|
|
7289
|
+
}
|
|
7290
|
+
return null;
|
|
7291
|
+
}
|
|
7292
|
+
if (source === "project") {
|
|
7293
|
+
let realCwd;
|
|
7294
|
+
try {
|
|
7295
|
+
realCwd = await realpath(cwd);
|
|
7296
|
+
} catch {
|
|
7297
|
+
return null;
|
|
7298
|
+
}
|
|
7299
|
+
const rel = relative2(realCwd, realDir);
|
|
7300
|
+
if (rel !== "" && isPathOutside(rel)) {
|
|
7301
|
+
warnings.push(`commands dir ${dir} escapes workspace via symlink \u2014 skipped`);
|
|
7302
|
+
return null;
|
|
7303
|
+
}
|
|
7304
|
+
}
|
|
7305
|
+
return realDir;
|
|
7306
|
+
}
|
|
7307
|
+
async function loadOne(file, rootDir, source, warnings) {
|
|
7308
|
+
let content;
|
|
7309
|
+
try {
|
|
7310
|
+
const handle = await open(file, "r");
|
|
7311
|
+
try {
|
|
7312
|
+
const stats = await handle.stat();
|
|
7313
|
+
if (stats.size > MAX_COMMAND_FILE_BYTES) {
|
|
7314
|
+
warnings.push(`command file ${file} exceeds ${MAX_COMMAND_FILE_BYTES} bytes \u2014 skipped`);
|
|
7315
|
+
return null;
|
|
7316
|
+
}
|
|
7317
|
+
content = await handle.readFile("utf8");
|
|
7318
|
+
} finally {
|
|
7319
|
+
await handle.close();
|
|
7320
|
+
}
|
|
7321
|
+
} catch (e) {
|
|
7322
|
+
warnings.push(`failed to read command file ${file}: ${e.message}`);
|
|
7323
|
+
return null;
|
|
7324
|
+
}
|
|
7325
|
+
const name = filenameToCommandName(file, rootDir);
|
|
7326
|
+
if (!name) {
|
|
7327
|
+
warnings.push(`invalid command name from ${file}`);
|
|
7328
|
+
return null;
|
|
7329
|
+
}
|
|
7330
|
+
const { data, body, errors } = parseFrontmatter(content);
|
|
7331
|
+
if (errors.length > 0) {
|
|
7332
|
+
warnings.push(`frontmatter errors in ${file}: ${errors.join("; ")} \u2014 skipped`);
|
|
7333
|
+
return null;
|
|
7334
|
+
}
|
|
7335
|
+
const cmd = {
|
|
7336
|
+
name,
|
|
7337
|
+
template: body,
|
|
7338
|
+
source,
|
|
7339
|
+
filepath: file
|
|
7340
|
+
};
|
|
7341
|
+
if (data.description) cmd.description = data.description;
|
|
7342
|
+
const modeRaw = data.mode ?? data.agent;
|
|
7343
|
+
if (modeRaw !== void 0) {
|
|
7344
|
+
const normalized = modeRaw === "build" ? "edit" : modeRaw;
|
|
7345
|
+
if (MODES.includes(normalized)) {
|
|
7346
|
+
cmd.mode = normalized;
|
|
7347
|
+
} else {
|
|
7348
|
+
warnings.push(`unknown mode "${modeRaw}" in ${file} \u2014 ignored`);
|
|
7349
|
+
}
|
|
7350
|
+
}
|
|
7351
|
+
if (data.model !== void 0 && data.model !== "") {
|
|
7352
|
+
cmd.model = data.model;
|
|
7353
|
+
}
|
|
7354
|
+
if (data.effort !== void 0) {
|
|
7355
|
+
if (EFFORTS.includes(data.effort)) {
|
|
7356
|
+
cmd.effort = data.effort;
|
|
7357
|
+
} else {
|
|
7358
|
+
warnings.push(`unknown effort "${data.effort}" in ${file} \u2014 ignored`);
|
|
7359
|
+
}
|
|
7360
|
+
}
|
|
7361
|
+
return cmd;
|
|
7362
|
+
}
|
|
7363
|
+
function filenameToCommandName(file, rootDir) {
|
|
7364
|
+
const rel = relative2(rootDir, file);
|
|
7365
|
+
if (!rel || isPathOutside(rel)) return null;
|
|
7366
|
+
const noExt = rel.replace(/\.md$/i, "");
|
|
7367
|
+
const parts = noExt.split(sep2).filter((p) => p.length > 0);
|
|
7368
|
+
if (parts.length === 0) return null;
|
|
7369
|
+
if (parts.some((p) => !/^[\w.-]+$/.test(p))) return null;
|
|
7370
|
+
return parts.join("/");
|
|
7371
|
+
}
|
|
7372
|
+
var MAX_COMMAND_FILE_BYTES;
|
|
7373
|
+
var init_loader = __esm({
|
|
7374
|
+
"src/commands/loader.ts"() {
|
|
7375
|
+
"use strict";
|
|
7376
|
+
init_mode();
|
|
7377
|
+
init_config();
|
|
7378
|
+
init_paths();
|
|
7379
|
+
init_frontmatter();
|
|
7380
|
+
MAX_COMMAND_FILE_BYTES = 256 * 1024;
|
|
7381
|
+
}
|
|
7382
|
+
});
|
|
7383
|
+
|
|
7384
|
+
// src/commands/renderer.ts
|
|
7385
|
+
import { exec } from "child_process";
|
|
7386
|
+
import { open as open2, realpath as realpath2 } from "fs/promises";
|
|
7387
|
+
import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolvePathJoin } from "path";
|
|
7388
|
+
import { promisify as promisify2 } from "util";
|
|
7389
|
+
function tokenizeArgs(s) {
|
|
7390
|
+
return [...s.matchAll(ARG_TOKEN_RE)].map((match) => {
|
|
7391
|
+
const token = match[0];
|
|
7392
|
+
if (token.length >= 2 && (token.startsWith('"') && token.endsWith('"') || token.startsWith("'") && token.endsWith("'"))) {
|
|
7393
|
+
return token.slice(1, -1);
|
|
7394
|
+
}
|
|
7395
|
+
return token;
|
|
7396
|
+
});
|
|
7397
|
+
}
|
|
7398
|
+
async function renderCommand(cmd, rawInput, opts2 = {}) {
|
|
7399
|
+
const warnings = [];
|
|
7400
|
+
const cwd = opts2.cwd ?? process.cwd();
|
|
7401
|
+
const maxFileBytes = opts2.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
7402
|
+
const argsString = stripCommandName(rawInput);
|
|
7403
|
+
const args = tokenizeArgs(argsString);
|
|
7404
|
+
const originalTemplate = cmd.template;
|
|
7405
|
+
const hadArguments = originalTemplate.includes("$ARGUMENTS");
|
|
7406
|
+
const hadPositionals = HAS_POSITIONAL.test(originalTemplate);
|
|
7407
|
+
let prompt = replacePositionals(originalTemplate, args);
|
|
7408
|
+
prompt = prompt.replaceAll("$ARGUMENTS", argsString);
|
|
7409
|
+
if (!hadArguments && !hadPositionals && argsString !== "") {
|
|
7410
|
+
prompt += `
|
|
7411
|
+
|
|
7412
|
+
${argsString}`;
|
|
7413
|
+
}
|
|
7414
|
+
prompt = await replaceShell(prompt, warnings, opts2.shellTimeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS);
|
|
7415
|
+
prompt = await replaceFiles(prompt, warnings, cwd, maxFileBytes);
|
|
7416
|
+
if (prompt.trim() === "") {
|
|
7417
|
+
warnings.push("rendered prompt is empty");
|
|
7418
|
+
}
|
|
7419
|
+
return { prompt, warnings };
|
|
7420
|
+
}
|
|
7421
|
+
function stripCommandName(rawInput) {
|
|
7422
|
+
if (!rawInput.startsWith("/")) {
|
|
7423
|
+
return rawInput;
|
|
7424
|
+
}
|
|
7425
|
+
return rawInput.replace(/^\/\S+\s*/, "");
|
|
7426
|
+
}
|
|
7427
|
+
function replacePositionals(template, args) {
|
|
7428
|
+
const indexes = [...template.matchAll(POSITIONAL_RE)].map(
|
|
7429
|
+
(match) => Number(match[1])
|
|
7430
|
+
);
|
|
7431
|
+
const highest = indexes.length === 0 ? -1 : Math.max(...indexes);
|
|
7432
|
+
return template.replace(POSITIONAL_RE, (_match, n) => {
|
|
7433
|
+
const index = Number(n);
|
|
7434
|
+
if (index <= 0) {
|
|
7435
|
+
return "";
|
|
7436
|
+
}
|
|
7437
|
+
if (index === highest) {
|
|
7438
|
+
return args.slice(index - 1).join(" ");
|
|
7439
|
+
}
|
|
7440
|
+
return args[index - 1] ?? "";
|
|
7441
|
+
});
|
|
7442
|
+
}
|
|
7443
|
+
async function replaceShell(prompt, warnings, shellTimeoutMs) {
|
|
7444
|
+
const matches = [...prompt.matchAll(SHELL_RE)];
|
|
7445
|
+
const replacements = await Promise.all(
|
|
7446
|
+
matches.map(async (match) => {
|
|
7447
|
+
const command = match[1] ?? "";
|
|
7448
|
+
try {
|
|
7449
|
+
const { stdout } = await execAsync(command, {
|
|
7450
|
+
timeout: shellTimeoutMs,
|
|
7451
|
+
maxBuffer: 1024 * 1024
|
|
7452
|
+
});
|
|
7453
|
+
return String(stdout).trimEnd();
|
|
7454
|
+
} catch (error) {
|
|
7455
|
+
warnings.push(`shell command failed: \`${command}\` \u2014 ${message(error)}`);
|
|
7456
|
+
return "";
|
|
7457
|
+
}
|
|
7458
|
+
})
|
|
7459
|
+
);
|
|
7460
|
+
let index = 0;
|
|
7461
|
+
return prompt.replace(SHELL_RE, () => replacements[index++] ?? "");
|
|
7462
|
+
}
|
|
7463
|
+
async function replaceFiles(prompt, warnings, cwd, maxFileBytes) {
|
|
7464
|
+
const matches = [...prompt.matchAll(FILE_RE)];
|
|
7465
|
+
if (matches.length === 0) return prompt;
|
|
7466
|
+
const realCwd = await realpath2(cwd).catch(() => cwd);
|
|
7467
|
+
const replacements = await Promise.all(
|
|
7468
|
+
matches.map(async (match) => {
|
|
7469
|
+
const rawPath = match[1] ?? "";
|
|
7470
|
+
if (isAbsolute2(rawPath) || rawPath.startsWith("~")) {
|
|
7471
|
+
warnings.push(`file inclusion skipped: @${rawPath} \u2014 outside workspace`);
|
|
7472
|
+
return "";
|
|
7473
|
+
}
|
|
7474
|
+
const resolved = resolvePathJoin(cwd, rawPath);
|
|
7475
|
+
if (isPathOutside(relative3(cwd, resolved))) {
|
|
7476
|
+
warnings.push(`file inclusion skipped: @${rawPath} \u2014 outside workspace`);
|
|
7477
|
+
return "";
|
|
7478
|
+
}
|
|
7479
|
+
let real;
|
|
7480
|
+
try {
|
|
7481
|
+
real = await realpath2(resolved);
|
|
7482
|
+
} catch (error) {
|
|
7483
|
+
warnings.push(`file inclusion failed: @${rawPath} \u2014 ${message(error)}`);
|
|
7484
|
+
return "";
|
|
7485
|
+
}
|
|
7486
|
+
if (isPathOutside(relative3(realCwd, real))) {
|
|
7487
|
+
warnings.push(`file inclusion skipped: @${rawPath} \u2014 symlink escapes workspace`);
|
|
7488
|
+
return "";
|
|
7489
|
+
}
|
|
7490
|
+
try {
|
|
7491
|
+
const handle = await open2(real, "r");
|
|
7492
|
+
try {
|
|
7493
|
+
const stats = await handle.stat();
|
|
7494
|
+
if (stats.size > maxFileBytes) {
|
|
7495
|
+
warnings.push(
|
|
7496
|
+
`file inclusion skipped: @${rawPath} \u2014 exceeds ${maxFileBytes} bytes`
|
|
7497
|
+
);
|
|
7498
|
+
return "";
|
|
7499
|
+
}
|
|
7500
|
+
return await handle.readFile("utf8");
|
|
7501
|
+
} finally {
|
|
7502
|
+
await handle.close();
|
|
7503
|
+
}
|
|
7504
|
+
} catch (error) {
|
|
7505
|
+
warnings.push(`file inclusion failed: @${rawPath} \u2014 ${message(error)}`);
|
|
7506
|
+
return "";
|
|
7507
|
+
}
|
|
7508
|
+
})
|
|
7509
|
+
);
|
|
7510
|
+
let index = 0;
|
|
7511
|
+
return prompt.replace(FILE_RE, (_match, _path, trailing = "") => {
|
|
7512
|
+
const replacement = replacements[index++] ?? "";
|
|
7513
|
+
return replacement + trailing;
|
|
7514
|
+
});
|
|
7515
|
+
}
|
|
7516
|
+
function message(error) {
|
|
7517
|
+
return error instanceof Error ? error.message : String(error);
|
|
7518
|
+
}
|
|
7519
|
+
var execAsync, ARG_TOKEN_RE, POSITIONAL_RE, HAS_POSITIONAL, SHELL_RE, FILE_RE, DEFAULT_MAX_FILE_BYTES, DEFAULT_SHELL_TIMEOUT_MS;
|
|
7520
|
+
var init_renderer = __esm({
|
|
7521
|
+
"src/commands/renderer.ts"() {
|
|
7522
|
+
"use strict";
|
|
7523
|
+
init_paths();
|
|
7524
|
+
execAsync = promisify2(exec);
|
|
7525
|
+
ARG_TOKEN_RE = /(?:"[^"]*"|'[^']*'|[^\s"']+)/g;
|
|
7526
|
+
POSITIONAL_RE = /\$(\d+)/g;
|
|
7527
|
+
HAS_POSITIONAL = /\$\d+/;
|
|
7528
|
+
SHELL_RE = /!`([^`]+)`/g;
|
|
7529
|
+
FILE_RE = /(?<![\w`])@(\.?[^\s`,]+?)([.,;:!?)\]}]*)(?=[\s`,]|$)/g;
|
|
7530
|
+
DEFAULT_MAX_FILE_BYTES = 100 * 1024;
|
|
7531
|
+
DEFAULT_SHELL_TIMEOUT_MS = 5e3;
|
|
7532
|
+
}
|
|
7533
|
+
});
|
|
7534
|
+
|
|
6875
7535
|
// src/app.tsx
|
|
6876
7536
|
var app_exports = {};
|
|
6877
7537
|
__export(app_exports, {
|
|
6878
7538
|
renderApp: () => renderApp
|
|
6879
7539
|
});
|
|
6880
|
-
import { useState as
|
|
6881
|
-
import { Box as
|
|
7540
|
+
import { useState as useState7, useRef as useRef3, useEffect as useEffect4, useCallback } from "react";
|
|
7541
|
+
import { Box as Box13, Text as Text14, useApp, useInput as useInput3, render } from "ink";
|
|
6882
7542
|
import { existsSync } from "fs";
|
|
6883
|
-
import { join as
|
|
7543
|
+
import { join as join13 } from "path";
|
|
6884
7544
|
import { unlink as unlink2 } from "fs/promises";
|
|
6885
|
-
import {
|
|
7545
|
+
import { spawn as spawn2 } from "child_process";
|
|
7546
|
+
import { platform as platform2 } from "os";
|
|
7547
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
6886
7548
|
function gatewayFromConfig(cfg) {
|
|
6887
7549
|
if (!cfg.aiGatewayId) return void 0;
|
|
6888
7550
|
return {
|
|
@@ -6902,10 +7564,34 @@ function gatewayUsageLookupFromConfig(cfg, meta) {
|
|
|
6902
7564
|
meta
|
|
6903
7565
|
};
|
|
6904
7566
|
}
|
|
7567
|
+
function openBrowser(url) {
|
|
7568
|
+
const cmd = platform2() === "darwin" ? "open" : platform2() === "win32" ? "start" : "xdg-open";
|
|
7569
|
+
const child = spawn2(cmd, [url], { detached: true, stdio: "ignore" });
|
|
7570
|
+
child.unref();
|
|
7571
|
+
}
|
|
6905
7572
|
function capEvents(prev) {
|
|
6906
7573
|
if (prev.length <= MAX_EVENTS) return prev;
|
|
6907
7574
|
return prev.slice(prev.length - MAX_EVENTS);
|
|
6908
7575
|
}
|
|
7576
|
+
function compactEventsVisual(prev, keepLastTurns) {
|
|
7577
|
+
let seen = 0;
|
|
7578
|
+
let cutoff = -1;
|
|
7579
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
7580
|
+
if (prev[i].kind === "user") {
|
|
7581
|
+
seen++;
|
|
7582
|
+
if (seen === keepLastTurns + 1) {
|
|
7583
|
+
cutoff = i;
|
|
7584
|
+
break;
|
|
7585
|
+
}
|
|
7586
|
+
}
|
|
7587
|
+
}
|
|
7588
|
+
if (cutoff <= 0) return prev;
|
|
7589
|
+
const kept = prev.slice(cutoff);
|
|
7590
|
+
return [
|
|
7591
|
+
{ kind: "info", key: mkKey(), text: `\xB7\xB7\xB7 ${cutoff} earlier messages compacted \xB7\xB7\xB7` },
|
|
7592
|
+
...kept
|
|
7593
|
+
];
|
|
7594
|
+
}
|
|
6909
7595
|
function makePrefixMessages(cacheStable, model, mode, tools) {
|
|
6910
7596
|
if (cacheStable) {
|
|
6911
7597
|
return buildSystemMessages({ cwd: process.cwd(), tools, model, mode });
|
|
@@ -6929,8 +7615,8 @@ function findImagePaths(text) {
|
|
|
6929
7615
|
}
|
|
6930
7616
|
function App({ initialCfg, initialUpdateResult }) {
|
|
6931
7617
|
const { exit } = useApp();
|
|
6932
|
-
const [cfg, setCfg] =
|
|
6933
|
-
const [events, setRawEvents] =
|
|
7618
|
+
const [cfg, setCfg] = useState7(initialCfg);
|
|
7619
|
+
const [events, setRawEvents] = useState7([]);
|
|
6934
7620
|
const setEvents = useCallback(
|
|
6935
7621
|
(updater) => {
|
|
6936
7622
|
setRawEvents((prev) => {
|
|
@@ -6940,33 +7626,34 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
6940
7626
|
},
|
|
6941
7627
|
[]
|
|
6942
7628
|
);
|
|
6943
|
-
const [input, setInput] =
|
|
6944
|
-
const [busy, setBusy] =
|
|
6945
|
-
const [usage, setUsage] =
|
|
6946
|
-
const [sessionUsage, setSessionUsage] =
|
|
6947
|
-
const [gatewayMeta, setGatewayMeta] =
|
|
6948
|
-
const [showReasoning, setShowReasoning] =
|
|
6949
|
-
const [perm, setPerm] =
|
|
6950
|
-
const [queue, setQueue] =
|
|
6951
|
-
const [history, setHistory] =
|
|
6952
|
-
const [historyIndex, setHistoryIndex] =
|
|
6953
|
-
const [draftInput, setDraftInput] =
|
|
6954
|
-
const [mode, setMode] =
|
|
6955
|
-
const [codeMode, setCodeMode] =
|
|
6956
|
-
const [effort, setEffort] =
|
|
7629
|
+
const [input, setInput] = useState7("");
|
|
7630
|
+
const [busy, setBusy] = useState7(false);
|
|
7631
|
+
const [usage, setUsage] = useState7(null);
|
|
7632
|
+
const [sessionUsage, setSessionUsage] = useState7(null);
|
|
7633
|
+
const [gatewayMeta, setGatewayMeta] = useState7(null);
|
|
7634
|
+
const [showReasoning, setShowReasoning] = useState7(false);
|
|
7635
|
+
const [perm, setPerm] = useState7(null);
|
|
7636
|
+
const [queue, setQueue] = useState7([]);
|
|
7637
|
+
const [history, setHistory] = useState7([]);
|
|
7638
|
+
const [historyIndex, setHistoryIndex] = useState7(-1);
|
|
7639
|
+
const [draftInput, setDraftInput] = useState7("");
|
|
7640
|
+
const [mode, setMode] = useState7("edit");
|
|
7641
|
+
const [codeMode, setCodeMode] = useState7(initialCfg?.codeMode ?? false);
|
|
7642
|
+
const [effort, setEffort] = useState7(
|
|
6957
7643
|
initialCfg?.reasoningEffort ?? DEFAULT_REASONING_EFFORT
|
|
6958
7644
|
);
|
|
6959
|
-
const [theme, setTheme] =
|
|
6960
|
-
const [resumeSessions, setResumeSessions] =
|
|
6961
|
-
const [showThemePicker, setShowThemePicker] =
|
|
6962
|
-
const [
|
|
6963
|
-
const [
|
|
6964
|
-
const [
|
|
6965
|
-
const [
|
|
6966
|
-
const [
|
|
6967
|
-
const [
|
|
6968
|
-
const [
|
|
6969
|
-
const [
|
|
7645
|
+
const [theme, setTheme] = useState7(resolveTheme(initialCfg?.theme));
|
|
7646
|
+
const [resumeSessions, setResumeSessions] = useState7(null);
|
|
7647
|
+
const [showThemePicker, setShowThemePicker] = useState7(false);
|
|
7648
|
+
const [showHelpMenu, setShowHelpMenu] = useState7(false);
|
|
7649
|
+
const [originalTheme, setOriginalTheme] = useState7(null);
|
|
7650
|
+
const [tasks, setTasks] = useState7([]);
|
|
7651
|
+
const [tasksStartedAt, setTasksStartedAt] = useState7(null);
|
|
7652
|
+
const [tasksStartTokens, setTasksStartTokens] = useState7(0);
|
|
7653
|
+
const [turnStartedAt, setTurnStartedAt] = useState7(null);
|
|
7654
|
+
const [verbose, setVerbose] = useState7(false);
|
|
7655
|
+
const [hasUpdate, setHasUpdate] = useState7(initialUpdateResult?.hasUpdate ?? false);
|
|
7656
|
+
const [latestVersion, setLatestVersion] = useState7(initialUpdateResult?.latestVersion ?? null);
|
|
6970
7657
|
const cacheStableRef = useRef3(initialCfg?.cacheStablePrompts !== false);
|
|
6971
7658
|
const messagesRef = useRef3(
|
|
6972
7659
|
makePrefixMessages(cacheStableRef.current, cfg?.model ?? DEFAULT_MODEL, "edit", ALL_TOOLS)
|
|
@@ -6992,6 +7679,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
6992
7679
|
const memoryManagerRef = useRef3(null);
|
|
6993
7680
|
const pendingTextRef = useRef3(/* @__PURE__ */ new Map());
|
|
6994
7681
|
const flushTimeoutRef = useRef3(null);
|
|
7682
|
+
const customCommandsRef = useRef3([]);
|
|
6995
7683
|
useEffect4(() => {
|
|
6996
7684
|
if (!cfg) return;
|
|
6997
7685
|
void Promise.resolve().then(() => (init_sessions(), sessions_exports)).then(
|
|
@@ -7004,8 +7692,21 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7004
7692
|
}
|
|
7005
7693
|
})
|
|
7006
7694
|
);
|
|
7695
|
+
void shouldShowCreatorMessage(getAppVersion()).then((shouldShow) => {
|
|
7696
|
+
if (shouldShow) {
|
|
7697
|
+
setEvents((e) => [
|
|
7698
|
+
...e,
|
|
7699
|
+
{
|
|
7700
|
+
kind: "info",
|
|
7701
|
+
key: mkKey(),
|
|
7702
|
+
text: "Hey, how do you like this version? I'd love to hear from you \u2014 type /hello to send me a voice note. Only I see it, and I may DM you back."
|
|
7703
|
+
}
|
|
7704
|
+
]);
|
|
7705
|
+
void markCreatorMessageSeen(getAppVersion());
|
|
7706
|
+
}
|
|
7707
|
+
});
|
|
7007
7708
|
if (cfg.memoryEnabled) {
|
|
7008
|
-
const dbPath = cfg.memoryDbPath ??
|
|
7709
|
+
const dbPath = cfg.memoryDbPath ?? join13(process.cwd(), ".kimiflare", "memory.db");
|
|
7009
7710
|
const manager = new MemoryManager({
|
|
7010
7711
|
dbPath,
|
|
7011
7712
|
accountId: cfg.accountId,
|
|
@@ -7039,7 +7740,20 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7039
7740
|
memoryManagerRef.current?.close();
|
|
7040
7741
|
memoryManagerRef.current = null;
|
|
7041
7742
|
}
|
|
7042
|
-
|
|
7743
|
+
void loadCustomCommands(process.cwd()).then(({ commands, warnings }) => {
|
|
7744
|
+
customCommandsRef.current = commands;
|
|
7745
|
+
for (const w of warnings) {
|
|
7746
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: `commands: ${w}` }]);
|
|
7747
|
+
}
|
|
7748
|
+
const shadowed = commands.filter((c) => BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase()));
|
|
7749
|
+
for (const c of shadowed) {
|
|
7750
|
+
setEvents((e) => [
|
|
7751
|
+
...e,
|
|
7752
|
+
{ kind: "info", key: mkKey(), text: `commands: /${c.name} (${c.filepath}) shadowed by built-in \u2014 will not run` }
|
|
7753
|
+
]);
|
|
7754
|
+
}
|
|
7755
|
+
});
|
|
7756
|
+
}, [cfg, setEvents]);
|
|
7043
7757
|
useEffect4(() => {
|
|
7044
7758
|
if (!cfg || updateCheckedRef.current) return;
|
|
7045
7759
|
updateCheckedRef.current = true;
|
|
@@ -7247,7 +7961,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7247
7961
|
} catch {
|
|
7248
7962
|
}
|
|
7249
7963
|
}, [cfg, ensureSessionId]);
|
|
7250
|
-
|
|
7964
|
+
useInput3((inputChar, key) => {
|
|
7251
7965
|
if (key.ctrl && inputChar === "c") {
|
|
7252
7966
|
if (busy && activeControllerRef.current) {
|
|
7253
7967
|
activeControllerRef.current.abort();
|
|
@@ -7366,14 +8080,19 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7366
8080
|
} else {
|
|
7367
8081
|
messagesRef.current = result.newMessages;
|
|
7368
8082
|
sessionStateRef.current = result.newState;
|
|
7369
|
-
setEvents(
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
8083
|
+
setEvents(
|
|
8084
|
+
(e) => compactEventsVisual(
|
|
8085
|
+
[
|
|
8086
|
+
...e,
|
|
8087
|
+
{
|
|
8088
|
+
kind: "info",
|
|
8089
|
+
key: mkKey(),
|
|
8090
|
+
text: `compacted ${result.metrics.rawTurnsRemoved} turns \u2192 ${result.metrics.estimatedTokensBefore} \u2192 ${result.metrics.estimatedTokensAfter} tokens, ${result.metrics.archivedArtifacts} artifacts`
|
|
8091
|
+
}
|
|
8092
|
+
],
|
|
8093
|
+
4
|
|
8094
|
+
)
|
|
8095
|
+
);
|
|
7377
8096
|
await saveSessionSafe();
|
|
7378
8097
|
}
|
|
7379
8098
|
} else {
|
|
@@ -7392,14 +8111,19 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7392
8111
|
]);
|
|
7393
8112
|
} else {
|
|
7394
8113
|
messagesRef.current = result.newMessages;
|
|
7395
|
-
setEvents(
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
8114
|
+
setEvents(
|
|
8115
|
+
(e) => compactEventsVisual(
|
|
8116
|
+
[
|
|
8117
|
+
...e,
|
|
8118
|
+
{
|
|
8119
|
+
kind: "info",
|
|
8120
|
+
key: mkKey(),
|
|
8121
|
+
text: `compacted ${result.replacedCount} messages into a summary`
|
|
8122
|
+
}
|
|
8123
|
+
],
|
|
8124
|
+
4
|
|
8125
|
+
)
|
|
8126
|
+
);
|
|
7403
8127
|
await saveSessionSafe();
|
|
7404
8128
|
}
|
|
7405
8129
|
}
|
|
@@ -7428,13 +8152,13 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7428
8152
|
}
|
|
7429
8153
|
const cwd = process.cwd();
|
|
7430
8154
|
for (const name of ["KIMI.md", "KIMIFLARE.md", "AGENT.md"]) {
|
|
7431
|
-
if (existsSync(
|
|
8155
|
+
if (existsSync(join13(cwd, name))) {
|
|
7432
8156
|
setEvents((e) => [
|
|
7433
8157
|
...e,
|
|
7434
8158
|
{
|
|
7435
8159
|
kind: "info",
|
|
7436
8160
|
key: mkKey(),
|
|
7437
|
-
text: `${name} already exists at ${
|
|
8161
|
+
text: `${name} already exists at ${join13(cwd, name)} \u2014 delete it first if you want to regenerate`
|
|
7438
8162
|
}
|
|
7439
8163
|
]);
|
|
7440
8164
|
return;
|
|
@@ -7543,6 +8267,10 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7543
8267
|
resolve2("allow");
|
|
7544
8268
|
return;
|
|
7545
8269
|
}
|
|
8270
|
+
if (req.tool.name === "bash") {
|
|
8271
|
+
setPerm({ tool: req.tool, args: req.args, resolve: resolve2 });
|
|
8272
|
+
return;
|
|
8273
|
+
}
|
|
7546
8274
|
setEvents((e) => [
|
|
7547
8275
|
...e,
|
|
7548
8276
|
{
|
|
@@ -7558,7 +8286,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7558
8286
|
})
|
|
7559
8287
|
}
|
|
7560
8288
|
});
|
|
7561
|
-
if (existsSync(
|
|
8289
|
+
if (existsSync(join13(cwd, "KIMI.md"))) {
|
|
7562
8290
|
if (cacheStableRef.current) {
|
|
7563
8291
|
messagesRef.current[1] = {
|
|
7564
8292
|
role: "system",
|
|
@@ -7704,15 +8432,16 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7704
8432
|
return true;
|
|
7705
8433
|
}
|
|
7706
8434
|
if (c === "/cost") {
|
|
7707
|
-
|
|
7708
|
-
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "no usage recorded yet" }]);
|
|
7709
|
-
return true;
|
|
7710
|
-
}
|
|
7711
|
-
void getCostReport(sessionIdRef.current).then((report) => {
|
|
8435
|
+
void getCostReport(sessionIdRef.current ?? void 0).then((report) => {
|
|
7712
8436
|
setEvents((e) => [
|
|
7713
8437
|
...e,
|
|
7714
8438
|
{ kind: "info", key: mkKey(), text: formatCostReport(report) }
|
|
7715
8439
|
]);
|
|
8440
|
+
}).catch((err) => {
|
|
8441
|
+
setEvents((e) => [
|
|
8442
|
+
...e,
|
|
8443
|
+
{ kind: "error", key: mkKey(), text: `cost report failed: ${err.message}` }
|
|
8444
|
+
]);
|
|
7716
8445
|
});
|
|
7717
8446
|
return true;
|
|
7718
8447
|
}
|
|
@@ -7921,8 +8650,25 @@ use: /thinking low | medium | high`
|
|
|
7921
8650
|
return true;
|
|
7922
8651
|
}
|
|
7923
8652
|
if (c === "/memory") {
|
|
7924
|
-
if (!cfg
|
|
7925
|
-
|
|
8653
|
+
if (!cfg) return true;
|
|
8654
|
+
if (arg === "on") {
|
|
8655
|
+
const next = { ...cfg, memoryEnabled: true };
|
|
8656
|
+
setCfg(next);
|
|
8657
|
+
void saveConfig(next).catch(() => {
|
|
8658
|
+
});
|
|
8659
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "memory enabled" }]);
|
|
8660
|
+
return true;
|
|
8661
|
+
}
|
|
8662
|
+
if (arg === "off") {
|
|
8663
|
+
const next = { ...cfg, memoryEnabled: false };
|
|
8664
|
+
setCfg(next);
|
|
8665
|
+
void saveConfig(next).catch(() => {
|
|
8666
|
+
});
|
|
8667
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "memory disabled" }]);
|
|
8668
|
+
return true;
|
|
8669
|
+
}
|
|
8670
|
+
if (!cfg.memoryEnabled) {
|
|
8671
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "memory is disabled. Use /memory on to enable it, or set KIMIFLARE_MEMORY_ENABLED=1" }]);
|
|
7926
8672
|
return true;
|
|
7927
8673
|
}
|
|
7928
8674
|
if (arg === "clear") {
|
|
@@ -7962,19 +8708,6 @@ ${lines.join("\n")}` }]);
|
|
|
7962
8708
|
}
|
|
7963
8709
|
return true;
|
|
7964
8710
|
}
|
|
7965
|
-
if (c === "/cost") {
|
|
7966
|
-
if (!sessionIdRef.current) {
|
|
7967
|
-
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "no usage recorded yet" }]);
|
|
7968
|
-
return true;
|
|
7969
|
-
}
|
|
7970
|
-
void getCostReport(sessionIdRef.current).then((report) => {
|
|
7971
|
-
setEvents((e) => [
|
|
7972
|
-
...e,
|
|
7973
|
-
{ kind: "info", key: mkKey(), text: formatCostReport(report) }
|
|
7974
|
-
]);
|
|
7975
|
-
});
|
|
7976
|
-
return true;
|
|
7977
|
-
}
|
|
7978
8711
|
if (c === "/resume") {
|
|
7979
8712
|
void openResumePicker();
|
|
7980
8713
|
return true;
|
|
@@ -8056,6 +8789,24 @@ ${lines.join("\n")}` }]);
|
|
|
8056
8789
|
]);
|
|
8057
8790
|
return true;
|
|
8058
8791
|
}
|
|
8792
|
+
if (c === "/hello") {
|
|
8793
|
+
const session = crypto.randomUUID();
|
|
8794
|
+
const url = `${FEEDBACK_WORKER_URL}/?s=${session}&v=${getAppVersion()}`;
|
|
8795
|
+
openBrowser(url);
|
|
8796
|
+
setEvents((e) => [
|
|
8797
|
+
...e,
|
|
8798
|
+
{ kind: "info", key: mkKey(), text: "Opened voice note page in your browser. Record your message there and hit Send when you're done." }
|
|
8799
|
+
]);
|
|
8800
|
+
return true;
|
|
8801
|
+
}
|
|
8802
|
+
if (c === "/community") {
|
|
8803
|
+
openBrowser("https://discord.gg/aEuAUHNTK5");
|
|
8804
|
+
setEvents((e) => [
|
|
8805
|
+
...e,
|
|
8806
|
+
{ kind: "info", key: mkKey(), text: "Opened Discord invite in your browser." }
|
|
8807
|
+
]);
|
|
8808
|
+
return true;
|
|
8809
|
+
}
|
|
8059
8810
|
if (c === "/logout") {
|
|
8060
8811
|
unlink2(configPath()).catch(() => {
|
|
8061
8812
|
});
|
|
@@ -8067,27 +8818,57 @@ ${lines.join("\n")}` }]);
|
|
|
8067
8818
|
return true;
|
|
8068
8819
|
}
|
|
8069
8820
|
if (c === "/help") {
|
|
8070
|
-
|
|
8071
|
-
...e,
|
|
8072
|
-
{
|
|
8073
|
-
kind: "info",
|
|
8074
|
-
key: mkKey(),
|
|
8075
|
-
text: "commands:\n /mode edit|plan|auto switch mode (or shift+tab to cycle)\n /plan /auto /edit shortcuts for /mode\n /thinking low|med|high set reasoning effort (quality vs speed)\n /theme interactive theme picker (or ctrl+t)\n /theme NAME set theme by name\n /resume pick a past conversation\n /compact summarize old turns to free context\n /init scan this repo and write a KIMI.md for future agents\n /memory show memory stats\n /memory search <query> search stored memories\n /memory clear wipe memories for this repo\n /mcp list list connected MCP servers and tools\n /mcp reload reconnect all configured MCP servers\n /reasoning toggle show/hide model reasoning\n /clear clear current conversation\n /gateway show gateway status\n /gateway ID enable AI Gateway\n /gateway off disable AI Gateway (direct Workers AI)\n /gateway cache-ttl N set gateway cache TTL in seconds\n /gateway skip-cache T|F set gateway skip-cache flag\n /gateway collect-logs T|F include payload in gateway logs\n /gateway metadata K=V add metadata key-value pair\n /gateway metadata clear remove all metadata\n /cost /model /update /logout /help /exit\nkeys: ctrl-c interrupt/exit \xB7 ctrl-r toggle reasoning \xB7 ctrl-o verbose \xB7 ctrl+t theme \xB7 shift+tab cycle mode \xB7 \u2191/\u2193 history"
|
|
8076
|
-
}
|
|
8077
|
-
]);
|
|
8821
|
+
setShowHelpMenu(true);
|
|
8078
8822
|
return true;
|
|
8079
8823
|
}
|
|
8080
8824
|
return false;
|
|
8081
8825
|
},
|
|
8082
8826
|
[cfg, exit, usage, effort, theme, mode, openResumePicker, runCompact, runInit, initMcp, setCfg]
|
|
8083
8827
|
);
|
|
8828
|
+
const handleHelpCommand = useCallback(
|
|
8829
|
+
(command) => {
|
|
8830
|
+
setShowHelpMenu(false);
|
|
8831
|
+
const executed = handleSlash(command);
|
|
8832
|
+
if (!executed) {
|
|
8833
|
+
setEvents((e) => [...e, { kind: "error", key: mkKey(), text: `unknown command: ${command}` }]);
|
|
8834
|
+
}
|
|
8835
|
+
},
|
|
8836
|
+
[handleSlash]
|
|
8837
|
+
);
|
|
8084
8838
|
const processMessage = useCallback(
|
|
8085
8839
|
async (text, displayText) => {
|
|
8086
8840
|
if (!cfg) return;
|
|
8087
|
-
|
|
8841
|
+
let trimmed = text.trim();
|
|
8088
8842
|
if (!trimmed) return;
|
|
8089
|
-
|
|
8090
|
-
|
|
8843
|
+
let overrideModel;
|
|
8844
|
+
let overrideEffort;
|
|
8845
|
+
let display = displayText?.trim() || trimmed;
|
|
8846
|
+
if (trimmed.startsWith("/")) {
|
|
8847
|
+
if (handleSlash(trimmed)) return;
|
|
8848
|
+
const head = trimmed.split(/\s+/)[0].slice(1);
|
|
8849
|
+
const custom = customCommandsRef.current.find((c) => c.name === head);
|
|
8850
|
+
if (custom) {
|
|
8851
|
+
const info = (text2) => setEvents((e) => [...e, { kind: "info", key: mkKey(), text: text2 }]);
|
|
8852
|
+
const { prompt: rendered, warnings } = await renderCommand(custom, trimmed, {
|
|
8853
|
+
cwd: process.cwd()
|
|
8854
|
+
});
|
|
8855
|
+
for (const w of warnings) info(`${custom.name}: ${w}`);
|
|
8856
|
+
if (!rendered.trim()) return;
|
|
8857
|
+
const parts = [];
|
|
8858
|
+
if (custom.model) {
|
|
8859
|
+
overrideModel = custom.model;
|
|
8860
|
+
parts.push(`model=${custom.model}`);
|
|
8861
|
+
}
|
|
8862
|
+
if (custom.effort) {
|
|
8863
|
+
overrideEffort = custom.effort;
|
|
8864
|
+
parts.push(`effort=${custom.effort}`);
|
|
8865
|
+
}
|
|
8866
|
+
if (parts.length > 0) info(`command '${custom.name}' \u2192 ${parts.join(", ")} (this turn)`);
|
|
8867
|
+
if (custom.mode) info(`note: mode override (${custom.mode}) is not yet wired; current mode applies`);
|
|
8868
|
+
display = trimmed;
|
|
8869
|
+
trimmed = rendered;
|
|
8870
|
+
}
|
|
8871
|
+
}
|
|
8091
8872
|
const imagePaths = findImagePaths(trimmed).slice(0, MAX_IMAGES_PER_MESSAGE);
|
|
8092
8873
|
let images = [];
|
|
8093
8874
|
let content = sanitizeString(trimmed);
|
|
@@ -8139,14 +8920,14 @@ ${lines.join("\n")}` }]);
|
|
|
8139
8920
|
await runAgentTurn({
|
|
8140
8921
|
accountId: cfg.accountId,
|
|
8141
8922
|
apiToken: cfg.apiToken,
|
|
8142
|
-
model: cfg.model,
|
|
8923
|
+
model: overrideModel ?? cfg.model,
|
|
8143
8924
|
gateway: gatewayFromConfig(cfg),
|
|
8144
8925
|
messages: messagesRef.current,
|
|
8145
8926
|
tools: [...ALL_TOOLS, ...mcpToolsRef.current],
|
|
8146
8927
|
executor: executorRef.current,
|
|
8147
8928
|
cwd: process.cwd(),
|
|
8148
8929
|
signal: controller.signal,
|
|
8149
|
-
reasoningEffort: effortRef.current,
|
|
8930
|
+
reasoningEffort: overrideEffort ?? effortRef.current,
|
|
8150
8931
|
coauthor: cfg.coauthor !== false ? { name: cfg.coauthorName || "kimiflare", email: cfg.coauthorEmail || "kimiflare@proton.me" } : void 0,
|
|
8151
8932
|
sessionId: ensureSessionId(),
|
|
8152
8933
|
memoryManager: memoryManagerRef.current,
|
|
@@ -8208,6 +8989,7 @@ ${lines.join("\n")}` }]);
|
|
|
8208
8989
|
onUsageFinal: (u, meta) => {
|
|
8209
8990
|
const sid = ensureSessionId();
|
|
8210
8991
|
void recordUsage(sid, u, gatewayUsageLookupFromConfig(cfg, meta ?? gatewayMetaRef.current));
|
|
8992
|
+
void getCostReport(sid).then((report) => setSessionUsage(report.session));
|
|
8211
8993
|
},
|
|
8212
8994
|
onGatewayMeta: updateGatewayMeta,
|
|
8213
8995
|
onTasks: (nextTasks) => {
|
|
@@ -8250,24 +9032,60 @@ ${lines.join("\n")}` }]);
|
|
|
8250
9032
|
}
|
|
8251
9033
|
});
|
|
8252
9034
|
await saveSessionSafe();
|
|
8253
|
-
if (
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
9035
|
+
if (shouldCompact({ messages: messagesRef.current })) {
|
|
9036
|
+
if (compiledContextRef.current) {
|
|
9037
|
+
const result = compactMessages2({
|
|
9038
|
+
messages: messagesRef.current,
|
|
9039
|
+
state: sessionStateRef.current,
|
|
9040
|
+
store: artifactStoreRef.current
|
|
9041
|
+
});
|
|
9042
|
+
if (result.metrics.rawTurnsRemoved > 0) {
|
|
9043
|
+
messagesRef.current = result.newMessages;
|
|
9044
|
+
sessionStateRef.current = result.newState;
|
|
9045
|
+
setEvents((e) => [
|
|
9046
|
+
...e,
|
|
9047
|
+
{
|
|
9048
|
+
kind: "info",
|
|
9049
|
+
key: mkKey(),
|
|
9050
|
+
text: `auto-compacted: ${result.metrics.estimatedTokensBefore} \u2192 ${result.metrics.estimatedTokensAfter} tokens (${result.metrics.archivedArtifacts} artifacts)`
|
|
9051
|
+
}
|
|
9052
|
+
]);
|
|
9053
|
+
await saveSessionSafe();
|
|
9054
|
+
}
|
|
9055
|
+
} else {
|
|
9056
|
+
try {
|
|
9057
|
+
const result = await compactMessages({
|
|
9058
|
+
accountId: cfg.accountId,
|
|
9059
|
+
apiToken: cfg.apiToken,
|
|
9060
|
+
model: cfg.model,
|
|
9061
|
+
messages: messagesRef.current,
|
|
9062
|
+
signal: controller.signal,
|
|
9063
|
+
gateway: gatewayFromConfig(cfg)
|
|
9064
|
+
});
|
|
9065
|
+
if (result.replacedCount > 0) {
|
|
9066
|
+
messagesRef.current = result.newMessages;
|
|
9067
|
+
setEvents((e) => [
|
|
9068
|
+
...e,
|
|
9069
|
+
{
|
|
9070
|
+
kind: "info",
|
|
9071
|
+
key: mkKey(),
|
|
9072
|
+
text: `auto-compacted: ${result.replacedCount} messages summarized`
|
|
9073
|
+
}
|
|
9074
|
+
]);
|
|
9075
|
+
await saveSessionSafe();
|
|
8268
9076
|
}
|
|
8269
|
-
|
|
8270
|
-
|
|
9077
|
+
} catch (compactErr) {
|
|
9078
|
+
if (compactErr.name !== "AbortError") {
|
|
9079
|
+
setEvents((es) => [
|
|
9080
|
+
...es,
|
|
9081
|
+
{
|
|
9082
|
+
kind: "info",
|
|
9083
|
+
key: mkKey(),
|
|
9084
|
+
text: `auto-compact failed: ${compactErr.message ?? String(compactErr)}`
|
|
9085
|
+
}
|
|
9086
|
+
]);
|
|
9087
|
+
}
|
|
9088
|
+
}
|
|
8271
9089
|
}
|
|
8272
9090
|
}
|
|
8273
9091
|
} catch (e) {
|
|
@@ -8343,7 +9161,7 @@ ${lines.join("\n")}` }]);
|
|
|
8343
9161
|
}
|
|
8344
9162
|
}, [usage]);
|
|
8345
9163
|
if (!cfg) {
|
|
8346
|
-
return /* @__PURE__ */
|
|
9164
|
+
return /* @__PURE__ */ jsx14(
|
|
8347
9165
|
Onboarding,
|
|
8348
9166
|
{
|
|
8349
9167
|
onDone: (newCfg) => {
|
|
@@ -8357,15 +9175,28 @@ ${lines.join("\n")}` }]);
|
|
|
8357
9175
|
);
|
|
8358
9176
|
}
|
|
8359
9177
|
if (resumeSessions !== null) {
|
|
8360
|
-
return /* @__PURE__ */
|
|
9178
|
+
return /* @__PURE__ */ jsx14(Box13, { flexDirection: "column", children: /* @__PURE__ */ jsx14(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick, theme }) });
|
|
8361
9179
|
}
|
|
8362
9180
|
if (showThemePicker) {
|
|
8363
|
-
return /* @__PURE__ */
|
|
9181
|
+
return /* @__PURE__ */ jsx14(Box13, { flexDirection: "column", children: /* @__PURE__ */ jsx14(ThemePicker, { themes: themeList(), current: theme, onPick: handleThemePick, onPreview: (t) => setTheme(t) }) });
|
|
9182
|
+
}
|
|
9183
|
+
if (showHelpMenu) {
|
|
9184
|
+
return /* @__PURE__ */ jsx14(Box13, { flexDirection: "column", children: /* @__PURE__ */ jsx14(
|
|
9185
|
+
HelpMenu,
|
|
9186
|
+
{
|
|
9187
|
+
theme,
|
|
9188
|
+
themes: themeList().map((t) => ({ name: t.name, label: t.label })),
|
|
9189
|
+
currentThemeName: theme.name,
|
|
9190
|
+
customCommands: customCommandsRef.current.filter((c) => !BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase())).map((c) => ({ name: c.name, description: c.description })),
|
|
9191
|
+
onDone: () => setShowHelpMenu(false),
|
|
9192
|
+
onCommand: handleHelpCommand
|
|
9193
|
+
}
|
|
9194
|
+
) });
|
|
8364
9195
|
}
|
|
8365
9196
|
const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
|
|
8366
|
-
return /* @__PURE__ */
|
|
8367
|
-
!hasConversation && events.length === 0 ? /* @__PURE__ */
|
|
8368
|
-
perm ? /* @__PURE__ */
|
|
9197
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
9198
|
+
!hasConversation && events.length === 0 ? /* @__PURE__ */ jsx14(Welcome, { theme, accountId: cfg.accountId }) : /* @__PURE__ */ jsx14(ChatView, { events, showReasoning, theme, verbose }),
|
|
9199
|
+
perm ? /* @__PURE__ */ jsx14(
|
|
8369
9200
|
PermissionModal,
|
|
8370
9201
|
{
|
|
8371
9202
|
tool: perm.tool,
|
|
@@ -8376,8 +9207,8 @@ ${lines.join("\n")}` }]);
|
|
|
8376
9207
|
setPerm(null);
|
|
8377
9208
|
}
|
|
8378
9209
|
}
|
|
8379
|
-
) : /* @__PURE__ */
|
|
8380
|
-
tasks.length > 0 && /* @__PURE__ */
|
|
9210
|
+
) : /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginTop: 1, children: [
|
|
9211
|
+
tasks.length > 0 && /* @__PURE__ */ jsx14(
|
|
8381
9212
|
TaskList,
|
|
8382
9213
|
{
|
|
8383
9214
|
tasks,
|
|
@@ -8386,11 +9217,11 @@ ${lines.join("\n")}` }]);
|
|
|
8386
9217
|
tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
|
|
8387
9218
|
}
|
|
8388
9219
|
),
|
|
8389
|
-
queue.length > 0 && /* @__PURE__ */
|
|
9220
|
+
queue.length > 0 && /* @__PURE__ */ jsx14(Box13, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs13(Text14, { color: theme.queue.color, dimColor: theme.queue.dim, children: [
|
|
8390
9221
|
"\u23F3 ",
|
|
8391
9222
|
q.display
|
|
8392
9223
|
] }, `queue_${i}`)) }),
|
|
8393
|
-
/* @__PURE__ */
|
|
9224
|
+
/* @__PURE__ */ jsx14(
|
|
8394
9225
|
StatusBar,
|
|
8395
9226
|
{
|
|
8396
9227
|
model: cfg.model,
|
|
@@ -8408,9 +9239,9 @@ ${lines.join("\n")}` }]);
|
|
|
8408
9239
|
codeMode
|
|
8409
9240
|
}
|
|
8410
9241
|
),
|
|
8411
|
-
/* @__PURE__ */
|
|
8412
|
-
/* @__PURE__ */
|
|
8413
|
-
/* @__PURE__ */
|
|
9242
|
+
/* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
|
|
9243
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.accent, children: "\u203A " }),
|
|
9244
|
+
/* @__PURE__ */ jsx14(
|
|
8414
9245
|
CustomTextInput,
|
|
8415
9246
|
{
|
|
8416
9247
|
value: input,
|
|
@@ -8459,12 +9290,12 @@ ${lines.join("\n")}` }]);
|
|
|
8459
9290
|
] });
|
|
8460
9291
|
}
|
|
8461
9292
|
async function renderApp(cfg, updateResult) {
|
|
8462
|
-
const instance = render(/* @__PURE__ */
|
|
9293
|
+
const instance = render(/* @__PURE__ */ jsx14(App, { initialCfg: cfg, initialUpdateResult: updateResult }), {
|
|
8463
9294
|
incrementalRendering: true
|
|
8464
9295
|
});
|
|
8465
9296
|
await instance.waitUntilExit();
|
|
8466
9297
|
}
|
|
8467
|
-
var CONTEXT_LIMIT, AUTO_COMPACT_SUGGEST_PCT, MAX_EVENTS, nextAssistantId, nextKey, mkKey, MAX_IMAGES_PER_MESSAGE, EFFORT_DESCRIPTIONS;
|
|
9298
|
+
var FEEDBACK_WORKER_URL, CONTEXT_LIMIT, AUTO_COMPACT_SUGGEST_PCT, MAX_EVENTS, nextAssistantId, nextKey, mkKey, MAX_IMAGES_PER_MESSAGE, BUILTIN_COMMAND_NAMES, EFFORT_DESCRIPTIONS;
|
|
8468
9299
|
var init_app = __esm({
|
|
8469
9300
|
"src/app.tsx"() {
|
|
8470
9301
|
"use strict";
|
|
@@ -8487,6 +9318,7 @@ var init_app = __esm({
|
|
|
8487
9318
|
init_update_check();
|
|
8488
9319
|
init_onboarding();
|
|
8489
9320
|
init_welcome();
|
|
9321
|
+
init_help_menu();
|
|
8490
9322
|
init_config();
|
|
8491
9323
|
init_theme();
|
|
8492
9324
|
init_mode();
|
|
@@ -8495,13 +9327,44 @@ var init_app = __esm({
|
|
|
8495
9327
|
init_usage_tracker();
|
|
8496
9328
|
init_manager2();
|
|
8497
9329
|
init_storage_limits();
|
|
9330
|
+
init_state();
|
|
9331
|
+
init_version();
|
|
9332
|
+
init_loader();
|
|
9333
|
+
init_renderer();
|
|
9334
|
+
FEEDBACK_WORKER_URL = "https://kimiflare-feedback.sina-b35.workers.dev";
|
|
8498
9335
|
CONTEXT_LIMIT = 262e3;
|
|
8499
9336
|
AUTO_COMPACT_SUGGEST_PCT = 0.8;
|
|
8500
|
-
MAX_EVENTS =
|
|
9337
|
+
MAX_EVENTS = 500;
|
|
8501
9338
|
nextAssistantId = 1;
|
|
8502
9339
|
nextKey = 1;
|
|
8503
9340
|
mkKey = () => `evt_${nextKey++}`;
|
|
8504
9341
|
MAX_IMAGES_PER_MESSAGE = 10;
|
|
9342
|
+
BUILTIN_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
9343
|
+
"exit",
|
|
9344
|
+
"quit",
|
|
9345
|
+
"clear",
|
|
9346
|
+
"reasoning",
|
|
9347
|
+
"cost",
|
|
9348
|
+
"model",
|
|
9349
|
+
"thinking",
|
|
9350
|
+
"effort",
|
|
9351
|
+
"theme",
|
|
9352
|
+
"mode",
|
|
9353
|
+
"plan",
|
|
9354
|
+
"auto",
|
|
9355
|
+
"edit",
|
|
9356
|
+
"resume",
|
|
9357
|
+
"compact",
|
|
9358
|
+
"init",
|
|
9359
|
+
"update",
|
|
9360
|
+
"mcp",
|
|
9361
|
+
"logout",
|
|
9362
|
+
"help",
|
|
9363
|
+
"memory",
|
|
9364
|
+
"gateway",
|
|
9365
|
+
"hello",
|
|
9366
|
+
"community"
|
|
9367
|
+
]);
|
|
8505
9368
|
EFFORT_DESCRIPTIONS = {
|
|
8506
9369
|
low: "low \u2014 fastest; lightest reasoning. Best for simple Q&A, small edits, quick coordination.",
|
|
8507
9370
|
medium: "medium \u2014 balanced (default). Solid quality on most edits, fast on trivial prompts.",
|
|
@@ -8516,21 +9379,10 @@ init_loop();
|
|
|
8516
9379
|
init_system_prompt();
|
|
8517
9380
|
init_executor();
|
|
8518
9381
|
init_update_check();
|
|
9382
|
+
init_version();
|
|
8519
9383
|
import { Command } from "commander";
|
|
8520
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
8521
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8522
|
-
import { dirname as dirname4, join as join11 } from "path";
|
|
8523
|
-
function readPackageVersion() {
|
|
8524
|
-
try {
|
|
8525
|
-
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
8526
|
-
const pkg = JSON.parse(readFileSync2(join11(here, "..", "package.json"), "utf8"));
|
|
8527
|
-
return pkg.version ?? "0.0.0";
|
|
8528
|
-
} catch {
|
|
8529
|
-
return "0.0.0";
|
|
8530
|
-
}
|
|
8531
|
-
}
|
|
8532
9384
|
var program = new Command();
|
|
8533
|
-
program.name("kimiflare").description("Terminal coding agent powered by Kimi-K2.6 on Cloudflare Workers AI.").version(
|
|
9385
|
+
program.name("kimiflare").description("Terminal coding agent powered by Kimi-K2.6 on Cloudflare Workers AI.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", "model id (defaults to @cf/moonshotai/kimi-k2.6)").option("--dangerously-allow-all", "auto-approve every permission prompt (print mode only)").option("--reasoning", "include reasoning in stdout (print mode only)").parse();
|
|
8534
9386
|
var opts = program.opts();
|
|
8535
9387
|
async function main() {
|
|
8536
9388
|
const cfg = await loadConfig();
|