@unerr-ai/unerr 0.0.0-beta.2 → 0.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/cli.js +80 -117
- package/package.json +24 -1
package/README.md
CHANGED
|
@@ -56,15 +56,15 @@ unerr gives it an intelligence layer that compounds. Every caller, every convent
|
|
|
56
56
|
<table>
|
|
57
57
|
<tr>
|
|
58
58
|
<td align="center">
|
|
59
|
-
<img src="
|
|
59
|
+
<img src="https://unerr.dev/open-cli/screenshots/token-trace-main.png" alt="unerr token trace — main view" width="250" />
|
|
60
60
|
<br/><sub>Token trace</sub>
|
|
61
61
|
</td>
|
|
62
62
|
<td align="center">
|
|
63
|
-
<img src="
|
|
63
|
+
<img src="https://unerr.dev/open-cli/screenshots/token-session.png" alt="unerr session token tracking" width="250" />
|
|
64
64
|
<br/><sub>Session tracking</sub>
|
|
65
65
|
</td>
|
|
66
66
|
<td align="center">
|
|
67
|
-
<img src="
|
|
67
|
+
<img src="https://unerr.dev/open-cli/screenshots/token-turn.png" alt="unerr per-turn token breakdown" width="250" />
|
|
68
68
|
<br/><sub>Per-turn breakdown</sub>
|
|
69
69
|
</td>
|
|
70
70
|
</tr>
|
|
@@ -88,6 +88,7 @@ unerr install claude-code # or: cursor, vscode, windsurf, codex, etc.
|
|
|
88
88
|
unerr
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
<!--
|
|
91
92
|
### Install from source
|
|
92
93
|
|
|
93
94
|
```bash
|
|
@@ -107,6 +108,7 @@ unerr install claude-code # or: cursor, vscode, windsurf, codex, etc.
|
|
|
107
108
|
# 4. Run
|
|
108
109
|
unerr
|
|
109
110
|
```
|
|
111
|
+
-->
|
|
110
112
|
|
|
111
113
|
After install, your AI agent automatically connects to unerr via MCP. No config files to edit manually.
|
|
112
114
|
|
package/dist/cli.js
CHANGED
|
@@ -8924,32 +8924,37 @@ function resolvePlatform() {
|
|
|
8924
8924
|
const platform2 = process.platform;
|
|
8925
8925
|
const arch2 = process.arch;
|
|
8926
8926
|
const os2 = platform2 === "darwin" ? "darwin" : platform2 === "win32" ? "windows" : "linux";
|
|
8927
|
-
const dlArch = arch2 === "arm64" ? "aarch64" : arch2 === "x64" ? "x86_64" : arch2;
|
|
8928
8927
|
const rustTriple = platform2 === "darwin" ? arch2 === "arm64" ? "aarch64-apple-darwin" : "x86_64-apple-darwin" : platform2 === "win32" ? "x86_64-pc-windows-msvc" : arch2 === "arm64" ? "aarch64-unknown-linux-gnu" : "x86_64-unknown-linux-gnu";
|
|
8929
|
-
|
|
8930
|
-
return { os: os2, arch: dlArch, rustTriple, ext };
|
|
8928
|
+
return { os: os2, arch: arch2 === "arm64" ? "aarch64" : "x86_64", nodeArch: arch2, rustTriple };
|
|
8931
8929
|
}
|
|
8932
8930
|
function buildDownloadUrl(spec, platform2, resolvedTag) {
|
|
8933
|
-
const
|
|
8934
|
-
|
|
8935
|
-
return `https://github.com/${spec.repo}/releases/download/${
|
|
8931
|
+
const assetName = spec.resolveAssetName(platform2);
|
|
8932
|
+
if (!assetName) return null;
|
|
8933
|
+
return `https://github.com/${spec.repo}/releases/download/${resolvedTag}/${assetName}`;
|
|
8936
8934
|
}
|
|
8937
|
-
async function
|
|
8935
|
+
async function resolveLatestRelease(repo) {
|
|
8938
8936
|
try {
|
|
8939
8937
|
const url = `https://api.github.com/repos/${repo}/releases/latest`;
|
|
8940
8938
|
const response = await fetch(url, {
|
|
8941
8939
|
headers: { Accept: "application/vnd.github.v3+json" },
|
|
8942
|
-
signal: AbortSignal.timeout(1e4)
|
|
8940
|
+
signal: AbortSignal.timeout(1e4),
|
|
8941
|
+
redirect: "follow"
|
|
8943
8942
|
});
|
|
8944
8943
|
if (!response.ok) {
|
|
8945
8944
|
log2.warn(`GitHub API returned ${response.status} for ${repo}`);
|
|
8946
8945
|
return null;
|
|
8947
8946
|
}
|
|
8948
8947
|
const data = await response.json();
|
|
8949
|
-
return
|
|
8948
|
+
return {
|
|
8949
|
+
tag: data.tag_name,
|
|
8950
|
+
assets: data.assets.map((a) => ({
|
|
8951
|
+
name: a.name,
|
|
8952
|
+
url: a.browser_download_url
|
|
8953
|
+
}))
|
|
8954
|
+
};
|
|
8950
8955
|
} catch (err) {
|
|
8951
8956
|
log2.warn(
|
|
8952
|
-
`Failed to resolve latest
|
|
8957
|
+
`Failed to resolve latest release for ${repo}: ${err instanceof Error ? err.message : String(err)}`
|
|
8953
8958
|
);
|
|
8954
8959
|
return null;
|
|
8955
8960
|
}
|
|
@@ -8975,55 +8980,59 @@ async function downloadScipBinary(language, onProgress) {
|
|
|
8975
8980
|
const platform2 = resolvePlatform();
|
|
8976
8981
|
const destPath = join19(binDir, spec.binaryName);
|
|
8977
8982
|
try {
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
+
onProgress?.(`Resolving latest ${spec.binaryName} version...`);
|
|
8984
|
+
const release2 = await resolveLatestRelease(spec.repo);
|
|
8985
|
+
if (!release2) {
|
|
8986
|
+
return {
|
|
8987
|
+
success: false,
|
|
8988
|
+
binaryPath: null,
|
|
8989
|
+
error: `Could not resolve latest release for ${spec.repo}. Check your internet connection.`,
|
|
8990
|
+
fromCache: false
|
|
8991
|
+
};
|
|
8992
|
+
}
|
|
8993
|
+
let downloadUrl;
|
|
8994
|
+
if (language === "java") {
|
|
8995
|
+
const javaAsset = release2.assets.find(
|
|
8996
|
+
(a) => a.name.startsWith("scip-java-") && !a.name.endsWith(".bat") && !a.name.endsWith(".sha256")
|
|
8997
|
+
);
|
|
8998
|
+
if (!javaAsset) {
|
|
8983
8999
|
return {
|
|
8984
9000
|
success: false,
|
|
8985
9001
|
binaryPath: null,
|
|
8986
|
-
error: `
|
|
9002
|
+
error: `No compatible scip-java asset found in release ${release2.tag}. ${spec.manualInstall}`,
|
|
8987
9003
|
fromCache: false
|
|
8988
9004
|
};
|
|
8989
9005
|
}
|
|
8990
|
-
|
|
9006
|
+
downloadUrl = javaAsset.url;
|
|
9007
|
+
} else {
|
|
9008
|
+
downloadUrl = buildDownloadUrl(spec, platform2, release2.tag);
|
|
8991
9009
|
}
|
|
8992
|
-
|
|
8993
|
-
onProgress?.(`Downloading ${spec.binaryName} (${tag})...`);
|
|
8994
|
-
log2.info(`Downloading ${url}`);
|
|
8995
|
-
const response = await fetch(url, {
|
|
8996
|
-
signal: AbortSignal.timeout(12e4),
|
|
8997
|
-
redirect: "follow"
|
|
8998
|
-
});
|
|
8999
|
-
if (!response.ok) {
|
|
9000
|
-
const altResult = await tryAlternateDownload(
|
|
9001
|
-
spec,
|
|
9002
|
-
platform2,
|
|
9003
|
-
tag,
|
|
9004
|
-
binDir,
|
|
9005
|
-
onProgress
|
|
9006
|
-
);
|
|
9007
|
-
if (altResult) return altResult;
|
|
9010
|
+
if (!downloadUrl) {
|
|
9008
9011
|
return {
|
|
9009
9012
|
success: false,
|
|
9010
9013
|
binaryPath: null,
|
|
9011
|
-
error: `
|
|
9014
|
+
error: `No ${spec.binaryName} binary available for ${platform2.os}/${platform2.nodeArch}. ${spec.manualInstall}`,
|
|
9012
9015
|
fromCache: false
|
|
9013
9016
|
};
|
|
9014
9017
|
}
|
|
9015
|
-
|
|
9018
|
+
onProgress?.(`Downloading ${spec.binaryName} (${release2.tag})...`);
|
|
9019
|
+
log2.info(`Downloading ${downloadUrl}`);
|
|
9020
|
+
const response = await fetch(downloadUrl, {
|
|
9021
|
+
signal: AbortSignal.timeout(12e4),
|
|
9022
|
+
redirect: "follow"
|
|
9023
|
+
});
|
|
9024
|
+
if (!response.ok || !response.body) {
|
|
9016
9025
|
return {
|
|
9017
9026
|
success: false,
|
|
9018
9027
|
binaryPath: null,
|
|
9019
|
-
error:
|
|
9028
|
+
error: `Download failed (HTTP ${response.status}). Try manually: ${spec.manualInstall}`,
|
|
9020
9029
|
fromCache: false
|
|
9021
9030
|
};
|
|
9022
9031
|
}
|
|
9023
9032
|
onProgress?.(`Installing ${spec.binaryName}...`);
|
|
9024
|
-
if (spec.
|
|
9033
|
+
if (spec.archiveType === "tar.gz" && spec.archiveBinaryPath) {
|
|
9025
9034
|
await extractTarGz(response, spec.archiveBinaryPath, destPath);
|
|
9026
|
-
} else if (spec.
|
|
9035
|
+
} else if (spec.archiveType === "gz") {
|
|
9027
9036
|
await extractGzSingle(response, destPath);
|
|
9028
9037
|
} else {
|
|
9029
9038
|
await downloadToFile(response, destPath);
|
|
@@ -9060,66 +9069,6 @@ async function downloadScipBinary(language, onProgress) {
|
|
|
9060
9069
|
};
|
|
9061
9070
|
}
|
|
9062
9071
|
}
|
|
9063
|
-
async function tryAlternateDownload(spec, platform2, tag, binDir, onProgress) {
|
|
9064
|
-
const alternates = [
|
|
9065
|
-
{
|
|
9066
|
-
os: platform2.os === "darwin" ? "macos" : platform2.os,
|
|
9067
|
-
arch: platform2.arch
|
|
9068
|
-
},
|
|
9069
|
-
{
|
|
9070
|
-
os: platform2.os,
|
|
9071
|
-
arch: platform2.arch === "x86_64" ? "amd64" : platform2.arch
|
|
9072
|
-
},
|
|
9073
|
-
{
|
|
9074
|
-
os: platform2.os === "darwin" ? "macos" : platform2.os,
|
|
9075
|
-
arch: platform2.arch === "x86_64" ? "amd64" : platform2.arch
|
|
9076
|
-
}
|
|
9077
|
-
];
|
|
9078
|
-
for (const alt of alternates) {
|
|
9079
|
-
const altPlatform = { ...platform2, os: alt.os, arch: alt.arch };
|
|
9080
|
-
const url = buildDownloadUrl(spec, altPlatform, tag);
|
|
9081
|
-
try {
|
|
9082
|
-
const response = await fetch(url, {
|
|
9083
|
-
signal: AbortSignal.timeout(12e4),
|
|
9084
|
-
redirect: "follow",
|
|
9085
|
-
method: "HEAD"
|
|
9086
|
-
});
|
|
9087
|
-
if (response.ok) {
|
|
9088
|
-
onProgress?.(`Downloading ${spec.binaryName} (${tag})...`);
|
|
9089
|
-
const fullResponse = await fetch(url, {
|
|
9090
|
-
signal: AbortSignal.timeout(12e4),
|
|
9091
|
-
redirect: "follow"
|
|
9092
|
-
});
|
|
9093
|
-
if (fullResponse.ok && fullResponse.body) {
|
|
9094
|
-
const destPath = join19(binDir, spec.binaryName);
|
|
9095
|
-
onProgress?.(`Installing ${spec.binaryName}...`);
|
|
9096
|
-
if (spec.assetPattern.endsWith(".tar.gz") && spec.archiveBinaryPath) {
|
|
9097
|
-
await extractTarGz(
|
|
9098
|
-
fullResponse,
|
|
9099
|
-
spec.archiveBinaryPath,
|
|
9100
|
-
destPath
|
|
9101
|
-
);
|
|
9102
|
-
} else if (spec.assetPattern.endsWith(".gz") && !spec.archiveBinaryPath) {
|
|
9103
|
-
await extractGzSingle(fullResponse, destPath);
|
|
9104
|
-
} else {
|
|
9105
|
-
await downloadToFile(fullResponse, destPath);
|
|
9106
|
-
}
|
|
9107
|
-
chmodSync2(destPath, 493);
|
|
9108
|
-
onProgress?.(`${spec.binaryName} installed successfully`);
|
|
9109
|
-
return {
|
|
9110
|
-
success: true,
|
|
9111
|
-
binaryPath: destPath,
|
|
9112
|
-
error: null,
|
|
9113
|
-
fromCache: false
|
|
9114
|
-
};
|
|
9115
|
-
}
|
|
9116
|
-
}
|
|
9117
|
-
} catch {
|
|
9118
|
-
continue;
|
|
9119
|
-
}
|
|
9120
|
-
}
|
|
9121
|
-
return null;
|
|
9122
|
-
}
|
|
9123
9072
|
async function extractTarGz(response, binaryPath, destPath) {
|
|
9124
9073
|
const { exec: exec2 } = await Promise.resolve().then(() => (init_exec(), exec_exports));
|
|
9125
9074
|
const archivePath = `${destPath}.tar.gz`;
|
|
@@ -9177,41 +9126,52 @@ var init_downloader = __esm({
|
|
|
9177
9126
|
init_logger();
|
|
9178
9127
|
log2 = createModuleLogger("scip-downloader");
|
|
9179
9128
|
DOWNLOAD_SPECS = {
|
|
9180
|
-
python: {
|
|
9181
|
-
language: "python",
|
|
9182
|
-
binaryName: "scip-python",
|
|
9183
|
-
repo: "sourcegraph/scip-python",
|
|
9184
|
-
tag: "latest",
|
|
9185
|
-
assetPattern: "scip-python-{os}-{arch}.tar.gz",
|
|
9186
|
-
archiveBinaryPath: "scip-python",
|
|
9187
|
-
manualInstall: "pip install scip-python # or download from https://github.com/sourcegraph/scip-python/releases"
|
|
9188
|
-
},
|
|
9189
9129
|
go: {
|
|
9190
9130
|
language: "go",
|
|
9191
9131
|
binaryName: "scip-go",
|
|
9192
|
-
repo: "
|
|
9132
|
+
repo: "scip-code/scip-go",
|
|
9133
|
+
// transferred from sourcegraph/scip-go
|
|
9193
9134
|
tag: "latest",
|
|
9194
|
-
|
|
9135
|
+
// Verified assets: scip-go-darwin-arm64.tar.gz, scip-go-linux-amd64.tar.gz, scip-go-linux-arm64.tar.gz
|
|
9136
|
+
// NOTE: No darwin-amd64 (Intel Mac) build available
|
|
9137
|
+
resolveAssetName: (p) => {
|
|
9138
|
+
const os2 = p.os;
|
|
9139
|
+
const arch2 = p.nodeArch === "arm64" ? "arm64" : "amd64";
|
|
9140
|
+
if (os2 === "darwin" && arch2 === "amd64") return null;
|
|
9141
|
+
if (os2 === "windows") return null;
|
|
9142
|
+
return `scip-go-${os2}-${arch2}.tar.gz`;
|
|
9143
|
+
},
|
|
9144
|
+
archiveType: "tar.gz",
|
|
9195
9145
|
archiveBinaryPath: "scip-go",
|
|
9196
|
-
manualInstall: "go install github.com/
|
|
9146
|
+
manualInstall: "go install github.com/scip-code/scip-go/cmd/scip-go@latest"
|
|
9197
9147
|
},
|
|
9198
9148
|
java: {
|
|
9199
9149
|
language: "java",
|
|
9200
9150
|
binaryName: "scip-java",
|
|
9201
9151
|
repo: "sourcegraph/scip-java",
|
|
9202
9152
|
tag: "latest",
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9153
|
+
// Verified assets: scip-java-v{ver} (unix script), scip-java-v{ver}.bat (windows)
|
|
9154
|
+
// The script is a Coursier launcher — requires JRE on PATH
|
|
9155
|
+
resolveAssetName: (p) => {
|
|
9156
|
+
if (p.os === "windows") return null;
|
|
9157
|
+
return null;
|
|
9158
|
+
},
|
|
9159
|
+
archiveType: "raw",
|
|
9160
|
+
archiveBinaryPath: null,
|
|
9161
|
+
manualInstall: "Download from https://github.com/sourcegraph/scip-java/releases (requires JRE)"
|
|
9206
9162
|
},
|
|
9207
9163
|
rust: {
|
|
9208
9164
|
language: "rust",
|
|
9209
9165
|
binaryName: "rust-analyzer",
|
|
9210
9166
|
repo: "rust-lang/rust-analyzer",
|
|
9211
9167
|
tag: "latest",
|
|
9212
|
-
|
|
9168
|
+
// Verified assets: rust-analyzer-{triple}.gz (darwin, linux), rust-analyzer-{triple}.zip (windows)
|
|
9169
|
+
resolveAssetName: (p) => {
|
|
9170
|
+
if (p.os === "windows") return null;
|
|
9171
|
+
return `rust-analyzer-${p.rustTriple}.gz`;
|
|
9172
|
+
},
|
|
9173
|
+
archiveType: "gz",
|
|
9213
9174
|
archiveBinaryPath: null,
|
|
9214
|
-
// .gz single file, not tar
|
|
9215
9175
|
manualInstall: "rustup component add rust-analyzer"
|
|
9216
9176
|
}
|
|
9217
9177
|
};
|
|
@@ -9325,10 +9285,13 @@ var init_detector = __esm({
|
|
|
9325
9285
|
typescript: {
|
|
9326
9286
|
bin: "scip-typescript",
|
|
9327
9287
|
resolveFrom: "@sourcegraph/scip-typescript"
|
|
9288
|
+
},
|
|
9289
|
+
python: {
|
|
9290
|
+
bin: "scip-python",
|
|
9291
|
+
resolveFrom: "@sourcegraph/scip-python"
|
|
9328
9292
|
}
|
|
9329
9293
|
};
|
|
9330
9294
|
EXTERNAL_SCIP = {
|
|
9331
|
-
python: ["scip-python", "pyright-scip"],
|
|
9332
9295
|
go: ["scip-go"],
|
|
9333
9296
|
java: ["scip-java"],
|
|
9334
9297
|
rust: ["rust-analyzer"]
|
|
@@ -9506,7 +9469,7 @@ function buildScipArgs(language, binaryPath, projectRoot, outputPath) {
|
|
|
9506
9469
|
return [
|
|
9507
9470
|
binaryPath,
|
|
9508
9471
|
"index",
|
|
9509
|
-
"--
|
|
9472
|
+
"--cwd",
|
|
9510
9473
|
projectRoot,
|
|
9511
9474
|
"--output",
|
|
9512
9475
|
outputPath
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unerr-ai/unerr",
|
|
3
|
-
"version": "0.0.0-beta.
|
|
3
|
+
"version": "0.0.0-beta.4",
|
|
4
4
|
"description": "Local-first code intelligence CLI for unerr",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"@hono/node-server": "^2.0.1",
|
|
19
19
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
20
20
|
"@parcel/watcher": "^2.5.6",
|
|
21
|
+
"@sourcegraph/scip-python": "^0.6.6",
|
|
21
22
|
"@sourcegraph/scip-typescript": "^0.4.0",
|
|
22
23
|
"@tanstack/react-query": "^5.90.12",
|
|
23
24
|
"ai": "^6.0.172",
|
|
@@ -76,6 +77,28 @@
|
|
|
76
77
|
"dist"
|
|
77
78
|
],
|
|
78
79
|
"license": "Elastic-2.0",
|
|
80
|
+
"keywords": [
|
|
81
|
+
"mcp",
|
|
82
|
+
"mcp-server",
|
|
83
|
+
"model-context-protocol",
|
|
84
|
+
"ai",
|
|
85
|
+
"cli",
|
|
86
|
+
"code-intelligence",
|
|
87
|
+
"code-graph",
|
|
88
|
+
"knowledge-graph",
|
|
89
|
+
"codebase-indexer",
|
|
90
|
+
"code-search",
|
|
91
|
+
"developer-tools",
|
|
92
|
+
"llm",
|
|
93
|
+
"cursor",
|
|
94
|
+
"claude-code",
|
|
95
|
+
"coding-agent",
|
|
96
|
+
"ai-agent",
|
|
97
|
+
"local-first",
|
|
98
|
+
"ast",
|
|
99
|
+
"static-analysis",
|
|
100
|
+
"typescript"
|
|
101
|
+
],
|
|
79
102
|
"scripts": {
|
|
80
103
|
"build": "pnpm run build:ui && pnpm run build:cli",
|
|
81
104
|
"build:cli": "tsup src/entrypoints/cli.ts --format esm --target node20 --dts --no-splitting",
|