@agimon-ai/doompi-config 0.0.1-alpha.44 → 0.0.1-alpha.45
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.cjs +1 -1
- package/dist/config.d.cts +2 -2
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +1 -1
- package/dist/services/configPolicy.cjs +1 -1
- package/dist/services/configPolicy.cjs.map +1 -1
- package/dist/services/configPolicy.d.cts +3 -2
- package/dist/services/configPolicy.d.cts.map +1 -1
- package/dist/services/configPolicy.d.mts +3 -2
- package/dist/services/configPolicy.d.mts.map +1 -1
- package/dist/services/configPolicy.mjs +1 -1
- package/dist/services/configPolicy.mjs.map +1 -1
- package/dist/types/config.d.cts +20 -1
- package/dist/types/config.d.cts.map +1 -1
- package/dist/types/config.d.mts +20 -1
- package/dist/types/config.d.mts.map +1 -1
- package/dist/types.d.cts +2 -2
- package/dist/types.d.mts +2 -2
- package/package.json +3 -3
package/dist/config.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/configPolicy.cjs"),t=require("./adapters/config.cjs");exports.DOOM_PLANNING_THINKING_LEVELS=e.DOOM_PLANNING_THINKING_LEVELS,exports.DOOM_VOICE_ENGINES=e.DOOM_VOICE_ENGINES,exports.DOOM_VOICE_TTS_ENGINES=e.DOOM_VOICE_TTS_ENGINES,exports.configLeafKeys=e.configLeafKeys,exports.configRootKeys=e.configRootKeys,exports.configScopeOf=e.configScopeOf,exports.globalDoomConfigDirectory=t.globalDoomConfigDirectory,exports.globalDoomConfigPath=t.globalDoomConfigPath,exports.loadDoomConfig=t.loadDoomConfig,exports.loadDoomConfigAsync=t.loadDoomConfigAsync,exports.loadDoomConfigLayers=t.loadDoomConfigLayers,exports.mergeDoomConfigs=e.mergeDoomConfigs,exports.parseDoomConfig=e.parseDoomConfig,exports.parsePlanningModeConfig=e.parsePlanningModeConfig,exports.repositoryDoomConfigPath=t.repositoryDoomConfigPath,exports.resolvePlanningPlansDirectory=t.resolvePlanningPlansDirectory,exports.resolveVoiceConfig=e.resolveVoiceConfig,exports.valueAtKeyPath=e.valueAtKeyPath;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/configPolicy.cjs"),t=require("./adapters/config.cjs");exports.DOOM_PLANNING_THINKING_LEVELS=e.DOOM_PLANNING_THINKING_LEVELS,exports.DOOM_VOICE_ENGINES=e.DOOM_VOICE_ENGINES,exports.DOOM_VOICE_TTS_ENGINES=e.DOOM_VOICE_TTS_ENGINES,exports.configLeafKeys=e.configLeafKeys,exports.configRootKeys=e.configRootKeys,exports.configScopeOf=e.configScopeOf,exports.globalDoomConfigDirectory=t.globalDoomConfigDirectory,exports.globalDoomConfigPath=t.globalDoomConfigPath,exports.loadDoomConfig=t.loadDoomConfig,exports.loadDoomConfigAsync=t.loadDoomConfigAsync,exports.loadDoomConfigLayers=t.loadDoomConfigLayers,exports.mergeDoomConfigs=e.mergeDoomConfigs,exports.parseAutocompactModeConfig=e.parseAutocompactModeConfig,exports.parseDoomConfig=e.parseDoomConfig,exports.parsePlanningModeConfig=e.parsePlanningModeConfig,exports.repositoryDoomConfigPath=t.repositoryDoomConfigPath,exports.resolvePlanningPlansDirectory=t.resolvePlanningPlansDirectory,exports.resolveVoiceConfig=e.resolveVoiceConfig,exports.valueAtKeyPath=e.valueAtKeyPath;
|
package/dist/config.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ConfigValueOrigin, DoomConfigLayer, DoomConfigLayers } from "./types/config.cjs";
|
|
2
2
|
import { globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, repositoryDoomConfigPath, resolvePlanningPlansDirectory } from "./adapters/config.cjs";
|
|
3
|
-
import { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath } from "./services/configPolicy.cjs";
|
|
4
|
-
export { type ConfigKeyScope, type ConfigValueOrigin, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, type DoomConfigLayer, type DoomConfigLayers, configLeafKeys, configRootKeys, configScopeOf, globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
|
3
|
+
import { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath } from "./services/configPolicy.cjs";
|
|
4
|
+
export { type ConfigKeyScope, type ConfigValueOrigin, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, type DoomConfigLayer, type DoomConfigLayers, configLeafKeys, configRootKeys, configScopeOf, globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
package/dist/config.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ConfigValueOrigin, DoomConfigLayer, DoomConfigLayers } from "./types/config.mjs";
|
|
2
2
|
import { globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, repositoryDoomConfigPath, resolvePlanningPlansDirectory } from "./adapters/config.mjs";
|
|
3
|
-
import { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath } from "./services/configPolicy.mjs";
|
|
4
|
-
export { type ConfigKeyScope, type ConfigValueOrigin, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, type DoomConfigLayer, type DoomConfigLayers, configLeafKeys, configRootKeys, configScopeOf, globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
|
3
|
+
import { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath } from "./services/configPolicy.mjs";
|
|
4
|
+
export { type ConfigKeyScope, type ConfigValueOrigin, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, type DoomConfigLayer, type DoomConfigLayers, configLeafKeys, configRootKeys, configScopeOf, globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, repositoryDoomConfigPath, resolvePlanningPlansDirectory, resolveVoiceConfig, valueAtKeyPath };
|
package/dist/config.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DOOM_PLANNING_THINKING_LEVELS as e,DOOM_VOICE_ENGINES as t,DOOM_VOICE_TTS_ENGINES as n,configLeafKeys as r,configRootKeys as i,configScopeOf as a,mergeDoomConfigs as o,
|
|
1
|
+
import{DOOM_PLANNING_THINKING_LEVELS as e,DOOM_VOICE_ENGINES as t,DOOM_VOICE_TTS_ENGINES as n,configLeafKeys as r,configRootKeys as i,configScopeOf as a,mergeDoomConfigs as o,parseAutocompactModeConfig as s,parseDoomConfig as c,parsePlanningModeConfig as l,resolveVoiceConfig as u,valueAtKeyPath as d}from"./services/configPolicy.mjs";import{globalDoomConfigDirectory as f,globalDoomConfigPath as p,loadDoomConfig as m,loadDoomConfigAsync as h,loadDoomConfigLayers as g,repositoryDoomConfigPath as _,resolvePlanningPlansDirectory as v}from"./adapters/config.mjs";export{e as DOOM_PLANNING_THINKING_LEVELS,t as DOOM_VOICE_ENGINES,n as DOOM_VOICE_TTS_ENGINES,r as configLeafKeys,i as configRootKeys,a as configScopeOf,f as globalDoomConfigDirectory,p as globalDoomConfigPath,m as loadDoomConfig,h as loadDoomConfigAsync,g as loadDoomConfigLayers,o as mergeDoomConfigs,s as parseAutocompactModeConfig,c as parseDoomConfig,l as parsePlanningModeConfig,_ as repositoryDoomConfigPath,v as resolvePlanningPlansDirectory,u as resolveVoiceConfig,d as valueAtKeyPath};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./adapters/atomicJson.cjs"),t=require("./services/configPolicy.cjs"),n=require("./adapters/config.cjs"),r=require("./adapters/configWriter.cjs"),i=require("./services/domains.cjs"),a=require("./adapters/layeredConfig.cjs"),o=require("./adapters/pluginCatalog.cjs"),s=require("./adapters/domains.cjs"),c=require("./adapters/harnessState.cjs"),l=require("./adapters/harnessStore.cjs"),u=require("./adapters/init.cjs"),d=require("./adapters/majorModes.cjs");require("./types/config.cjs");const f=require("./adapters/pi/piContext.cjs"),p=require("./adapters/piConfig.cjs"),m=require("./adapters/profiles.cjs");let h=require("@agimon-ai/doompi-extension-contracts/config");exports.DOOM_CONFIG_ENTRY_TYPE=f.DOOM_CONFIG_ENTRY_TYPE,Object.defineProperty(exports,"DOOM_CONFIG_SERVICE",{enumerable:!0,get:function(){return h.DOOM_CONFIG_SERVICE}}),exports.DOOM_CONFIG_TEMPLATES=u.DOOM_CONFIG_TEMPLATES,exports.DOOM_CONFIG_TRANSITION_ENTRY_TYPE=f.DOOM_CONFIG_TRANSITION_ENTRY_TYPE,exports.DOOM_DIR=a.DOOM_DIR,exports.DOOM_PLANNING_THINKING_LEVELS=t.DOOM_PLANNING_THINKING_LEVELS,exports.DOOM_VOICE_ENGINES=t.DOOM_VOICE_ENGINES,exports.DOOM_VOICE_TTS_ENGINES=t.DOOM_VOICE_TTS_ENGINES,exports.FILE_ONLY_STATE_FIELDS=c.FILE_ONLY_STATE_FIELDS,exports.GLOBAL_DOOM_SEED_FILES=u.GLOBAL_DOOM_SEED_FILES,exports.HARNESS_STATE_KEYS=c.HARNESS_STATE_KEYS,exports.HARNESS_STATE_POINTER=l.HARNESS_STATE_POINTER,exports.MARKETPLACE_MANIFEST_RELATIVE_PATHS=o.MARKETPLACE_MANIFEST_RELATIVE_PATHS,exports.PERSONA_FILES=m.PERSONA_FILES,exports.REPOSITORY_DOOM_CONFIG_TEMPLATES=u.REPOSITORY_DOOM_CONFIG_TEMPLATES,exports.acknowledgeDoomConfigTransition=f.acknowledgeDoomConfigTransition,exports.appendDoomConfigSelection=f.appendDoomConfigSelection,exports.appendDoomConfigTransition=f.appendDoomConfigTransition,exports.applyProfileEnvironment=m.applyProfileEnvironment,exports.buildPersonaPrompt=m.buildPersonaPrompt,exports.configLeafKeys=t.configLeafKeys,exports.configRootKeys=t.configRootKeys,exports.configScopeOf=t.configScopeOf,exports.createDoomConfigContext=f.createDoomConfigContext,exports.createDoomConfigContextAsync=f.createDoomConfigContextAsync,exports.createHarnessSession=l.createHarnessSession,exports.disposeHarnessState=l.disposeHarnessState,exports.domainCompletionItems=i.domainCompletionItems,exports.domainCompletionPrefix=i.domainCompletionPrefix,exports.expandDomainNames=i.expandDomainNames,exports.findPluginManifestPath=o.findPluginManifestPath,exports.freezeDoomConfigContext=f.freezeDoomConfigContext,exports.getHarnessState=l.getHarnessState,exports.globalDoomConfigDirectory=n.globalDoomConfigDirectory,exports.globalDoomConfigPath=n.globalDoomConfigPath,exports.harnessRoot=l.harnessRoot,exports.initializeGlobalDoomConfig=u.initializeGlobalDoomConfig,exports.initializeRepositoryDoomConfig=u.initializeRepositoryDoomConfig,exports.isLocalPackageSpecifier=d.isLocalPackageSpecifier,exports.isRemotePluginSource=o.isRemotePluginSource,exports.layerEntries=d.layerEntries,exports.layerHookGroups=d.layerHookGroups,exports.listDomainNames=s.listDomainNames,exports.listProfileNames=m.listProfileNames,exports.loadDomains=s.loadDomains,exports.loadDoomConfig=n.loadDoomConfig,exports.loadDoomConfigAsync=n.loadDoomConfigAsync,exports.loadDoomConfigLayers=n.loadDoomConfigLayers,exports.loadHarnessState=l.loadHarnessState,exports.loadMajorModesConfig=d.loadMajorModesConfig,exports.loadPiConfig=p.loadPiConfig,exports.loadPiConfigAsync=p.loadPiConfigAsync,exports.loadProfiles=m.loadProfiles,exports.mergeDoomConfigs=t.mergeDoomConfigs,exports.parseDoomConfig=t.parseDoomConfig,exports.parsePlanningModeConfig=t.parsePlanningModeConfig,exports.piConfigPaths=p.piConfigPaths,exports.pluginDirectoryForSource=o.pluginDirectoryForSource,exports.projectHarnessEnvironment=c.projectHarnessEnvironment,exports.provideDoomConfigContext=f.provideDoomConfigContext,exports.readDoomConfigContextGeneration=f.readDoomConfigContextGeneration,exports.readDoomConfigPendingSelection=f.readDoomConfigPendingSelection,exports.readDoomConfigSelection=f.readDoomConfigSelection,exports.readHarnessState=c.readHarnessState,exports.replaceDoomConfigContext=f.replaceDoomConfigContext,exports.replaceProfileEnvironment=m.replaceProfileEnvironment,exports.repositoryDoomConfigPath=n.repositoryDoomConfigPath,exports.requireDoomConfigContext=f.requireDoomConfigContext,exports.requireHarnessPaths=l.requireHarnessPaths,exports.requireHarnessRoot=l.requireHarnessRoot,exports.resetHarnessStore=l.resetHarnessStore,exports.resolveLayers=d.resolveLayers,exports.resolvePackageConfigurations=d.resolvePackageConfigurations,exports.resolvePlanningPlansDirectory=n.resolvePlanningPlansDirectory,exports.resolvePluginDirectories=s.resolvePluginDirectories,exports.resolvePluginEntries=s.resolvePluginEntries,exports.resolveProfile=m.resolveProfile,exports.resolveSharedSkills=s.resolveSharedSkills,exports.resolveVoiceConfig=t.resolveVoiceConfig,exports.restoreHarnessStateSnapshot=l.restoreHarnessStateSnapshot,exports.setDoomConfigValue=r.setDoomConfigValue,exports.snapshotHarnessState=l.snapshotHarnessState,exports.supersedeDoomConfigTransition=f.supersedeDoomConfigTransition,exports.unsetDoomConfigValue=r.unsetDoomConfigValue,exports.updateHarnessState=l.updateHarnessState,exports.valueAtKeyPath=t.valueAtKeyPath,exports.writeDoomConfigValues=r.writeDoomConfigValues,exports.writePrivateAtomicJson=e.writePrivateAtomicJson;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./adapters/atomicJson.cjs"),t=require("./services/configPolicy.cjs"),n=require("./adapters/config.cjs"),r=require("./adapters/configWriter.cjs"),i=require("./services/domains.cjs"),a=require("./adapters/layeredConfig.cjs"),o=require("./adapters/pluginCatalog.cjs"),s=require("./adapters/domains.cjs"),c=require("./adapters/harnessState.cjs"),l=require("./adapters/harnessStore.cjs"),u=require("./adapters/init.cjs"),d=require("./adapters/majorModes.cjs");require("./types/config.cjs");const f=require("./adapters/pi/piContext.cjs"),p=require("./adapters/piConfig.cjs"),m=require("./adapters/profiles.cjs");let h=require("@agimon-ai/doompi-extension-contracts/config");exports.DOOM_CONFIG_ENTRY_TYPE=f.DOOM_CONFIG_ENTRY_TYPE,Object.defineProperty(exports,"DOOM_CONFIG_SERVICE",{enumerable:!0,get:function(){return h.DOOM_CONFIG_SERVICE}}),exports.DOOM_CONFIG_TEMPLATES=u.DOOM_CONFIG_TEMPLATES,exports.DOOM_CONFIG_TRANSITION_ENTRY_TYPE=f.DOOM_CONFIG_TRANSITION_ENTRY_TYPE,exports.DOOM_DIR=a.DOOM_DIR,exports.DOOM_PLANNING_THINKING_LEVELS=t.DOOM_PLANNING_THINKING_LEVELS,exports.DOOM_VOICE_ENGINES=t.DOOM_VOICE_ENGINES,exports.DOOM_VOICE_TTS_ENGINES=t.DOOM_VOICE_TTS_ENGINES,exports.FILE_ONLY_STATE_FIELDS=c.FILE_ONLY_STATE_FIELDS,exports.GLOBAL_DOOM_SEED_FILES=u.GLOBAL_DOOM_SEED_FILES,exports.HARNESS_STATE_KEYS=c.HARNESS_STATE_KEYS,exports.HARNESS_STATE_POINTER=l.HARNESS_STATE_POINTER,exports.MARKETPLACE_MANIFEST_RELATIVE_PATHS=o.MARKETPLACE_MANIFEST_RELATIVE_PATHS,exports.PERSONA_FILES=m.PERSONA_FILES,exports.REPOSITORY_DOOM_CONFIG_TEMPLATES=u.REPOSITORY_DOOM_CONFIG_TEMPLATES,exports.acknowledgeDoomConfigTransition=f.acknowledgeDoomConfigTransition,exports.appendDoomConfigSelection=f.appendDoomConfigSelection,exports.appendDoomConfigTransition=f.appendDoomConfigTransition,exports.applyProfileEnvironment=m.applyProfileEnvironment,exports.buildPersonaPrompt=m.buildPersonaPrompt,exports.configLeafKeys=t.configLeafKeys,exports.configRootKeys=t.configRootKeys,exports.configScopeOf=t.configScopeOf,exports.createDoomConfigContext=f.createDoomConfigContext,exports.createDoomConfigContextAsync=f.createDoomConfigContextAsync,exports.createHarnessSession=l.createHarnessSession,exports.disposeHarnessState=l.disposeHarnessState,exports.domainCompletionItems=i.domainCompletionItems,exports.domainCompletionPrefix=i.domainCompletionPrefix,exports.expandDomainNames=i.expandDomainNames,exports.findPluginManifestPath=o.findPluginManifestPath,exports.freezeDoomConfigContext=f.freezeDoomConfigContext,exports.getHarnessState=l.getHarnessState,exports.globalDoomConfigDirectory=n.globalDoomConfigDirectory,exports.globalDoomConfigPath=n.globalDoomConfigPath,exports.harnessRoot=l.harnessRoot,exports.initializeGlobalDoomConfig=u.initializeGlobalDoomConfig,exports.initializeRepositoryDoomConfig=u.initializeRepositoryDoomConfig,exports.isLocalPackageSpecifier=d.isLocalPackageSpecifier,exports.isRemotePluginSource=o.isRemotePluginSource,exports.layerEntries=d.layerEntries,exports.layerHookGroups=d.layerHookGroups,exports.listDomainNames=s.listDomainNames,exports.listProfileNames=m.listProfileNames,exports.loadDomains=s.loadDomains,exports.loadDoomConfig=n.loadDoomConfig,exports.loadDoomConfigAsync=n.loadDoomConfigAsync,exports.loadDoomConfigLayers=n.loadDoomConfigLayers,exports.loadHarnessState=l.loadHarnessState,exports.loadMajorModesConfig=d.loadMajorModesConfig,exports.loadPiConfig=p.loadPiConfig,exports.loadPiConfigAsync=p.loadPiConfigAsync,exports.loadProfiles=m.loadProfiles,exports.mergeDoomConfigs=t.mergeDoomConfigs,exports.parseAutocompactModeConfig=t.parseAutocompactModeConfig,exports.parseDoomConfig=t.parseDoomConfig,exports.parsePlanningModeConfig=t.parsePlanningModeConfig,exports.piConfigPaths=p.piConfigPaths,exports.pluginDirectoryForSource=o.pluginDirectoryForSource,exports.projectHarnessEnvironment=c.projectHarnessEnvironment,exports.provideDoomConfigContext=f.provideDoomConfigContext,exports.readDoomConfigContextGeneration=f.readDoomConfigContextGeneration,exports.readDoomConfigPendingSelection=f.readDoomConfigPendingSelection,exports.readDoomConfigSelection=f.readDoomConfigSelection,exports.readHarnessState=c.readHarnessState,exports.replaceDoomConfigContext=f.replaceDoomConfigContext,exports.replaceProfileEnvironment=m.replaceProfileEnvironment,exports.repositoryDoomConfigPath=n.repositoryDoomConfigPath,exports.requireDoomConfigContext=f.requireDoomConfigContext,exports.requireHarnessPaths=l.requireHarnessPaths,exports.requireHarnessRoot=l.requireHarnessRoot,exports.resetHarnessStore=l.resetHarnessStore,exports.resolveLayers=d.resolveLayers,exports.resolvePackageConfigurations=d.resolvePackageConfigurations,exports.resolvePlanningPlansDirectory=n.resolvePlanningPlansDirectory,exports.resolvePluginDirectories=s.resolvePluginDirectories,exports.resolvePluginEntries=s.resolvePluginEntries,exports.resolveProfile=m.resolveProfile,exports.resolveSharedSkills=s.resolveSharedSkills,exports.resolveVoiceConfig=t.resolveVoiceConfig,exports.restoreHarnessStateSnapshot=l.restoreHarnessStateSnapshot,exports.setDoomConfigValue=r.setDoomConfigValue,exports.snapshotHarnessState=l.snapshotHarnessState,exports.supersedeDoomConfigTransition=f.supersedeDoomConfigTransition,exports.unsetDoomConfigValue=r.unsetDoomConfigValue,exports.updateHarnessState=l.updateHarnessState,exports.valueAtKeyPath=t.valueAtKeyPath,exports.writeDoomConfigValues=r.writeDoomConfigValues,exports.writePrivateAtomicJson=e.writePrivateAtomicJson;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writePrivateAtomicJson } from "./adapters/atomicJson.cjs";
|
|
2
|
-
import { ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine } from "./types/config.cjs";
|
|
2
|
+
import { AutocompactModeConfig, AutocompactThresholdConfig, ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine } from "./types/config.cjs";
|
|
3
3
|
import { globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, repositoryDoomConfigPath, resolvePlanningPlansDirectory } from "./adapters/config.cjs";
|
|
4
|
-
import { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath } from "./services/configPolicy.cjs";
|
|
4
|
+
import { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath } from "./services/configPolicy.cjs";
|
|
5
5
|
import { ConfigAdapterRegistrationOptions, PiConfig, PiConfigLoadOptions, PiConfigPaths } from "./schemas/config/schema.cjs";
|
|
6
6
|
import { loadPiConfig, loadPiConfigAsync, piConfigPaths } from "./adapters/piConfig.cjs";
|
|
7
7
|
import { DoomConfigEdit, DoomConfigScope, WriteDoomConfigOptions, setDoomConfigValue, unsetDoomConfigValue, writeDoomConfigValues } from "./adapters/configWriter.cjs";
|
|
@@ -16,4 +16,4 @@ import { DOOM_CONFIG_TEMPLATES, GLOBAL_DOOM_SEED_FILES, GlobalDoomInitResult, RE
|
|
|
16
16
|
import { LayerDefinition, LayerPackage, LayerPackageConfig, LayerResolvers, MajorModeDefinition, MajorModesConfig, ResolvedLayerDefinition, ResolvedPackageConfiguration, isLocalPackageSpecifier, layerEntries, layerHookGroups, loadMajorModesConfig, resolveLayers, resolvePackageConfigurations } from "./adapters/majorModes.cjs";
|
|
17
17
|
import { DOOM_CONFIG_ENTRY_TYPE, DOOM_CONFIG_TRANSITION_ENTRY_TYPE, DoomConfigSelection, acknowledgeDoomConfigTransition, appendDoomConfigSelection, appendDoomConfigTransition, createDoomConfigContext, createDoomConfigContextAsync, freezeDoomConfigContext, provideDoomConfigContext, readDoomConfigContextGeneration, readDoomConfigPendingSelection, readDoomConfigSelection, replaceDoomConfigContext, requireDoomConfigContext, supersedeDoomConfigTransition } from "./adapters/pi/piContext.cjs";
|
|
18
18
|
import { AgentProfile, PERSONA_FILES, applyProfileEnvironment, buildPersonaPrompt, listProfileNames, loadProfiles, replaceProfileEnvironment, resolveProfile } from "./adapters/profiles.cjs";
|
|
19
|
-
export { type AgentProfile, type ConfigAdapterRegistrationOptions, type ConfigKeyScope, type ConfigValueOrigin, DOOM_CONFIG_ENTRY_TYPE, DOOM_CONFIG_SERVICE, DOOM_CONFIG_TEMPLATES, DOOM_CONFIG_TRANSITION_ENTRY_TYPE, DOOM_DIR, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, type DeepReadonly, type DomainDefinition, type DomainManifest, type DomainMcpAllowlist, type DomainPlugin, type DoomConfig, type DoomConfigContext, type DoomConfigEdit, type DoomConfigLayer, type DoomConfigLayers, type DoomConfigPendingSelection, type DoomConfigScope, type DoomConfigSelection, type DoomConfigTransitionPhase, type DoomConfigTransitionRecord, type DoomConfigTransitionStrategy, type DoomHarnessContext, type DoomSelectionConfig, type EditorConfig, FILE_ONLY_STATE_FIELDS, GLOBAL_DOOM_SEED_FILES, type GitPluginSource, type GlobalDoomInitResult, HARNESS_STATE_KEYS, HARNESS_STATE_POINTER, type HarnessState, type HarnessStateFile, type HarnessStateParseReporter, type HarnessStateTransactionSnapshot, type IDoomConfigLoader, type IDoomConfigService, type LayerDefinition, type LayerPackage, type LayerPackageConfig, type LayerResolvers, type LoadedHarnessState, type LocalPluginSource, MARKETPLACE_MANIFEST_RELATIVE_PATHS, type MajorModeDefinition, type MajorModesConfig, type NpmPluginSource, PERSONA_FILES, type PiConfig, type PiConfigLoadOptions, type PiConfigPaths, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, type PluginCatalog, type PluginCatalogEntry, type PluginEntry, type PluginHookSource, type PluginManifestMetadata, type PluginSkillDiscovery, type PluginSource, type ProjectTrust, REPOSITORY_DOOM_CONFIG_TEMPLATES, type RepositoryDoomInitOptions, type RepositoryDoomInitResult, type ResolvedDomain, type ResolvedLayerDefinition, type ResolvedPackageConfiguration, type ResolvedVoiceAutoCaptureConfig, type ResolvedVoiceConfig, type VoiceAdapterConfig, type VoiceAutoCaptureConfig, type VoiceConfig, type VoiceEngine, type VoiceModelConfig, type VoiceTtsConfig, type VoiceTtsEngine, type WriteDoomConfigOptions, acknowledgeDoomConfigTransition, appendDoomConfigSelection, appendDoomConfigTransition, applyProfileEnvironment, buildPersonaPrompt, configLeafKeys, configRootKeys, configScopeOf, createDoomConfigContext, createDoomConfigContextAsync, createHarnessSession, disposeHarnessState, domainCompletionItems, domainCompletionPrefix, expandDomainNames, findPluginManifestPath, freezeDoomConfigContext, getHarnessState, globalDoomConfigDirectory, globalDoomConfigPath, harnessRoot, initializeGlobalDoomConfig, initializeRepositoryDoomConfig, isLocalPackageSpecifier, isRemotePluginSource, layerEntries, layerHookGroups, listDomainNames, listProfileNames, loadDomains, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, loadHarnessState, loadMajorModesConfig, loadPiConfig, loadPiConfigAsync, loadProfiles, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, piConfigPaths, pluginDirectoryForSource, projectHarnessEnvironment, provideDoomConfigContext, readDoomConfigContextGeneration, readDoomConfigPendingSelection, readDoomConfigSelection, readHarnessState, replaceDoomConfigContext, replaceProfileEnvironment, repositoryDoomConfigPath, requireDoomConfigContext, requireHarnessPaths, requireHarnessRoot, resetHarnessStore, resolveLayers, resolvePackageConfigurations, resolvePlanningPlansDirectory, resolvePluginDirectories, resolvePluginEntries, resolveProfile, resolveSharedSkills, resolveVoiceConfig, restoreHarnessStateSnapshot, setDoomConfigValue, snapshotHarnessState, supersedeDoomConfigTransition, unsetDoomConfigValue, updateHarnessState, valueAtKeyPath, writeDoomConfigValues, writePrivateAtomicJson };
|
|
19
|
+
export { type AgentProfile, type AutocompactModeConfig, type AutocompactThresholdConfig, type ConfigAdapterRegistrationOptions, type ConfigKeyScope, type ConfigValueOrigin, DOOM_CONFIG_ENTRY_TYPE, DOOM_CONFIG_SERVICE, DOOM_CONFIG_TEMPLATES, DOOM_CONFIG_TRANSITION_ENTRY_TYPE, DOOM_DIR, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, type DeepReadonly, type DomainDefinition, type DomainManifest, type DomainMcpAllowlist, type DomainPlugin, type DoomConfig, type DoomConfigContext, type DoomConfigEdit, type DoomConfigLayer, type DoomConfigLayers, type DoomConfigPendingSelection, type DoomConfigScope, type DoomConfigSelection, type DoomConfigTransitionPhase, type DoomConfigTransitionRecord, type DoomConfigTransitionStrategy, type DoomHarnessContext, type DoomSelectionConfig, type EditorConfig, FILE_ONLY_STATE_FIELDS, GLOBAL_DOOM_SEED_FILES, type GitPluginSource, type GlobalDoomInitResult, HARNESS_STATE_KEYS, HARNESS_STATE_POINTER, type HarnessState, type HarnessStateFile, type HarnessStateParseReporter, type HarnessStateTransactionSnapshot, type IDoomConfigLoader, type IDoomConfigService, type LayerDefinition, type LayerPackage, type LayerPackageConfig, type LayerResolvers, type LoadedHarnessState, type LocalPluginSource, MARKETPLACE_MANIFEST_RELATIVE_PATHS, type MajorModeDefinition, type MajorModesConfig, type NpmPluginSource, PERSONA_FILES, type PiConfig, type PiConfigLoadOptions, type PiConfigPaths, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, type PluginCatalog, type PluginCatalogEntry, type PluginEntry, type PluginHookSource, type PluginManifestMetadata, type PluginSkillDiscovery, type PluginSource, type ProjectTrust, REPOSITORY_DOOM_CONFIG_TEMPLATES, type RepositoryDoomInitOptions, type RepositoryDoomInitResult, type ResolvedDomain, type ResolvedLayerDefinition, type ResolvedPackageConfiguration, type ResolvedVoiceAutoCaptureConfig, type ResolvedVoiceConfig, type VoiceAdapterConfig, type VoiceAutoCaptureConfig, type VoiceConfig, type VoiceEngine, type VoiceModelConfig, type VoiceTtsConfig, type VoiceTtsEngine, type WriteDoomConfigOptions, acknowledgeDoomConfigTransition, appendDoomConfigSelection, appendDoomConfigTransition, applyProfileEnvironment, buildPersonaPrompt, configLeafKeys, configRootKeys, configScopeOf, createDoomConfigContext, createDoomConfigContextAsync, createHarnessSession, disposeHarnessState, domainCompletionItems, domainCompletionPrefix, expandDomainNames, findPluginManifestPath, freezeDoomConfigContext, getHarnessState, globalDoomConfigDirectory, globalDoomConfigPath, harnessRoot, initializeGlobalDoomConfig, initializeRepositoryDoomConfig, isLocalPackageSpecifier, isRemotePluginSource, layerEntries, layerHookGroups, listDomainNames, listProfileNames, loadDomains, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, loadHarnessState, loadMajorModesConfig, loadPiConfig, loadPiConfigAsync, loadProfiles, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, piConfigPaths, pluginDirectoryForSource, projectHarnessEnvironment, provideDoomConfigContext, readDoomConfigContextGeneration, readDoomConfigPendingSelection, readDoomConfigSelection, readHarnessState, replaceDoomConfigContext, replaceProfileEnvironment, repositoryDoomConfigPath, requireDoomConfigContext, requireHarnessPaths, requireHarnessRoot, resetHarnessStore, resolveLayers, resolvePackageConfigurations, resolvePlanningPlansDirectory, resolvePluginDirectories, resolvePluginEntries, resolveProfile, resolveSharedSkills, resolveVoiceConfig, restoreHarnessStateSnapshot, setDoomConfigValue, snapshotHarnessState, supersedeDoomConfigTransition, unsetDoomConfigValue, updateHarnessState, valueAtKeyPath, writeDoomConfigValues, writePrivateAtomicJson };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writePrivateAtomicJson } from "./adapters/atomicJson.mjs";
|
|
2
|
-
import { ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine } from "./types/config.mjs";
|
|
2
|
+
import { AutocompactModeConfig, AutocompactThresholdConfig, ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine } from "./types/config.mjs";
|
|
3
3
|
import { globalDoomConfigDirectory, globalDoomConfigPath, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, repositoryDoomConfigPath, resolvePlanningPlansDirectory } from "./adapters/config.mjs";
|
|
4
|
-
import { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath } from "./services/configPolicy.mjs";
|
|
4
|
+
import { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath } from "./services/configPolicy.mjs";
|
|
5
5
|
import { ConfigAdapterRegistrationOptions, PiConfig, PiConfigLoadOptions, PiConfigPaths } from "./schemas/config/schema.mjs";
|
|
6
6
|
import { loadPiConfig, loadPiConfigAsync, piConfigPaths } from "./adapters/piConfig.mjs";
|
|
7
7
|
import { DoomConfigEdit, DoomConfigScope, WriteDoomConfigOptions, setDoomConfigValue, unsetDoomConfigValue, writeDoomConfigValues } from "./adapters/configWriter.mjs";
|
|
@@ -16,4 +16,4 @@ import { DOOM_CONFIG_TEMPLATES, GLOBAL_DOOM_SEED_FILES, GlobalDoomInitResult, RE
|
|
|
16
16
|
import { LayerDefinition, LayerPackage, LayerPackageConfig, LayerResolvers, MajorModeDefinition, MajorModesConfig, ResolvedLayerDefinition, ResolvedPackageConfiguration, isLocalPackageSpecifier, layerEntries, layerHookGroups, loadMajorModesConfig, resolveLayers, resolvePackageConfigurations } from "./adapters/majorModes.mjs";
|
|
17
17
|
import { DOOM_CONFIG_ENTRY_TYPE, DOOM_CONFIG_TRANSITION_ENTRY_TYPE, DoomConfigSelection, acknowledgeDoomConfigTransition, appendDoomConfigSelection, appendDoomConfigTransition, createDoomConfigContext, createDoomConfigContextAsync, freezeDoomConfigContext, provideDoomConfigContext, readDoomConfigContextGeneration, readDoomConfigPendingSelection, readDoomConfigSelection, replaceDoomConfigContext, requireDoomConfigContext, supersedeDoomConfigTransition } from "./adapters/pi/piContext.mjs";
|
|
18
18
|
import { AgentProfile, PERSONA_FILES, applyProfileEnvironment, buildPersonaPrompt, listProfileNames, loadProfiles, replaceProfileEnvironment, resolveProfile } from "./adapters/profiles.mjs";
|
|
19
|
-
export { type AgentProfile, type ConfigAdapterRegistrationOptions, type ConfigKeyScope, type ConfigValueOrigin, DOOM_CONFIG_ENTRY_TYPE, DOOM_CONFIG_SERVICE, DOOM_CONFIG_TEMPLATES, DOOM_CONFIG_TRANSITION_ENTRY_TYPE, DOOM_DIR, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, type DeepReadonly, type DomainDefinition, type DomainManifest, type DomainMcpAllowlist, type DomainPlugin, type DoomConfig, type DoomConfigContext, type DoomConfigEdit, type DoomConfigLayer, type DoomConfigLayers, type DoomConfigPendingSelection, type DoomConfigScope, type DoomConfigSelection, type DoomConfigTransitionPhase, type DoomConfigTransitionRecord, type DoomConfigTransitionStrategy, type DoomHarnessContext, type DoomSelectionConfig, type EditorConfig, FILE_ONLY_STATE_FIELDS, GLOBAL_DOOM_SEED_FILES, type GitPluginSource, type GlobalDoomInitResult, HARNESS_STATE_KEYS, HARNESS_STATE_POINTER, type HarnessState, type HarnessStateFile, type HarnessStateParseReporter, type HarnessStateTransactionSnapshot, type IDoomConfigLoader, type IDoomConfigService, type LayerDefinition, type LayerPackage, type LayerPackageConfig, type LayerResolvers, type LoadedHarnessState, type LocalPluginSource, MARKETPLACE_MANIFEST_RELATIVE_PATHS, type MajorModeDefinition, type MajorModesConfig, type NpmPluginSource, PERSONA_FILES, type PiConfig, type PiConfigLoadOptions, type PiConfigPaths, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, type PluginCatalog, type PluginCatalogEntry, type PluginEntry, type PluginHookSource, type PluginManifestMetadata, type PluginSkillDiscovery, type PluginSource, type ProjectTrust, REPOSITORY_DOOM_CONFIG_TEMPLATES, type RepositoryDoomInitOptions, type RepositoryDoomInitResult, type ResolvedDomain, type ResolvedLayerDefinition, type ResolvedPackageConfiguration, type ResolvedVoiceAutoCaptureConfig, type ResolvedVoiceConfig, type VoiceAdapterConfig, type VoiceAutoCaptureConfig, type VoiceConfig, type VoiceEngine, type VoiceModelConfig, type VoiceTtsConfig, type VoiceTtsEngine, type WriteDoomConfigOptions, acknowledgeDoomConfigTransition, appendDoomConfigSelection, appendDoomConfigTransition, applyProfileEnvironment, buildPersonaPrompt, configLeafKeys, configRootKeys, configScopeOf, createDoomConfigContext, createDoomConfigContextAsync, createHarnessSession, disposeHarnessState, domainCompletionItems, domainCompletionPrefix, expandDomainNames, findPluginManifestPath, freezeDoomConfigContext, getHarnessState, globalDoomConfigDirectory, globalDoomConfigPath, harnessRoot, initializeGlobalDoomConfig, initializeRepositoryDoomConfig, isLocalPackageSpecifier, isRemotePluginSource, layerEntries, layerHookGroups, listDomainNames, listProfileNames, loadDomains, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, loadHarnessState, loadMajorModesConfig, loadPiConfig, loadPiConfigAsync, loadProfiles, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, piConfigPaths, pluginDirectoryForSource, projectHarnessEnvironment, provideDoomConfigContext, readDoomConfigContextGeneration, readDoomConfigPendingSelection, readDoomConfigSelection, readHarnessState, replaceDoomConfigContext, replaceProfileEnvironment, repositoryDoomConfigPath, requireDoomConfigContext, requireHarnessPaths, requireHarnessRoot, resetHarnessStore, resolveLayers, resolvePackageConfigurations, resolvePlanningPlansDirectory, resolvePluginDirectories, resolvePluginEntries, resolveProfile, resolveSharedSkills, resolveVoiceConfig, restoreHarnessStateSnapshot, setDoomConfigValue, snapshotHarnessState, supersedeDoomConfigTransition, unsetDoomConfigValue, updateHarnessState, valueAtKeyPath, writeDoomConfigValues, writePrivateAtomicJson };
|
|
19
|
+
export { type AgentProfile, type AutocompactModeConfig, type AutocompactThresholdConfig, type ConfigAdapterRegistrationOptions, type ConfigKeyScope, type ConfigValueOrigin, DOOM_CONFIG_ENTRY_TYPE, DOOM_CONFIG_SERVICE, DOOM_CONFIG_TEMPLATES, DOOM_CONFIG_TRANSITION_ENTRY_TYPE, DOOM_DIR, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, type DeepReadonly, type DomainDefinition, type DomainManifest, type DomainMcpAllowlist, type DomainPlugin, type DoomConfig, type DoomConfigContext, type DoomConfigEdit, type DoomConfigLayer, type DoomConfigLayers, type DoomConfigPendingSelection, type DoomConfigScope, type DoomConfigSelection, type DoomConfigTransitionPhase, type DoomConfigTransitionRecord, type DoomConfigTransitionStrategy, type DoomHarnessContext, type DoomSelectionConfig, type EditorConfig, FILE_ONLY_STATE_FIELDS, GLOBAL_DOOM_SEED_FILES, type GitPluginSource, type GlobalDoomInitResult, HARNESS_STATE_KEYS, HARNESS_STATE_POINTER, type HarnessState, type HarnessStateFile, type HarnessStateParseReporter, type HarnessStateTransactionSnapshot, type IDoomConfigLoader, type IDoomConfigService, type LayerDefinition, type LayerPackage, type LayerPackageConfig, type LayerResolvers, type LoadedHarnessState, type LocalPluginSource, MARKETPLACE_MANIFEST_RELATIVE_PATHS, type MajorModeDefinition, type MajorModesConfig, type NpmPluginSource, PERSONA_FILES, type PiConfig, type PiConfigLoadOptions, type PiConfigPaths, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, type PluginCatalog, type PluginCatalogEntry, type PluginEntry, type PluginHookSource, type PluginManifestMetadata, type PluginSkillDiscovery, type PluginSource, type ProjectTrust, REPOSITORY_DOOM_CONFIG_TEMPLATES, type RepositoryDoomInitOptions, type RepositoryDoomInitResult, type ResolvedDomain, type ResolvedLayerDefinition, type ResolvedPackageConfiguration, type ResolvedVoiceAutoCaptureConfig, type ResolvedVoiceConfig, type VoiceAdapterConfig, type VoiceAutoCaptureConfig, type VoiceConfig, type VoiceEngine, type VoiceModelConfig, type VoiceTtsConfig, type VoiceTtsEngine, type WriteDoomConfigOptions, acknowledgeDoomConfigTransition, appendDoomConfigSelection, appendDoomConfigTransition, applyProfileEnvironment, buildPersonaPrompt, configLeafKeys, configRootKeys, configScopeOf, createDoomConfigContext, createDoomConfigContextAsync, createHarnessSession, disposeHarnessState, domainCompletionItems, domainCompletionPrefix, expandDomainNames, findPluginManifestPath, freezeDoomConfigContext, getHarnessState, globalDoomConfigDirectory, globalDoomConfigPath, harnessRoot, initializeGlobalDoomConfig, initializeRepositoryDoomConfig, isLocalPackageSpecifier, isRemotePluginSource, layerEntries, layerHookGroups, listDomainNames, listProfileNames, loadDomains, loadDoomConfig, loadDoomConfigAsync, loadDoomConfigLayers, loadHarnessState, loadMajorModesConfig, loadPiConfig, loadPiConfigAsync, loadProfiles, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, piConfigPaths, pluginDirectoryForSource, projectHarnessEnvironment, provideDoomConfigContext, readDoomConfigContextGeneration, readDoomConfigPendingSelection, readDoomConfigSelection, readHarnessState, replaceDoomConfigContext, replaceProfileEnvironment, repositoryDoomConfigPath, requireDoomConfigContext, requireHarnessPaths, requireHarnessRoot, resetHarnessStore, resolveLayers, resolvePackageConfigurations, resolvePlanningPlansDirectory, resolvePluginDirectories, resolvePluginEntries, resolveProfile, resolveSharedSkills, resolveVoiceConfig, restoreHarnessStateSnapshot, setDoomConfigValue, snapshotHarnessState, supersedeDoomConfigTransition, unsetDoomConfigValue, updateHarnessState, valueAtKeyPath, writeDoomConfigValues, writePrivateAtomicJson };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{writePrivateAtomicJson as e}from"./adapters/atomicJson.mjs";import{DOOM_PLANNING_THINKING_LEVELS as t,DOOM_VOICE_ENGINES as n,DOOM_VOICE_TTS_ENGINES as r,configLeafKeys as i,configRootKeys as a,configScopeOf as o,mergeDoomConfigs as s,
|
|
1
|
+
import{writePrivateAtomicJson as e}from"./adapters/atomicJson.mjs";import{DOOM_PLANNING_THINKING_LEVELS as t,DOOM_VOICE_ENGINES as n,DOOM_VOICE_TTS_ENGINES as r,configLeafKeys as i,configRootKeys as a,configScopeOf as o,mergeDoomConfigs as s,parseAutocompactModeConfig as c,parseDoomConfig as l,parsePlanningModeConfig as u,resolveVoiceConfig as d,valueAtKeyPath as f}from"./services/configPolicy.mjs";import{globalDoomConfigDirectory as p,globalDoomConfigPath as m,loadDoomConfig as h,loadDoomConfigAsync as g,loadDoomConfigLayers as _,repositoryDoomConfigPath as v,resolvePlanningPlansDirectory as y}from"./adapters/config.mjs";import{setDoomConfigValue as b,unsetDoomConfigValue as x,writeDoomConfigValues as S}from"./adapters/configWriter.mjs";import{domainCompletionItems as C,domainCompletionPrefix as w,expandDomainNames as T}from"./services/domains.mjs";import{DOOM_DIR as E}from"./adapters/layeredConfig.mjs";import{MARKETPLACE_MANIFEST_RELATIVE_PATHS as D,findPluginManifestPath as O,isRemotePluginSource as k,pluginDirectoryForSource as A}from"./adapters/pluginCatalog.mjs";import{listDomainNames as j,loadDomains as M,resolvePluginDirectories as N,resolvePluginEntries as P,resolveSharedSkills as F}from"./adapters/domains.mjs";import{FILE_ONLY_STATE_FIELDS as I,HARNESS_STATE_KEYS as L,projectHarnessEnvironment as R,readHarnessState as z}from"./adapters/harnessState.mjs";import{HARNESS_STATE_POINTER as B,createHarnessSession as V,disposeHarnessState as H,getHarnessState as U,harnessRoot as W,loadHarnessState as G,requireHarnessPaths as K,requireHarnessRoot as q,resetHarnessStore as J,restoreHarnessStateSnapshot as Y,snapshotHarnessState as X,updateHarnessState as Z}from"./adapters/harnessStore.mjs";import{DOOM_CONFIG_TEMPLATES as Q,GLOBAL_DOOM_SEED_FILES as $,REPOSITORY_DOOM_CONFIG_TEMPLATES as ee,initializeGlobalDoomConfig as te,initializeRepositoryDoomConfig as ne}from"./adapters/init.mjs";import{isLocalPackageSpecifier as re,layerEntries as ie,layerHookGroups as ae,loadMajorModesConfig as oe,resolveLayers as se,resolvePackageConfigurations as ce}from"./adapters/majorModes.mjs";import{DOOM_CONFIG_SERVICE as le}from"./types/config.mjs";import{DOOM_CONFIG_ENTRY_TYPE as ue,DOOM_CONFIG_TRANSITION_ENTRY_TYPE as de,acknowledgeDoomConfigTransition as fe,appendDoomConfigSelection as pe,appendDoomConfigTransition as me,createDoomConfigContext as he,createDoomConfigContextAsync as ge,freezeDoomConfigContext as _e,provideDoomConfigContext as ve,readDoomConfigContextGeneration as ye,readDoomConfigPendingSelection as be,readDoomConfigSelection as xe,replaceDoomConfigContext as Se,requireDoomConfigContext as Ce,supersedeDoomConfigTransition as we}from"./adapters/pi/piContext.mjs";import{loadPiConfig as Te,loadPiConfigAsync as Ee,piConfigPaths as De}from"./adapters/piConfig.mjs";import{PERSONA_FILES as Oe,applyProfileEnvironment as ke,buildPersonaPrompt as Ae,listProfileNames as je,loadProfiles as Me,replaceProfileEnvironment as Ne,resolveProfile as Pe}from"./adapters/profiles.mjs";export{ue as DOOM_CONFIG_ENTRY_TYPE,le as DOOM_CONFIG_SERVICE,Q as DOOM_CONFIG_TEMPLATES,de as DOOM_CONFIG_TRANSITION_ENTRY_TYPE,E as DOOM_DIR,t as DOOM_PLANNING_THINKING_LEVELS,n as DOOM_VOICE_ENGINES,r as DOOM_VOICE_TTS_ENGINES,I as FILE_ONLY_STATE_FIELDS,$ as GLOBAL_DOOM_SEED_FILES,L as HARNESS_STATE_KEYS,B as HARNESS_STATE_POINTER,D as MARKETPLACE_MANIFEST_RELATIVE_PATHS,Oe as PERSONA_FILES,ee as REPOSITORY_DOOM_CONFIG_TEMPLATES,fe as acknowledgeDoomConfigTransition,pe as appendDoomConfigSelection,me as appendDoomConfigTransition,ke as applyProfileEnvironment,Ae as buildPersonaPrompt,i as configLeafKeys,a as configRootKeys,o as configScopeOf,he as createDoomConfigContext,ge as createDoomConfigContextAsync,V as createHarnessSession,H as disposeHarnessState,C as domainCompletionItems,w as domainCompletionPrefix,T as expandDomainNames,O as findPluginManifestPath,_e as freezeDoomConfigContext,U as getHarnessState,p as globalDoomConfigDirectory,m as globalDoomConfigPath,W as harnessRoot,te as initializeGlobalDoomConfig,ne as initializeRepositoryDoomConfig,re as isLocalPackageSpecifier,k as isRemotePluginSource,ie as layerEntries,ae as layerHookGroups,j as listDomainNames,je as listProfileNames,M as loadDomains,h as loadDoomConfig,g as loadDoomConfigAsync,_ as loadDoomConfigLayers,G as loadHarnessState,oe as loadMajorModesConfig,Te as loadPiConfig,Ee as loadPiConfigAsync,Me as loadProfiles,s as mergeDoomConfigs,c as parseAutocompactModeConfig,l as parseDoomConfig,u as parsePlanningModeConfig,De as piConfigPaths,A as pluginDirectoryForSource,R as projectHarnessEnvironment,ve as provideDoomConfigContext,ye as readDoomConfigContextGeneration,be as readDoomConfigPendingSelection,xe as readDoomConfigSelection,z as readHarnessState,Se as replaceDoomConfigContext,Ne as replaceProfileEnvironment,v as repositoryDoomConfigPath,Ce as requireDoomConfigContext,K as requireHarnessPaths,q as requireHarnessRoot,J as resetHarnessStore,se as resolveLayers,ce as resolvePackageConfigurations,y as resolvePlanningPlansDirectory,N as resolvePluginDirectories,P as resolvePluginEntries,Pe as resolveProfile,F as resolveSharedSkills,d as resolveVoiceConfig,Y as restoreHarnessStateSnapshot,b as setDoomConfigValue,X as snapshotHarnessState,we as supersedeDoomConfigTransition,x as unsetDoomConfigValue,Z as updateHarnessState,f as valueAtKeyPath,S as writeDoomConfigValues,e as writePrivateAtomicJson};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let e=require("yaml");const t=`auto`,n=[`modes`,`projectTrust`,`editor`,`voice`,`selection`],r=[`majorMode`,`domains`,`profile`],i=[`planning`],a=[`main`,`subagents`,`plansDirectory`],o=[`model`,`thinking`],s=[`command`],c=[`engine`,`language`,`recorder`,`adapters`,`autoCapture`],l=[`binary`,`device`],u=`whisper-cpp`,d=`openai-whisper`,f=`mlx-whisper`,p=[u,d,f],m=[`binary`,`model`],h=[`path`,`id`],g=[`model`,`startPhrases`,`stopPhrases`,`composeOpenPhrases`,`composeSendPhrases`,`composeCancelPhrases`,`utteranceIdleMs`,`composeUtteranceIdleMs`,`composeNudgeMs`,`transcriptionTimeoutMs`,`tts`],_=[`engine`,`voice`,`rate`],v=[`hey doom`,`doom prompt`],y=[`that's it`,`doom send`],b=[`doom cancel`,`scratch that`],x=/^[^/\s]+\/[^/\s]+(?:\/[^/\s]+)*$/u,S=/[\p{P}\p{S}]+/gu,C=[`off`,`minimal`,`low`,`medium`,`high`,`xhigh`,`max`],w=[t,u,d,f],T=[`macos-say`],E=new Set(C),D=new Set([`ask`,`always`,`never`]),O=new Set(w),k=new Set(T);function A(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function j(e,t,n,r){let i=Object.keys(e).filter(e=>!t.includes(e));if(i.length>0)throw Error(`Doom config at ${r} has unsupported ${n} field(s): ${i.join(`, `)}`)}function M(e,t,n){if(e!==void 0){if(typeof e!=`string`||e.trim().length===0)throw Error(`Doom config at ${n} requires ${t} to be a non-empty string`);return e.trim()}}function N(e){for(let t of e){let e=t.codePointAt(0);if(e!==void 0&&(e<=31||e===127))return!0}return!1}function ee(e,t,n,r){let i=M(e,t,n);if(i){if(i.length>r)throw Error(`Doom config at ${n} requires ${t} to be at most ${r} characters`);if(N(i))throw Error(`Doom config at ${n} does not allow control characters in ${t}`);return i}}function te(e,t){let n=`voice.autoCapture.model`,r=M(e,n,t);if(!r||!x.test(r))throw Error(`Doom config at ${t} requires ${n} in provider/model-id form`);return r}function P(e){return e.normalize(`NFKC`).toLocaleLowerCase(`en-US`).replace(S,` `).replace(/\s+/gu,` `).trim()}function F(e,t,n){if(e===void 0)return;if(!Array.isArray(e)||e.some(e=>typeof e!=`string`))throw Error(`Doom config at ${n} requires ${t} to be an array of strings`);if(e.length>16)throw Error(`Doom config at ${n} requires ${t} to contain at most 16 phrases`);let r=e.map(e=>e.trim()),i=new Set;for(let e of r){if(e.length===0)throw Error(`Doom config at ${n} requires ${t} to contain non-empty strings`);if(e.length>64)throw Error(`Doom config at ${n} requires ${t} phrases to be at most 64 characters`);if(N(e))throw Error(`Doom config at ${n} does not allow control characters in ${t}`);let r=P(e);if(!r)throw Error(`Doom config at ${n} requires ${t} to contain words`);if(i.has(r))throw Error(`Doom config at ${n} does not allow normalized duplicates in ${t}`);i.add(r)}return r}function I(e,t,n,r,i){if(e!==void 0){if(typeof e!=`number`||!Number.isInteger(e)||e<r||e>i)throw Error(`Doom config at ${n} requires ${t} to be an integer from ${r} to ${i}`);return e}}function L(e,t,n,r,i){let a=new Set((e??[]).map(P));if((t??[]).some(e=>a.has(P(e))))throw Error(`Doom config at ${i} does not allow a phrase in both ${n} and ${r}`)}function R(e,t){let n=`voice.autoCapture.tts`;if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);if(j(e,_,n,t),typeof e.engine!=`string`||!k.has(e.engine))throw Error(`Doom config at ${t} requires ${n}.engine to be one of: ${[...k].join(`, `)}`);let r=ee(e.voice,`${n}.voice`,t,64),i=e.rate;if(i!==void 0&&(typeof i!=`number`||!Number.isInteger(i)||i<80||i>500))throw Error(`Doom config at ${t} requires ${n}.rate to be an integer from 80 to 500`);return{engine:e.engine,...r?{voice:r}:{},...i===void 0?{}:{rate:i}}}function z(e,t){if(e===void 0)return;let n=`voice.autoCapture`;if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);j(e,g,n,t);let r=F(e.startPhrases,`${n}.startPhrases`,t),i=F(e.stopPhrases,`${n}.stopPhrases`,t),a=F(e.composeOpenPhrases,`${n}.composeOpenPhrases`,t),o=F(e.composeSendPhrases,`${n}.composeSendPhrases`,t),s=F(e.composeCancelPhrases,`${n}.composeCancelPhrases`,t),c=I(e.utteranceIdleMs,`${n}.utteranceIdleMs`,t,1500,1e4),l=I(e.composeUtteranceIdleMs,`${n}.composeUtteranceIdleMs`,t,800,3e3),u=e.composeNudgeMs===0?0:I(e.composeNudgeMs,`${n}.composeNudgeMs`,t,5e3,6e4),d=I(e.transcriptionTimeoutMs,`${n}.transcriptionTimeoutMs`,t,1e3,12e4);return L(r,i,`startPhrases`,`stopPhrases`,t),L(o,s,`composeSendPhrases`,`composeCancelPhrases`,t),L(a,o,`composeOpenPhrases`,`composeSendPhrases`,t),L(a,s,`composeOpenPhrases`,`composeCancelPhrases`,t),L(i,o,`stopPhrases`,`composeSendPhrases`,t),L(i,s,`stopPhrases`,`composeCancelPhrases`,t),{model:te(e.model,t),...r?{startPhrases:r}:{},...i?{stopPhrases:i}:{},...a?{composeOpenPhrases:a}:{},...o?{composeSendPhrases:o}:{},...s?{composeCancelPhrases:s}:{},...c===void 0?{}:{utteranceIdleMs:c},...l===void 0?{}:{composeUtteranceIdleMs:l},...u===void 0?{}:{composeNudgeMs:u},...d===void 0?{}:{transcriptionTimeoutMs:d},tts:R(e.tts,t)}}function B(e,t,n){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,o,t,n);let r=e.thinking;if(r!==void 0&&(typeof r!=`string`||!E.has(r)))throw Error(`Doom config at ${n} requires ${t}.thinking to be one of: ${[...E].join(`, `)}`);let i=M(e.model,`${t}.model`,n);return{...i?{model:i}:{},...r?{thinking:r}:{}}}function V(e,t,n=`modes.planning`){if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);return j(e,a,n,t),{main:B(e.main,`${n}.main`,t),subagents:B(e.subagents,`${n}.subagents`,t),plansDirectory:M(e.plansDirectory,`${n}.plansDirectory`,t)}}function H(e,t,n,r){if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,h,t,n);let i=M(e.path,`${t}.path`,n),a=M(e.id,`${t}.id`,n);if(!!i==!!a)throw Error(`Doom config at ${n} requires exactly one of ${t}.path or ${t}.id`);if(a&&!r)throw Error(`Doom config at ${n} does not support ${t}.id for whisper-cpp`);return{...i?{path:i}:{},...a?{id:a}:{}}}function U(e,t,n,r){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,m,t,n);let i=M(e.binary,`${t}.binary`,n);return{...i?{binary:i}:{},model:H(e.model,`${t}.model`,n,r)}}function W(e,t){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${t} requires voice to be an object`);j(e,c,`voice`,t);let n={};if(e.engine!==void 0){if(typeof e.engine!=`string`||!O.has(e.engine))throw Error(`Doom config at ${t} requires voice.engine to be one of: ${[...O].join(`, `)}`);n.engine=e.engine}let r=M(e.language,`voice.language`,t);if(r&&(n.language=r),e.recorder!==void 0){if(!A(e.recorder))throw Error(`Doom config at ${t} requires voice.recorder to be an object`);j(e.recorder,l,`voice.recorder`,t),n.recorder={};let r=M(e.recorder.binary,`voice.recorder.binary`,t),i=M(e.recorder.device,`voice.recorder.device`,t);r&&(n.recorder.binary=r),i&&(n.recorder.device=i)}if(e.adapters!==void 0){if(!A(e.adapters))throw Error(`Doom config at ${t} requires voice.adapters to be an object`);j(e.adapters,p,`voice.adapters`,t),n.adapters={[u]:U(e.adapters[u],`voice.adapters.${u}`,t,!1),[d]:U(e.adapters[d],`voice.adapters.${d}`,t,!0),[f]:U(e.adapters[f],`voice.adapters.${f}`,t,!0)}}let i=z(e.autoCapture,t);return i&&(n.autoCapture=i),n}function G(e,t){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${t} requires selection to be an object`);j(e,r,`selection`,t);let n=e.domains;if(n!==void 0&&(!Array.isArray(n)||n.some(e=>typeof e!=`string`)))throw Error(`Doom config at ${t} requires selection.domains to be an array of strings`);return{majorMode:M(e.majorMode,`selection.majorMode`,t),domains:n,profile:M(e.profile,`selection.profile`,t)}}function K(e,t){if(e!==void 0){if(!A(e))throw Error(`Doom config at ${t} requires editor to be an object`);return j(e,s,`editor`,t),{command:M(e.command,`editor.command`,t)}}}function q(t,r){let a;try{a=(0,e.parse)(t)??{}}catch(e){throw Error(`Could not parse Doom config at ${r}`,{cause:e})}if(!A(a))throw Error(`Doom config at ${r} must be a YAML object`);j(a,n,`root`,r);let o;if(a.modes!==void 0){if(!A(a.modes))throw Error(`Doom config at ${r} requires modes to be an object`);j(a.modes,i,`modes`,r),o=a.modes.planning===void 0?{}:{planning:V(a.modes.planning,r)}}let s=a.projectTrust===void 0?`ask`:a.projectTrust;if(typeof s!=`string`||!D.has(s))throw Error(`Doom config at ${r} projectTrust must be ask, always, or never`);return{modes:o,projectTrust:s,editor:K(a.editor,r),voice:W(a.voice,r),selection:G(a.selection,r)}}function J(e,t){return e||t?{...e,...t}:void 0}function Y(e,t){if(t.voice?.autoCapture)throw Error(`Repository Doom config voice.autoCapture is global-only; configure it in ~/.pi/.doom/config.yaml`);let n=e.modes?.planning,r=t.modes?.planning,i=n||r?{main:J(n?.main,r?.main),subagents:J(n?.subagents,r?.subagents),plansDirectory:r?.plansDirectory??n?.plansDirectory}:void 0,a=Z(e.voice,t.voice);return{modes:i?{planning:i}:void 0,projectTrust:t.projectTrust,editor:e.editor,voice:a,selection:e.selection||t.selection?{...e.selection,...t.selection}:void 0}}function X(e,t){if(!(!e&&!t))return{...e,...t,model:t?.model??e.model}}function Z(e,t){if(!(!e&&!t))return{...e,...t,recorder:e?.recorder||t?.recorder?{...e?.recorder,...t?.recorder}:void 0,adapters:e?.adapters||t?.adapters?{[u]:X(e?.adapters?.[u],t?.adapters?.[u]),[d]:X(e?.adapters?.[d],t?.adapters?.[d]),[f]:X(e?.adapters?.[f],t?.adapters?.[f])}:void 0,...e?.autoCapture?{autoCapture:e.autoCapture}:{}}}function ne(e){return{engine:e.engine??t,language:e.language??`auto`,recorder:{...e.recorder,device:e.recorder?.device??`none:default`},adapters:e.adapters??{},...e.autoCapture?{autoCapture:{...e.autoCapture,startPhrases:[...e.autoCapture.startPhrases??[]],stopPhrases:[...e.autoCapture.stopPhrases??[]],composeOpenPhrases:[...e.autoCapture.composeOpenPhrases??v],composeSendPhrases:[...e.autoCapture.composeSendPhrases??y],composeCancelPhrases:[...e.autoCapture.composeCancelPhrases??b],utteranceIdleMs:e.autoCapture.utteranceIdleMs??3e3,composeUtteranceIdleMs:e.autoCapture.composeUtteranceIdleMs??1200,composeNudgeMs:e.autoCapture.composeNudgeMs??1e4,transcriptionTimeoutMs:e.autoCapture.transcriptionTimeoutMs??15e3,tts:{...e.autoCapture.tts}}}:{}}}const re=[`editor`],ie=[`projectTrust`],ae=[[`voice`,`autoCapture`]];function oe(e,t){return t.length<=e.length&&t.every((t,n)=>e[n]===t)}function se(e){if(e.length===0)return`both`;if(ae.some(t=>oe(e,t)))return`global`;let t=e[0];return re.includes(t)?`global`:ie.includes(t)?`repository`:`both`}function ce(){return n}function Q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function $(e,t=[]){if(!Q(e))return t.length>0?[t.join(`.`)]:[];let n=Object.keys(e);return n.length===0?t.length>0?[t.join(`.`)]:[]:n.flatMap(n=>$(e[n],[...t,n]))}function le(e,t){let n=e;for(let e of t){if(!Q(n))return;n=n[e]}return n}exports.DOOM_PLANNING_THINKING_LEVELS=C,exports.DOOM_VOICE_ENGINES=w,exports.DOOM_VOICE_TTS_ENGINES=T,exports.configLeafKeys=$,exports.configRootKeys=ce,exports.configScopeOf=se,exports.mergeDoomConfigs=Y,exports.parseDoomConfig=q,exports.parsePlanningModeConfig=V,exports.resolveVoiceConfig=ne,exports.valueAtKeyPath=le;
|
|
1
|
+
let e=require("yaml");const t=`auto`,n=[`modes`,`projectTrust`,`editor`,`voice`,`selection`],r=[`majorMode`,`domains`,`profile`],i=[`planning`,`autocompact`],a=[`main`,`subagents`,`plansDirectory`],o=[`model`,`thinking`],s=[`enabled`,`model`,`thinking`,`thresholds`],c=[`pass1`,`pass2`,`pass3`],l=.05,u=.99,d=[`command`],f=[`engine`,`language`,`recorder`,`adapters`,`autoCapture`],ee=[`binary`,`device`],p=`whisper-cpp`,m=`openai-whisper`,h=`mlx-whisper`,g=[p,m,h],te=[`binary`,`model`],ne=[`path`,`id`],_=[`model`,`startPhrases`,`stopPhrases`,`composeOpenPhrases`,`composeSendPhrases`,`composeCancelPhrases`,`utteranceIdleMs`,`composeUtteranceIdleMs`,`composeNudgeMs`,`transcriptionTimeoutMs`,`tts`],v=[`engine`,`voice`,`rate`],y=[`hey doom`,`doom prompt`],b=[`that's it`,`doom send`],x=[`doom cancel`,`scratch that`],S=/^[^/\s]+\/[^/\s]+(?:\/[^/\s]+)*$/u,re=/[\p{P}\p{S}]+/gu,C=[`off`,`minimal`,`low`,`medium`,`high`,`xhigh`,`max`],w=[t,p,m,h],T=[`macos-say`],E=new Set(C),D=new Set([`ask`,`always`,`never`]),O=new Set(w),k=new Set(T);function A(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function j(e,t,n,r){let i=Object.keys(e).filter(e=>!t.includes(e));if(i.length>0)throw Error(`Doom config at ${r} has unsupported ${n} field(s): ${i.join(`, `)}`)}function M(e,t,n){if(e!==void 0){if(typeof e!=`string`||e.trim().length===0)throw Error(`Doom config at ${n} requires ${t} to be a non-empty string`);return e.trim()}}function N(e){for(let t of e){let e=t.codePointAt(0);if(e!==void 0&&(e<=31||e===127))return!0}return!1}function ie(e,t,n,r){let i=M(e,t,n);if(i){if(i.length>r)throw Error(`Doom config at ${n} requires ${t} to be at most ${r} characters`);if(N(i))throw Error(`Doom config at ${n} does not allow control characters in ${t}`);return i}}function ae(e,t){let n=`voice.autoCapture.model`,r=M(e,n,t);if(!r||!S.test(r))throw Error(`Doom config at ${t} requires ${n} in provider/model-id form`);return r}function P(e){return e.normalize(`NFKC`).toLocaleLowerCase(`en-US`).replace(re,` `).replace(/\s+/gu,` `).trim()}function F(e,t,n){if(e===void 0)return;if(!Array.isArray(e)||e.some(e=>typeof e!=`string`))throw Error(`Doom config at ${n} requires ${t} to be an array of strings`);if(e.length>16)throw Error(`Doom config at ${n} requires ${t} to contain at most 16 phrases`);let r=e.map(e=>e.trim()),i=new Set;for(let e of r){if(e.length===0)throw Error(`Doom config at ${n} requires ${t} to contain non-empty strings`);if(e.length>64)throw Error(`Doom config at ${n} requires ${t} phrases to be at most 64 characters`);if(N(e))throw Error(`Doom config at ${n} does not allow control characters in ${t}`);let r=P(e);if(!r)throw Error(`Doom config at ${n} requires ${t} to contain words`);if(i.has(r))throw Error(`Doom config at ${n} does not allow normalized duplicates in ${t}`);i.add(r)}return r}function I(e,t,n,r,i){if(e!==void 0){if(typeof e!=`number`||!Number.isInteger(e)||e<r||e>i)throw Error(`Doom config at ${n} requires ${t} to be an integer from ${r} to ${i}`);return e}}function L(e,t,n,r,i){let a=new Set((e??[]).map(P));if((t??[]).some(e=>a.has(P(e))))throw Error(`Doom config at ${i} does not allow a phrase in both ${n} and ${r}`)}function R(e,t){let n=`voice.autoCapture.tts`;if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);if(j(e,v,n,t),typeof e.engine!=`string`||!k.has(e.engine))throw Error(`Doom config at ${t} requires ${n}.engine to be one of: ${[...k].join(`, `)}`);let r=ie(e.voice,`${n}.voice`,t,64),i=e.rate;if(i!==void 0&&(typeof i!=`number`||!Number.isInteger(i)||i<80||i>500))throw Error(`Doom config at ${t} requires ${n}.rate to be an integer from 80 to 500`);return{engine:e.engine,...r?{voice:r}:{},...i===void 0?{}:{rate:i}}}function z(e,t){if(e===void 0)return;let n=`voice.autoCapture`;if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);j(e,_,n,t);let r=F(e.startPhrases,`${n}.startPhrases`,t),i=F(e.stopPhrases,`${n}.stopPhrases`,t),a=F(e.composeOpenPhrases,`${n}.composeOpenPhrases`,t),o=F(e.composeSendPhrases,`${n}.composeSendPhrases`,t),s=F(e.composeCancelPhrases,`${n}.composeCancelPhrases`,t),c=I(e.utteranceIdleMs,`${n}.utteranceIdleMs`,t,1500,1e4),l=I(e.composeUtteranceIdleMs,`${n}.composeUtteranceIdleMs`,t,800,3e3),u=e.composeNudgeMs===0?0:I(e.composeNudgeMs,`${n}.composeNudgeMs`,t,5e3,6e4),d=I(e.transcriptionTimeoutMs,`${n}.transcriptionTimeoutMs`,t,1e3,12e4);return L(r,i,`startPhrases`,`stopPhrases`,t),L(o,s,`composeSendPhrases`,`composeCancelPhrases`,t),L(a,o,`composeOpenPhrases`,`composeSendPhrases`,t),L(a,s,`composeOpenPhrases`,`composeCancelPhrases`,t),L(i,o,`stopPhrases`,`composeSendPhrases`,t),L(i,s,`stopPhrases`,`composeCancelPhrases`,t),{model:ae(e.model,t),...r?{startPhrases:r}:{},...i?{stopPhrases:i}:{},...a?{composeOpenPhrases:a}:{},...o?{composeSendPhrases:o}:{},...s?{composeCancelPhrases:s}:{},...c===void 0?{}:{utteranceIdleMs:c},...l===void 0?{}:{composeUtteranceIdleMs:l},...u===void 0?{}:{composeNudgeMs:u},...d===void 0?{}:{transcriptionTimeoutMs:d},tts:R(e.tts,t)}}function B(e,t,n){if(e!==void 0){if(typeof e!=`string`||!E.has(e))throw Error(`Doom config at ${n} requires ${t}.thinking to be one of: ${[...E].join(`, `)}`);return e}}function V(e,t,n){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,o,t,n);let r=B(e.thinking,t,n),i=M(e.model,`${t}.model`,n);return{...i?{model:i}:{},...r?{thinking:r}:{}}}function H(e,t,n){if(e!==void 0){if(typeof e==`boolean`)return e;if(e===`true`)return!0;if(e===`false`)return!1;throw Error(`Doom config at ${n} requires ${t} to be true or false`)}}function U(e,t,n){if(e===void 0)return;let r=typeof e==`string`?Number(e.trim()):e;if(typeof r!=`number`||!Number.isFinite(r)||r<l||r>u)throw Error(`Doom config at ${n} requires ${t} to be a number from ${l} to ${u}`);return r}function W(e,t,n){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,c,t,n);let r=U(e.pass1,`${t}.pass1`,n),i=U(e.pass2,`${t}.pass2`,n),a=U(e.pass3,`${t}.pass3`,n);return{...r===void 0?{}:{pass1:r},...i===void 0?{}:{pass2:i},...a===void 0?{}:{pass3:a}}}function G(e,t,n=`modes.autocompact`){if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);j(e,s,n,t);let r=H(e.enabled,`${n}.enabled`,t),i=M(e.model,`${n}.model`,t),a=B(e.thinking,n,t),o=W(e.thresholds,`${n}.thresholds`,t);return{...r===void 0?{}:{enabled:r},...i?{model:i}:{},...a?{thinking:a}:{},...o?{thresholds:o}:{}}}function K(e,t,n=`modes.planning`){if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);return j(e,a,n,t),{main:V(e.main,`${n}.main`,t),subagents:V(e.subagents,`${n}.subagents`,t),plansDirectory:M(e.plansDirectory,`${n}.plansDirectory`,t)}}function q(e,t,n,r){if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,ne,t,n);let i=M(e.path,`${t}.path`,n),a=M(e.id,`${t}.id`,n);if(!!i==!!a)throw Error(`Doom config at ${n} requires exactly one of ${t}.path or ${t}.id`);if(a&&!r)throw Error(`Doom config at ${n} does not support ${t}.id for whisper-cpp`);return{...i?{path:i}:{},...a?{id:a}:{}}}function J(e,t,n,r){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,te,t,n);let i=M(e.binary,`${t}.binary`,n);return{...i?{binary:i}:{},model:q(e.model,`${t}.model`,n,r)}}function oe(e,t){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${t} requires voice to be an object`);j(e,f,`voice`,t);let n={};if(e.engine!==void 0){if(typeof e.engine!=`string`||!O.has(e.engine))throw Error(`Doom config at ${t} requires voice.engine to be one of: ${[...O].join(`, `)}`);n.engine=e.engine}let r=M(e.language,`voice.language`,t);if(r&&(n.language=r),e.recorder!==void 0){if(!A(e.recorder))throw Error(`Doom config at ${t} requires voice.recorder to be an object`);j(e.recorder,ee,`voice.recorder`,t),n.recorder={};let r=M(e.recorder.binary,`voice.recorder.binary`,t),i=M(e.recorder.device,`voice.recorder.device`,t);r&&(n.recorder.binary=r),i&&(n.recorder.device=i)}if(e.adapters!==void 0){if(!A(e.adapters))throw Error(`Doom config at ${t} requires voice.adapters to be an object`);j(e.adapters,g,`voice.adapters`,t),n.adapters={[p]:J(e.adapters[p],`voice.adapters.${p}`,t,!1),[m]:J(e.adapters[m],`voice.adapters.${m}`,t,!0),[h]:J(e.adapters[h],`voice.adapters.${h}`,t,!0)}}let i=z(e.autoCapture,t);return i&&(n.autoCapture=i),n}function se(e,t){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${t} requires selection to be an object`);j(e,r,`selection`,t);let n=e.domains;if(n!==void 0&&(!Array.isArray(n)||n.some(e=>typeof e!=`string`)))throw Error(`Doom config at ${t} requires selection.domains to be an array of strings`);return{majorMode:M(e.majorMode,`selection.majorMode`,t),domains:n,profile:M(e.profile,`selection.profile`,t)}}function ce(e,t){if(e!==void 0){if(!A(e))throw Error(`Doom config at ${t} requires editor to be an object`);return j(e,d,`editor`,t),{command:M(e.command,`editor.command`,t)}}}function le(t,r){let a;try{a=(0,e.parse)(t)??{}}catch(e){throw Error(`Could not parse Doom config at ${r}`,{cause:e})}if(!A(a))throw Error(`Doom config at ${r} must be a YAML object`);j(a,n,`root`,r);let o;if(a.modes!==void 0){if(!A(a.modes))throw Error(`Doom config at ${r} requires modes to be an object`);j(a.modes,i,`modes`,r),o={...a.modes.planning===void 0?{}:{planning:K(a.modes.planning,r)},...a.modes.autocompact===void 0?{}:{autocompact:G(a.modes.autocompact,r)}}}let s=a.projectTrust===void 0?`ask`:a.projectTrust;if(typeof s!=`string`||!D.has(s))throw Error(`Doom config at ${r} projectTrust must be ask, always, or never`);return{modes:o,projectTrust:s,editor:ce(a.editor,r),voice:oe(a.voice,r),selection:se(a.selection,r)}}function Y(e,t){return e||t?{...e,...t}:void 0}function ue(e,t){if(t.voice?.autoCapture)throw Error(`Repository Doom config voice.autoCapture is global-only; configure it in ~/.pi/.doom/config.yaml`);let n=e.modes?.planning,r=t.modes?.planning,i=n||r?{main:Y(n?.main,r?.main),subagents:Y(n?.subagents,r?.subagents),plansDirectory:r?.plansDirectory??n?.plansDirectory}:void 0,a=e.modes?.autocompact,o=t.modes?.autocompact,s=a||o?{...a,...o,...a?.thresholds||o?.thresholds?{thresholds:{...a?.thresholds,...o?.thresholds}}:{}}:void 0,c=de(e.voice,t.voice);return{modes:i||s?{...i?{planning:i}:{},...s?{autocompact:s}:{}}:void 0,projectTrust:t.projectTrust,editor:e.editor,voice:c,selection:e.selection||t.selection?{...e.selection,...t.selection}:void 0}}function X(e,t){if(!(!e&&!t))return{...e,...t,model:t?.model??e.model}}function de(e,t){if(!(!e&&!t))return{...e,...t,recorder:e?.recorder||t?.recorder?{...e?.recorder,...t?.recorder}:void 0,adapters:e?.adapters||t?.adapters?{[p]:X(e?.adapters?.[p],t?.adapters?.[p]),[m]:X(e?.adapters?.[m],t?.adapters?.[m]),[h]:X(e?.adapters?.[h],t?.adapters?.[h])}:void 0,...e?.autoCapture?{autoCapture:e.autoCapture}:{}}}function fe(e){return{engine:e.engine??t,language:e.language??`auto`,recorder:{...e.recorder,device:e.recorder?.device??`none:default`},adapters:e.adapters??{},...e.autoCapture?{autoCapture:{...e.autoCapture,startPhrases:[...e.autoCapture.startPhrases??[]],stopPhrases:[...e.autoCapture.stopPhrases??[]],composeOpenPhrases:[...e.autoCapture.composeOpenPhrases??y],composeSendPhrases:[...e.autoCapture.composeSendPhrases??b],composeCancelPhrases:[...e.autoCapture.composeCancelPhrases??x],utteranceIdleMs:e.autoCapture.utteranceIdleMs??3e3,composeUtteranceIdleMs:e.autoCapture.composeUtteranceIdleMs??1200,composeNudgeMs:e.autoCapture.composeNudgeMs??1e4,transcriptionTimeoutMs:e.autoCapture.transcriptionTimeoutMs??15e3,tts:{...e.autoCapture.tts}}}:{}}}const pe=[`editor`],me=[`projectTrust`],Z=[[`voice`,`autoCapture`]];function he(e,t){return t.length<=e.length&&t.every((t,n)=>e[n]===t)}function ge(e){if(e.length===0)return`both`;if(Z.some(t=>he(e,t)))return`global`;let t=e[0];return pe.includes(t)?`global`:me.includes(t)?`repository`:`both`}function _e(){return n}function Q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function $(e,t=[]){if(!Q(e))return t.length>0?[t.join(`.`)]:[];let n=Object.keys(e);return n.length===0?t.length>0?[t.join(`.`)]:[]:n.flatMap(n=>$(e[n],[...t,n]))}function ve(e,t){let n=e;for(let e of t){if(!Q(n))return;n=n[e]}return n}exports.DOOM_PLANNING_THINKING_LEVELS=C,exports.DOOM_VOICE_ENGINES=w,exports.DOOM_VOICE_TTS_ENGINES=T,exports.configLeafKeys=$,exports.configRootKeys=_e,exports.configScopeOf=ge,exports.mergeDoomConfigs=ue,exports.parseAutocompactModeConfig=G,exports.parseDoomConfig=le,exports.parsePlanningModeConfig=K,exports.resolveVoiceConfig=fe,exports.valueAtKeyPath=ve;
|
|
2
2
|
//# sourceMappingURL=configPolicy.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configPolicy.cjs","names":["parseYaml"],"sources":["../../src/services/configPolicy.ts"],"sourcesContent":["import { parse as parseYaml } from 'yaml';\nimport type {\n DoomConfig,\n DoomSelectionConfig,\n EditorConfig,\n PlanningAgentConfig,\n PlanningModeConfig,\n PlanningThinkingLevel,\n ProjectTrust,\n ResolvedVoiceConfig,\n VoiceAdapterConfig,\n VoiceAutoCaptureConfig,\n VoiceConfig,\n VoiceEngine,\n VoiceModelConfig,\n VoiceTtsConfig,\n VoiceTtsEngine,\n} from '../types/config.ts';\n\nconst DEFAULT_PROJECT_TRUST: ProjectTrust = 'ask';\nconst DEFAULT_VOICE_ENGINE: VoiceEngine = 'auto';\nconst DEFAULT_VOICE_LANGUAGE = 'auto';\nconst DEFAULT_RECORDER_DEVICE = 'none:default';\nconst ROOT_KEYS = ['modes', 'projectTrust', 'editor', 'voice', 'selection'] as const;\nconst SELECTION_KEYS = ['majorMode', 'domains', 'profile'] as const;\nconst MODE_KEYS = ['planning'] as const;\nconst PLANNING_KEYS = ['main', 'subagents', 'plansDirectory'] as const;\nconst AGENT_KEYS = ['model', 'thinking'] as const;\nconst EDITOR_KEYS = ['command'] as const;\nconst VOICE_KEYS = ['engine', 'language', 'recorder', 'adapters', 'autoCapture'] as const;\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 = 15_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_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\nconst THINKING_VALUES = new Set<PlanningThinkingLevel>(DOOM_PLANNING_THINKING_LEVELS);\nconst TRUST_VALUES = new Set<ProjectTrust>(['ask', 'always', 'never']);\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}\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)\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 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 = value.thinking;\n if (\n thinking !== undefined &&\n (typeof thinking !== 'string' || !THINKING_VALUES.has(thinking as PlanningThinkingLevel))\n ) {\n throw new Error(\n `Doom config at ${filePath} requires ${location}.thinking to be one of: ${[...THINKING_VALUES].join(', ')}`,\n );\n }\n const model = optionalString(value.model, `${location}.model`, filePath);\n return { ...(model ? { model } : {}), ...(thinking ? { thinking: thinking as PlanningThinkingLevel } : {}) };\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.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 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}\nexport function parseDoomConfig(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 ? {} : { planning: parsePlanningModeConfig(parsed.modes.planning, filePath) };\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 projectTrust: trust as ProjectTrust,\n editor: parseEditor(parsed.editor, filePath),\n voice: parseVoice(parsed.voice, filePath),\n selection: parseSelection(parsed.selection, 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?.autoCapture)\n throw new Error('Repository Doom config voice.autoCapture is global-only; configure it in ~/.pi/.doom/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 voice = mergeVoice(globalConfig.voice, repositoryConfig.voice);\n return {\n modes: planning ? { planning } : undefined,\n projectTrust: repositoryConfig.projectTrust,\n editor: globalConfig.editor,\n voice,\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 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}\nexport function resolveVoiceConfig(config: VoiceConfig): ResolvedVoiceConfig {\n return {\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: { ...config.autoCapture.tts },\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 a repository `voice.autoCapture` throws outright.\n * A caller holding a key path has no way to ask. Without an answer, a settings\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[] = ['editor'];\nconst REPOSITORY_ONLY_ROOTS: readonly string[] = ['projectTrust'];\n/** The one nested exception; a repository declaration of it throws in the merge. */\nconst GLOBAL_ONLY_PATHS: readonly (readonly string[])[] = [['voice', 'autoCapture']];\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 * five 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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"}
|
|
1
|
+
{"version":3,"file":"configPolicy.cjs","names":["parseYaml"],"sources":["../../src/services/configPolicy.ts"],"sourcesContent":["import { parse as parseYaml } from 'yaml';\nimport type {\n AutocompactModeConfig,\n AutocompactThresholdConfig,\n DoomConfig,\n DoomSelectionConfig,\n EditorConfig,\n PlanningAgentConfig,\n PlanningModeConfig,\n PlanningThinkingLevel,\n ProjectTrust,\n ResolvedVoiceConfig,\n VoiceAdapterConfig,\n VoiceAutoCaptureConfig,\n VoiceConfig,\n VoiceEngine,\n VoiceModelConfig,\n VoiceTtsConfig,\n VoiceTtsEngine,\n} from '../types/config.ts';\n\nconst DEFAULT_PROJECT_TRUST: ProjectTrust = 'ask';\nconst DEFAULT_VOICE_ENGINE: VoiceEngine = 'auto';\nconst DEFAULT_VOICE_LANGUAGE = 'auto';\nconst DEFAULT_RECORDER_DEVICE = 'none:default';\nconst ROOT_KEYS = ['modes', 'projectTrust', 'editor', 'voice', 'selection'] 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'] as const;\nconst AUTOCOMPACT_THRESHOLD_KEYS = ['pass1', 'pass2', 'pass3'] 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;\nconst EDITOR_KEYS = ['command'] as const;\nconst VOICE_KEYS = ['engine', 'language', 'recorder', 'adapters', 'autoCapture'] as const;\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 = 15_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_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\nconst THINKING_VALUES = new Set<PlanningThinkingLevel>(DOOM_PLANNING_THINKING_LEVELS);\nconst TRUST_VALUES = new Set<ProjectTrust>(['ask', 'always', 'never']);\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}\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)\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}\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 return {\n ...(enabled === undefined ? {} : { enabled }),\n ...(model ? { model } : {}),\n ...(thinking ? { thinking } : {}),\n ...(thresholds ? { thresholds } : {}),\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.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 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}\nexport function parseDoomConfig(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 projectTrust: trust as ProjectTrust,\n editor: parseEditor(parsed.editor, filePath),\n voice: parseVoice(parsed.voice, filePath),\n selection: parseSelection(parsed.selection, 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?.autoCapture)\n throw new Error('Repository Doom config voice.autoCapture is global-only; configure it in ~/.pi/.doom/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.\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 projectTrust: repositoryConfig.projectTrust,\n editor: globalConfig.editor,\n voice,\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 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}\nexport function resolveVoiceConfig(config: VoiceConfig): ResolvedVoiceConfig {\n return {\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: { ...config.autoCapture.tts },\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 a repository `voice.autoCapture` throws outright.\n * A caller holding a key path has no way to ask. Without an answer, a settings\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[] = ['editor'];\nconst REPOSITORY_ONLY_ROOTS: readonly string[] = ['projectTrust'];\n/** The one nested exception; a repository declaration of it throws in the merge. */\nconst GLOBAL_ONLY_PATHS: readonly (readonly string[])[] = [['voice', 'autoCapture']];\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 * five 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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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DoomConfig, PlanningModeConfig, ResolvedVoiceConfig, VoiceConfig } from "../types/config.cjs";
|
|
1
|
+
import { AutocompactModeConfig, DoomConfig, PlanningModeConfig, ResolvedVoiceConfig, VoiceConfig } from "../types/config.cjs";
|
|
2
2
|
//#region src/services/configPolicy.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* The accepted values, in the order a picker should offer them.
|
|
@@ -10,6 +10,7 @@ import { DoomConfig, PlanningModeConfig, ResolvedVoiceConfig, VoiceConfig } from
|
|
|
10
10
|
declare const DOOM_PLANNING_THINKING_LEVELS: readonly ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
11
11
|
declare const DOOM_VOICE_ENGINES: readonly ["auto", "whisper-cpp", "openai-whisper", "mlx-whisper"];
|
|
12
12
|
declare const DOOM_VOICE_TTS_ENGINES: readonly ["macos-say"];
|
|
13
|
+
declare function parseAutocompactModeConfig(value: unknown, filePath: string, location?: string): AutocompactModeConfig;
|
|
13
14
|
declare function parsePlanningModeConfig(value: unknown, filePath: string, location?: string): PlanningModeConfig;
|
|
14
15
|
declare function parseDoomConfig(content: string, filePath: string): DoomConfig;
|
|
15
16
|
declare function mergeDoomConfigs(globalConfig: DoomConfig, repositoryConfig: DoomConfig): DoomConfig;
|
|
@@ -52,5 +53,5 @@ declare function configLeafKeys(value: unknown, prefix?: readonly string[]): str
|
|
|
52
53
|
/** The value a key path points at, or undefined when any step is missing. */
|
|
53
54
|
declare function valueAtKeyPath(value: unknown, keyPath: readonly string[]): unknown;
|
|
54
55
|
//#endregion
|
|
55
|
-
export { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath };
|
|
56
|
+
export { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath };
|
|
56
57
|
//# sourceMappingURL=configPolicy.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configPolicy.d.cts","names":[],"sources":["../../src/services/configPolicy.ts"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"configPolicy.d.cts","names":[],"sources":["../../src/services/configPolicy.ts"],"mappings":";;;;;;;;;cA2Ga;cACA;cAMA;iBA8RG,2BACd,gBACA,kBACA,oBACC;iBAca,wBACd,gBACA,kBACA,oBACC;iBAyGa,gBAAgB,iBAAiB,mBAAmB;iBAuCpD,iBAAiB,cAAc,YAAY,kBAAkB,aAAa;iBA+E1E,mBAAmB,QAAQ,cAAc;;;;;;;;;;;;;;KAyC7C;;;;;;iBAiBI,cAAc,6BAA6B;;iBAU3C;;;;;;;;;;;;;iBAsBA,eAAe,gBAAgB;;iBAQ/B,eAAe,gBAAgB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DoomConfig, PlanningModeConfig, ResolvedVoiceConfig, VoiceConfig } from "../types/config.mjs";
|
|
1
|
+
import { AutocompactModeConfig, DoomConfig, PlanningModeConfig, ResolvedVoiceConfig, VoiceConfig } from "../types/config.mjs";
|
|
2
2
|
//#region src/services/configPolicy.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* The accepted values, in the order a picker should offer them.
|
|
@@ -10,6 +10,7 @@ import { DoomConfig, PlanningModeConfig, ResolvedVoiceConfig, VoiceConfig } from
|
|
|
10
10
|
declare const DOOM_PLANNING_THINKING_LEVELS: readonly ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
11
11
|
declare const DOOM_VOICE_ENGINES: readonly ["auto", "whisper-cpp", "openai-whisper", "mlx-whisper"];
|
|
12
12
|
declare const DOOM_VOICE_TTS_ENGINES: readonly ["macos-say"];
|
|
13
|
+
declare function parseAutocompactModeConfig(value: unknown, filePath: string, location?: string): AutocompactModeConfig;
|
|
13
14
|
declare function parsePlanningModeConfig(value: unknown, filePath: string, location?: string): PlanningModeConfig;
|
|
14
15
|
declare function parseDoomConfig(content: string, filePath: string): DoomConfig;
|
|
15
16
|
declare function mergeDoomConfigs(globalConfig: DoomConfig, repositoryConfig: DoomConfig): DoomConfig;
|
|
@@ -52,5 +53,5 @@ declare function configLeafKeys(value: unknown, prefix?: readonly string[]): str
|
|
|
52
53
|
/** The value a key path points at, or undefined when any step is missing. */
|
|
53
54
|
declare function valueAtKeyPath(value: unknown, keyPath: readonly string[]): unknown;
|
|
54
55
|
//#endregion
|
|
55
|
-
export { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath };
|
|
56
|
+
export { ConfigKeyScope, DOOM_PLANNING_THINKING_LEVELS, DOOM_VOICE_ENGINES, DOOM_VOICE_TTS_ENGINES, configLeafKeys, configRootKeys, configScopeOf, mergeDoomConfigs, parseAutocompactModeConfig, parseDoomConfig, parsePlanningModeConfig, resolveVoiceConfig, valueAtKeyPath };
|
|
56
57
|
//# sourceMappingURL=configPolicy.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configPolicy.d.mts","names":[],"sources":["../../src/services/configPolicy.ts"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"configPolicy.d.mts","names":[],"sources":["../../src/services/configPolicy.ts"],"mappings":";;;;;;;;;cA2Ga;cACA;cAMA;iBA8RG,2BACd,gBACA,kBACA,oBACC;iBAca,wBACd,gBACA,kBACA,oBACC;iBAyGa,gBAAgB,iBAAiB,mBAAmB;iBAuCpD,iBAAiB,cAAc,YAAY,kBAAkB,aAAa;iBA+E1E,mBAAmB,QAAQ,cAAc;;;;;;;;;;;;;;KAyC7C;;;;;;iBAiBI,cAAc,6BAA6B;;iBAU3C;;;;;;;;;;;;;iBAsBA,eAAe,gBAAgB;;iBAQ/B,eAAe,gBAAgB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{parse as e}from"yaml";const t=`auto`,n=[`modes`,`projectTrust`,`editor`,`voice`,`selection`],r=[`majorMode`,`domains`,`profile`],i=[`planning`],a=[`main`,`subagents`,`plansDirectory`],o=[`model`,`thinking`],s=[`command`],c=[`engine`,`language`,`recorder`,`adapters`,`autoCapture`],l=[`binary`,`device`],u=`whisper-cpp`,d=`openai-whisper`,f=`mlx-whisper`,p=[u,d,f],m=[`binary`,`model`],h=[`path`,`id`],g=[`model`,`startPhrases`,`stopPhrases`,`composeOpenPhrases`,`composeSendPhrases`,`composeCancelPhrases`,`utteranceIdleMs`,`composeUtteranceIdleMs`,`composeNudgeMs`,`transcriptionTimeoutMs`,`tts`],_=[`engine`,`voice`,`rate`],v=[`hey doom`,`doom prompt`],y=[`that's it`,`doom send`],b=[`doom cancel`,`scratch that`],x=/^[^/\s]+\/[^/\s]+(?:\/[^/\s]+)*$/u,S=/[\p{P}\p{S}]+/gu,C=[`off`,`minimal`,`low`,`medium`,`high`,`xhigh`,`max`],w=[t,u,d,f],T=[`macos-say`],E=new Set(C),D=new Set([`ask`,`always`,`never`]),O=new Set(w),k=new Set(T);function A(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function j(e,t,n,r){let i=Object.keys(e).filter(e=>!t.includes(e));if(i.length>0)throw Error(`Doom config at ${r} has unsupported ${n} field(s): ${i.join(`, `)}`)}function M(e,t,n){if(e!==void 0){if(typeof e!=`string`||e.trim().length===0)throw Error(`Doom config at ${n} requires ${t} to be a non-empty string`);return e.trim()}}function N(e){for(let t of e){let e=t.codePointAt(0);if(e!==void 0&&(e<=31||e===127))return!0}return!1}function ee(e,t,n,r){let i=M(e,t,n);if(i){if(i.length>r)throw Error(`Doom config at ${n} requires ${t} to be at most ${r} characters`);if(N(i))throw Error(`Doom config at ${n} does not allow control characters in ${t}`);return i}}function te(e,t){let n=`voice.autoCapture.model`,r=M(e,n,t);if(!r||!x.test(r))throw Error(`Doom config at ${t} requires ${n} in provider/model-id form`);return r}function P(e){return e.normalize(`NFKC`).toLocaleLowerCase(`en-US`).replace(S,` `).replace(/\s+/gu,` `).trim()}function F(e,t,n){if(e===void 0)return;if(!Array.isArray(e)||e.some(e=>typeof e!=`string`))throw Error(`Doom config at ${n} requires ${t} to be an array of strings`);if(e.length>16)throw Error(`Doom config at ${n} requires ${t} to contain at most 16 phrases`);let r=e.map(e=>e.trim()),i=new Set;for(let e of r){if(e.length===0)throw Error(`Doom config at ${n} requires ${t} to contain non-empty strings`);if(e.length>64)throw Error(`Doom config at ${n} requires ${t} phrases to be at most 64 characters`);if(N(e))throw Error(`Doom config at ${n} does not allow control characters in ${t}`);let r=P(e);if(!r)throw Error(`Doom config at ${n} requires ${t} to contain words`);if(i.has(r))throw Error(`Doom config at ${n} does not allow normalized duplicates in ${t}`);i.add(r)}return r}function I(e,t,n,r,i){if(e!==void 0){if(typeof e!=`number`||!Number.isInteger(e)||e<r||e>i)throw Error(`Doom config at ${n} requires ${t} to be an integer from ${r} to ${i}`);return e}}function L(e,t,n,r,i){let a=new Set((e??[]).map(P));if((t??[]).some(e=>a.has(P(e))))throw Error(`Doom config at ${i} does not allow a phrase in both ${n} and ${r}`)}function R(e,t){let n=`voice.autoCapture.tts`;if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);if(j(e,_,n,t),typeof e.engine!=`string`||!k.has(e.engine))throw Error(`Doom config at ${t} requires ${n}.engine to be one of: ${[...k].join(`, `)}`);let r=ee(e.voice,`${n}.voice`,t,64),i=e.rate;if(i!==void 0&&(typeof i!=`number`||!Number.isInteger(i)||i<80||i>500))throw Error(`Doom config at ${t} requires ${n}.rate to be an integer from 80 to 500`);return{engine:e.engine,...r?{voice:r}:{},...i===void 0?{}:{rate:i}}}function z(e,t){if(e===void 0)return;let n=`voice.autoCapture`;if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);j(e,g,n,t);let r=F(e.startPhrases,`${n}.startPhrases`,t),i=F(e.stopPhrases,`${n}.stopPhrases`,t),a=F(e.composeOpenPhrases,`${n}.composeOpenPhrases`,t),o=F(e.composeSendPhrases,`${n}.composeSendPhrases`,t),s=F(e.composeCancelPhrases,`${n}.composeCancelPhrases`,t),c=I(e.utteranceIdleMs,`${n}.utteranceIdleMs`,t,1500,1e4),l=I(e.composeUtteranceIdleMs,`${n}.composeUtteranceIdleMs`,t,800,3e3),u=e.composeNudgeMs===0?0:I(e.composeNudgeMs,`${n}.composeNudgeMs`,t,5e3,6e4),d=I(e.transcriptionTimeoutMs,`${n}.transcriptionTimeoutMs`,t,1e3,12e4);return L(r,i,`startPhrases`,`stopPhrases`,t),L(o,s,`composeSendPhrases`,`composeCancelPhrases`,t),L(a,o,`composeOpenPhrases`,`composeSendPhrases`,t),L(a,s,`composeOpenPhrases`,`composeCancelPhrases`,t),L(i,o,`stopPhrases`,`composeSendPhrases`,t),L(i,s,`stopPhrases`,`composeCancelPhrases`,t),{model:te(e.model,t),...r?{startPhrases:r}:{},...i?{stopPhrases:i}:{},...a?{composeOpenPhrases:a}:{},...o?{composeSendPhrases:o}:{},...s?{composeCancelPhrases:s}:{},...c===void 0?{}:{utteranceIdleMs:c},...l===void 0?{}:{composeUtteranceIdleMs:l},...u===void 0?{}:{composeNudgeMs:u},...d===void 0?{}:{transcriptionTimeoutMs:d},tts:R(e.tts,t)}}function B(e,t,n){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,o,t,n);let r=e.thinking;if(r!==void 0&&(typeof r!=`string`||!E.has(r)))throw Error(`Doom config at ${n} requires ${t}.thinking to be one of: ${[...E].join(`, `)}`);let i=M(e.model,`${t}.model`,n);return{...i?{model:i}:{},...r?{thinking:r}:{}}}function V(e,t,n=`modes.planning`){if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);return j(e,a,n,t),{main:B(e.main,`${n}.main`,t),subagents:B(e.subagents,`${n}.subagents`,t),plansDirectory:M(e.plansDirectory,`${n}.plansDirectory`,t)}}function H(e,t,n,r){if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,h,t,n);let i=M(e.path,`${t}.path`,n),a=M(e.id,`${t}.id`,n);if(!!i==!!a)throw Error(`Doom config at ${n} requires exactly one of ${t}.path or ${t}.id`);if(a&&!r)throw Error(`Doom config at ${n} does not support ${t}.id for whisper-cpp`);return{...i?{path:i}:{},...a?{id:a}:{}}}function U(e,t,n,r){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,m,t,n);let i=M(e.binary,`${t}.binary`,n);return{...i?{binary:i}:{},model:H(e.model,`${t}.model`,n,r)}}function W(e,t){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${t} requires voice to be an object`);j(e,c,`voice`,t);let n={};if(e.engine!==void 0){if(typeof e.engine!=`string`||!O.has(e.engine))throw Error(`Doom config at ${t} requires voice.engine to be one of: ${[...O].join(`, `)}`);n.engine=e.engine}let r=M(e.language,`voice.language`,t);if(r&&(n.language=r),e.recorder!==void 0){if(!A(e.recorder))throw Error(`Doom config at ${t} requires voice.recorder to be an object`);j(e.recorder,l,`voice.recorder`,t),n.recorder={};let r=M(e.recorder.binary,`voice.recorder.binary`,t),i=M(e.recorder.device,`voice.recorder.device`,t);r&&(n.recorder.binary=r),i&&(n.recorder.device=i)}if(e.adapters!==void 0){if(!A(e.adapters))throw Error(`Doom config at ${t} requires voice.adapters to be an object`);j(e.adapters,p,`voice.adapters`,t),n.adapters={[u]:U(e.adapters[u],`voice.adapters.${u}`,t,!1),[d]:U(e.adapters[d],`voice.adapters.${d}`,t,!0),[f]:U(e.adapters[f],`voice.adapters.${f}`,t,!0)}}let i=z(e.autoCapture,t);return i&&(n.autoCapture=i),n}function G(e,t){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${t} requires selection to be an object`);j(e,r,`selection`,t);let n=e.domains;if(n!==void 0&&(!Array.isArray(n)||n.some(e=>typeof e!=`string`)))throw Error(`Doom config at ${t} requires selection.domains to be an array of strings`);return{majorMode:M(e.majorMode,`selection.majorMode`,t),domains:n,profile:M(e.profile,`selection.profile`,t)}}function K(e,t){if(e!==void 0){if(!A(e))throw Error(`Doom config at ${t} requires editor to be an object`);return j(e,s,`editor`,t),{command:M(e.command,`editor.command`,t)}}}function q(t,r){let a;try{a=e(t)??{}}catch(e){throw Error(`Could not parse Doom config at ${r}`,{cause:e})}if(!A(a))throw Error(`Doom config at ${r} must be a YAML object`);j(a,n,`root`,r);let o;if(a.modes!==void 0){if(!A(a.modes))throw Error(`Doom config at ${r} requires modes to be an object`);j(a.modes,i,`modes`,r),o=a.modes.planning===void 0?{}:{planning:V(a.modes.planning,r)}}let s=a.projectTrust===void 0?`ask`:a.projectTrust;if(typeof s!=`string`||!D.has(s))throw Error(`Doom config at ${r} projectTrust must be ask, always, or never`);return{modes:o,projectTrust:s,editor:K(a.editor,r),voice:W(a.voice,r),selection:G(a.selection,r)}}function J(e,t){return e||t?{...e,...t}:void 0}function Y(e,t){if(t.voice?.autoCapture)throw Error(`Repository Doom config voice.autoCapture is global-only; configure it in ~/.pi/.doom/config.yaml`);let n=e.modes?.planning,r=t.modes?.planning,i=n||r?{main:J(n?.main,r?.main),subagents:J(n?.subagents,r?.subagents),plansDirectory:r?.plansDirectory??n?.plansDirectory}:void 0,a=Z(e.voice,t.voice);return{modes:i?{planning:i}:void 0,projectTrust:t.projectTrust,editor:e.editor,voice:a,selection:e.selection||t.selection?{...e.selection,...t.selection}:void 0}}function X(e,t){if(!(!e&&!t))return{...e,...t,model:t?.model??e.model}}function Z(e,t){if(!(!e&&!t))return{...e,...t,recorder:e?.recorder||t?.recorder?{...e?.recorder,...t?.recorder}:void 0,adapters:e?.adapters||t?.adapters?{[u]:X(e?.adapters?.[u],t?.adapters?.[u]),[d]:X(e?.adapters?.[d],t?.adapters?.[d]),[f]:X(e?.adapters?.[f],t?.adapters?.[f])}:void 0,...e?.autoCapture?{autoCapture:e.autoCapture}:{}}}function ne(e){return{engine:e.engine??t,language:e.language??`auto`,recorder:{...e.recorder,device:e.recorder?.device??`none:default`},adapters:e.adapters??{},...e.autoCapture?{autoCapture:{...e.autoCapture,startPhrases:[...e.autoCapture.startPhrases??[]],stopPhrases:[...e.autoCapture.stopPhrases??[]],composeOpenPhrases:[...e.autoCapture.composeOpenPhrases??v],composeSendPhrases:[...e.autoCapture.composeSendPhrases??y],composeCancelPhrases:[...e.autoCapture.composeCancelPhrases??b],utteranceIdleMs:e.autoCapture.utteranceIdleMs??3e3,composeUtteranceIdleMs:e.autoCapture.composeUtteranceIdleMs??1200,composeNudgeMs:e.autoCapture.composeNudgeMs??1e4,transcriptionTimeoutMs:e.autoCapture.transcriptionTimeoutMs??15e3,tts:{...e.autoCapture.tts}}}:{}}}const re=[`editor`],ie=[`projectTrust`],ae=[[`voice`,`autoCapture`]];function oe(e,t){return t.length<=e.length&&t.every((t,n)=>e[n]===t)}function se(e){if(e.length===0)return`both`;if(ae.some(t=>oe(e,t)))return`global`;let t=e[0];return re.includes(t)?`global`:ie.includes(t)?`repository`:`both`}function ce(){return n}function Q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function $(e,t=[]){if(!Q(e))return t.length>0?[t.join(`.`)]:[];let n=Object.keys(e);return n.length===0?t.length>0?[t.join(`.`)]:[]:n.flatMap(n=>$(e[n],[...t,n]))}function le(e,t){let n=e;for(let e of t){if(!Q(n))return;n=n[e]}return n}export{C as DOOM_PLANNING_THINKING_LEVELS,w as DOOM_VOICE_ENGINES,T as DOOM_VOICE_TTS_ENGINES,$ as configLeafKeys,ce as configRootKeys,se as configScopeOf,Y as mergeDoomConfigs,q as parseDoomConfig,V as parsePlanningModeConfig,ne as resolveVoiceConfig,le as valueAtKeyPath};
|
|
1
|
+
import{parse as e}from"yaml";const t=`auto`,n=[`modes`,`projectTrust`,`editor`,`voice`,`selection`],r=[`majorMode`,`domains`,`profile`],i=[`planning`,`autocompact`],a=[`main`,`subagents`,`plansDirectory`],o=[`model`,`thinking`],s=[`enabled`,`model`,`thinking`,`thresholds`],c=[`pass1`,`pass2`,`pass3`],l=.05,u=.99,d=[`command`],f=[`engine`,`language`,`recorder`,`adapters`,`autoCapture`],ee=[`binary`,`device`],p=`whisper-cpp`,m=`openai-whisper`,h=`mlx-whisper`,g=[p,m,h],te=[`binary`,`model`],ne=[`path`,`id`],_=[`model`,`startPhrases`,`stopPhrases`,`composeOpenPhrases`,`composeSendPhrases`,`composeCancelPhrases`,`utteranceIdleMs`,`composeUtteranceIdleMs`,`composeNudgeMs`,`transcriptionTimeoutMs`,`tts`],v=[`engine`,`voice`,`rate`],y=[`hey doom`,`doom prompt`],b=[`that's it`,`doom send`],x=[`doom cancel`,`scratch that`],S=/^[^/\s]+\/[^/\s]+(?:\/[^/\s]+)*$/u,re=/[\p{P}\p{S}]+/gu,C=[`off`,`minimal`,`low`,`medium`,`high`,`xhigh`,`max`],w=[t,p,m,h],T=[`macos-say`],E=new Set(C),D=new Set([`ask`,`always`,`never`]),O=new Set(w),k=new Set(T);function A(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function j(e,t,n,r){let i=Object.keys(e).filter(e=>!t.includes(e));if(i.length>0)throw Error(`Doom config at ${r} has unsupported ${n} field(s): ${i.join(`, `)}`)}function M(e,t,n){if(e!==void 0){if(typeof e!=`string`||e.trim().length===0)throw Error(`Doom config at ${n} requires ${t} to be a non-empty string`);return e.trim()}}function N(e){for(let t of e){let e=t.codePointAt(0);if(e!==void 0&&(e<=31||e===127))return!0}return!1}function ie(e,t,n,r){let i=M(e,t,n);if(i){if(i.length>r)throw Error(`Doom config at ${n} requires ${t} to be at most ${r} characters`);if(N(i))throw Error(`Doom config at ${n} does not allow control characters in ${t}`);return i}}function ae(e,t){let n=`voice.autoCapture.model`,r=M(e,n,t);if(!r||!S.test(r))throw Error(`Doom config at ${t} requires ${n} in provider/model-id form`);return r}function P(e){return e.normalize(`NFKC`).toLocaleLowerCase(`en-US`).replace(re,` `).replace(/\s+/gu,` `).trim()}function F(e,t,n){if(e===void 0)return;if(!Array.isArray(e)||e.some(e=>typeof e!=`string`))throw Error(`Doom config at ${n} requires ${t} to be an array of strings`);if(e.length>16)throw Error(`Doom config at ${n} requires ${t} to contain at most 16 phrases`);let r=e.map(e=>e.trim()),i=new Set;for(let e of r){if(e.length===0)throw Error(`Doom config at ${n} requires ${t} to contain non-empty strings`);if(e.length>64)throw Error(`Doom config at ${n} requires ${t} phrases to be at most 64 characters`);if(N(e))throw Error(`Doom config at ${n} does not allow control characters in ${t}`);let r=P(e);if(!r)throw Error(`Doom config at ${n} requires ${t} to contain words`);if(i.has(r))throw Error(`Doom config at ${n} does not allow normalized duplicates in ${t}`);i.add(r)}return r}function I(e,t,n,r,i){if(e!==void 0){if(typeof e!=`number`||!Number.isInteger(e)||e<r||e>i)throw Error(`Doom config at ${n} requires ${t} to be an integer from ${r} to ${i}`);return e}}function L(e,t,n,r,i){let a=new Set((e??[]).map(P));if((t??[]).some(e=>a.has(P(e))))throw Error(`Doom config at ${i} does not allow a phrase in both ${n} and ${r}`)}function R(e,t){let n=`voice.autoCapture.tts`;if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);if(j(e,v,n,t),typeof e.engine!=`string`||!k.has(e.engine))throw Error(`Doom config at ${t} requires ${n}.engine to be one of: ${[...k].join(`, `)}`);let r=ie(e.voice,`${n}.voice`,t,64),i=e.rate;if(i!==void 0&&(typeof i!=`number`||!Number.isInteger(i)||i<80||i>500))throw Error(`Doom config at ${t} requires ${n}.rate to be an integer from 80 to 500`);return{engine:e.engine,...r?{voice:r}:{},...i===void 0?{}:{rate:i}}}function z(e,t){if(e===void 0)return;let n=`voice.autoCapture`;if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);j(e,_,n,t);let r=F(e.startPhrases,`${n}.startPhrases`,t),i=F(e.stopPhrases,`${n}.stopPhrases`,t),a=F(e.composeOpenPhrases,`${n}.composeOpenPhrases`,t),o=F(e.composeSendPhrases,`${n}.composeSendPhrases`,t),s=F(e.composeCancelPhrases,`${n}.composeCancelPhrases`,t),c=I(e.utteranceIdleMs,`${n}.utteranceIdleMs`,t,1500,1e4),l=I(e.composeUtteranceIdleMs,`${n}.composeUtteranceIdleMs`,t,800,3e3),u=e.composeNudgeMs===0?0:I(e.composeNudgeMs,`${n}.composeNudgeMs`,t,5e3,6e4),d=I(e.transcriptionTimeoutMs,`${n}.transcriptionTimeoutMs`,t,1e3,12e4);return L(r,i,`startPhrases`,`stopPhrases`,t),L(o,s,`composeSendPhrases`,`composeCancelPhrases`,t),L(a,o,`composeOpenPhrases`,`composeSendPhrases`,t),L(a,s,`composeOpenPhrases`,`composeCancelPhrases`,t),L(i,o,`stopPhrases`,`composeSendPhrases`,t),L(i,s,`stopPhrases`,`composeCancelPhrases`,t),{model:ae(e.model,t),...r?{startPhrases:r}:{},...i?{stopPhrases:i}:{},...a?{composeOpenPhrases:a}:{},...o?{composeSendPhrases:o}:{},...s?{composeCancelPhrases:s}:{},...c===void 0?{}:{utteranceIdleMs:c},...l===void 0?{}:{composeUtteranceIdleMs:l},...u===void 0?{}:{composeNudgeMs:u},...d===void 0?{}:{transcriptionTimeoutMs:d},tts:R(e.tts,t)}}function B(e,t,n){if(e!==void 0){if(typeof e!=`string`||!E.has(e))throw Error(`Doom config at ${n} requires ${t}.thinking to be one of: ${[...E].join(`, `)}`);return e}}function V(e,t,n){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,o,t,n);let r=B(e.thinking,t,n),i=M(e.model,`${t}.model`,n);return{...i?{model:i}:{},...r?{thinking:r}:{}}}function H(e,t,n){if(e!==void 0){if(typeof e==`boolean`)return e;if(e===`true`)return!0;if(e===`false`)return!1;throw Error(`Doom config at ${n} requires ${t} to be true or false`)}}function U(e,t,n){if(e===void 0)return;let r=typeof e==`string`?Number(e.trim()):e;if(typeof r!=`number`||!Number.isFinite(r)||r<l||r>u)throw Error(`Doom config at ${n} requires ${t} to be a number from ${l} to ${u}`);return r}function W(e,t,n){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,c,t,n);let r=U(e.pass1,`${t}.pass1`,n),i=U(e.pass2,`${t}.pass2`,n),a=U(e.pass3,`${t}.pass3`,n);return{...r===void 0?{}:{pass1:r},...i===void 0?{}:{pass2:i},...a===void 0?{}:{pass3:a}}}function G(e,t,n=`modes.autocompact`){if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);j(e,s,n,t);let r=H(e.enabled,`${n}.enabled`,t),i=M(e.model,`${n}.model`,t),a=B(e.thinking,n,t),o=W(e.thresholds,`${n}.thresholds`,t);return{...r===void 0?{}:{enabled:r},...i?{model:i}:{},...a?{thinking:a}:{},...o?{thresholds:o}:{}}}function K(e,t,n=`modes.planning`){if(!A(e))throw Error(`Doom config at ${t} requires ${n} to be an object`);return j(e,a,n,t),{main:V(e.main,`${n}.main`,t),subagents:V(e.subagents,`${n}.subagents`,t),plansDirectory:M(e.plansDirectory,`${n}.plansDirectory`,t)}}function q(e,t,n,r){if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,ne,t,n);let i=M(e.path,`${t}.path`,n),a=M(e.id,`${t}.id`,n);if(!!i==!!a)throw Error(`Doom config at ${n} requires exactly one of ${t}.path or ${t}.id`);if(a&&!r)throw Error(`Doom config at ${n} does not support ${t}.id for whisper-cpp`);return{...i?{path:i}:{},...a?{id:a}:{}}}function J(e,t,n,r){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${n} requires ${t} to be an object`);j(e,te,t,n);let i=M(e.binary,`${t}.binary`,n);return{...i?{binary:i}:{},model:q(e.model,`${t}.model`,n,r)}}function oe(e,t){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${t} requires voice to be an object`);j(e,f,`voice`,t);let n={};if(e.engine!==void 0){if(typeof e.engine!=`string`||!O.has(e.engine))throw Error(`Doom config at ${t} requires voice.engine to be one of: ${[...O].join(`, `)}`);n.engine=e.engine}let r=M(e.language,`voice.language`,t);if(r&&(n.language=r),e.recorder!==void 0){if(!A(e.recorder))throw Error(`Doom config at ${t} requires voice.recorder to be an object`);j(e.recorder,ee,`voice.recorder`,t),n.recorder={};let r=M(e.recorder.binary,`voice.recorder.binary`,t),i=M(e.recorder.device,`voice.recorder.device`,t);r&&(n.recorder.binary=r),i&&(n.recorder.device=i)}if(e.adapters!==void 0){if(!A(e.adapters))throw Error(`Doom config at ${t} requires voice.adapters to be an object`);j(e.adapters,g,`voice.adapters`,t),n.adapters={[p]:J(e.adapters[p],`voice.adapters.${p}`,t,!1),[m]:J(e.adapters[m],`voice.adapters.${m}`,t,!0),[h]:J(e.adapters[h],`voice.adapters.${h}`,t,!0)}}let i=z(e.autoCapture,t);return i&&(n.autoCapture=i),n}function se(e,t){if(e===void 0)return;if(!A(e))throw Error(`Doom config at ${t} requires selection to be an object`);j(e,r,`selection`,t);let n=e.domains;if(n!==void 0&&(!Array.isArray(n)||n.some(e=>typeof e!=`string`)))throw Error(`Doom config at ${t} requires selection.domains to be an array of strings`);return{majorMode:M(e.majorMode,`selection.majorMode`,t),domains:n,profile:M(e.profile,`selection.profile`,t)}}function ce(e,t){if(e!==void 0){if(!A(e))throw Error(`Doom config at ${t} requires editor to be an object`);return j(e,d,`editor`,t),{command:M(e.command,`editor.command`,t)}}}function le(t,r){let a;try{a=e(t)??{}}catch(e){throw Error(`Could not parse Doom config at ${r}`,{cause:e})}if(!A(a))throw Error(`Doom config at ${r} must be a YAML object`);j(a,n,`root`,r);let o;if(a.modes!==void 0){if(!A(a.modes))throw Error(`Doom config at ${r} requires modes to be an object`);j(a.modes,i,`modes`,r),o={...a.modes.planning===void 0?{}:{planning:K(a.modes.planning,r)},...a.modes.autocompact===void 0?{}:{autocompact:G(a.modes.autocompact,r)}}}let s=a.projectTrust===void 0?`ask`:a.projectTrust;if(typeof s!=`string`||!D.has(s))throw Error(`Doom config at ${r} projectTrust must be ask, always, or never`);return{modes:o,projectTrust:s,editor:ce(a.editor,r),voice:oe(a.voice,r),selection:se(a.selection,r)}}function Y(e,t){return e||t?{...e,...t}:void 0}function ue(e,t){if(t.voice?.autoCapture)throw Error(`Repository Doom config voice.autoCapture is global-only; configure it in ~/.pi/.doom/config.yaml`);let n=e.modes?.planning,r=t.modes?.planning,i=n||r?{main:Y(n?.main,r?.main),subagents:Y(n?.subagents,r?.subagents),plansDirectory:r?.plansDirectory??n?.plansDirectory}:void 0,a=e.modes?.autocompact,o=t.modes?.autocompact,s=a||o?{...a,...o,...a?.thresholds||o?.thresholds?{thresholds:{...a?.thresholds,...o?.thresholds}}:{}}:void 0,c=de(e.voice,t.voice);return{modes:i||s?{...i?{planning:i}:{},...s?{autocompact:s}:{}}:void 0,projectTrust:t.projectTrust,editor:e.editor,voice:c,selection:e.selection||t.selection?{...e.selection,...t.selection}:void 0}}function X(e,t){if(!(!e&&!t))return{...e,...t,model:t?.model??e.model}}function de(e,t){if(!(!e&&!t))return{...e,...t,recorder:e?.recorder||t?.recorder?{...e?.recorder,...t?.recorder}:void 0,adapters:e?.adapters||t?.adapters?{[p]:X(e?.adapters?.[p],t?.adapters?.[p]),[m]:X(e?.adapters?.[m],t?.adapters?.[m]),[h]:X(e?.adapters?.[h],t?.adapters?.[h])}:void 0,...e?.autoCapture?{autoCapture:e.autoCapture}:{}}}function fe(e){return{engine:e.engine??t,language:e.language??`auto`,recorder:{...e.recorder,device:e.recorder?.device??`none:default`},adapters:e.adapters??{},...e.autoCapture?{autoCapture:{...e.autoCapture,startPhrases:[...e.autoCapture.startPhrases??[]],stopPhrases:[...e.autoCapture.stopPhrases??[]],composeOpenPhrases:[...e.autoCapture.composeOpenPhrases??y],composeSendPhrases:[...e.autoCapture.composeSendPhrases??b],composeCancelPhrases:[...e.autoCapture.composeCancelPhrases??x],utteranceIdleMs:e.autoCapture.utteranceIdleMs??3e3,composeUtteranceIdleMs:e.autoCapture.composeUtteranceIdleMs??1200,composeNudgeMs:e.autoCapture.composeNudgeMs??1e4,transcriptionTimeoutMs:e.autoCapture.transcriptionTimeoutMs??15e3,tts:{...e.autoCapture.tts}}}:{}}}const pe=[`editor`],me=[`projectTrust`],Z=[[`voice`,`autoCapture`]];function he(e,t){return t.length<=e.length&&t.every((t,n)=>e[n]===t)}function ge(e){if(e.length===0)return`both`;if(Z.some(t=>he(e,t)))return`global`;let t=e[0];return pe.includes(t)?`global`:me.includes(t)?`repository`:`both`}function _e(){return n}function Q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function $(e,t=[]){if(!Q(e))return t.length>0?[t.join(`.`)]:[];let n=Object.keys(e);return n.length===0?t.length>0?[t.join(`.`)]:[]:n.flatMap(n=>$(e[n],[...t,n]))}function ve(e,t){let n=e;for(let e of t){if(!Q(n))return;n=n[e]}return n}export{C as DOOM_PLANNING_THINKING_LEVELS,w as DOOM_VOICE_ENGINES,T as DOOM_VOICE_TTS_ENGINES,$ as configLeafKeys,_e as configRootKeys,ge as configScopeOf,ue as mergeDoomConfigs,G as parseAutocompactModeConfig,le as parseDoomConfig,K as parsePlanningModeConfig,fe as resolveVoiceConfig,ve as valueAtKeyPath};
|
|
2
2
|
//# sourceMappingURL=configPolicy.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configPolicy.mjs","names":["parseYaml"],"sources":["../../src/services/configPolicy.ts"],"sourcesContent":["import { parse as parseYaml } from 'yaml';\nimport type {\n DoomConfig,\n DoomSelectionConfig,\n EditorConfig,\n PlanningAgentConfig,\n PlanningModeConfig,\n PlanningThinkingLevel,\n ProjectTrust,\n ResolvedVoiceConfig,\n VoiceAdapterConfig,\n VoiceAutoCaptureConfig,\n VoiceConfig,\n VoiceEngine,\n VoiceModelConfig,\n VoiceTtsConfig,\n VoiceTtsEngine,\n} from '../types/config.ts';\n\nconst DEFAULT_PROJECT_TRUST: ProjectTrust = 'ask';\nconst DEFAULT_VOICE_ENGINE: VoiceEngine = 'auto';\nconst DEFAULT_VOICE_LANGUAGE = 'auto';\nconst DEFAULT_RECORDER_DEVICE = 'none:default';\nconst ROOT_KEYS = ['modes', 'projectTrust', 'editor', 'voice', 'selection'] as const;\nconst SELECTION_KEYS = ['majorMode', 'domains', 'profile'] as const;\nconst MODE_KEYS = ['planning'] as const;\nconst PLANNING_KEYS = ['main', 'subagents', 'plansDirectory'] as const;\nconst AGENT_KEYS = ['model', 'thinking'] as const;\nconst EDITOR_KEYS = ['command'] as const;\nconst VOICE_KEYS = ['engine', 'language', 'recorder', 'adapters', 'autoCapture'] as const;\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 = 15_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_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\nconst THINKING_VALUES = new Set<PlanningThinkingLevel>(DOOM_PLANNING_THINKING_LEVELS);\nconst TRUST_VALUES = new Set<ProjectTrust>(['ask', 'always', 'never']);\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}\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)\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 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 = value.thinking;\n if (\n thinking !== undefined &&\n (typeof thinking !== 'string' || !THINKING_VALUES.has(thinking as PlanningThinkingLevel))\n ) {\n throw new Error(\n `Doom config at ${filePath} requires ${location}.thinking to be one of: ${[...THINKING_VALUES].join(', ')}`,\n );\n }\n const model = optionalString(value.model, `${location}.model`, filePath);\n return { ...(model ? { model } : {}), ...(thinking ? { thinking: thinking as PlanningThinkingLevel } : {}) };\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.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 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}\nexport function parseDoomConfig(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 ? {} : { planning: parsePlanningModeConfig(parsed.modes.planning, filePath) };\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 projectTrust: trust as ProjectTrust,\n editor: parseEditor(parsed.editor, filePath),\n voice: parseVoice(parsed.voice, filePath),\n selection: parseSelection(parsed.selection, 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?.autoCapture)\n throw new Error('Repository Doom config voice.autoCapture is global-only; configure it in ~/.pi/.doom/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 voice = mergeVoice(globalConfig.voice, repositoryConfig.voice);\n return {\n modes: planning ? { planning } : undefined,\n projectTrust: repositoryConfig.projectTrust,\n editor: globalConfig.editor,\n voice,\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 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}\nexport function resolveVoiceConfig(config: VoiceConfig): ResolvedVoiceConfig {\n return {\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: { ...config.autoCapture.tts },\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 a repository `voice.autoCapture` throws outright.\n * A caller holding a key path has no way to ask. Without an answer, a settings\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[] = ['editor'];\nconst REPOSITORY_ONLY_ROOTS: readonly string[] = ['projectTrust'];\n/** The one nested exception; a repository declaration of it throws in the merge. */\nconst GLOBAL_ONLY_PATHS: readonly (readonly string[])[] = [['voice', 'autoCapture']];\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 * five 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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"}
|
|
1
|
+
{"version":3,"file":"configPolicy.mjs","names":["parseYaml"],"sources":["../../src/services/configPolicy.ts"],"sourcesContent":["import { parse as parseYaml } from 'yaml';\nimport type {\n AutocompactModeConfig,\n AutocompactThresholdConfig,\n DoomConfig,\n DoomSelectionConfig,\n EditorConfig,\n PlanningAgentConfig,\n PlanningModeConfig,\n PlanningThinkingLevel,\n ProjectTrust,\n ResolvedVoiceConfig,\n VoiceAdapterConfig,\n VoiceAutoCaptureConfig,\n VoiceConfig,\n VoiceEngine,\n VoiceModelConfig,\n VoiceTtsConfig,\n VoiceTtsEngine,\n} from '../types/config.ts';\n\nconst DEFAULT_PROJECT_TRUST: ProjectTrust = 'ask';\nconst DEFAULT_VOICE_ENGINE: VoiceEngine = 'auto';\nconst DEFAULT_VOICE_LANGUAGE = 'auto';\nconst DEFAULT_RECORDER_DEVICE = 'none:default';\nconst ROOT_KEYS = ['modes', 'projectTrust', 'editor', 'voice', 'selection'] 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'] as const;\nconst AUTOCOMPACT_THRESHOLD_KEYS = ['pass1', 'pass2', 'pass3'] 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;\nconst EDITOR_KEYS = ['command'] as const;\nconst VOICE_KEYS = ['engine', 'language', 'recorder', 'adapters', 'autoCapture'] as const;\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 = 15_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_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\nconst THINKING_VALUES = new Set<PlanningThinkingLevel>(DOOM_PLANNING_THINKING_LEVELS);\nconst TRUST_VALUES = new Set<ProjectTrust>(['ask', 'always', 'never']);\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}\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)\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}\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 return {\n ...(enabled === undefined ? {} : { enabled }),\n ...(model ? { model } : {}),\n ...(thinking ? { thinking } : {}),\n ...(thresholds ? { thresholds } : {}),\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.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 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}\nexport function parseDoomConfig(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 projectTrust: trust as ProjectTrust,\n editor: parseEditor(parsed.editor, filePath),\n voice: parseVoice(parsed.voice, filePath),\n selection: parseSelection(parsed.selection, 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?.autoCapture)\n throw new Error('Repository Doom config voice.autoCapture is global-only; configure it in ~/.pi/.doom/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.\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 projectTrust: repositoryConfig.projectTrust,\n editor: globalConfig.editor,\n voice,\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 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}\nexport function resolveVoiceConfig(config: VoiceConfig): ResolvedVoiceConfig {\n return {\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: { ...config.autoCapture.tts },\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 a repository `voice.autoCapture` throws outright.\n * A caller holding a key path has no way to ask. Without an answer, a settings\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[] = ['editor'];\nconst REPOSITORY_ONLY_ROOTS: readonly string[] = ['projectTrust'];\n/** The one nested exception; a repository declaration of it throws in the merge. */\nconst GLOBAL_ONLY_PATHS: readonly (readonly string[])[] = [['voice', 'autoCapture']];\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 * five 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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"}
|
package/dist/types/config.d.cts
CHANGED
|
@@ -14,6 +14,24 @@ interface PlanningModeConfig {
|
|
|
14
14
|
subagents?: PlanningAgentConfig;
|
|
15
15
|
plansDirectory?: string;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Ratios of the context window at which each autocompact pass fires.
|
|
19
|
+
*
|
|
20
|
+
* Held as plain numbers so a reader can see the ladder in one place. The
|
|
21
|
+
* package owns the defaults and the ordering rule; this only carries what the
|
|
22
|
+
* file said.
|
|
23
|
+
*/
|
|
24
|
+
interface AutocompactThresholdConfig {
|
|
25
|
+
pass1?: number;
|
|
26
|
+
pass2?: number;
|
|
27
|
+
pass3?: number;
|
|
28
|
+
}
|
|
29
|
+
interface AutocompactModeConfig {
|
|
30
|
+
enabled?: boolean;
|
|
31
|
+
model?: string;
|
|
32
|
+
thinking?: PlanningThinkingLevel;
|
|
33
|
+
thresholds?: AutocompactThresholdConfig;
|
|
34
|
+
}
|
|
17
35
|
interface EditorConfig {
|
|
18
36
|
command?: string;
|
|
19
37
|
}
|
|
@@ -118,6 +136,7 @@ type DoomConfigPendingSelection = DoomConfigTransitionRecord & {
|
|
|
118
136
|
interface DoomConfig {
|
|
119
137
|
modes?: {
|
|
120
138
|
planning?: PlanningModeConfig;
|
|
139
|
+
autocompact?: AutocompactModeConfig;
|
|
121
140
|
};
|
|
122
141
|
projectTrust: ProjectTrust;
|
|
123
142
|
editor?: EditorConfig;
|
|
@@ -211,5 +230,5 @@ interface DoomConfigLayers {
|
|
|
211
230
|
valueAt(keyPath: readonly string[]): unknown;
|
|
212
231
|
}
|
|
213
232
|
//#endregion
|
|
214
|
-
export { ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService$1 as IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine };
|
|
233
|
+
export { AutocompactModeConfig, AutocompactThresholdConfig, ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService$1 as IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine };
|
|
215
234
|
//# sourceMappingURL=config.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.cts","names":[],"sources":["../../src/types/config.ts"],"mappings":";;;KAKY;KACA;KACA;KACA;UAEK;EACf;EACA,WAAW;;UAEI;EACf,OAAO;EACP,YAAY;EACZ;;UAEe;EACf;;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,SAAS;EACT;EACA;IAAa;IAAiB;;EAC9B;IACE,gBAAgB;IAChB,mBAAmB;IACnB,gBAAgB;;EAElB,cAAc;;UAEC;EACf,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;;
|
|
1
|
+
{"version":3,"file":"config.d.cts","names":[],"sources":["../../src/types/config.ts"],"mappings":";;;KAKY;KACA;KACA;KACA;UAEK;EACf;EACA,WAAW;;UAEI;EACf,OAAO;EACP,YAAY;EACZ;;;;;;;;;UASe;EACf;EACA;EACA;;UAEe;EACf;EACA;EACA,WAAW;EACX,aAAa;;UAEE;EACf;;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,SAAS;EACT;EACA;IAAa;IAAiB;;EAC9B;IACE,gBAAgB;IAChB,mBAAmB;IACnB,gBAAgB;;EAElB,cAAc;;UAEC;EACf,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,SAAS;EACT,QAAQ;EACR,YAAY;;UAGG;EACf;EACA;;UAGe;EACf;;EAEA;EACA;EACA;;EAEA;;EAEA;EACA;EACA,oBAAoB;EACpB;EACA;EACA;EACA;EACA;EACA;EACA,aAAa;;EAEb,gBAAgB;EAChB;EACA;EACA;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;;;UAIjC,6BAA2B,mBAA0B,mBAAmB;;YAG7E;IACR,eAAe;;;;KAQP;;UAGK;EACf;EACA;;;;;;EAMA;;EAEA;;;;;;;;;;UAWe;;EAEf,YAAY;EACZ,gBAAgB;EAChB,WAAW;;EAEX,SAAS,6BAA6B;;EAEtC,QAAQ"}
|
package/dist/types/config.d.mts
CHANGED
|
@@ -14,6 +14,24 @@ interface PlanningModeConfig {
|
|
|
14
14
|
subagents?: PlanningAgentConfig;
|
|
15
15
|
plansDirectory?: string;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Ratios of the context window at which each autocompact pass fires.
|
|
19
|
+
*
|
|
20
|
+
* Held as plain numbers so a reader can see the ladder in one place. The
|
|
21
|
+
* package owns the defaults and the ordering rule; this only carries what the
|
|
22
|
+
* file said.
|
|
23
|
+
*/
|
|
24
|
+
interface AutocompactThresholdConfig {
|
|
25
|
+
pass1?: number;
|
|
26
|
+
pass2?: number;
|
|
27
|
+
pass3?: number;
|
|
28
|
+
}
|
|
29
|
+
interface AutocompactModeConfig {
|
|
30
|
+
enabled?: boolean;
|
|
31
|
+
model?: string;
|
|
32
|
+
thinking?: PlanningThinkingLevel;
|
|
33
|
+
thresholds?: AutocompactThresholdConfig;
|
|
34
|
+
}
|
|
17
35
|
interface EditorConfig {
|
|
18
36
|
command?: string;
|
|
19
37
|
}
|
|
@@ -118,6 +136,7 @@ type DoomConfigPendingSelection = DoomConfigTransitionRecord & {
|
|
|
118
136
|
interface DoomConfig {
|
|
119
137
|
modes?: {
|
|
120
138
|
planning?: PlanningModeConfig;
|
|
139
|
+
autocompact?: AutocompactModeConfig;
|
|
121
140
|
};
|
|
122
141
|
projectTrust: ProjectTrust;
|
|
123
142
|
editor?: EditorConfig;
|
|
@@ -211,5 +230,5 @@ interface DoomConfigLayers {
|
|
|
211
230
|
valueAt(keyPath: readonly string[]): unknown;
|
|
212
231
|
}
|
|
213
232
|
//#endregion
|
|
214
|
-
export { ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService$1 as IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine };
|
|
233
|
+
export { AutocompactModeConfig, AutocompactThresholdConfig, ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService$1 as IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine };
|
|
215
234
|
//# sourceMappingURL=config.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.mts","names":[],"sources":["../../src/types/config.ts"],"mappings":";;;KAKY;KACA;KACA;KACA;UAEK;EACf;EACA,WAAW;;UAEI;EACf,OAAO;EACP,YAAY;EACZ;;UAEe;EACf;;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,SAAS;EACT;EACA;IAAa;IAAiB;;EAC9B;IACE,gBAAgB;IAChB,mBAAmB;IACnB,gBAAgB;;EAElB,cAAc;;UAEC;EACf,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;;
|
|
1
|
+
{"version":3,"file":"config.d.mts","names":[],"sources":["../../src/types/config.ts"],"mappings":";;;KAKY;KACA;KACA;KACA;UAEK;EACf;EACA,WAAW;;UAEI;EACf,OAAO;EACP,YAAY;EACZ;;;;;;;;;UASe;EACf;EACA;EACA;;UAEe;EACf;EACA;EACA,WAAW;EACX,aAAa;;UAEE;EACf;;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,SAAS;EACT;EACA;IAAa;IAAiB;;EAC9B;IACE,gBAAgB;IAChB,mBAAmB;IACnB,gBAAgB;;EAElB,cAAc;;UAEC;EACf,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,SAAS;EACT,QAAQ;EACR,YAAY;;UAGG;EACf;EACA;;UAGe;EACf;;EAEA;EACA;EACA;;EAEA;;EAEA;EACA;EACA,oBAAoB;EACpB;EACA;EACA;EACA;EACA;EACA;EACA,aAAa;;EAEb,gBAAgB;EAChB;EACA;EACA;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;;;UAIjC,6BAA2B,mBAA0B,mBAAmB;;YAG7E;IACR,eAAe;;;;KAQP;;UAGK;EACf;EACA;;;;;;EAMA;;EAEA;;;;;;;;;;UAWe;;EAEf,YAAY;EACZ,gBAAgB;EAChB,WAAW;;EAEX,SAAS,6BAA6B;;EAEtC,QAAQ"}
|
package/dist/types.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine } from "./types/config.cjs";
|
|
2
|
-
export { type ConfigValueOrigin, DOOM_CONFIG_SERVICE, type DeepReadonly, type DoomConfig, type DoomConfigContext, type DoomConfigLayer, type DoomConfigLayers, type DoomConfigPendingSelection, type DoomConfigSelection, type DoomConfigTransitionPhase, type DoomConfigTransitionRecord, type DoomConfigTransitionStrategy, type DoomHarnessContext, type DoomSelectionConfig, type EditorConfig, type HarnessState, type IDoomConfigLoader, type IDoomConfigService, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, type PluginHookSource, type ProjectTrust, type ResolvedVoiceAutoCaptureConfig, type ResolvedVoiceConfig, type VoiceAdapterConfig, type VoiceAutoCaptureConfig, type VoiceConfig, type VoiceEngine, type VoiceModelConfig, type VoiceTtsConfig, type VoiceTtsEngine };
|
|
1
|
+
import { AutocompactModeConfig, AutocompactThresholdConfig, ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine } from "./types/config.cjs";
|
|
2
|
+
export { type AutocompactModeConfig, type AutocompactThresholdConfig, type ConfigValueOrigin, DOOM_CONFIG_SERVICE, type DeepReadonly, type DoomConfig, type DoomConfigContext, type DoomConfigLayer, type DoomConfigLayers, type DoomConfigPendingSelection, type DoomConfigSelection, type DoomConfigTransitionPhase, type DoomConfigTransitionRecord, type DoomConfigTransitionStrategy, type DoomHarnessContext, type DoomSelectionConfig, type EditorConfig, type HarnessState, type IDoomConfigLoader, type IDoomConfigService, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, type PluginHookSource, type ProjectTrust, type ResolvedVoiceAutoCaptureConfig, type ResolvedVoiceConfig, type VoiceAdapterConfig, type VoiceAutoCaptureConfig, type VoiceConfig, type VoiceEngine, type VoiceModelConfig, type VoiceTtsConfig, type VoiceTtsEngine };
|
package/dist/types.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine } from "./types/config.mjs";
|
|
2
|
-
export { type ConfigValueOrigin, DOOM_CONFIG_SERVICE, type DeepReadonly, type DoomConfig, type DoomConfigContext, type DoomConfigLayer, type DoomConfigLayers, type DoomConfigPendingSelection, type DoomConfigSelection, type DoomConfigTransitionPhase, type DoomConfigTransitionRecord, type DoomConfigTransitionStrategy, type DoomHarnessContext, type DoomSelectionConfig, type EditorConfig, type HarnessState, type IDoomConfigLoader, type IDoomConfigService, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, type PluginHookSource, type ProjectTrust, type ResolvedVoiceAutoCaptureConfig, type ResolvedVoiceConfig, type VoiceAdapterConfig, type VoiceAutoCaptureConfig, type VoiceConfig, type VoiceEngine, type VoiceModelConfig, type VoiceTtsConfig, type VoiceTtsEngine };
|
|
1
|
+
import { AutocompactModeConfig, AutocompactThresholdConfig, ConfigValueOrigin, DOOM_CONFIG_SERVICE, DeepReadonly, DoomConfig, DoomConfigContext, DoomConfigLayer, DoomConfigLayers, DoomConfigPendingSelection, DoomConfigSelection, DoomConfigTransitionPhase, DoomConfigTransitionRecord, DoomConfigTransitionStrategy, DoomHarnessContext, DoomSelectionConfig, EditorConfig, HarnessState, IDoomConfigLoader, IDoomConfigService, PlanningAgentConfig, PlanningModeConfig, PlanningThinkingLevel, PluginHookSource, ProjectTrust, ResolvedVoiceAutoCaptureConfig, ResolvedVoiceConfig, VoiceAdapterConfig, VoiceAutoCaptureConfig, VoiceConfig, VoiceEngine, VoiceModelConfig, VoiceTtsConfig, VoiceTtsEngine } from "./types/config.mjs";
|
|
2
|
+
export { type AutocompactModeConfig, type AutocompactThresholdConfig, type ConfigValueOrigin, DOOM_CONFIG_SERVICE, type DeepReadonly, type DoomConfig, type DoomConfigContext, type DoomConfigLayer, type DoomConfigLayers, type DoomConfigPendingSelection, type DoomConfigSelection, type DoomConfigTransitionPhase, type DoomConfigTransitionRecord, type DoomConfigTransitionStrategy, type DoomHarnessContext, type DoomSelectionConfig, type EditorConfig, type HarnessState, type IDoomConfigLoader, type IDoomConfigService, type PlanningAgentConfig, type PlanningModeConfig, type PlanningThinkingLevel, type PluginHookSource, type ProjectTrust, type ResolvedVoiceAutoCaptureConfig, type ResolvedVoiceConfig, type VoiceAdapterConfig, type VoiceAutoCaptureConfig, type VoiceConfig, type VoiceEngine, type VoiceModelConfig, type VoiceTtsConfig, type VoiceTtsEngine };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/doompi-config",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.45",
|
|
4
4
|
"description": "Typed configuration loading, validation, and host adapters for composing DoomPi sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-configuration",
|
|
@@ -136,8 +136,8 @@
|
|
|
136
136
|
"dependencies": {
|
|
137
137
|
"@deepseek-ai/cordis": "4.0.1",
|
|
138
138
|
"yaml": "2.9.0",
|
|
139
|
-
"@agimon-ai/doompi-
|
|
140
|
-
"@agimon-ai/doompi-
|
|
139
|
+
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.45",
|
|
140
|
+
"@agimon-ai/doompi-telemetry": "0.0.1-alpha.45"
|
|
141
141
|
},
|
|
142
142
|
"devDependencies": {
|
|
143
143
|
"@earendil-works/pi-coding-agent": "0.84.4",
|