Skip to content

Commit e30396e

Browse files
heqikaicursoragent
andcommitted
fix(desktop): bundle Node 22 for CodeGraph and update dmg download link
Embed Node 22.19 (node:sqlite) in desktop staging with version stamp invalidation; refresh Baidu Netdisk URL and Gatekeeper workaround in README. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 544488c commit e30396e

4 files changed

Lines changed: 28 additions & 9 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,15 @@ Roadmap and deferred work: [docs/codedelta/ROADMAP.md](docs/codedelta/ROADMAP.md
211211

212212
## Desktop (macOS)
213213

214-
CodeDelta ships a **macOS desktop app** ([`apps/desktop/`](apps/desktop/)) — a Tauri 2 shell that bundles Node 20 and the API server. End users do not need a separate Node install.
214+
CodeDelta ships a **macOS desktop app** ([`apps/desktop/`](apps/desktop/)) — a Tauri 2 shell that bundles Node 22 (for CodeGraph’s `node:sqlite`) and the API server. End users do not need a separate Node install.
215215

216216
### Download (Apple Silicon)
217217

218218
Pre-built **unsigned** `.dmg` (arm64 / M1–M4):
219219

220-
- [百度网盘](https://pan.baidu.com/s/16DL3nvpFA9FR6UsskqoFyA?pwd=frog) · 提取码: `frog`
220+
- [百度网盘](https://pan.baidu.com/s/1FQxOgNHyvU1Y5EB34RpogQ?pwd=frog) · 提取码: `frog`
221221

222-
Install: open the dmg → drag **CodeDelta** to Applications. If macOS blocks launch, right-click the app → **Open**. Requires **git** on `PATH`.
222+
Install: open the dmg → drag **CodeDelta** to Applications. If macOS blocks launch, right-click the app → **Open**, or run `xattr -cr /Applications/CodeDelta.app` (common after Baidu Netdisk download). Requires **git** on `PATH`.
223223

224224
**Runtime data:** `~/Library/Application Support/CodeDelta` (repos, snapshots, settings).
225225

docs/codedelta/ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ Not implemented yet (planned):
126126

127127
- [x] `@codedelta/server` static UI hosting + `CODEDELTA_MONOREPO_ROOT`
128128
- [x] Web boot screen (`/api/health` polling, git banner)
129-
- [x] `scripts/desktop-stage.mjs` — embedded Node 20 + production runtime
129+
- [x] `scripts/desktop-stage.mjs` — embedded Node 22+ (`node:sqlite`) + production runtime
130130
- [x] `apps/desktop` Tauri 2 shell (spawn/kill API, single instance, `127.0.0.1:3847`)
131131
- [x] Import page recent repositories
132132
- [x] `npm run dev:desktop` / `stage:desktop` / `build:desktop`

packages/codedelta-server/src/services/compare.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export async function compareCommits(
7070
}
7171
if (err instanceof SnapshotEmptyError) {
7272
throw new CompareError(
73-
'Repository produced an empty structural graph. This can happen when fallback extraction cannot parse the language yet. Please retry compare once; if it persists, use TS/JS repo or enable full CodeGraph extraction support for this language.',
73+
'Repository produced an empty structural graph. CodeGraph indexing did not run or found no symbols, and the TS/JS fallback found no .ts/.js files. Retry once; on desktop ensure the bundled Node is 22.5+ (rebuild with npm run build:desktop). Python and other languages need CodeGraph, not fallback.',
7474
422,
7575
);
7676
}

scripts/desktop-stage.mjs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ const APP_ROOT = path.join(RUNTIME_ROOT, 'app');
1818
const WEB_DIST = path.join(RUNTIME_ROOT, 'web-dist');
1919
const NODE_ROOT = path.join(RUNTIME_ROOT, 'node');
2020

21-
const NODE_VERSION = process.env.CODEDELTA_NODE_VERSION ?? '20.19.2';
21+
// CodeGraph requires node:sqlite (Node.js 22.5+). Keep in sync with scripts/build-bundle.sh LTS line.
22+
const NODE_VERSION = process.env.CODEDELTA_NODE_VERSION ?? '22.19.0';
2223
const CODEDELTA_PACKAGES = [
2324
'codedelta-types',
2425
'codedelta-repo-manager',
@@ -97,10 +98,16 @@ async function ensureNodeBinary() {
9798
const tarName = `${base}.tar.gz`;
9899
const url = `https://nodejs.org/dist/v${NODE_VERSION}/${tarName}`;
99100
const nodeBin = path.join(NODE_ROOT, 'bin', 'node');
100-
if (fs.existsSync(nodeBin)) {
101-
log(`Reusing embedded Node at ${nodeBin}`);
101+
const versionStamp = path.join(NODE_ROOT, '.node-version');
102+
const stamped =
103+
fs.existsSync(versionStamp) && fs.readFileSync(versionStamp, 'utf8').trim() === NODE_VERSION;
104+
if (fs.existsSync(nodeBin) && stamped) {
105+
log(`Reusing embedded Node ${NODE_VERSION} at ${nodeBin}`);
102106
return nodeBin;
103107
}
108+
if (fs.existsSync(nodeBin)) {
109+
log(`Embedded Node version changed — re-downloading ${NODE_VERSION}`);
110+
}
104111
rmrf(NODE_ROOT);
105112
const tmpTar = path.join(RUNTIME_ROOT, tarName);
106113
fs.mkdirSync(RUNTIME_ROOT, { recursive: true });
@@ -112,6 +119,7 @@ async function ensureNodeBinary() {
112119
if (!fs.existsSync(nodeBin)) {
113120
throw new Error(`Node binary missing after extract: ${nodeBin}`);
114121
}
122+
fs.writeFileSync(versionStamp, `${NODE_VERSION}\n`);
115123
return nodeBin;
116124
}
117125

@@ -210,7 +218,18 @@ function sleep(ms) {
210218
}
211219

212220
function smokeTest(nodeBin) {
213-
log('Smoke test: CodeGraph load + health endpoint');
221+
log('Smoke test: node:sqlite + CodeGraph load + health endpoint');
222+
const sqliteCheck = spawnSync(
223+
nodeBin,
224+
['-e', "const { DatabaseSync } = require('node:sqlite'); new DatabaseSync(':memory:').close()"],
225+
{ cwd: APP_ROOT, stdio: 'inherit' },
226+
);
227+
if (sqliteCheck.status !== 0) {
228+
throw new Error(
229+
'Embedded Node lacks node:sqlite (need Node 22.5+). Bump CODEDELTA_NODE_VERSION in desktop-stage.mjs',
230+
);
231+
}
232+
214233
const cgCheck = spawnSync(
215234
nodeBin,
216235
['-e', "const m=require('./dist/index.js'); if(!m.default&&!m.CodeGraph) process.exit(1)"],

0 commit comments

Comments
 (0)