@livx.cc/agentx 0.99.74 → 0.99.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Agent-Bs2ufrIU.d.ts → Agent-BBlKI8uD.d.ts} +7 -0
- package/dist/cli.d.ts +7 -1
- package/dist/cli.js +138 -113
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -308,6 +308,13 @@ interface RunResult {
|
|
|
308
308
|
cacheCreationTokens?: number;
|
|
309
309
|
cacheReadTokens?: number;
|
|
310
310
|
};
|
|
311
|
+
/** Present iff `finishReason === 'budget'`: the weighted spend vs `maxTokens`, and the last step's prompt
|
|
312
|
+
* size — a prompt near the limit means the CONVERSATION is too big for one run (compact / new chat). */
|
|
313
|
+
budget?: {
|
|
314
|
+
spent: number;
|
|
315
|
+
limit: number;
|
|
316
|
+
stepPrompt: number;
|
|
317
|
+
};
|
|
311
318
|
/** True if ANY turn's usage was estimated (provider gave none) rather than exact — lets the UI mark cost `~`. */
|
|
312
319
|
usageEstimated?: boolean;
|
|
313
320
|
/** Set by a router (`--model auto`) whose turn spans several models: the turn's USD at each model's own rate. */
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { m as RouterState, H as Hooks, n as RunResult, R as ReasoningEffort, A as Agent } from './Agent-
|
|
2
|
+
import { m as RouterState, H as Hooks, n as RunResult, R as ReasoningEffort, A as Agent } from './Agent-BBlKI8uD.js';
|
|
3
3
|
import { IFilesystem } from '@livx.cc/wcli/core';
|
|
4
4
|
import { M as Message, U as UserQuestion, H as HostBridge, c as ContentPart, o as MessageContent } from './tools-lC3jn60o.js';
|
|
5
5
|
|
|
@@ -147,6 +147,7 @@ interface Args {
|
|
|
147
147
|
appendSystemPrompt?: string;
|
|
148
148
|
voiceSystemPrompt?: string;
|
|
149
149
|
addDirs?: string[];
|
|
150
|
+
mcpConfig?: string;
|
|
150
151
|
print?: boolean;
|
|
151
152
|
debug?: boolean;
|
|
152
153
|
scratch?: boolean;
|
|
@@ -297,6 +298,11 @@ declare function jsonResult(res: RunResult, session: SessionData): {
|
|
|
297
298
|
sessionId: string;
|
|
298
299
|
costUsd?: number | undefined;
|
|
299
300
|
routing?: Record<string, unknown> | undefined;
|
|
301
|
+
budget?: {
|
|
302
|
+
spent: number;
|
|
303
|
+
limit: number;
|
|
304
|
+
stepPrompt: number;
|
|
305
|
+
} | undefined;
|
|
300
306
|
text: string;
|
|
301
307
|
steps: number;
|
|
302
308
|
tools: number;
|
package/dist/cli.js
CHANGED
|
@@ -4876,6 +4876,7 @@ var Agent = class _Agent {
|
|
|
4876
4876
|
let steps = 0;
|
|
4877
4877
|
const usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
|
|
4878
4878
|
let usageEstimated = false;
|
|
4879
|
+
let spent = 0, prevPrompt = -1, stepPrompt = 0;
|
|
4879
4880
|
const start = Date.now();
|
|
4880
4881
|
this.parkedMs = 0;
|
|
4881
4882
|
this.ctx.needsInput = void 0;
|
|
@@ -4886,12 +4887,12 @@ var Agent = class _Agent {
|
|
|
4886
4887
|
let closureNudged = false;
|
|
4887
4888
|
let lastProgressAt = start;
|
|
4888
4889
|
const kill = (finishReason) => {
|
|
4889
|
-
log8.warn(`kill-switch: ${finishReason} (steps=${steps}, tokens=${usage.totalTokens}, budgetTokens=${Math.round(
|
|
4890
|
+
log8.warn(`kill-switch: ${finishReason} (steps=${steps}, tokens=${usage.totalTokens}, budgetTokens=${Math.round(spent)}, ms=${Date.now() - start - this.parkedMs}${finishReason === "timeout" ? `, idle=${Date.now() - lastProgressAt - this.parkedMs}ms` : ""}${this.parkedMs ? ` +${this.parkedMs} parked` : ""})`);
|
|
4890
4891
|
this.jobs.killAll(`run ended: ${finishReason}`, true);
|
|
4891
4892
|
const claims = this.survivingClaims();
|
|
4892
|
-
return { text: lastAssistantText(this.transcript), steps, finishReason, messages: this.transcript, usage, usageEstimated, ...claims.length ? { fabricatedToolClaims: claims } : {} };
|
|
4893
|
+
return { text: lastAssistantText(this.transcript), steps, finishReason, messages: this.transcript, usage, usageEstimated, ...finishReason === "budget" ? { budget: { spent: Math.round(spent), limit: o.maxTokens, stepPrompt } } : {}, ...claims.length ? { fabricatedToolClaims: claims } : {} };
|
|
4893
4894
|
};
|
|
4894
|
-
const overBudget = () => !!o.maxTokens &&
|
|
4895
|
+
const overBudget = () => !!o.maxTokens && spent >= o.maxTokens;
|
|
4895
4896
|
const canNudge = () => steps < o.maxSteps && !overBudget();
|
|
4896
4897
|
while (true) {
|
|
4897
4898
|
if (o.signal?.aborted) return kill("aborted");
|
|
@@ -5045,6 +5046,14 @@ var Agent = class _Agent {
|
|
|
5045
5046
|
usage.totalTokens += res.usage.totalTokens ?? 0;
|
|
5046
5047
|
usage.cacheCreationTokens += res.usage.cacheCreationTokens ?? 0;
|
|
5047
5048
|
usage.cacheReadTokens += res.usage.cacheReadTokens ?? 0;
|
|
5049
|
+
const prompt = res.usage.promptTokens ?? 0, cacheRead = res.usage.cacheReadTokens ?? 0;
|
|
5050
|
+
if (prevPrompt < 0) {
|
|
5051
|
+
const u = sent.map((m) => m.role).lastIndexOf("user");
|
|
5052
|
+
prevPrompt = u > 0 ? estimateTokens(sent.slice(0, u)) : 0;
|
|
5053
|
+
}
|
|
5054
|
+
const reused = Math.min(prompt, Math.max(cacheRead, prevPrompt));
|
|
5055
|
+
spent += (res.usage.totalTokens ?? 0) - 0.9 * reused;
|
|
5056
|
+
prevPrompt = stepPrompt = prompt;
|
|
5048
5057
|
}
|
|
5049
5058
|
const delegatedTools = res.delegatedTools ?? [];
|
|
5050
5059
|
if (delegatedTools.length) {
|
|
@@ -12880,14 +12889,90 @@ var JsonlDiagSink = class {
|
|
|
12880
12889
|
};
|
|
12881
12890
|
|
|
12882
12891
|
// cli/config.ts
|
|
12883
|
-
import { homedir as
|
|
12892
|
+
import { homedir as homedir5 } from "os";
|
|
12884
12893
|
import { existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
|
|
12885
|
-
import { join as
|
|
12894
|
+
import { join as join8 } from "path";
|
|
12886
12895
|
import { pathToFileURL } from "url";
|
|
12896
|
+
|
|
12897
|
+
// cli/permissions.ts
|
|
12898
|
+
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync7 } from "fs";
|
|
12899
|
+
import { homedir as homedir4 } from "os";
|
|
12900
|
+
import { join as join7 } from "path";
|
|
12901
|
+
var RULE_RE = /^(\w[\w*-]*)(?:\((.+)\))?$/;
|
|
12902
|
+
function parseOne(raw, decision) {
|
|
12903
|
+
const m = RULE_RE.exec(raw.trim());
|
|
12904
|
+
if (!m) return null;
|
|
12905
|
+
const [, tool, pathGlob] = m;
|
|
12906
|
+
return pathGlob ? { tool, pathGlob, decision } : { tool, decision };
|
|
12907
|
+
}
|
|
12908
|
+
function parsePermRules(perms, explicit = false) {
|
|
12909
|
+
if (!perms) return [];
|
|
12910
|
+
const out = [];
|
|
12911
|
+
for (const [decision, list] of [["deny", perms.deny], ["allow", perms.allow], ["ask", perms.ask]]) {
|
|
12912
|
+
for (const raw of list ?? []) {
|
|
12913
|
+
const r = parseOne(raw, decision);
|
|
12914
|
+
if (r) out.push(explicit ? { ...r, explicit } : r);
|
|
12915
|
+
}
|
|
12916
|
+
}
|
|
12917
|
+
return out;
|
|
12918
|
+
}
|
|
12919
|
+
function describeRule(r) {
|
|
12920
|
+
return `${r.decision.padEnd(5)} ${r.tool ?? "*"}${r.pathGlob ? `(${r.pathGlob})` : ""}`;
|
|
12921
|
+
}
|
|
12922
|
+
var PERM_FILE = (cwd) => join7(cwd, ".agent", "permissions.json");
|
|
12923
|
+
function loadPersistedRules(cwd) {
|
|
12924
|
+
const j = readJsonFile(PERM_FILE(cwd), null);
|
|
12925
|
+
return j ? { allow: j.allow ?? [], ask: j.ask ?? [], deny: j.deny ?? [] } : {};
|
|
12926
|
+
}
|
|
12927
|
+
function loadClaudeSettings(cwd, home = homedir4()) {
|
|
12928
|
+
const files = [join7(home, ".claude", "settings.json"), join7(cwd, ".claude", "settings.json"), join7(cwd, ".claude", "settings.local.json")];
|
|
12929
|
+
let out = {};
|
|
12930
|
+
for (const p of files) {
|
|
12931
|
+
const perms = readJsonFile(p, null)?.permissions;
|
|
12932
|
+
if (perms) out = mergePerms(out, { allow: perms.allow, ask: perms.ask, deny: perms.deny }) ?? out;
|
|
12933
|
+
}
|
|
12934
|
+
return out;
|
|
12935
|
+
}
|
|
12936
|
+
function persistRule(cwd, decision, ruleStr) {
|
|
12937
|
+
const cur = loadPersistedRules(cwd);
|
|
12938
|
+
const list = cur[decision] ??= [];
|
|
12939
|
+
if (!list.includes(ruleStr)) list.push(ruleStr);
|
|
12940
|
+
try {
|
|
12941
|
+
mkdirSync7(join7(cwd, ".agent"), { recursive: true });
|
|
12942
|
+
writeFileSync4(PERM_FILE(cwd), JSON.stringify(cur, null, 2) + "\n");
|
|
12943
|
+
} catch {
|
|
12944
|
+
}
|
|
12945
|
+
}
|
|
12946
|
+
function mergePerms(a, b) {
|
|
12947
|
+
if (!a && !b) return void 0;
|
|
12948
|
+
const out = {};
|
|
12949
|
+
for (const k of ["allow", "ask", "deny"]) {
|
|
12950
|
+
const merged = [...a?.[k] ?? [], ...b?.[k] ?? []];
|
|
12951
|
+
if (merged.length) out[k] = [...new Set(merged)];
|
|
12952
|
+
}
|
|
12953
|
+
return Object.keys(out).length ? out : void 0;
|
|
12954
|
+
}
|
|
12955
|
+
var TRUST_FILE = join7(homedir4(), ".agent", "trusted.json");
|
|
12956
|
+
function isTrusted(cwd, file = TRUST_FILE) {
|
|
12957
|
+
const list = readJsonFile(file, []);
|
|
12958
|
+
return Array.isArray(list) && list.includes(cwd);
|
|
12959
|
+
}
|
|
12960
|
+
function trustDir(cwd, file = TRUST_FILE) {
|
|
12961
|
+
let list = readJsonFile(file, []);
|
|
12962
|
+
if (!Array.isArray(list)) list = [];
|
|
12963
|
+
if (!list.includes(cwd)) list.push(cwd);
|
|
12964
|
+
try {
|
|
12965
|
+
mkdirSync7(join7(file, ".."), { recursive: true });
|
|
12966
|
+
writeFileSync4(file, JSON.stringify(list, null, 2) + "\n");
|
|
12967
|
+
} catch {
|
|
12968
|
+
}
|
|
12969
|
+
}
|
|
12970
|
+
|
|
12971
|
+
// cli/config.ts
|
|
12887
12972
|
var FILES = ["config.ts", "config.js", "config.mjs", "config.json"];
|
|
12888
12973
|
async function loadFrom(dir) {
|
|
12889
12974
|
for (const f of FILES) {
|
|
12890
|
-
const p =
|
|
12975
|
+
const p = join8(dir, ".agent", f);
|
|
12891
12976
|
if (!existsSync5(p)) continue;
|
|
12892
12977
|
try {
|
|
12893
12978
|
const mod = await import(pathToFileURL(p).href, f.endsWith(".json") ? { with: { type: "json" } } : void 0);
|
|
@@ -12900,7 +12985,7 @@ async function loadFrom(dir) {
|
|
|
12900
12985
|
return {};
|
|
12901
12986
|
}
|
|
12902
12987
|
function loadSettings(dir) {
|
|
12903
|
-
const p =
|
|
12988
|
+
const p = join8(dir, ".agent", "settings.json");
|
|
12904
12989
|
if (!existsSync5(p)) return {};
|
|
12905
12990
|
try {
|
|
12906
12991
|
const raw = JSON.parse(readFileSync7(p, "utf8"));
|
|
@@ -12923,17 +13008,28 @@ function loadSettings(dir) {
|
|
|
12923
13008
|
return {};
|
|
12924
13009
|
}
|
|
12925
13010
|
}
|
|
12926
|
-
async function loadConfig(cwd) {
|
|
12927
|
-
const userSettings = loadSettings(
|
|
12928
|
-
const user = await loadFrom(
|
|
13011
|
+
async function loadConfig(cwd, overlayFile) {
|
|
13012
|
+
const userSettings = loadSettings(homedir5());
|
|
13013
|
+
const user = await loadFrom(homedir5());
|
|
12929
13014
|
const projectSettings = loadSettings(cwd);
|
|
12930
13015
|
const project = await loadFrom(cwd);
|
|
12931
13016
|
const merged = { ...userSettings, ...user, ...projectSettings, ...project };
|
|
12932
13017
|
if (userSettings.mcpServers || user.mcpServers || projectSettings.mcpServers || project.mcpServers) {
|
|
12933
13018
|
merged.mcpServers = { ...userSettings.mcpServers, ...user.mcpServers, ...projectSettings.mcpServers, ...project.mcpServers };
|
|
12934
13019
|
}
|
|
13020
|
+
if (overlayFile) applyOverlay(merged, overlayFile);
|
|
12935
13021
|
return merged;
|
|
12936
13022
|
}
|
|
13023
|
+
function applyOverlay(cfg, file) {
|
|
13024
|
+
let raw;
|
|
13025
|
+
try {
|
|
13026
|
+
raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
13027
|
+
} catch (e) {
|
|
13028
|
+
throw new Error(`--mcp-config ${file}: ${e?.message ?? e}`);
|
|
13029
|
+
}
|
|
13030
|
+
if (raw?.mcpServers && typeof raw.mcpServers === "object") cfg.mcpServers = { ...cfg.mcpServers, ...raw.mcpServers };
|
|
13031
|
+
if (raw?.permissions && typeof raw.permissions === "object") cfg.permissions = mergePerms(cfg.permissions, raw.permissions);
|
|
13032
|
+
}
|
|
12937
13033
|
|
|
12938
13034
|
// cli/hooks-config.ts
|
|
12939
13035
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
@@ -13058,15 +13154,15 @@ function formatDiff(ops, opts = {}) {
|
|
|
13058
13154
|
}
|
|
13059
13155
|
|
|
13060
13156
|
// cli/session.ts
|
|
13061
|
-
import { existsSync as existsSync6, mkdirSync as
|
|
13062
|
-
import { homedir as
|
|
13063
|
-
import { join as
|
|
13157
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync5, readdirSync, renameSync, symlinkSync as symlinkSync2, unlinkSync, readlinkSync, statSync as statSync6 } from "fs";
|
|
13158
|
+
import { homedir as homedir6 } from "os";
|
|
13159
|
+
import { join as join9 } from "path";
|
|
13064
13160
|
var log30 = forComponent("session");
|
|
13065
|
-
var globalDir = () =>
|
|
13161
|
+
var globalDir = () => join9(homedir6(), ".agent", "sessions");
|
|
13066
13162
|
var SessionStore = class {
|
|
13067
13163
|
dir;
|
|
13068
13164
|
constructor(cwd) {
|
|
13069
|
-
this.dir =
|
|
13165
|
+
this.dir = join9(cwd, ".agent", "sessions");
|
|
13070
13166
|
}
|
|
13071
13167
|
/** Sortable, human-readable id: `YYYYMMDD-HHMMSS-<folder>`. */
|
|
13072
13168
|
newId(now4 = Date.now(), cwd) {
|
|
@@ -13074,10 +13170,10 @@ var SessionStore = class {
|
|
|
13074
13170
|
const p = (n, w = 2) => String(n).padStart(w, "0");
|
|
13075
13171
|
const slug2 = (cwd ?? process.cwd()).split("/").pop()?.replace(/[^A-Za-z0-9_-]/g, "") || "session";
|
|
13076
13172
|
let id = `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}-${slug2}`;
|
|
13077
|
-
if (existsSync6(this.dir) && existsSync6(
|
|
13173
|
+
if (existsSync6(this.dir) && existsSync6(join9(this.dir, `${id}.json`))) {
|
|
13078
13174
|
for (let i = 2; i <= 99; i++) {
|
|
13079
13175
|
const c = `${id}-${i}`;
|
|
13080
|
-
if (!existsSync6(
|
|
13176
|
+
if (!existsSync6(join9(this.dir, `${c}.json`))) {
|
|
13081
13177
|
id = c;
|
|
13082
13178
|
break;
|
|
13083
13179
|
}
|
|
@@ -13091,15 +13187,15 @@ var SessionStore = class {
|
|
|
13091
13187
|
}
|
|
13092
13188
|
save(data) {
|
|
13093
13189
|
if (!this.safeId(data.meta.id)) throw new Error(`unsafe session id: ${data.meta.id}`);
|
|
13094
|
-
if (!existsSync6(this.dir))
|
|
13095
|
-
const path =
|
|
13190
|
+
if (!existsSync6(this.dir)) mkdirSync8(this.dir, { recursive: true });
|
|
13191
|
+
const path = join9(this.dir, `${data.meta.id}.json`);
|
|
13096
13192
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
13097
|
-
|
|
13193
|
+
writeFileSync5(tmp, JSON.stringify(data));
|
|
13098
13194
|
renameSync(tmp, path);
|
|
13099
13195
|
try {
|
|
13100
13196
|
const gd = globalDir();
|
|
13101
|
-
if (!existsSync6(gd))
|
|
13102
|
-
const link2 =
|
|
13197
|
+
if (!existsSync6(gd)) mkdirSync8(gd, { recursive: true });
|
|
13198
|
+
const link2 = join9(gd, `${data.meta.id}.json`);
|
|
13103
13199
|
if (!existsSync6(link2)) symlinkSync2(path, link2);
|
|
13104
13200
|
} catch {
|
|
13105
13201
|
}
|
|
@@ -13109,7 +13205,7 @@ var SessionStore = class {
|
|
|
13109
13205
|
log30.debug(`rejecting unsafe session id: ${id}`);
|
|
13110
13206
|
return void 0;
|
|
13111
13207
|
}
|
|
13112
|
-
const path =
|
|
13208
|
+
const path = join9(this.dir, `${id}.json`);
|
|
13113
13209
|
if (!existsSync6(path)) return void 0;
|
|
13114
13210
|
try {
|
|
13115
13211
|
return JSON.parse(readFileSync8(path, "utf8"));
|
|
@@ -13125,7 +13221,7 @@ var SessionStore = class {
|
|
|
13125
13221
|
for (const f of readdirSync(this.dir)) {
|
|
13126
13222
|
if (!f.endsWith(".json")) continue;
|
|
13127
13223
|
try {
|
|
13128
|
-
metas.push(JSON.parse(readFileSync8(
|
|
13224
|
+
metas.push(JSON.parse(readFileSync8(join9(this.dir, f), "utf8")).meta);
|
|
13129
13225
|
} catch (e) {
|
|
13130
13226
|
log30.debug(`skipping unreadable session file ${f}`, e);
|
|
13131
13227
|
}
|
|
@@ -13140,7 +13236,7 @@ var SessionStore = class {
|
|
|
13140
13236
|
for (const f of readdirSync(this.dir)) {
|
|
13141
13237
|
if (!f.endsWith(".json")) continue;
|
|
13142
13238
|
try {
|
|
13143
|
-
const st = statSync6(
|
|
13239
|
+
const st = statSync6(join9(this.dir, f));
|
|
13144
13240
|
out.push({ id: f.slice(0, -5), mtime: st.mtimeMs, size: st.size });
|
|
13145
13241
|
} catch {
|
|
13146
13242
|
}
|
|
@@ -13159,7 +13255,7 @@ var SessionStore = class {
|
|
|
13159
13255
|
function globalSessionLoad(idOrPrefix) {
|
|
13160
13256
|
const gd = globalDir();
|
|
13161
13257
|
if (!existsSync6(gd)) return void 0;
|
|
13162
|
-
const exact =
|
|
13258
|
+
const exact = join9(gd, `${idOrPrefix}.json`);
|
|
13163
13259
|
if (existsSync6(exact)) {
|
|
13164
13260
|
try {
|
|
13165
13261
|
const target = readlinkSync(exact);
|
|
@@ -13173,7 +13269,7 @@ function globalSessionLoad(idOrPrefix) {
|
|
|
13173
13269
|
if (!f.endsWith(".json")) continue;
|
|
13174
13270
|
const base = f.slice(0, -5);
|
|
13175
13271
|
if (base.includes(idOrPrefix) || base.endsWith(idOrPrefix)) {
|
|
13176
|
-
const target = readlinkSync(
|
|
13272
|
+
const target = readlinkSync(join9(gd, f));
|
|
13177
13273
|
return JSON.parse(readFileSync8(target, "utf8"));
|
|
13178
13274
|
}
|
|
13179
13275
|
}
|
|
@@ -13188,10 +13284,10 @@ function globalSessionList() {
|
|
|
13188
13284
|
for (const f of readdirSync(gd)) {
|
|
13189
13285
|
if (!f.endsWith(".json")) continue;
|
|
13190
13286
|
try {
|
|
13191
|
-
const target = readlinkSync(
|
|
13287
|
+
const target = readlinkSync(join9(gd, f));
|
|
13192
13288
|
if (!existsSync6(target)) {
|
|
13193
13289
|
try {
|
|
13194
|
-
unlinkSync(
|
|
13290
|
+
unlinkSync(join9(gd, f));
|
|
13195
13291
|
} catch {
|
|
13196
13292
|
}
|
|
13197
13293
|
continue;
|
|
@@ -13363,15 +13459,15 @@ ${formatDiff(ops)}`);
|
|
|
13363
13459
|
// cli/gitCheckpoints.ts
|
|
13364
13460
|
import { execFile as execFile3 } from "child_process";
|
|
13365
13461
|
import { promisify } from "util";
|
|
13366
|
-
import { writeFileSync as
|
|
13367
|
-
import { homedir as
|
|
13368
|
-
import { join as
|
|
13462
|
+
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync9 } from "fs";
|
|
13463
|
+
import { homedir as homedir7 } from "os";
|
|
13464
|
+
import { join as join10, resolve as resolve3, sep as sep3, parse as parsePath } from "path";
|
|
13369
13465
|
var log31 = forComponent("checkpoints");
|
|
13370
13466
|
var exec = promisify(execFile3);
|
|
13371
13467
|
var DEFAULT_EXCLUDE = [".agent/", ".git/", "node_modules/", "dist/", "build/", ".next/", "target/", ".venv/", "__pycache__/", "*.log"];
|
|
13372
13468
|
function isBroadRoot(p) {
|
|
13373
13469
|
const abs = resolve3(p);
|
|
13374
|
-
return abs === resolve3(
|
|
13470
|
+
return abs === resolve3(homedir7()) || abs === parsePath(abs).root;
|
|
13375
13471
|
}
|
|
13376
13472
|
var ShadowRepo = class {
|
|
13377
13473
|
// undefined = unprobed; false = git/this root unusable
|
|
@@ -13405,11 +13501,11 @@ var ShadowRepo = class {
|
|
|
13405
13501
|
if (this.ready !== void 0) return this.ready;
|
|
13406
13502
|
try {
|
|
13407
13503
|
await exec(this.git, ["--version"]);
|
|
13408
|
-
|
|
13504
|
+
mkdirSync9(this.gitDir, { recursive: true });
|
|
13409
13505
|
const valid = await this.run("rev-parse", "--git-dir").then(() => true, () => false);
|
|
13410
13506
|
if (!valid) await this.run("init", "-q");
|
|
13411
|
-
|
|
13412
|
-
|
|
13507
|
+
mkdirSync9(join10(this.gitDir, "info"), { recursive: true });
|
|
13508
|
+
writeFileSync6(join10(this.gitDir, "info", "exclude"), this.exclude.join("\n") + "\n");
|
|
13413
13509
|
this.ready = true;
|
|
13414
13510
|
} catch (e) {
|
|
13415
13511
|
log31.debug(`git checkpoints unavailable for ${this.workTree}`, e);
|
|
@@ -13524,7 +13620,7 @@ var GitCheckpoints = class {
|
|
|
13524
13620
|
const abs = resolve3(d);
|
|
13525
13621
|
if (abs === cwd || abs.startsWith(cwd + sep3)) continue;
|
|
13526
13622
|
if (cwd.startsWith(abs + sep3)) continue;
|
|
13527
|
-
out.push({ workTree: abs, gitDir:
|
|
13623
|
+
out.push({ workTree: abs, gitDir: join10(abs, ".agent", "checkpoints.git") });
|
|
13528
13624
|
}
|
|
13529
13625
|
return out;
|
|
13530
13626
|
}
|
|
@@ -13667,7 +13763,7 @@ var GitCheckpointsOptions = class {
|
|
|
13667
13763
|
/** Real working tree to snapshot (the launch cwd). */
|
|
13668
13764
|
workTree = process.cwd();
|
|
13669
13765
|
/** Isolated git dir for the cwd shadow repo (kept out of the user's real .git). */
|
|
13670
|
-
gitDir =
|
|
13766
|
+
gitDir = join10(process.cwd(), ".agent", "checkpoints.git");
|
|
13671
13767
|
/** Extra mounted dirs (`--add-dir`); those outside cwd each get their own shadow repo. */
|
|
13672
13768
|
addDirs = [];
|
|
13673
13769
|
/** Conversation id → per-session restore-point ref. */
|
|
@@ -13682,80 +13778,6 @@ var GitCheckpointsOptions = class {
|
|
|
13682
13778
|
git = "git";
|
|
13683
13779
|
};
|
|
13684
13780
|
|
|
13685
|
-
// cli/permissions.ts
|
|
13686
|
-
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync9 } from "fs";
|
|
13687
|
-
import { homedir as homedir7 } from "os";
|
|
13688
|
-
import { join as join10 } from "path";
|
|
13689
|
-
var RULE_RE = /^(\w[\w*-]*)(?:\((.+)\))?$/;
|
|
13690
|
-
function parseOne(raw, decision) {
|
|
13691
|
-
const m = RULE_RE.exec(raw.trim());
|
|
13692
|
-
if (!m) return null;
|
|
13693
|
-
const [, tool, pathGlob] = m;
|
|
13694
|
-
return pathGlob ? { tool, pathGlob, decision } : { tool, decision };
|
|
13695
|
-
}
|
|
13696
|
-
function parsePermRules(perms, explicit = false) {
|
|
13697
|
-
if (!perms) return [];
|
|
13698
|
-
const out = [];
|
|
13699
|
-
for (const [decision, list] of [["deny", perms.deny], ["allow", perms.allow], ["ask", perms.ask]]) {
|
|
13700
|
-
for (const raw of list ?? []) {
|
|
13701
|
-
const r = parseOne(raw, decision);
|
|
13702
|
-
if (r) out.push(explicit ? { ...r, explicit } : r);
|
|
13703
|
-
}
|
|
13704
|
-
}
|
|
13705
|
-
return out;
|
|
13706
|
-
}
|
|
13707
|
-
function describeRule(r) {
|
|
13708
|
-
return `${r.decision.padEnd(5)} ${r.tool ?? "*"}${r.pathGlob ? `(${r.pathGlob})` : ""}`;
|
|
13709
|
-
}
|
|
13710
|
-
var PERM_FILE = (cwd) => join10(cwd, ".agent", "permissions.json");
|
|
13711
|
-
function loadPersistedRules(cwd) {
|
|
13712
|
-
const j = readJsonFile(PERM_FILE(cwd), null);
|
|
13713
|
-
return j ? { allow: j.allow ?? [], ask: j.ask ?? [], deny: j.deny ?? [] } : {};
|
|
13714
|
-
}
|
|
13715
|
-
function loadClaudeSettings(cwd, home = homedir7()) {
|
|
13716
|
-
const files = [join10(home, ".claude", "settings.json"), join10(cwd, ".claude", "settings.json"), join10(cwd, ".claude", "settings.local.json")];
|
|
13717
|
-
let out = {};
|
|
13718
|
-
for (const p of files) {
|
|
13719
|
-
const perms = readJsonFile(p, null)?.permissions;
|
|
13720
|
-
if (perms) out = mergePerms(out, { allow: perms.allow, ask: perms.ask, deny: perms.deny }) ?? out;
|
|
13721
|
-
}
|
|
13722
|
-
return out;
|
|
13723
|
-
}
|
|
13724
|
-
function persistRule(cwd, decision, ruleStr) {
|
|
13725
|
-
const cur = loadPersistedRules(cwd);
|
|
13726
|
-
const list = cur[decision] ??= [];
|
|
13727
|
-
if (!list.includes(ruleStr)) list.push(ruleStr);
|
|
13728
|
-
try {
|
|
13729
|
-
mkdirSync9(join10(cwd, ".agent"), { recursive: true });
|
|
13730
|
-
writeFileSync6(PERM_FILE(cwd), JSON.stringify(cur, null, 2) + "\n");
|
|
13731
|
-
} catch {
|
|
13732
|
-
}
|
|
13733
|
-
}
|
|
13734
|
-
function mergePerms(a, b) {
|
|
13735
|
-
if (!a && !b) return void 0;
|
|
13736
|
-
const out = {};
|
|
13737
|
-
for (const k of ["allow", "ask", "deny"]) {
|
|
13738
|
-
const merged = [...a?.[k] ?? [], ...b?.[k] ?? []];
|
|
13739
|
-
if (merged.length) out[k] = [...new Set(merged)];
|
|
13740
|
-
}
|
|
13741
|
-
return Object.keys(out).length ? out : void 0;
|
|
13742
|
-
}
|
|
13743
|
-
var TRUST_FILE = join10(homedir7(), ".agent", "trusted.json");
|
|
13744
|
-
function isTrusted(cwd, file = TRUST_FILE) {
|
|
13745
|
-
const list = readJsonFile(file, []);
|
|
13746
|
-
return Array.isArray(list) && list.includes(cwd);
|
|
13747
|
-
}
|
|
13748
|
-
function trustDir(cwd, file = TRUST_FILE) {
|
|
13749
|
-
let list = readJsonFile(file, []);
|
|
13750
|
-
if (!Array.isArray(list)) list = [];
|
|
13751
|
-
if (!list.includes(cwd)) list.push(cwd);
|
|
13752
|
-
try {
|
|
13753
|
-
mkdirSync9(join10(file, ".."), { recursive: true });
|
|
13754
|
-
writeFileSync6(file, JSON.stringify(list, null, 2) + "\n");
|
|
13755
|
-
} catch {
|
|
13756
|
-
}
|
|
13757
|
-
}
|
|
13758
|
-
|
|
13759
13781
|
// cli/complete.ts
|
|
13760
13782
|
function lastToken(line) {
|
|
13761
13783
|
const m = line.match(/(\S*)$/);
|
|
@@ -15964,6 +15986,7 @@ function parseArgs(argv) {
|
|
|
15964
15986
|
else if (x === "--append-system-prompt") a.appendSystemPrompt = val(++i, x);
|
|
15965
15987
|
else if (x === "--voice-system-prompt") a.voiceSystemPrompt = val(++i, x);
|
|
15966
15988
|
else if (x === "--add-dir") (a.addDirs ??= []).push(val(++i, x));
|
|
15989
|
+
else if (x === "--mcp-config") a.mcpConfig = val(++i, x);
|
|
15967
15990
|
else if (x === "--reasoning") a.reasoning = parseReasoning(val(++i, x));
|
|
15968
15991
|
else if (x === "--session-id") a.sessionId = val(++i, x);
|
|
15969
15992
|
else if (x === "--fork-session") a.fork = true;
|
|
@@ -16045,6 +16068,7 @@ Flags:
|
|
|
16045
16068
|
--no-think with --duplex: disable the Think tier (Act handles everything)
|
|
16046
16069
|
--voice-system-prompt <text> with --duplex: appended to the voice (reflex) prompt only (--append-system-prompt \u2192 workers)
|
|
16047
16070
|
--add-dir <path> mount another directory into the workspace (repeatable; disk mode only)
|
|
16071
|
+
--mcp-config <file> JSON { mcpServers?, permissions? } merged over .agent config for this run only
|
|
16048
16072
|
--subagents allow the Task tool (spawn child agents)
|
|
16049
16073
|
--reasoning <e> extended thinking: off|low|medium|high or a token budget (anthropic/openai)
|
|
16050
16074
|
--session-id <id> use this id for the session (instead of an auto-generated one)
|
|
@@ -16942,6 +16966,7 @@ function jsonResult(res, session) {
|
|
|
16942
16966
|
steps: res.steps,
|
|
16943
16967
|
tools: res.messages.slice(lastUser).filter((m) => m.role === "tool").length,
|
|
16944
16968
|
usage: res.usage,
|
|
16969
|
+
...res.budget ? { budget: res.budget } : {},
|
|
16945
16970
|
...res.routing ? { costUsd: res.costUsd, routing: res.routing } : {},
|
|
16946
16971
|
// cast: tsup dts hoists a modelRouter import above the shebang
|
|
16947
16972
|
sessionId: session.meta.id,
|
|
@@ -19600,7 +19625,7 @@ async function main() {
|
|
|
19600
19625
|
};
|
|
19601
19626
|
}
|
|
19602
19627
|
const cwd = resolve4(args.cwd ?? process.cwd());
|
|
19603
|
-
const cfg = await loadConfig(cwd);
|
|
19628
|
+
const cfg = await loadConfig(cwd, args.mcpConfig && resolve4(args.mcpConfig));
|
|
19604
19629
|
if (!args.autoRoute && !args.model && (cfg.model === "auto" || !cfg.model && await jevAvailable())) {
|
|
19605
19630
|
args.autoRoute = true;
|
|
19606
19631
|
args.model = autoModels().standard;
|