diff --git a/.github/scripts/sync-atomgit-release.mjs b/.github/scripts/sync-atomgit-release.mjs
deleted file mode 100644
index 489b4e174f..0000000000
--- a/.github/scripts/sync-atomgit-release.mjs
+++ /dev/null
@@ -1,405 +0,0 @@
-#!/usr/bin/env node
-
-import { basename, join } from "node:path";
-import { readdirSync, readFileSync, statSync } from "node:fs";
-import { spawn } from "node:child_process";
-import { pathToFileURL } from "node:url";
-
-const DEFAULT_API_BASE = "https://api.atomgit.com/api/v5";
-const DEFAULT_REPOSITORY = "t8y2/dbx";
-const DEFAULT_CONCURRENCY = 3;
-
-function parseArgs(argv) {
- const args = {
- apiBase: process.env.ATOMGIT_API_BASE || DEFAULT_API_BASE,
- repository: process.env.ATOMGIT_REPOSITORY || DEFAULT_REPOSITORY,
- token: process.env.ATOMGIT_TOKEN || "",
- githubReleasePath: "",
- assetsDir: "",
- skipExistingAssets: true,
- concurrency: Number.parseInt(process.env.ATOMGIT_UPLOAD_CONCURRENCY || `${DEFAULT_CONCURRENCY}`, 10),
- };
-
- for (let i = 0; i < argv.length; i++) {
- const arg = argv[i];
- if (arg === "--github-release") {
- args.githubReleasePath = argv[++i];
- } else if (arg === "--assets-dir") {
- args.assetsDir = argv[++i];
- } else if (arg === "--repository") {
- args.repository = argv[++i];
- } else if (arg === "--api-base") {
- args.apiBase = argv[++i];
- } else if (arg === "--replace-assets") {
- args.skipExistingAssets = false;
- } else {
- throw new Error(`Unknown argument: ${arg}`);
- }
- }
-
- if (!args.token) {
- throw new Error("ATOMGIT_TOKEN is required.");
- }
- if (!args.githubReleasePath || !args.assetsDir) {
- throw new Error("Usage: sync-atomgit-release.mjs --github-release --assets-dir ");
- }
- if (!args.repository.includes("/")) {
- throw new Error(`Invalid AtomGit repository: ${args.repository}`);
- }
- if (!Number.isInteger(args.concurrency) || args.concurrency < 1) {
- throw new Error("ATOMGIT_UPLOAD_CONCURRENCY must be a positive integer.");
- }
- return args;
-}
-
-async function main() {
- const args = parseArgs(process.argv.slice(2));
- const [owner, repo] = args.repository.split("/", 2);
- const release = JSON.parse(readFileSync(args.githubReleasePath, "utf8"));
- const tag = release.tagName || release.tag_name;
- if (!tag) {
- throw new Error("GitHub release JSON is missing tagName.");
- }
-
- const client = new AtomGitClient({ apiBase: args.apiBase, token: args.token, owner, repo });
- const atomRelease = await ensureRelease(client, release);
- // PATCH responses may omit attachments, so re-read before deciding what must be replaced.
- const existingAssets = atomGitAssets((await client.getRelease(tag)) || atomRelease);
- const assets = localAssets(args.assetsDir);
- if (assets.length === 0) {
- console.log("No release assets found to sync.");
- return;
- }
-
- const pendingAssets = assets.filter((assetPath) => {
- const name = basename(assetPath);
- if (args.skipExistingAssets && existingAssets.has(name)) {
- console.log(`Skipping existing AtomGit asset: ${name}`);
- return false;
- }
- return true;
- });
-
- if (!args.skipExistingAssets) {
- for (const assetPath of pendingAssets) {
- const name = basename(assetPath);
- const existingAsset = existingAssets.get(name);
- if (!existingAsset) continue;
- if (existingAsset.id === null) {
- throw new Error(`Cannot replace AtomGit asset without an attachment id: ${name}`);
- }
- console.log(`Deleting existing AtomGit asset: ${name}`);
- await client.deleteAsset(tag, existingAsset.id);
- }
- }
-
- console.log(`Uploading ${pendingAssets.length} asset(s) with concurrency ${args.concurrency}.`);
- await mapWithConcurrency(pendingAssets, args.concurrency, (assetPath) => uploadAsset(client, tag, assetPath));
-
- const refreshedRelease = await client.getRelease(tag);
- const uploadedAssets = atomGitAssets(refreshedRelease);
- const missingAssets = pendingAssets.map(basename).filter((name) => !uploadedAssets.has(name));
- if (missingAssets.length > 0) {
- throw new Error(`AtomGit did not register uploaded assets: ${missingAssets.join(", ")}`);
- }
-}
-
-async function ensureRelease(client, githubRelease) {
- const tag = githubRelease.tagName || githubRelease.tag_name;
- const payload = {
- tag_name: tag,
- name: githubRelease.name || tag,
- body: githubRelease.body || "",
- target_commitish: githubRelease.targetCommitish || githubRelease.target_commitish || "",
- prerelease: Boolean(githubRelease.isPrerelease || githubRelease.prerelease),
- };
-
- const existing = await client.getRelease(tag);
- if (existing) {
- console.log(`Updating existing AtomGit release: ${tag}`);
- return client.updateRelease(tag, payload);
- }
-
- console.log(`Creating AtomGit release: ${tag}`);
- return client.createRelease(payload);
-}
-
-async function uploadAsset(client, tag, filePath) {
- const name = basename(filePath);
- const size = statSync(filePath).size;
- console.log(`Uploading ${name} (${size} bytes)`);
- const uploadTarget = await client.getUploadTarget(tag, name);
- const contentType = contentTypeFor(name);
- const uploadHeaders = uploadTarget.headers.length > 0
- ? uploadTarget.headers
- : [
- ["Authorization", `Bearer ${client.token}`],
- ["X-Api-Version", "2023-02-21"],
- ];
- const contentTypeHeader = headerValue(uploadHeaders, "Content-Type") || contentType;
- const curlHeaders = uploadHeaders
- .filter(([key]) => key.toLowerCase() !== "content-type")
- .flatMap(([key, value]) => ["--header", `${key}: ${value}`]);
-
- // AtomGit returns a per-file upload URL plus required upload headers.
- // Try raw PUT first and fall back to multipart POST for API-compatible deployments.
- const putResult = await runCurl([
- "--fail-with-body",
- "--location",
- "--silent",
- "--show-error",
- "--retry",
- "3",
- "--retry-delay",
- "5",
- "--request",
- "PUT",
- ...curlHeaders,
- "--header",
- `Content-Type: ${contentTypeHeader}`,
- "--upload-file",
- filePath,
- uploadTarget.url,
- ]);
- if (uploadResultSucceeded(putResult)) {
- return;
- }
-
- console.warn(`PUT upload failed for ${name}: ${uploadFailureMessage(putResult)}; retrying as multipart POST.`);
- const postResult = await runCurl([
- "--fail-with-body",
- "--location",
- "--silent",
- "--show-error",
- "--retry",
- "3",
- "--retry-delay",
- "5",
- "--request",
- "POST",
- ...curlHeaders,
- "--form",
- `file=@${filePath};filename=${name};type=${contentTypeHeader}`,
- uploadTarget.url,
- ]);
- if (!uploadResultSucceeded(postResult)) {
- throw new Error(`Failed to upload ${name} to AtomGit: ${uploadFailureMessage(postResult)}`);
- }
-}
-
-function runCurl(args) {
- return new Promise((resolve, reject) => {
- const child = spawn("curl", args, { stdio: ["ignore", "pipe", "pipe"] });
- let stdout = "";
- let stderr = "";
- child.stdout.setEncoding("utf8");
- child.stderr.setEncoding("utf8");
- child.stdout.on("data", (chunk) => {
- stdout += chunk;
- });
- child.stderr.on("data", (chunk) => {
- stderr += chunk;
- });
- child.once("error", reject);
- child.once("close", (code) => resolve({ status: code ?? 1, stdout, stderr }));
- });
-}
-
-export function uploadResultSucceeded(result) {
- if (result.status !== 0) return false;
- const responseBody = result.stdout.trim();
- if (!responseBody || responseBody.toLowerCase() === "success") return true;
- try {
- const response = JSON.parse(responseBody);
- return response.success === true || response.status === "success";
- } catch {
- return true;
- }
-}
-
-function uploadFailureMessage(result) {
- return result.stderr.trim() || result.stdout.trim() || `curl exited with status ${result.status}`;
-}
-
-async function mapWithConcurrency(items, concurrency, worker) {
- let nextIndex = 0;
- async function runWorker() {
- while (nextIndex < items.length) {
- const index = nextIndex++;
- await worker(items[index]);
- }
- }
- await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, runWorker));
-}
-
-function localAssets(dir) {
- return readdirSync(dir)
- .map((name) => join(dir, name))
- .filter((path) => statSync(path).isFile())
- .sort((a, b) => statSync(a).size - statSync(b).size || basename(a).localeCompare(basename(b)));
-}
-
-export function atomGitAssets(release) {
- const assets = new Map();
- const groups = [
- release?.assets,
- release?.attach_files,
- release?.attachFiles,
- release?.files,
- release?.attachments,
- ];
- for (const group of groups) {
- if (!Array.isArray(group)) {
- continue;
- }
- for (const item of group) {
- const name = item?.name || item?.file_name || item?.filename || item?.title;
- if (name) {
- assets.set(name, {
- id: Number.isInteger(item?.id) ? item.id : null,
- name,
- });
- }
- }
- }
- return assets;
-}
-
-function contentTypeFor(name) {
- if (name.endsWith(".json")) return "application/json";
- if (name.endsWith(".zip")) return "application/zip";
- if (name.endsWith(".gz") || name.endsWith(".tgz")) return "application/gzip";
- if (name.endsWith(".dmg")) return "application/x-apple-diskimage";
- if (name.endsWith(".exe") || name.endsWith(".msi")) return "application/octet-stream";
- if (name.endsWith(".deb")) return "application/vnd.debian.binary-package";
- if (name.endsWith(".rpm")) return "application/x-rpm";
- if (name.endsWith(".AppImage")) return "application/octet-stream";
- return "application/octet-stream";
-}
-
-function headerValue(headers, name) {
- const normalizedName = name.toLowerCase();
- const entry = headers.find(([key]) => key.toLowerCase() === normalizedName);
- return entry ? entry[1] : "";
-}
-
-export class AtomGitClient {
- constructor({ apiBase, token, owner, repo }) {
- this.apiBase = apiBase.replace(/\/+$/, "");
- this.token = token;
- this.owner = owner;
- this.repo = repo;
- }
-
- async getRelease(tag) {
- const res = await this.request("GET", `/repos/${this.owner}/${this.repo}/releases/${encodeURIComponent(tag)}`, null, {
- allow404: true,
- });
- if (res.status === 404) {
- return null;
- }
- return parseJsonResponse(res);
- }
-
- async createRelease(payload) {
- const res = await this.request("POST", `/repos/${this.owner}/${this.repo}/releases`, payload, {
- acceptStatuses: [409, 422],
- });
- if (res.status === 409 || res.status === 422) {
- return this.updateRelease(payload.tag_name, payload);
- }
- return parseJsonResponse(res);
- }
-
- async updateRelease(tag, payload) {
- const res = await this.request("PATCH", `/repos/${this.owner}/${this.repo}/releases/${encodeURIComponent(tag)}`, payload);
- return parseJsonResponse(res);
- }
-
- async getUploadTarget(tag, fileName) {
- const params = new URLSearchParams({ file_name: fileName });
- const res = await this.request("GET", `/repos/${this.owner}/${this.repo}/releases/${encodeURIComponent(tag)}/upload_url?${params}`);
- const body = await parseJsonResponse(res);
- if (body && typeof body === "object" && !Array.isArray(body)) {
- console.log(`AtomGit upload_url response keys: ${Object.keys(body).sort().join(", ")}`);
- if (body.headers && typeof body.headers === "object") {
- console.log(`AtomGit upload header keys: ${Object.keys(body.headers).sort().join(", ")}`);
- }
- }
- const uploadUrl = typeof body === "string" ? body : body.url || body.upload_url || body.uploadUrl;
- if (!uploadUrl) {
- throw new Error(`AtomGit upload_url response did not include an upload URL: ${JSON.stringify(body)}`);
- }
- console.log(`AtomGit upload target: ${sanitizeUrlForLog(uploadUrl)}`);
- return {
- url: uploadUrl,
- headers: normalizeUploadHeaders(typeof body === "string" ? null : body.headers),
- };
- }
-
- async deleteAsset(tag, assetId) {
- await this.request(
- "DELETE",
- `/repos/${this.owner}/${this.repo}/releases/${encodeURIComponent(tag)}/attach_files/${assetId}`,
- );
- }
-
- async request(method, path, body = null, requestOptions = {}) {
- const headers = {
- Accept: "application/json",
- Authorization: `Bearer ${this.token}`,
- "X-Api-Version": "2023-02-21",
- };
- const fetchOptions = { method, headers };
- if (body) {
- const cleanBody = Object.fromEntries(Object.entries(body).filter(([, value]) => value !== ""));
- headers["Content-Type"] = "application/json";
- fetchOptions.body = JSON.stringify(cleanBody);
- }
-
- const res = await fetch(`${this.apiBase}${path}`, fetchOptions);
- const acceptedStatus = requestOptions.acceptStatuses?.includes(res.status);
- if (!res.ok && !(requestOptions.allow404 && res.status === 404) && !acceptedStatus) {
- const text = await res.text();
- throw new Error(`AtomGit API ${method} ${path} failed with ${res.status}: ${text}`);
- }
- return res;
- }
-}
-
-async function parseJsonResponse(res) {
- const text = await res.text();
- if (!text.trim()) {
- return {};
- }
- try {
- return JSON.parse(text);
- } catch {
- return text;
- }
-}
-
-function normalizeUploadHeaders(headers) {
- if (!headers || typeof headers !== "object" || Array.isArray(headers)) {
- return [];
- }
- return Object.entries(headers)
- .filter(([key, value]) => key && value !== null && value !== undefined && value !== "")
- .map(([key, value]) => [key, String(value)]);
-}
-
-function sanitizeUrlForLog(value) {
- try {
- const url = new URL(value);
- return `${url.origin}${url.pathname}`;
- } catch {
- return "";
- }
-}
-
-if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
- main().catch((error) => {
- console.error(error);
- process.exit(1);
- });
-}
diff --git a/.github/scripts/sync-atomgit-release.test.mjs b/.github/scripts/sync-atomgit-release.test.mjs
deleted file mode 100644
index 048d3995b5..0000000000
--- a/.github/scripts/sync-atomgit-release.test.mjs
+++ /dev/null
@@ -1,52 +0,0 @@
-import assert from "node:assert/strict";
-import { createServer } from "node:http";
-import test from "node:test";
-
-import { AtomGitClient, atomGitAssets, uploadResultSucceeded } from "./sync-atomgit-release.mjs";
-
-test("uploadResultSucceeded rejects AtomGit callback errors returned with HTTP success", () => {
- assert.equal(uploadResultSucceeded({ status: 0, stdout: "success", stderr: "" }), true);
- assert.equal(
- uploadResultSucceeded({
- status: 0,
- stdout: JSON.stringify({ message: "Fail to read response body", code: "CallBack.0002" }),
- stderr: "",
- }),
- false,
- );
-});
-
-test("atomGitAssets preserves attachment ids required for replacement", () => {
- assert.deepEqual(
- atomGitAssets({ assets: [{ id: 118266, name: "agent-registry.json" }] }),
- new Map([["agent-registry.json", { id: 118266, name: "agent-registry.json" }]]),
- );
-});
-
-test("deleteAsset removes an existing release attachment by id", async (t) => {
- const requests = [];
- const server = createServer((request, response) => {
- requests.push({ method: request.method, url: request.url });
- response.statusCode = 204;
- response.end();
- });
- await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
- t.after(() => new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve()))));
-
- const address = server.address();
- assert.ok(address && typeof address !== "string");
- const client = new AtomGitClient({
- apiBase: `http://127.0.0.1:${address.port}`,
- token: "test-token",
- owner: "t8y2",
- repo: "dbx",
- });
-
- await client.deleteAsset("agents-latest", 118266);
- assert.deepEqual(requests, [
- {
- method: "DELETE",
- url: "/repos/t8y2/dbx/releases/agents-latest/attach_files/118266",
- },
- ]);
-});
diff --git a/.github/workflows/agents-release.yml b/.github/workflows/agents-release.yml
index 3bcd9cfb7f..e0ab737166 100644
--- a/.github/workflows/agents-release.yml
+++ b/.github/workflows/agents-release.yml
@@ -599,40 +599,3 @@ jobs:
args+=(--overwrite-existing)
fi
node .github/scripts/sync-cnb-release.mjs "${args[@]}"
-
- sync-release-to-atomgit:
- name: Sync agents releases to AtomGit
- needs: release
- if: ${{ always() && needs.release.result == 'success' }}
- runs-on: ubuntu-latest
- continue-on-error: true
- strategy:
- fail-fast: false
- matrix:
- tag: ["${{ github.ref_name }}", "agents-latest"]
- steps:
- - uses: actions/checkout@v5
- with:
- fetch-depth: 0
- - name: Sync release assets to AtomGit
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAG_NAME: ${{ matrix.tag }}
- GITHUB_REPOSITORY: ${{ github.repository }}
- ATOMGIT_TOKEN: ${{ secrets.ATOMGIT_TOKEN }}
- ATOMGIT_REPOSITORY: t8y2/dbx
- run: |
- set -euo pipefail
- git fetch origin "refs/tags/${TAG_NAME}:refs/tags/${TAG_NAME}" --force
- git remote add atomgit "https://t8y2:${ATOMGIT_TOKEN}@atomgit.com/t8y2/dbx.git"
- git push atomgit "refs/tags/${TAG_NAME}:refs/tags/${TAG_NAME}" --force
- mkdir -p "$RUNNER_TEMP/github-release" "$RUNNER_TEMP/release-assets"
- gh release view "$TAG_NAME" --repo "$GITHUB_REPOSITORY" \
- --json tagName,name,body,targetCommitish,isPrerelease,isDraft,assets \
- > "$RUNNER_TEMP/github-release/release.json"
- gh release download "$TAG_NAME" --repo "$GITHUB_REPOSITORY" \
- --dir "$RUNNER_TEMP/release-assets" --clobber
- node .github/scripts/sync-atomgit-release.mjs \
- --github-release "$RUNNER_TEMP/github-release/release.json" \
- --assets-dir "$RUNNER_TEMP/release-assets" \
- ${{ matrix.tag == 'agents-latest' && '--replace-assets' || '' }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 7a7159eeaf..b0a23ed1ce 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -423,55 +423,6 @@ jobs:
--github-release "$RUNNER_TEMP/github-release/release.json" \
--assets-dir "$RUNNER_TEMP/release-assets"
- sync-release-to-atomgit:
- name: Sync release to AtomGit
- needs: publish
- runs-on: ubuntu-latest
- steps:
- - name: Checkout repository
- uses: actions/checkout@v5
- with:
- fetch-depth: 0
-
- - name: Ensure AtomGit tag exists
- env:
- TAG_NAME: ${{ github.ref_name }}
- ATOMGIT_TOKEN: ${{ secrets.ATOMGIT_TOKEN }}
- run: |
- set -euo pipefail
- git fetch origin "refs/tags/${TAG_NAME}:refs/tags/${TAG_NAME}" --force
- git remote add atomgit "https://t8y2:${ATOMGIT_TOKEN}@atomgit.com/t8y2/dbx.git"
- git push atomgit "refs/tags/${TAG_NAME}:refs/tags/${TAG_NAME}" --force
-
- - name: Download GitHub release assets
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAG_NAME: ${{ github.ref_name }}
- GITHUB_REPOSITORY: ${{ github.repository }}
- run: |
- set -euo pipefail
- mkdir -p "$RUNNER_TEMP/github-release" "$RUNNER_TEMP/release-assets"
- gh release view "$TAG_NAME" \
- --repo "$GITHUB_REPOSITORY" \
- --json tagName,name,body,targetCommitish,isPrerelease,isDraft,assets \
- > "$RUNNER_TEMP/github-release/release.json"
- gh release download "$TAG_NAME" \
- --repo "$GITHUB_REPOSITORY" \
- --dir "$RUNNER_TEMP/release-assets" \
- --clobber
-
- - name: Sync release assets to AtomGit
- env:
- ATOMGIT_TOKEN: ${{ secrets.ATOMGIT_TOKEN }}
- ATOMGIT_REPOSITORY: "t8y2/dbx"
- # AtomGit throttles concurrent large-asset uploads, which can expire their temporary upload URLs.
- ATOMGIT_UPLOAD_CONCURRENCY: "1"
- run: |
- set -euo pipefail
- node .github/scripts/sync-atomgit-release.mjs \
- --github-release "$RUNNER_TEMP/github-release/release.json" \
- --assets-dir "$RUNNER_TEMP/release-assets"
-
docker:
runs-on: ubuntu-latest
strategy:
diff --git a/.github/workflows/sync-atomgit-release-assets.yml b/.github/workflows/sync-atomgit-release-assets.yml
deleted file mode 100644
index 4c6e87c589..0000000000
--- a/.github/workflows/sync-atomgit-release-assets.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-name: Sync AtomGit Release Assets
-
-on:
- workflow_dispatch:
- inputs:
- tag:
- description: "Release tag to sync"
- required: true
- type: string
-
-permissions:
- contents: read
-
-env:
- ATOMGIT_REPOSITORY: "t8y2/dbx"
-
-jobs:
- sync-release-to-atomgit:
- name: Sync release to AtomGit
- runs-on: ubuntu-latest
- steps:
- - name: Checkout repository
- uses: actions/checkout@v5
- with:
- fetch-depth: 0
-
- - name: Ensure AtomGit tag exists
- env:
- TAG_NAME: ${{ inputs.tag }}
- ATOMGIT_TOKEN: ${{ secrets.ATOMGIT_TOKEN }}
- run: |
- set -euo pipefail
- git fetch origin "refs/tags/${TAG_NAME}:refs/tags/${TAG_NAME}" --force
- git remote add atomgit "https://t8y2:${ATOMGIT_TOKEN}@atomgit.com/t8y2/dbx.git"
- git push atomgit "refs/tags/${TAG_NAME}:refs/tags/${TAG_NAME}" --force
-
- - name: Download GitHub release assets
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAG_NAME: ${{ inputs.tag }}
- GITHUB_REPOSITORY: ${{ github.repository }}
- run: |
- set -euo pipefail
- mkdir -p "$RUNNER_TEMP/github-release" "$RUNNER_TEMP/release-assets"
- gh release view "$TAG_NAME" \
- --repo "$GITHUB_REPOSITORY" \
- --json tagName,name,body,targetCommitish,isPrerelease,isDraft,assets \
- > "$RUNNER_TEMP/github-release/release.json"
- gh release download "$TAG_NAME" \
- --repo "$GITHUB_REPOSITORY" \
- --dir "$RUNNER_TEMP/release-assets" \
- --clobber
-
- - name: Sync release assets to AtomGit
- env:
- ATOMGIT_TOKEN: ${{ secrets.ATOMGIT_TOKEN }}
- ATOMGIT_REPOSITORY: ${{ env.ATOMGIT_REPOSITORY }}
- run: |
- set -euo pipefail
- node .github/scripts/sync-atomgit-release.mjs \
- --github-release "$RUNNER_TEMP/github-release/release.json" \
- --assets-dir "$RUNNER_TEMP/release-assets"
diff --git a/README.md b/README.md
index 6792e61bee..d3262613e0 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,6 @@
-
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 6b7f549c5e..4a4b0745f2 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -45,7 +45,6 @@
-
diff --git a/apps/desktop/src/components/config/DriverStoreDialog.vue b/apps/desktop/src/components/config/DriverStoreDialog.vue
index f35e1a3eca..56c731ed3b 100644
--- a/apps/desktop/src/components/config/DriverStoreDialog.vue
+++ b/apps/desktop/src/components/config/DriverStoreDialog.vue
@@ -332,7 +332,7 @@ async function forceRefresh() {
}
function setUpdateDownloadSource(value: unknown) {
- if (value !== "official" && value !== "cnb" && value !== "atomgit") return;
+ if (value !== "official" && value !== "cnb") return;
if (value === settingsStore.editorSettings.updateDownloadSource) return;
settingsStore.updateEditorSettings({ updateDownloadSource: value });
void forceRefresh().catch(() => undefined);
@@ -1161,7 +1161,6 @@ watch(driverStoreTab, (tab) => {
{{ t("settings.updateDownloadSourceOfficial") }}
{{ t("settings.updateDownloadSourceCnb") }}
- {{ t("settings.updateDownloadSourceAtomgit") }}
diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue
index 357cf839f0..262c399eb4 100644
--- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue
+++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue
@@ -1210,7 +1210,7 @@ function onLocaleChange(v: any) {
}
function onUpdateDownloadSourceChange(v: any) {
- if (v === "official" || v === "cnb" || v === "atomgit") editUpdateDownloadSource.value = v;
+ if (v === "official" || v === "cnb") editUpdateDownloadSource.value = v;
}
function setSidebarObjectDisplay(value: "grouped" | "simple") {
@@ -5007,7 +5007,6 @@ onUnmounted(cleanupPreviewEditor);
{{ t("settings.updateDownloadSourceOfficial") }}
{{ t("settings.updateDownloadSourceCnb") }}
- {{ t("settings.updateDownloadSourceAtomgit") }}
diff --git a/apps/desktop/src/composables/useAppUpdater.ts b/apps/desktop/src/composables/useAppUpdater.ts
index 130a676bcb..385ff7819d 100644
--- a/apps/desktop/src/composables/useAppUpdater.ts
+++ b/apps/desktop/src/composables/useAppUpdater.ts
@@ -17,7 +17,8 @@ export function canDownloadAndInstallUpdate(info: api.UpdateInfo | null, isDeskt
}
export function normalizeUpdateDownloadSource(value: unknown): SettingsUpdateDownloadSource {
- if (value === "atomgit") return "atomgit";
+ // Old persisted AtomGit preferences should retain their mainland mirror behavior.
+ if (value === "atomgit") return "cnb";
return value === "cnb" ? "cnb" : "official";
}
@@ -31,9 +32,6 @@ export function resolveUpdateReleaseUrl(info: api.UpdateInfo | null, source: unk
if (normalizedSource === "cnb" && info?.latest_version) {
return `https://cnb.cool/dbxio.com/dbx/-/releases/tag/${tagVersion(info.latest_version)}`;
}
- if (normalizedSource === "atomgit" && info?.latest_version) {
- return `https://atomgit.com/t8y2/dbx/releases/${tagVersion(info.latest_version)}`;
- }
return info?.release_url || fallbackUrl;
}
diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts
index 748e6ea5e8..e44c098441 100644
--- a/apps/desktop/src/i18n/locales/en.ts
+++ b/apps/desktop/src/i18n/locales/en.ts
@@ -3513,10 +3513,9 @@ export default {
updateNotificationsEnabled: "Enable update reminders",
updateNotificationsEnabledDescription: "When disabled, DBX will not automatically check app or driver updates or show update badges. Manual checks are still available.",
updateDownloadSource: "Update download source",
- updateDownloadSourceDescription: "Choose where app updates, database agents, drivers, and managed JREs are downloaded from. The official source is recommended; CNB or AtomGit can be faster on mainland China networks.",
+ updateDownloadSourceDescription: "Choose where app updates, database agents, drivers, and managed JREs are downloaded from. The official source is recommended; CNB can be faster on mainland China networks.",
updateDownloadSourceOfficial: "Official source (recommended)",
updateDownloadSourceCnb: "CNB",
- updateDownloadSourceAtomgit: "AtomGit",
debugLoggingEnabled: "Enable debug logs",
debugLoggingEnabledDescription: "Record more detailed local user-side diagnostic logs while troubleshooting reports. Disabled by default.",
duckDbWorkerProcessIsolation: "DuckDB process isolation mode (Experimental)",
diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts
index db92f054d0..5e33626512 100644
--- a/apps/desktop/src/i18n/locales/es.ts
+++ b/apps/desktop/src/i18n/locales/es.ts
@@ -3291,10 +3291,9 @@ export default withEnglishFallback({
updateNotificationsEnabled: "Activar recordatorios de actualización",
updateNotificationsEnabledDescription: "Al desactivarlo, DBX no comprobará automáticamente actualizaciones de la app ni de los controladores, ni mostrará indicadores. Las comprobaciones manuales siguen disponibles.",
updateDownloadSource: "Origen de descarga de actualizaciones",
- updateDownloadSourceDescription: "Elige de dónde se descargan los instaladores de actualización. Se recomienda la fuente oficial; CNB o AtomGit pueden ser más rápidos en redes de China continental.",
+ updateDownloadSourceDescription: "Elige de dónde se descargan los instaladores de actualización. Se recomienda la fuente oficial; CNB puede ser más rápido en redes de China continental.",
updateDownloadSourceOfficial: "Fuente oficial (recomendada)",
updateDownloadSourceCnb: "CNB",
- updateDownloadSourceAtomgit: "AtomGit",
debugLoggingEnabled: "Activar logs de depuración",
debugLoggingEnabledDescription: "Registra logs de diagnóstico locales del lado del usuario al investigar reportes. Desactivado por defecto.",
duckDbWorkerProcessIsolation: "Modo de aislamiento de proceso de DuckDB (experimental)",
diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts
index dec4d76de6..d719dd0f72 100644
--- a/apps/desktop/src/i18n/locales/it.ts
+++ b/apps/desktop/src/i18n/locales/it.ts
@@ -3289,10 +3289,9 @@ export default withEnglishFallback({
updateNotificationsEnabled: "Abilita promemoria aggiornamenti",
updateNotificationsEnabledDescription: "Se disattivato, DBX non controllerà automaticamente gli aggiornamenti dell'app o dei driver e non mostrerà badge. I controlli manuali restano disponibili.",
updateDownloadSource: "Fonte download aggiornamenti",
- updateDownloadSourceDescription: "Scegli da dove scaricare gli installer degli aggiornamenti. La fonte ufficiale è consigliata; CNB o AtomGit possono essere più veloci sulle reti della Cina continentale.",
+ updateDownloadSourceDescription: "Scegli da dove scaricare gli installer degli aggiornamenti. La fonte ufficiale è consigliata; CNB può essere più veloce sulle reti della Cina continentale.",
updateDownloadSourceOfficial: "Fonte ufficiale (consigliata)",
updateDownloadSourceCnb: "CNB",
- updateDownloadSourceAtomgit: "AtomGit",
debugLoggingEnabled: "Abilita log di debug",
debugLoggingEnabledDescription: "Registra log diagnostici locali lato utente durante l'analisi delle segnalazioni. Disattivato per impostazione predefinita.",
duckDbWorkerProcessIsolation: "Modalità di isolamento del processo DuckDB (sperimentale)",
diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts
index fd8b7a45fe..e75175851b 100644
--- a/apps/desktop/src/i18n/locales/ja.ts
+++ b/apps/desktop/src/i18n/locales/ja.ts
@@ -3615,10 +3615,9 @@ export default withEnglishFallback({
mcpRefresh: "再確認",
mcpGuide: "MCPガイド",
updateDownloadSource: "アップデートのダウンロード元",
- updateDownloadSourceDescription: "アプリ内アップデートのインストーラーのダウンロード元を選択します。公式ソース推奨。中国本土ではCNBまたはAtomGitの方が高速な場合があります。",
+ updateDownloadSourceDescription: "アプリ内アップデートのインストーラーのダウンロード元を選択します。公式ソース推奨。中国本土ではCNBの方が高速な場合があります。",
updateDownloadSourceOfficial: "公式ソース(推奨)",
updateDownloadSourceCnb: "CNB",
- updateDownloadSourceAtomgit: "AtomGit",
infiniteScroll: "無限スクロール読み込み",
autoCalculateTotalRows: "総行数を自動計算",
autoCalculateTotalRowsDescription: "クエリごとに COUNT(*) を自動実行し、一致する総行数を表示します。大きなクエリを高速に保つため既定はオフです。結果フッターから必要に応じて計算できます。",
diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts
index 61e843c944..dc17668165 100644
--- a/apps/desktop/src/i18n/locales/pt-BR.ts
+++ b/apps/desktop/src/i18n/locales/pt-BR.ts
@@ -3291,10 +3291,9 @@ export default withEnglishFallback({
updateNotificationsEnabled: "Ativar lembretes de atualização",
updateNotificationsEnabledDescription: "Quando desativado, o DBX não verificará automaticamente atualizações do app ou dos drivers nem mostrará indicadores. Verificações manuais continuam disponíveis.",
updateDownloadSource: "Fonte de download de atualização",
- updateDownloadSourceDescription: "Escolha de onde os instaladores de atualização no aplicativo são baixados. A fonte oficial é recomendada; CNB ou AtomGit podem ser mais rápidos em redes da China continental.",
+ updateDownloadSourceDescription: "Escolha de onde os instaladores de atualização no aplicativo são baixados. A fonte oficial é recomendada; CNB pode ser mais rápido em redes da China continental.",
updateDownloadSourceOfficial: "Fonte oficial (recomendada)",
updateDownloadSourceCnb: "CNB",
- updateDownloadSourceAtomgit: "AtomGit",
debugLoggingEnabled: "Ativar logs de depuração",
debugLoggingEnabledDescription: "Registra logs locais de diagnóstico do lado do usuário ao investigar relatos. Desativado por padrão.",
duckDbWorkerProcessIsolation: "Modo de isolamento de processo do DuckDB (experimental)",
diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts
index db0f7a3bba..eb050f6690 100644
--- a/apps/desktop/src/i18n/locales/zh-CN.ts
+++ b/apps/desktop/src/i18n/locales/zh-CN.ts
@@ -3483,10 +3483,9 @@ export default withEnglishFallback({
updateNotificationsEnabled: "启用更新提醒",
updateNotificationsEnabledDescription: "关闭后,DBX 不会自动检查应用和驱动更新,也不会显示更新红点;仍可手动检查更新。",
updateDownloadSource: "更新下载源",
- updateDownloadSourceDescription: "选择应用更新、数据库 Agent、驱动和托管 JRE 的下载来源。官方源为推荐选项,CNB 或 AtomGit 适合国内网络环境。",
+ updateDownloadSourceDescription: "选择应用更新、数据库 Agent、驱动和托管 JRE 的下载来源。官方源为推荐选项,CNB 适合国内网络环境。",
updateDownloadSourceOfficial: "官方源(推荐)",
updateDownloadSourceCnb: "CNB",
- updateDownloadSourceAtomgit: "AtomGit",
debugLoggingEnabled: "启用调试日志",
debugLoggingEnabledDescription: "开启后在本机记录更详细的用户侧诊断日志,反馈问题时可临时开启;默认关闭。",
duckDbWorkerProcessIsolation: "DuckDB 进程隔离模式(实验性)",
diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts
index 1f53c6be7f..790c032552 100644
--- a/apps/desktop/src/i18n/locales/zh-TW.ts
+++ b/apps/desktop/src/i18n/locales/zh-TW.ts
@@ -3473,10 +3473,9 @@ export default withEnglishFallback({
mcpRefresh: "重新檢查",
mcpGuide: "MCP 指南",
updateDownloadSource: "更新下載來源",
- updateDownloadSourceDescription: "選擇應用程式內更新安裝程式的下載來源。建議使用官方來源;CNB 或 AtomGit 在中國大陸網路環境下可能更快。",
+ updateDownloadSourceDescription: "選擇應用程式內更新安裝程式的下載來源。建議使用官方來源;CNB 在中國大陸網路環境下可能更快。",
updateDownloadSourceOfficial: "官方來源(建議)",
updateDownloadSourceCnb: "CNB",
- updateDownloadSourceAtomgit: "AtomGit",
exportSection: "匯出",
exportBatchSize: "匯出批次大小",
dateTimeSection: "日期與時間",
diff --git a/apps/desktop/src/lib/backend/tauri.ts b/apps/desktop/src/lib/backend/tauri.ts
index 83018f7706..614089e0fb 100644
--- a/apps/desktop/src/lib/backend/tauri.ts
+++ b/apps/desktop/src/lib/backend/tauri.ts
@@ -1406,7 +1406,7 @@ export interface UpdateInfo {
release_notes: string;
}
-export type UpdateDownloadSource = "official" | "cnb" | "atomgit";
+export type UpdateDownloadSource = "official" | "cnb";
export interface UpdateDownloadProgress {
downloaded: number;
diff --git a/apps/desktop/src/stores/__tests__/settingsStore.spec.ts b/apps/desktop/src/stores/__tests__/settingsStore.spec.ts
index d2f9567a8a..68ed00af72 100644
--- a/apps/desktop/src/stores/__tests__/settingsStore.spec.ts
+++ b/apps/desktop/src/stores/__tests__/settingsStore.spec.ts
@@ -69,9 +69,9 @@ describe("normalizeEditorSettings", () => {
expect(normalizeEditorSettings({ restoreOpenTabsOnLaunch: true } as any).openTabsRestoreMode).toBe("all");
});
- it("preserves mirror update download sources and rejects invalid values", () => {
+ it("preserves CNB, migrates AtomGit to CNB, and rejects invalid values", () => {
expect(normalizeEditorSettings({ updateDownloadSource: "cnb" }).updateDownloadSource).toBe("cnb");
- expect(normalizeEditorSettings({ updateDownloadSource: "atomgit" }).updateDownloadSource).toBe("atomgit");
+ expect(normalizeEditorSettings({ updateDownloadSource: "atomgit" as any }).updateDownloadSource).toBe("cnb");
expect(normalizeEditorSettings({ updateDownloadSource: "mirror" as any }).updateDownloadSource).toBe("official");
});
diff --git a/apps/desktop/src/stores/settingsStore.ts b/apps/desktop/src/stores/settingsStore.ts
index b78e710bb3..8bfa876336 100644
--- a/apps/desktop/src/stores/settingsStore.ts
+++ b/apps/desktop/src/stores/settingsStore.ts
@@ -38,7 +38,7 @@ export type DesktopIconTheme = "default" | "black";
export type InterfaceLayout = "separated" | "classic";
-export type UpdateDownloadSource = "official" | "cnb" | "atomgit";
+export type UpdateDownloadSource = "official" | "cnb";
export type SqlSemanticDiagnosticsMode = "auto" | "enabled" | "disabled";
export type OpenTabsRestoreMode = "all" | "pinned" | "none";
@@ -626,7 +626,8 @@ function normalizeTableFontSize(value: unknown): number {
}
function normalizeUpdateDownloadSource(value: unknown): UpdateDownloadSource {
- if (value === "atomgit") return "atomgit";
+ // Preserve the intent of users who previously selected the mainland-China mirror.
+ if (value === "atomgit") return "cnb";
return value === "cnb" ? "cnb" : DEFAULT_EDITOR_SETTINGS.updateDownloadSource;
}
@@ -887,7 +888,12 @@ export const useSettingsStore = defineStore("settings", () => {
if (isEditorSettingsLoaded.value) return;
const saved = await api.loadEditorSettings().catch(() => null);
if (saved && typeof saved === "object" && !Array.isArray(saved)) {
- editorSettings.value = normalizeEditorSettings(saved as Partial);
+ const normalized = normalizeEditorSettings(saved as Partial);
+ editorSettings.value = normalized;
+ if ((saved as { updateDownloadSource?: unknown }).updateDownloadSource === "atomgit") {
+ // Persist the channel migration so the removed source cannot reappear in older settings data.
+ await api.saveEditorSettings(normalized).catch(() => {});
+ }
isEditorSettingsLoaded.value = true;
return;
}
diff --git a/crates/dbx-core/src/lib.rs b/crates/dbx-core/src/lib.rs
index e84039bca6..15da4a7c97 100644
--- a/crates/dbx-core/src/lib.rs
+++ b/crates/dbx-core/src/lib.rs
@@ -74,7 +74,6 @@ pub mod xlsx_export;
pub const R2_CDN_BASE: &str = "https://dl.dbxio.com/";
pub const GITHUB_RELEASE_DOWNLOAD_PREFIX: &str = "https://github.com/t8y2/dbx/releases/download/";
pub const CNB_RELEASE_DOWNLOAD_PREFIX: &str = "https://cnb.cool/dbxio.com/dbx/-/releases/download/";
-pub const ATOMGIT_RELEASE_API_PREFIX: &str = "https://api.atomgit.com/api/v5/repos/t8y2/dbx/releases/";
#[derive(Clone, Copy, Debug, Default, serde::Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "lowercase")]
@@ -82,7 +81,6 @@ pub enum DownloadSource {
#[default]
Official,
Cnb,
- Atomgit,
}
impl DownloadSource {
@@ -94,11 +92,6 @@ impl DownloadSource {
r2_path,
rewrite_github_release_url(github_url, CNB_RELEASE_DOWNLOAD_PREFIX)?,
)),
- Self::Atomgit => Ok(mirror_download_candidate_urls(
- github_url,
- r2_path,
- rewrite_github_release_url_for_atomgit(github_url)?,
- )),
}
}
}
@@ -122,20 +115,6 @@ fn rewrite_github_release_url(url: &str, target_prefix: &str) -> Result Result {
- if url.starts_with(ATOMGIT_RELEASE_API_PREFIX) {
- return Ok(url.to_string());
- }
- let path = url
- .strip_prefix(GITHUB_RELEASE_DOWNLOAD_PREFIX)
- .ok_or_else(|| format!("Unsupported DBX release download URL: {url}"))?;
- let (tag, file_name) = path
- .split_once('/')
- .filter(|(_, file_name)| !file_name.contains('/'))
- .ok_or_else(|| format!("Unsupported DBX release asset path: {path}"))?;
- Ok(format!("{ATOMGIT_RELEASE_API_PREFIX}{tag}/attach_files/{file_name}/download"))
-}
-
pub fn download_candidate_urls(github_url: &str, r2_path: &str) -> Vec {
vec![format!("{R2_CDN_BASE}{r2_path}"), github_url.to_string()]
}
@@ -206,24 +185,5 @@ mod tests {
"https://cnb.cool/dbxio.com/dbx/-/releases/download/agents-latest/agent-registry.json",
]
);
- assert_eq!(
- DownloadSource::Atomgit.download_candidate_urls(github_url, "agents/agent-registry.json").unwrap(),
- vec![
- "https://dl.dbxio.com/agents/agent-registry.json",
- "https://api.atomgit.com/api/v5/repos/t8y2/dbx/releases/agents-latest/attach_files/agent-registry.json/download",
- ]
- );
- }
-
- #[test]
- fn atomgit_versioned_assets_use_attachment_download_api_first() {
- let github_url = "https://github.com/t8y2/dbx/releases/download/agents-v0.2.55/dbx-agent-h2.jar";
- assert_eq!(
- DownloadSource::Atomgit.download_candidate_urls(github_url, "agents/dbx-agent-h2.jar").unwrap(),
- vec![
- "https://api.atomgit.com/api/v5/repos/t8y2/dbx/releases/agents-v0.2.55/attach_files/dbx-agent-h2.jar/download",
- "https://dl.dbxio.com/agents/dbx-agent-h2.jar",
- ]
- );
}
}
diff --git a/docs/app/[lang]/drivers/DriversClient.tsx b/docs/app/[lang]/drivers/DriversClient.tsx
index 07545968ec..5612da53b7 100644
--- a/docs/app/[lang]/drivers/DriversClient.tsx
+++ b/docs/app/[lang]/drivers/DriversClient.tsx
@@ -37,12 +37,11 @@ const i18n = {
showing: "Showing",
of: "of",
clearSearch: "Clear search",
- mirrorHint: "CNB and AtomGit mirrors are available for GitHub release assets on mainland China networks.",
+ mirrorHint: "The CNB mirror is available for GitHub release assets on mainland China networks.",
downloadSources: "Download source",
sources: {
github: "GitHub",
cnb: "CNB",
- atomgit: "AtomGit",
official: "Official",
},
downloadHint: "For air-gapped environments: download the bundle for your platform on an internet-connected machine, then transfer it to the offline machine and import it in DBX from Settings > Driver Manager. Use the driver and JRE tabs only when you need individual artifacts.",
@@ -77,12 +76,11 @@ const i18n = {
showing: "显示",
of: "/",
clearSearch: "清空搜索",
- mirrorHint: "中国大陆网络可选择 CNB 或 AtomGit 镜像下载,GitHub Release 资源保持同步。",
+ mirrorHint: "中国大陆网络可选择 CNB 镜像下载,GitHub Release 资源保持同步。",
downloadSources: "下载来源",
sources: {
github: "GitHub",
cnb: "CNB",
- atomgit: "AtomGit",
official: "官方下载",
},
downloadHint: "内网环境使用说明:在有网的电脑上下载对应平台的整包,然后传输到内网机器,在 DBX 的“设置 > 驱动管理”中导入。只有需要单个产物时再使用驱动和 JRE 标签页。",
@@ -120,7 +118,7 @@ function DownloadLinks({ url, t }: { url: string; t: DriverTranslations }) {
key={link.source}
href={link.url}
download
- className={`landing-nav-link inline-flex h-8 items-center gap-1 whitespace-nowrap rounded-[6px] border px-2 text-xs font-medium transition-colors hover:border-landing-blue ${link.source === "cnb" || link.source === "atomgit" ? "border-landing-blue/45 bg-landing-blue/10 text-landing-sky" : "border-landing-line"}`}
+ className={`landing-nav-link inline-flex h-8 items-center gap-1 whitespace-nowrap rounded-[6px] border px-2 text-xs font-medium transition-colors hover:border-landing-blue ${link.source === "cnb" ? "border-landing-blue/45 bg-landing-blue/10 text-landing-sky" : "border-landing-line"}`}
aria-label={`${t.download}: ${t.sources[link.source as DownloadSource]}`}
>
diff --git a/docs/lib/agentRegistry.test.ts b/docs/lib/agentRegistry.test.ts
index 9370d41ff4..7231f2655f 100644
--- a/docs/lib/agentRegistry.test.ts
+++ b/docs/lib/agentRegistry.test.ts
@@ -16,11 +16,10 @@ test("offline download catalog includes the JDBC plugin ZIP", () => {
});
});
-test("release assets expose GitHub, CNB, and AtomGit download links", () => {
+test("release assets expose GitHub and CNB download links", () => {
assert.deepEqual(downloadLinksFor("https://github.com/t8y2/dbx/releases/download/agents-latest/dbx-agents-offline-macos-aarch64.zip"), [
{ source: "github", url: "https://github.com/t8y2/dbx/releases/download/agents-latest/dbx-agents-offline-macos-aarch64.zip" },
{ source: "cnb", url: "https://cnb.cool/dbxio.com/dbx/-/releases/download/agents-latest/dbx-agents-offline-macos-aarch64.zip" },
- { source: "atomgit", url: "https://atomgit.com/t8y2/dbx/releases/download/agents-latest/dbx-agents-offline-macos-aarch64.zip" },
]);
});
@@ -30,7 +29,7 @@ test("non-release assets retain their official download link", () => {
]);
});
-test("catalog falls back from GitHub to CNB and then AtomGit", async () => {
+test("catalog falls back from GitHub to CNB", async () => {
const requestedUrls: string[] = [];
vi.stubGlobal(
"fetch",
@@ -38,14 +37,17 @@ test("catalog falls back from GitHub to CNB and then AtomGit", async () => {
const url = String(input);
requestedUrls.push(url);
if (url.includes("api.github.com")) return new Response("rate limited", { status: 403 });
- if (url.includes("cnb.cool")) throw new TypeError("CORS blocked");
return Response.json({
- tag_name: "agents-latest",
- assets: [
- { name: "dbx-agent-access.jar", type: "attach" },
- { name: "dbx-jre-21-macos-aarch64.tar.gz", type: "attach" },
- { name: "dbx-agents-offline-macos-aarch64.zip", type: "attach" },
- ],
+ drivers: {
+ access: { jar: { url: "https://dl.dbxio.com/agents/dbx-agent-access.jar", size: 1 } },
+ },
+ jres: {
+ "21": {
+ platforms: {
+ "macos-aarch64": { url: "https://dl.dbxio.com/jres/dbx-jre-21-macos-aarch64.tar.gz", size: 1 },
+ },
+ },
+ },
});
}),
);
@@ -55,7 +57,6 @@ test("catalog falls back from GitHub to CNB and then AtomGit", async () => {
assert.deepEqual(requestedUrls, [
"https://api.github.com/repos/t8y2/dbx/releases/tags/agents-latest",
"https://cnb.cool/dbxio.com/dbx/-/releases/download/agents-latest/agent-registry.json",
- "https://api.atomgit.com/api/v5/repos/t8y2/dbx/releases/agents-latest",
]);
assert.equal(catalog?.drivers[0]?.key, "access");
assert.equal(catalog?.jres[0]?.platformKey, "macos-aarch64");
diff --git a/docs/lib/agentRegistry.ts b/docs/lib/agentRegistry.ts
index 78fcf01bde..32101aff8e 100644
--- a/docs/lib/agentRegistry.ts
+++ b/docs/lib/agentRegistry.ts
@@ -5,7 +5,7 @@ export interface ArtifactInfo {
size: number;
}
-export type DownloadSource = "github" | "cnb" | "atomgit" | "official";
+export type DownloadSource = "github" | "cnb" | "official";
export interface DownloadLink {
source: DownloadSource;
@@ -37,11 +37,6 @@ interface AgentRegistry {
drivers?: Record;
}
-interface AtomGitRelease {
- tag_name?: string;
- assets?: Array<{ name?: string; type?: string }>;
-}
-
export interface OfflineBundleEntry {
platformKey: string;
platformLabel: string;
@@ -93,11 +88,9 @@ export interface AgentDownloadCatalog {
const AGENTS_LATEST_RELEASE_API_URL = "https://api.github.com/repos/t8y2/dbx/releases/tags/agents-latest";
const CNB_AGENT_REGISTRY_URL = "https://cnb.cool/dbxio.com/dbx/-/releases/download/agents-latest/agent-registry.json";
-const ATOMGIT_LATEST_RELEASE_API_URL = "https://api.atomgit.com/api/v5/repos/t8y2/dbx/releases/agents-latest";
const JDBC_PLUGIN_DOWNLOAD_URL = "https://dl.dbxio.com/releases/latest/dbx-jdbc-plugin-latest.zip";
const GITHUB_RELEASE_DOWNLOAD_PREFIX = "https://github.com/t8y2/dbx/releases/download/";
const CNB_RELEASE_DOWNLOAD_PREFIX = "https://cnb.cool/dbxio.com/dbx/-/releases/download/";
-const ATOMGIT_RELEASE_DOWNLOAD_PREFIX = "https://atomgit.com/t8y2/dbx/releases/download/";
const MIN_APP_VERSION = "0.6.0";
const driverVersionMap = driverVersions as Record;
const nativeDriverKeys = new Set(["oracle", "xugu"]);
@@ -213,13 +206,6 @@ function registryReleaseAssets(registry: AgentRegistry): GitHubReleaseAsset[] {
return Array.from(assets.values());
}
-function atomGitReleaseAssets(release: AtomGitRelease): GitHubReleaseAsset[] {
- const tag = release.tag_name || "agents-latest";
- return (release.assets ?? [])
- .filter((asset): asset is { name: string; type?: string } => Boolean(asset.name) && asset.type !== "source")
- .map((asset) => githubReleaseAsset(asset.name, 0, tag));
-}
-
function hasDownloadAssets(catalog: AgentDownloadCatalog): boolean {
return catalog.bundles.length > 0 || catalog.drivers.length > 0 || catalog.jres.length > 0 || catalog.nativeAgents.length > 0;
}
@@ -237,7 +223,6 @@ export function downloadLinksFor(url: string): DownloadLink[] {
return [
{ source: "github", url },
{ source: "cnb", url: `${CNB_RELEASE_DOWNLOAD_PREFIX}${releasePath}` },
- { source: "atomgit", url: `${ATOMGIT_RELEASE_DOWNLOAD_PREFIX}${releasePath}` },
];
}
@@ -249,7 +234,6 @@ export async function fetchAgentDownloadCatalog(): Promise Promise> = [
async () => (await fetchJson(AGENTS_LATEST_RELEASE_API_URL, { Accept: "application/vnd.github+json" })).assets ?? [],
async () => registryReleaseAssets(await fetchJson(CNB_AGENT_REGISTRY_URL)),
- async () => atomGitReleaseAssets(await fetchJson(ATOMGIT_LATEST_RELEASE_API_URL, { Accept: "application/json" })),
];
for (const loadAssets of loaders) {
diff --git a/packages/app-tests/appUpdater.test.ts b/packages/app-tests/appUpdater.test.ts
index 74f25dea3a..767fb79ef8 100644
--- a/packages/app-tests/appUpdater.test.ts
+++ b/packages/app-tests/appUpdater.test.ts
@@ -34,7 +34,7 @@ test("blocks in-app update installation outside desktop runtime or without an up
test("normalizes update download source", () => {
assert.equal(normalizeUpdateDownloadSource("official"), "official");
assert.equal(normalizeUpdateDownloadSource("cnb"), "cnb");
- assert.equal(normalizeUpdateDownloadSource("atomgit"), "atomgit");
+ assert.equal(normalizeUpdateDownloadSource("atomgit"), "cnb");
assert.equal(normalizeUpdateDownloadSource("unknown"), "official");
});
@@ -46,7 +46,6 @@ test("normalizes release tag versions", () => {
test("resolves release page URL from update download source", () => {
const fallbackUrl = "https://github.com/t8y2/dbx/releases/latest";
assert.equal(resolveUpdateReleaseUrl(updateInfo({ latest_version: "0.5.39" }), "cnb", fallbackUrl), "https://cnb.cool/dbxio.com/dbx/-/releases/tag/v0.5.39");
- assert.equal(resolveUpdateReleaseUrl(updateInfo({ latest_version: "0.5.44" }), "atomgit", fallbackUrl), "https://atomgit.com/t8y2/dbx/releases/v0.5.44");
assert.equal(resolveUpdateReleaseUrl(updateInfo({ release_url: "https://github.com/t8y2/dbx/releases/tag/v0.5.39" }), "official", fallbackUrl), "https://github.com/t8y2/dbx/releases/tag/v0.5.39");
assert.equal(resolveUpdateReleaseUrl(null, "cnb", fallbackUrl), fallbackUrl);
});
diff --git a/src-tauri/src/commands/update.rs b/src-tauri/src/commands/update.rs
index 223394daa0..36308b6889 100644
--- a/src-tauri/src/commands/update.rs
+++ b/src-tauri/src/commands/update.rs
@@ -15,7 +15,6 @@ const OFFICIAL_UPDATE_ENDPOINTS: [&str; 2] = [
const R2_LATEST_RELEASE_DOWNLOAD_PREFIX: &str = "https://dl.dbxio.com/releases/latest/";
const CNB_RELEASE_DOWNLOAD_PREFIX: &str = "https://cnb.cool/dbxio.com/dbx/-/releases/download/";
const GITHUB_RELEASE_DOWNLOAD_PREFIX: &str = "https://github.com/t8y2/dbx/releases/download/";
-const ATOMGIT_RELEASE_DOWNLOAD_PREFIX: &str = "https://atomgit.com/t8y2/dbx/releases/download/";
const UPDATE_DOWNLOAD_PROGRESS_EVENT: &str = "update-download-progress";
#[derive(Debug, Deserialize)]
@@ -23,7 +22,6 @@ const UPDATE_DOWNLOAD_PROGRESS_EVENT: &str = "update-download-progress";
pub enum UpdateDownloadSource {
Official,
Cnb,
- Atomgit,
}
#[derive(Clone, Debug, Serialize)]
@@ -37,7 +35,6 @@ impl UpdateDownloadSource {
match self {
Self::Official => "official",
Self::Cnb => "cnb",
- Self::Atomgit => "atomgit",
}
}
@@ -52,14 +49,6 @@ impl UpdateDownloadSource {
OFFICIAL_UPDATE_ENDPOINTS[0].to_string(),
])
}
- Self::Atomgit => {
- let version =
- latest_version.ok_or_else(|| "Latest version is required for AtomGit updates.".to_string())?;
- Ok(vec![
- format!("{ATOMGIT_RELEASE_DOWNLOAD_PREFIX}{}/latest.json", tag_version(version)),
- OFFICIAL_UPDATE_ENDPOINTS[0].to_string(),
- ])
- }
}
}
@@ -81,7 +70,6 @@ impl UpdateDownloadSource {
fn mirror_download_prefix(&self) -> Option<&'static str> {
match self {
Self::Cnb => Some(CNB_RELEASE_DOWNLOAD_PREFIX),
- Self::Atomgit => Some(ATOMGIT_RELEASE_DOWNLOAD_PREFIX),
Self::Official => None,
}
}
@@ -207,8 +195,8 @@ async fn update_url_is_available(url: &str) -> bool {
#[cfg(test)]
mod tests {
use super::{
- tag_version, UpdateDownloadSource, ATOMGIT_RELEASE_DOWNLOAD_PREFIX, CNB_RELEASE_DOWNLOAD_PREFIX,
- OFFICIAL_UPDATE_ENDPOINTS, R2_LATEST_RELEASE_DOWNLOAD_PREFIX,
+ tag_version, UpdateDownloadSource, CNB_RELEASE_DOWNLOAD_PREFIX, OFFICIAL_UPDATE_ENDPOINTS,
+ R2_LATEST_RELEASE_DOWNLOAD_PREFIX,
};
#[test]
@@ -232,18 +220,6 @@ mod tests {
);
}
- #[test]
- fn builds_atomgit_update_endpoint_for_tag() {
- let endpoints = UpdateDownloadSource::Atomgit.endpoints(Some("0.5.44")).unwrap();
- assert_eq!(
- endpoints,
- vec![
- format!("{ATOMGIT_RELEASE_DOWNLOAD_PREFIX}v0.5.44/latest.json"),
- OFFICIAL_UPDATE_ENDPOINTS[0].to_string(),
- ]
- );
- }
-
#[test]
fn rewrites_github_asset_url_to_cnb() {
let download_url = UpdateDownloadSource::Cnb
@@ -261,27 +237,10 @@ mod tests {
assert_eq!(download_url, None);
}
- #[test]
- fn rewrites_github_asset_url_to_atomgit() {
- let download_url = UpdateDownloadSource::Atomgit
- .rewrite_download_url("https://github.com/t8y2/dbx/releases/download/v0.5.44/DBX_0.5.44_x64.dmg")
- .unwrap()
- .unwrap();
- assert_eq!(download_url, "https://atomgit.com/t8y2/dbx/releases/download/v0.5.44/DBX_0.5.44_x64.dmg");
- }
-
- #[test]
- fn accepts_existing_atomgit_asset_url() {
- let download_url = UpdateDownloadSource::Atomgit
- .rewrite_download_url("https://atomgit.com/t8y2/dbx/releases/download/v0.5.44/DBX_0.5.44_x64.dmg")
- .unwrap();
- assert_eq!(download_url, None);
- }
-
#[test]
fn builds_r2_fallback_for_mirror_asset() {
- let fallback = UpdateDownloadSource::Atomgit
- .r2_fallback_url("https://atomgit.com/t8y2/dbx/releases/download/v0.5.44/DBX_0.5.44_x64.dmg")
+ let fallback = UpdateDownloadSource::Cnb
+ .r2_fallback_url("https://cnb.cool/dbxio.com/dbx/-/releases/download/v0.5.44/DBX_0.5.44_x64.dmg")
.unwrap();
assert_eq!(fallback, Some(format!("{R2_LATEST_RELEASE_DOWNLOAD_PREFIX}DBX_0.5.44_x64.dmg")));
}