gitnexus 1.6.11-rc.48 → 1.6.11-rc.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/cli/analyze.js +0 -1
- package/dist/cli/command-banner.d.ts +15 -0
- package/dist/cli/command-banner.js +44 -0
- package/dist/cli/doctor.d.ts +7 -0
- package/dist/cli/doctor.js +14 -0
- package/dist/cli/help-i18n.js +1 -0
- package/dist/cli/i18n/en.d.ts +8 -0
- package/dist/cli/i18n/en.js +8 -0
- package/dist/cli/i18n/resources.d.ts +16 -0
- package/dist/cli/i18n/zh-CN.d.ts +8 -0
- package/dist/cli/i18n/zh-CN.js +8 -0
- package/dist/cli/index.js +14 -0
- package/dist/cli/mcp.d.ts +15 -0
- package/dist/cli/mcp.js +44 -0
- package/dist/cli/update-notice.d.ts +34 -0
- package/dist/cli/update-notice.js +91 -0
- package/dist/cli/update.d.ts +21 -0
- package/dist/cli/update.js +95 -0
- package/dist/core/group/storage.js +2 -2
- package/dist/core/install-context.d.ts +4 -0
- package/dist/core/install-context.js +152 -0
- package/dist/core/net/url-guard.d.ts +6 -0
- package/dist/core/net/url-guard.js +147 -0
- package/dist/core/update-cache.d.ts +39 -0
- package/dist/core/update-cache.js +141 -0
- package/dist/core/update-check.d.ts +31 -0
- package/dist/core/update-check.js +276 -0
- package/dist/server/api.d.ts +1 -1
- package/dist/server/api.js +7 -18
- package/dist/server/git-clone.d.ts +2 -7
- package/dist/server/git-clone.js +2 -146
- package/dist/server/update-controller.d.ts +29 -0
- package/dist/server/update-controller.js +84 -0
- package/dist/storage/global-dir.d.ts +2 -0
- package/dist/storage/global-dir.js +6 -0
- package/dist/storage/repo-manager.d.ts +1 -4
- package/dist/storage/repo-manager.js +2 -7
- package/package.json +1 -1
- package/scripts/cross-platform-tests.ts +2 -0
- package/web/assets/{agent-CsQH9GJv.js → agent-BMRqXorA.js} +1 -1
- package/web/assets/{index-CJDpyH-n.css → index-C2_aej58.css} +1 -1
- package/web/assets/{index-TqwlBESG.js → index-Dj3vQOHK.js} +51 -51
- package/web/assets/src-Df5C1Nz4.js +1 -0
- package/web/index.html +3 -3
- package/web/assets/src-sSE475bl.js +0 -1
package/README.md
CHANGED
|
@@ -264,6 +264,7 @@ gitnexus wiki --provider grok # Local Grok Build CLI (uses `grok login`, no A
|
|
|
264
264
|
gitnexus wiki --base-url http://llama-box.local:8080/v1 --allow-insecure-connection llama-box.local
|
|
265
265
|
# Allow an exact LAN/self-hosted HTTP LLM host; env: GITNEXUS_ALLOW_INSECURE_CONNECTION
|
|
266
266
|
gitnexus doctor # Show runtime platform capabilities and embedding configuration
|
|
267
|
+
gitnexus update # Install the latest published GitNexus (`npm i -g gitnexus@<x.y.z>`)
|
|
267
268
|
|
|
268
269
|
# Direct graph queries — the same tools the MCP server exposes, no MCP daemon needed
|
|
269
270
|
gitnexus query "<concept>" # Process-grouped hybrid search
|
|
@@ -492,6 +493,40 @@ bigger cycle) and `N` increments per published rc. Example sequence:
|
|
|
492
493
|
`1.6.3-rc.1`. See the [Releases page](https://github.com/abhigyanpatwari/GitNexus/releases)
|
|
493
494
|
for the full list; stable `latest` is unaffected.
|
|
494
495
|
|
|
496
|
+
## Update notifications
|
|
497
|
+
|
|
498
|
+
GitNexus checks the npm registry's `latest` dist-tag at most once every 24
|
|
499
|
+
hours per installation and tells you when a newer stable version exists. The
|
|
500
|
+
result is cached under `$GITNEXUS_HOME` (`~/.gitnexus` by default), so the
|
|
501
|
+
check never runs on the command's hot path and never blocks output. Where the
|
|
502
|
+
notice appears:
|
|
503
|
+
|
|
504
|
+
- **CLI** — one line on stderr when you run a command interactively (never on
|
|
505
|
+
stdout, so `gitnexus query … | jq` and other piped output stay clean), a
|
|
506
|
+
line in `gitnexus doctor` when an update is known. Automatic notices never
|
|
507
|
+
install. `gitnexus update` checks even when notices are opted out, then
|
|
508
|
+
runs `npm i -g gitnexus@<x.y.z>` (same idea as `claude update` /
|
|
509
|
+
`codex update`).
|
|
510
|
+
- **MCP server** — one structured log record on the server's stderr per
|
|
511
|
+
process per version (visible in your host's MCP log panel). Tool results,
|
|
512
|
+
resources, prompts, and server instructions never carry update text.
|
|
513
|
+
- **Web UI** — a dismissible banner when the server reports a newer version;
|
|
514
|
+
dismissal persists per version.
|
|
515
|
+
|
|
516
|
+
The check is skipped entirely (no network request, no output) when `CI` is
|
|
517
|
+
truthy, when the install is not an npm global/local install (npx cache, dev
|
|
518
|
+
checkout, Docker image — the Docker CLI image sets the opt-out itself), or
|
|
519
|
+
when opted out:
|
|
520
|
+
|
|
521
|
+
| Variable | Effect |
|
|
522
|
+
| --- | --- |
|
|
523
|
+
| `GITNEXUS_NO_UPDATE_NOTIFIER` | Truthy (`1`, `true`, …) disables the update check on every surface. |
|
|
524
|
+
| `NO_UPDATE_NOTIFIER` | Cross-tool convention; honored the same way. |
|
|
525
|
+
| `npm_config_registry` | The check reads the `latest` dist-tag from this registry instead of `https://registry.npmjs.org`. Credentials are never sent, and registries that require authentication are not supported (the check silently skips). |
|
|
526
|
+
|
|
527
|
+
Eval harnesses running a global install can set `GITNEXUS_NO_UPDATE_NOTIFIER`
|
|
528
|
+
for a quiet registry.
|
|
529
|
+
|
|
495
530
|
## Troubleshooting
|
|
496
531
|
|
|
497
532
|
### `Cannot destructure property 'package' of 'node.target' as it is null`
|
package/dist/cli/analyze.js
CHANGED
|
@@ -609,7 +609,6 @@ export async function analyzeOrWatchCommandWithRunnerIdentity(runnerIdentityAtBo
|
|
|
609
609
|
await analyzeCommandWithRunnerIdentity(runnerIdentityAtBootstrap, inputPath, options);
|
|
610
610
|
}
|
|
611
611
|
const analyzeCommandImpl = async (inputPath, cliOptions, runnerIdentityAtBootstrap) => {
|
|
612
|
-
console.log('\n GitNexus Analyzer\n');
|
|
613
612
|
// ── Resolve the target repo root ──────────────────────────────────
|
|
614
613
|
// Resolved FIRST because `.gitnexusrc` is read from the repo root (not the
|
|
615
614
|
// caller's cwd), and config can set defaults that the validation below
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-line identity printed before every CLI action:
|
|
3
|
+
* `GitNexus Analyzer (1.6.10)`. Goes to stderr so stdout stays
|
|
4
|
+
* pipe/JSON-safe (`gitnexus query … | jq`, `status --json`).
|
|
5
|
+
*/
|
|
6
|
+
import type { Command } from 'commander';
|
|
7
|
+
export declare function installedCliVersion(): string;
|
|
8
|
+
export declare function commandDisplayName(name: string): string;
|
|
9
|
+
export declare function commandBannerTitle(command: Command): string;
|
|
10
|
+
export declare function formatCommandBanner(title: string, version?: string): string;
|
|
11
|
+
export interface WriteCommandBannerDependencies {
|
|
12
|
+
write?: (text: string) => void;
|
|
13
|
+
version?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function writeCommandBanner(command: Command, deps?: WriteCommandBannerDependencies): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-line identity printed before every CLI action:
|
|
3
|
+
* `GitNexus Analyzer (1.6.10)`. Goes to stderr so stdout stays
|
|
4
|
+
* pipe/JSON-safe (`gitnexus query … | jq`, `status --json`).
|
|
5
|
+
*/
|
|
6
|
+
import { createRequire } from 'node:module';
|
|
7
|
+
const _require = createRequire(import.meta.url);
|
|
8
|
+
const pkg = _require('../../package.json');
|
|
9
|
+
const SKIP_COMMAND_BANNER = new Set(['__update-check', 'help']);
|
|
10
|
+
const SPECIAL_TITLES = {
|
|
11
|
+
analyze: 'Analyzer',
|
|
12
|
+
mcp: 'MCP',
|
|
13
|
+
};
|
|
14
|
+
export function installedCliVersion() {
|
|
15
|
+
return typeof pkg.version === 'string' ? pkg.version : '';
|
|
16
|
+
}
|
|
17
|
+
export function commandDisplayName(name) {
|
|
18
|
+
return (SPECIAL_TITLES[name] ??
|
|
19
|
+
name
|
|
20
|
+
.split('-')
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
23
|
+
.join(' '));
|
|
24
|
+
}
|
|
25
|
+
export function commandBannerTitle(command) {
|
|
26
|
+
const names = [];
|
|
27
|
+
for (let current = command; current?.parent; current = current.parent) {
|
|
28
|
+
names.unshift(current.name());
|
|
29
|
+
}
|
|
30
|
+
return names.map(commandDisplayName).join(' ');
|
|
31
|
+
}
|
|
32
|
+
export function formatCommandBanner(title, version = installedCliVersion()) {
|
|
33
|
+
if (!title)
|
|
34
|
+
return '';
|
|
35
|
+
return version ? `\n GitNexus ${title} (${version})\n` : `\n GitNexus ${title}\n`;
|
|
36
|
+
}
|
|
37
|
+
export function writeCommandBanner(command, deps = {}) {
|
|
38
|
+
if (SKIP_COMMAND_BANNER.has(command.name()))
|
|
39
|
+
return;
|
|
40
|
+
const text = formatCommandBanner(commandBannerTitle(command), deps.version ?? installedCliVersion());
|
|
41
|
+
if (!text)
|
|
42
|
+
return;
|
|
43
|
+
(deps.write ?? ((line) => process.stderr.write(line)))(text);
|
|
44
|
+
}
|
package/dist/cli/doctor.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type EmbeddingRuntimeResolution } from '../core/embeddings/runtime-install.js';
|
|
2
2
|
import { type NativeCheckResult } from '../core/lbug/native-check.js';
|
|
3
|
+
import { type ValidatedUpdateCache } from '../core/update-cache.js';
|
|
3
4
|
export declare function displayWidth(value: string): number;
|
|
4
5
|
export declare function padDisplayEnd(value: string, columns: number): string;
|
|
5
6
|
/**
|
|
@@ -59,4 +60,10 @@ export declare function poolSizeDoctorLine(pool: number, envRaw: string | undefi
|
|
|
59
60
|
* stderr right below said the opposite. Render what the check actually found.
|
|
60
61
|
*/
|
|
61
62
|
export declare function nativeStatusLine(check: NativeCheckResult): string;
|
|
63
|
+
export declare function cachedUpdateDoctorLine(options: {
|
|
64
|
+
installedVersion: string;
|
|
65
|
+
eligible: boolean;
|
|
66
|
+
env: NodeJS.ProcessEnv;
|
|
67
|
+
readCache: () => ValidatedUpdateCache | null;
|
|
68
|
+
}): string | null;
|
|
62
69
|
export declare const doctorCommand: () => Promise<void>;
|
package/dist/cli/doctor.js
CHANGED
|
@@ -8,7 +8,10 @@ import { checkLbugNative, probeFtsExtensionLoad, probeVectorExtensionLoad, } fro
|
|
|
8
8
|
import { getEffectiveBufferPoolSize, getOsPageSize, isPageSizeAwareLadybug, } from '../core/lbug/lbug-config.js';
|
|
9
9
|
import { diagnoseExtensionLoad } from '../core/lbug/extension-load-error.js';
|
|
10
10
|
import { getExtensionInstallPolicy } from '../core/lbug/extension-loader.js';
|
|
11
|
+
import { updateEligibleInstallSync } from '../core/install-context.js';
|
|
12
|
+
import { readValidatedUpdateCacheSync } from '../core/update-cache.js';
|
|
11
13
|
import { t } from './i18n/index.js';
|
|
14
|
+
import { cachedUpdateNoticeLine } from './update-notice.js';
|
|
12
15
|
function isCombiningMark(codePoint) {
|
|
13
16
|
return ((codePoint >= 0x0300 && codePoint <= 0x036f) ||
|
|
14
17
|
(codePoint >= 0x1ab0 && codePoint <= 0x1aff) ||
|
|
@@ -160,6 +163,9 @@ function nativeStatusText(check) {
|
|
|
160
163
|
return '✗ lbugjs.node missing';
|
|
161
164
|
}
|
|
162
165
|
}
|
|
166
|
+
export function cachedUpdateDoctorLine(options) {
|
|
167
|
+
return cachedUpdateNoticeLine(options);
|
|
168
|
+
}
|
|
163
169
|
export const doctorCommand = async () => {
|
|
164
170
|
const fingerprint = getRuntimeFingerprint();
|
|
165
171
|
const capabilities = getRuntimeCapabilities();
|
|
@@ -169,6 +175,14 @@ export const doctorCommand = async () => {
|
|
|
169
175
|
console.log(` ${label('doctor.labels.os', 10)}${fingerprint.platform}/${fingerprint.arch}`);
|
|
170
176
|
console.log(` ${label('doctor.labels.node', 10)}${fingerprint.node}`);
|
|
171
177
|
console.log(` ${label('doctor.labels.gitnexus', 10)}${fingerprint.gitnexus}`);
|
|
178
|
+
const updateLine = cachedUpdateDoctorLine({
|
|
179
|
+
installedVersion: fingerprint.gitnexus,
|
|
180
|
+
eligible: updateEligibleInstallSync(),
|
|
181
|
+
env: process.env,
|
|
182
|
+
readCache: () => readValidatedUpdateCacheSync(),
|
|
183
|
+
});
|
|
184
|
+
if (updateLine)
|
|
185
|
+
console.log(` ${updateLine}`);
|
|
172
186
|
console.log(` ${label('doctor.labels.ladybugdb', 10)}${fingerprint.ladybugdb ?? 'unknown'}`);
|
|
173
187
|
// OS page size next to the LadybugDB version because the two interact:
|
|
174
188
|
// @ladybugdb/core < 0.18.0 assumed 4 KiB pages in its buffer manager and
|
package/dist/cli/help-i18n.js
CHANGED
|
@@ -19,6 +19,7 @@ const COMMAND_DESCRIPTION_KEYS = {
|
|
|
19
19
|
list: 'help.command.list.description',
|
|
20
20
|
status: 'help.command.status.description',
|
|
21
21
|
doctor: 'help.command.doctor.description',
|
|
22
|
+
update: 'help.command.update.description',
|
|
22
23
|
embeddings: 'help.command.embeddings.description',
|
|
23
24
|
'embeddings install': 'help.command.embeddings.install.description',
|
|
24
25
|
clean: 'help.command.clean.description',
|
package/dist/cli/i18n/en.d.ts
CHANGED
|
@@ -7,6 +7,13 @@ export declare const en: {
|
|
|
7
7
|
readonly 'common.storage': "Storage";
|
|
8
8
|
readonly 'common.deleted': "Deleted: {{target}}";
|
|
9
9
|
readonly 'common.error': "Error: {{message}}";
|
|
10
|
+
readonly 'update.available': "GitNexus {{latestVersion}} is available (you are running {{installedVersion}}).";
|
|
11
|
+
readonly 'update.current': "GitNexus {{installedVersion}} is current or newer than the latest stable version.";
|
|
12
|
+
readonly 'update.installing': "Installing with {{command}}…";
|
|
13
|
+
readonly 'update.installed': "Installed gitnexus@{{version}}. Restart long-running mcp/serve processes.";
|
|
14
|
+
readonly 'update.installFailed': "npm install failed. You can retry: {{command}}";
|
|
15
|
+
readonly 'update.installError': "Could not run npm: {{message}}";
|
|
16
|
+
readonly 'update.checkFailed': "Could not check for updates (offline, private registry, or the check failed open).";
|
|
10
17
|
readonly 'list.title': "Indexed Repositories ({{count}})";
|
|
11
18
|
readonly 'list.indexed': "Indexed";
|
|
12
19
|
readonly 'list.commit': "Commit";
|
|
@@ -137,6 +144,7 @@ export declare const en: {
|
|
|
137
144
|
readonly 'help.command.list.description': "List all indexed repositories";
|
|
138
145
|
readonly 'help.command.status.description': "Show index status for current repo";
|
|
139
146
|
readonly 'help.command.doctor.description': "Show runtime platform capabilities and embedding configuration";
|
|
147
|
+
readonly 'help.command.update.description': "Install the latest published GitNexus globally (`npm i -g gitnexus@<x.y.z>`).";
|
|
140
148
|
readonly 'help.command.embeddings.description': "Manage the on-demand local embedding runtime";
|
|
141
149
|
readonly 'help.command.embeddings.install.description': "Install the local embedding stack (@huggingface/transformers + onnxruntime-node) on demand. Heals installs where npm skipped the optional packages (e.g. behind an HTTP proxy, #2370). Downloads only from your configured npm registry — mirrors and proxies apply.";
|
|
142
150
|
readonly 'help.command.clean.description': "Delete GitNexus index for current repo";
|
package/dist/cli/i18n/en.js
CHANGED
|
@@ -7,6 +7,13 @@ export const en = {
|
|
|
7
7
|
'common.storage': 'Storage',
|
|
8
8
|
'common.deleted': 'Deleted: {{target}}',
|
|
9
9
|
'common.error': 'Error: {{message}}',
|
|
10
|
+
'update.available': 'GitNexus {{latestVersion}} is available (you are running {{installedVersion}}).',
|
|
11
|
+
'update.current': 'GitNexus {{installedVersion}} is current or newer than the latest stable version.',
|
|
12
|
+
'update.installing': 'Installing with {{command}}…',
|
|
13
|
+
'update.installed': 'Installed gitnexus@{{version}}. Restart long-running mcp/serve processes.',
|
|
14
|
+
'update.installFailed': 'npm install failed. You can retry: {{command}}',
|
|
15
|
+
'update.installError': 'Could not run npm: {{message}}',
|
|
16
|
+
'update.checkFailed': 'Could not check for updates (offline, private registry, or the check failed open).',
|
|
10
17
|
'list.title': 'Indexed Repositories ({{count}})',
|
|
11
18
|
'list.indexed': 'Indexed',
|
|
12
19
|
'list.commit': 'Commit',
|
|
@@ -139,6 +146,7 @@ export const en = {
|
|
|
139
146
|
'help.command.list.description': 'List all indexed repositories',
|
|
140
147
|
'help.command.status.description': 'Show index status for current repo',
|
|
141
148
|
'help.command.doctor.description': 'Show runtime platform capabilities and embedding configuration',
|
|
149
|
+
'help.command.update.description': 'Install the latest published GitNexus globally (`npm i -g gitnexus@<x.y.z>`).',
|
|
142
150
|
'help.command.embeddings.description': 'Manage the on-demand local embedding runtime',
|
|
143
151
|
'help.command.embeddings.install.description': 'Install the local embedding stack (@huggingface/transformers + onnxruntime-node) on demand. Heals installs where npm skipped the optional packages (e.g. behind an HTTP proxy, #2370). Downloads only from your configured npm registry — mirrors and proxies apply.',
|
|
144
152
|
'help.command.clean.description': 'Delete GitNexus index for current repo',
|
|
@@ -8,6 +8,13 @@ export declare const cliResources: {
|
|
|
8
8
|
readonly 'common.storage': "Storage";
|
|
9
9
|
readonly 'common.deleted': "Deleted: {{target}}";
|
|
10
10
|
readonly 'common.error': "Error: {{message}}";
|
|
11
|
+
readonly 'update.available': "GitNexus {{latestVersion}} is available (you are running {{installedVersion}}).";
|
|
12
|
+
readonly 'update.current': "GitNexus {{installedVersion}} is current or newer than the latest stable version.";
|
|
13
|
+
readonly 'update.installing': "Installing with {{command}}…";
|
|
14
|
+
readonly 'update.installed': "Installed gitnexus@{{version}}. Restart long-running mcp/serve processes.";
|
|
15
|
+
readonly 'update.installFailed': "npm install failed. You can retry: {{command}}";
|
|
16
|
+
readonly 'update.installError': "Could not run npm: {{message}}";
|
|
17
|
+
readonly 'update.checkFailed': "Could not check for updates (offline, private registry, or the check failed open).";
|
|
11
18
|
readonly 'list.title': "Indexed Repositories ({{count}})";
|
|
12
19
|
readonly 'list.indexed': "Indexed";
|
|
13
20
|
readonly 'list.commit': "Commit";
|
|
@@ -138,6 +145,7 @@ export declare const cliResources: {
|
|
|
138
145
|
readonly 'help.command.list.description': "List all indexed repositories";
|
|
139
146
|
readonly 'help.command.status.description': "Show index status for current repo";
|
|
140
147
|
readonly 'help.command.doctor.description': "Show runtime platform capabilities and embedding configuration";
|
|
148
|
+
readonly 'help.command.update.description': "Install the latest published GitNexus globally (`npm i -g gitnexus@<x.y.z>`).";
|
|
141
149
|
readonly 'help.command.embeddings.description': "Manage the on-demand local embedding runtime";
|
|
142
150
|
readonly 'help.command.embeddings.install.description': "Install the local embedding stack (@huggingface/transformers + onnxruntime-node) on demand. Heals installs where npm skipped the optional packages (e.g. behind an HTTP proxy, #2370). Downloads only from your configured npm registry — mirrors and proxies apply.";
|
|
143
151
|
readonly 'help.command.clean.description': "Delete GitNexus index for current repo";
|
|
@@ -279,6 +287,13 @@ export declare const cliResources: {
|
|
|
279
287
|
'common.storage': string;
|
|
280
288
|
'common.deleted': string;
|
|
281
289
|
'common.error': string;
|
|
290
|
+
'update.available': string;
|
|
291
|
+
'update.current': string;
|
|
292
|
+
'update.installing': string;
|
|
293
|
+
'update.installed': string;
|
|
294
|
+
'update.installFailed': string;
|
|
295
|
+
'update.installError': string;
|
|
296
|
+
'update.checkFailed': string;
|
|
282
297
|
'list.title': string;
|
|
283
298
|
'list.indexed': string;
|
|
284
299
|
'list.commit': string;
|
|
@@ -409,6 +424,7 @@ export declare const cliResources: {
|
|
|
409
424
|
'help.command.list.description': string;
|
|
410
425
|
'help.command.status.description': string;
|
|
411
426
|
'help.command.doctor.description': string;
|
|
427
|
+
'help.command.update.description': string;
|
|
412
428
|
'help.command.embeddings.description': string;
|
|
413
429
|
'help.command.embeddings.install.description': string;
|
|
414
430
|
'help.command.clean.description': string;
|
package/dist/cli/i18n/zh-CN.d.ts
CHANGED
|
@@ -7,6 +7,13 @@ export declare const zhCN: {
|
|
|
7
7
|
'common.storage': string;
|
|
8
8
|
'common.deleted': string;
|
|
9
9
|
'common.error': string;
|
|
10
|
+
'update.available': string;
|
|
11
|
+
'update.current': string;
|
|
12
|
+
'update.installing': string;
|
|
13
|
+
'update.installed': string;
|
|
14
|
+
'update.installFailed': string;
|
|
15
|
+
'update.installError': string;
|
|
16
|
+
'update.checkFailed': string;
|
|
10
17
|
'list.title': string;
|
|
11
18
|
'list.indexed': string;
|
|
12
19
|
'list.commit': string;
|
|
@@ -137,6 +144,7 @@ export declare const zhCN: {
|
|
|
137
144
|
'help.command.list.description': string;
|
|
138
145
|
'help.command.status.description': string;
|
|
139
146
|
'help.command.doctor.description': string;
|
|
147
|
+
'help.command.update.description': string;
|
|
140
148
|
'help.command.embeddings.description': string;
|
|
141
149
|
'help.command.embeddings.install.description': string;
|
|
142
150
|
'help.command.clean.description': string;
|
package/dist/cli/i18n/zh-CN.js
CHANGED
|
@@ -7,6 +7,13 @@ export const zhCN = {
|
|
|
7
7
|
'common.storage': '存储',
|
|
8
8
|
'common.deleted': '已删除:{{target}}',
|
|
9
9
|
'common.error': '错误:{{message}}',
|
|
10
|
+
'update.available': 'GitNexus {{latestVersion}} 已发布(当前运行 {{installedVersion}})。',
|
|
11
|
+
'update.current': 'GitNexus {{installedVersion}} 已是最新稳定版或不低于该版本。',
|
|
12
|
+
'update.installing': '正在执行 {{command}}…',
|
|
13
|
+
'update.installed': '已安装 gitnexus@{{version}}。请重启仍在运行的 mcp/serve 进程。',
|
|
14
|
+
'update.installFailed': 'npm 安装失败。可重试:{{command}}',
|
|
15
|
+
'update.installError': '无法运行 npm:{{message}}',
|
|
16
|
+
'update.checkFailed': '无法检查更新(离线、私有仓库,或检查失败)。',
|
|
10
17
|
'list.title': '已索引仓库({{count}})',
|
|
11
18
|
'list.indexed': '索引时间',
|
|
12
19
|
'list.commit': '提交',
|
|
@@ -137,6 +144,7 @@ export const zhCN = {
|
|
|
137
144
|
'help.command.list.description': '列出所有已索引仓库',
|
|
138
145
|
'help.command.status.description': '显示当前仓库的索引状态',
|
|
139
146
|
'help.command.doctor.description': '显示运行平台能力和嵌入配置',
|
|
147
|
+
'help.command.update.description': '通过 npm 全局安装最新发布的 GitNexus(`npm i -g gitnexus@<x.y.z>`)。',
|
|
140
148
|
'help.command.embeddings.description': '管理按需安装的本地嵌入运行时',
|
|
141
149
|
'help.command.embeddings.install.description': '按需安装本地嵌入组件(@huggingface/transformers + onnxruntime-node)。修复 npm 跳过可选包的安装(例如在 HTTP 代理后,#2370)。仅从你配置的 npm registry 下载 — 镜像和代理均生效。',
|
|
142
150
|
'help.command.clean.description': '删除当前仓库的 GitNexus 索引',
|
package/dist/cli/index.js
CHANGED
|
@@ -8,6 +8,8 @@ import { EMBEDDING_DIMS_ERROR, normalizeEmbeddingDims } from './embedding-dims.j
|
|
|
8
8
|
import { registerGroupCommands } from './group.js';
|
|
9
9
|
import { localizeCliHelp } from './help-i18n.js';
|
|
10
10
|
import { t } from './i18n/index.js';
|
|
11
|
+
import { writeCommandBanner } from './command-banner.js';
|
|
12
|
+
import { runProcessCliUpdateNotice } from './update-notice.js';
|
|
11
13
|
const _require = createRequire(import.meta.url);
|
|
12
14
|
const pkg = _require('../../package.json');
|
|
13
15
|
const program = new Command();
|
|
@@ -180,6 +182,10 @@ program
|
|
|
180
182
|
.command('doctor')
|
|
181
183
|
.description('Show runtime platform capabilities and embedding configuration')
|
|
182
184
|
.action(createLazyAction(() => import('./doctor.js'), 'doctorCommand'));
|
|
185
|
+
program
|
|
186
|
+
.command('update')
|
|
187
|
+
.description('Install the latest published GitNexus globally (`npm i -g gitnexus@<x.y.z>`).')
|
|
188
|
+
.action(createLazyAction(() => import('./update.js'), 'updateCommand'));
|
|
183
189
|
program
|
|
184
190
|
.command('embeddings')
|
|
185
191
|
.description('Manage the on-demand local embedding runtime')
|
|
@@ -324,6 +330,14 @@ program
|
|
|
324
330
|
.option('--host <host>', 'Bind address or resolvable hostname (default: 127.0.0.1; non-loopback requires GITNEXUS_AUTH_TOKEN; hostnames resolve to IPv4)')
|
|
325
331
|
.option('--idle-timeout <seconds>', 'Auto-shutdown after N seconds idle (0 = disabled)', '0')
|
|
326
332
|
.action(createLbugLazyAction(() => import('./eval-server.js'), 'evalServerCommand'));
|
|
333
|
+
program.command('__update-check', { hidden: true }).action(async () => {
|
|
334
|
+
const { refresh } = await import('../core/update-check.js');
|
|
335
|
+
await refresh();
|
|
336
|
+
});
|
|
327
337
|
registerGroupCommands(program);
|
|
328
338
|
localizeCliHelp(program);
|
|
339
|
+
program.hook('preAction', (_thisCommand, actionCommand) => {
|
|
340
|
+
writeCommandBanner(actionCommand);
|
|
341
|
+
});
|
|
342
|
+
runProcessCliUpdateNotice(typeof pkg.version === 'string' ? pkg.version : '');
|
|
329
343
|
program.parse(process.argv);
|
package/dist/cli/mcp.d.ts
CHANGED
|
@@ -26,9 +26,24 @@
|
|
|
26
26
|
* `mcpCommand` after the sentinel install. The regression test at
|
|
27
27
|
* `gitnexus/test/integration/mcp/import-closure.test.ts` enforces this.
|
|
28
28
|
*/
|
|
29
|
+
import type { UpdateState } from '../core/update-check.js';
|
|
30
|
+
interface McpUpdateLogger {
|
|
31
|
+
info(bindings: Record<string, unknown>, message: string): unknown;
|
|
32
|
+
}
|
|
33
|
+
interface McpUpdateChecker {
|
|
34
|
+
evaluate(): Promise<UpdateState | null>;
|
|
35
|
+
armUpdateRefreshScheduler(onState: (state: UpdateState | null) => void): () => void;
|
|
36
|
+
}
|
|
37
|
+
type LoadMcpUpdateChecker = () => Promise<McpUpdateChecker>;
|
|
38
|
+
/**
|
|
39
|
+
* Start the process-scoped MCP update adapter after its transport startup
|
|
40
|
+
* boundary. All failures stay inside this best-effort side channel.
|
|
41
|
+
*/
|
|
42
|
+
export declare function startMcpUpdateNotifier(logger: McpUpdateLogger, loadChecker?: LoadMcpUpdateChecker): Promise<void>;
|
|
29
43
|
export declare const mcpCommand: (options?: {
|
|
30
44
|
http?: boolean;
|
|
31
45
|
port?: string;
|
|
32
46
|
host?: string;
|
|
33
47
|
authToken?: string;
|
|
34
48
|
}) => Promise<void>;
|
|
49
|
+
export {};
|
package/dist/cli/mcp.js
CHANGED
|
@@ -27,6 +27,48 @@
|
|
|
27
27
|
* `gitnexus/test/integration/mcp/import-closure.test.ts` enforces this.
|
|
28
28
|
*/
|
|
29
29
|
import { installGlobalStdoutSentinel } from '../mcp/stdio-context.js';
|
|
30
|
+
const announcedUpdateVersions = new Set();
|
|
31
|
+
/**
|
|
32
|
+
* Start the process-scoped MCP update adapter after its transport startup
|
|
33
|
+
* boundary. All failures stay inside this best-effort side channel.
|
|
34
|
+
*/
|
|
35
|
+
export async function startMcpUpdateNotifier(logger, loadChecker = () => import('../core/update-check.js')) {
|
|
36
|
+
let checker;
|
|
37
|
+
try {
|
|
38
|
+
checker = await loadChecker();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const announce = (state) => {
|
|
44
|
+
try {
|
|
45
|
+
if (!state?.updateAvailable ||
|
|
46
|
+
!state.latestVersion ||
|
|
47
|
+
announcedUpdateVersions.has(state.latestVersion)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
announcedUpdateVersions.add(state.latestVersion);
|
|
51
|
+
logger.info({ event: 'gitnexus.update_available', latestVersion: state.latestVersion }, 'GitNexus update available');
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Logging must never escape into MCP startup or scheduler promises.
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
try {
|
|
58
|
+
announce(await checker.evaluate());
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Cache evaluation and any detached refresh are best-effort.
|
|
62
|
+
}
|
|
63
|
+
let stop;
|
|
64
|
+
try {
|
|
65
|
+
stop = checker.armUpdateRefreshScheduler(announce);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
process.once('exit', () => stop?.());
|
|
71
|
+
}
|
|
30
72
|
export const mcpCommand = async (options) => {
|
|
31
73
|
// Install the global stdout sentinel as the very first thing — before
|
|
32
74
|
// ANY other module loads. The static-import closure above is leaf-only
|
|
@@ -94,8 +136,10 @@ export const mcpCommand = async (options) => {
|
|
|
94
136
|
logger.error({ err: err instanceof Error ? err.message : err }, 'Failed to start the MCP HTTP server');
|
|
95
137
|
process.exit(1);
|
|
96
138
|
}
|
|
139
|
+
void startMcpUpdateNotifier(logger).catch(() => { });
|
|
97
140
|
return;
|
|
98
141
|
}
|
|
99
142
|
// Start MCP server (serves all repos, discovers new ones lazily)
|
|
100
143
|
await startMCPServer(backend, repositoryPolicy);
|
|
144
|
+
void startMcpUpdateNotifier(logger).catch(() => { });
|
|
101
145
|
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ValidatedUpdateCache } from '../core/update-cache.js';
|
|
2
|
+
type SpawnResult = {
|
|
3
|
+
unref(): void;
|
|
4
|
+
};
|
|
5
|
+
type SpawnLike = (command: string, args: readonly string[], options: {
|
|
6
|
+
detached: true;
|
|
7
|
+
stdio: 'ignore';
|
|
8
|
+
windowsHide: true;
|
|
9
|
+
}) => SpawnResult;
|
|
10
|
+
export interface CliUpdateNoticeDependencies {
|
|
11
|
+
argv: string[];
|
|
12
|
+
env: NodeJS.ProcessEnv;
|
|
13
|
+
installedVersion: string;
|
|
14
|
+
isTTY: boolean | undefined;
|
|
15
|
+
eligible: boolean;
|
|
16
|
+
now: number;
|
|
17
|
+
readCache: (options: {
|
|
18
|
+
env: NodeJS.ProcessEnv;
|
|
19
|
+
now: number;
|
|
20
|
+
}) => ValidatedUpdateCache | null;
|
|
21
|
+
writeStderr: (line: string) => unknown;
|
|
22
|
+
spawn: SpawnLike;
|
|
23
|
+
}
|
|
24
|
+
export declare function updateNoticeText(installedVersion: string, latestVersion: string): string;
|
|
25
|
+
/** Shared cache-gated notice line used by the CLI banner and `doctor`. */
|
|
26
|
+
export declare function cachedUpdateNoticeLine(options: {
|
|
27
|
+
installedVersion: string;
|
|
28
|
+
eligible: boolean;
|
|
29
|
+
env: NodeJS.ProcessEnv;
|
|
30
|
+
readCache: () => ValidatedUpdateCache | null;
|
|
31
|
+
}): string | null;
|
|
32
|
+
export declare function runCliUpdateNotice(deps: CliUpdateNoticeDependencies): void;
|
|
33
|
+
export declare function runProcessCliUpdateNotice(installedVersion: string): void;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { spawn as nodeSpawn } from 'node:child_process';
|
|
2
|
+
import { updateEligibleInstallSync } from '../core/install-context.js';
|
|
3
|
+
import { isNewerVersion, readValidatedUpdateCacheSync, updateNotifierOptedOut, updateRefreshInProgress, } from '../core/update-cache.js';
|
|
4
|
+
import { t } from './i18n/index.js';
|
|
5
|
+
const EXCLUDED_COMMANDS = new Set([
|
|
6
|
+
'augment',
|
|
7
|
+
'mcp',
|
|
8
|
+
'serve',
|
|
9
|
+
'eval-server',
|
|
10
|
+
'update',
|
|
11
|
+
'__update-check',
|
|
12
|
+
]);
|
|
13
|
+
const EXCLUDED_FLAGS = new Set(['--help', '-h', '--version', '-V']);
|
|
14
|
+
function excludedInvocation(argv) {
|
|
15
|
+
const args = argv.slice(2);
|
|
16
|
+
if (args.some((arg) => EXCLUDED_FLAGS.has(arg)))
|
|
17
|
+
return true;
|
|
18
|
+
const command = args.find((arg) => !arg.startsWith('-'));
|
|
19
|
+
return command !== undefined && EXCLUDED_COMMANDS.has(command);
|
|
20
|
+
}
|
|
21
|
+
export function updateNoticeText(installedVersion, latestVersion) {
|
|
22
|
+
return t('update.available', { installedVersion, latestVersion });
|
|
23
|
+
}
|
|
24
|
+
/** Shared cache-gated notice line used by the CLI banner and `doctor`. */
|
|
25
|
+
export function cachedUpdateNoticeLine(options) {
|
|
26
|
+
try {
|
|
27
|
+
if (!options.eligible || updateNotifierOptedOut(options.env))
|
|
28
|
+
return null;
|
|
29
|
+
const cache = options.readCache();
|
|
30
|
+
if (!cache?.latestVersion || !isNewerVersion(options.installedVersion, cache.latestVersion)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return updateNoticeText(options.installedVersion, cache.latestVersion);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function runCliUpdateNotice(deps) {
|
|
40
|
+
try {
|
|
41
|
+
if (deps.isTTY !== true ||
|
|
42
|
+
updateNotifierOptedOut(deps.env) ||
|
|
43
|
+
!deps.eligible ||
|
|
44
|
+
excludedInvocation(deps.argv)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const cache = deps.readCache({ env: deps.env, now: deps.now });
|
|
48
|
+
if (cache?.latestVersion && isNewerVersion(deps.installedVersion, cache.latestVersion)) {
|
|
49
|
+
deps.writeStderr(`${updateNoticeText(deps.installedVersion, cache.latestVersion)}\n`);
|
|
50
|
+
}
|
|
51
|
+
if (cache === null || cache.stale) {
|
|
52
|
+
// Coalesce parallel invocations: when a live process holds the refresh
|
|
53
|
+
// lock, its refresh covers us, so don't fork another CLI.
|
|
54
|
+
if (!updateRefreshInProgress(deps.env)) {
|
|
55
|
+
try {
|
|
56
|
+
deps
|
|
57
|
+
.spawn(process.execPath, [deps.argv[1] ?? '', '__update-check'], {
|
|
58
|
+
detached: true,
|
|
59
|
+
stdio: 'ignore',
|
|
60
|
+
windowsHide: true,
|
|
61
|
+
})
|
|
62
|
+
.unref();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Update refresh is best-effort and must never reach Commander parsing.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Cache reads and all adapter logic fail open.
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function runProcessCliUpdateNotice(installedVersion) {
|
|
75
|
+
if (process.stderr.isTTY !== true ||
|
|
76
|
+
updateNotifierOptedOut(process.env) ||
|
|
77
|
+
excludedInvocation(process.argv)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
runCliUpdateNotice({
|
|
81
|
+
argv: process.argv,
|
|
82
|
+
env: process.env,
|
|
83
|
+
installedVersion,
|
|
84
|
+
isTTY: process.stderr.isTTY,
|
|
85
|
+
eligible: updateEligibleInstallSync(),
|
|
86
|
+
now: Date.now(),
|
|
87
|
+
readCache: readValidatedUpdateCacheSync,
|
|
88
|
+
writeStderr: (line) => process.stderr.write(line),
|
|
89
|
+
spawn: nodeSpawn,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explicit `gitnexus update`: refresh the latest dist-tag, then install
|
|
3
|
+
* `gitnexus@<version>` globally with npm — the same shape as `claude update`
|
|
4
|
+
* / `codex update`. Other commands only notify; they never spawn npm.
|
|
5
|
+
*/
|
|
6
|
+
import { type UpdateState } from '../core/update-check.js';
|
|
7
|
+
export declare const UPDATE_PACKAGE = "gitnexus";
|
|
8
|
+
export interface UpdateCommandDependencies {
|
|
9
|
+
installedVersion: string;
|
|
10
|
+
refresh: (options: {
|
|
11
|
+
eligible: true;
|
|
12
|
+
ignoreOptOut: true;
|
|
13
|
+
installedVersion: string;
|
|
14
|
+
}) => Promise<UpdateState | null>;
|
|
15
|
+
writeStdout: (line: string) => void;
|
|
16
|
+
runInstall: (version: string) => Promise<number>;
|
|
17
|
+
setExitCode: (code: number) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function updateInstallArgs(version: string): string[];
|
|
20
|
+
export declare function updateInstallCommand(version: string): string;
|
|
21
|
+
export declare function updateCommand(maybeDeps?: unknown): Promise<void>;
|