kimiflare 0.49.0 → 0.50.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -0
- package/dist/index.js +135 -53
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.js +74 -31
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,6 +77,107 @@ kimiflare -p "..." --dangerously-allow-all # auto-approve mutating tool
|
|
|
77
77
|
kimiflare -p "..." --reasoning # include chain-of-thought in stderr
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
+
### Headless SDK
|
|
81
|
+
|
|
82
|
+
Use KimiFlare programmatically from your own application — no TUI required.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { createAgentSession } from "kimiflare/sdk";
|
|
86
|
+
|
|
87
|
+
const { session } = await createAgentSession({
|
|
88
|
+
cwd: "/path/to/project",
|
|
89
|
+
config: {
|
|
90
|
+
accountId: process.env.CLOUDFLARE_ACCOUNT_ID,
|
|
91
|
+
apiToken: process.env.CLOUDFLARE_API_TOKEN,
|
|
92
|
+
model: "@cf/moonshotai/kimi-k2.6",
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Stream every event: text deltas, tool calls, tasks, usage
|
|
97
|
+
session.subscribe((event) => {
|
|
98
|
+
console.log(event.type, event);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Send a prompt
|
|
102
|
+
await session.prompt("Refactor auth to JWT + Redis");
|
|
103
|
+
|
|
104
|
+
// Mid-flight correction while the agent is still running
|
|
105
|
+
await session.steer("Use Redis instead of in-memory store");
|
|
106
|
+
|
|
107
|
+
// After the turn finishes
|
|
108
|
+
await session.followUp("Also add unit tests");
|
|
109
|
+
|
|
110
|
+
// Clean up
|
|
111
|
+
session.dispose();
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Key features:**
|
|
115
|
+
- `subscribe()` — receive typed events (`text_delta`, `tool_call`, `tool_result`, `task_update`, `usage`, `error`, `done`, etc.)
|
|
116
|
+
- `prompt()` / `steer()` / `followUp()` — full conversation lifecycle
|
|
117
|
+
- `pause()` / `resume()` — graceful preemption
|
|
118
|
+
- `getStatus()` / `getUsage()` — inspect session state
|
|
119
|
+
- Custom `permissionHandler` — decide programmatically whether to allow mutating tools
|
|
120
|
+
- Optional `memoryEnabled`, `lspEnabled`, `costAttribution` flags
|
|
121
|
+
|
|
122
|
+
#### SDK Authentication
|
|
123
|
+
|
|
124
|
+
The SDK needs a Cloudflare **Account ID** and **API Token** to call Workers AI directly. Credentials are resolved in this priority order:
|
|
125
|
+
|
|
126
|
+
1. **Explicit `config` object** (recommended for apps)
|
|
127
|
+
2. **Environment variables**: `CLOUDFLARE_ACCOUNT_ID` / `CF_ACCOUNT_ID`, `CLOUDFLARE_API_TOKEN` / `CF_API_TOKEN`
|
|
128
|
+
3. **Config file**: `~/.config/kimiflare/config.json`
|
|
129
|
+
|
|
130
|
+
**For Electron / desktop apps**, we recommend storing credentials in the OS keychain (e.g. Electron `safeStorage` or `keytar`) and passing them explicitly:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { createAgentSession } from "kimiflare/sdk";
|
|
134
|
+
|
|
135
|
+
const accountId = await keytar.getPassword("kimiflare", "accountId");
|
|
136
|
+
const apiToken = await keytar.getPassword("kimiflare", "apiToken");
|
|
137
|
+
|
|
138
|
+
const { session } = await createAgentSession({
|
|
139
|
+
cwd: projectPath,
|
|
140
|
+
config: { accountId, apiToken },
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**For zero-credential onboarding**, use KimiFlare Cloud mode. The user authenticates via GitHub device flow and a Cloudflare Worker proxies AI requests. Your app never sees raw Cloudflare credentials — only a GitHub token and `remoteWorkerUrl`.
|
|
145
|
+
|
|
146
|
+
#### RPC mode (subprocess)
|
|
147
|
+
|
|
148
|
+
If you need process isolation or a non-Node consumer, run KimiFlare in JSONL-over-stdio RPC mode:
|
|
149
|
+
|
|
150
|
+
```sh
|
|
151
|
+
node bin/kimiflare.mjs --mode rpc
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { spawn } from "node:child_process";
|
|
156
|
+
|
|
157
|
+
const proc = spawn("npx", ["kimiflare", "--mode", "rpc"], {
|
|
158
|
+
cwd: projectPath,
|
|
159
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Read events
|
|
163
|
+
proc.stdout.on("data", (chunk) => {
|
|
164
|
+
for (const line of chunk.toString().split("\n")) {
|
|
165
|
+
if (!line.trim()) continue;
|
|
166
|
+
const event = JSON.parse(line);
|
|
167
|
+
console.log(event.type, event);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Send commands
|
|
172
|
+
proc.stdin.write(JSON.stringify({ type: "new_session" }) + "\n");
|
|
173
|
+
proc.stdin.write(JSON.stringify({ type: "prompt", message: "Hello" }) + "\n");
|
|
174
|
+
|
|
175
|
+
// Resolve a permission request
|
|
176
|
+
proc.stdin.write(
|
|
177
|
+
JSON.stringify({ type: "resolve_permission", requestId: "req_0", decision: "allow" }) + "\n"
|
|
178
|
+
);
|
|
179
|
+
```
|
|
180
|
+
|
|
80
181
|
### Image understanding
|
|
81
182
|
|
|
82
183
|
```sh
|
package/dist/index.js
CHANGED
|
@@ -453,6 +453,34 @@ var init_sse = __esm({
|
|
|
453
453
|
function isCloudQuotaExhaustedError(err) {
|
|
454
454
|
return err instanceof KimiApiError && err.httpStatus === 429 && /token quota exhausted/i.test(err.message);
|
|
455
455
|
}
|
|
456
|
+
function humanizeCloudflareError(err) {
|
|
457
|
+
const { code, httpStatus, message: message2 } = err;
|
|
458
|
+
if (code === 3040) {
|
|
459
|
+
return "Cloudflare Workers AI is at capacity. Retrying automatically\u2026";
|
|
460
|
+
}
|
|
461
|
+
if (httpStatus === 429) {
|
|
462
|
+
return "Rate limit hit. Please wait a moment and try again.";
|
|
463
|
+
}
|
|
464
|
+
if (httpStatus === 403 || code === 1e4) {
|
|
465
|
+
return "Authentication failed. Check that your Cloudflare API token has the 'Workers AI' permission.\nGet a new token: https://dash.cloudflare.com/profile/api-tokens";
|
|
466
|
+
}
|
|
467
|
+
if (httpStatus === 401) {
|
|
468
|
+
return "Authentication required. Please check your API token or run `kimiflare auth cloud` if using cloud mode.";
|
|
469
|
+
}
|
|
470
|
+
if (httpStatus === 400) {
|
|
471
|
+
if (message2.includes("invalid escaped character")) {
|
|
472
|
+
return "API rejected request (invalid JSON in conversation history). Run /clear to reset if it persists.";
|
|
473
|
+
}
|
|
474
|
+
if (message2.includes("Invalid model ID")) {
|
|
475
|
+
return message2;
|
|
476
|
+
}
|
|
477
|
+
return "Bad request. The conversation may be too long or contain invalid characters. Run /compact or /clear.";
|
|
478
|
+
}
|
|
479
|
+
if (httpStatus && httpStatus >= 500) {
|
|
480
|
+
return "Cloudflare servers are experiencing issues. Retrying automatically\u2026";
|
|
481
|
+
}
|
|
482
|
+
return message2.replace(/\{[\s\S]*?\}/g, "(see logs for details)");
|
|
483
|
+
}
|
|
456
484
|
var KimiApiError;
|
|
457
485
|
var init_errors = __esm({
|
|
458
486
|
"src/util/errors.ts"() {
|
|
@@ -620,7 +648,7 @@ async function* runKimi(opts2) {
|
|
|
620
648
|
parsed = JSON.parse(text);
|
|
621
649
|
} catch {
|
|
622
650
|
}
|
|
623
|
-
const err = extractCloudflareError(parsed);
|
|
651
|
+
const err = extractCloudflareError(parsed, text);
|
|
624
652
|
const rawMsg = err?.message ?? `HTTP ${res.status}: ${text.slice(0, 300)}`;
|
|
625
653
|
const msg = cleanErrorMessage(rawMsg);
|
|
626
654
|
const apiErr = new KimiApiError(`kimiflare: ${msg}`, err?.code, res.status);
|
|
@@ -827,16 +855,23 @@ function validateJsonArguments(raw) {
|
|
|
827
855
|
return "{}";
|
|
828
856
|
}
|
|
829
857
|
}
|
|
830
|
-
function extractCloudflareError(parsed) {
|
|
831
|
-
if (
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
858
|
+
function extractCloudflareError(parsed, rawText) {
|
|
859
|
+
if (parsed && typeof parsed === "object") {
|
|
860
|
+
const cf = parsed;
|
|
861
|
+
if (cf.success === false && Array.isArray(cf.errors) && cf.errors.length > 0) {
|
|
862
|
+
return { code: cf.errors[0]?.code, message: cf.errors[0]?.message };
|
|
863
|
+
}
|
|
864
|
+
const oai = parsed;
|
|
865
|
+
if (oai.object === "error" && typeof oai.message === "string") {
|
|
866
|
+
const codeNum = typeof oai.code === "number" ? oai.code : void 0;
|
|
867
|
+
return { code: codeNum, message: oai.message };
|
|
868
|
+
}
|
|
835
869
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
870
|
+
if (rawText) {
|
|
871
|
+
const msgMatch = rawText.match(/"message"\s*:\s*"([^"]+)"/);
|
|
872
|
+
if (msgMatch?.[1]) {
|
|
873
|
+
return { message: msgMatch[1] };
|
|
874
|
+
}
|
|
840
875
|
}
|
|
841
876
|
return null;
|
|
842
877
|
}
|
|
@@ -3314,8 +3349,8 @@ var init_write = __esm({
|
|
|
3314
3349
|
},
|
|
3315
3350
|
needsPermission: true,
|
|
3316
3351
|
render: (args) => ({
|
|
3317
|
-
title: `write ${collapsePath(args.path, process.cwd())} (${args.content.length} chars)`,
|
|
3318
|
-
diff: { path: args.path, before: "", after: args.content }
|
|
3352
|
+
title: `write ${collapsePath(String(args.path ?? ""), process.cwd())} (${String(args.content ?? "").length} chars)`,
|
|
3353
|
+
diff: { path: String(args.path ?? ""), before: "", after: String(args.content ?? "") }
|
|
3319
3354
|
}),
|
|
3320
3355
|
async run(args, ctx) {
|
|
3321
3356
|
const abs = resolvePath(ctx.cwd, args.path);
|
|
@@ -3367,8 +3402,8 @@ var init_edit = __esm({
|
|
|
3367
3402
|
},
|
|
3368
3403
|
needsPermission: true,
|
|
3369
3404
|
render: (args) => ({
|
|
3370
|
-
title: `edit ${collapsePath(args.path, process.cwd())}${args.replace_all ? " (replace_all)" : ""}`,
|
|
3371
|
-
diff: { path: args.path, before: args.old_string, after: args.new_string }
|
|
3405
|
+
title: `edit ${collapsePath(String(args.path ?? ""), process.cwd())}${args.replace_all ? " (replace_all)" : ""}`,
|
|
3406
|
+
diff: { path: String(args.path ?? ""), before: String(args.old_string ?? ""), after: String(args.new_string ?? "") }
|
|
3372
3407
|
}),
|
|
3373
3408
|
async run(args, ctx) {
|
|
3374
3409
|
const abs = resolvePath(ctx.cwd, args.path);
|
|
@@ -3516,7 +3551,7 @@ var init_bash = __esm({
|
|
|
3516
3551
|
additionalProperties: false
|
|
3517
3552
|
},
|
|
3518
3553
|
needsPermission: true,
|
|
3519
|
-
render: (args) => ({ title: formatBashTitle(args.command) }),
|
|
3554
|
+
render: (args) => ({ title: formatBashTitle(String(args.command ?? "")) }),
|
|
3520
3555
|
run: (args, ctx) => runBash(args, ctx)
|
|
3521
3556
|
};
|
|
3522
3557
|
}
|
|
@@ -3542,7 +3577,7 @@ var init_glob = __esm({
|
|
|
3542
3577
|
additionalProperties: false
|
|
3543
3578
|
},
|
|
3544
3579
|
needsPermission: false,
|
|
3545
|
-
render: (args) => ({ title: `glob ${args.pattern}${args.path ? ` in ${collapsePath(args.path, process.cwd())}` : ""}` }),
|
|
3580
|
+
render: (args) => ({ title: `glob ${args.pattern ?? ""}${args.path ? ` in ${collapsePath(String(args.path), process.cwd())}` : ""}` }),
|
|
3546
3581
|
async run(args, ctx) {
|
|
3547
3582
|
const root = args.path ? resolvePath(ctx.cwd, args.path) : ctx.cwd;
|
|
3548
3583
|
const entries = await fg(args.pattern, {
|
|
@@ -3660,7 +3695,7 @@ var init_grep = __esm({
|
|
|
3660
3695
|
additionalProperties: false
|
|
3661
3696
|
},
|
|
3662
3697
|
needsPermission: false,
|
|
3663
|
-
render: (args) => ({ title: `grep ${args.pattern}${args.glob ? ` (${args.glob})` : ""}` }),
|
|
3698
|
+
render: (args) => ({ title: `grep ${args.pattern ?? ""}${args.glob ? ` (${args.glob})` : ""}` }),
|
|
3664
3699
|
async run(args, ctx) {
|
|
3665
3700
|
const root = args.path ? resolvePath(ctx.cwd, args.path) : ctx.cwd;
|
|
3666
3701
|
const mode = args.output_mode ?? "content";
|
|
@@ -3692,7 +3727,7 @@ var init_web_fetch = __esm({
|
|
|
3692
3727
|
additionalProperties: false
|
|
3693
3728
|
},
|
|
3694
3729
|
needsPermission: false,
|
|
3695
|
-
render: (args) => ({ title: `GET ${args.url}` }),
|
|
3730
|
+
render: (args) => ({ title: `GET ${args.url ?? ""}` }),
|
|
3696
3731
|
async run(args) {
|
|
3697
3732
|
const controller = new AbortController();
|
|
3698
3733
|
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
@@ -3827,7 +3862,7 @@ var init_web_search = __esm({
|
|
|
3827
3862
|
additionalProperties: false
|
|
3828
3863
|
},
|
|
3829
3864
|
needsPermission: false,
|
|
3830
|
-
render: (args) => ({ title: `search web: ${args.query}` }),
|
|
3865
|
+
render: (args) => ({ title: `search web: ${args.query ?? ""}` }),
|
|
3831
3866
|
async run(args) {
|
|
3832
3867
|
const count = Math.min(Math.max(args.count ?? DEFAULT_RESULTS, 1), MAX_RESULTS);
|
|
3833
3868
|
try {
|
|
@@ -3913,7 +3948,7 @@ var init_github = __esm({
|
|
|
3913
3948
|
additionalProperties: false
|
|
3914
3949
|
},
|
|
3915
3950
|
needsPermission: false,
|
|
3916
|
-
render: (args) => ({ title: `GitHub PR ${args.owner}/${args.repo}#${args.number}` }),
|
|
3951
|
+
render: (args) => ({ title: `GitHub PR ${args.owner ?? ""}/${args.repo ?? ""}#${args.number ?? ""}` }),
|
|
3917
3952
|
async run(args, ctx) {
|
|
3918
3953
|
const token = getToken(ctx);
|
|
3919
3954
|
const pr = await githubFetch(`/repos/${args.owner}/${args.repo}/pulls/${args.number}`, token);
|
|
@@ -3955,7 +3990,7 @@ var init_github = __esm({
|
|
|
3955
3990
|
additionalProperties: false
|
|
3956
3991
|
},
|
|
3957
3992
|
needsPermission: false,
|
|
3958
|
-
render: (args) => ({ title: `GitHub issue ${args.owner}/${args.repo}#${args.number}` }),
|
|
3993
|
+
render: (args) => ({ title: `GitHub issue ${args.owner ?? ""}/${args.repo ?? ""}#${args.number ?? ""}` }),
|
|
3959
3994
|
async run(args, ctx) {
|
|
3960
3995
|
const token = getToken(ctx);
|
|
3961
3996
|
const issue = await githubFetch(`/repos/${args.owner}/${args.repo}/issues/${args.number}`, token);
|
|
@@ -4002,7 +4037,7 @@ var init_github = __esm({
|
|
|
4002
4037
|
},
|
|
4003
4038
|
needsPermission: false,
|
|
4004
4039
|
render: (args) => ({
|
|
4005
|
-
title: `GitHub code ${args.owner}/${args.repo}/${args.path}${args.ref ? `@${args.ref}` : ""}`
|
|
4040
|
+
title: `GitHub code ${args.owner ?? ""}/${args.repo ?? ""}/${args.path ?? ""}${args.ref ? `@${args.ref}` : ""}`
|
|
4006
4041
|
}),
|
|
4007
4042
|
async run(args, ctx) {
|
|
4008
4043
|
const token = getToken(ctx);
|
|
@@ -4080,7 +4115,7 @@ var init_browser = __esm({
|
|
|
4080
4115
|
},
|
|
4081
4116
|
needsPermission: false,
|
|
4082
4117
|
render: (args) => ({
|
|
4083
|
-
title: `browser ${args.url}${args.screenshot ? " (screenshot)" : ""}`
|
|
4118
|
+
title: `browser ${args.url ?? ""}${args.screenshot ? " (screenshot)" : ""}`
|
|
4084
4119
|
}),
|
|
4085
4120
|
async run(args, ctx) {
|
|
4086
4121
|
let playwright;
|
|
@@ -4206,10 +4241,13 @@ var init_tasks = __esm({
|
|
|
4206
4241
|
required: ["tasks"]
|
|
4207
4242
|
},
|
|
4208
4243
|
needsPermission: false,
|
|
4209
|
-
render: (args) =>
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4244
|
+
render: (args) => {
|
|
4245
|
+
const tasks = Array.isArray(args.tasks) ? args.tasks : [];
|
|
4246
|
+
return {
|
|
4247
|
+
title: `tasks (${tasks.length} items)`,
|
|
4248
|
+
body: tasks.map((t) => `${t.status === "completed" ? "\u2713" : t.status === "in_progress" ? "\u25B8" : "\xB7"} ${t.title}`).join("\n")
|
|
4249
|
+
};
|
|
4250
|
+
},
|
|
4213
4251
|
run: async (args, ctx) => {
|
|
4214
4252
|
let tasks;
|
|
4215
4253
|
try {
|
|
@@ -4260,7 +4298,7 @@ var init_memory = __esm({
|
|
|
4260
4298
|
needsPermission: false,
|
|
4261
4299
|
render: (args) => ({
|
|
4262
4300
|
title: "memory_remember",
|
|
4263
|
-
body: `[${args.category}] ${args.content} (importance: ${args.importance})`
|
|
4301
|
+
body: `[${args.category ?? "unknown"}] ${args.content ?? ""} (importance: ${args.importance ?? 1})`
|
|
4264
4302
|
}),
|
|
4265
4303
|
run: async (args, ctx) => {
|
|
4266
4304
|
if (!isMemoryCtx(ctx) || !ctx.memoryManager) {
|
|
@@ -4315,7 +4353,7 @@ var init_memory = __esm({
|
|
|
4315
4353
|
needsPermission: false,
|
|
4316
4354
|
render: (args) => ({
|
|
4317
4355
|
title: "memory_recall",
|
|
4318
|
-
body: `Query: "${args.query}"`
|
|
4356
|
+
body: `Query: "${args.query ?? ""}"`
|
|
4319
4357
|
}),
|
|
4320
4358
|
run: async (args, ctx) => {
|
|
4321
4359
|
if (!isMemoryCtx(ctx) || !ctx.memoryManager) {
|
|
@@ -4360,7 +4398,7 @@ var init_memory = __esm({
|
|
|
4360
4398
|
needsPermission: false,
|
|
4361
4399
|
render: (args) => ({
|
|
4362
4400
|
title: "memory_forget",
|
|
4363
|
-
body: `Forgetting memory ${args.memory_id}`
|
|
4401
|
+
body: `Forgetting memory ${args.memory_id ?? ""}`
|
|
4364
4402
|
}),
|
|
4365
4403
|
run: async (args, ctx) => {
|
|
4366
4404
|
if (!isMemoryCtx(ctx) || !ctx.memoryManager) {
|
|
@@ -4920,7 +4958,7 @@ function makeExpandArtifactTool(store) {
|
|
|
4920
4958
|
additionalProperties: false
|
|
4921
4959
|
},
|
|
4922
4960
|
needsPermission: false,
|
|
4923
|
-
render: (args) => ({ title: `expand ${args.artifact_id}` }),
|
|
4961
|
+
render: (args) => ({ title: `expand ${args.artifact_id ?? ""}` }),
|
|
4924
4962
|
run: async (args) => {
|
|
4925
4963
|
const raw = store.retrieve(args.artifact_id);
|
|
4926
4964
|
if (!raw) {
|
|
@@ -8415,6 +8453,9 @@ function usageDir2() {
|
|
|
8415
8453
|
function usagePath2() {
|
|
8416
8454
|
return join18(usageDir2(), "usage.json");
|
|
8417
8455
|
}
|
|
8456
|
+
function historyPath() {
|
|
8457
|
+
return join18(usageDir2(), "history.jsonl");
|
|
8458
|
+
}
|
|
8418
8459
|
function today2() {
|
|
8419
8460
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8420
8461
|
}
|
|
@@ -8435,6 +8476,35 @@ async function saveLog(log2) {
|
|
|
8435
8476
|
await mkdir9(usageDir2(), { recursive: true });
|
|
8436
8477
|
await writeFile10(usagePath2(), JSON.stringify(log2, null, 2), "utf8");
|
|
8437
8478
|
}
|
|
8479
|
+
async function loadHistory() {
|
|
8480
|
+
try {
|
|
8481
|
+
const raw = await readFile13(historyPath(), "utf8");
|
|
8482
|
+
const lines = raw.split("\n").filter((l) => l.trim());
|
|
8483
|
+
const entries = [];
|
|
8484
|
+
for (const line of lines) {
|
|
8485
|
+
try {
|
|
8486
|
+
const parsed = JSON.parse(line);
|
|
8487
|
+
if (parsed.date) entries.push(parsed);
|
|
8488
|
+
} catch {
|
|
8489
|
+
}
|
|
8490
|
+
}
|
|
8491
|
+
return entries;
|
|
8492
|
+
} catch {
|
|
8493
|
+
}
|
|
8494
|
+
return [];
|
|
8495
|
+
}
|
|
8496
|
+
async function upsertHistoryDay(day) {
|
|
8497
|
+
const entries = await loadHistory();
|
|
8498
|
+
const idx = entries.findIndex((e) => e.date === day.date);
|
|
8499
|
+
if (idx >= 0) {
|
|
8500
|
+
entries[idx] = day;
|
|
8501
|
+
} else {
|
|
8502
|
+
entries.push(day);
|
|
8503
|
+
}
|
|
8504
|
+
const lines = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
8505
|
+
await mkdir9(usageDir2(), { recursive: true });
|
|
8506
|
+
await writeFile10(historyPath(), lines, "utf8");
|
|
8507
|
+
}
|
|
8438
8508
|
function getOrCreateDay(log2, date) {
|
|
8439
8509
|
let day = log2.days.find((d) => d.date === date);
|
|
8440
8510
|
if (!day) {
|
|
@@ -8534,9 +8604,18 @@ async function recordUsage(sessionId, usage, gateway) {
|
|
|
8534
8604
|
session.gatewayLogs = [...session.gatewayLogs ?? [], gatewaySnapshot].slice(-100);
|
|
8535
8605
|
}
|
|
8536
8606
|
await saveLog(log2);
|
|
8607
|
+
await upsertHistoryDay(day);
|
|
8608
|
+
}
|
|
8609
|
+
function mergeDays(usageDays, historyDays) {
|
|
8610
|
+
const map = /* @__PURE__ */ new Map();
|
|
8611
|
+
for (const d of historyDays) map.set(d.date, d);
|
|
8612
|
+
for (const d of usageDays) map.set(d.date, d);
|
|
8613
|
+
return Array.from(map.values()).sort((a, b) => a.date < b.date ? -1 : a.date > b.date ? 1 : 0);
|
|
8537
8614
|
}
|
|
8538
8615
|
async function getCostReport(sessionId) {
|
|
8539
8616
|
const log2 = pruneUsageLog(await loadLog2());
|
|
8617
|
+
const history = await loadHistory();
|
|
8618
|
+
const allDays = mergeDays(log2.days, history);
|
|
8540
8619
|
const date = today2();
|
|
8541
8620
|
const currentMonth = date.slice(0, 7);
|
|
8542
8621
|
const session = sessionId ? log2.sessions.find((s) => s.id === sessionId) ?? { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 } : { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
|
|
@@ -8548,7 +8627,7 @@ async function getCostReport(sessionId) {
|
|
|
8548
8627
|
cachedTokens: 0,
|
|
8549
8628
|
cost: 0
|
|
8550
8629
|
};
|
|
8551
|
-
for (const d of
|
|
8630
|
+
for (const d of allDays) {
|
|
8552
8631
|
if (d.date.startsWith(currentMonth)) {
|
|
8553
8632
|
monthUsage.promptTokens += d.promptTokens;
|
|
8554
8633
|
monthUsage.completionTokens += d.completionTokens;
|
|
@@ -8566,7 +8645,7 @@ async function getCostReport(sessionId) {
|
|
|
8566
8645
|
cachedTokens: 0,
|
|
8567
8646
|
cost: 0
|
|
8568
8647
|
};
|
|
8569
|
-
for (const d of
|
|
8648
|
+
for (const d of allDays) {
|
|
8570
8649
|
allTime.promptTokens += d.promptTokens;
|
|
8571
8650
|
allTime.completionTokens += d.completionTokens;
|
|
8572
8651
|
allTime.cachedTokens += d.cachedTokens;
|
|
@@ -9654,7 +9733,9 @@ import { createTwoFilesPatch } from "diff";
|
|
|
9654
9733
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
9655
9734
|
function DiffView({ path, before, after, maxLines = 40 }) {
|
|
9656
9735
|
const theme = useTheme();
|
|
9657
|
-
const
|
|
9736
|
+
const safeBefore = before ?? "";
|
|
9737
|
+
const safeAfter = after ?? "";
|
|
9738
|
+
const patch = createTwoFilesPatch(path, path, safeBefore, safeAfter, "", "", { context: 2 });
|
|
9658
9739
|
const raw = patch.split("\n").slice(4);
|
|
9659
9740
|
const lines = raw.filter((l) => {
|
|
9660
9741
|
if (l.startsWith("--- ") || l.startsWith("+++ ")) return false;
|
|
@@ -10669,7 +10750,11 @@ import SelectInput from "ink-select-input";
|
|
|
10669
10750
|
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
10670
10751
|
function PermissionModal({ tool, args, onDecide }) {
|
|
10671
10752
|
const theme = useTheme();
|
|
10672
|
-
|
|
10753
|
+
let render2;
|
|
10754
|
+
try {
|
|
10755
|
+
render2 = tool.render?.(args);
|
|
10756
|
+
} catch {
|
|
10757
|
+
}
|
|
10673
10758
|
const items = [
|
|
10674
10759
|
{ label: "Allow once", value: "allow" },
|
|
10675
10760
|
{ label: "Allow for this session", value: "allow_session" },
|
|
@@ -17960,9 +18045,10 @@ ${wcagWarnings.join("\n")}` }
|
|
|
17960
18045
|
{ kind: "cloud_quota_exhausted", key: mkKey(), used, limit, expiresAt }
|
|
17961
18046
|
]);
|
|
17962
18047
|
} else {
|
|
18048
|
+
const displayText = e instanceof KimiApiError ? humanizeCloudflareError(e) : `init failed: ${e.message}`;
|
|
17963
18049
|
setEvents((es) => [
|
|
17964
18050
|
...es,
|
|
17965
|
-
{ kind: "error", key: mkKey(), text:
|
|
18051
|
+
{ kind: "error", key: mkKey(), text: displayText }
|
|
17966
18052
|
]);
|
|
17967
18053
|
}
|
|
17968
18054
|
} finally {
|
|
@@ -19512,23 +19598,11 @@ ${lines.join("\n")}` }]);
|
|
|
19512
19598
|
{ kind: "cloud_quota_exhausted", key: mkKey(), used, limit, expiresAt }
|
|
19513
19599
|
]);
|
|
19514
19600
|
} else {
|
|
19515
|
-
const
|
|
19516
|
-
|
|
19517
|
-
|
|
19518
|
-
|
|
19519
|
-
|
|
19520
|
-
{
|
|
19521
|
-
kind: "error",
|
|
19522
|
-
key: mkKey(),
|
|
19523
|
-
text: "API rejected request (invalid JSON in conversation history). Retrying may work; run /clear to reset if it persists."
|
|
19524
|
-
}
|
|
19525
|
-
]);
|
|
19526
|
-
} else {
|
|
19527
|
-
setEvents((es) => [
|
|
19528
|
-
...es,
|
|
19529
|
-
{ kind: "error", key: mkKey(), text: e.message ?? String(e) }
|
|
19530
|
-
]);
|
|
19531
|
-
}
|
|
19601
|
+
const displayText2 = e instanceof KimiApiError ? humanizeCloudflareError(e) : e.message ?? String(e);
|
|
19602
|
+
setEvents((es) => [
|
|
19603
|
+
...es,
|
|
19604
|
+
{ kind: "error", key: mkKey(), text: displayText2 }
|
|
19605
|
+
]);
|
|
19532
19606
|
}
|
|
19533
19607
|
cleanupTurn();
|
|
19534
19608
|
}
|
|
@@ -20007,6 +20081,7 @@ var init_app = __esm({
|
|
|
20007
20081
|
init_config();
|
|
20008
20082
|
init_lsp_config();
|
|
20009
20083
|
init_loop();
|
|
20084
|
+
init_errors();
|
|
20010
20085
|
init_system_prompt();
|
|
20011
20086
|
init_executor();
|
|
20012
20087
|
init_update_check();
|
|
@@ -20359,6 +20434,13 @@ async function runPrintMode(opts2) {
|
|
|
20359
20434
|
process.exitCode = 42;
|
|
20360
20435
|
return;
|
|
20361
20436
|
}
|
|
20437
|
+
if (err instanceof KimiApiError) {
|
|
20438
|
+
process.stderr.write(`
|
|
20439
|
+
\x1B[31mError: ${humanizeCloudflareError(err)}\x1B[0m
|
|
20440
|
+
`);
|
|
20441
|
+
process.exitCode = 1;
|
|
20442
|
+
return;
|
|
20443
|
+
}
|
|
20362
20444
|
throw err;
|
|
20363
20445
|
}
|
|
20364
20446
|
process.stdout.write("\n");
|