diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index 77a48e8ce..944455615 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -6,7 +6,7 @@ "plugins": [ { "name": "gitnexus", - "version": "1.6.10", + "version": "1.6.11", "source": { "source": "local", "path": "./gitnexus-claude-plugin" diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 717a4c132..57073ec59 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -11,7 +11,7 @@ "plugins": [ { "name": "gitnexus", - "version": "1.6.10", + "version": "1.6.11", "source": "./gitnexus-claude-plugin", "description": "Code intelligence powered by a knowledge graph. Provides execution flow tracing, blast radius analysis, and augmented search across your codebase." } diff --git a/gitnexus-claude-plugin/.claude-plugin/plugin.json b/gitnexus-claude-plugin/.claude-plugin/plugin.json index 9e9372dea..13f937f59 100644 --- a/gitnexus-claude-plugin/.claude-plugin/plugin.json +++ b/gitnexus-claude-plugin/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "gitnexus", "description": "Code intelligence powered by a knowledge graph. Provides execution flow tracing, blast radius analysis, and augmented search across your codebase.", - "version": "1.6.10", + "version": "1.6.11", "author": { "name": "GitNexus" }, diff --git a/gitnexus-claude-plugin/.codex-plugin/plugin.json b/gitnexus-claude-plugin/.codex-plugin/plugin.json index 67ef62af2..2e2b43e2e 100644 --- a/gitnexus-claude-plugin/.codex-plugin/plugin.json +++ b/gitnexus-claude-plugin/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "gitnexus", "description": "Code intelligence powered by a knowledge graph. Provides execution flow tracing, blast radius analysis, and augmented search across your codebase.", - "version": "1.6.10", + "version": "1.6.11", "skills": "./skills", "mcpServers": "./.mcp.json", "hooks": "./hooks/hooks.json", diff --git a/gitnexus-claude-plugin/skills/gitnexus-cli/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-cli/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-cli/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-cli/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus-claude-plugin/skills/gitnexus-debugging/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-debugging/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-debugging/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-debugging/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus-claude-plugin/skills/gitnexus-exploring/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-exploring/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-exploring/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-exploring/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus-claude-plugin/skills/gitnexus-guide/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-guide/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-guide/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-guide/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus-claude-plugin/skills/gitnexus-impact-analysis/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-impact-analysis/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-impact-analysis/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-impact-analysis/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus-claude-plugin/skills/gitnexus-lfg/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-lfg/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-lfg/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-lfg/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus-claude-plugin/skills/gitnexus-plan/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-plan/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-plan/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-plan/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus-claude-plugin/skills/gitnexus-refactoring/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-refactoring/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-refactoring/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-refactoring/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus-claude-plugin/skills/gitnexus-review/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-review/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-review/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-review/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus-claude-plugin/skills/gitnexus-work/mcp.json b/gitnexus-claude-plugin/skills/gitnexus-work/mcp.json index 1af6255fb..57267bfb0 100644 --- a/gitnexus-claude-plugin/skills/gitnexus-work/mcp.json +++ b/gitnexus-claude-plugin/skills/gitnexus-work/mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "gitnexus": { "command": "npx", - "args": ["-y", "gitnexus@1.6.10", "mcp"] + "args": ["-y", "gitnexus@1.6.11", "mcp"] } } } diff --git a/gitnexus/CHANGELOG.md b/gitnexus/CHANGELOG.md index 6b4520d63..091870103 100644 --- a/gitnexus/CHANGELOG.md +++ b/gitnexus/CHANGELOG.md @@ -4,6 +4,50 @@ All notable changes to GitNexus will be documented in this file. ## [Unreleased] +## [1.6.11] - 2026-09-04 + +### Added + +- **Zig is a supported language** — functions, methods, structs/enums/unions, relative and `build.zig` / `build.zig.zon` imports, and CALLS including receiver-bound dispatch. `comptime`-false branches mark CALLS as `staticGated`. The grammar is an optional dependency, so a missing native binding skips `.zig` files instead of failing install (#1432, #3161) +- **Update notifications** — cache-first npm `latest` check with one stderr line on interactive CLI, a `doctor` line, one MCP process log, and a dismissible web banner from `/api/info`. Silent for npx, dev checkouts, and Docker; opt out with `GITNEXUS_NO_UPDATE_NOTIFIER` (#3175) +- **`gitnexus auto-sync`** — scheduled SSH clone/pull and analyze from `GITNEXUS_HOME/watch_config.yml`. `gitnexus watch` is reserved and prints the split with `analyze --watch` (#2493) +- **`analyze --watch`** — local incremental re-index with debounce, serialized writers, and last-good graph on failure (#3072) +- **`--no-parse-cache` forces a cold parser rebuild** on analyze (#3153) +- **Spring / JVM modeling** — vendor-suffix mapping annotations (#2883), messaging destinations (#3132), handler annotation arguments and template publishes (#3128), Kotlin decorator routes and config consumers (#3133, #3126), optional Actuator runtime import (#3107), `SpringContextUtil.getBeans` dynamic lookups (#2886), Lombok and Kotlin accessor synthesis (#2885), and Java static-wildcard / Kotlin star-import folding for route constants (#3110, #3059) +- **More contract and route surfaces** — AsyncAPI 3.x Destination nodes (#3140), wrapped-client HTTP consumers with leading-prefix template stripping (#3111), GraphQL cross-repo contracts (#3070), and PHP generated-client `Request(method, host + resourcePath)` consumers (#3079) +- **Wiki `grok` local CLI provider** (#3069) +- **Optional bearer auth on the `serve` MCP route** (#3100) + +### Fixed + +- **Web UI is built from `prepack`**, not on every `npm ci` (#3166) +- **`analyze --watch` no longer drops events** across a gitignore reload (#3159) +- **`detect_changes` does not call a zero-symbol result a clean tree** (#3138) +- **`includeTests` is honored** for C#, Java, Swift and PHP test paths (#2866) +- **Decorator routes connect to their handler function** (#2865) +- **Analyze no longer clobbers customized GitNexus skills** (#3124) +- **Generated agent block requires graph tools** on structural reads (#3125) +- **`group` degraded links, sync warnings and UID-only impact actually work** (#3113); Maven child coordinates parse independently of parent POMs (#3108); ambiguous sync names fail closed and `analyze --name` is honored (#3094) +- **Grep tool honors regex, `fileFilter`, and `caseSensitive`** in serve and the web UI (#3109) +- **Razor ViewComponent names bind to in-repo classes** (#3104) +- **Incremental analyze skips derived layers it can reuse** (#3016, #3102) +- **Parse-cache chunks are stable** and ParsedFile loads are cheaper (#3093) +- **MCP omitted `repo` resolves from cwd** (#3085) +- **`status` judges freshness by covered files**, not a dirty working tree (#3083) +- **`impact` File risk is comparable via shared axes** (#3075, #3082), repo-relative paths resolve through `filePath` (#3074, #3084), and scope-extraction omissions are reported (#3071) +- **Cursor hooks preserve quoted shell search patterns** (#2938) + +### Performance + +- **Six equivalent redundancies dropped** on the Java-scale emit path (#3129) +- **V8 sidecars plus hardlinked ParsedFile restore** (#3099) + +### Chore / Dependencies + +- **Transitive CVE patches** (#3095) +- **Major runtime bumps** — `chokidar` 4 → 5 (#3117), `graphql` 16 → 17 (#3119) +- **Dependency bumps** across gitnexus (`js-yaml`, `qs`, `fast-uri`, `ignore`, `tsx`, `@types/node`, `onnxruntime-node`), gitnexus-web (`axios`, `mermaid`, Playwright, Vitest, Testing Library), and the CodeQL action group (#3115, #3118, #3135, #3141–#3151, #3154, #3155, #3158) + ## [1.6.10] - 2026-08-27 ### Added diff --git a/gitnexus/package-lock.json b/gitnexus/package-lock.json index 924776110..c13d24635 100644 --- a/gitnexus/package-lock.json +++ b/gitnexus/package-lock.json @@ -1,12 +1,12 @@ { "name": "gitnexus", - "version": "1.6.10", + "version": "1.6.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gitnexus", - "version": "1.6.10", + "version": "1.6.11", "hasInstallScript": true, "license": "PolyForm-Noncommercial-1.0.0", "dependencies": { diff --git a/gitnexus/package.json b/gitnexus/package.json index 2eff9e678..eda58d62b 100644 --- a/gitnexus/package.json +++ b/gitnexus/package.json @@ -1,6 +1,6 @@ { "name": "gitnexus", - "version": "1.6.10", + "version": "1.6.11", "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.", "author": "Abhigyan Patwari", "license": "PolyForm-Noncommercial-1.0.0", diff --git a/gitnexus/src/cli/command-banner.ts b/gitnexus/src/cli/command-banner.ts index 83fe65383..bfc921894 100644 --- a/gitnexus/src/cli/command-banner.ts +++ b/gitnexus/src/cli/command-banner.ts @@ -4,11 +4,8 @@ * pipe/JSON-safe (`gitnexus query … | jq`, `status --json`). */ -import { createRequire } from 'node:module'; import type { Command } from 'commander'; - -const _require = createRequire(import.meta.url); -const pkg = _require('../../package.json') as { version?: unknown }; +import { packageVersion } from '../core/package-version.js'; const SKIP_COMMAND_BANNER = new Set(['__update-check', 'help']); @@ -18,7 +15,7 @@ const SPECIAL_TITLES: Record = { }; export function installedCliVersion(): string { - return typeof pkg.version === 'string' ? pkg.version : ''; + return packageVersion(); } export function commandDisplayName(name: string): string { diff --git a/gitnexus/src/cli/index.ts b/gitnexus/src/cli/index.ts index 08694bc4c..70238dc00 100644 --- a/gitnexus/src/cli/index.ts +++ b/gitnexus/src/cli/index.ts @@ -4,7 +4,7 @@ // Removing it from here improves MCP server startup time significantly. import { Command } from 'commander'; -import { createRequire } from 'node:module'; +import { packageVersion } from '../core/package-version.js'; import { createAnalyzerLbugLazyAction, createLazyAction, @@ -17,15 +17,13 @@ import { t } from './i18n/index.js'; import { writeCommandBanner } from './command-banner.js'; import { runProcessCliUpdateNotice } from './update-notice.js'; -const _require = createRequire(import.meta.url); -const pkg = _require('../../package.json'); const program = new Command(); function collectCodingAgents(value: string, previous: string[] | undefined): string[] { return [...(previous ?? []), ...value.split(',')]; } -program.name('gitnexus').description('GitNexus local CLI and MCP server').version(pkg.version); +program.name('gitnexus').description('GitNexus local CLI and MCP server').version(packageVersion()); program .command('setup') @@ -521,5 +519,5 @@ program.hook('preAction', (_thisCommand, actionCommand) => { writeCommandBanner(actionCommand); }); -runProcessCliUpdateNotice(typeof pkg.version === 'string' ? pkg.version : ''); +runProcessCliUpdateNotice(packageVersion()); program.parse(process.argv); diff --git a/gitnexus/src/cli/setup.ts b/gitnexus/src/cli/setup.ts index 6dd0f9b85..7ca83643c 100644 --- a/gitnexus/src/cli/setup.ts +++ b/gitnexus/src/cli/setup.ts @@ -10,10 +10,10 @@ import fs from 'fs/promises'; import path from 'path'; import os from 'os'; import { execFile, execFileSync } from 'child_process'; -import { createRequire } from 'module'; import { promisify } from 'util'; import { fileURLToPath } from 'url'; import { parseTree, modify, applyEdits, ParseError, parse as parseJsonc } from 'jsonc-parser'; +import { packageVersion } from '../core/package-version.js'; import { getGlobalDir } from '../storage/repo-manager.js'; import { getEditorTargets, @@ -37,9 +37,8 @@ const execFileAsync = promisify(execFile); // re-stamped every release by scripts/sync-plugin-manifests.mjs (#2445), // since they too execute `gitnexus@` on connect. Only the READMEs // stay on `gitnexus@latest` — they're quickstart docs, not executed state. -const _require = createRequire(import.meta.url); -const _pkg = _require('../../package.json') as { version?: unknown }; -if (typeof _pkg.version !== 'string' || !_pkg.version) { +const PKG_VERSION = packageVersion(); +if (!PKG_VERSION) { throw new Error( 'gitnexus/package.json#version is missing or not a string — cannot generate MCP fallback config.', ); @@ -47,7 +46,7 @@ if (typeof _pkg.version !== 'string' || !_pkg.version) { // Version-pinned ref for the persisted MCP entry — deliberately distinct from // the cjs's exported `gitnexus@latest` hint ref (resolve-analyze-cmd.cjs); the // two are not unified (see the comment above and that file's MCP_PINNED_REF). -const MCP_PINNED_REF = `gitnexus@${_pkg.version}`; +const MCP_PINNED_REF = `gitnexus@${PKG_VERSION}`; /** * Build the `command` string written into an editor's hook settings, which the diff --git a/gitnexus/src/cli/update.ts b/gitnexus/src/cli/update.ts index edd2596ef..adde2ae2b 100644 --- a/gitnexus/src/cli/update.ts +++ b/gitnexus/src/cli/update.ts @@ -5,16 +5,13 @@ */ import { spawn } from 'node:child_process'; -import { createRequire } from 'node:module'; import { homedir } from 'node:os'; import { composeWin32NpmCommand } from '../core/embeddings/runtime-install.js'; +import { packageVersion } from '../core/package-version.js'; import { STRICT_UPDATE_VERSION } from '../core/update-cache.js'; import { refresh, type UpdateState } from '../core/update-check.js'; import { t } from './i18n/index.js'; -const _require = createRequire(import.meta.url); -const pkg = _require('../../package.json') as { version?: unknown }; - export const UPDATE_PACKAGE = 'gitnexus'; export interface UpdateCommandDependencies { @@ -30,7 +27,7 @@ export interface UpdateCommandDependencies { } function defaultInstalledVersion(): string { - return typeof pkg.version === 'string' ? pkg.version : ''; + return packageVersion(); } export function updateInstallArgs(version: string): string[] { diff --git a/gitnexus/src/core/package-version.ts b/gitnexus/src/core/package-version.ts new file mode 100644 index 000000000..c4e9ab170 --- /dev/null +++ b/gitnexus/src/core/package-version.ts @@ -0,0 +1,12 @@ +import { createRequire } from 'node:module'; + +const _require = createRequire(import.meta.url); +const pkg = _require('../../package.json') as { version?: unknown }; + +/** + * Published version from this package's `package.json`. + * Empty string if the field is missing or not a string. + */ +export function packageVersion(): string { + return typeof pkg.version === 'string' ? pkg.version : ''; +} diff --git a/gitnexus/src/core/update-check.ts b/gitnexus/src/core/update-check.ts index fa2364490..265bf912b 100644 --- a/gitnexus/src/core/update-check.ts +++ b/gitnexus/src/core/update-check.ts @@ -1,11 +1,11 @@ import fs from 'node:fs/promises'; -import { createRequire } from 'node:module'; import { getGlobalDir } from '../storage/global-dir.js'; import { writeFileAtomic } from '../storage/fs-atomic.js'; import { acquireFileLock, FileLockBusyError } from '../storage/file-lock.js'; import { validateGitUrl } from './net/url-guard.js'; import { updateEligibleInstall } from './install-context.js'; import { createLogger } from './logger.js'; +import { packageVersion } from './package-version.js'; import { isNewerVersion, isUpdateCacheFresh, @@ -19,9 +19,6 @@ import { type UpdateCacheEntry, } from './update-cache.js'; -const _require = createRequire(import.meta.url); -const pkg = _require('../../package.json') as { version?: unknown }; - const FETCH_TIMEOUT_MS = 3_000; const MAX_RESPONSE_BYTES = 64 * 1024; const MAX_REDIRECTS = 5; @@ -31,7 +28,7 @@ const LOCK_BUSY_RETRY_JITTER_MS = 30_000; const updateLogger = createLogger('update-check'); function defaultInstalledVersion(): string { - return typeof pkg.version === 'string' ? pkg.version : ''; + return packageVersion(); } function nextSchedulerDelay(entry: UpdateCacheEntry | null, now: number): number { diff --git a/gitnexus/src/mcp/server.ts b/gitnexus/src/mcp/server.ts index a3df48b4c..118f28fa1 100644 --- a/gitnexus/src/mcp/server.ts +++ b/gitnexus/src/mcp/server.ts @@ -11,8 +11,8 @@ * Resources: repos, repo/{name}/context, repo/{name}/clusters, ... */ -import { createRequire } from 'module'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { packageVersion } from '../core/package-version.js'; import { CompatibleStdioServerTransport } from './compatible-stdio-transport.js'; import { CallToolRequestSchema, @@ -106,12 +106,10 @@ export function createMCPServer( } const repositoryPolicy = options.repositoryPolicy ?? McpRepositoryPolicy.unrestricted(); const scopedBackend = repositoryPolicy.scopeBackend(backend); - const require = createRequire(import.meta.url); - const pkgVersion: string = require('../../package.json').version; const server = new Server( { name: 'gitnexus', - version: pkgVersion, + version: packageVersion(), }, { capabilities: { diff --git a/gitnexus/src/server/update-controller.ts b/gitnexus/src/server/update-controller.ts index fdc0ed70c..81b91f911 100644 --- a/gitnexus/src/server/update-controller.ts +++ b/gitnexus/src/server/update-controller.ts @@ -1,9 +1,6 @@ -import { createRequire } from 'node:module'; +import { packageVersion } from '../core/package-version.js'; import { armUpdateRefreshScheduler, evaluate, type UpdateState } from '../core/update-check.js'; -const _require = createRequire(import.meta.url); -const pkg = _require('../../package.json'); - export interface ServerInfoResponse { version: string; launchContext: 'npx' | 'global' | 'local'; @@ -92,7 +89,7 @@ export const buildServerInfo = (updateState: UpdateState | null): ServerInfoResp } return { - version: pkg.version, + version: packageVersion(), launchContext, nodeVersion: process.version, ...(updateState?.updateAvailable && updateState.latestVersion diff --git a/gitnexus/test/integration/cli/update-notice.test.ts b/gitnexus/test/integration/cli/update-notice.test.ts index ed49d3204..abebfbd28 100644 --- a/gitnexus/test/integration/cli/update-notice.test.ts +++ b/gitnexus/test/integration/cli/update-notice.test.ts @@ -7,8 +7,10 @@ import { afterEach, describe, expect, it } from 'vitest'; import { CLI_SPAWN_PREFIX, tsxLoaderUrl } from '../../helpers/cli-entry.js'; import { cleanupTempDirSync } from '../../helpers/test-db.js'; +import { packageVersion } from '../../../src/core/package-version.js'; const repoRoot = path.resolve(import.meta.dirname, '../../..'); +const installedVersion = packageVersion(); const tempDirs: string[] = []; function tempHome(): string { @@ -218,7 +220,9 @@ globalThis.fetch = async () => { }, ); - expect(result.stderr).toContain('GitNexus 99.0.0 is available (you are running 1.6.10).'); + expect(result.stderr).toContain( + `GitNexus 99.0.0 is available (you are running ${installedVersion}).`, + ); expect(result.stdout).not.toContain('99.0.0 is available'); }); }); diff --git a/gitnexus/test/unit/package-version.test.ts b/gitnexus/test/unit/package-version.test.ts new file mode 100644 index 000000000..a38e5cd32 --- /dev/null +++ b/gitnexus/test/unit/package-version.test.ts @@ -0,0 +1,13 @@ +import { createRequire } from 'node:module'; +import { describe, expect, it } from 'vitest'; +import { packageVersion } from '../../src/core/package-version.js'; + +const fromManifest = (createRequire(import.meta.url)('../../package.json') as { version: string }) + .version; + +describe('packageVersion', () => { + it('returns the same string as gitnexus/package.json#version', () => { + expect(packageVersion()).toBe(fromManifest); + expect(packageVersion()).toMatch(/^\d+\.\d+\.\d+/); + }); +}); diff --git a/gitnexus/test/unit/server-info.test.ts b/gitnexus/test/unit/server-info.test.ts index 9e46baf76..ea395c089 100644 --- a/gitnexus/test/unit/server-info.test.ts +++ b/gitnexus/test/unit/server-info.test.ts @@ -8,9 +8,11 @@ import { buildServerInfo, createServeUpdateController, } from '../../src/server/update-controller.js'; +import { packageVersion } from '../../src/core/package-version.js'; import { evaluate } from '../../src/core/update-check.js'; import type { UpdateState } from '../../src/core/update-check.js'; +const PKG_VERSION = packageVersion(); const baseKeys = ['version', 'launchContext', 'nodeVersion']; const tempDirs: string[] = []; @@ -27,7 +29,7 @@ describe('GET /api/info update state', () => { expect(Object.keys(response)).toEqual(baseKeys); expect(response).toEqual({ - version: '1.6.10', + version: PKG_VERSION, launchContext: expect.stringMatching(/^(npx|global|local)$/), nodeVersion: process.version, }); @@ -35,7 +37,7 @@ describe('GET /api/info update state', () => { it('adds optional update fields only for an available version', () => { expect(buildServerInfo({ updateAvailable: true, latestVersion: '9.8.7' })).toEqual({ - version: '1.6.10', + version: PKG_VERSION, launchContext: expect.stringMatching(/^(npx|global|local)$/), nodeVersion: process.version, latestVersion: '9.8.7', @@ -43,7 +45,7 @@ describe('GET /api/info update state', () => { }); expect( - Object.keys(buildServerInfo({ updateAvailable: false, latestVersion: '1.6.10' })), + Object.keys(buildServerInfo({ updateAvailable: false, latestVersion: PKG_VERSION })), ).toEqual(baseKeys); }); diff --git a/gitnexus/test/unit/setup-antigravity.test.ts b/gitnexus/test/unit/setup-antigravity.test.ts index 338b75806..4f817c89e 100644 --- a/gitnexus/test/unit/setup-antigravity.test.ts +++ b/gitnexus/test/unit/setup-antigravity.test.ts @@ -20,11 +20,10 @@ import fs from 'fs/promises'; import os from 'os'; import path from 'path'; import { spawnSync } from 'child_process'; -import { createRequire } from 'module'; import { commitAll, initGitRepo } from '../helpers/temp-git-repo.js'; +import { packageVersion } from '../../src/core/package-version.js'; -const PKG_VERSION = (createRequire(import.meta.url)('../../package.json') as { version: string }) - .version; +const PKG_VERSION = packageVersion(); const NPX_REF = `gitnexus@${PKG_VERSION}`; // vi.hoisted lets the mock factory below (which is hoisted by Vitest) see diff --git a/gitnexus/test/unit/setup-codex.test.ts b/gitnexus/test/unit/setup-codex.test.ts index 9ede4a67b..10a19e38c 100644 --- a/gitnexus/test/unit/setup-codex.test.ts +++ b/gitnexus/test/unit/setup-codex.test.ts @@ -2,10 +2,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import fs from 'fs/promises'; import os from 'os'; import path from 'path'; -import { createRequire } from 'module'; +import { packageVersion } from '../../src/core/package-version.js'; -const PKG_VERSION = (createRequire(import.meta.url)('../../package.json') as { version: string }) - .version; +const PKG_VERSION = packageVersion(); const NPX_REF = `gitnexus@${PKG_VERSION}`; const execFileMock = vi.fn((...args: any[]) => { diff --git a/gitnexus/test/unit/setup-jsonc.test.ts b/gitnexus/test/unit/setup-jsonc.test.ts index 1bd8dd267..d84b9a41b 100644 --- a/gitnexus/test/unit/setup-jsonc.test.ts +++ b/gitnexus/test/unit/setup-jsonc.test.ts @@ -3,10 +3,9 @@ import fs from 'fs/promises'; import os from 'os'; import path from 'path'; import { parse as parseJsonc } from 'jsonc-parser'; -import { createRequire } from 'module'; +import { packageVersion } from '../../src/core/package-version.js'; -const PKG_VERSION = (createRequire(import.meta.url)('../../package.json') as { version: string }) - .version; +const PKG_VERSION = packageVersion(); const NPX_REF = `gitnexus@${PKG_VERSION}`; const execFileMock = vi.fn((...args: any[]) => { diff --git a/gitnexus/test/unit/setup.test.ts b/gitnexus/test/unit/setup.test.ts index 448074669..97744511d 100644 --- a/gitnexus/test/unit/setup.test.ts +++ b/gitnexus/test/unit/setup.test.ts @@ -2,12 +2,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import fs from 'fs/promises'; import os from 'os'; import path from 'path'; -import { createRequire } from 'module'; +import { packageVersion } from '../../src/core/package-version.js'; -// Match what setup.ts emits — read the version from the same package.json -// so the test never goes stale on a release bump. -const PKG_VERSION = (createRequire(import.meta.url)('../../package.json') as { version: string }) - .version; +const PKG_VERSION = packageVersion(); const MCP_PINNED_REF = `gitnexus@${PKG_VERSION}`; /** Flatten the spied console.log calls into one searchable string. */