@raegent/earshot 0.2.0 → 0.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/dist/main.js +352 -3
- package/dist/main.js.map +7 -6
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -18381,7 +18381,7 @@ class ShadowGit {
|
|
|
18381
18381
|
}
|
|
18382
18382
|
|
|
18383
18383
|
// packages/core/src/version.ts
|
|
18384
|
-
var VERSION = "0.
|
|
18384
|
+
var VERSION = "0.3.0";
|
|
18385
18385
|
|
|
18386
18386
|
// packages/core/src/session/repair.ts
|
|
18387
18387
|
var REPAIR_TEXT = "No result was recorded for this call: earshot exited before the tool finished. " + "The call may or may not have run, so treat its effect as unknown and check " + "the current state rather than assuming either outcome.";
|
|
@@ -18642,7 +18642,16 @@ function parseArgs(argv) {
|
|
|
18642
18642
|
positionals.push(arg);
|
|
18643
18643
|
}
|
|
18644
18644
|
}
|
|
18645
|
-
const known = new Set([
|
|
18645
|
+
const known = new Set([
|
|
18646
|
+
"auth",
|
|
18647
|
+
"mcp",
|
|
18648
|
+
"extensions",
|
|
18649
|
+
"config",
|
|
18650
|
+
"models",
|
|
18651
|
+
"acp",
|
|
18652
|
+
"doctor",
|
|
18653
|
+
"update"
|
|
18654
|
+
]);
|
|
18646
18655
|
const command = positionals[0] !== undefined && known.has(positionals[0]) ? positionals[0] : undefined;
|
|
18647
18656
|
return { command, flags, positionals: command ? positionals.slice(1) : positionals };
|
|
18648
18657
|
}
|
|
@@ -22654,6 +22663,343 @@ ${models.length} models across ${new Set(models.map((m) => m.providerId)).size}
|
|
|
22654
22663
|
return 0;
|
|
22655
22664
|
}
|
|
22656
22665
|
|
|
22666
|
+
// packages/cli/src/commands/update.ts
|
|
22667
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
22668
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
22669
|
+
import { existsSync as existsSync2, realpathSync } from "node:fs";
|
|
22670
|
+
import { chmod, readdir as readdir8, rename as rename2, rm as rm2, writeFile as writeFile10 } from "node:fs/promises";
|
|
22671
|
+
import { basename as basename2, dirname as dirname9, join as join19, sep as sep5 } from "node:path";
|
|
22672
|
+
import { createInterface } from "node:readline/promises";
|
|
22673
|
+
import { fileURLToPath } from "node:url";
|
|
22674
|
+
var PACKAGE = "@raegent/earshot";
|
|
22675
|
+
var REPO = "rishabhguptajs/earshot";
|
|
22676
|
+
var REGISTRY = `https://registry.npmjs.org/${PACKAGE.replace("/", "%2f")}/latest`;
|
|
22677
|
+
var RELEASE = `https://api.github.com/repos/${REPO}/releases/latest`;
|
|
22678
|
+
var BUNFS_MARKERS = ["/$bunfs/", "\\$bunfs\\", "/~BUN/", "\\~BUN\\"];
|
|
22679
|
+
var ASSETS = {
|
|
22680
|
+
"darwin-arm64": "earshot-darwin-arm64",
|
|
22681
|
+
"darwin-x64": "earshot-darwin-x64",
|
|
22682
|
+
"linux-x64": "earshot-linux-x64",
|
|
22683
|
+
"linux-arm64": "earshot-linux-arm64",
|
|
22684
|
+
"win32-x64": "earshot-windows-x64.exe"
|
|
22685
|
+
};
|
|
22686
|
+
function modulePath(moduleUrl) {
|
|
22687
|
+
try {
|
|
22688
|
+
return fileURLToPath(moduleUrl);
|
|
22689
|
+
} catch {
|
|
22690
|
+
return moduleUrl;
|
|
22691
|
+
}
|
|
22692
|
+
}
|
|
22693
|
+
function managerOf(dir) {
|
|
22694
|
+
const lower = dir.toLowerCase().replaceAll("\\", "/");
|
|
22695
|
+
if (lower.includes("/.bun/install/global"))
|
|
22696
|
+
return "bun";
|
|
22697
|
+
if (lower.includes("/.volta/"))
|
|
22698
|
+
return "volta";
|
|
22699
|
+
if (lower.includes("/pnpm/global") || lower.includes("/.pnpm/"))
|
|
22700
|
+
return "pnpm";
|
|
22701
|
+
if (lower.includes("/.yarn/") || lower.includes("/yarn/global"))
|
|
22702
|
+
return "yarn";
|
|
22703
|
+
return "npm";
|
|
22704
|
+
}
|
|
22705
|
+
function detectInstall(options) {
|
|
22706
|
+
const { execPath, moduleUrl, bunVersion, platform: platform7, arch } = options;
|
|
22707
|
+
const realpath = options.realpath ?? ((path) => path);
|
|
22708
|
+
const file = modulePath(moduleUrl);
|
|
22709
|
+
if (BUNFS_MARKERS.some((marker3) => file.includes(marker3)) && bunVersion !== undefined) {
|
|
22710
|
+
const asset = ASSETS[`${platform7}-${arch}`];
|
|
22711
|
+
const target = realpath(execPath);
|
|
22712
|
+
if (asset === undefined) {
|
|
22713
|
+
return {
|
|
22714
|
+
kind: "binary",
|
|
22715
|
+
path: target,
|
|
22716
|
+
reason: `no release asset is built for ${platform7}-${arch}`
|
|
22717
|
+
};
|
|
22718
|
+
}
|
|
22719
|
+
return { kind: "binary", path: target, asset };
|
|
22720
|
+
}
|
|
22721
|
+
const marker2 = `${sep5}node_modules${sep5}${PACKAGE.split("/").join(sep5)}${sep5}`;
|
|
22722
|
+
const index = `${file}${sep5}`.indexOf(marker2);
|
|
22723
|
+
if (index !== -1) {
|
|
22724
|
+
const packageDir = file.slice(0, index + marker2.length - 1);
|
|
22725
|
+
const tree = packageDir.slice(0, packageDir.indexOf(`${sep5}node_modules${sep5}`));
|
|
22726
|
+
const isProjectRoot = options.isProjectRoot ?? (() => false);
|
|
22727
|
+
return {
|
|
22728
|
+
kind: "npm",
|
|
22729
|
+
path: packageDir,
|
|
22730
|
+
manager: managerOf(packageDir),
|
|
22731
|
+
local: isProjectRoot(tree)
|
|
22732
|
+
};
|
|
22733
|
+
}
|
|
22734
|
+
if (file.includes(`${sep5}packages${sep5}cli${sep5}`) || file.endsWith(".ts")) {
|
|
22735
|
+
return { kind: "source", path: file, reason: "running from a source checkout" };
|
|
22736
|
+
}
|
|
22737
|
+
return { kind: "unknown", path: file, reason: `cannot tell how ${execPath} was installed` };
|
|
22738
|
+
}
|
|
22739
|
+
function compareVersions(a, b) {
|
|
22740
|
+
const split = (value) => {
|
|
22741
|
+
const [core = "", pre] = value.replace(/^v/, "").split("-");
|
|
22742
|
+
const parts = core.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
22743
|
+
return { parts, pre };
|
|
22744
|
+
};
|
|
22745
|
+
const left = split(a);
|
|
22746
|
+
const right = split(b);
|
|
22747
|
+
for (let i = 0;i < 3; i++) {
|
|
22748
|
+
const diff2 = (left.parts[i] ?? 0) - (right.parts[i] ?? 0);
|
|
22749
|
+
if (diff2 !== 0)
|
|
22750
|
+
return diff2 < 0 ? -1 : 1;
|
|
22751
|
+
}
|
|
22752
|
+
if (left.pre === right.pre)
|
|
22753
|
+
return 0;
|
|
22754
|
+
if (left.pre === undefined)
|
|
22755
|
+
return 1;
|
|
22756
|
+
if (right.pre === undefined)
|
|
22757
|
+
return -1;
|
|
22758
|
+
return left.pre < right.pre ? -1 : 1;
|
|
22759
|
+
}
|
|
22760
|
+
async function resolveLatest(kind, fetchImpl) {
|
|
22761
|
+
if (kind === "npm") {
|
|
22762
|
+
const response2 = await fetchImpl(REGISTRY);
|
|
22763
|
+
if (!response2.ok)
|
|
22764
|
+
throw new Error(`npm registry returned ${response2.status}`);
|
|
22765
|
+
const body2 = await response2.json();
|
|
22766
|
+
if (!body2.version)
|
|
22767
|
+
throw new Error("npm registry returned no version");
|
|
22768
|
+
return body2.version;
|
|
22769
|
+
}
|
|
22770
|
+
const response = await fetchImpl(RELEASE);
|
|
22771
|
+
if (!response.ok)
|
|
22772
|
+
throw new Error(`GitHub releases returned ${response.status}`);
|
|
22773
|
+
const body = await response.json();
|
|
22774
|
+
if (!body.tag_name)
|
|
22775
|
+
throw new Error("GitHub returned a release with no tag");
|
|
22776
|
+
return body.tag_name.replace(/^v/, "");
|
|
22777
|
+
}
|
|
22778
|
+
function findChecksum(sums, asset) {
|
|
22779
|
+
for (const line of sums.split(`
|
|
22780
|
+
`)) {
|
|
22781
|
+
const [hash, ...rest] = line.trim().split(/\s+/);
|
|
22782
|
+
const name = rest.join(" ").replace(/^\*/, "");
|
|
22783
|
+
if (hash && name && basename2(name) === asset)
|
|
22784
|
+
return hash.toLowerCase();
|
|
22785
|
+
}
|
|
22786
|
+
return;
|
|
22787
|
+
}
|
|
22788
|
+
var installCommand = {
|
|
22789
|
+
npm: `npm install -g ${PACKAGE}@latest`,
|
|
22790
|
+
bun: `bun add -g ${PACKAGE}@latest`,
|
|
22791
|
+
pnpm: `pnpm add -g ${PACKAGE}@latest`,
|
|
22792
|
+
yarn: `yarn global add ${PACKAGE}@latest`,
|
|
22793
|
+
volta: `volta install ${PACKAGE}@latest`
|
|
22794
|
+
};
|
|
22795
|
+
async function runUpdate(options = {}) {
|
|
22796
|
+
const out = options.out ?? ((text2) => process.stdout.write(text2));
|
|
22797
|
+
const err = options.err ?? ((text2) => process.stderr.write(text2));
|
|
22798
|
+
const current = options.current ?? VERSION;
|
|
22799
|
+
const install = options.install ?? detectInstall({
|
|
22800
|
+
execPath: process.execPath,
|
|
22801
|
+
moduleUrl: import.meta.url,
|
|
22802
|
+
bunVersion: process.versions.bun,
|
|
22803
|
+
platform: process.platform,
|
|
22804
|
+
arch: process.arch,
|
|
22805
|
+
realpath: (path) => {
|
|
22806
|
+
try {
|
|
22807
|
+
return realpathSync(path);
|
|
22808
|
+
} catch {
|
|
22809
|
+
return path;
|
|
22810
|
+
}
|
|
22811
|
+
},
|
|
22812
|
+
isProjectRoot: (dir) => existsSync2(join19(dir, "package.json"))
|
|
22813
|
+
});
|
|
22814
|
+
const fetchImpl = options.fetch ?? ((url) => fetch(url));
|
|
22815
|
+
if (install.kind === "source" || install.kind === "unknown") {
|
|
22816
|
+
err(`earshot update: ${install.reason}
|
|
22817
|
+
`);
|
|
22818
|
+
err(install.kind === "source" ? `update the checkout with git instead
|
|
22819
|
+
` : `reinstall from ${`https://github.com/${REPO}/releases`}
|
|
22820
|
+
`);
|
|
22821
|
+
return 2;
|
|
22822
|
+
}
|
|
22823
|
+
if (install.kind === "binary" && install.asset === undefined) {
|
|
22824
|
+
err(`earshot update: ${install.reason}
|
|
22825
|
+
`);
|
|
22826
|
+
return 2;
|
|
22827
|
+
}
|
|
22828
|
+
let latest;
|
|
22829
|
+
try {
|
|
22830
|
+
latest = await resolveLatest(install.kind, fetchImpl);
|
|
22831
|
+
} catch (error) {
|
|
22832
|
+
err(`earshot update: ${error.message}
|
|
22833
|
+
`);
|
|
22834
|
+
return 1;
|
|
22835
|
+
}
|
|
22836
|
+
if (compareVersions(current, latest) >= 0) {
|
|
22837
|
+
out(`earshot ${current} is the latest version
|
|
22838
|
+
`);
|
|
22839
|
+
return 0;
|
|
22840
|
+
}
|
|
22841
|
+
const where = install.kind === "npm" ? `installed with ${install.manager}, ${install.local ? "in this project" : "globally"}` : "standalone binary";
|
|
22842
|
+
out(`earshot ${current} -> ${latest} (${where})
|
|
22843
|
+
`);
|
|
22844
|
+
if (install.kind === "npm") {
|
|
22845
|
+
const manager2 = install.manager ?? "npm";
|
|
22846
|
+
const command = install.local ? `${manager2 === "npm" ? "npm install" : `${manager2} add`} ${PACKAGE}@latest` : installCommand[manager2];
|
|
22847
|
+
out(`
|
|
22848
|
+
${command}
|
|
22849
|
+
|
|
22850
|
+
`);
|
|
22851
|
+
if (install.local || manager2 !== "npm") {
|
|
22852
|
+
out(`run that to update
|
|
22853
|
+
`);
|
|
22854
|
+
return options.check ? 4 : 0;
|
|
22855
|
+
}
|
|
22856
|
+
if (options.check)
|
|
22857
|
+
return 4;
|
|
22858
|
+
if (!await confirmed(options, "run it now?")) {
|
|
22859
|
+
out(`run that to update
|
|
22860
|
+
`);
|
|
22861
|
+
return 0;
|
|
22862
|
+
}
|
|
22863
|
+
const run4 = options.run ?? runCommand2;
|
|
22864
|
+
const result = run4("npm", ["install", "-g", `${PACKAGE}@latest`]);
|
|
22865
|
+
if (result.status !== 0) {
|
|
22866
|
+
err(`earshot update: npm exited ${result.status}
|
|
22867
|
+
`);
|
|
22868
|
+
return 1;
|
|
22869
|
+
}
|
|
22870
|
+
out(`updated to ${latest}
|
|
22871
|
+
`);
|
|
22872
|
+
return 0;
|
|
22873
|
+
}
|
|
22874
|
+
return await updateBinary(install, latest, options, out, err);
|
|
22875
|
+
}
|
|
22876
|
+
function runCommand2(command, args) {
|
|
22877
|
+
const result = spawnSync2(command, args, { stdio: "inherit", windowsHide: true, shell: false });
|
|
22878
|
+
return { status: result.status };
|
|
22879
|
+
}
|
|
22880
|
+
async function confirmed(options, question) {
|
|
22881
|
+
if (options.yes)
|
|
22882
|
+
return true;
|
|
22883
|
+
const confirm = options.confirm ?? defaultConfirm;
|
|
22884
|
+
return await confirm(question);
|
|
22885
|
+
}
|
|
22886
|
+
async function defaultConfirm(question) {
|
|
22887
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
22888
|
+
return false;
|
|
22889
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
22890
|
+
try {
|
|
22891
|
+
const answer = await rl.question(`${question} [y/N] `);
|
|
22892
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
22893
|
+
} finally {
|
|
22894
|
+
rl.close();
|
|
22895
|
+
}
|
|
22896
|
+
}
|
|
22897
|
+
async function updateBinary(install, latest, options, out, err) {
|
|
22898
|
+
const target = install.path;
|
|
22899
|
+
const asset = install.asset;
|
|
22900
|
+
const dir = dirname9(target);
|
|
22901
|
+
const fetchImpl = options.fetch ?? ((url) => fetch(url));
|
|
22902
|
+
await sweepStale(dir, target);
|
|
22903
|
+
out(` ${target} ${asset}
|
|
22904
|
+
`);
|
|
22905
|
+
if (options.check)
|
|
22906
|
+
return 4;
|
|
22907
|
+
try {
|
|
22908
|
+
await writeFile10(join19(dir, `.earshot-update-probe-${process.pid}`), "");
|
|
22909
|
+
await rm2(join19(dir, `.earshot-update-probe-${process.pid}`), { force: true });
|
|
22910
|
+
} catch {
|
|
22911
|
+
err(`earshot update: cannot write to ${dir}
|
|
22912
|
+
`);
|
|
22913
|
+
err(`re-run with the permissions that own that directory
|
|
22914
|
+
`);
|
|
22915
|
+
return 1;
|
|
22916
|
+
}
|
|
22917
|
+
if (!await confirmed(options, `download ${asset} and replace it?`)) {
|
|
22918
|
+
out(`nothing was changed
|
|
22919
|
+
`);
|
|
22920
|
+
return 0;
|
|
22921
|
+
}
|
|
22922
|
+
const base = `https://github.com/${REPO}/releases/download/v${latest}`;
|
|
22923
|
+
const temp = join19(dir, `.earshot-update-${process.pid}.tmp`);
|
|
22924
|
+
try {
|
|
22925
|
+
out(" downloading… ");
|
|
22926
|
+
const download = await fetchImpl(`${base}/${asset}`);
|
|
22927
|
+
if (!download.ok)
|
|
22928
|
+
throw new Error(`downloading ${asset} returned ${download.status}`);
|
|
22929
|
+
const bytes = new Uint8Array(await download.arrayBuffer());
|
|
22930
|
+
out("verifying SHA256… ");
|
|
22931
|
+
const sumsResponse = await fetchImpl(`${base}/SHA256SUMS`);
|
|
22932
|
+
if (!sumsResponse.ok)
|
|
22933
|
+
throw new Error(`SHA256SUMS returned ${sumsResponse.status}`);
|
|
22934
|
+
const expected = findChecksum(await sumsResponse.text(), asset);
|
|
22935
|
+
if (expected === undefined)
|
|
22936
|
+
throw new Error(`SHA256SUMS does not list ${asset}`);
|
|
22937
|
+
const actual = createHash4("sha256").update(bytes).digest("hex");
|
|
22938
|
+
if (actual !== expected) {
|
|
22939
|
+
throw new Error(`checksum mismatch for ${asset}: expected ${expected}, got ${actual}`);
|
|
22940
|
+
}
|
|
22941
|
+
out("replacing… ");
|
|
22942
|
+
await writeFile10(temp, bytes);
|
|
22943
|
+
const platform7 = options.platform ?? process.platform;
|
|
22944
|
+
if (platform7 !== "win32")
|
|
22945
|
+
await chmod(temp, 493);
|
|
22946
|
+
await replace(temp, target, platform7);
|
|
22947
|
+
out(`
|
|
22948
|
+
updated to ${latest}
|
|
22949
|
+
`);
|
|
22950
|
+
return 0;
|
|
22951
|
+
} catch (error) {
|
|
22952
|
+
await rm2(temp, { force: true });
|
|
22953
|
+
out(`
|
|
22954
|
+
`);
|
|
22955
|
+
err(`earshot update: ${error.message}
|
|
22956
|
+
`);
|
|
22957
|
+
err(`nothing was replaced
|
|
22958
|
+
`);
|
|
22959
|
+
return 1;
|
|
22960
|
+
}
|
|
22961
|
+
}
|
|
22962
|
+
var realIo = {
|
|
22963
|
+
rename: (from, to) => rename2(from, to),
|
|
22964
|
+
remove: (path) => rm2(path, { force: true })
|
|
22965
|
+
};
|
|
22966
|
+
async function replace(temp, target, platform7, io = realIo) {
|
|
22967
|
+
if (platform7 !== "win32") {
|
|
22968
|
+
await io.rename(temp, target);
|
|
22969
|
+
return;
|
|
22970
|
+
}
|
|
22971
|
+
const aside = `${target}.old-${process.pid}`;
|
|
22972
|
+
await io.rename(target, aside);
|
|
22973
|
+
try {
|
|
22974
|
+
await io.rename(temp, target);
|
|
22975
|
+
} catch (error) {
|
|
22976
|
+
await io.rename(aside, target).catch(() => {});
|
|
22977
|
+
throw error;
|
|
22978
|
+
}
|
|
22979
|
+
await io.remove(aside).catch(() => {});
|
|
22980
|
+
}
|
|
22981
|
+
async function sweepStale(dir, target) {
|
|
22982
|
+
const prefix = `${basename2(target)}.old-`;
|
|
22983
|
+
const entries = await readdir8(dir).catch(() => []);
|
|
22984
|
+
for (const entry of entries) {
|
|
22985
|
+
if (entry.startsWith(prefix))
|
|
22986
|
+
await rm2(join19(dir, entry), { force: true }).catch(() => {});
|
|
22987
|
+
}
|
|
22988
|
+
}
|
|
22989
|
+
async function updateCommand(args) {
|
|
22990
|
+
if (args.positionals.length > 0) {
|
|
22991
|
+
process.stderr.write(`earshot update: unexpected argument "${args.positionals[0]}"
|
|
22992
|
+
`);
|
|
22993
|
+
process.stderr.write(`usage: earshot update [--check] [--yes]
|
|
22994
|
+
`);
|
|
22995
|
+
return 2;
|
|
22996
|
+
}
|
|
22997
|
+
return runUpdate({
|
|
22998
|
+
check: args.flags.check === true,
|
|
22999
|
+
yes: args.flags.yes === true || args.flags.y === true
|
|
23000
|
+
});
|
|
23001
|
+
}
|
|
23002
|
+
|
|
22657
23003
|
// packages/cli/src/index.ts
|
|
22658
23004
|
var HELP = `earshot ${VERSION} - a terminal coding agent that actually listens
|
|
22659
23005
|
|
|
@@ -22666,6 +23012,7 @@ Usage
|
|
|
22666
23012
|
earshot extensions <cmd> list, trust or untrust in-process extensions
|
|
22667
23013
|
earshot acp serve editor clients over ACP v1 on stdio
|
|
22668
23014
|
earshot doctor diagnose the local setup
|
|
23015
|
+
earshot update [--check] update earshot to the latest release
|
|
22669
23016
|
|
|
22670
23017
|
Flags
|
|
22671
23018
|
--model <provider/model> model for this session
|
|
@@ -22705,6 +23052,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
22705
23052
|
return authCommand(args);
|
|
22706
23053
|
if (command === "doctor")
|
|
22707
23054
|
return doctorCommand(args);
|
|
23055
|
+
if (command === "update")
|
|
23056
|
+
return updateCommand(args);
|
|
22708
23057
|
if (command === "acp")
|
|
22709
23058
|
return acpCommand(args);
|
|
22710
23059
|
if (command) {
|
|
@@ -22719,5 +23068,5 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
22719
23068
|
var code = await main();
|
|
22720
23069
|
process.exitCode = code;
|
|
22721
23070
|
|
|
22722
|
-
//# debugId=
|
|
23071
|
+
//# debugId=8F9F015F9221906F64756E2164756E21
|
|
22723
23072
|
//# sourceMappingURL=main.js.map
|