@agimon-ai/po-config 0.0.0-alpha.1 → 0.0.0-alpha.2
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/{config-BUw5kHsx.cjs → config-CfTb0_9G.cjs} +2 -2
- package/dist/{config-BUw5kHsx.cjs.map → config-CfTb0_9G.cjs.map} +1 -1
- package/dist/{config-Cm3EV1jp.d.mts → config-D2HbBLzo.d.mts} +14 -1
- package/dist/config-D2HbBLzo.d.mts.map +1 -0
- package/dist/{config-CKA07FxG.mjs → config-DoQWSt1V.mjs} +2 -2
- package/dist/{config-CKA07FxG.mjs.map → config-DoQWSt1V.mjs.map} +1 -1
- package/dist/config.cjs +3 -2
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +3 -3
- package/dist/{configPolicy-DmsZEp0t.cjs → configPolicy-Ce1QKDxa.cjs} +93 -5
- package/dist/configPolicy-Ce1QKDxa.cjs.map +1 -0
- package/dist/{configPolicy--TNX7feH.mjs → configPolicy-DCQgF5-f.mjs} +88 -6
- package/dist/configPolicy-DCQgF5-f.mjs.map +1 -0
- package/dist/{configWriter-BTuinLjs.cjs → configWriter-B7uO8MuN.cjs} +2 -2
- package/dist/{configWriter-BTuinLjs.cjs.map → configWriter-B7uO8MuN.cjs.map} +1 -1
- package/dist/{configWriter-BgkGaLrf.mjs → configWriter-DUtLgOlD.mjs} +2 -2
- package/dist/{configWriter-BgkGaLrf.mjs.map → configWriter-DUtLgOlD.mjs.map} +1 -1
- package/dist/configWriter.cjs +1 -1
- package/dist/configWriter.mjs +1 -1
- package/dist/{domains-DZOu9vYM.mjs → domains-BroCVHrS.mjs} +3 -3
- package/dist/{domains-DZOu9vYM.mjs.map → domains-BroCVHrS.mjs.map} +1 -1
- package/dist/{domains-CBYkuxs5.cjs → domains-DGCb7uMC.cjs} +3 -3
- package/dist/{domains-CBYkuxs5.cjs.map → domains-DGCb7uMC.cjs.map} +1 -1
- package/dist/domains.cjs +2 -2
- package/dist/domains.mjs +2 -2
- package/dist/extensions/server.cjs +7 -7
- package/dist/extensions/server.mjs +7 -7
- package/dist/harnessState.d.mts +1 -1
- package/dist/harnessStore.d.mts +1 -1
- package/dist/{index-BAaTySaM.d.mts → index-78zvoS9s.d.mts} +2 -2
- package/dist/{index-BAaTySaM.d.mts.map → index-78zvoS9s.d.mts.map} +1 -1
- package/dist/{index-DJpG-I9K.d.mts → index-CEUc7m16.d.mts} +3 -3
- package/dist/{index-DJpG-I9K.d.mts.map → index-CEUc7m16.d.mts.map} +1 -1
- package/dist/{index-CeOk2kqs.d.mts → index-CkDDvVQt.d.mts} +2 -2
- package/dist/{index-CeOk2kqs.d.mts.map → index-CkDDvVQt.d.mts.map} +1 -1
- package/dist/{index-B_lp0W3U.d.mts → index-DdH0w56b.d.mts} +7 -5
- package/dist/index-DdH0w56b.d.mts.map +1 -0
- package/dist/{index-CIQrKS1A.d.mts → index-Dy_-m7gx.d.mts} +2 -2
- package/dist/{index-CIQrKS1A.d.mts.map → index-Dy_-m7gx.d.mts.map} +1 -1
- package/dist/index.cjs +10 -9
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +10 -10
- package/dist/{init-C_9nyp3-.cjs → init-Cd3Ki6Ub.cjs} +2 -2
- package/dist/{init-C_9nyp3-.cjs.map → init-Cd3Ki6Ub.cjs.map} +1 -1
- package/dist/{init-DJ6wm-dr.mjs → init-DVzhiCUE.mjs} +2 -2
- package/dist/{init-DJ6wm-dr.mjs.map → init-DVzhiCUE.mjs.map} +1 -1
- package/dist/init.cjs +1 -1
- package/dist/init.mjs +1 -1
- package/dist/{layeredConfig-B922ibgn.mjs → layeredConfig-fukqN2EA.mjs} +2 -2
- package/dist/{layeredConfig-B922ibgn.mjs.map → layeredConfig-fukqN2EA.mjs.map} +1 -1
- package/dist/{layeredConfig-DdI5ysUf.cjs → layeredConfig-ol0274TN.cjs} +2 -2
- package/dist/{layeredConfig-DdI5ysUf.cjs.map → layeredConfig-ol0274TN.cjs.map} +1 -1
- package/dist/layeredConfig.cjs +1 -1
- package/dist/layeredConfig.mjs +1 -1
- package/dist/{majorModes-CmPLEpMT.mjs → majorModes-D1Itd8SN.mjs} +7 -3
- package/dist/majorModes-D1Itd8SN.mjs.map +1 -0
- package/dist/{majorModes-DPhVMuhT.cjs → majorModes-DnNSH9ZK.cjs} +7 -3
- package/dist/majorModes-DnNSH9ZK.cjs.map +1 -0
- package/dist/majorModes.cjs +1 -1
- package/dist/majorModes.d.mts +1 -1
- package/dist/majorModes.mjs +1 -1
- package/dist/piContext.cjs +1 -1
- package/dist/piContext.d.mts +2 -2
- package/dist/piContext.mjs +1 -1
- package/dist/{profiles-fujQKrS0.mjs → profiles-DBcYg5nA.mjs} +2 -2
- package/dist/{profiles-fujQKrS0.mjs.map → profiles-DBcYg5nA.mjs.map} +1 -1
- package/dist/{profiles-DnF9DBpd.cjs → profiles-tpplXY4r.cjs} +2 -2
- package/dist/{profiles-DnF9DBpd.cjs.map → profiles-tpplXY4r.cjs.map} +1 -1
- package/dist/profiles.cjs +1 -1
- package/dist/profiles.mjs +1 -1
- package/dist/selectionSwitch.cjs +2 -2
- package/dist/selectionSwitch.d.mts +2 -2
- package/dist/selectionSwitch.mjs +2 -2
- package/dist/{sessionConfig-Boh4Fdje.cjs → sessionConfig-Bf6xHWLd.cjs} +2 -2
- package/dist/{sessionConfig-Boh4Fdje.cjs.map → sessionConfig-Bf6xHWLd.cjs.map} +1 -1
- package/dist/{sessionConfig-CtLoc-lO.mjs → sessionConfig-DV5xTRRw.mjs} +2 -2
- package/dist/{sessionConfig-CtLoc-lO.mjs.map → sessionConfig-DV5xTRRw.mjs.map} +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +7 -7
- package/dist/config-Cm3EV1jp.d.mts.map +0 -1
- package/dist/configPolicy--TNX7feH.mjs.map +0 -1
- package/dist/configPolicy-DmsZEp0t.cjs.map +0 -1
- package/dist/index-B_lp0W3U.d.mts.map +0 -1
- package/dist/majorModes-CmPLEpMT.mjs.map +0 -1
- package/dist/majorModes-DPhVMuhT.cjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
-
const require_configPolicy = require("./configPolicy-
|
|
2
|
+
const require_configPolicy = require("./configPolicy-Ce1QKDxa.cjs");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let node_fs = require("node:fs");
|
|
5
5
|
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
@@ -216,4 +216,4 @@ Object.defineProperty(exports, "resolvePlanningPlansDirectory", {
|
|
|
216
216
|
}
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
-
//# sourceMappingURL=config-
|
|
219
|
+
//# sourceMappingURL=config-CfTb0_9G.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-BUw5kHsx.cjs","names":["fs","parseDoomConfig","os","poHomeDirectory","path","mergeDoomConfigs","parseYaml","createHash","configLeafKeys","configScopeOf","valueAtKeyPath"],"sources":["../src/services/config/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { parse as parseYaml } from 'yaml';\n\nimport type {\n ConfigDiagnostic,\n ConfigValueOrigin,\n DoomConfig,\n DoomConfigLayer,\n DoomConfigLayers,\n LenientParseResult,\n} from '../../types/config';\nimport { configLeafKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, valueAtKeyPath } from '../configPolicy';\n\nconst DOOM_DIR = '.po';\nconst CONFIG_FILE = 'config.yaml';\nconst PLANS_DIR = 'plans';\n\nfunction readConfig(filePath: string): DoomConfig {\n return fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath)\n : { projectTrust: 'ask' };\n}\n\nasync function readConfigAsync(filePath: string): Promise<DoomConfig> {\n try {\n return parseDoomConfig(await fs.promises.readFile(filePath, 'utf8'), filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { projectTrust: 'ask' };\n throw error;\n }\n}\n\nexport function globalDoomConfigDirectory(homeDirectory = os.homedir()): string {\n return poHomeDirectory(homeDirectory);\n}\n\nexport function globalDoomConfigPath(homeDirectory = os.homedir()): string {\n return path.join(globalDoomConfigDirectory(homeDirectory), CONFIG_FILE);\n}\n\nexport function resolvePlanningPlansDirectory(\n configured: string | undefined,\n repoRoot: string,\n homeDirectory = os.homedir(),\n): string {\n // Under Po's home, so Po writes nothing into ~/.pi.\n if (!configured) return path.join(globalDoomConfigDirectory(homeDirectory), PLANS_DIR);\n if (configured === '~') return homeDirectory;\n if (configured.startsWith('~/')) return path.resolve(homeDirectory, configured.slice(2));\n if (configured.startsWith('~')) {\n throw new Error(\"Doom planning plansDirectory supports only '~' or '~/' home aliases\");\n }\n return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);\n}\n\nexport function repositoryDoomConfigPath(repoRoot: string): string {\n return path.join(repoRoot, DOOM_DIR, CONFIG_FILE);\n}\n\n/**\n * True when a repository's `.po` folder is Po's home itself, as it is for a\n * session rooted at home. That folder is already the global layer; reading it\n * again as the repository layer would apply global-only keys at repository scope.\n */\nexport function isGlobalDoomConfigRoot(repoRoot: string, homeDirectory = os.homedir()): boolean {\n return path.resolve(repoRoot, DOOM_DIR) === path.resolve(globalDoomConfigDirectory(homeDirectory));\n}\n\nfunction repositoryConfigFor(repoRoot: string, homeDirectory: string): string | undefined {\n return isGlobalDoomConfigRoot(repoRoot, homeDirectory) ? undefined : repositoryDoomConfigPath(repoRoot);\n}\n\n/** Process-local distribution defaults never grant native authority or modify user files. */\nfunction distributionDefaults(config: DoomConfig, environment: NodeJS.ProcessEnv): DoomConfig {\n if (environment.PO_DISTRIBUTION !== 'desktop') return config;\n return { ...config, computerUse: { ...config.computerUse, enabled: config.computerUse?.enabled ?? true } };\n}\n\nexport function loadDoomConfig(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfig {\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n return distributionDefaults(\n mergeDoomConfigs(\n readConfig(globalDoomConfigPath(homeDirectory)),\n repositoryPath === undefined ? { projectTrust: 'ask' } : readConfig(repositoryPath),\n ),\n environment,\n );\n}\n\n/**\n * Loads the merged config, tolerating unknown keys in either file.\n *\n * Only `po sync` uses this. Everything that runs during a session keeps\n * `loadDoomConfig`, because a key a running extension cannot understand is\n * better reported than silently ignored; a build that refuses to start over\n * the same key is not.\n */\nexport function loadDoomConfigLenient(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): LenientParseResult {\n const read = (filePath: string | undefined): LenientParseResult =>\n filePath !== undefined && fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath, { lenient: true })\n : { config: { projectTrust: 'ask' }, diagnostics: [] };\n const globalConfig = read(globalDoomConfigPath(homeDirectory));\n const repositoryConfig = read(repositoryConfigFor(repoRoot, homeDirectory));\n const diagnostics: ConfigDiagnostic[] = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];\n // mergeDoomConfigs stays strict on purpose: its errors are cross-file scope\n // violations on known keys, which is a different fault from an unknown key.\n return {\n config: distributionDefaults(mergeDoomConfigs(globalConfig.config, repositoryConfig.config), environment),\n diagnostics,\n };\n}\n\nexport async function loadDoomConfigAsync(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<DoomConfig> {\n const globalConfig = await readConfigAsync(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryConfig: DoomConfig =\n repositoryPath === undefined ? { projectTrust: 'ask' } : await readConfigAsync(repositoryPath);\n return distributionDefaults(mergeDoomConfigs(globalConfig, repositoryConfig), environment);\n}\n\n/**\n * Reads one config file as a layer: what it is, what it sets, and the bytes it\n * held. A file that does not exist is a layer that sets nothing, which is a\n * normal state rather than an error.\n */\nfunction readLayer(filePath: string): DoomConfigLayer {\n let text: string;\n try {\n text = fs.readFileSync(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { filePath, exists: false, hash: '', keys: [] };\n }\n throw error;\n }\n // The raw document, not the parsed config: this is the one read that has to\n // distinguish a key the file set from a key the parser defaulted.\n const document = (parseYaml(text) ?? {}) as unknown;\n return {\n filePath,\n exists: true,\n hash: createHash('sha256').update(text, 'utf8').digest('hex'),\n keys: configLeafKeys(document),\n };\n}\n\n/**\n * The two config files kept apart, with the merge alongside them.\n *\n * `repoRoot` is optional because the global file is complete on its own: a\n * settings surface with no repository in view still has settings to show, and\n * demanding one would leave it with nothing to render rather than with the\n * global half.\n *\n * The origin answer respects the merge's own per-field rules rather than simply\n * preferring the repository: `editor` is read from the global side whatever the\n * repository says, and `projectTrust` from the repository side whatever the\n * global one says. Reporting a file as the source of a value the merge discards\n * is the exact confusion this exists to remove.\n */\nexport function loadDoomConfigLayers(\n repoRoot: string | undefined,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfigLayers {\n const globalLayer = readLayer(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryLayer =\n repositoryPath === undefined ? { filePath: '', exists: false, hash: '', keys: [] } : readLayer(repositoryPath);\n // With no repository there is nothing to merge, so the global file stands as\n // the effective config on its own.\n const effective =\n repoRoot === undefined\n ? distributionDefaults(\n mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), { projectTrust: 'ask' }),\n environment,\n )\n : loadDoomConfig(repoRoot, homeDirectory, environment);\n const sets = (layer: DoomConfigLayer, keyPath: readonly string[]): boolean => {\n const dotted = keyPath.join('.');\n return layer.keys.some((key) => key === dotted || key.startsWith(`${dotted}.`));\n };\n return {\n globalFile: globalLayer,\n repositoryFile: repositoryLayer,\n effective,\n originOf(keyPath: readonly string[]): ConfigValueOrigin {\n const scope = configScopeOf(keyPath);\n if (scope !== 'global' && sets(repositoryLayer, keyPath)) return 'repository';\n if (scope !== 'repository' && sets(globalLayer, keyPath)) return 'global';\n return 'default';\n },\n valueAt: (keyPath: readonly string[]) => valueAtKeyPath(effective, keyPath),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config-CfTb0_9G.cjs","names":["fs","parseDoomConfig","os","poHomeDirectory","path","mergeDoomConfigs","parseYaml","createHash","configLeafKeys","configScopeOf","valueAtKeyPath"],"sources":["../src/services/config/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { parse as parseYaml } from 'yaml';\n\nimport type {\n ConfigDiagnostic,\n ConfigValueOrigin,\n DoomConfig,\n DoomConfigLayer,\n DoomConfigLayers,\n LenientParseResult,\n} from '../../types/config';\nimport { configLeafKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, valueAtKeyPath } from '../configPolicy';\n\nconst DOOM_DIR = '.po';\nconst CONFIG_FILE = 'config.yaml';\nconst PLANS_DIR = 'plans';\n\nfunction readConfig(filePath: string): DoomConfig {\n return fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath)\n : { projectTrust: 'ask' };\n}\n\nasync function readConfigAsync(filePath: string): Promise<DoomConfig> {\n try {\n return parseDoomConfig(await fs.promises.readFile(filePath, 'utf8'), filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { projectTrust: 'ask' };\n throw error;\n }\n}\n\nexport function globalDoomConfigDirectory(homeDirectory = os.homedir()): string {\n return poHomeDirectory(homeDirectory);\n}\n\nexport function globalDoomConfigPath(homeDirectory = os.homedir()): string {\n return path.join(globalDoomConfigDirectory(homeDirectory), CONFIG_FILE);\n}\n\nexport function resolvePlanningPlansDirectory(\n configured: string | undefined,\n repoRoot: string,\n homeDirectory = os.homedir(),\n): string {\n // Under Po's home, so Po writes nothing into ~/.pi.\n if (!configured) return path.join(globalDoomConfigDirectory(homeDirectory), PLANS_DIR);\n if (configured === '~') return homeDirectory;\n if (configured.startsWith('~/')) return path.resolve(homeDirectory, configured.slice(2));\n if (configured.startsWith('~')) {\n throw new Error(\"Doom planning plansDirectory supports only '~' or '~/' home aliases\");\n }\n return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);\n}\n\nexport function repositoryDoomConfigPath(repoRoot: string): string {\n return path.join(repoRoot, DOOM_DIR, CONFIG_FILE);\n}\n\n/**\n * True when a repository's `.po` folder is Po's home itself, as it is for a\n * session rooted at home. That folder is already the global layer; reading it\n * again as the repository layer would apply global-only keys at repository scope.\n */\nexport function isGlobalDoomConfigRoot(repoRoot: string, homeDirectory = os.homedir()): boolean {\n return path.resolve(repoRoot, DOOM_DIR) === path.resolve(globalDoomConfigDirectory(homeDirectory));\n}\n\nfunction repositoryConfigFor(repoRoot: string, homeDirectory: string): string | undefined {\n return isGlobalDoomConfigRoot(repoRoot, homeDirectory) ? undefined : repositoryDoomConfigPath(repoRoot);\n}\n\n/** Process-local distribution defaults never grant native authority or modify user files. */\nfunction distributionDefaults(config: DoomConfig, environment: NodeJS.ProcessEnv): DoomConfig {\n if (environment.PO_DISTRIBUTION !== 'desktop') return config;\n return { ...config, computerUse: { ...config.computerUse, enabled: config.computerUse?.enabled ?? true } };\n}\n\nexport function loadDoomConfig(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfig {\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n return distributionDefaults(\n mergeDoomConfigs(\n readConfig(globalDoomConfigPath(homeDirectory)),\n repositoryPath === undefined ? { projectTrust: 'ask' } : readConfig(repositoryPath),\n ),\n environment,\n );\n}\n\n/**\n * Loads the merged config, tolerating unknown keys in either file.\n *\n * Only `po sync` uses this. Everything that runs during a session keeps\n * `loadDoomConfig`, because a key a running extension cannot understand is\n * better reported than silently ignored; a build that refuses to start over\n * the same key is not.\n */\nexport function loadDoomConfigLenient(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): LenientParseResult {\n const read = (filePath: string | undefined): LenientParseResult =>\n filePath !== undefined && fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath, { lenient: true })\n : { config: { projectTrust: 'ask' }, diagnostics: [] };\n const globalConfig = read(globalDoomConfigPath(homeDirectory));\n const repositoryConfig = read(repositoryConfigFor(repoRoot, homeDirectory));\n const diagnostics: ConfigDiagnostic[] = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];\n // mergeDoomConfigs stays strict on purpose: its errors are cross-file scope\n // violations on known keys, which is a different fault from an unknown key.\n return {\n config: distributionDefaults(mergeDoomConfigs(globalConfig.config, repositoryConfig.config), environment),\n diagnostics,\n };\n}\n\nexport async function loadDoomConfigAsync(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<DoomConfig> {\n const globalConfig = await readConfigAsync(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryConfig: DoomConfig =\n repositoryPath === undefined ? { projectTrust: 'ask' } : await readConfigAsync(repositoryPath);\n return distributionDefaults(mergeDoomConfigs(globalConfig, repositoryConfig), environment);\n}\n\n/**\n * Reads one config file as a layer: what it is, what it sets, and the bytes it\n * held. A file that does not exist is a layer that sets nothing, which is a\n * normal state rather than an error.\n */\nfunction readLayer(filePath: string): DoomConfigLayer {\n let text: string;\n try {\n text = fs.readFileSync(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { filePath, exists: false, hash: '', keys: [] };\n }\n throw error;\n }\n // The raw document, not the parsed config: this is the one read that has to\n // distinguish a key the file set from a key the parser defaulted.\n const document = (parseYaml(text) ?? {}) as unknown;\n return {\n filePath,\n exists: true,\n hash: createHash('sha256').update(text, 'utf8').digest('hex'),\n keys: configLeafKeys(document),\n };\n}\n\n/**\n * The two config files kept apart, with the merge alongside them.\n *\n * `repoRoot` is optional because the global file is complete on its own: a\n * settings surface with no repository in view still has settings to show, and\n * demanding one would leave it with nothing to render rather than with the\n * global half.\n *\n * The origin answer respects the merge's own per-field rules rather than simply\n * preferring the repository: `editor` is read from the global side whatever the\n * repository says, and `projectTrust` from the repository side whatever the\n * global one says. Reporting a file as the source of a value the merge discards\n * is the exact confusion this exists to remove.\n */\nexport function loadDoomConfigLayers(\n repoRoot: string | undefined,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfigLayers {\n const globalLayer = readLayer(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryLayer =\n repositoryPath === undefined ? { filePath: '', exists: false, hash: '', keys: [] } : readLayer(repositoryPath);\n // With no repository there is nothing to merge, so the global file stands as\n // the effective config on its own.\n const effective =\n repoRoot === undefined\n ? distributionDefaults(\n mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), { projectTrust: 'ask' }),\n environment,\n )\n : loadDoomConfig(repoRoot, homeDirectory, environment);\n const sets = (layer: DoomConfigLayer, keyPath: readonly string[]): boolean => {\n const dotted = keyPath.join('.');\n return layer.keys.some((key) => key === dotted || key.startsWith(`${dotted}.`));\n };\n return {\n globalFile: globalLayer,\n repositoryFile: repositoryLayer,\n effective,\n originOf(keyPath: readonly string[]): ConfigValueOrigin {\n const scope = configScopeOf(keyPath);\n if (scope !== 'global' && sets(repositoryLayer, keyPath)) return 'repository';\n if (scope !== 'repository' && sets(globalLayer, keyPath)) return 'global';\n return 'default';\n },\n valueAt: (keyPath: readonly string[]) => valueAtKeyPath(effective, keyPath),\n };\n}\n"],"mappings":"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"}
|
|
@@ -65,6 +65,13 @@ interface ComputerUseConfig {
|
|
|
65
65
|
interface EditorConfig {
|
|
66
66
|
command?: string;
|
|
67
67
|
}
|
|
68
|
+
/** How browse-tool launches Chromium. Global-only: one daemon serves every repository. */
|
|
69
|
+
interface BrowseConfig {
|
|
70
|
+
/** Unset keeps browse-tool's built-in choice. */
|
|
71
|
+
engine?: 'cloak' | 'chrome-for-testing';
|
|
72
|
+
/** What to do when CloakBrowser cannot start. Unset means stop with the error. */
|
|
73
|
+
fallback?: 'none' | 'chrome-for-testing';
|
|
74
|
+
}
|
|
68
75
|
interface VoiceModelConfig {
|
|
69
76
|
path?: string;
|
|
70
77
|
id?: string;
|
|
@@ -118,6 +125,11 @@ interface VoiceConfig {
|
|
|
118
125
|
'mlx-whisper'?: VoiceAdapterConfig;
|
|
119
126
|
};
|
|
120
127
|
autoCapture?: VoiceAutoCaptureConfig;
|
|
128
|
+
/** Live conversation settings. Global-only; unset fields use the realtime defaults. */
|
|
129
|
+
live?: {
|
|
130
|
+
voice?: string;
|
|
131
|
+
model?: string;
|
|
132
|
+
};
|
|
121
133
|
}
|
|
122
134
|
interface ResolvedVoiceConfig {
|
|
123
135
|
mode: VoiceMode;
|
|
@@ -173,6 +185,7 @@ interface DoomConfig {
|
|
|
173
185
|
computerUse?: ComputerUseConfig;
|
|
174
186
|
projectTrust: ProjectTrust;
|
|
175
187
|
editor?: EditorConfig;
|
|
188
|
+
browse?: BrowseConfig;
|
|
176
189
|
voice?: VoiceConfig;
|
|
177
190
|
selection?: DoomSelectionConfig;
|
|
178
191
|
/** Default layout identifier, resolved against the available web template packages. */
|
|
@@ -317,4 +330,4 @@ interface LenientParseResult {
|
|
|
317
330
|
}
|
|
318
331
|
//#endregion
|
|
319
332
|
export { PluginHookSource as A, VoiceTtsConfig as B, IDoomConfigService$1 as C, PlanningAgentConfig as D, PackageAttribution$1 as E, VoiceAutoCaptureConfig as F, VoiceConfig as I, VoiceEngine as L, ResolvedVoiceAutoCaptureConfig as M, ResolvedVoiceConfig as N, PlanningModeConfig as O, VoiceAdapterConfig as P, VoiceMode as R, IDoomConfigLoader as S, LenientParseResult as T, VoiceTtsEngine as V, DoomConfigTransitionStrategy as _, ConfigDiagnostic as a, EditorConfig as b, DeepReadonly as c, DoomConfigLayer as d, DoomConfigLayers as f, DoomConfigTransitionRecord as g, DoomConfigTransitionPhase as h, AutocompactTokenConfig as i, ProjectTrust as j, PlanningThinkingLevel as k, DoomConfig as l, DoomConfigSelection as m, AutocompactOverrideConfig as n, ConfigValueOrigin as o, DoomConfigPendingSelection as p, AutocompactThresholdConfig as r, DOOM_CONFIG_SERVICE as s, AutocompactModeConfig as t, DoomConfigContext as u, DoomHarnessContext as v, LenientParseOptions as w, HarnessState as x, DoomSelectionConfig as y, VoiceModelConfig as z };
|
|
320
|
-
//# sourceMappingURL=config-
|
|
333
|
+
//# sourceMappingURL=config-D2HbBLzo.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-D2HbBLzo.d.mts","names":["IDoomConfigService","DoomConfigServiceContract"],"sources":["../src/types/config.ts"],"mappings":";;;;;KAOY;KACA;KACA;KACA;KACA;UAEK;EACf;EACA,WAAW;;UAEI;EACf,OAAO;EACP,YAAY;EACZ;;;;;;;;;UASe;EACf;EACA;EACA;;;;;;;;;UASe;EACf;EACA;EACA;;;;;;;;;UASe;EACf;EACA,QAAQ;;UAEO;EACf;EACA;EACA,WAAW;EACX,aAAa;EACb,YAAY;;UAEG;EACf;;UAGe;EACf;;;UAGe;;EAEf;;EAEA;;UAEe;EACf;EACA;;UAEe;EACf;EACA,OAAO;;UAEQ;EACf,QAAQ;EACR;EACA;;UAEe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;;UAEU;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,KAAK;;UAEU;EACf,OAAO;EACP,SAAS;EACT;EACA;IAAa;IAAiB;;EAC9B;IACE,gBAAgB;IAChB,mBAAmB;IACnB,gBAAgB;;EAElB,cAAc;;EAEd;IAAS;IAAgB;;;UAEV;EACf,MAAM;EACN,QAAQ;EACR;EACA;IAAY;IAAiB;;EAC7B,UAAU,YAAY;EACtB,cAAc;;;;;;;;;UASC;EACf;EACA;EACA;;;UAIe;WACN;WACA;WACA;WACA;;WAEA;;KAGC;KACA;UAEK;WACN;WACA;WACA,QAAQ;WACR,QAAQ;WACR,UAAU;WACV,OAAO;;;KAIN,6BAA6B;WAAwC;;UAEhE;EACf;IAAU,WAAW;IAAoB,cAAc;;EACvD,cAAc;EACd,cAAc;EACd,SAAS;EACT,SAAS;EACT,QAAQ;EACR,YAAY;;EAEZ;IAAQ;;;EAER;IAAW;;;UAGI;EACf;EACA;;UAMe;EACf;;EAEA;EACA;EACA;;EAEA;;;;;;;;;;;EAWA,qBAAqB,eAAe;;EAEpC;EACA;EACA,oBAAoB;EACpB;EACA;EACA;EACA;EACA;EACA;EACA,aAAa;;EAEb,gBAAgB;;EAEhB;IAAgB;;EAChB;EACA;;;;;;EAMA,kBAAkB;;EAElB,eAAe;EACf;EACA;EACA;EACA;;KAGU,aAAa,UAAU,oBAAmB,6BAClD,SACA,+BAA+B,oBACpB,aAAa,WACtB,oCACc,cAAc,SAAS,aAAa,OAAO,YACvD;KAEI,qBAAqB,aAAa;UAE7B;WACN,UAAU,aAAa;WACvB,SAAS;;WAET,mBAAmB,aAAa;;WAEhC;;;UAIM;EACf,KAAK,kBAAkB,yBAAyB;;;UAIjCA,6BAA2BC,mBAA0B,mBAAmB;;YAG7E;IACR,eAAeD;;;;KAQP;;UAGK;EACf;EACA;;;;;;EAMA;;EAEA;;;;;;;;;;UAWe;;EAEf,YAAY;EACZ,gBAAgB;EAChB,WAAW;;EAEX,SAAS,6BAA6B;;EAEtC,QAAQ;;;;;;;;;UAUO;EACf;;EAEA;EACA;;;UAIe;EACf;;;UAIe;EACf,QAAQ;EACR,aAAa"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as configScopeOf, d as parseDoomConfig, l as mergeDoomConfigs, m as valueAtKeyPath, o as configLeafKeys } from "./configPolicy-DCQgF5-f.mjs";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
@@ -159,4 +159,4 @@ function loadDoomConfigLayers(repoRoot, homeDirectory = os.homedir(), environmen
|
|
|
159
159
|
//#endregion
|
|
160
160
|
export { loadDoomConfigAsync as a, repositoryDoomConfigPath as c, loadDoomConfig as i, resolvePlanningPlansDirectory as l, globalDoomConfigPath as n, loadDoomConfigLayers as o, isGlobalDoomConfigRoot as r, loadDoomConfigLenient as s, globalDoomConfigDirectory as t };
|
|
161
161
|
|
|
162
|
-
//# sourceMappingURL=config-
|
|
162
|
+
//# sourceMappingURL=config-DoQWSt1V.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-CKA07FxG.mjs","names":["parseYaml"],"sources":["../src/services/config/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { parse as parseYaml } from 'yaml';\n\nimport type {\n ConfigDiagnostic,\n ConfigValueOrigin,\n DoomConfig,\n DoomConfigLayer,\n DoomConfigLayers,\n LenientParseResult,\n} from '../../types/config';\nimport { configLeafKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, valueAtKeyPath } from '../configPolicy';\n\nconst DOOM_DIR = '.po';\nconst CONFIG_FILE = 'config.yaml';\nconst PLANS_DIR = 'plans';\n\nfunction readConfig(filePath: string): DoomConfig {\n return fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath)\n : { projectTrust: 'ask' };\n}\n\nasync function readConfigAsync(filePath: string): Promise<DoomConfig> {\n try {\n return parseDoomConfig(await fs.promises.readFile(filePath, 'utf8'), filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { projectTrust: 'ask' };\n throw error;\n }\n}\n\nexport function globalDoomConfigDirectory(homeDirectory = os.homedir()): string {\n return poHomeDirectory(homeDirectory);\n}\n\nexport function globalDoomConfigPath(homeDirectory = os.homedir()): string {\n return path.join(globalDoomConfigDirectory(homeDirectory), CONFIG_FILE);\n}\n\nexport function resolvePlanningPlansDirectory(\n configured: string | undefined,\n repoRoot: string,\n homeDirectory = os.homedir(),\n): string {\n // Under Po's home, so Po writes nothing into ~/.pi.\n if (!configured) return path.join(globalDoomConfigDirectory(homeDirectory), PLANS_DIR);\n if (configured === '~') return homeDirectory;\n if (configured.startsWith('~/')) return path.resolve(homeDirectory, configured.slice(2));\n if (configured.startsWith('~')) {\n throw new Error(\"Doom planning plansDirectory supports only '~' or '~/' home aliases\");\n }\n return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);\n}\n\nexport function repositoryDoomConfigPath(repoRoot: string): string {\n return path.join(repoRoot, DOOM_DIR, CONFIG_FILE);\n}\n\n/**\n * True when a repository's `.po` folder is Po's home itself, as it is for a\n * session rooted at home. That folder is already the global layer; reading it\n * again as the repository layer would apply global-only keys at repository scope.\n */\nexport function isGlobalDoomConfigRoot(repoRoot: string, homeDirectory = os.homedir()): boolean {\n return path.resolve(repoRoot, DOOM_DIR) === path.resolve(globalDoomConfigDirectory(homeDirectory));\n}\n\nfunction repositoryConfigFor(repoRoot: string, homeDirectory: string): string | undefined {\n return isGlobalDoomConfigRoot(repoRoot, homeDirectory) ? undefined : repositoryDoomConfigPath(repoRoot);\n}\n\n/** Process-local distribution defaults never grant native authority or modify user files. */\nfunction distributionDefaults(config: DoomConfig, environment: NodeJS.ProcessEnv): DoomConfig {\n if (environment.PO_DISTRIBUTION !== 'desktop') return config;\n return { ...config, computerUse: { ...config.computerUse, enabled: config.computerUse?.enabled ?? true } };\n}\n\nexport function loadDoomConfig(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfig {\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n return distributionDefaults(\n mergeDoomConfigs(\n readConfig(globalDoomConfigPath(homeDirectory)),\n repositoryPath === undefined ? { projectTrust: 'ask' } : readConfig(repositoryPath),\n ),\n environment,\n );\n}\n\n/**\n * Loads the merged config, tolerating unknown keys in either file.\n *\n * Only `po sync` uses this. Everything that runs during a session keeps\n * `loadDoomConfig`, because a key a running extension cannot understand is\n * better reported than silently ignored; a build that refuses to start over\n * the same key is not.\n */\nexport function loadDoomConfigLenient(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): LenientParseResult {\n const read = (filePath: string | undefined): LenientParseResult =>\n filePath !== undefined && fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath, { lenient: true })\n : { config: { projectTrust: 'ask' }, diagnostics: [] };\n const globalConfig = read(globalDoomConfigPath(homeDirectory));\n const repositoryConfig = read(repositoryConfigFor(repoRoot, homeDirectory));\n const diagnostics: ConfigDiagnostic[] = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];\n // mergeDoomConfigs stays strict on purpose: its errors are cross-file scope\n // violations on known keys, which is a different fault from an unknown key.\n return {\n config: distributionDefaults(mergeDoomConfigs(globalConfig.config, repositoryConfig.config), environment),\n diagnostics,\n };\n}\n\nexport async function loadDoomConfigAsync(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<DoomConfig> {\n const globalConfig = await readConfigAsync(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryConfig: DoomConfig =\n repositoryPath === undefined ? { projectTrust: 'ask' } : await readConfigAsync(repositoryPath);\n return distributionDefaults(mergeDoomConfigs(globalConfig, repositoryConfig), environment);\n}\n\n/**\n * Reads one config file as a layer: what it is, what it sets, and the bytes it\n * held. A file that does not exist is a layer that sets nothing, which is a\n * normal state rather than an error.\n */\nfunction readLayer(filePath: string): DoomConfigLayer {\n let text: string;\n try {\n text = fs.readFileSync(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { filePath, exists: false, hash: '', keys: [] };\n }\n throw error;\n }\n // The raw document, not the parsed config: this is the one read that has to\n // distinguish a key the file set from a key the parser defaulted.\n const document = (parseYaml(text) ?? {}) as unknown;\n return {\n filePath,\n exists: true,\n hash: createHash('sha256').update(text, 'utf8').digest('hex'),\n keys: configLeafKeys(document),\n };\n}\n\n/**\n * The two config files kept apart, with the merge alongside them.\n *\n * `repoRoot` is optional because the global file is complete on its own: a\n * settings surface with no repository in view still has settings to show, and\n * demanding one would leave it with nothing to render rather than with the\n * global half.\n *\n * The origin answer respects the merge's own per-field rules rather than simply\n * preferring the repository: `editor` is read from the global side whatever the\n * repository says, and `projectTrust` from the repository side whatever the\n * global one says. Reporting a file as the source of a value the merge discards\n * is the exact confusion this exists to remove.\n */\nexport function loadDoomConfigLayers(\n repoRoot: string | undefined,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfigLayers {\n const globalLayer = readLayer(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryLayer =\n repositoryPath === undefined ? { filePath: '', exists: false, hash: '', keys: [] } : readLayer(repositoryPath);\n // With no repository there is nothing to merge, so the global file stands as\n // the effective config on its own.\n const effective =\n repoRoot === undefined\n ? distributionDefaults(\n mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), { projectTrust: 'ask' }),\n environment,\n )\n : loadDoomConfig(repoRoot, homeDirectory, environment);\n const sets = (layer: DoomConfigLayer, keyPath: readonly string[]): boolean => {\n const dotted = keyPath.join('.');\n return layer.keys.some((key) => key === dotted || key.startsWith(`${dotted}.`));\n };\n return {\n globalFile: globalLayer,\n repositoryFile: repositoryLayer,\n effective,\n originOf(keyPath: readonly string[]): ConfigValueOrigin {\n const scope = configScopeOf(keyPath);\n if (scope !== 'global' && sets(repositoryLayer, keyPath)) return 'repository';\n if (scope !== 'repository' && sets(globalLayer, keyPath)) return 'global';\n return 'default';\n },\n valueAt: (keyPath: readonly string[]) => valueAtKeyPath(effective, keyPath),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config-DoQWSt1V.mjs","names":["parseYaml"],"sources":["../src/services/config/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { parse as parseYaml } from 'yaml';\n\nimport type {\n ConfigDiagnostic,\n ConfigValueOrigin,\n DoomConfig,\n DoomConfigLayer,\n DoomConfigLayers,\n LenientParseResult,\n} from '../../types/config';\nimport { configLeafKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, valueAtKeyPath } from '../configPolicy';\n\nconst DOOM_DIR = '.po';\nconst CONFIG_FILE = 'config.yaml';\nconst PLANS_DIR = 'plans';\n\nfunction readConfig(filePath: string): DoomConfig {\n return fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath)\n : { projectTrust: 'ask' };\n}\n\nasync function readConfigAsync(filePath: string): Promise<DoomConfig> {\n try {\n return parseDoomConfig(await fs.promises.readFile(filePath, 'utf8'), filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { projectTrust: 'ask' };\n throw error;\n }\n}\n\nexport function globalDoomConfigDirectory(homeDirectory = os.homedir()): string {\n return poHomeDirectory(homeDirectory);\n}\n\nexport function globalDoomConfigPath(homeDirectory = os.homedir()): string {\n return path.join(globalDoomConfigDirectory(homeDirectory), CONFIG_FILE);\n}\n\nexport function resolvePlanningPlansDirectory(\n configured: string | undefined,\n repoRoot: string,\n homeDirectory = os.homedir(),\n): string {\n // Under Po's home, so Po writes nothing into ~/.pi.\n if (!configured) return path.join(globalDoomConfigDirectory(homeDirectory), PLANS_DIR);\n if (configured === '~') return homeDirectory;\n if (configured.startsWith('~/')) return path.resolve(homeDirectory, configured.slice(2));\n if (configured.startsWith('~')) {\n throw new Error(\"Doom planning plansDirectory supports only '~' or '~/' home aliases\");\n }\n return path.isAbsolute(configured) ? path.normalize(configured) : path.resolve(repoRoot, configured);\n}\n\nexport function repositoryDoomConfigPath(repoRoot: string): string {\n return path.join(repoRoot, DOOM_DIR, CONFIG_FILE);\n}\n\n/**\n * True when a repository's `.po` folder is Po's home itself, as it is for a\n * session rooted at home. That folder is already the global layer; reading it\n * again as the repository layer would apply global-only keys at repository scope.\n */\nexport function isGlobalDoomConfigRoot(repoRoot: string, homeDirectory = os.homedir()): boolean {\n return path.resolve(repoRoot, DOOM_DIR) === path.resolve(globalDoomConfigDirectory(homeDirectory));\n}\n\nfunction repositoryConfigFor(repoRoot: string, homeDirectory: string): string | undefined {\n return isGlobalDoomConfigRoot(repoRoot, homeDirectory) ? undefined : repositoryDoomConfigPath(repoRoot);\n}\n\n/** Process-local distribution defaults never grant native authority or modify user files. */\nfunction distributionDefaults(config: DoomConfig, environment: NodeJS.ProcessEnv): DoomConfig {\n if (environment.PO_DISTRIBUTION !== 'desktop') return config;\n return { ...config, computerUse: { ...config.computerUse, enabled: config.computerUse?.enabled ?? true } };\n}\n\nexport function loadDoomConfig(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfig {\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n return distributionDefaults(\n mergeDoomConfigs(\n readConfig(globalDoomConfigPath(homeDirectory)),\n repositoryPath === undefined ? { projectTrust: 'ask' } : readConfig(repositoryPath),\n ),\n environment,\n );\n}\n\n/**\n * Loads the merged config, tolerating unknown keys in either file.\n *\n * Only `po sync` uses this. Everything that runs during a session keeps\n * `loadDoomConfig`, because a key a running extension cannot understand is\n * better reported than silently ignored; a build that refuses to start over\n * the same key is not.\n */\nexport function loadDoomConfigLenient(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): LenientParseResult {\n const read = (filePath: string | undefined): LenientParseResult =>\n filePath !== undefined && fs.existsSync(filePath)\n ? parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath, { lenient: true })\n : { config: { projectTrust: 'ask' }, diagnostics: [] };\n const globalConfig = read(globalDoomConfigPath(homeDirectory));\n const repositoryConfig = read(repositoryConfigFor(repoRoot, homeDirectory));\n const diagnostics: ConfigDiagnostic[] = [...globalConfig.diagnostics, ...repositoryConfig.diagnostics];\n // mergeDoomConfigs stays strict on purpose: its errors are cross-file scope\n // violations on known keys, which is a different fault from an unknown key.\n return {\n config: distributionDefaults(mergeDoomConfigs(globalConfig.config, repositoryConfig.config), environment),\n diagnostics,\n };\n}\n\nexport async function loadDoomConfigAsync(\n repoRoot: string,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<DoomConfig> {\n const globalConfig = await readConfigAsync(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryConfig: DoomConfig =\n repositoryPath === undefined ? { projectTrust: 'ask' } : await readConfigAsync(repositoryPath);\n return distributionDefaults(mergeDoomConfigs(globalConfig, repositoryConfig), environment);\n}\n\n/**\n * Reads one config file as a layer: what it is, what it sets, and the bytes it\n * held. A file that does not exist is a layer that sets nothing, which is a\n * normal state rather than an error.\n */\nfunction readLayer(filePath: string): DoomConfigLayer {\n let text: string;\n try {\n text = fs.readFileSync(filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { filePath, exists: false, hash: '', keys: [] };\n }\n throw error;\n }\n // The raw document, not the parsed config: this is the one read that has to\n // distinguish a key the file set from a key the parser defaulted.\n const document = (parseYaml(text) ?? {}) as unknown;\n return {\n filePath,\n exists: true,\n hash: createHash('sha256').update(text, 'utf8').digest('hex'),\n keys: configLeafKeys(document),\n };\n}\n\n/**\n * The two config files kept apart, with the merge alongside them.\n *\n * `repoRoot` is optional because the global file is complete on its own: a\n * settings surface with no repository in view still has settings to show, and\n * demanding one would leave it with nothing to render rather than with the\n * global half.\n *\n * The origin answer respects the merge's own per-field rules rather than simply\n * preferring the repository: `editor` is read from the global side whatever the\n * repository says, and `projectTrust` from the repository side whatever the\n * global one says. Reporting a file as the source of a value the merge discards\n * is the exact confusion this exists to remove.\n */\nexport function loadDoomConfigLayers(\n repoRoot: string | undefined,\n homeDirectory = os.homedir(),\n environment: NodeJS.ProcessEnv = process.env,\n): DoomConfigLayers {\n const globalLayer = readLayer(globalDoomConfigPath(homeDirectory));\n const repositoryPath = repoRoot === undefined ? undefined : repositoryConfigFor(repoRoot, homeDirectory);\n const repositoryLayer =\n repositoryPath === undefined ? { filePath: '', exists: false, hash: '', keys: [] } : readLayer(repositoryPath);\n // With no repository there is nothing to merge, so the global file stands as\n // the effective config on its own.\n const effective =\n repoRoot === undefined\n ? distributionDefaults(\n mergeDoomConfigs(readConfig(globalDoomConfigPath(homeDirectory)), { projectTrust: 'ask' }),\n environment,\n )\n : loadDoomConfig(repoRoot, homeDirectory, environment);\n const sets = (layer: DoomConfigLayer, keyPath: readonly string[]): boolean => {\n const dotted = keyPath.join('.');\n return layer.keys.some((key) => key === dotted || key.startsWith(`${dotted}.`));\n };\n return {\n globalFile: globalLayer,\n repositoryFile: repositoryLayer,\n effective,\n originOf(keyPath: readonly string[]): ConfigValueOrigin {\n const scope = configScopeOf(keyPath);\n if (scope !== 'global' && sets(repositoryLayer, keyPath)) return 'repository';\n if (scope !== 'repository' && sets(globalLayer, keyPath)) return 'global';\n return 'default';\n },\n valueAt: (keyPath: readonly string[]) => valueAtKeyPath(effective, keyPath),\n };\n}\n"],"mappings":"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"}
|
package/dist/config.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_configPolicy = require("./configPolicy-
|
|
3
|
-
const require_config = require("./config-
|
|
2
|
+
const require_configPolicy = require("./configPolicy-Ce1QKDxa.cjs");
|
|
3
|
+
const require_config = require("./config-CfTb0_9G.cjs");
|
|
4
4
|
exports.DOOM_PLANNING_THINKING_LEVELS = require_configPolicy.DOOM_PLANNING_THINKING_LEVELS;
|
|
5
5
|
exports.DOOM_VOICE_ENGINES = require_configPolicy.DOOM_VOICE_ENGINES;
|
|
6
|
+
exports.DOOM_VOICE_LIVE_VOICES = require_configPolicy.DOOM_VOICE_LIVE_VOICES;
|
|
6
7
|
exports.DOOM_VOICE_MODES = require_configPolicy.DOOM_VOICE_MODES;
|
|
7
8
|
exports.DOOM_VOICE_TTS_ENGINES = require_configPolicy.DOOM_VOICE_TTS_ENGINES;
|
|
8
9
|
exports.configLeafKeys = require_configPolicy.configLeafKeys;
|
package/dist/config.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { T as LenientParseResult, a as ConfigDiagnostic, d as DoomConfigLayer, f as DoomConfigLayers, o as ConfigValueOrigin, w as LenientParseOptions } from "./config-
|
|
2
|
-
import {
|
|
3
|
-
export { type ConfigDiagnostic, type ConfigKeyScope, type ConfigValueOrigin, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_MODES, DOOM_VOICE_TTS_ENGINES, type DoomConfigLayer, type DoomConfigLayers, type LenientParseOptions, type LenientParseResult, configLeafKeys, configRootKeys, configScopeOf, globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, loadDoomConfigLenient, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
|
1
|
+
import { T as LenientParseResult, a as ConfigDiagnostic, d as DoomConfigLayer, f as DoomConfigLayers, o as ConfigValueOrigin, w as LenientParseOptions } from "./config-D2HbBLzo.mjs";
|
|
2
|
+
import { C as resolvePlanningPlansDirectory, S as repositoryDoomConfigPath, _ as globalDoomConfigPath, a as DOOM_VOICE_MODES, b as loadDoomConfigLayers, c as configRootKeys, d as parseAutocompactModeConfig, f as parseDoomConfig, g as globalDoomConfigDirectory, h as valueAtKeyPath, i as DOOM_VOICE_LIVE_VOICES, l as configScopeOf, m as resolveVoiceConfig, n as DOOM_PLANNING_THINKING_LEVELS, o as DOOM_VOICE_TTS_ENGINES, p as parsePlanningModeConfig, r as DOOM_VOICE_ENGINES, s as configLeafKeys, t as ConfigKeyScope, u as mergeDoomConfigs, v as loadDoomConfig, x as loadDoomConfigLenient, y as loadDoomConfigAsync } from "./index-DdH0w56b.mjs";
|
|
3
|
+
export { type ConfigDiagnostic, type ConfigKeyScope, type ConfigValueOrigin, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_LIVE_VOICES, DOOM_VOICE_MODES, DOOM_VOICE_TTS_ENGINES, type DoomConfigLayer, type DoomConfigLayers, type LenientParseOptions, type LenientParseResult, configLeafKeys, configRootKeys, configScopeOf, globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, loadDoomConfigLenient, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
package/dist/config.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { a as loadDoomConfigAsync, c as repositoryDoomConfigPath, i as loadDoomConfig, l as resolvePlanningPlansDirectory, n as globalDoomConfigPath, o as loadDoomConfigLayers, s as loadDoomConfigLenient, t as globalDoomConfigDirectory } from "./config-
|
|
3
|
-
export { DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_MODES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, loadDoomConfigLenient, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
|
1
|
+
import { a as DOOM_VOICE_TTS_ENGINES, c as configScopeOf, d as parseDoomConfig, f as parsePlanningModeConfig, i as DOOM_VOICE_MODES, l as mergeDoomConfigs, m as valueAtKeyPath, n as DOOM_VOICE_ENGINES, o as configLeafKeys, p as resolveVoiceConfig, r as DOOM_VOICE_LIVE_VOICES, s as configRootKeys, t as DOOM_PLANNING_THINKING_LEVELS, u as parseAutocompactModeConfig } from "./configPolicy-DCQgF5-f.mjs";
|
|
2
|
+
import { a as loadDoomConfigAsync, c as repositoryDoomConfigPath, i as loadDoomConfig, l as resolvePlanningPlansDirectory, n as globalDoomConfigPath, o as loadDoomConfigLayers, s as loadDoomConfigLenient, t as globalDoomConfigDirectory } from "./config-DoQWSt1V.mjs";
|
|
3
|
+
export { DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_LIVE_VOICES, DOOM_VOICE_MODES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, loadDoomConfigLenient, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
|
@@ -10,11 +10,15 @@ const ROOT_KEYS = [
|
|
|
10
10
|
"computerUse",
|
|
11
11
|
"projectTrust",
|
|
12
12
|
"editor",
|
|
13
|
+
"browse",
|
|
13
14
|
"voice",
|
|
14
15
|
"selection",
|
|
15
16
|
"web",
|
|
16
17
|
"native"
|
|
17
18
|
];
|
|
19
|
+
const BROWSE_KEYS = ["engine", "fallback"];
|
|
20
|
+
const DOOM_BROWSE_ENGINES = ["cloak", "chrome-for-testing"];
|
|
21
|
+
const DOOM_BROWSE_FALLBACKS = ["none", "chrome-for-testing"];
|
|
18
22
|
const SELECTION_KEYS = [
|
|
19
23
|
"majorMode",
|
|
20
24
|
"domains",
|
|
@@ -57,8 +61,12 @@ const VOICE_KEYS = [
|
|
|
57
61
|
"language",
|
|
58
62
|
"recorder",
|
|
59
63
|
"adapters",
|
|
60
|
-
"autoCapture"
|
|
64
|
+
"autoCapture",
|
|
65
|
+
"live"
|
|
61
66
|
];
|
|
67
|
+
const VOICE_LIVE_KEYS = ["voice", "model"];
|
|
68
|
+
const LIVE_MODEL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u;
|
|
69
|
+
const MAX_LIVE_MODEL_LENGTH = 64;
|
|
62
70
|
const RECORDER_KEYS = ["binary", "device"];
|
|
63
71
|
const WHISPER_CPP_ENGINE = "whisper-cpp";
|
|
64
72
|
const OPENAI_WHISPER_ENGINE = "openai-whisper";
|
|
@@ -154,6 +162,34 @@ const DOOM_VOICE_ENGINES = [
|
|
|
154
162
|
MLX_WHISPER_ENGINE
|
|
155
163
|
];
|
|
156
164
|
const DOOM_VOICE_TTS_ENGINES = [MACOS_SAY_TTS_ENGINE];
|
|
165
|
+
/** Codex realtime V3 voices, from `codex-rs/protocol/src/protocol.rs` `RealtimeVoicesList::builtin()`. */
|
|
166
|
+
const DOOM_VOICE_LIVE_VOICES = [
|
|
167
|
+
"juniper",
|
|
168
|
+
"maple",
|
|
169
|
+
"spruce",
|
|
170
|
+
"ember",
|
|
171
|
+
"vale",
|
|
172
|
+
"breeze",
|
|
173
|
+
"arbor",
|
|
174
|
+
"sol",
|
|
175
|
+
"cove",
|
|
176
|
+
"aube",
|
|
177
|
+
"bubbie",
|
|
178
|
+
"haetsal",
|
|
179
|
+
"hanul",
|
|
180
|
+
"himari",
|
|
181
|
+
"leher",
|
|
182
|
+
"miko",
|
|
183
|
+
"neer",
|
|
184
|
+
"porto",
|
|
185
|
+
"rindo",
|
|
186
|
+
"rio",
|
|
187
|
+
"rivage",
|
|
188
|
+
"selva",
|
|
189
|
+
"sonna",
|
|
190
|
+
"tinta",
|
|
191
|
+
"viola"
|
|
192
|
+
];
|
|
157
193
|
const THINKING_VALUES = new Set(DOOM_PLANNING_THINKING_LEVELS);
|
|
158
194
|
const TRUST_VALUES = /* @__PURE__ */ new Set([
|
|
159
195
|
"ask",
|
|
@@ -461,6 +497,23 @@ function parseVoice(value, filePath) {
|
|
|
461
497
|
}
|
|
462
498
|
const autoCapture = parseAutoCapture(value.autoCapture, filePath);
|
|
463
499
|
if (autoCapture) result.autoCapture = autoCapture;
|
|
500
|
+
const live = parseVoiceLive(value.live, filePath);
|
|
501
|
+
if (live) result.live = live;
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
504
|
+
function parseVoiceLive(value, filePath) {
|
|
505
|
+
if (value === void 0) return void 0;
|
|
506
|
+
if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires voice.live to be an object`);
|
|
507
|
+
assertKeys(value, VOICE_LIVE_KEYS, "voice.live", filePath);
|
|
508
|
+
const result = {};
|
|
509
|
+
if (value.voice !== void 0) {
|
|
510
|
+
if (typeof value.voice !== "string" || !DOOM_VOICE_LIVE_VOICES.includes(value.voice)) throw new Error(`Doom config at ${filePath} requires voice.live.voice to be one of: ${DOOM_VOICE_LIVE_VOICES.join(", ")}`);
|
|
511
|
+
result.voice = value.voice;
|
|
512
|
+
}
|
|
513
|
+
if (value.model !== void 0) {
|
|
514
|
+
if (typeof value.model !== "string" || value.model.length > MAX_LIVE_MODEL_LENGTH || !LIVE_MODEL_PATTERN.test(value.model)) throw new Error(`Doom config at ${filePath} requires voice.live.model to be a model id of at most ${MAX_LIVE_MODEL_LENGTH} letters, digits, dots, colons, underscores or dashes`);
|
|
515
|
+
result.model = value.model;
|
|
516
|
+
}
|
|
464
517
|
return result;
|
|
465
518
|
}
|
|
466
519
|
function parseSelection(value, filePath) {
|
|
@@ -481,6 +534,23 @@ function parseEditor(value, filePath) {
|
|
|
481
534
|
assertKeys(value, EDITOR_KEYS, "editor", filePath);
|
|
482
535
|
return { command: optionalString(value.command, "editor.command", filePath) };
|
|
483
536
|
}
|
|
537
|
+
function parseBrowse(value, filePath) {
|
|
538
|
+
if (value === void 0) return void 0;
|
|
539
|
+
if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires browse to be an object`);
|
|
540
|
+
assertKeys(value, BROWSE_KEYS, "browse", filePath);
|
|
541
|
+
const pick = (key, allowed) => {
|
|
542
|
+
const raw = value[key];
|
|
543
|
+
if (raw === void 0) return void 0;
|
|
544
|
+
if (typeof raw !== "string" || !allowed.includes(raw)) throw new Error(`Doom config at ${filePath} requires browse.${key} to be one of: ${allowed.join(", ")}`);
|
|
545
|
+
return raw;
|
|
546
|
+
};
|
|
547
|
+
const engine = pick("engine", DOOM_BROWSE_ENGINES);
|
|
548
|
+
const fallback = pick("fallback", DOOM_BROWSE_FALLBACKS);
|
|
549
|
+
return {
|
|
550
|
+
...engine ? { engine } : {},
|
|
551
|
+
...fallback ? { fallback } : {}
|
|
552
|
+
};
|
|
553
|
+
}
|
|
484
554
|
/** `web` and `native` each choose a template, so both read the same `{ template }` shape. */
|
|
485
555
|
function parseTemplateChoice(value, root, filePath) {
|
|
486
556
|
if (value === void 0) return void 0;
|
|
@@ -537,6 +607,7 @@ function parseStrict(content, filePath) {
|
|
|
537
607
|
computerUse: parseComputerUse(parsed.computerUse, filePath),
|
|
538
608
|
projectTrust: trust,
|
|
539
609
|
editor: parseEditor(parsed.editor, filePath),
|
|
610
|
+
browse: parseBrowse(parsed.browse, filePath),
|
|
540
611
|
voice: parseVoice(parsed.voice, filePath),
|
|
541
612
|
selection: parseSelection(parsed.selection, filePath),
|
|
542
613
|
web: parseTemplateChoice(parsed.web, "web", filePath),
|
|
@@ -552,7 +623,9 @@ function mergeAgent(globalValue, repositoryValue) {
|
|
|
552
623
|
function mergeDoomConfigs(globalConfig, repositoryConfig) {
|
|
553
624
|
if (repositoryConfig.voice?.mode) throw new Error("Repository Doom config voice.mode is global-only; configure it in ~/.po/config.yaml");
|
|
554
625
|
if (repositoryConfig.voice?.autoCapture) throw new Error("Repository Doom config voice.autoCapture is global-only; configure it in ~/.po/config.yaml");
|
|
626
|
+
if (repositoryConfig.voice?.live) throw new Error("Repository Doom config voice.live is global-only; configure it in ~/.po/config.yaml");
|
|
555
627
|
if (repositoryConfig.computerUse) throw new Error("Repository Doom config computerUse is global-only; configure it in ~/.po/config.yaml");
|
|
628
|
+
if (repositoryConfig.browse) throw new Error("Repository Doom config browse is global-only; configure it in ~/.po/config.yaml");
|
|
556
629
|
const globalPlanning = globalConfig.modes?.planning;
|
|
557
630
|
const repositoryPlanning = repositoryConfig.modes?.planning;
|
|
558
631
|
const planning = globalPlanning || repositoryPlanning ? {
|
|
@@ -579,6 +652,7 @@ function mergeDoomConfigs(globalConfig, repositoryConfig) {
|
|
|
579
652
|
computerUse: globalConfig.computerUse,
|
|
580
653
|
projectTrust: repositoryConfig.projectTrust,
|
|
581
654
|
editor: globalConfig.editor,
|
|
655
|
+
browse: globalConfig.browse,
|
|
582
656
|
voice,
|
|
583
657
|
web: globalConfig.web || repositoryConfig.web ? { template: repositoryConfig.web?.template ?? globalConfig.web?.template } : void 0,
|
|
584
658
|
native: globalConfig.native || repositoryConfig.native ? { template: repositoryConfig.native?.template ?? globalConfig.native?.template } : void 0,
|
|
@@ -657,10 +731,18 @@ function resolveVoiceConfig(config, ttsOverride) {
|
|
|
657
731
|
};
|
|
658
732
|
}
|
|
659
733
|
/** Root keys the merge reads from one side only. */
|
|
660
|
-
const GLOBAL_ONLY_ROOTS = [
|
|
734
|
+
const GLOBAL_ONLY_ROOTS = [
|
|
735
|
+
"computerUse",
|
|
736
|
+
"editor",
|
|
737
|
+
"browse"
|
|
738
|
+
];
|
|
661
739
|
const REPOSITORY_ONLY_ROOTS = ["projectTrust"];
|
|
662
|
-
/** Nested exceptions; a repository declaration of
|
|
663
|
-
const GLOBAL_ONLY_PATHS = [
|
|
740
|
+
/** Nested exceptions; a repository declaration of any of them throws in the merge. */
|
|
741
|
+
const GLOBAL_ONLY_PATHS = [
|
|
742
|
+
["voice", "mode"],
|
|
743
|
+
["voice", "autoCapture"],
|
|
744
|
+
["voice", "live"]
|
|
745
|
+
];
|
|
664
746
|
function startsWith(keyPath, prefix) {
|
|
665
747
|
return prefix.length <= keyPath.length && prefix.every((segment, index) => keyPath[index] === segment);
|
|
666
748
|
}
|
|
@@ -725,6 +807,12 @@ Object.defineProperty(exports, "DOOM_VOICE_ENGINES", {
|
|
|
725
807
|
return DOOM_VOICE_ENGINES;
|
|
726
808
|
}
|
|
727
809
|
});
|
|
810
|
+
Object.defineProperty(exports, "DOOM_VOICE_LIVE_VOICES", {
|
|
811
|
+
enumerable: true,
|
|
812
|
+
get: function() {
|
|
813
|
+
return DOOM_VOICE_LIVE_VOICES;
|
|
814
|
+
}
|
|
815
|
+
});
|
|
728
816
|
Object.defineProperty(exports, "DOOM_VOICE_MODES", {
|
|
729
817
|
enumerable: true,
|
|
730
818
|
get: function() {
|
|
@@ -792,4 +880,4 @@ Object.defineProperty(exports, "valueAtKeyPath", {
|
|
|
792
880
|
}
|
|
793
881
|
});
|
|
794
882
|
|
|
795
|
-
//# sourceMappingURL=configPolicy-
|
|
883
|
+
//# sourceMappingURL=configPolicy-Ce1QKDxa.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configPolicy-Ce1QKDxa.cjs","names":["parseYaml"],"sources":["../src/services/configPolicy/index.ts"],"sourcesContent":["import { parse as parseYaml } from 'yaml';\n\nimport type {\n AutocompactModeConfig,\n AutocompactOverrideConfig,\n AutocompactThresholdConfig,\n BrowseConfig,\n ComputerUseConfig,\n ConfigDiagnostic,\n DoomConfig,\n DoomSelectionConfig,\n EditorConfig,\n LenientParseOptions,\n LenientParseResult,\n PlanningAgentConfig,\n PlanningModeConfig,\n PlanningThinkingLevel,\n ProjectTrust,\n ResolvedVoiceConfig,\n VoiceAdapterConfig,\n VoiceAutoCaptureConfig,\n VoiceConfig,\n VoiceEngine,\n VoiceMode,\n VoiceModelConfig,\n VoiceTtsConfig,\n VoiceTtsEngine,\n} from '../../types/config';\nimport type { PersonaVoiceOverride } from '../../types/profiles';\n\nconst DEFAULT_PROJECT_TRUST: ProjectTrust = 'ask';\nconst DEFAULT_VOICE_MODE: VoiceMode = 'legacy';\nconst DEFAULT_VOICE_ENGINE: VoiceEngine = 'auto';\nconst DEFAULT_VOICE_LANGUAGE = 'auto';\nconst DEFAULT_RECORDER_DEVICE = 'none:default';\nconst ROOT_KEYS = [\n 'modes',\n 'computerUse',\n 'projectTrust',\n 'editor',\n 'browse',\n 'voice',\n 'selection',\n 'web',\n 'native',\n] as const;\nconst BROWSE_KEYS = ['engine', 'fallback'] as const;\nexport const DOOM_BROWSE_ENGINES = ['cloak', 'chrome-for-testing'] as const;\nexport const DOOM_BROWSE_FALLBACKS = ['none', 'chrome-for-testing'] as const;\nconst SELECTION_KEYS = ['majorMode', 'domains', 'profile'] as const;\nconst MODE_KEYS = ['planning', 'autocompact'] as const;\nconst PLANNING_KEYS = ['main', 'subagents', 'plansDirectory'] as const;\nconst AGENT_KEYS = ['model', 'thinking'] as const;\nconst AUTOCOMPACT_KEYS = ['enabled', 'model', 'thinking', 'thresholds', 'overrides'] as const;\nconst AUTOCOMPACT_THRESHOLD_KEYS = ['pass1', 'pass2', 'pass3'] as const;\nconst AUTOCOMPACT_OVERRIDE_KEYS = ['model', 'tokens'] as const;\nconst COMPUTER_USE_KEYS = ['enabled'] as const;\n/** A pass that fires below this is noise; one above it never fires before Pi compacts natively. */\nconst MIN_AUTOCOMPACT_RATIO = 0.05;\nconst MAX_AUTOCOMPACT_RATIO = 0.99;\n/**\n * A checkpoint at zero tokens fires before the session has said anything. There is\n * deliberately no ceiling: the package takes the lower of the ratio and the token\n * value, so one larger than the window is inert rather than dangerous.\n */\nconst MIN_AUTOCOMPACT_TOKENS = 1;\nconst EDITOR_KEYS = ['command'] as const;\nconst VOICE_KEYS = ['mode', 'engine', 'language', 'recorder', 'adapters', 'autoCapture', 'live'] as const;\nconst VOICE_LIVE_KEYS = ['voice', 'model'] as const;\nconst LIVE_MODEL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u;\nconst MAX_LIVE_MODEL_LENGTH = 64;\nconst RECORDER_KEYS = ['binary', 'device'] as const;\nconst WHISPER_CPP_ENGINE = 'whisper-cpp' as const;\nconst OPENAI_WHISPER_ENGINE = 'openai-whisper' as const;\nconst MLX_WHISPER_ENGINE = 'mlx-whisper' as const;\nconst MACOS_SAY_TTS_ENGINE = 'macos-say' as const;\nconst ADAPTERS_KEYS = [WHISPER_CPP_ENGINE, OPENAI_WHISPER_ENGINE, MLX_WHISPER_ENGINE] as const;\nconst ADAPTER_KEYS = ['binary', 'model'] as const;\nconst MODEL_KEYS = ['path', 'id'] as const;\nconst AUTO_CAPTURE_KEYS = [\n 'model',\n 'startPhrases',\n 'stopPhrases',\n 'composeOpenPhrases',\n 'composeSendPhrases',\n 'composeCancelPhrases',\n 'utteranceIdleMs',\n 'composeUtteranceIdleMs',\n 'composeNudgeMs',\n 'transcriptionTimeoutMs',\n 'tts',\n] as const;\nconst TTS_KEYS = ['engine', 'voice', 'rate'] as const;\nconst DEFAULT_UTTERANCE_IDLE_MS = 3_000;\nconst MIN_UTTERANCE_IDLE_MS = 1_500;\nconst MAX_UTTERANCE_IDLE_MS = 10_000;\n/**\n * The endpoint window used while a composition draft is collecting.\n *\n * Shorter than `utteranceIdleMs` on purpose. A turn produces exactly one transcript, so\n * with the ordinary ~3 s window a short command spoken after a brief pause arrives glued\n * to the end of the preceding sentence and can never be read as a command. Roughly twice\n * the VAD's own 600 ms trailing-silence window: long enough that ordinary speech rhythm\n * does not split a sentence, short enough that a deliberate pause does. Over-splitting is\n * harmless here and only here, because draft segments are joined back together with a\n * space.\n */\nconst DEFAULT_COMPOSE_UTTERANCE_IDLE_MS = 1_200;\nconst MIN_COMPOSE_UTTERANCE_IDLE_MS = 800;\nconst MAX_COMPOSE_UTTERANCE_IDLE_MS = 3_000;\n/** Silence before Voice reminds the user a draft is still open. `0` disables it. */\nconst DEFAULT_COMPOSE_NUDGE_MS = 10_000;\nconst MIN_COMPOSE_NUDGE_MS = 5_000;\nconst MAX_COMPOSE_NUDGE_MS = 60_000;\n/**\n * Defaults kept as lists so the phrases that shipped first keep working.\n *\n * `hey doom` and `that's it` read as speech; `doom prompt` and `doom send` are what\n * existing users have in their fingers. Dropping the originals would break them for no\n * gain, and the cost of carrying both is two extra comparisons per command candidate.\n */\nconst DEFAULT_COMPOSE_OPEN_PHRASES = ['hey doom', 'doom prompt'] as const;\nconst DEFAULT_COMPOSE_SEND_PHRASES = [\"that's it\", 'doom send'] as const;\nconst DEFAULT_COMPOSE_CANCEL_PHRASES = ['doom cancel', 'scratch that'] as const;\nconst DEFAULT_TRANSCRIPTION_TIMEOUT_MS = 120_000;\nconst MIN_TRANSCRIPTION_TIMEOUT_MS = 1_000;\nconst MAX_TRANSCRIPTION_TIMEOUT_MS = 120_000;\nconst MAX_CONTROL_PHRASES = 16;\nconst MAX_CONTROL_PHRASE_LENGTH = 64;\nconst MAX_TTS_VOICE_LENGTH = 64;\nconst MIN_TTS_RATE = 80;\nconst MAX_TTS_RATE = 500;\nconst MODEL_REFERENCE_PATTERN = /^[^/\\s]+\\/[^/\\s]+(?:\\/[^/\\s]+)*$/u;\nconst PHRASE_PUNCTUATION_PATTERN = /[\\p{P}\\p{S}]+/gu;\n/**\n * The accepted values, in the order a picker should offer them.\n *\n * Exported because the config UI has to offer exactly what the parser accepts,\n * and a second hand-written list in the contributing package would drift. The\n * validating Sets below are built from these for the same reason.\n */\nexport const DOOM_PLANNING_THINKING_LEVELS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'] as const;\nexport const DOOM_VOICE_MODES = [DEFAULT_VOICE_MODE, 'live'] as const;\nexport const DOOM_VOICE_ENGINES = [\n DEFAULT_VOICE_ENGINE,\n WHISPER_CPP_ENGINE,\n OPENAI_WHISPER_ENGINE,\n MLX_WHISPER_ENGINE,\n] as const;\nexport const DOOM_VOICE_TTS_ENGINES = [MACOS_SAY_TTS_ENGINE] as const;\n/** Codex realtime V3 voices, from `codex-rs/protocol/src/protocol.rs` `RealtimeVoicesList::builtin()`. */\nexport const DOOM_VOICE_LIVE_VOICES = [\n 'juniper',\n 'maple',\n 'spruce',\n 'ember',\n 'vale',\n 'breeze',\n 'arbor',\n 'sol',\n 'cove',\n 'aube',\n 'bubbie',\n 'haetsal',\n 'hanul',\n 'himari',\n 'leher',\n 'miko',\n 'neer',\n 'porto',\n 'rindo',\n 'rio',\n 'rivage',\n 'selva',\n 'sonna',\n 'tinta',\n 'viola',\n] as const;\n\nconst THINKING_VALUES = new Set<PlanningThinkingLevel>(DOOM_PLANNING_THINKING_LEVELS);\nconst TRUST_VALUES = new Set<ProjectTrust>(['ask', 'always', 'never']);\nconst VOICE_MODE_VALUES = new Set<VoiceMode>(DOOM_VOICE_MODES);\nconst ENGINE_VALUES = new Set<VoiceEngine>(DOOM_VOICE_ENGINES);\nconst TTS_ENGINE_VALUES = new Set<VoiceTtsEngine>(DOOM_VOICE_TTS_ENGINES);\ntype ConfigObject = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is ConfigObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n/**\n * Where a lenient parse collects unknown keys instead of throwing.\n *\n * Module scope rather than a parameter threaded through the twelve nested\n * parsers: `assertKeys` is the only reader, parsing is synchronous end to end,\n * and `parseDoomConfig` owns the whole window in a try/finally. Threading would\n * touch every parser to change behaviour in one of them.\n */\nlet unknownKeySink: ConfigDiagnostic[] | undefined;\n\nfunction assertKeys(value: ConfigObject, allowed: readonly string[], location: string, filePath: string): void {\n const unknown = Object.keys(value).filter((key) => !allowed.includes(key));\n if (unknown.length === 0) return;\n if (unknownKeySink !== undefined) {\n // Left on the object rather than deleted: every parser reads the fields it\n // knows by name, so an unknown sibling is already inert.\n for (const key of unknown) {\n unknownKeySink.push({\n filePath,\n path: location === 'root' ? key : `${location}.${key}`,\n message: `unsupported ${location} field`,\n });\n }\n return;\n }\n throw new Error(`Doom config at ${filePath} has unsupported ${location} field(s): ${unknown.join(', ')}`);\n}\nfunction optionalString(value: unknown, location: string, filePath: string): string | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'string' || value.trim().length === 0)\n throw new Error(`Doom config at ${filePath} requires ${location} to be a non-empty string`);\n return value.trim();\n}\nfunction hasControlCharacters(value: string): boolean {\n for (const character of value) {\n const codePoint = character.codePointAt(0);\n if (codePoint !== undefined && (codePoint <= 0x1f || codePoint === 0x7f)) return true;\n }\n return false;\n}\nfunction boundedOptionalString(\n value: unknown,\n location: string,\n filePath: string,\n maximumLength: number,\n): string | undefined {\n const text = optionalString(value, location, filePath);\n if (!text) return undefined;\n if (text.length > maximumLength)\n throw new Error(`Doom config at ${filePath} requires ${location} to be at most ${maximumLength} characters`);\n if (hasControlCharacters(text))\n throw new Error(`Doom config at ${filePath} does not allow control characters in ${location}`);\n return text;\n}\nfunction parseModelReference(value: unknown, filePath: string): string {\n const location = 'voice.autoCapture.model';\n const model = optionalString(value, location, filePath);\n if (!model || !MODEL_REFERENCE_PATTERN.test(model))\n throw new Error(`Doom config at ${filePath} requires ${location} in provider/model-id form`);\n return model;\n}\nfunction normalizeControlPhrase(value: string): string {\n return value\n .normalize('NFKC')\n .toLocaleLowerCase('en-US')\n .replace(PHRASE_PUNCTUATION_PATTERN, ' ')\n .replace(/\\s+/gu, ' ')\n .trim();\n}\nfunction parseControlPhrases(value: unknown, location: string, filePath: string): string[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value) || value.some((phrase) => typeof phrase !== 'string'))\n throw new Error(`Doom config at ${filePath} requires ${location} to be an array of strings`);\n if (value.length > MAX_CONTROL_PHRASES)\n throw new Error(\n `Doom config at ${filePath} requires ${location} to contain at most ${MAX_CONTROL_PHRASES} phrases`,\n );\n const phrases = value.map((phrase) => phrase.trim());\n const normalized = new Set<string>();\n for (const phrase of phrases) {\n if (phrase.length === 0)\n throw new Error(`Doom config at ${filePath} requires ${location} to contain non-empty strings`);\n if (phrase.length > MAX_CONTROL_PHRASE_LENGTH)\n throw new Error(\n `Doom config at ${filePath} requires ${location} phrases to be at most ${MAX_CONTROL_PHRASE_LENGTH} characters`,\n );\n if (hasControlCharacters(phrase))\n throw new Error(`Doom config at ${filePath} does not allow control characters in ${location}`);\n const key = normalizeControlPhrase(phrase);\n if (!key) throw new Error(`Doom config at ${filePath} requires ${location} to contain words`);\n if (normalized.has(key))\n throw new Error(`Doom config at ${filePath} does not allow normalized duplicates in ${location}`);\n normalized.add(key);\n }\n return phrases;\n}\nfunction parseBoundedInteger(\n value: unknown,\n location: string,\n filePath: string,\n minimum: number,\n maximum: number,\n): number | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'number' || !Number.isInteger(value) || value < minimum || value > maximum)\n throw new Error(`Doom config at ${filePath} requires ${location} to be an integer from ${minimum} to ${maximum}`);\n return value;\n}\n/**\n * Rejects a phrase claimed by two control roles at once.\n *\n * Composition commands are adjudicated before stop phrases and before leading\n * start-phrase removal, so a phrase shared with a later role is not ambiguous, it is\n * silently unreachable. Without a screen there is nothing to show which role won.\n */\nfunction assertDisjointPhrases(\n left: readonly string[] | undefined,\n right: readonly string[] | undefined,\n leftName: string,\n rightName: string,\n filePath: string,\n): void {\n const keys = new Set((left ?? []).map(normalizeControlPhrase));\n if ((right ?? []).some((phrase) => keys.has(normalizeControlPhrase(phrase))))\n throw new Error(`Doom config at ${filePath} does not allow a phrase in both ${leftName} and ${rightName}`);\n}\nfunction parseTtsConfig(value: unknown, filePath: string): VoiceTtsConfig {\n const location = 'voice.autoCapture.tts';\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be an object`);\n assertKeys(value, TTS_KEYS, location, filePath);\n if (typeof value.engine !== 'string' || !TTS_ENGINE_VALUES.has(value.engine as VoiceTtsEngine))\n throw new Error(\n `Doom config at ${filePath} requires ${location}.engine to be one of: ${[...TTS_ENGINE_VALUES].join(', ')}`,\n );\n const voice = boundedOptionalString(value.voice, `${location}.voice`, filePath, MAX_TTS_VOICE_LENGTH);\n const rate = value.rate;\n if (\n rate !== undefined &&\n (typeof rate !== 'number' || !Number.isInteger(rate) || rate < MIN_TTS_RATE || rate > MAX_TTS_RATE)\n ) {\n throw new Error(\n `Doom config at ${filePath} requires ${location}.rate to be an integer from ${MIN_TTS_RATE} to ${MAX_TTS_RATE}`,\n );\n }\n return {\n engine: value.engine as VoiceTtsEngine,\n ...(voice ? { voice } : {}),\n ...(rate === undefined ? {} : { rate }),\n };\n}\nfunction parseAutoCapture(value: unknown, filePath: string): VoiceAutoCaptureConfig | undefined {\n if (value === undefined) return undefined;\n const location = 'voice.autoCapture';\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be an object`);\n assertKeys(value, AUTO_CAPTURE_KEYS, location, filePath);\n const startPhrases = parseControlPhrases(value.startPhrases, `${location}.startPhrases`, filePath);\n const stopPhrases = parseControlPhrases(value.stopPhrases, `${location}.stopPhrases`, filePath);\n const composeOpenPhrases = parseControlPhrases(value.composeOpenPhrases, `${location}.composeOpenPhrases`, filePath);\n const composeSendPhrases = parseControlPhrases(value.composeSendPhrases, `${location}.composeSendPhrases`, filePath);\n const composeCancelPhrases = parseControlPhrases(\n value.composeCancelPhrases,\n `${location}.composeCancelPhrases`,\n filePath,\n );\n const utteranceIdleMs = parseBoundedInteger(\n value.utteranceIdleMs,\n `${location}.utteranceIdleMs`,\n filePath,\n MIN_UTTERANCE_IDLE_MS,\n MAX_UTTERANCE_IDLE_MS,\n );\n const composeUtteranceIdleMs = parseBoundedInteger(\n value.composeUtteranceIdleMs,\n `${location}.composeUtteranceIdleMs`,\n filePath,\n MIN_COMPOSE_UTTERANCE_IDLE_MS,\n MAX_COMPOSE_UTTERANCE_IDLE_MS,\n );\n // Zero is the documented off switch, so it is accepted outside the range rather than\n // forcing a separate boolean that could disagree with the interval.\n const composeNudgeMs =\n value.composeNudgeMs === 0\n ? 0\n : parseBoundedInteger(\n value.composeNudgeMs,\n `${location}.composeNudgeMs`,\n filePath,\n MIN_COMPOSE_NUDGE_MS,\n MAX_COMPOSE_NUDGE_MS,\n );\n const transcriptionTimeoutMs = parseBoundedInteger(\n value.transcriptionTimeoutMs,\n `${location}.transcriptionTimeoutMs`,\n filePath,\n MIN_TRANSCRIPTION_TIMEOUT_MS,\n MAX_TRANSCRIPTION_TIMEOUT_MS,\n );\n assertDisjointPhrases(startPhrases, stopPhrases, 'startPhrases', 'stopPhrases', filePath);\n // `composeOpenPhrases` may overlap `startPhrases`: addressing the agent and opening a\n // draft are the same gesture, composition is adjudicated first, and the shipped\n // defaults deliberately share `hey doom`.\n assertDisjointPhrases(\n composeSendPhrases,\n composeCancelPhrases,\n 'composeSendPhrases',\n 'composeCancelPhrases',\n filePath,\n );\n assertDisjointPhrases(composeOpenPhrases, composeSendPhrases, 'composeOpenPhrases', 'composeSendPhrases', filePath);\n assertDisjointPhrases(\n composeOpenPhrases,\n composeCancelPhrases,\n 'composeOpenPhrases',\n 'composeCancelPhrases',\n filePath,\n );\n assertDisjointPhrases(stopPhrases, composeSendPhrases, 'stopPhrases', 'composeSendPhrases', filePath);\n assertDisjointPhrases(stopPhrases, composeCancelPhrases, 'stopPhrases', 'composeCancelPhrases', filePath);\n return {\n model: parseModelReference(value.model, filePath),\n ...(startPhrases ? { startPhrases } : {}),\n ...(stopPhrases ? { stopPhrases } : {}),\n ...(composeOpenPhrases ? { composeOpenPhrases } : {}),\n ...(composeSendPhrases ? { composeSendPhrases } : {}),\n ...(composeCancelPhrases ? { composeCancelPhrases } : {}),\n ...(utteranceIdleMs === undefined ? {} : { utteranceIdleMs }),\n ...(composeUtteranceIdleMs === undefined ? {} : { composeUtteranceIdleMs }),\n ...(composeNudgeMs === undefined ? {} : { composeNudgeMs }),\n ...(transcriptionTimeoutMs === undefined ? {} : { transcriptionTimeoutMs }),\n tts: parseTtsConfig(value.tts, filePath),\n };\n}\nfunction parseThinking(value: unknown, location: string, filePath: string): PlanningThinkingLevel | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'string' || !THINKING_VALUES.has(value as PlanningThinkingLevel)) {\n throw new Error(\n `Doom config at ${filePath} requires ${location}.thinking to be one of: ${[...THINKING_VALUES].join(', ')}`,\n );\n }\n return value as PlanningThinkingLevel;\n}\nfunction parseAgent(value: unknown, location: string, filePath: string): PlanningAgentConfig | undefined {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be an object`);\n assertKeys(value, AGENT_KEYS, location, filePath);\n const thinking = parseThinking(value.thinking, location, filePath);\n const model = optionalString(value.model, `${location}.model`, filePath);\n return { ...(model ? { model } : {}), ...(thinking ? { thinking } : {}) };\n}\n/**\n * A flag the cockpit can write.\n *\n * The settings page writes strings and nothing else, so `'true'` has to mean\n * what a hand-edited `true` means. Anything else is rejected rather than\n * treated as false, because a typo that silently disables a feature is the\n * worst reading of it.\n */\nfunction parseFlexibleBoolean(value: unknown, location: string, filePath: string): boolean | undefined {\n if (value === undefined) return undefined;\n if (typeof value === 'boolean') return value;\n if (value === 'true') return true;\n if (value === 'false') return false;\n throw new Error(`Doom config at ${filePath} requires ${location} to be true or false`);\n}\n/** Same story as the flag: a number, or the string form the settings page writes. */\nfunction parseFlexibleRatio(value: unknown, location: string, filePath: string): number | undefined {\n if (value === undefined) return undefined;\n const ratio = typeof value === 'string' ? Number(value.trim()) : value;\n if (\n typeof ratio !== 'number' ||\n !Number.isFinite(ratio) ||\n ratio < MIN_AUTOCOMPACT_RATIO ||\n ratio > MAX_AUTOCOMPACT_RATIO\n ) {\n throw new Error(\n `Doom config at ${filePath} requires ${location} to be a number from ${MIN_AUTOCOMPACT_RATIO} to ${MAX_AUTOCOMPACT_RATIO}`,\n );\n }\n return ratio;\n}\nfunction parseAutocompactThresholds(\n value: unknown,\n location: string,\n filePath: string,\n): AutocompactThresholdConfig | undefined {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be an object`);\n assertKeys(value, AUTOCOMPACT_THRESHOLD_KEYS, location, filePath);\n const pass1 = parseFlexibleRatio(value.pass1, `${location}.pass1`, filePath);\n const pass2 = parseFlexibleRatio(value.pass2, `${location}.pass2`, filePath);\n const pass3 = parseFlexibleRatio(value.pass3, `${location}.pass3`, filePath);\n return {\n ...(pass1 === undefined ? {} : { pass1 }),\n ...(pass2 === undefined ? {} : { pass2 }),\n ...(pass3 === undefined ? {} : { pass3 }),\n };\n}\n/** Absolute token counts, unlike the ratios, are only ever written by hand, so no string form is accepted. */\nfunction parseAutocompactTokenCount(value: unknown, location: string, filePath: string): number | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < MIN_AUTOCOMPACT_TOKENS)\n throw new Error(\n `Doom config at ${filePath} requires ${location} to be an integer of at least ${MIN_AUTOCOMPACT_TOKENS}`,\n );\n return value;\n}\nfunction parseAutocompactOverrideEntry(value: unknown, location: string, filePath: string): AutocompactOverrideConfig {\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be an object`);\n assertKeys(value, AUTOCOMPACT_OVERRIDE_KEYS, location, filePath);\n const model = optionalString(value.model, `${location}.model`, filePath);\n if (!model) throw new Error(`Doom config at ${filePath} requires ${location}.model`);\n if (!isObject(value.tokens))\n throw new Error(`Doom config at ${filePath} requires ${location}.tokens to be an object`);\n assertKeys(value.tokens, AUTOCOMPACT_THRESHOLD_KEYS, `${location}.tokens`, filePath);\n const pass1 = parseAutocompactTokenCount(value.tokens.pass1, `${location}.tokens.pass1`, filePath);\n const pass2 = parseAutocompactTokenCount(value.tokens.pass2, `${location}.tokens.pass2`, filePath);\n const pass3 = parseAutocompactTokenCount(value.tokens.pass3, `${location}.tokens.pass3`, filePath);\n // An entry that pins nothing is a typo rather than a way to say \"leave this model alone\":\n // omitting the entry already does that, and a silent no-op reads like the override worked.\n if (pass1 === undefined && pass2 === undefined && pass3 === undefined)\n throw new Error(`Doom config at ${filePath} requires one of ${location}.tokens.pass1, pass2, or pass3`);\n return {\n model,\n tokens: {\n ...(pass1 === undefined ? {} : { pass1 }),\n ...(pass2 === undefined ? {} : { pass2 }),\n ...(pass3 === undefined ? {} : { pass3 }),\n },\n };\n}\nfunction parseAutocompactOverrides(\n value: unknown,\n location: string,\n filePath: string,\n): AutocompactOverrideConfig[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be a list`);\n return value.map((entry, index) => parseAutocompactOverrideEntry(entry, `${location}[${index}]`, filePath));\n}\nexport function parseAutocompactModeConfig(\n value: unknown,\n filePath: string,\n location = 'modes.autocompact',\n): AutocompactModeConfig {\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be an object`);\n assertKeys(value, AUTOCOMPACT_KEYS, location, filePath);\n const enabled = parseFlexibleBoolean(value.enabled, `${location}.enabled`, filePath);\n const model = optionalString(value.model, `${location}.model`, filePath);\n const thinking = parseThinking(value.thinking, location, filePath);\n const thresholds = parseAutocompactThresholds(value.thresholds, `${location}.thresholds`, filePath);\n const overrides = parseAutocompactOverrides(value.overrides, `${location}.overrides`, filePath);\n return {\n ...(enabled === undefined ? {} : { enabled }),\n ...(model ? { model } : {}),\n ...(thinking ? { thinking } : {}),\n ...(thresholds ? { thresholds } : {}),\n ...(overrides ? { overrides } : {}),\n };\n}\nexport function parsePlanningModeConfig(\n value: unknown,\n filePath: string,\n location = 'modes.planning',\n): PlanningModeConfig {\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be an object`);\n assertKeys(value, PLANNING_KEYS, location, filePath);\n return {\n main: parseAgent(value.main, `${location}.main`, filePath),\n subagents: parseAgent(value.subagents, `${location}.subagents`, filePath),\n plansDirectory: optionalString(value.plansDirectory, `${location}.plansDirectory`, filePath),\n };\n}\nfunction parseModel(value: unknown, location: string, filePath: string, allowId: boolean): VoiceModelConfig {\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be an object`);\n assertKeys(value, MODEL_KEYS, location, filePath);\n const modelPath = optionalString(value.path, `${location}.path`, filePath);\n const id = optionalString(value.id, `${location}.id`, filePath);\n if (Boolean(modelPath) === Boolean(id))\n throw new Error(`Doom config at ${filePath} requires exactly one of ${location}.path or ${location}.id`);\n if (id && !allowId) throw new Error(`Doom config at ${filePath} does not support ${location}.id for whisper-cpp`);\n return { ...(modelPath ? { path: modelPath } : {}), ...(id ? { id } : {}) };\n}\nfunction parseAdapter(\n value: unknown,\n location: string,\n filePath: string,\n allowId: boolean,\n): VoiceAdapterConfig | undefined {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${location} to be an object`);\n assertKeys(value, ADAPTER_KEYS, location, filePath);\n const binary = optionalString(value.binary, `${location}.binary`, filePath);\n return { ...(binary ? { binary } : {}), model: parseModel(value.model, `${location}.model`, filePath, allowId) };\n}\nfunction parseVoice(value: unknown, filePath: string): VoiceConfig | undefined {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires voice to be an object`);\n assertKeys(value, VOICE_KEYS, 'voice', filePath);\n const result: VoiceConfig = {};\n if (value.mode !== undefined) {\n if (typeof value.mode !== 'string' || !VOICE_MODE_VALUES.has(value.mode as VoiceMode))\n throw new Error(\n `Doom config at ${filePath} requires voice.mode to be one of: ${[...VOICE_MODE_VALUES].join(', ')}`,\n );\n result.mode = value.mode as VoiceMode;\n }\n if (value.engine !== undefined) {\n if (typeof value.engine !== 'string' || !ENGINE_VALUES.has(value.engine as VoiceEngine))\n throw new Error(\n `Doom config at ${filePath} requires voice.engine to be one of: ${[...ENGINE_VALUES].join(', ')}`,\n );\n result.engine = value.engine as VoiceEngine;\n }\n const language = optionalString(value.language, 'voice.language', filePath);\n if (language) result.language = language;\n if (value.recorder !== undefined) {\n if (!isObject(value.recorder))\n throw new Error(`Doom config at ${filePath} requires voice.recorder to be an object`);\n assertKeys(value.recorder, RECORDER_KEYS, 'voice.recorder', filePath);\n result.recorder = {};\n const binary = optionalString(value.recorder.binary, 'voice.recorder.binary', filePath);\n const device = optionalString(value.recorder.device, 'voice.recorder.device', filePath);\n if (binary) result.recorder.binary = binary;\n if (device) result.recorder.device = device;\n }\n if (value.adapters !== undefined) {\n if (!isObject(value.adapters))\n throw new Error(`Doom config at ${filePath} requires voice.adapters to be an object`);\n assertKeys(value.adapters, ADAPTERS_KEYS, 'voice.adapters', filePath);\n result.adapters = {\n [WHISPER_CPP_ENGINE]: parseAdapter(\n value.adapters[WHISPER_CPP_ENGINE],\n `voice.adapters.${WHISPER_CPP_ENGINE}`,\n filePath,\n false,\n ),\n [OPENAI_WHISPER_ENGINE]: parseAdapter(\n value.adapters[OPENAI_WHISPER_ENGINE],\n `voice.adapters.${OPENAI_WHISPER_ENGINE}`,\n filePath,\n true,\n ),\n [MLX_WHISPER_ENGINE]: parseAdapter(\n value.adapters[MLX_WHISPER_ENGINE],\n `voice.adapters.${MLX_WHISPER_ENGINE}`,\n filePath,\n true,\n ),\n };\n }\n const autoCapture = parseAutoCapture(value.autoCapture, filePath);\n if (autoCapture) result.autoCapture = autoCapture;\n const live = parseVoiceLive(value.live, filePath);\n if (live) result.live = live;\n return result;\n}\nfunction parseVoiceLive(value: unknown, filePath: string): VoiceConfig['live'] {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires voice.live to be an object`);\n assertKeys(value, VOICE_LIVE_KEYS, 'voice.live', filePath);\n const result: NonNullable<VoiceConfig['live']> = {};\n if (value.voice !== undefined) {\n if (typeof value.voice !== 'string' || !(DOOM_VOICE_LIVE_VOICES as readonly string[]).includes(value.voice))\n throw new Error(\n `Doom config at ${filePath} requires voice.live.voice to be one of: ${DOOM_VOICE_LIVE_VOICES.join(', ')}`,\n );\n result.voice = value.voice;\n }\n if (value.model !== undefined) {\n if (\n typeof value.model !== 'string' ||\n value.model.length > MAX_LIVE_MODEL_LENGTH ||\n !LIVE_MODEL_PATTERN.test(value.model)\n )\n throw new Error(\n `Doom config at ${filePath} requires voice.live.model to be a model id of at most ${MAX_LIVE_MODEL_LENGTH} letters, digits, dots, colons, underscores or dashes`,\n );\n result.model = value.model;\n }\n return result;\n}\nfunction parseSelection(value: unknown, filePath: string): DoomSelectionConfig | undefined {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires selection to be an object`);\n assertKeys(value, SELECTION_KEYS, 'selection', filePath);\n const domains = value.domains;\n if (domains !== undefined && (!Array.isArray(domains) || domains.some((name) => typeof name !== 'string'))) {\n throw new Error(`Doom config at ${filePath} requires selection.domains to be an array of strings`);\n }\n return {\n majorMode: optionalString(value.majorMode, 'selection.majorMode', filePath),\n // An empty list is meaningful: it selects no content domains at all.\n domains: domains as string[] | undefined,\n profile: optionalString(value.profile, 'selection.profile', filePath),\n };\n}\nfunction parseEditor(value: unknown, filePath: string): EditorConfig | undefined {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires editor to be an object`);\n assertKeys(value, EDITOR_KEYS, 'editor', filePath);\n return { command: optionalString(value.command, 'editor.command', filePath) };\n}\nfunction parseBrowse(value: unknown, filePath: string): BrowseConfig | undefined {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires browse to be an object`);\n assertKeys(value, BROWSE_KEYS, 'browse', filePath);\n const pick = <T extends string>(key: string, allowed: readonly T[]): T | undefined => {\n const raw = value[key];\n if (raw === undefined) return undefined;\n if (typeof raw !== 'string' || !allowed.includes(raw as T))\n throw new Error(`Doom config at ${filePath} requires browse.${key} to be one of: ${allowed.join(', ')}`);\n return raw as T;\n };\n const engine = pick('engine', DOOM_BROWSE_ENGINES);\n const fallback = pick('fallback', DOOM_BROWSE_FALLBACKS);\n return { ...(engine ? { engine } : {}), ...(fallback ? { fallback } : {}) };\n}\n\n/** `web` and `native` each choose a template, so both read the same `{ template }` shape. */\nfunction parseTemplateChoice(\n value: unknown,\n root: 'web' | 'native',\n filePath: string,\n): DoomConfig['web'] | DoomConfig['native'] {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires ${root} to be an object`);\n assertKeys(value, ['template'], root, filePath);\n if (value.template === undefined) return {};\n const template = optionalString(value.template, `${root}.template`, filePath);\n if (!template || template.length > 160 || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(template)) {\n throw new Error(`Doom config at ${filePath} requires ${root}.template to be a kebab-case template identifier`);\n }\n return { template };\n}\nfunction parseComputerUse(value: unknown, filePath: string): ComputerUseConfig | undefined {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`Doom config at ${filePath} requires computerUse to be an object`);\n assertKeys(value, COMPUTER_USE_KEYS, 'computerUse', filePath);\n const enabled = parseFlexibleBoolean(value.enabled, 'computerUse.enabled', filePath);\n return enabled === undefined ? {} : { enabled };\n}\n/**\n * Reads one Doom config file.\n *\n * The two-argument form is the strict contract every harness-launch consumer\n * relies on: an unknown key is a hard error. `po sync` opts into the\n * lenient form so a config written for a different version cannot break a\n * build; `po doctor` is the strict check that still reports those keys.\n * Invalid values for known keys throw in both modes.\n */\nexport function parseDoomConfig(content: string, filePath: string): DoomConfig;\nexport function parseDoomConfig(content: string, filePath: string, options: LenientParseOptions): LenientParseResult;\nexport function parseDoomConfig(\n content: string,\n filePath: string,\n options?: LenientParseOptions,\n): DoomConfig | LenientParseResult {\n if (options?.lenient !== true) return parseStrict(content, filePath);\n const diagnostics: ConfigDiagnostic[] = [];\n const previous = unknownKeySink;\n unknownKeySink = diagnostics;\n try {\n return { config: parseStrict(content, filePath), diagnostics };\n } finally {\n unknownKeySink = previous;\n }\n}\n\nfunction parseStrict(content: string, filePath: string): DoomConfig {\n let parsed: unknown;\n try {\n parsed = parseYaml(content) ?? {};\n } catch (error) {\n throw new Error(`Could not parse Doom config at ${filePath}`, { cause: error });\n }\n if (!isObject(parsed)) throw new Error(`Doom config at ${filePath} must be a YAML object`);\n assertKeys(parsed, ROOT_KEYS, 'root', filePath);\n let modes: DoomConfig['modes'];\n if (parsed.modes !== undefined) {\n if (!isObject(parsed.modes)) throw new Error(`Doom config at ${filePath} requires modes to be an object`);\n assertKeys(parsed.modes, MODE_KEYS, 'modes', filePath);\n modes = {\n ...(parsed.modes.planning === undefined\n ? {}\n : { planning: parsePlanningModeConfig(parsed.modes.planning, filePath) }),\n ...(parsed.modes.autocompact === undefined\n ? {}\n : { autocompact: parseAutocompactModeConfig(parsed.modes.autocompact, filePath) }),\n };\n }\n const trust = parsed.projectTrust === undefined ? DEFAULT_PROJECT_TRUST : parsed.projectTrust;\n if (typeof trust !== 'string' || !TRUST_VALUES.has(trust as ProjectTrust))\n throw new Error(`Doom config at ${filePath} projectTrust must be ask, always, or never`);\n return {\n modes,\n computerUse: parseComputerUse(parsed.computerUse, filePath),\n projectTrust: trust as ProjectTrust,\n editor: parseEditor(parsed.editor, filePath),\n browse: parseBrowse(parsed.browse, filePath),\n voice: parseVoice(parsed.voice, filePath),\n selection: parseSelection(parsed.selection, filePath),\n web: parseTemplateChoice(parsed.web, 'web', filePath),\n native: parseTemplateChoice(parsed.native, 'native', filePath),\n };\n}\nfunction mergeAgent(\n globalValue?: PlanningAgentConfig,\n repositoryValue?: PlanningAgentConfig,\n): PlanningAgentConfig | undefined {\n return globalValue || repositoryValue ? { ...globalValue, ...repositoryValue } : undefined;\n}\nexport function mergeDoomConfigs(globalConfig: DoomConfig, repositoryConfig: DoomConfig): DoomConfig {\n if (repositoryConfig.voice?.mode)\n throw new Error('Repository Doom config voice.mode is global-only; configure it in ~/.po/config.yaml');\n if (repositoryConfig.voice?.autoCapture)\n throw new Error('Repository Doom config voice.autoCapture is global-only; configure it in ~/.po/config.yaml');\n if (repositoryConfig.voice?.live)\n throw new Error('Repository Doom config voice.live is global-only; configure it in ~/.po/config.yaml');\n if (repositoryConfig.computerUse)\n throw new Error('Repository Doom config computerUse is global-only; configure it in ~/.po/config.yaml');\n if (repositoryConfig.browse)\n throw new Error('Repository Doom config browse is global-only; configure it in ~/.po/config.yaml');\n const globalPlanning = globalConfig.modes?.planning;\n const repositoryPlanning = repositoryConfig.modes?.planning;\n const planning =\n globalPlanning || repositoryPlanning\n ? {\n main: mergeAgent(globalPlanning?.main, repositoryPlanning?.main),\n subagents: mergeAgent(globalPlanning?.subagents, repositoryPlanning?.subagents),\n plansDirectory: repositoryPlanning?.plansDirectory ?? globalPlanning?.plansDirectory,\n }\n : undefined;\n const globalAutocompact = globalConfig.modes?.autocompact;\n const repositoryAutocompact = repositoryConfig.modes?.autocompact;\n // Per key, so a repository can pin the model and inherit the ladder, or the\n // other way round. `overrides` is deliberately not merged that way: the spread\n // below lets a repository list replace the global one whole, because the rules\n // are first-match-wins and interleaving two files a reader cannot see together\n // would decide precedence somewhere neither of them says.\n const autocompact =\n globalAutocompact || repositoryAutocompact\n ? {\n ...globalAutocompact,\n ...repositoryAutocompact,\n ...(globalAutocompact?.thresholds || repositoryAutocompact?.thresholds\n ? { thresholds: { ...globalAutocompact?.thresholds, ...repositoryAutocompact?.thresholds } }\n : {}),\n }\n : undefined;\n const voice = mergeVoice(globalConfig.voice, repositoryConfig.voice);\n return {\n modes:\n planning || autocompact\n ? { ...(planning ? { planning } : {}), ...(autocompact ? { autocompact } : {}) }\n : undefined,\n computerUse: globalConfig.computerUse,\n projectTrust: repositoryConfig.projectTrust,\n editor: globalConfig.editor,\n browse: globalConfig.browse,\n voice,\n web:\n globalConfig.web || repositoryConfig.web\n ? { template: repositoryConfig.web?.template ?? globalConfig.web?.template }\n : undefined,\n native:\n globalConfig.native || repositoryConfig.native\n ? { template: repositoryConfig.native?.template ?? globalConfig.native?.template }\n : undefined,\n // Per key, so a repository can pin one axis and inherit the rest.\n selection:\n globalConfig.selection || repositoryConfig.selection\n ? { ...globalConfig.selection, ...repositoryConfig.selection }\n : undefined,\n };\n}\nfunction mergeAdapter(\n globalValue?: VoiceAdapterConfig,\n repositoryValue?: VoiceAdapterConfig,\n): VoiceAdapterConfig | undefined {\n if (!globalValue && !repositoryValue) return undefined;\n return { ...globalValue, ...repositoryValue, model: repositoryValue?.model ?? globalValue!.model };\n}\nfunction mergeVoice(globalValue?: VoiceConfig, repositoryValue?: VoiceConfig): VoiceConfig | undefined {\n if (!globalValue && !repositoryValue) return undefined;\n return {\n ...globalValue,\n ...repositoryValue,\n ...(globalValue?.mode ? { mode: globalValue.mode } : {}),\n recorder:\n globalValue?.recorder || repositoryValue?.recorder\n ? { ...globalValue?.recorder, ...repositoryValue?.recorder }\n : undefined,\n adapters:\n globalValue?.adapters || repositoryValue?.adapters\n ? {\n [WHISPER_CPP_ENGINE]: mergeAdapter(\n globalValue?.adapters?.[WHISPER_CPP_ENGINE],\n repositoryValue?.adapters?.[WHISPER_CPP_ENGINE],\n ),\n [OPENAI_WHISPER_ENGINE]: mergeAdapter(\n globalValue?.adapters?.[OPENAI_WHISPER_ENGINE],\n repositoryValue?.adapters?.[OPENAI_WHISPER_ENGINE],\n ),\n [MLX_WHISPER_ENGINE]: mergeAdapter(\n globalValue?.adapters?.[MLX_WHISPER_ENGINE],\n repositoryValue?.adapters?.[MLX_WHISPER_ENGINE],\n ),\n }\n : undefined,\n ...(globalValue?.autoCapture ? { autoCapture: globalValue.autoCapture } : {}),\n };\n}\n/**\n * Resolves voice settings, optionally shadowed by the active profile's override.\n *\n * The override is per field, so a persona that sets only `rate` keeps the voice\n * from config.yaml. `engine` is deliberately not overridable: it selects the\n * synthesiser binary, which is a machine-level fact rather than a persona's.\n *\n * The result is read once when autonomous voice activates, because\n * `VoiceNarrationPlayback.config` is assigned in `activate()` and has no setter.\n * That is sufficient today only because every profile switch reloads the\n * session, which deactivates and reactivates voice. A future in-place profile\n * switch would leave the spoken voice stale until the next activation.\n */\nexport function resolveVoiceConfig(config: VoiceConfig, ttsOverride?: PersonaVoiceOverride): ResolvedVoiceConfig {\n return {\n mode: config.mode ?? DEFAULT_VOICE_MODE,\n engine: config.engine ?? DEFAULT_VOICE_ENGINE,\n language: config.language ?? DEFAULT_VOICE_LANGUAGE,\n recorder: { ...config.recorder, device: config.recorder?.device ?? DEFAULT_RECORDER_DEVICE },\n adapters: config.adapters ?? {},\n ...(config.autoCapture\n ? {\n autoCapture: {\n ...config.autoCapture,\n startPhrases: [...(config.autoCapture.startPhrases ?? [])],\n stopPhrases: [...(config.autoCapture.stopPhrases ?? [])],\n // Unlike start and stop phrases, these default to a non-empty list: without\n // a send phrase a draft could be opened and never submitted.\n composeOpenPhrases: [...(config.autoCapture.composeOpenPhrases ?? DEFAULT_COMPOSE_OPEN_PHRASES)],\n composeSendPhrases: [...(config.autoCapture.composeSendPhrases ?? DEFAULT_COMPOSE_SEND_PHRASES)],\n composeCancelPhrases: [...(config.autoCapture.composeCancelPhrases ?? DEFAULT_COMPOSE_CANCEL_PHRASES)],\n utteranceIdleMs: config.autoCapture.utteranceIdleMs ?? DEFAULT_UTTERANCE_IDLE_MS,\n composeUtteranceIdleMs: config.autoCapture.composeUtteranceIdleMs ?? DEFAULT_COMPOSE_UTTERANCE_IDLE_MS,\n composeNudgeMs: config.autoCapture.composeNudgeMs ?? DEFAULT_COMPOSE_NUDGE_MS,\n transcriptionTimeoutMs: config.autoCapture.transcriptionTimeoutMs ?? DEFAULT_TRANSCRIPTION_TIMEOUT_MS,\n tts: {\n ...config.autoCapture.tts,\n ...(ttsOverride?.voice === undefined ? {} : { voice: ttsOverride.voice }),\n ...(ttsOverride?.rate === undefined ? {} : { rate: ttsOverride.rate }),\n },\n },\n }\n : {}),\n };\n}\n\n/**\n * Which files a key may be written to.\n *\n * `mergeDoomConfigs` above already decides this per field, but it decides it by\n * doing it: `editor` reads only from the global side, `projectTrust` only from\n * the repository side, and repository `voice.mode`, `voice.autoCapture` or\n * `voice.live` declarations throw outright. A caller holding a key path has no way to ask.\n * surface offers writes that throw, or worse, writes that land in a file the\n * merge will ignore, so the change appears to do nothing.\n *\n * Declared here rather than beside the writer because the rule is a property of\n * the merge, not of the filesystem, and a test asserts the two agree.\n */\nexport type ConfigKeyScope = 'global' | 'repository' | 'both';\n\n/** Root keys the merge reads from one side only. */\nconst GLOBAL_ONLY_ROOTS: readonly string[] = ['computerUse', 'editor', 'browse'];\nconst REPOSITORY_ONLY_ROOTS: readonly string[] = ['projectTrust'];\n/** Nested exceptions; a repository declaration of any of them throws in the merge. */\nconst GLOBAL_ONLY_PATHS: readonly (readonly string[])[] = [\n ['voice', 'mode'],\n ['voice', 'autoCapture'],\n ['voice', 'live'],\n];\n\nfunction startsWith(keyPath: readonly string[], prefix: readonly string[]): boolean {\n return prefix.length <= keyPath.length && prefix.every((segment, index) => keyPath[index] === segment);\n}\n\n/**\n * The scopes a key path accepts. An unknown root answers `both` rather than\n * throwing: the parser is what rejects unsupported keys, and it reports them\n * far better than a scope lookup could.\n */\nexport function configScopeOf(keyPath: readonly string[]): ConfigKeyScope {\n if (keyPath.length === 0) return 'both';\n if (GLOBAL_ONLY_PATHS.some((prefix) => startsWith(keyPath, prefix))) return 'global';\n const root = keyPath[0]!;\n if (GLOBAL_ONLY_ROOTS.includes(root)) return 'global';\n if (REPOSITORY_ONLY_ROOTS.includes(root)) return 'repository';\n return 'both';\n}\n\n/** Every root key the config accepts, so a caller can enumerate without importing the parser's internals. */\nexport function configRootKeys(): readonly string[] {\n return ROOT_KEYS;\n}\n\nconst KEY_SEPARATOR = '.';\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Every key path a parsed document actually sets, as dotted strings.\n *\n * A settings surface needs to tell \"this file set this key\" from \"this file is\n * silent about it\", and the parsed `DoomConfig` cannot answer: an absent file\n * reads as `{ projectTrust: 'ask' }` and `parseDoomConfig` always returns all\n * known root keys, some undefined. So the question is asked of the raw document\n * instead, before any defaulting has happened.\n *\n * Leaves only. A list is a leaf because it is replaced whole, and an empty\n * record sets nothing.\n */\nexport function configLeafKeys(value: unknown, prefix: readonly string[] = []): string[] {\n if (!isPlainRecord(value)) return prefix.length > 0 ? [prefix.join(KEY_SEPARATOR)] : [];\n const keys = Object.keys(value);\n if (keys.length === 0) return prefix.length > 0 ? [prefix.join(KEY_SEPARATOR)] : [];\n return keys.flatMap((key) => configLeafKeys(value[key], [...prefix, key]));\n}\n\n/** The value a key path points at, or undefined when any step is missing. */\nexport function valueAtKeyPath(value: unknown, keyPath: readonly string[]): unknown {\n let current: unknown = value;\n for (const segment of keyPath) {\n if (!isPlainRecord(current)) return undefined;\n current = current[segment];\n }\n return current;\n}\n"],"mappings":"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"}
|