Skip to content
This repository was archived by the owner on Feb 14, 2026. It is now read-only.

Commit e96c1e9

Browse files
Chris Arterclaude
andcommitted
Add overlapping-paths bug fix tests and --global flag for refdocs add
Cover the isPathCovered overlapping-paths fix with unit and integration tests, add findMarkdownFiles dedup tests, and implement a --global flag across all CLI commands to store/search docs at ~/.refdocs/ with automatic local+global result merging. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 707078a commit e96c1e9

9 files changed

Lines changed: 596 additions & 55 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@dynamik-dev/refdocs",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"type": "module",
55
"description": "Local CLI tool that indexes markdown documentation and exposes fast fuzzy search with intelligent chunking",
66
"main": "dist/src/index.js",

src/add.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ export async function addFromUrl(
3434
const parsed = parseGitHubUrl(url);
3535
const branch = options.branch ?? parsed.branch ?? undefined;
3636
const token = options.token ?? process.env.GITHUB_TOKEN ?? undefined;
37-
const localPath = options.path ?? `ref-docs/${parsed.repo}`;
37+
const defaultPath = parsed.subpath
38+
? `ref-docs/${parsed.owner}/${parsed.repo}/${parsed.subpath}`
39+
: `ref-docs/${parsed.owner}/${parsed.repo}`;
40+
const localPath = options.path ?? defaultPath;
3841

3942
const tarball = await downloadTarball(parsed.owner, parsed.repo, branch, token);
4043

@@ -54,7 +57,7 @@ export async function addFromUrl(
5457
addedAt: new Date().toISOString(),
5558
};
5659

57-
const paths = config.paths.includes(localPath)
60+
const paths = isPathCovered(config.paths, localPath)
5861
? config.paths
5962
: [...config.paths, localPath];
6063

@@ -217,6 +220,12 @@ function stripTarPrefix(entryName: string): string {
217220
return parts.slice(1).join("/");
218221
}
219222

223+
export function isPathCovered(existingPaths: string[], newPath: string): boolean {
224+
return existingPaths.some(
225+
(p) => p === newPath || newPath.startsWith(p + "/"),
226+
);
227+
}
228+
220229
function upsertSource(sources: Source[], newSource: Source): Source[] {
221230
const key = `${newSource.owner}/${newSource.repo}/${newSource.subpath}`;
222231
const filtered = sources.filter(

src/config.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { readFileSync, writeFileSync, existsSync } from "node:fs";
1+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
22
import { join, dirname, resolve } from "node:path";
3+
import { homedir } from "node:os";
34
import type { RefdocsConfig, Source } from "./types.js";
45

56
export const CONFIG_FILENAME = ".refdocs.json";
@@ -128,3 +129,42 @@ export function saveConfig(config: Partial<RefdocsConfig>, configDir: string): v
128129
const merged = { ...existing, ...config };
129130
writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
130131
}
132+
133+
let globalDirOverride: string | null = null;
134+
135+
export function setGlobalDirOverride(dir: string | null): void {
136+
globalDirOverride = dir;
137+
}
138+
139+
export function getGlobalConfigDir(): string {
140+
return globalDirOverride ?? join(homedir(), ".refdocs");
141+
}
142+
143+
export function initGlobalConfig(): void {
144+
const globalDir = getGlobalConfigDir();
145+
mkdirSync(globalDir, { recursive: true });
146+
const configPath = join(globalDir, CONFIG_FILENAME);
147+
if (existsSync(configPath)) return;
148+
const globalDefault: RefdocsConfig = {
149+
...DEFAULT_CONFIG,
150+
paths: ["docs"],
151+
};
152+
writeFileSync(configPath, JSON.stringify(globalDefault, null, 2) + "\n", "utf-8");
153+
}
154+
155+
export function loadGlobalConfig(): ConfigResult | null {
156+
const globalDir = getGlobalConfigDir();
157+
const configPath = join(globalDir, CONFIG_FILENAME);
158+
if (!existsSync(configPath)) return null;
159+
try {
160+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
161+
const errors = validateConfig(raw);
162+
if (errors.length > 0) return null;
163+
return {
164+
config: { ...DEFAULT_CONFIG, ...raw, boostFields: { ...DEFAULT_CONFIG.boostFields, ...raw.boostFields } },
165+
configDir: globalDir,
166+
};
167+
} catch {
168+
return null;
169+
}
170+
}

0 commit comments

Comments
 (0)