diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 937cf953..cbba654a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -57,6 +57,11 @@ jobs: echo "Stable release: $VERSION (from tag $TAG)" elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then VERSION="${{ inputs.version }}" + VERSION="${VERSION#v}" + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then + echo "::error::Invalid version '$VERSION'. Expected semver (e.g. 2.1.0)." + exit 1 + fi NPM_TAG="latest" echo "Stable release (manual retry): $VERSION" else @@ -175,19 +180,23 @@ jobs: with: path: artifacts/ - - name: Verify version not already on npm + - name: Check if main package already published + id: check-main env: VERSION: ${{ needs.compute-version.outputs.version }} run: | PKG="@optave/codegraph" echo "Checking if $PKG@$VERSION already exists on npm..." if npm view "$PKG@$VERSION" version 2>/dev/null; then - echo "::error::$PKG@$VERSION is already published on npm." - exit 1 + echo "⚠️ $PKG@$VERSION is already published — will skip publish steps" + echo "already_published=true" >> "$GITHUB_OUTPUT" + else + echo "$PKG@$VERSION is not yet published — proceeding" + echo "already_published=false" >> "$GITHUB_OUTPUT" fi - echo "$PKG@$VERSION is not yet published — proceeding" - name: Publish platform packages + if: steps.check-main.outputs.already_published == 'false' env: VERSION: ${{ needs.compute-version.outputs.version }} NPM_TAG: ${{ needs.compute-version.outputs.npm_tag }} @@ -226,11 +235,18 @@ jobs: } PKGJSON + # Skip if this exact version is already published (idempotent re-runs) + if npm view "${pkg_name}@${VERSION}" version 2>/dev/null; then + echo "⚠️ ${pkg_name}@${VERSION} already published — skipping" + continue + fi + echo "Publishing ${pkg_name}@${VERSION} with --tag ${NPM_TAG}" npm publish "./pkg/$platform" --access public --provenance --tag "$NPM_TAG" done - name: Publish main package + if: steps.check-main.outputs.already_published == 'false' env: NPM_TAG: ${{ needs.compute-version.outputs.npm_tag }} run: npm publish --access public --provenance --tag "$NPM_TAG" diff --git a/COMPETITIVE_ANALYSIS.md b/COMPETITIVE_ANALYSIS.md index 0d1e9707..881e1f0f 100644 --- a/COMPETITIVE_ANALYSIS.md +++ b/COMPETITIVE_ANALYSIS.md @@ -19,7 +19,7 @@ Ranked by weighted score across 6 dimensions (each 1–5): | 4 | 4.2 | [Fraunhofer-AISEC/cpg](https://github.com/Fraunhofer-AISEC/cpg) | 411 | Kotlin | Apache-2.0 | CPG library for 8+ languages with MCP module, Neo4j visualization, formal specs, LLVM IR support | | 5 | 4.2 | [seatedro/glimpse](https://github.com/seatedro/glimpse) | 349 | Rust | MIT | Clipboard-first codebase-to-LLM tool with call graphs, token counting, LSP resolution | | 6 | 4.0 | [SimplyLiz/CodeMCP (CKB)](https://github.com/SimplyLiz/CodeMCP) | 59 | Go | Custom | SCIP-based indexing, compound operations (83% token savings), CODEOWNERS, secret scanning | -| 7 | 4.0 | [abhigyanpatwari/GitNexus](https://github.com/abhigyanpatwari/GitNexus) | — | TS/JS | MIT | Knowledge graph with precomputed structural intelligence, 7 MCP tools, hybrid BM25+semantic search, clustering, process tracing, KuzuDB | +| 7 | 4.0 | [abhigyanpatwari/GitNexus](https://github.com/abhigyanpatwari/GitNexus) | — | TS/JS | PolyForm NC | Knowledge graph with precomputed structural intelligence, 7 MCP tools, hybrid BM25+semantic search, clustering, process tracing, KuzuDB. **Non-commercial only** | | 8 | 3.9 | [harshkedia177/axon](https://github.com/harshkedia177/axon) | 29 | Python | None | 11-phase pipeline, KuzuDB, Leiden community detection, dead code, change coupling | | 9 | 3.8 | [anrgct/autodev-codebase](https://github.com/anrgct/autodev-codebase) | 111 | TypeScript | None | 40+ languages, 7 embedding providers, Cytoscape.js visualization, LLM reranking | | 10 | 3.8 | [ShiftLeftSecurity/codepropertygraph](https://github.com/ShiftLeftSecurity/codepropertygraph) | 564 | Scala | Apache-2.0 | CPG specification + Tinkergraph library, Scala query DSL, protobuf serialization (Joern foundation) | diff --git a/README.md b/README.md index 0eedcbee..7441c4d3 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Most code graph tools make you choose: **fast local analysis with no AI, or powe | Zero config | **Yes** | — | **Yes** | — | — | — | — | — | | Embeddable JS library (`npm install`) | **Yes** | — | — | — | — | — | — | — | | LLM-optional (works without API keys) | **Yes** | **Yes** | **Yes** | — | **Yes** | **Yes** | **Yes** | **Yes** | +| Commercial use allowed | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | — | — | — | | Open source | **Yes** | Yes | Yes | Yes | Yes | Yes | Custom | — | ### What makes codegraph different @@ -108,7 +109,7 @@ The key question is: **can you rebuild your graph on every commit in a large cod | [narsil-mcp](https://github.com/postrv/narsil-mcp) | 90 MCP tools, 32 languages, taint analysis, SBOM, dead code, neural search, Merkle-tree incremental indexing, single ~30MB binary | Primarily MCP-only — no standalone CLI query interface. Neural search requires API key or ONNX source build | | [code-graph-rag](https://github.com/vitali87/code-graph-rag) | Graph RAG with Memgraph, multi-provider AI, semantic search, code editing via AST | No incremental rebuilds — full re-index + re-embed through cloud APIs on every change. Requires Docker | | [cpg](https://github.com/Fraunhofer-AISEC/cpg) | Formal Code Property Graph (AST + CFG + PDG + DFG), ~10 languages, MCP module, LLVM IR support, academic specifications | No incremental builds. Requires JVM + Gradle, no zero config, no watch mode | -| [GitNexus](https://github.com/abhigyanpatwari/GitNexus) | Knowledge graph with precomputed structural intelligence, 7 MCP tools, hybrid search (BM25 + semantic + RRF), clustering, process tracing | Full 6-phase pipeline re-run on changes. KuzuDB graph DB, browser mode limited to ~5,000 files | +| [GitNexus](https://github.com/abhigyanpatwari/GitNexus) | Knowledge graph with precomputed structural intelligence, 7 MCP tools, hybrid search (BM25 + semantic + RRF), clustering, process tracing | Full 6-phase pipeline re-run on changes. KuzuDB graph DB, browser mode limited to ~5,000 files. **PolyForm NC — no commercial use** | | [CodeMCP](https://github.com/SimplyLiz/CodeMCP) | SCIP compiler-grade indexing, compound operations (83% token savings), secret scanning | No incremental builds. Custom license, requires SCIP toolchains per language | | [axon](https://github.com/harshkedia177/axon) | 11-phase pipeline, KuzuDB, community detection, dead code, change coupling | Full pipeline re-run on changes. No license, Python-only, no MCP | | [Madge](https://github.com/pahen/madge) | Simple file-level JS/TS dependency graphs | No function-level analysis, no impact tracing, JS/TS only | diff --git a/package.json b/package.json index c63ded9f..756ce7cb 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "lint:fix": "biome check --write src/ tests/", "format": "biome format --write src/ tests/", "prepare": "npm run build:wasm && husky && npm run deps:tree", - "deps:tree": "node -e \"const{execSync}=require('child_process');const t=execSync('npm ls --all --omit=dev',{encoding:'utf8'});require('fs').writeFileSync('DEPENDENCIES.md','# Dependencies\\n\\n```\\n'+t+'```\\n')\"", + "deps:tree": "node scripts/gen-deps.cjs", "release": "commit-and-tag-version", "release:dry-run": "commit-and-tag-version --dry-run", "version": "node scripts/sync-native-versions.js && git add package.json", diff --git a/scripts/gen-deps.cjs b/scripts/gen-deps.cjs new file mode 100644 index 00000000..16e1ca1b --- /dev/null +++ b/scripts/gen-deps.cjs @@ -0,0 +1,21 @@ +const { execSync } = require('child_process'); +const fs = require('fs'); + +try { + const tree = execSync('npm ls --all --omit=dev', { encoding: 'utf8' }); + fs.writeFileSync( + 'DEPENDENCIES.md', + '# Dependencies\n\n```\n' + tree + '```\n', + ); +} catch (err) { + // npm ls exits non-zero on ELSPROBLEMS (version mismatches in optional deps). + // If stdout still has content, write it; otherwise skip silently. + if (err.stdout) { + fs.writeFileSync( + 'DEPENDENCIES.md', + '# Dependencies\n\n```\n' + err.stdout + '```\n', + ); + } else { + console.warn('deps:tree skipped —', err.message); + } +}