gitnexus 1.6.13-rc.23 → 1.6.13-rc.25
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/dist/cli/clean.d.ts +1 -0
- package/dist/cli/clean.js +114 -13
- package/dist/cli/doctor.d.ts +7 -0
- package/dist/cli/doctor.js +50 -0
- package/dist/cli/help-i18n.js +1 -0
- package/dist/cli/i18n/en.d.ts +21 -1
- package/dist/cli/i18n/en.js +21 -1
- package/dist/cli/i18n/resources.d.ts +41 -1
- package/dist/cli/i18n/zh-CN.d.ts +20 -0
- package/dist/cli/i18n/zh-CN.js +21 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/stale-branch-format.d.ts +4 -0
- package/dist/cli/stale-branch-format.js +34 -0
- package/dist/storage/git.d.ts +6 -0
- package/dist/storage/git.js +31 -1
- package/dist/storage/repo-manager.d.ts +2 -0
- package/dist/storage/repo-manager.js +5 -0
- package/dist/storage/stale-branch-slots.d.ts +46 -0
- package/dist/storage/stale-branch-slots.js +300 -0
- package/package.json +1 -1
- package/web/assets/{abnfDiagram-PAR5IXJI-BbkO1pGM.js → abnfDiagram-PAR5IXJI-8u563MEU.js} +1 -1
- package/web/assets/{agent-CJi9-qSV.js → agent-DyMwsoMH.js} +2 -2
- package/web/assets/{architectureDiagram-2PNWDENW-DogGaV6A.js → architectureDiagram-2PNWDENW-BjWbN2PO.js} +1 -1
- package/web/assets/{chunk-32MCUW2P-Ctlz9gwz.js → chunk-32MCUW2P-DEek-0Ht.js} +1 -1
- package/web/assets/{chunk-CLS4B6BI-CUaYtG_9.js → chunk-CLS4B6BI-D8hARACd.js} +1 -1
- package/web/assets/{chunk-NF366YI6-Qj4nm-M7.js → chunk-NF366YI6-B-9n0uvs.js} +1 -1
- package/web/assets/{chunk-SLDQ463B-BV20g0Ip.js → chunk-SLDQ463B-BskBwVBC.js} +1 -1
- package/web/assets/{classDiagram-FGAMPOII-BJ3tM2Pw.js → classDiagram-FGAMPOII-DaSs7-5O.js} +1 -1
- package/web/assets/{classDiagram-v2-AI5RJEK4-BJ3tM2Pw.js → classDiagram-v2-AI5RJEK4-DaSs7-5O.js} +1 -1
- package/web/assets/{cynefinDiagram-2OOWUY4M-tlBa8eNB.js → cynefinDiagram-2OOWUY4M-DjbooVji.js} +1 -1
- package/web/assets/{dagre-MPVFI544-BYv3SuFs.js → dagre-MPVFI544-B-wqpxUN.js} +1 -1
- package/web/assets/{diagram-AE4NWXFW-CNU2EXJM.js → diagram-AE4NWXFW-Bkmf_O6L.js} +1 -1
- package/web/assets/{diagram-BUJID5UG-NdiVLl-k.js → diagram-BUJID5UG-CbUC2Fie.js} +1 -1
- package/web/assets/{diagram-C44CZ5NI-Crd33kec.js → diagram-C44CZ5NI-dwPTAnfj.js} +1 -1
- package/web/assets/{diagram-EYOLEXXS-DSuOnVRp.js → diagram-EYOLEXXS-OD8zf2mA.js} +1 -1
- package/web/assets/{ebnfDiagram-FTPZ3PV6-CZaFjKJN.js → ebnfDiagram-FTPZ3PV6-u4D1E694.js} +1 -1
- package/web/assets/{erDiagram-H3ERR26V-k9RqGdZo.js → erDiagram-H3ERR26V-BBtjOXBa.js} +1 -1
- package/web/assets/{flowDiagram-YHGXBVSY-J9Z9GYtM.js → flowDiagram-YHGXBVSY-C7uNeQLW.js} +1 -1
- package/web/assets/{index-C7HdBqix.js → index-BvcE-KTJ.js} +70 -70
- package/web/assets/{infoDiagram-LV547AFH-DIxUoHUu.js → infoDiagram-LV547AFH-BHH9OuWU.js} +1 -1
- package/web/assets/{ishikawaDiagram-PUJQGNDS-B17wOvKI.js → ishikawaDiagram-PUJQGNDS-uat_n043.js} +1 -1
- package/web/assets/{kanban-definition-JSQERAZB-CkMxG6ux.js → kanban-definition-JSQERAZB-Cc-n7-iv.js} +1 -1
- package/web/assets/{mindmap-definition-VBJCLQLM-D3NcUXdF.js → mindmap-definition-VBJCLQLM-CcnYi775.js} +1 -1
- package/web/assets/{node.browser-GepThmNa.js → node.browser-Dx1ppNym.js} +1 -1
- package/web/assets/{pegDiagram-7WILOQTJ-DK-8FVqJ.js → pegDiagram-7WILOQTJ-CjsU2E8I.js} +1 -1
- package/web/assets/{pieDiagram-EFA7CBSB-B5a1nRL0.js → pieDiagram-EFA7CBSB-DFarVbT5.js} +1 -1
- package/web/assets/{railroadDiagram-5NIQVNLQ-DX9znCx0.js → railroadDiagram-5NIQVNLQ-BOc4TKmb.js} +1 -1
- package/web/assets/{requirementDiagram-SXREGOKZ-GuKNX_G7.js → requirementDiagram-SXREGOKZ-IYeU8wzI.js} +1 -1
- package/web/assets/{sequenceDiagram-52ZFIFDL-BqvlsagX.js → sequenceDiagram-52ZFIFDL-Bvb237FL.js} +1 -1
- package/web/assets/{stateDiagram-3QAKPIVI-CGtuJb_I.js → stateDiagram-3QAKPIVI-Bj5eSjtk.js} +1 -1
- package/web/assets/{stateDiagram-v2-HN2P4RDZ-B9XtRUVy.js → stateDiagram-v2-HN2P4RDZ-CgNVPo1K.js} +1 -1
- package/web/assets/{swimlanes-QLVP42QD-D6DRxdhV.js → swimlanes-QLVP42QD-BBXlMTuI.js} +1 -1
- package/web/assets/{swimlanesDiagram-JKPDBFCN-BbdS67fA.js → swimlanesDiagram-JKPDBFCN-g8DoalWG.js} +1 -1
- package/web/assets/{timeline-definition-GS45XAXW-Nh9YvCo_.js → timeline-definition-GS45XAXW-Dkl4ie3U.js} +1 -1
- package/web/assets/{vennDiagram-QIQU2ZRJ-ClVab1a4.js → vennDiagram-QIQU2ZRJ-8swT0k92.js} +1 -1
- package/web/assets/{wardleyDiagram-U6YNM66N-BRhCx1wz.js → wardleyDiagram-U6YNM66N-CtH6gYM2.js} +1 -1
- package/web/assets/{xychartDiagram-XJAZEDNM-uPLq3TT_.js → xychartDiagram-XJAZEDNM-BkWLFLb6.js} +1 -1
- package/web/index.html +1 -1
package/dist/cli/clean.d.ts
CHANGED
package/dist/cli/clean.js
CHANGED
|
@@ -7,11 +7,112 @@
|
|
|
7
7
|
import fs from 'fs/promises';
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import { logger } from '../core/logger.js';
|
|
10
|
-
import { findRepo, unregisterRepo, listRegisteredRepos, getStoragePaths,
|
|
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';
|
|
13
|
+
import { listLocalHeads } from '../storage/git.js';
|
|
14
|
+
import { isContainedBranchDir, isDeleteCandidate, listStaleBranchSlots, removeBranchSlot, staleListingBlock, } from '../storage/stale-branch-slots.js';
|
|
12
15
|
import { cleanParkedLbugSidecars, inspectLbugSidecars, listParkedLbugSidecars, } from '../core/lbug/sidecar-recovery.js';
|
|
13
16
|
import { t } from './i18n/index.js';
|
|
14
17
|
export const cleanCommand = async (options) => {
|
|
18
|
+
// --stale: reclaim leftover per-branch slots whose recorded branch is not
|
|
19
|
+
// a live local head (#3331). Exclusive arm before --branch.
|
|
20
|
+
if (options?.stale) {
|
|
21
|
+
const cwd = process.cwd();
|
|
22
|
+
const repo = await findRepo(cwd);
|
|
23
|
+
if (!repo) {
|
|
24
|
+
console.log(t('clean.notFoundHere'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const entries = await listRegisteredRepos();
|
|
28
|
+
const entry = findRegistryEntryByRepoPath(entries, repo.repoPath);
|
|
29
|
+
let storagePath;
|
|
30
|
+
try {
|
|
31
|
+
storagePath = await requireDeletableStoragePath({
|
|
32
|
+
path: repo.repoPath,
|
|
33
|
+
storagePath: repo.storagePath,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
if (err instanceof StorageDeletionError) {
|
|
38
|
+
logger.error(`Refusing to clean leftover branch indexes: ${err.message}`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
const slots = await listStaleBranchSlots({
|
|
44
|
+
repoPath: repo.repoPath,
|
|
45
|
+
storagePath,
|
|
46
|
+
branches: entry?.branches,
|
|
47
|
+
includeSize: !options.force,
|
|
48
|
+
});
|
|
49
|
+
const listingBlock = staleListingBlock(slots);
|
|
50
|
+
if (listingBlock === 'heads-unavailable') {
|
|
51
|
+
console.log(t('clean.stale.headsUnavailable'));
|
|
52
|
+
for (const slot of slots.filter((row) => row.reason === 'heads-unavailable')) {
|
|
53
|
+
console.log(` - ${formatStaleSlotLine(slot)}`);
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (listingBlock === 'listing-failed') {
|
|
58
|
+
console.log(t('clean.stale.listingFailed'));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const candidates = slots.filter(isDeleteCandidate);
|
|
62
|
+
const probeFailed = slots.filter((slot) => slot.reason === 'probe-failed');
|
|
63
|
+
const printProbeFailed = () => {
|
|
64
|
+
console.log(t('clean.stale.probeFailed'));
|
|
65
|
+
for (const slot of probeFailed) {
|
|
66
|
+
console.log(` - ${formatStaleSlotLine(slot)}`);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
if (candidates.length === 0) {
|
|
70
|
+
if (probeFailed.length > 0) {
|
|
71
|
+
printProbeFailed();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
console.log(t('clean.stale.none'));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!options.force) {
|
|
78
|
+
console.log(t('clean.stale.preview', { count: candidates.length }));
|
|
79
|
+
for (const slot of candidates) {
|
|
80
|
+
console.log(` - ${formatStaleSlotLine(slot)}`);
|
|
81
|
+
}
|
|
82
|
+
if (probeFailed.length > 0) {
|
|
83
|
+
printProbeFailed();
|
|
84
|
+
}
|
|
85
|
+
console.log(`\n${t('common.runForceConfirm')}`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
for (const slot of candidates) {
|
|
89
|
+
const heads = listLocalHeads(repo.repoPath);
|
|
90
|
+
if (heads === null) {
|
|
91
|
+
console.log(t('clean.stale.headsUnavailable'));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (heads.includes(slot.branch)) {
|
|
95
|
+
console.log(t('clean.stale.skippedLive', { branch: slot.branch }));
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const result = await removeBranchSlot({
|
|
99
|
+
repoPath: repo.repoPath,
|
|
100
|
+
storagePath,
|
|
101
|
+
branch: slot.branch,
|
|
102
|
+
dir: slot.dir,
|
|
103
|
+
});
|
|
104
|
+
if (!result.ok) {
|
|
105
|
+
console.log(t('clean.stale.failed', { branch: slot.branch }));
|
|
106
|
+
logger.error({ err: result.error }, 'Failed to delete leftover branch index:');
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
console.log(t('clean.stale.deleted', { branch: slot.branch }));
|
|
110
|
+
}
|
|
111
|
+
if (probeFailed.length > 0) {
|
|
112
|
+
printProbeFailed();
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
15
116
|
// --branch <name>: remove a single non-primary branch's index (#2106 R7).
|
|
16
117
|
// Resolve against the RECORDED branches[] summary (never by slugging the
|
|
17
118
|
// user's raw input, which can disagree with the index-time-sanitized label).
|
|
@@ -23,7 +124,7 @@ export const cleanCommand = async (options) => {
|
|
|
23
124
|
return;
|
|
24
125
|
}
|
|
25
126
|
const entries = await listRegisteredRepos();
|
|
26
|
-
const entry = entries
|
|
127
|
+
const entry = findRegistryEntryByRepoPath(entries, repo.repoPath);
|
|
27
128
|
const summary = entry?.branches?.find((b) => b.branch === options.branch);
|
|
28
129
|
if (!summary) {
|
|
29
130
|
console.log(t('clean.branchNotIndexed', { branch: options.branch }));
|
|
@@ -45,10 +146,7 @@ export const cleanCommand = async (options) => {
|
|
|
45
146
|
}
|
|
46
147
|
const { lbugPath } = getStoragePaths(repo.repoPath, summary.branch, storagePath);
|
|
47
148
|
const branchDir = path.dirname(lbugPath);
|
|
48
|
-
|
|
49
|
-
// storage slot's `branches/` directory before any destructive fs.rm.
|
|
50
|
-
const branchesRoot = path.join(storagePath, 'branches') + path.sep;
|
|
51
|
-
if (!branchDir.startsWith(branchesRoot)) {
|
|
149
|
+
if (!isContainedBranchDir(storagePath, branchDir)) {
|
|
52
150
|
logger.error(`Refusing to clean branch index outside the validated storage slot: ${branchDir}`);
|
|
53
151
|
return;
|
|
54
152
|
}
|
|
@@ -57,14 +155,17 @@ export const cleanCommand = async (options) => {
|
|
|
57
155
|
console.log(`\n${t('common.runForceConfirm')}`);
|
|
58
156
|
return;
|
|
59
157
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
158
|
+
const result = await removeBranchSlot({
|
|
159
|
+
repoPath: repo.repoPath,
|
|
160
|
+
storagePath,
|
|
161
|
+
branch: summary.branch,
|
|
162
|
+
dir: branchDir,
|
|
163
|
+
});
|
|
164
|
+
if (!result.ok) {
|
|
165
|
+
logger.error({ err: result.error }, 'Failed to delete branch index:');
|
|
166
|
+
return;
|
|
67
167
|
}
|
|
168
|
+
console.log(t('clean.deletedBranch', { branch: summary.branch }));
|
|
68
169
|
return;
|
|
69
170
|
}
|
|
70
171
|
if (options?.lbugSidecars) {
|
package/dist/cli/doctor.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type EmbeddingRuntimeResolution } from '../core/embeddings/runtime-install.js';
|
|
2
2
|
import { type NativeCheckResult } from '../core/lbug/native-check.js';
|
|
3
3
|
import { type ValidatedUpdateCache } from '../core/update-cache.js';
|
|
4
|
+
import { type StaleBranchSlot } from '../storage/stale-branch-slots.js';
|
|
4
5
|
export declare function displayWidth(value: string): number;
|
|
5
6
|
export declare function padDisplayEnd(value: string, columns: number): string;
|
|
6
7
|
/**
|
|
@@ -60,6 +61,12 @@ export declare function poolSizeDoctorLine(pool: number, envRaw: string | undefi
|
|
|
60
61
|
* stderr right below said the opposite. Render what the check actually found.
|
|
61
62
|
*/
|
|
62
63
|
export declare function nativeStatusLine(check: NativeCheckResult): string;
|
|
64
|
+
/**
|
|
65
|
+
* Cwd leftover-slot lines (#3331). Pure: no deletes and no registry scan.
|
|
66
|
+
* When heads cannot be listed, do not title rows as orphaned or name
|
|
67
|
+
* `clean --stale` (#3337): that command refuses to delete in the same state.
|
|
68
|
+
*/
|
|
69
|
+
export declare function orphanedBranchSlotDoctorLines(slots: StaleBranchSlot[]): string[];
|
|
63
70
|
export declare function cachedUpdateDoctorLine(options: {
|
|
64
71
|
installedVersion: string;
|
|
65
72
|
eligible: boolean;
|
package/dist/cli/doctor.js
CHANGED
|
@@ -13,6 +13,9 @@ import { updateEligibleInstallSync } from '../core/install-context.js';
|
|
|
13
13
|
import { readValidatedUpdateCacheSync } from '../core/update-cache.js';
|
|
14
14
|
import { t } from './i18n/index.js';
|
|
15
15
|
import { cachedUpdateNoticeLine } from './update-notice.js';
|
|
16
|
+
import { formatSlotSize, staleReasonLabel } from './stale-branch-format.js';
|
|
17
|
+
import { findRegistryEntryByRepoPath, findRepo, listRegisteredRepos, } from '../storage/repo-manager.js';
|
|
18
|
+
import { isDeleteCandidate, listStaleBranchSlots, staleListingBlock, } from '../storage/stale-branch-slots.js';
|
|
16
19
|
function isCombiningMark(codePoint) {
|
|
17
20
|
return ((codePoint >= 0x0300 && codePoint <= 0x036f) ||
|
|
18
21
|
(codePoint >= 0x1ab0 && codePoint <= 0x1aff) ||
|
|
@@ -145,6 +148,33 @@ export function poolSizeDoctorLine(pool, envRaw) {
|
|
|
145
148
|
export function nativeStatusLine(check) {
|
|
146
149
|
return ` ${padDisplayEnd('native', 10)}${nativeStatusText(check)}`;
|
|
147
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Cwd leftover-slot lines (#3331). Pure: no deletes and no registry scan.
|
|
153
|
+
* When heads cannot be listed, do not title rows as orphaned or name
|
|
154
|
+
* `clean --stale` (#3337): that command refuses to delete in the same state.
|
|
155
|
+
*/
|
|
156
|
+
export function orphanedBranchSlotDoctorLines(slots) {
|
|
157
|
+
if (slots.length === 0)
|
|
158
|
+
return [];
|
|
159
|
+
const listingBlock = staleListingBlock(slots);
|
|
160
|
+
if (listingBlock === 'heads-unavailable') {
|
|
161
|
+
return [t('clean.stale.headsUnavailable')];
|
|
162
|
+
}
|
|
163
|
+
if (listingBlock === 'listing-failed') {
|
|
164
|
+
return [t('clean.stale.listingFailed')];
|
|
165
|
+
}
|
|
166
|
+
const lines = [t('doctor.orphanedBranches')];
|
|
167
|
+
let total = 0;
|
|
168
|
+
for (const slot of slots) {
|
|
169
|
+
total += slot.sizeBytes;
|
|
170
|
+
lines.push(` ${slot.branch} ${staleReasonLabel(slot.reason)} ${formatSlotSize(slot.sizeBytes)}`);
|
|
171
|
+
}
|
|
172
|
+
lines.push(` ${t('doctor.orphanedBranches.total', { size: formatSlotSize(total) })}`);
|
|
173
|
+
if (slots.some(isDeleteCandidate)) {
|
|
174
|
+
lines.push(` ${t('doctor.orphanedBranches.reclaim')}`);
|
|
175
|
+
}
|
|
176
|
+
return lines;
|
|
177
|
+
}
|
|
148
178
|
function nativeStatusText(check) {
|
|
149
179
|
if (check.ok)
|
|
150
180
|
return '✓ lbugjs.node loaded';
|
|
@@ -285,4 +315,24 @@ export const doctorCommand = async () => {
|
|
|
285
315
|
console.log(` ${padDisplayEnd('', 12)}${cudaRedirect.detail}`);
|
|
286
316
|
}
|
|
287
317
|
}
|
|
318
|
+
// Doctor stays runtime-global. Add only a cwd leftover-slot section when
|
|
319
|
+
// this process is inside an indexed repo. Look up that repo's registry row
|
|
320
|
+
// for recorded branch slugs; do not report leftovers for every registered
|
|
321
|
+
// repo, and never delete.
|
|
322
|
+
const [cwdRepo, entries] = await Promise.all([findRepo(process.cwd()), listRegisteredRepos()]);
|
|
323
|
+
if (!cwdRepo)
|
|
324
|
+
return;
|
|
325
|
+
const entry = findRegistryEntryByRepoPath(entries, cwdRepo.repoPath);
|
|
326
|
+
const slots = await listStaleBranchSlots({
|
|
327
|
+
repoPath: cwdRepo.repoPath,
|
|
328
|
+
storagePath: cwdRepo.storagePath,
|
|
329
|
+
branches: entry?.branches,
|
|
330
|
+
});
|
|
331
|
+
const orphanLines = orphanedBranchSlotDoctorLines(slots);
|
|
332
|
+
if (orphanLines.length === 0)
|
|
333
|
+
return;
|
|
334
|
+
console.log('');
|
|
335
|
+
for (const line of orphanLines) {
|
|
336
|
+
console.log(line);
|
|
337
|
+
}
|
|
288
338
|
};
|
package/dist/cli/help-i18n.js
CHANGED
|
@@ -92,6 +92,7 @@ const OPTION_DESCRIPTION_KEYS = {
|
|
|
92
92
|
'clean|--all': 'help.option.clean.all',
|
|
93
93
|
'clean|--branch <name>': 'help.option.clean.branch',
|
|
94
94
|
'clean|--lbug-sidecars': 'help.option.clean.lbugSidecars',
|
|
95
|
+
'clean|--stale': 'help.option.clean.stale',
|
|
95
96
|
'remove|-f, --force': 'help.option.force.confirmation',
|
|
96
97
|
'wiki|-f, --force': 'help.option.wiki.force',
|
|
97
98
|
'wiki|--provider <provider>': 'help.option.wiki.provider',
|
package/dist/cli/i18n/en.d.ts
CHANGED
|
@@ -53,7 +53,23 @@ export declare const en: {
|
|
|
53
53
|
readonly 'clean.deletedRepo': 'Deleted: {{name}} ({{storagePath}})';
|
|
54
54
|
readonly 'clean.notFoundHere': 'No indexed repository found in this directory.';
|
|
55
55
|
readonly 'clean.deleteCurrent': 'This will delete the GitNexus index for: {{repoName}}';
|
|
56
|
-
readonly 'clean.branchNotIndexed': 'No indexed branch named "{{branch}}" for this repository.';
|
|
56
|
+
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
|
+
readonly 'clean.stale.none': 'No leftover branch indexes to reclaim.';
|
|
58
|
+
readonly 'clean.stale.preview': 'This will delete {{count}} leftover branch index(es):';
|
|
59
|
+
readonly 'clean.stale.item': '{{branch}} {{reason}} {{path}} {{size}}';
|
|
60
|
+
readonly 'clean.stale.registryOnlyPath': '(registry only)';
|
|
61
|
+
readonly 'clean.stale.headsUnavailable': 'Could not list local heads; leftover branch indexes were not deleted. Re-run `gitnexus clean --stale` when git is available.';
|
|
62
|
+
readonly 'clean.stale.listingFailed': 'Could not read leftover branch index directories; leftover indexes were not deleted. Check permissions on the branches/ directory and re-run `gitnexus clean --stale`.';
|
|
63
|
+
readonly 'clean.stale.probeFailed': 'Could not inspect leftover branch index path(s); those slots were not deleted.';
|
|
64
|
+
readonly 'clean.stale.deleted': 'Deleted leftover branch index: {{branch}}';
|
|
65
|
+
readonly 'clean.stale.failed': 'Could not delete leftover branch index "{{branch}}".';
|
|
66
|
+
readonly 'clean.stale.skippedLive': 'Skipped leftover branch index "{{branch}}" — it is a local head again.';
|
|
67
|
+
readonly 'clean.stale.reason.refMissing': 'not a local head';
|
|
68
|
+
readonly 'clean.stale.reason.diskOnly': 'leftover directory (no registry row)';
|
|
69
|
+
readonly 'clean.stale.reason.registryOnly': 'registry row (directory gone)';
|
|
70
|
+
readonly 'clean.stale.reason.headsUnavailable': 'could not list local heads';
|
|
71
|
+
readonly 'clean.stale.reason.probeFailed': 'could not inspect slot path';
|
|
72
|
+
readonly 'clean.stale.reason.listingFailed': 'could not list leftover directories';
|
|
57
73
|
readonly 'clean.deleteBranch': 'This will delete the branch index "{{branch}}" at: {{path}}';
|
|
58
74
|
readonly 'clean.deletedBranch': 'Deleted branch index: {{branch}}';
|
|
59
75
|
readonly 'clean.lbugSidecars.state': 'LadybugDB sidecar state: {{state}}';
|
|
@@ -95,6 +111,9 @@ export declare const en: {
|
|
|
95
111
|
readonly 'doctor.runtime': 'Runtime';
|
|
96
112
|
readonly 'doctor.capabilities': 'Capabilities';
|
|
97
113
|
readonly 'doctor.embeddings': 'Embeddings';
|
|
114
|
+
readonly 'doctor.orphanedBranches': 'Orphaned branch indexes';
|
|
115
|
+
readonly 'doctor.orphanedBranches.total': 'Total: {{size}}';
|
|
116
|
+
readonly 'doctor.orphanedBranches.reclaim': 'Reclaim with: gitnexus clean --stale';
|
|
98
117
|
readonly 'doctor.labels.os': 'OS:';
|
|
99
118
|
readonly 'doctor.labels.node': 'Node:';
|
|
100
119
|
readonly 'doctor.labels.gitnexus': 'GitNexus:';
|
|
@@ -215,6 +234,7 @@ export declare const en: {
|
|
|
215
234
|
readonly 'help.option.clean.all': 'Clean all indexed repos';
|
|
216
235
|
readonly 'help.option.clean.branch': 'Delete only the named branch index (not the workspace index)';
|
|
217
236
|
readonly 'help.option.clean.lbugSidecars': 'Clean parked LadybugDB recovery sidecars (missing-shadow WAL quarantines and dirty-recovery parks)';
|
|
237
|
+
readonly 'help.option.clean.stale': 'Reclaim leftover branch indexes that are not a live local head';
|
|
218
238
|
readonly 'help.option.wiki.force': 'Force full regeneration even if up to date';
|
|
219
239
|
readonly 'help.option.wiki.provider': 'LLM provider: minimax, openai, openrouter, azure, custom, cursor, claude, codex, opencode, or grok (default: minimax)';
|
|
220
240
|
readonly 'help.option.wiki.model': 'LLM model or deployment name (default: MiniMax-M3)';
|
package/dist/cli/i18n/en.js
CHANGED
|
@@ -53,7 +53,23 @@ export const en = {
|
|
|
53
53
|
'clean.deletedRepo': 'Deleted: {{name}} ({{storagePath}})',
|
|
54
54
|
'clean.notFoundHere': 'No indexed repository found in this directory.',
|
|
55
55
|
'clean.deleteCurrent': 'This will delete the GitNexus index for: {{repoName}}',
|
|
56
|
-
'clean.branchNotIndexed': 'No indexed branch named "{{branch}}" for this repository.',
|
|
56
|
+
'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
|
+
'clean.stale.none': 'No leftover branch indexes to reclaim.',
|
|
58
|
+
'clean.stale.preview': 'This will delete {{count}} leftover branch index(es):',
|
|
59
|
+
'clean.stale.item': '{{branch}} {{reason}} {{path}} {{size}}',
|
|
60
|
+
'clean.stale.registryOnlyPath': '(registry only)',
|
|
61
|
+
'clean.stale.headsUnavailable': 'Could not list local heads; leftover branch indexes were not deleted. Re-run `gitnexus clean --stale` when git is available.',
|
|
62
|
+
'clean.stale.listingFailed': 'Could not read leftover branch index directories; leftover indexes were not deleted. Check permissions on the branches/ directory and re-run `gitnexus clean --stale`.',
|
|
63
|
+
'clean.stale.probeFailed': 'Could not inspect leftover branch index path(s); those slots were not deleted.',
|
|
64
|
+
'clean.stale.deleted': 'Deleted leftover branch index: {{branch}}',
|
|
65
|
+
'clean.stale.failed': 'Could not delete leftover branch index "{{branch}}".',
|
|
66
|
+
'clean.stale.skippedLive': 'Skipped leftover branch index "{{branch}}" — it is a local head again.',
|
|
67
|
+
'clean.stale.reason.refMissing': 'not a local head',
|
|
68
|
+
'clean.stale.reason.diskOnly': 'leftover directory (no registry row)',
|
|
69
|
+
'clean.stale.reason.registryOnly': 'registry row (directory gone)',
|
|
70
|
+
'clean.stale.reason.headsUnavailable': 'could not list local heads',
|
|
71
|
+
'clean.stale.reason.probeFailed': 'could not inspect slot path',
|
|
72
|
+
'clean.stale.reason.listingFailed': 'could not list leftover directories',
|
|
57
73
|
'clean.deleteBranch': 'This will delete the branch index "{{branch}}" at: {{path}}',
|
|
58
74
|
'clean.deletedBranch': 'Deleted branch index: {{branch}}',
|
|
59
75
|
'clean.lbugSidecars.state': 'LadybugDB sidecar state: {{state}}',
|
|
@@ -97,6 +113,9 @@ export const en = {
|
|
|
97
113
|
'doctor.runtime': 'Runtime',
|
|
98
114
|
'doctor.capabilities': 'Capabilities',
|
|
99
115
|
'doctor.embeddings': 'Embeddings',
|
|
116
|
+
'doctor.orphanedBranches': 'Orphaned branch indexes',
|
|
117
|
+
'doctor.orphanedBranches.total': 'Total: {{size}}',
|
|
118
|
+
'doctor.orphanedBranches.reclaim': 'Reclaim with: gitnexus clean --stale',
|
|
100
119
|
'doctor.labels.os': 'OS:',
|
|
101
120
|
'doctor.labels.node': 'Node:',
|
|
102
121
|
'doctor.labels.gitnexus': 'GitNexus:',
|
|
@@ -217,6 +236,7 @@ export const en = {
|
|
|
217
236
|
'help.option.clean.all': 'Clean all indexed repos',
|
|
218
237
|
'help.option.clean.branch': 'Delete only the named branch index (not the workspace index)',
|
|
219
238
|
'help.option.clean.lbugSidecars': 'Clean parked LadybugDB recovery sidecars (missing-shadow WAL quarantines and dirty-recovery parks)',
|
|
239
|
+
'help.option.clean.stale': 'Reclaim leftover branch indexes that are not a live local head',
|
|
220
240
|
'help.option.wiki.force': 'Force full regeneration even if up to date',
|
|
221
241
|
'help.option.wiki.provider': 'LLM provider: minimax, openai, openrouter, azure, custom, cursor, claude, codex, opencode, or grok (default: minimax)',
|
|
222
242
|
'help.option.wiki.model': 'LLM model or deployment name (default: MiniMax-M3)',
|
|
@@ -54,7 +54,23 @@ export declare const cliResources: {
|
|
|
54
54
|
readonly 'clean.deletedRepo': 'Deleted: {{name}} ({{storagePath}})';
|
|
55
55
|
readonly 'clean.notFoundHere': 'No indexed repository found in this directory.';
|
|
56
56
|
readonly 'clean.deleteCurrent': 'This will delete the GitNexus index for: {{repoName}}';
|
|
57
|
-
readonly 'clean.branchNotIndexed': 'No indexed branch named "{{branch}}" for this repository.';
|
|
57
|
+
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
|
+
readonly 'clean.stale.none': 'No leftover branch indexes to reclaim.';
|
|
59
|
+
readonly 'clean.stale.preview': 'This will delete {{count}} leftover branch index(es):';
|
|
60
|
+
readonly 'clean.stale.item': '{{branch}} {{reason}} {{path}} {{size}}';
|
|
61
|
+
readonly 'clean.stale.registryOnlyPath': '(registry only)';
|
|
62
|
+
readonly 'clean.stale.headsUnavailable': 'Could not list local heads; leftover branch indexes were not deleted. Re-run `gitnexus clean --stale` when git is available.';
|
|
63
|
+
readonly 'clean.stale.listingFailed': 'Could not read leftover branch index directories; leftover indexes were not deleted. Check permissions on the branches/ directory and re-run `gitnexus clean --stale`.';
|
|
64
|
+
readonly 'clean.stale.probeFailed': 'Could not inspect leftover branch index path(s); those slots were not deleted.';
|
|
65
|
+
readonly 'clean.stale.deleted': 'Deleted leftover branch index: {{branch}}';
|
|
66
|
+
readonly 'clean.stale.failed': 'Could not delete leftover branch index "{{branch}}".';
|
|
67
|
+
readonly 'clean.stale.skippedLive': 'Skipped leftover branch index "{{branch}}" — it is a local head again.';
|
|
68
|
+
readonly 'clean.stale.reason.refMissing': 'not a local head';
|
|
69
|
+
readonly 'clean.stale.reason.diskOnly': 'leftover directory (no registry row)';
|
|
70
|
+
readonly 'clean.stale.reason.registryOnly': 'registry row (directory gone)';
|
|
71
|
+
readonly 'clean.stale.reason.headsUnavailable': 'could not list local heads';
|
|
72
|
+
readonly 'clean.stale.reason.probeFailed': 'could not inspect slot path';
|
|
73
|
+
readonly 'clean.stale.reason.listingFailed': 'could not list leftover directories';
|
|
58
74
|
readonly 'clean.deleteBranch': 'This will delete the branch index "{{branch}}" at: {{path}}';
|
|
59
75
|
readonly 'clean.deletedBranch': 'Deleted branch index: {{branch}}';
|
|
60
76
|
readonly 'clean.lbugSidecars.state': 'LadybugDB sidecar state: {{state}}';
|
|
@@ -96,6 +112,9 @@ export declare const cliResources: {
|
|
|
96
112
|
readonly 'doctor.runtime': 'Runtime';
|
|
97
113
|
readonly 'doctor.capabilities': 'Capabilities';
|
|
98
114
|
readonly 'doctor.embeddings': 'Embeddings';
|
|
115
|
+
readonly 'doctor.orphanedBranches': 'Orphaned branch indexes';
|
|
116
|
+
readonly 'doctor.orphanedBranches.total': 'Total: {{size}}';
|
|
117
|
+
readonly 'doctor.orphanedBranches.reclaim': 'Reclaim with: gitnexus clean --stale';
|
|
99
118
|
readonly 'doctor.labels.os': 'OS:';
|
|
100
119
|
readonly 'doctor.labels.node': 'Node:';
|
|
101
120
|
readonly 'doctor.labels.gitnexus': 'GitNexus:';
|
|
@@ -216,6 +235,7 @@ export declare const cliResources: {
|
|
|
216
235
|
readonly 'help.option.clean.all': 'Clean all indexed repos';
|
|
217
236
|
readonly 'help.option.clean.branch': 'Delete only the named branch index (not the workspace index)';
|
|
218
237
|
readonly 'help.option.clean.lbugSidecars': 'Clean parked LadybugDB recovery sidecars (missing-shadow WAL quarantines and dirty-recovery parks)';
|
|
238
|
+
readonly 'help.option.clean.stale': 'Reclaim leftover branch indexes that are not a live local head';
|
|
219
239
|
readonly 'help.option.wiki.force': 'Force full regeneration even if up to date';
|
|
220
240
|
readonly 'help.option.wiki.provider': 'LLM provider: minimax, openai, openrouter, azure, custom, cursor, claude, codex, opencode, or grok (default: minimax)';
|
|
221
241
|
readonly 'help.option.wiki.model': 'LLM model or deployment name (default: MiniMax-M3)';
|
|
@@ -341,6 +361,22 @@ export declare const cliResources: {
|
|
|
341
361
|
'clean.notFoundHere': string;
|
|
342
362
|
'clean.deleteCurrent': string;
|
|
343
363
|
'clean.branchNotIndexed': string;
|
|
364
|
+
'clean.stale.none': string;
|
|
365
|
+
'clean.stale.preview': string;
|
|
366
|
+
'clean.stale.item': string;
|
|
367
|
+
'clean.stale.registryOnlyPath': string;
|
|
368
|
+
'clean.stale.headsUnavailable': string;
|
|
369
|
+
'clean.stale.listingFailed': string;
|
|
370
|
+
'clean.stale.probeFailed': string;
|
|
371
|
+
'clean.stale.deleted': string;
|
|
372
|
+
'clean.stale.failed': string;
|
|
373
|
+
'clean.stale.skippedLive': string;
|
|
374
|
+
'clean.stale.reason.refMissing': string;
|
|
375
|
+
'clean.stale.reason.diskOnly': string;
|
|
376
|
+
'clean.stale.reason.registryOnly': string;
|
|
377
|
+
'clean.stale.reason.headsUnavailable': string;
|
|
378
|
+
'clean.stale.reason.probeFailed': string;
|
|
379
|
+
'clean.stale.reason.listingFailed': string;
|
|
344
380
|
'clean.deleteBranch': string;
|
|
345
381
|
'clean.deletedBranch': string;
|
|
346
382
|
'clean.lbugSidecars.state': string;
|
|
@@ -382,6 +418,9 @@ export declare const cliResources: {
|
|
|
382
418
|
'doctor.runtime': string;
|
|
383
419
|
'doctor.capabilities': string;
|
|
384
420
|
'doctor.embeddings': string;
|
|
421
|
+
'doctor.orphanedBranches': string;
|
|
422
|
+
'doctor.orphanedBranches.total': string;
|
|
423
|
+
'doctor.orphanedBranches.reclaim': string;
|
|
385
424
|
'doctor.labels.os': string;
|
|
386
425
|
'doctor.labels.node': string;
|
|
387
426
|
'doctor.labels.gitnexus': string;
|
|
@@ -502,6 +541,7 @@ export declare const cliResources: {
|
|
|
502
541
|
'help.option.clean.all': string;
|
|
503
542
|
'help.option.clean.branch': string;
|
|
504
543
|
'help.option.clean.lbugSidecars': string;
|
|
544
|
+
'help.option.clean.stale': string;
|
|
505
545
|
'help.option.wiki.force': string;
|
|
506
546
|
'help.option.wiki.provider': string;
|
|
507
547
|
'help.option.wiki.model': string;
|
package/dist/cli/i18n/zh-CN.d.ts
CHANGED
|
@@ -54,6 +54,22 @@ export declare const zhCN: {
|
|
|
54
54
|
'clean.notFoundHere': string;
|
|
55
55
|
'clean.deleteCurrent': string;
|
|
56
56
|
'clean.branchNotIndexed': string;
|
|
57
|
+
'clean.stale.none': string;
|
|
58
|
+
'clean.stale.preview': string;
|
|
59
|
+
'clean.stale.item': string;
|
|
60
|
+
'clean.stale.registryOnlyPath': string;
|
|
61
|
+
'clean.stale.headsUnavailable': string;
|
|
62
|
+
'clean.stale.listingFailed': string;
|
|
63
|
+
'clean.stale.probeFailed': string;
|
|
64
|
+
'clean.stale.deleted': string;
|
|
65
|
+
'clean.stale.failed': string;
|
|
66
|
+
'clean.stale.skippedLive': string;
|
|
67
|
+
'clean.stale.reason.refMissing': string;
|
|
68
|
+
'clean.stale.reason.diskOnly': string;
|
|
69
|
+
'clean.stale.reason.registryOnly': string;
|
|
70
|
+
'clean.stale.reason.headsUnavailable': string;
|
|
71
|
+
'clean.stale.reason.probeFailed': string;
|
|
72
|
+
'clean.stale.reason.listingFailed': string;
|
|
57
73
|
'clean.deleteBranch': string;
|
|
58
74
|
'clean.deletedBranch': string;
|
|
59
75
|
'clean.lbugSidecars.state': string;
|
|
@@ -95,6 +111,9 @@ export declare const zhCN: {
|
|
|
95
111
|
'doctor.runtime': string;
|
|
96
112
|
'doctor.capabilities': string;
|
|
97
113
|
'doctor.embeddings': string;
|
|
114
|
+
'doctor.orphanedBranches': string;
|
|
115
|
+
'doctor.orphanedBranches.total': string;
|
|
116
|
+
'doctor.orphanedBranches.reclaim': string;
|
|
98
117
|
'doctor.labels.os': string;
|
|
99
118
|
'doctor.labels.node': string;
|
|
100
119
|
'doctor.labels.gitnexus': string;
|
|
@@ -215,6 +234,7 @@ export declare const zhCN: {
|
|
|
215
234
|
'help.option.clean.all': string;
|
|
216
235
|
'help.option.clean.branch': string;
|
|
217
236
|
'help.option.clean.lbugSidecars': string;
|
|
237
|
+
'help.option.clean.stale': string;
|
|
218
238
|
'help.option.wiki.force': string;
|
|
219
239
|
'help.option.wiki.provider': string;
|
|
220
240
|
'help.option.wiki.model': string;
|
package/dist/cli/i18n/zh-CN.js
CHANGED
|
@@ -53,7 +53,23 @@ export const zhCN = {
|
|
|
53
53
|
'clean.deletedRepo': '已删除:{{name}}({{storagePath}})',
|
|
54
54
|
'clean.notFoundHere': '当前目录未找到已索引仓库。',
|
|
55
55
|
'clean.deleteCurrent': '将删除该仓库的 GitNexus 索引:{{repoName}}',
|
|
56
|
-
'clean.branchNotIndexed': '该仓库没有名为 “{{branch}}”
|
|
56
|
+
'clean.branchNotIndexed': '该仓库没有名为 “{{branch}}” 的已索引分支。使用 `gitnexus clean --stale` 回收残留分支索引,或使用 `gitnexus list` 查看已记录名称。',
|
|
57
|
+
'clean.stale.none': '没有可回收的残留分支索引。',
|
|
58
|
+
'clean.stale.preview': '将删除 {{count}} 个残留分支索引:',
|
|
59
|
+
'clean.stale.item': '{{branch}} {{reason}} {{path}} {{size}}',
|
|
60
|
+
'clean.stale.registryOnlyPath': '(仅注册表)',
|
|
61
|
+
'clean.stale.headsUnavailable': '无法列出本地分支,因此未删除残留分支索引。请在 git 可用后重新运行 `gitnexus clean --stale`。',
|
|
62
|
+
'clean.stale.listingFailed': '无法读取残留分支索引目录,因此未删除残留索引。请检查 branches/ 目录权限后重新运行 `gitnexus clean --stale`。',
|
|
63
|
+
'clean.stale.probeFailed': '无法检查残留分支索引路径,因此未删除这些槽位。',
|
|
64
|
+
'clean.stale.deleted': '已删除残留分支索引:{{branch}}',
|
|
65
|
+
'clean.stale.failed': '无法删除残留分支索引 “{{branch}}”。',
|
|
66
|
+
'clean.stale.skippedLive': '已跳过残留分支索引 “{{branch}}” — 它再次成为本地分支。',
|
|
67
|
+
'clean.stale.reason.refMissing': '不是本地分支',
|
|
68
|
+
'clean.stale.reason.diskOnly': '残留目录(无注册表记录)',
|
|
69
|
+
'clean.stale.reason.registryOnly': '注册表记录(目录已不存在)',
|
|
70
|
+
'clean.stale.reason.headsUnavailable': '无法列出本地分支',
|
|
71
|
+
'clean.stale.reason.probeFailed': '无法检查槽位路径',
|
|
72
|
+
'clean.stale.reason.listingFailed': '无法列出残留目录',
|
|
57
73
|
'clean.deleteBranch': '将删除分支索引 “{{branch}}”,路径:{{path}}',
|
|
58
74
|
'clean.deletedBranch': '已删除分支索引:{{branch}}',
|
|
59
75
|
'clean.lbugSidecars.state': 'LadybugDB sidecar 状态:{{state}}',
|
|
@@ -95,6 +111,9 @@ export const zhCN = {
|
|
|
95
111
|
'doctor.runtime': '运行时',
|
|
96
112
|
'doctor.capabilities': '能力',
|
|
97
113
|
'doctor.embeddings': '嵌入',
|
|
114
|
+
'doctor.orphanedBranches': '残留分支索引',
|
|
115
|
+
'doctor.orphanedBranches.total': '合计:{{size}}',
|
|
116
|
+
'doctor.orphanedBranches.reclaim': '回收命令:gitnexus clean --stale',
|
|
98
117
|
'doctor.labels.os': '系统:',
|
|
99
118
|
'doctor.labels.node': 'Node:',
|
|
100
119
|
'doctor.labels.gitnexus': 'GitNexus:',
|
|
@@ -215,6 +234,7 @@ export const zhCN = {
|
|
|
215
234
|
'help.option.clean.all': '清理所有已索引仓库',
|
|
216
235
|
'help.option.clean.branch': '仅删除指定分支的索引(不影响工作区索引)',
|
|
217
236
|
'help.option.clean.lbugSidecars': '清理已暂存的 LadybugDB 恢复 sidecar(missing-shadow WAL 隔离文件与 dirty-recovery 暂存文件)',
|
|
237
|
+
'help.option.clean.stale': '回收已不是本地 head 的残留分支索引',
|
|
218
238
|
'help.option.wiki.force': '即使已是最新也强制完整重新生成',
|
|
219
239
|
'help.option.wiki.provider': 'LLM 提供商:minimax、openai、openrouter、azure、custom、cursor、claude、codex、opencode 或 grok(默认:minimax)',
|
|
220
240
|
'help.option.wiki.model': 'LLM 模型或 deployment 名称(默认:MiniMax-M3)',
|
package/dist/cli/index.js
CHANGED
|
@@ -211,6 +211,7 @@ program
|
|
|
211
211
|
.option('-f, --force', 'Skip confirmation prompt')
|
|
212
212
|
.option('--all', 'Clean all indexed repos')
|
|
213
213
|
.option('--branch <name>', 'Delete only the named branch index (not the workspace index)')
|
|
214
|
+
.option('--stale', 'Reclaim leftover branch indexes that are not a live local head')
|
|
214
215
|
.option('--lbug-sidecars', 'Clean parked LadybugDB recovery sidecars (missing-shadow WAL quarantines and dirty-recovery parks)')
|
|
215
216
|
.action(createLazyAction(() => import('./clean.js'), 'cleanCommand'));
|
|
216
217
|
program
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type StaleBranchReason, type StaleBranchSlot } from '../storage/stale-branch-slots.js';
|
|
2
|
+
export declare const formatSlotSize: (bytes: number) => string;
|
|
3
|
+
export declare const staleReasonLabel: (reason: StaleBranchReason) => string;
|
|
4
|
+
export declare const formatStaleSlotLine: (slot: StaleBranchSlot) => string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { t } from './i18n/index.js';
|
|
2
|
+
export const formatSlotSize = (bytes) => {
|
|
3
|
+
if (bytes < 1024)
|
|
4
|
+
return `${bytes} B`;
|
|
5
|
+
if (bytes < 1024 * 1024)
|
|
6
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
7
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
8
|
+
};
|
|
9
|
+
export const staleReasonLabel = (reason) => {
|
|
10
|
+
switch (reason) {
|
|
11
|
+
case 'ref-missing':
|
|
12
|
+
return t('clean.stale.reason.refMissing');
|
|
13
|
+
case 'disk-only':
|
|
14
|
+
return t('clean.stale.reason.diskOnly');
|
|
15
|
+
case 'registry-only':
|
|
16
|
+
return t('clean.stale.reason.registryOnly');
|
|
17
|
+
case 'heads-unavailable':
|
|
18
|
+
return t('clean.stale.reason.headsUnavailable');
|
|
19
|
+
case 'probe-failed':
|
|
20
|
+
return t('clean.stale.reason.probeFailed');
|
|
21
|
+
case 'listing-failed':
|
|
22
|
+
return t('clean.stale.reason.listingFailed');
|
|
23
|
+
default: {
|
|
24
|
+
const _exhaustive = reason;
|
|
25
|
+
return _exhaustive;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export const formatStaleSlotLine = (slot) => t('clean.stale.item', {
|
|
30
|
+
branch: slot.branch,
|
|
31
|
+
reason: staleReasonLabel(slot.reason),
|
|
32
|
+
path: slot.dir ?? t('clean.stale.registryOnlyPath'),
|
|
33
|
+
size: formatSlotSize(slot.sizeBytes),
|
|
34
|
+
});
|
package/dist/storage/git.d.ts
CHANGED
|
@@ -227,6 +227,12 @@ export declare const getDefaultBranch: (repoPath: string) => string | null;
|
|
|
227
227
|
* "HEAD" (#2106).
|
|
228
228
|
*/
|
|
229
229
|
export declare const getCurrentBranch: (repoPath: string) => string | null;
|
|
230
|
+
/**
|
|
231
|
+
* Local `refs/heads` names, or `null` when the directory is not a git
|
|
232
|
+
* worktree or git cannot run. An empty array means the listing succeeded
|
|
233
|
+
* and there are no local heads — that is not a listing failure (#3331).
|
|
234
|
+
*/
|
|
235
|
+
export declare const listLocalHeads: (repoPath: string) => string[] | null;
|
|
230
236
|
/**
|
|
231
237
|
* Sanitize a repository name to prevent argument injection and ensure
|
|
232
238
|
* cross-platform filesystem compatibility.
|
package/dist/storage/git.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execFileSync, execSync } from 'child_process';
|
|
1
|
+
import { execFileSync, execSync, spawnSync } from 'child_process';
|
|
2
2
|
import { statSync, existsSync } from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import os from 'os';
|
|
@@ -633,6 +633,36 @@ export const getCurrentBranch = (repoPath) => {
|
|
|
633
633
|
return null;
|
|
634
634
|
}
|
|
635
635
|
};
|
|
636
|
+
/**
|
|
637
|
+
* Local `refs/heads` names, or `null` when the directory is not a git
|
|
638
|
+
* worktree or git cannot run. An empty array means the listing succeeded
|
|
639
|
+
* and there are no local heads — that is not a listing failure (#3331).
|
|
640
|
+
*/
|
|
641
|
+
export const listLocalHeads = (repoPath) => {
|
|
642
|
+
try {
|
|
643
|
+
const result = spawnSync('git', ['for-each-ref', '--format=%(refname)', 'refs/heads'], {
|
|
644
|
+
cwd: repoPath,
|
|
645
|
+
encoding: 'utf-8',
|
|
646
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
647
|
+
windowsHide: true,
|
|
648
|
+
maxBuffer: GIT_PATH_LIST_MAX_BUFFER,
|
|
649
|
+
});
|
|
650
|
+
if (result.error || result.status !== 0)
|
|
651
|
+
return null;
|
|
652
|
+
const output = (result.stdout ?? '').toString().trim();
|
|
653
|
+
if (!output)
|
|
654
|
+
return [];
|
|
655
|
+
return output
|
|
656
|
+
.split('\n')
|
|
657
|
+
.map((line) => line.trim())
|
|
658
|
+
.filter((line) => line.startsWith('refs/heads/'))
|
|
659
|
+
.map((line) => line.slice('refs/heads/'.length))
|
|
660
|
+
.filter((line) => line.length > 0);
|
|
661
|
+
}
|
|
662
|
+
catch {
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
};
|
|
636
666
|
/**
|
|
637
667
|
* Sanitize a repository name to prevent argument injection and ensure
|
|
638
668
|
* cross-platform filesystem compatibility.
|
|
@@ -120,6 +120,8 @@ export interface RegistryEntry {
|
|
|
120
120
|
*/
|
|
121
121
|
branches?: BranchSummary[];
|
|
122
122
|
}
|
|
123
|
+
/** Path-only registry lookup. Canonicalizes `repoPath` once. Does not throw. */
|
|
124
|
+
export declare const findRegistryEntryByRepoPath: (entries: readonly RegistryEntry[], repoPath: string) => RegistryEntry | undefined;
|
|
123
125
|
/**
|
|
124
126
|
* Get paths to key storage files.
|
|
125
127
|
*
|