@ncukondo/search-hub 0.22.0 → 0.23.0

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.
@@ -6,4 +6,5 @@
6
6
  export { loadConfig, saveConfig, type LoadConfigOptions, type SaveConfigOptions } from './loader';
7
7
  export { ConfigSchema, type Config, type ProviderConfig } from './schema';
8
8
  export { getDefaultConfig, DEFAULT_CONFIG } from './defaults';
9
+ export { getProjectDir, getLocalConfigPath, getLocalSessionsDir, getLocalQueriesDir, isInsideProject, } from './paths';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,SAAS,CAAC"}
@@ -7,8 +7,10 @@ export type RawConfig = Partial<Config>;
7
7
  export interface LoadConfigOptions {
8
8
  /** Path to global config file (default: platform-specific via getDefaultConfigPath()) */
9
9
  globalConfigPath?: string;
10
- /** Path to local config file (default: ./search-hub.config.toml) */
10
+ /** Path to local config file (default: .search-hub/config.toml via getLocalConfigPath()) */
11
11
  localConfigPath?: string;
12
+ /** Project directory for .search-hub/ resolution (default: cwd) */
13
+ projectDir?: string;
12
14
  /**
13
15
  * Explicit config file path specified via CLI --config option.
14
16
  * Takes priority over global and local config files (applied after env vars).
@@ -30,7 +32,7 @@ export declare function loadTomlFile(path: string): Promise<RawConfig>;
30
32
  * 1. CLI options (cliOptions)
31
33
  * 2. Explicit --config file (explicitConfigPath)
32
34
  * 3. Environment variables
33
- * 4. Local config (./search-hub.config.toml)
35
+ * 4. Local config (.search-hub/config.toml)
34
36
  * 5. Global config (platform-specific, e.g. ~/.config/search-hub/config.toml on Linux)
35
37
  * 6. Default values
36
38
  */
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAIxD,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGrE,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yFAAyF;IACzF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8CAA8C;IAC9C,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAyBnE;AAOD;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4CjF;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AASD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAoBf"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAIxD,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGrE,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yFAAyF;IACzF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4FAA4F;IAC5F,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8CAA8C;IAC9C,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAyBnE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkDjF;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AASD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAoBf"}
@@ -1,10 +1,10 @@
1
- import { mkdir, writeFile, readFile } from "node:fs/promises";
1
+ import { readFile, mkdir, writeFile } from "node:fs/promises";
2
2
  import { dirname } from "node:path";
3
- import { stringify, parse } from "@iarna/toml";
3
+ import { parse, stringify } from "@iarna/toml";
4
4
  import { ConfigSchema } from "./schema.js";
5
5
  import { getDefaultConfig } from "./defaults.js";
6
6
  import { applyEnvVars } from "./env.js";
7
- import { getDefaultConfigPath, getDefaultSessionsDir } from "./paths.js";
7
+ import { getDefaultConfigPath, getLocalConfigPath, isInsideProject, getLocalSessionsDir, getDefaultSessionsDir } from "./paths.js";
8
8
  import { deepMerge } from "../utils/deep-merge.js";
9
9
  import { expandPath } from "../utils/path.js";
10
10
  async function loadTomlFile(path) {
@@ -28,11 +28,11 @@ async function loadTomlFile(path) {
28
28
  );
29
29
  }
30
30
  }
31
- const DEFAULT_LOCAL_CONFIG_PATH = "./search-hub.config.toml";
32
31
  async function loadConfig(options = {}) {
33
32
  const {
34
33
  globalConfigPath = getDefaultConfigPath(),
35
- localConfigPath = DEFAULT_LOCAL_CONFIG_PATH,
34
+ localConfigPath = getLocalConfigPath(),
35
+ projectDir,
36
36
  explicitConfigPath,
37
37
  cliOptions
38
38
  } = options;
@@ -53,7 +53,8 @@ async function loadConfig(options = {}) {
53
53
  }
54
54
  config = ConfigSchema.parse(config);
55
55
  if (!config.session.directory) {
56
- config.session.directory = getDefaultSessionsDir();
56
+ const inProject = projectDir ? await isInsideProject(projectDir) : false;
57
+ config.session.directory = inProject ? getLocalSessionsDir(projectDir) : getDefaultSessionsDir();
57
58
  }
58
59
  return config;
59
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sources":["../../src/config/loader.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { parse as parseToml, stringify as stringifyToml } from '@iarna/toml';\nimport { ConfigSchema, type Config } from './schema.js';\nimport { getDefaultConfig } from './defaults.js';\nimport { applyEnvVars } from './env.js';\nimport { getDefaultConfigPath, getDefaultSessionsDir } from './paths.js';\nimport { deepMerge, type DeepPartial } from '../utils/deep-merge.js';\nimport { expandPath } from '../utils/path.js';\n\nexport type RawConfig = Partial<Config>;\n\n/**\n * Options for loadConfig function.\n */\nexport interface LoadConfigOptions {\n /** Path to global config file (default: platform-specific via getDefaultConfigPath()) */\n globalConfigPath?: string;\n /** Path to local config file (default: ./search-hub.config.toml) */\n localConfigPath?: string;\n /**\n * Explicit config file path specified via CLI --config option.\n * Takes priority over global and local config files (applied after env vars).\n */\n explicitConfigPath?: string;\n /** CLI options to apply (highest priority) */\n cliOptions?: DeepPartial<Config>;\n}\n\n/**\n * Load and parse a TOML config file.\n * Returns empty object if file doesn't exist.\n * Throws with clear message if TOML is invalid.\n */\nexport async function loadTomlFile(path: string): Promise<RawConfig> {\n let content: string;\n\n try {\n content = await readFile(path, 'utf-8');\n } catch (error) {\n // File doesn't exist or can't be read\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw error;\n }\n\n // Empty file\n if (!content.trim()) {\n return {};\n }\n\n try {\n return parseToml(content) as RawConfig;\n } catch (error) {\n throw new Error(\n `Invalid TOML in ${path}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * Default local config file path.\n */\nconst DEFAULT_LOCAL_CONFIG_PATH = './search-hub.config.toml';\n\n/**\n * Load configuration from all sources and merge them.\n *\n * Priority (highest to lowest):\n * 1. CLI options (cliOptions)\n * 2. Explicit --config file (explicitConfigPath)\n * 3. Environment variables\n * 4. Local config (./search-hub.config.toml)\n * 5. Global config (platform-specific, e.g. ~/.config/search-hub/config.toml on Linux)\n * 6. Default values\n */\nexport async function loadConfig(options: LoadConfigOptions = {}): Promise<Config> {\n const {\n globalConfigPath = getDefaultConfigPath(),\n localConfigPath = DEFAULT_LOCAL_CONFIG_PATH,\n explicitConfigPath,\n cliOptions,\n } = options;\n\n // 1. Start with defaults\n let config = getDefaultConfig();\n\n // 2. Load and merge global config (lowest file priority)\n const expandedGlobalPath = expandPath(globalConfigPath);\n const globalConfig = await loadTomlFile(expandedGlobalPath);\n config = deepMerge(config, globalConfig as DeepPartial<Config>);\n\n // 3. Load and merge local config (overrides global)\n const localConfig = await loadTomlFile(localConfigPath);\n config = deepMerge(config, localConfig as DeepPartial<Config>);\n\n // 4. Apply environment variables (overrides local)\n config = applyEnvVars(config);\n\n // 5. Apply explicit --config file (overrides env vars, local, and global)\n if (explicitConfigPath) {\n const expandedExplicitPath = expandPath(explicitConfigPath);\n const explicitConfig = await loadTomlFile(expandedExplicitPath);\n config = deepMerge(config, explicitConfig as DeepPartial<Config>);\n }\n\n // 6. Apply CLI options (highest priority)\n if (cliOptions) {\n config = deepMerge(config, cliOptions);\n }\n\n // 7. Validate\n config = ConfigSchema.parse(config);\n\n // 8. Resolve empty session.directory to platform default\n if (!config.session.directory) {\n config.session.directory = getDefaultSessionsDir();\n }\n\n return config;\n}\n\n/**\n * Options for saveConfig function.\n */\nexport interface SaveConfigOptions {\n /** Path to save config file (default: platform-specific via getDefaultConfigPath()) */\n path?: string;\n /** Create directory if it doesn't exist (default: true) */\n createDir?: boolean;\n}\n\n// Re-define JsonMap type to match @iarna/toml's expected input\n// This is necessary because the library's JsonMap type is not exported\ntype TomlValue = boolean | number | string | Date | TomlMap | TomlValue[];\ninterface TomlMap {\n [key: string]: TomlValue;\n}\n\n/**\n * Save configuration to a TOML file.\n *\n * @param config - Configuration object to save\n * @param options - Save options\n * @throws Error if config is invalid or file write fails\n */\nexport async function saveConfig(\n config: Config,\n options: SaveConfigOptions = {}\n): Promise<void> {\n const {\n path = getDefaultConfigPath(),\n createDir = true,\n } = options;\n\n // Validate config before saving\n ConfigSchema.parse(config);\n\n // Expand path and ensure directory exists\n const expandedPath = expandPath(path);\n if (createDir) {\n await mkdir(dirname(expandedPath), { recursive: true });\n }\n\n // Convert to TOML and write\n // Config structure is compatible with TOML's JsonMap type\n // The cast is safe because Config only contains TOML-compatible types\n const tomlContent = stringifyToml(config as TomlMap);\n await writeFile(expandedPath, tomlContent, 'utf-8');\n}\n"],"names":["parseToml","stringifyToml"],"mappings":";;;;;;;;;AAkCA,eAAsB,aAAa,MAAkC;AACnE,MAAI;AAEJ,MAAI;AACF,cAAU,MAAM,SAAS,MAAM,OAAO;AAAA,EACxC,SAAS,OAAO;AAEd,QAAK,MAAgC,SAAS,UAAU;AACtD,aAAO,CAAA;AAAA,IACT;AACA,UAAM;AAAA,EACR;AAGA,MAAI,CAAC,QAAQ,QAAQ;AACnB,WAAO,CAAA;AAAA,EACT;AAEA,MAAI;AACF,WAAOA,MAAU,OAAO;AAAA,EAC1B,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,mBAAmB,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAAA;AAAA,EAEtF;AACF;AAKA,MAAM,4BAA4B;AAalC,eAAsB,WAAW,UAA6B,IAAqB;AACjF,QAAM;AAAA,IACJ,mBAAmB,qBAAA;AAAA,IACnB,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,EAAA,IACE;AAGJ,MAAI,SAAS,iBAAA;AAGb,QAAM,qBAAqB,WAAW,gBAAgB;AACtD,QAAM,eAAe,MAAM,aAAa,kBAAkB;AAC1D,WAAS,UAAU,QAAQ,YAAmC;AAG9D,QAAM,cAAc,MAAM,aAAa,eAAe;AACtD,WAAS,UAAU,QAAQ,WAAkC;AAG7D,WAAS,aAAa,MAAM;AAG5B,MAAI,oBAAoB;AACtB,UAAM,uBAAuB,WAAW,kBAAkB;AAC1D,UAAM,iBAAiB,MAAM,aAAa,oBAAoB;AAC9D,aAAS,UAAU,QAAQ,cAAqC;AAAA,EAClE;AAGA,MAAI,YAAY;AACd,aAAS,UAAU,QAAQ,UAAU;AAAA,EACvC;AAGA,WAAS,aAAa,MAAM,MAAM;AAGlC,MAAI,CAAC,OAAO,QAAQ,WAAW;AAC7B,WAAO,QAAQ,YAAY,sBAAA;AAAA,EAC7B;AAEA,SAAO;AACT;AA0BA,eAAsB,WACpB,QACA,UAA6B,IACd;AACf,QAAM;AAAA,IACJ,OAAO,qBAAA;AAAA,IACP,YAAY;AAAA,EAAA,IACV;AAGJ,eAAa,MAAM,MAAM;AAGzB,QAAM,eAAe,WAAW,IAAI;AACpC,MAAI,WAAW;AACb,UAAM,MAAM,QAAQ,YAAY,GAAG,EAAE,WAAW,MAAM;AAAA,EACxD;AAKA,QAAM,cAAcC,UAAc,MAAiB;AACnD,QAAM,UAAU,cAAc,aAAa,OAAO;AACpD;"}
1
+ {"version":3,"file":"loader.js","sources":["../../src/config/loader.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { parse as parseToml, stringify as stringifyToml } from '@iarna/toml';\nimport { ConfigSchema, type Config } from './schema.js';\nimport { getDefaultConfig } from './defaults.js';\nimport { applyEnvVars } from './env.js';\nimport { getDefaultConfigPath, getDefaultSessionsDir, getLocalConfigPath, getLocalSessionsDir, isInsideProject } from './paths.js';\nimport { deepMerge, type DeepPartial } from '../utils/deep-merge.js';\nimport { expandPath } from '../utils/path.js';\n\nexport type RawConfig = Partial<Config>;\n\n/**\n * Options for loadConfig function.\n */\nexport interface LoadConfigOptions {\n /** Path to global config file (default: platform-specific via getDefaultConfigPath()) */\n globalConfigPath?: string;\n /** Path to local config file (default: .search-hub/config.toml via getLocalConfigPath()) */\n localConfigPath?: string;\n /** Project directory for .search-hub/ resolution (default: cwd) */\n projectDir?: string;\n /**\n * Explicit config file path specified via CLI --config option.\n * Takes priority over global and local config files (applied after env vars).\n */\n explicitConfigPath?: string;\n /** CLI options to apply (highest priority) */\n cliOptions?: DeepPartial<Config>;\n}\n\n/**\n * Load and parse a TOML config file.\n * Returns empty object if file doesn't exist.\n * Throws with clear message if TOML is invalid.\n */\nexport async function loadTomlFile(path: string): Promise<RawConfig> {\n let content: string;\n\n try {\n content = await readFile(path, 'utf-8');\n } catch (error) {\n // File doesn't exist or can't be read\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw error;\n }\n\n // Empty file\n if (!content.trim()) {\n return {};\n }\n\n try {\n return parseToml(content) as RawConfig;\n } catch (error) {\n throw new Error(\n `Invalid TOML in ${path}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * Load configuration from all sources and merge them.\n *\n * Priority (highest to lowest):\n * 1. CLI options (cliOptions)\n * 2. Explicit --config file (explicitConfigPath)\n * 3. Environment variables\n * 4. Local config (.search-hub/config.toml)\n * 5. Global config (platform-specific, e.g. ~/.config/search-hub/config.toml on Linux)\n * 6. Default values\n */\nexport async function loadConfig(options: LoadConfigOptions = {}): Promise<Config> {\n const {\n globalConfigPath = getDefaultConfigPath(),\n localConfigPath = getLocalConfigPath(),\n projectDir,\n explicitConfigPath,\n cliOptions,\n } = options;\n\n // 1. Start with defaults\n let config = getDefaultConfig();\n\n // 2. Load and merge global config (lowest file priority)\n const expandedGlobalPath = expandPath(globalConfigPath);\n const globalConfig = await loadTomlFile(expandedGlobalPath);\n config = deepMerge(config, globalConfig as DeepPartial<Config>);\n\n // 3. Load and merge local config (overrides global)\n const localConfig = await loadTomlFile(localConfigPath);\n config = deepMerge(config, localConfig as DeepPartial<Config>);\n\n // 4. Apply environment variables (overrides local)\n config = applyEnvVars(config);\n\n // 5. Apply explicit --config file (overrides env vars, local, and global)\n if (explicitConfigPath) {\n const expandedExplicitPath = expandPath(explicitConfigPath);\n const explicitConfig = await loadTomlFile(expandedExplicitPath);\n config = deepMerge(config, explicitConfig as DeepPartial<Config>);\n }\n\n // 6. Apply CLI options (highest priority)\n if (cliOptions) {\n config = deepMerge(config, cliOptions);\n }\n\n // 7. Validate\n config = ConfigSchema.parse(config);\n\n // 8. Resolve empty session.directory based on project context\n if (!config.session.directory) {\n const inProject = projectDir\n ? await isInsideProject(projectDir)\n : false;\n config.session.directory = inProject\n ? getLocalSessionsDir(projectDir)\n : getDefaultSessionsDir();\n }\n\n return config;\n}\n\n/**\n * Options for saveConfig function.\n */\nexport interface SaveConfigOptions {\n /** Path to save config file (default: platform-specific via getDefaultConfigPath()) */\n path?: string;\n /** Create directory if it doesn't exist (default: true) */\n createDir?: boolean;\n}\n\n// Re-define JsonMap type to match @iarna/toml's expected input\n// This is necessary because the library's JsonMap type is not exported\ntype TomlValue = boolean | number | string | Date | TomlMap | TomlValue[];\ninterface TomlMap {\n [key: string]: TomlValue;\n}\n\n/**\n * Save configuration to a TOML file.\n *\n * @param config - Configuration object to save\n * @param options - Save options\n * @throws Error if config is invalid or file write fails\n */\nexport async function saveConfig(\n config: Config,\n options: SaveConfigOptions = {}\n): Promise<void> {\n const {\n path = getDefaultConfigPath(),\n createDir = true,\n } = options;\n\n // Validate config before saving\n ConfigSchema.parse(config);\n\n // Expand path and ensure directory exists\n const expandedPath = expandPath(path);\n if (createDir) {\n await mkdir(dirname(expandedPath), { recursive: true });\n }\n\n // Convert to TOML and write\n // Config structure is compatible with TOML's JsonMap type\n // The cast is safe because Config only contains TOML-compatible types\n const tomlContent = stringifyToml(config as TomlMap);\n await writeFile(expandedPath, tomlContent, 'utf-8');\n}\n"],"names":["parseToml","stringifyToml"],"mappings":";;;;;;;;;AAoCA,eAAsB,aAAa,MAAkC;AACnE,MAAI;AAEJ,MAAI;AACF,cAAU,MAAM,SAAS,MAAM,OAAO;AAAA,EACxC,SAAS,OAAO;AAEd,QAAK,MAAgC,SAAS,UAAU;AACtD,aAAO,CAAA;AAAA,IACT;AACA,UAAM;AAAA,EACR;AAGA,MAAI,CAAC,QAAQ,QAAQ;AACnB,WAAO,CAAA;AAAA,EACT;AAEA,MAAI;AACF,WAAOA,MAAU,OAAO;AAAA,EAC1B,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,mBAAmB,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAAA;AAAA,EAEtF;AACF;AAaA,eAAsB,WAAW,UAA6B,IAAqB;AACjF,QAAM;AAAA,IACJ,mBAAmB,qBAAA;AAAA,IACnB,kBAAkB,mBAAA;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE;AAGJ,MAAI,SAAS,iBAAA;AAGb,QAAM,qBAAqB,WAAW,gBAAgB;AACtD,QAAM,eAAe,MAAM,aAAa,kBAAkB;AAC1D,WAAS,UAAU,QAAQ,YAAmC;AAG9D,QAAM,cAAc,MAAM,aAAa,eAAe;AACtD,WAAS,UAAU,QAAQ,WAAkC;AAG7D,WAAS,aAAa,MAAM;AAG5B,MAAI,oBAAoB;AACtB,UAAM,uBAAuB,WAAW,kBAAkB;AAC1D,UAAM,iBAAiB,MAAM,aAAa,oBAAoB;AAC9D,aAAS,UAAU,QAAQ,cAAqC;AAAA,EAClE;AAGA,MAAI,YAAY;AACd,aAAS,UAAU,QAAQ,UAAU;AAAA,EACvC;AAGA,WAAS,aAAa,MAAM,MAAM;AAGlC,MAAI,CAAC,OAAO,QAAQ,WAAW;AAC7B,UAAM,YAAY,aACd,MAAM,gBAAgB,UAAU,IAChC;AACJ,WAAO,QAAQ,YAAY,YACvB,oBAAoB,UAAU,IAC9B,sBAAA;AAAA,EACN;AAEA,SAAO;AACT;AA0BA,eAAsB,WACpB,QACA,UAA6B,IACd;AACf,QAAM;AAAA,IACJ,OAAO,qBAAA;AAAA,IACP,YAAY;AAAA,EAAA,IACV;AAGJ,eAAa,MAAM,MAAM;AAGzB,QAAM,eAAe,WAAW,IAAI;AACpC,MAAI,WAAW;AACb,UAAM,MAAM,QAAQ,YAAY,GAAG,EAAE,WAAW,MAAM;AAAA,EACxD;AAKA,QAAM,cAAcC,UAAc,MAAiB;AACnD,QAAM,UAAU,cAAc,aAAa,OAAO;AACpD;"}
@@ -20,4 +20,25 @@ export declare function getDefaultConfigPath(): string;
20
20
  * Get the default sessions directory.
21
21
  */
22
22
  export declare function getDefaultSessionsDir(): string;
23
+ /**
24
+ * Get the project directory path (.search-hub/) relative to a base directory.
25
+ * Defaults to cwd.
26
+ */
27
+ export declare function getProjectDir(baseDir?: string): string;
28
+ /**
29
+ * Get the local config file path (.search-hub/config.toml).
30
+ */
31
+ export declare function getLocalConfigPath(baseDir?: string): string;
32
+ /**
33
+ * Get the local sessions directory (.search-hub/sessions/).
34
+ */
35
+ export declare function getLocalSessionsDir(baseDir?: string): string;
36
+ /**
37
+ * Get the local queries directory (.search-hub/queries/).
38
+ */
39
+ export declare function getLocalQueriesDir(baseDir?: string): string;
40
+ /**
41
+ * Check if the given directory (default: cwd) contains a .search-hub/ project directory.
42
+ */
43
+ export declare function isInsideProject(baseDir?: string): Promise<boolean>;
23
44
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAKD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOxE"}
@@ -1,22 +1,45 @@
1
1
  import envPaths from "env-paths";
2
2
  import { join } from "node:path";
3
+ import { stat } from "node:fs/promises";
3
4
  const paths = envPaths("search-hub", { suffix: "" });
4
5
  function getConfigDir() {
5
6
  return paths.config;
6
7
  }
7
- function getDataDir() {
8
- return paths.data;
9
- }
10
8
  function getDefaultConfigPath() {
11
9
  return join(paths.config, "config.toml");
12
10
  }
13
11
  function getDefaultSessionsDir() {
14
12
  return join(paths.data, "sessions");
15
13
  }
14
+ const PROJECT_DIR_NAME = ".search-hub";
15
+ function getProjectDir(baseDir) {
16
+ return join(baseDir ?? process.cwd(), PROJECT_DIR_NAME);
17
+ }
18
+ function getLocalConfigPath(baseDir) {
19
+ return join(getProjectDir(baseDir), "config.toml");
20
+ }
21
+ function getLocalSessionsDir(baseDir) {
22
+ return join(getProjectDir(baseDir), "sessions");
23
+ }
24
+ function getLocalQueriesDir(baseDir) {
25
+ return join(getProjectDir(baseDir), "queries");
26
+ }
27
+ async function isInsideProject(baseDir) {
28
+ try {
29
+ const stats = await stat(getProjectDir(baseDir));
30
+ return stats.isDirectory();
31
+ } catch {
32
+ return false;
33
+ }
34
+ }
16
35
  export {
17
36
  getConfigDir,
18
- getDataDir,
19
37
  getDefaultConfigPath,
20
- getDefaultSessionsDir
38
+ getDefaultSessionsDir,
39
+ getLocalConfigPath,
40
+ getLocalQueriesDir,
41
+ getLocalSessionsDir,
42
+ getProjectDir,
43
+ isInsideProject
21
44
  };
22
45
  //# sourceMappingURL=paths.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sources":["../../src/config/paths.ts"],"sourcesContent":["/**\n * Platform-specific paths using XDG Base Directory spec on Linux,\n * ~/Library on macOS, and AppData on Windows.\n */\nimport envPaths from 'env-paths';\nimport { join } from 'node:path';\n\n// Use empty suffix to get clean 'search-hub' directory names\nconst paths = envPaths('search-hub', { suffix: '' });\n\n/**\n * Get the config directory for search-hub.\n * - Linux: ~/.config/search-hub\n * - macOS: ~/Library/Preferences/search-hub\n * - Windows: %APPDATA%\\search-hub\\Config\n */\nexport function getConfigDir(): string {\n return paths.config;\n}\n\n/**\n * Get the data directory for search-hub.\n * - Linux: ~/.local/share/search-hub\n * - macOS: ~/Library/Application Support/search-hub\n * - Windows: %LOCALAPPDATA%\\search-hub\\Data\n */\nexport function getDataDir(): string {\n return paths.data;\n}\n\n/**\n * Get the default config file path.\n */\nexport function getDefaultConfigPath(): string {\n return join(paths.config, 'config.toml');\n}\n\n/**\n * Get the default sessions directory.\n */\nexport function getDefaultSessionsDir(): string {\n return join(paths.data, 'sessions');\n}\n"],"names":[],"mappings":";;AAQA,MAAM,QAAQ,SAAS,cAAc,EAAE,QAAQ,IAAI;AAQ5C,SAAS,eAAuB;AACrC,SAAO,MAAM;AACf;AAQO,SAAS,aAAqB;AACnC,SAAO,MAAM;AACf;AAKO,SAAS,uBAA+B;AAC7C,SAAO,KAAK,MAAM,QAAQ,aAAa;AACzC;AAKO,SAAS,wBAAgC;AAC9C,SAAO,KAAK,MAAM,MAAM,UAAU;AACpC;"}
1
+ {"version":3,"file":"paths.js","sources":["../../src/config/paths.ts"],"sourcesContent":["/**\n * Platform-specific paths using XDG Base Directory spec on Linux,\n * ~/Library on macOS, and AppData on Windows.\n */\nimport envPaths from 'env-paths';\nimport { join } from 'node:path';\nimport { stat } from 'node:fs/promises';\n\n// Use empty suffix to get clean 'search-hub' directory names\nconst paths = envPaths('search-hub', { suffix: '' });\n\n/**\n * Get the config directory for search-hub.\n * - Linux: ~/.config/search-hub\n * - macOS: ~/Library/Preferences/search-hub\n * - Windows: %APPDATA%\\search-hub\\Config\n */\nexport function getConfigDir(): string {\n return paths.config;\n}\n\n/**\n * Get the data directory for search-hub.\n * - Linux: ~/.local/share/search-hub\n * - macOS: ~/Library/Application Support/search-hub\n * - Windows: %LOCALAPPDATA%\\search-hub\\Data\n */\nexport function getDataDir(): string {\n return paths.data;\n}\n\n/**\n * Get the default config file path.\n */\nexport function getDefaultConfigPath(): string {\n return join(paths.config, 'config.toml');\n}\n\n/**\n * Get the default sessions directory.\n */\nexport function getDefaultSessionsDir(): string {\n return join(paths.data, 'sessions');\n}\n\n/** Name of the project-local directory. */\nconst PROJECT_DIR_NAME = '.search-hub';\n\n/**\n * Get the project directory path (.search-hub/) relative to a base directory.\n * Defaults to cwd.\n */\nexport function getProjectDir(baseDir?: string): string {\n return join(baseDir ?? process.cwd(), PROJECT_DIR_NAME);\n}\n\n/**\n * Get the local config file path (.search-hub/config.toml).\n */\nexport function getLocalConfigPath(baseDir?: string): string {\n return join(getProjectDir(baseDir), 'config.toml');\n}\n\n/**\n * Get the local sessions directory (.search-hub/sessions/).\n */\nexport function getLocalSessionsDir(baseDir?: string): string {\n return join(getProjectDir(baseDir), 'sessions');\n}\n\n/**\n * Get the local queries directory (.search-hub/queries/).\n */\nexport function getLocalQueriesDir(baseDir?: string): string {\n return join(getProjectDir(baseDir), 'queries');\n}\n\n/**\n * Check if the given directory (default: cwd) contains a .search-hub/ project directory.\n */\nexport async function isInsideProject(baseDir?: string): Promise<boolean> {\n try {\n const stats = await stat(getProjectDir(baseDir));\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n"],"names":[],"mappings":";;;AASA,MAAM,QAAQ,SAAS,cAAc,EAAE,QAAQ,IAAI;AAQ5C,SAAS,eAAuB;AACrC,SAAO,MAAM;AACf;AAeO,SAAS,uBAA+B;AAC7C,SAAO,KAAK,MAAM,QAAQ,aAAa;AACzC;AAKO,SAAS,wBAAgC;AAC9C,SAAO,KAAK,MAAM,MAAM,UAAU;AACpC;AAGA,MAAM,mBAAmB;AAMlB,SAAS,cAAc,SAA0B;AACtD,SAAO,KAAK,WAAW,QAAQ,IAAA,GAAO,gBAAgB;AACxD;AAKO,SAAS,mBAAmB,SAA0B;AAC3D,SAAO,KAAK,cAAc,OAAO,GAAG,aAAa;AACnD;AAKO,SAAS,oBAAoB,SAA0B;AAC5D,SAAO,KAAK,cAAc,OAAO,GAAG,UAAU;AAChD;AAKO,SAAS,mBAAmB,SAA0B;AAC3D,SAAO,KAAK,cAAc,OAAO,GAAG,SAAS;AAC/C;AAKA,eAAsB,gBAAgB,SAAoC;AACxE,MAAI;AACF,UAAM,QAAQ,MAAM,KAAK,cAAc,OAAO,CAAC;AAC/C,WAAO,MAAM,YAAA;AAAA,EACf,QAAQ;AACN,WAAO;AAAA,EACT;AACF;"}
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { extractControlledVocabTerms, validateControlledVocab } from "./query/vo
6
6
  import { loadConfig, saveConfig } from "./config/loader.js";
7
7
  import { ConfigSchema } from "./config/schema.js";
8
8
  import { DEFAULT_CONFIG, getDefaultConfig } from "./config/defaults.js";
9
+ import { getLocalConfigPath, getLocalQueriesDir, getLocalSessionsDir, getProjectDir, isInsideProject } from "./config/paths.js";
9
10
  import { createSession, generateSessionId, getResumableProviders, listSessions, loadSession, sanitizeName, saveSession, sessionExists, updateDatabaseStatus, updateSessionStatus } from "./session/manager.js";
10
11
  import { SessionLogger } from "./session/logger.js";
11
12
  import { createProviderError, isAuthError, isProviderError, isRateLimitError } from "./providers/base/types.js";
@@ -33,9 +34,14 @@ export {
33
34
  formatValidationErrors,
34
35
  generateSessionId,
35
36
  getDefaultConfig,
37
+ getLocalConfigPath,
38
+ getLocalQueriesDir,
39
+ getLocalSessionsDir,
40
+ getProjectDir,
36
41
  getResumableProviders,
37
42
  globalRegistry,
38
43
  isAuthError,
44
+ isInsideProject,
39
45
  isProviderError,
40
46
  isRateLimitError,
41
47
  listSessions,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
@@ -1,4 +1,4 @@
1
- const version = "0.22.0";
1
+ const version = "0.23.0";
2
2
  const pkg = {
3
3
  version
4
4
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ncukondo/search-hub",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "A CLI tool for systematic literature searching across multiple academic databases",
5
5
  "type": "module",
6
6
  "engines": {