autopilot-ai 1.24.2 → 1.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1041 -828
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.js +651 -503
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
1
|
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
3
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
4
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
5
|
}) : x)(function(x) {
|
|
@@ -18,33 +14,10 @@ var __esm = (fn, res, err) => function __init() {
|
|
|
18
14
|
throw err = [e], e;
|
|
19
15
|
}
|
|
20
16
|
};
|
|
21
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
22
|
-
try {
|
|
23
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
24
|
-
} catch (e) {
|
|
25
|
-
throw mod = 0, e;
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
17
|
var __export = (target, all) => {
|
|
29
18
|
for (var name in all)
|
|
30
19
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
31
20
|
};
|
|
32
|
-
var __copyProps = (to, from, except, desc) => {
|
|
33
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
34
|
-
for (let key of __getOwnPropNames(from))
|
|
35
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
36
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
37
|
-
}
|
|
38
|
-
return to;
|
|
39
|
-
};
|
|
40
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
41
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
42
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
43
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
44
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
45
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
46
|
-
mod
|
|
47
|
-
));
|
|
48
21
|
|
|
49
22
|
// src/util/log-sink.ts
|
|
50
23
|
var log_sink_exports = {};
|
|
@@ -102,8 +75,8 @@ async function flushAndCloseForTesting() {
|
|
|
102
75
|
const s = currentStream;
|
|
103
76
|
currentStream = null;
|
|
104
77
|
currentDate = null;
|
|
105
|
-
await new Promise((
|
|
106
|
-
s.end(() =>
|
|
78
|
+
await new Promise((resolve20) => {
|
|
79
|
+
s.end(() => resolve20());
|
|
107
80
|
});
|
|
108
81
|
}
|
|
109
82
|
function isLogSinkEnabled() {
|
|
@@ -1289,13 +1262,13 @@ async function checkDeployStatus() {
|
|
|
1289
1262
|
}
|
|
1290
1263
|
return { wrangler, wranglerAuth, docker, workerUrl };
|
|
1291
1264
|
}
|
|
1292
|
-
var
|
|
1265
|
+
var __dirname, REMOTE_DIR, WORKER_DIR;
|
|
1293
1266
|
var init_deploy = __esm({
|
|
1294
1267
|
"src/remote/deploy.ts"() {
|
|
1295
1268
|
"use strict";
|
|
1296
1269
|
init_config();
|
|
1297
|
-
|
|
1298
|
-
REMOTE_DIR = join7(
|
|
1270
|
+
__dirname = dirname4(fileURLToPath3(import.meta.url));
|
|
1271
|
+
REMOTE_DIR = join7(__dirname, "..", "..", "..", "remote");
|
|
1299
1272
|
WORKER_DIR = join7(REMOTE_DIR, "worker");
|
|
1300
1273
|
}
|
|
1301
1274
|
});
|
|
@@ -1342,10 +1315,10 @@ async function* readSSE(stream, signal, idleTimeoutMs, postFirstByteIdleTimeoutM
|
|
|
1342
1315
|
gotFirstByte = true;
|
|
1343
1316
|
buffer += decoder.decode(value, { stream: true });
|
|
1344
1317
|
buffer = buffer.replace(/\r\n/g, "\n");
|
|
1345
|
-
let
|
|
1346
|
-
while ((
|
|
1347
|
-
const event = buffer.slice(0,
|
|
1348
|
-
buffer = buffer.slice(
|
|
1318
|
+
let sep8;
|
|
1319
|
+
while ((sep8 = buffer.indexOf("\n\n")) !== -1) {
|
|
1320
|
+
const event = buffer.slice(0, sep8);
|
|
1321
|
+
buffer = buffer.slice(sep8 + 2);
|
|
1349
1322
|
const data = extractData(event);
|
|
1350
1323
|
if (data !== null) yield data;
|
|
1351
1324
|
}
|
|
@@ -2782,7 +2755,8 @@ async function* parseStream(body, signal, idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_M
|
|
|
2782
2755
|
index: idx,
|
|
2783
2756
|
id: buf.id,
|
|
2784
2757
|
name: buf.name,
|
|
2785
|
-
arguments: buf.args
|
|
2758
|
+
arguments: buf.args,
|
|
2759
|
+
finishReason
|
|
2786
2760
|
};
|
|
2787
2761
|
}
|
|
2788
2762
|
yield { type: "done", finishReason, usage: lastUsage };
|
|
@@ -2850,11 +2824,11 @@ function extractApiError(parsed, rawText) {
|
|
|
2850
2824
|
return null;
|
|
2851
2825
|
}
|
|
2852
2826
|
function sleep(ms, signal) {
|
|
2853
|
-
return new Promise((
|
|
2827
|
+
return new Promise((resolve20, reject) => {
|
|
2854
2828
|
if (signal?.aborted) return reject(new DOMException("aborted", "AbortError"));
|
|
2855
2829
|
const t = setTimeout(() => {
|
|
2856
2830
|
signal?.removeEventListener("abort", onAbort);
|
|
2857
|
-
|
|
2831
|
+
resolve20();
|
|
2858
2832
|
}, ms);
|
|
2859
2833
|
const onAbort = () => {
|
|
2860
2834
|
clearTimeout(t);
|
|
@@ -2993,7 +2967,7 @@ async function pruneFiles(files, maxAgeDays, maxCount) {
|
|
|
2993
2967
|
return removed;
|
|
2994
2968
|
}
|
|
2995
2969
|
async function rotateJsonl(path, maxBytes, rotations) {
|
|
2996
|
-
const { rename:
|
|
2970
|
+
const { rename: rename4 } = await import("fs/promises");
|
|
2997
2971
|
let s;
|
|
2998
2972
|
try {
|
|
2999
2973
|
s = await stat2(path);
|
|
@@ -3005,7 +2979,7 @@ async function rotateJsonl(path, maxBytes, rotations) {
|
|
|
3005
2979
|
const src = i === 1 ? path : `${path}.${i - 1}`;
|
|
3006
2980
|
const dst = `${path}.${i}`;
|
|
3007
2981
|
try {
|
|
3008
|
-
await
|
|
2982
|
+
await rename4(src, dst);
|
|
3009
2983
|
} catch {
|
|
3010
2984
|
}
|
|
3011
2985
|
}
|
|
@@ -3574,197 +3548,6 @@ var init_api_generator = __esm({
|
|
|
3574
3548
|
}
|
|
3575
3549
|
});
|
|
3576
3550
|
|
|
3577
|
-
// node_modules/node-gyp-build/node-gyp-build.js
|
|
3578
|
-
var require_node_gyp_build = __commonJS({
|
|
3579
|
-
"node_modules/node-gyp-build/node-gyp-build.js"(exports, module) {
|
|
3580
|
-
"use strict";
|
|
3581
|
-
var fs = __require("fs");
|
|
3582
|
-
var path = __require("path");
|
|
3583
|
-
var os2 = __require("os");
|
|
3584
|
-
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
3585
|
-
var vars = process.config && process.config.variables || {};
|
|
3586
|
-
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
3587
|
-
var abi = process.versions.modules;
|
|
3588
|
-
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
3589
|
-
var arch = process.env.npm_config_arch || os2.arch();
|
|
3590
|
-
var platform8 = process.env.npm_config_platform || os2.platform();
|
|
3591
|
-
var libc = process.env.LIBC || (isAlpine(platform8) ? "musl" : "glibc");
|
|
3592
|
-
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
|
|
3593
|
-
var uv = (process.versions.uv || "").split(".")[0];
|
|
3594
|
-
module.exports = load;
|
|
3595
|
-
function load(dir) {
|
|
3596
|
-
return runtimeRequire(load.resolve(dir));
|
|
3597
|
-
}
|
|
3598
|
-
load.resolve = load.path = function(dir) {
|
|
3599
|
-
dir = path.resolve(dir || ".");
|
|
3600
|
-
try {
|
|
3601
|
-
var name = runtimeRequire(path.join(dir, "package.json")).name.toUpperCase().replace(/-/g, "_");
|
|
3602
|
-
if (process.env[name + "_PREBUILD"]) dir = process.env[name + "_PREBUILD"];
|
|
3603
|
-
} catch (err) {
|
|
3604
|
-
}
|
|
3605
|
-
if (!prebuildsOnly) {
|
|
3606
|
-
var release2 = getFirst(path.join(dir, "build/Release"), matchBuild);
|
|
3607
|
-
if (release2) return release2;
|
|
3608
|
-
var debug = getFirst(path.join(dir, "build/Debug"), matchBuild);
|
|
3609
|
-
if (debug) return debug;
|
|
3610
|
-
}
|
|
3611
|
-
var prebuild = resolve19(dir);
|
|
3612
|
-
if (prebuild) return prebuild;
|
|
3613
|
-
var nearby = resolve19(path.dirname(process.execPath));
|
|
3614
|
-
if (nearby) return nearby;
|
|
3615
|
-
var target = [
|
|
3616
|
-
"platform=" + platform8,
|
|
3617
|
-
"arch=" + arch,
|
|
3618
|
-
"runtime=" + runtime,
|
|
3619
|
-
"abi=" + abi,
|
|
3620
|
-
"uv=" + uv,
|
|
3621
|
-
armv ? "armv=" + armv : "",
|
|
3622
|
-
"libc=" + libc,
|
|
3623
|
-
"node=" + process.versions.node,
|
|
3624
|
-
process.versions.electron ? "electron=" + process.versions.electron : "",
|
|
3625
|
-
typeof __webpack_require__ === "function" ? "webpack=true" : ""
|
|
3626
|
-
// eslint-disable-line
|
|
3627
|
-
].filter(Boolean).join(" ");
|
|
3628
|
-
throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n");
|
|
3629
|
-
function resolve19(dir2) {
|
|
3630
|
-
var tuples = readdirSync2(path.join(dir2, "prebuilds")).map(parseTuple);
|
|
3631
|
-
var tuple = tuples.filter(matchTuple(platform8, arch)).sort(compareTuples)[0];
|
|
3632
|
-
if (!tuple) return;
|
|
3633
|
-
var prebuilds = path.join(dir2, "prebuilds", tuple.name);
|
|
3634
|
-
var parsed = readdirSync2(prebuilds).map(parseTags);
|
|
3635
|
-
var candidates = parsed.filter(matchTags(runtime, abi));
|
|
3636
|
-
var winner = candidates.sort(compareTags(runtime))[0];
|
|
3637
|
-
if (winner) return path.join(prebuilds, winner.file);
|
|
3638
|
-
}
|
|
3639
|
-
};
|
|
3640
|
-
function readdirSync2(dir) {
|
|
3641
|
-
try {
|
|
3642
|
-
return fs.readdirSync(dir);
|
|
3643
|
-
} catch (err) {
|
|
3644
|
-
return [];
|
|
3645
|
-
}
|
|
3646
|
-
}
|
|
3647
|
-
function getFirst(dir, filter) {
|
|
3648
|
-
var files = readdirSync2(dir).filter(filter);
|
|
3649
|
-
return files[0] && path.join(dir, files[0]);
|
|
3650
|
-
}
|
|
3651
|
-
function matchBuild(name) {
|
|
3652
|
-
return /\.node$/.test(name);
|
|
3653
|
-
}
|
|
3654
|
-
function parseTuple(name) {
|
|
3655
|
-
var arr = name.split("-");
|
|
3656
|
-
if (arr.length !== 2) return;
|
|
3657
|
-
var platform9 = arr[0];
|
|
3658
|
-
var architectures = arr[1].split("+");
|
|
3659
|
-
if (!platform9) return;
|
|
3660
|
-
if (!architectures.length) return;
|
|
3661
|
-
if (!architectures.every(Boolean)) return;
|
|
3662
|
-
return { name, platform: platform9, architectures };
|
|
3663
|
-
}
|
|
3664
|
-
function matchTuple(platform9, arch2) {
|
|
3665
|
-
return function(tuple) {
|
|
3666
|
-
if (tuple == null) return false;
|
|
3667
|
-
if (tuple.platform !== platform9) return false;
|
|
3668
|
-
return tuple.architectures.includes(arch2);
|
|
3669
|
-
};
|
|
3670
|
-
}
|
|
3671
|
-
function compareTuples(a, b) {
|
|
3672
|
-
return a.architectures.length - b.architectures.length;
|
|
3673
|
-
}
|
|
3674
|
-
function parseTags(file) {
|
|
3675
|
-
var arr = file.split(".");
|
|
3676
|
-
var extension = arr.pop();
|
|
3677
|
-
var tags = { file, specificity: 0 };
|
|
3678
|
-
if (extension !== "node") return;
|
|
3679
|
-
for (var i = 0; i < arr.length; i++) {
|
|
3680
|
-
var tag2 = arr[i];
|
|
3681
|
-
if (tag2 === "node" || tag2 === "electron" || tag2 === "node-webkit") {
|
|
3682
|
-
tags.runtime = tag2;
|
|
3683
|
-
} else if (tag2 === "napi") {
|
|
3684
|
-
tags.napi = true;
|
|
3685
|
-
} else if (tag2.slice(0, 3) === "abi") {
|
|
3686
|
-
tags.abi = tag2.slice(3);
|
|
3687
|
-
} else if (tag2.slice(0, 2) === "uv") {
|
|
3688
|
-
tags.uv = tag2.slice(2);
|
|
3689
|
-
} else if (tag2.slice(0, 4) === "armv") {
|
|
3690
|
-
tags.armv = tag2.slice(4);
|
|
3691
|
-
} else if (tag2 === "glibc" || tag2 === "musl") {
|
|
3692
|
-
tags.libc = tag2;
|
|
3693
|
-
} else {
|
|
3694
|
-
continue;
|
|
3695
|
-
}
|
|
3696
|
-
tags.specificity++;
|
|
3697
|
-
}
|
|
3698
|
-
return tags;
|
|
3699
|
-
}
|
|
3700
|
-
function matchTags(runtime2, abi2) {
|
|
3701
|
-
return function(tags) {
|
|
3702
|
-
if (tags == null) return false;
|
|
3703
|
-
if (tags.runtime && tags.runtime !== runtime2 && !runtimeAgnostic(tags)) return false;
|
|
3704
|
-
if (tags.abi && tags.abi !== abi2 && !tags.napi) return false;
|
|
3705
|
-
if (tags.uv && tags.uv !== uv) return false;
|
|
3706
|
-
if (tags.armv && tags.armv !== armv) return false;
|
|
3707
|
-
if (tags.libc && tags.libc !== libc) return false;
|
|
3708
|
-
return true;
|
|
3709
|
-
};
|
|
3710
|
-
}
|
|
3711
|
-
function runtimeAgnostic(tags) {
|
|
3712
|
-
return tags.runtime === "node" && tags.napi;
|
|
3713
|
-
}
|
|
3714
|
-
function compareTags(runtime2) {
|
|
3715
|
-
return function(a, b) {
|
|
3716
|
-
if (a.runtime !== b.runtime) {
|
|
3717
|
-
return a.runtime === runtime2 ? -1 : 1;
|
|
3718
|
-
} else if (a.abi !== b.abi) {
|
|
3719
|
-
return a.abi ? -1 : 1;
|
|
3720
|
-
} else if (a.specificity !== b.specificity) {
|
|
3721
|
-
return a.specificity > b.specificity ? -1 : 1;
|
|
3722
|
-
} else {
|
|
3723
|
-
return 0;
|
|
3724
|
-
}
|
|
3725
|
-
};
|
|
3726
|
-
}
|
|
3727
|
-
function isNwjs() {
|
|
3728
|
-
return !!(process.versions && process.versions.nw);
|
|
3729
|
-
}
|
|
3730
|
-
function isElectron() {
|
|
3731
|
-
if (process.versions && process.versions.electron) return true;
|
|
3732
|
-
if (process.env.ELECTRON_RUN_AS_NODE) return true;
|
|
3733
|
-
return typeof window !== "undefined" && window.process && window.process.type === "renderer";
|
|
3734
|
-
}
|
|
3735
|
-
function isAlpine(platform9) {
|
|
3736
|
-
return platform9 === "linux" && fs.existsSync("/etc/alpine-release");
|
|
3737
|
-
}
|
|
3738
|
-
load.parseTags = parseTags;
|
|
3739
|
-
load.matchTags = matchTags;
|
|
3740
|
-
load.compareTags = compareTags;
|
|
3741
|
-
load.parseTuple = parseTuple;
|
|
3742
|
-
load.matchTuple = matchTuple;
|
|
3743
|
-
load.compareTuples = compareTuples;
|
|
3744
|
-
}
|
|
3745
|
-
});
|
|
3746
|
-
|
|
3747
|
-
// node_modules/node-gyp-build/index.js
|
|
3748
|
-
var require_node_gyp_build2 = __commonJS({
|
|
3749
|
-
"node_modules/node-gyp-build/index.js"(exports, module) {
|
|
3750
|
-
"use strict";
|
|
3751
|
-
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
3752
|
-
if (typeof runtimeRequire.addon === "function") {
|
|
3753
|
-
module.exports = runtimeRequire.addon.bind(runtimeRequire);
|
|
3754
|
-
} else {
|
|
3755
|
-
module.exports = require_node_gyp_build();
|
|
3756
|
-
}
|
|
3757
|
-
}
|
|
3758
|
-
});
|
|
3759
|
-
|
|
3760
|
-
// node_modules/isolated-vm/isolated-vm.js
|
|
3761
|
-
var require_isolated_vm = __commonJS({
|
|
3762
|
-
"node_modules/isolated-vm/isolated-vm.js"(exports, module) {
|
|
3763
|
-
"use strict";
|
|
3764
|
-
module.exports = require_node_gyp_build2()(__dirname).ivm;
|
|
3765
|
-
}
|
|
3766
|
-
});
|
|
3767
|
-
|
|
3768
3551
|
// src/code-mode/sandbox.ts
|
|
3769
3552
|
import { join as join12, dirname as dirname5 } from "path";
|
|
3770
3553
|
import { pathToFileURL } from "url";
|
|
@@ -3819,9 +3602,38 @@ async function transpileOrStrip(code, cwd) {
|
|
|
3819
3602
|
warnings: ["TypeScript not found in node_modules. Using fallback parser; install typescript for reliable transpilation."]
|
|
3820
3603
|
};
|
|
3821
3604
|
}
|
|
3605
|
+
async function loadIsolatedVm() {
|
|
3606
|
+
const mod = await import("isolated-vm");
|
|
3607
|
+
const ivm = mod.default?.Isolate ? mod.default : mod;
|
|
3608
|
+
if (typeof ivm.Isolate !== "function") throw new Error("isolated-vm loaded but exposes no Isolate constructor");
|
|
3609
|
+
return ivm;
|
|
3610
|
+
}
|
|
3611
|
+
function makeToolBridge(opts2, toolCalls) {
|
|
3612
|
+
let mutationTail = Promise.resolve();
|
|
3613
|
+
return (tool) => async (args) => {
|
|
3614
|
+
const invoke = async () => {
|
|
3615
|
+
const toolCallId = `code_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
3616
|
+
return opts2.executor.run(
|
|
3617
|
+
{ id: toolCallId, name: tool.name, arguments: JSON.stringify(args ?? {}) },
|
|
3618
|
+
opts2.askPermission,
|
|
3619
|
+
opts2.ctx
|
|
3620
|
+
);
|
|
3621
|
+
};
|
|
3622
|
+
let result2;
|
|
3623
|
+
if (tool.isReadOnly === true || tool.concurrent === true) {
|
|
3624
|
+
result2 = await invoke();
|
|
3625
|
+
} else {
|
|
3626
|
+
const run = mutationTail.then(invoke, invoke);
|
|
3627
|
+
mutationTail = run.catch(() => void 0);
|
|
3628
|
+
result2 = await run;
|
|
3629
|
+
}
|
|
3630
|
+
toolCalls.push({ name: tool.name, args, result: result2.content, ok: result2.ok });
|
|
3631
|
+
return result2.content;
|
|
3632
|
+
};
|
|
3633
|
+
}
|
|
3822
3634
|
async function runWithIsolatedVm(opts2) {
|
|
3823
|
-
const
|
|
3824
|
-
const isolate = new Isolate({ memoryLimit: opts2.memoryLimitMB ?? 128 });
|
|
3635
|
+
const ivm = await loadIsolatedVm();
|
|
3636
|
+
const isolate = new ivm.Isolate({ memoryLimit: opts2.memoryLimitMB ?? 128 });
|
|
3825
3637
|
const context = await isolate.createContext();
|
|
3826
3638
|
const jail = context.global;
|
|
3827
3639
|
await jail.set("global", jail.derefInto());
|
|
@@ -3835,30 +3647,15 @@ async function runWithIsolatedVm(opts2) {
|
|
|
3835
3647
|
{ arguments: { reference: true } }
|
|
3836
3648
|
);
|
|
3837
3649
|
await context.eval(`var console = { log: function(...args) { _log(args.map(String).join(" ")); } };`);
|
|
3838
|
-
const
|
|
3650
|
+
const bridge = makeToolBridge(opts2, toolCalls);
|
|
3839
3651
|
for (const tool of opts2.tools) {
|
|
3840
|
-
const
|
|
3841
|
-
|
|
3842
|
-
const args = JSON.parse(argsJson);
|
|
3843
|
-
const toolCallId = `code_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
3844
|
-
const result2 = await opts2.executor.run(
|
|
3845
|
-
{ id: toolCallId, name: tool.name, arguments: JSON.stringify(args) },
|
|
3846
|
-
opts2.askPermission,
|
|
3847
|
-
opts2.ctx
|
|
3848
|
-
);
|
|
3849
|
-
toolCalls.push({
|
|
3850
|
-
name: tool.name,
|
|
3851
|
-
args,
|
|
3852
|
-
result: result2.content
|
|
3853
|
-
});
|
|
3854
|
-
return result2.content;
|
|
3855
|
-
}
|
|
3856
|
-
);
|
|
3652
|
+
const call = bridge(tool);
|
|
3653
|
+
const host = async (argsJson) => call(JSON.parse(argsJson));
|
|
3857
3654
|
await context.evalClosure(
|
|
3858
3655
|
`globalThis["_api_${tool.name}"] = function(argsJson) {
|
|
3859
3656
|
return $0.applySyncPromise(undefined, [argsJson], { arguments: { copy: true } });
|
|
3860
3657
|
};`,
|
|
3861
|
-
[
|
|
3658
|
+
[host],
|
|
3862
3659
|
{ arguments: { reference: true } }
|
|
3863
3660
|
);
|
|
3864
3661
|
}
|
|
@@ -3932,22 +3729,10 @@ async function runWithNodeVm(opts2) {
|
|
|
3932
3729
|
NaN: NaN,
|
|
3933
3730
|
undefined: void 0
|
|
3934
3731
|
};
|
|
3732
|
+
const bridge = makeToolBridge(opts2, toolCalls);
|
|
3935
3733
|
for (const tool of opts2.tools) {
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
const toolCallId = `code_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
3939
|
-
const result2 = await opts2.executor.run(
|
|
3940
|
-
{ id: toolCallId, name: tool.name, arguments: JSON.stringify(args) },
|
|
3941
|
-
opts2.askPermission,
|
|
3942
|
-
opts2.ctx
|
|
3943
|
-
);
|
|
3944
|
-
toolCalls.push({
|
|
3945
|
-
name: tool.name,
|
|
3946
|
-
args,
|
|
3947
|
-
result: result2.content
|
|
3948
|
-
});
|
|
3949
|
-
return result2.content;
|
|
3950
|
-
};
|
|
3734
|
+
const call = bridge(tool);
|
|
3735
|
+
sandbox.api[tool.name] = (input) => call(input ?? {});
|
|
3951
3736
|
}
|
|
3952
3737
|
const { js: jsCode, warnings } = await transpileOrStrip(opts2.code, opts2.ctx.cwd);
|
|
3953
3738
|
const wrapped = `"use strict";
|
|
@@ -4047,7 +3832,7 @@ function truncateForEmbedding(text) {
|
|
|
4047
3832
|
return text.slice(0, MAX_EMBED_CHARS);
|
|
4048
3833
|
}
|
|
4049
3834
|
async function sleep2(ms) {
|
|
4050
|
-
return new Promise((
|
|
3835
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
4051
3836
|
}
|
|
4052
3837
|
async function fetchWithRetry(url, init, retries = 3) {
|
|
4053
3838
|
let lastError;
|
|
@@ -4662,7 +4447,8 @@ How to work:
|
|
|
4662
4447
|
- Prefer calling tools over guessing. Read files before editing them. Use \`glob\` and \`grep\` to explore code before assuming structure.
|
|
4663
4448
|
- Before any mutating tool call (write, edit, bash), state in one short sentence what you're about to do, then call the tool. The user will be asked to approve each mutating call.
|
|
4664
4449
|
- When the user asks for a change, make the change. Do not paste code in chat that you could apply with \`edit\` or \`write\`.
|
|
4665
|
-
-
|
|
4450
|
+
- For any request that needs two or more distinct steps, proactively create a visible checklist with \`tasks_set\` before doing work; do not wait for the user to ask. Keep it high-level (about 2\u20136 steps) and skip it only for a genuinely quick single-action request.
|
|
4451
|
+
- When working through a task list, call \`tasks_set\` **immediately before starting each new step** and **immediately after completing each step**. Pass the full list and show exactly one active step. Do not execute mutating tools (\`write\`, \`edit\`, \`bash\`) without updating task progress first.
|
|
4666
4452
|
- Keep responses concise, but make them useful: the user sees tool calls inline, so do not re-summarize routine progress.
|
|
4667
4453
|
- Treat blockers as problems to work through, not as a stopping point. After an error or failed attempt, diagnose the cause and try a safe, materially different recovery or verification path when possible; do not repeat the same failed attempt blindly.
|
|
4668
4454
|
- Prefer resolving a blocker yourself with available tools over shifting diagnosis to the user. If you still cannot finish after reasonable attempts, say what remains undone, why it is blocked, and the single most useful next action. Make that action concrete (for example, an exact command, setting to check, or specific input you need). Ask the user to act only when their access, choice, or interactive participation is genuinely required, and never imply unverified work succeeded.
|
|
@@ -4699,6 +4485,8 @@ If the user asks what model you are, answer with exactly: \`${opts2.model}\`. Th
|
|
|
4699
4485
|
- Today: ${date}`;
|
|
4700
4486
|
const hasLsp = opts2.tools.some((t) => t.name.startsWith("lsp_"));
|
|
4701
4487
|
const lspBlock = hasLsp ? "\n\nLSP tools are available for semantic code intelligence. Prefer `lsp_definition` over `grep` when looking for the source of a symbol. Prefer `lsp_references` over `grep` when finding usages. Use `lsp_hover` to confirm types before refactoring." : "";
|
|
4488
|
+
const hasArtifactTool = opts2.tools.some((t) => t.name === "create_artifact");
|
|
4489
|
+
const artifactGuidance = hasArtifactTool ? "\n\n## Choosing when to create an artifact\nUse `create_artifact` when the user would benefit from a visual, interactive, or polished standalone deliverable (for example, a dashboard, chart, diagram, prototype, or long structured report). Prefer a normal terminal response for brief answers, explanations, code snippets, and routine repository changes. For an artifact, first use `write` to save the complete HTML document as a local `.html` file in the workspace; then call `create_artifact` with a concise title and that file's workspace-relative `sourcePath`. Never put the full HTML document in `create_artifact` arguments. After it opens, summarize the result briefly in the terminal." : "";
|
|
4702
4490
|
const tools = `Tools available:
|
|
4703
4491
|
${toolsBlock}`;
|
|
4704
4492
|
const userShellBlock = userShellCommandsEnabled() ? `
|
|
@@ -4740,7 +4528,7 @@ ${opts2.lspContext}` : "";
|
|
|
4740
4528
|
The following MCP server information was pre-computed by the coordinator.
|
|
4741
4529
|
|
|
4742
4530
|
${opts2.mcpContext}` : "";
|
|
4743
|
-
return identity + "\n\n" + env2 + "\n\n" + tools + lspBlock + userShellBlock + contextBlock + modeBlock + skillsBlock + memoryBlock + lspContextBlock + mcpContextBlock;
|
|
4531
|
+
return identity + "\n\n" + env2 + "\n\n" + tools + artifactGuidance + lspBlock + userShellBlock + contextBlock + modeBlock + skillsBlock + memoryBlock + lspContextBlock + mcpContextBlock;
|
|
4744
4532
|
}
|
|
4745
4533
|
function buildSystemPrompt(opts2) {
|
|
4746
4534
|
return buildStaticPrefix(opts2) + "\n\n" + buildSessionPrefix(opts2);
|
|
@@ -5128,7 +4916,7 @@ function shouldCheckCompletion(input, tier) {
|
|
|
5128
4916
|
}
|
|
5129
4917
|
function createJevCompletionCheck(apiKey, ask = askJev) {
|
|
5130
4918
|
return async (input, signal) => {
|
|
5131
|
-
const
|
|
4919
|
+
const clip3 = (text, max) => redactPrompt(text.replace(/\s+/g, " ").trim()).slice(0, max);
|
|
5132
4920
|
const used = input.toolsUsed.length ? `${input.toolsUsed.length} tool calls (${[...new Set(input.toolsUsed)].join(", ")}); ${input.toolsUsed.some((t) => WRITE_TOOLS.has(t)) ? "it ran commands or edited files" : "it only read or searched"}` : "no tool calls";
|
|
5133
4921
|
const timeout = AbortSignal.timeout(COMPLETION_CHECK_TIMEOUT_MS);
|
|
5134
4922
|
try {
|
|
@@ -5136,9 +4924,9 @@ function createJevCompletionCheck(apiKey, ask = askJev) {
|
|
|
5136
4924
|
kind: "yes",
|
|
5137
4925
|
prompt: [
|
|
5138
4926
|
"Did the assistant end its turn legitimately \u2014 either by fully completing the user's request, or by clearly explaining a blocker or question that needs the user \u2014 as opposed to stopping early, only planning, or announcing next steps it has not done?",
|
|
5139
|
-
`User asked: ${
|
|
4927
|
+
`User asked: ${clip3(input.userRequest, 1200)}`,
|
|
5140
4928
|
`During the turn the assistant made ${used}.`,
|
|
5141
|
-
`Assistant's final message: ${
|
|
4929
|
+
`Assistant's final message: ${clip3(input.finalText, 1500)}`
|
|
5142
4930
|
].join("\n")
|
|
5143
4931
|
}, { signal: AbortSignal.any([timeout, signal]) });
|
|
5144
4932
|
return answer.type === "noul" && typeof answer.noul === "number" ? answer.noul : null;
|
|
@@ -5438,15 +5226,15 @@ async function gitNumstat(cwd, opts2 = {}) {
|
|
|
5438
5226
|
if (opts2.includeUntracked) {
|
|
5439
5227
|
try {
|
|
5440
5228
|
const { stdout } = await execFileAsync("git", ["ls-files", "--others", "--exclude-standard"], { cwd, timeout: 5e3 });
|
|
5441
|
-
const { readFile:
|
|
5442
|
-
const { join:
|
|
5229
|
+
const { readFile: readFile38, stat: stat15 } = await import("fs/promises");
|
|
5230
|
+
const { join: join59 } = await import("path");
|
|
5443
5231
|
for (const file of stdout.split("\n").filter(Boolean)) {
|
|
5444
5232
|
let lines = 0;
|
|
5445
5233
|
try {
|
|
5446
|
-
const path =
|
|
5447
|
-
const size = (await
|
|
5234
|
+
const path = join59(cwd, file);
|
|
5235
|
+
const size = (await stat15(path)).size;
|
|
5448
5236
|
if (size > 0 && size <= 1024 * 1024) {
|
|
5449
|
-
const text = await
|
|
5237
|
+
const text = await readFile38(path, "utf8");
|
|
5450
5238
|
lines = text.split("\n").length - (text.endsWith("\n") ? 1 : 0);
|
|
5451
5239
|
}
|
|
5452
5240
|
} catch {
|
|
@@ -5815,7 +5603,9 @@ ${codeModeApiString}
|
|
|
5815
5603
|
|
|
5816
5604
|
Use console.log() to return results. Only console.log output is sent back to you.
|
|
5817
5605
|
|
|
5818
|
-
IMPORTANT \u2014 explore through code, not direct tools: to read files, run shell commands, grep, or glob, call api.read(...), api.bash(...), api.grep(...), api.glob(...) INSIDE this code block and console.log only what you need. Do NOT call read/bash/grep/glob as separate tools \u2014 their full output floods your context, while here only what you log returns. Batch multiple reads/greps/commands into a single execute_code call
|
|
5606
|
+
IMPORTANT \u2014 explore through code, not direct tools: to read files, run shell commands, grep, or glob, call api.read(...), api.bash(...), api.grep(...), api.glob(...) INSIDE this code block and console.log only what you need. Do NOT call read/bash/grep/glob as separate tools \u2014 their full output floods your context, while here only what you log returns. Batch multiple reads/greps/commands into a single execute_code call.
|
|
5607
|
+
|
|
5608
|
+
Mutating calls (edit, write, bash, \u2026) run one at a time in call order even inside Promise.all; apply edits to the same file sequentially and re-read the file before editing it again.` + (directTools.length > 0 ? `
|
|
5819
5609
|
|
|
5820
5610
|
Not in this API \u2014 call these as separate tools instead: ${directTools.map((t) => t.name).join(", ")}.` : ""),
|
|
5821
5611
|
parameters: {
|
|
@@ -6048,11 +5838,11 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
6048
5838
|
opts2.callbacks.onToolCallArgs?.(ev.index, ev.argsDelta);
|
|
6049
5839
|
break;
|
|
6050
5840
|
case "tool_call_complete": {
|
|
6051
|
-
const
|
|
5841
|
+
const callArgs = validateToolArguments(ev.arguments, ev.name, ev.id, ev.finishReason, opts2.sessionId);
|
|
6052
5842
|
const call = {
|
|
6053
5843
|
id: ev.id,
|
|
6054
5844
|
type: "function",
|
|
6055
|
-
function: { name: normalizeToolName(ev.name, opts2.tools), arguments:
|
|
5845
|
+
function: { name: normalizeToolName(ev.name, opts2.tools), arguments: callArgs }
|
|
6056
5846
|
};
|
|
6057
5847
|
toolCalls.push(call);
|
|
6058
5848
|
tr.toolsUsed.push(call.function.name);
|
|
@@ -6535,6 +6325,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
6535
6325
|
turnId
|
|
6536
6326
|
);
|
|
6537
6327
|
}
|
|
6328
|
+
logger.debug("turn:code_mode_start", { sessionId: opts2.sessionId, toolCallId: tc.id, codeChars: code.length });
|
|
6538
6329
|
const sandboxResult = await runInSandbox({
|
|
6539
6330
|
code,
|
|
6540
6331
|
tools: sandboxTools,
|
|
@@ -6556,12 +6347,23 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
6556
6347
|
timeoutMs: 3e4,
|
|
6557
6348
|
memoryLimitMB: 128
|
|
6558
6349
|
});
|
|
6350
|
+
logger.debug("turn:code_mode_end", {
|
|
6351
|
+
sessionId: opts2.sessionId,
|
|
6352
|
+
toolCallId: tc.id,
|
|
6353
|
+
durationMs: Math.round(performance.now() - sandboxStartedAt),
|
|
6354
|
+
error: sandboxResult.error ?? null,
|
|
6355
|
+
calls: sandboxResult.toolCalls.map((c) => ({
|
|
6356
|
+
name: c.name,
|
|
6357
|
+
ok: c.ok,
|
|
6358
|
+
path: typeof c.args?.path === "string" ? c.args.path : void 0
|
|
6359
|
+
}))
|
|
6360
|
+
});
|
|
6559
6361
|
for (const stc of sandboxResult.toolCalls) {
|
|
6560
6362
|
const toolResult = {
|
|
6561
6363
|
tool_call_id: tc.id,
|
|
6562
6364
|
name: stc.name,
|
|
6563
6365
|
content: stc.result,
|
|
6564
|
-
ok:
|
|
6366
|
+
ok: stc.ok
|
|
6565
6367
|
};
|
|
6566
6368
|
toolResults.push(toolResult);
|
|
6567
6369
|
opts2.callbacks.onToolResult?.(toolResult);
|
|
@@ -6901,14 +6703,29 @@ function replaceMessagesInPlace(target, next) {
|
|
|
6901
6703
|
function normalizeToolName(name, tools) {
|
|
6902
6704
|
return name === "spawn_worker" && tools.some((t) => t.name === "subagent") ? "subagent" : name;
|
|
6903
6705
|
}
|
|
6904
|
-
function validateToolArguments(raw) {
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6706
|
+
function validateToolArguments(raw, name, id, finishReason, sessionId) {
|
|
6707
|
+
let issue = null;
|
|
6708
|
+
if (!raw.trim()) {
|
|
6709
|
+
issue = "empty arguments";
|
|
6710
|
+
} else {
|
|
6711
|
+
try {
|
|
6712
|
+
const parsed = JSON.parse(raw);
|
|
6713
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) issue = "arguments must be a JSON object";
|
|
6714
|
+
} catch (error) {
|
|
6715
|
+
issue = error instanceof Error ? error.message : "invalid JSON";
|
|
6716
|
+
}
|
|
6717
|
+
}
|
|
6718
|
+
if (issue) {
|
|
6719
|
+
logger.warn("turn:tool_arguments_invalid", {
|
|
6720
|
+
sessionId,
|
|
6721
|
+
tool: name,
|
|
6722
|
+
toolCallId: id,
|
|
6723
|
+
argumentBytes: Buffer.byteLength(raw, "utf8"),
|
|
6724
|
+
finishReason,
|
|
6725
|
+
issue
|
|
6726
|
+
});
|
|
6911
6727
|
}
|
|
6728
|
+
return raw;
|
|
6912
6729
|
}
|
|
6913
6730
|
function llmAuthOf(opts2) {
|
|
6914
6731
|
return {
|
|
@@ -7649,14 +7466,79 @@ var init_read = __esm({
|
|
|
7649
7466
|
}
|
|
7650
7467
|
});
|
|
7651
7468
|
|
|
7469
|
+
// src/util/file-lock.ts
|
|
7470
|
+
import { realpath } from "fs/promises";
|
|
7471
|
+
async function lockKeyFor(absPath) {
|
|
7472
|
+
try {
|
|
7473
|
+
return await realpath(absPath);
|
|
7474
|
+
} catch {
|
|
7475
|
+
return absPath;
|
|
7476
|
+
}
|
|
7477
|
+
}
|
|
7478
|
+
async function withFileLock2(absPath, fn) {
|
|
7479
|
+
const key = await lockKeyFor(absPath);
|
|
7480
|
+
const prev = tails.get(key) ?? Promise.resolve();
|
|
7481
|
+
const run = prev.then(fn, fn);
|
|
7482
|
+
const tail = run.then(
|
|
7483
|
+
() => void 0,
|
|
7484
|
+
() => void 0
|
|
7485
|
+
);
|
|
7486
|
+
tails.set(key, tail);
|
|
7487
|
+
try {
|
|
7488
|
+
return await run;
|
|
7489
|
+
} finally {
|
|
7490
|
+
if (tails.get(key) === tail) tails.delete(key);
|
|
7491
|
+
}
|
|
7492
|
+
}
|
|
7493
|
+
var tails;
|
|
7494
|
+
var init_file_lock = __esm({
|
|
7495
|
+
"src/util/file-lock.ts"() {
|
|
7496
|
+
"use strict";
|
|
7497
|
+
tails = /* @__PURE__ */ new Map();
|
|
7498
|
+
}
|
|
7499
|
+
});
|
|
7500
|
+
|
|
7501
|
+
// src/util/safe-write.ts
|
|
7502
|
+
import { chmod as chmod2, readFile as readFile7, rename as rename3, stat as stat5, unlink as unlink2, writeFile as writeFile6 } from "fs/promises";
|
|
7503
|
+
import { basename as basename2, dirname as dirname7, join as join16 } from "path";
|
|
7504
|
+
async function writeFileVerified(absPath, content) {
|
|
7505
|
+
const target = await lockKeyFor(absPath);
|
|
7506
|
+
let mode;
|
|
7507
|
+
try {
|
|
7508
|
+
mode = (await stat5(target)).mode & 511;
|
|
7509
|
+
} catch {
|
|
7510
|
+
}
|
|
7511
|
+
const tmp = join16(dirname7(target), `.${basename2(target)}.${process.pid}.${Math.random().toString(36).slice(2, 8)}.tmp`);
|
|
7512
|
+
try {
|
|
7513
|
+
await writeFile6(tmp, content, "utf8");
|
|
7514
|
+
if (mode !== void 0) await chmod2(tmp, mode);
|
|
7515
|
+
await rename3(tmp, target);
|
|
7516
|
+
} catch {
|
|
7517
|
+
await unlink2(tmp).catch(() => void 0);
|
|
7518
|
+
await writeFile6(target, content, "utf8");
|
|
7519
|
+
}
|
|
7520
|
+
const onDisk = await readFile7(target, "utf8");
|
|
7521
|
+
if (onDisk !== content) {
|
|
7522
|
+
throw new Error(`write verification failed for ${absPath}: file on disk does not match the intended content`);
|
|
7523
|
+
}
|
|
7524
|
+
}
|
|
7525
|
+
var init_safe_write = __esm({
|
|
7526
|
+
"src/util/safe-write.ts"() {
|
|
7527
|
+
"use strict";
|
|
7528
|
+
init_file_lock();
|
|
7529
|
+
}
|
|
7530
|
+
});
|
|
7531
|
+
|
|
7652
7532
|
// src/tools/write.ts
|
|
7653
|
-
import { mkdir as mkdir7, readFile as
|
|
7654
|
-
import { dirname as
|
|
7533
|
+
import { mkdir as mkdir7, readFile as readFile8 } from "fs/promises";
|
|
7534
|
+
import { dirname as dirname8 } from "path";
|
|
7655
7535
|
var writeTool;
|
|
7656
7536
|
var init_write = __esm({
|
|
7657
7537
|
"src/tools/write.ts"() {
|
|
7658
7538
|
"use strict";
|
|
7659
7539
|
init_paths2();
|
|
7540
|
+
init_file_lock();
|
|
7541
|
+
init_safe_write();
|
|
7660
7542
|
writeTool = {
|
|
7661
7543
|
name: "write",
|
|
7662
7544
|
description: "Create a file or overwrite an existing one with the given contents. Prompts the user for permission first and shows a diff preview.",
|
|
@@ -7676,22 +7558,30 @@ var init_write = __esm({
|
|
|
7676
7558
|
}),
|
|
7677
7559
|
async run(args, ctx) {
|
|
7678
7560
|
const abs = resolvePath(ctx.cwd, args.path);
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7561
|
+
return withFileLock2(abs, async () => {
|
|
7562
|
+
let before = "";
|
|
7563
|
+
try {
|
|
7564
|
+
before = await readFile8(abs, "utf8");
|
|
7565
|
+
} catch {
|
|
7566
|
+
}
|
|
7567
|
+
await mkdir7(dirname8(abs), { recursive: true });
|
|
7568
|
+
await writeFileVerified(abs, args.content);
|
|
7569
|
+
const verb = before ? "Overwrote" : "Created";
|
|
7570
|
+
return `${verb} ${args.path} (${args.content.length} chars).`;
|
|
7571
|
+
});
|
|
7688
7572
|
}
|
|
7689
7573
|
};
|
|
7690
7574
|
}
|
|
7691
7575
|
});
|
|
7692
7576
|
|
|
7693
7577
|
// src/tools/edit.ts
|
|
7694
|
-
import { readFile as
|
|
7578
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
7579
|
+
function replaceLiteral(haystack, needle, replacement, all) {
|
|
7580
|
+
if (all) return haystack.split(needle).join(replacement);
|
|
7581
|
+
const i = haystack.indexOf(needle);
|
|
7582
|
+
if (i === -1) return haystack;
|
|
7583
|
+
return haystack.slice(0, i) + replacement + haystack.slice(i + needle.length);
|
|
7584
|
+
}
|
|
7695
7585
|
function countOccurrences(haystack, needle) {
|
|
7696
7586
|
if (!needle) return 0;
|
|
7697
7587
|
let count = 0;
|
|
@@ -7708,6 +7598,8 @@ var init_edit = __esm({
|
|
|
7708
7598
|
"src/tools/edit.ts"() {
|
|
7709
7599
|
"use strict";
|
|
7710
7600
|
init_paths2();
|
|
7601
|
+
init_file_lock();
|
|
7602
|
+
init_safe_write();
|
|
7711
7603
|
editTool = {
|
|
7712
7604
|
name: "edit",
|
|
7713
7605
|
description: "Replace an exact string in a file. If replace_all is false (default), the old_string must appear exactly once or the call fails. Prompts the user for permission first and shows a diff preview.",
|
|
@@ -7729,17 +7621,19 @@ var init_edit = __esm({
|
|
|
7729
7621
|
}),
|
|
7730
7622
|
async run(args, ctx) {
|
|
7731
7623
|
const abs = resolvePath(ctx.cwd, args.path);
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
7624
|
+
return withFileLock2(abs, async () => {
|
|
7625
|
+
const orig = await readFile9(abs, "utf8");
|
|
7626
|
+
const occurrences = countOccurrences(orig, args.old_string);
|
|
7627
|
+
if (occurrences === 0) throw new Error(`old_string not found in ${args.path}`);
|
|
7628
|
+
if (occurrences > 1 && !args.replace_all) {
|
|
7629
|
+
throw new Error(
|
|
7630
|
+
`old_string appears ${occurrences} times in ${args.path}; pass replace_all=true or include more surrounding context`
|
|
7631
|
+
);
|
|
7632
|
+
}
|
|
7633
|
+
const next = replaceLiteral(orig, args.old_string, args.new_string, args.replace_all === true);
|
|
7634
|
+
await writeFileVerified(abs, next);
|
|
7635
|
+
return `Replaced ${occurrences} occurrence(s) in ${args.path}.`;
|
|
7636
|
+
});
|
|
7743
7637
|
}
|
|
7744
7638
|
};
|
|
7745
7639
|
}
|
|
@@ -7748,7 +7642,7 @@ var init_edit = __esm({
|
|
|
7748
7642
|
// src/tools/bash.ts
|
|
7749
7643
|
import { spawn } from "child_process";
|
|
7750
7644
|
import { tmpdir, platform as platform2 } from "os";
|
|
7751
|
-
import { join as
|
|
7645
|
+
import { join as join17 } from "path";
|
|
7752
7646
|
function getShellCommand(override) {
|
|
7753
7647
|
const raw = override?.trim();
|
|
7754
7648
|
if (raw && raw !== "auto") {
|
|
@@ -7813,15 +7707,15 @@ function makeErrorOutput(message2) {
|
|
|
7813
7707
|
return { content: message2, rawBytes: bytes, reducedBytes: bytes };
|
|
7814
7708
|
}
|
|
7815
7709
|
async function execOnce(command, cwd) {
|
|
7816
|
-
return new Promise((
|
|
7710
|
+
return new Promise((resolve20) => {
|
|
7817
7711
|
const child = spawn("bash", ["-lc", command], { cwd });
|
|
7818
7712
|
let out = "";
|
|
7819
7713
|
child.stdout.on("data", (d) => {
|
|
7820
7714
|
out += d.toString("utf8");
|
|
7821
7715
|
});
|
|
7822
7716
|
child.on("close", (code) => {
|
|
7823
|
-
if (code !== 0) return
|
|
7824
|
-
|
|
7717
|
+
if (code !== 0) return resolve20(void 0);
|
|
7718
|
+
resolve20(out.trim() || void 0);
|
|
7825
7719
|
});
|
|
7826
7720
|
});
|
|
7827
7721
|
}
|
|
@@ -7950,7 +7844,7 @@ function injectCoauthor(command, coauthor) {
|
|
|
7950
7844
|
if (movesHeadOnly) return unchanged;
|
|
7951
7845
|
const env2 = {
|
|
7952
7846
|
[COAUTHOR_TRAILER_ENV]: trailer,
|
|
7953
|
-
[COAUTHOR_MSG_ENV]:
|
|
7847
|
+
[COAUTHOR_MSG_ENV]: join17(tmpdir(), `kf-coauthor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`)
|
|
7954
7848
|
};
|
|
7955
7849
|
if (createsCommit || isRebaseContinue) {
|
|
7956
7850
|
return { command: `(${command}) && { ${AMEND_BLOCK}
|
|
@@ -7975,7 +7869,7 @@ async function runBash(args, ctx) {
|
|
|
7975
7869
|
if (pushGuard) return pushGuard;
|
|
7976
7870
|
const { shell, args: shellArgs, isPosix } = getShellCommand(ctx.shell);
|
|
7977
7871
|
const { command, env: coauthorEnv } = isPosix ? injectCoauthor(args.command, ctx.coauthor) : { command: args.command, env: {} };
|
|
7978
|
-
return new Promise((
|
|
7872
|
+
return new Promise((resolve20, reject) => {
|
|
7979
7873
|
logger.debug("bash:spawn", { command: args.command.slice(0, 200), cwd: ctx.cwd, shell });
|
|
7980
7874
|
const child = spawn(shell, [...shellArgs, command], {
|
|
7981
7875
|
cwd: ctx.cwd,
|
|
@@ -8040,7 +7934,7 @@ ${stderr}`
|
|
|
8040
7934
|
if (hint) parts.push(hint);
|
|
8041
7935
|
}
|
|
8042
7936
|
const raw = parts.join("\n");
|
|
8043
|
-
|
|
7937
|
+
resolve20({
|
|
8044
7938
|
content: raw,
|
|
8045
7939
|
rawBytes: Buffer.byteLength(raw, "utf8"),
|
|
8046
7940
|
reducedBytes: Buffer.byteLength(raw, "utf8"),
|
|
@@ -8091,8 +7985,8 @@ var init_bash = __esm({
|
|
|
8091
7985
|
});
|
|
8092
7986
|
|
|
8093
7987
|
// src/util/glob.ts
|
|
8094
|
-
import { readdir as readdir3, lstat, realpath } from "fs/promises";
|
|
8095
|
-
import { join as
|
|
7988
|
+
import { readdir as readdir3, lstat, realpath as realpath2 } from "fs/promises";
|
|
7989
|
+
import { join as join18, relative as relative2, resolve as resolve2 } from "path";
|
|
8096
7990
|
function parsePattern(pattern) {
|
|
8097
7991
|
const parts = pattern.split(/\//g);
|
|
8098
7992
|
return parts.map((p) => {
|
|
@@ -8201,7 +8095,7 @@ async function* walk(root, pattern, options) {
|
|
|
8201
8095
|
if (!dot && name.startsWith(".")) continue;
|
|
8202
8096
|
const matched = seg.type === "literal" ? seg.value === name : matchSegment(name, seg.value);
|
|
8203
8097
|
if (!matched) continue;
|
|
8204
|
-
const childPath =
|
|
8098
|
+
const childPath = join18(dirPath, name);
|
|
8205
8099
|
const childRel = [...relativeParts, name];
|
|
8206
8100
|
const childRelStr = childRel.join("/");
|
|
8207
8101
|
if (shouldIgnore(childRelStr, ignorePatterns)) continue;
|
|
@@ -8226,14 +8120,14 @@ async function* walk(root, pattern, options) {
|
|
|
8226
8120
|
if (!dot && name.startsWith(".")) continue;
|
|
8227
8121
|
const matched = seg.type === "literal" ? seg.value === name : matchSegment(name, seg.value);
|
|
8228
8122
|
if (!matched) continue;
|
|
8229
|
-
const childPath =
|
|
8123
|
+
const childPath = join18(dirPath, name);
|
|
8230
8124
|
const childRel = [...relativeParts, name];
|
|
8231
8125
|
const childRelStr = childRel.join("/");
|
|
8232
8126
|
if (shouldIgnore(childRelStr, ignorePatterns)) continue;
|
|
8233
8127
|
let isDir = ent.isDirectory();
|
|
8234
8128
|
if (!isDir && followSymbolicLinks && ent.isSymbolicLink()) {
|
|
8235
8129
|
try {
|
|
8236
|
-
const rp = await
|
|
8130
|
+
const rp = await realpath2(childPath);
|
|
8237
8131
|
const s = await lstat(rp);
|
|
8238
8132
|
isDir = s.isDirectory();
|
|
8239
8133
|
} catch {
|
|
@@ -8268,7 +8162,7 @@ async function* walk(root, pattern, options) {
|
|
|
8268
8162
|
const name = String(ent.name);
|
|
8269
8163
|
if (name === "." || name === "..") continue;
|
|
8270
8164
|
if (!dot && name.startsWith(".")) continue;
|
|
8271
|
-
const childPath =
|
|
8165
|
+
const childPath = join18(dirPath, name);
|
|
8272
8166
|
const childRel = [...relativeParts, name];
|
|
8273
8167
|
const childRelStr = childRel.join("/");
|
|
8274
8168
|
if (shouldIgnore(childRelStr, ignorePatterns)) continue;
|
|
@@ -8276,7 +8170,7 @@ async function* walk(root, pattern, options) {
|
|
|
8276
8170
|
let isDir = ent.isDirectory();
|
|
8277
8171
|
if (!isDir && followSymbolicLinks && ent.isSymbolicLink()) {
|
|
8278
8172
|
try {
|
|
8279
|
-
const rp = await
|
|
8173
|
+
const rp = await realpath2(childPath);
|
|
8280
8174
|
const s = await lstat(rp);
|
|
8281
8175
|
isDir = s.isDirectory();
|
|
8282
8176
|
} catch {
|
|
@@ -8435,7 +8329,7 @@ var init_glob2 = __esm({
|
|
|
8435
8329
|
// src/tools/grep.ts
|
|
8436
8330
|
import { execFile as execFile2 } from "child_process";
|
|
8437
8331
|
import { promisify as promisify2 } from "util";
|
|
8438
|
-
import { readFile as
|
|
8332
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
8439
8333
|
async function hasRipgrep() {
|
|
8440
8334
|
if (cachedHasRg !== null) return cachedHasRg;
|
|
8441
8335
|
try {
|
|
@@ -8482,7 +8376,7 @@ async function runJsFallback(args, root, mode, signal) {
|
|
|
8482
8376
|
if (signal?.aborted) throw new DOMException("aborted", "AbortError");
|
|
8483
8377
|
const file = files[fi];
|
|
8484
8378
|
try {
|
|
8485
|
-
const content = await
|
|
8379
|
+
const content = await readFile10(file, "utf8");
|
|
8486
8380
|
if (mode === "files") {
|
|
8487
8381
|
if (re.test(content)) out.push(file);
|
|
8488
8382
|
} else {
|
|
@@ -9085,9 +8979,9 @@ var changelog_image_exports = {};
|
|
|
9085
8979
|
__export(changelog_image_exports, {
|
|
9086
8980
|
changelogImageTool: () => changelogImageTool
|
|
9087
8981
|
});
|
|
9088
|
-
import { readFile as
|
|
9089
|
-
import { writeFile as
|
|
9090
|
-
import { join as
|
|
8982
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
8983
|
+
import { writeFile as writeFile7 } from "fs/promises";
|
|
8984
|
+
import { join as join19 } from "path";
|
|
9091
8985
|
async function githubFetch2(path, token) {
|
|
9092
8986
|
const controller = new AbortController();
|
|
9093
8987
|
const timer3 = setTimeout(() => controller.abort(), TIMEOUT_MS4);
|
|
@@ -9118,7 +9012,7 @@ function escapeXml(str) {
|
|
|
9118
9012
|
}
|
|
9119
9013
|
async function loadLogoBase64() {
|
|
9120
9014
|
try {
|
|
9121
|
-
const buf = await
|
|
9015
|
+
const buf = await readFile11(join19(process.cwd(), "docs", "logo.png"));
|
|
9122
9016
|
return `data:image/png;base64,${buf.toString("base64")}`;
|
|
9123
9017
|
} catch {
|
|
9124
9018
|
return null;
|
|
@@ -9420,7 +9314,7 @@ Format your response as plain text bullet points, one per line, starting with "\
|
|
|
9420
9314
|
setTask("4", "completed");
|
|
9421
9315
|
setTask("5", "in_progress");
|
|
9422
9316
|
const outputPath = args.output ?? `./changelog-${args.repo}-${version.replace(/[^a-zA-Z0-9._-]/g, "_")}.png`;
|
|
9423
|
-
await
|
|
9317
|
+
await writeFile7(outputPath, pngBuffer);
|
|
9424
9318
|
setTask("5", "completed");
|
|
9425
9319
|
const periodLabel = days === 1 ? "past day" : `past ${days} days`;
|
|
9426
9320
|
const content = `\u2713 Changelog image saved to ${outputPath}
|
|
@@ -9435,10 +9329,10 @@ Format your response as plain text bullet points, one per line, starting with "\
|
|
|
9435
9329
|
// src/tools/browser.ts
|
|
9436
9330
|
import { mkdir as mkdir8 } from "fs/promises";
|
|
9437
9331
|
import { tmpdir as tmpdir2 } from "os";
|
|
9438
|
-
import { join as
|
|
9332
|
+
import { join as join20, dirname as dirname9 } from "path";
|
|
9439
9333
|
async function autoScroll(page) {
|
|
9440
9334
|
await page.evaluate(async () => {
|
|
9441
|
-
await new Promise((
|
|
9335
|
+
await new Promise((resolve20) => {
|
|
9442
9336
|
let totalHeight = 0;
|
|
9443
9337
|
const distance = 300;
|
|
9444
9338
|
const timer3 = setInterval(() => {
|
|
@@ -9447,12 +9341,12 @@ async function autoScroll(page) {
|
|
|
9447
9341
|
totalHeight += distance;
|
|
9448
9342
|
if (totalHeight >= scrollHeight) {
|
|
9449
9343
|
clearInterval(timer3);
|
|
9450
|
-
|
|
9344
|
+
resolve20();
|
|
9451
9345
|
}
|
|
9452
9346
|
}, 100);
|
|
9453
9347
|
setTimeout(() => {
|
|
9454
9348
|
clearInterval(timer3);
|
|
9455
|
-
|
|
9349
|
+
resolve20();
|
|
9456
9350
|
}, 1e4);
|
|
9457
9351
|
});
|
|
9458
9352
|
});
|
|
@@ -9511,8 +9405,8 @@ var init_browser = __esm({
|
|
|
9511
9405
|
}
|
|
9512
9406
|
let screenshotPath;
|
|
9513
9407
|
if (args.screenshot) {
|
|
9514
|
-
screenshotPath =
|
|
9515
|
-
await mkdir8(
|
|
9408
|
+
screenshotPath = join20(tmpdir2(), `kimiflare-browser-${Date.now()}.png`);
|
|
9409
|
+
await mkdir8(dirname9(screenshotPath), { recursive: true });
|
|
9516
9410
|
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
9517
9411
|
}
|
|
9518
9412
|
const text = await page.evaluate(() => {
|
|
@@ -9551,6 +9445,288 @@ var init_browser = __esm({
|
|
|
9551
9445
|
}
|
|
9552
9446
|
});
|
|
9553
9447
|
|
|
9448
|
+
// src/util/open-browser.ts
|
|
9449
|
+
import { spawn as spawn2 } from "child_process";
|
|
9450
|
+
import { platform as platform3 } from "os";
|
|
9451
|
+
function openBrowser(url) {
|
|
9452
|
+
if (process.env.KIMIFLARE_NO_BROWSER === "1" || process.env.BROWSER === "none") return false;
|
|
9453
|
+
try {
|
|
9454
|
+
const os2 = platform3();
|
|
9455
|
+
const [cmd, args] = os2 === "darwin" ? ["open", [url]] : os2 === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
9456
|
+
const child = spawn2(cmd, args, { detached: true, stdio: "ignore" });
|
|
9457
|
+
child.on("error", () => void 0);
|
|
9458
|
+
child.unref();
|
|
9459
|
+
return true;
|
|
9460
|
+
} catch {
|
|
9461
|
+
return false;
|
|
9462
|
+
}
|
|
9463
|
+
}
|
|
9464
|
+
var init_open_browser = __esm({
|
|
9465
|
+
"src/util/open-browser.ts"() {
|
|
9466
|
+
"use strict";
|
|
9467
|
+
}
|
|
9468
|
+
});
|
|
9469
|
+
|
|
9470
|
+
// src/tools/html-artifact.ts
|
|
9471
|
+
import { chmod as chmod3, lstat as lstat2, mkdir as mkdir9, mkdtemp, readFile as readFile12, readdir as readdir4, realpath as realpath3, rm as rm2, stat as stat6, writeFile as writeFile9 } from "fs/promises";
|
|
9472
|
+
import { execFileSync } from "child_process";
|
|
9473
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
9474
|
+
import { isAbsolute as isAbsolute2, join as join21, relative as relative3, resolve as resolve3, sep as sep2 } from "path";
|
|
9475
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
9476
|
+
async function createHtmlArtifactFromFile(args, cwd, options = {}) {
|
|
9477
|
+
assertArtifactSourceArgs(args);
|
|
9478
|
+
const workspaceRoot = await getWorkspaceRoot(cwd);
|
|
9479
|
+
const workspaceReal = await realpath3(workspaceRoot);
|
|
9480
|
+
const inputPath = resolvePath(cwd, args.sourcePath);
|
|
9481
|
+
let inputReal;
|
|
9482
|
+
try {
|
|
9483
|
+
inputReal = await realpath3(inputPath);
|
|
9484
|
+
} catch (error) {
|
|
9485
|
+
if (error.code === "ENOENT") {
|
|
9486
|
+
throw new ToolError({
|
|
9487
|
+
code: "not_found",
|
|
9488
|
+
message: `Artifact source file not found: ${args.sourcePath}`,
|
|
9489
|
+
suggestion: "Use the write tool to create the complete HTML file first, then pass its path as sourcePath."
|
|
9490
|
+
});
|
|
9491
|
+
}
|
|
9492
|
+
throw error;
|
|
9493
|
+
}
|
|
9494
|
+
if (!isWithin(workspaceReal, inputReal)) {
|
|
9495
|
+
throw new ToolError({
|
|
9496
|
+
code: "policy_rejection",
|
|
9497
|
+
message: "Artifact sourcePath must resolve to a file inside the current workspace.",
|
|
9498
|
+
suggestion: "Write the HTML file inside the workspace and retry with its workspace-relative path."
|
|
9499
|
+
});
|
|
9500
|
+
}
|
|
9501
|
+
const info = await stat6(inputReal);
|
|
9502
|
+
if (!info.isFile()) {
|
|
9503
|
+
throw new ToolError({ code: "invalid_args", message: "Artifact sourcePath must be a regular HTML file." });
|
|
9504
|
+
}
|
|
9505
|
+
if (info.size > MAX_ARTIFACT_HTML_LENGTH * 4) {
|
|
9506
|
+
throw new ToolError({ code: "invalid_args", message: `Artifact HTML exceeds ${MAX_ARTIFACT_HTML_LENGTH} characters.` });
|
|
9507
|
+
}
|
|
9508
|
+
const html = await readFile12(inputReal, "utf8");
|
|
9509
|
+
return createHtmlArtifact({ title: args.title, html }, cwd, options);
|
|
9510
|
+
}
|
|
9511
|
+
async function createHtmlArtifact(args, cwd, options = {}) {
|
|
9512
|
+
assertArtifactHtmlArgs(args);
|
|
9513
|
+
const rootDir = options.rootDir ?? join21(tmpdir3(), ARTIFACT_ROOT);
|
|
9514
|
+
const workspaceRoot = await getWorkspaceRoot(cwd);
|
|
9515
|
+
const workspaceReal = await realpath3(workspaceRoot);
|
|
9516
|
+
if (isWithin(workspaceReal, resolve3(rootDir))) {
|
|
9517
|
+
throw new Error("Refusing to store an artifact inside the workspace: " + rootDir);
|
|
9518
|
+
}
|
|
9519
|
+
await ensureSecureRoot(rootDir);
|
|
9520
|
+
const rootReal = await realpath3(rootDir);
|
|
9521
|
+
if (isWithin(workspaceReal, rootReal)) {
|
|
9522
|
+
throw new Error("Refusing to store an artifact inside the workspace: " + rootReal);
|
|
9523
|
+
}
|
|
9524
|
+
await cleanupOldArtifacts(rootDir, (options.now ?? Date.now)());
|
|
9525
|
+
const artifactDir = await mkdtemp(join21(rootDir, ARTIFACT_PREFIX));
|
|
9526
|
+
await chmod3(artifactDir, 448);
|
|
9527
|
+
const filePath = join21(artifactDir, "index.html");
|
|
9528
|
+
await writeFile9(filePath, buildArtifactHtml(args.title, args.html), {
|
|
9529
|
+
encoding: "utf8",
|
|
9530
|
+
flag: "wx",
|
|
9531
|
+
mode: 384
|
|
9532
|
+
});
|
|
9533
|
+
const opened = (options.open ?? openBrowser)(pathToFileURL2(filePath).href);
|
|
9534
|
+
const status = opened ? "Opened in your browser." : "Could not open a browser automatically.";
|
|
9535
|
+
return "Artifact: " + args.title + "\n" + status + "\nTemporary file: " + filePath;
|
|
9536
|
+
}
|
|
9537
|
+
async function cleanupOldArtifacts(rootDir, now2 = Date.now()) {
|
|
9538
|
+
let entries;
|
|
9539
|
+
try {
|
|
9540
|
+
entries = await readdir4(rootDir, { withFileTypes: true });
|
|
9541
|
+
} catch {
|
|
9542
|
+
return;
|
|
9543
|
+
}
|
|
9544
|
+
for (const entry of entries) {
|
|
9545
|
+
if (!entry.name.startsWith(ARTIFACT_PREFIX) || !entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
9546
|
+
const path = join21(rootDir, entry.name);
|
|
9547
|
+
try {
|
|
9548
|
+
const info = await lstat2(path);
|
|
9549
|
+
if (!info.isDirectory() || info.isSymbolicLink() || now2 - info.mtimeMs < ARTIFACT_MAX_AGE_MS) continue;
|
|
9550
|
+
await rm2(path, { recursive: true, force: true });
|
|
9551
|
+
} catch {
|
|
9552
|
+
}
|
|
9553
|
+
}
|
|
9554
|
+
}
|
|
9555
|
+
function buildArtifactHtml(title, html) {
|
|
9556
|
+
assertArtifactHtmlArgs({ title, html });
|
|
9557
|
+
const safeTitle = escapeHtml(title);
|
|
9558
|
+
const safeSrcdoc = escapeAttribute(html);
|
|
9559
|
+
const lines = [
|
|
9560
|
+
"<!doctype html>",
|
|
9561
|
+
'<html lang="en">',
|
|
9562
|
+
"<head>",
|
|
9563
|
+
' <meta charset="utf-8">',
|
|
9564
|
+
' <meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
9565
|
+
' <meta name="theme-color" content="#090909">',
|
|
9566
|
+
" <title>" + safeTitle + " \xB7 Autopilot</title>",
|
|
9567
|
+
" <style>",
|
|
9568
|
+
' :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }',
|
|
9569
|
+
" * { box-sizing: border-box; }",
|
|
9570
|
+
" html, body { width: 100%; height: 100%; margin: 0; }",
|
|
9571
|
+
" body { display: grid; grid-template-rows: auto minmax(0, 1fr); overflow: hidden; background: #090909; color: #f4f4f5; }",
|
|
9572
|
+
" .autopilot-bar { position: sticky; top: 0; z-index: 10; display: flex; min-height: 54px; align-items: center; justify-content: space-between; gap: 16px; padding: 0 22px; border-bottom: 1px solid #262626; background: rgba(9, 9, 9, .96); backdrop-filter: blur(12px); }",
|
|
9573
|
+
" .autopilot-brand { display: inline-flex; align-items: center; gap: 9px; color: #f5f5f5; font-size: 14px; font-weight: 650; letter-spacing: -.025em; text-decoration: none; }",
|
|
9574
|
+
" .autopilot-mark { width: 20px; height: 20px; flex: none; }",
|
|
9575
|
+
" .autopilot-actions { display: flex; align-items: center; gap: 16px; }",
|
|
9576
|
+
" .autopilot-actions a { color: #a3a3a3; font-size: 12px; text-decoration: none; transition: color .15s ease; }",
|
|
9577
|
+
" .autopilot-actions a:hover { color: #fff; }",
|
|
9578
|
+
" .autopilot-actions .star { padding: 7px 11px; border: 1px solid #343434; border-radius: 7px; color: #f0f0f0; }",
|
|
9579
|
+
" .autopilot-actions .star:hover { border-color: #ff9933; color: #ffb15c; }",
|
|
9580
|
+
" main { min-width: 0; min-height: 0; }",
|
|
9581
|
+
" iframe { display: block; width: 100%; height: 100%; border: 0; background: #fff; }",
|
|
9582
|
+
" @media (max-width: 520px) { .autopilot-bar { min-height: 48px; padding: 0 14px; } .autopilot-actions { gap: 10px; } .autopilot-actions a { font-size: 11px; } }",
|
|
9583
|
+
" </style>",
|
|
9584
|
+
"</head>",
|
|
9585
|
+
"<body>",
|
|
9586
|
+
' <header class="autopilot-bar">',
|
|
9587
|
+
' <a class="autopilot-brand" href="' + AUTOPILOT_URL + '" target="_blank" rel="noopener noreferrer" aria-label="Autopilot on GitHub">',
|
|
9588
|
+
' <svg class="autopilot-mark" viewBox="0 0 24 24" role="img" aria-label="Autopilot logo" xmlns="http://www.w3.org/2000/svg">',
|
|
9589
|
+
' <path fill="#ff9933" d="M12 1.8a10.2 10.2 0 1 0 10.2 10.2A10.21 10.21 0 0 0 12 1.8Zm0 2.3a7.9 7.9 0 1 1 0 15.8 7.9 7.9 0 0 1 0-15.8Z"/>',
|
|
9590
|
+
' <path fill="#ff9933" d="m6.9 16.8 4.3-9.6c.3-.7 1.3-.7 1.6 0l4.3 9.6h-2.5l-2.6-6-2.6 6H6.9Z"/>',
|
|
9591
|
+
" </svg>",
|
|
9592
|
+
" <span>autopilot</span>",
|
|
9593
|
+
" </a>",
|
|
9594
|
+
' <nav class="autopilot-actions" aria-label="Autopilot links">',
|
|
9595
|
+
' <a href="' + AUTOPILOT_URL + '" target="_blank" rel="noopener noreferrer">About Autopilot \u2197</a>',
|
|
9596
|
+
' <a class="star" href="' + AUTOPILOT_URL + '" target="_blank" rel="noopener noreferrer" aria-label="Star Autopilot on GitHub">\u2606 Star on GitHub</a>',
|
|
9597
|
+
" </nav>",
|
|
9598
|
+
" </header>",
|
|
9599
|
+
' <main><iframe title="' + escapeAttribute(title) + '" sandbox="allow-scripts" srcdoc="' + safeSrcdoc + '"></iframe></main>',
|
|
9600
|
+
"</body>",
|
|
9601
|
+
"</html>"
|
|
9602
|
+
];
|
|
9603
|
+
return lines.join("\n") + "\n";
|
|
9604
|
+
}
|
|
9605
|
+
function assertArtifactSourceArgs(value) {
|
|
9606
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
9607
|
+
throw new ToolError({
|
|
9608
|
+
code: "invalid_args",
|
|
9609
|
+
recoverable: true,
|
|
9610
|
+
message: "Invalid create_artifact arguments: expected an object with a title and sourcePath.",
|
|
9611
|
+
suggestion: "Use write to save the complete HTML file in the workspace, then pass its path as sourcePath."
|
|
9612
|
+
});
|
|
9613
|
+
}
|
|
9614
|
+
const args = value;
|
|
9615
|
+
const issues = [];
|
|
9616
|
+
if (typeof args.title !== "string" || args.title.trim().length === 0 || args.title.length > MAX_ARTIFACT_TITLE_LENGTH) {
|
|
9617
|
+
issues.push(`title must be a non-empty string of at most ${MAX_ARTIFACT_TITLE_LENGTH} characters`);
|
|
9618
|
+
}
|
|
9619
|
+
if (typeof args.sourcePath !== "string" || args.sourcePath.trim().length === 0) {
|
|
9620
|
+
issues.push("sourcePath must be a non-empty path to an HTML file created with write");
|
|
9621
|
+
}
|
|
9622
|
+
if (issues.length > 0) {
|
|
9623
|
+
throw new ToolError({
|
|
9624
|
+
code: "invalid_args",
|
|
9625
|
+
recoverable: true,
|
|
9626
|
+
message: `Invalid create_artifact arguments: ${issues.join("; ")}.`,
|
|
9627
|
+
suggestion: "Use write to save the complete HTML file in the workspace, then call create_artifact with its title and sourcePath."
|
|
9628
|
+
});
|
|
9629
|
+
}
|
|
9630
|
+
}
|
|
9631
|
+
function assertArtifactHtmlArgs(value) {
|
|
9632
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
9633
|
+
throw new ToolError({
|
|
9634
|
+
code: "invalid_args",
|
|
9635
|
+
recoverable: true,
|
|
9636
|
+
message: "Invalid artifact content: expected an object with a title and HTML document.",
|
|
9637
|
+
suggestion: "Provide a non-empty title and complete HTML content."
|
|
9638
|
+
});
|
|
9639
|
+
}
|
|
9640
|
+
const args = value;
|
|
9641
|
+
const issues = [];
|
|
9642
|
+
if (typeof args.title !== "string" || args.title.trim().length === 0 || args.title.length > MAX_ARTIFACT_TITLE_LENGTH) {
|
|
9643
|
+
issues.push(`title must be a non-empty string of at most ${MAX_ARTIFACT_TITLE_LENGTH} characters`);
|
|
9644
|
+
}
|
|
9645
|
+
if (typeof args.html !== "string" || args.html.trim().length === 0 || args.html.length > MAX_ARTIFACT_HTML_LENGTH) {
|
|
9646
|
+
issues.push(`html must be a non-empty string of at most ${MAX_ARTIFACT_HTML_LENGTH} characters`);
|
|
9647
|
+
}
|
|
9648
|
+
if (issues.length > 0) {
|
|
9649
|
+
throw new ToolError({
|
|
9650
|
+
code: "invalid_args",
|
|
9651
|
+
recoverable: true,
|
|
9652
|
+
message: `Invalid artifact content: ${issues.join("; ")}.`,
|
|
9653
|
+
suggestion: "Supply a non-empty title and complete HTML document."
|
|
9654
|
+
});
|
|
9655
|
+
}
|
|
9656
|
+
}
|
|
9657
|
+
async function ensureSecureRoot(rootDir) {
|
|
9658
|
+
await mkdir9(rootDir, { recursive: true, mode: 448 });
|
|
9659
|
+
const info = await lstat2(rootDir);
|
|
9660
|
+
if (!info.isDirectory() || info.isSymbolicLink()) throw new Error("Artifact storage path is not a real directory: " + rootDir);
|
|
9661
|
+
if (typeof process.getuid === "function" && info.uid !== process.getuid()) {
|
|
9662
|
+
throw new Error("Artifact storage directory is not owned by the current user: " + rootDir);
|
|
9663
|
+
}
|
|
9664
|
+
if ((info.mode & 63) !== 0) await chmod3(rootDir, 448);
|
|
9665
|
+
}
|
|
9666
|
+
async function getWorkspaceRoot(cwd) {
|
|
9667
|
+
try {
|
|
9668
|
+
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
9669
|
+
cwd,
|
|
9670
|
+
encoding: "utf8",
|
|
9671
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
9672
|
+
}).trim();
|
|
9673
|
+
} catch {
|
|
9674
|
+
return cwd;
|
|
9675
|
+
}
|
|
9676
|
+
}
|
|
9677
|
+
function isWithin(parent, candidate) {
|
|
9678
|
+
const rel = relative3(parent, candidate);
|
|
9679
|
+
return rel === "" || rel !== ".." && !rel.startsWith(".." + sep2) && !isAbsolute2(rel);
|
|
9680
|
+
}
|
|
9681
|
+
function escapeHtml(value) {
|
|
9682
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
9683
|
+
}
|
|
9684
|
+
function escapeAttribute(value) {
|
|
9685
|
+
return escapeHtml(value).replaceAll('"', """).replaceAll("'", "'");
|
|
9686
|
+
}
|
|
9687
|
+
var ARTIFACT_ROOT, ARTIFACT_PREFIX, ARTIFACT_MAX_AGE_MS, AUTOPILOT_URL, MAX_ARTIFACT_TITLE_LENGTH, MAX_ARTIFACT_HTML_LENGTH, htmlArtifactTool;
|
|
9688
|
+
var init_html_artifact = __esm({
|
|
9689
|
+
"src/tools/html-artifact.ts"() {
|
|
9690
|
+
"use strict";
|
|
9691
|
+
init_paths2();
|
|
9692
|
+
init_open_browser();
|
|
9693
|
+
init_tool_error();
|
|
9694
|
+
ARTIFACT_ROOT = "autopilot-artifacts";
|
|
9695
|
+
ARTIFACT_PREFIX = "artifact-";
|
|
9696
|
+
ARTIFACT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
9697
|
+
AUTOPILOT_URL = "https://github.com/sinameraji/autopilot";
|
|
9698
|
+
MAX_ARTIFACT_TITLE_LENGTH = 160;
|
|
9699
|
+
MAX_ARTIFACT_HTML_LENGTH = 1e6;
|
|
9700
|
+
htmlArtifactTool = {
|
|
9701
|
+
name: "create_artifact",
|
|
9702
|
+
description: "Open a polished standalone HTML artifact in the user's browser. First use the normal write tool to save the complete HTML document as a local .html file in the workspace. Then call create_artifact with its title and sourcePath; do not pass the full HTML as a tool argument. The source file is kept in the workspace, and a branded, sandboxed browser copy is stored outside the project. Use for visual or interactive deliverables, dashboards, diagrams, prototypes, and substantial structured reports\u2014not short answers, explanations, code snippets, or routine code changes.",
|
|
9703
|
+
parameters: {
|
|
9704
|
+
type: "object",
|
|
9705
|
+
properties: {
|
|
9706
|
+
title: {
|
|
9707
|
+
type: "string",
|
|
9708
|
+
description: "Non-empty, short human-readable artifact title."
|
|
9709
|
+
},
|
|
9710
|
+
sourcePath: {
|
|
9711
|
+
type: "string",
|
|
9712
|
+
description: "Workspace-relative path to the complete HTML file already created with the write tool."
|
|
9713
|
+
}
|
|
9714
|
+
},
|
|
9715
|
+
required: ["title", "sourcePath"],
|
|
9716
|
+
additionalProperties: false
|
|
9717
|
+
},
|
|
9718
|
+
needsPermission: true,
|
|
9719
|
+
render: (args) => ({
|
|
9720
|
+
title: "create artifact: " + String(args.title ?? "Missing title").slice(0, 80),
|
|
9721
|
+
body: `Read ${String(args.sourcePath ?? "Missing sourcePath")} \xB7 opens in your browser`
|
|
9722
|
+
}),
|
|
9723
|
+
async run(args, ctx) {
|
|
9724
|
+
return createHtmlArtifactFromFile(args, ctx.cwd);
|
|
9725
|
+
}
|
|
9726
|
+
};
|
|
9727
|
+
}
|
|
9728
|
+
});
|
|
9729
|
+
|
|
9554
9730
|
// src/tools/tasks.ts
|
|
9555
9731
|
var tasksSetTool;
|
|
9556
9732
|
var init_tasks = __esm({
|
|
@@ -9561,8 +9737,8 @@ var init_tasks = __esm({
|
|
|
9561
9737
|
name: "tasks_set",
|
|
9562
9738
|
description: [
|
|
9563
9739
|
"Set the visible task list shown to the user during this turn.",
|
|
9564
|
-
"Call this
|
|
9565
|
-
"at the start (all tasks pending
|
|
9740
|
+
"Call this proactively for any request that needs two or more distinct steps, before starting work, and whenever progress changes:",
|
|
9741
|
+
"at the start (all tasks pending except exactly one in_progress), and after each step completes",
|
|
9566
9742
|
"(flip that task to completed and the next to in_progress).",
|
|
9567
9743
|
"Pass the ENTIRE task list each call \u2014 this replaces the panel.",
|
|
9568
9744
|
"Keep tasks short (one imperative clause). Only one should be in_progress at a time.",
|
|
@@ -9766,9 +9942,9 @@ var init_memory = __esm({
|
|
|
9766
9942
|
|
|
9767
9943
|
// src/tools/hotcell-snapshot.ts
|
|
9768
9944
|
import { execFile as execFile4 } from "child_process";
|
|
9769
|
-
import { mkdtemp, rm as
|
|
9770
|
-
import { tmpdir as
|
|
9771
|
-
import { join as
|
|
9945
|
+
import { mkdtemp as mkdtemp2, rm as rm3 } from "fs/promises";
|
|
9946
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
9947
|
+
import { join as join22 } from "path";
|
|
9772
9948
|
import { promisify as promisify4 } from "util";
|
|
9773
9949
|
async function git(args, cwd, env2) {
|
|
9774
9950
|
const { stdout } = await execFileAsync2("git", args, {
|
|
@@ -9816,9 +9992,9 @@ async function getRepositorySnapshot(cwd) {
|
|
|
9816
9992
|
if (!ref) {
|
|
9817
9993
|
throw new Error("Could not find an origin branch containing the base commit. Run git fetch, then retry.");
|
|
9818
9994
|
}
|
|
9819
|
-
const scratch = await
|
|
9995
|
+
const scratch = await mkdtemp2(join22(tmpdir4(), "autopilot-snapshot-"));
|
|
9820
9996
|
try {
|
|
9821
|
-
const env2 = { GIT_INDEX_FILE:
|
|
9997
|
+
const env2 = { GIT_INDEX_FILE: join22(scratch, "index") };
|
|
9822
9998
|
await git(["read-tree", "HEAD"], root, env2);
|
|
9823
9999
|
await git(["add", "-A", "--", ".", ...SECRET_EXCLUDES], root, env2);
|
|
9824
10000
|
const tree = (await git(["write-tree"], root, env2)).trim();
|
|
@@ -9837,15 +10013,15 @@ async function getRepositorySnapshot(cwd) {
|
|
|
9837
10013
|
}
|
|
9838
10014
|
return { url, ref, commit, patch: patch.toString("base64"), changedFiles: names.length };
|
|
9839
10015
|
} finally {
|
|
9840
|
-
await
|
|
10016
|
+
await rm3(scratch, { recursive: true, force: true });
|
|
9841
10017
|
}
|
|
9842
10018
|
}
|
|
9843
10019
|
async function getWorkingTreeArchive(cwd, limitBytes = MAX_ARCHIVE_BYTES) {
|
|
9844
10020
|
const root = (await git(["rev-parse", "--show-toplevel"], cwd).catch(() => "")).trim();
|
|
9845
10021
|
if (!root) throw new Error("Subagents need to run inside a Git repository.");
|
|
9846
|
-
const scratch = await
|
|
10022
|
+
const scratch = await mkdtemp2(join22(tmpdir4(), "autopilot-archive-"));
|
|
9847
10023
|
try {
|
|
9848
|
-
const env2 = { GIT_INDEX_FILE:
|
|
10024
|
+
const env2 = { GIT_INDEX_FILE: join22(scratch, "index") };
|
|
9849
10025
|
const hasHead = await git(["rev-parse", "--verify", "-q", "HEAD"], root).then(() => true, () => false);
|
|
9850
10026
|
await git(hasHead ? ["read-tree", "HEAD"] : ["read-tree", "--empty"], root, env2);
|
|
9851
10027
|
await git(["add", "-A", "--", ".", ...SECRET_EXCLUDES], root, env2);
|
|
@@ -9859,7 +10035,7 @@ async function getWorkingTreeArchive(cwd, limitBytes = MAX_ARCHIVE_BYTES) {
|
|
|
9859
10035
|
bytes: tarball.byteLength
|
|
9860
10036
|
};
|
|
9861
10037
|
} finally {
|
|
9862
|
-
await
|
|
10038
|
+
await rm3(scratch, { recursive: true, force: true });
|
|
9863
10039
|
}
|
|
9864
10040
|
}
|
|
9865
10041
|
function chunkPayload(base64, chunkSize = PAYLOAD_CHUNK_CHARS) {
|
|
@@ -9893,22 +10069,22 @@ var init_hotcell_snapshot = __esm({
|
|
|
9893
10069
|
});
|
|
9894
10070
|
|
|
9895
10071
|
// src/tools/hotcell-worker-cache.ts
|
|
9896
|
-
import { mkdir as
|
|
10072
|
+
import { mkdir as mkdir10, readFile as readFile13, writeFile as writeFile10 } from "fs/promises";
|
|
9897
10073
|
import { homedir as homedir11 } from "os";
|
|
9898
|
-
import { dirname as
|
|
10074
|
+
import { dirname as dirname10, join as join23 } from "path";
|
|
9899
10075
|
function workerCachePath() {
|
|
9900
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
9901
|
-
return
|
|
10076
|
+
const xdg = process.env.XDG_CONFIG_HOME || join23(homedir11(), ".config");
|
|
10077
|
+
return join23(xdg, "kimiflare", "hotcell-worker-cache.json");
|
|
9902
10078
|
}
|
|
9903
10079
|
async function readCache2() {
|
|
9904
10080
|
try {
|
|
9905
|
-
return JSON.parse(await
|
|
10081
|
+
return JSON.parse(await readFile13(workerCachePath(), "utf8"));
|
|
9906
10082
|
} catch {
|
|
9907
10083
|
return {};
|
|
9908
10084
|
}
|
|
9909
10085
|
}
|
|
9910
10086
|
async function writeCache2(cache) {
|
|
9911
|
-
await
|
|
10087
|
+
await mkdir10(dirname10(workerCachePath()), { recursive: true });
|
|
9912
10088
|
await writeFile10(workerCachePath(), JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
|
|
9913
10089
|
}
|
|
9914
10090
|
function ensureWorkerBackup(opts2) {
|
|
@@ -9969,13 +10145,13 @@ var init_hotcell_worker_cache = __esm({
|
|
|
9969
10145
|
});
|
|
9970
10146
|
|
|
9971
10147
|
// src/tools/hotcell-worker.ts
|
|
9972
|
-
import { spawn as
|
|
10148
|
+
import { spawn as spawn3 } from "child_process";
|
|
9973
10149
|
import { promisify as promisify5 } from "util";
|
|
9974
10150
|
import { execFile as execFile5 } from "child_process";
|
|
9975
|
-
import { resolve as
|
|
10151
|
+
import { resolve as resolve4 } from "path";
|
|
9976
10152
|
async function runHotcellWorker(options) {
|
|
9977
10153
|
const workerId = `hotcell-${crypto.randomUUID().slice(0, 8)}`;
|
|
9978
|
-
const cwd =
|
|
10154
|
+
const cwd = resolve4(options.cwd ?? process.cwd());
|
|
9979
10155
|
const model = options.model.trim();
|
|
9980
10156
|
if (!model) throw new Error("Hotcell workers require the coordinator's explicit model ID.");
|
|
9981
10157
|
validateModelId(model);
|
|
@@ -10283,7 +10459,7 @@ function parsePrintOutput(stdout) {
|
|
|
10283
10459
|
async function runProcess(executable, args, options) {
|
|
10284
10460
|
if (options.signal?.aborted) return { code: 130, stdout: "", stderr: "", aborted: true };
|
|
10285
10461
|
return await new Promise((resolvePromise, reject) => {
|
|
10286
|
-
const child =
|
|
10462
|
+
const child = spawn3(executable, args, { cwd: options.cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
10287
10463
|
const stdout = [];
|
|
10288
10464
|
const stderr = [];
|
|
10289
10465
|
let bytes = 0;
|
|
@@ -10515,17 +10691,17 @@ var init_worker_registry = __esm({
|
|
|
10515
10691
|
});
|
|
10516
10692
|
|
|
10517
10693
|
// src/tools/subagent-stats.ts
|
|
10518
|
-
import { appendFile as appendFile2, mkdir as
|
|
10694
|
+
import { appendFile as appendFile2, mkdir as mkdir11, readFile as readFile14 } from "fs/promises";
|
|
10519
10695
|
import { homedir as homedir12 } from "os";
|
|
10520
|
-
import { dirname as
|
|
10696
|
+
import { dirname as dirname11, join as join24 } from "path";
|
|
10521
10697
|
function subagentStatsPath() {
|
|
10522
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
10523
|
-
return
|
|
10698
|
+
const xdg = process.env.XDG_DATA_HOME || join24(homedir12(), ".local", "share");
|
|
10699
|
+
return join24(xdg, "kimiflare", "subagents.jsonl");
|
|
10524
10700
|
}
|
|
10525
10701
|
async function recordSubagentEvent(event) {
|
|
10526
10702
|
const path = subagentStatsPath();
|
|
10527
10703
|
try {
|
|
10528
|
-
await
|
|
10704
|
+
await mkdir11(dirname11(path), { recursive: true });
|
|
10529
10705
|
await appendFile2(path, JSON.stringify(event) + "\n");
|
|
10530
10706
|
} catch (error) {
|
|
10531
10707
|
logger.debug("subagents:stats_write_failed", { error: String(error) });
|
|
@@ -10545,7 +10721,7 @@ function failureReason(error) {
|
|
|
10545
10721
|
async function readSubagentStats(days = 7, now2 = Date.now()) {
|
|
10546
10722
|
let raw = "";
|
|
10547
10723
|
try {
|
|
10548
|
-
raw = await
|
|
10724
|
+
raw = await readFile14(subagentStatsPath(), "utf8");
|
|
10549
10725
|
} catch {
|
|
10550
10726
|
}
|
|
10551
10727
|
const since = now2 - days * 24 * 60 * 60 * 1e3;
|
|
@@ -11439,18 +11615,18 @@ var init_expand_artifact = __esm({
|
|
|
11439
11615
|
|
|
11440
11616
|
// src/jobs/manager.ts
|
|
11441
11617
|
import Database from "better-sqlite3";
|
|
11442
|
-
import { spawn as
|
|
11618
|
+
import { spawn as spawn4, execFileSync as execFileSync2 } from "child_process";
|
|
11443
11619
|
import { mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync4, readSync, existsSync as existsSync4, statSync as statSync3, closeSync, rmSync } from "fs";
|
|
11444
11620
|
import { homedir as homedir13 } from "os";
|
|
11445
|
-
import { dirname as
|
|
11621
|
+
import { dirname as dirname12, join as join25 } from "path";
|
|
11446
11622
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
11447
11623
|
function defaultJobDbPath() {
|
|
11448
|
-
const root = process.env.XDG_STATE_HOME ||
|
|
11449
|
-
return process.env.AUTOPILOT_JOBS_DB ||
|
|
11624
|
+
const root = process.env.XDG_STATE_HOME || join25(homedir13(), ".local", "state");
|
|
11625
|
+
return process.env.AUTOPILOT_JOBS_DB || join25(root, "autopilot", "jobs.db");
|
|
11450
11626
|
}
|
|
11451
11627
|
function isProcessGroupAlive(pgid) {
|
|
11452
11628
|
try {
|
|
11453
|
-
const rows =
|
|
11629
|
+
const rows = execFileSync2("ps", ["-axo", "pgid=,state="], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
11454
11630
|
return rows.split("\n").some((line) => {
|
|
11455
11631
|
const match = line.trim().match(/^(\d+)\s+(\S+)/);
|
|
11456
11632
|
return match?.[1] === String(pgid) && !match[2].startsWith("Z");
|
|
@@ -11476,22 +11652,22 @@ function waitForProcessStartTime(pid, jobId, exitPath) {
|
|
|
11476
11652
|
function readProcessStartTime(pid) {
|
|
11477
11653
|
if (process.platform === "linux") {
|
|
11478
11654
|
try {
|
|
11479
|
-
const
|
|
11480
|
-
const fieldsAfterCommand =
|
|
11655
|
+
const stat15 = readFileSync4(`/proc/${pid}/stat`, "utf8");
|
|
11656
|
+
const fieldsAfterCommand = stat15.slice(stat15.lastIndexOf(")") + 1).trim().split(/\s+/);
|
|
11481
11657
|
return fieldsAfterCommand[19] ? `linux:${fieldsAfterCommand[19]}` : null;
|
|
11482
11658
|
} catch {
|
|
11483
11659
|
return null;
|
|
11484
11660
|
}
|
|
11485
11661
|
}
|
|
11486
11662
|
try {
|
|
11487
|
-
return
|
|
11663
|
+
return execFileSync2("ps", ["-o", "lstart=", "-o", "command=", "-p", String(pid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
|
|
11488
11664
|
} catch {
|
|
11489
11665
|
return null;
|
|
11490
11666
|
}
|
|
11491
11667
|
}
|
|
11492
11668
|
function isZombie(pid) {
|
|
11493
11669
|
try {
|
|
11494
|
-
const state =
|
|
11670
|
+
const state = execFileSync2("ps", ["-o", "state=", "-p", String(pid)], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
11495
11671
|
return state.startsWith("Z");
|
|
11496
11672
|
} catch {
|
|
11497
11673
|
return true;
|
|
@@ -11589,8 +11765,8 @@ child.on('close', (code, signal) => {
|
|
|
11589
11765
|
db;
|
|
11590
11766
|
jobsDir;
|
|
11591
11767
|
constructor(dbPath = defaultJobDbPath()) {
|
|
11592
|
-
mkdirSync5(
|
|
11593
|
-
this.jobsDir =
|
|
11768
|
+
mkdirSync5(dirname12(dbPath), { recursive: true, mode: 448 });
|
|
11769
|
+
this.jobsDir = join25(dirname12(dbPath), "jobs");
|
|
11594
11770
|
mkdirSync5(this.jobsDir, { recursive: true, mode: 448 });
|
|
11595
11771
|
this.db = new Database(dbPath);
|
|
11596
11772
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -11641,13 +11817,13 @@ child.on('close', (code, signal) => {
|
|
|
11641
11817
|
if (existing) return toJobRecord(existing);
|
|
11642
11818
|
}
|
|
11643
11819
|
const id = randomUUID4();
|
|
11644
|
-
const jobDir =
|
|
11820
|
+
const jobDir = join25(this.jobsDir, id);
|
|
11645
11821
|
mkdirSync5(jobDir, { recursive: true, mode: 448 });
|
|
11646
11822
|
const paths = {
|
|
11647
|
-
stdoutPath:
|
|
11648
|
-
stderrPath:
|
|
11649
|
-
exitPath:
|
|
11650
|
-
pidPath:
|
|
11823
|
+
stdoutPath: join25(jobDir, "stdout.log"),
|
|
11824
|
+
stderrPath: join25(jobDir, "stderr.log"),
|
|
11825
|
+
exitPath: join25(jobDir, "exit.json"),
|
|
11826
|
+
pidPath: join25(jobDir, "pid")
|
|
11651
11827
|
};
|
|
11652
11828
|
const now2 = Date.now();
|
|
11653
11829
|
try {
|
|
@@ -11671,7 +11847,7 @@ child.on('close', (code, signal) => {
|
|
|
11671
11847
|
timeoutMs: options.timeoutMs ?? null,
|
|
11672
11848
|
...paths
|
|
11673
11849
|
});
|
|
11674
|
-
const child =
|
|
11850
|
+
const child = spawn4(process.execPath, ["--input-type=module", "-e", JOB_WRAPPER, spec], {
|
|
11675
11851
|
cwd: options.cwd,
|
|
11676
11852
|
detached: true,
|
|
11677
11853
|
stdio: "ignore",
|
|
@@ -11928,10 +12104,10 @@ import Database2 from "better-sqlite3";
|
|
|
11928
12104
|
import { createHash as createHash2, randomUUID as randomUUID5 } from "crypto";
|
|
11929
12105
|
import { chmodSync, mkdirSync as mkdirSync6 } from "fs";
|
|
11930
12106
|
import { homedir as homedir14 } from "os";
|
|
11931
|
-
import { dirname as
|
|
12107
|
+
import { dirname as dirname13, join as join26 } from "path";
|
|
11932
12108
|
function defaultRunsDbPath() {
|
|
11933
|
-
const root = process.env.XDG_STATE_HOME ||
|
|
11934
|
-
return process.env.AUTOPILOT_RUNS_DB ||
|
|
12109
|
+
const root = process.env.XDG_STATE_HOME || join26(homedir14(), ".local", "state");
|
|
12110
|
+
return process.env.AUTOPILOT_RUNS_DB || join26(root, "autopilot", "runs.db");
|
|
11935
12111
|
}
|
|
11936
12112
|
function validateOptionalPositiveInteger(name, value, minimum = 1) {
|
|
11937
12113
|
if (value !== null && (!Number.isSafeInteger(value) || value < minimum)) {
|
|
@@ -12019,7 +12195,7 @@ var init_store = __esm({
|
|
|
12019
12195
|
RunStore = class {
|
|
12020
12196
|
db;
|
|
12021
12197
|
constructor(dbPath = defaultRunsDbPath()) {
|
|
12022
|
-
mkdirSync6(
|
|
12198
|
+
mkdirSync6(dirname13(dbPath), { recursive: true, mode: 448 });
|
|
12023
12199
|
this.db = new Database2(dbPath);
|
|
12024
12200
|
this.db.pragma("journal_mode = WAL");
|
|
12025
12201
|
this.db.pragma("foreign_keys = ON");
|
|
@@ -12541,8 +12717,8 @@ var init_wait_for = __esm({
|
|
|
12541
12717
|
});
|
|
12542
12718
|
|
|
12543
12719
|
// src/tools/executor.ts
|
|
12544
|
-
import { realpath as
|
|
12545
|
-
import { isAbsolute as
|
|
12720
|
+
import { realpath as realpath4 } from "fs/promises";
|
|
12721
|
+
import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve5, sep as sep3 } from "path";
|
|
12546
12722
|
function getWorkerTools(profile) {
|
|
12547
12723
|
return profile === "research" ? ALL_TOOLS.filter((tool) => RESEARCH_WORKER_TOOL_NAMES.has(tool.name) && tool.isReadOnly === true).map(restrictResearchTool) : ALL_TOOLS;
|
|
12548
12724
|
}
|
|
@@ -12563,28 +12739,28 @@ function restrictResearchTool(tool) {
|
|
|
12563
12739
|
}
|
|
12564
12740
|
async function assertResearchPath(pathValue, cwd) {
|
|
12565
12741
|
if (typeof pathValue !== "string" || !pathValue) throw new Error("Research worker paths must be non-empty strings.");
|
|
12566
|
-
const root = await
|
|
12567
|
-
const candidate =
|
|
12742
|
+
const root = await realpath4(cwd);
|
|
12743
|
+
const candidate = resolve5(root, pathValue);
|
|
12568
12744
|
assertInsideResearchRoot(candidate, root);
|
|
12569
12745
|
assertNoSensitivePath(candidate, root);
|
|
12570
|
-
const actual = await
|
|
12746
|
+
const actual = await realpath4(candidate);
|
|
12571
12747
|
assertInsideResearchRoot(actual, root);
|
|
12572
12748
|
assertNoSensitivePath(actual, root);
|
|
12573
12749
|
}
|
|
12574
12750
|
function assertInsideResearchRoot(path, root) {
|
|
12575
|
-
const rel =
|
|
12576
|
-
if (rel === ".." || rel.startsWith(`..${
|
|
12751
|
+
const rel = relative4(root, path);
|
|
12752
|
+
if (rel === ".." || rel.startsWith(`..${sep3}`) || isAbsolute3(rel)) {
|
|
12577
12753
|
throw new Error("Research workers may only inspect paths inside their cloned repository.");
|
|
12578
12754
|
}
|
|
12579
12755
|
}
|
|
12580
12756
|
function assertNoSensitivePath(path, root) {
|
|
12581
|
-
const parts =
|
|
12757
|
+
const parts = relative4(root, path).split(sep3).filter(Boolean).map((part) => part.toLowerCase());
|
|
12582
12758
|
if (parts.some((part) => part === ".env" || part.startsWith(".env.") || SENSITIVE_RESEARCH_PATHS.has(part))) {
|
|
12583
12759
|
throw new Error("Research worker access to environment, credential, and VCS metadata paths is blocked.");
|
|
12584
12760
|
}
|
|
12585
12761
|
}
|
|
12586
12762
|
function assertSafePattern(value) {
|
|
12587
|
-
if (typeof value !== "string" || !value ||
|
|
12763
|
+
if (typeof value !== "string" || !value || isAbsolute3(value)) {
|
|
12588
12764
|
throw new Error("Research worker glob patterns must be relative to the repository.");
|
|
12589
12765
|
}
|
|
12590
12766
|
const parts = value.replaceAll("\\\\", "/").split("/");
|
|
@@ -12637,9 +12813,6 @@ function normalizeToolOutput(result2) {
|
|
|
12637
12813
|
}
|
|
12638
12814
|
return result2;
|
|
12639
12815
|
}
|
|
12640
|
-
function truncateForError(s) {
|
|
12641
|
-
return s.length <= 200 ? s : `${s.slice(0, 200)}... [${s.length - 200} more chars]`;
|
|
12642
|
-
}
|
|
12643
12816
|
var ALL_TOOLS, RESEARCH_WORKER_TOOL_NAMES, SENSITIVE_RESEARCH_PATHS, HOOK_RESULT_CONTENT_CAP_BYTES, ToolExecutor, TRACE_ARGS_INLINE_MAX, ToolTrace;
|
|
12644
12817
|
var init_executor = __esm({
|
|
12645
12818
|
"src/tools/executor.ts"() {
|
|
@@ -12658,6 +12831,7 @@ var init_executor = __esm({
|
|
|
12658
12831
|
init_github();
|
|
12659
12832
|
init_changelog_image();
|
|
12660
12833
|
init_browser();
|
|
12834
|
+
init_html_artifact();
|
|
12661
12835
|
init_tasks();
|
|
12662
12836
|
init_memory();
|
|
12663
12837
|
init_subagent();
|
|
@@ -12685,6 +12859,7 @@ var init_executor = __esm({
|
|
|
12685
12859
|
githubCreatePrTool,
|
|
12686
12860
|
{ ...changelogImageTool, isReadOnly: true },
|
|
12687
12861
|
{ ...browserFetchTool, isReadOnly: true },
|
|
12862
|
+
htmlArtifactTool,
|
|
12688
12863
|
tasksSetTool,
|
|
12689
12864
|
memoryRememberTool,
|
|
12690
12865
|
{ ...memoryRecallTool, isReadOnly: true },
|
|
@@ -12783,17 +12958,23 @@ var init_executor = __esm({
|
|
|
12783
12958
|
}
|
|
12784
12959
|
let args;
|
|
12785
12960
|
try {
|
|
12786
|
-
|
|
12961
|
+
if (!call.arguments.trim()) throw new SyntaxError("tool arguments were empty");
|
|
12962
|
+
const parsed = JSON.parse(call.arguments);
|
|
12963
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
12964
|
+
throw new SyntaxError("tool arguments must be a JSON object");
|
|
12965
|
+
}
|
|
12966
|
+
args = parsed;
|
|
12787
12967
|
} catch (e) {
|
|
12788
12968
|
tr?.call(null, tool.needsPermission);
|
|
12969
|
+
const artifactSuggestion = call.name === "create_artifact" ? "Use write to save the complete HTML document as a workspace .html file, then call create_artifact with its title and sourcePath." : "Retry with valid JSON object arguments for this tool.";
|
|
12789
12970
|
return {
|
|
12790
12971
|
tool_call_id: call.id,
|
|
12791
12972
|
name: call.name,
|
|
12792
|
-
content: `Error: invalid JSON arguments for ${call.name}: ${e.message}.
|
|
12973
|
+
content: `Error: invalid JSON arguments for ${call.name}: ${e.message}. No tool action was performed (${Buffer.byteLength(call.arguments, "utf8")} argument bytes).`,
|
|
12793
12974
|
ok: false,
|
|
12794
12975
|
errorCode: "invalid_args",
|
|
12795
|
-
recoverable:
|
|
12796
|
-
suggestion:
|
|
12976
|
+
recoverable: true,
|
|
12977
|
+
suggestion: artifactSuggestion
|
|
12797
12978
|
};
|
|
12798
12979
|
}
|
|
12799
12980
|
tr?.call(args, tool.needsPermission);
|
|
@@ -13110,12 +13291,12 @@ __export(sessions_exports, {
|
|
|
13110
13291
|
saveSession: () => saveSession,
|
|
13111
13292
|
sessionsDir: () => sessionsDir
|
|
13112
13293
|
});
|
|
13113
|
-
import { readFile as
|
|
13294
|
+
import { readFile as readFile15, writeFile as writeFile11, mkdir as mkdir12, readdir as readdir5, stat as stat7 } from "fs/promises";
|
|
13114
13295
|
import { homedir as homedir15 } from "os";
|
|
13115
|
-
import { join as
|
|
13296
|
+
import { join as join27 } from "path";
|
|
13116
13297
|
function sessionsDir() {
|
|
13117
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
13118
|
-
return
|
|
13298
|
+
const xdg = process.env.XDG_DATA_HOME || join27(homedir15(), ".local", "share");
|
|
13299
|
+
return join27(xdg, "kimiflare", "sessions");
|
|
13119
13300
|
}
|
|
13120
13301
|
function sanitize(text) {
|
|
13121
13302
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -13134,8 +13315,8 @@ function makeSessionId(firstPrompt) {
|
|
|
13134
13315
|
}
|
|
13135
13316
|
async function saveSession(file) {
|
|
13136
13317
|
const dir = sessionsDir();
|
|
13137
|
-
await
|
|
13138
|
-
const path =
|
|
13318
|
+
await mkdir12(dir, { recursive: true });
|
|
13319
|
+
const path = join27(dir, `${file.id}.json`);
|
|
13139
13320
|
await writeFile11(path, JSON.stringify(file, null, 2), "utf8");
|
|
13140
13321
|
return path;
|
|
13141
13322
|
}
|
|
@@ -13148,16 +13329,16 @@ async function listSessions(limit = 30, cwd) {
|
|
|
13148
13329
|
const dir = sessionsDir();
|
|
13149
13330
|
let entries;
|
|
13150
13331
|
try {
|
|
13151
|
-
entries = await
|
|
13332
|
+
entries = await readdir5(dir);
|
|
13152
13333
|
} catch {
|
|
13153
13334
|
return [];
|
|
13154
13335
|
}
|
|
13155
13336
|
const summaries = [];
|
|
13156
13337
|
for (const name of entries) {
|
|
13157
13338
|
if (!name.endsWith(".json")) continue;
|
|
13158
|
-
const path =
|
|
13339
|
+
const path = join27(dir, name);
|
|
13159
13340
|
try {
|
|
13160
|
-
const [s, raw] = await Promise.all([
|
|
13341
|
+
const [s, raw] = await Promise.all([stat7(path), readFile15(path, "utf8")]);
|
|
13161
13342
|
const parsed = JSON.parse(raw);
|
|
13162
13343
|
if (cwd && parsed.cwd !== cwd) continue;
|
|
13163
13344
|
const firstUser = parsed.messages.find((m) => m.role === "user");
|
|
@@ -13179,7 +13360,7 @@ async function listSessions(limit = 30, cwd) {
|
|
|
13179
13360
|
return summaries.slice(0, limit);
|
|
13180
13361
|
}
|
|
13181
13362
|
async function loadSession(filePath) {
|
|
13182
|
-
const raw = await
|
|
13363
|
+
const raw = await readFile15(filePath, "utf8");
|
|
13183
13364
|
const file = JSON.parse(raw);
|
|
13184
13365
|
if (Array.isArray(file.messages)) repairDanglingToolCalls(file.messages);
|
|
13185
13366
|
return file;
|
|
@@ -13229,10 +13410,10 @@ var init_sessions = __esm({
|
|
|
13229
13410
|
});
|
|
13230
13411
|
|
|
13231
13412
|
// src/util/image.ts
|
|
13232
|
-
import { readFile as
|
|
13233
|
-
import { basename as
|
|
13413
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
13414
|
+
import { basename as basename3 } from "path";
|
|
13234
13415
|
async function encodeImageFile(filePath) {
|
|
13235
|
-
const buf = await
|
|
13416
|
+
const buf = await readFile16(filePath);
|
|
13236
13417
|
if (buf.byteLength > MAX_IMAGE_BYTES) {
|
|
13237
13418
|
throw new Error(
|
|
13238
13419
|
`image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
|
|
@@ -13242,7 +13423,7 @@ async function encodeImageFile(filePath) {
|
|
|
13242
13423
|
const mime = EXT_TO_MIME[ext] ?? "image/jpeg";
|
|
13243
13424
|
const b64 = buf.toString("base64");
|
|
13244
13425
|
return {
|
|
13245
|
-
filename:
|
|
13426
|
+
filename: basename3(filePath),
|
|
13246
13427
|
mime,
|
|
13247
13428
|
dataUrl: `data:${mime};base64,${b64}`
|
|
13248
13429
|
};
|
|
@@ -13268,7 +13449,7 @@ var init_image = __esm({
|
|
|
13268
13449
|
});
|
|
13269
13450
|
|
|
13270
13451
|
// src/permissions-evaluator.ts
|
|
13271
|
-
import { resolve as
|
|
13452
|
+
import { resolve as resolve6, relative as relative5 } from "path";
|
|
13272
13453
|
import { homedir as homedir16 } from "os";
|
|
13273
13454
|
function evaluatePermissionRules(req, rules) {
|
|
13274
13455
|
const toolRules = rules[req.tool];
|
|
@@ -13285,7 +13466,7 @@ function evaluatePermissionRules(req, rules) {
|
|
|
13285
13466
|
}
|
|
13286
13467
|
function expandHome(path) {
|
|
13287
13468
|
if (path.startsWith("~/")) {
|
|
13288
|
-
return
|
|
13469
|
+
return resolve6(homedir16(), path.slice(2));
|
|
13289
13470
|
}
|
|
13290
13471
|
return path;
|
|
13291
13472
|
}
|
|
@@ -13296,7 +13477,7 @@ function extractTarget(tool, args, cwd) {
|
|
|
13296
13477
|
case "read":
|
|
13297
13478
|
case "glob":
|
|
13298
13479
|
case "grep":
|
|
13299
|
-
return typeof args.path === "string" ?
|
|
13480
|
+
return typeof args.path === "string" ? resolve6(cwd, expandHome(args.path)) : null;
|
|
13300
13481
|
case "bash":
|
|
13301
13482
|
return typeof args.command === "string" ? args.command : null;
|
|
13302
13483
|
case "browser_fetch":
|
|
@@ -13305,13 +13486,13 @@ function extractTarget(tool, args, cwd) {
|
|
|
13305
13486
|
case "search_web":
|
|
13306
13487
|
return typeof args.query === "string" ? args.query : null;
|
|
13307
13488
|
default:
|
|
13308
|
-
return (typeof args.path === "string" ?
|
|
13489
|
+
return (typeof args.path === "string" ? resolve6(cwd, expandHome(args.path)) : null) ?? (typeof args.url === "string" ? args.url : null) ?? (typeof args.command === "string" ? args.command : null);
|
|
13309
13490
|
}
|
|
13310
13491
|
}
|
|
13311
13492
|
function matchPattern(target, pattern, cwd) {
|
|
13312
13493
|
let expandedPattern = pattern;
|
|
13313
13494
|
if (pattern.startsWith("~/")) {
|
|
13314
|
-
expandedPattern =
|
|
13495
|
+
expandedPattern = resolve6(homedir16(), pattern.slice(2));
|
|
13315
13496
|
}
|
|
13316
13497
|
if (target.startsWith(expandedPattern)) {
|
|
13317
13498
|
return true;
|
|
@@ -13321,7 +13502,7 @@ function matchPattern(target, pattern, cwd) {
|
|
|
13321
13502
|
return true;
|
|
13322
13503
|
}
|
|
13323
13504
|
try {
|
|
13324
|
-
const relTarget =
|
|
13505
|
+
const relTarget = relative5(cwd, target);
|
|
13325
13506
|
if (regex.test(relTarget)) {
|
|
13326
13507
|
return true;
|
|
13327
13508
|
}
|
|
@@ -13394,17 +13575,17 @@ __export(retention_exports, {
|
|
|
13394
13575
|
listTraceSessions: () => listTraceSessions,
|
|
13395
13576
|
pruneTraces: () => pruneTraces
|
|
13396
13577
|
});
|
|
13397
|
-
import { readdir as
|
|
13398
|
-
import { join as
|
|
13578
|
+
import { readdir as readdir6, rm as rm4, stat as stat8 } from "fs/promises";
|
|
13579
|
+
import { join as join28 } from "path";
|
|
13399
13580
|
async function dirSize(path) {
|
|
13400
13581
|
let total = 0;
|
|
13401
|
-
const entries = await
|
|
13582
|
+
const entries = await readdir6(path, { withFileTypes: true });
|
|
13402
13583
|
for (const entry of entries) {
|
|
13403
|
-
const p =
|
|
13584
|
+
const p = join28(path, entry.name);
|
|
13404
13585
|
if (entry.isDirectory()) total += await dirSize(p);
|
|
13405
13586
|
else if (entry.isFile()) {
|
|
13406
13587
|
try {
|
|
13407
|
-
total += (await
|
|
13588
|
+
total += (await stat8(p)).size;
|
|
13408
13589
|
} catch {
|
|
13409
13590
|
}
|
|
13410
13591
|
}
|
|
@@ -13415,19 +13596,19 @@ async function listTraceSessions(root) {
|
|
|
13415
13596
|
const base = traceRoot(root);
|
|
13416
13597
|
let names;
|
|
13417
13598
|
try {
|
|
13418
|
-
names = await
|
|
13599
|
+
names = await readdir6(base);
|
|
13419
13600
|
} catch {
|
|
13420
13601
|
return [];
|
|
13421
13602
|
}
|
|
13422
13603
|
const sessions = [];
|
|
13423
13604
|
for (const name of names) {
|
|
13424
|
-
const path =
|
|
13605
|
+
const path = join28(base, name);
|
|
13425
13606
|
try {
|
|
13426
|
-
const s = await
|
|
13607
|
+
const s = await stat8(path);
|
|
13427
13608
|
if (!s.isDirectory()) continue;
|
|
13428
13609
|
let mtime = s.mtime;
|
|
13429
13610
|
try {
|
|
13430
|
-
mtime = (await
|
|
13611
|
+
mtime = (await stat8(join28(path, TRACE_FILE_NAME))).mtime;
|
|
13431
13612
|
} catch {
|
|
13432
13613
|
}
|
|
13433
13614
|
sessions.push({ sessionId: name, path, mtime, bytes: await dirSize(path) });
|
|
@@ -13452,7 +13633,7 @@ async function pruneTraces(opts2 = {}) {
|
|
|
13452
13633
|
}
|
|
13453
13634
|
const remove = async (s) => {
|
|
13454
13635
|
try {
|
|
13455
|
-
await
|
|
13636
|
+
await rm4(s.path, { recursive: true, force: true });
|
|
13456
13637
|
removed.push(s.sessionId);
|
|
13457
13638
|
} catch {
|
|
13458
13639
|
}
|
|
@@ -13481,7 +13662,7 @@ var init_retention = __esm({
|
|
|
13481
13662
|
// src/trace/session-start.ts
|
|
13482
13663
|
import { execFile as execFile6 } from "child_process";
|
|
13483
13664
|
import { existsSync as existsSync5 } from "fs";
|
|
13484
|
-
import { dirname as
|
|
13665
|
+
import { dirname as dirname14, join as join29 } from "path";
|
|
13485
13666
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13486
13667
|
import { promisify as promisify6 } from "util";
|
|
13487
13668
|
async function git2(args, cwd) {
|
|
@@ -13494,9 +13675,9 @@ async function git2(args, cwd) {
|
|
|
13494
13675
|
}
|
|
13495
13676
|
}
|
|
13496
13677
|
function harnessCheckoutDir() {
|
|
13497
|
-
const here =
|
|
13498
|
-
for (const candidate of [
|
|
13499
|
-
if (existsSync5(
|
|
13678
|
+
const here = dirname14(fileURLToPath4(import.meta.url));
|
|
13679
|
+
for (const candidate of [join29(here, "..", ".."), join29(here, "..")]) {
|
|
13680
|
+
if (existsSync5(join29(candidate, "package.json")) && existsSync5(join29(candidate, ".git"))) return candidate;
|
|
13500
13681
|
}
|
|
13501
13682
|
return null;
|
|
13502
13683
|
}
|
|
@@ -13634,14 +13815,14 @@ var init_types2 = __esm({
|
|
|
13634
13815
|
// src/hooks/settings.ts
|
|
13635
13816
|
import { existsSync as existsSync6, readFileSync as readFileSync5, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
13636
13817
|
import { homedir as homedir17 } from "os";
|
|
13637
|
-
import { join as
|
|
13818
|
+
import { join as join30, dirname as dirname15 } from "path";
|
|
13638
13819
|
import { createHash as createHash3 } from "crypto";
|
|
13639
13820
|
function globalSettingsPath() {
|
|
13640
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
13641
|
-
return
|
|
13821
|
+
const xdg = process.env.XDG_CONFIG_HOME || join30(homedir17(), ".config");
|
|
13822
|
+
return join30(xdg, "kimiflare", "settings.json");
|
|
13642
13823
|
}
|
|
13643
13824
|
function projectSettingsPath(cwd) {
|
|
13644
|
-
return
|
|
13825
|
+
return join30(cwd, ".kimiflare", "settings.json");
|
|
13645
13826
|
}
|
|
13646
13827
|
function readSettingsFile(path) {
|
|
13647
13828
|
if (!existsSync6(path)) return null;
|
|
@@ -13717,7 +13898,7 @@ function appendHook(scope, cwd, event, hook) {
|
|
|
13717
13898
|
return rest;
|
|
13718
13899
|
});
|
|
13719
13900
|
existing.hooks = hooks;
|
|
13720
|
-
mkdirSync7(
|
|
13901
|
+
mkdirSync7(dirname15(path), { recursive: true });
|
|
13721
13902
|
writeFileSync4(path, JSON.stringify(existing, null, 2) + "\n", "utf8");
|
|
13722
13903
|
return path;
|
|
13723
13904
|
}
|
|
@@ -13743,7 +13924,7 @@ function setHookEnabled(cwd, id, enabled2) {
|
|
|
13743
13924
|
}
|
|
13744
13925
|
}
|
|
13745
13926
|
if (changed) {
|
|
13746
|
-
mkdirSync7(
|
|
13927
|
+
mkdirSync7(dirname15(path), { recursive: true });
|
|
13747
13928
|
writeFileSync4(path, JSON.stringify(existing, null, 2) + "\n", "utf8");
|
|
13748
13929
|
return path;
|
|
13749
13930
|
}
|
|
@@ -13759,7 +13940,7 @@ var init_settings = __esm({
|
|
|
13759
13940
|
});
|
|
13760
13941
|
|
|
13761
13942
|
// src/hooks/runner.ts
|
|
13762
|
-
import { spawn as
|
|
13943
|
+
import { spawn as spawn5 } from "child_process";
|
|
13763
13944
|
function isVetoEvent(event) {
|
|
13764
13945
|
return event === "PreToolUse" || event === "UserPromptSubmit";
|
|
13765
13946
|
}
|
|
@@ -13876,8 +14057,8 @@ var init_runner = __esm({
|
|
|
13876
14057
|
init_logger();
|
|
13877
14058
|
DEFAULT_TIMEOUT_MS = 3e4;
|
|
13878
14059
|
STREAM_CAP_BYTES = 4 * 1024;
|
|
13879
|
-
defaultSpawn = (command, payloadJson, env2, cwd, timeoutMs, signal) => new Promise((
|
|
13880
|
-
const child =
|
|
14060
|
+
defaultSpawn = (command, payloadJson, env2, cwd, timeoutMs, signal) => new Promise((resolve20) => {
|
|
14061
|
+
const child = spawn5(command, {
|
|
13881
14062
|
shell: true,
|
|
13882
14063
|
cwd,
|
|
13883
14064
|
env: env2,
|
|
@@ -13891,7 +14072,7 @@ var init_runner = __esm({
|
|
|
13891
14072
|
settled = true;
|
|
13892
14073
|
clearTimeout(timer3);
|
|
13893
14074
|
signal?.removeEventListener("abort", onAbort);
|
|
13894
|
-
|
|
14075
|
+
resolve20({ exitCode, stdout, stderr, timedOut });
|
|
13895
14076
|
};
|
|
13896
14077
|
const onAbort = () => {
|
|
13897
14078
|
child.kill("SIGTERM");
|
|
@@ -13964,18 +14145,18 @@ var init_manager2 = __esm({
|
|
|
13964
14145
|
});
|
|
13965
14146
|
|
|
13966
14147
|
// src/eval/config.ts
|
|
13967
|
-
import { readFile as
|
|
13968
|
-
import { basename as
|
|
14148
|
+
import { readFile as readFile18 } from "fs/promises";
|
|
14149
|
+
import { basename as basename5, resolve as resolve8 } from "path";
|
|
13969
14150
|
async function loadEvalConfig(file) {
|
|
13970
|
-
const path =
|
|
13971
|
-
const raw = JSON.parse(await
|
|
14151
|
+
const path = resolve8(file);
|
|
14152
|
+
const raw = JSON.parse(await readFile18(path, "utf8"));
|
|
13972
14153
|
if (!raw || typeof raw !== "object") throw new Error(`${file}: config must be a JSON object`);
|
|
13973
14154
|
const config2 = raw.config ?? {};
|
|
13974
14155
|
if (typeof config2 !== "object" || Array.isArray(config2)) throw new Error(`${file}: "config" must be an object`);
|
|
13975
14156
|
if (raw.model !== void 0 && typeof raw.model !== "string") throw new Error(`${file}: "model" must be a string`);
|
|
13976
14157
|
if (raw.temperature !== void 0 && typeof raw.temperature !== "number") throw new Error(`${file}: "temperature" must be a number`);
|
|
13977
14158
|
return {
|
|
13978
|
-
name: typeof raw.name === "string" && raw.name ? raw.name :
|
|
14159
|
+
name: typeof raw.name === "string" && raw.name ? raw.name : basename5(path).replace(/\.json$/, ""),
|
|
13979
14160
|
...raw.model ? { model: raw.model } : {},
|
|
13980
14161
|
...raw.temperature !== void 0 ? { temperature: raw.temperature } : {},
|
|
13981
14162
|
config: config2
|
|
@@ -13988,8 +14169,8 @@ var init_config2 = __esm({
|
|
|
13988
14169
|
});
|
|
13989
14170
|
|
|
13990
14171
|
// src/eval/tasks.ts
|
|
13991
|
-
import { readdir as
|
|
13992
|
-
import { basename as
|
|
14172
|
+
import { readdir as readdir7, readFile as readFile19, stat as stat9 } from "fs/promises";
|
|
14173
|
+
import { basename as basename6, join as join31, resolve as resolve9 } from "path";
|
|
13993
14174
|
function isNonEmptyString(v) {
|
|
13994
14175
|
return typeof v === "string" && v.trim().length > 0;
|
|
13995
14176
|
}
|
|
@@ -14017,22 +14198,22 @@ function matchesTaskFilter(id, filter) {
|
|
|
14017
14198
|
return filter.split(",").map((g) => g.trim()).filter(Boolean).some((g) => matchGlob(id, g));
|
|
14018
14199
|
}
|
|
14019
14200
|
async function loadTasks(dir, filter) {
|
|
14020
|
-
const root =
|
|
14021
|
-
const names = (await
|
|
14201
|
+
const root = resolve9(dir);
|
|
14202
|
+
const names = (await readdir7(root)).filter((n) => n.endsWith(".json")).sort();
|
|
14022
14203
|
const tasks = [];
|
|
14023
14204
|
const seen = /* @__PURE__ */ new Set();
|
|
14024
14205
|
for (const name of names) {
|
|
14025
|
-
const file =
|
|
14026
|
-
const task = validateTask(JSON.parse(await
|
|
14027
|
-
if (task.id !==
|
|
14206
|
+
const file = join31(root, name);
|
|
14207
|
+
const task = validateTask(JSON.parse(await readFile19(file, "utf8")), name);
|
|
14208
|
+
if (task.id !== basename6(name, ".json")) throw new Error(`${name}: "id" (${task.id}) must match the file name`);
|
|
14028
14209
|
if (seen.has(task.id)) throw new Error(`duplicate task id ${task.id}`);
|
|
14029
14210
|
seen.add(task.id);
|
|
14030
14211
|
if (!matchesTaskFilter(task.id, filter)) continue;
|
|
14031
14212
|
const resolvedFiles = {};
|
|
14032
14213
|
for (const [dest, src] of Object.entries(task.files ?? {})) {
|
|
14033
|
-
const abs =
|
|
14214
|
+
const abs = resolve9(root, src);
|
|
14034
14215
|
if (!abs.startsWith(root)) throw new Error(`${name}: files["${dest}"] escapes the task directory`);
|
|
14035
|
-
await
|
|
14216
|
+
await stat9(abs).catch(() => {
|
|
14036
14217
|
throw new Error(`${name}: files["${dest}"] -> ${src} does not exist`);
|
|
14037
14218
|
});
|
|
14038
14219
|
resolvedFiles[dest] = abs;
|
|
@@ -14053,15 +14234,15 @@ var init_tasks2 = __esm({
|
|
|
14053
14234
|
// src/eval/workspace.ts
|
|
14054
14235
|
import { execFile as execFile7 } from "child_process";
|
|
14055
14236
|
import { createHash as createHash4 } from "crypto";
|
|
14056
|
-
import { mkdir as
|
|
14057
|
-
import { isAbsolute as
|
|
14237
|
+
import { mkdir as mkdir13, rm as rm5, stat as stat10 } from "fs/promises";
|
|
14238
|
+
import { isAbsolute as isAbsolute4, join as join32, resolve as resolve10 } from "path";
|
|
14058
14239
|
import { promisify as promisify7 } from "util";
|
|
14059
14240
|
async function git3(args, cwd, timeoutMs = 6e5) {
|
|
14060
14241
|
const { stdout } = await execFileAsync5("git", args, { cwd, timeout: timeoutMs, maxBuffer: 64 * 1024 * 1024 });
|
|
14061
14242
|
return stdout.trim();
|
|
14062
14243
|
}
|
|
14063
14244
|
function isLocalRepo(repo) {
|
|
14064
|
-
return
|
|
14245
|
+
return isAbsolute4(repo) || repo.startsWith(".") || repo.startsWith("~");
|
|
14065
14246
|
}
|
|
14066
14247
|
function prepareSourceRepo(repo, cacheDir) {
|
|
14067
14248
|
const key = `${cacheDir}\0${repo}`;
|
|
@@ -14074,14 +14255,14 @@ function prepareSourceRepo(repo, cacheDir) {
|
|
|
14074
14255
|
}
|
|
14075
14256
|
async function prepareSourceRepoUncached(repo, cacheDir) {
|
|
14076
14257
|
if (isLocalRepo(repo)) {
|
|
14077
|
-
const path =
|
|
14258
|
+
const path = resolve10(repo.replace(/^~/, process.env.HOME ?? ""));
|
|
14078
14259
|
await git3(["rev-parse", "--git-dir"], path);
|
|
14079
14260
|
return path;
|
|
14080
14261
|
}
|
|
14081
14262
|
const slug = `${repo.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(-60)}-${createHash4("sha1").update(repo).digest("hex").slice(0, 8)}`;
|
|
14082
|
-
const dir =
|
|
14083
|
-
await
|
|
14084
|
-
const exists = await
|
|
14263
|
+
const dir = join32(cacheDir, slug);
|
|
14264
|
+
await mkdir13(cacheDir, { recursive: true });
|
|
14265
|
+
const exists = await stat10(join32(dir, ".git")).then(() => true).catch(() => false);
|
|
14085
14266
|
if (!exists) {
|
|
14086
14267
|
await git3(["clone", "--quiet", "--no-checkout", repo, dir], cacheDir);
|
|
14087
14268
|
} else {
|
|
@@ -14100,13 +14281,13 @@ async function ensureCommit(sourceRepo, commit) {
|
|
|
14100
14281
|
async function createWorktree(sourceRepo, commit, path) {
|
|
14101
14282
|
await ensureCommit(sourceRepo, commit);
|
|
14102
14283
|
await removeWorktree({ sourceRepo, path }).catch(() => void 0);
|
|
14103
|
-
await
|
|
14284
|
+
await mkdir13(join32(path, ".."), { recursive: true });
|
|
14104
14285
|
await git3(["worktree", "add", "--quiet", "--detach", path, commit], sourceRepo);
|
|
14105
14286
|
return { sourceRepo, path };
|
|
14106
14287
|
}
|
|
14107
14288
|
async function removeWorktree(wt) {
|
|
14108
14289
|
await git3(["worktree", "remove", "--force", wt.path], wt.sourceRepo).catch(() => void 0);
|
|
14109
|
-
await
|
|
14290
|
+
await rm5(wt.path, { recursive: true, force: true });
|
|
14110
14291
|
await git3(["worktree", "prune"], wt.sourceRepo).catch(() => void 0);
|
|
14111
14292
|
}
|
|
14112
14293
|
var execFileAsync5, preparing;
|
|
@@ -14156,7 +14337,7 @@ __export(db_exports, {
|
|
|
14156
14337
|
updateMemoryEmbedding: () => updateMemoryEmbedding
|
|
14157
14338
|
});
|
|
14158
14339
|
import Database3 from "better-sqlite3";
|
|
14159
|
-
import { dirname as
|
|
14340
|
+
import { dirname as dirname16 } from "path";
|
|
14160
14341
|
import { mkdirSync as mkdirSync8, statSync as statSync4 } from "fs";
|
|
14161
14342
|
function initSchema(db) {
|
|
14162
14343
|
db.exec(`
|
|
@@ -14241,7 +14422,7 @@ function openMemoryDb(dbPath) {
|
|
|
14241
14422
|
if (dbInstance) {
|
|
14242
14423
|
dbInstance.close();
|
|
14243
14424
|
}
|
|
14244
|
-
mkdirSync8(
|
|
14425
|
+
mkdirSync8(dirname16(dbPath), { recursive: true });
|
|
14245
14426
|
dbInstance = new Database3(dbPath);
|
|
14246
14427
|
dbInstance.pragma("journal_mode = WAL");
|
|
14247
14428
|
dbInstance.pragma("foreign_keys = ON");
|
|
@@ -14577,8 +14758,8 @@ function computeExactScore(memory, queryText, cwd) {
|
|
|
14577
14758
|
let score = 0;
|
|
14578
14759
|
const lowerQuery = queryText.toLowerCase();
|
|
14579
14760
|
for (const file of memory.relatedFiles) {
|
|
14580
|
-
const
|
|
14581
|
-
if (lowerQuery.includes(
|
|
14761
|
+
const basename12 = file.split("/").pop() ?? file;
|
|
14762
|
+
if (lowerQuery.includes(basename12.toLowerCase()) || basename12.toLowerCase().includes(lowerQuery)) {
|
|
14582
14763
|
score += 0.3;
|
|
14583
14764
|
}
|
|
14584
14765
|
if (cwd && file.startsWith(cwd)) {
|
|
@@ -15201,7 +15382,7 @@ Context: This memory was explicitly provided by the user during a conversation.`
|
|
|
15201
15382
|
});
|
|
15202
15383
|
|
|
15203
15384
|
// src/lsp/connection.ts
|
|
15204
|
-
import { spawn as
|
|
15385
|
+
import { spawn as spawn6 } from "child_process";
|
|
15205
15386
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
15206
15387
|
var LspConnection;
|
|
15207
15388
|
var init_connection = __esm({
|
|
@@ -15223,7 +15404,7 @@ var init_connection = __esm({
|
|
|
15223
15404
|
if (this.child) {
|
|
15224
15405
|
throw new Error("LSP connection already started");
|
|
15225
15406
|
}
|
|
15226
|
-
return new Promise((
|
|
15407
|
+
return new Promise((resolve20, reject) => {
|
|
15227
15408
|
const abortController = new AbortController();
|
|
15228
15409
|
const spawnTimer = setTimeout(() => {
|
|
15229
15410
|
abortController.abort();
|
|
@@ -15231,7 +15412,7 @@ var init_connection = __esm({
|
|
|
15231
15412
|
reject(new Error(`LSP server spawn timed out after ${spawnTimeoutMs}ms`));
|
|
15232
15413
|
}, spawnTimeoutMs);
|
|
15233
15414
|
try {
|
|
15234
|
-
const child =
|
|
15415
|
+
const child = spawn6(command[0], command.slice(1), {
|
|
15235
15416
|
env: { ...process.env, ...env2 },
|
|
15236
15417
|
stdio: ["pipe", "pipe", "pipe"]
|
|
15237
15418
|
});
|
|
@@ -15262,7 +15443,7 @@ var init_connection = __esm({
|
|
|
15262
15443
|
if (child.pid) {
|
|
15263
15444
|
clearTimeout(spawnTimer);
|
|
15264
15445
|
this.child = child;
|
|
15265
|
-
|
|
15446
|
+
resolve20();
|
|
15266
15447
|
}
|
|
15267
15448
|
});
|
|
15268
15449
|
} catch (err) {
|
|
@@ -15277,12 +15458,12 @@ var init_connection = __esm({
|
|
|
15277
15458
|
}
|
|
15278
15459
|
const id = this.nextId++;
|
|
15279
15460
|
const msg = { jsonrpc: "2.0", id, method, params };
|
|
15280
|
-
return new Promise((
|
|
15461
|
+
return new Promise((resolve20, reject) => {
|
|
15281
15462
|
const timer3 = setTimeout(() => {
|
|
15282
15463
|
this.pending.delete(id);
|
|
15283
15464
|
reject(toolTimeoutError(`LSP request '${method}'`, this.requestTimeoutMs));
|
|
15284
15465
|
}, this.requestTimeoutMs);
|
|
15285
|
-
const pending = { resolve:
|
|
15466
|
+
const pending = { resolve: resolve20, reject, signal, timer: timer3 };
|
|
15286
15467
|
this.pending.set(id, pending);
|
|
15287
15468
|
if (signal) {
|
|
15288
15469
|
const onAbort = () => {
|
|
@@ -15375,9 +15556,9 @@ var init_connection = __esm({
|
|
|
15375
15556
|
});
|
|
15376
15557
|
|
|
15377
15558
|
// src/lsp/protocol.ts
|
|
15378
|
-
import { pathToFileURL as
|
|
15559
|
+
import { pathToFileURL as pathToFileURL3, fileURLToPath as fileURLToPath5 } from "url";
|
|
15379
15560
|
function toUri(path) {
|
|
15380
|
-
return
|
|
15561
|
+
return pathToFileURL3(path).href;
|
|
15381
15562
|
}
|
|
15382
15563
|
function fromUri(uri) {
|
|
15383
15564
|
return fileURLToPath5(uri);
|
|
@@ -15846,10 +16027,10 @@ var init_manager4 = __esm({
|
|
|
15846
16027
|
});
|
|
15847
16028
|
|
|
15848
16029
|
// src/lsp/adapter.ts
|
|
15849
|
-
import { relative as
|
|
16030
|
+
import { relative as relative6 } from "path";
|
|
15850
16031
|
function formatLocation(loc, cwd) {
|
|
15851
16032
|
const path = fromUri(loc.uri);
|
|
15852
|
-
const rel =
|
|
16033
|
+
const rel = relative6(cwd, path) || path;
|
|
15853
16034
|
return `${rel}:${loc.range.start.line + 1}:${loc.range.start.character + 1}`;
|
|
15854
16035
|
}
|
|
15855
16036
|
function formatLocations(locs, cwd) {
|
|
@@ -15886,7 +16067,7 @@ function formatWorkspaceSymbols(symbols, cwd) {
|
|
|
15886
16067
|
if (!symbols || symbols.length === 0) return "No symbols found.";
|
|
15887
16068
|
return symbols.map((s) => {
|
|
15888
16069
|
const path = fromUri(s.location.uri);
|
|
15889
|
-
const rel =
|
|
16070
|
+
const rel = relative6(cwd, path) || path;
|
|
15890
16071
|
const container = s.containerName ? ` in ${s.containerName}` : "";
|
|
15891
16072
|
return `${s.name} (${symbolKindName(s.kind)})${container} \u2014 ${rel}:${s.location.range.start.line + 1}:${s.location.range.start.character + 1}`;
|
|
15892
16073
|
}).join("\n");
|
|
@@ -15906,7 +16087,7 @@ function formatWorkspaceEdit(edit, cwd) {
|
|
|
15906
16087
|
if (edit.changes) {
|
|
15907
16088
|
for (const [uri, edits] of Object.entries(edit.changes)) {
|
|
15908
16089
|
const path = fromUri(uri);
|
|
15909
|
-
const rel =
|
|
16090
|
+
const rel = relative6(cwd, path) || path;
|
|
15910
16091
|
lines.push(`File: ${rel}`);
|
|
15911
16092
|
for (const e of edits) {
|
|
15912
16093
|
lines.push(` ${e.range.start.line + 1}:${e.range.start.character + 1}-${e.range.end.line + 1}:${e.range.end.character + 1}: ${e.newText}`);
|
|
@@ -15931,7 +16112,7 @@ var init_adapter = __esm({
|
|
|
15931
16112
|
});
|
|
15932
16113
|
|
|
15933
16114
|
// src/tools/lsp.ts
|
|
15934
|
-
import { relative as
|
|
16115
|
+
import { relative as relative7 } from "path";
|
|
15935
16116
|
function makeOutput2(content) {
|
|
15936
16117
|
const bytes = Buffer.byteLength(content, "utf8");
|
|
15937
16118
|
return { content, rawBytes: bytes, reducedBytes: bytes };
|
|
@@ -15939,7 +16120,7 @@ function makeOutput2(content) {
|
|
|
15939
16120
|
function resolveLspPath(args, ctx) {
|
|
15940
16121
|
const raw = typeof args.path === "string" ? args.path : "";
|
|
15941
16122
|
const resolved = resolvePath(ctx.cwd, raw);
|
|
15942
|
-
const rel =
|
|
16123
|
+
const rel = relative7(ctx.cwd, resolved);
|
|
15943
16124
|
if (isPathOutside(rel)) {
|
|
15944
16125
|
throw new Error(`Path outside workspace: ${raw}`);
|
|
15945
16126
|
}
|
|
@@ -16205,12 +16386,12 @@ __export(openrouter_catalog_exports, {
|
|
|
16205
16386
|
loadOpenRouterCatalog: () => loadOpenRouterCatalog,
|
|
16206
16387
|
mapOpenRouterModel: () => mapOpenRouterModel
|
|
16207
16388
|
});
|
|
16208
|
-
import { readFile as
|
|
16389
|
+
import { readFile as readFile20, writeFile as writeFile12, mkdir as mkdir14 } from "fs/promises";
|
|
16209
16390
|
import { homedir as homedir18 } from "os";
|
|
16210
|
-
import { join as
|
|
16391
|
+
import { join as join34, dirname as dirname17 } from "path";
|
|
16211
16392
|
function catalogCachePath() {
|
|
16212
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
16213
|
-
return
|
|
16393
|
+
const xdg = process.env.XDG_CONFIG_HOME || join34(homedir18(), ".config");
|
|
16394
|
+
return join34(xdg, "kimiflare", "openrouter-models.json");
|
|
16214
16395
|
}
|
|
16215
16396
|
function perMtok(perToken) {
|
|
16216
16397
|
const n = Number(perToken);
|
|
@@ -16261,7 +16442,7 @@ async function fetchOpenRouterCatalog(fetchImpl2 = fetch) {
|
|
|
16261
16442
|
}
|
|
16262
16443
|
async function readCache3() {
|
|
16263
16444
|
try {
|
|
16264
|
-
const raw = await
|
|
16445
|
+
const raw = await readFile20(catalogCachePath(), "utf8");
|
|
16265
16446
|
const parsed = JSON.parse(raw);
|
|
16266
16447
|
return parsed.version === CACHE_VERSION ? parsed : null;
|
|
16267
16448
|
} catch {
|
|
@@ -16271,7 +16452,7 @@ async function readCache3() {
|
|
|
16271
16452
|
async function writeCache3(models) {
|
|
16272
16453
|
const path = catalogCachePath();
|
|
16273
16454
|
try {
|
|
16274
|
-
await
|
|
16455
|
+
await mkdir14(dirname17(path), { recursive: true });
|
|
16275
16456
|
const cache = { version: CACHE_VERSION, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), models };
|
|
16276
16457
|
await writeFile12(path, JSON.stringify(cache, null, 2), "utf8");
|
|
16277
16458
|
} catch {
|
|
@@ -16320,12 +16501,12 @@ __export(requesty_catalog_exports, {
|
|
|
16320
16501
|
loadRequestyCatalog: () => loadRequestyCatalog,
|
|
16321
16502
|
mapRequestyModel: () => mapRequestyModel
|
|
16322
16503
|
});
|
|
16323
|
-
import { readFile as
|
|
16504
|
+
import { readFile as readFile21, writeFile as writeFile13, mkdir as mkdir15 } from "fs/promises";
|
|
16324
16505
|
import { homedir as homedir19 } from "os";
|
|
16325
|
-
import { join as
|
|
16506
|
+
import { join as join35, dirname as dirname18 } from "path";
|
|
16326
16507
|
function catalogCachePath2() {
|
|
16327
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
16328
|
-
return
|
|
16508
|
+
const xdg = process.env.XDG_CONFIG_HOME || join35(homedir19(), ".config");
|
|
16509
|
+
return join35(xdg, "kimiflare", "requesty-models.json");
|
|
16329
16510
|
}
|
|
16330
16511
|
function isSafeModelId(id) {
|
|
16331
16512
|
return typeof id === "string" && id.length > 0 && !CONTROL_CHARS.test(id);
|
|
@@ -16381,7 +16562,7 @@ async function fetchRequestyCatalog(fetchImpl2 = fetch) {
|
|
|
16381
16562
|
}
|
|
16382
16563
|
async function readCache4() {
|
|
16383
16564
|
try {
|
|
16384
|
-
const raw = await
|
|
16565
|
+
const raw = await readFile21(catalogCachePath2(), "utf8");
|
|
16385
16566
|
const parsed = JSON.parse(raw);
|
|
16386
16567
|
if (parsed.version !== CACHE_VERSION2) return null;
|
|
16387
16568
|
return {
|
|
@@ -16396,7 +16577,7 @@ async function readCache4() {
|
|
|
16396
16577
|
async function writeCache4(catalog) {
|
|
16397
16578
|
const path = catalogCachePath2();
|
|
16398
16579
|
try {
|
|
16399
|
-
await
|
|
16580
|
+
await mkdir15(dirname18(path), { recursive: true });
|
|
16400
16581
|
const cache = { version: CACHE_VERSION2, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), ...catalog };
|
|
16401
16582
|
await writeFile13(path, JSON.stringify(cache, null, 2), "utf8");
|
|
16402
16583
|
} catch {
|
|
@@ -16491,15 +16672,15 @@ var session_exports = {};
|
|
|
16491
16672
|
__export(session_exports, {
|
|
16492
16673
|
createAgentSession: () => createAgentSession
|
|
16493
16674
|
});
|
|
16494
|
-
import { resolve as
|
|
16675
|
+
import { resolve as resolve11 } from "path";
|
|
16495
16676
|
import { homedir as homedir20 } from "os";
|
|
16496
|
-
import { join as
|
|
16677
|
+
import { join as join36 } from "path";
|
|
16497
16678
|
import { existsSync as existsSync7 } from "fs";
|
|
16498
16679
|
async function createAgentSession(opts2) {
|
|
16499
16680
|
const config2 = await resolveSdkConfig(opts2);
|
|
16500
16681
|
if (usesRequesty(llmAuthFromConfig(config2))) await ensureRequestyCatalog();
|
|
16501
16682
|
else if (!resolveCustomEndpoint(config2)) await ensureOpenRouterCatalog();
|
|
16502
|
-
const cwd =
|
|
16683
|
+
const cwd = resolve11(opts2.cwd ?? process.cwd());
|
|
16503
16684
|
const tools = opts2.tools ?? ALL_TOOLS;
|
|
16504
16685
|
let hooks;
|
|
16505
16686
|
if (opts2.enableHooks) {
|
|
@@ -16510,7 +16691,7 @@ async function createAgentSession(opts2) {
|
|
|
16510
16691
|
let memoryManager = null;
|
|
16511
16692
|
const memoryEnabled = opts2.memoryEnabled ?? config2.memoryEnabled ?? false;
|
|
16512
16693
|
if (memoryEnabled) {
|
|
16513
|
-
const dbPath = config2.memoryDbPath ??
|
|
16694
|
+
const dbPath = config2.memoryDbPath ?? join36(homedir20(), ".local", "share", "kimiflare", "memory.db");
|
|
16514
16695
|
memoryManager = new MemoryManager({
|
|
16515
16696
|
dbPath,
|
|
16516
16697
|
...llmAuthFromConfig(config2),
|
|
@@ -16540,7 +16721,7 @@ async function createAgentSession(opts2) {
|
|
|
16540
16721
|
}
|
|
16541
16722
|
let sessionFile;
|
|
16542
16723
|
if (opts2.sessionId) {
|
|
16543
|
-
const filePath =
|
|
16724
|
+
const filePath = join36(sessionsDir(), `${opts2.sessionId}.json`);
|
|
16544
16725
|
try {
|
|
16545
16726
|
sessionFile = await loadSession(filePath);
|
|
16546
16727
|
} catch {
|
|
@@ -16739,8 +16920,8 @@ var init_session = __esm({
|
|
|
16739
16920
|
const parts = [{ type: "text", text }];
|
|
16740
16921
|
for (const img of options.images) {
|
|
16741
16922
|
if ("path" in img) {
|
|
16742
|
-
const { readFile:
|
|
16743
|
-
const data = await
|
|
16923
|
+
const { readFile: readFile38 } = await import("fs/promises");
|
|
16924
|
+
const data = await readFile38(img.path, "base64");
|
|
16744
16925
|
const mimeType = img.path.endsWith(".png") ? "image/png" : img.path.endsWith(".jpg") || img.path.endsWith(".jpeg") ? "image/jpeg" : "image/webp";
|
|
16745
16926
|
parts.push({ type: "image_url", image_url: { url: `data:${mimeType};base64,${data}` } });
|
|
16746
16927
|
} else {
|
|
@@ -16999,12 +17180,12 @@ var init_session = __esm({
|
|
|
16999
17180
|
toolName: req.tool.name,
|
|
17000
17181
|
args: req.args
|
|
17001
17182
|
});
|
|
17002
|
-
const decision = await new Promise((
|
|
17003
|
-
this.permissionResolvers.set(requestId,
|
|
17183
|
+
const decision = await new Promise((resolve20) => {
|
|
17184
|
+
this.permissionResolvers.set(requestId, resolve20);
|
|
17004
17185
|
setTimeout(() => {
|
|
17005
17186
|
if (this.permissionResolvers.has(requestId)) {
|
|
17006
17187
|
this.permissionResolvers.delete(requestId);
|
|
17007
|
-
|
|
17188
|
+
resolve20("deny");
|
|
17008
17189
|
}
|
|
17009
17190
|
}, 3e5);
|
|
17010
17191
|
});
|
|
@@ -17063,14 +17244,14 @@ var init_session = __esm({
|
|
|
17063
17244
|
this.lspManager?.notifyChange(path, content);
|
|
17064
17245
|
} else {
|
|
17065
17246
|
void import("fs/promises").then(
|
|
17066
|
-
({ readFile:
|
|
17247
|
+
({ readFile: readFile38 }) => readFile38(path, "utf8").then((c) => this.lspManager?.notifyChange(path, c)).catch(() => {
|
|
17067
17248
|
})
|
|
17068
17249
|
).catch(() => {
|
|
17069
17250
|
});
|
|
17070
17251
|
}
|
|
17071
17252
|
}
|
|
17072
17253
|
});
|
|
17073
|
-
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync7(
|
|
17254
|
+
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync7(join36(this.cwd, name)))) {
|
|
17074
17255
|
this.messages[0] = {
|
|
17075
17256
|
role: "system",
|
|
17076
17257
|
content: buildSystemPrompt({
|
|
@@ -17094,13 +17275,13 @@ __export(run_exports, {
|
|
|
17094
17275
|
runShell: () => runShell,
|
|
17095
17276
|
summarizeTrace: () => summarizeTrace
|
|
17096
17277
|
});
|
|
17097
|
-
import { spawn as
|
|
17098
|
-
import { appendFile as appendFile3, copyFile, mkdir as
|
|
17099
|
-
import { dirname as
|
|
17278
|
+
import { spawn as spawn7 } from "child_process";
|
|
17279
|
+
import { appendFile as appendFile3, copyFile, mkdir as mkdir16, readFile as readFile22, writeFile as writeFile14 } from "fs/promises";
|
|
17280
|
+
import { dirname as dirname19, join as join37, resolve as resolve12 } from "path";
|
|
17100
17281
|
import { performance as performance2 } from "perf_hooks";
|
|
17101
17282
|
function runShell(command, cwd, timeoutMs) {
|
|
17102
17283
|
return new Promise((resolveShell) => {
|
|
17103
|
-
const child =
|
|
17284
|
+
const child = spawn7(process.platform === "win32" ? process.env.COMSPEC || "cmd.exe" : "bash", [process.platform === "win32" ? "/c" : "-lc", command], {
|
|
17104
17285
|
cwd,
|
|
17105
17286
|
env: { ...process.env, CI: "1", GIT_EDITOR: "true" }
|
|
17106
17287
|
});
|
|
@@ -17129,8 +17310,8 @@ ${err.message}`, timedOut });
|
|
|
17129
17310
|
}
|
|
17130
17311
|
async function copyTaskFiles(task, worktree) {
|
|
17131
17312
|
for (const [dest, src] of Object.entries(task.resolvedFiles)) {
|
|
17132
|
-
const target =
|
|
17133
|
-
await
|
|
17313
|
+
const target = join37(worktree, dest);
|
|
17314
|
+
await mkdir16(dirname19(target), { recursive: true });
|
|
17134
17315
|
await copyFile(src, target);
|
|
17135
17316
|
}
|
|
17136
17317
|
}
|
|
@@ -17138,7 +17319,7 @@ async function summarizeTrace(traceFile) {
|
|
|
17138
17319
|
const out = { cost_usd: 0, prompt_tokens: 0, completion_tokens: 0, turns: 0, tool_calls: 0, overflow: false };
|
|
17139
17320
|
let raw;
|
|
17140
17321
|
try {
|
|
17141
|
-
raw = await
|
|
17322
|
+
raw = await readFile22(traceFile, "utf8");
|
|
17142
17323
|
} catch {
|
|
17143
17324
|
return out;
|
|
17144
17325
|
}
|
|
@@ -17170,7 +17351,7 @@ function sessionIdFor(runName, task, sample) {
|
|
|
17170
17351
|
async function runOne(task, sample, ctx) {
|
|
17171
17352
|
const startedAt2 = performance2.now();
|
|
17172
17353
|
const sessionId = sessionIdFor(ctx.runName, task, sample);
|
|
17173
|
-
const traceDir =
|
|
17354
|
+
const traceDir = join37(ctx.tracesRoot, sessionId);
|
|
17174
17355
|
const base = {
|
|
17175
17356
|
task_id: task.id,
|
|
17176
17357
|
sample,
|
|
@@ -17195,15 +17376,15 @@ async function runOne(task, sample, ctx) {
|
|
|
17195
17376
|
});
|
|
17196
17377
|
let worktree = null;
|
|
17197
17378
|
try {
|
|
17198
|
-
const sourceRepo = await prepareSourceRepo(task.repo,
|
|
17199
|
-
worktree = await createWorktree(sourceRepo, task.base_commit,
|
|
17379
|
+
const sourceRepo = await prepareSourceRepo(task.repo, join37(ctx.out, "cache"));
|
|
17380
|
+
worktree = await createWorktree(sourceRepo, task.base_commit, join37(ctx.out, "work", task.id, String(sample)));
|
|
17200
17381
|
await copyTaskFiles(task, worktree.path);
|
|
17201
17382
|
const timeoutMs = (task.timeout_s ?? DEFAULT_TASK_TIMEOUT_S) * 1e3;
|
|
17202
17383
|
if (task.setup) {
|
|
17203
17384
|
ctx.log(`[${task.id}#${sample}] setup`);
|
|
17204
17385
|
const setup = await runShell(task.setup, worktree.path, timeoutMs);
|
|
17205
17386
|
if (setup.exitCode !== 0) {
|
|
17206
|
-
await writeFile14(
|
|
17387
|
+
await writeFile14(join37(worktree.path, ".eval-setup.log"), setup.log, "utf8").catch(() => void 0);
|
|
17207
17388
|
return finish({ error: `setup failed (exit ${setup.exitCode}${setup.timedOut ? ", timed out" : ""}): ${setup.log.slice(-500)}` });
|
|
17208
17389
|
}
|
|
17209
17390
|
}
|
|
@@ -17237,8 +17418,8 @@ async function runOne(task, sample, ctx) {
|
|
|
17237
17418
|
const test = await runShell(task.test, worktree.path, timeoutMs);
|
|
17238
17419
|
const testMs = Math.round(performance2.now() - testStartedAt);
|
|
17239
17420
|
const passed = test.exitCode === 0 && !test.timedOut;
|
|
17240
|
-
await
|
|
17241
|
-
await writeFile14(
|
|
17421
|
+
await mkdir16(traceDir, { recursive: true }).catch(() => void 0);
|
|
17422
|
+
await writeFile14(join37(traceDir, "test.log"), test.log, "utf8").catch(() => void 0);
|
|
17242
17423
|
if (session.trace.enabled) {
|
|
17243
17424
|
session.trace.emit(
|
|
17244
17425
|
"outcome",
|
|
@@ -17256,7 +17437,7 @@ async function runOne(task, sample, ctx) {
|
|
|
17256
17437
|
}
|
|
17257
17438
|
session.dispose({ traceEndReason: "eval_done" });
|
|
17258
17439
|
await session.trace.flush();
|
|
17259
|
-
const stats = await summarizeTrace(
|
|
17440
|
+
const stats = await summarizeTrace(join37(traceDir, "trace.jsonl"));
|
|
17260
17441
|
ctx.log(`[${task.id}#${sample}] ${passed ? "PASS" : "FAIL"} in ${agentMs + testMs} ms${agentError ? ` (${agentError.slice(0, 120)})` : ""}`);
|
|
17261
17442
|
return finish({
|
|
17262
17443
|
passed,
|
|
@@ -17274,7 +17455,7 @@ async function runOne(task, sample, ctx) {
|
|
|
17274
17455
|
}
|
|
17275
17456
|
}
|
|
17276
17457
|
async function runEval(opts2) {
|
|
17277
|
-
const out =
|
|
17458
|
+
const out = resolve12(opts2.out);
|
|
17278
17459
|
const log2 = opts2.log ?? ((line) => process.stderr.write(`${line}
|
|
17279
17460
|
`));
|
|
17280
17461
|
const evalConfig = await loadEvalConfig(opts2.configFile);
|
|
@@ -17285,12 +17466,12 @@ async function runEval(opts2) {
|
|
|
17285
17466
|
const samples = Math.max(1, Math.floor(opts2.samples ?? 1));
|
|
17286
17467
|
const concurrency = Math.max(1, Math.floor(opts2.concurrency ?? 1));
|
|
17287
17468
|
const createSession = opts2.createSession ?? (await Promise.resolve().then(() => (init_session(), session_exports))).createAgentSession;
|
|
17288
|
-
await
|
|
17289
|
-
const tracesRoot =
|
|
17469
|
+
await mkdir16(out, { recursive: true });
|
|
17470
|
+
const tracesRoot = join37(out, "traces");
|
|
17290
17471
|
const runName = evalConfig.name;
|
|
17291
|
-
const resultsFile =
|
|
17472
|
+
const resultsFile = join37(out, "results.jsonl");
|
|
17292
17473
|
await writeFile14(
|
|
17293
|
-
|
|
17474
|
+
join37(out, "config.json"),
|
|
17294
17475
|
JSON.stringify({ name: evalConfig.name, model, temperature: evalConfig.temperature ?? null, config: redactConfig(evalConfig.config), tasks: opts2.tasksDir, samples, started_at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
17295
17476
|
"utf8"
|
|
17296
17477
|
);
|
|
@@ -17334,9 +17515,9 @@ __export(compare_exports, {
|
|
|
17334
17515
|
perTask: () => perTask,
|
|
17335
17516
|
summarizeArm: () => summarizeArm
|
|
17336
17517
|
});
|
|
17337
|
-
import { readFile as
|
|
17518
|
+
import { readFile as readFile23 } from "fs/promises";
|
|
17338
17519
|
async function loadResults(file) {
|
|
17339
|
-
const raw = await
|
|
17520
|
+
const raw = await readFile23(file, "utf8");
|
|
17340
17521
|
return raw.split("\n").filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
17341
17522
|
}
|
|
17342
17523
|
function median(values) {
|
|
@@ -17469,16 +17650,16 @@ __export(cost_verify_exports, {
|
|
|
17469
17650
|
verifySession: () => verifySession,
|
|
17470
17651
|
verifyTurn: () => verifyTurn
|
|
17471
17652
|
});
|
|
17472
|
-
import { readFile as
|
|
17653
|
+
import { readFile as readFile24 } from "fs/promises";
|
|
17473
17654
|
import { homedir as homedir21 } from "os";
|
|
17474
|
-
import { join as
|
|
17655
|
+
import { join as join38 } from "path";
|
|
17475
17656
|
function usagePath2() {
|
|
17476
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
17477
|
-
return
|
|
17657
|
+
const xdg = process.env.XDG_DATA_HOME || join38(homedir21(), ".local", "share");
|
|
17658
|
+
return join38(xdg, "kimiflare", "usage.json");
|
|
17478
17659
|
}
|
|
17479
17660
|
async function loadSessions() {
|
|
17480
17661
|
try {
|
|
17481
|
-
return JSON.parse(await
|
|
17662
|
+
return JSON.parse(await readFile24(usagePath2(), "utf8")).sessions ?? [];
|
|
17482
17663
|
} catch {
|
|
17483
17664
|
return [];
|
|
17484
17665
|
}
|
|
@@ -17797,12 +17978,12 @@ function extOf(path) {
|
|
|
17797
17978
|
const idx = path.lastIndexOf(".");
|
|
17798
17979
|
return idx >= 0 ? path.slice(idx).toLowerCase() : "";
|
|
17799
17980
|
}
|
|
17800
|
-
function
|
|
17981
|
+
function basename7(path) {
|
|
17801
17982
|
const idx = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
17802
17983
|
return idx >= 0 ? path.slice(idx + 1) : path;
|
|
17803
17984
|
}
|
|
17804
17985
|
function classifyFile(path) {
|
|
17805
|
-
const base =
|
|
17986
|
+
const base = basename7(path);
|
|
17806
17987
|
const ext = extOf(path);
|
|
17807
17988
|
if (TEST_PATTERNS.test(base)) return "writing-tests";
|
|
17808
17989
|
if (base.toLowerCase().startsWith("readme")) return "reading-documentation";
|
|
@@ -17813,7 +17994,7 @@ function classifyFile(path) {
|
|
|
17813
17994
|
return null;
|
|
17814
17995
|
}
|
|
17815
17996
|
function classifyWriteFile(path) {
|
|
17816
|
-
const base =
|
|
17997
|
+
const base = basename7(path);
|
|
17817
17998
|
const ext = extOf(path);
|
|
17818
17999
|
if (TEST_PATTERNS.test(base)) return "writing-tests";
|
|
17819
18000
|
if (base.toLowerCase().startsWith("readme") || DOC_EXTS.has(ext)) return "writing-documentation";
|
|
@@ -17822,7 +18003,7 @@ function classifyWriteFile(path) {
|
|
|
17822
18003
|
return null;
|
|
17823
18004
|
}
|
|
17824
18005
|
function classifyEditFile(path) {
|
|
17825
|
-
const base =
|
|
18006
|
+
const base = basename7(path);
|
|
17826
18007
|
const ext = extOf(path);
|
|
17827
18008
|
if (base.toLowerCase().startsWith("readme") || DOC_EXTS.has(ext)) return "editing-documentation";
|
|
17828
18009
|
if (CONFIG_EXTS.has(ext)) return "editing-configuration";
|
|
@@ -18009,12 +18190,12 @@ var init_heuristic = __esm({
|
|
|
18009
18190
|
});
|
|
18010
18191
|
|
|
18011
18192
|
// src/cost-attribution/classify-from-session.ts
|
|
18012
|
-
import { readFile as
|
|
18013
|
-
import { join as
|
|
18193
|
+
import { readFile as readFile25 } from "fs/promises";
|
|
18194
|
+
import { join as join39 } from "path";
|
|
18014
18195
|
import { homedir as homedir22 } from "os";
|
|
18015
18196
|
function sessionsDir2() {
|
|
18016
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
18017
|
-
return
|
|
18197
|
+
const xdg = process.env.XDG_DATA_HOME || join39(homedir22(), ".local", "share");
|
|
18198
|
+
return join39(xdg, "kimiflare", "sessions");
|
|
18018
18199
|
}
|
|
18019
18200
|
function parseToolCalls(calls) {
|
|
18020
18201
|
return calls.map((c) => {
|
|
@@ -18028,7 +18209,7 @@ function parseToolCalls(calls) {
|
|
|
18028
18209
|
}
|
|
18029
18210
|
async function classifyFromSessionFile(sessionId) {
|
|
18030
18211
|
try {
|
|
18031
|
-
const raw = await
|
|
18212
|
+
const raw = await readFile25(join39(sessionsDir2(), `${sessionId}.json`), "utf8");
|
|
18032
18213
|
const session = JSON.parse(raw);
|
|
18033
18214
|
const messages = session.messages ?? [];
|
|
18034
18215
|
const turns = [];
|
|
@@ -18061,15 +18242,15 @@ var cli_exports = {};
|
|
|
18061
18242
|
__export(cli_exports, {
|
|
18062
18243
|
runCostCommand: () => runCostCommand
|
|
18063
18244
|
});
|
|
18064
|
-
import { readFile as
|
|
18065
|
-
import { join as
|
|
18245
|
+
import { readFile as readFile26 } from "fs/promises";
|
|
18246
|
+
import { join as join40 } from "path";
|
|
18066
18247
|
import { homedir as homedir23 } from "os";
|
|
18067
18248
|
function usageDir2() {
|
|
18068
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
18069
|
-
return
|
|
18249
|
+
const xdg = process.env.XDG_DATA_HOME || join40(homedir23(), ".local", "share");
|
|
18250
|
+
return join40(xdg, "kimiflare");
|
|
18070
18251
|
}
|
|
18071
18252
|
function usagePath3() {
|
|
18072
|
-
return
|
|
18253
|
+
return join40(usageDir2(), "usage.json");
|
|
18073
18254
|
}
|
|
18074
18255
|
function today2() {
|
|
18075
18256
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -18081,7 +18262,7 @@ function daysAgo(n) {
|
|
|
18081
18262
|
}
|
|
18082
18263
|
async function loadLog2() {
|
|
18083
18264
|
try {
|
|
18084
|
-
const raw = await
|
|
18265
|
+
const raw = await readFile26(usagePath3(), "utf8");
|
|
18085
18266
|
return JSON.parse(raw);
|
|
18086
18267
|
} catch {
|
|
18087
18268
|
return { version: 1, days: [], sessions: [] };
|
|
@@ -18171,12 +18352,12 @@ __export(aster_workspaces_exports, {
|
|
|
18171
18352
|
findAsterWorkspace: () => findAsterWorkspace,
|
|
18172
18353
|
loadAsterServerConfig: () => loadAsterServerConfig
|
|
18173
18354
|
});
|
|
18174
|
-
import { readFile as
|
|
18175
|
-
import { isAbsolute as
|
|
18355
|
+
import { readFile as readFile27, realpath as realpath5, stat as stat11 } from "fs/promises";
|
|
18356
|
+
import { isAbsolute as isAbsolute5, relative as relative8, sep as sep4 } from "path";
|
|
18176
18357
|
async function loadAsterServerConfig(configPath3 = process.env.AUTOPILOT_ASTER_CONFIG || "/etc/autopilot/aster.json") {
|
|
18177
18358
|
let raw;
|
|
18178
18359
|
try {
|
|
18179
|
-
raw = JSON.parse(await
|
|
18360
|
+
raw = JSON.parse(await readFile27(configPath3, "utf8"));
|
|
18180
18361
|
} catch {
|
|
18181
18362
|
throw new AsterConfigError();
|
|
18182
18363
|
}
|
|
@@ -18209,15 +18390,15 @@ async function loadAsterServerConfig(configPath3 = process.env.AUTOPILOT_ASTER_C
|
|
|
18209
18390
|
if (typeof workspace.displayName !== "string" || !workspace.displayName.trim() || workspace.displayName.length > 100) {
|
|
18210
18391
|
throw new AsterConfigError();
|
|
18211
18392
|
}
|
|
18212
|
-
if (typeof workspace.rootPath !== "string" || !
|
|
18393
|
+
if (typeof workspace.rootPath !== "string" || !isAbsolute5(workspace.rootPath)) throw new AsterConfigError();
|
|
18213
18394
|
let rootPath;
|
|
18214
18395
|
try {
|
|
18215
|
-
rootPath = await
|
|
18216
|
-
if (!(await
|
|
18396
|
+
rootPath = await realpath5(workspace.rootPath);
|
|
18397
|
+
if (!(await stat11(rootPath)).isDirectory()) throw new Error("not a directory");
|
|
18217
18398
|
} catch {
|
|
18218
18399
|
throw new AsterConfigError();
|
|
18219
18400
|
}
|
|
18220
|
-
if (roots.some((root) =>
|
|
18401
|
+
if (roots.some((root) => isWithin2(root, rootPath) || isWithin2(rootPath, root))) {
|
|
18221
18402
|
throw new AsterConfigError();
|
|
18222
18403
|
}
|
|
18223
18404
|
ids.add(workspace.id);
|
|
@@ -18229,9 +18410,9 @@ async function loadAsterServerConfig(configPath3 = process.env.AUTOPILOT_ASTER_C
|
|
|
18229
18410
|
function findAsterWorkspace(config2, workspaceId) {
|
|
18230
18411
|
return config2.workspaces.find((workspace) => workspace.id === workspaceId);
|
|
18231
18412
|
}
|
|
18232
|
-
function
|
|
18233
|
-
const rel =
|
|
18234
|
-
return rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
18413
|
+
function isWithin2(parent, candidate) {
|
|
18414
|
+
const rel = relative8(parent, candidate);
|
|
18415
|
+
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep4}`) && !isAbsolute5(rel);
|
|
18235
18416
|
}
|
|
18236
18417
|
var AsterConfigError;
|
|
18237
18418
|
var init_aster_workspaces = __esm({
|
|
@@ -18255,10 +18436,10 @@ import Database4 from "better-sqlite3";
|
|
|
18255
18436
|
import { createHash as createHash5, randomBytes as randomBytes2, randomUUID as randomUUID6 } from "crypto";
|
|
18256
18437
|
import { chmodSync as chmodSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
18257
18438
|
import { homedir as homedir24 } from "os";
|
|
18258
|
-
import { dirname as
|
|
18439
|
+
import { dirname as dirname20, join as join41 } from "path";
|
|
18259
18440
|
function defaultAsterDbPath() {
|
|
18260
|
-
const root = process.env.XDG_STATE_HOME ||
|
|
18261
|
-
return process.env.AUTOPILOT_ASTER_DB ||
|
|
18441
|
+
const root = process.env.XDG_STATE_HOME || join41(homedir24(), ".local", "state");
|
|
18442
|
+
return process.env.AUTOPILOT_ASTER_DB || join41(root, "autopilot", "aster.db");
|
|
18262
18443
|
}
|
|
18263
18444
|
function hashToken(token) {
|
|
18264
18445
|
return createHash5("sha256").update(token).digest("hex");
|
|
@@ -18309,9 +18490,9 @@ var init_aster_store = __esm({
|
|
|
18309
18490
|
AsterStore = class {
|
|
18310
18491
|
db;
|
|
18311
18492
|
constructor(dbPath = defaultAsterDbPath()) {
|
|
18312
|
-
mkdirSync9(
|
|
18493
|
+
mkdirSync9(dirname20(dbPath), { recursive: true, mode: 448 });
|
|
18313
18494
|
try {
|
|
18314
|
-
chmodSync2(
|
|
18495
|
+
chmodSync2(dirname20(dbPath), 448);
|
|
18315
18496
|
} catch {
|
|
18316
18497
|
}
|
|
18317
18498
|
this.db = new Database4(dbPath);
|
|
@@ -18612,7 +18793,7 @@ __export(tui_auth_exports, {
|
|
|
18612
18793
|
authGitHubForTui: () => authGitHubForTui
|
|
18613
18794
|
});
|
|
18614
18795
|
function sleep3(ms) {
|
|
18615
|
-
return new Promise((
|
|
18796
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
18616
18797
|
}
|
|
18617
18798
|
async function* authGitHubForTui() {
|
|
18618
18799
|
yield { message: "Starting GitHub OAuth device flow..." };
|
|
@@ -19183,18 +19364,18 @@ var init_openapi = __esm({
|
|
|
19183
19364
|
|
|
19184
19365
|
// src/runs/worktrees.ts
|
|
19185
19366
|
import { execFile as execFile8 } from "child_process";
|
|
19186
|
-
import { access as access2, chmod as
|
|
19367
|
+
import { access as access2, chmod as chmod4, mkdir as mkdir17, realpath as realpath6 } from "fs/promises";
|
|
19187
19368
|
import { homedir as homedir25 } from "os";
|
|
19188
|
-
import { isAbsolute as
|
|
19369
|
+
import { isAbsolute as isAbsolute6, join as join42, parse, relative as relative9, resolve as resolve13, sep as sep5 } from "path";
|
|
19189
19370
|
function defaultWorktreesDir() {
|
|
19190
|
-
const dataHome = process.env.XDG_DATA_HOME ||
|
|
19191
|
-
return
|
|
19371
|
+
const dataHome = process.env.XDG_DATA_HOME || join42(homedir25(), ".local", "share");
|
|
19372
|
+
return join42(dataHome, "autopilot", "worktrees");
|
|
19192
19373
|
}
|
|
19193
19374
|
function isOutside(path) {
|
|
19194
|
-
return path === ".." || path.startsWith(`..${
|
|
19375
|
+
return path === ".." || path.startsWith(`..${sep5}`) || isAbsolute6(path);
|
|
19195
19376
|
}
|
|
19196
|
-
function
|
|
19197
|
-
const path =
|
|
19377
|
+
function isWithin3(parent, candidate) {
|
|
19378
|
+
const path = relative9(parent, candidate);
|
|
19198
19379
|
return path === "" || !isOutside(path);
|
|
19199
19380
|
}
|
|
19200
19381
|
function runGit(args, cwd) {
|
|
@@ -19222,24 +19403,24 @@ var init_worktrees = __esm({
|
|
|
19222
19403
|
if (runId === "." || runId === ".." || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(runId)) {
|
|
19223
19404
|
throw new Error("runId must contain only letters, numbers, dots, underscores, or hyphens");
|
|
19224
19405
|
}
|
|
19225
|
-
const source = await
|
|
19406
|
+
const source = await realpath6(sourceCwd);
|
|
19226
19407
|
const repositoryRoot = (await runGit(["rev-parse", "--show-toplevel"], source)).trim();
|
|
19227
|
-
const repository = await
|
|
19228
|
-
const sourceRelativePath =
|
|
19408
|
+
const repository = await realpath6(repositoryRoot);
|
|
19409
|
+
const sourceRelativePath = relative9(repository, source);
|
|
19229
19410
|
if (isOutside(sourceRelativePath)) {
|
|
19230
19411
|
throw new Error("sourceCwd must be inside the Git repository");
|
|
19231
19412
|
}
|
|
19232
|
-
const configuredRoot =
|
|
19233
|
-
if (configuredRoot === parse(configuredRoot).root ||
|
|
19413
|
+
const configuredRoot = resolve13(this.rootDir);
|
|
19414
|
+
if (configuredRoot === parse(configuredRoot).root || isWithin3(repository, configuredRoot)) {
|
|
19234
19415
|
throw new Error("worktree root must be outside the source repository and not the filesystem root");
|
|
19235
19416
|
}
|
|
19236
|
-
await
|
|
19237
|
-
const worktreesRoot = await
|
|
19238
|
-
if (
|
|
19417
|
+
await mkdir17(configuredRoot, { recursive: true, mode: 448 });
|
|
19418
|
+
const worktreesRoot = await realpath6(configuredRoot);
|
|
19419
|
+
if (isWithin3(repository, worktreesRoot)) {
|
|
19239
19420
|
throw new Error("worktree root must be outside the source repository");
|
|
19240
19421
|
}
|
|
19241
|
-
await
|
|
19242
|
-
const worktreePath =
|
|
19422
|
+
await chmod4(worktreesRoot, 448);
|
|
19423
|
+
const worktreePath = join42(worktreesRoot, runId);
|
|
19243
19424
|
try {
|
|
19244
19425
|
await access2(worktreePath);
|
|
19245
19426
|
throw new Error(`worktree path already exists for run ${runId}`);
|
|
@@ -19253,16 +19434,16 @@ var init_worktrees = __esm({
|
|
|
19253
19434
|
repositoryRoot: repository,
|
|
19254
19435
|
sourceCwd: source,
|
|
19255
19436
|
worktreePath,
|
|
19256
|
-
cwd:
|
|
19437
|
+
cwd: resolve13(worktreePath, sourceRelativePath),
|
|
19257
19438
|
branch
|
|
19258
19439
|
};
|
|
19259
19440
|
}
|
|
19260
19441
|
/** Remove a newly-created, still-clean worktree when run initialization fails. */
|
|
19261
19442
|
async discard(worktree) {
|
|
19262
|
-
const root = await
|
|
19263
|
-
const target = await
|
|
19264
|
-
const repository = await
|
|
19265
|
-
if (target === root || !
|
|
19443
|
+
const root = await realpath6(this.rootDir);
|
|
19444
|
+
const target = await realpath6(worktree.worktreePath);
|
|
19445
|
+
const repository = await realpath6(worktree.repositoryRoot);
|
|
19446
|
+
if (target === root || !isWithin3(root, target)) {
|
|
19266
19447
|
throw new Error("worktree path is outside the configured worktree root");
|
|
19267
19448
|
}
|
|
19268
19449
|
if (worktree.branch !== `autopilot/run/${worktree.runId}`) {
|
|
@@ -19407,8 +19588,8 @@ var init_wake_scheduler = __esm({
|
|
|
19407
19588
|
});
|
|
19408
19589
|
|
|
19409
19590
|
// src/server/aster-tools.ts
|
|
19410
|
-
import { realpath as
|
|
19411
|
-
import { isAbsolute as
|
|
19591
|
+
import { realpath as realpath7 } from "fs/promises";
|
|
19592
|
+
import { isAbsolute as isAbsolute7, relative as relative10, sep as sep6 } from "path";
|
|
19412
19593
|
function createAsterTools(workspaceRoot) {
|
|
19413
19594
|
return ASTR_TOOLS.map((tool) => ({
|
|
19414
19595
|
...tool,
|
|
@@ -19420,25 +19601,25 @@ function createAsterTools(workspaceRoot) {
|
|
|
19420
19601
|
}
|
|
19421
19602
|
async function assertAsterWorkspacePath(workspaceRoot, value, allowMissing = false) {
|
|
19422
19603
|
if (typeof value !== "string" || !value.trim()) throw new Error("workspace_path_invalid");
|
|
19423
|
-
const root = await
|
|
19604
|
+
const root = await realpath7(workspaceRoot);
|
|
19424
19605
|
const candidate = resolvePath(root, value);
|
|
19425
19606
|
assertInside(root, candidate);
|
|
19426
19607
|
assertNotSensitive(root, candidate);
|
|
19427
19608
|
let actual;
|
|
19428
19609
|
try {
|
|
19429
|
-
actual = await
|
|
19610
|
+
actual = await realpath7(candidate);
|
|
19430
19611
|
} catch (error) {
|
|
19431
19612
|
if (!allowMissing || error.code !== "ENOENT") throw new Error("workspace_path_unavailable");
|
|
19432
19613
|
let ancestor = candidate;
|
|
19433
19614
|
while (true) {
|
|
19434
19615
|
try {
|
|
19435
|
-
actual = await
|
|
19616
|
+
actual = await realpath7(ancestor);
|
|
19436
19617
|
break;
|
|
19437
19618
|
} catch (ancestorError) {
|
|
19438
19619
|
if (ancestorError.code !== "ENOENT") throw new Error("workspace_path_unavailable");
|
|
19439
|
-
const parent =
|
|
19620
|
+
const parent = relative10(root, ancestor);
|
|
19440
19621
|
if (!parent || parent === ".") throw new Error("workspace_path_unavailable");
|
|
19441
|
-
ancestor = ancestor.slice(0, ancestor.lastIndexOf(
|
|
19622
|
+
ancestor = ancestor.slice(0, ancestor.lastIndexOf(sep6));
|
|
19442
19623
|
}
|
|
19443
19624
|
}
|
|
19444
19625
|
}
|
|
@@ -19460,11 +19641,11 @@ function redactLikelySecrets(value) {
|
|
|
19460
19641
|
return value.replace(SK_CANDIDATE_RE, (match) => isLikelySkKey(match) ? "[REDACTED_PROVIDER_SECRET]" : match).replace(/\bgh[pousr]_[A-Za-z0-9]{20,}/g, "[REDACTED_PROVIDER_SECRET]").replace(/\bgithub_pat_[A-Za-z0-9_]{20,}/g, "[REDACTED_PROVIDER_SECRET]");
|
|
19461
19642
|
}
|
|
19462
19643
|
function assertInside(root, candidate) {
|
|
19463
|
-
const rel =
|
|
19464
|
-
if (rel === ".." || rel.startsWith(`..${
|
|
19644
|
+
const rel = relative10(root, candidate);
|
|
19645
|
+
if (rel === ".." || rel.startsWith(`..${sep6}`) || isAbsolute7(rel)) throw new Error("workspace_path_forbidden");
|
|
19465
19646
|
}
|
|
19466
19647
|
function assertNotSensitive(root, candidate) {
|
|
19467
|
-
const parts =
|
|
19648
|
+
const parts = relative10(root, candidate).split(sep6).filter(Boolean).map((part) => part.toLowerCase());
|
|
19468
19649
|
if (parts.some((part) => part === ".env" || part.startsWith(".env.") || SENSITIVE_NAMES.has(part))) {
|
|
19469
19650
|
throw new Error("workspace_sensitive_path_forbidden");
|
|
19470
19651
|
}
|
|
@@ -19498,8 +19679,8 @@ var init_aster_tools = __esm({
|
|
|
19498
19679
|
|
|
19499
19680
|
// src/server/aster-api.ts
|
|
19500
19681
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
19501
|
-
import { unlink as
|
|
19502
|
-
import { resolve as
|
|
19682
|
+
import { unlink as unlink3 } from "fs/promises";
|
|
19683
|
+
import { resolve as resolve14 } from "path";
|
|
19503
19684
|
function parseCursor(header, query) {
|
|
19504
19685
|
const value = (Array.isArray(header) ? header[0] : header) ?? query ?? "0";
|
|
19505
19686
|
if (!/^\d{1,16}$/.test(value)) return void 0;
|
|
@@ -19812,7 +19993,7 @@ var init_aster_api = __esm({
|
|
|
19812
19993
|
store.appendEvent(id, null, "conversation.created", { conversationId: id, workspaceId: workspace.id, model });
|
|
19813
19994
|
json(res, 201, publicConversation(conversation));
|
|
19814
19995
|
} catch {
|
|
19815
|
-
await
|
|
19996
|
+
await unlink3(resolve14(sessionsDir(), `${sessionId}.json`)).catch(() => {
|
|
19816
19997
|
});
|
|
19817
19998
|
await worktreeManager.discard(worktree).catch(() => {
|
|
19818
19999
|
});
|
|
@@ -19837,7 +20018,7 @@ var init_aster_api = __esm({
|
|
|
19837
20018
|
sendError(res, 409, "conversation_busy", "A turn is already active for this conversation");
|
|
19838
20019
|
return;
|
|
19839
20020
|
}
|
|
19840
|
-
const sessionPath =
|
|
20021
|
+
const sessionPath = resolve14(sessionsDir(), conversation.sessionId + ".json");
|
|
19841
20022
|
let sessionFile;
|
|
19842
20023
|
try {
|
|
19843
20024
|
sessionFile = await loadSession(sessionPath);
|
|
@@ -20155,7 +20336,7 @@ data: ${JSON.stringify(event.data)}
|
|
|
20155
20336
|
|
|
20156
20337
|
// src/server/aster-cell-runtime.ts
|
|
20157
20338
|
import { execFile as execFile9 } from "child_process";
|
|
20158
|
-
import { readFile as
|
|
20339
|
+
import { readFile as readFile28 } from "fs/promises";
|
|
20159
20340
|
import { promisify as promisify8 } from "util";
|
|
20160
20341
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
20161
20342
|
async function writeCellFileChunked(cell, path, content) {
|
|
@@ -20185,7 +20366,7 @@ async function writeCellFileChunked(cell, path, content) {
|
|
|
20185
20366
|
async function readBundledCellSdkBundle() {
|
|
20186
20367
|
for (const url of [new URL("./sdk/index.js", import.meta.url), new URL("../sdk/index.js", import.meta.url)]) {
|
|
20187
20368
|
try {
|
|
20188
|
-
return await
|
|
20369
|
+
return await readFile28(url, "utf8");
|
|
20189
20370
|
} catch {
|
|
20190
20371
|
}
|
|
20191
20372
|
}
|
|
@@ -20238,7 +20419,7 @@ function boundedToolText(text, limit) {
|
|
|
20238
20419
|
${redacted.slice(-half)}`;
|
|
20239
20420
|
}
|
|
20240
20421
|
function sleep4(ms) {
|
|
20241
|
-
return new Promise((
|
|
20422
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
20242
20423
|
}
|
|
20243
20424
|
var execFileAsync6, CELL_WORKSPACE, CELL_STATE_DIR, CHECKPOINT_MESSAGE_FILE, CELL_RUNTIME_DIR, INSTALLED_RUNTIME_PACKAGE, CELL_RUNTIME_SDK_ENTRY, NOTES_FILE, MEMORY_FILE, MEMORY_EXTRACTION_TIMEOUT_MS, LIVENESS_CHECK_MS, ARTIFACTS_DIR, MAX_ARTIFACTS, MAX_ARTIFACT_BYTES, BRANCH_RE, REPOSITORY_RE, GIT, COMMIT_SHA_RE, MAX_TOOL_OUTPUT_CHARS, MAX_TOOL_INPUT_CHARS, MAX_CHECKPOINTS, CELL_CONTROL_DIR, BRIDGE_MARKER, CONTROL_RUNNER, BRIDGE_RUNNER, HEALTH_TIMEOUT_MS, EVENT_POLL_MS, AsterHotcellRuntime, CELL_FILE_WRITE_CHUNK_CHARS, ARTIFACT_MIME_TYPES;
|
|
20244
20425
|
var init_aster_cell_runtime = __esm({
|
|
@@ -20681,9 +20862,9 @@ ${turn.userText}` : turn.userText;
|
|
|
20681
20862
|
if (!isSafeArtifactPath(path)) throw new Error("invalid_artifact_path");
|
|
20682
20863
|
const cell = await this.provider.getCell(cellId);
|
|
20683
20864
|
const file = shellQuote2(`${ARTIFACTS_DIR}/${path}`);
|
|
20684
|
-
const
|
|
20685
|
-
if (
|
|
20686
|
-
if (Number(
|
|
20865
|
+
const stat15 = await cell.exec(`[ -f ${file} ] && [ ! -L ${file} ] && stat -c %s -- ${file}`);
|
|
20866
|
+
if (stat15.exitCode !== 0) throw new Error("artifact_not_found");
|
|
20867
|
+
if (Number(stat15.stdout.trim()) > MAX_ARTIFACT_BYTES) throw new Error("artifact_too_large");
|
|
20687
20868
|
const encoded = await cell.exec(`base64 -w0 -- ${file}`);
|
|
20688
20869
|
if (encoded.exitCode !== 0) throw new Error("artifact_not_found");
|
|
20689
20870
|
return { data: Buffer.from(encoded.stdout.trim(), "base64"), mimeType: artifactMimeType(path), name: path.split("/").pop() ?? path };
|
|
@@ -20980,8 +21161,8 @@ var init_hotcell_provider = __esm({
|
|
|
20980
21161
|
// src/server/routes.ts
|
|
20981
21162
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
20982
21163
|
import { URL as URL2 } from "url";
|
|
20983
|
-
import { readFile as
|
|
20984
|
-
import { resolve as
|
|
21164
|
+
import { readFile as readFile29, unlink as unlink4 } from "fs/promises";
|
|
21165
|
+
import { resolve as resolve15, basename as basename8 } from "path";
|
|
20985
21166
|
function createHotcellAsterRuntime() {
|
|
20986
21167
|
try {
|
|
20987
21168
|
const idlePauseMs = Number(process.env.AUTOPILOT_ASTER_IDLE_PAUSE_MS ?? 15 * 60 * 1e3);
|
|
@@ -21064,9 +21245,9 @@ async function resolveFiles2(filePatterns, cwd) {
|
|
|
21064
21245
|
const resolved = /* @__PURE__ */ new Set();
|
|
21065
21246
|
for (const pattern of filePatterns) {
|
|
21066
21247
|
try {
|
|
21067
|
-
const
|
|
21068
|
-
if (
|
|
21069
|
-
resolved.add(
|
|
21248
|
+
const stat15 = await import("fs/promises").then((m) => m.stat(resolve15(cwd, pattern)));
|
|
21249
|
+
if (stat15.isFile()) {
|
|
21250
|
+
resolved.add(resolve15(cwd, pattern));
|
|
21070
21251
|
continue;
|
|
21071
21252
|
}
|
|
21072
21253
|
} catch {
|
|
@@ -21089,12 +21270,12 @@ async function buildUserMessage2(prompt, files, cwd) {
|
|
|
21089
21270
|
imageParts.push({ type: "image_url", image_url: { url: img.dataUrl } });
|
|
21090
21271
|
} catch (e) {
|
|
21091
21272
|
fileContents.push(`
|
|
21092
|
-
<!-- failed to attach image ${
|
|
21273
|
+
<!-- failed to attach image ${basename8(filePath)}: ${e.message} -->
|
|
21093
21274
|
`);
|
|
21094
21275
|
}
|
|
21095
21276
|
} else {
|
|
21096
21277
|
try {
|
|
21097
|
-
const content = await
|
|
21278
|
+
const content = await readFile29(filePath, "utf8");
|
|
21098
21279
|
const relPath = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
|
|
21099
21280
|
fileContents.push(`
|
|
21100
21281
|
--- ${relPath} ---
|
|
@@ -21103,7 +21284,7 @@ ${content}
|
|
|
21103
21284
|
`);
|
|
21104
21285
|
} catch (e) {
|
|
21105
21286
|
fileContents.push(`
|
|
21106
|
-
<!-- failed to read ${
|
|
21287
|
+
<!-- failed to read ${basename8(filePath)}: ${e.message} -->
|
|
21107
21288
|
`);
|
|
21108
21289
|
}
|
|
21109
21290
|
}
|
|
@@ -21123,7 +21304,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
21123
21304
|
if (!run.sessionId) throw new Error("Cannot restore run without a session id: " + run.id);
|
|
21124
21305
|
const existing = activeRuns.get(run.id) ?? activeSessions.get(run.sessionId);
|
|
21125
21306
|
if (existing) return existing;
|
|
21126
|
-
const sessionFile = await loadSession(
|
|
21307
|
+
const sessionFile = await loadSession(resolve15(sessionsDir(), run.sessionId + ".json"));
|
|
21127
21308
|
const allowedTools = new Set(run.allowedTools);
|
|
21128
21309
|
allowedTools.add("wait_for");
|
|
21129
21310
|
const tools = ALL_TOOLS.filter((tool) => allowedTools.has(tool.name));
|
|
@@ -21258,7 +21439,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
21258
21439
|
const task = typeof body.task === "string" ? body.task.trim() : "";
|
|
21259
21440
|
let cwd;
|
|
21260
21441
|
try {
|
|
21261
|
-
cwd = typeof body.cwd === "string" ?
|
|
21442
|
+
cwd = typeof body.cwd === "string" ? resolve15(body.cwd) : process.cwd();
|
|
21262
21443
|
} catch {
|
|
21263
21444
|
badRequest(res, "cwd must be a valid path");
|
|
21264
21445
|
return;
|
|
@@ -21371,7 +21552,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
21371
21552
|
store.close();
|
|
21372
21553
|
}
|
|
21373
21554
|
} catch (error) {
|
|
21374
|
-
await
|
|
21555
|
+
await unlink4(resolve15(sessionsDir(), `${sessionId}.json`)).catch(() => {
|
|
21375
21556
|
});
|
|
21376
21557
|
if (worktree) {
|
|
21377
21558
|
await worktreeManager.discard(worktree).catch((cleanupError) => {
|
|
@@ -21506,7 +21687,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
21506
21687
|
return;
|
|
21507
21688
|
}
|
|
21508
21689
|
try {
|
|
21509
|
-
const file = await loadSession(
|
|
21690
|
+
const file = await loadSession(resolve15(sessionsDir(), `${sessionId}.json`));
|
|
21510
21691
|
json2(res, 200, {
|
|
21511
21692
|
id: file.id,
|
|
21512
21693
|
cwd: file.cwd,
|
|
@@ -21525,8 +21706,8 @@ function setupRoutes(config2, options = {}) {
|
|
|
21525
21706
|
const sessionId = sessionMatch[1];
|
|
21526
21707
|
activeSessions.delete(sessionId);
|
|
21527
21708
|
try {
|
|
21528
|
-
const { unlink:
|
|
21529
|
-
await
|
|
21709
|
+
const { unlink: unlink7 } = await import("fs/promises");
|
|
21710
|
+
await unlink7(resolve15(sessionsDir(), `${sessionId}.json`));
|
|
21530
21711
|
} catch {
|
|
21531
21712
|
}
|
|
21532
21713
|
json2(res, 200, { deleted: sessionId });
|
|
@@ -21977,13 +22158,13 @@ async function startServer(opts2) {
|
|
|
21977
22158
|
};
|
|
21978
22159
|
process.on("SIGINT", shutdown);
|
|
21979
22160
|
process.on("SIGTERM", shutdown);
|
|
21980
|
-
return new Promise((
|
|
22161
|
+
return new Promise((resolve20, reject) => {
|
|
21981
22162
|
server.listen(opts2.port, opts2.hostname, () => {
|
|
21982
22163
|
logger.info("server: listening", { hostname: opts2.hostname, port: opts2.port });
|
|
21983
22164
|
console.log(`kimiflare serve: http://${opts2.hostname}:${opts2.port}`);
|
|
21984
22165
|
console.log(` API docs: http://${opts2.hostname}:${opts2.port}/doc`);
|
|
21985
22166
|
console.log(` SSE stream: http://${opts2.hostname}:${opts2.port}/event`);
|
|
21986
|
-
|
|
22167
|
+
resolve20(server);
|
|
21987
22168
|
});
|
|
21988
22169
|
server.on("error", reject);
|
|
21989
22170
|
});
|
|
@@ -22288,8 +22469,8 @@ async function runEmitMode(opts2) {
|
|
|
22288
22469
|
async function nextFollowUp() {
|
|
22289
22470
|
if (followUpQueue.length > 0) return followUpQueue.shift();
|
|
22290
22471
|
if (stdinClosed) return null;
|
|
22291
|
-
return new Promise((
|
|
22292
|
-
followUpResolver =
|
|
22472
|
+
return new Promise((resolve20) => {
|
|
22473
|
+
followUpResolver = resolve20;
|
|
22293
22474
|
});
|
|
22294
22475
|
}
|
|
22295
22476
|
const cwd = process.cwd();
|
|
@@ -22426,8 +22607,8 @@ async function runEmitMode(opts2) {
|
|
|
22426
22607
|
return "allow";
|
|
22427
22608
|
}
|
|
22428
22609
|
if (opts2.multiTurn) {
|
|
22429
|
-
const choice = await new Promise((
|
|
22430
|
-
pendingPermissions.set(reqId,
|
|
22610
|
+
const choice = await new Promise((resolve20) => {
|
|
22611
|
+
pendingPermissions.set(reqId, resolve20);
|
|
22431
22612
|
});
|
|
22432
22613
|
if (choice === "allow" || choice === "allow_session") {
|
|
22433
22614
|
emit("PermissionGranted", { request_id: reqId });
|
|
@@ -22562,7 +22743,7 @@ async function runAttachMode(opts2) {
|
|
|
22562
22743
|
async function streamSse(url, sessionId, format) {
|
|
22563
22744
|
const eventSource = new EventSource(`${url}/event`);
|
|
22564
22745
|
let done = false;
|
|
22565
|
-
return new Promise((
|
|
22746
|
+
return new Promise((resolve20, reject) => {
|
|
22566
22747
|
eventSource.onmessage = (event) => {
|
|
22567
22748
|
try {
|
|
22568
22749
|
const data = JSON.parse(event.data);
|
|
@@ -22609,7 +22790,7 @@ async function streamSse(url, sessionId, format) {
|
|
|
22609
22790
|
done = true;
|
|
22610
22791
|
eventSource.close();
|
|
22611
22792
|
if (format === "text") process.stdout.write("\n");
|
|
22612
|
-
|
|
22793
|
+
resolve20(void 0);
|
|
22613
22794
|
break;
|
|
22614
22795
|
case "error":
|
|
22615
22796
|
done = true;
|
|
@@ -22622,7 +22803,7 @@ async function streamSse(url, sessionId, format) {
|
|
|
22622
22803
|
process.stdout.write(JSON.stringify({ event: "error", message: data.message }) + "\n");
|
|
22623
22804
|
}
|
|
22624
22805
|
process.exitCode = 1;
|
|
22625
|
-
|
|
22806
|
+
resolve20(void 0);
|
|
22626
22807
|
break;
|
|
22627
22808
|
}
|
|
22628
22809
|
} catch {
|
|
@@ -22648,7 +22829,7 @@ async function streamSseJson(url, sessionId) {
|
|
|
22648
22829
|
const toolResults = [];
|
|
22649
22830
|
let usage;
|
|
22650
22831
|
const eventSource = new EventSource(`${url}/event`);
|
|
22651
|
-
return new Promise((
|
|
22832
|
+
return new Promise((resolve20, reject) => {
|
|
22652
22833
|
eventSource.onmessage = (event) => {
|
|
22653
22834
|
try {
|
|
22654
22835
|
const data = JSON.parse(event.data);
|
|
@@ -22685,7 +22866,7 @@ async function streamSseJson(url, sessionId) {
|
|
|
22685
22866
|
2
|
|
22686
22867
|
) + "\n"
|
|
22687
22868
|
);
|
|
22688
|
-
|
|
22869
|
+
resolve20(void 0);
|
|
22689
22870
|
break;
|
|
22690
22871
|
case "error":
|
|
22691
22872
|
eventSource.close();
|
|
@@ -22693,7 +22874,7 @@ async function streamSseJson(url, sessionId) {
|
|
|
22693
22874
|
JSON.stringify({ error: data.message, sessionId }, null, 2) + "\n"
|
|
22694
22875
|
);
|
|
22695
22876
|
process.exitCode = 1;
|
|
22696
|
-
|
|
22877
|
+
resolve20(void 0);
|
|
22697
22878
|
break;
|
|
22698
22879
|
}
|
|
22699
22880
|
} catch {
|
|
@@ -23422,10 +23603,9 @@ __export(app_helpers_exports, {
|
|
|
23422
23603
|
replaceUserPromptEvent: () => replaceUserPromptEvent,
|
|
23423
23604
|
trackRecentFile: () => trackRecentFile
|
|
23424
23605
|
});
|
|
23425
|
-
import { execSync as execSync3
|
|
23606
|
+
import { execSync as execSync3 } from "child_process";
|
|
23426
23607
|
import { existsSync as existsSync8, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
|
|
23427
|
-
import { join as
|
|
23428
|
-
import { platform as platform3 } from "os";
|
|
23608
|
+
import { join as join43 } from "path";
|
|
23429
23609
|
function replaceQueuedPrompt(queue2, key, full, display) {
|
|
23430
23610
|
const index = queue2.findIndex((item) => item.key === key);
|
|
23431
23611
|
if (index >= 0) {
|
|
@@ -23532,7 +23712,7 @@ function buildFilePickerIgnoreList(cwd) {
|
|
|
23532
23712
|
];
|
|
23533
23713
|
const gitignorePatterns = [];
|
|
23534
23714
|
try {
|
|
23535
|
-
const gitignorePath =
|
|
23715
|
+
const gitignorePath = join43(cwd, ".gitignore");
|
|
23536
23716
|
const stats = statSync5(gitignorePath);
|
|
23537
23717
|
if (stats.size > MAX_GITIGNORE_SIZE) {
|
|
23538
23718
|
return hardcoded;
|
|
@@ -23563,19 +23743,6 @@ function costLookupFromConfig(cfg, meta) {
|
|
|
23563
23743
|
if (resolveCustomEndpoint(cfg)) return void 0;
|
|
23564
23744
|
return { apiKey: cfg.openrouterApiKey, meta };
|
|
23565
23745
|
}
|
|
23566
|
-
function openBrowser(url) {
|
|
23567
|
-
if (process.env.KIMIFLARE_NO_BROWSER === "1" || process.env.BROWSER === "none") return false;
|
|
23568
|
-
try {
|
|
23569
|
-
const os2 = platform3();
|
|
23570
|
-
const [cmd, args] = os2 === "darwin" ? ["open", [url]] : os2 === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
23571
|
-
const child = spawn7(cmd, args, { detached: true, stdio: "ignore" });
|
|
23572
|
-
child.on("error", () => void 0);
|
|
23573
|
-
child.unref();
|
|
23574
|
-
return true;
|
|
23575
|
-
} catch {
|
|
23576
|
-
return false;
|
|
23577
|
-
}
|
|
23578
|
-
}
|
|
23579
23746
|
function detectGitHubRepo(cachedRepo) {
|
|
23580
23747
|
if (cachedRepo) {
|
|
23581
23748
|
const parts = cachedRepo.split("/");
|
|
@@ -23694,6 +23861,7 @@ var init_app_helpers = __esm({
|
|
|
23694
23861
|
init_system_prompt();
|
|
23695
23862
|
init_image();
|
|
23696
23863
|
init_queue_batch();
|
|
23864
|
+
init_open_browser();
|
|
23697
23865
|
MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
|
|
23698
23866
|
CONTEXT_LIMIT = 262e3;
|
|
23699
23867
|
AUTO_COMPACT_THRESHOLD = 0.8;
|
|
@@ -23710,9 +23878,9 @@ var init_app_helpers = __esm({
|
|
|
23710
23878
|
|
|
23711
23879
|
// src/ui/bang-command.ts
|
|
23712
23880
|
import { spawn as spawn8 } from "child_process";
|
|
23713
|
-
import { mkdtemp as
|
|
23714
|
-
import { tmpdir as
|
|
23715
|
-
import { join as
|
|
23881
|
+
import { mkdtemp as mkdtemp3, readFile as readFile30, rm as rm6 } from "fs/promises";
|
|
23882
|
+
import { tmpdir as tmpdir5, platform as platform4 } from "os";
|
|
23883
|
+
import { join as join44 } from "path";
|
|
23716
23884
|
function registerInkInstance(instance) {
|
|
23717
23885
|
inkInstance = instance;
|
|
23718
23886
|
}
|
|
@@ -23720,13 +23888,13 @@ function registerTerminalHandoff(h) {
|
|
|
23720
23888
|
terminalHandoff = h;
|
|
23721
23889
|
}
|
|
23722
23890
|
function runCaptured(inv, cwd) {
|
|
23723
|
-
return new Promise((
|
|
23891
|
+
return new Promise((resolve20) => {
|
|
23724
23892
|
const child = spawn8(inv.file, inv.args, { cwd, stdio: ["ignore", "pipe", "pipe"], env: inv.env ?? process.env });
|
|
23725
23893
|
let output = "";
|
|
23726
23894
|
child.stdout?.on("data", (c) => output += c.toString("utf8"));
|
|
23727
23895
|
child.stderr?.on("data", (c) => output += c.toString("utf8"));
|
|
23728
|
-
child.once("error", (e) =>
|
|
23729
|
-
child.once("exit", (code, signal) =>
|
|
23896
|
+
child.once("error", (e) => resolve20({ code: 127, signal: null, output: `failed to start: ${e.message}` }));
|
|
23897
|
+
child.once("exit", (code, signal) => resolve20({ code, signal, output }));
|
|
23730
23898
|
});
|
|
23731
23899
|
}
|
|
23732
23900
|
function isTerminalHandedOff() {
|
|
@@ -23794,10 +23962,10 @@ function swallow() {
|
|
|
23794
23962
|
});
|
|
23795
23963
|
}
|
|
23796
23964
|
function spawnInherit(inv, cwd) {
|
|
23797
|
-
return new Promise((
|
|
23965
|
+
return new Promise((resolve20, reject) => {
|
|
23798
23966
|
const child = spawn8(inv.file, inv.args, { cwd, stdio: "inherit", env: inv.env ?? process.env });
|
|
23799
23967
|
child.once("error", reject);
|
|
23800
|
-
child.once("exit", (code, signal) =>
|
|
23968
|
+
child.once("exit", (code, signal) => resolve20({ code, signal }));
|
|
23801
23969
|
});
|
|
23802
23970
|
}
|
|
23803
23971
|
async function runBangCommand(command, cwd) {
|
|
@@ -23815,8 +23983,8 @@ async function runBangCommand(command, cwd) {
|
|
|
23815
23983
|
const origErr = stderr.write;
|
|
23816
23984
|
const readable = stdin.listeners("readable");
|
|
23817
23985
|
const wasRaw = stdin.isTTY ? stdin.isRaw : false;
|
|
23818
|
-
const logDir2 = isWindows ? null : await
|
|
23819
|
-
const logPath = logDir2 ?
|
|
23986
|
+
const logDir2 = isWindows ? null : await mkdtemp3(join44(tmpdir5(), "autopilot-bang-"));
|
|
23987
|
+
const logPath = logDir2 ? join44(logDir2, "out.log") : null;
|
|
23820
23988
|
const viaScript = logPath ? scriptInvocation(command, shell, logPath) : null;
|
|
23821
23989
|
inkInstance?.clear();
|
|
23822
23990
|
origOut.call(stdout, `
|
|
@@ -23858,9 +24026,9 @@ $ ${command}
|
|
|
23858
24026
|
}
|
|
23859
24027
|
let output = spawnError ? `failed to start: ${spawnError}` : null;
|
|
23860
24028
|
if (captured && logPath) {
|
|
23861
|
-
output = cleanTerminalOutput(await
|
|
24029
|
+
output = cleanTerminalOutput(await readFile30(logPath, "utf8").catch(() => ""));
|
|
23862
24030
|
}
|
|
23863
|
-
if (logDir2) await
|
|
24031
|
+
if (logDir2) await rm6(logDir2, { recursive: true, force: true }).catch(() => {
|
|
23864
24032
|
});
|
|
23865
24033
|
return { command, exitCode: result2.code, signal: result2.signal, output };
|
|
23866
24034
|
}
|
|
@@ -26039,6 +26207,7 @@ var init_activity = __esm({
|
|
|
26039
26207
|
var camouflage_view_exports = {};
|
|
26040
26208
|
__export(camouflage_view_exports, {
|
|
26041
26209
|
CamouflageUnavailable: () => CamouflageUnavailable,
|
|
26210
|
+
executeCodeSummary: () => executeCodeSummary,
|
|
26042
26211
|
helpOptions: () => helpOptions,
|
|
26043
26212
|
listMentionDir: () => listMentionDir,
|
|
26044
26213
|
modelOptions: () => modelOptions,
|
|
@@ -26050,10 +26219,10 @@ __export(camouflage_view_exports, {
|
|
|
26050
26219
|
toolSummary: () => toolSummary,
|
|
26051
26220
|
validateCommandName: () => validateCommandName
|
|
26052
26221
|
});
|
|
26053
|
-
import { execFileSync as
|
|
26054
|
-
import { readdir as
|
|
26222
|
+
import { execFileSync as execFileSync3, spawn as spawn10 } from "child_process";
|
|
26223
|
+
import { readdir as readdir8 } from "fs/promises";
|
|
26055
26224
|
import { homedir as homedir26 } from "os";
|
|
26056
|
-
import { join as
|
|
26225
|
+
import { join as join45, resolve as resolve16 } from "path";
|
|
26057
26226
|
async function loadSdk() {
|
|
26058
26227
|
const sdk = await import("camouflage-tui").catch((err) => {
|
|
26059
26228
|
throw new CamouflageUnavailable(`camouflage-tui is not installed (${err.message})`);
|
|
@@ -26142,14 +26311,14 @@ async function runCamouflageView(opts2) {
|
|
|
26142
26311
|
}
|
|
26143
26312
|
}
|
|
26144
26313
|
function runShell2(command) {
|
|
26145
|
-
return new Promise((
|
|
26314
|
+
return new Promise((resolve20) => {
|
|
26146
26315
|
const { shell, args } = getShellCommand();
|
|
26147
26316
|
const child = spawn10(shell, [...args, command], { env: process.env });
|
|
26148
26317
|
let out = "";
|
|
26149
26318
|
child.stdout?.on("data", (c) => out += c.toString("utf8"));
|
|
26150
26319
|
child.stderr?.on("data", (c) => out += c.toString("utf8"));
|
|
26151
|
-
child.on("close", (code) =>
|
|
26152
|
-
child.on("error", (err) =>
|
|
26320
|
+
child.on("close", (code) => resolve20({ ok: code === 0, output: out || (code === 0 ? "" : `Exit code: ${code}`) }));
|
|
26321
|
+
child.on("error", (err) => resolve20({ ok: false, output: err.message }));
|
|
26153
26322
|
});
|
|
26154
26323
|
}
|
|
26155
26324
|
function syncSlashCommands(custom, lastKey, send) {
|
|
@@ -26232,10 +26401,10 @@ function truncateText(s, max) {
|
|
|
26232
26401
|
async function listMentionDir(cwd, query) {
|
|
26233
26402
|
const exact = query === "~" || query === "." || query === ".." || query.endsWith("/..");
|
|
26234
26403
|
const dir = exact ? `${query}/` : query.slice(0, query.lastIndexOf("/") + 1);
|
|
26235
|
-
const expanded = dir.startsWith("~") ?
|
|
26236
|
-
const target =
|
|
26404
|
+
const expanded = dir.startsWith("~") ? join45(homedir26(), dir.slice(1)) : dir;
|
|
26405
|
+
const target = resolve16(cwd, expanded || ".");
|
|
26237
26406
|
try {
|
|
26238
|
-
const items = await
|
|
26407
|
+
const items = await readdir8(target, { withFileTypes: true });
|
|
26239
26408
|
const entries = items.filter((d) => !d.name.startsWith(".")).map((d) => ({ name: d.name, isDir: d.isDirectory() })).sort((a, b) => a.isDir !== b.isDir ? a.isDir ? -1 : 1 : a.name.localeCompare(b.name)).slice(0, 300).map((d) => `${dir}${d.name}${d.isDir ? "/" : ""}`);
|
|
26240
26409
|
return { dir, entries };
|
|
26241
26410
|
} catch {
|
|
@@ -26270,8 +26439,26 @@ function toolRow(name, title, rawArgs) {
|
|
|
26270
26439
|
const rest = title.toLowerCase().startsWith(`${name.toLowerCase()} `) ? title.slice(name.length + 1) : title;
|
|
26271
26440
|
return { label, args: rest.trim() };
|
|
26272
26441
|
}
|
|
26442
|
+
if (name === "execute_code") {
|
|
26443
|
+
return { label: "Code", args: clip(executeCodeSummary(rawArgs)) };
|
|
26444
|
+
}
|
|
26273
26445
|
const args = (rawArgs ?? "").replace(/\s+/g, " ").trim();
|
|
26274
|
-
return { label, args: args
|
|
26446
|
+
return { label, args: clip(args) };
|
|
26447
|
+
}
|
|
26448
|
+
function clip(s) {
|
|
26449
|
+
return s.length > 120 ? `${s.slice(0, 119)}\u2026` : s;
|
|
26450
|
+
}
|
|
26451
|
+
function executeCodeSummary(rawArgs) {
|
|
26452
|
+
let parsed = {};
|
|
26453
|
+
try {
|
|
26454
|
+
parsed = rawArgs ? JSON.parse(rawArgs) : {};
|
|
26455
|
+
} catch {
|
|
26456
|
+
return "running a code batch";
|
|
26457
|
+
}
|
|
26458
|
+
if (typeof parsed.reasoning === "string" && parsed.reasoning.trim()) return parsed.reasoning.replace(/\s+/g, " ").trim();
|
|
26459
|
+
const code = typeof parsed.code === "string" ? parsed.code : "";
|
|
26460
|
+
const first = code.split("\n").map((l) => l.trim()).find((l) => l && !l.startsWith("//"));
|
|
26461
|
+
return first ? first.replace(/\s+/g, " ") : "running a code batch";
|
|
26275
26462
|
}
|
|
26276
26463
|
function toolSummary(name, ok, declined, content) {
|
|
26277
26464
|
if (declined) return "You declined this \xB7 tell autopilot what to do instead";
|
|
@@ -26318,14 +26505,14 @@ function shortPath(p) {
|
|
|
26318
26505
|
}
|
|
26319
26506
|
function gitBranch(cwd) {
|
|
26320
26507
|
try {
|
|
26321
|
-
return
|
|
26508
|
+
return execFileSync3("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd, encoding: "utf8", timeout: 500, stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
26322
26509
|
} catch {
|
|
26323
26510
|
return "";
|
|
26324
26511
|
}
|
|
26325
26512
|
}
|
|
26326
26513
|
function listFiles(cwd) {
|
|
26327
26514
|
try {
|
|
26328
|
-
const out =
|
|
26515
|
+
const out = execFileSync3("git", ["ls-files", "--cached", "--others", "--exclude-standard"], {
|
|
26329
26516
|
cwd,
|
|
26330
26517
|
encoding: "utf8",
|
|
26331
26518
|
timeout: 2e3,
|
|
@@ -29224,19 +29411,19 @@ function usePermissionController(getMode, onPlanModeBlocked) {
|
|
|
29224
29411
|
const onPlanModeBlockedRef = useRef3(onPlanModeBlocked);
|
|
29225
29412
|
onPlanModeBlockedRef.current = onPlanModeBlocked;
|
|
29226
29413
|
const askPermission = useCallback2(
|
|
29227
|
-
(req, askOpts) => new Promise((
|
|
29414
|
+
(req, askOpts) => new Promise((resolve20) => {
|
|
29228
29415
|
const outcome = decidePermission(req, getModeRef.current(), askOpts);
|
|
29229
29416
|
if (outcome.kind === "resolve") {
|
|
29230
|
-
|
|
29417
|
+
resolve20(outcome.decision);
|
|
29231
29418
|
return;
|
|
29232
29419
|
}
|
|
29233
29420
|
if (outcome.kind === "plan_blocked") {
|
|
29234
29421
|
onPlanModeBlockedRef.current(outcome.toolName);
|
|
29235
|
-
|
|
29422
|
+
resolve20(AUTO_DENY);
|
|
29236
29423
|
return;
|
|
29237
29424
|
}
|
|
29238
|
-
resolveRef.current =
|
|
29239
|
-
setPending({ tool: req.tool, args: req.args, resolve:
|
|
29425
|
+
resolveRef.current = resolve20;
|
|
29426
|
+
setPending({ tool: req.tool, args: req.args, resolve: resolve20 });
|
|
29240
29427
|
}),
|
|
29241
29428
|
[]
|
|
29242
29429
|
);
|
|
@@ -29581,9 +29768,9 @@ var init_queue_plan_picker = __esm({
|
|
|
29581
29768
|
});
|
|
29582
29769
|
|
|
29583
29770
|
// src/agent/jev-context.ts
|
|
29584
|
-
import { execFileSync as
|
|
29585
|
-
import { readFile as
|
|
29586
|
-
import { basename as
|
|
29771
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
29772
|
+
import { readFile as readFile31 } from "fs/promises";
|
|
29773
|
+
import { basename as basename9, join as join46, resolve as resolve17 } from "path";
|
|
29587
29774
|
function messageText(message2) {
|
|
29588
29775
|
if (typeof message2.content === "string") return message2.content.trim();
|
|
29589
29776
|
if (!Array.isArray(message2.content)) return "";
|
|
@@ -29594,18 +29781,18 @@ function redactCommonSecrets(text) {
|
|
|
29594
29781
|
}
|
|
29595
29782
|
function projectRoot(cwd) {
|
|
29596
29783
|
try {
|
|
29597
|
-
return
|
|
29784
|
+
return execFileSync4("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
|
|
29598
29785
|
encoding: "utf8",
|
|
29599
29786
|
stdio: ["ignore", "pipe", "ignore"],
|
|
29600
29787
|
timeout: 1e3
|
|
29601
29788
|
}).trim();
|
|
29602
29789
|
} catch {
|
|
29603
|
-
return
|
|
29790
|
+
return resolve17(cwd);
|
|
29604
29791
|
}
|
|
29605
29792
|
}
|
|
29606
29793
|
async function readPackageMetadata(root) {
|
|
29607
29794
|
try {
|
|
29608
|
-
const parsed = JSON.parse(await
|
|
29795
|
+
const parsed = JSON.parse(await readFile31(join46(root, "package.json"), "utf8"));
|
|
29609
29796
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
29610
29797
|
const pkg = parsed;
|
|
29611
29798
|
const metadata = {};
|
|
@@ -29622,7 +29809,7 @@ async function readPackageMetadata(root) {
|
|
|
29622
29809
|
async function readLicenseEvidence(root) {
|
|
29623
29810
|
for (const name of ["LICENSE", "LICENSE.md", "LICENSE.txt", "LICENCE", "COPYING"]) {
|
|
29624
29811
|
try {
|
|
29625
|
-
const content = (await
|
|
29812
|
+
const content = (await readFile31(join46(root, name), "utf8")).trim();
|
|
29626
29813
|
if (content) return { source: `project license (${name})`, content: content.slice(0, 700) };
|
|
29627
29814
|
} catch {
|
|
29628
29815
|
}
|
|
@@ -29655,13 +29842,13 @@ async function buildJevContext(question, messages, cwd = process.cwd()) {
|
|
|
29655
29842
|
conversationRemaining -= source.length + content.length + 2;
|
|
29656
29843
|
}
|
|
29657
29844
|
}
|
|
29658
|
-
const currentDirectory =
|
|
29845
|
+
const currentDirectory = basename9(resolve17(cwd));
|
|
29659
29846
|
const escapedDirectory = currentDirectory.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
29660
29847
|
const namesCurrentDirectory = currentDirectory.length >= 5 && !/^(?:agent|app|code|lib|project|repo|src|test|tests|workspace)$/i.test(currentDirectory) && new RegExp(`\\b${escapedDirectory}\\b`, "i").test(question);
|
|
29661
29848
|
if (CURRENT_PROJECT_REFERENCE.test(question) || namesCurrentDirectory) {
|
|
29662
29849
|
const root = projectRoot(cwd);
|
|
29663
29850
|
const metadata = await readPackageMetadata(root);
|
|
29664
|
-
if (!metadata.name) metadata.name =
|
|
29851
|
+
if (!metadata.name) metadata.name = basename9(root);
|
|
29665
29852
|
add("project metadata (package.json or directory)", JSON.stringify(metadata));
|
|
29666
29853
|
if (LICENSE_QUESTION.test(question)) {
|
|
29667
29854
|
const license = await readLicenseEvidence(root);
|
|
@@ -30704,8 +30891,8 @@ var init_frontmatter = __esm({
|
|
|
30704
30891
|
});
|
|
30705
30892
|
|
|
30706
30893
|
// src/skills/loader.ts
|
|
30707
|
-
import { readFile as
|
|
30708
|
-
import { join as
|
|
30894
|
+
import { readFile as readFile32, readdir as readdir9, stat as stat12 } from "fs/promises";
|
|
30895
|
+
import { join as join47, extname } from "path";
|
|
30709
30896
|
function normalizeManifest(raw, filePath) {
|
|
30710
30897
|
const name = typeof raw.name === "string" ? raw.name : "";
|
|
30711
30898
|
const description = typeof raw.description === "string" ? raw.description : "";
|
|
@@ -30719,7 +30906,7 @@ function normalizeManifest(raw, filePath) {
|
|
|
30719
30906
|
return { name, description, match, scope, priority, enabled: enabled2 };
|
|
30720
30907
|
}
|
|
30721
30908
|
async function loadSkillFile(filePath) {
|
|
30722
|
-
const raw = await
|
|
30909
|
+
const raw = await readFile32(filePath, "utf-8");
|
|
30723
30910
|
const parsed = parseFrontmatter(raw);
|
|
30724
30911
|
const manifest = normalizeManifest(parsed.data, filePath);
|
|
30725
30912
|
const body = parsed.content.trim();
|
|
@@ -30738,11 +30925,11 @@ async function loadSkillFile(filePath) {
|
|
|
30738
30925
|
}
|
|
30739
30926
|
async function loadSkillsFromDir(dirPath) {
|
|
30740
30927
|
try {
|
|
30741
|
-
const entries = await
|
|
30928
|
+
const entries = await readdir9(dirPath);
|
|
30742
30929
|
const files = [];
|
|
30743
30930
|
for (const entry of entries) {
|
|
30744
|
-
const full =
|
|
30745
|
-
const s = await
|
|
30931
|
+
const full = join47(dirPath, entry);
|
|
30932
|
+
const s = await stat12(full);
|
|
30746
30933
|
if (s.isFile() && extname(entry) === ".md") {
|
|
30747
30934
|
files.push(full);
|
|
30748
30935
|
}
|
|
@@ -30769,12 +30956,12 @@ var init_loader = __esm({
|
|
|
30769
30956
|
});
|
|
30770
30957
|
|
|
30771
30958
|
// src/skills/manager.ts
|
|
30772
|
-
import { mkdir as
|
|
30773
|
-
import { join as
|
|
30959
|
+
import { mkdir as mkdir18, writeFile as writeFile15, unlink as unlink5, readFile as readFile33 } from "fs/promises";
|
|
30960
|
+
import { join as join48 } from "path";
|
|
30774
30961
|
function getSkillDirs(cwd) {
|
|
30775
30962
|
return {
|
|
30776
|
-
projectDir:
|
|
30777
|
-
globalDir:
|
|
30963
|
+
projectDir: join48(cwd, ".kimiflare", "skills"),
|
|
30964
|
+
globalDir: join48(process.env.HOME ?? "", ".config", "kimiflare", "skills")
|
|
30778
30965
|
};
|
|
30779
30966
|
}
|
|
30780
30967
|
async function listAllSkills(cwd) {
|
|
@@ -30788,7 +30975,7 @@ async function listAllSkills(cwd) {
|
|
|
30788
30975
|
async function createSkill(opts2) {
|
|
30789
30976
|
const dirs = getSkillDirs(opts2.cwd);
|
|
30790
30977
|
const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
|
|
30791
|
-
const filepath =
|
|
30978
|
+
const filepath = join48(dir, `${opts2.name}.md`);
|
|
30792
30979
|
const frontmatter = {
|
|
30793
30980
|
name: opts2.name,
|
|
30794
30981
|
enabled: true,
|
|
@@ -30809,7 +30996,7 @@ ${yaml}
|
|
|
30809
30996
|
|
|
30810
30997
|
Add your instructions here.
|
|
30811
30998
|
`;
|
|
30812
|
-
await
|
|
30999
|
+
await mkdir18(dir, { recursive: true });
|
|
30813
31000
|
await writeFile15(filepath, content, "utf8");
|
|
30814
31001
|
return { filepath };
|
|
30815
31002
|
}
|
|
@@ -30817,14 +31004,14 @@ async function deleteSkill(name, cwd) {
|
|
|
30817
31004
|
const all = await listAllSkills(cwd);
|
|
30818
31005
|
const skill = all.project.find((s) => s.name === name) ?? all.global.find((s) => s.name === name);
|
|
30819
31006
|
if (!skill) throw new Error(`skill "${name}" not found`);
|
|
30820
|
-
await
|
|
31007
|
+
await unlink5(skill.filePath);
|
|
30821
31008
|
return { filepath: skill.filePath };
|
|
30822
31009
|
}
|
|
30823
31010
|
async function setSkillEnabled(name, enabled2, cwd) {
|
|
30824
31011
|
const all = await listAllSkills(cwd);
|
|
30825
31012
|
const skill = all.project.find((s) => s.name === name) ?? all.global.find((s) => s.name === name);
|
|
30826
31013
|
if (!skill) throw new Error(`skill "${name}" not found`);
|
|
30827
|
-
const raw = await
|
|
31014
|
+
const raw = await readFile33(skill.filePath, "utf-8");
|
|
30828
31015
|
const parsed = parseFrontmatter(raw);
|
|
30829
31016
|
parsed.data.enabled = enabled2;
|
|
30830
31017
|
const yaml = Object.entries(parsed.data).map(([k, v]) => {
|
|
@@ -31096,15 +31283,15 @@ var tui_report_exports = {};
|
|
|
31096
31283
|
__export(tui_report_exports, {
|
|
31097
31284
|
getCategoryReportText: () => getCategoryReportText
|
|
31098
31285
|
});
|
|
31099
|
-
import { readFile as
|
|
31100
|
-
import { join as
|
|
31286
|
+
import { readFile as readFile34 } from "fs/promises";
|
|
31287
|
+
import { join as join49 } from "path";
|
|
31101
31288
|
import { homedir as homedir27 } from "os";
|
|
31102
31289
|
function usageDir3() {
|
|
31103
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
31104
|
-
return
|
|
31290
|
+
const xdg = process.env.XDG_DATA_HOME || join49(homedir27(), ".local", "share");
|
|
31291
|
+
return join49(xdg, "kimiflare");
|
|
31105
31292
|
}
|
|
31106
31293
|
function usagePath4() {
|
|
31107
|
-
return
|
|
31294
|
+
return join49(usageDir3(), "usage.json");
|
|
31108
31295
|
}
|
|
31109
31296
|
function today3() {
|
|
31110
31297
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -31116,7 +31303,7 @@ function daysAgo2(n) {
|
|
|
31116
31303
|
}
|
|
31117
31304
|
async function loadLog3() {
|
|
31118
31305
|
try {
|
|
31119
|
-
const raw = await
|
|
31306
|
+
const raw = await readFile34(usagePath4(), "utf8");
|
|
31120
31307
|
return JSON.parse(raw);
|
|
31121
31308
|
} catch {
|
|
31122
31309
|
return { version: 1, days: [], sessions: [] };
|
|
@@ -31173,7 +31360,7 @@ var init_tui_report = __esm({
|
|
|
31173
31360
|
});
|
|
31174
31361
|
|
|
31175
31362
|
// src/ui/slash-commands.ts
|
|
31176
|
-
import { join as
|
|
31363
|
+
import { join as join50 } from "path";
|
|
31177
31364
|
import QRCode from "qrcode";
|
|
31178
31365
|
function executeFreshStart(ctx, planText, overrideMode, opts2 = {}) {
|
|
31179
31366
|
const oldSessionId = ctx.sessionIdRef.current;
|
|
@@ -31644,7 +31831,7 @@ auto (default) lets the coordinator assess substantial tasks and delegate indepe
|
|
|
31644
31831
|
const context = noContext ? [] : await buildJevContext(question.prompt, ctx.messagesRef.current, process.cwd());
|
|
31645
31832
|
const receipt = formatJevContextReceipt(context, showContext);
|
|
31646
31833
|
setResult(eventKey, { kind: "info", key: eventKey, text: `Jev is evaluating \xB7 ${receipt}`, pending: true });
|
|
31647
|
-
await new Promise((
|
|
31834
|
+
await new Promise((resolve20) => setTimeout(resolve20, 0));
|
|
31648
31835
|
const answer = await askJev(apiKey, question, { context });
|
|
31649
31836
|
const presentation = presentJevAnswer(question, answer);
|
|
31650
31837
|
setResult(eventKey, {
|
|
@@ -32105,7 +32292,7 @@ ${lines.join("\n")}` }]);
|
|
|
32105
32292
|
void (async () => {
|
|
32106
32293
|
try {
|
|
32107
32294
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
32108
|
-
const file = await loadSession(
|
|
32295
|
+
const file = await loadSession(join50(sessionsDir3(), `${currentId}.json`));
|
|
32109
32296
|
const cps = file.checkpoints ?? [];
|
|
32110
32297
|
if (cps.length === 0) {
|
|
32111
32298
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "no checkpoints in this session" }]);
|
|
@@ -32150,7 +32337,7 @@ ${lines.join("\n")}` }]);
|
|
|
32150
32337
|
try {
|
|
32151
32338
|
ctx.ensureSessionId();
|
|
32152
32339
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
32153
|
-
const filePath =
|
|
32340
|
+
const filePath = join50(sessionsDir3(), `${ctx.sessionIdRef.current}.json`);
|
|
32154
32341
|
await addCheckpoint(filePath, cp);
|
|
32155
32342
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: `checkpoint saved: "${label}"` }]);
|
|
32156
32343
|
} catch (e) {
|
|
@@ -32875,9 +33062,9 @@ async function triageIncoming(text, context, opts2 = {}) {
|
|
|
32875
33062
|
"steer = it adjusts or adds to the current task and should be folded in at the next step;",
|
|
32876
33063
|
"queue = it is separate work that should run after the current task;",
|
|
32877
33064
|
"aside = it is a question about progress that can be answered without changing the work.",
|
|
32878
|
-
`Current task: ${
|
|
32879
|
-
context.activity ? `Doing now: ${
|
|
32880
|
-
`New message: ${
|
|
33065
|
+
`Current task: ${clip2(context.currentTask)}`,
|
|
33066
|
+
context.activity ? `Doing now: ${clip2(context.activity, 200)}` : "",
|
|
33067
|
+
`New message: ${clip2(text)}`
|
|
32881
33068
|
].filter(Boolean).join("\n"),
|
|
32882
33069
|
options: [...OPTIONS2]
|
|
32883
33070
|
};
|
|
@@ -32905,7 +33092,7 @@ async function triageIncoming(text, context, opts2 = {}) {
|
|
|
32905
33092
|
function unsure(reason, confidence) {
|
|
32906
33093
|
return { kind: "queue", source: "default", reason, ...confidence === void 0 ? {} : { confidence } };
|
|
32907
33094
|
}
|
|
32908
|
-
function
|
|
33095
|
+
function clip2(text, max = MAX_CHARS) {
|
|
32909
33096
|
const single = text.replace(/\s+/g, " ").trim();
|
|
32910
33097
|
return single.length > max ? `${single.slice(0, max - 1)}\u2026` : single;
|
|
32911
33098
|
}
|
|
@@ -32952,7 +33139,7 @@ var init_inbox_triage = __esm({
|
|
|
32952
33139
|
|
|
32953
33140
|
// src/agent/aside.ts
|
|
32954
33141
|
async function answerAside(question, context, opts2) {
|
|
32955
|
-
const
|
|
33142
|
+
const clip3 = (text2, max) => (text2 ?? "").replace(/\s+/g, " ").trim().slice(0, max);
|
|
32956
33143
|
const messages = [
|
|
32957
33144
|
{
|
|
32958
33145
|
role: "system",
|
|
@@ -32961,11 +33148,11 @@ async function answerAside(question, context, opts2) {
|
|
|
32961
33148
|
{
|
|
32962
33149
|
role: "user",
|
|
32963
33150
|
content: [
|
|
32964
|
-
`Task: ${
|
|
32965
|
-
context.progress ? `Progress: ${
|
|
32966
|
-
context.activity ? `Running now: ${
|
|
32967
|
-
context.recentAssistantText ? `Latest agent message: ${
|
|
32968
|
-
`Question: ${
|
|
33151
|
+
`Task: ${clip3(context.currentTask, 600)}`,
|
|
33152
|
+
context.progress ? `Progress: ${clip3(context.progress, 600)}` : "",
|
|
33153
|
+
context.activity ? `Running now: ${clip3(context.activity, 300)}` : "",
|
|
33154
|
+
context.recentAssistantText ? `Latest agent message: ${clip3(context.recentAssistantText, 800)}` : "",
|
|
33155
|
+
`Question: ${clip3(question, 400)}`
|
|
32969
33156
|
].filter(Boolean).join("\n")
|
|
32970
33157
|
}
|
|
32971
33158
|
];
|
|
@@ -33206,9 +33393,9 @@ async function startLoopbackListener(opts2 = {}) {
|
|
|
33206
33393
|
rejectCode(e);
|
|
33207
33394
|
finish();
|
|
33208
33395
|
}
|
|
33209
|
-
await new Promise((
|
|
33396
|
+
await new Promise((resolve20, reject) => {
|
|
33210
33397
|
server.once("error", reject);
|
|
33211
|
-
server.listen(0, "127.0.0.1", () =>
|
|
33398
|
+
server.listen(0, "127.0.0.1", () => resolve20());
|
|
33212
33399
|
});
|
|
33213
33400
|
const address = server.address();
|
|
33214
33401
|
const port = typeof address === "object" && address ? address.port : 0;
|
|
@@ -33634,15 +33821,15 @@ var init_frontmatter2 = __esm({
|
|
|
33634
33821
|
});
|
|
33635
33822
|
|
|
33636
33823
|
// src/commands/loader.ts
|
|
33637
|
-
import { open, realpath as
|
|
33824
|
+
import { open, realpath as realpath8 } from "fs/promises";
|
|
33638
33825
|
import { homedir as homedir28 } from "os";
|
|
33639
|
-
import { join as
|
|
33826
|
+
import { join as join51, relative as relative11, sep as sep7 } from "path";
|
|
33640
33827
|
function projectCommandsDir(cwd = process.cwd()) {
|
|
33641
|
-
return
|
|
33828
|
+
return join51(cwd, ".kimiflare", "commands");
|
|
33642
33829
|
}
|
|
33643
33830
|
function globalCommandsDir() {
|
|
33644
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
33645
|
-
return
|
|
33831
|
+
const xdg = process.env.XDG_CONFIG_HOME || join51(homedir28(), ".config");
|
|
33832
|
+
return join51(xdg, "kimiflare", "commands");
|
|
33646
33833
|
}
|
|
33647
33834
|
async function loadCustomCommands(cwd = process.cwd()) {
|
|
33648
33835
|
const warnings = [];
|
|
@@ -33681,7 +33868,7 @@ async function loadCustomCommands(cwd = process.cwd()) {
|
|
|
33681
33868
|
async function resolveSafeDir(dir, source, cwd, warnings) {
|
|
33682
33869
|
let realDir;
|
|
33683
33870
|
try {
|
|
33684
|
-
realDir = await
|
|
33871
|
+
realDir = await realpath8(dir);
|
|
33685
33872
|
} catch (err) {
|
|
33686
33873
|
const code = err.code;
|
|
33687
33874
|
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
@@ -33692,11 +33879,11 @@ async function resolveSafeDir(dir, source, cwd, warnings) {
|
|
|
33692
33879
|
if (source === "project") {
|
|
33693
33880
|
let realCwd;
|
|
33694
33881
|
try {
|
|
33695
|
-
realCwd = await
|
|
33882
|
+
realCwd = await realpath8(cwd);
|
|
33696
33883
|
} catch {
|
|
33697
33884
|
return null;
|
|
33698
33885
|
}
|
|
33699
|
-
const rel =
|
|
33886
|
+
const rel = relative11(realCwd, realDir);
|
|
33700
33887
|
if (rel !== "" && isPathOutside(rel)) {
|
|
33701
33888
|
warnings.push(`commands dir ${dir} escapes workspace via symlink \u2014 skipped`);
|
|
33702
33889
|
return null;
|
|
@@ -33771,10 +33958,10 @@ async function loadOne(file, rootDir, source, warnings) {
|
|
|
33771
33958
|
return cmd;
|
|
33772
33959
|
}
|
|
33773
33960
|
function filenameToCommandName(file, rootDir) {
|
|
33774
|
-
const rel =
|
|
33961
|
+
const rel = relative11(rootDir, file);
|
|
33775
33962
|
if (!rel || isPathOutside(rel)) return null;
|
|
33776
33963
|
const noExt = rel.replace(/\.md$/i, "");
|
|
33777
|
-
const parts = noExt.split(
|
|
33964
|
+
const parts = noExt.split(sep7).filter((p) => p.length > 0);
|
|
33778
33965
|
if (parts.length === 0) return null;
|
|
33779
33966
|
if (parts.some((p) => !/^[\w.-]+$/.test(p))) return null;
|
|
33780
33967
|
return parts.join("/");
|
|
@@ -33794,8 +33981,8 @@ var init_loader2 = __esm({
|
|
|
33794
33981
|
|
|
33795
33982
|
// src/commands/renderer.ts
|
|
33796
33983
|
import { exec } from "child_process";
|
|
33797
|
-
import { open as open2, realpath as
|
|
33798
|
-
import { isAbsolute as
|
|
33984
|
+
import { open as open2, realpath as realpath9 } from "fs/promises";
|
|
33985
|
+
import { isAbsolute as isAbsolute8, relative as relative12, resolve as resolvePathJoin, basename as pathBasename } from "path";
|
|
33799
33986
|
import { promisify as promisify9 } from "util";
|
|
33800
33987
|
function tokenizeArgs(s) {
|
|
33801
33988
|
return [...s.matchAll(ARG_TOKEN_RE)].map((match) => {
|
|
@@ -33886,7 +34073,7 @@ async function replaceFiles(prompt, warnings, cmd, cwd, maxFileBytes) {
|
|
|
33886
34073
|
return "" + trailing;
|
|
33887
34074
|
});
|
|
33888
34075
|
}
|
|
33889
|
-
const realCwd = await
|
|
34076
|
+
const realCwd = await realpath9(cwd).catch(() => cwd);
|
|
33890
34077
|
const replacements = await Promise.all(
|
|
33891
34078
|
matches.map(async (match) => {
|
|
33892
34079
|
const rawPath = match[1] ?? "";
|
|
@@ -33895,23 +34082,23 @@ async function replaceFiles(prompt, warnings, cmd, cwd, maxFileBytes) {
|
|
|
33895
34082
|
warnings.push(`file inclusion blocked: @${rawPath} \u2014 secret file pattern`);
|
|
33896
34083
|
return "";
|
|
33897
34084
|
}
|
|
33898
|
-
if (
|
|
34085
|
+
if (isAbsolute8(rawPath) || rawPath.startsWith("~")) {
|
|
33899
34086
|
warnings.push(`file inclusion skipped: @${rawPath} \u2014 outside workspace`);
|
|
33900
34087
|
return "";
|
|
33901
34088
|
}
|
|
33902
34089
|
const resolved = resolvePathJoin(cwd, rawPath);
|
|
33903
|
-
if (isPathOutside(
|
|
34090
|
+
if (isPathOutside(relative12(cwd, resolved))) {
|
|
33904
34091
|
warnings.push(`file inclusion skipped: @${rawPath} \u2014 outside workspace`);
|
|
33905
34092
|
return "";
|
|
33906
34093
|
}
|
|
33907
34094
|
let real;
|
|
33908
34095
|
try {
|
|
33909
|
-
real = await
|
|
34096
|
+
real = await realpath9(resolved);
|
|
33910
34097
|
} catch (error) {
|
|
33911
34098
|
warnings.push(`file inclusion failed: @${rawPath} \u2014 ${message(error)}`);
|
|
33912
34099
|
return "";
|
|
33913
34100
|
}
|
|
33914
|
-
if (isPathOutside(
|
|
34101
|
+
if (isPathOutside(relative12(realCwd, real))) {
|
|
33915
34102
|
warnings.push(`file inclusion skipped: @${rawPath} \u2014 symlink escapes workspace`);
|
|
33916
34103
|
return "";
|
|
33917
34104
|
}
|
|
@@ -34024,11 +34211,11 @@ var init_wcag = __esm({
|
|
|
34024
34211
|
});
|
|
34025
34212
|
|
|
34026
34213
|
// src/ui/theme-loader.ts
|
|
34027
|
-
import { readFile as
|
|
34028
|
-
import { join as
|
|
34214
|
+
import { readFile as readFile35, readdir as readdir10 } from "fs/promises";
|
|
34215
|
+
import { join as join52 } from "path";
|
|
34029
34216
|
import { homedir as homedir29 } from "os";
|
|
34030
34217
|
function projectThemesDir(cwd = process.cwd()) {
|
|
34031
|
-
return
|
|
34218
|
+
return join52(cwd, ".kimiflare", "themes");
|
|
34032
34219
|
}
|
|
34033
34220
|
function isHexColor(c) {
|
|
34034
34221
|
return /^#[0-9a-fA-F]{6}$/.test(c);
|
|
@@ -34112,15 +34299,15 @@ async function loadThemesFromDir(dir, source) {
|
|
|
34112
34299
|
const errors = [];
|
|
34113
34300
|
let files;
|
|
34114
34301
|
try {
|
|
34115
|
-
files = await
|
|
34302
|
+
files = await readdir10(dir);
|
|
34116
34303
|
} catch {
|
|
34117
34304
|
return { themes, errors };
|
|
34118
34305
|
}
|
|
34119
34306
|
for (const file of files.filter((f) => f.endsWith(".json"))) {
|
|
34120
|
-
const path =
|
|
34307
|
+
const path = join52(dir, file);
|
|
34121
34308
|
let raw;
|
|
34122
34309
|
try {
|
|
34123
|
-
raw = await
|
|
34310
|
+
raw = await readFile35(path, "utf-8");
|
|
34124
34311
|
} catch (e) {
|
|
34125
34312
|
errors.push(`${path}: ${e instanceof Error ? e.message : String(e)}`);
|
|
34126
34313
|
continue;
|
|
@@ -34266,8 +34453,8 @@ var init_theme_loader = __esm({
|
|
|
34266
34453
|
"use strict";
|
|
34267
34454
|
init_wcag();
|
|
34268
34455
|
init_theme();
|
|
34269
|
-
USER_THEMES_DIR =
|
|
34270
|
-
process.env.XDG_CONFIG_HOME ||
|
|
34456
|
+
USER_THEMES_DIR = join52(
|
|
34457
|
+
process.env.XDG_CONFIG_HOME || join52(homedir29(), ".config"),
|
|
34271
34458
|
"kimiflare",
|
|
34272
34459
|
"themes"
|
|
34273
34460
|
);
|
|
@@ -36798,9 +36985,9 @@ var init_resume_progress = __esm({
|
|
|
36798
36985
|
});
|
|
36799
36986
|
|
|
36800
36987
|
// src/agent/supervisor.ts
|
|
36801
|
-
import { readdir as
|
|
36988
|
+
import { readdir as readdir11, readFile as readFile36, stat as stat13 } from "fs/promises";
|
|
36802
36989
|
import { createHash as createHash7 } from "crypto";
|
|
36803
|
-
import { resolve as
|
|
36990
|
+
import { resolve as resolve18, join as join53 } from "path";
|
|
36804
36991
|
var TurnSupervisor;
|
|
36805
36992
|
var init_supervisor = __esm({
|
|
36806
36993
|
"src/agent/supervisor.ts"() {
|
|
@@ -37190,12 +37377,12 @@ var init_input_handlers = __esm({
|
|
|
37190
37377
|
|
|
37191
37378
|
// src/init/context-generator.ts
|
|
37192
37379
|
import { existsSync as existsSync9, statSync as statSync6 } from "fs";
|
|
37193
|
-
import { join as
|
|
37380
|
+
import { join as join54 } from "path";
|
|
37194
37381
|
function detectFlavor(cwd) {
|
|
37195
37382
|
for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
|
|
37196
37383
|
if (flavor === "generic") continue;
|
|
37197
37384
|
for (const sig of signatures) {
|
|
37198
|
-
const path =
|
|
37385
|
+
const path = join54(cwd, sig);
|
|
37199
37386
|
if (sig.includes("*")) {
|
|
37200
37387
|
try {
|
|
37201
37388
|
const parts = sig.split("*");
|
|
@@ -37216,14 +37403,14 @@ function detectFlavor(cwd) {
|
|
|
37216
37403
|
}
|
|
37217
37404
|
function findFile(cwd, candidates) {
|
|
37218
37405
|
for (const c of candidates) {
|
|
37219
|
-
if (existsSync9(
|
|
37406
|
+
if (existsSync9(join54(cwd, c))) return c;
|
|
37220
37407
|
}
|
|
37221
37408
|
return null;
|
|
37222
37409
|
}
|
|
37223
37410
|
function findSourceRoots(cwd) {
|
|
37224
37411
|
const roots = [];
|
|
37225
37412
|
for (const r of SOURCE_ROOT_CANDIDATES) {
|
|
37226
|
-
const p =
|
|
37413
|
+
const p = join54(cwd, r);
|
|
37227
37414
|
try {
|
|
37228
37415
|
const s = statSync6(p);
|
|
37229
37416
|
if (s.isDirectory()) roots.push(r);
|
|
@@ -37234,9 +37421,9 @@ function findSourceRoots(cwd) {
|
|
|
37234
37421
|
}
|
|
37235
37422
|
function findCiConfig(cwd) {
|
|
37236
37423
|
for (const c of CI_PATHS) {
|
|
37237
|
-
if (existsSync9(
|
|
37424
|
+
if (existsSync9(join54(cwd, c))) {
|
|
37238
37425
|
try {
|
|
37239
|
-
const s = statSync6(
|
|
37426
|
+
const s = statSync6(join54(cwd, c));
|
|
37240
37427
|
return s.isDirectory() ? c : c;
|
|
37241
37428
|
} catch {
|
|
37242
37429
|
}
|
|
@@ -37373,7 +37560,7 @@ function analyzeProject(cwd) {
|
|
|
37373
37560
|
ciConfig: findCiConfig(cwd),
|
|
37374
37561
|
readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
|
|
37375
37562
|
sourceRoots: findSourceRoots(cwd),
|
|
37376
|
-
hasGit: existsSync9(
|
|
37563
|
+
hasGit: existsSync9(join54(cwd, ".git"))
|
|
37377
37564
|
};
|
|
37378
37565
|
}
|
|
37379
37566
|
function bashDiscoveryCommands(profile) {
|
|
@@ -37536,19 +37723,33 @@ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
|
|
|
37536
37723
|
- State management approach
|
|
37537
37724
|
`.trim();
|
|
37538
37725
|
}
|
|
37726
|
+
function buildInitTasks(targetFilename) {
|
|
37727
|
+
return [
|
|
37728
|
+
{ id: "identity", title: "Inspect project identity and configuration", status: "in_progress" },
|
|
37729
|
+
{ id: "structure", title: "Discover source structure, tests, and conventions", status: "pending" },
|
|
37730
|
+
{ id: "workflow", title: "Identify build and development workflows", status: "pending" },
|
|
37731
|
+
{ id: "architecture", title: "Map architecture and project patterns", status: "pending" },
|
|
37732
|
+
{ id: "write", title: "Write or refresh " + targetFilename, status: "pending" },
|
|
37733
|
+
{ id: "verify", title: "Re-read and verify " + targetFilename, status: "pending" }
|
|
37734
|
+
];
|
|
37735
|
+
}
|
|
37539
37736
|
function buildInitPrompt(cwd) {
|
|
37540
37737
|
const existingName = ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
|
|
37541
|
-
(n) => existsSync9(
|
|
37738
|
+
(n) => existsSync9(join54(cwd, n))
|
|
37542
37739
|
);
|
|
37543
37740
|
const isRefresh = existingName !== void 0;
|
|
37544
37741
|
const targetFilename = existingName ?? "AGENTS.md";
|
|
37545
37742
|
const profile = analyzeProject(cwd);
|
|
37546
37743
|
const checklist = discoveryChecklist(profile);
|
|
37547
37744
|
const sections = sectionTemplate();
|
|
37745
|
+
const tasks = buildInitTasks(targetFilename);
|
|
37548
37746
|
const promptParts = [
|
|
37549
37747
|
isRefresh ? `Regenerate \`${targetFilename}\` at the repository root to refresh project context. The file already exists \u2014 read it first and preserve anything still accurate, updating only what has changed or is missing.` : `Generate a \`${targetFilename}\` at the repository root so future agents have comprehensive project context.`,
|
|
37550
37748
|
"",
|
|
37551
37749
|
"This is a **structured investigation**. Follow the checklist below systematically. Use the `glob`, `read`, `grep`, and `bash` tools to gather information. Do not skip steps.",
|
|
37750
|
+
`Visible task list (already initialized in the UI; keep these IDs and titles):
|
|
37751
|
+
${tasks.map((task) => "- " + task.id + ": " + task.status + ": " + task.title).join("\n")}`,
|
|
37752
|
+
"Keep the visible task checklist synchronized with your progress using `tasks_set`: update the current phase and mark the next phase active before moving on. Map the detailed checklist below onto these high-level tasks.",
|
|
37552
37753
|
"",
|
|
37553
37754
|
`**Detected project profile:** ${profile.primaryLanguage} (${profile.flavor})`,
|
|
37554
37755
|
profile.packageFile ? `- Package file: ${profile.packageFile}` : null,
|
|
@@ -37570,10 +37771,10 @@ function buildInitPrompt(cwd) {
|
|
|
37570
37771
|
"",
|
|
37571
37772
|
isRefresh ? `After writing the file, re-read \`${targetFilename}\` and verify it is complete and accurate.` : "After writing the file, re-read it and verify all sections are present and accurate.",
|
|
37572
37773
|
"",
|
|
37573
|
-
"
|
|
37774
|
+
"The visible task checklist is already initialized. Mark investigation phases complete as you finish them, and complete the write and verification tasks only after re-reading the generated file."
|
|
37574
37775
|
];
|
|
37575
37776
|
const prompt = promptParts.filter((p) => p !== null).join("\n");
|
|
37576
|
-
return { prompt, targetFilename, isRefresh };
|
|
37777
|
+
return { prompt, targetFilename, isRefresh, tasks };
|
|
37577
37778
|
}
|
|
37578
37779
|
var FLAVOR_SIGNATURES, SOURCE_ROOT_CANDIDATES, CI_PATHS;
|
|
37579
37780
|
var init_context_generator = __esm({
|
|
@@ -37622,7 +37823,7 @@ var init_context_generator = __esm({
|
|
|
37622
37823
|
|
|
37623
37824
|
// src/init/run-init.ts
|
|
37624
37825
|
import { existsSync as existsSync10 } from "fs";
|
|
37625
|
-
import { join as
|
|
37826
|
+
import { join as join55 } from "path";
|
|
37626
37827
|
async function runInit(deps) {
|
|
37627
37828
|
const {
|
|
37628
37829
|
cfg,
|
|
@@ -37636,6 +37837,7 @@ async function runInit(deps) {
|
|
|
37636
37837
|
setUsage,
|
|
37637
37838
|
setSessionUsage,
|
|
37638
37839
|
setKimiMdStale,
|
|
37840
|
+
onTasks,
|
|
37639
37841
|
beginTurn,
|
|
37640
37842
|
endTurn,
|
|
37641
37843
|
ensureSessionId,
|
|
@@ -37670,7 +37872,8 @@ async function runInit(deps) {
|
|
|
37670
37872
|
return;
|
|
37671
37873
|
}
|
|
37672
37874
|
const cwd = process.cwd();
|
|
37673
|
-
const { prompt, targetFilename, isRefresh } = buildInitPrompt(cwd);
|
|
37875
|
+
const { prompt, targetFilename, isRefresh, tasks } = buildInitPrompt(cwd);
|
|
37876
|
+
onTasks(tasks);
|
|
37674
37877
|
setEvents((e) => [
|
|
37675
37878
|
...e,
|
|
37676
37879
|
{ kind: "user", key: mkKey2(), text: isRefresh ? `/init (refreshing ${targetFilename})` : "/init" }
|
|
@@ -37715,7 +37918,7 @@ async function runInit(deps) {
|
|
|
37715
37918
|
lspManagerRef.current.notifyChange(path, content);
|
|
37716
37919
|
} else {
|
|
37717
37920
|
void import("fs/promises").then(
|
|
37718
|
-
({ readFile:
|
|
37921
|
+
({ readFile: readFile38 }) => readFile38(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
|
|
37719
37922
|
})
|
|
37720
37923
|
);
|
|
37721
37924
|
}
|
|
@@ -37800,6 +38003,7 @@ async function runInit(deps) {
|
|
|
37800
38003
|
void getCostReport(sid).then((report) => setSessionUsage(report.session));
|
|
37801
38004
|
},
|
|
37802
38005
|
onResponseMeta: updateResponseMeta,
|
|
38006
|
+
onTasks,
|
|
37803
38007
|
askPermission: (req) => askForPermission(req, { promptOnBlockedBash: true }),
|
|
37804
38008
|
onGuardrail: (ev) => {
|
|
37805
38009
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: ev.message }]);
|
|
@@ -37820,7 +38024,7 @@ async function runInit(deps) {
|
|
|
37820
38024
|
}
|
|
37821
38025
|
}
|
|
37822
38026
|
});
|
|
37823
|
-
if (existsSync10(
|
|
38027
|
+
if (existsSync10(join55(cwd, targetFilename))) {
|
|
37824
38028
|
if (cacheStableRef.current) {
|
|
37825
38029
|
messagesRef.current[1] = {
|
|
37826
38030
|
role: "system",
|
|
@@ -37885,6 +38089,7 @@ async function runInit(deps) {
|
|
|
37885
38089
|
} finally {
|
|
37886
38090
|
logger.info("runInit:finally");
|
|
37887
38091
|
setCodeMode(false);
|
|
38092
|
+
onTasks([]);
|
|
37888
38093
|
const asstId = activeAsstIdRef.current;
|
|
37889
38094
|
if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
|
|
37890
38095
|
endTurn();
|
|
@@ -37912,11 +38117,11 @@ var init_run_init = __esm({
|
|
|
37912
38117
|
});
|
|
37913
38118
|
|
|
37914
38119
|
// src/skills/discovery.ts
|
|
37915
|
-
import { readdir as
|
|
37916
|
-
import { join as
|
|
38120
|
+
import { readdir as readdir12, stat as stat14, readFile as readFile37 } from "fs/promises";
|
|
38121
|
+
import { join as join56, extname as extname2 } from "path";
|
|
37917
38122
|
async function dirExists(path) {
|
|
37918
38123
|
try {
|
|
37919
|
-
const s = await
|
|
38124
|
+
const s = await stat14(path);
|
|
37920
38125
|
return s.isDirectory();
|
|
37921
38126
|
} catch {
|
|
37922
38127
|
return false;
|
|
@@ -37924,7 +38129,7 @@ async function dirExists(path) {
|
|
|
37924
38129
|
}
|
|
37925
38130
|
async function fileExists(path) {
|
|
37926
38131
|
try {
|
|
37927
|
-
const s = await
|
|
38132
|
+
const s = await stat14(path);
|
|
37928
38133
|
return s.isFile();
|
|
37929
38134
|
} catch {
|
|
37930
38135
|
return false;
|
|
@@ -37932,25 +38137,25 @@ async function fileExists(path) {
|
|
|
37932
38137
|
}
|
|
37933
38138
|
async function scanSkillDir(dirPath, source) {
|
|
37934
38139
|
if (!await dirExists(dirPath)) return [];
|
|
37935
|
-
const entries = await
|
|
38140
|
+
const entries = await readdir12(dirPath, { withFileTypes: true });
|
|
37936
38141
|
const files = [];
|
|
37937
38142
|
for (const entry of entries) {
|
|
37938
38143
|
if (!entry.isFile()) continue;
|
|
37939
38144
|
if (!SKILL_EXTENSIONS.has(extname2(entry.name))) continue;
|
|
37940
|
-
files.push({ filePath:
|
|
38145
|
+
files.push({ filePath: join56(dirPath, entry.name), source });
|
|
37941
38146
|
}
|
|
37942
38147
|
return files;
|
|
37943
38148
|
}
|
|
37944
38149
|
async function discoverSkills(cwd) {
|
|
37945
|
-
const agentsSkills = await scanSkillDir(
|
|
37946
|
-
const agentsMd = await fileExists(
|
|
37947
|
-
const githubSkills = await scanSkillDir(
|
|
37948
|
-
const kimiflareSkills = await scanSkillDir(
|
|
38150
|
+
const agentsSkills = await scanSkillDir(join56(cwd, ".agents", "skills"), "agents");
|
|
38151
|
+
const agentsMd = await fileExists(join56(cwd, "AGENTS.md")) ? [{ filePath: join56(cwd, "AGENTS.md"), source: "agents-md" }] : [];
|
|
38152
|
+
const githubSkills = await scanSkillDir(join56(cwd, ".github", "skills"), "github");
|
|
38153
|
+
const kimiflareSkills = await scanSkillDir(join56(cwd, ".kimiflare", "skills"), "kimiflare");
|
|
37949
38154
|
const ordered = [...agentsSkills, ...agentsMd, ...githubSkills, ...kimiflareSkills];
|
|
37950
38155
|
return ordered;
|
|
37951
38156
|
}
|
|
37952
38157
|
async function readSkillFile(filePath) {
|
|
37953
|
-
const bytes = await
|
|
38158
|
+
const bytes = await readFile37(filePath);
|
|
37954
38159
|
return { bytes, text: bytes.toString("utf-8") };
|
|
37955
38160
|
}
|
|
37956
38161
|
var SKILL_EXTENSIONS;
|
|
@@ -38156,7 +38361,7 @@ var init_skills = __esm({
|
|
|
38156
38361
|
|
|
38157
38362
|
// src/ui/run-startup-tasks.ts
|
|
38158
38363
|
import { existsSync as existsSync11 } from "fs";
|
|
38159
|
-
import { join as
|
|
38364
|
+
import { join as join57 } from "path";
|
|
38160
38365
|
function runStartupTasks(deps) {
|
|
38161
38366
|
const {
|
|
38162
38367
|
cfg,
|
|
@@ -38179,7 +38384,7 @@ function runStartupTasks(deps) {
|
|
|
38179
38384
|
}
|
|
38180
38385
|
});
|
|
38181
38386
|
if (cfg.memoryEnabled) {
|
|
38182
|
-
const dbPath = cfg.memoryDbPath ??
|
|
38387
|
+
const dbPath = cfg.memoryDbPath ?? join57(process.cwd(), ".kimiflare", "memory.db");
|
|
38183
38388
|
const manager = new MemoryManager({
|
|
38184
38389
|
dbPath,
|
|
38185
38390
|
...auth,
|
|
@@ -38211,7 +38416,7 @@ function runStartupTasks(deps) {
|
|
|
38211
38416
|
});
|
|
38212
38417
|
const cwd = process.cwd();
|
|
38213
38418
|
sessionStartRecallRef.current = manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
|
|
38214
|
-
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync11(
|
|
38419
|
+
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync11(join57(cwd, name)))) {
|
|
38215
38420
|
const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
|
|
38216
38421
|
const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
|
|
38217
38422
|
if (driftCount >= 5) {
|
|
@@ -38222,7 +38427,7 @@ function runStartupTasks(deps) {
|
|
|
38222
38427
|
memoryManagerRef.current?.close();
|
|
38223
38428
|
memoryManagerRef.current = null;
|
|
38224
38429
|
}
|
|
38225
|
-
const skillDbPath = cfg.memoryDbPath ??
|
|
38430
|
+
const skillDbPath = cfg.memoryDbPath ?? join57(process.cwd(), ".kimiflare", "memory.db");
|
|
38226
38431
|
const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
|
|
38227
38432
|
initSkillsSchema(skillDb);
|
|
38228
38433
|
void indexSkills({
|
|
@@ -38579,8 +38784,8 @@ var init_run_compact = __esm({
|
|
|
38579
38784
|
});
|
|
38580
38785
|
|
|
38581
38786
|
// src/commands/save.ts
|
|
38582
|
-
import { mkdir as
|
|
38583
|
-
import { dirname as
|
|
38787
|
+
import { mkdir as mkdir19, writeFile as writeFile16, unlink as unlink6 } from "fs/promises";
|
|
38788
|
+
import { dirname as dirname22 } from "path";
|
|
38584
38789
|
async function saveCustomCommand(opts2) {
|
|
38585
38790
|
const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
|
|
38586
38791
|
const filepath = `${dir}/${opts2.name}.md`;
|
|
@@ -38591,12 +38796,12 @@ async function saveCustomCommand(opts2) {
|
|
|
38591
38796
|
if (opts2.effort) data.effort = opts2.effort;
|
|
38592
38797
|
const frontmatter = serializeFrontmatter(data);
|
|
38593
38798
|
const content = frontmatter + opts2.template;
|
|
38594
|
-
await
|
|
38799
|
+
await mkdir19(dirname22(filepath), { recursive: true });
|
|
38595
38800
|
await writeFile16(filepath, content, "utf8");
|
|
38596
38801
|
return { filepath };
|
|
38597
38802
|
}
|
|
38598
38803
|
async function deleteCustomCommand(cmd) {
|
|
38599
|
-
await
|
|
38804
|
+
await unlink6(cmd.filepath);
|
|
38600
38805
|
}
|
|
38601
38806
|
var init_save = __esm({
|
|
38602
38807
|
"src/commands/save.ts"() {
|
|
@@ -38715,7 +38920,7 @@ __export(app_exports, {
|
|
|
38715
38920
|
import React25, { useState as useState27, useRef as useRef9, useEffect as useEffect11, useCallback as useCallback8, useMemo as useMemo6 } from "react";
|
|
38716
38921
|
import { Box as Box40, Text as Text41, useApp, useInput as useInput19, useWindowSize as useWindowSize2, render } from "ink";
|
|
38717
38922
|
import { existsSync as existsSync12 } from "fs";
|
|
38718
|
-
import { join as
|
|
38923
|
+
import { join as join58, resolve as resolve19 } from "path";
|
|
38719
38924
|
import { homedir as homedir30 } from "os";
|
|
38720
38925
|
import { jsx as jsx42, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
38721
38926
|
function App({
|
|
@@ -38950,6 +39155,21 @@ ${wcagWarnings.join("\n")}` }
|
|
|
38950
39155
|
const effortRef = useRef9(effort);
|
|
38951
39156
|
const usageRef = useRef9(null);
|
|
38952
39157
|
const responseMetaRef = useRef9(null);
|
|
39158
|
+
const updateTaskTracking = useCallback8((nextTasks) => {
|
|
39159
|
+
const previousTasks = tasksRef.current;
|
|
39160
|
+
const prevEmpty = previousTasks.length === 0;
|
|
39161
|
+
const prevAllDone = previousTasks.length > 0 && previousTasks.every((task) => task.status === "completed");
|
|
39162
|
+
tasksRef.current = nextTasks;
|
|
39163
|
+
setTasks(nextTasks);
|
|
39164
|
+
if ((prevEmpty || prevAllDone) && nextTasks.length > 0) {
|
|
39165
|
+
setTasksStartedAt(Date.now());
|
|
39166
|
+
setTasksStartTokens(usageRef.current?.prompt_tokens ?? 0);
|
|
39167
|
+
}
|
|
39168
|
+
if (nextTasks.length === 0) {
|
|
39169
|
+
setTasksStartedAt(null);
|
|
39170
|
+
setTasksStartTokens(0);
|
|
39171
|
+
}
|
|
39172
|
+
}, [tasksRef, setTasks, setTasksStartedAt, setTasksStartTokens]);
|
|
38953
39173
|
const lastApiErrorRef = useRef9(null);
|
|
38954
39174
|
const updateCheckedRef = useRef9(false);
|
|
38955
39175
|
const sessionStateRef = useRef9(emptySessionState());
|
|
@@ -39043,8 +39263,8 @@ ${wcagWarnings.join("\n")}` }
|
|
|
39043
39263
|
const exactDirectory = query === "~" || query === "." || query === ".." || query.endsWith("/..");
|
|
39044
39264
|
const prefix = exactDirectory ? `${query.replace(/\/$/, "")}/` : slash >= 0 ? query.slice(0, slash + 1) : "";
|
|
39045
39265
|
const directory = exactDirectory ? query : slash >= 0 ? query.slice(0, slash + 1) : query;
|
|
39046
|
-
const expanded = directory.startsWith("~") ?
|
|
39047
|
-
const target =
|
|
39266
|
+
const expanded = directory.startsWith("~") ? join58(homedir30(), directory.slice(1)) : directory;
|
|
39267
|
+
const target = resolve19(cwd, expanded || ".");
|
|
39048
39268
|
const entries2 = await glob("*", {
|
|
39049
39269
|
cwd: target,
|
|
39050
39270
|
dot: false,
|
|
@@ -39543,6 +39763,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
39543
39763
|
setUsage,
|
|
39544
39764
|
setSessionUsage,
|
|
39545
39765
|
setKimiMdStale,
|
|
39766
|
+
onTasks: updateTaskTracking,
|
|
39546
39767
|
beginTurn,
|
|
39547
39768
|
endTurn,
|
|
39548
39769
|
ensureSessionId,
|
|
@@ -39572,7 +39793,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
39572
39793
|
lastApiErrorRef,
|
|
39573
39794
|
supervisorRef
|
|
39574
39795
|
});
|
|
39575
|
-
}, [cfg, busy, updateAssistant, updateTool, updateResponseMeta]);
|
|
39796
|
+
}, [cfg, busy, updateAssistant, updateTool, updateResponseMeta, updateTaskTracking]);
|
|
39576
39797
|
const handleThemePick = useCallback8(
|
|
39577
39798
|
(picked) => {
|
|
39578
39799
|
setShowThemePicker(false);
|
|
@@ -40026,7 +40247,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40026
40247
|
}
|
|
40027
40248
|
}
|
|
40028
40249
|
turnCounterRef.current += 1;
|
|
40029
|
-
if (turnCounterRef.current % 15 === 0 && ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync12(
|
|
40250
|
+
if (turnCounterRef.current % 15 === 0 && ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync12(join58(process.cwd(), name))) && !kimiMdStale) {
|
|
40030
40251
|
setEvents((e) => [
|
|
40031
40252
|
...e,
|
|
40032
40253
|
{ kind: "info", key: mkKey(), text: "Tip: Rerunning /init occasionally helps autopilot (formerly kimiflare) stay accurate as your project evolves." }
|
|
@@ -40050,7 +40271,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40050
40271
|
};
|
|
40051
40272
|
ensureSessionId();
|
|
40052
40273
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
40053
|
-
const filePath =
|
|
40274
|
+
const filePath = join58(sessionsDir3(), `${sessionIdRef.current}.json`);
|
|
40054
40275
|
await addCheckpoint(filePath, cp);
|
|
40055
40276
|
}
|
|
40056
40277
|
const summary = await generateContinuationSummary({
|
|
@@ -40201,24 +40422,16 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40201
40422
|
void getCostReport(sid).then((report) => setSessionUsage(report.session));
|
|
40202
40423
|
},
|
|
40203
40424
|
onResponseMeta: updateResponseMeta,
|
|
40204
|
-
onTasks:
|
|
40205
|
-
const prevEmpty = tasksRef.current.length === 0;
|
|
40206
|
-
const prevAllDone = tasksRef.current.length > 0 && tasksRef.current.every((t) => t.status === "completed");
|
|
40207
|
-
tasksRef.current = nextTasks;
|
|
40208
|
-
setTasks(nextTasks);
|
|
40209
|
-
if ((prevEmpty || prevAllDone) && nextTasks.length > 0) {
|
|
40210
|
-
setTasksStartedAt(Date.now());
|
|
40211
|
-
setTasksStartTokens(usageRef.current?.prompt_tokens ?? 0);
|
|
40212
|
-
}
|
|
40213
|
-
if (nextTasks.length === 0) {
|
|
40214
|
-
setTasksStartedAt(null);
|
|
40215
|
-
setTasksStartTokens(0);
|
|
40216
|
-
}
|
|
40217
|
-
},
|
|
40425
|
+
onTasks: updateTaskTracking,
|
|
40218
40426
|
onPlanOptions: (options) => {
|
|
40219
40427
|
planOptionsRef.current = options;
|
|
40220
40428
|
},
|
|
40221
40429
|
askPermission: askForPermission,
|
|
40430
|
+
// Sandbox/memory warnings (e.g. Code Mode falling back to the plain
|
|
40431
|
+
// node:vm sandbox) were previously dropped on the floor in the TUI.
|
|
40432
|
+
onWarning: (msg) => {
|
|
40433
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: msg }]);
|
|
40434
|
+
},
|
|
40222
40435
|
onGuardrail: (ev) => {
|
|
40223
40436
|
if (ev.kind === "loop_recovery" || ev.kind === "loop_stopped") return;
|
|
40224
40437
|
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: ev.message }]);
|
|
@@ -40381,7 +40594,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40381
40594
|
lspManagerRef.current.notifyChange(path, content2);
|
|
40382
40595
|
} else {
|
|
40383
40596
|
void import("fs/promises").then(
|
|
40384
|
-
({ readFile:
|
|
40597
|
+
({ readFile: readFile38 }) => readFile38(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
|
|
40385
40598
|
})
|
|
40386
40599
|
);
|
|
40387
40600
|
}
|
|
@@ -40574,7 +40787,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40574
40787
|
};
|
|
40575
40788
|
ensureSessionId();
|
|
40576
40789
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
40577
|
-
const filePath =
|
|
40790
|
+
const filePath = join58(sessionsDir3(), `${sessionIdRef.current}.json`);
|
|
40578
40791
|
await addCheckpoint(filePath, cp);
|
|
40579
40792
|
}
|
|
40580
40793
|
const summary = await generateContinuationSummary({
|
|
@@ -40650,7 +40863,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40650
40863
|
}
|
|
40651
40864
|
);
|
|
40652
40865
|
},
|
|
40653
|
-
[cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateResponseMeta, setShowPlanCompletePicker, runUserShellCommand, ensureTraceStarted]
|
|
40866
|
+
[cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateResponseMeta, setShowPlanCompletePicker, runUserShellCommand, ensureTraceStarted, updateTaskTracking]
|
|
40654
40867
|
);
|
|
40655
40868
|
useEffect11(() => {
|
|
40656
40869
|
if (canDrainQueue({
|
|
@@ -41141,7 +41354,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
41141
41354
|
lsp: {
|
|
41142
41355
|
servers: cfg?.lspServers ?? {},
|
|
41143
41356
|
scope: lspScope,
|
|
41144
|
-
hasProjectDir: existsSync12(
|
|
41357
|
+
hasProjectDir: existsSync12(join58(process.cwd(), ".kimiflare"))
|
|
41145
41358
|
}
|
|
41146
41359
|
});
|
|
41147
41360
|
});
|
|
@@ -41198,7 +41411,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
41198
41411
|
onCommandDelete: handleCommandDelete2,
|
|
41199
41412
|
lspServers: cfg?.lspServers ?? {},
|
|
41200
41413
|
lspScope,
|
|
41201
|
-
hasProjectDir: existsSync12(
|
|
41414
|
+
hasProjectDir: existsSync12(join58(process.cwd(), ".kimiflare")),
|
|
41202
41415
|
onLspSave: handleLspSave2,
|
|
41203
41416
|
themes: themeList(),
|
|
41204
41417
|
onPickTheme: handleThemePick,
|
|
@@ -41685,11 +41898,11 @@ init_classify();
|
|
|
41685
41898
|
init_subagent_policy();
|
|
41686
41899
|
init_trace();
|
|
41687
41900
|
init_registry2();
|
|
41688
|
-
import { readFile as
|
|
41689
|
-
import { resolve as
|
|
41901
|
+
import { readFile as readFile17 } from "fs/promises";
|
|
41902
|
+
import { resolve as resolve7, basename as basename4 } from "path";
|
|
41690
41903
|
async function resolveSession(opts2) {
|
|
41691
41904
|
if (opts2.sessionId) {
|
|
41692
|
-
const filePath =
|
|
41905
|
+
const filePath = resolve7(sessionsDir(), `${opts2.sessionId}.json`);
|
|
41693
41906
|
try {
|
|
41694
41907
|
const file = await loadSession(filePath);
|
|
41695
41908
|
return { sessionFile: file, isNew: false };
|
|
@@ -41697,7 +41910,7 @@ async function resolveSession(opts2) {
|
|
|
41697
41910
|
}
|
|
41698
41911
|
}
|
|
41699
41912
|
if (opts2.continueSession) {
|
|
41700
|
-
const cwd = opts2.dir ?
|
|
41913
|
+
const cwd = opts2.dir ? resolve7(opts2.dir) : process.cwd();
|
|
41701
41914
|
const sessions = await listSessions(1, cwd);
|
|
41702
41915
|
if (sessions.length > 0) {
|
|
41703
41916
|
const filePath = sessions[0].filePath;
|
|
@@ -41710,7 +41923,7 @@ async function resolveSession(opts2) {
|
|
|
41710
41923
|
return {
|
|
41711
41924
|
sessionFile: {
|
|
41712
41925
|
id,
|
|
41713
|
-
cwd: opts2.dir ?
|
|
41926
|
+
cwd: opts2.dir ? resolve7(opts2.dir) : process.cwd(),
|
|
41714
41927
|
model: opts2.model,
|
|
41715
41928
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41716
41929
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -41724,9 +41937,9 @@ async function resolveFiles(filePatterns, cwd) {
|
|
|
41724
41937
|
const resolved = /* @__PURE__ */ new Set();
|
|
41725
41938
|
for (const pattern of filePatterns) {
|
|
41726
41939
|
try {
|
|
41727
|
-
const
|
|
41728
|
-
if (
|
|
41729
|
-
resolved.add(
|
|
41940
|
+
const stat15 = await import("fs/promises").then((m) => m.stat(resolve7(cwd, pattern)));
|
|
41941
|
+
if (stat15.isFile()) {
|
|
41942
|
+
resolved.add(resolve7(cwd, pattern));
|
|
41730
41943
|
continue;
|
|
41731
41944
|
}
|
|
41732
41945
|
} catch {
|
|
@@ -41749,12 +41962,12 @@ async function buildUserMessage(prompt, files, cwd) {
|
|
|
41749
41962
|
imageParts.push({ type: "image_url", image_url: { url: img.dataUrl } });
|
|
41750
41963
|
} catch (e) {
|
|
41751
41964
|
fileContents.push(`
|
|
41752
|
-
<!-- failed to attach image ${
|
|
41965
|
+
<!-- failed to attach image ${basename4(filePath)}: ${e.message} -->
|
|
41753
41966
|
`);
|
|
41754
41967
|
}
|
|
41755
41968
|
} else {
|
|
41756
41969
|
try {
|
|
41757
|
-
const content = await
|
|
41970
|
+
const content = await readFile17(filePath, "utf8");
|
|
41758
41971
|
const relPath = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
|
|
41759
41972
|
fileContents.push(`
|
|
41760
41973
|
--- ${relPath} ---
|
|
@@ -41763,7 +41976,7 @@ ${content}
|
|
|
41763
41976
|
`);
|
|
41764
41977
|
} catch (e) {
|
|
41765
41978
|
fileContents.push(`
|
|
41766
|
-
<!-- failed to read ${
|
|
41979
|
+
<!-- failed to read ${basename4(filePath)}: ${e.message} -->
|
|
41767
41980
|
`);
|
|
41768
41981
|
}
|
|
41769
41982
|
}
|
|
@@ -41789,7 +42002,7 @@ async function runPrintMode(opts2) {
|
|
|
41789
42002
|
`
|
|
41790
42003
|
);
|
|
41791
42004
|
}
|
|
41792
|
-
const cwd = opts2.dir ?
|
|
42005
|
+
const cwd = opts2.dir ? resolve7(opts2.dir) : process.cwd();
|
|
41793
42006
|
const baseWorkerTools = getWorkerTools(opts2.workerProfile);
|
|
41794
42007
|
const { HooksManager: HooksManager2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports));
|
|
41795
42008
|
const hooks = new HooksManager2(cwd);
|
|
@@ -42469,11 +42682,11 @@ async function promptHidden(question) {
|
|
|
42469
42682
|
}
|
|
42470
42683
|
});
|
|
42471
42684
|
const rl = createInterface4({ input: process.stdin, output, terminal: true });
|
|
42472
|
-
return new Promise((
|
|
42685
|
+
return new Promise((resolve20) => {
|
|
42473
42686
|
rl.question(question, (answer) => {
|
|
42474
42687
|
rl.close();
|
|
42475
42688
|
process.stdout.write("\n");
|
|
42476
|
-
|
|
42689
|
+
resolve20(answer);
|
|
42477
42690
|
});
|
|
42478
42691
|
muted = true;
|
|
42479
42692
|
});
|