@livx.cc/agentx 0.94.38 → 0.95.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +313 -128
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js +157 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1420,6 +1420,172 @@ var init_JailedFilesystem = __esm({
|
|
|
1420
1420
|
}
|
|
1421
1421
|
});
|
|
1422
1422
|
|
|
1423
|
+
// src/worktree.ts
|
|
1424
|
+
var worktree_exports = {};
|
|
1425
|
+
__export(worktree_exports, {
|
|
1426
|
+
cleanupWorktree: () => cleanupWorktree,
|
|
1427
|
+
enterWorktree: () => enterWorktree,
|
|
1428
|
+
exitWorktree: () => exitWorktree,
|
|
1429
|
+
findGitRoot: () => findGitRoot,
|
|
1430
|
+
getOrCreateWorktree: () => getOrCreateWorktree,
|
|
1431
|
+
getWorktreeSession: () => getWorktreeSession,
|
|
1432
|
+
validateWorktreeSlug: () => validateWorktreeSlug,
|
|
1433
|
+
worktreeBranchName: () => worktreeBranchName
|
|
1434
|
+
});
|
|
1435
|
+
import { spawnSync } from "child_process";
|
|
1436
|
+
import { symlinkSync, mkdirSync, statSync as statSync2, readFileSync, rmSync } from "fs";
|
|
1437
|
+
import { join as join3 } from "path";
|
|
1438
|
+
function validateWorktreeSlug(slug2) {
|
|
1439
|
+
if (!slug2) throw new Error("worktree slug must not be empty");
|
|
1440
|
+
if (slug2.length > MAX_SLUG_LENGTH) throw new Error(`worktree slug must be \u2264${MAX_SLUG_LENGTH} chars (got ${slug2.length})`);
|
|
1441
|
+
for (const seg of slug2.split("/")) {
|
|
1442
|
+
if (seg === "." || seg === "..") throw new Error(`worktree slug must not contain "." or ".." segments`);
|
|
1443
|
+
if (!VALID_SEGMENT.test(seg)) throw new Error(`worktree slug segment "${seg}" contains invalid characters (allowed: a-z A-Z 0-9 . _ -)`);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
function flattenSlug(slug2) {
|
|
1447
|
+
return slug2.replaceAll("/", "+");
|
|
1448
|
+
}
|
|
1449
|
+
function worktreeBranchName(slug2) {
|
|
1450
|
+
return `worktree-${flattenSlug(slug2)}`;
|
|
1451
|
+
}
|
|
1452
|
+
function worktreesDir(repoRoot) {
|
|
1453
|
+
return join3(repoRoot, ".claude", "worktrees");
|
|
1454
|
+
}
|
|
1455
|
+
function worktreePathFor(repoRoot, slug2) {
|
|
1456
|
+
return join3(worktreesDir(repoRoot), flattenSlug(slug2));
|
|
1457
|
+
}
|
|
1458
|
+
function git(args, cwd) {
|
|
1459
|
+
const r = spawnSync("git", args, {
|
|
1460
|
+
cwd,
|
|
1461
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1462
|
+
env: { ...process.env, ...GIT_NO_PROMPT_ENV }
|
|
1463
|
+
});
|
|
1464
|
+
return { ok: r.status === 0, stdout: (r.stdout ?? "").toString().trim(), stderr: (r.stderr ?? "").toString().trim() };
|
|
1465
|
+
}
|
|
1466
|
+
function findGitRoot(from) {
|
|
1467
|
+
const r = git(["rev-parse", "--show-toplevel"], from);
|
|
1468
|
+
return r.ok ? r.stdout : null;
|
|
1469
|
+
}
|
|
1470
|
+
function readWorktreeHead(worktreePath) {
|
|
1471
|
+
try {
|
|
1472
|
+
const gitFile = readFileSync(join3(worktreePath, ".git"), "utf-8").trim();
|
|
1473
|
+
const m = gitFile.match(/^gitdir:\s*(.+)$/);
|
|
1474
|
+
if (!m) return null;
|
|
1475
|
+
const headPath = join3(m[1], "HEAD");
|
|
1476
|
+
const head = readFileSync(headPath, "utf-8").trim();
|
|
1477
|
+
const refMatch = head.match(/^ref:\s*(.+)$/);
|
|
1478
|
+
if (!refMatch) return head.length === 40 ? head : null;
|
|
1479
|
+
const refPath = join3(m[1], "..", refMatch[1]);
|
|
1480
|
+
try {
|
|
1481
|
+
return readFileSync(refPath, "utf-8").trim();
|
|
1482
|
+
} catch {
|
|
1483
|
+
}
|
|
1484
|
+
const r = git(["rev-parse", "HEAD"], worktreePath);
|
|
1485
|
+
return r.ok ? r.stdout : null;
|
|
1486
|
+
} catch {
|
|
1487
|
+
return null;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
function getOrCreateWorktree(repoRoot, slug2) {
|
|
1491
|
+
validateWorktreeSlug(slug2);
|
|
1492
|
+
const worktreePath = worktreePathFor(repoRoot, slug2);
|
|
1493
|
+
const branch = worktreeBranchName(slug2);
|
|
1494
|
+
const existingHead = readWorktreeHead(worktreePath);
|
|
1495
|
+
if (existingHead) return { worktreePath, branch, headCommit: existingHead, existed: true };
|
|
1496
|
+
mkdirSync(worktreesDir(repoRoot), { recursive: true });
|
|
1497
|
+
const defaultBranch = git(["symbolic-ref", "--short", "refs/remotes/origin/HEAD"], repoRoot);
|
|
1498
|
+
let baseBranch = defaultBranch.ok ? defaultBranch.stdout.replace(/^origin\//, "") : "HEAD";
|
|
1499
|
+
const originRef = `origin/${baseBranch}`;
|
|
1500
|
+
const hasOrigin = git(["rev-parse", "--verify", originRef], repoRoot);
|
|
1501
|
+
if (!hasOrigin.ok) {
|
|
1502
|
+
const fetched = git(["fetch", "origin", baseBranch], repoRoot);
|
|
1503
|
+
if (!fetched.ok) baseBranch = "HEAD";
|
|
1504
|
+
}
|
|
1505
|
+
const base = baseBranch === "HEAD" ? "HEAD" : originRef;
|
|
1506
|
+
const r = git(["worktree", "add", "-B", branch, worktreePath, base], repoRoot);
|
|
1507
|
+
if (!r.ok) throw new Error(`failed to create worktree: ${r.stderr}`);
|
|
1508
|
+
const headSha = git(["rev-parse", "HEAD"], worktreePath);
|
|
1509
|
+
symlinkDirs(repoRoot, worktreePath, ["node_modules", ".bun"]);
|
|
1510
|
+
return { worktreePath, branch, headCommit: headSha.stdout, existed: false, baseBranch };
|
|
1511
|
+
}
|
|
1512
|
+
function symlinkDirs(repoRoot, worktreePath, dirs) {
|
|
1513
|
+
for (const dir of dirs) {
|
|
1514
|
+
const src = join3(repoRoot, dir);
|
|
1515
|
+
const dst = join3(worktreePath, dir);
|
|
1516
|
+
try {
|
|
1517
|
+
statSync2(src);
|
|
1518
|
+
} catch {
|
|
1519
|
+
continue;
|
|
1520
|
+
}
|
|
1521
|
+
try {
|
|
1522
|
+
symlinkSync(src, dst, "dir");
|
|
1523
|
+
} catch (e) {
|
|
1524
|
+
if (e?.code !== "EEXIST") console.error(`[worktree] symlink ${dir}: ${e?.message ?? e}`);
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
function cleanupWorktree(repoRoot, slug2, opts) {
|
|
1529
|
+
validateWorktreeSlug(slug2);
|
|
1530
|
+
const worktreePath = worktreePathFor(repoRoot, slug2);
|
|
1531
|
+
const branch = worktreeBranchName(slug2);
|
|
1532
|
+
try {
|
|
1533
|
+
statSync2(worktreePath);
|
|
1534
|
+
} catch {
|
|
1535
|
+
return { removed: false, reason: "not found" };
|
|
1536
|
+
}
|
|
1537
|
+
if (!opts?.force) {
|
|
1538
|
+
const status = git(["status", "--porcelain", "-uno"], worktreePath);
|
|
1539
|
+
if (status.ok && status.stdout) return { removed: false, reason: "uncommitted changes" };
|
|
1540
|
+
}
|
|
1541
|
+
for (const dir of ["node_modules", ".bun"]) {
|
|
1542
|
+
try {
|
|
1543
|
+
rmSync(join3(worktreePath, dir));
|
|
1544
|
+
} catch {
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
const rm = git(["worktree", "remove", "--force", worktreePath], repoRoot);
|
|
1548
|
+
if (!rm.ok) return { removed: false, reason: rm.stderr };
|
|
1549
|
+
git(["branch", "-D", branch], repoRoot);
|
|
1550
|
+
return { removed: true };
|
|
1551
|
+
}
|
|
1552
|
+
function getWorktreeSession() {
|
|
1553
|
+
return _session;
|
|
1554
|
+
}
|
|
1555
|
+
function enterWorktree(slug2, cwd) {
|
|
1556
|
+
const repoRoot = findGitRoot(cwd);
|
|
1557
|
+
if (!repoRoot) throw new Error("--worktree requires a git repository");
|
|
1558
|
+
const info = getOrCreateWorktree(repoRoot, slug2);
|
|
1559
|
+
process.chdir(info.worktreePath);
|
|
1560
|
+
_session = {
|
|
1561
|
+
originalCwd: cwd,
|
|
1562
|
+
worktreePath: info.worktreePath,
|
|
1563
|
+
slug: slug2,
|
|
1564
|
+
branch: info.branch,
|
|
1565
|
+
headCommit: info.headCommit
|
|
1566
|
+
};
|
|
1567
|
+
return _session;
|
|
1568
|
+
}
|
|
1569
|
+
function exitWorktree() {
|
|
1570
|
+
if (!_session) return null;
|
|
1571
|
+
const repoRoot = findGitRoot(_session.originalCwd);
|
|
1572
|
+
if (!repoRoot) return null;
|
|
1573
|
+
process.chdir(_session.originalCwd);
|
|
1574
|
+
const result = cleanupWorktree(repoRoot, _session.slug);
|
|
1575
|
+
_session = null;
|
|
1576
|
+
return result;
|
|
1577
|
+
}
|
|
1578
|
+
var VALID_SEGMENT, MAX_SLUG_LENGTH, GIT_NO_PROMPT_ENV, _session;
|
|
1579
|
+
var init_worktree = __esm({
|
|
1580
|
+
"src/worktree.ts"() {
|
|
1581
|
+
"use strict";
|
|
1582
|
+
VALID_SEGMENT = /^[a-zA-Z0-9._-]+$/;
|
|
1583
|
+
MAX_SLUG_LENGTH = 64;
|
|
1584
|
+
GIT_NO_PROMPT_ENV = { GIT_TERMINAL_PROMPT: "0", GIT_ASKPASS: "" };
|
|
1585
|
+
_session = null;
|
|
1586
|
+
}
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1423
1589
|
// src/shell.sandbox.ts
|
|
1424
1590
|
function writable(cwd, o, tmpDir) {
|
|
1425
1591
|
const set = /* @__PURE__ */ new Set([cwd, "/tmp", "/private/tmp", "/private/var/folders", "/dev", ...tmpDir ? [tmpDir] : [], ...o.writePaths]);
|
|
@@ -1741,7 +1907,7 @@ var init_tools_shell = __esm({
|
|
|
1741
1907
|
|
|
1742
1908
|
// cli/cli.ts
|
|
1743
1909
|
import { createInterface } from "readline/promises";
|
|
1744
|
-
import { existsSync as existsSync10, readFileSync as
|
|
1910
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, appendFileSync, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, readdirSync as readdirSync4, statSync as statSync4, unlinkSync as unlinkSync5 } from "fs";
|
|
1745
1911
|
import { homedir as homedir9, tmpdir as tmpdir3 } from "os";
|
|
1746
1912
|
|
|
1747
1913
|
// cli/clipboard.ts
|
|
@@ -1809,7 +1975,7 @@ function copyTextToClipboard(text, platform2 = process.platform) {
|
|
|
1809
1975
|
}
|
|
1810
1976
|
|
|
1811
1977
|
// cli/cli.ts
|
|
1812
|
-
import { join as
|
|
1978
|
+
import { join as join13, resolve as resolve3, basename as basename2, extname, dirname as dirname4 } from "path";
|
|
1813
1979
|
import { AIClient, listModels, listProviders, getProviderFromModel, getModelInfo, resolveModel, isModelSupported, disposeCursorSessions } from "ai.libx.js";
|
|
1814
1980
|
|
|
1815
1981
|
// src/llm.ts
|
|
@@ -5736,6 +5902,7 @@ function base64ToBytes(b64) {
|
|
|
5736
5902
|
}
|
|
5737
5903
|
|
|
5738
5904
|
// src/index.ts
|
|
5905
|
+
init_worktree();
|
|
5739
5906
|
import { MemFilesystem as MemFilesystem3, IndexedDbFilesystem, CommandExecutor as CommandExecutor2, registerHeadlessCommands as registerHeadlessCommands2 } from "@livx.cc/wcli/core";
|
|
5740
5907
|
|
|
5741
5908
|
// src/mcp.client.ts
|
|
@@ -6064,7 +6231,7 @@ var defaultPool = new McpPool();
|
|
|
6064
6231
|
// cli/mcpOAuth.ts
|
|
6065
6232
|
import { createServer } from "http";
|
|
6066
6233
|
import { randomBytes, createHash as createHash2 } from "crypto";
|
|
6067
|
-
import { readFileSync, writeFileSync as writeFileSync2, mkdirSync, existsSync } from "fs";
|
|
6234
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync } from "fs";
|
|
6068
6235
|
import { dirname as dirname2 } from "path";
|
|
6069
6236
|
var McpOAuthOptions = class {
|
|
6070
6237
|
/** Where to persist tokens. Mode 0600. */
|
|
@@ -6092,13 +6259,13 @@ var McpOAuth = class {
|
|
|
6092
6259
|
// -- store I/O ----------------------------------------------------------------
|
|
6093
6260
|
load() {
|
|
6094
6261
|
try {
|
|
6095
|
-
return existsSync(this.options.storePath) ? JSON.parse(
|
|
6262
|
+
return existsSync(this.options.storePath) ? JSON.parse(readFileSync2(this.options.storePath, "utf8")) : {};
|
|
6096
6263
|
} catch {
|
|
6097
6264
|
return {};
|
|
6098
6265
|
}
|
|
6099
6266
|
}
|
|
6100
6267
|
save(store) {
|
|
6101
|
-
|
|
6268
|
+
mkdirSync2(dirname2(this.options.storePath), { recursive: true });
|
|
6102
6269
|
writeFileSync2(this.options.storePath, JSON.stringify(store, null, 2), { mode: 384 });
|
|
6103
6270
|
}
|
|
6104
6271
|
// -- ATTENDED: one-time authorization ----------------------------------------
|
|
@@ -6257,8 +6424,8 @@ function defaultOpenBrowser(url) {
|
|
|
6257
6424
|
// cli/core.ts
|
|
6258
6425
|
import { randomUUID } from "crypto";
|
|
6259
6426
|
import { execFile as execFile2 } from "child_process";
|
|
6260
|
-
import { resolve, basename, join as
|
|
6261
|
-
import { existsSync as existsSync3, mkdirSync as
|
|
6427
|
+
import { resolve, basename, join as join4 } from "path";
|
|
6428
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
6262
6429
|
import { platform, arch, release, userInfo, homedir as homedir2, tmpdir } from "os";
|
|
6263
6430
|
init_tools_shell();
|
|
6264
6431
|
|
|
@@ -6303,7 +6470,7 @@ import { BodDB as BodDB2 } from "@bod.ee/db";
|
|
|
6303
6470
|
|
|
6304
6471
|
// cli/util.ts
|
|
6305
6472
|
init_logging();
|
|
6306
|
-
import { existsSync as existsSync2, readFileSync as
|
|
6473
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
6307
6474
|
import { homedir } from "os";
|
|
6308
6475
|
var log14 = forComponent("cli-util");
|
|
6309
6476
|
function dotDirs(base, sub, opts = {}) {
|
|
@@ -6330,7 +6497,7 @@ function readJsonFile(path, fallback) {
|
|
|
6330
6497
|
if (!existsSync2(path)) return fallback;
|
|
6331
6498
|
let text;
|
|
6332
6499
|
try {
|
|
6333
|
-
text =
|
|
6500
|
+
text = readFileSync3(path, "utf8");
|
|
6334
6501
|
} catch (e) {
|
|
6335
6502
|
log14.debug(`readJsonFile(${path}) unreadable: ${e.message}`);
|
|
6336
6503
|
return fallback;
|
|
@@ -6416,8 +6583,8 @@ async function buildAgent(o) {
|
|
|
6416
6583
|
fs = mem;
|
|
6417
6584
|
} else if (o.boddb) {
|
|
6418
6585
|
const root = resolve(o.boddb);
|
|
6419
|
-
|
|
6420
|
-
const db = new BodDB2({ path:
|
|
6586
|
+
mkdirSync3(root, { recursive: true });
|
|
6587
|
+
const db = new BodDB2({ path: join4(root, "meta.db"), sweepInterval: 0, vfs: { storageRoot: join4(root, "files") } });
|
|
6421
6588
|
const bod = new BodDbFilesystem(db);
|
|
6422
6589
|
const firstRun = (await bod.readDir("/").catch(() => [])).length === 0;
|
|
6423
6590
|
await mkdirp(bod, cwd);
|
|
@@ -6576,10 +6743,10 @@ var trunc = (s, n) => (s == null ? "" : String(s).length > n ? String(s).slice(0
|
|
|
6576
6743
|
|
|
6577
6744
|
// cli/voice.ts
|
|
6578
6745
|
init_logging();
|
|
6579
|
-
import { spawn as spawn2, spawnSync } from "child_process";
|
|
6580
|
-
import { existsSync as existsSync4, mkdirSync as
|
|
6746
|
+
import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
|
|
6747
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, statSync as statSync3 } from "fs";
|
|
6581
6748
|
import { homedir as homedir3 } from "os";
|
|
6582
|
-
import { dirname as dirname3, join as
|
|
6749
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
6583
6750
|
import { fileURLToPath } from "url";
|
|
6584
6751
|
var log15 = forComponent("VoiceIO");
|
|
6585
6752
|
var now4 = () => performance.now();
|
|
@@ -6622,10 +6789,10 @@ var Player = class {
|
|
|
6622
6789
|
this.proc = null;
|
|
6623
6790
|
}
|
|
6624
6791
|
};
|
|
6625
|
-
var nativeDir = () =>
|
|
6792
|
+
var nativeDir = () => join5(dirname3(fileURLToPath(import.meta.url)), "native");
|
|
6626
6793
|
function detectFfmpegMic() {
|
|
6627
6794
|
if (process.env.MIC_DEVICE) return process.env.MIC_DEVICE;
|
|
6628
|
-
const out =
|
|
6795
|
+
const out = spawnSync2("ffmpeg", ["-f", "avfoundation", "-list_devices", "true", "-i", ""], { encoding: "utf8" }).stderr;
|
|
6629
6796
|
const audio = out.slice(out.indexOf("audio devices"));
|
|
6630
6797
|
const devices = [...audio.matchAll(/\[(\d+)\] (.+)/g)].map(([, idx, name]) => ({ idx, name: name.trim() }));
|
|
6631
6798
|
const mic = devices.find((d) => /microphone|built-in/i.test(d.name) && !/teams|blackhole|loopback/i.test(d.name)) ?? devices[0];
|
|
@@ -6636,10 +6803,10 @@ function detectFfmpegMic() {
|
|
|
6636
6803
|
function detectedInputDevice() {
|
|
6637
6804
|
if (process.platform !== "darwin") return null;
|
|
6638
6805
|
let name = "";
|
|
6639
|
-
if (
|
|
6640
|
-
name = (
|
|
6806
|
+
if (spawnSync2("which", ["SwitchAudioSource"]).status === 0) {
|
|
6807
|
+
name = (spawnSync2("SwitchAudioSource", ["-c", "-t", "input"], { encoding: "utf8" }).stdout || "").trim();
|
|
6641
6808
|
} else {
|
|
6642
|
-
const out =
|
|
6809
|
+
const out = spawnSync2("system_profiler", ["SPAudioDataType"], { encoding: "utf8" }).stdout || "";
|
|
6643
6810
|
let last = "";
|
|
6644
6811
|
for (const ln of out.split("\n")) {
|
|
6645
6812
|
const hdr = ln.match(/^\s{6,}(\S.*?):\s*$/);
|
|
@@ -6658,21 +6825,21 @@ function detectedInputDevice() {
|
|
|
6658
6825
|
}
|
|
6659
6826
|
function resolveAecBinary() {
|
|
6660
6827
|
if (process.env.MIC_AEC === "0" || process.platform !== "darwin") return null;
|
|
6661
|
-
const src =
|
|
6662
|
-
const plist =
|
|
6828
|
+
const src = join5(nativeDir(), "mic-aec.swift");
|
|
6829
|
+
const plist = join5(nativeDir(), "Info.plist");
|
|
6663
6830
|
if (!existsSync4(src)) return null;
|
|
6664
|
-
const cacheDir =
|
|
6665
|
-
const bin =
|
|
6666
|
-
if (existsSync4(bin) &&
|
|
6667
|
-
if (
|
|
6668
|
-
|
|
6831
|
+
const cacheDir = join5(homedir3(), ".agent", "cache");
|
|
6832
|
+
const bin = join5(cacheDir, "mic-aec");
|
|
6833
|
+
if (existsSync4(bin) && statSync3(bin).mtimeMs >= statSync3(src).mtimeMs) return bin;
|
|
6834
|
+
if (spawnSync2("which", ["swiftc"]).status !== 0) return null;
|
|
6835
|
+
mkdirSync4(cacheDir, { recursive: true });
|
|
6669
6836
|
log15.info("compiling AEC mic helper (first run)\u2026");
|
|
6670
|
-
const build =
|
|
6837
|
+
const build = spawnSync2("swiftc", ["-O", "-o", bin, src, "-Xlinker", "-sectcreate", "-Xlinker", "__TEXT", "-Xlinker", "__info_plist", "-Xlinker", plist], { encoding: "utf8" });
|
|
6671
6838
|
if (build.status !== 0) {
|
|
6672
6839
|
log15.warn(`AEC build failed: ${build.stderr?.slice(0, 400)}`);
|
|
6673
6840
|
return null;
|
|
6674
6841
|
}
|
|
6675
|
-
const sign =
|
|
6842
|
+
const sign = spawnSync2("codesign", ["-fs", "-", bin], { encoding: "utf8" });
|
|
6676
6843
|
if (sign.status !== 0) {
|
|
6677
6844
|
log15.warn(`codesign failed: ${sign.stderr?.slice(0, 200)}`);
|
|
6678
6845
|
return null;
|
|
@@ -6692,7 +6859,7 @@ var NodeMicSource = class {
|
|
|
6692
6859
|
if (this.bin) {
|
|
6693
6860
|
this.proc = spawn2(this.bin, [], { stdio: ["ignore", "pipe", "ignore"] });
|
|
6694
6861
|
} else {
|
|
6695
|
-
if (
|
|
6862
|
+
if (spawnSync2("which", ["ffmpeg"]).status !== 0) throw new Error("voice I/O unavailable: no AEC helper and no ffmpeg on PATH");
|
|
6696
6863
|
log15.info("mic: raw capture (no AEC) \u2014 echo handled heuristically; headphones recommended");
|
|
6697
6864
|
this.proc = spawn2(
|
|
6698
6865
|
"ffmpeg",
|
|
@@ -6861,13 +7028,13 @@ var VoiceIO = class extends VoiceEngine {
|
|
|
6861
7028
|
|
|
6862
7029
|
// cli/config.ts
|
|
6863
7030
|
import { homedir as homedir4 } from "os";
|
|
6864
|
-
import { existsSync as existsSync5, readFileSync as
|
|
6865
|
-
import { join as
|
|
7031
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
7032
|
+
import { join as join6 } from "path";
|
|
6866
7033
|
import { pathToFileURL } from "url";
|
|
6867
7034
|
var FILES = ["config.ts", "config.js", "config.mjs", "config.json"];
|
|
6868
7035
|
async function loadFrom(dir) {
|
|
6869
7036
|
for (const f of FILES) {
|
|
6870
|
-
const p =
|
|
7037
|
+
const p = join6(dir, ".agent", f);
|
|
6871
7038
|
if (!existsSync5(p)) continue;
|
|
6872
7039
|
try {
|
|
6873
7040
|
const mod = await import(pathToFileURL(p).href, f.endsWith(".json") ? { with: { type: "json" } } : void 0);
|
|
@@ -6880,10 +7047,10 @@ async function loadFrom(dir) {
|
|
|
6880
7047
|
return {};
|
|
6881
7048
|
}
|
|
6882
7049
|
function loadSettings(dir) {
|
|
6883
|
-
const p =
|
|
7050
|
+
const p = join6(dir, ".agent", "settings.json");
|
|
6884
7051
|
if (!existsSync5(p)) return {};
|
|
6885
7052
|
try {
|
|
6886
|
-
const raw = JSON.parse(
|
|
7053
|
+
const raw = JSON.parse(readFileSync4(p, "utf8"));
|
|
6887
7054
|
const cfg = {};
|
|
6888
7055
|
if (raw.mcpServers && typeof raw.mcpServers === "object") cfg.mcpServers = raw.mcpServers;
|
|
6889
7056
|
if (raw.permissions && typeof raw.permissions === "object") cfg.permissions = raw.permissions;
|
|
@@ -6916,7 +7083,7 @@ async function loadConfig(cwd) {
|
|
|
6916
7083
|
}
|
|
6917
7084
|
|
|
6918
7085
|
// cli/hooks-config.ts
|
|
6919
|
-
import { spawnSync as
|
|
7086
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
6920
7087
|
var log16 = forComponent("hooks");
|
|
6921
7088
|
var escapeRegex = (s) => s.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
6922
7089
|
function ruleMatches(rule, toolName) {
|
|
@@ -6926,7 +7093,7 @@ function ruleMatches(rule, toolName) {
|
|
|
6926
7093
|
}
|
|
6927
7094
|
function runCmd(rule, env) {
|
|
6928
7095
|
try {
|
|
6929
|
-
const r =
|
|
7096
|
+
const r = spawnSync3(rule.command, {
|
|
6930
7097
|
shell: true,
|
|
6931
7098
|
encoding: "utf8",
|
|
6932
7099
|
timeout: rule.timeoutMs ?? 1e4,
|
|
@@ -7038,15 +7205,15 @@ function formatDiff(ops, opts = {}) {
|
|
|
7038
7205
|
}
|
|
7039
7206
|
|
|
7040
7207
|
// cli/session.ts
|
|
7041
|
-
import { existsSync as existsSync6, mkdirSync as
|
|
7208
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3, readdirSync, renameSync, symlinkSync as symlinkSync2, unlinkSync, readlinkSync } from "fs";
|
|
7042
7209
|
import { homedir as homedir5 } from "os";
|
|
7043
|
-
import { join as
|
|
7210
|
+
import { join as join7 } from "path";
|
|
7044
7211
|
var log17 = forComponent("session");
|
|
7045
|
-
var globalDir = () =>
|
|
7212
|
+
var globalDir = () => join7(homedir5(), ".agent", "sessions");
|
|
7046
7213
|
var SessionStore = class {
|
|
7047
7214
|
dir;
|
|
7048
7215
|
constructor(cwd) {
|
|
7049
|
-
this.dir =
|
|
7216
|
+
this.dir = join7(cwd, ".agent", "sessions");
|
|
7050
7217
|
}
|
|
7051
7218
|
/** Sortable, human-readable id: `YYYYMMDD-HHMMSS-<folder>`. */
|
|
7052
7219
|
newId(now5 = Date.now(), cwd) {
|
|
@@ -7054,10 +7221,10 @@ var SessionStore = class {
|
|
|
7054
7221
|
const p = (n, w = 2) => String(n).padStart(w, "0");
|
|
7055
7222
|
const slug2 = (cwd ?? process.cwd()).split("/").pop()?.replace(/[^A-Za-z0-9_-]/g, "") || "session";
|
|
7056
7223
|
let id = `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}-${slug2}`;
|
|
7057
|
-
if (existsSync6(this.dir) && existsSync6(
|
|
7224
|
+
if (existsSync6(this.dir) && existsSync6(join7(this.dir, `${id}.json`))) {
|
|
7058
7225
|
for (let i = 2; i <= 99; i++) {
|
|
7059
7226
|
const c = `${id}-${i}`;
|
|
7060
|
-
if (!existsSync6(
|
|
7227
|
+
if (!existsSync6(join7(this.dir, `${c}.json`))) {
|
|
7061
7228
|
id = c;
|
|
7062
7229
|
break;
|
|
7063
7230
|
}
|
|
@@ -7071,16 +7238,16 @@ var SessionStore = class {
|
|
|
7071
7238
|
}
|
|
7072
7239
|
save(data) {
|
|
7073
7240
|
if (!this.safeId(data.meta.id)) throw new Error(`unsafe session id: ${data.meta.id}`);
|
|
7074
|
-
if (!existsSync6(this.dir))
|
|
7075
|
-
const path =
|
|
7241
|
+
if (!existsSync6(this.dir)) mkdirSync5(this.dir, { recursive: true });
|
|
7242
|
+
const path = join7(this.dir, `${data.meta.id}.json`);
|
|
7076
7243
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
7077
7244
|
writeFileSync3(tmp, JSON.stringify(data));
|
|
7078
7245
|
renameSync(tmp, path);
|
|
7079
7246
|
try {
|
|
7080
7247
|
const gd = globalDir();
|
|
7081
|
-
if (!existsSync6(gd))
|
|
7082
|
-
const link2 =
|
|
7083
|
-
if (!existsSync6(link2))
|
|
7248
|
+
if (!existsSync6(gd)) mkdirSync5(gd, { recursive: true });
|
|
7249
|
+
const link2 = join7(gd, `${data.meta.id}.json`);
|
|
7250
|
+
if (!existsSync6(link2)) symlinkSync2(path, link2);
|
|
7084
7251
|
} catch {
|
|
7085
7252
|
}
|
|
7086
7253
|
}
|
|
@@ -7089,10 +7256,10 @@ var SessionStore = class {
|
|
|
7089
7256
|
log17.debug(`rejecting unsafe session id: ${id}`);
|
|
7090
7257
|
return void 0;
|
|
7091
7258
|
}
|
|
7092
|
-
const path =
|
|
7259
|
+
const path = join7(this.dir, `${id}.json`);
|
|
7093
7260
|
if (!existsSync6(path)) return void 0;
|
|
7094
7261
|
try {
|
|
7095
|
-
return JSON.parse(
|
|
7262
|
+
return JSON.parse(readFileSync5(path, "utf8"));
|
|
7096
7263
|
} catch (e) {
|
|
7097
7264
|
log17.debug(`unreadable session ${id} \u2014 ignoring`, e);
|
|
7098
7265
|
return void 0;
|
|
@@ -7105,7 +7272,7 @@ var SessionStore = class {
|
|
|
7105
7272
|
for (const f of readdirSync(this.dir)) {
|
|
7106
7273
|
if (!f.endsWith(".json")) continue;
|
|
7107
7274
|
try {
|
|
7108
|
-
metas.push(JSON.parse(
|
|
7275
|
+
metas.push(JSON.parse(readFileSync5(join7(this.dir, f), "utf8")).meta);
|
|
7109
7276
|
} catch (e) {
|
|
7110
7277
|
log17.debug(`skipping unreadable session file ${f}`, e);
|
|
7111
7278
|
}
|
|
@@ -7124,11 +7291,11 @@ var SessionStore = class {
|
|
|
7124
7291
|
function globalSessionLoad(idOrPrefix) {
|
|
7125
7292
|
const gd = globalDir();
|
|
7126
7293
|
if (!existsSync6(gd)) return void 0;
|
|
7127
|
-
const exact =
|
|
7294
|
+
const exact = join7(gd, `${idOrPrefix}.json`);
|
|
7128
7295
|
if (existsSync6(exact)) {
|
|
7129
7296
|
try {
|
|
7130
7297
|
const target = readlinkSync(exact);
|
|
7131
|
-
return JSON.parse(
|
|
7298
|
+
return JSON.parse(readFileSync5(target, "utf8"));
|
|
7132
7299
|
} catch {
|
|
7133
7300
|
return void 0;
|
|
7134
7301
|
}
|
|
@@ -7138,8 +7305,8 @@ function globalSessionLoad(idOrPrefix) {
|
|
|
7138
7305
|
if (!f.endsWith(".json")) continue;
|
|
7139
7306
|
const base = f.slice(0, -5);
|
|
7140
7307
|
if (base.includes(idOrPrefix) || base.endsWith(idOrPrefix)) {
|
|
7141
|
-
const target = readlinkSync(
|
|
7142
|
-
return JSON.parse(
|
|
7308
|
+
const target = readlinkSync(join7(gd, f));
|
|
7309
|
+
return JSON.parse(readFileSync5(target, "utf8"));
|
|
7143
7310
|
}
|
|
7144
7311
|
}
|
|
7145
7312
|
} catch {
|
|
@@ -7153,15 +7320,15 @@ function globalSessionList() {
|
|
|
7153
7320
|
for (const f of readdirSync(gd)) {
|
|
7154
7321
|
if (!f.endsWith(".json")) continue;
|
|
7155
7322
|
try {
|
|
7156
|
-
const target = readlinkSync(
|
|
7323
|
+
const target = readlinkSync(join7(gd, f));
|
|
7157
7324
|
if (!existsSync6(target)) {
|
|
7158
7325
|
try {
|
|
7159
|
-
unlinkSync(
|
|
7326
|
+
unlinkSync(join7(gd, f));
|
|
7160
7327
|
} catch {
|
|
7161
7328
|
}
|
|
7162
7329
|
continue;
|
|
7163
7330
|
}
|
|
7164
|
-
metas.push(JSON.parse(
|
|
7331
|
+
metas.push(JSON.parse(readFileSync5(target, "utf8")).meta);
|
|
7165
7332
|
} catch {
|
|
7166
7333
|
}
|
|
7167
7334
|
}
|
|
@@ -7273,18 +7440,18 @@ ${formatDiff(ops)}`);
|
|
|
7273
7440
|
// cli/gitCheckpoints.ts
|
|
7274
7441
|
import { execFile as execFile3 } from "child_process";
|
|
7275
7442
|
import { promisify } from "util";
|
|
7276
|
-
import { writeFileSync as writeFileSync4, mkdirSync as
|
|
7277
|
-
import { join as
|
|
7443
|
+
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync6, existsSync as existsSync7 } from "fs";
|
|
7444
|
+
import { join as join8, resolve as resolve2, sep as sep2 } from "path";
|
|
7278
7445
|
var log18 = forComponent("checkpoints");
|
|
7279
7446
|
var exec = promisify(execFile3);
|
|
7280
7447
|
var DEFAULT_EXCLUDE = [".agent/", ".git/", "node_modules/", "dist/", "build/", ".next/", "target/", ".venv/", "__pycache__/", "*.log"];
|
|
7281
7448
|
var ShadowRepo = class {
|
|
7282
7449
|
// undefined = unprobed; false = git/this root unusable
|
|
7283
|
-
constructor(workTree, gitDir, exclude,
|
|
7450
|
+
constructor(workTree, gitDir, exclude, git2) {
|
|
7284
7451
|
this.workTree = workTree;
|
|
7285
7452
|
this.gitDir = gitDir;
|
|
7286
7453
|
this.exclude = exclude;
|
|
7287
|
-
this.git =
|
|
7454
|
+
this.git = git2;
|
|
7288
7455
|
}
|
|
7289
7456
|
workTree;
|
|
7290
7457
|
gitDir;
|
|
@@ -7307,10 +7474,10 @@ var ShadowRepo = class {
|
|
|
7307
7474
|
try {
|
|
7308
7475
|
await exec(this.git, ["--version"]);
|
|
7309
7476
|
if (!existsSync7(this.gitDir)) {
|
|
7310
|
-
|
|
7477
|
+
mkdirSync6(this.gitDir, { recursive: true });
|
|
7311
7478
|
await this.run("init", "-q");
|
|
7312
7479
|
}
|
|
7313
|
-
writeFileSync4(
|
|
7480
|
+
writeFileSync4(join8(this.gitDir, "info", "exclude"), this.exclude.join("\n") + "\n");
|
|
7314
7481
|
this.ready = true;
|
|
7315
7482
|
} catch (e) {
|
|
7316
7483
|
log18.debug(`git checkpoints unavailable for ${this.workTree}`, e);
|
|
@@ -7425,7 +7592,7 @@ var GitCheckpoints = class {
|
|
|
7425
7592
|
const abs = resolve2(d);
|
|
7426
7593
|
if (abs === cwd || abs.startsWith(cwd + sep2)) continue;
|
|
7427
7594
|
if (cwd.startsWith(abs + sep2)) continue;
|
|
7428
|
-
out.push({ workTree: abs, gitDir:
|
|
7595
|
+
out.push({ workTree: abs, gitDir: join8(abs, ".agent", "checkpoints.git") });
|
|
7429
7596
|
}
|
|
7430
7597
|
return out;
|
|
7431
7598
|
}
|
|
@@ -7546,7 +7713,7 @@ var GitCheckpointsOptions = class {
|
|
|
7546
7713
|
/** Real working tree to snapshot (the launch cwd). */
|
|
7547
7714
|
workTree = process.cwd();
|
|
7548
7715
|
/** Isolated git dir for the cwd shadow repo (kept out of the user's real .git). */
|
|
7549
|
-
gitDir =
|
|
7716
|
+
gitDir = join8(process.cwd(), ".agent", "checkpoints.git");
|
|
7550
7717
|
/** Extra mounted dirs (`--add-dir`); those outside cwd each get their own shadow repo. */
|
|
7551
7718
|
addDirs = [];
|
|
7552
7719
|
/** Conversation id → per-session restore-point ref. */
|
|
@@ -7560,9 +7727,9 @@ var GitCheckpointsOptions = class {
|
|
|
7560
7727
|
};
|
|
7561
7728
|
|
|
7562
7729
|
// cli/permissions.ts
|
|
7563
|
-
import { writeFileSync as writeFileSync5, mkdirSync as
|
|
7730
|
+
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync7 } from "fs";
|
|
7564
7731
|
import { homedir as homedir6 } from "os";
|
|
7565
|
-
import { join as
|
|
7732
|
+
import { join as join9 } from "path";
|
|
7566
7733
|
var RULE_RE = /^(\w+)(?:\((.+)\))?$/;
|
|
7567
7734
|
function parseOne(raw, decision) {
|
|
7568
7735
|
const m = RULE_RE.exec(raw.trim());
|
|
@@ -7584,13 +7751,13 @@ function parsePermRules(perms) {
|
|
|
7584
7751
|
function describeRule(r) {
|
|
7585
7752
|
return `${r.decision.padEnd(5)} ${r.tool ?? "*"}${r.pathGlob ? `(${r.pathGlob})` : ""}`;
|
|
7586
7753
|
}
|
|
7587
|
-
var PERM_FILE = (cwd) =>
|
|
7754
|
+
var PERM_FILE = (cwd) => join9(cwd, ".agent", "permissions.json");
|
|
7588
7755
|
function loadPersistedRules(cwd) {
|
|
7589
7756
|
const j = readJsonFile(PERM_FILE(cwd), null);
|
|
7590
7757
|
return j ? { allow: j.allow ?? [], ask: j.ask ?? [], deny: j.deny ?? [] } : {};
|
|
7591
7758
|
}
|
|
7592
7759
|
function loadClaudeSettings(cwd, home = homedir6()) {
|
|
7593
|
-
const files = [
|
|
7760
|
+
const files = [join9(home, ".claude", "settings.json"), join9(cwd, ".claude", "settings.json"), join9(cwd, ".claude", "settings.local.json")];
|
|
7594
7761
|
let out = {};
|
|
7595
7762
|
for (const p of files) {
|
|
7596
7763
|
const perms = readJsonFile(p, null)?.permissions;
|
|
@@ -7603,7 +7770,7 @@ function persistRule(cwd, decision, ruleStr) {
|
|
|
7603
7770
|
const list = cur[decision] ??= [];
|
|
7604
7771
|
if (!list.includes(ruleStr)) list.push(ruleStr);
|
|
7605
7772
|
try {
|
|
7606
|
-
|
|
7773
|
+
mkdirSync7(join9(cwd, ".agent"), { recursive: true });
|
|
7607
7774
|
writeFileSync5(PERM_FILE(cwd), JSON.stringify(cur, null, 2) + "\n");
|
|
7608
7775
|
} catch {
|
|
7609
7776
|
}
|
|
@@ -7617,7 +7784,7 @@ function mergePerms(a, b) {
|
|
|
7617
7784
|
}
|
|
7618
7785
|
return Object.keys(out).length ? out : void 0;
|
|
7619
7786
|
}
|
|
7620
|
-
var TRUST_FILE =
|
|
7787
|
+
var TRUST_FILE = join9(homedir6(), ".agent", "trusted.json");
|
|
7621
7788
|
function isTrusted(cwd, file = TRUST_FILE) {
|
|
7622
7789
|
const list = readJsonFile(file, []);
|
|
7623
7790
|
return Array.isArray(list) && list.includes(cwd);
|
|
@@ -7627,7 +7794,7 @@ function trustDir(cwd, file = TRUST_FILE) {
|
|
|
7627
7794
|
if (!Array.isArray(list)) list = [];
|
|
7628
7795
|
if (!list.includes(cwd)) list.push(cwd);
|
|
7629
7796
|
try {
|
|
7630
|
-
|
|
7797
|
+
mkdirSync7(join9(file, ".."), { recursive: true });
|
|
7631
7798
|
writeFileSync5(file, JSON.stringify(list, null, 2) + "\n");
|
|
7632
7799
|
} catch {
|
|
7633
7800
|
}
|
|
@@ -7687,10 +7854,10 @@ function completePath(listDir, ref) {
|
|
|
7687
7854
|
|
|
7688
7855
|
// cli/lineEditor.ts
|
|
7689
7856
|
import { emitKeypressEvents } from "readline";
|
|
7690
|
-
import { spawnSync as
|
|
7691
|
-
import { writeFileSync as writeFileSync6, readFileSync as
|
|
7857
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
7858
|
+
import { writeFileSync as writeFileSync6, readFileSync as readFileSync6, unlinkSync as unlinkSync2 } from "fs";
|
|
7692
7859
|
import { tmpdir as tmpdir2 } from "os";
|
|
7693
|
-
import { join as
|
|
7860
|
+
import { join as join10 } from "path";
|
|
7694
7861
|
|
|
7695
7862
|
// cli/bidi.ts
|
|
7696
7863
|
var RTL_RE = /[\u0590-\u05ff\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb1d-\ufdff\ufe70-\ufeff]/;
|
|
@@ -8767,14 +8934,14 @@ function createLineEditor(out) {
|
|
|
8767
8934
|
function externalEdit(s) {
|
|
8768
8935
|
const spec = process.env.VISUAL || process.env.EDITOR || "vi";
|
|
8769
8936
|
const [cmd, ...cargs] = spec.split(" ").filter(Boolean);
|
|
8770
|
-
const file =
|
|
8937
|
+
const file = join10(tmpdir2(), `agentx-edit-${process.pid}-${Date.now()}.md`);
|
|
8771
8938
|
try {
|
|
8772
8939
|
writeFileSync6(file, s.buf);
|
|
8773
8940
|
process.stdin.setRawMode(false);
|
|
8774
8941
|
out.write("\x1B[?2004l");
|
|
8775
|
-
const r =
|
|
8942
|
+
const r = spawnSync4(cmd, [...cargs, file], { stdio: "inherit" });
|
|
8776
8943
|
if (r.status === 0) {
|
|
8777
|
-
const text =
|
|
8944
|
+
const text = readFileSync6(file, "utf8").replace(/\n$/, "");
|
|
8778
8945
|
s.reset();
|
|
8779
8946
|
if (text) s.insert(text);
|
|
8780
8947
|
}
|
|
@@ -9196,10 +9363,10 @@ function readPlainLine() {
|
|
|
9196
9363
|
}
|
|
9197
9364
|
|
|
9198
9365
|
// cli/osScheduler.ts
|
|
9199
|
-
import { spawnSync as
|
|
9200
|
-
import { writeFileSync as writeFileSync7, mkdirSync as
|
|
9366
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
9367
|
+
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync8, readdirSync as readdirSync2, unlinkSync as unlinkSync3, chmodSync, existsSync as existsSync8 } from "fs";
|
|
9201
9368
|
import { homedir as homedir7 } from "os";
|
|
9202
|
-
import { join as
|
|
9369
|
+
import { join as join11 } from "path";
|
|
9203
9370
|
var log19 = forComponent("os-sched");
|
|
9204
9371
|
var OsScheduler = class {
|
|
9205
9372
|
options;
|
|
@@ -9207,13 +9374,13 @@ var OsScheduler = class {
|
|
|
9207
9374
|
this.options = { ...new OsSchedulerOptions(), ...options };
|
|
9208
9375
|
}
|
|
9209
9376
|
get dir() {
|
|
9210
|
-
return
|
|
9377
|
+
return join11(this.options.home, ".agent", "sched");
|
|
9211
9378
|
}
|
|
9212
9379
|
label(id) {
|
|
9213
9380
|
return `cc.livx.agentx.sched-${id}`;
|
|
9214
9381
|
}
|
|
9215
9382
|
plistPath(id) {
|
|
9216
|
-
return
|
|
9383
|
+
return join11(this.options.home, "Library", "LaunchAgents", `${this.label(id)}.plist`);
|
|
9217
9384
|
}
|
|
9218
9385
|
run(cmd, args, input) {
|
|
9219
9386
|
return this.options.exec(cmd, args, input);
|
|
@@ -9224,16 +9391,16 @@ var OsScheduler = class {
|
|
|
9224
9391
|
/** Register the job with the OS. Returns a human description of the mechanism used. Throws on failure. */
|
|
9225
9392
|
schedule(spec) {
|
|
9226
9393
|
if (!this.available()) throw new Error(`no OS scheduler on ${this.options.platform}`);
|
|
9227
|
-
|
|
9394
|
+
mkdirSync8(this.dir, { recursive: true });
|
|
9228
9395
|
const oneOff = "at" in spec.trigger;
|
|
9229
9396
|
const script = this.writeScript(spec, oneOff);
|
|
9230
9397
|
const mechanism = this.options.platform === "darwin" ? this.scheduleDarwin(spec, script) : this.scheduleLinux(spec, script, oneOff);
|
|
9231
9398
|
const meta = { ...spec, created: Date.now(), mechanism };
|
|
9232
|
-
writeFileSync7(
|
|
9399
|
+
writeFileSync7(join11(this.dir, `${spec.id}.json`), JSON.stringify(meta, null, 2));
|
|
9233
9400
|
return mechanism;
|
|
9234
9401
|
}
|
|
9235
9402
|
cancel(id) {
|
|
9236
|
-
const meta = readJsonFile(
|
|
9403
|
+
const meta = readJsonFile(join11(this.dir, `${id}.json`), null);
|
|
9237
9404
|
if (!meta) return false;
|
|
9238
9405
|
try {
|
|
9239
9406
|
if (this.options.platform === "darwin") {
|
|
@@ -9266,7 +9433,7 @@ var OsScheduler = class {
|
|
|
9266
9433
|
}
|
|
9267
9434
|
for (const f of [`${id}.json`, `${id}.sh`]) {
|
|
9268
9435
|
try {
|
|
9269
|
-
unlinkSync3(
|
|
9436
|
+
unlinkSync3(join11(this.dir, f));
|
|
9270
9437
|
} catch {
|
|
9271
9438
|
}
|
|
9272
9439
|
}
|
|
@@ -9274,19 +9441,19 @@ var OsScheduler = class {
|
|
|
9274
9441
|
}
|
|
9275
9442
|
list() {
|
|
9276
9443
|
if (!existsSync8(this.dir)) return [];
|
|
9277
|
-
return readdirSync2(this.dir).filter((f) => f.endsWith(".json")).map((f) => readJsonFile(
|
|
9444
|
+
return readdirSync2(this.dir).filter((f) => f.endsWith(".json")).map((f) => readJsonFile(join11(this.dir, f), null)).filter(Boolean);
|
|
9278
9445
|
}
|
|
9279
9446
|
/** The per-job runner script: cd to the project, headless-resume the session, log, notify. */
|
|
9280
9447
|
writeScript(spec, oneOff) {
|
|
9281
|
-
const p =
|
|
9448
|
+
const p = join11(this.dir, `${spec.id}.sh`);
|
|
9282
9449
|
const q2 = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
9283
|
-
const cleanup = oneOff ? this.options.platform === "darwin" ? `launchctl remove ${this.label(spec.id)} 2>/dev/null; rm -f ${q2(this.plistPath(spec.id))} ${q2(
|
|
9284
|
-
` : `rm -f ${q2(
|
|
9450
|
+
const cleanup = oneOff ? this.options.platform === "darwin" ? `launchctl remove ${this.label(spec.id)} 2>/dev/null; rm -f ${q2(this.plistPath(spec.id))} ${q2(join11(this.dir, `${spec.id}.json`))} ${q2(p)}
|
|
9451
|
+
` : `rm -f ${q2(join11(this.dir, `${spec.id}.json`))} ${q2(p)}
|
|
9285
9452
|
` : "";
|
|
9286
9453
|
writeFileSync7(p, `#!/bin/sh
|
|
9287
9454
|
# agentx scheduled job ${spec.id}${spec.label ? ` \u2014 ${spec.label}` : ""}
|
|
9288
9455
|
cd ${q2(spec.cwd)} || exit 1
|
|
9289
|
-
${this.options.agentx} -p ${q2(spec.prompt)} --resume ${q2(spec.sessionId)} --yes >> ${q2(
|
|
9456
|
+
${this.options.agentx} -p ${q2(spec.prompt)} --resume ${q2(spec.sessionId)} --yes >> ${q2(join11(this.dir, `${spec.id}.log`))} 2>&1
|
|
9290
9457
|
${cleanup}`);
|
|
9291
9458
|
chmodSync(p, 493);
|
|
9292
9459
|
return p;
|
|
@@ -9323,7 +9490,7 @@ ${trigger}
|
|
|
9323
9490
|
<key>RunAtLoad</key><false/>
|
|
9324
9491
|
</dict></plist>
|
|
9325
9492
|
`;
|
|
9326
|
-
|
|
9493
|
+
mkdirSync8(join11(this.options.home, "Library", "LaunchAgents"), { recursive: true });
|
|
9327
9494
|
writeFileSync7(this.plistPath(spec.id), plist);
|
|
9328
9495
|
this.run("launchctl", ["load", this.plistPath(spec.id)]);
|
|
9329
9496
|
return `launchd:${this.label(spec.id)}`;
|
|
@@ -9361,7 +9528,7 @@ var OsSchedulerOptions = class {
|
|
|
9361
9528
|
/** Injectable executor for tests. Returns stdout+stderr merged — `at` reports "job N" on STDERR,
|
|
9362
9529
|
* and the job id is what atrm needs for cancel. Throws on non-zero exit. */
|
|
9363
9530
|
exec = (cmd, args, input) => {
|
|
9364
|
-
const r =
|
|
9531
|
+
const r = spawnSync5(cmd, args, { input, encoding: "utf8" });
|
|
9365
9532
|
if (r.error) throw r.error;
|
|
9366
9533
|
if (r.status !== 0) throw new Error(`${cmd} exited ${r.status}: ${r.stderr || r.stdout}`);
|
|
9367
9534
|
return `${r.stdout ?? ""}${r.stderr ?? ""}`;
|
|
@@ -9376,12 +9543,12 @@ function routeTrigger(trigger, backendHint, now5 = Date.now()) {
|
|
|
9376
9543
|
// cli/remoteTrigger.ts
|
|
9377
9544
|
import { createServer as createServer2, createConnection } from "net";
|
|
9378
9545
|
import { spawn as spawn3 } from "child_process";
|
|
9379
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
9546
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync9, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
|
|
9380
9547
|
import { homedir as homedir8 } from "os";
|
|
9381
|
-
import { join as
|
|
9548
|
+
import { join as join12 } from "path";
|
|
9382
9549
|
var log20 = forComponent("remote-trigger");
|
|
9383
|
-
var TRIGGER_DIR = () =>
|
|
9384
|
-
var sockPath = (sessionId, dir = TRIGGER_DIR()) =>
|
|
9550
|
+
var TRIGGER_DIR = () => join12(homedir8(), ".agent", "triggers");
|
|
9551
|
+
var sockPath = (sessionId, dir = TRIGGER_DIR()) => join12(dir, `${sessionId}.sock`);
|
|
9385
9552
|
var TriggerServer = class {
|
|
9386
9553
|
constructor(onTrigger) {
|
|
9387
9554
|
this.onTrigger = onTrigger;
|
|
@@ -9393,7 +9560,7 @@ var TriggerServer = class {
|
|
|
9393
9560
|
start(sessionId, dir = TRIGGER_DIR()) {
|
|
9394
9561
|
this.stop();
|
|
9395
9562
|
try {
|
|
9396
|
-
|
|
9563
|
+
mkdirSync9(dir, { recursive: true, mode: 448 });
|
|
9397
9564
|
const p = sockPath(sessionId, dir);
|
|
9398
9565
|
try {
|
|
9399
9566
|
unlinkSync4(p);
|
|
@@ -9547,7 +9714,7 @@ var err = (s) => process.stderr.write(s);
|
|
|
9547
9714
|
var log21 = forComponent("cli");
|
|
9548
9715
|
var VERSION = (() => {
|
|
9549
9716
|
try {
|
|
9550
|
-
return JSON.parse(
|
|
9717
|
+
return JSON.parse(readFileSync7(new URL("../package.json", import.meta.url), "utf8")).version ?? "?";
|
|
9551
9718
|
} catch {
|
|
9552
9719
|
return "?";
|
|
9553
9720
|
}
|
|
@@ -9659,6 +9826,7 @@ function parseArgs(argv) {
|
|
|
9659
9826
|
else if (x === "--reasoning") a.reasoning = parseReasoning(val(++i, x));
|
|
9660
9827
|
else if (x === "--session-id") a.sessionId = val(++i, x);
|
|
9661
9828
|
else if (x === "--fork-session") a.fork = true;
|
|
9829
|
+
else if (x === "--worktree" || x === "-w") a.worktree = val(++i, x);
|
|
9662
9830
|
else if (x === "--max-steps") a.maxSteps = numFlag(argv[++i], "--max-steps");
|
|
9663
9831
|
else if (x === "--max-tokens") a.maxTokens = numFlag(argv[++i], "--max-tokens");
|
|
9664
9832
|
else if (x === "--timeout") a.timeoutMs = numFlag(argv[++i], "--timeout") * 1e3;
|
|
@@ -9671,6 +9839,7 @@ function parseArgs(argv) {
|
|
|
9671
9839
|
if (!a.task && rest.length) a.task = rest.join(" ");
|
|
9672
9840
|
if (a.boddb && a.vfs) throw new Error("--boddb and --sandbox are mutually exclusive (both are non-disk filesystems; pick one)");
|
|
9673
9841
|
if (a.seed && !a.boddb) throw new Error("--seed only applies with --boddb (it seeds the database from cwd on first run)");
|
|
9842
|
+
if (a.worktree && (a.vfs || a.boddb)) throw new Error("--worktree is a real-disk concept \u2014 incompatible with --vfs/--boddb");
|
|
9674
9843
|
if (a.duplex && (a.task || a.print)) throw new Error("--duplex is interactive-only (a conversational mode) \u2014 drop the task/-p");
|
|
9675
9844
|
if (a.duplex && a.plan) throw new Error("--plan is not supported in --duplex (workers are non-interactive; a plan could never be approved)");
|
|
9676
9845
|
if (a.voiceModel && !a.duplex) throw new Error("--voice-model only applies with --duplex");
|
|
@@ -9722,6 +9891,7 @@ Flags:
|
|
|
9722
9891
|
--reasoning <e> extended thinking: off|low|medium|high or a token budget (anthropic/openai)
|
|
9723
9892
|
--session-id <id> use this id for the session (instead of an auto-generated one)
|
|
9724
9893
|
--fork-session with -r/-c: branch the resumed session into a new id (source left untouched)
|
|
9894
|
+
-w, --worktree <slug> run in an isolated git worktree (.claude/worktrees/<slug>); auto-cleaned on exit if no changes
|
|
9725
9895
|
--max-steps <n> step budget (default 30)
|
|
9726
9896
|
--max-tokens <n> token budget kill-switch (default 200000)
|
|
9727
9897
|
--timeout <sec> wall-clock kill-switch (default 120)
|
|
@@ -9769,11 +9939,11 @@ function resolveModelOrNewest(model) {
|
|
|
9769
9939
|
var ENV_KEY_ALIASES = { google: ["GEMINI_API_KEY"] };
|
|
9770
9940
|
function loadInstallEnv() {
|
|
9771
9941
|
let dir = dirname4(import.meta.path);
|
|
9772
|
-
for (let i = 0; i < 5 && !existsSync10(
|
|
9942
|
+
for (let i = 0; i < 5 && !existsSync10(join13(dir, "package.json")); i++) dir = dirname4(dir);
|
|
9773
9943
|
for (const name of [".env", ".env.local"]) {
|
|
9774
|
-
const file =
|
|
9944
|
+
const file = join13(dir, name);
|
|
9775
9945
|
if (!existsSync10(file)) continue;
|
|
9776
|
-
for (const line of
|
|
9946
|
+
for (const line of readFileSync7(file, "utf8").split("\n")) {
|
|
9777
9947
|
const m = line.match(/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
|
|
9778
9948
|
if (!m || m[1] in process.env) continue;
|
|
9779
9949
|
let val = m[2].trim();
|
|
@@ -10365,7 +10535,7 @@ var IMG_EXT = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg"
|
|
|
10365
10535
|
function mentionRefs(line) {
|
|
10366
10536
|
return [...line.matchAll(/(?:^|\s)@(?:"([^"]+)"|(\S+))/g)].map((m) => m[1] ?? m[2].replace(/[?!.,;:)\]}'">]+$/, "")).filter(Boolean);
|
|
10367
10537
|
}
|
|
10368
|
-
var untilde = (p) => p.startsWith("~/") ?
|
|
10538
|
+
var untilde = (p) => p.startsWith("~/") ? join13(homedir9(), p.slice(2)) : p;
|
|
10369
10539
|
function readImageParts(cwd, line) {
|
|
10370
10540
|
const refs = mentionRefs(line);
|
|
10371
10541
|
const parts = [];
|
|
@@ -10374,7 +10544,7 @@ function readImageParts(cwd, line) {
|
|
|
10374
10544
|
if (!mime) continue;
|
|
10375
10545
|
const abs = ref.startsWith("~/") ? untilde(ref) : resolve3(cwd, ref);
|
|
10376
10546
|
try {
|
|
10377
|
-
parts.push(imagePart(`data:${mime};base64,${
|
|
10547
|
+
parts.push(imagePart(`data:${mime};base64,${readFileSync7(abs).toString("base64")}`));
|
|
10378
10548
|
} catch {
|
|
10379
10549
|
}
|
|
10380
10550
|
}
|
|
@@ -10388,7 +10558,7 @@ function pastePathClassifier(cwd) {
|
|
|
10388
10558
|
if (!/^(\/|~\/|\.\/|\.\.\/)/.test(t)) return null;
|
|
10389
10559
|
const abs = t.startsWith("~/") ? untilde(t) : resolve3(cwd, t);
|
|
10390
10560
|
try {
|
|
10391
|
-
if (!
|
|
10561
|
+
if (!statSync4(abs).isFile()) return null;
|
|
10392
10562
|
} catch {
|
|
10393
10563
|
return null;
|
|
10394
10564
|
}
|
|
@@ -10605,24 +10775,24 @@ var AGENTS_MD_TEMPLATE = `# ${"${name}"}
|
|
|
10605
10775
|
`;
|
|
10606
10776
|
function initInstructions(cwd) {
|
|
10607
10777
|
for (const f of ["AGENTS.md", "CLAUDE.md"]) {
|
|
10608
|
-
if (existsSync10(
|
|
10778
|
+
if (existsSync10(join13(cwd, f))) {
|
|
10609
10779
|
err(yellow(` ${f} already exists \u2014 leaving it as-is
|
|
10610
10780
|
`));
|
|
10611
10781
|
return;
|
|
10612
10782
|
}
|
|
10613
10783
|
}
|
|
10614
|
-
const path =
|
|
10784
|
+
const path = join13(cwd, "AGENTS.md");
|
|
10615
10785
|
writeFileSync8(path, AGENTS_MD_TEMPLATE.replace("${name}", basename2(cwd)));
|
|
10616
10786
|
err(green(` created ${path}
|
|
10617
10787
|
`) + dim(" edit it, then it auto-loads into every run.\n"));
|
|
10618
10788
|
}
|
|
10619
10789
|
function persistSetting(cwd, key, value) {
|
|
10620
|
-
const path =
|
|
10790
|
+
const path = join13(cwd, ".agent", "settings.json");
|
|
10621
10791
|
try {
|
|
10622
|
-
const obj = existsSync10(path) ? JSON.parse(
|
|
10792
|
+
const obj = existsSync10(path) ? JSON.parse(readFileSync7(path, "utf8")) : {};
|
|
10623
10793
|
if (obj[key] === value) return;
|
|
10624
10794
|
obj[key] = value;
|
|
10625
|
-
|
|
10795
|
+
mkdirSync10(dirname4(path), { recursive: true });
|
|
10626
10796
|
writeFileSync8(path, JSON.stringify(obj, null, 2) + "\n");
|
|
10627
10797
|
} catch (e) {
|
|
10628
10798
|
err(yellow(` \u26A0 couldn't persist ${key} to ${path} \u2014 ${e?.message ?? e}
|
|
@@ -10655,7 +10825,7 @@ function installCancelGuards(mounted) {
|
|
|
10655
10825
|
});
|
|
10656
10826
|
}
|
|
10657
10827
|
async function repl(args, ai, cfg, cwd) {
|
|
10658
|
-
const oauth = new McpOAuth({ storePath:
|
|
10828
|
+
const oauth = new McpOAuth({ storePath: join13(cwd, ".agent", "mcp-auth.json") });
|
|
10659
10829
|
const mounted = await mountMcp(cfg, oauth);
|
|
10660
10830
|
let mcpToolNames = [];
|
|
10661
10831
|
const initialMcpTools = mcpAgentTools(mounted);
|
|
@@ -10863,7 +11033,7 @@ async function repl(args, ai, cfg, cwd) {
|
|
|
10863
11033
|
quickLook: {
|
|
10864
11034
|
branch: () => {
|
|
10865
11035
|
try {
|
|
10866
|
-
const head =
|
|
11036
|
+
const head = readFileSync7(join13(cwd, ".git", "HEAD"), "utf8").trim();
|
|
10867
11037
|
return head.startsWith("ref: refs/heads/") ? `branch: ${head.slice("ref: refs/heads/".length)}` : `detached HEAD at ${head.slice(0, 12)}`;
|
|
10868
11038
|
} catch {
|
|
10869
11039
|
return "not a git repository";
|
|
@@ -10992,9 +11162,9 @@ async function repl(args, ai, cfg, cwd) {
|
|
|
10992
11162
|
const pendingImages = [];
|
|
10993
11163
|
const bangContext = [];
|
|
10994
11164
|
const grabClipboardAttachment = () => {
|
|
10995
|
-
const dir =
|
|
11165
|
+
const dir = join13(tmpdir3(), "agentx-pasted");
|
|
10996
11166
|
try {
|
|
10997
|
-
|
|
11167
|
+
mkdirSync10(dir, { recursive: true });
|
|
10998
11168
|
} catch {
|
|
10999
11169
|
}
|
|
11000
11170
|
const img = grabClipboardImage(dir, String(Date.now()));
|
|
@@ -11045,7 +11215,7 @@ async function repl(args, ai, cfg, cwd) {
|
|
|
11045
11215
|
err(dim(` \u23F0 ${scheduler.size} scheduled job(s) re-armed
|
|
11046
11216
|
`));
|
|
11047
11217
|
}
|
|
11048
|
-
const checkpoints = args.vfs || args.boddb ? new CheckpointStack(agent.options.fs) : new GitCheckpoints({ workTree: cwd, gitDir:
|
|
11218
|
+
const checkpoints = args.vfs || args.boddb ? new CheckpointStack(agent.options.fs) : new GitCheckpoints({ workTree: cwd, gitDir: join13(cwd, ".agent", "checkpoints.git"), addDirs: args.addDirs, sessionId: session.meta.id });
|
|
11049
11219
|
const cpHooks = checkpoints.hooks?.();
|
|
11050
11220
|
if (cpHooks) {
|
|
11051
11221
|
agent.options.hooks = composeHooks(agent.options.hooks, cpHooks);
|
|
@@ -11097,11 +11267,11 @@ ${lines.join("\n")}
|
|
|
11097
11267
|
Added entries are loadable now via the Skill/SlashCommand tools; removed ones are gone even if still listed in the system prompt.
|
|
11098
11268
|
</system-reminder>`;
|
|
11099
11269
|
};
|
|
11100
|
-
const histPath =
|
|
11101
|
-
const history = existsSync10(histPath) ?
|
|
11270
|
+
const histPath = join13(cwd, ".agent", "history");
|
|
11271
|
+
const history = existsSync10(histPath) ? readFileSync7(histPath, "utf8").split("\n").filter(Boolean).reverse().slice(0, 500) : [];
|
|
11102
11272
|
const remember = (line) => {
|
|
11103
11273
|
try {
|
|
11104
|
-
|
|
11274
|
+
mkdirSync10(join13(cwd, ".agent"), { recursive: true });
|
|
11105
11275
|
appendFileSync(histPath, line + "\n");
|
|
11106
11276
|
} catch (e) {
|
|
11107
11277
|
log21.debug("history write failed", e);
|
|
@@ -11401,8 +11571,8 @@ ${task}`;
|
|
|
11401
11571
|
const wasRaw = process.stdin.isTTY && process.stdin.isRaw;
|
|
11402
11572
|
if (wasRaw) process.stdin.setRawMode(false);
|
|
11403
11573
|
try {
|
|
11404
|
-
const { spawnSync:
|
|
11405
|
-
const r =
|
|
11574
|
+
const { spawnSync: spawnSync6 } = await import("child_process");
|
|
11575
|
+
const r = spawnSync6("less", ["-R"], { input: text, stdio: ["pipe", "inherit", "inherit"] });
|
|
11406
11576
|
if (r.error) err(text);
|
|
11407
11577
|
} finally {
|
|
11408
11578
|
if (wasRaw) process.stdin.setRawMode(true);
|
|
@@ -11426,7 +11596,7 @@ ${task}`;
|
|
|
11426
11596
|
cfgFiles.length ? ok(`config: ${cfgFiles.join(", ")}`) : warn("no .agent/config.* found (project or ~) \u2014 running on defaults");
|
|
11427
11597
|
try {
|
|
11428
11598
|
const probe = `${cwd}/.agent/sessions/.doctor-probe`;
|
|
11429
|
-
|
|
11599
|
+
mkdirSync10(`${cwd}/.agent/sessions`, { recursive: true });
|
|
11430
11600
|
writeFileSync8(probe, "ok");
|
|
11431
11601
|
unlinkSync5(probe);
|
|
11432
11602
|
ok(`session store writable (${cwd}/.agent/sessions)`);
|
|
@@ -11792,8 +11962,8 @@ ${task}`;
|
|
|
11792
11962
|
const wasRaw = process.stdin.isTTY && process.stdin.isRaw;
|
|
11793
11963
|
if (wasRaw) process.stdin.setRawMode(false);
|
|
11794
11964
|
try {
|
|
11795
|
-
const { spawnSync:
|
|
11796
|
-
|
|
11965
|
+
const { spawnSync: spawnSync6 } = await import("child_process");
|
|
11966
|
+
spawnSync6(ed, [idx], { stdio: "inherit" });
|
|
11797
11967
|
} finally {
|
|
11798
11968
|
if (wasRaw) process.stdin.setRawMode(true);
|
|
11799
11969
|
}
|
|
@@ -12160,10 +12330,10 @@ ${task}`;
|
|
|
12160
12330
|
return;
|
|
12161
12331
|
}
|
|
12162
12332
|
const md = exportMarkdown(session.meta, shown);
|
|
12163
|
-
const name = a[0] ? extname(a[0]) ? a[0] : a[0] + ".md" :
|
|
12333
|
+
const name = a[0] ? extname(a[0]) ? a[0] : a[0] + ".md" : join13(".agent", "exports", `${session.meta.id}.md`);
|
|
12164
12334
|
const path = resolve3(cwd, name);
|
|
12165
12335
|
try {
|
|
12166
|
-
|
|
12336
|
+
mkdirSync10(dirname4(path), { recursive: true });
|
|
12167
12337
|
writeFileSync8(path, md);
|
|
12168
12338
|
err(green(` \u2713 exported \u2192 ${path}
|
|
12169
12339
|
`) + dim(` ${shown.length} message(s) \xB7 ${md.length} chars
|
|
@@ -12226,7 +12396,7 @@ ${task}`;
|
|
|
12226
12396
|
if (dx) banner(dim(`\u25D1 duplex \u2014 reflex: ${dx.options.reflexModel} \xB7 act: ${work.model}${dx.options.thinkModel !== false ? ` \xB7 think: ${dx.options.thinkModel}` : ""} (real work runs in background tasks, re-voiced when done)`));
|
|
12227
12397
|
const listDir = (absDir) => {
|
|
12228
12398
|
try {
|
|
12229
|
-
return readdirSync4(
|
|
12399
|
+
return readdirSync4(join13(cwd, absDir.replace(/^\/+/, "")), { withFileTypes: true }).map((d) => ({ name: d.name, dir: d.isDirectory() }));
|
|
12230
12400
|
} catch (e) {
|
|
12231
12401
|
log21.debug("completion readdir failed", absDir, e);
|
|
12232
12402
|
return null;
|
|
@@ -12697,6 +12867,19 @@ async function main() {
|
|
|
12697
12867
|
}
|
|
12698
12868
|
if (args.debug) process.env.DEBUG ||= "*";
|
|
12699
12869
|
if (args.print && !args.task && !process.stdin.isTTY) args.task = (await readAllStdin()).trim();
|
|
12870
|
+
let worktreeCleanup;
|
|
12871
|
+
if (args.worktree) {
|
|
12872
|
+
const { enterWorktree: enterWorktree2, exitWorktree: exitWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
|
|
12873
|
+
const session = enterWorktree2(args.worktree, resolve3(args.cwd ?? process.cwd()));
|
|
12874
|
+
err(dim(` \u2295 worktree: ${session.worktreePath} (branch ${session.branch})
|
|
12875
|
+
`));
|
|
12876
|
+
worktreeCleanup = () => {
|
|
12877
|
+
const r = exitWorktree2();
|
|
12878
|
+
if (r?.removed) err(dim(" \u2296 worktree cleaned up (no changes)\n"));
|
|
12879
|
+
else if (r && !r.removed) err(dim(` \u2295 worktree kept: ${r.reason}
|
|
12880
|
+
`));
|
|
12881
|
+
};
|
|
12882
|
+
}
|
|
12700
12883
|
const cwd = resolve3(args.cwd ?? process.cwd());
|
|
12701
12884
|
const cfg = await loadConfig(cwd);
|
|
12702
12885
|
cfg.permissions = mergePerms(loadClaudeSettings(cwd), mergePerms(loadPersistedRules(cwd), cfg.permissions));
|
|
@@ -12742,7 +12925,7 @@ async function main() {
|
|
|
12742
12925
|
}
|
|
12743
12926
|
});
|
|
12744
12927
|
if (args.task) {
|
|
12745
|
-
const mounted = await mountMcp(cfg, new McpOAuth({ storePath:
|
|
12928
|
+
const mounted = await mountMcp(cfg, new McpOAuth({ storePath: join13(cwd, ".agent", "mcp-auth.json") }));
|
|
12746
12929
|
const agent = await makeAgent(args, ai, cfg, mcpAgentTools(mounted));
|
|
12747
12930
|
const store = new SessionStore(cwd);
|
|
12748
12931
|
const session = startSession(args, store, agent, cwd);
|
|
@@ -12759,9 +12942,11 @@ async function main() {
|
|
|
12759
12942
|
const obj = res ? jsonResult(res, session) : { ok: false, finishReason: "error", sessionId: session.meta.id };
|
|
12760
12943
|
process.stdout.write(JSON.stringify(args.outputFormat === "stream-json" ? { type: "result", ...obj } : obj) + "\n");
|
|
12761
12944
|
}
|
|
12945
|
+
worktreeCleanup?.();
|
|
12762
12946
|
process.exit(ok ? 0 : 1);
|
|
12763
12947
|
}
|
|
12764
12948
|
await repl(args, ai, cfg, cwd);
|
|
12949
|
+
worktreeCleanup?.();
|
|
12765
12950
|
}
|
|
12766
12951
|
if (import.meta.main) main().catch((e) => {
|
|
12767
12952
|
console.error(e?.message ?? e);
|