autopilot-ai 2.1.0 → 2.3.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 +27 -3
- package/dist/index.js +1523 -436
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.d.ts +16 -1
- package/dist/sdk/index.js +323 -70
- package/dist/sdk/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -75,8 +75,8 @@ async function flushAndCloseForTesting() {
|
|
|
75
75
|
const s = currentStream;
|
|
76
76
|
currentStream = null;
|
|
77
77
|
currentDate = null;
|
|
78
|
-
await new Promise((
|
|
79
|
-
s.end(() =>
|
|
78
|
+
await new Promise((resolve22) => {
|
|
79
|
+
s.end(() => resolve22());
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
function isLogSinkEnabled() {
|
|
@@ -1067,10 +1067,10 @@ async function tokenFromFile(file, fetchImpl2, now2) {
|
|
|
1067
1067
|
return { token: t.access_token, expiresAt: now2 + (t.expires_in ?? 3600) * 1e3 };
|
|
1068
1068
|
}
|
|
1069
1069
|
function gcloudToken() {
|
|
1070
|
-
return new Promise((
|
|
1070
|
+
return new Promise((resolve22, reject) => {
|
|
1071
1071
|
execFile("gcloud", ["auth", "print-access-token"], { timeout: 15e3 }, (err, stdout) => {
|
|
1072
1072
|
if (err) reject(new Error("No Google credentials found. Run `gcloud auth application-default login`, or set GOOGLE_APPLICATION_CREDENTIALS."));
|
|
1073
|
-
else
|
|
1073
|
+
else resolve22(stdout.trim());
|
|
1074
1074
|
});
|
|
1075
1075
|
});
|
|
1076
1076
|
}
|
|
@@ -2322,8 +2322,8 @@ function onShutdown(name, task, phase = SHUTDOWN_PHASE.sessions) {
|
|
|
2322
2322
|
}
|
|
2323
2323
|
function withDeadline(work, ms) {
|
|
2324
2324
|
let timer2;
|
|
2325
|
-
const deadline = new Promise((
|
|
2326
|
-
timer2 = setTimeout(() =>
|
|
2325
|
+
const deadline = new Promise((resolve22) => {
|
|
2326
|
+
timer2 = setTimeout(() => resolve22("timeout"), Math.max(0, ms));
|
|
2327
2327
|
});
|
|
2328
2328
|
return Promise.race([work, deadline]).finally(() => clearTimeout(timer2));
|
|
2329
2329
|
}
|
|
@@ -3782,8 +3782,8 @@ var init_copilot = __esm({
|
|
|
3782
3782
|
COPILOT_API_VERSION = "2026-08-01";
|
|
3783
3783
|
USER_API_VERSION = "2025-04-01";
|
|
3784
3784
|
COPILOT_DEFAULT_BASE = "https://api.githubcopilot.com";
|
|
3785
|
-
sleep = (ms, signal) => new Promise((
|
|
3786
|
-
const t = setTimeout(
|
|
3785
|
+
sleep = (ms, signal) => new Promise((resolve22, reject) => {
|
|
3786
|
+
const t = setTimeout(resolve22, ms);
|
|
3787
3787
|
signal?.addEventListener("abort", () => {
|
|
3788
3788
|
clearTimeout(t);
|
|
3789
3789
|
reject(new DOMException("aborted", "AbortError"));
|
|
@@ -3874,10 +3874,10 @@ async function startChatGPTSignIn(opts2) {
|
|
|
3874
3874
|
const { verifier, challenge } = pkce();
|
|
3875
3875
|
const state = randomBytes(32).toString("base64url");
|
|
3876
3876
|
const nonce = randomBytes(32).toString("base64url");
|
|
3877
|
-
let
|
|
3877
|
+
let resolve22;
|
|
3878
3878
|
let reject;
|
|
3879
3879
|
const done = new Promise((res, rej) => {
|
|
3880
|
-
|
|
3880
|
+
resolve22 = res;
|
|
3881
3881
|
reject = rej;
|
|
3882
3882
|
});
|
|
3883
3883
|
done.catch(() => void 0);
|
|
@@ -3900,7 +3900,7 @@ async function startChatGPTSignIn(opts2) {
|
|
|
3900
3900
|
}
|
|
3901
3901
|
if (!clientId) return finish("No client id returned"), reject(new Error("ChatGPT sign-in did not return a client id. Try again."));
|
|
3902
3902
|
completeSignIn(code, clientId, redirect, verifier, nonce, opts2.fetchImpl).then(
|
|
3903
|
-
(s) => (finish(),
|
|
3903
|
+
(s) => (finish(), resolve22(s)),
|
|
3904
3904
|
(e) => (finish(e.message), reject(e))
|
|
3905
3905
|
);
|
|
3906
3906
|
});
|
|
@@ -4608,8 +4608,8 @@ async function* runKimi(opts2) {
|
|
|
4608
4608
|
if (isAbortError(fetchErr)) throw fetchErr;
|
|
4609
4609
|
logger.warn("runKimi:fetch_error", { requestId, attempt, error: msg });
|
|
4610
4610
|
if (attempt < MAX_ATTEMPTS - 1) {
|
|
4611
|
-
const
|
|
4612
|
-
await sleep2(
|
|
4611
|
+
const delay2 = Math.random() * (500 * 2 ** attempt);
|
|
4612
|
+
await sleep2(delay2, opts2.signal);
|
|
4613
4613
|
continue;
|
|
4614
4614
|
}
|
|
4615
4615
|
const local = customEndpoint?.providerId && !preset.keyRequired;
|
|
@@ -4652,9 +4652,9 @@ Is ${preset.name} running at ${customEndpoint.baseUrl}? Start it, or set provide
|
|
|
4652
4652
|
const isRateLimit = apiErr.httpStatus === 429;
|
|
4653
4653
|
const baseDelay = isRateLimit ? 2e3 : 500;
|
|
4654
4654
|
const retryAfterSec = Number(res.headers.get("retry-after"));
|
|
4655
|
-
const
|
|
4656
|
-
logger.warn("runKimi:retrying", { requestId, attempt, code: apiErr.code, httpStatus: apiErr.httpStatus, delay });
|
|
4657
|
-
await sleep2(
|
|
4655
|
+
const delay2 = Number.isFinite(retryAfterSec) && retryAfterSec > 0 ? Math.min(retryAfterSec * 1e3, 3e4) : Math.random() * (baseDelay * 2 ** attempt);
|
|
4656
|
+
logger.warn("runKimi:retrying", { requestId, attempt, code: apiErr.code, httpStatus: apiErr.httpStatus, delay: delay2 });
|
|
4657
|
+
await sleep2(delay2, opts2.signal);
|
|
4658
4658
|
continue;
|
|
4659
4659
|
}
|
|
4660
4660
|
throw apiErr;
|
|
@@ -5106,11 +5106,11 @@ function extractApiError(parsed, rawText) {
|
|
|
5106
5106
|
return null;
|
|
5107
5107
|
}
|
|
5108
5108
|
function sleep2(ms, signal) {
|
|
5109
|
-
return new Promise((
|
|
5109
|
+
return new Promise((resolve22, reject) => {
|
|
5110
5110
|
if (signal?.aborted) return reject(new DOMException("aborted", "AbortError"));
|
|
5111
5111
|
const t = setTimeout(() => {
|
|
5112
5112
|
signal?.removeEventListener("abort", onAbort);
|
|
5113
|
-
|
|
5113
|
+
resolve22();
|
|
5114
5114
|
}, ms);
|
|
5115
5115
|
const onAbort = () => {
|
|
5116
5116
|
clearTimeout(t);
|
|
@@ -5260,7 +5260,7 @@ var init_worker_registry = __esm({
|
|
|
5260
5260
|
delivered: false
|
|
5261
5261
|
};
|
|
5262
5262
|
if (done.background) this.finished.set(info.id, done);
|
|
5263
|
-
for (const
|
|
5263
|
+
for (const resolve22 of this.waiters.get(info.id) ?? []) resolve22(done);
|
|
5264
5264
|
this.waiters.delete(info.id);
|
|
5265
5265
|
for (const l of this.finishListeners) {
|
|
5266
5266
|
try {
|
|
@@ -5292,14 +5292,14 @@ var init_worker_registry = __esm({
|
|
|
5292
5292
|
if (!found) return Promise.reject(new Error(`No subagent ${ref}`));
|
|
5293
5293
|
if (found.finished) return Promise.resolve(found.finished);
|
|
5294
5294
|
const id = found.running.id;
|
|
5295
|
-
return new Promise((
|
|
5295
|
+
return new Promise((resolve22, reject) => {
|
|
5296
5296
|
const onAbort = () => reject(new DOMException("aborted", "AbortError"));
|
|
5297
5297
|
if (signal?.aborted) return onAbort();
|
|
5298
5298
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5299
5299
|
const list = this.waiters.get(id) ?? [];
|
|
5300
5300
|
list.push((w) => {
|
|
5301
5301
|
signal?.removeEventListener("abort", onAbort);
|
|
5302
|
-
|
|
5302
|
+
resolve22(w);
|
|
5303
5303
|
});
|
|
5304
5304
|
this.waiters.set(id, list);
|
|
5305
5305
|
});
|
|
@@ -5547,7 +5547,7 @@ async function pruneFiles(files, maxAgeDays, maxCount) {
|
|
|
5547
5547
|
return removed;
|
|
5548
5548
|
}
|
|
5549
5549
|
async function rotateJsonl(path, maxBytes, rotations) {
|
|
5550
|
-
const { rename:
|
|
5550
|
+
const { rename: rename5 } = await import("fs/promises");
|
|
5551
5551
|
let s;
|
|
5552
5552
|
try {
|
|
5553
5553
|
s = await stat(path);
|
|
@@ -5559,7 +5559,7 @@ async function rotateJsonl(path, maxBytes, rotations) {
|
|
|
5559
5559
|
const src = i === 1 ? path : `${path}.${i - 1}`;
|
|
5560
5560
|
const dst = `${path}.${i}`;
|
|
5561
5561
|
try {
|
|
5562
|
-
await
|
|
5562
|
+
await rename5(src, dst);
|
|
5563
5563
|
} catch {
|
|
5564
5564
|
}
|
|
5565
5565
|
}
|
|
@@ -6610,7 +6610,7 @@ function truncateForEmbedding(text3) {
|
|
|
6610
6610
|
return text3.slice(0, MAX_EMBED_CHARS);
|
|
6611
6611
|
}
|
|
6612
6612
|
async function sleep3(ms) {
|
|
6613
|
-
return new Promise((
|
|
6613
|
+
return new Promise((resolve22) => setTimeout(resolve22, ms));
|
|
6614
6614
|
}
|
|
6615
6615
|
async function fetchWithRetry(url, init, retries = 3) {
|
|
6616
6616
|
let lastError;
|
|
@@ -6619,8 +6619,8 @@ async function fetchWithRetry(url, init, retries = 3) {
|
|
|
6619
6619
|
const res = await fetch(url, init);
|
|
6620
6620
|
if (res.ok) return res;
|
|
6621
6621
|
if (res.status === 429 || res.status >= 500) {
|
|
6622
|
-
const
|
|
6623
|
-
await sleep3(
|
|
6622
|
+
const delay2 = 1e3 * 2 ** i;
|
|
6623
|
+
await sleep3(delay2);
|
|
6624
6624
|
continue;
|
|
6625
6625
|
}
|
|
6626
6626
|
const errText = await res.text().catch(() => "unknown error");
|
|
@@ -8050,15 +8050,15 @@ async function gitNumstat(cwd, opts2 = {}) {
|
|
|
8050
8050
|
if (opts2.includeUntracked) {
|
|
8051
8051
|
try {
|
|
8052
8052
|
const { stdout } = await execFileAsync("git", ["ls-files", "--others", "--exclude-standard"], { cwd, timeout: 5e3 });
|
|
8053
|
-
const { readFile:
|
|
8054
|
-
const { join:
|
|
8053
|
+
const { readFile: readFile42, stat: stat15 } = await import("fs/promises");
|
|
8054
|
+
const { join: join64 } = await import("path");
|
|
8055
8055
|
for (const file of stdout.split("\n").filter(Boolean)) {
|
|
8056
8056
|
let lines = 0;
|
|
8057
8057
|
try {
|
|
8058
|
-
const path =
|
|
8059
|
-
const size = (await
|
|
8058
|
+
const path = join64(cwd, file);
|
|
8059
|
+
const size = (await stat15(path)).size;
|
|
8060
8060
|
if (size > 0 && size <= 1024 * 1024) {
|
|
8061
|
-
const text3 = await
|
|
8061
|
+
const text3 = await readFile42(path, "utf8");
|
|
8062
8062
|
lines = text3.split("\n").length - (text3.endsWith("\n") ? 1 : 0);
|
|
8063
8063
|
}
|
|
8064
8064
|
} catch {
|
|
@@ -8177,6 +8177,146 @@ var init_git_delta = __esm({
|
|
|
8177
8177
|
}
|
|
8178
8178
|
});
|
|
8179
8179
|
|
|
8180
|
+
// src/util/line-diff.ts
|
|
8181
|
+
function splitLines(text3) {
|
|
8182
|
+
if (text3 === "") return [];
|
|
8183
|
+
const lines = text3.split("\n");
|
|
8184
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
8185
|
+
return lines;
|
|
8186
|
+
}
|
|
8187
|
+
function myers(a, b) {
|
|
8188
|
+
const n = a.length;
|
|
8189
|
+
const m = b.length;
|
|
8190
|
+
const max = n + m;
|
|
8191
|
+
if (max === 0) return [];
|
|
8192
|
+
const offset = max;
|
|
8193
|
+
let v = new Int32Array(2 * max + 2);
|
|
8194
|
+
const trace = [];
|
|
8195
|
+
for (let d = 0; d <= max; d++) {
|
|
8196
|
+
if ((n + m) * d > MAX_MYERS_COST) return null;
|
|
8197
|
+
trace.push(v.slice());
|
|
8198
|
+
const next = v;
|
|
8199
|
+
for (let k = -d; k <= d; k += 2) {
|
|
8200
|
+
let x;
|
|
8201
|
+
if (k === -d || k !== d && next[offset + k - 1] < next[offset + k + 1]) x = next[offset + k + 1];
|
|
8202
|
+
else x = next[offset + k - 1] + 1;
|
|
8203
|
+
let y = x - k;
|
|
8204
|
+
while (x < n && y < m && a[x] === b[y]) {
|
|
8205
|
+
x++;
|
|
8206
|
+
y++;
|
|
8207
|
+
}
|
|
8208
|
+
next[offset + k] = x;
|
|
8209
|
+
if (x >= n && y >= m) {
|
|
8210
|
+
trace.push(next.slice());
|
|
8211
|
+
return backtrack(trace, a, b, offset);
|
|
8212
|
+
}
|
|
8213
|
+
}
|
|
8214
|
+
v = next;
|
|
8215
|
+
}
|
|
8216
|
+
return null;
|
|
8217
|
+
}
|
|
8218
|
+
function backtrack(trace, a, b, offset) {
|
|
8219
|
+
const ops = [];
|
|
8220
|
+
let x = a.length;
|
|
8221
|
+
let y = b.length;
|
|
8222
|
+
for (let d = trace.length - 2; d >= 0; d--) {
|
|
8223
|
+
const v = trace[d];
|
|
8224
|
+
const k = x - y;
|
|
8225
|
+
let prevK;
|
|
8226
|
+
if (k === -d || k !== d && v[offset + k - 1] < v[offset + k + 1]) prevK = k + 1;
|
|
8227
|
+
else prevK = k - 1;
|
|
8228
|
+
const prevX = d === 0 ? 0 : v[offset + prevK];
|
|
8229
|
+
const prevY = prevX - prevK;
|
|
8230
|
+
while (x > prevX && y > prevY) {
|
|
8231
|
+
ops.push({ kind: " ", text: a[x - 1] });
|
|
8232
|
+
x--;
|
|
8233
|
+
y--;
|
|
8234
|
+
}
|
|
8235
|
+
if (d === 0) break;
|
|
8236
|
+
if (x === prevX) ops.push({ kind: "+", text: b[y - 1] });
|
|
8237
|
+
else ops.push({ kind: "-", text: a[x - 1] });
|
|
8238
|
+
x = prevX;
|
|
8239
|
+
y = prevY;
|
|
8240
|
+
}
|
|
8241
|
+
while (x > 0 && y > 0) {
|
|
8242
|
+
ops.push({ kind: " ", text: a[x - 1] });
|
|
8243
|
+
x--;
|
|
8244
|
+
y--;
|
|
8245
|
+
}
|
|
8246
|
+
return ops.reverse();
|
|
8247
|
+
}
|
|
8248
|
+
function editScript(a, b) {
|
|
8249
|
+
let pre = 0;
|
|
8250
|
+
while (pre < a.length && pre < b.length && a[pre] === b[pre]) pre++;
|
|
8251
|
+
let suf = 0;
|
|
8252
|
+
while (suf < a.length - pre && suf < b.length - pre && a[a.length - 1 - suf] === b[b.length - 1 - suf]) suf++;
|
|
8253
|
+
const midA = a.slice(pre, a.length - suf);
|
|
8254
|
+
const midB = b.slice(pre, b.length - suf);
|
|
8255
|
+
const mid = myers(midA, midB) ?? [
|
|
8256
|
+
...midA.map((text3) => ({ kind: "-", text: text3 })),
|
|
8257
|
+
...midB.map((text3) => ({ kind: "+", text: text3 }))
|
|
8258
|
+
];
|
|
8259
|
+
return [
|
|
8260
|
+
...a.slice(0, pre).map((text3) => ({ kind: " ", text: text3 })),
|
|
8261
|
+
...mid,
|
|
8262
|
+
...a.slice(a.length - suf).map((text3) => ({ kind: " ", text: text3 }))
|
|
8263
|
+
];
|
|
8264
|
+
}
|
|
8265
|
+
function structuredPatch(oldText, newText, context = DEFAULT_CONTEXT) {
|
|
8266
|
+
const ops = editScript(splitLines(oldText), splitLines(newText));
|
|
8267
|
+
const hunks = [];
|
|
8268
|
+
let oldNo = 1;
|
|
8269
|
+
let newNo = 1;
|
|
8270
|
+
const pos = ops.map((op) => {
|
|
8271
|
+
const at = { old: oldNo, new: newNo };
|
|
8272
|
+
if (op.kind !== "+") oldNo++;
|
|
8273
|
+
if (op.kind !== "-") newNo++;
|
|
8274
|
+
return at;
|
|
8275
|
+
});
|
|
8276
|
+
let i = 0;
|
|
8277
|
+
while (i < ops.length) {
|
|
8278
|
+
if (ops[i].kind === " ") {
|
|
8279
|
+
i++;
|
|
8280
|
+
continue;
|
|
8281
|
+
}
|
|
8282
|
+
const start = Math.max(0, i - context);
|
|
8283
|
+
let end = i;
|
|
8284
|
+
for (; ; ) {
|
|
8285
|
+
while (end < ops.length && ops[end].kind !== " ") end++;
|
|
8286
|
+
let gap = end;
|
|
8287
|
+
while (gap < ops.length && ops[gap].kind === " ") gap++;
|
|
8288
|
+
if (gap < ops.length && gap - end <= 2 * context) {
|
|
8289
|
+
end = gap;
|
|
8290
|
+
continue;
|
|
8291
|
+
}
|
|
8292
|
+
end = Math.min(ops.length, end + context);
|
|
8293
|
+
break;
|
|
8294
|
+
}
|
|
8295
|
+
const slice = ops.slice(start, end);
|
|
8296
|
+
const oldLines = slice.filter((o) => o.kind !== "+").length;
|
|
8297
|
+
const newLines = slice.filter((o) => o.kind !== "-").length;
|
|
8298
|
+
const first = pos[start];
|
|
8299
|
+
hunks.push({
|
|
8300
|
+
// jsdiff's convention: a hunk with no old (or new) lines starts one line earlier.
|
|
8301
|
+
oldStart: oldLines === 0 ? first.old - 1 : first.old,
|
|
8302
|
+
oldLines,
|
|
8303
|
+
newStart: newLines === 0 ? first.new - 1 : first.new,
|
|
8304
|
+
newLines,
|
|
8305
|
+
lines: slice.map((o) => o.kind + o.text)
|
|
8306
|
+
});
|
|
8307
|
+
i = end;
|
|
8308
|
+
}
|
|
8309
|
+
return hunks;
|
|
8310
|
+
}
|
|
8311
|
+
var DEFAULT_CONTEXT, MAX_MYERS_COST;
|
|
8312
|
+
var init_line_diff = __esm({
|
|
8313
|
+
"src/util/line-diff.ts"() {
|
|
8314
|
+
"use strict";
|
|
8315
|
+
DEFAULT_CONTEXT = 3;
|
|
8316
|
+
MAX_MYERS_COST = 4e6;
|
|
8317
|
+
}
|
|
8318
|
+
});
|
|
8319
|
+
|
|
8180
8320
|
// src/hooks/claude-compat.ts
|
|
8181
8321
|
function claudeToolName(tool, args) {
|
|
8182
8322
|
if (tool === "edit" && Array.isArray(args.edits)) return "MultiEdit";
|
|
@@ -8261,9 +8401,35 @@ function claudeToolResponse(tool, args, cwd, result2) {
|
|
|
8261
8401
|
}
|
|
8262
8402
|
if ((tool === "write" || tool === "edit") && isStr(args.path) && !failed) {
|
|
8263
8403
|
response.filePath = resolvePath(cwd, args.path);
|
|
8404
|
+
if (result2.fileChange) Object.assign(response, claudeFileChangeFields(tool, args, result2.fileChange));
|
|
8264
8405
|
}
|
|
8265
8406
|
return response;
|
|
8266
8407
|
}
|
|
8408
|
+
function claudeFileChangeFields(tool, args, change) {
|
|
8409
|
+
const fields = {};
|
|
8410
|
+
if (tool === "write") {
|
|
8411
|
+
fields.type = change.existed ? "update" : "create";
|
|
8412
|
+
if (isStr(args.content)) fields.content = args.content;
|
|
8413
|
+
} else if (Array.isArray(args.edits)) {
|
|
8414
|
+
fields.edits = editPairs(args);
|
|
8415
|
+
} else {
|
|
8416
|
+
fields.oldString = args.old_string;
|
|
8417
|
+
fields.newString = args.new_string;
|
|
8418
|
+
fields.replaceAll = args.replace_all === true;
|
|
8419
|
+
}
|
|
8420
|
+
if (!change.existed) {
|
|
8421
|
+
fields.originalFile = null;
|
|
8422
|
+
fields.structuredPatch = [];
|
|
8423
|
+
} else {
|
|
8424
|
+
if (change.original !== null && Buffer.byteLength(change.original, "utf8") <= ORIGINAL_FILE_CAP_BYTES) {
|
|
8425
|
+
fields.originalFile = change.original;
|
|
8426
|
+
}
|
|
8427
|
+
if (change.original !== null && change.updated !== null) {
|
|
8428
|
+
fields.structuredPatch = structuredPatch(change.original, change.updated);
|
|
8429
|
+
}
|
|
8430
|
+
}
|
|
8431
|
+
return fields;
|
|
8432
|
+
}
|
|
8267
8433
|
function claudeError(result2) {
|
|
8268
8434
|
if (isNum(result2.exitCode) && result2.exitCode !== 0) {
|
|
8269
8435
|
const output = [result2.stdout, result2.stderr].filter((s) => s && s.trim()).map((s) => s.trimEnd()).join("\n");
|
|
@@ -8296,12 +8462,13 @@ function claudeToolFields(payload) {
|
|
|
8296
8462
|
}
|
|
8297
8463
|
return { tool_name: toolName, ...fields };
|
|
8298
8464
|
}
|
|
8299
|
-
var CLAUDE_TOOL_NAMES, FILE_EDIT_NAMES, isStr, isNum;
|
|
8465
|
+
var CLAUDE_TOOL_NAMES, FILE_EDIT_NAMES, isStr, isNum, ORIGINAL_FILE_CAP_BYTES;
|
|
8300
8466
|
var init_claude_compat = __esm({
|
|
8301
8467
|
"src/hooks/claude-compat.ts"() {
|
|
8302
8468
|
"use strict";
|
|
8303
8469
|
init_edit();
|
|
8304
8470
|
init_paths();
|
|
8471
|
+
init_line_diff();
|
|
8305
8472
|
CLAUDE_TOOL_NAMES = {
|
|
8306
8473
|
bash: "Bash",
|
|
8307
8474
|
edit: "Edit",
|
|
@@ -8316,6 +8483,7 @@ var init_claude_compat = __esm({
|
|
|
8316
8483
|
FILE_EDIT_NAMES = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit"]);
|
|
8317
8484
|
isStr = (v) => typeof v === "string";
|
|
8318
8485
|
isNum = (v) => typeof v === "number";
|
|
8486
|
+
ORIGINAL_FILE_CAP_BYTES = 256 * 1024;
|
|
8319
8487
|
}
|
|
8320
8488
|
});
|
|
8321
8489
|
|
|
@@ -10125,8 +10293,8 @@ function applyConfirmedCost(log2, session, turn, snapshot) {
|
|
|
10125
10293
|
session.gatewayLogs = logs.slice(-100);
|
|
10126
10294
|
}
|
|
10127
10295
|
async function reconcileTurnCost(sessionId, turnId, lookup, fetchImpl2 = fetch, delaysMs = RECONCILE_DELAYS_MS) {
|
|
10128
|
-
for (const
|
|
10129
|
-
await new Promise((r) => setTimeout(r,
|
|
10296
|
+
for (const delay2 of delaysMs) {
|
|
10297
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
10130
10298
|
let snapshot;
|
|
10131
10299
|
try {
|
|
10132
10300
|
snapshot = await fetchGenerationSnapshot(lookup, fetchImpl2);
|
|
@@ -10606,15 +10774,15 @@ function makeErrorOutput(message2) {
|
|
|
10606
10774
|
return { content: message2, rawBytes: bytes, reducedBytes: bytes };
|
|
10607
10775
|
}
|
|
10608
10776
|
async function execOnce(command, cwd) {
|
|
10609
|
-
return new Promise((
|
|
10777
|
+
return new Promise((resolve22) => {
|
|
10610
10778
|
const child = spawn("bash", ["-lc", command], { cwd });
|
|
10611
10779
|
let out = "";
|
|
10612
10780
|
child.stdout.on("data", (d) => {
|
|
10613
10781
|
out += d.toString("utf8");
|
|
10614
10782
|
});
|
|
10615
10783
|
child.on("close", (code) => {
|
|
10616
|
-
if (code !== 0) return
|
|
10617
|
-
|
|
10784
|
+
if (code !== 0) return resolve22(void 0);
|
|
10785
|
+
resolve22(out.trim() || void 0);
|
|
10618
10786
|
});
|
|
10619
10787
|
});
|
|
10620
10788
|
}
|
|
@@ -10768,7 +10936,7 @@ async function runBash(args, ctx) {
|
|
|
10768
10936
|
if (pushGuard) return pushGuard;
|
|
10769
10937
|
const { shell, args: shellArgs, isPosix } = getShellCommand(ctx.shell);
|
|
10770
10938
|
const { command, env: coauthorEnv } = isPosix ? injectCoauthor(args.command, ctx.coauthor) : { command: args.command, env: {} };
|
|
10771
|
-
return new Promise((
|
|
10939
|
+
return new Promise((resolve22, reject) => {
|
|
10772
10940
|
logger.debug("bash:spawn", { command: args.command.slice(0, 200), cwd: ctx.cwd, shell });
|
|
10773
10941
|
const child = spawn(shell, [...shellArgs, command], {
|
|
10774
10942
|
cwd: ctx.cwd,
|
|
@@ -10833,7 +11001,7 @@ ${stderr}`
|
|
|
10833
11001
|
if (hint) parts.push(hint);
|
|
10834
11002
|
}
|
|
10835
11003
|
const raw = parts.join("\n");
|
|
10836
|
-
|
|
11004
|
+
resolve22({
|
|
10837
11005
|
content: raw,
|
|
10838
11006
|
rawBytes: Buffer.byteLength(raw, "utf8"),
|
|
10839
11007
|
reducedBytes: Buffer.byteLength(raw, "utf8"),
|
|
@@ -12231,7 +12399,7 @@ import { tmpdir as tmpdir2 } from "os";
|
|
|
12231
12399
|
import { join as join22, dirname as dirname9 } from "path";
|
|
12232
12400
|
async function autoScroll(page) {
|
|
12233
12401
|
await page.evaluate(async () => {
|
|
12234
|
-
await new Promise((
|
|
12402
|
+
await new Promise((resolve22) => {
|
|
12235
12403
|
let totalHeight = 0;
|
|
12236
12404
|
const distance = 300;
|
|
12237
12405
|
const timer2 = setInterval(() => {
|
|
@@ -12240,12 +12408,12 @@ async function autoScroll(page) {
|
|
|
12240
12408
|
totalHeight += distance;
|
|
12241
12409
|
if (totalHeight >= scrollHeight) {
|
|
12242
12410
|
clearInterval(timer2);
|
|
12243
|
-
|
|
12411
|
+
resolve22();
|
|
12244
12412
|
}
|
|
12245
12413
|
}, 100);
|
|
12246
12414
|
setTimeout(() => {
|
|
12247
12415
|
clearInterval(timer2);
|
|
12248
|
-
|
|
12416
|
+
resolve22();
|
|
12249
12417
|
}, 1e4);
|
|
12250
12418
|
});
|
|
12251
12419
|
});
|
|
@@ -14494,8 +14662,8 @@ function waitForProcessStartTime(pid, jobId, exitPath) {
|
|
|
14494
14662
|
function readProcessStartTime(pid) {
|
|
14495
14663
|
if (process.platform === "linux") {
|
|
14496
14664
|
try {
|
|
14497
|
-
const
|
|
14498
|
-
const fieldsAfterCommand =
|
|
14665
|
+
const stat15 = readFileSync6(`/proc/${pid}/stat`, "utf8");
|
|
14666
|
+
const fieldsAfterCommand = stat15.slice(stat15.lastIndexOf(")") + 1).trim().split(/\s+/);
|
|
14499
14667
|
return fieldsAfterCommand[19] ? `linux:${fieldsAfterCommand[19]}` : null;
|
|
14500
14668
|
} catch {
|
|
14501
14669
|
return null;
|
|
@@ -15501,8 +15669,8 @@ var init_store = __esm({
|
|
|
15501
15669
|
if (timer2.attempts >= timer2.maxAttempts) {
|
|
15502
15670
|
this.db.prepare("UPDATE run_timers SET status = 'failed', lease_until = NULL, last_error = ? WHERE id = ?").run(error.slice(0, 1e3), id);
|
|
15503
15671
|
} else {
|
|
15504
|
-
const
|
|
15505
|
-
this.db.prepare("UPDATE run_timers SET status = 'scheduled', wake_at = ?, lease_until = NULL, last_error = ? WHERE id = ?").run(now2 +
|
|
15672
|
+
const delay2 = Math.min(MAX_RETRY_MS, DEFAULT_RETRY_MS * 2 ** Math.max(0, timer2.attempts - 1));
|
|
15673
|
+
this.db.prepare("UPDATE run_timers SET status = 'scheduled', wake_at = ?, lease_until = NULL, last_error = ? WHERE id = ?").run(now2 + delay2, error.slice(0, 1e3), id);
|
|
15506
15674
|
}
|
|
15507
15675
|
});
|
|
15508
15676
|
}
|
|
@@ -15675,7 +15843,7 @@ var init_wait_for = __esm({
|
|
|
15675
15843
|
});
|
|
15676
15844
|
|
|
15677
15845
|
// src/tools/executor.ts
|
|
15678
|
-
import { realpath as realpath4 } from "fs/promises";
|
|
15846
|
+
import { readFile as readFile17, realpath as realpath4, stat as stat7 } from "fs/promises";
|
|
15679
15847
|
import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve5, sep as sep3 } from "path";
|
|
15680
15848
|
function getWorkerTools(profile) {
|
|
15681
15849
|
return profile === "research" ? ALL_TOOLS.filter((tool) => RESEARCH_WORKER_TOOL_NAMES.has(tool.name) && tool.isReadOnly === true).map(restrictResearchTool) : ALL_TOOLS;
|
|
@@ -15744,6 +15912,16 @@ function toPermissionResult(d) {
|
|
|
15744
15912
|
}
|
|
15745
15913
|
return d;
|
|
15746
15914
|
}
|
|
15915
|
+
async function snapshotForHook(abs) {
|
|
15916
|
+
try {
|
|
15917
|
+
const st = await stat7(abs);
|
|
15918
|
+
if (!st.isFile()) return { existed: true, content: null };
|
|
15919
|
+
if (st.size > HOOK_FILE_SNAPSHOT_MAX_BYTES) return { existed: true, content: null };
|
|
15920
|
+
return { existed: true, content: await readFile17(abs, "utf8") };
|
|
15921
|
+
} catch {
|
|
15922
|
+
return { existed: false, content: null };
|
|
15923
|
+
}
|
|
15924
|
+
}
|
|
15747
15925
|
function shellResultForHook(meta) {
|
|
15748
15926
|
if (!meta || meta.exitCode === void 0) return {};
|
|
15749
15927
|
return {
|
|
@@ -15762,6 +15940,15 @@ function capContentForHook(s) {
|
|
|
15762
15940
|
return `${cut}
|
|
15763
15941
|
[\u2026truncated for hook payload]`;
|
|
15764
15942
|
}
|
|
15943
|
+
async function fileChangeAfter(tool, args, cwd, before) {
|
|
15944
|
+
let updated = null;
|
|
15945
|
+
if (tool === "write" && typeof args.content === "string") {
|
|
15946
|
+
updated = Buffer.byteLength(args.content, "utf8") <= HOOK_FILE_SNAPSHOT_MAX_BYTES ? args.content : null;
|
|
15947
|
+
} else {
|
|
15948
|
+
updated = (await snapshotForHook(resolvePath(cwd, args.path))).content;
|
|
15949
|
+
}
|
|
15950
|
+
return { existed: before.existed, original: before.content, updated };
|
|
15951
|
+
}
|
|
15765
15952
|
function tracePermissionDecision(result2) {
|
|
15766
15953
|
if (result2.decision === "deny") return "deny";
|
|
15767
15954
|
if (result2.scope === "session") return "allow_session";
|
|
@@ -15785,7 +15972,7 @@ function normalizeToolOutput(result2) {
|
|
|
15785
15972
|
}
|
|
15786
15973
|
return result2;
|
|
15787
15974
|
}
|
|
15788
|
-
var ALL_TOOLS, RESEARCH_WORKER_TOOL_NAMES, SENSITIVE_RESEARCH_PATHS, HOOK_RESULT_CONTENT_CAP_BYTES, ToolExecutor, TRACE_ARGS_INLINE_MAX, ToolTrace;
|
|
15975
|
+
var ALL_TOOLS, RESEARCH_WORKER_TOOL_NAMES, SENSITIVE_RESEARCH_PATHS, HOOK_RESULT_CONTENT_CAP_BYTES, HOOK_FILE_SNAPSHOT_MAX_BYTES, ToolExecutor, TRACE_ARGS_INLINE_MAX, ToolTrace;
|
|
15789
15976
|
var init_executor = __esm({
|
|
15790
15977
|
"src/tools/executor.ts"() {
|
|
15791
15978
|
"use strict";
|
|
@@ -15815,6 +16002,7 @@ var init_executor = __esm({
|
|
|
15815
16002
|
init_jobs();
|
|
15816
16003
|
init_wait_for();
|
|
15817
16004
|
init_workers();
|
|
16005
|
+
init_paths();
|
|
15818
16006
|
init_store();
|
|
15819
16007
|
ALL_TOOLS = [
|
|
15820
16008
|
{ ...readTool, isReadOnly: true },
|
|
@@ -15869,6 +16057,7 @@ var init_executor = __esm({
|
|
|
15869
16057
|
".git-credentials"
|
|
15870
16058
|
]);
|
|
15871
16059
|
HOOK_RESULT_CONTENT_CAP_BYTES = 4 * 1024;
|
|
16060
|
+
HOOK_FILE_SNAPSHOT_MAX_BYTES = 1024 * 1024;
|
|
15872
16061
|
ToolExecutor = class {
|
|
15873
16062
|
sessionAllowed = /* @__PURE__ */ new Set();
|
|
15874
16063
|
tools;
|
|
@@ -16046,8 +16235,10 @@ var init_executor = __esm({
|
|
|
16046
16235
|
runStore.recordToolIntent(ctx.runId, call.id, call.name, args);
|
|
16047
16236
|
intentRecorded = true;
|
|
16048
16237
|
}
|
|
16238
|
+
const before = this.wantsFileChange(call.name, args) ? await snapshotForHook(resolvePath(ctx.cwd, args.path)) : void 0;
|
|
16049
16239
|
const result2 = await tool.run(args, ctx);
|
|
16050
16240
|
toolCompleted = true;
|
|
16241
|
+
const fileChange = before ? await fileChangeAfter(call.name, args, ctx.cwd, before) : void 0;
|
|
16051
16242
|
const normalized = normalizeToolOutput(result2);
|
|
16052
16243
|
tr?.raw(normalized);
|
|
16053
16244
|
if (runStore && ctx.runId) {
|
|
@@ -16099,7 +16290,7 @@ var init_executor = __esm({
|
|
|
16099
16290
|
artifactId: reduced.artifactId,
|
|
16100
16291
|
...normalized.waitRequest ? { waitRequest: normalized.waitRequest } : {}
|
|
16101
16292
|
};
|
|
16102
|
-
this.firePostToolUse(call, args, success, ctx, normalized.meta);
|
|
16293
|
+
this.firePostToolUse(call, args, success, ctx, normalized.meta, fileChange);
|
|
16103
16294
|
return success;
|
|
16104
16295
|
} catch (e) {
|
|
16105
16296
|
if (e instanceof RunToolBudgetExceededError) ctx.onRunBudgetExceeded?.(e.reason);
|
|
@@ -16170,7 +16361,7 @@ var init_executor = __esm({
|
|
|
16170
16361
|
* `content` field is capped via `capContentForHook` to keep large tool
|
|
16171
16362
|
* outputs from blowing the OS env-var limits on `KIMIFLARE_HOOK_PAYLOAD`.
|
|
16172
16363
|
*/
|
|
16173
|
-
firePostToolUse(call, args, result2, ctx, meta) {
|
|
16364
|
+
firePostToolUse(call, args, result2, ctx, meta, fileChange) {
|
|
16174
16365
|
const hooks = this.hooks;
|
|
16175
16366
|
if (!hooks) return;
|
|
16176
16367
|
const post = hooks.hasEnabledHooks("PostToolUse");
|
|
@@ -16180,7 +16371,8 @@ var init_executor = __esm({
|
|
|
16180
16371
|
ok: result2.ok,
|
|
16181
16372
|
content: capContentForHook(result2.content),
|
|
16182
16373
|
errorCode: result2.errorCode,
|
|
16183
|
-
...shellResultForHook(meta)
|
|
16374
|
+
...shellResultForHook(meta),
|
|
16375
|
+
...fileChange ? { fileChange } : {}
|
|
16184
16376
|
};
|
|
16185
16377
|
const base = {
|
|
16186
16378
|
session_id: ctx.sessionId ?? null,
|
|
@@ -16198,6 +16390,11 @@ var init_executor = __esm({
|
|
|
16198
16390
|
void hooks.fire("PostToolUseFailure", { event: "PostToolUseFailure", ...base, error: claudeError(resultFields) }, call.name, ctx.signal).catch(swallow2);
|
|
16199
16391
|
}
|
|
16200
16392
|
}
|
|
16393
|
+
/** True when a PostToolUse hook would get this write / edit call's diff. */
|
|
16394
|
+
wantsFileChange(tool, args) {
|
|
16395
|
+
if (tool !== "write" && tool !== "edit" || typeof args.path !== "string" || !args.path) return false;
|
|
16396
|
+
return !!this.hooks && (this.hooks.hasEnabledHooks("PostToolUse") || this.hooks.hasEnabledHooks("PostToolUseFailure"));
|
|
16397
|
+
}
|
|
16201
16398
|
permissionKey(tool, args) {
|
|
16202
16399
|
if (tool.name === "bash" && typeof args.command === "string") {
|
|
16203
16400
|
const firstToken = args.command.trim().split(/\s+/)[0] ?? "";
|
|
@@ -16324,8 +16521,106 @@ var init_executor = __esm({
|
|
|
16324
16521
|
}
|
|
16325
16522
|
});
|
|
16326
16523
|
|
|
16524
|
+
// src/intent/classify.ts
|
|
16525
|
+
function classifyIntent(prompt) {
|
|
16526
|
+
let intentScore = 0;
|
|
16527
|
+
let matchedIntent = "other";
|
|
16528
|
+
for (const [intent, pattern] of Object.entries(INTENT_PATTERNS)) {
|
|
16529
|
+
const matches = (prompt.match(pattern) || []).length;
|
|
16530
|
+
if (matches > intentScore) {
|
|
16531
|
+
intentScore = matches;
|
|
16532
|
+
matchedIntent = intent;
|
|
16533
|
+
}
|
|
16534
|
+
}
|
|
16535
|
+
const hasFileMentions = (prompt.match(/@\w+|\b[\w/-]+\.(ts|tsx|js|jsx|py|go|rs)\b/g) || []).length;
|
|
16536
|
+
const hasMutatingVerb = /\b(add|create|write|edit|delete|remove|rename|migrate|implement)\b/i.test(prompt);
|
|
16537
|
+
const isQuestion = prompt.trim().endsWith("?") || /\b(what|how|why|is|does|can)\b/i.test(prompt.split(" ")[0] || "");
|
|
16538
|
+
const hasHeavySignal = HEAVY_SIGNAL.test(prompt);
|
|
16539
|
+
const rawScore = Math.min(
|
|
16540
|
+
1,
|
|
16541
|
+
intentScore * 0.25 + (hasFileMentions > 2 ? 0.3 : hasFileMentions * 0.1) + (hasMutatingVerb ? 0.25 : 0) + (isQuestion ? 0 : 0.1) + (hasHeavySignal ? 0.6 : 0)
|
|
16542
|
+
);
|
|
16543
|
+
const tier = rawScore < 0.3 ? "light" : rawScore < 0.65 ? "medium" : "heavy";
|
|
16544
|
+
return {
|
|
16545
|
+
intent: hasHeavySignal && matchedIntent === "other" ? "explore" : matchedIntent,
|
|
16546
|
+
rawScore,
|
|
16547
|
+
tier,
|
|
16548
|
+
confidence: 0.5 + (intentScore > 0 || hasHeavySignal ? 0.3 : 0) + (hasFileMentions > 0 ? 0.1 : 0)
|
|
16549
|
+
};
|
|
16550
|
+
}
|
|
16551
|
+
var INTENT_PATTERNS, HEAVY_SIGNAL;
|
|
16552
|
+
var init_classify = __esm({
|
|
16553
|
+
"src/intent/classify.ts"() {
|
|
16554
|
+
"use strict";
|
|
16555
|
+
INTENT_PATTERNS = {
|
|
16556
|
+
qa: /\b(what|how|why|explain|describe|what's|what is)\b/i,
|
|
16557
|
+
diagnose: /\b(broken|failing|error|bug|crash|why.*fail|not working)\b/i,
|
|
16558
|
+
verify: /\b(correct|right|verify|review|check|is this|does this)\b/i,
|
|
16559
|
+
polish: /\b(rename|refactor|extract|move|clean|lint|format)\b/i,
|
|
16560
|
+
small_edit: /\b(add|change|update|fix|remove|delete)\b.+\b(line|here|this|variable|function)\b/i,
|
|
16561
|
+
feature_bounded: /\b(add|implement|create|support)\b.+\b(flag|option|param|arg|field)\b/i,
|
|
16562
|
+
feature_exploratory: /\b(add|implement|migrate|integrate|build)\b.+\b(module|system|auth|oauth|framework|service)\b/i,
|
|
16563
|
+
explore: /\b(how.*work|architecture|structure|where.*used|find.*all|understand)\b/i,
|
|
16564
|
+
meta: /\b(plan|design|strategy|ontology|roadmap|approach)\b/i
|
|
16565
|
+
};
|
|
16566
|
+
HEAVY_SIGNAL = /\b(research|investigat\w*|audit|deep[\s-]?(dive|thinking)|explorat\w*|comprehensive|end[\s-]?to[\s-]?end|entire\s+(code\s?base|repo\w*|project|app)|whole\s+(code\s?base|repo\w*|project|app)|across\s+the\s+(code\s?base|repo\w*|project)|security|vulnerab\w*|loophole|exploit\w*|threat\s?model|attack\s+surface|penetration)\b/i;
|
|
16567
|
+
}
|
|
16568
|
+
});
|
|
16569
|
+
|
|
16570
|
+
// src/hooks/prompt-submit.ts
|
|
16571
|
+
async function submitUserPrompt(info) {
|
|
16572
|
+
let provider;
|
|
16573
|
+
try {
|
|
16574
|
+
provider = info.auth ? providerPresetOf(info.auth).id : void 0;
|
|
16575
|
+
} catch {
|
|
16576
|
+
provider = void 0;
|
|
16577
|
+
}
|
|
16578
|
+
await noteSessionStart({
|
|
16579
|
+
...info.hooks ? { hooks: info.hooks } : {},
|
|
16580
|
+
sessionId: info.sessionId,
|
|
16581
|
+
cwd: info.cwd,
|
|
16582
|
+
resumed: info.resumed,
|
|
16583
|
+
model: info.model,
|
|
16584
|
+
...provider ? { provider } : {}
|
|
16585
|
+
});
|
|
16586
|
+
if (!info.hooks?.hasEnabledHooks("UserPromptSubmit")) return { blocked: false };
|
|
16587
|
+
const outcome = await info.hooks.fire(
|
|
16588
|
+
"UserPromptSubmit",
|
|
16589
|
+
{
|
|
16590
|
+
event: "UserPromptSubmit",
|
|
16591
|
+
session_id: info.sessionId,
|
|
16592
|
+
cwd: info.cwd,
|
|
16593
|
+
prompt: info.prompt,
|
|
16594
|
+
tier: info.tier ?? classifyIntent(info.prompt).tier
|
|
16595
|
+
},
|
|
16596
|
+
null
|
|
16597
|
+
);
|
|
16598
|
+
if (!outcome.vetoed) return { blocked: false };
|
|
16599
|
+
return { blocked: true, reason: outcome.vetoReason || PROMPT_BLOCKED_DEFAULT_REASON };
|
|
16600
|
+
}
|
|
16601
|
+
var PROMPT_BLOCKED_EXIT_CODE, PROMPT_BLOCKED_DEFAULT_REASON, PromptBlockedError;
|
|
16602
|
+
var init_prompt_submit = __esm({
|
|
16603
|
+
"src/hooks/prompt-submit.ts"() {
|
|
16604
|
+
"use strict";
|
|
16605
|
+
init_session_lifecycle();
|
|
16606
|
+
init_classify();
|
|
16607
|
+
init_llm_auth();
|
|
16608
|
+
PROMPT_BLOCKED_EXIT_CODE = 44;
|
|
16609
|
+
PROMPT_BLOCKED_DEFAULT_REASON = "UserPromptSubmit hook blocked the prompt";
|
|
16610
|
+
PromptBlockedError = class extends Error {
|
|
16611
|
+
reason;
|
|
16612
|
+
code = "prompt_blocked";
|
|
16613
|
+
constructor(reason) {
|
|
16614
|
+
super(`prompt blocked by a UserPromptSubmit hook: ${reason}`);
|
|
16615
|
+
this.name = "PromptBlockedError";
|
|
16616
|
+
this.reason = reason;
|
|
16617
|
+
}
|
|
16618
|
+
};
|
|
16619
|
+
}
|
|
16620
|
+
});
|
|
16621
|
+
|
|
16327
16622
|
// src/util/image.ts
|
|
16328
|
-
import { readFile as
|
|
16623
|
+
import { readFile as readFile18 } from "fs/promises";
|
|
16329
16624
|
import { basename as basename3 } from "path";
|
|
16330
16625
|
import jpeg from "jpeg-js";
|
|
16331
16626
|
import { PNG } from "pngjs";
|
|
@@ -16404,7 +16699,7 @@ function imageNote(path, change) {
|
|
|
16404
16699
|
return `[Attached image ${basename3(path)} was downscaled to ${change.width}\xD7${change.height} for upload; the full-resolution original is at ${path}]`;
|
|
16405
16700
|
}
|
|
16406
16701
|
async function encodeImageFile(filePath, opts2 = {}) {
|
|
16407
|
-
const buf = await
|
|
16702
|
+
const buf = await readFile18(filePath);
|
|
16408
16703
|
if (buf.byteLength > MAX_IMAGE_BYTES) {
|
|
16409
16704
|
throw new Error(
|
|
16410
16705
|
`image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
|
|
@@ -16448,7 +16743,7 @@ var init_image = __esm({
|
|
|
16448
16743
|
});
|
|
16449
16744
|
|
|
16450
16745
|
// src/util/attachments.ts
|
|
16451
|
-
import { readFile as
|
|
16746
|
+
import { readFile as readFile19 } from "fs/promises";
|
|
16452
16747
|
import { basename as basename4 } from "path";
|
|
16453
16748
|
async function buildAttachmentMessage(prompt, files, cwd, imageOptions2 = {}) {
|
|
16454
16749
|
let text3 = prompt;
|
|
@@ -16471,7 +16766,7 @@ async function buildAttachmentMessage(prompt, files, cwd, imageOptions2 = {}) {
|
|
|
16471
16766
|
}
|
|
16472
16767
|
} else {
|
|
16473
16768
|
try {
|
|
16474
|
-
const content = await
|
|
16769
|
+
const content = await readFile19(filePath, "utf8");
|
|
16475
16770
|
const relPath = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
|
|
16476
16771
|
fileContents.push(`
|
|
16477
16772
|
--- ${relPath} ---
|
|
@@ -16571,52 +16866,6 @@ var init_permissions_evaluator = __esm({
|
|
|
16571
16866
|
}
|
|
16572
16867
|
});
|
|
16573
16868
|
|
|
16574
|
-
// src/intent/classify.ts
|
|
16575
|
-
function classifyIntent(prompt) {
|
|
16576
|
-
let intentScore = 0;
|
|
16577
|
-
let matchedIntent = "other";
|
|
16578
|
-
for (const [intent, pattern] of Object.entries(INTENT_PATTERNS)) {
|
|
16579
|
-
const matches = (prompt.match(pattern) || []).length;
|
|
16580
|
-
if (matches > intentScore) {
|
|
16581
|
-
intentScore = matches;
|
|
16582
|
-
matchedIntent = intent;
|
|
16583
|
-
}
|
|
16584
|
-
}
|
|
16585
|
-
const hasFileMentions = (prompt.match(/@\w+|\b[\w/-]+\.(ts|tsx|js|jsx|py|go|rs)\b/g) || []).length;
|
|
16586
|
-
const hasMutatingVerb = /\b(add|create|write|edit|delete|remove|rename|migrate|implement)\b/i.test(prompt);
|
|
16587
|
-
const isQuestion = prompt.trim().endsWith("?") || /\b(what|how|why|is|does|can)\b/i.test(prompt.split(" ")[0] || "");
|
|
16588
|
-
const hasHeavySignal = HEAVY_SIGNAL.test(prompt);
|
|
16589
|
-
const rawScore = Math.min(
|
|
16590
|
-
1,
|
|
16591
|
-
intentScore * 0.25 + (hasFileMentions > 2 ? 0.3 : hasFileMentions * 0.1) + (hasMutatingVerb ? 0.25 : 0) + (isQuestion ? 0 : 0.1) + (hasHeavySignal ? 0.6 : 0)
|
|
16592
|
-
);
|
|
16593
|
-
const tier = rawScore < 0.3 ? "light" : rawScore < 0.65 ? "medium" : "heavy";
|
|
16594
|
-
return {
|
|
16595
|
-
intent: hasHeavySignal && matchedIntent === "other" ? "explore" : matchedIntent,
|
|
16596
|
-
rawScore,
|
|
16597
|
-
tier,
|
|
16598
|
-
confidence: 0.5 + (intentScore > 0 || hasHeavySignal ? 0.3 : 0) + (hasFileMentions > 0 ? 0.1 : 0)
|
|
16599
|
-
};
|
|
16600
|
-
}
|
|
16601
|
-
var INTENT_PATTERNS, HEAVY_SIGNAL;
|
|
16602
|
-
var init_classify = __esm({
|
|
16603
|
-
"src/intent/classify.ts"() {
|
|
16604
|
-
"use strict";
|
|
16605
|
-
INTENT_PATTERNS = {
|
|
16606
|
-
qa: /\b(what|how|why|explain|describe|what's|what is)\b/i,
|
|
16607
|
-
diagnose: /\b(broken|failing|error|bug|crash|why.*fail|not working)\b/i,
|
|
16608
|
-
verify: /\b(correct|right|verify|review|check|is this|does this)\b/i,
|
|
16609
|
-
polish: /\b(rename|refactor|extract|move|clean|lint|format)\b/i,
|
|
16610
|
-
small_edit: /\b(add|change|update|fix|remove|delete)\b.+\b(line|here|this|variable|function)\b/i,
|
|
16611
|
-
feature_bounded: /\b(add|implement|create|support)\b.+\b(flag|option|param|arg|field)\b/i,
|
|
16612
|
-
feature_exploratory: /\b(add|implement|migrate|integrate|build)\b.+\b(module|system|auth|oauth|framework|service)\b/i,
|
|
16613
|
-
explore: /\b(how.*work|architecture|structure|where.*used|find.*all|understand)\b/i,
|
|
16614
|
-
meta: /\b(plan|design|strategy|ontology|roadmap|approach)\b/i
|
|
16615
|
-
};
|
|
16616
|
-
HEAVY_SIGNAL = /\b(research|investigat\w*|audit|deep[\s-]?(dive|thinking)|explorat\w*|comprehensive|end[\s-]?to[\s-]?end|entire\s+(code\s?base|repo\w*|project|app)|whole\s+(code\s?base|repo\w*|project|app)|across\s+the\s+(code\s?base|repo\w*|project)|security|vulnerab\w*|loophole|exploit\w*|threat\s?model|attack\s+surface|penetration)\b/i;
|
|
16617
|
-
}
|
|
16618
|
-
});
|
|
16619
|
-
|
|
16620
16869
|
// src/agent/session-core.ts
|
|
16621
16870
|
function lastUserText(messages) {
|
|
16622
16871
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -16707,7 +16956,7 @@ __export(retention_exports, {
|
|
|
16707
16956
|
listTraceSessions: () => listTraceSessions,
|
|
16708
16957
|
pruneTraces: () => pruneTraces
|
|
16709
16958
|
});
|
|
16710
|
-
import { readdir as readdir5, rm as rm4, stat as
|
|
16959
|
+
import { readdir as readdir5, rm as rm4, stat as stat8 } from "fs/promises";
|
|
16711
16960
|
import { join as join29 } from "path";
|
|
16712
16961
|
async function dirSize(path) {
|
|
16713
16962
|
let total = 0;
|
|
@@ -16717,7 +16966,7 @@ async function dirSize(path) {
|
|
|
16717
16966
|
if (entry.isDirectory()) total += await dirSize(p);
|
|
16718
16967
|
else if (entry.isFile()) {
|
|
16719
16968
|
try {
|
|
16720
|
-
total += (await
|
|
16969
|
+
total += (await stat8(p)).size;
|
|
16721
16970
|
} catch {
|
|
16722
16971
|
}
|
|
16723
16972
|
}
|
|
@@ -16736,11 +16985,11 @@ async function listTraceSessions(root) {
|
|
|
16736
16985
|
for (const name of names) {
|
|
16737
16986
|
const path = join29(base, name);
|
|
16738
16987
|
try {
|
|
16739
|
-
const s = await
|
|
16988
|
+
const s = await stat8(path);
|
|
16740
16989
|
if (!s.isDirectory()) continue;
|
|
16741
16990
|
let mtime = s.mtime;
|
|
16742
16991
|
try {
|
|
16743
|
-
mtime = (await
|
|
16992
|
+
mtime = (await stat8(join29(path, TRACE_FILE_NAME))).mtime;
|
|
16744
16993
|
} catch {
|
|
16745
16994
|
}
|
|
16746
16995
|
sessions.push({ sessionId: name, path, mtime, bytes: await dirSize(path) });
|
|
@@ -17343,6 +17592,10 @@ function hookWirePayload(payload) {
|
|
|
17343
17592
|
if (payload.session_id) Object.assign(wire, hookTranscriptFields(payload.session_id));
|
|
17344
17593
|
if (isToolEventPayload(payload)) {
|
|
17345
17594
|
Object.assign(wire, claudeToolFields(payload));
|
|
17595
|
+
if ((payload.event === "PostToolUse" || payload.event === "PostToolUseFailure") && payload.result.fileChange) {
|
|
17596
|
+
const { fileChange: _fileChange, ...result2 } = payload.result;
|
|
17597
|
+
wire.result = result2;
|
|
17598
|
+
}
|
|
17346
17599
|
if (payload.tool_call_id) wire.tool_use_id = payload.tool_call_id;
|
|
17347
17600
|
if (payload.event === "PermissionRequest") wire.permission_mode = claudePermissionMode(payload.mode);
|
|
17348
17601
|
}
|
|
@@ -17514,7 +17767,7 @@ var init_runner = __esm({
|
|
|
17514
17767
|
DECISION_STDOUT_CAP_BYTES = 64 * 1024;
|
|
17515
17768
|
HOOK_ENV_PAYLOAD_MAX_BYTES = 32 * 1024;
|
|
17516
17769
|
HOOK_BLOCK_EXIT_CODE = 2;
|
|
17517
|
-
defaultSpawn = (command, payloadJson, env, cwd, timeoutMs, signal) => new Promise((
|
|
17770
|
+
defaultSpawn = (command, payloadJson, env, cwd, timeoutMs, signal) => new Promise((resolve22) => {
|
|
17518
17771
|
const child = spawn5(command, {
|
|
17519
17772
|
shell: true,
|
|
17520
17773
|
cwd,
|
|
@@ -17529,7 +17782,7 @@ var init_runner = __esm({
|
|
|
17529
17782
|
settled = true;
|
|
17530
17783
|
clearTimeout(timer2);
|
|
17531
17784
|
signal?.removeEventListener("abort", onAbort);
|
|
17532
|
-
|
|
17785
|
+
resolve22({ exitCode, stdout, stderr, timedOut });
|
|
17533
17786
|
};
|
|
17534
17787
|
const onAbort = () => {
|
|
17535
17788
|
child.kill("SIGTERM");
|
|
@@ -17677,7 +17930,7 @@ var init_manager2 = __esm({
|
|
|
17677
17930
|
});
|
|
17678
17931
|
|
|
17679
17932
|
// src/util/state.ts
|
|
17680
|
-
import { readFile as
|
|
17933
|
+
import { readFile as readFile20, writeFile as writeFile11, mkdir as mkdir12 } from "fs/promises";
|
|
17681
17934
|
import { homedir as homedir19 } from "os";
|
|
17682
17935
|
import { join as join32 } from "path";
|
|
17683
17936
|
function statePath() {
|
|
@@ -17686,7 +17939,7 @@ function statePath() {
|
|
|
17686
17939
|
}
|
|
17687
17940
|
async function readState() {
|
|
17688
17941
|
try {
|
|
17689
|
-
const raw = await
|
|
17942
|
+
const raw = await readFile20(statePath(), "utf8");
|
|
17690
17943
|
return JSON.parse(raw);
|
|
17691
17944
|
} catch {
|
|
17692
17945
|
return {};
|
|
@@ -17766,11 +18019,11 @@ var init_notices = __esm({
|
|
|
17766
18019
|
});
|
|
17767
18020
|
|
|
17768
18021
|
// src/eval/config.ts
|
|
17769
|
-
import { readFile as
|
|
18022
|
+
import { readFile as readFile21 } from "fs/promises";
|
|
17770
18023
|
import { basename as basename6, resolve as resolve8 } from "path";
|
|
17771
18024
|
async function loadEvalConfig(file) {
|
|
17772
18025
|
const path = resolve8(file);
|
|
17773
|
-
const raw = JSON.parse(await
|
|
18026
|
+
const raw = JSON.parse(await readFile21(path, "utf8"));
|
|
17774
18027
|
if (!raw || typeof raw !== "object") throw new Error(`${file}: config must be a JSON object`);
|
|
17775
18028
|
const config2 = raw.config ?? {};
|
|
17776
18029
|
if (typeof config2 !== "object" || Array.isArray(config2)) throw new Error(`${file}: "config" must be an object`);
|
|
@@ -17790,7 +18043,7 @@ var init_config2 = __esm({
|
|
|
17790
18043
|
});
|
|
17791
18044
|
|
|
17792
18045
|
// src/eval/tasks.ts
|
|
17793
|
-
import { readdir as readdir6, readFile as
|
|
18046
|
+
import { readdir as readdir6, readFile as readFile22, stat as stat9 } from "fs/promises";
|
|
17794
18047
|
import { basename as basename7, join as join33, resolve as resolve9 } from "path";
|
|
17795
18048
|
function isNonEmptyString(v) {
|
|
17796
18049
|
return typeof v === "string" && v.trim().length > 0;
|
|
@@ -17825,7 +18078,7 @@ async function loadTasks(dir, filter) {
|
|
|
17825
18078
|
const seen = /* @__PURE__ */ new Set();
|
|
17826
18079
|
for (const name of names) {
|
|
17827
18080
|
const file = join33(root, name);
|
|
17828
|
-
const task = validateTask(JSON.parse(await
|
|
18081
|
+
const task = validateTask(JSON.parse(await readFile22(file, "utf8")), name);
|
|
17829
18082
|
if (task.id !== basename7(name, ".json")) throw new Error(`${name}: "id" (${task.id}) must match the file name`);
|
|
17830
18083
|
if (seen.has(task.id)) throw new Error(`duplicate task id ${task.id}`);
|
|
17831
18084
|
seen.add(task.id);
|
|
@@ -17834,7 +18087,7 @@ async function loadTasks(dir, filter) {
|
|
|
17834
18087
|
for (const [dest, src] of Object.entries(task.files ?? {})) {
|
|
17835
18088
|
const abs = resolve9(root, src);
|
|
17836
18089
|
if (!abs.startsWith(root)) throw new Error(`${name}: files["${dest}"] escapes the task directory`);
|
|
17837
|
-
await
|
|
18090
|
+
await stat9(abs).catch(() => {
|
|
17838
18091
|
throw new Error(`${name}: files["${dest}"] -> ${src} does not exist`);
|
|
17839
18092
|
});
|
|
17840
18093
|
resolvedFiles[dest] = abs;
|
|
@@ -17855,7 +18108,7 @@ var init_tasks2 = __esm({
|
|
|
17855
18108
|
// src/eval/workspace.ts
|
|
17856
18109
|
import { execFile as execFile8 } from "child_process";
|
|
17857
18110
|
import { createHash as createHash6 } from "crypto";
|
|
17858
|
-
import { mkdir as mkdir13, rm as rm5, stat as
|
|
18111
|
+
import { mkdir as mkdir13, rm as rm5, stat as stat10 } from "fs/promises";
|
|
17859
18112
|
import { isAbsolute as isAbsolute4, join as join34, resolve as resolve10 } from "path";
|
|
17860
18113
|
import { promisify as promisify7 } from "util";
|
|
17861
18114
|
async function git3(args, cwd, timeoutMs = 6e5) {
|
|
@@ -17883,7 +18136,7 @@ async function prepareSourceRepoUncached(repo, cacheDir) {
|
|
|
17883
18136
|
const slug = `${repo.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(-60)}-${createHash6("sha1").update(repo).digest("hex").slice(0, 8)}`;
|
|
17884
18137
|
const dir = join34(cacheDir, slug);
|
|
17885
18138
|
await mkdir13(cacheDir, { recursive: true });
|
|
17886
|
-
const exists = await
|
|
18139
|
+
const exists = await stat10(join34(dir, ".git")).then(() => true).catch(() => false);
|
|
17887
18140
|
if (!exists) {
|
|
17888
18141
|
await git3(["clone", "--quiet", "--no-checkout", repo, dir], cacheDir);
|
|
17889
18142
|
} else {
|
|
@@ -19155,7 +19408,7 @@ var init_connection = __esm({
|
|
|
19155
19408
|
if (this.child) {
|
|
19156
19409
|
throw new Error("LSP connection already started");
|
|
19157
19410
|
}
|
|
19158
|
-
return new Promise((
|
|
19411
|
+
return new Promise((resolve22, reject) => {
|
|
19159
19412
|
const abortController = new AbortController();
|
|
19160
19413
|
const spawnTimer = setTimeout(() => {
|
|
19161
19414
|
abortController.abort();
|
|
@@ -19194,7 +19447,7 @@ var init_connection = __esm({
|
|
|
19194
19447
|
if (child.pid) {
|
|
19195
19448
|
clearTimeout(spawnTimer);
|
|
19196
19449
|
this.child = child;
|
|
19197
|
-
|
|
19450
|
+
resolve22();
|
|
19198
19451
|
}
|
|
19199
19452
|
});
|
|
19200
19453
|
} catch (err) {
|
|
@@ -19209,12 +19462,12 @@ var init_connection = __esm({
|
|
|
19209
19462
|
}
|
|
19210
19463
|
const id = this.nextId++;
|
|
19211
19464
|
const msg = { jsonrpc: "2.0", id, method, params };
|
|
19212
|
-
return new Promise((
|
|
19465
|
+
return new Promise((resolve22, reject) => {
|
|
19213
19466
|
const timer2 = setTimeout(() => {
|
|
19214
19467
|
this.pending.delete(id);
|
|
19215
19468
|
reject(toolTimeoutError(`LSP request '${method}'`, this.requestTimeoutMs));
|
|
19216
19469
|
}, this.requestTimeoutMs);
|
|
19217
|
-
const pending = { resolve:
|
|
19470
|
+
const pending = { resolve: resolve22, reject, signal, timer: timer2 };
|
|
19218
19471
|
this.pending.set(id, pending);
|
|
19219
19472
|
if (signal) {
|
|
19220
19473
|
const onAbort = () => {
|
|
@@ -20118,7 +20371,7 @@ __export(openrouter_catalog_exports, {
|
|
|
20118
20371
|
loadOpenRouterCatalog: () => loadOpenRouterCatalog,
|
|
20119
20372
|
mapOpenRouterModel: () => mapOpenRouterModel
|
|
20120
20373
|
});
|
|
20121
|
-
import { readFile as
|
|
20374
|
+
import { readFile as readFile23, writeFile as writeFile12, mkdir as mkdir14 } from "fs/promises";
|
|
20122
20375
|
import { homedir as homedir20 } from "os";
|
|
20123
20376
|
import { join as join36, dirname as dirname17 } from "path";
|
|
20124
20377
|
function catalogCachePath() {
|
|
@@ -20174,7 +20427,7 @@ async function fetchOpenRouterCatalog(fetchImpl2 = fetch) {
|
|
|
20174
20427
|
}
|
|
20175
20428
|
async function readCache3() {
|
|
20176
20429
|
try {
|
|
20177
|
-
const raw = await
|
|
20430
|
+
const raw = await readFile23(catalogCachePath(), "utf8");
|
|
20178
20431
|
const parsed = JSON.parse(raw);
|
|
20179
20432
|
return parsed.version === CACHE_VERSION ? parsed : null;
|
|
20180
20433
|
} catch {
|
|
@@ -20233,7 +20486,7 @@ __export(requesty_catalog_exports, {
|
|
|
20233
20486
|
loadRequestyCatalog: () => loadRequestyCatalog,
|
|
20234
20487
|
mapRequestyModel: () => mapRequestyModel
|
|
20235
20488
|
});
|
|
20236
|
-
import { readFile as
|
|
20489
|
+
import { readFile as readFile24, writeFile as writeFile13, mkdir as mkdir15 } from "fs/promises";
|
|
20237
20490
|
import { homedir as homedir21 } from "os";
|
|
20238
20491
|
import { join as join37, dirname as dirname18 } from "path";
|
|
20239
20492
|
function catalogCachePath2() {
|
|
@@ -20294,7 +20547,7 @@ async function fetchRequestyCatalog(fetchImpl2 = fetch) {
|
|
|
20294
20547
|
}
|
|
20295
20548
|
async function readCache4() {
|
|
20296
20549
|
try {
|
|
20297
|
-
const raw = await
|
|
20550
|
+
const raw = await readFile24(catalogCachePath2(), "utf8");
|
|
20298
20551
|
const parsed = JSON.parse(raw);
|
|
20299
20552
|
if (parsed.version !== CACHE_VERSION2) return null;
|
|
20300
20553
|
return {
|
|
@@ -20372,7 +20625,7 @@ __export(provider_catalog_exports, {
|
|
|
20372
20625
|
mapModelsDevModel: () => mapModelsDevModel,
|
|
20373
20626
|
mapModelsDevProvider: () => mapModelsDevProvider
|
|
20374
20627
|
});
|
|
20375
|
-
import { readFile as
|
|
20628
|
+
import { readFile as readFile25, writeFile as writeFile14, mkdir as mkdir16 } from "fs/promises";
|
|
20376
20629
|
import { homedir as homedir22 } from "os";
|
|
20377
20630
|
import { join as join38, dirname as dirname19 } from "path";
|
|
20378
20631
|
function mapModelsDevModel(m) {
|
|
@@ -20412,7 +20665,7 @@ function cachePath2() {
|
|
|
20412
20665
|
}
|
|
20413
20666
|
async function readCache5() {
|
|
20414
20667
|
try {
|
|
20415
|
-
const parsed = JSON.parse(await
|
|
20668
|
+
const parsed = JSON.parse(await readFile25(cachePath2(), "utf8"));
|
|
20416
20669
|
return parsed.version === CACHE_VERSION3 ? parsed : null;
|
|
20417
20670
|
} catch {
|
|
20418
20671
|
return null;
|
|
@@ -20787,6 +21040,7 @@ var init_session = __esm({
|
|
|
20787
21040
|
"use strict";
|
|
20788
21041
|
init_image();
|
|
20789
21042
|
init_session_lifecycle();
|
|
21043
|
+
init_prompt_submit();
|
|
20790
21044
|
init_process_exit();
|
|
20791
21045
|
init_loop();
|
|
20792
21046
|
init_system_prompt();
|
|
@@ -20930,6 +21184,16 @@ var init_session = __esm({
|
|
|
20930
21184
|
return;
|
|
20931
21185
|
}
|
|
20932
21186
|
const mode = options?.mode ?? this.currentMode;
|
|
21187
|
+
const gate = await submitUserPrompt({
|
|
21188
|
+
...this.hooks ? { hooks: this.hooks } : {},
|
|
21189
|
+
sessionId: this.sessionId,
|
|
21190
|
+
cwd: this.cwd,
|
|
21191
|
+
prompt: text3,
|
|
21192
|
+
resumed: this.messages.some((m) => m.role === "assistant"),
|
|
21193
|
+
model: this.model,
|
|
21194
|
+
auth: llmAuthFromConfig(this.config)
|
|
21195
|
+
});
|
|
21196
|
+
if (gate.blocked) throw new PromptBlockedError(gate.reason);
|
|
20933
21197
|
const messageId = `msg_${this.nextMessageId++}`;
|
|
20934
21198
|
let userContent2 = text3;
|
|
20935
21199
|
if (options?.images && options.images.length > 0) {
|
|
@@ -21209,12 +21473,12 @@ ${notes.join("\n")}` };
|
|
|
21209
21473
|
toolName: req.tool.name,
|
|
21210
21474
|
args: req.args
|
|
21211
21475
|
});
|
|
21212
|
-
const decision = await new Promise((
|
|
21213
|
-
this.permissionResolvers.set(requestId,
|
|
21476
|
+
const decision = await new Promise((resolve22) => {
|
|
21477
|
+
this.permissionResolvers.set(requestId, resolve22);
|
|
21214
21478
|
setTimeout(() => {
|
|
21215
21479
|
if (this.permissionResolvers.has(requestId)) {
|
|
21216
21480
|
this.permissionResolvers.delete(requestId);
|
|
21217
|
-
|
|
21481
|
+
resolve22("deny");
|
|
21218
21482
|
}
|
|
21219
21483
|
}, 3e5);
|
|
21220
21484
|
});
|
|
@@ -21275,7 +21539,7 @@ ${notes.join("\n")}` };
|
|
|
21275
21539
|
this.lspManager?.notifyChange(path, content);
|
|
21276
21540
|
} else {
|
|
21277
21541
|
void import("fs/promises").then(
|
|
21278
|
-
({ readFile:
|
|
21542
|
+
({ readFile: readFile42 }) => readFile42(path, "utf8").then((c) => this.lspManager?.notifyChange(path, c)).catch(() => {
|
|
21279
21543
|
})
|
|
21280
21544
|
).catch(() => {
|
|
21281
21545
|
});
|
|
@@ -21307,7 +21571,7 @@ __export(run_exports, {
|
|
|
21307
21571
|
summarizeTrace: () => summarizeTrace
|
|
21308
21572
|
});
|
|
21309
21573
|
import { spawn as spawn7 } from "child_process";
|
|
21310
|
-
import { appendFile as appendFile3, copyFile, mkdir as mkdir17, readFile as
|
|
21574
|
+
import { appendFile as appendFile3, copyFile, mkdir as mkdir17, readFile as readFile26, writeFile as writeFile15 } from "fs/promises";
|
|
21311
21575
|
import { dirname as dirname20, join as join40, resolve as resolve12 } from "path";
|
|
21312
21576
|
import { performance as performance2 } from "perf_hooks";
|
|
21313
21577
|
function runShell(command, cwd, timeoutMs) {
|
|
@@ -21350,7 +21614,7 @@ async function summarizeTrace(traceFile) {
|
|
|
21350
21614
|
const out = { cost_usd: 0, prompt_tokens: 0, completion_tokens: 0, turns: 0, tool_calls: 0, overflow: false };
|
|
21351
21615
|
let raw;
|
|
21352
21616
|
try {
|
|
21353
|
-
raw = await
|
|
21617
|
+
raw = await readFile26(traceFile, "utf8");
|
|
21354
21618
|
} catch {
|
|
21355
21619
|
return out;
|
|
21356
21620
|
}
|
|
@@ -21546,9 +21810,9 @@ __export(compare_exports, {
|
|
|
21546
21810
|
perTask: () => perTask,
|
|
21547
21811
|
summarizeArm: () => summarizeArm
|
|
21548
21812
|
});
|
|
21549
|
-
import { readFile as
|
|
21813
|
+
import { readFile as readFile27 } from "fs/promises";
|
|
21550
21814
|
async function loadResults(file) {
|
|
21551
|
-
const raw = await
|
|
21815
|
+
const raw = await readFile27(file, "utf8");
|
|
21552
21816
|
return raw.split("\n").filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
21553
21817
|
}
|
|
21554
21818
|
function median(values) {
|
|
@@ -21681,7 +21945,7 @@ __export(cost_verify_exports, {
|
|
|
21681
21945
|
verifySession: () => verifySession,
|
|
21682
21946
|
verifyTurn: () => verifyTurn
|
|
21683
21947
|
});
|
|
21684
|
-
import { readFile as
|
|
21948
|
+
import { readFile as readFile28 } from "fs/promises";
|
|
21685
21949
|
import { homedir as homedir24 } from "os";
|
|
21686
21950
|
import { join as join41 } from "path";
|
|
21687
21951
|
function usagePath2() {
|
|
@@ -21690,7 +21954,7 @@ function usagePath2() {
|
|
|
21690
21954
|
}
|
|
21691
21955
|
async function loadSessions() {
|
|
21692
21956
|
try {
|
|
21693
|
-
return JSON.parse(await
|
|
21957
|
+
return JSON.parse(await readFile28(usagePath2(), "utf8")).sessions ?? [];
|
|
21694
21958
|
} catch {
|
|
21695
21959
|
return [];
|
|
21696
21960
|
}
|
|
@@ -22221,7 +22485,7 @@ var init_heuristic = __esm({
|
|
|
22221
22485
|
});
|
|
22222
22486
|
|
|
22223
22487
|
// src/cost-attribution/classify-from-session.ts
|
|
22224
|
-
import { readFile as
|
|
22488
|
+
import { readFile as readFile29 } from "fs/promises";
|
|
22225
22489
|
import { join as join42 } from "path";
|
|
22226
22490
|
import { homedir as homedir25 } from "os";
|
|
22227
22491
|
function sessionsDir2() {
|
|
@@ -22240,7 +22504,7 @@ function parseToolCalls(calls) {
|
|
|
22240
22504
|
}
|
|
22241
22505
|
async function classifyFromSessionFile(sessionId) {
|
|
22242
22506
|
try {
|
|
22243
|
-
const raw = await
|
|
22507
|
+
const raw = await readFile29(join42(sessionsDir2(), `${sessionId}.json`), "utf8");
|
|
22244
22508
|
const session = JSON.parse(raw);
|
|
22245
22509
|
const messages = session.messages ?? [];
|
|
22246
22510
|
const turns = [];
|
|
@@ -22273,7 +22537,7 @@ var cli_exports = {};
|
|
|
22273
22537
|
__export(cli_exports, {
|
|
22274
22538
|
runCostCommand: () => runCostCommand
|
|
22275
22539
|
});
|
|
22276
|
-
import { readFile as
|
|
22540
|
+
import { readFile as readFile30 } from "fs/promises";
|
|
22277
22541
|
import { join as join43 } from "path";
|
|
22278
22542
|
import { homedir as homedir26 } from "os";
|
|
22279
22543
|
function usageDir2() {
|
|
@@ -22293,7 +22557,7 @@ function daysAgo(n) {
|
|
|
22293
22557
|
}
|
|
22294
22558
|
async function loadLog2() {
|
|
22295
22559
|
try {
|
|
22296
|
-
const raw = await
|
|
22560
|
+
const raw = await readFile30(usagePath3(), "utf8");
|
|
22297
22561
|
return JSON.parse(raw);
|
|
22298
22562
|
} catch {
|
|
22299
22563
|
return { version: 1, days: [], sessions: [] };
|
|
@@ -22377,6 +22641,662 @@ var init_cli = __esm({
|
|
|
22377
22641
|
}
|
|
22378
22642
|
});
|
|
22379
22643
|
|
|
22644
|
+
// src/remote/client.ts
|
|
22645
|
+
async function* parseEventStream(body) {
|
|
22646
|
+
const decoder = new TextDecoder();
|
|
22647
|
+
let buffer = "";
|
|
22648
|
+
for await (const chunk of body) {
|
|
22649
|
+
buffer += decoder.decode(chunk, { stream: true }).replace(/\r\n/g, "\n");
|
|
22650
|
+
let boundary;
|
|
22651
|
+
while ((boundary = buffer.indexOf("\n\n")) >= 0) {
|
|
22652
|
+
const frame = buffer.slice(0, boundary);
|
|
22653
|
+
buffer = buffer.slice(boundary + 2);
|
|
22654
|
+
const event = parseFrame(frame);
|
|
22655
|
+
if (event) yield event;
|
|
22656
|
+
}
|
|
22657
|
+
}
|
|
22658
|
+
}
|
|
22659
|
+
function parseFrame(frame) {
|
|
22660
|
+
let id;
|
|
22661
|
+
let type = "message";
|
|
22662
|
+
const data = [];
|
|
22663
|
+
for (const line of frame.split("\n")) {
|
|
22664
|
+
if (!line || line.startsWith(":")) continue;
|
|
22665
|
+
const colon = line.indexOf(":");
|
|
22666
|
+
const field = colon < 0 ? line : line.slice(0, colon);
|
|
22667
|
+
const value = colon < 0 ? "" : line.slice(colon + 1).replace(/^ /, "");
|
|
22668
|
+
if (field === "id" && /^\d+$/.test(value)) id = Number(value);
|
|
22669
|
+
else if (field === "event") type = value;
|
|
22670
|
+
else if (field === "data") data.push(value);
|
|
22671
|
+
}
|
|
22672
|
+
if (id === void 0) return void 0;
|
|
22673
|
+
let parsed = {};
|
|
22674
|
+
try {
|
|
22675
|
+
parsed = data.length ? JSON.parse(data.join("\n")) : {};
|
|
22676
|
+
} catch {
|
|
22677
|
+
return void 0;
|
|
22678
|
+
}
|
|
22679
|
+
return { id, type, data: parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {} };
|
|
22680
|
+
}
|
|
22681
|
+
async function toApiError(response) {
|
|
22682
|
+
let code = `http_${response.status}`;
|
|
22683
|
+
let message2 = `Server returned ${response.status}`;
|
|
22684
|
+
try {
|
|
22685
|
+
const body = await response.json();
|
|
22686
|
+
if (body.error?.code) code = body.error.code;
|
|
22687
|
+
if (body.error?.message) message2 = body.error.message;
|
|
22688
|
+
} catch {
|
|
22689
|
+
}
|
|
22690
|
+
return new RemoteApiError(response.status, code, message2);
|
|
22691
|
+
}
|
|
22692
|
+
function delay(ms, signal) {
|
|
22693
|
+
return new Promise((resolve22, reject) => {
|
|
22694
|
+
if (signal?.aborted) return reject(signal.reason);
|
|
22695
|
+
const timer2 = setTimeout(() => {
|
|
22696
|
+
signal?.removeEventListener("abort", onAbort);
|
|
22697
|
+
resolve22();
|
|
22698
|
+
}, ms);
|
|
22699
|
+
const onAbort = () => {
|
|
22700
|
+
clearTimeout(timer2);
|
|
22701
|
+
reject(signal?.reason);
|
|
22702
|
+
};
|
|
22703
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
22704
|
+
});
|
|
22705
|
+
}
|
|
22706
|
+
var TERMINAL_STATUSES, RemoteApiError, RemoteClient;
|
|
22707
|
+
var init_client3 = __esm({
|
|
22708
|
+
"src/remote/client.ts"() {
|
|
22709
|
+
"use strict";
|
|
22710
|
+
TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "interrupted", "merged", "destroyed"]);
|
|
22711
|
+
RemoteApiError = class extends Error {
|
|
22712
|
+
constructor(status, code, message2) {
|
|
22713
|
+
super(message2);
|
|
22714
|
+
this.status = status;
|
|
22715
|
+
this.code = code;
|
|
22716
|
+
this.name = "RemoteApiError";
|
|
22717
|
+
}
|
|
22718
|
+
status;
|
|
22719
|
+
code;
|
|
22720
|
+
};
|
|
22721
|
+
RemoteClient = class {
|
|
22722
|
+
constructor(baseUrl, token, fetchImpl2 = fetch) {
|
|
22723
|
+
this.baseUrl = baseUrl;
|
|
22724
|
+
this.token = token;
|
|
22725
|
+
this.fetchImpl = fetchImpl2;
|
|
22726
|
+
}
|
|
22727
|
+
baseUrl;
|
|
22728
|
+
token;
|
|
22729
|
+
fetchImpl;
|
|
22730
|
+
startDeviceAuthorization(clientName2) {
|
|
22731
|
+
return this.request("POST", "/auth/device", { body: { clientName: clientName2 }, auth: false });
|
|
22732
|
+
}
|
|
22733
|
+
/** Polls until the owner decides; resolves with the credential, rejects on denial or expiry. */
|
|
22734
|
+
async waitForCredential(device, options = {}) {
|
|
22735
|
+
const sleep6 = options.sleep ?? ((ms) => delay(ms, options.signal));
|
|
22736
|
+
let intervalMs = Math.max(1, device.interval) * 1e3;
|
|
22737
|
+
const deadline = Date.now() + device.expiresIn * 1e3;
|
|
22738
|
+
while (Date.now() < deadline) {
|
|
22739
|
+
await sleep6(intervalMs);
|
|
22740
|
+
try {
|
|
22741
|
+
return await this.request("POST", "/auth/device/token", { body: { deviceCode: device.deviceCode }, auth: false, signal: options.signal });
|
|
22742
|
+
} catch (error) {
|
|
22743
|
+
if (!(error instanceof RemoteApiError)) throw error;
|
|
22744
|
+
if (error.code === "authorization_pending") continue;
|
|
22745
|
+
if (error.code === "slow_down") {
|
|
22746
|
+
intervalMs += 5e3;
|
|
22747
|
+
continue;
|
|
22748
|
+
}
|
|
22749
|
+
throw error;
|
|
22750
|
+
}
|
|
22751
|
+
}
|
|
22752
|
+
throw new RemoteApiError(400, "expired_token", "The pairing code expired before it was approved; run the command again");
|
|
22753
|
+
}
|
|
22754
|
+
health() {
|
|
22755
|
+
return this.request("GET", "/health");
|
|
22756
|
+
}
|
|
22757
|
+
async workspaces() {
|
|
22758
|
+
return (await this.request("GET", "/workspaces")).workspaces;
|
|
22759
|
+
}
|
|
22760
|
+
async models() {
|
|
22761
|
+
return (await this.request("GET", "/models")).models;
|
|
22762
|
+
}
|
|
22763
|
+
createCodeConversation(input) {
|
|
22764
|
+
const { idempotencyKey, ...body } = input;
|
|
22765
|
+
return this.withRetries(() => this.request("POST", "/conversations", {
|
|
22766
|
+
body: { ...body, kind: "code" },
|
|
22767
|
+
headers: { "Idempotency-Key": idempotencyKey }
|
|
22768
|
+
}));
|
|
22769
|
+
}
|
|
22770
|
+
submitTurn(conversationId, text3, clientTurnId) {
|
|
22771
|
+
return this.withRetries(() => this.request("POST", `/conversations/${encodeURIComponent(conversationId)}/turns`, { body: { clientTurnId, text: text3 } }));
|
|
22772
|
+
}
|
|
22773
|
+
getConversation(conversationId) {
|
|
22774
|
+
return this.request("GET", `/conversations/${encodeURIComponent(conversationId)}`);
|
|
22775
|
+
}
|
|
22776
|
+
async listConversations(limit = 50) {
|
|
22777
|
+
return (await this.request("GET", `/conversations?limit=${limit}`)).conversations;
|
|
22778
|
+
}
|
|
22779
|
+
cancel(conversationId) {
|
|
22780
|
+
return this.request("POST", `/conversations/${encodeURIComponent(conversationId)}/cancel`);
|
|
22781
|
+
}
|
|
22782
|
+
/**
|
|
22783
|
+
* Events after `cursor`, reconnecting with the last seen ID when the stream drops,
|
|
22784
|
+
* until the caller stops iterating or the signal aborts.
|
|
22785
|
+
*/
|
|
22786
|
+
async *events(conversationId, cursor, signal) {
|
|
22787
|
+
let last = cursor;
|
|
22788
|
+
let failures = 0;
|
|
22789
|
+
while (!signal?.aborted) {
|
|
22790
|
+
try {
|
|
22791
|
+
const response = await this.fetchImpl(this.url(`/conversations/${encodeURIComponent(conversationId)}/events`), {
|
|
22792
|
+
headers: { ...this.authHeaders(), Accept: "text/event-stream", "Last-Event-ID": String(last) },
|
|
22793
|
+
signal
|
|
22794
|
+
});
|
|
22795
|
+
if (!response.ok || !response.body) throw await toApiError(response);
|
|
22796
|
+
failures = 0;
|
|
22797
|
+
for await (const event of parseEventStream(response.body)) {
|
|
22798
|
+
if (event.id <= last) continue;
|
|
22799
|
+
last = event.id;
|
|
22800
|
+
yield event;
|
|
22801
|
+
}
|
|
22802
|
+
} catch (error) {
|
|
22803
|
+
if (signal?.aborted) return;
|
|
22804
|
+
if (error instanceof RemoteApiError && error.status < 500) throw error;
|
|
22805
|
+
if (++failures > 30) throw error;
|
|
22806
|
+
}
|
|
22807
|
+
await delay(Math.min(1e3 * failures, 1e4), signal).catch(() => {
|
|
22808
|
+
});
|
|
22809
|
+
}
|
|
22810
|
+
}
|
|
22811
|
+
async request(method, path, options = {}) {
|
|
22812
|
+
const response = await this.fetchImpl(this.url(path), {
|
|
22813
|
+
method,
|
|
22814
|
+
headers: {
|
|
22815
|
+
...options.auth === false ? {} : this.authHeaders(),
|
|
22816
|
+
...options.body === void 0 ? {} : { "Content-Type": "application/json" },
|
|
22817
|
+
...options.headers
|
|
22818
|
+
},
|
|
22819
|
+
...options.body === void 0 ? {} : { body: JSON.stringify(options.body) },
|
|
22820
|
+
...options.signal ? { signal: options.signal } : {}
|
|
22821
|
+
});
|
|
22822
|
+
if (!response.ok) throw await toApiError(response);
|
|
22823
|
+
return await response.json();
|
|
22824
|
+
}
|
|
22825
|
+
/** Retries network failures and 5xx; safe only for requests carrying an idempotency key. */
|
|
22826
|
+
async withRetries(attempt) {
|
|
22827
|
+
for (let tries = 1; ; tries++) {
|
|
22828
|
+
try {
|
|
22829
|
+
return await attempt();
|
|
22830
|
+
} catch (error) {
|
|
22831
|
+
const retryable = !(error instanceof RemoteApiError) || error.status >= 500;
|
|
22832
|
+
if (!retryable || tries >= 3) throw error;
|
|
22833
|
+
await delay(1e3 * tries);
|
|
22834
|
+
}
|
|
22835
|
+
}
|
|
22836
|
+
}
|
|
22837
|
+
url(path) {
|
|
22838
|
+
return `${this.baseUrl}/api/v1${path}`;
|
|
22839
|
+
}
|
|
22840
|
+
authHeaders() {
|
|
22841
|
+
return this.token ? { Authorization: `Bearer ${this.token}` } : {};
|
|
22842
|
+
}
|
|
22843
|
+
};
|
|
22844
|
+
}
|
|
22845
|
+
});
|
|
22846
|
+
|
|
22847
|
+
// src/remote/config.ts
|
|
22848
|
+
import { chmod as chmod4, mkdir as mkdir18, readFile as readFile31, rename as rename4, writeFile as writeFile16 } from "fs/promises";
|
|
22849
|
+
import { homedir as homedir27 } from "os";
|
|
22850
|
+
import { dirname as dirname21, join as join44 } from "path";
|
|
22851
|
+
function remotesPath(env = process.env) {
|
|
22852
|
+
if (env.AUTOPILOT_REMOTES_FILE) return env.AUTOPILOT_REMOTES_FILE;
|
|
22853
|
+
const configHome2 = env.XDG_CONFIG_HOME?.trim() || join44(homedir27(), ".config");
|
|
22854
|
+
return join44(configHome2, "autopilot", "remotes.json");
|
|
22855
|
+
}
|
|
22856
|
+
async function loadRemotes(path = remotesPath()) {
|
|
22857
|
+
let raw;
|
|
22858
|
+
try {
|
|
22859
|
+
raw = await readFile31(path, "utf8");
|
|
22860
|
+
} catch (error) {
|
|
22861
|
+
if (error.code === "ENOENT") return [];
|
|
22862
|
+
throw error;
|
|
22863
|
+
}
|
|
22864
|
+
const parsed = JSON.parse(raw);
|
|
22865
|
+
return Array.isArray(parsed.remotes) ? parsed.remotes.filter(isRemote) : [];
|
|
22866
|
+
}
|
|
22867
|
+
async function saveRemote(remote, path = remotesPath()) {
|
|
22868
|
+
const remotes = (await loadRemotes(path)).filter((entry) => entry.name !== remote.name);
|
|
22869
|
+
remotes.push(remote);
|
|
22870
|
+
await writeRemotes(remotes, path);
|
|
22871
|
+
}
|
|
22872
|
+
async function removeRemote(name, path = remotesPath()) {
|
|
22873
|
+
const remotes = await loadRemotes(path);
|
|
22874
|
+
const kept = remotes.filter((entry) => entry.name !== name);
|
|
22875
|
+
if (kept.length === remotes.length) return false;
|
|
22876
|
+
await writeRemotes(kept, path);
|
|
22877
|
+
return true;
|
|
22878
|
+
}
|
|
22879
|
+
async function resolveRemote(name, path = remotesPath()) {
|
|
22880
|
+
const remotes = await loadRemotes(path);
|
|
22881
|
+
if (remotes.length === 0) throw new Error("No servers paired yet. Run: autopilot remote add https://your-server");
|
|
22882
|
+
if (name === void 0) {
|
|
22883
|
+
if (remotes.length === 1) return remotes[0];
|
|
22884
|
+
throw new Error(`Several servers are paired; pick one with --on (${remotes.map((entry) => entry.name).join(", ")})`);
|
|
22885
|
+
}
|
|
22886
|
+
const remote = remotes.find((entry) => entry.name === name);
|
|
22887
|
+
if (!remote) throw new Error(`No server named "${name}". Paired: ${remotes.map((entry) => entry.name).join(", ")}`);
|
|
22888
|
+
return remote;
|
|
22889
|
+
}
|
|
22890
|
+
function defaultRemoteName(url) {
|
|
22891
|
+
const host = new URL(url).hostname.toLowerCase();
|
|
22892
|
+
const label = /^\d+(\.\d+){3}$/.test(host) ? host.replace(/\./g, "-") : host.split(".")[0] ?? "server";
|
|
22893
|
+
const name = label.replace(/[^a-z0-9-]/g, "-").replace(/^-+/, "").slice(0, 40);
|
|
22894
|
+
return REMOTE_NAME_RE.test(name) ? name : "server";
|
|
22895
|
+
}
|
|
22896
|
+
function normalizeServerUrl(input) {
|
|
22897
|
+
let url;
|
|
22898
|
+
try {
|
|
22899
|
+
url = new URL(/^[a-z]+:\/\//i.test(input) ? input : `https://${input}`);
|
|
22900
|
+
} catch {
|
|
22901
|
+
throw new Error(`Not a URL: ${input}`);
|
|
22902
|
+
}
|
|
22903
|
+
const loopback = url.hostname === "localhost" || url.hostname === "[::1]" || url.hostname.startsWith("127.");
|
|
22904
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
|
|
22905
|
+
throw new Error("Use an https:// server URL (http:// is only allowed for localhost)");
|
|
22906
|
+
}
|
|
22907
|
+
if (url.username || url.password || url.search || url.hash) throw new Error("The server URL must not include credentials, a query, or a fragment");
|
|
22908
|
+
return `${url.origin}${url.pathname.replace(/\/+$/, "")}`;
|
|
22909
|
+
}
|
|
22910
|
+
async function writeRemotes(remotes, path) {
|
|
22911
|
+
await mkdir18(dirname21(path), { recursive: true, mode: 448 });
|
|
22912
|
+
const temp = `${path}.${process.pid}.tmp`;
|
|
22913
|
+
await writeFile16(temp, `${JSON.stringify({ version: 1, remotes }, null, 2)}
|
|
22914
|
+
`, { mode: 384 });
|
|
22915
|
+
await chmod4(temp, 384);
|
|
22916
|
+
await rename4(temp, path);
|
|
22917
|
+
}
|
|
22918
|
+
function isRemote(value) {
|
|
22919
|
+
if (!value || typeof value !== "object") return false;
|
|
22920
|
+
const entry = value;
|
|
22921
|
+
return ["name", "url", "token", "credentialId", "expiresAt", "addedAt"].every((key) => typeof entry[key] === "string");
|
|
22922
|
+
}
|
|
22923
|
+
var REMOTE_NAME_RE;
|
|
22924
|
+
var init_config4 = __esm({
|
|
22925
|
+
"src/remote/config.ts"() {
|
|
22926
|
+
"use strict";
|
|
22927
|
+
REMOTE_NAME_RE = /^[a-z0-9][a-z0-9-]{0,39}$/;
|
|
22928
|
+
}
|
|
22929
|
+
});
|
|
22930
|
+
|
|
22931
|
+
// src/remote/git.ts
|
|
22932
|
+
import { execFile as execFile9 } from "child_process";
|
|
22933
|
+
import { mkdtemp as mkdtemp3, rm as rm6, copyFile as copyFile2 } from "fs/promises";
|
|
22934
|
+
import { tmpdir as tmpdir5 } from "os";
|
|
22935
|
+
import { join as join45, resolve as resolve13 } from "path";
|
|
22936
|
+
import { promisify as promisify8 } from "util";
|
|
22937
|
+
function parseGitHubRemote(url) {
|
|
22938
|
+
const match = url.trim().match(/^(?:https:\/\/(?:[^@/]+@)?github\.com\/|ssh:\/\/git@github\.com(?::\d+)?\/|git@github\.com:)([A-Za-z0-9-]{1,39})\/([A-Za-z0-9._-]{1,100}?)(?:\.git)?\/?$/);
|
|
22939
|
+
return match ? `${match[1]}/${match[2]}` : void 0;
|
|
22940
|
+
}
|
|
22941
|
+
async function detectGitHubRepository(cwd, remote = "origin") {
|
|
22942
|
+
let url;
|
|
22943
|
+
try {
|
|
22944
|
+
url = await git4(cwd, ["remote", "get-url", remote]);
|
|
22945
|
+
} catch {
|
|
22946
|
+
throw new Error(`This directory has no "${remote}" git remote; pass --repo owner/name`);
|
|
22947
|
+
}
|
|
22948
|
+
const repository = parseGitHubRemote(url);
|
|
22949
|
+
if (!repository) throw new Error(`The "${remote}" remote is not a GitHub repository (${url}); pass --repo owner/name`);
|
|
22950
|
+
return repository;
|
|
22951
|
+
}
|
|
22952
|
+
async function snapshotWorkingTree(cwd) {
|
|
22953
|
+
const root = await git4(cwd, ["rev-parse", "--show-toplevel"]).catch(() => {
|
|
22954
|
+
throw new Error("Not inside a git repository");
|
|
22955
|
+
});
|
|
22956
|
+
await git4(root, ["rev-parse", "--verify", "HEAD"]).catch(() => {
|
|
22957
|
+
throw new Error("This repository has no commits yet; push a first commit before running remotely");
|
|
22958
|
+
});
|
|
22959
|
+
const baseRef = await upstreamRef(root);
|
|
22960
|
+
const baseCommit = await git4(root, ["merge-base", "HEAD", baseRef]).catch(() => {
|
|
22961
|
+
throw new Error(`HEAD shares no history with ${baseRef}`);
|
|
22962
|
+
});
|
|
22963
|
+
const scratch = await mkdtemp3(join45(tmpdir5(), "autopilot-snapshot-"));
|
|
22964
|
+
try {
|
|
22965
|
+
const index = join45(scratch, "index");
|
|
22966
|
+
const realIndex = resolve13(root, await git4(root, ["rev-parse", "--git-path", "index"]));
|
|
22967
|
+
await copyFile2(realIndex, index).catch(() => {
|
|
22968
|
+
});
|
|
22969
|
+
const env = { ...process.env, GIT_INDEX_FILE: index };
|
|
22970
|
+
await git4(root, ["add", "--all"], env);
|
|
22971
|
+
const patch = await git4(root, ["diff", "--cached", "--binary", "--no-color", "--no-ext-diff", baseCommit], env, false);
|
|
22972
|
+
if (patch.length > MAX_PATCH_CHARS) {
|
|
22973
|
+
throw new Error(`Local changes are ${(patch.length / 1024 / 1024).toFixed(1)} MiB, over the 3 MiB limit; commit and push some of them first`);
|
|
22974
|
+
}
|
|
22975
|
+
const files = (await git4(root, ["diff", "--cached", "--name-only", "--no-renames", baseCommit], env)).split("\n").filter(Boolean);
|
|
22976
|
+
return { baseCommit, patch, baseRef, files };
|
|
22977
|
+
} finally {
|
|
22978
|
+
await rm6(scratch, { recursive: true, force: true });
|
|
22979
|
+
}
|
|
22980
|
+
}
|
|
22981
|
+
async function upstreamRef(root) {
|
|
22982
|
+
const upstream = await git4(root, ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"]).catch(() => "");
|
|
22983
|
+
if (upstream.startsWith("origin/")) return upstream;
|
|
22984
|
+
const originHead = await git4(root, ["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"]).catch(() => "");
|
|
22985
|
+
if (originHead) return originHead;
|
|
22986
|
+
for (const candidate of ["origin/main", "origin/master"]) {
|
|
22987
|
+
if (await git4(root, ["rev-parse", "--verify", "--quiet", candidate]).then(() => true, () => false)) return candidate;
|
|
22988
|
+
}
|
|
22989
|
+
throw new Error("Can't find this branch on origin; run `git fetch origin` (or push the branch) first");
|
|
22990
|
+
}
|
|
22991
|
+
async function git4(cwd, args, env, trim = true) {
|
|
22992
|
+
const { stdout } = await execFileAsync6("git", ["-C", cwd, ...args], { env: env ?? process.env, maxBuffer: 64 * 1024 * 1024 });
|
|
22993
|
+
return trim ? stdout.trim() : stdout;
|
|
22994
|
+
}
|
|
22995
|
+
var execFileAsync6, MAX_PATCH_CHARS;
|
|
22996
|
+
var init_git = __esm({
|
|
22997
|
+
"src/remote/git.ts"() {
|
|
22998
|
+
"use strict";
|
|
22999
|
+
execFileAsync6 = promisify8(execFile9);
|
|
23000
|
+
MAX_PATCH_CHARS = 3 * 1024 * 1024;
|
|
23001
|
+
}
|
|
23002
|
+
});
|
|
23003
|
+
|
|
23004
|
+
// src/remote/cli.ts
|
|
23005
|
+
var cli_exports2 = {};
|
|
23006
|
+
__export(cli_exports2, {
|
|
23007
|
+
cancelRun: () => cancelRun,
|
|
23008
|
+
describeError: () => describeError,
|
|
23009
|
+
listRuns: () => listRuns,
|
|
23010
|
+
pullRun: () => pullRun,
|
|
23011
|
+
remoteAdd: () => remoteAdd,
|
|
23012
|
+
remoteList: () => remoteList,
|
|
23013
|
+
remoteRemove: () => remoteRemove,
|
|
23014
|
+
runOnRemote: () => runOnRemote,
|
|
23015
|
+
watchRun: () => watchRun
|
|
23016
|
+
});
|
|
23017
|
+
import { execFile as execFile10 } from "child_process";
|
|
23018
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
23019
|
+
import { hostname } from "os";
|
|
23020
|
+
import { promisify as promisify9 } from "util";
|
|
23021
|
+
async function remoteAdd(input, io = processIO) {
|
|
23022
|
+
const url = normalizeServerUrl(input.url);
|
|
23023
|
+
const name = input.name ?? defaultRemoteName(url);
|
|
23024
|
+
if (!REMOTE_NAME_RE.test(name)) throw new Error("Server names are 1-40 lowercase letters, digits, or dashes");
|
|
23025
|
+
const anonymous = new RemoteClient(url, void 0);
|
|
23026
|
+
const device = await anonymous.startDeviceAuthorization(clientName());
|
|
23027
|
+
io.out(`To pair this machine with ${url}, approve code ${device.userCode} at:
|
|
23028
|
+
${device.verificationUriComplete}
|
|
23029
|
+
`);
|
|
23030
|
+
if (input.open !== false && openBrowser(device.verificationUriComplete)) io.out("(opened in your browser)\n");
|
|
23031
|
+
io.out("Waiting for approval\u2026\n");
|
|
23032
|
+
const credential = await anonymous.waitForCredential(device, {
|
|
23033
|
+
...input.signal ? { signal: input.signal } : {},
|
|
23034
|
+
...input.sleep ? { sleep: input.sleep } : {}
|
|
23035
|
+
});
|
|
23036
|
+
const remote = {
|
|
23037
|
+
name,
|
|
23038
|
+
url,
|
|
23039
|
+
token: credential.token,
|
|
23040
|
+
credentialId: credential.credentialId,
|
|
23041
|
+
expiresAt: credential.expiresAt,
|
|
23042
|
+
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23043
|
+
};
|
|
23044
|
+
await new RemoteClient(url, remote.token).health();
|
|
23045
|
+
await saveRemote(remote);
|
|
23046
|
+
io.out(`\u2713 Paired as "${name}" (credential expires ${remote.expiresAt.slice(0, 10)}).
|
|
23047
|
+
Try: autopilot --on ${name} "fix the flaky test"
|
|
23048
|
+
`);
|
|
23049
|
+
return remote;
|
|
23050
|
+
}
|
|
23051
|
+
async function remoteList(io = processIO) {
|
|
23052
|
+
const remotes = await loadRemotes();
|
|
23053
|
+
if (remotes.length === 0) {
|
|
23054
|
+
io.out("No servers paired. Run: autopilot remote add https://your-server\n");
|
|
23055
|
+
return;
|
|
23056
|
+
}
|
|
23057
|
+
for (const remote of remotes) io.out(`${remote.name} ${remote.url} expires ${remote.expiresAt.slice(0, 10)}
|
|
23058
|
+
`);
|
|
23059
|
+
}
|
|
23060
|
+
async function remoteRemove(name, io = processIO) {
|
|
23061
|
+
const removed = await removeRemote(name);
|
|
23062
|
+
if (removed) io.out(`Removed "${name}". To revoke its credential on the server: autopilot aster token revoke <id>
|
|
23063
|
+
`);
|
|
23064
|
+
else io.err(`No server named "${name}".
|
|
23065
|
+
`);
|
|
23066
|
+
return removed;
|
|
23067
|
+
}
|
|
23068
|
+
async function runOnRemote(input, io = processIO) {
|
|
23069
|
+
const remote = await resolveRemote(input.remote);
|
|
23070
|
+
const client = new RemoteClient(remote.url, remote.token);
|
|
23071
|
+
const repository = input.repository ?? await detectGitHubRepository(input.cwd);
|
|
23072
|
+
const snapshot = await snapshotWorkingTree(input.cwd);
|
|
23073
|
+
const [workspaces, models] = await Promise.all([client.workspaces(), client.models()]);
|
|
23074
|
+
const workspace = workspaces[0];
|
|
23075
|
+
if (!workspace) throw new Error(`${remote.name} has no workspace this credential can use`);
|
|
23076
|
+
const model = pickModel(models, input.model, input.preferredModel);
|
|
23077
|
+
io.err(`Starting on ${remote.name}: ${repository} from ${snapshot.baseCommit.slice(0, 7)} (${snapshot.baseRef})${snapshot.files.length ? `, with ${snapshot.files.length} changed file${snapshot.files.length === 1 ? "" : "s"}` : ""} \xB7 ${model}
|
|
23078
|
+
`);
|
|
23079
|
+
const conversation = await client.createCodeConversation({
|
|
23080
|
+
workspaceId: workspace.id,
|
|
23081
|
+
model,
|
|
23082
|
+
repository,
|
|
23083
|
+
baseCommit: snapshot.baseCommit,
|
|
23084
|
+
...snapshot.patch ? { patch: snapshot.patch } : {},
|
|
23085
|
+
idempotencyKey: `cli-${randomUUID8()}`
|
|
23086
|
+
});
|
|
23087
|
+
await client.submitTurn(conversation.conversationId, input.task, `cli-${randomUUID8()}`);
|
|
23088
|
+
const shortId = conversation.conversationId.slice(0, 8);
|
|
23089
|
+
io.err(`Run ${shortId} \xB7 branch ${conversation.branch ?? "?"}
|
|
23090
|
+
`);
|
|
23091
|
+
if (input.detach) {
|
|
23092
|
+
io.err(`Detached. Follow it with: autopilot runs watch ${shortId}
|
|
23093
|
+
`);
|
|
23094
|
+
return 0;
|
|
23095
|
+
}
|
|
23096
|
+
io.err(`Ctrl-C detaches; the run keeps going on the server (autopilot runs watch ${shortId}).
|
|
23097
|
+
|
|
23098
|
+
`);
|
|
23099
|
+
return watchConversation(client, remote, conversation.conversationId, conversation.lastEventId, input.signal, io);
|
|
23100
|
+
}
|
|
23101
|
+
async function listRuns(input, io = processIO) {
|
|
23102
|
+
const remotes = input.remote ? [await resolveRemote(input.remote)] : await loadRemotes();
|
|
23103
|
+
if (remotes.length === 0) throw new Error("No servers paired yet. Run: autopilot remote add https://your-server");
|
|
23104
|
+
const rows = [];
|
|
23105
|
+
for (const remote of remotes) {
|
|
23106
|
+
try {
|
|
23107
|
+
const runs = await new RemoteClient(remote.url, remote.token).listConversations();
|
|
23108
|
+
rows.push(...runs.filter((run) => run.kind === "code").map((run) => ({ ...run, remote: remote.name })));
|
|
23109
|
+
} catch (error) {
|
|
23110
|
+
io.err(`${remote.name}: ${describeError(error)}
|
|
23111
|
+
`);
|
|
23112
|
+
}
|
|
23113
|
+
}
|
|
23114
|
+
rows.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
23115
|
+
if (input.json) {
|
|
23116
|
+
io.out(`${JSON.stringify(rows, null, 2)}
|
|
23117
|
+
`);
|
|
23118
|
+
return;
|
|
23119
|
+
}
|
|
23120
|
+
if (rows.length === 0) {
|
|
23121
|
+
io.out("No runs yet.\n");
|
|
23122
|
+
return;
|
|
23123
|
+
}
|
|
23124
|
+
for (const run of rows) {
|
|
23125
|
+
io.out([
|
|
23126
|
+
run.conversationId.slice(0, 8),
|
|
23127
|
+
run.remote,
|
|
23128
|
+
run.status.padEnd(16),
|
|
23129
|
+
run.repository ?? "",
|
|
23130
|
+
run.pullRequestURL ?? run.branch ?? "",
|
|
23131
|
+
run.createdAt.slice(0, 16).replace("T", " ")
|
|
23132
|
+
].join(" ") + "\n");
|
|
23133
|
+
}
|
|
23134
|
+
}
|
|
23135
|
+
async function watchRun(input, io = processIO) {
|
|
23136
|
+
const { remote, run } = await findRun(input.id, input.remote);
|
|
23137
|
+
const client = new RemoteClient(remote.url, remote.token);
|
|
23138
|
+
const finished = TERMINAL_STATUSES.has(run.status) && !run.activeRunId;
|
|
23139
|
+
return watchConversation(client, remote, run.conversationId, 0, input.signal, io, finished ? run.lastEventId : void 0);
|
|
23140
|
+
}
|
|
23141
|
+
async function cancelRun(input, io = processIO) {
|
|
23142
|
+
const { remote, run } = await findRun(input.id, input.remote);
|
|
23143
|
+
const cancelled = await new RemoteClient(remote.url, remote.token).cancel(run.conversationId);
|
|
23144
|
+
io.out(`${run.conversationId.slice(0, 8)}: ${cancelled.status}
|
|
23145
|
+
`);
|
|
23146
|
+
}
|
|
23147
|
+
async function pullRun(input, io = processIO) {
|
|
23148
|
+
const { run } = await findRun(input.id, input.remote);
|
|
23149
|
+
const branch = run.branch;
|
|
23150
|
+
if (!branch) throw new Error("That run has no branch");
|
|
23151
|
+
if (run.activeRunId) io.err("The run is still going; you'll get what it has pushed so far.\n");
|
|
23152
|
+
const git5 = (args) => execFileAsync7("git", ["-C", input.cwd, ...args]);
|
|
23153
|
+
try {
|
|
23154
|
+
await git5(["fetch", "origin", `+refs/heads/${branch}:refs/remotes/origin/${branch}`]);
|
|
23155
|
+
} catch {
|
|
23156
|
+
throw new Error(`Branch ${branch} isn't on origin yet (the run pushes it when a turn finishes)`);
|
|
23157
|
+
}
|
|
23158
|
+
const exists = await git5(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`]).then(() => true, () => false);
|
|
23159
|
+
if (exists) {
|
|
23160
|
+
await git5(["switch", branch]);
|
|
23161
|
+
await git5(["merge", "--ff-only", `origin/${branch}`]);
|
|
23162
|
+
} else {
|
|
23163
|
+
await git5(["switch", "-c", branch, "--track", `origin/${branch}`]);
|
|
23164
|
+
}
|
|
23165
|
+
io.out(`On ${branch}${run.pullRequestURL ? ` \xB7 ${run.pullRequestURL}` : ""}
|
|
23166
|
+
`);
|
|
23167
|
+
}
|
|
23168
|
+
async function watchConversation(client, remote, conversationId, cursor, signal, io, replayUntil) {
|
|
23169
|
+
const controller = new AbortController();
|
|
23170
|
+
const stop = () => controller.abort();
|
|
23171
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
23172
|
+
if (signal?.aborted) stop();
|
|
23173
|
+
const renderer = new EventRenderer(io);
|
|
23174
|
+
let outcome;
|
|
23175
|
+
try {
|
|
23176
|
+
if (replayUntil === void 0 || replayUntil > cursor) {
|
|
23177
|
+
for await (const event of client.events(conversationId, cursor, controller.signal)) {
|
|
23178
|
+
renderer.render(event);
|
|
23179
|
+
if (RUN_EVENT_TYPES.has(event.type)) outcome = event.type;
|
|
23180
|
+
if (replayUntil === void 0 ? RUN_EVENT_TYPES.has(event.type) : event.id >= replayUntil) break;
|
|
23181
|
+
}
|
|
23182
|
+
}
|
|
23183
|
+
if (replayUntil !== void 0 && !controller.signal.aborted) outcome ??= "completed";
|
|
23184
|
+
} finally {
|
|
23185
|
+
signal?.removeEventListener("abort", stop);
|
|
23186
|
+
controller.abort();
|
|
23187
|
+
}
|
|
23188
|
+
renderer.finish();
|
|
23189
|
+
const shortId = conversationId.slice(0, 8);
|
|
23190
|
+
if (!outcome) {
|
|
23191
|
+
io.err(`
|
|
23192
|
+
Detached from ${shortId}; it keeps running on ${remote.name}. Follow it with: autopilot runs watch ${shortId}
|
|
23193
|
+
`);
|
|
23194
|
+
return 0;
|
|
23195
|
+
}
|
|
23196
|
+
const final = await client.getConversation(conversationId);
|
|
23197
|
+
if (outcome === "completed") {
|
|
23198
|
+
io.err(`
|
|
23199
|
+
\u2713 ${shortId} completed${final.pullRequestURL ? `: ${final.pullRequestURL}` : " (no changes, so no pull request)"}
|
|
23200
|
+
`);
|
|
23201
|
+
if (final.pullRequestURL) io.err(` Check it out locally: autopilot pull ${shortId}
|
|
23202
|
+
`);
|
|
23203
|
+
return 0;
|
|
23204
|
+
}
|
|
23205
|
+
io.err(`
|
|
23206
|
+
\u2717 ${shortId} ${outcome}
|
|
23207
|
+
`);
|
|
23208
|
+
return 1;
|
|
23209
|
+
}
|
|
23210
|
+
async function findRun(id, remoteName) {
|
|
23211
|
+
const needle = id.trim().toLowerCase();
|
|
23212
|
+
if (!/^[0-9a-f-]{4,36}$/.test(needle)) throw new Error("Run IDs are the hex IDs `autopilot runs` shows");
|
|
23213
|
+
const remotes = remoteName ? [await resolveRemote(remoteName)] : await loadRemotes();
|
|
23214
|
+
const matches = [];
|
|
23215
|
+
for (const remote of remotes) {
|
|
23216
|
+
const runs = await new RemoteClient(remote.url, remote.token).listConversations(200).catch(() => []);
|
|
23217
|
+
for (const run of runs) if (run.conversationId.startsWith(needle)) matches.push({ remote, run });
|
|
23218
|
+
}
|
|
23219
|
+
if (matches.length === 0) throw new Error(`No run ${id} on ${remoteName ?? "any paired server"}`);
|
|
23220
|
+
if (matches.length > 1) throw new Error(`${id} matches several runs; use more characters`);
|
|
23221
|
+
return matches[0];
|
|
23222
|
+
}
|
|
23223
|
+
function pickModel(models, requested, preferred) {
|
|
23224
|
+
if (requested) {
|
|
23225
|
+
if (!models.includes(requested)) throw new Error(`The server doesn't offer ${requested}`);
|
|
23226
|
+
return requested;
|
|
23227
|
+
}
|
|
23228
|
+
if (preferred && models.includes(preferred)) return preferred;
|
|
23229
|
+
const first = models[0];
|
|
23230
|
+
if (!first) throw new Error("The server offers no models");
|
|
23231
|
+
return first;
|
|
23232
|
+
}
|
|
23233
|
+
function clientName() {
|
|
23234
|
+
const host = hostname().replace(/\.local$/, "").replace(/[^\p{L}\p{N} ._'()@-]/gu, "-").slice(0, 40) || "laptop";
|
|
23235
|
+
return `${host} (autopilot)`;
|
|
23236
|
+
}
|
|
23237
|
+
function oneLine(text3, max) {
|
|
23238
|
+
const flat = text3.replace(/\s+/g, " ").trim();
|
|
23239
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
23240
|
+
}
|
|
23241
|
+
function describeError(error) {
|
|
23242
|
+
if (error instanceof RemoteApiError) return `${error.message} (${error.code})`;
|
|
23243
|
+
return error instanceof Error ? error.message : String(error);
|
|
23244
|
+
}
|
|
23245
|
+
var execFileAsync7, RUN_EVENT_TYPES, processIO, EventRenderer;
|
|
23246
|
+
var init_cli2 = __esm({
|
|
23247
|
+
"src/remote/cli.ts"() {
|
|
23248
|
+
"use strict";
|
|
23249
|
+
init_open_browser();
|
|
23250
|
+
init_client3();
|
|
23251
|
+
init_config4();
|
|
23252
|
+
init_git();
|
|
23253
|
+
execFileAsync7 = promisify9(execFile10);
|
|
23254
|
+
RUN_EVENT_TYPES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "interrupted"]);
|
|
23255
|
+
processIO = {
|
|
23256
|
+
out: (text3) => process.stdout.write(text3),
|
|
23257
|
+
err: (text3) => process.stderr.write(text3)
|
|
23258
|
+
};
|
|
23259
|
+
EventRenderer = class {
|
|
23260
|
+
constructor(io) {
|
|
23261
|
+
this.io = io;
|
|
23262
|
+
}
|
|
23263
|
+
io;
|
|
23264
|
+
midLine = false;
|
|
23265
|
+
render(event) {
|
|
23266
|
+
const data = event.data;
|
|
23267
|
+
if (event.type === "assistant.delta") {
|
|
23268
|
+
const text3 = typeof data.text === "string" ? data.text : typeof data.delta === "string" ? data.delta : "";
|
|
23269
|
+
if (!text3) return;
|
|
23270
|
+
this.io.out(text3);
|
|
23271
|
+
this.midLine = !text3.endsWith("\n");
|
|
23272
|
+
return;
|
|
23273
|
+
}
|
|
23274
|
+
if (event.type === "tool.activity" && data.activity === "started") {
|
|
23275
|
+
const input = typeof data.input === "string" ? ` ${oneLine(data.input, 120)}` : "";
|
|
23276
|
+
this.line(` \u203A ${String(data.tool ?? "tool")}${input}`);
|
|
23277
|
+
return;
|
|
23278
|
+
}
|
|
23279
|
+
if (event.type === "tool.activity" && data.activity === "failed") {
|
|
23280
|
+
this.line(` \u2717 ${String(data.tool ?? "tool")} failed`);
|
|
23281
|
+
return;
|
|
23282
|
+
}
|
|
23283
|
+
if (event.type === "checkpoint.created" && typeof data.message === "string") {
|
|
23284
|
+
this.line(` \u25CF ${oneLine(data.message, 100)}`);
|
|
23285
|
+
}
|
|
23286
|
+
}
|
|
23287
|
+
finish() {
|
|
23288
|
+
if (this.midLine) this.io.out("\n");
|
|
23289
|
+
this.midLine = false;
|
|
23290
|
+
}
|
|
23291
|
+
line(text3) {
|
|
23292
|
+
this.finish();
|
|
23293
|
+
this.io.out(`${text3}
|
|
23294
|
+
`);
|
|
23295
|
+
}
|
|
23296
|
+
};
|
|
23297
|
+
}
|
|
23298
|
+
});
|
|
23299
|
+
|
|
22380
23300
|
// src/server/aster-workspaces.ts
|
|
22381
23301
|
var aster_workspaces_exports = {};
|
|
22382
23302
|
__export(aster_workspaces_exports, {
|
|
@@ -22387,23 +23307,23 @@ __export(aster_workspaces_exports, {
|
|
|
22387
23307
|
resolveAsterServerConfigPath: () => resolveAsterServerConfigPath
|
|
22388
23308
|
});
|
|
22389
23309
|
import { existsSync as existsSync11 } from "fs";
|
|
22390
|
-
import { readFile as
|
|
22391
|
-
import { homedir as
|
|
22392
|
-
import { isAbsolute as isAbsolute5, join as
|
|
23310
|
+
import { readFile as readFile32, realpath as realpath5, stat as stat11 } from "fs/promises";
|
|
23311
|
+
import { homedir as homedir28 } from "os";
|
|
23312
|
+
import { isAbsolute as isAbsolute5, join as join46, relative as relative8, resolve as resolve14, sep as sep4 } from "path";
|
|
22393
23313
|
function localAsterConfigPath(env = process.env) {
|
|
22394
|
-
const configHome2 = env.XDG_CONFIG_HOME?.trim() ||
|
|
22395
|
-
return
|
|
23314
|
+
const configHome2 = env.XDG_CONFIG_HOME?.trim() || join46(homedir28(), ".config");
|
|
23315
|
+
return resolve14(configHome2, "autopilot", "aster.json");
|
|
22396
23316
|
}
|
|
22397
23317
|
function resolveAsterServerConfigPath(env = process.env) {
|
|
22398
23318
|
const configuredPath = env.AUTOPILOT_ASTER_CONFIG?.trim();
|
|
22399
|
-
if (configuredPath) return
|
|
23319
|
+
if (configuredPath) return resolve14(configuredPath);
|
|
22400
23320
|
const userConfigPath = localAsterConfigPath(env);
|
|
22401
23321
|
return existsSync11(userConfigPath) ? userConfigPath : SYSTEM_ASTER_CONFIG_PATH;
|
|
22402
23322
|
}
|
|
22403
23323
|
async function loadAsterServerConfig(configPath2 = resolveAsterServerConfigPath()) {
|
|
22404
23324
|
let raw;
|
|
22405
23325
|
try {
|
|
22406
|
-
raw = JSON.parse(await
|
|
23326
|
+
raw = JSON.parse(await readFile32(configPath2, "utf8"));
|
|
22407
23327
|
} catch {
|
|
22408
23328
|
throw new AsterConfigError();
|
|
22409
23329
|
}
|
|
@@ -22440,7 +23360,7 @@ async function loadAsterServerConfig(configPath2 = resolveAsterServerConfigPath(
|
|
|
22440
23360
|
let rootPath;
|
|
22441
23361
|
try {
|
|
22442
23362
|
rootPath = await realpath5(workspace.rootPath);
|
|
22443
|
-
if (!(await
|
|
23363
|
+
if (!(await stat11(rootPath)).isDirectory()) throw new Error("not a directory");
|
|
22444
23364
|
} catch {
|
|
22445
23365
|
throw new AsterConfigError();
|
|
22446
23366
|
}
|
|
@@ -22480,10 +23400,10 @@ __export(aster_setup_exports, {
|
|
|
22480
23400
|
setupLocalAsterConfig: () => setupLocalAsterConfig
|
|
22481
23401
|
});
|
|
22482
23402
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
22483
|
-
import { randomUUID as
|
|
23403
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
22484
23404
|
import { existsSync as existsSync12 } from "fs";
|
|
22485
|
-
import { chmod as
|
|
22486
|
-
import { basename as basename9, dirname as
|
|
23405
|
+
import { chmod as chmod5, link, mkdir as mkdir19, realpath as realpath6, rm as rm7, stat as stat12, writeFile as writeFile17 } from "fs/promises";
|
|
23406
|
+
import { basename as basename9, dirname as dirname22, resolve as resolve15 } from "path";
|
|
22487
23407
|
async function setupLocalAsterConfig(options) {
|
|
22488
23408
|
if (options.workspacePaths.length === 0 || options.workspacePaths.length > 100) {
|
|
22489
23409
|
throw new Error("provide between 1 and 100 Git workspace roots");
|
|
@@ -22495,7 +23415,7 @@ async function setupLocalAsterConfig(options) {
|
|
|
22495
23415
|
const requestedWorkspaces = await createWorkspaceEntries(options.workspacePaths);
|
|
22496
23416
|
const env = options.env ?? process.env;
|
|
22497
23417
|
const requestedPath = options.configPath?.trim() || env.AUTOPILOT_ASTER_CONFIG?.trim() || localAsterConfigPath(env);
|
|
22498
|
-
const path =
|
|
23418
|
+
const path = resolve15(requestedPath);
|
|
22499
23419
|
if (existsSync12(path)) {
|
|
22500
23420
|
const config3 = await loadAsterServerConfig(path);
|
|
22501
23421
|
const selectedWorkspaces = requestedWorkspaces.map((requested) => {
|
|
@@ -22511,21 +23431,21 @@ async function setupLocalAsterConfig(options) {
|
|
|
22511
23431
|
models: models.length > 0 ? models : "openrouter",
|
|
22512
23432
|
workspaces: requestedWorkspaces
|
|
22513
23433
|
};
|
|
22514
|
-
const directory =
|
|
22515
|
-
await
|
|
22516
|
-
await
|
|
23434
|
+
const directory = dirname22(path);
|
|
23435
|
+
await mkdir19(directory, { recursive: true, mode: 448 });
|
|
23436
|
+
await chmod5(directory, 448).catch(() => {
|
|
22517
23437
|
});
|
|
22518
|
-
const temporaryPath = `${path}.tmp-${
|
|
23438
|
+
const temporaryPath = `${path}.tmp-${randomUUID9()}`;
|
|
22519
23439
|
try {
|
|
22520
|
-
await
|
|
23440
|
+
await writeFile17(temporaryPath, `${JSON.stringify(config2, null, 2)}
|
|
22521
23441
|
`, { encoding: "utf8", mode: 384, flag: "wx" });
|
|
22522
|
-
await
|
|
23442
|
+
await chmod5(temporaryPath, 384);
|
|
22523
23443
|
const validated = await loadAsterServerConfig(temporaryPath);
|
|
22524
23444
|
await link(temporaryPath, path);
|
|
22525
|
-
await
|
|
23445
|
+
await rm7(temporaryPath);
|
|
22526
23446
|
return { path, config: validated, selectedWorkspaces: validated.workspaces };
|
|
22527
23447
|
} catch (error) {
|
|
22528
|
-
await
|
|
23448
|
+
await rm7(temporaryPath, { force: true }).catch(() => {
|
|
22529
23449
|
});
|
|
22530
23450
|
if (isAlreadyExists(error)) {
|
|
22531
23451
|
return setupLocalAsterConfig(options);
|
|
@@ -22537,11 +23457,11 @@ async function createWorkspaceEntries(paths) {
|
|
|
22537
23457
|
const usedIds = /* @__PURE__ */ new Set();
|
|
22538
23458
|
const workspaces = [];
|
|
22539
23459
|
for (const input of paths) {
|
|
22540
|
-
const requested =
|
|
23460
|
+
const requested = resolve15(input);
|
|
22541
23461
|
let root;
|
|
22542
23462
|
try {
|
|
22543
23463
|
root = await realpath6(requested);
|
|
22544
|
-
if (!(await
|
|
23464
|
+
if (!(await stat12(root)).isDirectory()) throw new Error("not a directory");
|
|
22545
23465
|
const output = execFileSync3("git", ["-C", root, "rev-parse", "--show-toplevel"], {
|
|
22546
23466
|
encoding: "utf8",
|
|
22547
23467
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -22588,13 +23508,13 @@ __export(aster_store_exports, {
|
|
|
22588
23508
|
normalizeUserCode: () => normalizeUserCode
|
|
22589
23509
|
});
|
|
22590
23510
|
import Database4 from "better-sqlite3";
|
|
22591
|
-
import { createHash as createHash7, randomBytes as randomBytes3, randomInt, randomUUID as
|
|
23511
|
+
import { createHash as createHash7, randomBytes as randomBytes3, randomInt, randomUUID as randomUUID10 } from "crypto";
|
|
22592
23512
|
import { chmodSync as chmodSync2, mkdirSync as mkdirSync10 } from "fs";
|
|
22593
|
-
import { homedir as
|
|
22594
|
-
import { dirname as
|
|
23513
|
+
import { homedir as homedir29 } from "os";
|
|
23514
|
+
import { dirname as dirname23, join as join47 } from "path";
|
|
22595
23515
|
function defaultAsterDbPath() {
|
|
22596
|
-
const root = process.env.XDG_STATE_HOME ||
|
|
22597
|
-
return process.env.AUTOPILOT_ASTER_DB ||
|
|
23516
|
+
const root = process.env.XDG_STATE_HOME || join47(homedir29(), ".local", "state");
|
|
23517
|
+
return process.env.AUTOPILOT_ASTER_DB || join47(root, "autopilot", "aster.db");
|
|
22598
23518
|
}
|
|
22599
23519
|
function hashToken(token) {
|
|
22600
23520
|
return createHash7("sha256").update(token).digest("hex");
|
|
@@ -22681,9 +23601,9 @@ var init_aster_store = __esm({
|
|
|
22681
23601
|
AsterStore = class {
|
|
22682
23602
|
db;
|
|
22683
23603
|
constructor(dbPath = defaultAsterDbPath()) {
|
|
22684
|
-
mkdirSync10(
|
|
23604
|
+
mkdirSync10(dirname23(dbPath), { recursive: true, mode: 448 });
|
|
22685
23605
|
try {
|
|
22686
|
-
chmodSync2(
|
|
23606
|
+
chmodSync2(dirname23(dbPath), 448);
|
|
22687
23607
|
} catch {
|
|
22688
23608
|
}
|
|
22689
23609
|
this.db = new Database4(dbPath);
|
|
@@ -22898,7 +23818,7 @@ var init_aster_store = __esm({
|
|
|
22898
23818
|
const scopes = [...new Set(input.scopes)];
|
|
22899
23819
|
if (scopes.length === 0 || scopes.some((scope) => !VALID_SCOPES.has(scope))) throw new Error("credential scopes are invalid");
|
|
22900
23820
|
if (!Number.isSafeInteger(input.expiresAt) || input.expiresAt <= Date.now()) throw new Error("credential expiry must be in the future");
|
|
22901
|
-
const id =
|
|
23821
|
+
const id = randomUUID10();
|
|
22902
23822
|
const token = `aster_${randomBytes3(32).toString("base64url")}`;
|
|
22903
23823
|
const now2 = Date.now();
|
|
22904
23824
|
this.db.prepare(`INSERT INTO aster_credentials
|
|
@@ -22952,7 +23872,7 @@ var init_aster_store = __esm({
|
|
|
22952
23872
|
}
|
|
22953
23873
|
/** The owner's decision on a user code. An approval fixes the credential the client will receive. */
|
|
22954
23874
|
resolveDeviceAuthorization(userCode, decision, grant, now2 = Date.now()) {
|
|
22955
|
-
const
|
|
23875
|
+
const resolve22 = this.db.transaction(() => {
|
|
22956
23876
|
const row = this.db.prepare("SELECT * FROM aster_device_authorizations WHERE user_code = ?").get(normalizeUserCode(userCode));
|
|
22957
23877
|
if (!row) return "not_found";
|
|
22958
23878
|
if (row.status !== "pending") return "already_resolved";
|
|
@@ -22965,7 +23885,7 @@ var init_aster_store = __esm({
|
|
|
22965
23885
|
SET status = 'approved', workspace_ids_json = ?, credential_ttl_ms = ?, resolved_at = ? WHERE user_code = ?`).run(JSON.stringify(grant.workspaceIds), grant.credentialTtlMs, now2, row.user_code);
|
|
22966
23886
|
return "approved";
|
|
22967
23887
|
});
|
|
22968
|
-
return
|
|
23888
|
+
return resolve22.immediate();
|
|
22969
23889
|
}
|
|
22970
23890
|
/** The client's poll. An approved code is exchanged for its credential exactly once. */
|
|
22971
23891
|
redeemDeviceAuthorization(deviceCode, now2 = Date.now()) {
|
|
@@ -23212,7 +24132,7 @@ var init_aster_store = __esm({
|
|
|
23212
24132
|
}));
|
|
23213
24133
|
}
|
|
23214
24134
|
createApproval(input) {
|
|
23215
|
-
const id =
|
|
24135
|
+
const id = randomUUID10();
|
|
23216
24136
|
const now2 = Date.now();
|
|
23217
24137
|
this.db.prepare(`INSERT INTO aster_approvals
|
|
23218
24138
|
(id, conversation_id, run_id, tool_name, explanation, arguments_json, status, expires_at, created_at)
|
|
@@ -23315,9 +24235,9 @@ async function handleAsterPairing(req, res, url, store) {
|
|
|
23315
24235
|
const method = req.method ?? "GET";
|
|
23316
24236
|
if (path === `${AUTH_PREFIX}/device` && method === "POST") {
|
|
23317
24237
|
const body = await readJsonBody(req);
|
|
23318
|
-
const
|
|
23319
|
-
if (!CLIENT_NAME_RE.test(
|
|
23320
|
-
const started2 = store.createDeviceAuthorization({ clientName, ttlMs: DEVICE_CODE_TTL_MS, maxPending: MAX_PENDING_DEVICE_CODES });
|
|
24238
|
+
const clientName2 = typeof body.clientName === "string" ? body.clientName.trim() : "Autopilot CLI";
|
|
24239
|
+
if (!CLIENT_NAME_RE.test(clientName2)) return sendError(res, 400, "invalid_client_name", "clientName must be 1-60 letters, digits, spaces, or ._'()@-");
|
|
24240
|
+
const started2 = store.createDeviceAuthorization({ clientName: clientName2, ttlMs: DEVICE_CODE_TTL_MS, maxPending: MAX_PENDING_DEVICE_CODES });
|
|
23321
24241
|
if (!started2) return sendError(res, 429, "too_many_pending", "Too many pairings are waiting for approval; try again later");
|
|
23322
24242
|
const verificationUri = `${publicBaseUrl(req)}${AUTH_PREFIX}/approve`;
|
|
23323
24243
|
return json(res, 200, {
|
|
@@ -23464,9 +24384,9 @@ function notOwnerBody(code) {
|
|
|
23464
24384
|
<p>You can also approve from the server directly:</p>
|
|
23465
24385
|
<pre>autopilot aster pair approve ${escapeHtml2(code ?? "<code>")}</pre>`;
|
|
23466
24386
|
}
|
|
23467
|
-
function approvalForm(userCode,
|
|
24387
|
+
function approvalForm(userCode, clientName2) {
|
|
23468
24388
|
return `
|
|
23469
|
-
<p><strong>${escapeHtml2(
|
|
24389
|
+
<p><strong>${escapeHtml2(clientName2)}</strong> wants to use this server.</p>
|
|
23470
24390
|
<p class="code">${escapeHtml2(userCode)}</p>
|
|
23471
24391
|
<p class="muted">Approve only if this matches the code shown on your device.</p>
|
|
23472
24392
|
<form method="post" action="${AUTH_PREFIX}/approve">
|
|
@@ -23587,7 +24507,7 @@ __export(keys_exports, {
|
|
|
23587
24507
|
saveProviderKey: () => saveProviderKey,
|
|
23588
24508
|
switchProvider: () => switchProvider
|
|
23589
24509
|
});
|
|
23590
|
-
import { readFile as
|
|
24510
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
23591
24511
|
function looksLikeProviderKey(id, key) {
|
|
23592
24512
|
if (id === "openrouter") return looksLikeOpenRouterKey(key);
|
|
23593
24513
|
return key.length >= 8 && !/\s/.test(key);
|
|
@@ -23670,7 +24590,7 @@ async function checkProviderKey(id, key, baseUrl, fetchImpl2 = fetch) {
|
|
|
23670
24590
|
}
|
|
23671
24591
|
async function persistedProviders() {
|
|
23672
24592
|
try {
|
|
23673
|
-
const raw = JSON.parse(await
|
|
24593
|
+
const raw = JSON.parse(await readFile33(configPath(), "utf8"));
|
|
23674
24594
|
return raw.providers ?? {};
|
|
23675
24595
|
} catch {
|
|
23676
24596
|
return {};
|
|
@@ -23948,7 +24868,7 @@ __export(github_auth_exports, {
|
|
|
23948
24868
|
authGitHubForTui: () => authGitHubForTui
|
|
23949
24869
|
});
|
|
23950
24870
|
function sleep4(ms) {
|
|
23951
|
-
return new Promise((
|
|
24871
|
+
return new Promise((resolve22) => setTimeout(resolve22, ms));
|
|
23952
24872
|
}
|
|
23953
24873
|
async function* authGitHubForTui() {
|
|
23954
24874
|
yield { message: "Starting GitHub OAuth device flow..." };
|
|
@@ -24030,6 +24950,23 @@ var init_github_auth = __esm({
|
|
|
24030
24950
|
}
|
|
24031
24951
|
});
|
|
24032
24952
|
|
|
24953
|
+
// src/server/serve-config.ts
|
|
24954
|
+
var serve_config_exports = {};
|
|
24955
|
+
__export(serve_config_exports, {
|
|
24956
|
+
resolveServeConfig: () => resolveServeConfig
|
|
24957
|
+
});
|
|
24958
|
+
function resolveServeConfig(cfg, env = process.env) {
|
|
24959
|
+
if (cfg) return { config: cfg, asterOnly: false };
|
|
24960
|
+
if (!env.AUTOPILOT_HOTCELL_ENDPOINT?.trim()) return void 0;
|
|
24961
|
+
return { config: { model: DEFAULT_MODEL }, asterOnly: true };
|
|
24962
|
+
}
|
|
24963
|
+
var init_serve_config = __esm({
|
|
24964
|
+
"src/server/serve-config.ts"() {
|
|
24965
|
+
"use strict";
|
|
24966
|
+
init_config();
|
|
24967
|
+
}
|
|
24968
|
+
});
|
|
24969
|
+
|
|
24033
24970
|
// src/runs/notifications.ts
|
|
24034
24971
|
function resendTransport(apiKey, opts2 = {}) {
|
|
24035
24972
|
const fetchImpl2 = opts2.fetchImpl ?? fetch;
|
|
@@ -24955,13 +25892,13 @@ var init_openapi = __esm({
|
|
|
24955
25892
|
});
|
|
24956
25893
|
|
|
24957
25894
|
// src/runs/worktrees.ts
|
|
24958
|
-
import { execFile as
|
|
24959
|
-
import { access as access2, chmod as
|
|
24960
|
-
import { homedir as
|
|
24961
|
-
import { isAbsolute as isAbsolute6, join as
|
|
25895
|
+
import { execFile as execFile11 } from "child_process";
|
|
25896
|
+
import { access as access2, chmod as chmod6, mkdir as mkdir20, realpath as realpath7 } from "fs/promises";
|
|
25897
|
+
import { homedir as homedir30 } from "os";
|
|
25898
|
+
import { isAbsolute as isAbsolute6, join as join48, parse, relative as relative9, resolve as resolve16, sep as sep5 } from "path";
|
|
24962
25899
|
function defaultWorktreesDir() {
|
|
24963
|
-
const dataHome = process.env.XDG_DATA_HOME ||
|
|
24964
|
-
return
|
|
25900
|
+
const dataHome = process.env.XDG_DATA_HOME || join48(homedir30(), ".local", "share");
|
|
25901
|
+
return join48(dataHome, "autopilot", "worktrees");
|
|
24965
25902
|
}
|
|
24966
25903
|
function isOutside(path) {
|
|
24967
25904
|
return path === ".." || path.startsWith(`..${sep5}`) || isAbsolute6(path);
|
|
@@ -24972,7 +25909,7 @@ function isWithin3(parent, candidate) {
|
|
|
24972
25909
|
}
|
|
24973
25910
|
function runGit(args, cwd) {
|
|
24974
25911
|
return new Promise((resolveOutput, reject) => {
|
|
24975
|
-
|
|
25912
|
+
execFile11("git", args, { cwd, encoding: "utf8", timeout: 3e4, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
|
|
24976
25913
|
if (error) {
|
|
24977
25914
|
const detail = stderr.trim();
|
|
24978
25915
|
reject(new Error(`git ${args[0]} failed${detail ? `: ${detail}` : ""}`, { cause: error }));
|
|
@@ -25002,17 +25939,17 @@ var init_worktrees = __esm({
|
|
|
25002
25939
|
if (isOutside(sourceRelativePath)) {
|
|
25003
25940
|
throw new Error("sourceCwd must be inside the Git repository");
|
|
25004
25941
|
}
|
|
25005
|
-
const configuredRoot =
|
|
25942
|
+
const configuredRoot = resolve16(this.rootDir);
|
|
25006
25943
|
if (configuredRoot === parse(configuredRoot).root || isWithin3(repository, configuredRoot)) {
|
|
25007
25944
|
throw new Error("worktree root must be outside the source repository and not the filesystem root");
|
|
25008
25945
|
}
|
|
25009
|
-
await
|
|
25946
|
+
await mkdir20(configuredRoot, { recursive: true, mode: 448 });
|
|
25010
25947
|
const worktreesRoot = await realpath7(configuredRoot);
|
|
25011
25948
|
if (isWithin3(repository, worktreesRoot)) {
|
|
25012
25949
|
throw new Error("worktree root must be outside the source repository");
|
|
25013
25950
|
}
|
|
25014
|
-
await
|
|
25015
|
-
const worktreePath =
|
|
25951
|
+
await chmod6(worktreesRoot, 448);
|
|
25952
|
+
const worktreePath = join48(worktreesRoot, runId);
|
|
25016
25953
|
try {
|
|
25017
25954
|
await access2(worktreePath);
|
|
25018
25955
|
throw new Error(`worktree path already exists for run ${runId}`);
|
|
@@ -25026,7 +25963,7 @@ var init_worktrees = __esm({
|
|
|
25026
25963
|
repositoryRoot: repository,
|
|
25027
25964
|
sourceCwd: source,
|
|
25028
25965
|
worktreePath,
|
|
25029
|
-
cwd:
|
|
25966
|
+
cwd: resolve16(worktreePath, sourceRelativePath),
|
|
25030
25967
|
branch
|
|
25031
25968
|
};
|
|
25032
25969
|
}
|
|
@@ -25108,10 +26045,10 @@ var init_wake_scheduler = __esm({
|
|
|
25108
26045
|
scheduleNextTick() {
|
|
25109
26046
|
if (!this.running || this.disposed) return;
|
|
25110
26047
|
const nextAt = this.store.nextTimerAt();
|
|
25111
|
-
const
|
|
26048
|
+
const delay2 = nextAt === null ? IDLE_RECHECK_MS : Math.max(0, Math.min(MAX_NODE_TIMEOUT_MS, nextAt - Date.now()));
|
|
25112
26049
|
this.timer = setTimeout(() => {
|
|
25113
26050
|
void this.tick();
|
|
25114
|
-
},
|
|
26051
|
+
}, delay2);
|
|
25115
26052
|
this.timer.unref();
|
|
25116
26053
|
}
|
|
25117
26054
|
async processTimer(timer2, now2) {
|
|
@@ -25473,9 +26410,9 @@ var init_aster_tools = __esm({
|
|
|
25473
26410
|
|
|
25474
26411
|
// src/server/aster-memory.ts
|
|
25475
26412
|
import Database5 from "better-sqlite3";
|
|
25476
|
-
import { randomUUID as
|
|
26413
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
25477
26414
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync11 } from "fs";
|
|
25478
|
-
import { dirname as
|
|
26415
|
+
import { dirname as dirname24 } from "path";
|
|
25479
26416
|
function rowToItem(row) {
|
|
25480
26417
|
return {
|
|
25481
26418
|
id: row.id,
|
|
@@ -25528,7 +26465,7 @@ var init_aster_memory = __esm({
|
|
|
25528
26465
|
AsterMemory = class {
|
|
25529
26466
|
constructor(dbPath = defaultAsterDbPath(), options = {}) {
|
|
25530
26467
|
this.options = options;
|
|
25531
|
-
mkdirSync11(
|
|
26468
|
+
mkdirSync11(dirname24(dbPath), { recursive: true, mode: 448 });
|
|
25532
26469
|
this.db = new Database5(dbPath);
|
|
25533
26470
|
this.db.pragma("journal_mode = WAL");
|
|
25534
26471
|
this.db.pragma("busy_timeout = 5000");
|
|
@@ -25592,7 +26529,7 @@ var init_aster_memory = __esm({
|
|
|
25592
26529
|
this.db.prepare("UPDATE aster_memories SET title = ?, content = ?, pinned = ?, updated_at = ? WHERE id = ?").run(title, content, existing.pinned || input.pinned ? 1 : 0, now2, existing.id);
|
|
25593
26530
|
return { item: this.get(existing.id), change: "updated" };
|
|
25594
26531
|
}
|
|
25595
|
-
const id =
|
|
26532
|
+
const id = randomUUID11();
|
|
25596
26533
|
this.db.prepare(`INSERT INTO aster_memories (id, kind, key, title, content, pinned, source_conversation_id, created_at, updated_at)
|
|
25597
26534
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.kind, input.key ?? null, title, content, input.pinned ? 1 : 0, input.sourceConversationId ?? null, now2, now2);
|
|
25598
26535
|
return { item: this.get(id), change: "added" };
|
|
@@ -25780,14 +26717,14 @@ function parseReceivePackCommands(data) {
|
|
|
25780
26717
|
function isSafeBranch(branch) {
|
|
25781
26718
|
return /^[A-Za-z0-9._/-]{1,200}$/.test(branch) && !branch.startsWith("-") && !branch.endsWith("/") && !branch.includes("..") && !branch.includes("//") && !branch.includes("@{") && branch.split("/").every((part) => part !== "" && part !== "." && part !== ".." && !part.endsWith(".lock"));
|
|
25782
26719
|
}
|
|
25783
|
-
function upstreamHeaders(req, token,
|
|
26720
|
+
function upstreamHeaders(req, token, git5) {
|
|
25784
26721
|
const headers = {};
|
|
25785
26722
|
for (const name of FORWARDED_REQUEST_HEADERS) {
|
|
25786
26723
|
const value = req.headers[name];
|
|
25787
26724
|
if (typeof value === "string") headers[name] = value;
|
|
25788
26725
|
}
|
|
25789
26726
|
headers["user-agent"] ??= "autopilot-aster";
|
|
25790
|
-
headers.authorization =
|
|
26727
|
+
headers.authorization = git5 ? "Basic " + Buffer.from(`x-access-token:${token}`).toString("base64") : `Bearer ${token}`;
|
|
25791
26728
|
return headers;
|
|
25792
26729
|
}
|
|
25793
26730
|
function pipeResponse(upstreamRes, res) {
|
|
@@ -25837,9 +26774,9 @@ var init_aster_github_proxy = __esm({
|
|
|
25837
26774
|
gitUpstream;
|
|
25838
26775
|
async listen(port, host) {
|
|
25839
26776
|
this.server = createServer2((req, res) => this.handle(req, res));
|
|
25840
|
-
await new Promise((
|
|
26777
|
+
await new Promise((resolve22, reject) => {
|
|
25841
26778
|
this.server.once("error", reject);
|
|
25842
|
-
this.server.listen(port, host, () =>
|
|
26779
|
+
this.server.listen(port, host, () => resolve22());
|
|
25843
26780
|
});
|
|
25844
26781
|
const address = this.server.address();
|
|
25845
26782
|
return typeof address === "object" && address ? address.port : port;
|
|
@@ -25850,8 +26787,8 @@ var init_aster_github_proxy = __esm({
|
|
|
25850
26787
|
}
|
|
25851
26788
|
handle(req, res, pathOverride) {
|
|
25852
26789
|
const url = new URL(pathOverride ?? req.url ?? "/", "http://proxy.local");
|
|
25853
|
-
const
|
|
25854
|
-
if (!
|
|
26790
|
+
const git5 = url.pathname.match(GIT_PATH_RE);
|
|
26791
|
+
if (!git5) return deny(res, 404, "Only Git Smart HTTP is available through this proxy");
|
|
25855
26792
|
const grantToken = extractToken(req);
|
|
25856
26793
|
if (!grantToken) {
|
|
25857
26794
|
res.writeHead(401, { "www-authenticate": 'Basic realm="aster-github"', "content-type": "text/plain" });
|
|
@@ -25860,7 +26797,7 @@ var init_aster_github_proxy = __esm({
|
|
|
25860
26797
|
}
|
|
25861
26798
|
const grant = this.options.resolveGrant(grantToken);
|
|
25862
26799
|
if (!grant) return deny(res, 403, "This repository grant is invalid or was revoked");
|
|
25863
|
-
const [, owner, name, service] =
|
|
26800
|
+
const [, owner, name, service] = git5;
|
|
25864
26801
|
if (`${owner}/${name}`.toLowerCase() !== grant.repository.toLowerCase()) {
|
|
25865
26802
|
return deny(res, 403, `This conversation can only access ${grant.repository}`);
|
|
25866
26803
|
}
|
|
@@ -26021,7 +26958,7 @@ var init_aster_push = __esm({
|
|
|
26021
26958
|
};
|
|
26022
26959
|
if (this.options.deliver) return this.options.deliver({ host, token, headers, payload });
|
|
26023
26960
|
const session = this.session(host);
|
|
26024
|
-
return await new Promise((
|
|
26961
|
+
return await new Promise((resolve22, reject) => {
|
|
26025
26962
|
const stream = session.request({ ":method": "POST", ":path": `/3/device/${token}`, ...headers, "content-type": "application/json" });
|
|
26026
26963
|
let status = 0;
|
|
26027
26964
|
stream.setTimeout(15e3, () => stream.close());
|
|
@@ -26029,7 +26966,7 @@ var init_aster_push = __esm({
|
|
|
26029
26966
|
status = Number(responseHeaders[":status"]) || 0;
|
|
26030
26967
|
});
|
|
26031
26968
|
stream.on("error", reject);
|
|
26032
|
-
stream.on("close", () =>
|
|
26969
|
+
stream.on("close", () => resolve22(status));
|
|
26033
26970
|
stream.resume();
|
|
26034
26971
|
stream.end(payload);
|
|
26035
26972
|
});
|
|
@@ -26060,9 +26997,9 @@ var init_aster_push = __esm({
|
|
|
26060
26997
|
});
|
|
26061
26998
|
|
|
26062
26999
|
// src/server/aster-api.ts
|
|
26063
|
-
import { randomUUID as
|
|
27000
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
26064
27001
|
import { unlink as unlink3 } from "fs/promises";
|
|
26065
|
-
import { resolve as
|
|
27002
|
+
import { resolve as resolve17 } from "path";
|
|
26066
27003
|
function parseCursor(header, query) {
|
|
26067
27004
|
const value = (Array.isArray(header) ? header[0] : header) ?? query ?? "0";
|
|
26068
27005
|
if (!/^\d{1,16}$/.test(value)) return void 0;
|
|
@@ -26164,7 +27101,7 @@ function json2(res, status, data) {
|
|
|
26164
27101
|
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" });
|
|
26165
27102
|
res.end(JSON.stringify(data));
|
|
26166
27103
|
}
|
|
26167
|
-
var API_PREFIX, MAX_BODY_BYTES, MAX_USER_TURN_CHARS, CLIENT_TURN_ID_RE, CREATE_IDEMPOTENCY_KEY_RE, MAX_APPROVAL_ARG_BYTES, CONVERSATION_ID_RE, ALLOWED_ASTER_TOOLS, BASE_COMMIT_RE,
|
|
27104
|
+
var API_PREFIX, MAX_BODY_BYTES, MAX_USER_TURN_CHARS, CLIENT_TURN_ID_RE, CREATE_IDEMPOTENCY_KEY_RE, MAX_APPROVAL_ARG_BYTES, CONVERSATION_ID_RE, ALLOWED_ASTER_TOOLS, BASE_COMMIT_RE, MAX_PATCH_CHARS2, MAX_LISTED_CONVERSATIONS, AsterApi;
|
|
26168
27105
|
var init_aster_api = __esm({
|
|
26169
27106
|
"src/server/aster-api.ts"() {
|
|
26170
27107
|
"use strict";
|
|
@@ -26190,7 +27127,7 @@ var init_aster_api = __esm({
|
|
|
26190
27127
|
CONVERSATION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
26191
27128
|
ALLOWED_ASTER_TOOLS = ["read", "write", "edit"];
|
|
26192
27129
|
BASE_COMMIT_RE = /^[0-9a-f]{40}$/;
|
|
26193
|
-
|
|
27130
|
+
MAX_PATCH_CHARS2 = 3 * 1024 * 1024;
|
|
26194
27131
|
MAX_LISTED_CONVERSATIONS = 200;
|
|
26195
27132
|
AsterApi = class {
|
|
26196
27133
|
store;
|
|
@@ -26310,7 +27247,7 @@ var init_aster_api = __esm({
|
|
|
26310
27247
|
if (body.baseCommit !== void 0 && (typeof body.baseCommit !== "string" || !BASE_COMMIT_RE.test(body.baseCommit))) {
|
|
26311
27248
|
return sendError2(res, 400, "invalid_base_commit", "baseCommit must be a full 40-character commit SHA");
|
|
26312
27249
|
}
|
|
26313
|
-
if (body.patch !== void 0 && (typeof body.patch !== "string" || body.patch.length >
|
|
27250
|
+
if (body.patch !== void 0 && (typeof body.patch !== "string" || body.patch.length > MAX_PATCH_CHARS2)) {
|
|
26314
27251
|
return sendError2(res, 400, "invalid_patch", "patch must be a git diff of at most 3 MiB");
|
|
26315
27252
|
}
|
|
26316
27253
|
if (typeof body.patch === "string" && containsLikelyProviderSecret(body.patch)) {
|
|
@@ -26675,8 +27612,8 @@ var init_aster_api = __esm({
|
|
|
26675
27612
|
};
|
|
26676
27613
|
}
|
|
26677
27614
|
async createConversation(res, store, principal, workspace, model, idempotencyKey, kind, repository, changes) {
|
|
26678
|
-
const candidateId =
|
|
26679
|
-
const candidateSessionId =
|
|
27615
|
+
const candidateId = randomUUID12();
|
|
27616
|
+
const candidateSessionId = randomUUID12();
|
|
26680
27617
|
const reservation = store.reserveCellConversation({
|
|
26681
27618
|
conversationId: candidateId,
|
|
26682
27619
|
credentialId: principal.credentialId,
|
|
@@ -26817,12 +27754,12 @@ var init_aster_api = __esm({
|
|
|
26817
27754
|
sendError2(res, 409, "conversation_cell_unavailable", "Conversation cell is not available");
|
|
26818
27755
|
return;
|
|
26819
27756
|
}
|
|
26820
|
-
const runId =
|
|
27757
|
+
const runId = randomUUID12();
|
|
26821
27758
|
if (!idempotent && !store.beginTurn(conversation.id, runId)) {
|
|
26822
27759
|
sendError2(res, 409, "conversation_busy", "A turn is already active for this conversation");
|
|
26823
27760
|
return;
|
|
26824
27761
|
}
|
|
26825
|
-
const sessionPath =
|
|
27762
|
+
const sessionPath = resolve17(sessionsDir(), conversation.sessionId + ".json");
|
|
26826
27763
|
let sessionFile;
|
|
26827
27764
|
try {
|
|
26828
27765
|
sessionFile = await loadSession(sessionPath);
|
|
@@ -27132,7 +28069,7 @@ var init_aster_api = __esm({
|
|
|
27132
28069
|
}
|
|
27133
28070
|
try {
|
|
27134
28071
|
if (mapping.cellId) await this.runtime.destroyCell(mapping.cellId);
|
|
27135
|
-
await unlink3(
|
|
28072
|
+
await unlink3(resolve17(sessionsDir(), mapping.sessionId + ".json")).catch(() => {
|
|
27136
28073
|
});
|
|
27137
28074
|
store.setCellStatus(conversation.id, "destroyed");
|
|
27138
28075
|
store.setConversationStatus(conversation.id, "destroyed");
|
|
@@ -27179,7 +28116,7 @@ var init_aster_api = __esm({
|
|
|
27179
28116
|
return void 0;
|
|
27180
28117
|
}
|
|
27181
28118
|
try {
|
|
27182
|
-
const sessionPath =
|
|
28119
|
+
const sessionPath = resolve17(sessionsDir(), conversation.sessionId + ".json");
|
|
27183
28120
|
const sessionFile = await loadSession(sessionPath);
|
|
27184
28121
|
sessionFile.model = model;
|
|
27185
28122
|
await saveSession(sessionFile);
|
|
@@ -27318,10 +28255,10 @@ data: ${JSON.stringify(event.data)}
|
|
|
27318
28255
|
});
|
|
27319
28256
|
|
|
27320
28257
|
// src/server/aster-cell-runtime.ts
|
|
27321
|
-
import { execFile as
|
|
27322
|
-
import { readFile as
|
|
27323
|
-
import { promisify as
|
|
27324
|
-
import { randomUUID as
|
|
28258
|
+
import { execFile as execFile12 } from "child_process";
|
|
28259
|
+
import { readFile as readFile34 } from "fs/promises";
|
|
28260
|
+
import { promisify as promisify10 } from "util";
|
|
28261
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
27325
28262
|
async function writeCellFileChunked(cell, path, content) {
|
|
27326
28263
|
if (Buffer.byteLength(content, "utf8") <= CELL_FILE_WRITE_CHUNK_CHARS) {
|
|
27327
28264
|
await cell.writeFile(path, content, { mode: "0600" });
|
|
@@ -27349,14 +28286,14 @@ async function writeCellFileChunked(cell, path, content) {
|
|
|
27349
28286
|
async function readBundledCellSdkBundle() {
|
|
27350
28287
|
for (const url of [new URL("./sdk/index.js", import.meta.url), new URL("../sdk/index.js", import.meta.url)]) {
|
|
27351
28288
|
try {
|
|
27352
|
-
return await
|
|
28289
|
+
return await readFile34(url, "utf8");
|
|
27353
28290
|
} catch {
|
|
27354
28291
|
}
|
|
27355
28292
|
}
|
|
27356
28293
|
throw new Error("cell_runtime_bundle_unavailable");
|
|
27357
28294
|
}
|
|
27358
28295
|
async function defaultArchiveWorkspace(workspaceRoot) {
|
|
27359
|
-
const { stdout } = await
|
|
28296
|
+
const { stdout } = await execFileAsync8("git", ["-C", workspaceRoot, "archive", "--format=tar", "HEAD"], {
|
|
27360
28297
|
encoding: "buffer",
|
|
27361
28298
|
maxBuffer: 512 * 1024 * 1024
|
|
27362
28299
|
});
|
|
@@ -27402,15 +28339,15 @@ function boundedToolText(text3, limit) {
|
|
|
27402
28339
|
${redacted.slice(-half)}`;
|
|
27403
28340
|
}
|
|
27404
28341
|
function sleep5(ms) {
|
|
27405
|
-
return new Promise((
|
|
28342
|
+
return new Promise((resolve22) => setTimeout(resolve22, ms));
|
|
27406
28343
|
}
|
|
27407
|
-
var
|
|
28344
|
+
var execFileAsync8, 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_RE2, REPOSITORY_RE, GIT, COMMIT_SHA_RE, FULL_COMMIT_SHA_RE, LOCAL_CHANGES_PATCH, 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;
|
|
27408
28345
|
var init_aster_cell_runtime = __esm({
|
|
27409
28346
|
"src/server/aster-cell-runtime.ts"() {
|
|
27410
28347
|
"use strict";
|
|
27411
28348
|
init_version();
|
|
27412
28349
|
init_aster_tools();
|
|
27413
|
-
|
|
28350
|
+
execFileAsync8 = promisify10(execFile12);
|
|
27414
28351
|
CELL_WORKSPACE = "/workspace";
|
|
27415
28352
|
CELL_STATE_DIR = "/workspace/.aster";
|
|
27416
28353
|
CHECKPOINT_MESSAGE_FILE = `${CELL_STATE_DIR}/checkpoint-message`;
|
|
@@ -27519,7 +28456,7 @@ var init_aster_cell_runtime = __esm({
|
|
|
27519
28456
|
await this.installRuntime(cell);
|
|
27520
28457
|
await this.ensureBridge(cell);
|
|
27521
28458
|
await this.control(cell, "POST", "/rpc", {
|
|
27522
|
-
id:
|
|
28459
|
+
id: randomUUID13(),
|
|
27523
28460
|
type: "new_session",
|
|
27524
28461
|
sessionId: input.sessionId,
|
|
27525
28462
|
config: { model: input.model, cwd: CELL_WORKSPACE }
|
|
@@ -27538,7 +28475,7 @@ var init_aster_cell_runtime = __esm({
|
|
|
27538
28475
|
/** Switch the cell session's model between turns. The bridge persists it for session restore. */
|
|
27539
28476
|
async setModel(cellId, model) {
|
|
27540
28477
|
await this.ensureReady(cellId);
|
|
27541
|
-
await this.controlById(cellId, "POST", "/rpc", { id:
|
|
28478
|
+
await this.controlById(cellId, "POST", "/rpc", { id: randomUUID13(), type: "set_model", modelId: model });
|
|
27542
28479
|
}
|
|
27543
28480
|
/** Reinstall the runtime if the cell's image lost it and restart the bridge if it isn't running. */
|
|
27544
28481
|
async ensureReady(cellId) {
|
|
@@ -27636,7 +28573,7 @@ var init_aster_cell_runtime = __esm({
|
|
|
27636
28573
|
const active = this.activeRuns.get(runId);
|
|
27637
28574
|
if (!active) return;
|
|
27638
28575
|
active.stop();
|
|
27639
|
-
void this.controlById(active.cellId, "POST", "/rpc", { id:
|
|
28576
|
+
void this.controlById(active.cellId, "POST", "/rpc", { id: randomUUID13(), type: "abort" }).catch(() => {
|
|
27640
28577
|
});
|
|
27641
28578
|
}
|
|
27642
28579
|
async runTurn(turn, options = {}) {
|
|
@@ -27736,7 +28673,7 @@ ${turn.userText}` : turn.userText;
|
|
|
27736
28673
|
args: event.args ?? {}
|
|
27737
28674
|
});
|
|
27738
28675
|
await this.controlById(cellId, "POST", "/rpc", {
|
|
27739
|
-
id:
|
|
28676
|
+
id: randomUUID13(),
|
|
27740
28677
|
type: "resolve_permission",
|
|
27741
28678
|
requestId: event.requestId,
|
|
27742
28679
|
decision
|
|
@@ -27917,9 +28854,9 @@ ${turn.userText}` : turn.userText;
|
|
|
27917
28854
|
if (!isSafeArtifactPath(path)) throw new Error("invalid_artifact_path");
|
|
27918
28855
|
const cell = await this.provider.getCell(cellId);
|
|
27919
28856
|
const file = shellQuote2(`${ARTIFACTS_DIR}/${path}`);
|
|
27920
|
-
const
|
|
27921
|
-
if (
|
|
27922
|
-
if (Number(
|
|
28857
|
+
const stat15 = await cell.exec(`[ -f ${file} ] && [ ! -L ${file} ] && stat -c %s -- ${file}`);
|
|
28858
|
+
if (stat15.exitCode !== 0) throw new Error("artifact_not_found");
|
|
28859
|
+
if (Number(stat15.stdout.trim()) > MAX_ARTIFACT_BYTES) throw new Error("artifact_too_large");
|
|
27923
28860
|
const encoded = await cell.exec(`base64 -w0 -- ${file}`);
|
|
27924
28861
|
if (encoded.exitCode !== 0) throw new Error("artifact_not_found");
|
|
27925
28862
|
return { data: Buffer.from(encoded.stdout.trim(), "base64"), mimeType: artifactMimeType(path), name: path.split("/").pop() ?? path };
|
|
@@ -27998,7 +28935,7 @@ ${text3}` : text3, { mode: "0600" });
|
|
|
27998
28935
|
}
|
|
27999
28936
|
}
|
|
28000
28937
|
async control(cell, method, path, body) {
|
|
28001
|
-
const requestId =
|
|
28938
|
+
const requestId = randomUUID13();
|
|
28002
28939
|
await cell.mkdir(CELL_CONTROL_DIR, { parents: true });
|
|
28003
28940
|
await writeCellFileChunked(cell, `${CELL_CONTROL_DIR}/${requestId}.json`, JSON.stringify({ method, path, body }));
|
|
28004
28941
|
const result2 = await cell.exec(`${CONTROL_RUNNER} ${requestId}`);
|
|
@@ -28214,11 +29151,11 @@ var init_hotcell_provider = __esm({
|
|
|
28214
29151
|
});
|
|
28215
29152
|
|
|
28216
29153
|
// src/server/routes.ts
|
|
28217
|
-
import { randomUUID as
|
|
28218
|
-
import { hostname } from "os";
|
|
29154
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
29155
|
+
import { hostname as hostname2 } from "os";
|
|
28219
29156
|
import { URL as URL2 } from "url";
|
|
28220
29157
|
import { unlink as unlink4 } from "fs/promises";
|
|
28221
|
-
import { resolve as
|
|
29158
|
+
import { resolve as resolve18 } from "path";
|
|
28222
29159
|
function createHotcellAsterRuntime() {
|
|
28223
29160
|
try {
|
|
28224
29161
|
const idlePauseMs = Number(process.env.AUTOPILOT_ASTER_IDLE_PAUSE_MS ?? 15 * 60 * 1e3);
|
|
@@ -28282,6 +29219,9 @@ function json3(res, status, data) {
|
|
|
28282
29219
|
function badRequest(res, message2) {
|
|
28283
29220
|
json3(res, 400, { error: message2 });
|
|
28284
29221
|
}
|
|
29222
|
+
function promptBlocked(res, reason) {
|
|
29223
|
+
json3(res, 403, { error: "prompt_blocked", reason, message: `prompt blocked by a UserPromptSubmit hook: ${reason}` });
|
|
29224
|
+
}
|
|
28285
29225
|
function notFound(res, message2) {
|
|
28286
29226
|
json3(res, 404, { error: message2 });
|
|
28287
29227
|
}
|
|
@@ -28301,9 +29241,9 @@ async function resolveFiles2(filePatterns, cwd) {
|
|
|
28301
29241
|
const resolved = /* @__PURE__ */ new Set();
|
|
28302
29242
|
for (const pattern of filePatterns) {
|
|
28303
29243
|
try {
|
|
28304
|
-
const
|
|
28305
|
-
if (
|
|
28306
|
-
resolved.add(
|
|
29244
|
+
const stat15 = await import("fs/promises").then((m) => m.stat(resolve18(cwd, pattern)));
|
|
29245
|
+
if (stat15.isFile()) {
|
|
29246
|
+
resolved.add(resolve18(cwd, pattern));
|
|
28307
29247
|
continue;
|
|
28308
29248
|
}
|
|
28309
29249
|
} catch {
|
|
@@ -28353,7 +29293,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
28353
29293
|
if (!run.sessionId) throw new Error("Cannot restore run without a session id: " + run.id);
|
|
28354
29294
|
const existing = activeRuns.get(run.id) ?? activeSessions.get(run.sessionId);
|
|
28355
29295
|
if (existing) return existing;
|
|
28356
|
-
const sessionFile = await loadSession(
|
|
29296
|
+
const sessionFile = await loadSession(resolve18(sessionsDir(), run.sessionId + ".json"));
|
|
28357
29297
|
const allowedTools = new Set(run.allowedTools);
|
|
28358
29298
|
allowedTools.add("wait_for");
|
|
28359
29299
|
const tools = ALL_TOOLS.filter((tool) => allowedTools.has(tool.name));
|
|
@@ -28405,7 +29345,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
28405
29345
|
}
|
|
28406
29346
|
});
|
|
28407
29347
|
const notificationSettings = notificationSettingsFromConfig(config2);
|
|
28408
|
-
const stopNotifications = notificationSettings ? startNotificationDispatcher(() => new RunStore(), notificationSettings, { host:
|
|
29348
|
+
const stopNotifications = notificationSettings ? startNotificationDispatcher(() => new RunStore(), notificationSettings, { host: hostname2() }) : () => {
|
|
28409
29349
|
};
|
|
28410
29350
|
const imapSettings = notificationSettings?.decisionsReplyTo ? imapSettingsFromEnv() : null;
|
|
28411
29351
|
const stopDecisions = imapSettings && notificationSettings ? startDecisionPoller(imapSettings, async (mail) => {
|
|
@@ -28420,7 +29360,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
28420
29360
|
},
|
|
28421
29361
|
modelExists: (id) => listModels().some((m) => m.id === id),
|
|
28422
29362
|
confirm: async (to, subject, text3) => {
|
|
28423
|
-
await notificationSettings.transport.send({ to: [to], from: notificationSettings.from, subject, text: text3, idempotencyKey: `confirm_${
|
|
29363
|
+
await notificationSettings.transport.send({ to: [to], from: notificationSettings.from, subject, text: text3, idempotencyKey: `confirm_${randomUUID14()}` });
|
|
28424
29364
|
}
|
|
28425
29365
|
}, { allowedSenders: notificationSettings.to, requireAuthentication: process.env.AUTOPILOT_DECISIONS_REQUIRE_AUTH !== "0" });
|
|
28426
29366
|
} finally {
|
|
@@ -28556,7 +29496,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
28556
29496
|
const task = typeof body.task === "string" ? body.task.trim() : "";
|
|
28557
29497
|
let cwd;
|
|
28558
29498
|
try {
|
|
28559
|
-
cwd = typeof body.cwd === "string" ?
|
|
29499
|
+
cwd = typeof body.cwd === "string" ? resolve18(body.cwd) : process.cwd();
|
|
28560
29500
|
} catch {
|
|
28561
29501
|
badRequest(res, "cwd must be a valid path");
|
|
28562
29502
|
return;
|
|
@@ -28620,7 +29560,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
28620
29560
|
const executor = new ToolExecutor(tools);
|
|
28621
29561
|
const { makeSessionId: makeSessionId2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
28622
29562
|
const sessionId = makeSessionId2(task);
|
|
28623
|
-
const runId =
|
|
29563
|
+
const runId = randomUUID14();
|
|
28624
29564
|
const worktreeManager = new RunWorktreeManager();
|
|
28625
29565
|
let worktree;
|
|
28626
29566
|
if (useWorktree) {
|
|
@@ -28669,7 +29609,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
28669
29609
|
store.close();
|
|
28670
29610
|
}
|
|
28671
29611
|
} catch (error) {
|
|
28672
|
-
await unlink4(
|
|
29612
|
+
await unlink4(resolve18(sessionsDir(), `${sessionId}.json`)).catch(() => {
|
|
28673
29613
|
});
|
|
28674
29614
|
if (worktree) {
|
|
28675
29615
|
await worktreeManager.discard(worktree).catch((cleanupError) => {
|
|
@@ -28812,7 +29752,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
28812
29752
|
return;
|
|
28813
29753
|
}
|
|
28814
29754
|
try {
|
|
28815
|
-
const file = await loadSession(
|
|
29755
|
+
const file = await loadSession(resolve18(sessionsDir(), `${sessionId}.json`));
|
|
28816
29756
|
json3(res, 200, {
|
|
28817
29757
|
id: file.id,
|
|
28818
29758
|
cwd: file.cwd,
|
|
@@ -28832,7 +29772,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
28832
29772
|
activeSessions.delete(sessionId);
|
|
28833
29773
|
try {
|
|
28834
29774
|
const { unlink: unlink7 } = await import("fs/promises");
|
|
28835
|
-
await unlink7(
|
|
29775
|
+
await unlink7(resolve18(sessionsDir(), `${sessionId}.json`));
|
|
28836
29776
|
} catch {
|
|
28837
29777
|
}
|
|
28838
29778
|
json3(res, 200, { deleted: sessionId });
|
|
@@ -28862,6 +29802,12 @@ function setupRoutes(config2, options = {}) {
|
|
|
28862
29802
|
title
|
|
28863
29803
|
};
|
|
28864
29804
|
const hooks = new HooksManager(cwd);
|
|
29805
|
+
const gate = await submitUserPrompt({ hooks, sessionId, cwd, prompt, resumed: false, model, auth: llmAuthFromConfig(config2) });
|
|
29806
|
+
if (gate.blocked) {
|
|
29807
|
+
await endSession(sessionId, "exit");
|
|
29808
|
+
promptBlocked(res, gate.reason);
|
|
29809
|
+
return;
|
|
29810
|
+
}
|
|
28865
29811
|
const executor = new ToolExecutor(ALL_TOOLS, { hooks });
|
|
28866
29812
|
const messages = [
|
|
28867
29813
|
{
|
|
@@ -28914,6 +29860,19 @@ function setupRoutes(config2, options = {}) {
|
|
|
28914
29860
|
badRequest(res, "prompt is required");
|
|
28915
29861
|
return;
|
|
28916
29862
|
}
|
|
29863
|
+
const gate = await submitUserPrompt({
|
|
29864
|
+
...active.hooks ? { hooks: active.hooks } : {},
|
|
29865
|
+
sessionId,
|
|
29866
|
+
cwd: active.sessionFile.cwd,
|
|
29867
|
+
prompt,
|
|
29868
|
+
resumed: active.messages.some((m) => m.role === "assistant"),
|
|
29869
|
+
model: active.sessionFile.model,
|
|
29870
|
+
auth: llmAuthFromConfig(config2)
|
|
29871
|
+
});
|
|
29872
|
+
if (gate.blocked) {
|
|
29873
|
+
promptBlocked(res, gate.reason);
|
|
29874
|
+
return;
|
|
29875
|
+
}
|
|
28917
29876
|
const resolvedFiles = await resolveFiles2(files, active.sessionFile.cwd);
|
|
28918
29877
|
const { content: userContent2 } = await buildAttachmentMessage(prompt, resolvedFiles, active.sessionFile.cwd, imageOptions(config2));
|
|
28919
29878
|
active.messages.push({ role: "user", content: userContent2 });
|
|
@@ -29237,6 +30196,7 @@ var init_routes = __esm({
|
|
|
29237
30196
|
"use strict";
|
|
29238
30197
|
init_session_core();
|
|
29239
30198
|
init_session_lifecycle();
|
|
30199
|
+
init_prompt_submit();
|
|
29240
30200
|
init_manager2();
|
|
29241
30201
|
init_exit();
|
|
29242
30202
|
init_registry();
|
|
@@ -29328,7 +30288,7 @@ async function startServer(opts2) {
|
|
|
29328
30288
|
server.keepAliveTimeout = 5e3;
|
|
29329
30289
|
const unregisterShutdown = onShutdown("server", async () => {
|
|
29330
30290
|
const ended = cleanup();
|
|
29331
|
-
const closed = new Promise((
|
|
30291
|
+
const closed = new Promise((resolve22) => server.close(() => resolve22()));
|
|
29332
30292
|
server.closeAllConnections();
|
|
29333
30293
|
await Promise.all([ended, closed]);
|
|
29334
30294
|
});
|
|
@@ -29337,13 +30297,13 @@ async function startServer(opts2) {
|
|
|
29337
30297
|
void cleanup();
|
|
29338
30298
|
});
|
|
29339
30299
|
installExitHandlers({ signals: ["SIGINT", "SIGTERM"], exitCode: () => 0, crashes: true });
|
|
29340
|
-
return new Promise((
|
|
30300
|
+
return new Promise((resolve22, reject) => {
|
|
29341
30301
|
server.listen(opts2.port, opts2.hostname, () => {
|
|
29342
30302
|
logger.info("server: listening", { hostname: opts2.hostname, port: opts2.port });
|
|
29343
30303
|
console.log(`kimiflare serve: http://${opts2.hostname}:${opts2.port}`);
|
|
29344
30304
|
console.log(` API docs: http://${opts2.hostname}:${opts2.port}/doc`);
|
|
29345
30305
|
console.log(` SSE stream: http://${opts2.hostname}:${opts2.port}/event`);
|
|
29346
|
-
|
|
30306
|
+
resolve22(server);
|
|
29347
30307
|
});
|
|
29348
30308
|
server.on("error", reject);
|
|
29349
30309
|
});
|
|
@@ -29677,8 +30637,8 @@ async function runEmitMode(opts2) {
|
|
|
29677
30637
|
async function nextFollowUp() {
|
|
29678
30638
|
if (followUpQueue.length > 0) return followUpQueue.shift();
|
|
29679
30639
|
if (stdinClosed) return null;
|
|
29680
|
-
return new Promise((
|
|
29681
|
-
followUpResolver =
|
|
30640
|
+
return new Promise((resolve22) => {
|
|
30641
|
+
followUpResolver = resolve22;
|
|
29682
30642
|
});
|
|
29683
30643
|
}
|
|
29684
30644
|
const cwd = process.cwd();
|
|
@@ -29708,6 +30668,25 @@ async function runEmitMode(opts2) {
|
|
|
29708
30668
|
process.on("SIGINT", sigintHandler);
|
|
29709
30669
|
async function runTurn(text3) {
|
|
29710
30670
|
emit("UserMessageCreated", { text: text3 });
|
|
30671
|
+
const gate = await submitUserPrompt({
|
|
30672
|
+
hooks,
|
|
30673
|
+
sessionId,
|
|
30674
|
+
cwd,
|
|
30675
|
+
prompt: text3,
|
|
30676
|
+
resumed: messages.some((m) => m.role === "assistant"),
|
|
30677
|
+
model: opts2.model,
|
|
30678
|
+
auth: llmAuthFromConfig(opts2)
|
|
30679
|
+
});
|
|
30680
|
+
if (gate.blocked) {
|
|
30681
|
+
emit("RuntimeError", {
|
|
30682
|
+
message: `prompt blocked by a UserPromptSubmit hook: ${gate.reason}`,
|
|
30683
|
+
source: "hooks",
|
|
30684
|
+
kind: "generic",
|
|
30685
|
+
severity: "error"
|
|
30686
|
+
});
|
|
30687
|
+
if (!opts2.multiTurn) exitCode = PROMPT_BLOCKED_EXIT_CODE;
|
|
30688
|
+
return;
|
|
30689
|
+
}
|
|
29711
30690
|
messages.push({ role: "user", content: text3 });
|
|
29712
30691
|
try {
|
|
29713
30692
|
const policy = await resolveTurnPolicy({ cfg: opts2, prompt: text3, tools: ALL_TOOLS, signal: controller.signal });
|
|
@@ -29830,8 +30809,8 @@ async function runEmitMode(opts2) {
|
|
|
29830
30809
|
return fromHook;
|
|
29831
30810
|
}
|
|
29832
30811
|
if (opts2.multiTurn) {
|
|
29833
|
-
const choice = await new Promise((
|
|
29834
|
-
pendingPermissions.set(reqId,
|
|
30812
|
+
const choice = await new Promise((resolve22) => {
|
|
30813
|
+
pendingPermissions.set(reqId, resolve22);
|
|
29835
30814
|
});
|
|
29836
30815
|
if (choice === "allow" || choice === "allow_session") {
|
|
29837
30816
|
emit("PermissionGranted", { request_id: reqId });
|
|
@@ -29931,6 +30910,7 @@ var init_emit_mode = __esm({
|
|
|
29931
30910
|
init_executor();
|
|
29932
30911
|
init_errors();
|
|
29933
30912
|
init_session_lifecycle();
|
|
30913
|
+
init_prompt_submit();
|
|
29934
30914
|
init_sessions();
|
|
29935
30915
|
}
|
|
29936
30916
|
});
|
|
@@ -29958,7 +30938,7 @@ async function runAttachMode(opts2) {
|
|
|
29958
30938
|
if (!response.ok) {
|
|
29959
30939
|
const text3 = await response.text().catch(() => "unknown error");
|
|
29960
30940
|
console.error(`kimiflare attach: ${response.status} ${text3}`);
|
|
29961
|
-
process.exit(1);
|
|
30941
|
+
process.exit(response.status === 403 && text3.includes('"prompt_blocked"') ? PROMPT_BLOCKED_EXIT_CODE : 1);
|
|
29962
30942
|
}
|
|
29963
30943
|
const result2 = await response.json();
|
|
29964
30944
|
const sessionId = result2.sessionId;
|
|
@@ -29971,7 +30951,7 @@ async function runAttachMode(opts2) {
|
|
|
29971
30951
|
async function streamSse(url, sessionId, format) {
|
|
29972
30952
|
const eventSource = new EventSource(`${url}/event`);
|
|
29973
30953
|
let done = false;
|
|
29974
|
-
return new Promise((
|
|
30954
|
+
return new Promise((resolve22, reject) => {
|
|
29975
30955
|
eventSource.onmessage = (event) => {
|
|
29976
30956
|
try {
|
|
29977
30957
|
const data = JSON.parse(event.data);
|
|
@@ -30018,7 +30998,7 @@ async function streamSse(url, sessionId, format) {
|
|
|
30018
30998
|
done = true;
|
|
30019
30999
|
eventSource.close();
|
|
30020
31000
|
if (format === "text") process.stdout.write("\n");
|
|
30021
|
-
|
|
31001
|
+
resolve22(void 0);
|
|
30022
31002
|
break;
|
|
30023
31003
|
case "error":
|
|
30024
31004
|
done = true;
|
|
@@ -30031,7 +31011,7 @@ async function streamSse(url, sessionId, format) {
|
|
|
30031
31011
|
process.stdout.write(JSON.stringify({ event: "error", message: data.message }) + "\n");
|
|
30032
31012
|
}
|
|
30033
31013
|
process.exitCode = 1;
|
|
30034
|
-
|
|
31014
|
+
resolve22(void 0);
|
|
30035
31015
|
break;
|
|
30036
31016
|
}
|
|
30037
31017
|
} catch {
|
|
@@ -30057,7 +31037,7 @@ async function streamSseJson(url, sessionId) {
|
|
|
30057
31037
|
const toolResults = [];
|
|
30058
31038
|
let usage;
|
|
30059
31039
|
const eventSource = new EventSource(`${url}/event`);
|
|
30060
|
-
return new Promise((
|
|
31040
|
+
return new Promise((resolve22, reject) => {
|
|
30061
31041
|
eventSource.onmessage = (event) => {
|
|
30062
31042
|
try {
|
|
30063
31043
|
const data = JSON.parse(event.data);
|
|
@@ -30094,7 +31074,7 @@ async function streamSseJson(url, sessionId) {
|
|
|
30094
31074
|
2
|
|
30095
31075
|
) + "\n"
|
|
30096
31076
|
);
|
|
30097
|
-
|
|
31077
|
+
resolve22(void 0);
|
|
30098
31078
|
break;
|
|
30099
31079
|
case "error":
|
|
30100
31080
|
eventSource.close();
|
|
@@ -30102,7 +31082,7 @@ async function streamSseJson(url, sessionId) {
|
|
|
30102
31082
|
JSON.stringify({ error: data.message, sessionId }, null, 2) + "\n"
|
|
30103
31083
|
);
|
|
30104
31084
|
process.exitCode = 1;
|
|
30105
|
-
|
|
31085
|
+
resolve22(void 0);
|
|
30106
31086
|
break;
|
|
30107
31087
|
}
|
|
30108
31088
|
} catch {
|
|
@@ -30122,6 +31102,7 @@ var EventSource;
|
|
|
30122
31102
|
var init_attach_mode = __esm({
|
|
30123
31103
|
"src/attach-mode.ts"() {
|
|
30124
31104
|
"use strict";
|
|
31105
|
+
init_prompt_submit();
|
|
30125
31106
|
EventSource = class {
|
|
30126
31107
|
url;
|
|
30127
31108
|
controller;
|
|
@@ -30279,7 +31260,7 @@ __export(openrouter_oauth_exports, {
|
|
|
30279
31260
|
});
|
|
30280
31261
|
import { createHash as createHash8, randomBytes as randomBytes4 } from "crypto";
|
|
30281
31262
|
import { createServer as createServer4 } from "http";
|
|
30282
|
-
import { hostname as
|
|
31263
|
+
import { hostname as hostname3 } from "os";
|
|
30283
31264
|
function createPkce() {
|
|
30284
31265
|
const verifier = randomBytes4(32).toString("base64url");
|
|
30285
31266
|
return { verifier, challenge: pkceChallenge(verifier) };
|
|
@@ -30291,7 +31272,7 @@ function openRouterAuthPageUrl() {
|
|
|
30291
31272
|
return (process.env.OPENROUTER_AUTH_URL?.trim() || "https://openrouter.ai/auth").replace(/\/+$/, "");
|
|
30292
31273
|
}
|
|
30293
31274
|
function defaultKeyLabel() {
|
|
30294
|
-
return `autopilot (${
|
|
31275
|
+
return `autopilot (${hostname3()})`.slice(0, 60);
|
|
30295
31276
|
}
|
|
30296
31277
|
function buildAuthUrl(opts2) {
|
|
30297
31278
|
const params = new URLSearchParams();
|
|
@@ -30368,9 +31349,9 @@ async function startLoopbackListener(opts2 = {}) {
|
|
|
30368
31349
|
rejectCode(e);
|
|
30369
31350
|
finish();
|
|
30370
31351
|
}
|
|
30371
|
-
await new Promise((
|
|
31352
|
+
await new Promise((resolve22, reject) => {
|
|
30372
31353
|
server.once("error", reject);
|
|
30373
|
-
server.listen(0, "127.0.0.1", () =>
|
|
31354
|
+
server.listen(0, "127.0.0.1", () => resolve22());
|
|
30374
31355
|
});
|
|
30375
31356
|
const address = server.address();
|
|
30376
31357
|
const port = typeof address === "object" && address ? address.port : 0;
|
|
@@ -30517,11 +31498,11 @@ async function chatgptSignIn(onUrl, signal) {
|
|
|
30517
31498
|
}
|
|
30518
31499
|
function untilAborted(p, signal) {
|
|
30519
31500
|
if (!signal) return p;
|
|
30520
|
-
return new Promise((
|
|
31501
|
+
return new Promise((resolve22, reject) => {
|
|
30521
31502
|
const abort = () => reject(new DOMException("sign-in cancelled", "AbortError"));
|
|
30522
31503
|
if (signal.aborted) return abort();
|
|
30523
31504
|
signal.addEventListener("abort", abort, { once: true });
|
|
30524
|
-
p.then(
|
|
31505
|
+
p.then(resolve22, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
30525
31506
|
});
|
|
30526
31507
|
}
|
|
30527
31508
|
async function openRouterSignIn(io) {
|
|
@@ -30767,20 +31748,20 @@ var init_help_catalog = __esm({
|
|
|
30767
31748
|
|
|
30768
31749
|
// src/ui/bang-command.ts
|
|
30769
31750
|
import { spawn as spawn8 } from "child_process";
|
|
30770
|
-
import { mkdtemp as
|
|
30771
|
-
import { tmpdir as
|
|
30772
|
-
import { join as
|
|
31751
|
+
import { mkdtemp as mkdtemp4, readFile as readFile36, rm as rm8 } from "fs/promises";
|
|
31752
|
+
import { tmpdir as tmpdir6, platform as platform5 } from "os";
|
|
31753
|
+
import { join as join49 } from "path";
|
|
30773
31754
|
function registerTerminalHandoff(h) {
|
|
30774
31755
|
terminalHandoff = h;
|
|
30775
31756
|
}
|
|
30776
31757
|
function runCaptured(inv, cwd) {
|
|
30777
|
-
return new Promise((
|
|
31758
|
+
return new Promise((resolve22) => {
|
|
30778
31759
|
const child = spawn8(inv.file, inv.args, { cwd, stdio: ["ignore", "pipe", "pipe"], env: inv.env ?? process.env });
|
|
30779
31760
|
let output = "";
|
|
30780
31761
|
child.stdout?.on("data", (c) => output += c.toString("utf8"));
|
|
30781
31762
|
child.stderr?.on("data", (c) => output += c.toString("utf8"));
|
|
30782
|
-
child.once("error", (e) =>
|
|
30783
|
-
child.once("exit", (code, signal) =>
|
|
31763
|
+
child.once("error", (e) => resolve22({ code: 127, signal: null, output: `failed to start: ${e.message}` }));
|
|
31764
|
+
child.once("exit", (code, signal) => resolve22({ code, signal, output }));
|
|
30784
31765
|
});
|
|
30785
31766
|
}
|
|
30786
31767
|
function isTerminalHandedOff() {
|
|
@@ -30848,10 +31829,10 @@ function swallow() {
|
|
|
30848
31829
|
});
|
|
30849
31830
|
}
|
|
30850
31831
|
function spawnInherit(inv, cwd) {
|
|
30851
|
-
return new Promise((
|
|
31832
|
+
return new Promise((resolve22, reject) => {
|
|
30852
31833
|
const child = spawn8(inv.file, inv.args, { cwd, stdio: "inherit", env: inv.env ?? process.env });
|
|
30853
31834
|
child.once("error", reject);
|
|
30854
|
-
child.once("exit", (code, signal) =>
|
|
31835
|
+
child.once("exit", (code, signal) => resolve22({ code, signal }));
|
|
30855
31836
|
});
|
|
30856
31837
|
}
|
|
30857
31838
|
async function runBangCommand(command, cwd) {
|
|
@@ -30869,8 +31850,8 @@ async function runBangCommand(command, cwd) {
|
|
|
30869
31850
|
const origErr = stderr.write;
|
|
30870
31851
|
const readable = stdin.listeners("readable");
|
|
30871
31852
|
const wasRaw = stdin.isTTY ? stdin.isRaw : false;
|
|
30872
|
-
const logDir2 = isWindows ? null : await
|
|
30873
|
-
const logPath = logDir2 ?
|
|
31853
|
+
const logDir2 = isWindows ? null : await mkdtemp4(join49(tmpdir6(), "autopilot-bang-"));
|
|
31854
|
+
const logPath = logDir2 ? join49(logDir2, "out.log") : null;
|
|
30874
31855
|
const viaScript = logPath ? scriptInvocation(command, shell, logPath) : null;
|
|
30875
31856
|
origOut.call(stdout, `
|
|
30876
31857
|
$ ${command}
|
|
@@ -30911,9 +31892,9 @@ $ ${command}
|
|
|
30911
31892
|
}
|
|
30912
31893
|
let output = spawnError ? `failed to start: ${spawnError}` : null;
|
|
30913
31894
|
if (captured && logPath) {
|
|
30914
|
-
output = cleanTerminalOutput(await
|
|
31895
|
+
output = cleanTerminalOutput(await readFile36(logPath, "utf8").catch(() => ""));
|
|
30915
31896
|
}
|
|
30916
|
-
if (logDir2) await
|
|
31897
|
+
if (logDir2) await rm8(logDir2, { recursive: true, force: true }).catch(() => {
|
|
30917
31898
|
});
|
|
30918
31899
|
return { command, exitCode: result2.code, signal: result2.signal, output };
|
|
30919
31900
|
}
|
|
@@ -31150,8 +32131,8 @@ function activityFromSubagent(worker) {
|
|
|
31150
32131
|
};
|
|
31151
32132
|
}
|
|
31152
32133
|
function activityTaskPreview(task) {
|
|
31153
|
-
const
|
|
31154
|
-
return
|
|
32134
|
+
const oneLine3 = task.replace(/\s+/g, " ").trim();
|
|
32135
|
+
return oneLine3.length > 72 ? `${oneLine3.slice(0, 71)}\u2026` : oneLine3;
|
|
31155
32136
|
}
|
|
31156
32137
|
function diffActivityItems(previous, current, snapshotSent) {
|
|
31157
32138
|
if (!snapshotSent) return [{ type: "ActivitySnapshot", payload: { items: [...current] } }];
|
|
@@ -31188,14 +32169,14 @@ __export(camouflage_launch_exports, {
|
|
|
31188
32169
|
runWithCrashRestarts: () => runWithCrashRestarts
|
|
31189
32170
|
});
|
|
31190
32171
|
import { accessSync, constants, existsSync as existsSync14, readFileSync as readFileSync9 } from "fs";
|
|
31191
|
-
import { homedir as
|
|
31192
|
-
import { delimiter, dirname as
|
|
32172
|
+
import { homedir as homedir31 } from "os";
|
|
32173
|
+
import { delimiter, dirname as dirname25, isAbsolute as isAbsolute8, join as join50, resolve as resolve19, sep as sep7 } from "path";
|
|
31193
32174
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
31194
32175
|
function defaultPackageDir() {
|
|
31195
32176
|
try {
|
|
31196
|
-
let dir =
|
|
31197
|
-
while (!existsSync14(
|
|
31198
|
-
return existsSync14(
|
|
32177
|
+
let dir = dirname25(fileURLToPath5(import.meta.resolve("camouflage-tui")));
|
|
32178
|
+
while (!existsSync14(join50(dir, "package.json")) && dirname25(dir) !== dir) dir = dirname25(dir);
|
|
32179
|
+
return existsSync14(join50(dir, "package.json")) ? dir : null;
|
|
31199
32180
|
} catch {
|
|
31200
32181
|
return null;
|
|
31201
32182
|
}
|
|
@@ -31209,11 +32190,11 @@ function defaultIsExecutable(path) {
|
|
|
31209
32190
|
}
|
|
31210
32191
|
}
|
|
31211
32192
|
function findOnPath(bin, env, platform7, isExecutable) {
|
|
31212
|
-
if (isAbsolute8(bin) || bin.includes("/") || bin.includes(sep7)) return isExecutable(
|
|
32193
|
+
if (isAbsolute8(bin) || bin.includes("/") || bin.includes(sep7)) return isExecutable(resolve19(bin));
|
|
31213
32194
|
const exts = platform7 === "win32" ? ["", ...(env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")] : [""];
|
|
31214
32195
|
for (const dir of (env.PATH ?? "").split(delimiter)) {
|
|
31215
32196
|
if (!dir) continue;
|
|
31216
|
-
for (const ext of exts) if (isExecutable(
|
|
32197
|
+
for (const ext of exts) if (isExecutable(join50(dir, bin + ext))) return true;
|
|
31217
32198
|
}
|
|
31218
32199
|
return false;
|
|
31219
32200
|
}
|
|
@@ -31222,21 +32203,21 @@ function diagnoseRenderer(deps = {}) {
|
|
|
31222
32203
|
const platform7 = deps.platform ?? process.platform;
|
|
31223
32204
|
const arch = deps.arch ?? process.arch;
|
|
31224
32205
|
const isExecutable = deps.isExecutable ?? defaultIsExecutable;
|
|
31225
|
-
const
|
|
32206
|
+
const readFile42 = deps.readFile ?? ((p) => readFileSync9(p, "utf8"));
|
|
31226
32207
|
const packageDir = (deps.packageDir ?? defaultPackageDir)();
|
|
31227
32208
|
let packageVersion = null;
|
|
31228
32209
|
let packageBin = null;
|
|
31229
32210
|
if (packageDir) {
|
|
31230
32211
|
try {
|
|
31231
|
-
packageVersion = JSON.parse(
|
|
32212
|
+
packageVersion = JSON.parse(readFile42(join50(packageDir, "package.json"))).version ?? null;
|
|
31232
32213
|
} catch {
|
|
31233
32214
|
}
|
|
31234
|
-
packageBin =
|
|
32215
|
+
packageBin = join50(packageDir, "bin", platform7 === "win32" ? "camouflage-tui.exe" : "camouflage-tui");
|
|
31235
32216
|
}
|
|
31236
|
-
const installErrorPath =
|
|
32217
|
+
const installErrorPath = join50(deps.home ?? homedir31(), ".camouflage", "install-error.txt");
|
|
31237
32218
|
let installError = null;
|
|
31238
32219
|
try {
|
|
31239
|
-
installError =
|
|
32220
|
+
installError = readFile42(installErrorPath).trim() || null;
|
|
31240
32221
|
} catch {
|
|
31241
32222
|
}
|
|
31242
32223
|
const envBin = env.CAMOUFLAGE_BIN || null;
|
|
@@ -31283,7 +32264,7 @@ function formatUnavailable(d, reason) {
|
|
|
31283
32264
|
if (d.envBin) lines.push(` - point CAMOUFLAGE_BIN at an existing camouflage-tui binary, or unset it to use the bundled one`);
|
|
31284
32265
|
if (d.packageDir) {
|
|
31285
32266
|
lines.push(
|
|
31286
|
-
` - download the renderer again: node "${
|
|
32267
|
+
` - download the renderer again: node "${join50(d.packageDir, "scripts", "install.js")}"`,
|
|
31287
32268
|
` (or run \`npm rebuild camouflage-tui\` where autopilot-ai is installed; \`npm rebuild -g camouflage-tui\` for a global install)`
|
|
31288
32269
|
);
|
|
31289
32270
|
}
|
|
@@ -31332,7 +32313,7 @@ async function runWithCrashRestarts(run, opts2 = {}) {
|
|
|
31332
32313
|
function crashGiveUpMessage(outcome, windowMs = 6e4) {
|
|
31333
32314
|
const lines = [
|
|
31334
32315
|
`autopilot: the Camouflage renderer crashed ${outcome.crashes} times within ${Math.round(windowMs / 1e3)} seconds, so autopilot stopped restarting it.`,
|
|
31335
|
-
`Crash reports: ${
|
|
32316
|
+
`Crash reports: ${join50(homedir31(), ".camouflage")} (crash-*.txt). Please attach one to an issue: https://github.com/sinameraji/autopilot/issues`
|
|
31336
32317
|
];
|
|
31337
32318
|
if (outcome.sessionId) {
|
|
31338
32319
|
lines.push(
|
|
@@ -31414,11 +32395,11 @@ __export(interactive_resume_exports, {
|
|
|
31414
32395
|
resumeHint: () => resumeHint
|
|
31415
32396
|
});
|
|
31416
32397
|
import { existsSync as existsSync15 } from "fs";
|
|
31417
|
-
import { join as
|
|
32398
|
+
import { join as join51 } from "path";
|
|
31418
32399
|
async function resolveInteractiveResume(req, cwd = process.cwd()) {
|
|
31419
32400
|
if (req.sessionId !== void 0) {
|
|
31420
32401
|
const id = req.sessionId.trim().replace(/\.json$/, "");
|
|
31421
|
-
if (!SESSION_ID.test(id) || !existsSync15(
|
|
32402
|
+
if (!SESSION_ID.test(id) || !existsSync15(join51(sessionsDir(), `${id}.json`))) {
|
|
31422
32403
|
return { kind: "error", message: `no saved conversation with id "${req.sessionId}". Run \`autopilot resume\` to pick one.` };
|
|
31423
32404
|
}
|
|
31424
32405
|
return { kind: "session", sessionId: id };
|
|
@@ -31431,7 +32412,7 @@ async function resolveInteractiveResume(req, cwd = process.cwd()) {
|
|
|
31431
32412
|
return { kind: "picker" };
|
|
31432
32413
|
}
|
|
31433
32414
|
function resumeHint(sessionId) {
|
|
31434
|
-
if (!sessionId || !SESSION_ID.test(sessionId) || !existsSync15(
|
|
32415
|
+
if (!sessionId || !SESSION_ID.test(sessionId) || !existsSync15(join51(sessionsDir(), `${sessionId}.json`))) return null;
|
|
31435
32416
|
return `Resume this conversation with: autopilot resume ${sessionId}
|
|
31436
32417
|
`;
|
|
31437
32418
|
}
|
|
@@ -31471,8 +32452,8 @@ __export(camouflage_view_exports, {
|
|
|
31471
32452
|
import { execFileSync as execFileSync4, spawn as spawn9 } from "child_process";
|
|
31472
32453
|
import { readdir as readdir7 } from "fs/promises";
|
|
31473
32454
|
import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
|
|
31474
|
-
import { homedir as
|
|
31475
|
-
import { dirname as
|
|
32455
|
+
import { homedir as homedir32 } from "os";
|
|
32456
|
+
import { dirname as dirname26, join as join52, resolve as resolve20 } from "path";
|
|
31476
32457
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
31477
32458
|
function noticeSeverity(e) {
|
|
31478
32459
|
return e.kind === "info" && e.tone === "warn" ? "warn" : "info";
|
|
@@ -31493,10 +32474,10 @@ function rendererInfo(env = process.env) {
|
|
|
31493
32474
|
let packageVersion = null;
|
|
31494
32475
|
let packageBin = "camouflage-tui";
|
|
31495
32476
|
try {
|
|
31496
|
-
let dir =
|
|
31497
|
-
while (!existsSync16(
|
|
31498
|
-
packageVersion = JSON.parse(readFileSync10(
|
|
31499
|
-
const local =
|
|
32477
|
+
let dir = dirname26(fileURLToPath6(import.meta.resolve("camouflage-tui")));
|
|
32478
|
+
while (!existsSync16(join52(dir, "package.json")) && dirname26(dir) !== dir) dir = dirname26(dir);
|
|
32479
|
+
packageVersion = JSON.parse(readFileSync10(join52(dir, "package.json"), "utf8")).version ?? null;
|
|
32480
|
+
const local = join52(dir, "bin", process.platform === "win32" ? "camouflage-tui.exe" : "camouflage-tui");
|
|
31500
32481
|
packageBin = local;
|
|
31501
32482
|
} catch {
|
|
31502
32483
|
}
|
|
@@ -31624,7 +32605,7 @@ async function runCamouflageView(opts2) {
|
|
|
31624
32605
|
if (process.stdin.isTTY) process.stdin.setRawMode?.(false);
|
|
31625
32606
|
process.stderr.write(
|
|
31626
32607
|
`
|
|
31627
|
-
The Camouflage renderer stopped unexpectedly (${signal ?? `exit code ${code}`}). Its crash report is in ${
|
|
32608
|
+
The Camouflage renderer stopped unexpectedly (${signal ?? `exit code ${code}`}). Its crash report is in ${join52(homedir32(), ".camouflage")} (crash-*.txt).
|
|
31628
32609
|
` + (view.busy ? "Finishing the current turn first\u2026\n" : "")
|
|
31629
32610
|
);
|
|
31630
32611
|
await view.settle();
|
|
@@ -31635,7 +32616,7 @@ The Camouflage renderer stopped unexpectedly (${signal ?? `exit code ${code}`}).
|
|
|
31635
32616
|
let endBeforeApp = () => {
|
|
31636
32617
|
};
|
|
31637
32618
|
let quitBeforeApp = false;
|
|
31638
|
-
const beforeApp = new Promise((
|
|
32619
|
+
const beforeApp = new Promise((resolve22) => endBeforeApp = resolve22);
|
|
31639
32620
|
let setup = null;
|
|
31640
32621
|
try {
|
|
31641
32622
|
let cfg = opts2.cfg;
|
|
@@ -31680,14 +32661,14 @@ The Camouflage renderer stopped unexpectedly (${signal ?? `exit code ${code}`}).
|
|
|
31680
32661
|
return "done";
|
|
31681
32662
|
}
|
|
31682
32663
|
function runShell2(command) {
|
|
31683
|
-
return new Promise((
|
|
32664
|
+
return new Promise((resolve22) => {
|
|
31684
32665
|
const { shell, args } = getShellCommand();
|
|
31685
32666
|
const child = spawn9(shell, [...args, command], { env: process.env });
|
|
31686
32667
|
let out = "";
|
|
31687
32668
|
child.stdout?.on("data", (c) => out += c.toString("utf8"));
|
|
31688
32669
|
child.stderr?.on("data", (c) => out += c.toString("utf8"));
|
|
31689
|
-
child.on("close", (code) =>
|
|
31690
|
-
child.on("error", (err) =>
|
|
32670
|
+
child.on("close", (code) => resolve22({ ok: code === 0, output: out || (code === 0 ? "" : `Exit code: ${code}`) }));
|
|
32671
|
+
child.on("error", (err) => resolve22({ ok: false, output: err.message }));
|
|
31691
32672
|
});
|
|
31692
32673
|
}
|
|
31693
32674
|
function syncSlashCommands(custom, lastKey, send) {
|
|
@@ -31770,8 +32751,8 @@ function truncateText(s, max) {
|
|
|
31770
32751
|
async function listMentionDir(cwd, query) {
|
|
31771
32752
|
const exact = query === "~" || query === "." || query === ".." || query.endsWith("/..");
|
|
31772
32753
|
const dir = exact ? `${query}/` : query.slice(0, query.lastIndexOf("/") + 1);
|
|
31773
|
-
const expanded = dir.startsWith("~") ?
|
|
31774
|
-
const target =
|
|
32754
|
+
const expanded = dir.startsWith("~") ? join52(homedir32(), dir.slice(1)) : dir;
|
|
32755
|
+
const target = resolve20(cwd, expanded || ".");
|
|
31775
32756
|
try {
|
|
31776
32757
|
const items = await readdir7(target, { withFileTypes: true });
|
|
31777
32758
|
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 ? "/" : ""}`);
|
|
@@ -31910,7 +32891,7 @@ function shortModel(id) {
|
|
|
31910
32891
|
return id.includes("/") ? id.slice(id.indexOf("/") + 1) : id;
|
|
31911
32892
|
}
|
|
31912
32893
|
function shortPath(p) {
|
|
31913
|
-
const home =
|
|
32894
|
+
const home = homedir32();
|
|
31914
32895
|
return p === home ? "~" : p.startsWith(home + "/") ? `~${p.slice(home.length)}` : p;
|
|
31915
32896
|
}
|
|
31916
32897
|
function gitBranch(cwd) {
|
|
@@ -32032,15 +33013,15 @@ var init_camouflage_view = __esm({
|
|
|
32032
33013
|
/** Resolves once the App is idle (no turn running). */
|
|
32033
33014
|
settle(maxWaitMs = 12e4) {
|
|
32034
33015
|
if (!this.busy) return Promise.resolve();
|
|
32035
|
-
return new Promise((
|
|
32036
|
-
this.idleWaiters.push(
|
|
32037
|
-
setTimeout(
|
|
33016
|
+
return new Promise((resolve22) => {
|
|
33017
|
+
this.idleWaiters.push(resolve22);
|
|
33018
|
+
setTimeout(resolve22, maxWaitMs).unref();
|
|
32038
33019
|
});
|
|
32039
33020
|
}
|
|
32040
33021
|
sync(s) {
|
|
32041
33022
|
this.busy = s.turnRunning;
|
|
32042
33023
|
this.sessionId = s.sessionId;
|
|
32043
|
-
if (!s.turnRunning) for (const
|
|
33024
|
+
if (!s.turnRunning) for (const resolve22 of this.idleWaiters.splice(0)) resolve22();
|
|
32044
33025
|
if (this.disposed) {
|
|
32045
33026
|
if (s.permission) this.actions?.decidePermission("deny");
|
|
32046
33027
|
return;
|
|
@@ -32337,7 +33318,7 @@ var init_camouflage_view = __esm({
|
|
|
32337
33318
|
*/
|
|
32338
33319
|
async denyFeedback(given, escaped) {
|
|
32339
33320
|
if (given?.trim()) return given.trim();
|
|
32340
|
-
await new Promise((
|
|
33321
|
+
await new Promise((resolve22) => setTimeout(resolve22, 50));
|
|
32341
33322
|
if (escaped() || this.disposed) return "";
|
|
32342
33323
|
const r = await this.sdk.form(this.cam, {
|
|
32343
33324
|
id: `deny-${Date.now()}`,
|
|
@@ -33447,9 +34428,9 @@ function usePermissionController(getMode, onPlanModeBlocked) {
|
|
|
33447
34428
|
const askPermission = useCallback(
|
|
33448
34429
|
(req, askOpts) => resolvePermission(req, getModeRef.current(), askOpts, {
|
|
33449
34430
|
onPlanModeBlocked: (toolName) => onPlanModeBlockedRef.current(toolName),
|
|
33450
|
-
prompt: () => new Promise((
|
|
33451
|
-
resolveRef.current =
|
|
33452
|
-
setPending({ tool: req.tool, args: req.args, resolve:
|
|
34431
|
+
prompt: () => new Promise((resolve22) => {
|
|
34432
|
+
resolveRef.current = resolve22;
|
|
34433
|
+
setPending({ tool: req.tool, args: req.args, resolve: resolve22 });
|
|
33453
34434
|
})
|
|
33454
34435
|
}),
|
|
33455
34436
|
[]
|
|
@@ -33830,14 +34811,14 @@ var init_frontmatter = __esm({
|
|
|
33830
34811
|
|
|
33831
34812
|
// src/commands/loader.ts
|
|
33832
34813
|
import { open as open2, realpath as realpath9 } from "fs/promises";
|
|
33833
|
-
import { homedir as
|
|
33834
|
-
import { join as
|
|
34814
|
+
import { homedir as homedir33 } from "os";
|
|
34815
|
+
import { join as join53, relative as relative11, sep as sep8 } from "path";
|
|
33835
34816
|
function projectCommandsDir(cwd = process.cwd()) {
|
|
33836
|
-
return
|
|
34817
|
+
return join53(cwd, ".kimiflare", "commands");
|
|
33837
34818
|
}
|
|
33838
34819
|
function globalCommandsDir() {
|
|
33839
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
33840
|
-
return
|
|
34820
|
+
const xdg = process.env.XDG_CONFIG_HOME || join53(homedir33(), ".config");
|
|
34821
|
+
return join53(xdg, "kimiflare", "commands");
|
|
33841
34822
|
}
|
|
33842
34823
|
async function loadCustomCommands(cwd = process.cwd()) {
|
|
33843
34824
|
const warnings = [];
|
|
@@ -33991,7 +34972,7 @@ var init_loader = __esm({
|
|
|
33991
34972
|
import { exec } from "child_process";
|
|
33992
34973
|
import { open as open3, realpath as realpath10 } from "fs/promises";
|
|
33993
34974
|
import { isAbsolute as isAbsolute9, relative as relative12, resolve as resolvePathJoin, basename as pathBasename } from "path";
|
|
33994
|
-
import { promisify as
|
|
34975
|
+
import { promisify as promisify11 } from "util";
|
|
33995
34976
|
function tokenizeArgs(s) {
|
|
33996
34977
|
return [...s.matchAll(ARG_TOKEN_RE)].map((match) => {
|
|
33997
34978
|
const token = match[0];
|
|
@@ -34144,7 +35125,7 @@ var init_renderer2 = __esm({
|
|
|
34144
35125
|
"src/commands/renderer.ts"() {
|
|
34145
35126
|
"use strict";
|
|
34146
35127
|
init_paths();
|
|
34147
|
-
execAsync =
|
|
35128
|
+
execAsync = promisify11(exec);
|
|
34148
35129
|
ARG_TOKEN_RE = /(?:"[^"]*"|'[^']*'|[^\s"']+)/g;
|
|
34149
35130
|
POSITIONAL_RE = /\$(\d+)/g;
|
|
34150
35131
|
HAS_POSITIONAL = /\$\d+/;
|
|
@@ -34453,6 +35434,9 @@ Rules:
|
|
|
34453
35434
|
|
|
34454
35435
|
// src/ui/use-session-manager.ts
|
|
34455
35436
|
import React, { useCallback as useCallback2, useRef as useRef2, useState as useState4 } from "react";
|
|
35437
|
+
function sessionNameText(messages, firstPrompt) {
|
|
35438
|
+
return firstPrompt?.trim() || extractFirstUserText(messages);
|
|
35439
|
+
}
|
|
34456
35440
|
function extractFirstUserText(messages) {
|
|
34457
35441
|
const firstUser = messages.find((m) => m.role === "user");
|
|
34458
35442
|
if (!firstUser) return "session";
|
|
@@ -34485,9 +35469,9 @@ function useSessionManager(deps) {
|
|
|
34485
35469
|
const [checkpointList, setCheckpointList] = useState4([]);
|
|
34486
35470
|
const depsRef = useRef2(deps);
|
|
34487
35471
|
depsRef.current = deps;
|
|
34488
|
-
const ensureSessionId = useCallback2(() => {
|
|
35472
|
+
const ensureSessionId = useCallback2((firstPrompt) => {
|
|
34489
35473
|
if (sessionIdRef.current) return sessionIdRef.current;
|
|
34490
|
-
const text3 =
|
|
35474
|
+
const text3 = sessionNameText(depsRef.current.messagesRef.current, firstPrompt);
|
|
34491
35475
|
sessionIdRef.current = makeSessionId(text3);
|
|
34492
35476
|
setLogSessionId(sessionIdRef.current);
|
|
34493
35477
|
return sessionIdRef.current;
|
|
@@ -34986,8 +35970,8 @@ var init_terminal_qr = __esm({
|
|
|
34986
35970
|
|
|
34987
35971
|
// src/agent/jev-context.ts
|
|
34988
35972
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
34989
|
-
import { readFile as
|
|
34990
|
-
import { basename as basename11, join as
|
|
35973
|
+
import { readFile as readFile37 } from "fs/promises";
|
|
35974
|
+
import { basename as basename11, join as join54, resolve as resolve21 } from "path";
|
|
34991
35975
|
function messageText(message2) {
|
|
34992
35976
|
if (typeof message2.content === "string") return message2.content.trim();
|
|
34993
35977
|
if (!Array.isArray(message2.content)) return "";
|
|
@@ -35004,12 +35988,12 @@ function projectRoot(cwd) {
|
|
|
35004
35988
|
timeout: 1e3
|
|
35005
35989
|
}).trim();
|
|
35006
35990
|
} catch {
|
|
35007
|
-
return
|
|
35991
|
+
return resolve21(cwd);
|
|
35008
35992
|
}
|
|
35009
35993
|
}
|
|
35010
35994
|
async function readPackageMetadata(root) {
|
|
35011
35995
|
try {
|
|
35012
|
-
const parsed = JSON.parse(await
|
|
35996
|
+
const parsed = JSON.parse(await readFile37(join54(root, "package.json"), "utf8"));
|
|
35013
35997
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
35014
35998
|
const pkg = parsed;
|
|
35015
35999
|
const metadata = {};
|
|
@@ -35026,7 +36010,7 @@ async function readPackageMetadata(root) {
|
|
|
35026
36010
|
async function readLicenseEvidence(root) {
|
|
35027
36011
|
for (const name of ["LICENSE", "LICENSE.md", "LICENSE.txt", "LICENCE", "COPYING"]) {
|
|
35028
36012
|
try {
|
|
35029
|
-
const content = (await
|
|
36013
|
+
const content = (await readFile37(join54(root, name), "utf8")).trim();
|
|
35030
36014
|
if (content) return { source: `project license (${name})`, content: content.slice(0, 700) };
|
|
35031
36015
|
} catch {
|
|
35032
36016
|
}
|
|
@@ -35059,7 +36043,7 @@ async function buildJevContext(question, messages, cwd = process.cwd()) {
|
|
|
35059
36043
|
conversationRemaining -= source.length + content.length + 2;
|
|
35060
36044
|
}
|
|
35061
36045
|
}
|
|
35062
|
-
const currentDirectory = basename11(
|
|
36046
|
+
const currentDirectory = basename11(resolve21(cwd));
|
|
35063
36047
|
const escapedDirectory = currentDirectory.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
35064
36048
|
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);
|
|
35065
36049
|
if (CURRENT_PROJECT_REFERENCE.test(question) || namesCurrentDirectory) {
|
|
@@ -35282,8 +36266,8 @@ var init_frontmatter2 = __esm({
|
|
|
35282
36266
|
});
|
|
35283
36267
|
|
|
35284
36268
|
// src/skills/loader.ts
|
|
35285
|
-
import { readFile as
|
|
35286
|
-
import { join as
|
|
36269
|
+
import { readFile as readFile38, readdir as readdir8, stat as stat13 } from "fs/promises";
|
|
36270
|
+
import { join as join55, extname } from "path";
|
|
35287
36271
|
function normalizeManifest(raw, filePath) {
|
|
35288
36272
|
const name = typeof raw.name === "string" ? raw.name : "";
|
|
35289
36273
|
const description = typeof raw.description === "string" ? raw.description : "";
|
|
@@ -35297,7 +36281,7 @@ function normalizeManifest(raw, filePath) {
|
|
|
35297
36281
|
return { name, description, match, scope, priority, enabled: enabled2 };
|
|
35298
36282
|
}
|
|
35299
36283
|
async function loadSkillFile(filePath) {
|
|
35300
|
-
const raw = await
|
|
36284
|
+
const raw = await readFile38(filePath, "utf-8");
|
|
35301
36285
|
const parsed = parseFrontmatter2(raw);
|
|
35302
36286
|
const manifest = normalizeManifest(parsed.data, filePath);
|
|
35303
36287
|
const body = parsed.content.trim();
|
|
@@ -35319,8 +36303,8 @@ async function loadSkillsFromDir(dirPath) {
|
|
|
35319
36303
|
const entries = await readdir8(dirPath);
|
|
35320
36304
|
const files = [];
|
|
35321
36305
|
for (const entry of entries) {
|
|
35322
|
-
const full =
|
|
35323
|
-
const s = await
|
|
36306
|
+
const full = join55(dirPath, entry);
|
|
36307
|
+
const s = await stat13(full);
|
|
35324
36308
|
if (s.isFile() && extname(entry) === ".md") {
|
|
35325
36309
|
files.push(full);
|
|
35326
36310
|
}
|
|
@@ -35347,12 +36331,12 @@ var init_loader2 = __esm({
|
|
|
35347
36331
|
});
|
|
35348
36332
|
|
|
35349
36333
|
// src/skills/manager.ts
|
|
35350
|
-
import { mkdir as
|
|
35351
|
-
import { join as
|
|
36334
|
+
import { mkdir as mkdir21, writeFile as writeFile18, unlink as unlink5, readFile as readFile39 } from "fs/promises";
|
|
36335
|
+
import { join as join56 } from "path";
|
|
35352
36336
|
function getSkillDirs(cwd) {
|
|
35353
36337
|
return {
|
|
35354
|
-
projectDir:
|
|
35355
|
-
globalDir:
|
|
36338
|
+
projectDir: join56(cwd, ".kimiflare", "skills"),
|
|
36339
|
+
globalDir: join56(process.env.HOME ?? "", ".config", "kimiflare", "skills")
|
|
35356
36340
|
};
|
|
35357
36341
|
}
|
|
35358
36342
|
async function listAllSkills(cwd) {
|
|
@@ -35366,7 +36350,7 @@ async function listAllSkills(cwd) {
|
|
|
35366
36350
|
async function createSkill(opts2) {
|
|
35367
36351
|
const dirs = getSkillDirs(opts2.cwd);
|
|
35368
36352
|
const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
|
|
35369
|
-
const filepath =
|
|
36353
|
+
const filepath = join56(dir, `${opts2.name}.md`);
|
|
35370
36354
|
const frontmatter = {
|
|
35371
36355
|
name: opts2.name,
|
|
35372
36356
|
enabled: true,
|
|
@@ -35387,8 +36371,8 @@ ${yaml}
|
|
|
35387
36371
|
|
|
35388
36372
|
Add your instructions here.
|
|
35389
36373
|
`;
|
|
35390
|
-
await
|
|
35391
|
-
await
|
|
36374
|
+
await mkdir21(dir, { recursive: true });
|
|
36375
|
+
await writeFile18(filepath, content, "utf8");
|
|
35392
36376
|
return { filepath };
|
|
35393
36377
|
}
|
|
35394
36378
|
async function deleteSkill(name, cwd) {
|
|
@@ -35402,7 +36386,7 @@ async function setSkillEnabled(name, enabled2, cwd) {
|
|
|
35402
36386
|
const all = await listAllSkills(cwd);
|
|
35403
36387
|
const skill = all.project.find((s) => s.name === name) ?? all.global.find((s) => s.name === name);
|
|
35404
36388
|
if (!skill) throw new Error(`skill "${name}" not found`);
|
|
35405
|
-
const raw = await
|
|
36389
|
+
const raw = await readFile39(skill.filePath, "utf-8");
|
|
35406
36390
|
const parsed = parseFrontmatter2(raw);
|
|
35407
36391
|
parsed.data.enabled = enabled2;
|
|
35408
36392
|
const yaml = Object.entries(parsed.data).map(([k, v]) => {
|
|
@@ -35414,7 +36398,7 @@ ${v.map((item) => ` - ${item}`).join("\n")}`;
|
|
|
35414
36398
|
${yaml}
|
|
35415
36399
|
---
|
|
35416
36400
|
${parsed.content}`;
|
|
35417
|
-
await
|
|
36401
|
+
await writeFile18(skill.filePath, content, "utf8");
|
|
35418
36402
|
return { filepath: skill.filePath };
|
|
35419
36403
|
}
|
|
35420
36404
|
async function findSkillFile(name, cwd) {
|
|
@@ -35495,15 +36479,15 @@ var tui_report_exports = {};
|
|
|
35495
36479
|
__export(tui_report_exports, {
|
|
35496
36480
|
getCategoryReportText: () => getCategoryReportText
|
|
35497
36481
|
});
|
|
35498
|
-
import { readFile as
|
|
35499
|
-
import { join as
|
|
35500
|
-
import { homedir as
|
|
36482
|
+
import { readFile as readFile40 } from "fs/promises";
|
|
36483
|
+
import { join as join57 } from "path";
|
|
36484
|
+
import { homedir as homedir34 } from "os";
|
|
35501
36485
|
function usageDir3() {
|
|
35502
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
35503
|
-
return
|
|
36486
|
+
const xdg = process.env.XDG_DATA_HOME || join57(homedir34(), ".local", "share");
|
|
36487
|
+
return join57(xdg, "kimiflare");
|
|
35504
36488
|
}
|
|
35505
36489
|
function usagePath4() {
|
|
35506
|
-
return
|
|
36490
|
+
return join57(usageDir3(), "usage.json");
|
|
35507
36491
|
}
|
|
35508
36492
|
function today3() {
|
|
35509
36493
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -35515,7 +36499,7 @@ function daysAgo2(n) {
|
|
|
35515
36499
|
}
|
|
35516
36500
|
async function loadLog3() {
|
|
35517
36501
|
try {
|
|
35518
|
-
const raw = await
|
|
36502
|
+
const raw = await readFile40(usagePath4(), "utf8");
|
|
35519
36503
|
return JSON.parse(raw);
|
|
35520
36504
|
} catch {
|
|
35521
36505
|
return { version: 1, days: [], sessions: [] };
|
|
@@ -35572,7 +36556,7 @@ var init_tui_report = __esm({
|
|
|
35572
36556
|
});
|
|
35573
36557
|
|
|
35574
36558
|
// src/ui/slash-commands.ts
|
|
35575
|
-
import { join as
|
|
36559
|
+
import { join as join58 } from "path";
|
|
35576
36560
|
function executeFreshStart(ctx, planText, overrideMode, opts2 = {}) {
|
|
35577
36561
|
const oldSessionId = ctx.sessionIdRef.current;
|
|
35578
36562
|
if (ctx.cacheStableRef.current && ctx.messagesRef.current.length >= 2) {
|
|
@@ -35624,7 +36608,7 @@ function formatRunningSubagents(now2 = Date.now()) {
|
|
|
35624
36608
|
if (workers.length === 0) return "no subagents running";
|
|
35625
36609
|
return [
|
|
35626
36610
|
`${workers.length} subagent${workers.length === 1 ? "" : "s"} running:`,
|
|
35627
|
-
...workers.map((w) => ` #${w.index} ${formatElapsed2(now2 - w.startedAt)} ${w.status === "cancelling" ? "(cancelling) " : ""}${
|
|
36611
|
+
...workers.map((w) => ` #${w.index} ${formatElapsed2(now2 - w.startedAt)} ${w.status === "cancelling" ? "(cancelling) " : ""}${oneLine2(w.task, 90)}`),
|
|
35628
36612
|
"cancel one with /subagents cancel <n>, or all with /subagents cancel all \u2014 the turn keeps going"
|
|
35629
36613
|
].join("\n");
|
|
35630
36614
|
}
|
|
@@ -35637,7 +36621,7 @@ function cancelSubagents(target) {
|
|
|
35637
36621
|
const ref = target.replace(/^#/, "");
|
|
35638
36622
|
const cancelled = workerRegistry.cancel(/^\d+$/.test(ref) ? Number(ref) : ref);
|
|
35639
36623
|
if (!cancelled) return `no running subagent #${ref} (see /subagents list)`;
|
|
35640
|
-
return `cancelling subagent #${cancelled.index} (${
|
|
36624
|
+
return `cancelling subagent #${cancelled.index} (${oneLine2(cancelled.task, 60)}); the turn continues`;
|
|
35641
36625
|
}
|
|
35642
36626
|
function formatElapsed2(ms) {
|
|
35643
36627
|
const total = Math.max(0, Math.floor(ms / 1e3));
|
|
@@ -35645,7 +36629,7 @@ function formatElapsed2(ms) {
|
|
|
35645
36629
|
const sec = total % 60;
|
|
35646
36630
|
return m > 0 ? `${m}m${String(sec).padStart(2, "0")}s` : `${sec}s`;
|
|
35647
36631
|
}
|
|
35648
|
-
function
|
|
36632
|
+
function oneLine2(text3, max) {
|
|
35649
36633
|
const single = text3.replace(/\s+/g, " ").trim();
|
|
35650
36634
|
return single.length > max ? `${single.slice(0, max - 1)}\u2026` : single;
|
|
35651
36635
|
}
|
|
@@ -36044,7 +37028,7 @@ auto (default) lets the coordinator assess substantial tasks and delegate indepe
|
|
|
36044
37028
|
const context = noContext ? [] : await buildJevContext(question.prompt, ctx.messagesRef.current, process.cwd());
|
|
36045
37029
|
const receipt = formatJevContextReceipt(context, showContext);
|
|
36046
37030
|
setResult(eventKey, { kind: "info", key: eventKey, text: `Jev is evaluating \xB7 ${receipt}`, pending: true });
|
|
36047
|
-
await new Promise((
|
|
37031
|
+
await new Promise((resolve22) => setTimeout(resolve22, 0));
|
|
36048
37032
|
const answer = await askJev(apiKey, question, { context });
|
|
36049
37033
|
const presentation = presentJevAnswer(question, answer);
|
|
36050
37034
|
setResult(eventKey, {
|
|
@@ -36542,7 +37526,7 @@ ${lines.join("\n")}` }]);
|
|
|
36542
37526
|
void (async () => {
|
|
36543
37527
|
try {
|
|
36544
37528
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
36545
|
-
const file = await loadSession(
|
|
37529
|
+
const file = await loadSession(join58(sessionsDir3(), `${currentId}.json`));
|
|
36546
37530
|
const cps = file.checkpoints ?? [];
|
|
36547
37531
|
if (cps.length === 0) {
|
|
36548
37532
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "no checkpoints in this session" }]);
|
|
@@ -36587,7 +37571,7 @@ ${lines.join("\n")}` }]);
|
|
|
36587
37571
|
try {
|
|
36588
37572
|
ctx.ensureSessionId();
|
|
36589
37573
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
36590
|
-
const filePath =
|
|
37574
|
+
const filePath = join58(sessionsDir3(), `${ctx.sessionIdRef.current}.json`);
|
|
36591
37575
|
await addCheckpoint(filePath, cp);
|
|
36592
37576
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: `checkpoint saved: "${label}"` }]);
|
|
36593
37577
|
} catch (e) {
|
|
@@ -37087,12 +38071,12 @@ also read (legacy): ${legacyGlobalSettingsPath()}, ${legacyProjectSettingsPath(c
|
|
|
37087
38071
|
|
|
37088
38072
|
// src/init/context-generator.ts
|
|
37089
38073
|
import { existsSync as existsSync17, statSync as statSync6 } from "fs";
|
|
37090
|
-
import { join as
|
|
38074
|
+
import { join as join59 } from "path";
|
|
37091
38075
|
function detectFlavor(cwd) {
|
|
37092
38076
|
for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
|
|
37093
38077
|
if (flavor === "generic") continue;
|
|
37094
38078
|
for (const sig of signatures) {
|
|
37095
|
-
const path =
|
|
38079
|
+
const path = join59(cwd, sig);
|
|
37096
38080
|
if (sig.includes("*")) {
|
|
37097
38081
|
try {
|
|
37098
38082
|
const parts = sig.split("*");
|
|
@@ -37113,14 +38097,14 @@ function detectFlavor(cwd) {
|
|
|
37113
38097
|
}
|
|
37114
38098
|
function findFile(cwd, candidates) {
|
|
37115
38099
|
for (const c of candidates) {
|
|
37116
|
-
if (existsSync17(
|
|
38100
|
+
if (existsSync17(join59(cwd, c))) return c;
|
|
37117
38101
|
}
|
|
37118
38102
|
return null;
|
|
37119
38103
|
}
|
|
37120
38104
|
function findSourceRoots(cwd) {
|
|
37121
38105
|
const roots = [];
|
|
37122
38106
|
for (const r of SOURCE_ROOT_CANDIDATES) {
|
|
37123
|
-
const p =
|
|
38107
|
+
const p = join59(cwd, r);
|
|
37124
38108
|
try {
|
|
37125
38109
|
const s = statSync6(p);
|
|
37126
38110
|
if (s.isDirectory()) roots.push(r);
|
|
@@ -37131,9 +38115,9 @@ function findSourceRoots(cwd) {
|
|
|
37131
38115
|
}
|
|
37132
38116
|
function findCiConfig(cwd) {
|
|
37133
38117
|
for (const c of CI_PATHS) {
|
|
37134
|
-
if (existsSync17(
|
|
38118
|
+
if (existsSync17(join59(cwd, c))) {
|
|
37135
38119
|
try {
|
|
37136
|
-
const s = statSync6(
|
|
38120
|
+
const s = statSync6(join59(cwd, c));
|
|
37137
38121
|
return s.isDirectory() ? c : c;
|
|
37138
38122
|
} catch {
|
|
37139
38123
|
}
|
|
@@ -37270,7 +38254,7 @@ function analyzeProject(cwd) {
|
|
|
37270
38254
|
ciConfig: findCiConfig(cwd),
|
|
37271
38255
|
readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
|
|
37272
38256
|
sourceRoots: findSourceRoots(cwd),
|
|
37273
|
-
hasGit: existsSync17(
|
|
38257
|
+
hasGit: existsSync17(join59(cwd, ".git"))
|
|
37274
38258
|
};
|
|
37275
38259
|
}
|
|
37276
38260
|
function bashDiscoveryCommands(profile) {
|
|
@@ -37445,7 +38429,7 @@ function buildInitTasks(targetFilename) {
|
|
|
37445
38429
|
}
|
|
37446
38430
|
function buildInitPrompt(cwd) {
|
|
37447
38431
|
const existingName = ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
|
|
37448
|
-
(n) => existsSync17(
|
|
38432
|
+
(n) => existsSync17(join59(cwd, n))
|
|
37449
38433
|
);
|
|
37450
38434
|
const isRefresh = existingName !== void 0;
|
|
37451
38435
|
const targetFilename = existingName ?? "AGENTS.md";
|
|
@@ -37533,7 +38517,7 @@ var init_context_generator = __esm({
|
|
|
37533
38517
|
|
|
37534
38518
|
// src/init/run-init.ts
|
|
37535
38519
|
import { existsSync as existsSync18 } from "fs";
|
|
37536
|
-
import { join as
|
|
38520
|
+
import { join as join60 } from "path";
|
|
37537
38521
|
async function runInit(deps) {
|
|
37538
38522
|
const {
|
|
37539
38523
|
cfg,
|
|
@@ -37629,7 +38613,7 @@ async function runInit(deps) {
|
|
|
37629
38613
|
lspManagerRef.current.notifyChange(path, content);
|
|
37630
38614
|
} else {
|
|
37631
38615
|
void import("fs/promises").then(
|
|
37632
|
-
({ readFile:
|
|
38616
|
+
({ readFile: readFile42 }) => readFile42(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
|
|
37633
38617
|
})
|
|
37634
38618
|
);
|
|
37635
38619
|
}
|
|
@@ -37730,7 +38714,7 @@ async function runInit(deps) {
|
|
|
37730
38714
|
}
|
|
37731
38715
|
}
|
|
37732
38716
|
} }));
|
|
37733
|
-
if (existsSync18(
|
|
38717
|
+
if (existsSync18(join60(cwd, targetFilename))) {
|
|
37734
38718
|
if (cacheStableRef.current) {
|
|
37735
38719
|
messagesRef.current[1] = {
|
|
37736
38720
|
role: "system",
|
|
@@ -37824,11 +38808,11 @@ var init_run_init = __esm({
|
|
|
37824
38808
|
});
|
|
37825
38809
|
|
|
37826
38810
|
// src/skills/discovery.ts
|
|
37827
|
-
import { readdir as readdir9, stat as
|
|
37828
|
-
import { join as
|
|
38811
|
+
import { readdir as readdir9, stat as stat14, readFile as readFile41 } from "fs/promises";
|
|
38812
|
+
import { join as join61, extname as extname2 } from "path";
|
|
37829
38813
|
async function dirExists(path) {
|
|
37830
38814
|
try {
|
|
37831
|
-
const s = await
|
|
38815
|
+
const s = await stat14(path);
|
|
37832
38816
|
return s.isDirectory();
|
|
37833
38817
|
} catch {
|
|
37834
38818
|
return false;
|
|
@@ -37836,7 +38820,7 @@ async function dirExists(path) {
|
|
|
37836
38820
|
}
|
|
37837
38821
|
async function fileExists(path) {
|
|
37838
38822
|
try {
|
|
37839
|
-
const s = await
|
|
38823
|
+
const s = await stat14(path);
|
|
37840
38824
|
return s.isFile();
|
|
37841
38825
|
} catch {
|
|
37842
38826
|
return false;
|
|
@@ -37849,20 +38833,20 @@ async function scanSkillDir(dirPath, source) {
|
|
|
37849
38833
|
for (const entry of entries) {
|
|
37850
38834
|
if (!entry.isFile()) continue;
|
|
37851
38835
|
if (!SKILL_EXTENSIONS.has(extname2(entry.name))) continue;
|
|
37852
|
-
files.push({ filePath:
|
|
38836
|
+
files.push({ filePath: join61(dirPath, entry.name), source });
|
|
37853
38837
|
}
|
|
37854
38838
|
return files;
|
|
37855
38839
|
}
|
|
37856
38840
|
async function discoverSkills(cwd) {
|
|
37857
|
-
const agentsSkills = await scanSkillDir(
|
|
37858
|
-
const agentsMd = await fileExists(
|
|
37859
|
-
const githubSkills = await scanSkillDir(
|
|
37860
|
-
const kimiflareSkills = await scanSkillDir(
|
|
38841
|
+
const agentsSkills = await scanSkillDir(join61(cwd, ".agents", "skills"), "agents");
|
|
38842
|
+
const agentsMd = await fileExists(join61(cwd, "AGENTS.md")) ? [{ filePath: join61(cwd, "AGENTS.md"), source: "agents-md" }] : [];
|
|
38843
|
+
const githubSkills = await scanSkillDir(join61(cwd, ".github", "skills"), "github");
|
|
38844
|
+
const kimiflareSkills = await scanSkillDir(join61(cwd, ".kimiflare", "skills"), "kimiflare");
|
|
37861
38845
|
const ordered = [...agentsSkills, ...agentsMd, ...githubSkills, ...kimiflareSkills];
|
|
37862
38846
|
return ordered;
|
|
37863
38847
|
}
|
|
37864
38848
|
async function readSkillFile(filePath) {
|
|
37865
|
-
const bytes = await
|
|
38849
|
+
const bytes = await readFile41(filePath);
|
|
37866
38850
|
return { bytes, text: bytes.toString("utf-8") };
|
|
37867
38851
|
}
|
|
37868
38852
|
var SKILL_EXTENSIONS;
|
|
@@ -38069,7 +39053,7 @@ var init_skills = __esm({
|
|
|
38069
39053
|
|
|
38070
39054
|
// src/ui/run-startup-tasks.ts
|
|
38071
39055
|
import { existsSync as existsSync19 } from "fs";
|
|
38072
|
-
import { join as
|
|
39056
|
+
import { join as join62 } from "path";
|
|
38073
39057
|
function runStartupTasks(deps) {
|
|
38074
39058
|
const {
|
|
38075
39059
|
cfg,
|
|
@@ -38092,7 +39076,7 @@ function runStartupTasks(deps) {
|
|
|
38092
39076
|
}
|
|
38093
39077
|
});
|
|
38094
39078
|
if (cfg.memoryEnabled) {
|
|
38095
|
-
const dbPath = cfg.memoryDbPath ??
|
|
39079
|
+
const dbPath = cfg.memoryDbPath ?? join62(process.cwd(), ".kimiflare", "memory.db");
|
|
38096
39080
|
const manager = new MemoryManager({
|
|
38097
39081
|
dbPath,
|
|
38098
39082
|
...auth,
|
|
@@ -38125,7 +39109,7 @@ function runStartupTasks(deps) {
|
|
|
38125
39109
|
});
|
|
38126
39110
|
const cwd = process.cwd();
|
|
38127
39111
|
sessionStartRecallRef.current = manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
|
|
38128
|
-
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync19(
|
|
39112
|
+
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync19(join62(cwd, name)))) {
|
|
38129
39113
|
const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
|
|
38130
39114
|
const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
|
|
38131
39115
|
if (driftCount >= 5) {
|
|
@@ -38136,7 +39120,7 @@ function runStartupTasks(deps) {
|
|
|
38136
39120
|
memoryManagerRef.current?.close();
|
|
38137
39121
|
memoryManagerRef.current = null;
|
|
38138
39122
|
}
|
|
38139
|
-
const skillDbPath = cfg.memoryDbPath ??
|
|
39123
|
+
const skillDbPath = cfg.memoryDbPath ?? join62(process.cwd(), ".kimiflare", "memory.db");
|
|
38140
39124
|
const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
|
|
38141
39125
|
initSkillsSchema(skillDb);
|
|
38142
39126
|
void indexSkills({
|
|
@@ -38812,8 +39796,8 @@ var init_turn_nudges = __esm({
|
|
|
38812
39796
|
});
|
|
38813
39797
|
|
|
38814
39798
|
// src/commands/save.ts
|
|
38815
|
-
import { mkdir as
|
|
38816
|
-
import { dirname as
|
|
39799
|
+
import { mkdir as mkdir22, writeFile as writeFile19, unlink as unlink6 } from "fs/promises";
|
|
39800
|
+
import { dirname as dirname28 } from "path";
|
|
38817
39801
|
async function saveCustomCommand(opts2) {
|
|
38818
39802
|
const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
|
|
38819
39803
|
const filepath = `${dir}/${opts2.name}.md`;
|
|
@@ -38824,8 +39808,8 @@ async function saveCustomCommand(opts2) {
|
|
|
38824
39808
|
if (opts2.effort) data.effort = opts2.effort;
|
|
38825
39809
|
const frontmatter = serializeFrontmatter(data);
|
|
38826
39810
|
const content = frontmatter + opts2.template;
|
|
38827
|
-
await
|
|
38828
|
-
await
|
|
39811
|
+
await mkdir22(dirname28(filepath), { recursive: true });
|
|
39812
|
+
await writeFile19(filepath, content, "utf8");
|
|
38829
39813
|
return { filepath };
|
|
38830
39814
|
}
|
|
38831
39815
|
async function deleteCustomCommand(cmd) {
|
|
@@ -38924,7 +39908,7 @@ __export(app_exports, {
|
|
|
38924
39908
|
import { useState as useState6, useRef as useRef4, useEffect as useEffect2, useCallback as useCallback4, useMemo } from "react";
|
|
38925
39909
|
import { useApp, render } from "ink";
|
|
38926
39910
|
import { existsSync as existsSync20 } from "fs";
|
|
38927
|
-
import { join as
|
|
39911
|
+
import { join as join63 } from "path";
|
|
38928
39912
|
import { jsx } from "react/jsx-runtime";
|
|
38929
39913
|
function App({
|
|
38930
39914
|
initialCfg,
|
|
@@ -39178,7 +40162,7 @@ function App({
|
|
|
39178
40162
|
void (async () => {
|
|
39179
40163
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
39180
40164
|
try {
|
|
39181
|
-
await doResumeSession(
|
|
40165
|
+
await doResumeSession(join63(sessionsDir3(), `${initialResumeSessionId}.json`));
|
|
39182
40166
|
if (initialResumeReason === "crash") {
|
|
39183
40167
|
setEvents((e) => [
|
|
39184
40168
|
...e,
|
|
@@ -39411,7 +40395,7 @@ function App({
|
|
|
39411
40395
|
saveCheckpoint: async (checkpoint) => {
|
|
39412
40396
|
ensureSessionId();
|
|
39413
40397
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
39414
|
-
await addCheckpoint(
|
|
40398
|
+
await addCheckpoint(join63(sessionsDir3(), `${sessionIdRef.current}.json`), checkpoint);
|
|
39415
40399
|
},
|
|
39416
40400
|
summarize: () => generateContinuationSummary({
|
|
39417
40401
|
messages: messagesRef.current,
|
|
@@ -39930,27 +40914,20 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39930
40914
|
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: nudge }]);
|
|
39931
40915
|
}
|
|
39932
40916
|
const classification = classifyIntent(trimmed);
|
|
39933
|
-
|
|
39934
|
-
|
|
39935
|
-
|
|
39936
|
-
|
|
39937
|
-
|
|
39938
|
-
|
|
39939
|
-
|
|
39940
|
-
|
|
39941
|
-
|
|
39942
|
-
|
|
39943
|
-
|
|
39944
|
-
);
|
|
39945
|
-
|
|
39946
|
-
|
|
39947
|
-
setEvents((e) => [
|
|
39948
|
-
...e,
|
|
39949
|
-
{ kind: "info", key: mkKey(), text: `hook blocked the prompt: ${reason}` }
|
|
39950
|
-
]);
|
|
39951
|
-
endTurn();
|
|
39952
|
-
return;
|
|
39953
|
-
}
|
|
40917
|
+
const promptGate = await submitUserPrompt({
|
|
40918
|
+
hooks: hooksManagerRef.current,
|
|
40919
|
+
sessionId: ensureSessionId(trimmed),
|
|
40920
|
+
cwd: process.cwd(),
|
|
40921
|
+
prompt: opts2?.userPromptForHooks ?? display,
|
|
40922
|
+
tier: classification.tier,
|
|
40923
|
+
resumed: messagesRef.current.some((m) => m.role === "assistant"),
|
|
40924
|
+
model: overrideModel ?? cfg.model,
|
|
40925
|
+
auth: llmAuthFromConfig(cfg)
|
|
40926
|
+
});
|
|
40927
|
+
if (promptGate.blocked) {
|
|
40928
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: `hook blocked the prompt: ${promptGate.reason}` }]);
|
|
40929
|
+
endTurn();
|
|
40930
|
+
return;
|
|
39954
40931
|
}
|
|
39955
40932
|
messagesRef.current.push({ role: "user", content });
|
|
39956
40933
|
const traceUserSource = denyFeedbackRef.current ? "deny_feedback" : "typed";
|
|
@@ -39970,7 +40947,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39970
40947
|
turnCounterRef.current += 1;
|
|
39971
40948
|
const nudges = turnNudges({
|
|
39972
40949
|
turn: turnCounterRef.current,
|
|
39973
|
-
hasContextFile: ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync20(
|
|
40950
|
+
hasContextFile: ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync20(join63(process.cwd(), name))),
|
|
39974
40951
|
contextStale: kimiMdStale,
|
|
39975
40952
|
mode: modeRef.current,
|
|
39976
40953
|
freshAfterTurns: cfg?.autoFreshSuggestionTurns ?? DEFAULT_AUTO_FRESH_SUGGESTION_TURNS,
|
|
@@ -40147,7 +41124,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40147
41124
|
lspManagerRef.current.notifyChange(path, content2);
|
|
40148
41125
|
} else {
|
|
40149
41126
|
void import("fs/promises").then(
|
|
40150
|
-
({ readFile:
|
|
41127
|
+
({ readFile: readFile42 }) => readFile42(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
|
|
40151
41128
|
})
|
|
40152
41129
|
);
|
|
40153
41130
|
}
|
|
@@ -40655,7 +41632,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40655
41632
|
lsp: {
|
|
40656
41633
|
servers: cfg?.lspServers ?? {},
|
|
40657
41634
|
scope: lspScope,
|
|
40658
|
-
hasProjectDir: existsSync20(
|
|
41635
|
+
hasProjectDir: existsSync20(join63(process.cwd(), ".kimiflare"))
|
|
40659
41636
|
}
|
|
40660
41637
|
});
|
|
40661
41638
|
});
|
|
@@ -40747,6 +41724,7 @@ var init_app = __esm({
|
|
|
40747
41724
|
init_run_init();
|
|
40748
41725
|
init_connect();
|
|
40749
41726
|
init_session_lifecycle();
|
|
41727
|
+
init_prompt_submit();
|
|
40750
41728
|
init_run_startup_tasks();
|
|
40751
41729
|
init_manager_init();
|
|
40752
41730
|
init_run_compact();
|
|
@@ -40786,6 +41764,7 @@ init_sessions();
|
|
|
40786
41764
|
init_context_budget();
|
|
40787
41765
|
init_subagent_stats();
|
|
40788
41766
|
init_session_lifecycle();
|
|
41767
|
+
init_prompt_submit();
|
|
40789
41768
|
init_attachments();
|
|
40790
41769
|
init_glob();
|
|
40791
41770
|
init_permissions_evaluator();
|
|
@@ -40830,8 +41809,8 @@ async function resolveFiles(filePatterns, cwd) {
|
|
|
40830
41809
|
const resolved = /* @__PURE__ */ new Set();
|
|
40831
41810
|
for (const pattern of filePatterns) {
|
|
40832
41811
|
try {
|
|
40833
|
-
const
|
|
40834
|
-
if (
|
|
41812
|
+
const stat15 = await import("fs/promises").then((m) => m.stat(resolve7(cwd, pattern)));
|
|
41813
|
+
if (stat15.isFile()) {
|
|
40835
41814
|
resolved.add(resolve7(cwd, pattern));
|
|
40836
41815
|
continue;
|
|
40837
41816
|
}
|
|
@@ -40959,6 +41938,33 @@ async function runPrintMode(opts2) {
|
|
|
40959
41938
|
});
|
|
40960
41939
|
const usageWrites = [];
|
|
40961
41940
|
const auth = llmAuthFromConfig(opts2);
|
|
41941
|
+
const gate = await submitUserPrompt({
|
|
41942
|
+
hooks,
|
|
41943
|
+
sessionId: sessionFile.id,
|
|
41944
|
+
cwd,
|
|
41945
|
+
prompt: opts2.prompt,
|
|
41946
|
+
tier: policy.classification.tier,
|
|
41947
|
+
resumed: messages.some((m) => m.role === "assistant"),
|
|
41948
|
+
model: opts2.model,
|
|
41949
|
+
auth
|
|
41950
|
+
});
|
|
41951
|
+
if (gate.blocked) {
|
|
41952
|
+
const msg = `prompt blocked by a UserPromptSubmit hook: ${gate.reason}`;
|
|
41953
|
+
if (format === "text") {
|
|
41954
|
+
process.stderr.write(`\x1B[31mautopilot: ${msg}\x1B[0m
|
|
41955
|
+
`);
|
|
41956
|
+
} else if (format === "json") {
|
|
41957
|
+
jsonOutput.durationMs = Date.now() - startMs;
|
|
41958
|
+
process.stdout.write(JSON.stringify({ ...jsonOutput, error: msg, blocked: { reason: gate.reason } }, null, 2) + "\n");
|
|
41959
|
+
} else {
|
|
41960
|
+
emitStreamJson("error", { message: msg, code: PROMPT_BLOCKED_EXIT_CODE, reason: "prompt_blocked" });
|
|
41961
|
+
}
|
|
41962
|
+
process.exitCode = PROMPT_BLOCKED_EXIT_CODE;
|
|
41963
|
+
await endSessions("exit");
|
|
41964
|
+
trace.emit("session_end", { reason: "exit" }, null);
|
|
41965
|
+
await trace.flush();
|
|
41966
|
+
return;
|
|
41967
|
+
}
|
|
40962
41968
|
const callbacks = {
|
|
40963
41969
|
onUsageFinal: (u, meta) => {
|
|
40964
41970
|
const lookup = opts2.openrouterApiKey && !auth.customEndpoint && meta?.generationId ? { apiKey: opts2.openrouterApiKey, meta } : void 0;
|
|
@@ -41204,7 +42210,7 @@ function registerEvalCommand(program2) {
|
|
|
41204
42210
|
// src/index.tsx
|
|
41205
42211
|
var resumeCommand = null;
|
|
41206
42212
|
var program = new Command();
|
|
41207
|
-
program.name("autopilot").description("Terminal coding agent. Bring your own provider: OpenRouter, OpenAI, DeepSeek, Kimi, Z.ai, Ollama, any OpenAI-compatible endpoint.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", "model id for the active provider (defaults to its configured 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").option("--mode <mode>", "run mode: interactive (default), print, rpc").option("-c, --continue", "continue the most recent session in the current working directory").option("-S, --session <id>", "resume a specific session by id").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)");
|
|
42213
|
+
program.name("autopilot").description("Terminal coding agent. Bring your own provider: OpenRouter, OpenAI, DeepSeek, Kimi, Z.ai, Ollama, any OpenAI-compatible endpoint.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", "model id for the active provider (defaults to its configured 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").option("--mode <mode>", "run mode: interactive (default), print, rpc").option("-c, --continue", "continue the most recent session in the current working directory").option("-S, --session <id>", "resume a specific session by id").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)").option("--on <server>", "run the task on a paired server (autopilot remote add) instead of this machine").option("--local", "run on this machine (the default)").option("--repo <owner/name>", "with --on: GitHub repository (default: this checkout's origin)").option("--detach", "with --on: start the task and return without streaming its output").argument("[task...]", "with --on: the task to run on the server");
|
|
41208
42214
|
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) => {
|
|
41209
42215
|
const cfg = await loadConfig();
|
|
41210
42216
|
if (cmdOpts.verify) {
|
|
@@ -41235,10 +42241,51 @@ program.command("cost").description("Show cost attribution by task type (require
|
|
|
41235
42241
|
const { runCostCommand: runCostCommand2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
41236
42242
|
await runCostCommand2({ ...cmdOpts, config: cfg });
|
|
41237
42243
|
});
|
|
41238
|
-
|
|
41239
|
-
|
|
41240
|
-
|
|
41241
|
-
|
|
42244
|
+
async function runRemoteCommand(fn) {
|
|
42245
|
+
const controller = new AbortController();
|
|
42246
|
+
const onInterrupt = () => controller.abort();
|
|
42247
|
+
process.once("SIGINT", onInterrupt);
|
|
42248
|
+
try {
|
|
42249
|
+
const code = await fn(controller.signal);
|
|
42250
|
+
if (typeof code === "number") process.exitCode = code;
|
|
42251
|
+
} catch (error) {
|
|
42252
|
+
if (controller.signal.aborted) return;
|
|
42253
|
+
const { describeError: describeError2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
42254
|
+
console.error(`autopilot: ${describeError2(error)}`);
|
|
42255
|
+
process.exitCode = 1;
|
|
42256
|
+
} finally {
|
|
42257
|
+
process.off("SIGINT", onInterrupt);
|
|
42258
|
+
}
|
|
42259
|
+
}
|
|
42260
|
+
var remoteCommand = program.command("remote").description("Pair this machine with Autopilot servers that run tasks for you");
|
|
42261
|
+
remoteCommand.command("add").description("Pair with a server: approve the code it shows in your browser (no keys copied)").argument("<url>", "server URL, e.g. https://acme.example.com").option("-n, --name <name>", "short name for --on (default: the host's first label)").option("--no-open", "print the approval link instead of opening a browser").action((url, cmdOpts) => runRemoteCommand(async (signal) => {
|
|
42262
|
+
const { remoteAdd: remoteAdd2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
42263
|
+
await remoteAdd2({ url, open: cmdOpts.open, signal, ...cmdOpts.name ? { name: cmdOpts.name } : {} });
|
|
42264
|
+
}));
|
|
42265
|
+
remoteCommand.command("list").description("List paired servers").action(() => runRemoteCommand(async () => {
|
|
42266
|
+
const { remoteList: remoteList2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
42267
|
+
await remoteList2();
|
|
42268
|
+
}));
|
|
42269
|
+
remoteCommand.command("remove").description("Forget a paired server").argument("<name>").action((name) => runRemoteCommand(async () => {
|
|
42270
|
+
const { remoteRemove: remoteRemove2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
42271
|
+
return await remoteRemove2(name) ? 0 : 1;
|
|
42272
|
+
}));
|
|
42273
|
+
var runsCommand = program.command("runs").description("List tasks running or finished on your servers").option("--on <server>", "only this server").option("--json", "machine-readable output").action((cmdOpts) => runRemoteCommand(async () => {
|
|
42274
|
+
const { listRuns: listRuns2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
42275
|
+
await listRuns2({ ...cmdOpts.on ? { remote: cmdOpts.on } : {}, json: !!cmdOpts.json });
|
|
42276
|
+
}));
|
|
42277
|
+
runsCommand.command("watch").description("Show a run's output and follow it until it ends (Ctrl-C detaches)").argument("<run>", "run ID or prefix").option("--on <server>", "server the run is on").action((id, cmdOpts) => runRemoteCommand(async (signal) => {
|
|
42278
|
+
const { watchRun: watchRun2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
42279
|
+
return watchRun2({ id, signal, ...cmdOpts.on ? { remote: cmdOpts.on } : {} });
|
|
42280
|
+
}));
|
|
42281
|
+
runsCommand.command("cancel").description("Stop a running task").argument("<run>", "run ID or prefix").option("--on <server>", "server the run is on").action((id, cmdOpts) => runRemoteCommand(async () => {
|
|
42282
|
+
const { cancelRun: cancelRun2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
42283
|
+
await cancelRun2({ id, ...cmdOpts.on ? { remote: cmdOpts.on } : {} });
|
|
42284
|
+
}));
|
|
42285
|
+
program.command("pull").description("Check out a run's branch in this repository").argument("<run>", "run ID or prefix").option("--on <server>", "server the run is on").action((id, cmdOpts) => runRemoteCommand(async () => {
|
|
42286
|
+
const { pullRun: pullRun2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
42287
|
+
await pullRun2({ id, cwd: process.cwd(), ...cmdOpts.on ? { remote: cmdOpts.on } : {} });
|
|
42288
|
+
}));
|
|
41242
42289
|
registerEvalCommand(program);
|
|
41243
42290
|
var asterCommand = program.command("aster").description("Manage the Aster mobile API");
|
|
41244
42291
|
asterCommand.command("setup").description("Configure Aster for one or more local Git workspaces").requiredOption("-w, --workspace <path>", "Local Git repository root (repeatable)", (value, previous = []) => [...previous, value]).option("--json", "Print the selected workspace IDs as JSON").action(async (options) => {
|
|
@@ -41620,11 +42667,16 @@ Open: ${step.url}`);
|
|
|
41620
42667
|
})
|
|
41621
42668
|
);
|
|
41622
42669
|
program.command("serve").description("Start a headless HTTP server for API access and CI integration").option("--port <n>", "port to listen on", (v) => parseInt(v, 10), 4096).option("--hostname <host>", "hostname to listen on", "127.0.0.1").action(async (cmdOpts) => {
|
|
41623
|
-
const
|
|
41624
|
-
|
|
42670
|
+
const { resolveServeConfig: resolveServeConfig2 } = await Promise.resolve().then(() => (init_serve_config(), serve_config_exports));
|
|
42671
|
+
const resolved = resolveServeConfig2(await loadConfig());
|
|
42672
|
+
if (!resolved) {
|
|
41625
42673
|
console.error(`autopilot serve: ${await noCredentialsMessage()}`);
|
|
41626
42674
|
process.exit(2);
|
|
41627
42675
|
}
|
|
42676
|
+
if (resolved.asterOnly) {
|
|
42677
|
+
console.error("autopilot serve: no provider key on this host; serving the Aster API, whose cells reach the model through Hotcell's gateway.");
|
|
42678
|
+
}
|
|
42679
|
+
const cfg = resolved.config;
|
|
41628
42680
|
await initOtel();
|
|
41629
42681
|
await ensureModelCatalog(cfg);
|
|
41630
42682
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
@@ -41639,7 +42691,9 @@ program.command("serve").description("Start a headless HTTP server for API acces
|
|
|
41639
42691
|
process.exit(1);
|
|
41640
42692
|
}
|
|
41641
42693
|
});
|
|
41642
|
-
|
|
42694
|
+
var positionalTask = [];
|
|
42695
|
+
program.action(async (task = []) => {
|
|
42696
|
+
positionalTask = task;
|
|
41643
42697
|
await main();
|
|
41644
42698
|
const { runShutdownTasks: runShutdownTasks2 } = await Promise.resolve().then(() => (init_exit(), exit_exports));
|
|
41645
42699
|
await runShutdownTasks2();
|
|
@@ -41654,10 +42708,43 @@ async function initOtel() {
|
|
|
41654
42708
|
onShutdown2("otel-flush", shutdownOtelSink2, SHUTDOWN_PHASE2.flush);
|
|
41655
42709
|
}
|
|
41656
42710
|
}
|
|
42711
|
+
async function runRemoteTask() {
|
|
42712
|
+
if (opts.on === void 0) {
|
|
42713
|
+
console.error(`autopilot: unknown command "${positionalTask[0]}". To run a task here use -p "\u2026"; on a server, --on <server> "\u2026".`);
|
|
42714
|
+
process.exit(2);
|
|
42715
|
+
}
|
|
42716
|
+
if (opts.local) {
|
|
42717
|
+
console.error("autopilot: --on and --local can't be combined.");
|
|
42718
|
+
process.exit(2);
|
|
42719
|
+
}
|
|
42720
|
+
const task = (positionalTask.join(" ") || opts.print || "").trim();
|
|
42721
|
+
if (!task) {
|
|
42722
|
+
console.error(`autopilot: --on needs a task, e.g. autopilot --on ${opts.on} "fix the flaky checkout test"`);
|
|
42723
|
+
process.exit(2);
|
|
42724
|
+
}
|
|
42725
|
+
const cfg = await loadConfig().catch(() => null);
|
|
42726
|
+
await runRemoteCommand(async (signal) => {
|
|
42727
|
+
const { runOnRemote: runOnRemote2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
42728
|
+
return runOnRemote2({
|
|
42729
|
+
remote: opts.on,
|
|
42730
|
+
task,
|
|
42731
|
+
cwd: opts.dir ?? process.cwd(),
|
|
42732
|
+
signal,
|
|
42733
|
+
detach: !!opts.detach,
|
|
42734
|
+
...opts.model ? { model: opts.model } : {},
|
|
42735
|
+
...cfg?.model ? { preferredModel: cfg.model } : {},
|
|
42736
|
+
...opts.repo ? { repository: opts.repo } : {}
|
|
42737
|
+
});
|
|
42738
|
+
});
|
|
42739
|
+
}
|
|
41657
42740
|
async function main() {
|
|
41658
42741
|
await initOtel();
|
|
41659
42742
|
const { installExitHandlers: installExitHandlers2 } = await Promise.resolve().then(() => (init_exit(), exit_exports));
|
|
41660
42743
|
installExitHandlers2({ crashes: true });
|
|
42744
|
+
if (opts.on !== void 0 || positionalTask.length > 0) {
|
|
42745
|
+
await runRemoteTask();
|
|
42746
|
+
return;
|
|
42747
|
+
}
|
|
41661
42748
|
const globalCfg = await loadConfig();
|
|
41662
42749
|
const updateResult = await checkForUpdate();
|
|
41663
42750
|
let cfg = globalCfg;
|
|
@@ -41836,12 +42923,12 @@ function requireModel(model) {
|
|
|
41836
42923
|
process.exit(2);
|
|
41837
42924
|
}
|
|
41838
42925
|
async function noCredentialsMessage() {
|
|
41839
|
-
const { readFile:
|
|
42926
|
+
const { readFile: readFile42 } = await import("fs/promises");
|
|
41840
42927
|
const { configPath: configPath2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
41841
42928
|
const { resolveActiveProvider: resolveActiveProvider2 } = await Promise.resolve().then(() => (init_resolve(), resolve_exports));
|
|
41842
42929
|
let persisted = {};
|
|
41843
42930
|
try {
|
|
41844
|
-
persisted = JSON.parse(await
|
|
42931
|
+
persisted = JSON.parse(await readFile42(configPath2(), "utf8"));
|
|
41845
42932
|
} catch {
|
|
41846
42933
|
}
|
|
41847
42934
|
const { id, preset } = resolveActiveProvider2(persisted);
|
|
@@ -41869,11 +42956,11 @@ async function promptHidden(question) {
|
|
|
41869
42956
|
}
|
|
41870
42957
|
});
|
|
41871
42958
|
const rl = createInterface4({ input: process.stdin, output, terminal: true });
|
|
41872
|
-
return new Promise((
|
|
42959
|
+
return new Promise((resolve22) => {
|
|
41873
42960
|
rl.question(question, (answer) => {
|
|
41874
42961
|
rl.close();
|
|
41875
42962
|
process.stdout.write("\n");
|
|
41876
|
-
|
|
42963
|
+
resolve22(answer);
|
|
41877
42964
|
});
|
|
41878
42965
|
muted = true;
|
|
41879
42966
|
});
|