diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 719473def..4dc2f3260 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -11,7 +11,7 @@ "plugins": [ { "name": "gitnexus", - "version": "1.3.3", + "version": "1.6.6", "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/CONTRIBUTING.md b/CONTRIBUTING.md index ddefad384..848884be4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -157,7 +157,12 @@ routes between two modes based on the triggering event: suffix; RC tags are excluded at trigger via a negative glob). Publishes to the `latest` dist-tag with a changelog-backed GitHub release. Maintainers are expected to tag from `main` as a convention; the workflow itself does - not enforce branch reachability. No Docker build (RC-only). + not enforce branch reachability. No Docker build (RC-only). Before cutting a + stable release, keep `gitnexus/package.json`, + `gitnexus-claude-plugin/.claude-plugin/plugin.json`, + `.claude-plugin/marketplace.json`, and the matching `CHANGELOG.md` entry in + lockstep — the always-on `gitnexus` unit suite now fails if those manifest + versions drift. - **Release-candidate mode** — runs on every push to `main` (typically a merged PR) plus manual `workflow_dispatch`. Docs-only changes are skipped via `paths-ignore`. Publishes to the `rc` dist-tag with version diff --git a/gitnexus-claude-plugin/.claude-plugin/plugin.json b/gitnexus-claude-plugin/.claude-plugin/plugin.json index bd4b8c426..da6b42a7b 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.3.6", + "version": "1.6.6", "author": { "name": "GitNexus" }, diff --git a/gitnexus/test/unit/cli-commands.test.ts b/gitnexus/test/unit/cli-commands.test.ts index 26b0b6f66..fcae5d0bd 100644 --- a/gitnexus/test/unit/cli-commands.test.ts +++ b/gitnexus/test/unit/cli-commands.test.ts @@ -1,5 +1,14 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; import { describe, it, expect, vi } from 'vitest'; +const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..'); + +async function readRepoJson(relativePath: string): Promise { + return JSON.parse(await fs.readFile(path.join(REPO_ROOT, relativePath), 'utf8')) as T; +} + // Mock all the heavy imports before importing index vi.mock('../../src/cli/analyze.js', () => ({ analyzeCommand: vi.fn(), @@ -20,6 +29,26 @@ describe('CLI commands', () => { const pkg = await import('../../package.json', { with: { type: 'json' } }); expect(pkg.default.version).toMatch(/^\d+\.\d+\.\d+/); }); + + it('keeps Claude plugin manifests aligned with the gitnexus release version', async () => { + const pkg = await import('../../package.json', { with: { type: 'json' } }); + const pluginManifest = await readRepoJson<{ version: string }>( + 'gitnexus-claude-plugin/.claude-plugin/plugin.json', + ); + const marketplaceManifest = await readRepoJson<{ + plugins?: Array<{ name: string; version: string }>; + }>('.claude-plugin/marketplace.json'); + + expect(Array.isArray(marketplaceManifest.plugins)).toBe(true); + + const gitnexusEntries = (marketplaceManifest.plugins ?? []).filter( + (plugin) => plugin.name === 'gitnexus', + ); + + expect(gitnexusEntries).toHaveLength(1); + expect(pluginManifest.version).toBe(pkg.default.version); + expect(gitnexusEntries[0]?.version).toBe(pkg.default.version); + }); }); describe('package.json scripts', () => {