gitnexus 1.6.13-rc.34 → 1.6.13-rc.36
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 +30 -2
- package/dist/cli/ai-context.js +11 -3
- package/dist/cli/analyze-options.d.ts +4 -0
- package/dist/cli/analyze.js +2 -0
- package/dist/cli/clean.d.ts +2 -0
- package/dist/cli/clean.js +95 -5
- package/dist/cli/doctor.js +7 -0
- package/dist/cli/editor-targets.d.ts +1 -1
- package/dist/cli/editor-targets.js +12 -0
- package/dist/cli/embeddings-sync.js +9 -1
- package/dist/cli/help-i18n.js +4 -0
- package/dist/cli/i18n/en.d.ts +20 -1
- package/dist/cli/i18n/en.js +20 -1
- package/dist/cli/i18n/resources.d.ts +39 -1
- package/dist/cli/i18n/zh-CN.d.ts +19 -0
- package/dist/cli/i18n/zh-CN.js +20 -1
- package/dist/cli/index.js +9 -1
- package/dist/cli/remove.js +3 -3
- package/dist/cli/setup.js +57 -0
- package/dist/cli/status.js +46 -0
- package/dist/core/augmentation/engine.js +4 -1
- package/dist/core/group/sync.js +2 -2
- package/dist/core/ingestion/class-extractors/configs/ruby.d.ts +13 -1
- package/dist/core/ingestion/class-extractors/configs/ruby.js +50 -2
- package/dist/core/ingestion/languages/ruby.js +17 -2
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +74 -0
- package/dist/core/ingestion/utils/ast-helpers.js +16 -0
- package/dist/core/run-analyze.d.ts +7 -0
- package/dist/core/run-analyze.js +127 -13
- package/dist/core/shared-store-analyze.d.ts +89 -0
- package/dist/core/shared-store-analyze.js +570 -0
- package/dist/mcp/local/local-backend.d.ts +8 -0
- package/dist/mcp/local/local-backend.js +23 -3
- package/dist/server/analyze-launch.js +27 -8
- package/dist/server/analyze-worker-ipc.d.ts +1 -1
- package/dist/server/analyze-worker-ipc.js +3 -0
- package/dist/server/api.js +39 -10
- package/dist/storage/git.d.ts +13 -0
- package/dist/storage/git.js +55 -0
- package/dist/storage/index-lock.d.ts +5 -0
- package/dist/storage/index-lock.js +1 -1
- package/dist/storage/repo-manager.d.ts +21 -3
- package/dist/storage/repo-manager.js +27 -5
- package/dist/storage/repo-meta.d.ts +6 -0
- package/dist/storage/shared-store-lifecycle.d.ts +95 -0
- package/dist/storage/shared-store-lifecycle.js +393 -0
- package/dist/storage/shared-store.d.ts +65 -0
- package/dist/storage/shared-store.js +297 -0
- package/dist/storage/storage-resolver.d.ts +2 -2
- package/dist/storage/storage-resolver.js +27 -32
- package/dist/storage/storage-slot.d.ts +17 -0
- package/dist/storage/storage-slot.js +48 -0
- package/hooks/claude/hook-db-lock-probe.cjs +74 -43
- package/hooks/claude/hook-lock.cjs +130 -6
- package/hooks/claude/registry-query.cjs +61 -29
- package/package.json +1 -1
- package/scripts/cross-platform-tests.ts +1 -0
- package/scripts/sync-plugin-manifests.mjs +13 -0
- package/web/assets/{abnfDiagram-PAR5IXJI-nRjsvWp-.js → abnfDiagram-PAR5IXJI-CM9OPETj.js} +1 -1
- package/web/assets/{agent-Bv5z78CW.js → agent-C8bWDcKv.js} +2 -2
- package/web/assets/{architectureDiagram-2PNWDENW-56fl8SSH.js → architectureDiagram-2PNWDENW-CFGPVOFL.js} +1 -1
- package/web/assets/{chunk-32MCUW2P-xLjc0mcF.js → chunk-32MCUW2P-BAKWSoJ_.js} +1 -1
- package/web/assets/{chunk-CLS4B6BI-DPDLP81t.js → chunk-CLS4B6BI-C6Eyf-Zq.js} +1 -1
- package/web/assets/{chunk-NF366YI6-D2OzsNXY.js → chunk-NF366YI6-BjQUpZZg.js} +1 -1
- package/web/assets/{chunk-SLDQ463B-DUcQswS-.js → chunk-SLDQ463B-DAs7sJcm.js} +1 -1
- package/web/assets/{classDiagram-FGAMPOII-q43g3Dpn.js → classDiagram-FGAMPOII-ipJcwT2g.js} +1 -1
- package/web/assets/{classDiagram-v2-AI5RJEK4-q43g3Dpn.js → classDiagram-v2-AI5RJEK4-ipJcwT2g.js} +1 -1
- package/web/assets/{cynefinDiagram-2OOWUY4M-Cfoko1Ws.js → cynefinDiagram-2OOWUY4M-BfCkzyqC.js} +1 -1
- package/web/assets/{dagre-MPVFI544-CTob3D2r.js → dagre-MPVFI544-CMeiFj2H.js} +1 -1
- package/web/assets/{diagram-AE4NWXFW-Dt2xfADa.js → diagram-AE4NWXFW-B7JUvrjH.js} +1 -1
- package/web/assets/{diagram-BUJID5UG-D-RUCl07.js → diagram-BUJID5UG-KMWjNniB.js} +1 -1
- package/web/assets/{diagram-C44CZ5NI-B9gPH4Gl.js → diagram-C44CZ5NI-Bx93uHLb.js} +1 -1
- package/web/assets/{diagram-EYOLEXXS-wR__cI23.js → diagram-EYOLEXXS-Dsja58oR.js} +1 -1
- package/web/assets/{ebnfDiagram-FTPZ3PV6-uw79FGz3.js → ebnfDiagram-FTPZ3PV6-Iwxb9NAS.js} +1 -1
- package/web/assets/{erDiagram-H3ERR26V-ZP_VIa5d.js → erDiagram-H3ERR26V-CJU6qpcb.js} +1 -1
- package/web/assets/{flowDiagram-YHGXBVSY-DEsmG3vH.js → flowDiagram-YHGXBVSY-Dz6dhw6j.js} +1 -1
- package/web/assets/{index-DofRiYRj.js → index-dXsywuPQ.js} +7 -7
- package/web/assets/{infoDiagram-LV547AFH-D1JPzJlf.js → infoDiagram-LV547AFH-P074dR6u.js} +1 -1
- package/web/assets/{ishikawaDiagram-PUJQGNDS-DxWZMRPX.js → ishikawaDiagram-PUJQGNDS-CZlaIkzm.js} +1 -1
- package/web/assets/{kanban-definition-JSQERAZB-S1lKJN_M.js → kanban-definition-JSQERAZB-BLX38hbF.js} +1 -1
- package/web/assets/{mindmap-definition-VBJCLQLM-JwX0Gc3J.js → mindmap-definition-VBJCLQLM-Bnu-7Z_9.js} +1 -1
- package/web/assets/{node.browser-C9G7Ehhe.js → node.browser-DIc1knUO.js} +1 -1
- package/web/assets/{pegDiagram-7WILOQTJ-DJWiAJJM.js → pegDiagram-7WILOQTJ-SH-3F770.js} +1 -1
- package/web/assets/{pieDiagram-EFA7CBSB-3i7IEboS.js → pieDiagram-EFA7CBSB-BGEXuMLa.js} +1 -1
- package/web/assets/{railroadDiagram-5NIQVNLQ-CQGcjlaN.js → railroadDiagram-5NIQVNLQ-DZMK703w.js} +1 -1
- package/web/assets/{requirementDiagram-SXREGOKZ-DH-LMk5X.js → requirementDiagram-SXREGOKZ-DLW6bNTm.js} +1 -1
- package/web/assets/{sequenceDiagram-52ZFIFDL-CrUW-Kdw.js → sequenceDiagram-52ZFIFDL-Bu6IKvYQ.js} +1 -1
- package/web/assets/{stateDiagram-3QAKPIVI-BuvX8wUJ.js → stateDiagram-3QAKPIVI-BrLxhUMB.js} +1 -1
- package/web/assets/{stateDiagram-v2-HN2P4RDZ-N7DodpOh.js → stateDiagram-v2-HN2P4RDZ-yZRLNv94.js} +1 -1
- package/web/assets/{swimlanes-QLVP42QD-DpvGI6UP.js → swimlanes-QLVP42QD-BN3CFF8X.js} +1 -1
- package/web/assets/{swimlanesDiagram-JKPDBFCN-Rd-o-as4.js → swimlanesDiagram-JKPDBFCN-BQ7NwLky.js} +1 -1
- package/web/assets/{timeline-definition-GS45XAXW-B9Rw1d9t.js → timeline-definition-GS45XAXW-DMlAtIe0.js} +1 -1
- package/web/assets/{vennDiagram-QIQU2ZRJ-CGo08RCI.js → vennDiagram-QIQU2ZRJ-DWmjtOEV.js} +1 -1
- package/web/assets/{wardleyDiagram-U6YNM66N-Dk7T5hBn.js → wardleyDiagram-U6YNM66N-BRdmEKKB.js} +1 -1
- package/web/assets/{xychartDiagram-XJAZEDNM-BJr5UGSi.js → xychartDiagram-XJAZEDNM-roHne1SF.js} +1 -1
- package/web/index.html +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Graph-powered code intelligence for AI agents.** Index any codebase into a knowledge graph, then query it via MCP or CLI.
|
|
4
4
|
|
|
5
|
-
Works with **Cursor**, **Claude Code**, **Antigravity** (Google), **Codex**, **Windsurf**, **Cline**, **OpenCode**, **CodeBuddy** (Tencent), **Qoder** (Alibaba), and any MCP-compatible tool.
|
|
5
|
+
Works with **Cursor**, **Claude Code**, **Antigravity** (Google), **Codex**, **Factory** (Droid), **Windsurf**, **Cline**, **OpenCode**, **CodeBuddy** (Tencent), **Qoder** (Alibaba), and any MCP-compatible tool.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/gitnexus)
|
|
8
8
|
[](https://polyformproject.org/licenses/noncommercial/1.0.0/)
|
|
@@ -44,12 +44,13 @@ To configure MCP for your editor, run `npx gitnexus setup` once — or set it up
|
|
|
44
44
|
| **Cursor** | Yes | Yes | Yes (postToolUse, [manual install](../gitnexus-cursor-integration/README.md#hook-install)) | **Full** |
|
|
45
45
|
| **Antigravity** (Google) | Yes | Yes | Yes (AfterTool, [Gemini CLI hooks schema](https://geminicli.com/docs/hooks/reference/)) | **Full** |
|
|
46
46
|
| **Codex** | Yes | Yes | Yes (PreToolUse + PostToolUse, [Codex hooks](https://developers.openai.com/codex/hooks)) | **Full** |
|
|
47
|
+
| **Factory** (Droid) | Yes | Yes | Yes (PostToolUse, [plugin](../gitnexus-factory-plugin/)) | **Full** |
|
|
47
48
|
| **OpenCode** | Yes | Yes | — | MCP + Skills |
|
|
48
49
|
| **CodeBuddy** (Tencent) | Yes | Yes | — | MCP + Skills |
|
|
49
50
|
| **Qoder** (Alibaba) | Yes | Yes | — | MCP + Skills |
|
|
50
51
|
| **Windsurf** | Yes | — | — | MCP |
|
|
51
52
|
|
|
52
|
-
> **
|
|
53
|
+
> **Full** means MCP tools + agent skills + hooks that enrich searches with graph context. **Claude Code** and **Codex** go deepest: their PreToolUse hooks enrich the search before it runs, and their PostToolUse hooks also detect a stale index after commits and prompt the agent to reindex. **Cursor**, **Antigravity**, and **Factory** augment from a post-tool hook only, so they enrich the result rather than the query and do not carry the stale-index hint.
|
|
53
54
|
|
|
54
55
|
### Community Integrations
|
|
55
56
|
|
|
@@ -88,6 +89,33 @@ codex plugin marketplace add abhigyanpatwari/GitNexus
|
|
|
88
89
|
|
|
89
90
|
> **Codex notes:** SessionStart is intentionally not registered — Codex reads [AGENTS.md natively](https://developers.openai.com/codex/guides/agents-md), which already carries the GitNexus context block. Newly installed hooks need a one-time approval in Codex via `/hooks` before they run. Pick **one** install route (`gitnexus setup -c codex` **or** the plugin): plugin hooks load alongside `~/.codex/hooks.json`, so installing both can fire duplicate hooks per tool call.
|
|
90
91
|
|
|
92
|
+
### Factory (Droid) (full support — MCP + skills + hooks)
|
|
93
|
+
|
|
94
|
+
`gitnexus setup -c droid` writes the MCP server to `~/.factory/mcp.json` and installs skills to
|
|
95
|
+
`~/.factory/skills/`. To configure MCP by hand instead, add to `~/.factory/mcp.json`
|
|
96
|
+
([user scope](https://docs.factory.ai/cli/configuration/mcp) — applies to all projects):
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"mcpServers": {
|
|
101
|
+
"gitnexus": {
|
|
102
|
+
"command": "npx",
|
|
103
|
+
"args": ["-y", "gitnexus@latest", "mcp"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For the PostToolUse search-augment hook, install the bundled
|
|
110
|
+
[`gitnexus-factory-plugin/`](../gitnexus-factory-plugin/) with `droid plugin install gitnexus@<marketplace>`
|
|
111
|
+
from a marketplace that includes this repo, or point Droid at it via `extraKnownMarketplaces` in
|
|
112
|
+
`.factory/settings.json`.
|
|
113
|
+
|
|
114
|
+
> **Factory notes:** Droid reads [AGENTS.md natively](https://docs.factory.ai/), which already carries the
|
|
115
|
+
> GitNexus context block, so no SessionStart hook is registered. Pick **one** install route
|
|
116
|
+
> (`gitnexus setup -c droid` **or** the plugin) — the plugin ships its own MCP entry, so installing both
|
|
117
|
+
> can register the server twice.
|
|
118
|
+
|
|
91
119
|
### Cursor / Windsurf
|
|
92
120
|
|
|
93
121
|
Add to `~/.cursor/mcp.json` (global — works for all projects):
|
package/dist/cli/ai-context.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* AGENTS.md is the standard read by Cursor, Windsurf, OpenCode, Codex, Cline, CodeBuddy, Qoder, etc.
|
|
6
6
|
* CLAUDE.md is for Claude Code which only reads that file.
|
|
7
7
|
*/
|
|
8
|
+
import { GITNEXUS_DIR } from '../storage/storage-constants.js';
|
|
9
|
+
import { storeRootOfCheckoutSlot } from '../storage/shared-store.js';
|
|
8
10
|
import fs from 'fs/promises';
|
|
9
11
|
import path from 'path';
|
|
10
12
|
import { fileURLToPath } from 'url';
|
|
@@ -470,11 +472,17 @@ export async function generateAIContextFiles(repoPath, storagePath, projectName,
|
|
|
470
472
|
// CLI and hooks already share; failure to copy is non-fatal (docs carry a
|
|
471
473
|
// bootstrap fallback). `runnerPath` is project-relative with POSIX separators
|
|
472
474
|
// so the emitted command is identical across platforms.
|
|
473
|
-
|
|
475
|
+
// A shared-store slot (#3352) lives under the GitNexus home, so its path
|
|
476
|
+
// would be machine- and worktree-specific in committed docs; the runner goes
|
|
477
|
+
// next to the checkout's store pointer instead.
|
|
478
|
+
const runnerDir = storeRootOfCheckoutSlot(storagePath)
|
|
479
|
+
? path.join(repoPath, GITNEXUS_DIR)
|
|
480
|
+
: storagePath;
|
|
481
|
+
const runnerPath = path.relative(repoPath, path.join(runnerDir, 'run.cjs')).replace(/\\/g, '/');
|
|
474
482
|
try {
|
|
475
483
|
const runnerSrc = path.join(__dirname, '..', '..', 'hooks', 'claude', 'resolve-analyze-cmd.cjs');
|
|
476
|
-
await fs.mkdir(
|
|
477
|
-
await fs.copyFile(runnerSrc, path.join(
|
|
484
|
+
await fs.mkdir(runnerDir, { recursive: true });
|
|
485
|
+
await fs.copyFile(runnerSrc, path.join(runnerDir, 'run.cjs'));
|
|
478
486
|
}
|
|
479
487
|
catch (err) {
|
|
480
488
|
logger.warn(`Could not write GitNexus runner to ${runnerPath}: ${String(err)}`);
|
|
@@ -103,6 +103,10 @@ export interface AnalyzeOptions {
|
|
|
103
103
|
* `allowDuplicateName` option end-to-end.
|
|
104
104
|
*/
|
|
105
105
|
allowDuplicateName?: boolean;
|
|
106
|
+
/** `--share-with <repo>`: join that checkout's shared store (#3352). */
|
|
107
|
+
shareWith?: string;
|
|
108
|
+
/** `--no-share` sets this to false: leave the shared store (#3352). */
|
|
109
|
+
share?: boolean;
|
|
106
110
|
/**
|
|
107
111
|
* Override the walker's large-file skip threshold (#991). Value in KB;
|
|
108
112
|
* clamped downstream to the tree-sitter 32 MB ceiling. Sets
|
package/dist/cli/analyze.js
CHANGED
|
@@ -1128,6 +1128,8 @@ const analyzeCommandImpl = async (inputPath, cliOptions, runnerIdentityAtBootstr
|
|
|
1128
1128
|
// be able to accept the duplicate name without also paying the
|
|
1129
1129
|
// cost of a full pipeline re-index. See #829 review round 2.
|
|
1130
1130
|
allowDuplicateName: options.allowDuplicateName,
|
|
1131
|
+
shareWith: options.shareWith,
|
|
1132
|
+
noShare: options.share === false,
|
|
1131
1133
|
// Worker pool size threaded from --workers, replacing the previous
|
|
1132
1134
|
// GITNEXUS_WORKER_POOL_SIZE env mutation. `undefined` defers to the
|
|
1133
1135
|
// env / auto-formula fallback inside the pipeline.
|
package/dist/cli/clean.d.ts
CHANGED
package/dist/cli/clean.js
CHANGED
|
@@ -9,11 +9,14 @@ import path from 'path';
|
|
|
9
9
|
import { logger } from '../core/logger.js';
|
|
10
10
|
import { findRegistryEntryByRepoPath, findRepo, unregisterRepo, listRegisteredRepos, getStoragePaths, } from '../storage/repo-manager.js';
|
|
11
11
|
import { requireDeletableStoragePath, StorageDeletionError } from '../storage/storage-resolver.js';
|
|
12
|
-
import { formatStaleSlotLine } from './stale-branch-format.js';
|
|
12
|
+
import { formatSlotSize, formatStaleSlotLine } from './stale-branch-format.js';
|
|
13
13
|
import { listLocalHeads } from '../storage/git.js';
|
|
14
14
|
import { isContainedBranchDir, isDeleteCandidate, listStaleBranchSlots, removeBranchSlot, staleListingBlock, } from '../storage/stale-branch-slots.js';
|
|
15
15
|
import { cleanParkedLbugSidecars, inspectLbugSidecars, listParkedLbugSidecars, } from '../core/lbug/sidecar-recovery.js';
|
|
16
16
|
import { t } from './i18n/index.js';
|
|
17
|
+
import { getGlobalDir } from '../storage/global-dir.js';
|
|
18
|
+
import { STORES_DIR } from '../storage/shared-store.js';
|
|
19
|
+
import { findLegacyLocalIndex, reclaimAfterSlotRemoval, reclaimSharedStore, removeLegacyLocalIndex, removeCheckoutStorage, } from '../storage/shared-store-lifecycle.js';
|
|
17
20
|
const resolveOwnedCwdStorage = async (refusePrefix) => {
|
|
18
21
|
const repo = await findRepo(process.cwd());
|
|
19
22
|
if (!repo) {
|
|
@@ -115,7 +118,91 @@ const cleanStaleBranchSlots = async (force) => {
|
|
|
115
118
|
printStaleSlotLines(t('clean.stale.probeFailed'), probeFailed);
|
|
116
119
|
}
|
|
117
120
|
};
|
|
121
|
+
const reportReclaim = (result) => {
|
|
122
|
+
if (!result)
|
|
123
|
+
return;
|
|
124
|
+
if (result.removed.length > 0) {
|
|
125
|
+
console.log(t('clean.shared.reclaimed', { count: result.removed.length }));
|
|
126
|
+
}
|
|
127
|
+
if (result.kept.length > 0)
|
|
128
|
+
console.log(t('clean.shared.kept', { count: result.kept.length }));
|
|
129
|
+
};
|
|
130
|
+
/** `clean --gc`: collect every shared store under GITNEXUS_HOME (#3352). */
|
|
131
|
+
const collectSharedStores = async (force) => {
|
|
132
|
+
const storesDir = path.join(getGlobalDir(), STORES_DIR);
|
|
133
|
+
// Only a missing stores root means "nothing to collect"; an unreadable one
|
|
134
|
+
// must fail loudly rather than report success.
|
|
135
|
+
const names = await fs.readdir(storesDir).catch((err) => {
|
|
136
|
+
if (err.code === 'ENOENT')
|
|
137
|
+
return [];
|
|
138
|
+
throw err;
|
|
139
|
+
});
|
|
140
|
+
// Stray files (`.DS_Store`) are not stores, and a symlink is not followed:
|
|
141
|
+
// reclaim deletes under the root it is given. A store another collector
|
|
142
|
+
// removed meanwhile is simply gone. The lstat skips a stray link; it is not
|
|
143
|
+
// a race guard, since stores/ belongs to the user running clean and anyone
|
|
144
|
+
// able to swap an entry there can already delete the store itself.
|
|
145
|
+
const roots = [];
|
|
146
|
+
for (const name of names) {
|
|
147
|
+
const root = path.join(storesDir, name);
|
|
148
|
+
const stat = await fs.lstat(root).catch((err) => {
|
|
149
|
+
if (err.code === 'ENOENT')
|
|
150
|
+
return null;
|
|
151
|
+
throw err;
|
|
152
|
+
});
|
|
153
|
+
if (stat?.isDirectory())
|
|
154
|
+
roots.push(root);
|
|
155
|
+
}
|
|
156
|
+
if (roots.length === 0) {
|
|
157
|
+
console.log(t('clean.gc.none'));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
for (const root of roots) {
|
|
161
|
+
// Without --force this is a preview: same selection, nothing deleted.
|
|
162
|
+
const result = await reclaimSharedStore(root, { gc: true, dryRun: !force });
|
|
163
|
+
console.log(t(force ? 'clean.gc.store' : 'clean.gc.preview', {
|
|
164
|
+
path: root,
|
|
165
|
+
members: result.droppedMembers.length,
|
|
166
|
+
graphs: result.removed.length,
|
|
167
|
+
}));
|
|
168
|
+
if (result.keptMembers.length > 0) {
|
|
169
|
+
console.log(t('clean.gc.keptMembers', { count: result.keptMembers.length }));
|
|
170
|
+
}
|
|
171
|
+
if (result.kept.length > 0)
|
|
172
|
+
console.log(t('clean.shared.kept', { count: result.kept.length }));
|
|
173
|
+
if (result.storeRemoved)
|
|
174
|
+
console.log(t('clean.shared.storeRemoved', { path: root }));
|
|
175
|
+
}
|
|
176
|
+
if (!force)
|
|
177
|
+
console.log(`\n${t('common.runForceConfirm')}`);
|
|
178
|
+
};
|
|
118
179
|
export const cleanCommand = async (options) => {
|
|
180
|
+
if (options?.gc) {
|
|
181
|
+
await collectSharedStores(options.force === true);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
// --local-index: delete a pre-adoption index left in <checkout>/.gitnexus
|
|
185
|
+
// after the checkout moved into a shared store (#3352). Keeps the pointer.
|
|
186
|
+
if (options?.localIndex) {
|
|
187
|
+
const repo = await findRepo(process.cwd());
|
|
188
|
+
if (!repo) {
|
|
189
|
+
console.log(t('clean.notFoundHere'));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const legacy = await findLegacyLocalIndex(repo.repoPath, repo.storagePath);
|
|
193
|
+
if (!legacy) {
|
|
194
|
+
console.log(t('clean.localIndex.none'));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (!options.force) {
|
|
198
|
+
console.log(t('clean.localIndex.preview', { path: legacy.dir, size: formatSlotSize(legacy.bytes) }));
|
|
199
|
+
console.log(`\n${t('common.runForceConfirm')}`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
await removeLegacyLocalIndex(repo.repoPath, repo.storagePath);
|
|
203
|
+
console.log(t('clean.localIndex.deleted', { path: legacy.dir, size: formatSlotSize(legacy.bytes) }));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
119
206
|
// --stale: reclaim leftover per-branch slots whose recorded branch is not
|
|
120
207
|
// a live local head (#3331). Exclusive arm before --branch.
|
|
121
208
|
if (options?.stale) {
|
|
@@ -246,9 +333,12 @@ export const cleanCommand = async (options) => {
|
|
|
246
333
|
for (const entry of entries) {
|
|
247
334
|
try {
|
|
248
335
|
const storagePath = await requireDeletableStoragePath(entry);
|
|
249
|
-
|
|
250
|
-
|
|
336
|
+
// A shared slot is unregistered before it is deleted: its lock file
|
|
337
|
+
// lives inside it, so it must go last. A failed delete throws with the
|
|
338
|
+
// `clean --gc --force` recovery (shared-store-clean.test.ts).
|
|
339
|
+
await removeCheckoutStorage(storagePath, () => unregisterRepo(entry.path), entry.path);
|
|
251
340
|
console.log(t('clean.deletedRepo', { name: entry.name, storagePath }));
|
|
341
|
+
reportReclaim(await reclaimAfterSlotRemoval(storagePath));
|
|
252
342
|
}
|
|
253
343
|
catch (err) {
|
|
254
344
|
if (err instanceof StorageDeletionError) {
|
|
@@ -289,9 +379,9 @@ export const cleanCommand = async (options) => {
|
|
|
289
379
|
return;
|
|
290
380
|
}
|
|
291
381
|
try {
|
|
292
|
-
await
|
|
293
|
-
await unregisterRepo(repo.repoPath);
|
|
382
|
+
await removeCheckoutStorage(storagePath, () => unregisterRepo(repo.repoPath), repo.repoPath);
|
|
294
383
|
console.log(t('common.deleted', { target: storagePath }));
|
|
384
|
+
reportReclaim(await reclaimAfterSlotRemoval(storagePath));
|
|
295
385
|
}
|
|
296
386
|
catch (err) {
|
|
297
387
|
logger.error({ err }, 'Failed to delete:');
|
package/dist/cli/doctor.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getRuntimeCapabilities, getRuntimeFingerprint } from '../core/platform/capabilities.js';
|
|
2
|
+
import { findLegacyLocalIndex } from '../storage/shared-store-lifecycle.js';
|
|
2
3
|
import { resolveEmbeddingConfig } from '../core/embeddings/config.js';
|
|
3
4
|
import { isHttpMode } from '../core/embeddings/http-client.js';
|
|
4
5
|
import { getLocalEmbeddingRuntimeBlocker, localEmbeddingPrefixUnloadableMessage, localEmbeddingStackMissingMessage, } from '../core/embeddings/runtime-support.js';
|
|
@@ -327,6 +328,12 @@ export const doctorCommand = async () => {
|
|
|
327
328
|
branches: entry?.branches,
|
|
328
329
|
});
|
|
329
330
|
const leftoverLines = leftoverBranchSlotDoctorLines(slots);
|
|
331
|
+
// A pre-adoption index left in <repo>/.gitnexus after this checkout moved
|
|
332
|
+
// into a shared store (#3352).
|
|
333
|
+
const legacy = await findLegacyLocalIndex(cwdRepo.repoPath, cwdRepo.storagePath);
|
|
334
|
+
if (legacy) {
|
|
335
|
+
leftoverLines.push(t('status.legacyLocalIndex', { path: legacy.dir, size: formatSlotSize(legacy.bytes) }));
|
|
336
|
+
}
|
|
330
337
|
if (leftoverLines.length === 0)
|
|
331
338
|
return;
|
|
332
339
|
console.log('');
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* implementations remain behaviourally symmetrical on top of this shared
|
|
16
16
|
* structure.
|
|
17
17
|
*/
|
|
18
|
-
export type EditorId = 'cursor' | 'claude' | 'antigravity' | 'opencode' | 'codebuddy' | 'qoder' | 'codex';
|
|
18
|
+
export type EditorId = 'cursor' | 'claude' | 'antigravity' | 'opencode' | 'codebuddy' | 'qoder' | 'codex' | 'droid';
|
|
19
19
|
/** An editor whose MCP config is a JSONC document (server keyed by name). */
|
|
20
20
|
export interface McpJsoncTarget {
|
|
21
21
|
id: EditorId;
|
|
@@ -76,6 +76,15 @@ export function getEditorTargets(home = os.homedir()) {
|
|
|
76
76
|
file: path.join(home, '.qoder.json'),
|
|
77
77
|
keyPath: ['mcpServers', 'gitnexus'],
|
|
78
78
|
},
|
|
79
|
+
{
|
|
80
|
+
id: 'droid',
|
|
81
|
+
label: 'Factory Droid',
|
|
82
|
+
// Factory's user-scope MCP config (https://docs.factory.ai/cli/configuration/mcp).
|
|
83
|
+
// Same `mcpServers` object shape as Cursor/Claude; user config takes
|
|
84
|
+
// precedence over project-level .factory/mcp.json.
|
|
85
|
+
file: path.join(home, '.factory', 'mcp.json'),
|
|
86
|
+
keyPath: ['mcpServers', 'gitnexus'],
|
|
87
|
+
},
|
|
79
88
|
];
|
|
80
89
|
const codex = {
|
|
81
90
|
id: 'codex',
|
|
@@ -98,6 +107,9 @@ export function getEditorTargets(home = os.homedir()) {
|
|
|
98
107
|
{ id: 'qoder', label: 'Qoder', dir: path.join(home, '.qoder', 'skills') },
|
|
99
108
|
// Codex reads skills from ~/.agents/skills (not ~/.codex).
|
|
100
109
|
{ id: 'codex', label: 'Codex', dir: path.join(home, '.agents', 'skills') },
|
|
110
|
+
// Factory Droid reads user-scope skills from ~/.factory/skills/{name}/SKILL.md
|
|
111
|
+
// (https://docs.factory.ai/cli/configuration/skills).
|
|
112
|
+
{ id: 'droid', label: 'Factory Droid', dir: path.join(home, '.factory', 'skills') },
|
|
101
113
|
];
|
|
102
114
|
const hooks = [
|
|
103
115
|
{
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { lstat } from 'node:fs/promises';
|
|
2
|
+
import { ensurePrivateSharedGraph } from '../core/shared-store-analyze.js';
|
|
3
|
+
import { LBUG_DIRECTORY } from '../storage/storage-constants.js';
|
|
2
4
|
import path from 'node:path';
|
|
3
5
|
import { cliInfo } from './cli-message.js';
|
|
4
6
|
import { getGitRoot } from '../storage/git.js';
|
|
@@ -17,11 +19,17 @@ export const embeddingsSyncCommand = async (inputPath) => {
|
|
|
17
19
|
const repoPath = inputPath ? path.resolve(inputPath) : getGitRoot(process.cwd());
|
|
18
20
|
if (!repoPath)
|
|
19
21
|
throw new Error('Not inside a git repository. Pass a repository path.');
|
|
20
|
-
const {
|
|
22
|
+
const { metaPath } = getStoragePaths(repoPath);
|
|
21
23
|
const metaDir = path.dirname(metaPath);
|
|
24
|
+
// Writes go to the slot's own graph. A shared-store checkout that reads an
|
|
25
|
+
// immutable commit graph (#3352) takes a private copy first.
|
|
26
|
+
const lbugPath = path.join(metaDir, LBUG_DIRECTORY);
|
|
22
27
|
const lock = await acquireIndexLock(metaDir);
|
|
23
28
|
try {
|
|
24
29
|
requireExclusiveIndexLock(lock, `Cannot acquire the index lock at ${metaDir}; refusing an unlocked embeddings sync.`);
|
|
30
|
+
if (!(await ensurePrivateSharedGraph(metaDir, (m) => console.log(` ${m}`)))) {
|
|
31
|
+
throw new Error('The shared graph this checkout reads is gone. Run gitnexus analyze first.');
|
|
32
|
+
}
|
|
25
33
|
const meta = await loadMeta(metaDir);
|
|
26
34
|
if (!meta)
|
|
27
35
|
throw new Error(`No GitNexus index found for ${repoPath}. Run gitnexus analyze first.`);
|
package/dist/cli/help-i18n.js
CHANGED
|
@@ -63,6 +63,8 @@ const OPTION_DESCRIPTION_KEYS = {
|
|
|
63
63
|
'analyze|--skip-git': 'help.option.skipGit',
|
|
64
64
|
'analyze|--name <alias>': 'help.option.analyze.name',
|
|
65
65
|
'analyze|--allow-duplicate-name': 'help.option.analyze.allowDuplicateName',
|
|
66
|
+
'analyze|--share-with <repo>': 'help.option.analyze.shareWith',
|
|
67
|
+
'analyze|--no-share': 'help.option.analyze.noShare',
|
|
66
68
|
'analyze|-v, --verbose': 'help.option.verbose',
|
|
67
69
|
'analyze|--max-file-size <kb>': 'help.option.analyze.maxFileSize',
|
|
68
70
|
'analyze|--worker-timeout <seconds>': 'help.option.analyze.workerTimeout',
|
|
@@ -93,6 +95,8 @@ const OPTION_DESCRIPTION_KEYS = {
|
|
|
93
95
|
'clean|--branch <name>': 'help.option.clean.branch',
|
|
94
96
|
'clean|--lbug-sidecars': 'help.option.clean.lbugSidecars',
|
|
95
97
|
'clean|--stale': 'help.option.clean.stale',
|
|
98
|
+
'clean|--gc': 'help.option.clean.gc',
|
|
99
|
+
'clean|--local-index': 'help.option.clean.localIndex',
|
|
96
100
|
'remove|-f, --force': 'help.option.force.confirmation',
|
|
97
101
|
'wiki|-f, --force': 'help.option.wiki.force',
|
|
98
102
|
'wiki|--provider <provider>': 'help.option.wiki.provider',
|
package/dist/cli/i18n/en.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ export declare const en: {
|
|
|
25
25
|
readonly 'list.clusters': 'Clusters';
|
|
26
26
|
readonly 'list.processes': 'Processes';
|
|
27
27
|
readonly 'list.unknown': 'unknown';
|
|
28
|
+
readonly 'status.sharedStoreShared': 'Shared index: store {{key}}, shared graph for commit {{commit}}';
|
|
29
|
+
readonly 'status.sharedStorePrivate': 'Shared index: store {{key}}, private graph (local changes or a pinned branch index)';
|
|
30
|
+
readonly 'status.sharedStoreCloneCow': ' Copied copy-on-write: unchanged pages are shared with the commit graph on disk';
|
|
31
|
+
readonly 'status.sharedStoreCloneCopy': ' Full copy: this filesystem cannot clone copy-on-write (APFS, btrfs and XFS can)';
|
|
32
|
+
readonly 'status.legacyLocalIndex': 'Leftover local index: {{path}} ({{size}}); remove it with `gitnexus clean --local-index --force`';
|
|
28
33
|
readonly 'status.notGitRepo': 'Not a git repository.';
|
|
29
34
|
readonly 'status.staleKuzu': 'Repository has a stale KuzuDB index from a previous version.';
|
|
30
35
|
readonly 'status.rebuildLadybug': 'Run: gitnexus analyze (rebuilds the index with LadybugDB)';
|
|
@@ -52,6 +57,16 @@ export declare const en: {
|
|
|
52
57
|
readonly 'clean.deleteAll': 'This will delete GitNexus indexes for {{count}} repo(s):';
|
|
53
58
|
readonly 'clean.deletedRepo': 'Deleted: {{name}} ({{storagePath}})';
|
|
54
59
|
readonly 'clean.notFoundHere': 'No indexed repository found in this directory.';
|
|
60
|
+
readonly 'clean.shared.reclaimed': 'Shared store: removed {{count}} commit graph(s) no checkout references.';
|
|
61
|
+
readonly 'clean.shared.kept': 'Shared store: kept {{count}} unreferenced commit graph(s) that could not be removed (in use or not writable); run `gitnexus clean --gc` later.';
|
|
62
|
+
readonly 'clean.shared.storeRemoved': 'Shared store: removed {{path}} (no checkouts remain).';
|
|
63
|
+
readonly 'clean.gc.none': 'No shared stores to collect.';
|
|
64
|
+
readonly 'clean.gc.keptMembers': 'Shared store: kept {{count}} checkout(s) it could not delete; run `gitnexus clean --gc --force` later.';
|
|
65
|
+
readonly 'clean.gc.store': 'Shared store {{path}}: dropped {{members}} checkout(s), removed {{graphs}} commit graph(s).';
|
|
66
|
+
readonly 'clean.gc.preview': 'Shared store {{path}}: would drop {{members}} checkout(s) and remove {{graphs}} commit graph(s).';
|
|
67
|
+
readonly 'clean.localIndex.none': 'No leftover local index in this checkout.';
|
|
68
|
+
readonly 'clean.localIndex.preview': 'This will delete the leftover local index at {{path}} ({{size}}). The shared index is not affected.';
|
|
69
|
+
readonly 'clean.localIndex.deleted': 'Deleted the leftover local index at {{path}} ({{size}}).';
|
|
55
70
|
readonly 'clean.deleteCurrent': 'This will delete the GitNexus index for: {{repoName}}';
|
|
56
71
|
readonly 'clean.branchNotIndexed': 'No indexed branch named "{{branch}}" for this repository. Use `gitnexus clean --stale` to reclaim leftover branch indexes, or `gitnexus list` to see recorded names.';
|
|
57
72
|
readonly 'clean.stale.none': 'No leftover branch indexes to reclaim.';
|
|
@@ -152,7 +167,7 @@ export declare const en: {
|
|
|
152
167
|
readonly 'help.command.help.description': 'display help for command';
|
|
153
168
|
readonly 'help.option.help': 'display help for command';
|
|
154
169
|
readonly 'help.option.version': 'output the version number';
|
|
155
|
-
readonly 'help.command.setup.description': 'One-time setup: configure MCP for Cursor, Claude Code, Antigravity, OpenCode, CodeBuddy, Qoder, Codex';
|
|
170
|
+
readonly 'help.command.setup.description': 'One-time setup: configure MCP for Cursor, Claude Code, Antigravity, OpenCode, CodeBuddy, Qoder, Codex, Factory Droid';
|
|
156
171
|
readonly 'help.command.uninstall.description': 'Reverse `setup`: remove GitNexus MCP entries, skills, and hooks from all detected editors';
|
|
157
172
|
readonly 'help.command.autoSync.description': 'Control scheduled repository clone/pull and analysis from GITNEXUS_HOME/watch_config.yml';
|
|
158
173
|
readonly 'help.autoSync.details': '\nActions: init, start (default), restart, stop, status, reset\nConfiguration: GITNEXUS_HOME/watch_config.yml\nRuntime files: GITNEXUS_HOME/watch/watch.pid, watch.mutex, watch.owner.json, watch.status.json, auto-sync-state.json\nRecovery: mutexes with verified dead owners are reclaimed automatically; invalid or legacy mutexes fail closed and require manual removal after confirming no watch process is running.\nWrites: GITNEXUS_HOME/watch/project_commit_info.txt\nRemote URLs: only SSH URLs on github.com, gitlab.com, and gitee.com are allowed.\nRuns once immediately, then repeats on sync_interval_minutes.';
|
|
@@ -208,6 +223,8 @@ export declare const en: {
|
|
|
208
223
|
readonly 'help.option.skipGit': 'Treat the provided path/cwd as the index root and skip parent git-root discovery';
|
|
209
224
|
readonly 'help.option.analyze.name': 'Register this repo under a custom name in ~/.gitnexus/registry.json (disambiguates repos whose paths share a basename, e.g. two different .../app folders)';
|
|
210
225
|
readonly 'help.option.analyze.allowDuplicateName': 'Register this repo even if another path already uses the same --name alias. Leaves `-r <name>` ambiguous for the two paths; use -r <path> to disambiguate.';
|
|
226
|
+
readonly 'help.option.analyze.shareWith': 'Join the shared index store of a registered checkout of the same repository (name or path); the remote URL must match. Clones join a sibling clone’s store automatically; this names one explicitly and clears a --no-share opt-out.';
|
|
227
|
+
readonly 'help.option.analyze.noShare': 'Clones only: leave the shared index store, index into <repo>/.gitnexus again, and stop joining sibling clones automatically until --share-with (linked worktrees always share; set GITNEXUS_SHARED_STORE=off instead)';
|
|
211
228
|
readonly 'help.option.verbose': 'Enable verbose output';
|
|
212
229
|
readonly 'help.option.analyze.maxFileSize': 'Skip files larger than this (KB). Default: 512. Hard cap: 32768 (tree-sitter limit).';
|
|
213
230
|
readonly 'help.option.analyze.workerTimeout': 'Worker sub-batch idle timeout before retry/fallback. Default: 30.';
|
|
@@ -236,6 +253,8 @@ export declare const en: {
|
|
|
236
253
|
readonly 'help.option.clean.branch': 'Delete only the named branch index (not the workspace index)';
|
|
237
254
|
readonly 'help.option.clean.lbugSidecars': 'Clean parked LadybugDB recovery sidecars (missing-shadow WAL quarantines and dirty-recovery parks)';
|
|
238
255
|
readonly 'help.option.clean.stale': 'Reclaim leftover branch indexes that are not a live local head';
|
|
256
|
+
readonly 'help.option.clean.gc': 'Drop shared-store checkouts no registry entry uses and delete commit graphs nothing references';
|
|
257
|
+
readonly 'help.option.clean.localIndex': 'Delete the index left in <repo>/.gitnexus after this checkout moved into a shared store';
|
|
239
258
|
readonly 'help.option.wiki.force': 'Force full regeneration even if up to date';
|
|
240
259
|
readonly 'help.option.wiki.provider': 'LLM provider: minimax, openai, openrouter, azure, custom, cursor, claude, codex, opencode, or grok (default: minimax)';
|
|
241
260
|
readonly 'help.option.wiki.model': 'LLM model or deployment name (default: MiniMax-M3)';
|
package/dist/cli/i18n/en.js
CHANGED
|
@@ -25,6 +25,11 @@ export const en = {
|
|
|
25
25
|
'list.clusters': 'Clusters',
|
|
26
26
|
'list.processes': 'Processes',
|
|
27
27
|
'list.unknown': 'unknown',
|
|
28
|
+
'status.sharedStoreShared': 'Shared index: store {{key}}, shared graph for commit {{commit}}',
|
|
29
|
+
'status.sharedStorePrivate': 'Shared index: store {{key}}, private graph (local changes or a pinned branch index)',
|
|
30
|
+
'status.sharedStoreCloneCow': ' Copied copy-on-write: unchanged pages are shared with the commit graph on disk',
|
|
31
|
+
'status.sharedStoreCloneCopy': ' Full copy: this filesystem cannot clone copy-on-write (APFS, btrfs and XFS can)',
|
|
32
|
+
'status.legacyLocalIndex': 'Leftover local index: {{path}} ({{size}}); remove it with `gitnexus clean --local-index --force`',
|
|
28
33
|
'status.notGitRepo': 'Not a git repository.',
|
|
29
34
|
'status.staleKuzu': 'Repository has a stale KuzuDB index from a previous version.',
|
|
30
35
|
'status.rebuildLadybug': 'Run: gitnexus analyze (rebuilds the index with LadybugDB)',
|
|
@@ -52,6 +57,16 @@ export const en = {
|
|
|
52
57
|
'clean.deleteAll': 'This will delete GitNexus indexes for {{count}} repo(s):',
|
|
53
58
|
'clean.deletedRepo': 'Deleted: {{name}} ({{storagePath}})',
|
|
54
59
|
'clean.notFoundHere': 'No indexed repository found in this directory.',
|
|
60
|
+
'clean.shared.reclaimed': 'Shared store: removed {{count}} commit graph(s) no checkout references.',
|
|
61
|
+
'clean.shared.kept': 'Shared store: kept {{count}} unreferenced commit graph(s) that could not be removed (in use or not writable); run `gitnexus clean --gc` later.',
|
|
62
|
+
'clean.shared.storeRemoved': 'Shared store: removed {{path}} (no checkouts remain).',
|
|
63
|
+
'clean.gc.none': 'No shared stores to collect.',
|
|
64
|
+
'clean.gc.keptMembers': 'Shared store: kept {{count}} checkout(s) it could not delete; run `gitnexus clean --gc --force` later.',
|
|
65
|
+
'clean.gc.store': 'Shared store {{path}}: dropped {{members}} checkout(s), removed {{graphs}} commit graph(s).',
|
|
66
|
+
'clean.gc.preview': 'Shared store {{path}}: would drop {{members}} checkout(s) and remove {{graphs}} commit graph(s).',
|
|
67
|
+
'clean.localIndex.none': 'No leftover local index in this checkout.',
|
|
68
|
+
'clean.localIndex.preview': 'This will delete the leftover local index at {{path}} ({{size}}). The shared index is not affected.',
|
|
69
|
+
'clean.localIndex.deleted': 'Deleted the leftover local index at {{path}} ({{size}}).',
|
|
55
70
|
'clean.deleteCurrent': 'This will delete the GitNexus index for: {{repoName}}',
|
|
56
71
|
'clean.branchNotIndexed': 'No indexed branch named "{{branch}}" for this repository. Use `gitnexus clean --stale` to reclaim leftover branch indexes, or `gitnexus list` to see recorded names.',
|
|
57
72
|
'clean.stale.none': 'No leftover branch indexes to reclaim.',
|
|
@@ -154,7 +169,7 @@ export const en = {
|
|
|
154
169
|
'help.command.help.description': 'display help for command',
|
|
155
170
|
'help.option.help': 'display help for command',
|
|
156
171
|
'help.option.version': 'output the version number',
|
|
157
|
-
'help.command.setup.description': 'One-time setup: configure MCP for Cursor, Claude Code, Antigravity, OpenCode, CodeBuddy, Qoder, Codex',
|
|
172
|
+
'help.command.setup.description': 'One-time setup: configure MCP for Cursor, Claude Code, Antigravity, OpenCode, CodeBuddy, Qoder, Codex, Factory Droid',
|
|
158
173
|
'help.command.uninstall.description': 'Reverse `setup`: remove GitNexus MCP entries, skills, and hooks from all detected editors',
|
|
159
174
|
'help.command.autoSync.description': 'Control scheduled repository clone/pull and analysis from GITNEXUS_HOME/watch_config.yml',
|
|
160
175
|
'help.autoSync.details': '\nActions: init, start (default), restart, stop, status, reset\nConfiguration: GITNEXUS_HOME/watch_config.yml\nRuntime files: GITNEXUS_HOME/watch/watch.pid, watch.mutex, watch.owner.json, watch.status.json, auto-sync-state.json\nRecovery: mutexes with verified dead owners are reclaimed automatically; invalid or legacy mutexes fail closed and require manual removal after confirming no watch process is running.\nWrites: GITNEXUS_HOME/watch/project_commit_info.txt\nRemote URLs: only SSH URLs on github.com, gitlab.com, and gitee.com are allowed.\nRuns once immediately, then repeats on sync_interval_minutes.',
|
|
@@ -210,6 +225,8 @@ export const en = {
|
|
|
210
225
|
'help.option.skipGit': 'Treat the provided path/cwd as the index root and skip parent git-root discovery',
|
|
211
226
|
'help.option.analyze.name': 'Register this repo under a custom name in ~/.gitnexus/registry.json (disambiguates repos whose paths share a basename, e.g. two different .../app folders)',
|
|
212
227
|
'help.option.analyze.allowDuplicateName': 'Register this repo even if another path already uses the same --name alias. Leaves `-r <name>` ambiguous for the two paths; use -r <path> to disambiguate.',
|
|
228
|
+
'help.option.analyze.shareWith': 'Join the shared index store of a registered checkout of the same repository (name or path); the remote URL must match. Clones join a sibling clone’s store automatically; this names one explicitly and clears a --no-share opt-out.',
|
|
229
|
+
'help.option.analyze.noShare': 'Clones only: leave the shared index store, index into <repo>/.gitnexus again, and stop joining sibling clones automatically until --share-with (linked worktrees always share; set GITNEXUS_SHARED_STORE=off instead)',
|
|
213
230
|
'help.option.verbose': 'Enable verbose output',
|
|
214
231
|
'help.option.analyze.maxFileSize': 'Skip files larger than this (KB). Default: 512. Hard cap: 32768 (tree-sitter limit).',
|
|
215
232
|
'help.option.analyze.workerTimeout': 'Worker sub-batch idle timeout before retry/fallback. Default: 30.',
|
|
@@ -238,6 +255,8 @@ export const en = {
|
|
|
238
255
|
'help.option.clean.branch': 'Delete only the named branch index (not the workspace index)',
|
|
239
256
|
'help.option.clean.lbugSidecars': 'Clean parked LadybugDB recovery sidecars (missing-shadow WAL quarantines and dirty-recovery parks)',
|
|
240
257
|
'help.option.clean.stale': 'Reclaim leftover branch indexes that are not a live local head',
|
|
258
|
+
'help.option.clean.gc': 'Drop shared-store checkouts no registry entry uses and delete commit graphs nothing references',
|
|
259
|
+
'help.option.clean.localIndex': 'Delete the index left in <repo>/.gitnexus after this checkout moved into a shared store',
|
|
241
260
|
'help.option.wiki.force': 'Force full regeneration even if up to date',
|
|
242
261
|
'help.option.wiki.provider': 'LLM provider: minimax, openai, openrouter, azure, custom, cursor, claude, codex, opencode, or grok (default: minimax)',
|
|
243
262
|
'help.option.wiki.model': 'LLM model or deployment name (default: MiniMax-M3)',
|
|
@@ -26,6 +26,11 @@ export declare const cliResources: {
|
|
|
26
26
|
readonly 'list.clusters': 'Clusters';
|
|
27
27
|
readonly 'list.processes': 'Processes';
|
|
28
28
|
readonly 'list.unknown': 'unknown';
|
|
29
|
+
readonly 'status.sharedStoreShared': 'Shared index: store {{key}}, shared graph for commit {{commit}}';
|
|
30
|
+
readonly 'status.sharedStorePrivate': 'Shared index: store {{key}}, private graph (local changes or a pinned branch index)';
|
|
31
|
+
readonly 'status.sharedStoreCloneCow': ' Copied copy-on-write: unchanged pages are shared with the commit graph on disk';
|
|
32
|
+
readonly 'status.sharedStoreCloneCopy': ' Full copy: this filesystem cannot clone copy-on-write (APFS, btrfs and XFS can)';
|
|
33
|
+
readonly 'status.legacyLocalIndex': 'Leftover local index: {{path}} ({{size}}); remove it with `gitnexus clean --local-index --force`';
|
|
29
34
|
readonly 'status.notGitRepo': 'Not a git repository.';
|
|
30
35
|
readonly 'status.staleKuzu': 'Repository has a stale KuzuDB index from a previous version.';
|
|
31
36
|
readonly 'status.rebuildLadybug': 'Run: gitnexus analyze (rebuilds the index with LadybugDB)';
|
|
@@ -53,6 +58,16 @@ export declare const cliResources: {
|
|
|
53
58
|
readonly 'clean.deleteAll': 'This will delete GitNexus indexes for {{count}} repo(s):';
|
|
54
59
|
readonly 'clean.deletedRepo': 'Deleted: {{name}} ({{storagePath}})';
|
|
55
60
|
readonly 'clean.notFoundHere': 'No indexed repository found in this directory.';
|
|
61
|
+
readonly 'clean.shared.reclaimed': 'Shared store: removed {{count}} commit graph(s) no checkout references.';
|
|
62
|
+
readonly 'clean.shared.kept': 'Shared store: kept {{count}} unreferenced commit graph(s) that could not be removed (in use or not writable); run `gitnexus clean --gc` later.';
|
|
63
|
+
readonly 'clean.shared.storeRemoved': 'Shared store: removed {{path}} (no checkouts remain).';
|
|
64
|
+
readonly 'clean.gc.none': 'No shared stores to collect.';
|
|
65
|
+
readonly 'clean.gc.keptMembers': 'Shared store: kept {{count}} checkout(s) it could not delete; run `gitnexus clean --gc --force` later.';
|
|
66
|
+
readonly 'clean.gc.store': 'Shared store {{path}}: dropped {{members}} checkout(s), removed {{graphs}} commit graph(s).';
|
|
67
|
+
readonly 'clean.gc.preview': 'Shared store {{path}}: would drop {{members}} checkout(s) and remove {{graphs}} commit graph(s).';
|
|
68
|
+
readonly 'clean.localIndex.none': 'No leftover local index in this checkout.';
|
|
69
|
+
readonly 'clean.localIndex.preview': 'This will delete the leftover local index at {{path}} ({{size}}). The shared index is not affected.';
|
|
70
|
+
readonly 'clean.localIndex.deleted': 'Deleted the leftover local index at {{path}} ({{size}}).';
|
|
56
71
|
readonly 'clean.deleteCurrent': 'This will delete the GitNexus index for: {{repoName}}';
|
|
57
72
|
readonly 'clean.branchNotIndexed': 'No indexed branch named "{{branch}}" for this repository. Use `gitnexus clean --stale` to reclaim leftover branch indexes, or `gitnexus list` to see recorded names.';
|
|
58
73
|
readonly 'clean.stale.none': 'No leftover branch indexes to reclaim.';
|
|
@@ -153,7 +168,7 @@ export declare const cliResources: {
|
|
|
153
168
|
readonly 'help.command.help.description': 'display help for command';
|
|
154
169
|
readonly 'help.option.help': 'display help for command';
|
|
155
170
|
readonly 'help.option.version': 'output the version number';
|
|
156
|
-
readonly 'help.command.setup.description': 'One-time setup: configure MCP for Cursor, Claude Code, Antigravity, OpenCode, CodeBuddy, Qoder, Codex';
|
|
171
|
+
readonly 'help.command.setup.description': 'One-time setup: configure MCP for Cursor, Claude Code, Antigravity, OpenCode, CodeBuddy, Qoder, Codex, Factory Droid';
|
|
157
172
|
readonly 'help.command.uninstall.description': 'Reverse `setup`: remove GitNexus MCP entries, skills, and hooks from all detected editors';
|
|
158
173
|
readonly 'help.command.autoSync.description': 'Control scheduled repository clone/pull and analysis from GITNEXUS_HOME/watch_config.yml';
|
|
159
174
|
readonly 'help.autoSync.details': '\nActions: init, start (default), restart, stop, status, reset\nConfiguration: GITNEXUS_HOME/watch_config.yml\nRuntime files: GITNEXUS_HOME/watch/watch.pid, watch.mutex, watch.owner.json, watch.status.json, auto-sync-state.json\nRecovery: mutexes with verified dead owners are reclaimed automatically; invalid or legacy mutexes fail closed and require manual removal after confirming no watch process is running.\nWrites: GITNEXUS_HOME/watch/project_commit_info.txt\nRemote URLs: only SSH URLs on github.com, gitlab.com, and gitee.com are allowed.\nRuns once immediately, then repeats on sync_interval_minutes.';
|
|
@@ -209,6 +224,8 @@ export declare const cliResources: {
|
|
|
209
224
|
readonly 'help.option.skipGit': 'Treat the provided path/cwd as the index root and skip parent git-root discovery';
|
|
210
225
|
readonly 'help.option.analyze.name': 'Register this repo under a custom name in ~/.gitnexus/registry.json (disambiguates repos whose paths share a basename, e.g. two different .../app folders)';
|
|
211
226
|
readonly 'help.option.analyze.allowDuplicateName': 'Register this repo even if another path already uses the same --name alias. Leaves `-r <name>` ambiguous for the two paths; use -r <path> to disambiguate.';
|
|
227
|
+
readonly 'help.option.analyze.shareWith': 'Join the shared index store of a registered checkout of the same repository (name or path); the remote URL must match. Clones join a sibling clone’s store automatically; this names one explicitly and clears a --no-share opt-out.';
|
|
228
|
+
readonly 'help.option.analyze.noShare': 'Clones only: leave the shared index store, index into <repo>/.gitnexus again, and stop joining sibling clones automatically until --share-with (linked worktrees always share; set GITNEXUS_SHARED_STORE=off instead)';
|
|
212
229
|
readonly 'help.option.verbose': 'Enable verbose output';
|
|
213
230
|
readonly 'help.option.analyze.maxFileSize': 'Skip files larger than this (KB). Default: 512. Hard cap: 32768 (tree-sitter limit).';
|
|
214
231
|
readonly 'help.option.analyze.workerTimeout': 'Worker sub-batch idle timeout before retry/fallback. Default: 30.';
|
|
@@ -237,6 +254,8 @@ export declare const cliResources: {
|
|
|
237
254
|
readonly 'help.option.clean.branch': 'Delete only the named branch index (not the workspace index)';
|
|
238
255
|
readonly 'help.option.clean.lbugSidecars': 'Clean parked LadybugDB recovery sidecars (missing-shadow WAL quarantines and dirty-recovery parks)';
|
|
239
256
|
readonly 'help.option.clean.stale': 'Reclaim leftover branch indexes that are not a live local head';
|
|
257
|
+
readonly 'help.option.clean.gc': 'Drop shared-store checkouts no registry entry uses and delete commit graphs nothing references';
|
|
258
|
+
readonly 'help.option.clean.localIndex': 'Delete the index left in <repo>/.gitnexus after this checkout moved into a shared store';
|
|
240
259
|
readonly 'help.option.wiki.force': 'Force full regeneration even if up to date';
|
|
241
260
|
readonly 'help.option.wiki.provider': 'LLM provider: minimax, openai, openrouter, azure, custom, cursor, claude, codex, opencode, or grok (default: minimax)';
|
|
242
261
|
readonly 'help.option.wiki.model': 'LLM model or deployment name (default: MiniMax-M3)';
|
|
@@ -333,6 +352,11 @@ export declare const cliResources: {
|
|
|
333
352
|
'list.clusters': string;
|
|
334
353
|
'list.processes': string;
|
|
335
354
|
'list.unknown': string;
|
|
355
|
+
'status.sharedStoreShared': string;
|
|
356
|
+
'status.sharedStorePrivate': string;
|
|
357
|
+
'status.sharedStoreCloneCow': string;
|
|
358
|
+
'status.sharedStoreCloneCopy': string;
|
|
359
|
+
'status.legacyLocalIndex': string;
|
|
336
360
|
'status.notGitRepo': string;
|
|
337
361
|
'status.staleKuzu': string;
|
|
338
362
|
'status.rebuildLadybug': string;
|
|
@@ -360,6 +384,16 @@ export declare const cliResources: {
|
|
|
360
384
|
'clean.deleteAll': string;
|
|
361
385
|
'clean.deletedRepo': string;
|
|
362
386
|
'clean.notFoundHere': string;
|
|
387
|
+
'clean.shared.reclaimed': string;
|
|
388
|
+
'clean.shared.kept': string;
|
|
389
|
+
'clean.shared.storeRemoved': string;
|
|
390
|
+
'clean.gc.none': string;
|
|
391
|
+
'clean.gc.keptMembers': string;
|
|
392
|
+
'clean.gc.store': string;
|
|
393
|
+
'clean.gc.preview': string;
|
|
394
|
+
'clean.localIndex.none': string;
|
|
395
|
+
'clean.localIndex.preview': string;
|
|
396
|
+
'clean.localIndex.deleted': string;
|
|
363
397
|
'clean.deleteCurrent': string;
|
|
364
398
|
'clean.branchNotIndexed': string;
|
|
365
399
|
'clean.stale.none': string;
|
|
@@ -516,6 +550,8 @@ export declare const cliResources: {
|
|
|
516
550
|
'help.option.skipGit': string;
|
|
517
551
|
'help.option.analyze.name': string;
|
|
518
552
|
'help.option.analyze.allowDuplicateName': string;
|
|
553
|
+
'help.option.analyze.shareWith': string;
|
|
554
|
+
'help.option.analyze.noShare': string;
|
|
519
555
|
'help.option.verbose': string;
|
|
520
556
|
'help.option.analyze.maxFileSize': string;
|
|
521
557
|
'help.option.analyze.workerTimeout': string;
|
|
@@ -544,6 +580,8 @@ export declare const cliResources: {
|
|
|
544
580
|
'help.option.clean.branch': string;
|
|
545
581
|
'help.option.clean.lbugSidecars': string;
|
|
546
582
|
'help.option.clean.stale': string;
|
|
583
|
+
'help.option.clean.gc': string;
|
|
584
|
+
'help.option.clean.localIndex': string;
|
|
547
585
|
'help.option.wiki.force': string;
|
|
548
586
|
'help.option.wiki.provider': string;
|
|
549
587
|
'help.option.wiki.model': string;
|
package/dist/cli/i18n/zh-CN.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ export declare const zhCN: {
|
|
|
25
25
|
'list.clusters': string;
|
|
26
26
|
'list.processes': string;
|
|
27
27
|
'list.unknown': string;
|
|
28
|
+
'status.sharedStoreShared': string;
|
|
29
|
+
'status.sharedStorePrivate': string;
|
|
30
|
+
'status.sharedStoreCloneCow': string;
|
|
31
|
+
'status.sharedStoreCloneCopy': string;
|
|
32
|
+
'status.legacyLocalIndex': string;
|
|
28
33
|
'status.notGitRepo': string;
|
|
29
34
|
'status.staleKuzu': string;
|
|
30
35
|
'status.rebuildLadybug': string;
|
|
@@ -52,6 +57,16 @@ export declare const zhCN: {
|
|
|
52
57
|
'clean.deleteAll': string;
|
|
53
58
|
'clean.deletedRepo': string;
|
|
54
59
|
'clean.notFoundHere': string;
|
|
60
|
+
'clean.shared.reclaimed': string;
|
|
61
|
+
'clean.shared.kept': string;
|
|
62
|
+
'clean.shared.storeRemoved': string;
|
|
63
|
+
'clean.gc.none': string;
|
|
64
|
+
'clean.gc.keptMembers': string;
|
|
65
|
+
'clean.gc.store': string;
|
|
66
|
+
'clean.gc.preview': string;
|
|
67
|
+
'clean.localIndex.none': string;
|
|
68
|
+
'clean.localIndex.preview': string;
|
|
69
|
+
'clean.localIndex.deleted': string;
|
|
55
70
|
'clean.deleteCurrent': string;
|
|
56
71
|
'clean.branchNotIndexed': string;
|
|
57
72
|
'clean.stale.none': string;
|
|
@@ -208,6 +223,8 @@ export declare const zhCN: {
|
|
|
208
223
|
'help.option.skipGit': string;
|
|
209
224
|
'help.option.analyze.name': string;
|
|
210
225
|
'help.option.analyze.allowDuplicateName': string;
|
|
226
|
+
'help.option.analyze.shareWith': string;
|
|
227
|
+
'help.option.analyze.noShare': string;
|
|
211
228
|
'help.option.verbose': string;
|
|
212
229
|
'help.option.analyze.maxFileSize': string;
|
|
213
230
|
'help.option.analyze.workerTimeout': string;
|
|
@@ -236,6 +253,8 @@ export declare const zhCN: {
|
|
|
236
253
|
'help.option.clean.branch': string;
|
|
237
254
|
'help.option.clean.lbugSidecars': string;
|
|
238
255
|
'help.option.clean.stale': string;
|
|
256
|
+
'help.option.clean.gc': string;
|
|
257
|
+
'help.option.clean.localIndex': string;
|
|
239
258
|
'help.option.wiki.force': string;
|
|
240
259
|
'help.option.wiki.provider': string;
|
|
241
260
|
'help.option.wiki.model': string;
|