autopilot-ai 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.js +497 -506
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.d.ts +5 -4
- package/dist/sdk/index.js +3 -3
- package/dist/sdk/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -37,6 +37,411 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
37
37
|
mod
|
|
38
38
|
));
|
|
39
39
|
|
|
40
|
+
// src/util/log-sink.ts
|
|
41
|
+
var log_sink_exports = {};
|
|
42
|
+
__export(log_sink_exports, {
|
|
43
|
+
flushAndCloseForTesting: () => flushAndCloseForTesting,
|
|
44
|
+
getLogSessionId: () => getLogSessionId,
|
|
45
|
+
getLogTurnId: () => getLogTurnId,
|
|
46
|
+
isLogSinkEnabled: () => isLogSinkEnabled,
|
|
47
|
+
logDir: () => logDir,
|
|
48
|
+
logPathFor: () => logPathFor,
|
|
49
|
+
pruneOldLogs: () => pruneOldLogs,
|
|
50
|
+
setLogDirForTesting: () => setLogDirForTesting,
|
|
51
|
+
setLogSessionId: () => setLogSessionId,
|
|
52
|
+
setLogSinkEnabled: () => setLogSinkEnabled,
|
|
53
|
+
setLogTurnId: () => setLogTurnId,
|
|
54
|
+
writeLogLine: () => writeLogLine
|
|
55
|
+
});
|
|
56
|
+
import { homedir } from "os";
|
|
57
|
+
import { join } from "path";
|
|
58
|
+
import { mkdirSync, createWriteStream, readdirSync, statSync, unlinkSync } from "fs";
|
|
59
|
+
function defaultLogDir() {
|
|
60
|
+
const xdg = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
61
|
+
return join(xdg, "kimiflare", "logs");
|
|
62
|
+
}
|
|
63
|
+
function isInNodeTestContext() {
|
|
64
|
+
if (process.env.NODE_TEST_CONTEXT) return true;
|
|
65
|
+
if (process.env.NODE_ENV === "test") return true;
|
|
66
|
+
if (process.argv.includes("--test")) return true;
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
function logDir() {
|
|
70
|
+
return overrideDir ?? defaultLogDir();
|
|
71
|
+
}
|
|
72
|
+
function logPathFor(date = /* @__PURE__ */ new Date()) {
|
|
73
|
+
return join(logDir(), `${date.toISOString().slice(0, 10)}.jsonl`);
|
|
74
|
+
}
|
|
75
|
+
function setLogDirForTesting(dir) {
|
|
76
|
+
if (currentStream) {
|
|
77
|
+
currentStream.end();
|
|
78
|
+
currentStream = null;
|
|
79
|
+
currentDate = null;
|
|
80
|
+
}
|
|
81
|
+
overrideDir = dir;
|
|
82
|
+
}
|
|
83
|
+
function setLogSinkEnabled(enabled2) {
|
|
84
|
+
if (!enabled2 && currentStream) {
|
|
85
|
+
currentStream.end();
|
|
86
|
+
currentStream = null;
|
|
87
|
+
currentDate = null;
|
|
88
|
+
}
|
|
89
|
+
sinkEnabled = enabled2;
|
|
90
|
+
}
|
|
91
|
+
async function flushAndCloseForTesting() {
|
|
92
|
+
if (!currentStream) return;
|
|
93
|
+
const s = currentStream;
|
|
94
|
+
currentStream = null;
|
|
95
|
+
currentDate = null;
|
|
96
|
+
await new Promise((resolve14) => {
|
|
97
|
+
s.end(() => resolve14());
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function isLogSinkEnabled() {
|
|
101
|
+
return sinkEnabled;
|
|
102
|
+
}
|
|
103
|
+
function ensureStream(now2) {
|
|
104
|
+
if (!sinkEnabled) return null;
|
|
105
|
+
const dateKey = now2.toISOString().slice(0, 10);
|
|
106
|
+
if (currentStream && currentDate === dateKey) return currentStream;
|
|
107
|
+
if (currentStream) {
|
|
108
|
+
currentStream.end();
|
|
109
|
+
currentStream = null;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
mkdirSync(logDir(), { recursive: true });
|
|
113
|
+
currentStream = createWriteStream(logPathFor(now2), { flags: "a" });
|
|
114
|
+
currentDate = dateKey;
|
|
115
|
+
currentStream.on("error", () => {
|
|
116
|
+
currentStream = null;
|
|
117
|
+
currentDate = null;
|
|
118
|
+
});
|
|
119
|
+
return currentStream;
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function writeLogLine(entry, now2 = /* @__PURE__ */ new Date()) {
|
|
125
|
+
const stream = ensureStream(now2);
|
|
126
|
+
if (!stream) return;
|
|
127
|
+
try {
|
|
128
|
+
stream.write(JSON.stringify(entry) + "\n");
|
|
129
|
+
} catch {
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function pruneOldLogs(retentionDays = RETENTION_DAYS) {
|
|
133
|
+
let removed = 0;
|
|
134
|
+
let entries;
|
|
135
|
+
try {
|
|
136
|
+
entries = readdirSync(logDir());
|
|
137
|
+
} catch {
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
|
140
|
+
const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
141
|
+
for (const name of entries) {
|
|
142
|
+
if (!name.endsWith(".jsonl")) continue;
|
|
143
|
+
const full = join(logDir(), name);
|
|
144
|
+
try {
|
|
145
|
+
const st = statSync(full);
|
|
146
|
+
if (st.mtimeMs < cutoff) {
|
|
147
|
+
unlinkSync(full);
|
|
148
|
+
removed += 1;
|
|
149
|
+
}
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return removed;
|
|
154
|
+
}
|
|
155
|
+
function setLogSessionId(id) {
|
|
156
|
+
currentSessionId = id;
|
|
157
|
+
}
|
|
158
|
+
function setLogTurnId(id) {
|
|
159
|
+
currentTurnId = id;
|
|
160
|
+
}
|
|
161
|
+
function getLogSessionId() {
|
|
162
|
+
return currentSessionId;
|
|
163
|
+
}
|
|
164
|
+
function getLogTurnId() {
|
|
165
|
+
return currentTurnId;
|
|
166
|
+
}
|
|
167
|
+
var RETENTION_DAYS, overrideDir, currentStream, currentDate, sinkEnabled, currentSessionId, currentTurnId;
|
|
168
|
+
var init_log_sink = __esm({
|
|
169
|
+
"src/util/log-sink.ts"() {
|
|
170
|
+
"use strict";
|
|
171
|
+
RETENTION_DAYS = 7;
|
|
172
|
+
overrideDir = null;
|
|
173
|
+
currentStream = null;
|
|
174
|
+
currentDate = null;
|
|
175
|
+
sinkEnabled = process.env.KIMIFLARE_LOG_SINK !== "off" && !isInNodeTestContext();
|
|
176
|
+
currentSessionId = null;
|
|
177
|
+
currentTurnId = null;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// src/util/otel-sink.ts
|
|
182
|
+
var otel_sink_exports = {};
|
|
183
|
+
__export(otel_sink_exports, {
|
|
184
|
+
buildOtlpPayload: () => buildOtlpPayload,
|
|
185
|
+
enqueueOtelLog: () => enqueueOtelLog,
|
|
186
|
+
flushOtelSink: () => flushOtelSink,
|
|
187
|
+
getOtelDropCount: () => getOtelDropCount,
|
|
188
|
+
getOtelQueueSize: () => getOtelQueueSize,
|
|
189
|
+
initOtelSink: () => initOtelSink,
|
|
190
|
+
installOtelExitHook: () => installOtelExitHook,
|
|
191
|
+
isOtelEnabled: () => isOtelEnabled,
|
|
192
|
+
resetOtelSinkForTesting: () => resetOtelSinkForTesting,
|
|
193
|
+
setFetchForTesting: () => setFetchForTesting
|
|
194
|
+
});
|
|
195
|
+
function setFetchForTesting(f) {
|
|
196
|
+
fetchImpl = f ?? ((url, init) => fetch(url, init));
|
|
197
|
+
}
|
|
198
|
+
function parseHeaders(raw) {
|
|
199
|
+
if (!raw) return {};
|
|
200
|
+
const out = {};
|
|
201
|
+
for (const pair of raw.split(",")) {
|
|
202
|
+
const trimmed = pair.trim();
|
|
203
|
+
if (!trimmed) continue;
|
|
204
|
+
const eq = trimmed.indexOf("=");
|
|
205
|
+
if (eq <= 0) continue;
|
|
206
|
+
const key = trimmed.slice(0, eq).trim();
|
|
207
|
+
const value = trimmed.slice(eq + 1).trim();
|
|
208
|
+
if (key) out[key] = value;
|
|
209
|
+
}
|
|
210
|
+
return out;
|
|
211
|
+
}
|
|
212
|
+
function normalizeEndpoint(raw) {
|
|
213
|
+
const stripped = raw.replace(/\/+$/, "");
|
|
214
|
+
if (/\/v1\/(logs|traces|metrics)$/.test(stripped)) return stripped;
|
|
215
|
+
return `${stripped}/v1/logs`;
|
|
216
|
+
}
|
|
217
|
+
function initOtelSink(opts2 = {}) {
|
|
218
|
+
const endpoint = opts2.endpoint ?? process.env.KIMIFLARE_OTEL_ENDPOINT;
|
|
219
|
+
if (!endpoint) {
|
|
220
|
+
config = null;
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
config = {
|
|
224
|
+
endpoint: normalizeEndpoint(endpoint),
|
|
225
|
+
headers: parseHeaders(opts2.headers ?? process.env.KIMIFLARE_OTEL_HEADERS),
|
|
226
|
+
serviceName: opts2.serviceName ?? "kimiflare",
|
|
227
|
+
serviceVersion: opts2.serviceVersion ?? process.env.npm_package_version ?? "0.0.0"
|
|
228
|
+
};
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
function isOtelEnabled() {
|
|
232
|
+
return config !== null;
|
|
233
|
+
}
|
|
234
|
+
function resetOtelSinkForTesting() {
|
|
235
|
+
if (timer) {
|
|
236
|
+
clearTimeout(timer);
|
|
237
|
+
timer = null;
|
|
238
|
+
}
|
|
239
|
+
queue = [];
|
|
240
|
+
config = null;
|
|
241
|
+
dropCount = 0;
|
|
242
|
+
inFlightFlush = null;
|
|
243
|
+
}
|
|
244
|
+
function getOtelDropCount() {
|
|
245
|
+
return dropCount;
|
|
246
|
+
}
|
|
247
|
+
function getOtelQueueSize() {
|
|
248
|
+
return queue.length;
|
|
249
|
+
}
|
|
250
|
+
function enqueueOtelLog(entry) {
|
|
251
|
+
if (!config) return;
|
|
252
|
+
queue.push(entry);
|
|
253
|
+
if (queue.length >= BATCH_MAX) {
|
|
254
|
+
void flushOtelSink();
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
scheduleFlush();
|
|
258
|
+
}
|
|
259
|
+
function scheduleFlush() {
|
|
260
|
+
if (timer) return;
|
|
261
|
+
timer = setTimeout(() => {
|
|
262
|
+
timer = null;
|
|
263
|
+
void flushOtelSink();
|
|
264
|
+
}, FLUSH_INTERVAL_MS);
|
|
265
|
+
if (typeof timer === "object" && timer && "unref" in timer) {
|
|
266
|
+
timer.unref();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async function flushOtelSink() {
|
|
270
|
+
if (!config) {
|
|
271
|
+
queue = [];
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (queue.length === 0) return;
|
|
275
|
+
if (inFlightFlush) return inFlightFlush;
|
|
276
|
+
const batch = queue;
|
|
277
|
+
queue = [];
|
|
278
|
+
const payload = buildOtlpPayload(batch, config);
|
|
279
|
+
inFlightFlush = (async () => {
|
|
280
|
+
try {
|
|
281
|
+
const res = await fetchImpl(config.endpoint, {
|
|
282
|
+
method: "POST",
|
|
283
|
+
headers: {
|
|
284
|
+
"Content-Type": "application/json",
|
|
285
|
+
...config.headers
|
|
286
|
+
},
|
|
287
|
+
body: JSON.stringify(payload)
|
|
288
|
+
});
|
|
289
|
+
if (!res.ok) {
|
|
290
|
+
dropCount += batch.length;
|
|
291
|
+
}
|
|
292
|
+
} catch {
|
|
293
|
+
dropCount += batch.length;
|
|
294
|
+
} finally {
|
|
295
|
+
inFlightFlush = null;
|
|
296
|
+
}
|
|
297
|
+
})();
|
|
298
|
+
return inFlightFlush;
|
|
299
|
+
}
|
|
300
|
+
function attr(key, value) {
|
|
301
|
+
if (value === null || value === void 0) return null;
|
|
302
|
+
if (typeof value === "string") return { key, value: { stringValue: value } };
|
|
303
|
+
if (typeof value === "boolean") return { key, value: { boolValue: value } };
|
|
304
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
305
|
+
return { key, value: { intValue: String(Math.trunc(value)) } };
|
|
306
|
+
}
|
|
307
|
+
return { key, value: { stringValue: JSON.stringify(value) } };
|
|
308
|
+
}
|
|
309
|
+
function flattenDataAttrs(data) {
|
|
310
|
+
if (!data) return [];
|
|
311
|
+
const out = [];
|
|
312
|
+
for (const [key, value] of Object.entries(data)) {
|
|
313
|
+
if (key === "request_id" || key === "requestId") continue;
|
|
314
|
+
const a = attr(key, value);
|
|
315
|
+
if (a) out.push(a);
|
|
316
|
+
}
|
|
317
|
+
return out;
|
|
318
|
+
}
|
|
319
|
+
function buildOtlpPayload(entries, cfg) {
|
|
320
|
+
const resourceAttrs = [
|
|
321
|
+
attr("service.name", cfg.serviceName),
|
|
322
|
+
attr("service.version", cfg.serviceVersion),
|
|
323
|
+
...process.env.HOSTNAME ? [attr("host.name", process.env.HOSTNAME)] : []
|
|
324
|
+
];
|
|
325
|
+
const logRecords = entries.map((e) => {
|
|
326
|
+
const attrs = [];
|
|
327
|
+
if (e.session_id) attrs.push(attr("session_id", e.session_id));
|
|
328
|
+
if (e.turn_id) attrs.push(attr("turn_id", e.turn_id));
|
|
329
|
+
if (e.request_id) attrs.push(attr("request_id", e.request_id));
|
|
330
|
+
attrs.push(attr("event", e.event));
|
|
331
|
+
attrs.push(...flattenDataAttrs(e.data));
|
|
332
|
+
const timeNs = String(BigInt(new Date(e.ts).getTime()) * 1000000n);
|
|
333
|
+
return {
|
|
334
|
+
timeUnixNano: timeNs,
|
|
335
|
+
observedTimeUnixNano: timeNs,
|
|
336
|
+
severityNumber: SEVERITY_NUMBER[e.level],
|
|
337
|
+
severityText: SEVERITY_TEXT[e.level],
|
|
338
|
+
body: { stringValue: e.event },
|
|
339
|
+
attributes: attrs
|
|
340
|
+
};
|
|
341
|
+
});
|
|
342
|
+
return {
|
|
343
|
+
resourceLogs: [
|
|
344
|
+
{
|
|
345
|
+
resource: { attributes: resourceAttrs },
|
|
346
|
+
scopeLogs: [
|
|
347
|
+
{
|
|
348
|
+
scope: { name: "kimiflare", version: cfg.serviceVersion },
|
|
349
|
+
logRecords
|
|
350
|
+
}
|
|
351
|
+
]
|
|
352
|
+
}
|
|
353
|
+
]
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function installOtelExitHook() {
|
|
357
|
+
if (exitHookInstalled) return;
|
|
358
|
+
exitHookInstalled = true;
|
|
359
|
+
const drain = () => {
|
|
360
|
+
if (queue.length === 0 && !inFlightFlush) return;
|
|
361
|
+
void flushOtelSink();
|
|
362
|
+
};
|
|
363
|
+
process.on("beforeExit", drain);
|
|
364
|
+
}
|
|
365
|
+
var BATCH_MAX, FLUSH_INTERVAL_MS, SEVERITY_NUMBER, SEVERITY_TEXT, config, queue, timer, dropCount, inFlightFlush, fetchImpl, exitHookInstalled;
|
|
366
|
+
var init_otel_sink = __esm({
|
|
367
|
+
"src/util/otel-sink.ts"() {
|
|
368
|
+
"use strict";
|
|
369
|
+
BATCH_MAX = 100;
|
|
370
|
+
FLUSH_INTERVAL_MS = 5e3;
|
|
371
|
+
SEVERITY_NUMBER = {
|
|
372
|
+
debug: 5,
|
|
373
|
+
info: 9,
|
|
374
|
+
warn: 13,
|
|
375
|
+
error: 17,
|
|
376
|
+
off: 0
|
|
377
|
+
// never actually emitted, but maps cleanly
|
|
378
|
+
};
|
|
379
|
+
SEVERITY_TEXT = {
|
|
380
|
+
debug: "DEBUG",
|
|
381
|
+
info: "INFO",
|
|
382
|
+
warn: "WARN",
|
|
383
|
+
error: "ERROR",
|
|
384
|
+
off: "OFF"
|
|
385
|
+
};
|
|
386
|
+
config = null;
|
|
387
|
+
queue = [];
|
|
388
|
+
timer = null;
|
|
389
|
+
dropCount = 0;
|
|
390
|
+
inFlightFlush = null;
|
|
391
|
+
fetchImpl = (url, init) => fetch(url, init);
|
|
392
|
+
exitHookInstalled = false;
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// src/util/logger.ts
|
|
397
|
+
function log(level, event, data) {
|
|
398
|
+
const sessionId = getLogSessionId();
|
|
399
|
+
const turnId = getLogTurnId();
|
|
400
|
+
const requestId = typeof data?.request_id === "string" ? data.request_id : typeof data?.requestId === "string" ? data.requestId : void 0;
|
|
401
|
+
const entry = {
|
|
402
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
403
|
+
level,
|
|
404
|
+
event,
|
|
405
|
+
...sessionId ? { session_id: sessionId } : {},
|
|
406
|
+
...turnId ? { turn_id: turnId } : {},
|
|
407
|
+
...requestId ? { request_id: requestId } : {},
|
|
408
|
+
data
|
|
409
|
+
};
|
|
410
|
+
recentLogs.push(entry);
|
|
411
|
+
if (recentLogs.length > RECENT_LOGS_MAX) {
|
|
412
|
+
recentLogs.shift();
|
|
413
|
+
}
|
|
414
|
+
if (LEVEL_ORDER[level] >= LEVEL_ORDER[globalMinLevel]) {
|
|
415
|
+
console.error(JSON.stringify(entry));
|
|
416
|
+
}
|
|
417
|
+
writeLogLine(entry);
|
|
418
|
+
enqueueOtelLog(entry);
|
|
419
|
+
}
|
|
420
|
+
var globalMinLevel, LEVEL_ORDER, RECENT_LOGS_MAX, recentLogs, logger;
|
|
421
|
+
var init_logger = __esm({
|
|
422
|
+
"src/util/logger.ts"() {
|
|
423
|
+
"use strict";
|
|
424
|
+
init_log_sink();
|
|
425
|
+
init_otel_sink();
|
|
426
|
+
globalMinLevel = process.env.KIMIFLARE_LOG_LEVEL ?? "off";
|
|
427
|
+
LEVEL_ORDER = {
|
|
428
|
+
debug: 0,
|
|
429
|
+
info: 1,
|
|
430
|
+
warn: 2,
|
|
431
|
+
error: 3,
|
|
432
|
+
off: 4
|
|
433
|
+
};
|
|
434
|
+
RECENT_LOGS_MAX = 100;
|
|
435
|
+
recentLogs = [];
|
|
436
|
+
logger = {
|
|
437
|
+
debug: (event, data) => log("debug", event, data),
|
|
438
|
+
info: (event, data) => log("info", event, data),
|
|
439
|
+
warn: (event, data) => log("warn", event, data),
|
|
440
|
+
error: (event, data) => log("error", event, data)
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
|
|
40
445
|
// src/models/registry.ts
|
|
41
446
|
function registerOpenRouterModels(entries) {
|
|
42
447
|
openRouterIndex = new Map(
|
|
@@ -195,11 +600,11 @@ __export(config_exports, {
|
|
|
195
600
|
saveConfig: () => saveConfig
|
|
196
601
|
});
|
|
197
602
|
import { readFile, mkdir, writeFile, chmod } from "fs/promises";
|
|
198
|
-
import { homedir } from "os";
|
|
199
|
-
import { join } from "path";
|
|
603
|
+
import { homedir as homedir2 } from "os";
|
|
604
|
+
import { join as join2 } from "path";
|
|
200
605
|
function configPath() {
|
|
201
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
202
|
-
return
|
|
606
|
+
const xdg = process.env.XDG_CONFIG_HOME || join2(homedir2(), ".config");
|
|
607
|
+
return join2(xdg, "kimiflare", "config.json");
|
|
203
608
|
}
|
|
204
609
|
function readReasoningEffortEnv() {
|
|
205
610
|
const raw = process.env.KIMI_REASONING_EFFORT?.toLowerCase();
|
|
@@ -270,7 +675,7 @@ async function loadConfig() {
|
|
|
270
675
|
model: m(envModel ?? persisted.model) ?? (requesty ? REQUESTY_DEFAULT_MODEL : DEFAULT_MODEL),
|
|
271
676
|
openrouterProvider: persisted.openrouterProvider,
|
|
272
677
|
reasoningEffort: envEffort ?? persisted.reasoningEffort,
|
|
273
|
-
subagentPolicy: envSubagentPolicy ?? (persisted.subagentPolicy === "off" || persisted.subagentPolicy === "suggest" || persisted.subagentPolicy === "auto" ? persisted.subagentPolicy : "
|
|
678
|
+
subagentPolicy: envSubagentPolicy ?? (persisted.subagentPolicy === "suggest" && persisted.subagentPolicyExplicit !== true ? "auto" : persisted.subagentPolicy === "off" || persisted.subagentPolicy === "suggest" || persisted.subagentPolicy === "auto" ? persisted.subagentPolicy : "auto"),
|
|
274
679
|
modesEnabled: persisted.modesEnabled,
|
|
275
680
|
coauthor: envCoauthor?.enabled ?? persisted.coauthor ?? true,
|
|
276
681
|
coauthorName: envCoauthor?.name ?? persisted.coauthorName,
|
|
@@ -380,7 +785,7 @@ async function patchPersistedConfig(patch) {
|
|
|
380
785
|
} catch {
|
|
381
786
|
}
|
|
382
787
|
const merged = { ...existing, ...patch };
|
|
383
|
-
await mkdir(
|
|
788
|
+
await mkdir(join2(p, ".."), { recursive: true });
|
|
384
789
|
await writeFile(p, JSON.stringify(merged, null, 2), "utf8");
|
|
385
790
|
await chmod(p, 384);
|
|
386
791
|
return p;
|
|
@@ -404,7 +809,7 @@ function resolveWorkerBudgetUsd(cfg) {
|
|
|
404
809
|
}
|
|
405
810
|
async function saveConfig(cfg) {
|
|
406
811
|
const p = configPath();
|
|
407
|
-
await mkdir(
|
|
812
|
+
await mkdir(join2(p, ".."), { recursive: true });
|
|
408
813
|
await writeFile(p, JSON.stringify(cfg, null, 2), "utf8");
|
|
409
814
|
await chmod(p, 384);
|
|
410
815
|
return p;
|
|
@@ -446,15 +851,15 @@ var init_config = __esm({
|
|
|
446
851
|
|
|
447
852
|
// src/util/lsp-config.ts
|
|
448
853
|
import { readFile as readFile2, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
449
|
-
import { join as
|
|
854
|
+
import { join as join3, dirname } from "path";
|
|
450
855
|
import { existsSync } from "fs";
|
|
451
856
|
function isGitRoot(dir) {
|
|
452
|
-
return existsSync(
|
|
857
|
+
return existsSync(join3(dir, ".git"));
|
|
453
858
|
}
|
|
454
859
|
function findProjectLspConfigPath(cwd) {
|
|
455
860
|
let current = cwd;
|
|
456
861
|
while (true) {
|
|
457
|
-
const candidate =
|
|
862
|
+
const candidate = join3(current, PROJECT_CONFIG_DIR, PROJECT_LSP_FILE);
|
|
458
863
|
if (existsSync(candidate)) {
|
|
459
864
|
return candidate;
|
|
460
865
|
}
|
|
@@ -483,7 +888,7 @@ async function loadProjectLspConfig(cwd) {
|
|
|
483
888
|
}
|
|
484
889
|
}
|
|
485
890
|
async function ensureGitignore(cwd) {
|
|
486
|
-
const gitignorePath =
|
|
891
|
+
const gitignorePath = join3(cwd, ".gitignore");
|
|
487
892
|
const entry = `${PROJECT_CONFIG_DIR}/${PROJECT_LSP_FILE}`;
|
|
488
893
|
try {
|
|
489
894
|
const content = await readFile2(gitignorePath, "utf8");
|
|
@@ -493,9 +898,9 @@ async function ensureGitignore(cwd) {
|
|
|
493
898
|
}
|
|
494
899
|
}
|
|
495
900
|
async function saveProjectLspConfig(cwd, cfg) {
|
|
496
|
-
const dir =
|
|
901
|
+
const dir = join3(cwd, PROJECT_CONFIG_DIR);
|
|
497
902
|
await mkdir2(dir, { recursive: true });
|
|
498
|
-
const path =
|
|
903
|
+
const path = join3(dir, PROJECT_LSP_FILE);
|
|
499
904
|
await writeFile2(path, JSON.stringify(cfg, null, 2), "utf8");
|
|
500
905
|
await ensureGitignore(cwd);
|
|
501
906
|
return path;
|
|
@@ -532,11 +937,11 @@ var init_lsp_config = __esm({
|
|
|
532
937
|
// src/util/version.ts
|
|
533
938
|
import { readFileSync } from "fs";
|
|
534
939
|
import { fileURLToPath } from "url";
|
|
535
|
-
import { dirname as dirname2, join as
|
|
940
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
536
941
|
function getAppVersion() {
|
|
537
942
|
if (cachedVersion !== null) return cachedVersion;
|
|
538
943
|
const here = dirname2(fileURLToPath(import.meta.url));
|
|
539
|
-
const candidates = [
|
|
944
|
+
const candidates = [join4(here, "..", "..", "package.json"), join4(here, "..", "package.json")];
|
|
540
945
|
for (const path of candidates) {
|
|
541
946
|
try {
|
|
542
947
|
const pkg = JSON.parse(readFileSync(path, "utf8"));
|
|
@@ -563,17 +968,17 @@ var init_version = __esm({
|
|
|
563
968
|
|
|
564
969
|
// src/util/update-check.ts
|
|
565
970
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
566
|
-
import { homedir as
|
|
567
|
-
import { join as
|
|
971
|
+
import { homedir as homedir3 } from "os";
|
|
972
|
+
import { join as join5, dirname as dirname3 } from "path";
|
|
568
973
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
569
974
|
function cachePath() {
|
|
570
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
571
|
-
return
|
|
975
|
+
const xdg = process.env.XDG_CONFIG_HOME || join5(homedir3(), ".config");
|
|
976
|
+
return join5(xdg, "kimiflare", "update-check.json");
|
|
572
977
|
}
|
|
573
978
|
async function findPackageJson(startDir) {
|
|
574
979
|
let dir = startDir;
|
|
575
980
|
while (true) {
|
|
576
|
-
const candidate =
|
|
981
|
+
const candidate = join5(dir, "package.json");
|
|
577
982
|
try {
|
|
578
983
|
const raw = await readFile3(candidate, "utf8");
|
|
579
984
|
const parsed = JSON.parse(raw);
|
|
@@ -665,21 +1070,21 @@ var init_update_check = __esm({
|
|
|
665
1070
|
|
|
666
1071
|
// src/remote/session-store.ts
|
|
667
1072
|
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir } from "fs/promises";
|
|
668
|
-
import { homedir as
|
|
669
|
-
import { join as
|
|
1073
|
+
import { homedir as homedir4 } from "os";
|
|
1074
|
+
import { join as join6 } from "path";
|
|
670
1075
|
function remoteDir() {
|
|
671
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
672
|
-
return
|
|
1076
|
+
const xdg = process.env.XDG_DATA_HOME || join6(homedir4(), ".config");
|
|
1077
|
+
return join6(xdg, "kimiflare", "remote");
|
|
673
1078
|
}
|
|
674
1079
|
async function saveRemoteSession(session) {
|
|
675
1080
|
const dir = remoteDir();
|
|
676
1081
|
await mkdir4(dir, { recursive: true });
|
|
677
|
-
const path =
|
|
1082
|
+
const path = join6(dir, `${session.sessionId}.json`);
|
|
678
1083
|
await writeFile4(path, JSON.stringify(session, null, 2) + "\n", "utf8");
|
|
679
1084
|
}
|
|
680
1085
|
async function loadRemoteSession(sessionId) {
|
|
681
1086
|
try {
|
|
682
|
-
const path =
|
|
1087
|
+
const path = join6(remoteDir(), `${sessionId}.json`);
|
|
683
1088
|
const raw = await readFile4(path, "utf8");
|
|
684
1089
|
return JSON.parse(raw);
|
|
685
1090
|
} catch {
|
|
@@ -694,7 +1099,7 @@ async function listRemoteSessions() {
|
|
|
694
1099
|
for (const file of files) {
|
|
695
1100
|
if (!file.endsWith(".json")) continue;
|
|
696
1101
|
try {
|
|
697
|
-
const raw = await readFile4(
|
|
1102
|
+
const raw = await readFile4(join6(dir, file), "utf8");
|
|
698
1103
|
sessions.push(JSON.parse(raw));
|
|
699
1104
|
} catch {
|
|
700
1105
|
}
|
|
@@ -716,7 +1121,7 @@ var init_session_store = __esm({
|
|
|
716
1121
|
|
|
717
1122
|
// src/remote/deploy.ts
|
|
718
1123
|
import { execSync } from "child_process";
|
|
719
|
-
import { join as
|
|
1124
|
+
import { join as join7, dirname as dirname4 } from "path";
|
|
720
1125
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
721
1126
|
import { randomBytes } from "crypto";
|
|
722
1127
|
function generateSecret() {
|
|
@@ -751,7 +1156,7 @@ async function* deployForTui() {
|
|
|
751
1156
|
yield { message: "Docker OK" };
|
|
752
1157
|
yield { message: "Building remote agent bundle..." };
|
|
753
1158
|
try {
|
|
754
|
-
runCapture("npm run build:remote-agent",
|
|
1159
|
+
runCapture("npm run build:remote-agent", join7(REMOTE_DIR, ".."));
|
|
755
1160
|
yield { message: "Agent bundle built" };
|
|
756
1161
|
} catch (err) {
|
|
757
1162
|
yield { message: `Build failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
|
|
@@ -881,413 +1286,8 @@ var init_deploy = __esm({
|
|
|
881
1286
|
"use strict";
|
|
882
1287
|
init_config();
|
|
883
1288
|
__dirname2 = dirname4(fileURLToPath3(import.meta.url));
|
|
884
|
-
REMOTE_DIR =
|
|
885
|
-
WORKER_DIR =
|
|
886
|
-
}
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
// src/util/log-sink.ts
|
|
890
|
-
var log_sink_exports = {};
|
|
891
|
-
__export(log_sink_exports, {
|
|
892
|
-
flushAndCloseForTesting: () => flushAndCloseForTesting,
|
|
893
|
-
getLogSessionId: () => getLogSessionId,
|
|
894
|
-
getLogTurnId: () => getLogTurnId,
|
|
895
|
-
isLogSinkEnabled: () => isLogSinkEnabled,
|
|
896
|
-
logDir: () => logDir,
|
|
897
|
-
logPathFor: () => logPathFor,
|
|
898
|
-
pruneOldLogs: () => pruneOldLogs,
|
|
899
|
-
setLogDirForTesting: () => setLogDirForTesting,
|
|
900
|
-
setLogSessionId: () => setLogSessionId,
|
|
901
|
-
setLogSinkEnabled: () => setLogSinkEnabled,
|
|
902
|
-
setLogTurnId: () => setLogTurnId,
|
|
903
|
-
writeLogLine: () => writeLogLine
|
|
904
|
-
});
|
|
905
|
-
import { homedir as homedir4 } from "os";
|
|
906
|
-
import { join as join7 } from "path";
|
|
907
|
-
import { mkdirSync, createWriteStream, readdirSync, statSync, unlinkSync } from "fs";
|
|
908
|
-
function defaultLogDir() {
|
|
909
|
-
const xdg = process.env.XDG_CONFIG_HOME || join7(homedir4(), ".config");
|
|
910
|
-
return join7(xdg, "kimiflare", "logs");
|
|
911
|
-
}
|
|
912
|
-
function isInNodeTestContext() {
|
|
913
|
-
if (process.env.NODE_TEST_CONTEXT) return true;
|
|
914
|
-
if (process.env.NODE_ENV === "test") return true;
|
|
915
|
-
if (process.argv.includes("--test")) return true;
|
|
916
|
-
return false;
|
|
917
|
-
}
|
|
918
|
-
function logDir() {
|
|
919
|
-
return overrideDir ?? defaultLogDir();
|
|
920
|
-
}
|
|
921
|
-
function logPathFor(date = /* @__PURE__ */ new Date()) {
|
|
922
|
-
return join7(logDir(), `${date.toISOString().slice(0, 10)}.jsonl`);
|
|
923
|
-
}
|
|
924
|
-
function setLogDirForTesting(dir) {
|
|
925
|
-
if (currentStream) {
|
|
926
|
-
currentStream.end();
|
|
927
|
-
currentStream = null;
|
|
928
|
-
currentDate = null;
|
|
929
|
-
}
|
|
930
|
-
overrideDir = dir;
|
|
931
|
-
}
|
|
932
|
-
function setLogSinkEnabled(enabled2) {
|
|
933
|
-
if (!enabled2 && currentStream) {
|
|
934
|
-
currentStream.end();
|
|
935
|
-
currentStream = null;
|
|
936
|
-
currentDate = null;
|
|
937
|
-
}
|
|
938
|
-
sinkEnabled = enabled2;
|
|
939
|
-
}
|
|
940
|
-
async function flushAndCloseForTesting() {
|
|
941
|
-
if (!currentStream) return;
|
|
942
|
-
const s = currentStream;
|
|
943
|
-
currentStream = null;
|
|
944
|
-
currentDate = null;
|
|
945
|
-
await new Promise((resolve14) => {
|
|
946
|
-
s.end(() => resolve14());
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
function isLogSinkEnabled() {
|
|
950
|
-
return sinkEnabled;
|
|
951
|
-
}
|
|
952
|
-
function ensureStream(now2) {
|
|
953
|
-
if (!sinkEnabled) return null;
|
|
954
|
-
const dateKey = now2.toISOString().slice(0, 10);
|
|
955
|
-
if (currentStream && currentDate === dateKey) return currentStream;
|
|
956
|
-
if (currentStream) {
|
|
957
|
-
currentStream.end();
|
|
958
|
-
currentStream = null;
|
|
959
|
-
}
|
|
960
|
-
try {
|
|
961
|
-
mkdirSync(logDir(), { recursive: true });
|
|
962
|
-
currentStream = createWriteStream(logPathFor(now2), { flags: "a" });
|
|
963
|
-
currentDate = dateKey;
|
|
964
|
-
currentStream.on("error", () => {
|
|
965
|
-
currentStream = null;
|
|
966
|
-
currentDate = null;
|
|
967
|
-
});
|
|
968
|
-
return currentStream;
|
|
969
|
-
} catch {
|
|
970
|
-
return null;
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
function writeLogLine(entry, now2 = /* @__PURE__ */ new Date()) {
|
|
974
|
-
const stream = ensureStream(now2);
|
|
975
|
-
if (!stream) return;
|
|
976
|
-
try {
|
|
977
|
-
stream.write(JSON.stringify(entry) + "\n");
|
|
978
|
-
} catch {
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
function pruneOldLogs(retentionDays = RETENTION_DAYS) {
|
|
982
|
-
let removed = 0;
|
|
983
|
-
let entries;
|
|
984
|
-
try {
|
|
985
|
-
entries = readdirSync(logDir());
|
|
986
|
-
} catch {
|
|
987
|
-
return 0;
|
|
988
|
-
}
|
|
989
|
-
const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
990
|
-
for (const name of entries) {
|
|
991
|
-
if (!name.endsWith(".jsonl")) continue;
|
|
992
|
-
const full = join7(logDir(), name);
|
|
993
|
-
try {
|
|
994
|
-
const st = statSync(full);
|
|
995
|
-
if (st.mtimeMs < cutoff) {
|
|
996
|
-
unlinkSync(full);
|
|
997
|
-
removed += 1;
|
|
998
|
-
}
|
|
999
|
-
} catch {
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
return removed;
|
|
1003
|
-
}
|
|
1004
|
-
function setLogSessionId(id) {
|
|
1005
|
-
currentSessionId = id;
|
|
1006
|
-
}
|
|
1007
|
-
function setLogTurnId(id) {
|
|
1008
|
-
currentTurnId = id;
|
|
1009
|
-
}
|
|
1010
|
-
function getLogSessionId() {
|
|
1011
|
-
return currentSessionId;
|
|
1012
|
-
}
|
|
1013
|
-
function getLogTurnId() {
|
|
1014
|
-
return currentTurnId;
|
|
1015
|
-
}
|
|
1016
|
-
var RETENTION_DAYS, overrideDir, currentStream, currentDate, sinkEnabled, currentSessionId, currentTurnId;
|
|
1017
|
-
var init_log_sink = __esm({
|
|
1018
|
-
"src/util/log-sink.ts"() {
|
|
1019
|
-
"use strict";
|
|
1020
|
-
RETENTION_DAYS = 7;
|
|
1021
|
-
overrideDir = null;
|
|
1022
|
-
currentStream = null;
|
|
1023
|
-
currentDate = null;
|
|
1024
|
-
sinkEnabled = process.env.KIMIFLARE_LOG_SINK !== "off" && !isInNodeTestContext();
|
|
1025
|
-
currentSessionId = null;
|
|
1026
|
-
currentTurnId = null;
|
|
1027
|
-
}
|
|
1028
|
-
});
|
|
1029
|
-
|
|
1030
|
-
// src/util/otel-sink.ts
|
|
1031
|
-
var otel_sink_exports = {};
|
|
1032
|
-
__export(otel_sink_exports, {
|
|
1033
|
-
buildOtlpPayload: () => buildOtlpPayload,
|
|
1034
|
-
enqueueOtelLog: () => enqueueOtelLog,
|
|
1035
|
-
flushOtelSink: () => flushOtelSink,
|
|
1036
|
-
getOtelDropCount: () => getOtelDropCount,
|
|
1037
|
-
getOtelQueueSize: () => getOtelQueueSize,
|
|
1038
|
-
initOtelSink: () => initOtelSink,
|
|
1039
|
-
installOtelExitHook: () => installOtelExitHook,
|
|
1040
|
-
isOtelEnabled: () => isOtelEnabled,
|
|
1041
|
-
resetOtelSinkForTesting: () => resetOtelSinkForTesting,
|
|
1042
|
-
setFetchForTesting: () => setFetchForTesting
|
|
1043
|
-
});
|
|
1044
|
-
function setFetchForTesting(f) {
|
|
1045
|
-
fetchImpl = f ?? ((url, init) => fetch(url, init));
|
|
1046
|
-
}
|
|
1047
|
-
function parseHeaders(raw) {
|
|
1048
|
-
if (!raw) return {};
|
|
1049
|
-
const out = {};
|
|
1050
|
-
for (const pair of raw.split(",")) {
|
|
1051
|
-
const trimmed = pair.trim();
|
|
1052
|
-
if (!trimmed) continue;
|
|
1053
|
-
const eq = trimmed.indexOf("=");
|
|
1054
|
-
if (eq <= 0) continue;
|
|
1055
|
-
const key = trimmed.slice(0, eq).trim();
|
|
1056
|
-
const value = trimmed.slice(eq + 1).trim();
|
|
1057
|
-
if (key) out[key] = value;
|
|
1058
|
-
}
|
|
1059
|
-
return out;
|
|
1060
|
-
}
|
|
1061
|
-
function normalizeEndpoint(raw) {
|
|
1062
|
-
const stripped = raw.replace(/\/+$/, "");
|
|
1063
|
-
if (/\/v1\/(logs|traces|metrics)$/.test(stripped)) return stripped;
|
|
1064
|
-
return `${stripped}/v1/logs`;
|
|
1065
|
-
}
|
|
1066
|
-
function initOtelSink(opts2 = {}) {
|
|
1067
|
-
const endpoint = opts2.endpoint ?? process.env.KIMIFLARE_OTEL_ENDPOINT;
|
|
1068
|
-
if (!endpoint) {
|
|
1069
|
-
config = null;
|
|
1070
|
-
return false;
|
|
1071
|
-
}
|
|
1072
|
-
config = {
|
|
1073
|
-
endpoint: normalizeEndpoint(endpoint),
|
|
1074
|
-
headers: parseHeaders(opts2.headers ?? process.env.KIMIFLARE_OTEL_HEADERS),
|
|
1075
|
-
serviceName: opts2.serviceName ?? "kimiflare",
|
|
1076
|
-
serviceVersion: opts2.serviceVersion ?? process.env.npm_package_version ?? "0.0.0"
|
|
1077
|
-
};
|
|
1078
|
-
return true;
|
|
1079
|
-
}
|
|
1080
|
-
function isOtelEnabled() {
|
|
1081
|
-
return config !== null;
|
|
1082
|
-
}
|
|
1083
|
-
function resetOtelSinkForTesting() {
|
|
1084
|
-
if (timer) {
|
|
1085
|
-
clearTimeout(timer);
|
|
1086
|
-
timer = null;
|
|
1087
|
-
}
|
|
1088
|
-
queue = [];
|
|
1089
|
-
config = null;
|
|
1090
|
-
dropCount = 0;
|
|
1091
|
-
inFlightFlush = null;
|
|
1092
|
-
}
|
|
1093
|
-
function getOtelDropCount() {
|
|
1094
|
-
return dropCount;
|
|
1095
|
-
}
|
|
1096
|
-
function getOtelQueueSize() {
|
|
1097
|
-
return queue.length;
|
|
1098
|
-
}
|
|
1099
|
-
function enqueueOtelLog(entry) {
|
|
1100
|
-
if (!config) return;
|
|
1101
|
-
queue.push(entry);
|
|
1102
|
-
if (queue.length >= BATCH_MAX) {
|
|
1103
|
-
void flushOtelSink();
|
|
1104
|
-
return;
|
|
1105
|
-
}
|
|
1106
|
-
scheduleFlush();
|
|
1107
|
-
}
|
|
1108
|
-
function scheduleFlush() {
|
|
1109
|
-
if (timer) return;
|
|
1110
|
-
timer = setTimeout(() => {
|
|
1111
|
-
timer = null;
|
|
1112
|
-
void flushOtelSink();
|
|
1113
|
-
}, FLUSH_INTERVAL_MS);
|
|
1114
|
-
if (typeof timer === "object" && timer && "unref" in timer) {
|
|
1115
|
-
timer.unref();
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
async function flushOtelSink() {
|
|
1119
|
-
if (!config) {
|
|
1120
|
-
queue = [];
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
if (queue.length === 0) return;
|
|
1124
|
-
if (inFlightFlush) return inFlightFlush;
|
|
1125
|
-
const batch = queue;
|
|
1126
|
-
queue = [];
|
|
1127
|
-
const payload = buildOtlpPayload(batch, config);
|
|
1128
|
-
inFlightFlush = (async () => {
|
|
1129
|
-
try {
|
|
1130
|
-
const res = await fetchImpl(config.endpoint, {
|
|
1131
|
-
method: "POST",
|
|
1132
|
-
headers: {
|
|
1133
|
-
"Content-Type": "application/json",
|
|
1134
|
-
...config.headers
|
|
1135
|
-
},
|
|
1136
|
-
body: JSON.stringify(payload)
|
|
1137
|
-
});
|
|
1138
|
-
if (!res.ok) {
|
|
1139
|
-
dropCount += batch.length;
|
|
1140
|
-
}
|
|
1141
|
-
} catch {
|
|
1142
|
-
dropCount += batch.length;
|
|
1143
|
-
} finally {
|
|
1144
|
-
inFlightFlush = null;
|
|
1145
|
-
}
|
|
1146
|
-
})();
|
|
1147
|
-
return inFlightFlush;
|
|
1148
|
-
}
|
|
1149
|
-
function attr(key, value) {
|
|
1150
|
-
if (value === null || value === void 0) return null;
|
|
1151
|
-
if (typeof value === "string") return { key, value: { stringValue: value } };
|
|
1152
|
-
if (typeof value === "boolean") return { key, value: { boolValue: value } };
|
|
1153
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1154
|
-
return { key, value: { intValue: String(Math.trunc(value)) } };
|
|
1155
|
-
}
|
|
1156
|
-
return { key, value: { stringValue: JSON.stringify(value) } };
|
|
1157
|
-
}
|
|
1158
|
-
function flattenDataAttrs(data) {
|
|
1159
|
-
if (!data) return [];
|
|
1160
|
-
const out = [];
|
|
1161
|
-
for (const [key, value] of Object.entries(data)) {
|
|
1162
|
-
if (key === "request_id" || key === "requestId") continue;
|
|
1163
|
-
const a = attr(key, value);
|
|
1164
|
-
if (a) out.push(a);
|
|
1165
|
-
}
|
|
1166
|
-
return out;
|
|
1167
|
-
}
|
|
1168
|
-
function buildOtlpPayload(entries, cfg) {
|
|
1169
|
-
const resourceAttrs = [
|
|
1170
|
-
attr("service.name", cfg.serviceName),
|
|
1171
|
-
attr("service.version", cfg.serviceVersion),
|
|
1172
|
-
...process.env.HOSTNAME ? [attr("host.name", process.env.HOSTNAME)] : []
|
|
1173
|
-
];
|
|
1174
|
-
const logRecords = entries.map((e) => {
|
|
1175
|
-
const attrs = [];
|
|
1176
|
-
if (e.session_id) attrs.push(attr("session_id", e.session_id));
|
|
1177
|
-
if (e.turn_id) attrs.push(attr("turn_id", e.turn_id));
|
|
1178
|
-
if (e.request_id) attrs.push(attr("request_id", e.request_id));
|
|
1179
|
-
attrs.push(attr("event", e.event));
|
|
1180
|
-
attrs.push(...flattenDataAttrs(e.data));
|
|
1181
|
-
const timeNs = String(BigInt(new Date(e.ts).getTime()) * 1000000n);
|
|
1182
|
-
return {
|
|
1183
|
-
timeUnixNano: timeNs,
|
|
1184
|
-
observedTimeUnixNano: timeNs,
|
|
1185
|
-
severityNumber: SEVERITY_NUMBER[e.level],
|
|
1186
|
-
severityText: SEVERITY_TEXT[e.level],
|
|
1187
|
-
body: { stringValue: e.event },
|
|
1188
|
-
attributes: attrs
|
|
1189
|
-
};
|
|
1190
|
-
});
|
|
1191
|
-
return {
|
|
1192
|
-
resourceLogs: [
|
|
1193
|
-
{
|
|
1194
|
-
resource: { attributes: resourceAttrs },
|
|
1195
|
-
scopeLogs: [
|
|
1196
|
-
{
|
|
1197
|
-
scope: { name: "kimiflare", version: cfg.serviceVersion },
|
|
1198
|
-
logRecords
|
|
1199
|
-
}
|
|
1200
|
-
]
|
|
1201
|
-
}
|
|
1202
|
-
]
|
|
1203
|
-
};
|
|
1204
|
-
}
|
|
1205
|
-
function installOtelExitHook() {
|
|
1206
|
-
if (exitHookInstalled) return;
|
|
1207
|
-
exitHookInstalled = true;
|
|
1208
|
-
const drain = () => {
|
|
1209
|
-
if (queue.length === 0 && !inFlightFlush) return;
|
|
1210
|
-
void flushOtelSink();
|
|
1211
|
-
};
|
|
1212
|
-
process.on("beforeExit", drain);
|
|
1213
|
-
}
|
|
1214
|
-
var BATCH_MAX, FLUSH_INTERVAL_MS, SEVERITY_NUMBER, SEVERITY_TEXT, config, queue, timer, dropCount, inFlightFlush, fetchImpl, exitHookInstalled;
|
|
1215
|
-
var init_otel_sink = __esm({
|
|
1216
|
-
"src/util/otel-sink.ts"() {
|
|
1217
|
-
"use strict";
|
|
1218
|
-
BATCH_MAX = 100;
|
|
1219
|
-
FLUSH_INTERVAL_MS = 5e3;
|
|
1220
|
-
SEVERITY_NUMBER = {
|
|
1221
|
-
debug: 5,
|
|
1222
|
-
info: 9,
|
|
1223
|
-
warn: 13,
|
|
1224
|
-
error: 17,
|
|
1225
|
-
off: 0
|
|
1226
|
-
// never actually emitted, but maps cleanly
|
|
1227
|
-
};
|
|
1228
|
-
SEVERITY_TEXT = {
|
|
1229
|
-
debug: "DEBUG",
|
|
1230
|
-
info: "INFO",
|
|
1231
|
-
warn: "WARN",
|
|
1232
|
-
error: "ERROR",
|
|
1233
|
-
off: "OFF"
|
|
1234
|
-
};
|
|
1235
|
-
config = null;
|
|
1236
|
-
queue = [];
|
|
1237
|
-
timer = null;
|
|
1238
|
-
dropCount = 0;
|
|
1239
|
-
inFlightFlush = null;
|
|
1240
|
-
fetchImpl = (url, init) => fetch(url, init);
|
|
1241
|
-
exitHookInstalled = false;
|
|
1242
|
-
}
|
|
1243
|
-
});
|
|
1244
|
-
|
|
1245
|
-
// src/util/logger.ts
|
|
1246
|
-
function log(level, event, data) {
|
|
1247
|
-
const sessionId = getLogSessionId();
|
|
1248
|
-
const turnId = getLogTurnId();
|
|
1249
|
-
const requestId = typeof data?.request_id === "string" ? data.request_id : typeof data?.requestId === "string" ? data.requestId : void 0;
|
|
1250
|
-
const entry = {
|
|
1251
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1252
|
-
level,
|
|
1253
|
-
event,
|
|
1254
|
-
...sessionId ? { session_id: sessionId } : {},
|
|
1255
|
-
...turnId ? { turn_id: turnId } : {},
|
|
1256
|
-
...requestId ? { request_id: requestId } : {},
|
|
1257
|
-
data
|
|
1258
|
-
};
|
|
1259
|
-
recentLogs.push(entry);
|
|
1260
|
-
if (recentLogs.length > RECENT_LOGS_MAX) {
|
|
1261
|
-
recentLogs.shift();
|
|
1262
|
-
}
|
|
1263
|
-
if (LEVEL_ORDER[level] >= LEVEL_ORDER[globalMinLevel]) {
|
|
1264
|
-
console.error(JSON.stringify(entry));
|
|
1265
|
-
}
|
|
1266
|
-
writeLogLine(entry);
|
|
1267
|
-
enqueueOtelLog(entry);
|
|
1268
|
-
}
|
|
1269
|
-
var globalMinLevel, LEVEL_ORDER, RECENT_LOGS_MAX, recentLogs, logger;
|
|
1270
|
-
var init_logger = __esm({
|
|
1271
|
-
"src/util/logger.ts"() {
|
|
1272
|
-
"use strict";
|
|
1273
|
-
init_log_sink();
|
|
1274
|
-
init_otel_sink();
|
|
1275
|
-
globalMinLevel = process.env.KIMIFLARE_LOG_LEVEL ?? "off";
|
|
1276
|
-
LEVEL_ORDER = {
|
|
1277
|
-
debug: 0,
|
|
1278
|
-
info: 1,
|
|
1279
|
-
warn: 2,
|
|
1280
|
-
error: 3,
|
|
1281
|
-
off: 4
|
|
1282
|
-
};
|
|
1283
|
-
RECENT_LOGS_MAX = 100;
|
|
1284
|
-
recentLogs = [];
|
|
1285
|
-
logger = {
|
|
1286
|
-
debug: (event, data) => log("debug", event, data),
|
|
1287
|
-
info: (event, data) => log("info", event, data),
|
|
1288
|
-
warn: (event, data) => log("warn", event, data),
|
|
1289
|
-
error: (event, data) => log("error", event, data)
|
|
1290
|
-
};
|
|
1289
|
+
REMOTE_DIR = join7(__dirname2, "..", "..", "..", "remote");
|
|
1290
|
+
WORKER_DIR = join7(REMOTE_DIR, "worker");
|
|
1291
1291
|
}
|
|
1292
1292
|
});
|
|
1293
1293
|
|
|
@@ -8782,7 +8782,7 @@ async function callWorkerEndpoint(endpoint, apiKey, payload, signal, timeoutMs =
|
|
|
8782
8782
|
...apiKey ? { "X-Worker-Api-Key": apiKey } : {}
|
|
8783
8783
|
};
|
|
8784
8784
|
const body = JSON.stringify(payload);
|
|
8785
|
-
const fetchSignal = signal
|
|
8785
|
+
const fetchSignal = signal ? AbortSignal.any([controller.signal, signal]) : controller.signal;
|
|
8786
8786
|
try {
|
|
8787
8787
|
const res = await fetch(url, { method: "POST", headers, body, signal: fetchSignal });
|
|
8788
8788
|
if (res.ok) {
|
|
@@ -8947,7 +8947,7 @@ ${finding.summary}`)
|
|
|
8947
8947
|
if (!endpoint) {
|
|
8948
8948
|
return textOutput("Worker endpoint not configured. Set KIMIFLARE_WORKER_ENDPOINT or workerEndpoint in config, or set workerBackend to hotcell.");
|
|
8949
8949
|
}
|
|
8950
|
-
const apiKey = process.env.KIMIFLARE_WORKER_API_KEY;
|
|
8950
|
+
const apiKey = process.env.KIMIFLARE_WORKER_API_KEY ?? cfg?.workerApiKey;
|
|
8951
8951
|
const defaultModel = cfg?.model ?? DEFAULT_MODEL;
|
|
8952
8952
|
const workerModel = args.model ?? ctx.model ?? defaultModel;
|
|
8953
8953
|
if (cfg && usesRequesty(llmAuthFromConfig(cfg)) && !workerModel.includes("/")) {
|
|
@@ -11510,13 +11510,13 @@ function directiveFor(kind) {
|
|
|
11510
11510
|
return "The user explicitly asked not to delegate. Do not call spawn_worker; handle the task in the main session and respect any stated dependencies.";
|
|
11511
11511
|
}
|
|
11512
11512
|
if (kind === "explicit-delegate") {
|
|
11513
|
-
return "The user explicitly requested subagents.
|
|
11513
|
+
return "The user explicitly requested subagents. Before acting, split the request into bounded missions that can make progress independently; use spawn_worker in plan mode for useful parallel read-only research, wait for the workers, and synthesize their findings before dependent implementation. Do not delegate tightly coupled or sequential steps. The tool's normal permission prompt and all configured safety limits still apply.";
|
|
11514
11514
|
}
|
|
11515
11515
|
if (kind === "suggest") {
|
|
11516
11516
|
return "The harness sees a possible parallel-work opportunity, but the user did not request delegation. Use spawn_worker only if you can define bounded, independent missions that materially help. The tool's normal permission prompt is the required user confirmation; never assume approval. Keep dependent implementation in the coordinator.";
|
|
11517
11517
|
}
|
|
11518
11518
|
if (kind === "auto-delegate") {
|
|
11519
|
-
return "
|
|
11519
|
+
return "Proactive subagent delegation is enabled for this substantial task. First assess its structure, dependencies, and coordination cost. If two or more bounded research tracks can make meaningful progress independently, delegate them with spawn_worker in plan mode in parallel, wait for their results, and synthesize the findings before doing dependent work in the coordinator. Keep trivial, tightly coupled, and sequential work local. Worker calls still require the normal permission approval and remain subject to the configured provider/backend, spend cap, concurrency, timeout, and read-only restrictions; never bypass them. If a worker cannot run or fails, explain that plainly and continue locally without implying delegation succeeded.";
|
|
11520
11520
|
}
|
|
11521
11521
|
return void 0;
|
|
11522
11522
|
}
|
|
@@ -11539,6 +11539,9 @@ async function resolveSubagentGuidance(options) {
|
|
|
11539
11539
|
return result(options.policy === "auto" ? "auto-delegate" : "suggest", "independent work is explicit");
|
|
11540
11540
|
}
|
|
11541
11541
|
if (options.tier === "light") return result("none", "routine or sequential task");
|
|
11542
|
+
if (options.policy === "auto") {
|
|
11543
|
+
return result("auto-delegate", "substantial task; coordinator assesses independence");
|
|
11544
|
+
}
|
|
11542
11545
|
if (!AMBIGUOUS_CANDIDATE.test(prompt)) return result("none", "no parallel-work signal");
|
|
11543
11546
|
if (!options.apiKey || options.customEndpoint) return result("none", "Jev is unavailable for this provider configuration");
|
|
11544
11547
|
if (options.signal?.aborted) return result("none", "turn cancelled before Jev advice");
|
|
@@ -11561,9 +11564,6 @@ async function resolveSubagentGuidance(options) {
|
|
|
11561
11564
|
if (probability === void 0 || !Number.isFinite(probability) || probability < 0 || probability > 1) {
|
|
11562
11565
|
return result("none", "Jev returned no usable delegation probability");
|
|
11563
11566
|
}
|
|
11564
|
-
if (options.policy === "auto" && probability >= AUTO_THRESHOLD) {
|
|
11565
|
-
return result("auto-delegate", "Jev recommends independent work", probability);
|
|
11566
|
-
}
|
|
11567
11567
|
if (probability >= SUGGEST_THRESHOLD) return result("suggest", "Jev sees a possible parallel-work benefit", probability);
|
|
11568
11568
|
return result("none", "Jev recommends sequential work", probability);
|
|
11569
11569
|
} catch {
|
|
@@ -11573,7 +11573,7 @@ async function resolveSubagentGuidance(options) {
|
|
|
11573
11573
|
function redactPrompt(prompt) {
|
|
11574
11574
|
return prompt.replace(/\b(?:sk-or-v1-|sk-ant-|gh[pousr]_|github_pat_)[A-Za-z0-9_-]{8,}\b/gi, "[REDACTED]").replace(/\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi, "Bearer [REDACTED]").replace(/\b[A-Z0-9_]*(?:API[_-]?KEY|ACCESS[_-]?TOKEN|SECRET|PASSWORD)\s*[:=]\s*[^\s,;]+/gi, "[REDACTED]");
|
|
11575
11575
|
}
|
|
11576
|
-
var EXPLICIT_NO, EXPLICIT_YES, SEQUENTIAL_DEPENDENCY, CLEAR_PARALLEL, AMBIGUOUS_CANDIDATE, SUBAGENT_JEV_TIMEOUT_MS, SUBAGENT_JEV_OPTIONS, SUGGEST_THRESHOLD,
|
|
11576
|
+
var EXPLICIT_NO, EXPLICIT_YES, SEQUENTIAL_DEPENDENCY, CLEAR_PARALLEL, AMBIGUOUS_CANDIDATE, SUBAGENT_JEV_TIMEOUT_MS, SUBAGENT_JEV_OPTIONS, SUGGEST_THRESHOLD, MAX_JEV_PROMPT_CHARS;
|
|
11577
11577
|
var init_subagent_policy = __esm({
|
|
11578
11578
|
"src/intent/subagent-policy.ts"() {
|
|
11579
11579
|
"use strict";
|
|
@@ -11586,7 +11586,6 @@ var init_subagent_policy = __esm({
|
|
|
11586
11586
|
SUBAGENT_JEV_TIMEOUT_MS = Math.min(JEV_TIMEOUT_MS, 4e3);
|
|
11587
11587
|
SUBAGENT_JEV_OPTIONS = ["delegate", "sequential"];
|
|
11588
11588
|
SUGGEST_THRESHOLD = 0.65;
|
|
11589
|
-
AUTO_THRESHOLD = 0.8;
|
|
11590
11589
|
MAX_JEV_PROMPT_CHARS = 1200;
|
|
11591
11590
|
}
|
|
11592
11591
|
});
|
|
@@ -18731,12 +18730,11 @@ var init_builtins = __esm({
|
|
|
18731
18730
|
{ name: "help", description: "Show keybindings and command list", source: "builtin" },
|
|
18732
18731
|
{ name: "model", argHint: "[list|<id>]", description: "Pick model (no args opens picker)", source: "builtin" },
|
|
18733
18732
|
{ name: "jev", argHint: "[yes|choose|score]", description: "Ask Jev for a one-shot decision with scoped chat/project context", source: "builtin" },
|
|
18734
|
-
{ name: "subagents", argHint: "[off|suggest|auto]", description: "
|
|
18733
|
+
{ name: "subagents", argHint: "[off|suggest|auto]", description: "Control proactive delegation for substantial independent work", source: "builtin" },
|
|
18735
18734
|
{ name: "mode", argHint: "[edit|plan|auto]", description: "Switch agent mode", source: "builtin" },
|
|
18736
18735
|
{ name: "multi-agent", argHint: "[enable|disable|status|setup]", description: "Configure multi-agent (endpoint, auto-implement, set up)", source: "builtin" },
|
|
18737
18736
|
{ name: "theme", argHint: "[<name>]", description: "Switch color theme", source: "builtin" },
|
|
18738
18737
|
// Ink is the only UI engine; handler remains for manual use.
|
|
18739
|
-
{ name: "ui", argHint: "[ink|camouflage]", description: "Switch between the Ink and Camouflage UIs (takes effect on next launch)", source: "builtin" },
|
|
18740
18738
|
{ name: "memory", argHint: "[on|off|clear|search ...]", description: "Manage memory", source: "builtin" },
|
|
18741
18739
|
{ name: "cost", argHint: "[verify|on|off]", description: "Show cost report or toggle attribution", source: "builtin" },
|
|
18742
18740
|
{ name: "settings", argHint: "[modes on|off]", description: "Show or change feature settings (e.g. plan/edit/auto modes)", source: "builtin" },
|
|
@@ -19201,7 +19199,11 @@ var init_help_menu = __esm({
|
|
|
19201
19199
|
{ command: "/settings modes off", description: "turn modes off (always auto)" },
|
|
19202
19200
|
{ command: "/mode edit", description: "switch to edit mode" },
|
|
19203
19201
|
{ command: "/mode plan", description: "switch to plan mode" },
|
|
19204
|
-
{ command: "/mode auto", description: "switch to auto mode" }
|
|
19202
|
+
{ command: "/mode auto", description: "switch to auto mode" },
|
|
19203
|
+
{ command: "/subagents", description: "show delegation policy and backend setup" },
|
|
19204
|
+
{ command: "/subagents auto", description: "let the coordinator assess substantial tasks (default)" },
|
|
19205
|
+
{ command: "/subagents suggest", description: "use conservative delegation suggestions" },
|
|
19206
|
+
{ command: "/subagents off", description: "disable automatic delegation suggestions" }
|
|
19205
19207
|
]
|
|
19206
19208
|
},
|
|
19207
19209
|
{
|
|
@@ -22253,6 +22255,7 @@ var init_hooks_wizard = __esm({
|
|
|
22253
22255
|
// src/camouflage-view.ts
|
|
22254
22256
|
var camouflage_view_exports = {};
|
|
22255
22257
|
__export(camouflage_view_exports, {
|
|
22258
|
+
CamouflageUnavailable: () => CamouflageUnavailable,
|
|
22256
22259
|
helpOptions: () => helpOptions,
|
|
22257
22260
|
listMentionDir: () => listMentionDir,
|
|
22258
22261
|
modelOptions: () => modelOptions,
|
|
@@ -22267,29 +22270,35 @@ import { homedir as homedir22 } from "os";
|
|
|
22267
22270
|
import { join as join33, resolve as resolve11 } from "path";
|
|
22268
22271
|
async function loadSdk() {
|
|
22269
22272
|
const sdk = await import("camouflage-tui").catch((err) => {
|
|
22270
|
-
throw new
|
|
22273
|
+
throw new CamouflageUnavailable(`camouflage-tui is not installed (${err.message})`);
|
|
22271
22274
|
});
|
|
22272
22275
|
if (typeof sdk.permission !== "function" || typeof sdk.mount !== "function" || typeof sdk.selectList !== "function") {
|
|
22273
|
-
throw new
|
|
22276
|
+
throw new CamouflageUnavailable("the installed camouflage-tui is too old");
|
|
22274
22277
|
}
|
|
22275
22278
|
return sdk;
|
|
22276
22279
|
}
|
|
22277
22280
|
async function runCamouflageView(opts2) {
|
|
22278
22281
|
const sdk = await loadSdk();
|
|
22279
22282
|
const restoreConsole = captureConsole();
|
|
22280
|
-
|
|
22281
|
-
|
|
22282
|
-
|
|
22283
|
-
|
|
22284
|
-
|
|
22285
|
-
|
|
22283
|
+
let cam;
|
|
22284
|
+
try {
|
|
22285
|
+
cam = await sdk.mount({
|
|
22286
|
+
ui: "inline",
|
|
22287
|
+
appTitle: "autopilot",
|
|
22288
|
+
inheritStderr: false,
|
|
22289
|
+
...process.env.CAMOUFLAGE_BIN ? { bin: process.env.CAMOUFLAGE_BIN } : {}
|
|
22290
|
+
});
|
|
22291
|
+
} catch (err) {
|
|
22292
|
+
restoreConsole();
|
|
22293
|
+
throw new CamouflageUnavailable(err.message);
|
|
22294
|
+
}
|
|
22286
22295
|
cam.on("stderr", (chunk) => logger.warn("camouflage.stderr", { chunk }));
|
|
22287
22296
|
const cwd = process.cwd();
|
|
22288
22297
|
cam.send("SessionStarted", {
|
|
22289
22298
|
title: `autopilot ${opts2.version}`,
|
|
22290
22299
|
detail: [
|
|
22291
22300
|
[shortModel(opts2.cfg.model), shortPath(cwd), gitBranch(cwd)].filter(Boolean).join(" \xB7 "),
|
|
22292
|
-
|
|
22301
|
+
`/ for commands \xB7 @ to mention files${opts2.cfg.modesEnabled ? " \xB7 shift+tab to switch modes" : ""}`
|
|
22293
22302
|
],
|
|
22294
22303
|
accent: "orange",
|
|
22295
22304
|
assistant_label: "autopilot"
|
|
@@ -22517,7 +22526,7 @@ function safeString(v) {
|
|
|
22517
22526
|
return String(v);
|
|
22518
22527
|
}
|
|
22519
22528
|
}
|
|
22520
|
-
var View;
|
|
22529
|
+
var CamouflageUnavailable, View;
|
|
22521
22530
|
var init_camouflage_view = __esm({
|
|
22522
22531
|
"src/camouflage-view.ts"() {
|
|
22523
22532
|
"use strict";
|
|
@@ -22536,6 +22545,8 @@ var init_camouflage_view = __esm({
|
|
|
22536
22545
|
init_hooks_wizard();
|
|
22537
22546
|
init_mode();
|
|
22538
22547
|
init_logger();
|
|
22548
|
+
CamouflageUnavailable = class extends Error {
|
|
22549
|
+
};
|
|
22539
22550
|
View = class {
|
|
22540
22551
|
constructor(cam, sdk) {
|
|
22541
22552
|
this.cam = cam;
|
|
@@ -22680,7 +22691,8 @@ var init_camouflage_view = __esm({
|
|
|
22680
22691
|
}
|
|
22681
22692
|
syncStatus(s) {
|
|
22682
22693
|
const next = {
|
|
22683
|
-
|
|
22694
|
+
// With modes off (the default) every turn is auto; show no mode badge.
|
|
22695
|
+
mode: !s.modesEnabled ? "" : s.mode === "auto" ? "auto" : s.mode === "plan" ? "plan" : "edit",
|
|
22684
22696
|
phase: s.busy ? "thinking" : "idle",
|
|
22685
22697
|
model: shortModel(s.model),
|
|
22686
22698
|
tokens: s.usage ? `${formatK2(s.usage.prompt_tokens)} tokens` : "",
|
|
@@ -22907,7 +22919,7 @@ var init_camouflage_view = __esm({
|
|
|
22907
22919
|
return want(`commandWizard-${s.commandWizard.mode}-${s.commandWizard.initial?.name ?? ""}`, () => this.commandEditor(s));
|
|
22908
22920
|
default:
|
|
22909
22921
|
this.cam.send("RuntimeError", {
|
|
22910
|
-
message: `${modalName(modal)} isn't available
|
|
22922
|
+
message: `${modalName(modal)} isn't available here yet.`,
|
|
22911
22923
|
severity: "warn"
|
|
22912
22924
|
});
|
|
22913
22925
|
a.closeModal(modal);
|
|
@@ -26397,7 +26409,7 @@ function Welcome() {
|
|
|
26397
26409
|
});
|
|
26398
26410
|
return /* @__PURE__ */ jsxs21(Box22, { flexDirection: "column", marginBottom: 1, children: [
|
|
26399
26411
|
/* @__PURE__ */ jsx24(Box22, { marginBottom: 1, children: /* @__PURE__ */ jsx24(Text23, { bold: true, color: theme.accent, children: headline }) }),
|
|
26400
|
-
/* @__PURE__ */ jsx24(Box22, { flexDirection: "column", children: /* @__PURE__ */ jsx24(Text23, { color: theme.info.color, dimColor: true, children: "Type / for commands" }) })
|
|
26412
|
+
/* @__PURE__ */ jsx24(Box22, { flexDirection: "column", children: /* @__PURE__ */ jsx24(Text23, { color: theme.info.color, dimColor: true, children: "Type / for commands \xB7 try /subagents help" }) })
|
|
26401
26413
|
] });
|
|
26402
26414
|
}
|
|
26403
26415
|
var init_welcome = __esm({
|
|
@@ -31697,7 +31709,7 @@ function dispatchSlashCommand(ctx, cmd) {
|
|
|
31697
31709
|
if (!handler) return false;
|
|
31698
31710
|
return handler(ctx, rest, arg);
|
|
31699
31711
|
}
|
|
31700
|
-
var handleExit, handleClear, handleFresh, handleReasoning, handleCost, handleShell, handleSubagents, handleJev, handleModel, SETTINGS, handleSettings, handleKey, handleMode, handleMultiAgent, handleTheme,
|
|
31712
|
+
var handleExit, handleClear, handleFresh, handleReasoning, handleCost, handleShell, handleSubagents, handleJev, handleModel, SETTINGS, handleSettings, handleKey, handleMode, handleMultiAgent, handleTheme, handlePlan, handleAuto, handleEdit, handleSkills, handleMemory, handleResume, handleCheckpoint, handleCompact, handleInit, handleUpdate, handleMcp, handleLsp, handleHooks, handleHello, handleInbox, handleLogout, handleCommand, handleRemote, handleHelp, handleChangelogImage, handlers;
|
|
31701
31713
|
var init_slash_commands = __esm({
|
|
31702
31714
|
"src/ui/slash-commands.ts"() {
|
|
31703
31715
|
"use strict";
|
|
@@ -31928,10 +31940,10 @@ var init_slash_commands = __esm({
|
|
|
31928
31940
|
setEvents((events) => [...events, {
|
|
31929
31941
|
kind: "info",
|
|
31930
31942
|
key: mkKey2(),
|
|
31931
|
-
text: `subagent policy: ${cfg?.subagentPolicy ?? "
|
|
31943
|
+
text: `subagent policy: ${cfg?.subagentPolicy ?? "auto"}
|
|
31932
31944
|
usage: /subagents off|suggest|auto
|
|
31933
31945
|
|
|
31934
|
-
|
|
31946
|
+
auto (default) lets the coordinator assess substantial tasks and delegate independent work; it is conditional, not a promise to spawn. suggest surfaces possible opportunities; off disables automatic suggestions. Explicit user instructions still win. Worker calls use normal permission checks and respect spend, concurrency, timeout, and read-only limits. Remote setup: KIMIFLARE_WORKER_ENDPOINT (or workerEndpoint in config). Hotcell: KIMIFLARE_WORKER_BACKEND=hotcell; plan mode only.`
|
|
31935
31947
|
}]);
|
|
31936
31948
|
return true;
|
|
31937
31949
|
}
|
|
@@ -31947,7 +31959,7 @@ off disables harness suggestions; suggest (default) asks before any worker call;
|
|
|
31947
31959
|
setEvents((events) => [...events, { kind: "error", key: mkKey2(), text: "configure an OpenRouter key or custom endpoint before changing subagent policy" }]);
|
|
31948
31960
|
return true;
|
|
31949
31961
|
}
|
|
31950
|
-
const next = { ...cfg, subagentPolicy: policy };
|
|
31962
|
+
const next = { ...cfg, subagentPolicy: policy, subagentPolicyExplicit: true };
|
|
31951
31963
|
setCfg(next);
|
|
31952
31964
|
void saveConfig(next).catch(() => {
|
|
31953
31965
|
});
|
|
@@ -32330,28 +32342,6 @@ off disables harness suggestions; suggest (default) asks before any worker call;
|
|
|
32330
32342
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: `theme: ${next.label} \u2014 restart to apply` }]);
|
|
32331
32343
|
return true;
|
|
32332
32344
|
};
|
|
32333
|
-
handleUi = (ctx, _rest, arg) => {
|
|
32334
|
-
const { setEvents, mkKey: mkKey2 } = ctx;
|
|
32335
|
-
const say = (text, kind = "info") => setEvents((e) => [...e, { kind, key: mkKey2(), text }]);
|
|
32336
|
-
if (!arg) {
|
|
32337
|
-
const current = ctx.cfg?.uiEngine ?? "ink";
|
|
32338
|
-
say(`UI: ${current}. Use /ui ink or /ui camouflage (takes effect next launch; --ui overrides for one run).`);
|
|
32339
|
-
return true;
|
|
32340
|
-
}
|
|
32341
|
-
if (arg !== "ink" && arg !== "camouflage") {
|
|
32342
|
-
say(`unknown UI "${arg}" \u2014 use ink or camouflage`, "error");
|
|
32343
|
-
return true;
|
|
32344
|
-
}
|
|
32345
|
-
ctx.setCfg((prev) => {
|
|
32346
|
-
if (!prev) return prev;
|
|
32347
|
-
const updated = { ...prev, uiEngine: arg };
|
|
32348
|
-
void saveConfig(updated).catch(() => {
|
|
32349
|
-
});
|
|
32350
|
-
return updated;
|
|
32351
|
-
});
|
|
32352
|
-
say(`UI set to ${arg}. It takes effect the next time you start autopilot.`);
|
|
32353
|
-
return true;
|
|
32354
|
-
};
|
|
32355
32345
|
handlePlan = (ctx) => {
|
|
32356
32346
|
if (!modesGate(ctx)) return true;
|
|
32357
32347
|
ctx.setMode("plan");
|
|
@@ -33224,7 +33214,6 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
33224
33214
|
"/mode": handleMode,
|
|
33225
33215
|
"/multi-agent": handleMultiAgent,
|
|
33226
33216
|
"/theme": handleTheme,
|
|
33227
|
-
"/ui": handleUi,
|
|
33228
33217
|
"/plan": handlePlan,
|
|
33229
33218
|
"/auto": handleAuto,
|
|
33230
33219
|
"/edit": handleEdit,
|
|
@@ -36559,14 +36548,14 @@ ${conflicts.join("\n")}` }
|
|
|
36559
36548
|
const delegationGuidance = await resolveSubagentGuidance({
|
|
36560
36549
|
prompt: display,
|
|
36561
36550
|
tier: classification.tier,
|
|
36562
|
-
policy: cfg.subagentPolicy ?? "
|
|
36551
|
+
policy: cfg.subagentPolicy ?? "auto",
|
|
36563
36552
|
apiKey: cfg.openrouterApiKey,
|
|
36564
36553
|
customEndpoint: Boolean(cfg.baseUrl),
|
|
36565
36554
|
signal: turnScope.signal
|
|
36566
36555
|
});
|
|
36567
36556
|
if (delegationGuidance.kind !== "none") {
|
|
36568
36557
|
const probability = delegationGuidance.probability === void 0 ? "" : ` (Jev estimate: ${Math.round(delegationGuidance.probability * 100)}%)`;
|
|
36569
|
-
const text2 = delegationGuidance.kind === "explicit-delegate" ? "Subagent policy: respecting your explicit request to delegate. Worker calls still require permission." : delegationGuidance.kind === "explicit-sequential" ? "Subagent policy: respecting your instruction to work without delegation." : delegationGuidance.kind === "auto-delegate" ?
|
|
36558
|
+
const text2 = delegationGuidance.kind === "explicit-delegate" ? "Subagent policy: respecting your explicit request to delegate. Worker calls still require permission." : delegationGuidance.kind === "explicit-sequential" ? "Subagent policy: respecting your instruction to work without delegation." : delegationGuidance.kind === "auto-delegate" ? "Subagent policy: auto will assess this substantial task for independent work; worker calls remain permission-gated." : `Subagent suggestion: independent work may help${probability}. No worker will launch without your confirmation.`;
|
|
36570
36559
|
setEvents((events2) => [...events2, { kind: "info", key: mkKey(), text: text2 }]);
|
|
36571
36560
|
}
|
|
36572
36561
|
const turnTools = [...ALL_TOOLS, ...mcpToolsRef.current, ...lspToolsRef.current].filter(
|
|
@@ -37200,6 +37189,7 @@ ${conflicts.join("\n")}` }
|
|
|
37200
37189
|
commandWizard: modals.commandWizard,
|
|
37201
37190
|
commandPickerMode: modals.commandPicker?.mode ?? null,
|
|
37202
37191
|
changelogImageRepo,
|
|
37192
|
+
modesEnabled,
|
|
37203
37193
|
multiAgent: {
|
|
37204
37194
|
multiAgentEnabled: cfg?.multiAgentEnabled,
|
|
37205
37195
|
workerEndpoint: cfg?.workerEndpoint,
|
|
@@ -37609,6 +37599,7 @@ var init_app = __esm({
|
|
|
37609
37599
|
});
|
|
37610
37600
|
|
|
37611
37601
|
// src/index.tsx
|
|
37602
|
+
init_logger();
|
|
37612
37603
|
init_config();
|
|
37613
37604
|
init_lsp_config();
|
|
37614
37605
|
init_update_check();
|
|
@@ -37856,7 +37847,7 @@ async function runPrintMode(opts2) {
|
|
|
37856
37847
|
const delegationGuidance = await resolveSubagentGuidance({
|
|
37857
37848
|
prompt: opts2.prompt,
|
|
37858
37849
|
tier: intent.tier,
|
|
37859
|
-
policy: opts2.subagentPolicy ?? "
|
|
37850
|
+
policy: opts2.subagentPolicy ?? "auto",
|
|
37860
37851
|
apiKey: opts2.openrouterApiKey,
|
|
37861
37852
|
customEndpoint: Boolean(opts2.baseUrl)
|
|
37862
37853
|
});
|
|
@@ -38089,7 +38080,7 @@ async function runPrintMode(opts2) {
|
|
|
38089
38080
|
|
|
38090
38081
|
// src/index.tsx
|
|
38091
38082
|
var program = new Command2();
|
|
38092
|
-
program.name("autopilot").description("Terminal coding agent. Runs any OpenRouter model with your own OpenRouter key.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", `OpenRouter model id (defaults to ${DEFAULT_MODEL})`).addOption(new Option("--cloud", "(retired) KimiFlare Cloud").hideHelp()).option("--dangerously-allow-all", "auto-approve every permission prompt (print mode only)").addOption(new Option("--worker-profile <profile>", "internal worker permission profile").hideHelp()).option("--reasoning", "include reasoning in stdout (print mode only)").option("--thinking", "alias for --reasoning").option("--continue-on-limit", "reset tool-call counter and continue when the 200-call limit is hit (print mode only)").option("--max-total-tool-iterations <n>", "hard ceiling on tool iterations per turn across --continue-on-limit resets (default 1000)", (v) => parseInt(v, 10)).option("--max-input-tokens <n>", "cumulative prompt token budget; exits 42 when exhausted (print mode only)", (v) => parseInt(v, 10)).option("--emit-events", "emit Camouflage NDJSON events to stdout; requires -p (for initial prompt)").option("--multi-turn", "with --emit-events: keep reading stdin for UserInputSubmitted follow-ups after the initial turn").
|
|
38083
|
+
program.name("autopilot").description("Terminal coding agent. Runs any OpenRouter model with your own OpenRouter key.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", `OpenRouter model id (defaults to ${DEFAULT_MODEL})`).addOption(new Option("--cloud", "(retired) KimiFlare Cloud").hideHelp()).option("--dangerously-allow-all", "auto-approve every permission prompt (print mode only)").addOption(new Option("--worker-profile <profile>", "internal worker permission profile").hideHelp()).option("--reasoning", "include reasoning in stdout (print mode only)").option("--thinking", "alias for --reasoning").option("--continue-on-limit", "reset tool-call counter and continue when the 200-call limit is hit (print mode only)").option("--max-total-tool-iterations <n>", "hard ceiling on tool iterations per turn across --continue-on-limit resets (default 1000)", (v) => parseInt(v, 10)).option("--max-input-tokens <n>", "cumulative prompt token budget; exits 42 when exhausted (print mode only)", (v) => parseInt(v, 10)).option("--emit-events", "emit Camouflage NDJSON events to stdout; requires -p (for initial prompt)").option("--multi-turn", "with --emit-events: keep reading stdin for UserInputSubmitted follow-ups after the initial turn").addOption(new Option("--ui <name>", "interface: camouflage (default) or ink").hideHelp()).option("--mode <mode>", "run mode: interactive (default), print, rpc").option("-c, --continue", "continue the most recent session in the current working directory (print mode only)").option("-S, --session <id>", "resume a specific session by id (print mode only)").option("-f, --file <path>", "attach file(s) to the prompt; repeatable, supports globs (print mode only)", (v, prev) => (prev ?? []).concat(v)).option("--format <mode>", "output format for print mode: text (default), json, stream-json").option("--dir <path>", "run in the specified directory instead of the current one (print mode only)").option("--title <title>", "override the auto-generated session title (print mode only)").option("--attach <url>", "attach to a running autopilot serve instance (print mode only)");
|
|
38093
38084
|
program.command("cost").description("Show cost attribution by task type (requires costAttribution enabled)").option("-w, --week", "last 7 days (default)").option("-m, --month", "last 30 days").option("-d, --day", "today only").option("-s, --session <id>", "single session detail").option("-c, --category <name>", "filter by category").option("--json", "machine-readable output").option("--reclassify", "re-run classification on all sessions").option("--local-only", "skip OpenRouter reconciliation (no network)").option("--verify", "check recorded tokens and cost against OpenRouter's generation records (latest session, or -s <id>)").action(async (cmdOpts) => {
|
|
38094
38085
|
const cfg = await loadConfig();
|
|
38095
38086
|
if (cmdOpts.verify) {
|
|
@@ -38348,22 +38339,22 @@ To use Requesty instead, set REQUESTY_API_KEY or run autopilot auth requesty`
|
|
|
38348
38339
|
process.exit(2);
|
|
38349
38340
|
}
|
|
38350
38341
|
const logoText = renderLogo(getAppVersion(), opts.model ?? cfg?.model);
|
|
38351
|
-
const uiEngine = (opts.ui ?? process.env.KIMIFLARE_UI ??
|
|
38352
|
-
if (uiEngine
|
|
38342
|
+
const uiEngine = (opts.ui ?? process.env.KIMIFLARE_UI ?? "camouflage").toLowerCase();
|
|
38343
|
+
if (uiEngine !== "ink" && cfg) {
|
|
38353
38344
|
const model = opts.model ?? cfg.model ?? DEFAULT_MODEL;
|
|
38354
|
-
const { runCamouflageView: runCamouflageView2 } = await Promise.resolve().then(() => (init_camouflage_view(), camouflage_view_exports));
|
|
38345
|
+
const { runCamouflageView: runCamouflageView2, CamouflageUnavailable: CamouflageUnavailable2 } = await Promise.resolve().then(() => (init_camouflage_view(), camouflage_view_exports));
|
|
38355
38346
|
const { renderAppWithBridge: renderAppWithBridge2 } = await Promise.resolve().then(() => (init_app(), app_exports));
|
|
38356
|
-
|
|
38357
|
-
|
|
38358
|
-
|
|
38359
|
-
|
|
38360
|
-
|
|
38361
|
-
|
|
38362
|
-
|
|
38363
|
-
|
|
38364
|
-
|
|
38365
|
-
|
|
38366
|
-
|
|
38347
|
+
try {
|
|
38348
|
+
await runCamouflageView2({
|
|
38349
|
+
cfg: { ...cfg, model },
|
|
38350
|
+
version: getAppVersion(),
|
|
38351
|
+
runApp: (bridge) => renderAppWithBridge2({ ...cfg, model }, bridge, updateResult, lspScope, lspProjectPath)
|
|
38352
|
+
});
|
|
38353
|
+
process.exit(0);
|
|
38354
|
+
} catch (err) {
|
|
38355
|
+
if (!(err instanceof CamouflageUnavailable2)) throw err;
|
|
38356
|
+
logger.warn("camouflage.unavailable", { error: err.message });
|
|
38357
|
+
}
|
|
38367
38358
|
}
|
|
38368
38359
|
console.log(logoText);
|
|
38369
38360
|
const { renderApp: renderApp2 } = await Promise.resolve().then(() => (init_app(), app_exports));
|