fix: bundle gitnexus-shared into CLI dist (#613)

* fix(ci): build gitnexus-shared before publish, use CHANGELOG for release notes

The publish workflow was missing the gitnexus-shared build step that
the setup-gitnexus composite action provides. Since PR #536 unified
the ingestion pipeline, gitnexus imports types from gitnexus-shared,
so it must be built first.

Also replaces generate_release_notes with CHANGELOG.md extraction so
GitHub Releases use the reviewed changelog entry instead of a flat
PR title list.

Made-with: Cursor

* fix: bundle gitnexus-shared into CLI dist to fix module resolution

gitnexus-shared was declared as a file: dependency but never published
to npm, causing ERR_MODULE_NOT_FOUND for users installing gitnexus
globally. The build script now copies gitnexus-shared/dist into
dist/_shared/ and rewrites bare specifiers to relative paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: move gitnexus-shared to devDependencies, use tsc for prepare

gitnexus-shared must remain available for tsc to resolve imports during
development/CI, but is not needed at runtime since it's bundled into
dist/_shared/. Moving it to devDependencies keeps it out of production
installs while allowing compilation. The prepare script now runs plain
tsc (no shared bundling needed for local dev).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Abhigyan Patwari <abhigyan@Abhigyans-MacBook-Air.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Abhigyan Patwari 2026-04-01 17:04:39 +05:30 committed by GitHub
parent 39322e37df
commit 71255a096c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 90 additions and 5 deletions

View file

@ -67,7 +67,22 @@ jobs:
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Extract release notes from CHANGELOG
id: changelog
shell: bash
run: |
VERSION="${GITHUB_REF#refs/tags/v}"
NOTES=$(awk "/^## \\[$VERSION\\]/{found=1; next} /^## \\[/{if(found) exit} found" gitnexus/CHANGELOG.md)
if [ -z "$NOTES" ]; then
echo "::warning::No CHANGELOG entry found for v$VERSION, falling back to auto-generated notes"
echo "fallback=true" >> "$GITHUB_OUTPUT"
else
echo "$NOTES" > /tmp/release-notes.md
echo "fallback=false" >> "$GITHUB_OUTPUT"
fi
- name: Create GitHub Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
with:
generate_release_notes: true
body_path: ${{ steps.changelog.outputs.fallback == 'false' && '/tmp/release-notes.md' || '' }}
generate_release_notes: ${{ steps.changelog.outputs.fallback == 'true' }}

View file

@ -16,7 +16,6 @@
"commander": "^12.0.0",
"cors": "^2.8.5",
"express": "^4.19.2",
"gitnexus-shared": "file:../gitnexus-shared",
"glob": "^11.0.0",
"graphology": "^0.25.4",
"graphology-indices": "^0.17.0",
@ -50,6 +49,7 @@
"@types/node": "^20.0.0",
"@types/uuid": "^10.0.0",
"@vitest/coverage-v8": "^4.0.18",
"gitnexus-shared": "file:../gitnexus-shared",
"tsx": "^4.0.0",
"typescript": "^5.4.5",
"vitest": "^4.0.18"
@ -65,6 +65,7 @@
},
"../gitnexus-shared": {
"version": "1.0.0",
"dev": true,
"devDependencies": {
"typescript": "^6.0.2"
}

View file

@ -38,7 +38,7 @@
"vendor"
],
"scripts": {
"build": "tsc",
"build": "node scripts/build.js",
"serve": "tsx src/cli/index.ts serve",
"dev": "tsx watch src/cli/index.ts",
"test": "vitest run",
@ -46,11 +46,10 @@
"test:integration": "vitest run test/integration",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"prepare": "npm run build",
"prepare": "tsc",
"prepack": "npm run build && chmod +x dist/cli/index.js"
},
"dependencies": {
"gitnexus-shared": "file:../gitnexus-shared",
"@huggingface/transformers": "^3.0.0",
"@ladybugdb/core": "^0.15.2",
"@modelcontextprotocol/sdk": "^1.0.0",
@ -87,6 +86,7 @@
"tree-sitter-swift": "^0.6.0"
},
"devDependencies": {
"gitnexus-shared": "file:../gitnexus-shared",
"@types/cli-progress": "^3.11.6",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",

69
gitnexus/scripts/build.js Normal file
View file

@ -0,0 +1,69 @@
#!/usr/bin/env node
/**
* Build script that compiles gitnexus and inlines gitnexus-shared into the dist.
*
* Steps:
* 1. Build gitnexus-shared (tsc)
* 2. Build gitnexus (tsc)
* 3. Copy gitnexus-shared/dist dist/_shared
* 4. Rewrite bare 'gitnexus-shared' specifiers relative paths
*/
import { execSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(__dirname, '..');
const SHARED_ROOT = path.resolve(ROOT, '..', 'gitnexus-shared');
const DIST = path.join(ROOT, 'dist');
const SHARED_DEST = path.join(DIST, '_shared');
// ── 1. Build gitnexus-shared ───────────────────────────────────────
console.log('[build] compiling gitnexus-shared…');
execSync('npx tsc', { cwd: SHARED_ROOT, stdio: 'inherit' });
// ── 2. Build gitnexus ──────────────────────────────────────────────
console.log('[build] compiling gitnexus…');
execSync('npx tsc', { cwd: ROOT, stdio: 'inherit' });
// ── 3. Copy shared dist ────────────────────────────────────────────
console.log('[build] copying shared module into dist/_shared…');
fs.cpSync(path.join(SHARED_ROOT, 'dist'), SHARED_DEST, { recursive: true });
// ── 4. Rewrite imports ─────────────────────────────────────────────
console.log('[build] rewriting gitnexus-shared imports…');
let rewritten = 0;
function rewriteFile(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
if (!content.includes('gitnexus-shared')) return;
const relDir = path.relative(path.dirname(filePath), SHARED_DEST);
// Always use posix separators and point to the package index
const relImport = relDir.split(path.sep).join('/') + '/index.js';
const updated = content
.replace(/from\s+['"]gitnexus-shared['"]/g, `from '${relImport}'`)
.replace(/import\(\s*['"]gitnexus-shared['"]\s*\)/g, `import('${relImport}')`);
if (updated !== content) {
fs.writeFileSync(filePath, updated);
rewritten++;
}
}
function walk(dir, extensions, cb) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
walk(full, extensions, cb);
} else if (extensions.some((ext) => entry.name.endsWith(ext))) {
cb(full);
}
}
}
walk(DIST, ['.js', '.d.ts'], rewriteFile);
console.log(`[build] done — rewrote ${rewritten} files.`);