mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
fix(backlinks): honor positional check-backlinks directory argument
The help text (gbrain check-backlinks <check|fix> [dir]) promised a positional directory argument, but runBacklinks only parsed --dir and defaulted to cwd, so the walker ran from the wrong root and could hit EPERM on unreadable sibling dirs. Extract parseBacklinksArgs: positional [dir] is now honored, --dir still overrides it, --dry-run preserved, and a --dir flag missing its value falls back to the positional dir instead of picking up undefined. Takeover of #852 (rebased onto master past the findBacklinkGaps dedupe test block). Fixes #485. Co-authored-by: Kage18 <Kage18@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Kage18
Claude Fable 5
parent
0612b0daa8
commit
fd7a85a56d
@@ -5,8 +5,8 @@
|
||||
* checks if back-links exist, and optionally creates them.
|
||||
*
|
||||
* Usage:
|
||||
* gbrain check-backlinks check [--dir <brain-dir>] # report missing back-links
|
||||
* gbrain check-backlinks fix [--dir <brain-dir>] # create missing back-links
|
||||
* gbrain check-backlinks check [dir] [--dir <brain-dir>] # report missing back-links
|
||||
* gbrain check-backlinks fix [dir] [--dir <brain-dir>] # create missing back-links
|
||||
* gbrain check-backlinks fix --dry-run # preview fixes
|
||||
*/
|
||||
|
||||
@@ -201,6 +201,40 @@ export interface BacklinksResult {
|
||||
dryRun: boolean;
|
||||
}
|
||||
|
||||
export interface ParsedBacklinksArgs {
|
||||
subcommand: string | undefined;
|
||||
brainDir: string;
|
||||
dryRun: boolean;
|
||||
}
|
||||
|
||||
export function parseBacklinksArgs(args: string[]): ParsedBacklinksArgs {
|
||||
const subcommand = args[0];
|
||||
const dryRun = args.includes('--dry-run');
|
||||
const dirIdx = args.indexOf('--dir');
|
||||
const flagDir = dirIdx >= 0 && args[dirIdx + 1] && !args[dirIdx + 1].startsWith('--')
|
||||
? args[dirIdx + 1]
|
||||
: undefined;
|
||||
|
||||
let positionalDir: string | undefined;
|
||||
for (let i = 1; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
if (arg === '--dir') {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (arg === '--dry-run') continue;
|
||||
if (arg.startsWith('--')) continue;
|
||||
positionalDir = arg;
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
subcommand,
|
||||
brainDir: flagDir ?? positionalDir ?? '.',
|
||||
dryRun,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Library-level backlinks check/fix. Throws on validation errors; returns a
|
||||
* structured result so Minions handlers + autopilot-cycle can surface counts.
|
||||
@@ -236,16 +270,14 @@ export async function runBacklinksCore(opts: BacklinksOpts): Promise<BacklinksRe
|
||||
}
|
||||
|
||||
export async function runBacklinks(args: string[]) {
|
||||
const subcommand = args[0];
|
||||
const dirIdx = args.indexOf('--dir');
|
||||
const brainDir = dirIdx >= 0 ? args[dirIdx + 1] : '.';
|
||||
const dryRun = args.includes('--dry-run');
|
||||
const { subcommand, brainDir, dryRun } = parseBacklinksArgs(args);
|
||||
|
||||
if (!subcommand || !['check', 'fix'].includes(subcommand)) {
|
||||
console.error('Usage: gbrain check-backlinks <check|fix> [--dir <brain-dir>] [--dry-run]');
|
||||
console.error('Usage: gbrain check-backlinks <check|fix> [dir] [--dir <brain-dir>] [--dry-run]');
|
||||
console.error(' check Report missing back-links');
|
||||
console.error(' fix Create missing back-links (appends to Timeline)');
|
||||
console.error(' --dir Brain directory (default: current directory)');
|
||||
console.error(' dir Brain directory (default: current directory)');
|
||||
console.error(' --dir Brain directory override');
|
||||
console.error(' --dry-run Preview fixes without writing');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
extractPageTitle,
|
||||
hasBacklink,
|
||||
buildBacklinkEntry,
|
||||
parseBacklinksArgs,
|
||||
} from '../src/commands/backlinks.ts';
|
||||
|
||||
describe('extractEntityRefs', () => {
|
||||
@@ -104,3 +105,26 @@ describe('findBacklinkGaps dedupe (v0.36.x #967 regression)', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseBacklinksArgs', () => {
|
||||
test('uses positional dir for check and fix subcommands', () => {
|
||||
expect(parseBacklinksArgs(['check', '/tmp/brain']).brainDir).toBe('/tmp/brain');
|
||||
expect(parseBacklinksArgs(['fix', '/tmp/brain']).brainDir).toBe('/tmp/brain');
|
||||
});
|
||||
|
||||
test('defaults to cwd when no dir given', () => {
|
||||
expect(parseBacklinksArgs(['check']).brainDir).toBe('.');
|
||||
});
|
||||
|
||||
test('--dir overrides positional dir and preserves dry-run', () => {
|
||||
const parsed = parseBacklinksArgs(['fix', '/tmp/ignored', '--dir', '/tmp/brain', '--dry-run']);
|
||||
expect(parsed.subcommand).toBe('fix');
|
||||
expect(parsed.brainDir).toBe('/tmp/brain');
|
||||
expect(parsed.dryRun).toBe(true);
|
||||
});
|
||||
|
||||
test('--dir missing its value falls back to positional dir', () => {
|
||||
expect(parseBacklinksArgs(['check', '/tmp/brain', '--dir']).brainDir).toBe('/tmp/brain');
|
||||
expect(parseBacklinksArgs(['check', '--dir', '--dry-run']).brainDir).toBe('.');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user