/ utils / plugins / addDirPluginSettings.ts
addDirPluginSettings.ts
 1  /**
 2   * Reads plugin-related settings (enabledPlugins, extraKnownMarketplaces)
 3   * from --add-dir directories.
 4   *
 5   * These have the LOWEST priority — callers must spread standard settings
 6   * on top so that user/project/local/flag/policy sources all override.
 7   */
 8  
 9  import { join } from 'path'
10  import type { z } from 'zod/v4'
11  import { getAdditionalDirectoriesForClaudeMd } from '../../bootstrap/state.js'
12  import { parseSettingsFile } from '../settings/settings.js'
13  import type {
14    ExtraKnownMarketplaceSchema,
15    SettingsJson,
16  } from '../settings/types.js'
17  
18  type ExtraKnownMarketplace = z.infer<
19    ReturnType<typeof ExtraKnownMarketplaceSchema>
20  >
21  
22  const SETTINGS_FILES = ['settings.json', 'settings.local.json'] as const
23  
24  /**
25   * Returns a merged record of enabledPlugins from all --add-dir directories.
26   *
27   * Within each directory, settings.local.json is processed after settings.json
28   * (local wins within that dir). Across directories, later CLI-order wins on
29   * conflict.
30   *
31   * This has the lowest priority — callers must spread their standard settings
32   * on top to let user/project/local/flag/policy override.
33   */
34  export function getAddDirEnabledPlugins(): NonNullable<
35    SettingsJson['enabledPlugins']
36  > {
37    const result: NonNullable<SettingsJson['enabledPlugins']> = {}
38    for (const dir of getAdditionalDirectoriesForClaudeMd()) {
39      for (const file of SETTINGS_FILES) {
40        const { settings } = parseSettingsFile(join(dir, '.claude', file))
41        if (!settings?.enabledPlugins) {
42          continue
43        }
44        Object.assign(result, settings.enabledPlugins)
45      }
46    }
47    return result
48  }
49  
50  /**
51   * Returns a merged record of extraKnownMarketplaces from all --add-dir directories.
52   *
53   * Same priority rules as getAddDirEnabledPlugins: settings.local.json wins
54   * within each dir, and callers spread standard settings on top.
55   */
56  export function getAddDirExtraMarketplaces(): Record<
57    string,
58    ExtraKnownMarketplace
59  > {
60    const result: Record<string, ExtraKnownMarketplace> = {}
61    for (const dir of getAdditionalDirectoriesForClaudeMd()) {
62      for (const file of SETTINGS_FILES) {
63        const { settings } = parseSettingsFile(join(dir, '.claude', file))
64        if (!settings?.extraKnownMarketplaces) {
65          continue
66        }
67        Object.assign(result, settings.extraKnownMarketplaces)
68      }
69    }
70    return result
71  }