@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.
Files changed (3) hide show
  1. package/README.md +5 -3
  2. package/dist/cli.js +80 -117
  3. 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="public/screenshots/token-trace-main.png" alt="unerr token trace — main view" width="250" />
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="public/screenshots/token-session.png" alt="unerr session token tracking" width="250" />
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="public/screenshots/token-turn.png" alt="unerr per-turn token breakdown" width="250" />
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
- const ext = platform2 === "win32" ? "zip" : "tar.gz";
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 tag = resolvedTag ?? spec.tag;
8934
- const assetName = spec.assetPattern.replace("{os}", platform2.os).replace("{arch}", platform2.arch).replace("{rustTriple}", platform2.rustTriple).replace("{ext}", platform2.ext);
8935
- return `https://github.com/${spec.repo}/releases/download/${tag}/${assetName}`;
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 resolveLatestTag(repo) {
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 data.tag_name;
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 tag for ${repo}: ${err instanceof Error ? err.message : String(err)}`
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
- let tag = spec.tag;
8979
- if (tag === "latest") {
8980
- onProgress?.(`Resolving latest ${spec.binaryName} version...`);
8981
- const resolved = await resolveLatestTag(spec.repo);
8982
- if (!resolved) {
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: `Could not resolve latest release for ${spec.repo}. Check your internet connection.`,
9002
+ error: `No compatible scip-java asset found in release ${release2.tag}. ${spec.manualInstall}`,
8987
9003
  fromCache: false
8988
9004
  };
8989
9005
  }
8990
- tag = resolved;
9006
+ downloadUrl = javaAsset.url;
9007
+ } else {
9008
+ downloadUrl = buildDownloadUrl(spec, platform2, release2.tag);
8991
9009
  }
8992
- const url = buildDownloadUrl(spec, platform2, tag);
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: `Download failed (HTTP ${response.status}). Try manually: ${spec.manualInstall}`,
9014
+ error: `No ${spec.binaryName} binary available for ${platform2.os}/${platform2.nodeArch}. ${spec.manualInstall}`,
9012
9015
  fromCache: false
9013
9016
  };
9014
9017
  }
9015
- if (!response.body) {
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: "Empty response body",
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.assetPattern.endsWith(".tar.gz") && spec.archiveBinaryPath) {
9033
+ if (spec.archiveType === "tar.gz" && spec.archiveBinaryPath) {
9025
9034
  await extractTarGz(response, spec.archiveBinaryPath, destPath);
9026
- } else if (spec.assetPattern.endsWith(".gz") && !spec.archiveBinaryPath) {
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: "sourcegraph/scip-go",
9132
+ repo: "scip-code/scip-go",
9133
+ // transferred from sourcegraph/scip-go
9193
9134
  tag: "latest",
9194
- assetPattern: "scip-go_{os}_{arch}.tar.gz",
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/sourcegraph/scip-go@latest"
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
- assetPattern: "scip-java-{os}-{arch}.tar.gz",
9204
- archiveBinaryPath: "scip-java",
9205
- manualInstall: "Download from https://github.com/sourcegraph/scip-java/releases"
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
- assetPattern: "rust-analyzer-{rustTriple}.gz",
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
- "--project-root",
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.2",
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",